#!/usr/bin/env escript %% -*- erlang -*- -mode(compile). 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, Deps1) -> dict:store(Path, detect_deps(Path), Deps1) end, dict:new(), ErlFiles ++ HrlFiles), Deps1 = 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, Deps), {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:"]), [write_deps(Hdl, IncludeDir, E) || E <- Dep], file:write(Hdl, [" ", ErlDir, "/", Module, ".erl\n"]); true -> ok = file:write(Hdl, [Path, ":"]), [write_deps(Hdl, IncludeDir, E) || E <- Dep], file:write(Hdl, "\n") end end, ok, Deps1), 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]). detect_deps(Path) -> {ok, Forms} = epp:parse_file(Path, [], [{use_specs, true}]), lists:foldl( fun ({attribute, _LineNumber, behaviour, Behaviour}, Deps) -> [{module, Behaviour} | Deps]; ({error, {_LineNumber, epp, {include, file, Include}}}, Deps) -> [{include, Include} | Deps]; (_Form, Deps) -> Deps end, [], Forms).