#!/usr/bin/env escript %% -*- erlang -*- -mode(compile). %% We expect the list of Erlang source and header files to arrive on %% stdin, with the entries colon-separated. main([TargetFile, EbinDir]) -> ErlsAndHrls = [ string:strip(S,left) || S <- string:tokens(io:get_line(""), ":\n")], ErlFiles = [F || F <- ErlsAndHrls, lists:suffix(".erl", F)], Modules = sets:from_list( [list_to_atom(filename:basename(FileName, ".erl")) || FileName <- ErlFiles]), HrlFiles = [F || F <- ErlsAndHrls, lists:suffix(".hrl", F)], IncludeDirs = lists:usort([filename:dirname(Path) || Path <- HrlFiles]), Headers = sets:from_list(HrlFiles), Deps = lists:foldl( fun (Path, Deps1) -> dict:store(Path, detect_deps(IncludeDirs, EbinDir, Modules, Headers, Path), Deps1) end, dict:new(), ErlFiles), {ok, Hdl} = file:open(TargetFile, [write, delayed_write]), dict:fold( fun (_Path, [], ok) -> ok; (Path, Dep, ok) -> Module = filename:basename(Path, ".erl"), ok = file:write(Hdl, [EbinDir, "/", Module, ".beam: ", Path]), ok = sets:fold(fun (E, ok) -> file:write(Hdl, [" ", E]) end, ok, Dep), file:write(Hdl, ["\n"]) end, ok, Deps), ok = file:write(Hdl, [TargetFile, ": ", escript:script_name(), "\n"]), ok = file:sync(Hdl), ok = file:close(Hdl). detect_deps(IncludeDirs, EbinDir, Modules, Headers, Path) -> {ok, Forms} = epp:parse_file(Path, IncludeDirs, [{use_specs, true}]), lists:foldl( fun ({attribute, _LineNumber, Attribute, Behaviour}, Deps) when Attribute =:= behaviour orelse Attribute =:= behavior -> case sets:is_element(Behaviour, Modules) of true -> sets:add_element( [EbinDir, "/", atom_to_list(Behaviour), ".beam"], Deps); false -> Deps end; ({attribute, _LineNumber, file, {FileName, _LineNumber1}}, Deps) -> case sets:is_element(FileName, Headers) of true -> sets:add_element(FileName, Deps); false -> Deps end; (_Form, Deps) -> Deps end, sets:new(), Forms).