Просмотр исходного кода

Improve file dependency detection

One case was added, where a -compile attribute specified a list
that included a parse_transform. This affected alog, for example.

The COMPILE_FIRST variable is now filled from a digraph. This
allows us to keep track of the dependency tree properly, rather
than rely on luck. This affected erlando.

With both of these changes in, a large chunk of the rebar
autopatch code can be removed, the part that concerned the
auto detection of file dependencies.

On the other hand, we still need to honor the erl_first_files
configuration value, otherwise the parse_trans project fails
to build. While it would be possible to detect these dependencies
automatically too, it's probably too complex to bother, at least
for now.
Loïc Hoguin 9 лет назад
Родитель
Сommit
649505cd5f
2 измененных файлов с 21 добавлено и 70 удалено
  1. 0 51
      core/deps.mk
  2. 21 19
      core/erlc.mk

+ 0 - 51
core/deps.mk

@@ -247,57 +247,6 @@ define dep_autopatch_rebar.erl
 				Write(io_lib:format("COMPILE_FIRST +=~s\n", [Names]))
 				Write(io_lib:format("COMPILE_FIRST +=~s\n", [Names]))
 		end
 		end
 	end(),
 	end(),
-	FindFirst = fun(F, Fd) ->
-		case io:parse_erl_form(Fd, undefined) of
-			{ok, {attribute, _, compile, {parse_transform, PT}}, _} ->
-				[PT, F(F, Fd)];
-			{ok, {attribute, _, compile, CompileOpts}, _} when is_list(CompileOpts) ->
-				case proplists:get_value(parse_transform, CompileOpts) of
-					undefined -> [F(F, Fd)];
-					PT -> [PT, F(F, Fd)]
-				end;
-			{ok, {attribute, _, include, Hrl}, _} ->
-				case file:open("$(call core_native_path,$(DEPS_DIR)/$1/include/)" ++ Hrl, [read]) of
-					{ok, HrlFd} -> [F(F, HrlFd), F(F, Fd)];
-					_ ->
-						case file:open("$(call core_native_path,$(DEPS_DIR)/$1/src/)" ++ Hrl, [read]) of
-							{ok, HrlFd} -> [F(F, HrlFd), F(F, Fd)];
-							_ -> [F(F, Fd)]
-						end
-				end;
-			{ok, {attribute, _, include_lib, "$(1)/include/" ++ Hrl}, _} ->
-				{ok, HrlFd} = file:open("$(call core_native_path,$(DEPS_DIR)/$1/include/)" ++ Hrl, [read]),
-				[F(F, HrlFd), F(F, Fd)];
-			{ok, {attribute, _, include_lib, Hrl}, _} ->
-				case file:open("$(call core_native_path,$(DEPS_DIR)/$1/include/)" ++ Hrl, [read]) of
-					{ok, HrlFd} -> [F(F, HrlFd), F(F, Fd)];
-					_ -> [F(F, Fd)]
-				end;
-			{ok, {attribute, _, import, {Imp, _}}, _} ->
-				case file:open("$(call core_native_path,$(DEPS_DIR)/$1/src/)" ++ atom_to_list(Imp) ++ ".erl", [read]) of
-					{ok, ImpFd} -> [Imp, F(F, ImpFd), F(F, Fd)];
-					_ -> [F(F, Fd)]
-				end;
-			{eof, _} ->
-				file:close(Fd),
-				[];
-			_ ->
-				F(F, Fd)
-		end
-	end,
-	fun() ->
-		ErlFiles = filelib:wildcard("$(call core_native_path,$(DEPS_DIR)/$1/src/)*.erl"),
-		First0 = lists:usort(lists:flatten([begin
-			{ok, Fd} = file:open(F, [read]),
-			FindFirst(FindFirst, Fd)
-		end || F <- ErlFiles])),
-		First = lists:flatten([begin
-			{ok, Fd} = file:open("$(call core_native_path,$(DEPS_DIR)/$1/src/)" ++ atom_to_list(M) ++ ".erl", [read]),
-			FindFirst(FindFirst, Fd)
-		end || M <- First0, lists:member("$(call core_native_path,$(DEPS_DIR)/$1/src/)" ++ atom_to_list(M) ++ ".erl", ErlFiles)]) ++ First0,
-		Write(["COMPILE_FIRST +=", [[" ", atom_to_list(M)] || M <- First,
-			lists:member("$(call core_native_path,$(DEPS_DIR)/$1/src/)" ++ atom_to_list(M) ++ ".erl", ErlFiles)], "\n"])
-	end(),
 	Write("\n\nrebar_dep: preprocess pre-deps deps pre-app app\n"),
 	Write("\n\nrebar_dep: preprocess pre-deps deps pre-app app\n"),
 	Write("\npreprocess::\n"),
 	Write("\npreprocess::\n"),
 	Write("\npre-deps::\n"),
 	Write("\npre-deps::\n"),

