#!/usr/bin/env escript %% -*- erlang -*- main([IncludeDir, ErlDir, TargetFile]) -> ErlDirContents = filelib:wildcard("*.erl", ErlDir), ErlFiles = [filename:join(ErlDir, FileName) || FileName <- ErlDirContents], Modules = sets:from_list( [list_to_atom(filename:basename(FileName, ".erl")) || FileName <- ErlDirContents]), IncludeDirContents = filelib:wildcard("*.hrl", IncludeDir), HrlFiles = [filename:join(IncludeDir, FileName) || FileName <- IncludeDirContents], Headers = sets:from_list(IncludeDirContents), Deps = lists:foldl(fun (Path, Acc) -> make_deps(Path, Acc) end, dict:new(), ErlFiles), Deps1 = lists:foldl(fun (Path, Acc) -> make_deps(Path, Acc) end, Deps, HrlFiles), Deps2 = dict:map( fun (_Path, Dep) -> lists:filter( fun ({module, Behaviour}) -> sets:is_element(Behaviour, Modules); ({include, Include}) -> sets:is_element(Include, Headers) end, Dep) end, Deps1), {ok, Hdl} = file:open(TargetFile, [write, delayed_write]), dict:fold( fun (_Path, [], ok) -> ok; (Path, Dep, ok) -> case lists:suffix(".hrl", Path) of false -> Module = filename:basename(Path, ".erl"), ok = file:write(Hdl, ["$(EBIN_DIR)/", Module, ".beam:"]), lists:foreach( fun (E) -> write_deps(Hdl, IncludeDir, E) end, Dep), file:write(Hdl, [" ", ErlDir, "/", Module, ".erl\n"]); true -> ok = file:write(Hdl, [Path, ":"]), lists:foreach( fun (E) -> write_deps(Hdl, IncludeDir, E) end, Dep), file:write(Hdl, "\n") end end, ok, Deps2), ok = file:write(Hdl, [TargetFile, ": ", escript:script_name(), "\n"]), ok = file:sync(Hdl), ok = file:close(Hdl). write_deps(Hdl, _IncludeDir, {module, Behaviour}) -> ok = file:write(Hdl, [" $(EBIN_DIR)/", atom_to_list(Behaviour), ".beam"]); write_deps(Hdl, IncludeDir, {include, Include}) -> ok = file:write(Hdl, [" ", IncludeDir, "/", Include]). make_deps(Path, Deps) -> {ok, Forms} = epp:parse_file(Path, [], []), Behaviours = lists:foldl(fun (Form, Acc) -> detect_deps(Form, Acc) end, [], Forms), dict:store(Path, Behaviours, Deps). detect_deps({attribute, _LineNumber, behaviour, Behaviour}, Deps) -> [{module, Behaviour} | Deps]; detect_deps({error, {_LineNumber, epp, {include, file, Include}}}, Deps) -> [{include, Include} | Deps]; detect_deps(_Form, Deps) -> Deps.