diff -Naur otp_src_R13B/erts/doc/src/erlc.xml otp_src_R13B-makedep/erts/doc/src/erlc.xml --- otp_src_R13B/erts/doc/src/erlc.xml 2009-03-12 13:15:18.000000000 +0100 +++ otp_src_R13B-makedep/erts/doc/src/erlc.xml 2009-06-08 11:21:54.410808851 +0200 @@ -137,6 +137,50 @@ for compiling native code, which needs to be compiled with the same run-time system that it should be run on.
+Produces a Makefile rule to track headers dependencies. The + rule is sent to stdout. No object file is produced. +
+Like the
Same as
In conjunction with
Like the
In conjunction with
In conjunction with
Signals that no more options will follow.
diff -Naur otp_src_R13B/erts/etc/common/erlc.c otp_src_R13B-makedep/erts/etc/common/erlc.c
--- otp_src_R13B/erts/etc/common/erlc.c 2009-03-12 13:16:53.000000000 +0100
+++ otp_src_R13B-makedep/erts/etc/common/erlc.c 2009-06-08 11:21:54.417804766 +0200
@@ -256,6 +256,66 @@
case 'I':
PUSH2("@i", process_opt(&argc, &argv, 0));
break;
+ case 'M':
+ {
+ char *buf, *key, *val;
+ size_t buf_len, key_len, val_len;
+
+ if (argv[1][2] == '\0') { /* -M */
+ buf = emalloc(4);
+ buf[0] = '\'';
+ buf[1] = argv[1][1];
+ buf[2] = '\'';
+ buf[3] = '\0';
+
+ PUSH2("@option", buf);
+ } else {
+ switch(argv[1][2]) {
+ case 'P': /* -MP */
+ case 'D': /* -MD */
+ case 'G': /* -MG */
+ buf = emalloc(5);
+ buf[0] = '\'';
+ buf[1] = argv[1][1];
+ buf[2] = argv[1][2];
+ buf[3] = '\'';
+ buf[4] = '\0';
+
+ PUSH2("@option", buf);
+ break;
+ case 'T': /* -MT
Produces a Makefile rule to track headers dependencies. The + rule is sent to stdout. No object file is produced. +
+Like the
Same as
In conjunction with
Like the
In conjunction with
In conjunction with
Produces a listing of the parsed code after preprocessing diff -Naur otp_src_R13B/lib/compiler/src/compile.erl otp_src_R13B-makedep/lib/compiler/src/compile.erl --- otp_src_R13B/lib/compiler/src/compile.erl 2009-04-16 11:23:39.000000000 +0200 +++ otp_src_R13B-makedep/lib/compiler/src/compile.erl 2009-06-08 11:21:54.543231742 +0200 @@ -150,6 +150,12 @@ expand_opt(no_float_opt, Os) -> %%Turn off the entire type optimization pass. [no_topt|Os]; +expand_opt('MD', Os) -> + ['M', {'MF', default} | Os]; +expand_opt({'MQ', T}, Os) -> + Fun = fun($$) -> "$$"; (C) -> C end, + T1 = lists:flatten(lists:map(Fun, T)), + [{'MT', T1} | Os]; expand_opt(O, Os) -> [O|Os]. %% format_error(ErrorDescriptor) -> string() @@ -404,6 +410,8 @@ %% file will be Ext. (Ext should not contain %% a period.) No more passes will be run. %% +%% done End compilation at this point. +%% %% {done,Ext} End compilation at this point. Produce a listing %% as with {listing,Ext}, unless 'binary' is %% specified, in which case the current @@ -437,6 +445,8 @@ [{listing,fun (St) -> src_listing(Ext, St) end}]; select_passes([{listing,Ext}|_], _Opts) -> [{listing,fun (St) -> listing(Ext, St) end}]; +select_passes([done|_], _Opts) -> + []; select_passes([{done,Ext}|_], Opts) -> select_passes([{unless,binary,{listing,Ext}}], Opts); select_passes([{iff,Flag,Pass}|Ps], Opts) -> @@ -519,6 +529,10 @@ standard_passes() -> [?pass(transform_module), + + {iff,'M',?pass(makedep)}, + {iff,'M',done}, + {iff,'dpp',{listing,"pp"}}, ?pass(lint_module), {iff,'P',{src_listing,"P"}}, @@ -862,6 +876,120 @@ errors=St#compile.errors ++ Es}} end. +makedep(#compile{options = Opts} = St) -> + Ifile = St#compile.ifile, + Ofile = St#compile.ofile, + % Get the target of the Makefile rule. + Target = case proplists:get_value('MT', Opts) of + undefined -> + % The target is derived from the output filename: eventually + % remove the current working directory to obtain a relative + % path. + Cwd = proplists:get_value(cwd, Opts), + case lists:prefix(Cwd, Ofile) of + true -> lists:nthtail(length(Cwd) + 1, Ofile); + false -> Ofile + end; + T -> + % The caller specified one with "-MT". + T + end, + Target1 = Target ++ ":", + % List the dependencies (includes) for this target. + {Main_Target, Phony} = makedep_add_headers(Ifile, St#compile.code, + [], length(Target1), Target1, "", Opts), + % Prepare the content of the Makefile. For instance: + % hello.erl: hello.hrl common.hrl + % + % Or if phony targets are enabled: + % hello.erl: hello.hrl common.hrl + % + % hello.hrl: + % + % common.hrl: + Makefile = case lists:member('MP', Opts) of + true -> Main_Target ++ Phony; + false -> Main_Target + end, + % Write this Makefile to the selected output. + case proplists:get_value('MF', Opts) of + undefined -> + % Output to stdout. + io:format("~s~n", [Makefile]); + O -> + % Output to a regular file. + Output = case O of + default -> filename:basename(Ofile, ".beam") ++ ".Pbeam"; + _ -> O + end, + case file:open(Output, write) of + {ok, Io_Dev} -> + io:fwrite(Io_Dev, "~s~n", [Makefile]), + file:close(Io_Dev); + {error, Reason} -> + io:format("Couldn't open makefile `~s': ~p~n", + [Output, Reason]) + end + end, + {ok, St}. + +makedep_add_headers(Ifile, [{attribute, _, file, {File, _}} | Rest], + Included, Line_Len, Main_Target, Phony, Opts) -> + {Included1, Line_Len1, Main_Target1, Phony1} = makedep_add_header( + Ifile, Included, Line_Len, Main_Target, Phony, File), + makedep_add_headers(Ifile, Rest, Included1, Line_Len1, + Main_Target1, Phony1, Opts); +makedep_add_headers(Ifile, [{error, {_, epp, {include, file, File}}} | Rest], + Included, Line_Len, Main_Target, Phony, Opts) -> + % The header doesn't exist, do we add it? + case lists:member('MG', Opts) of + true -> + {Included1, Line_Len1, Main_Target1, Phony1} = makedep_add_header( + Ifile, Included, Line_Len, Main_Target, Phony, File), + makedep_add_headers(Ifile, Rest, Included1, Line_Len1, + Main_Target1, Phony1, Opts); + false -> + makedep_add_headers(Ifile, Rest, Included, Line_Len, + Main_Target, Phony, Opts) + end; +makedep_add_headers(Ifile, [_ | Rest], Included, Line_Len, + Main_Target, Phony, Opts) -> + makedep_add_headers(Ifile, Rest, Included, + Line_Len, Main_Target, Phony, Opts); +makedep_add_headers(_Ifile, [], _Included, _Line_Len, + Main_Target, Phony, _Opts) -> + {Main_Target, Phony}. + +makedep_add_header(Ifile, Included, Line_Len, Main_Target, Phony, File) -> + case lists:member(File, Included) of + true -> + % This file was already listed in the dependencies, skip it. + {Included, Line_Len, Main_Target, Phony}; + false -> + Included1 = [File | Included], + % Remove "./" in front of the dependency filename. + File1 = case lists:prefix("./", File) of + true -> lists:nthtail(2, File); + false -> File + end, + % Prepare the phony target name. + Phony1 = case File of + Ifile -> Phony; + _ -> Phony ++ "\n\n" ++ File1 ++ ":" + end, + % Add the file to the dependencies. + if + Line_Len + 1 + length(File1) > 76 -> + Line_Len1 = 2 + length(File1), + Main_Target1 = Main_Target ++ " \\\n " ++ File1, + {Included1, Line_Len1, Main_Target1, Phony1}; + true -> + Line_Len1 = Line_Len + 1 + length(File1), + Main_Target1 = Main_Target ++ " " ++ File1, + {Included1, Line_Len1, Main_Target1, Phony1} + end + end. + %% expand_module(State) -> State' %% Do the common preprocessing of the input forms.