+ 21 - 19
core/erlc.mk

@@ -137,12 +137,17 @@ $(PROJECT).d:: $(XRL_FILES) $(YRL_FILES)
 # Erlang and Core Erlang files.
 # Erlang and Core Erlang files.
 
 
 define makedep.erl
 define makedep.erl
+	G = digraph:new([acyclic]),
 	ErlFiles = lists:usort(string:tokens("$(ERL_FILES)", " ")),
 	ErlFiles = lists:usort(string:tokens("$(ERL_FILES)", " ")),
 	Modules = [{filename:basename(F, ".erl"), F} || F <- ErlFiles],
 	Modules = [{filename:basename(F, ".erl"), F} || F <- ErlFiles],
-	Add = fun (Dep, Acc) ->
+	Add = fun (Mod, Dep, Acc) ->
 		case lists:keyfind(atom_to_list(Dep), 1, Modules) of
 		case lists:keyfind(atom_to_list(Dep), 1, Modules) of
-			{_, DepFile} -> [DepFile|Acc];
-			false -> Acc
+			false -> Acc;
+			{_, DepFile} ->
+				digraph:add_vertex(G, Mod),
+				digraph:add_vertex(G, Dep),
+				digraph:add_edge(G, Mod, Dep),
+				[DepFile|Acc]
 		end
 		end
 	end,
 	end,
 	AddHd = fun (Dep, Acc) ->
 	AddHd = fun (Dep, Acc) ->
@@ -152,36 +157,33 @@ define makedep.erl
 			_ -> Acc
 			_ -> Acc
 		end
 		end
 	end,
 	end,
-	CompileFirst = fun (Deps) ->
-		First0 = [case filename:extension(D) of
-			".erl" -> filename:basename(D, ".erl");
-			_ -> []
-		end || D <- Deps],
-		case lists:usort(First0) of
-			[] -> [];
-			[[]] -> [];
-			First -> ["COMPILE_FIRST +=", [[" ", F] || F <- First], "\n"]
-		end
-	end,
 	Depend = [begin
 	Depend = [begin
+		Mod = list_to_atom(filename:basename(F, ".erl")),
 		case epp:parse_file(F, ["include/"], []) of
 		case epp:parse_file(F, ["include/"], []) of
 			{ok, Forms} ->
 			{ok, Forms} ->
 				Deps = lists:usort(lists:foldl(fun
 				Deps = lists:usort(lists:foldl(fun
-					({attribute, _, behavior, Dep}, Acc) -> Add(Dep, Acc);
-					({attribute, _, behaviour, Dep}, Acc) -> Add(Dep, Acc);
-					({attribute, _, compile, {parse_transform, Dep}}, Acc) -> Add(Dep, Acc);
+					({attribute, _, behavior, Dep}, Acc) -> Add(Mod, Dep, Acc);
+					({attribute, _, behaviour, Dep}, Acc) -> Add(Mod, Dep, Acc);
+					({attribute, _, compile, {parse_transform, Dep}}, Acc) -> Add(Mod, Dep, Acc);
+					({attribute, _, compile, CompileOpts}, Acc) when is_list(CompileOpts) ->
+						case proplists:get_value(parse_transform, CompileOpts) of
+							undefined -> Acc;
+							Dep -> Add(Mod, Dep, Acc)
+						end;
 					({attribute, _, file, {Dep, _}}, Acc) -> AddHd(Dep, Acc);
 					({attribute, _, file, {Dep, _}}, Acc) -> AddHd(Dep, Acc);
 					(_, Acc) -> Acc
 					(_, Acc) -> Acc
 				end, [], Forms)),
 				end, [], Forms)),
 				case Deps of
 				case Deps of
 					[] -> "";
 					[] -> "";
-					_ -> [F, "::", [[" ", D] || D <- Deps], "; @touch \$$@\n", CompileFirst(Deps)]
+					_ -> [F, "::", [[" ", D] || D <- Deps], "; @touch \$$@\n"]
 				end;
 				end;
 			{error, enoent} ->
 			{error, enoent} ->
 				[]
 				[]
 		end
 		end
 	end || F <- ErlFiles],
 	end || F <- ErlFiles],
-	ok = file:write_file("$(1)", Depend),
+	CompileFirst = [X || X <- lists:reverse(digraph_utils:topsort(G)), [] =/= digraph:in_neighbours(G, X)],
+	ok = file:write_file("$(1)", [Depend, "\nCOMPILE_FIRST +=",
+		[[" ", atom_to_list(CF)] || CF <- CompileFirst], "\n"]),
 	halt()
 	halt()
 endef
 endef