123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176 |
- -module(mad_compile).
- -copyright('Sina Samavati').
- -compile(export_all).
- -define(COMPILE_OPTS(Inc, Ebin, Opts), [report, {i, Inc}, {outdir, Ebin}] ++ Opts).
- -type directory() :: string().
- -type filename() :: string().
- %% compile dependencies
- -spec deps(directory(), any(), filename(), [mad_deps:dependency()]) -> ok.
- deps(_, _, _, []) -> ok;
- deps(Cwd, Conf, ConfigFile, [H|T]) ->
- {Name, _} = mad_deps:name_and_repo(H),
- case get(Name) == compiled andalso get(mode) /= active of
- true -> ok;
- _ -> dep(Cwd, Conf, ConfigFile, Name) end,
- deps(Cwd, Conf, ConfigFile, T).
- %% compile a dependency
- -spec dep(directory(), any(), filename(), string()) -> ok.
- dep(Cwd, _Conf, ConfigFile, Name) ->
- io:format("==> ~p~n",[Name]),
- %% check dependencies of the dependency
- DepsDir = filename:join([mad_utils:get_value(deps_dir, _Conf, ["deps"])]),
- DepPath = filename:join([Cwd, DepsDir, Name]),
- DepConfigFile = filename:join(DepPath, ConfigFile),
- Conf = mad_utils:consult(DepConfigFile),
- Conf1 = mad_utils:script(DepConfigFile, Conf),
- deps(Cwd, Conf, ConfigFile, mad_utils:get_value(deps, Conf1, [])),
- %% add lib_dirs to path
- LibDirs = mad_utils:lib_dirs(DepPath, Conf1),
- code:add_paths(LibDirs),
- SrcDir = filename:join([mad_utils:src(DepPath)]),
- Files = yrl_files(SrcDir) ++ erl_files(SrcDir) ++ app_src_files(SrcDir),
- case Files of
- [] -> ok;
- Files ->
- IncDir = mad_utils:include(DepPath),
- EbinDir = mad_utils:ebin(DepPath),
- %% create EbinDir and add it to code path
- file:make_dir(EbinDir),
- code:add_path(EbinDir),
- Opts = mad_utils:get_value(erl_opts, Conf1, []),
- lists:foreach(compile_fun(IncDir, EbinDir, Opts), Files),
- dtl(DepPath,Conf1),
- put(Name, compiled),
- ok
- end.
- dtl(Dir,Config) ->
- case mad_utils:get_value(erlydtl_opts, Config, []) of
- [] -> skip;
- X -> compile_erlydtl_files(validate_erlydtl_opts(Dir,X)) end.
- -spec validate_property({atom(), term()}, term()) -> {atom(), term()}.
- validate_property({modules, _}, Modules) -> {modules, Modules};
- validate_property(Else, _) -> Else.
- -spec compile_fun(directory(), directory(), [compile:option()]) ->
- fun((file:name(),string(),string(),list(tuple(any(),any())),string()) -> ok).
- compile_fun(Inc,Bin,Opt) -> fun(File) -> compile(File,Inc,Bin,Opt,filetype(File)) end.
- filetype(File) -> L=length(hd(string:tokens(File,"."))), string:substr(File,L+1,length(File)).
- compile(File,Inc,Bin,Opt,".yrl") ->
- ErlFile = yrl_to_erl(File),
- Compiled = is_compiled(ErlFile,File),
- if Compiled == false ->
- yecc:file(File),
- compile(ErlFile,Inc,Bin,Opt,".erl"); true -> ok end;
- compile(File,Inc,Bin,Opt,".erl") ->
- BeamFile = erl_to_beam(Bin, File),
- Compiled = is_compiled(BeamFile, File),
- if Compiled =:= false ->
- io:format("Compiling ~s~n", [File]),
- Opts1 = ?COMPILE_OPTS(Inc, Bin, Opt),
- compile:file(File, Opts1),
- ok;
- true -> ok end;
- compile(File,_Inc,Bin,_Opt,".app.src") ->
- AppFile = filename:join(Bin, app_src_to_app(File)),
- Compiled = is_compiled(AppFile, File),
- if Compiled =:= false ->
- io:format("Writing ~s~n", [AppFile]),
- BeamFiles = filelib:wildcard("*.beam", Bin),
- Modules = [list_to_atom(filename:basename(X, ".beam")) || X <- BeamFiles],
- [Struct|_] = mad_utils:consult(File),
- {application, AppName, Props} = Struct,
- Props1 = add_modules_property(Props),
- Props2 = [validate_property(X, Modules) || X <- Props1],
- Struct1 = {application, AppName, Props2},
- file:write_file(AppFile, io_lib:format("~p.~n", [Struct1])),
- ok;
- true -> ok end;
- compile(File,_Inc,_Bin,_Opt,_) ->
- io:format("Unknown file type: ~p~n",[File]).
- -spec erl_files(directory()) -> [file:name()].
- -spec app_src_files(directory()) -> [file:name()].
- -spec app_src_to_app(file:name()) -> file:name().
- -spec erl_to_beam(directory(), file:name()) -> file:name().
- -spec is_compiled(directory(), file:name()) -> boolean().
- -spec add_modules_property([{atom(), term()}]) -> [{atom(), term()}].
- erl_files(Dir) -> filelib:fold_files(Dir, ".erl", true, fun(F, Acc) -> [F|Acc] end, []).
- yrl_files(Dir) -> filelib:fold_files(Dir, ".yrl", true, fun(F, Acc) -> [F|Acc] end, []).
- app_src_files(Dir) -> filelib:fold_files(Dir, ".app.src", false, fun(F, Acc) -> [F|Acc] end, []).
- app_src_to_app(Filename) -> filename:basename(Filename, ".app.src") ++ ".app".
- yrl_to_erl(Filename) -> filename:join(filename:dirname(Filename),filename:basename(Filename, ".yrl")) ++ ".erl".
- erl_to_beam(Bin, Filename) -> filename:join(Bin, filename:basename(Filename, ".erl") ++ ".beam").
- is_compiled(BeamFile, File) -> mad_utils:last_modified(BeamFile) > mad_utils:last_modified(File).
- add_modules_property(Properties) ->
- case lists:keyfind(modules, 1, Properties) of
- {modules, _} -> Properties;
- _ -> Properties ++ [{modules, []}] end.
- -spec foreach(fun((directory(), filename()) -> ok), [filename()], any(), filename()) -> ok.
- foreach(_, [], _, _) -> ok;
- foreach(Fun, [Dir|T], Config, ConfigFile) ->
- Fun(Dir, Config, ConfigFile),
- foreach(Fun, T, Config, ConfigFile).
- get_kv(K, Opts, Default) ->
- V = mad_utils:get_value(K, Opts, Default),
- KV = {K, V},
- {KV, Opts -- [KV]}.
- validate_erlydtl_opts(Cwd, Opts) ->
- DefaultDocRoot = filename:join("priv", "templates"),
- {DocRoot, Opts1} = get_kv(doc_root, Opts, DefaultDocRoot),
- {OutDir, Opts2} = get_kv(out_dir, Opts1, "ebin"),
- {CompilerOpts, Opts3} = get_kv(compiler_options, Opts2, []),
- {SourceExt, Opts4} = get_kv(source_ext, Opts3, ".dtl"),
- {ModuleExt, Opts5} = get_kv(module_ext, Opts4, ""),
- {_, DocRootDir} = DocRoot,
- DocRoot1 = {doc_root, filename:join(Cwd, DocRootDir)},
- {_, OutDir1} = OutDir,
- OutDir2 = {out_dir, filename:join(Cwd, OutDir1)},
- [DocRoot1, OutDir2, CompilerOpts, SourceExt, ModuleExt|Opts5].
- module_name(File, Ext, NewExt) ->
- list_to_atom(filename:basename(File, Ext) ++ NewExt).
- compile_erlydtl_files(Opts) ->
- {{_, DocRoot}, Opts1} = get_kv(doc_root, Opts, ""),
- {{_, SourceExt}, Opts2} = get_kv(source_ext, Opts1, ""),
- {{_, ModuleExt}, Opts3} = get_kv(module_ext, Opts2, ""),
- {{_, OutDir}, _} = get_kv(out_dir, Opts3, ""),
- Files = filelib:fold_files(DocRoot, SourceExt, true,
- fun(F, Acc) -> [F|Acc] end, []),
- Compile = fun(F) ->
- ModuleName = module_name(F, SourceExt, ModuleExt),
- BeamFile = erl_to_beam(OutDir, atom_to_list(ModuleName)),
- Compiled = is_compiled(BeamFile, F),
- if Compiled =:= false ->
- io:format("DTL Compiling ~s~n", [F]),
- erlydtl:compile(F, ModuleName, Opts3);
- true -> ok end
- end,
- lists:foreach(Compile, Files).
|