Browse Source

Merge pull request #57 from naga-framework/fix_port

fix port
Namdak Tonpa 8 years ago
parent
commit
d49d1d64db
4 changed files with 210 additions and 40 deletions
  1. 1 1
      include/mad.hrl
  2. BIN
      mad
  3. 73 13
      src/compile/mad_dtl.erl
  4. 136 26
      src/compile/mad_port.erl

+ 1 - 1
include/mad.hrl

@@ -1 +1 @@
--define(VERSION,"d18ba4").
+-define(VERSION,"ed64b0").

BIN
mad


+ 73 - 13
src/compile/mad_dtl.erl

@@ -5,7 +5,10 @@
 compile(Dir,Config) ->
     case mad_utils:get_value(erlydtl_opts, Config, []) of
         [] -> false;
-         X -> compile_erlydtl_files(validate_erlydtl_opts(Dir,X)) end.
+         X -> O = validate_erlydtl_opts(Dir,X),
+              case compile_erlydtl_files(O) of true -> true; 
+                false -> case compile_erlydtl_naga_files({naga,view_dir},O) of 
+                         true -> true; false -> compile_erlydtl_naga_files({naga_mail,mail_dir},O) end end end.
 
 get_kv(K, Opts, Default) ->
     V = mad_utils:get_value(K, Opts, Default),
@@ -15,22 +18,27 @@ get_kv(K, Opts, Default) ->
 file_to_beam(Bin, Filename) -> filename:join(Bin, filename:basename(Filename) ++ ".beam").
 
 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,
+    DefaultDocRoot          = filename:join("priv", "templates"),
+    {{_, DocRootDir}, Opts1}= get_kv(doc_root, Opts, DefaultDocRoot),
+    {{_, OutDir1}, 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, ""),
+
     DocRoot1 = {doc_root, filename:join(Cwd, DocRootDir)},
-    {_, OutDir1} = OutDir,
     OutDir2 = {out_dir, filename:join(Cwd, OutDir1)},
+ 
+    [{cwd, Cwd},DocRoot1, OutDir2, CompilerOpts, SourceExt, ModuleExt|Opts5].
 
-    [DocRoot1, OutDir2, CompilerOpts, SourceExt, ModuleExt|Opts5].
 
 module_name(File, Ext, NewExt) ->
     list_to_atom(filename:basename(File, Ext) ++ NewExt).
+module_name(File, ViewsOpts) ->
+    {{_, Cwd}, _} = get_kv(cwd, ViewsOpts, ""),
+    F = filename:split(File -- Cwd) -- ["/"],
+    %mad:info("module_name File ~p~n",[F]),
+    Name = mad_naga:view_module(F,ViewsOpts),
+    list_to_atom(Name).
 
 compile_erlydtl_files(Opts) ->
 
@@ -39,7 +47,7 @@ compile_erlydtl_files(Opts) ->
     {{_, ModuleExt}, Opts3} = get_kv(module_ext, Opts2, ""),
     {{_, OutDir},        _} = get_kv(out_dir,    Opts3, ""),
 
-    Files = filelib:fold_files(DocRoot, SourceExt, true,
+    Files = filelib:fold_files(DocRoot, SourceExt++"$", true,
                                fun(F, Acc) -> [F|Acc] end, []),
 
     Compile = fun(F) ->
@@ -55,4 +63,56 @@ compile_erlydtl_files(Opts) ->
              true -> ok end
     end,
 
-    lists:any(fun({error,_}) -> true; (ok) -> false end,[Compile(F) || F <- Files]).
+    lists:any(fun({error,_}) -> true; ({ok,_,_}) -> false; ({ok,_}) -> false; (ok) -> false end,[Compile(F) || F <- Files]).
+
+
+compile_erlydtl_naga_files({App0,D}, Opts) ->
+
+    {{_, Naga},    O1} = get_kv(App0,    Opts, []),    
+    {{_, OutDir},  O2} = get_kv(out_dir, O1, "ebin"),
+    {{_, Cwd},     O3} = get_kv(cwd,     O2, ""),
+
+    Get = fun(X) -> 
+            {{_, Val },  _} = get_kv(X, Naga, proplists:get_value(X, mad_naga:cfg_dtl())),
+            case Val of true -> true; false-> false; [{_,_}|_]=E -> E; 
+                Dir ->filename:join(Val) end end,
+
+    case Get(enable) of true -> 
+        NagaExt   = Get(extensions),
+        Force     = Get(force),
+        DocRoot   = filename:join(Cwd,Get(D)),
+        TagDir    = filename:join(Cwd,Get(tag_dir)),
+        FilterDir = filename:join(Cwd,Get(filter_dir)),
+        HtmlTags  = filename:join(Cwd,Get(htmltags_dir)),
+        CustomTags= filename:join(Cwd,Get(custom_tags)),
+        AutoEscape= Get(auto_escape),
+        App       = filename:basename(Cwd),
+        OO = [ {cwd,Cwd},{app,App},{extensions, NagaExt},{view_dir, DocRoot}
+              ,{htmltags_dir, HtmlTags},{tag_dir, TagDir}
+              ,{filter_dir, FilterDir},{custom_tags, CustomTags}
+              ],
+        NagaOpts = [
+         {cwd, Cwd},{doc_root, DocRoot},
+         {app,App},{extensions, NagaExt},{out_dir, OutDir},
+         {auto_escape, AutoEscape},
+         {custom_filters_modules,mad_naga:modules(tag_dir, OO)++mad_naga:modules(filter_dir, OO)},
+         {custom_tags_modules, mad_naga:modules(custom_tags, OO)},
+         {custom_tags_dir, mad_naga:modules(htmltags_dir, OO)}],
+      
+        Files = mad_naga:find_files(DocRoot,NagaExt),
+        
+        Compile = fun(F) ->
+            ModuleName = module_name(F, NagaOpts),
+            BeamFile = file_to_beam(OutDir, atom_to_list(ModuleName)),
+            Compiled = mad_compile:is_compiled(BeamFile, F),
+            if  Compiled =:= false orelse Force ->
+                 %mad:info("DTL options ~p",[NagaOpts]),
+                 mad:info("DTL Compiling ~s --> ~s~n", [F -- mad_utils:cwd(), atom_to_list(ModuleName)]),
+                 Res = erlydtl:compile(F, ModuleName, NagaOpts),
+                 case Res of {error,Error} -> mad:info("Error: ~p~n",[Error]);
+                                        OK -> OK end;
+                 true -> ok end
+        end,
+        lists:any(fun({error,_}) -> true; ({ok,_}) -> false; (ok) -> false end,[Compile(F) || F <- Files]); 
+        _ -> false end.
+

+ 136 - 26
src/compile/mad_port.erl

@@ -2,32 +2,142 @@
 -copyright('Maxim Sokhatsky').
 -compile(export_all).
 
-replace_env(String, []) -> String;
-replace_env(String, [{K,V}|Env]) ->
-   replace_env(re:replace(String, K, V, [global, {return, list}]),Env).
-
 compile(Dir,Config) ->
-    case mad_utils:get_value(port_specs, Config, []) of
-        [] -> [false];
-         X -> compile_port(Dir,X,Config) end.
+  case mad_utils:get_value(port_specs, Config, []) of
+      [] -> [false];
+       X -> compile_port(Dir,X,Config) end.
 
 compile_port(Dir,Specs0,Config) ->
-    {_,Flavour} = os:type(),
-    System = atom_to_list(Flavour),
-    Specs = [ {O,F} || {Sys,O,F} <- Specs0, Sys == System] ++
-            [ {O,F} || {O,F} <- Specs0],
-    filelib:ensure_dir(Dir ++ "/priv/"),
-    Env =  [ {Var,Val} || {Sys,Var,Val} <- mad_utils:get_value(port_env, Config, []), Sys == System ] ++
-          [ {Var,Val} || {Var,Val} <- mad_utils:get_value(port_env, Config, []) ] ++
-           [{"LDFLAGS",[]},{"CFLAGS",[]}],
-    [ begin
-           Template = string:join(filelib:wildcard(Dir ++ "/" ++ Files)," ") 
-              ++ " CFLAGS LDFLAGS -o " ++ Dir ++ "/" ++ Out,
-       Args = string:strip(replace_env(Template,Env),both,32),
-       %mad:info("Args: ~p~n",[Args]),
-       %mad:info("Env: ~p~n",[Env]),
-       {_,Status,Report} = sh:run("cc",string:tokens(Args," "),binary,Dir,Env),
-       case Status of
-          0 -> false;
-          _ -> mad:info("Port Compilation Error:~n" ++ io_lib:format("~ts",[Report]),[]), true end
-      end || {Out,Files} <- Specs ].
+  {_,Flavour} = os:type(),
+  System = atom_to_list(Flavour),
+  Specs = [ {O,F} || {Sys,O,F} <- Specs0, Sys == System] ++
+          [ {O,F} || {O,F} <- Specs0],
+  filelib:ensure_dir(Dir ++ "/priv/"),
+  Env = [ {Var,Val} || {Sys,Var,Val} <- mad_utils:get_value(port_env, Config, []), system(Sys,System) ] ++
+        [ {Var,Val} || {Var,Val} <- mad_utils:get_value(port_env, Config, []) ],
+
+  Job = fun({Target, Patterns}) ->
+          Files      = files(Dir,Patterns),
+          LinkLang   = link_lang(Files),
+          TargetType = target_type(extension(Target)),
+
+          Compile = fun(F) ->
+                       Obj = to_obj(F),
+                       case is_compiled(Obj,F) of
+                        false ->
+                           Ext   = extension(F),
+                           CC    = compiler(Ext),
+                           TplCC = tpl_cc(TargetType,CC),
+                           Env1  = [{"PORT_IN_FILES", F},{"PORT_OUT_FILE", Obj}] ++ Env ++ default_env(),
+                           CmdCC = string:strip(expand(System,TplCC,Env1)),
+                           Cmd = expand(System,CmdCC,[{"CXXFLAGS",""},{"LDFLAGS",""},{"CFLAGS",""}]),
+                           mad:info("cc ~s~n",[Cmd]),
+                           {_,Status,Report} = sh:run("cc",string:tokens(Cmd," "),binary,Dir,Env),
+                           case Status of 0 -> {ok,Obj} ;_ -> {error, Report} end;
+                        true -> {even,Obj}
+                       end 
+                    end,
+
+          {EvenOrOk,Errors} = lists:partition(fun({ok,_})   -> true;
+                                                 ({even,_}) -> true;
+                                                 ({error,_})-> false
+                                              end,[Compile(F) || F <- Files]),
+          %mad:info("EvenOrOk: ~p~nErrors: ~p~n",[EvenOrOk,Errors]),
+          case Errors of
+            [] -> case lists:any(fun({ok,_}) -> true;(_)->false end, EvenOrOk) of
+                   false ->  false; %% all even, no need to link target
+                   true  ->  Objs = [O||{_,O} <-EvenOrOk],
+                             Env2  = [{"PORT_IN_FILES", string:join(Objs," ")},
+                                      {"PORT_OUT_FILE", Target}] ++ Env ++ default_env(),
+                             TplLD = tpl_ld(TargetType,LinkLang),
+                             CmdLD = string:strip(expand(System,TplLD,Env2)),
+                             Cmd = expand(System,CmdLD,[{"CXXFLAGS",""},{"LDFLAGS",""},{"CFLAGS",""}]),
+                             mad:info("cc ~s~n",[Cmd]),
+                             {_,Status,Report} = sh:run("cc",string:tokens(Cmd," "),binary,Dir,Env),
+                             case Status of 
+                              0 -> false;
+                              _ -> mad:info("Port Compilation Error:~n" ++ io_lib:format("~ts",[Report]),[]),
+                                   {error, Report},true
+                             end                      
+                  end;
+            Errors -> mad:info("Port Compilation Error:~p~n",[Errors]),
+                      true
+          end
+        end,
+  [Job(S)||S<-Specs].
+
+to_obj(F) -> filename:rootname(F) ++ ".o".
+
+%%FIXME
+expand(System, String, []) -> String;
+expand(System, String, [{K,V}|Env]) ->
+  New = re:replace(String, io_lib:format("\\${?(~s)}?",[K]), V, [global, {return, list}]),
+  expand(System,New,Env);
+expand(System, String, [{Sys,K,V}|Env]) -> 
+  case system(Sys,System) of
+    true -> New = re:replace(String, io_lib:format("\\${?(~s)}?",[K]), V, [global, {return, list}]),
+            expand(System,New,Env);
+    false -> expand(System,String,Env)
+  end.
+
+extension(F)       -> filename:extension(F).
+is_compiled(O,F)   -> filelib:is_file(O) andalso (mad_utils:last_modified(O) >= mad_utils:last_modified(F)). 
+join(A,B)          -> filename:join(A,B).
+concat(X)          -> lists:concat(X).
+system(Sys,System) -> Sys == System orelse match(Sys,System).
+match(Re,System)   -> case re:run(System, Re, [{capture,none}]) of match -> true; nomatch -> false end.
+erts_dir()         -> join(code:root_dir(), concat(["erts-", erlang:system_info(version)])) .
+erts_dir(include)  -> " -I"++join(erts_dir(), "include").
+ei_dir()           -> case code:lib_dir(erl_interface) of {error,bad_name} -> ""; E -> E end.
+ei_dir(include)    -> case ei_dir() of "" -> ""; E -> " -I"++join(E,"include") end;
+ei_dir(lib)        -> case ei_dir() of "" -> ""; E -> " -L"++join(E,"lib") end.
+link_lang(Files)   -> lists:foldl(fun(F,cxx) -> cxx;
+                                     (F,cc) -> case compiler(extension(F)) == "$CXX" of 
+                                                true -> cxx;false -> cc end
+                                  end,cc,Files).
+
+files(Dir,Patterns)-> files(Dir,Patterns, []).
+files(_,[], Acc) -> lists:reverse(Acc);
+files(D,[H|T], Acc) ->
+  files(D,T,filelib:wildcard(join(D,H))++Acc). 
+
+
+target_type(".so")   -> drv;
+target_type(".dll")  -> drv;
+target_type("")      -> exe;
+target_type(".exe")  -> exe.
+
+tpl_cc(drv,"$CC") -> " -c $CFLAGS $DRV_CFLAGS $PORT_IN_FILES -o $PORT_OUT_FILE";  
+tpl_cc(drv,"$CXX")-> " -c $CXXFLAGS $DRV_CFLAGS $PORT_IN_FILES -o $PORT_OUT_FILE";  
+tpl_cc(exe,"$CC") -> " -c $CFLAGS $EXE_CFLAGS $PORT_IN_FILES -o $PORT_OUT_FILE";  
+tpl_cc(exe,"$CXX")-> " -c $CXXFLAGS $EXE_CFLAGS $PORT_IN_FILES -o $PORT_OUT_FILE".  
+
+tpl_ld(drv,cc)  -> " $PORT_IN_FILES $LDFLAGS $DRV_LDFLAGS -o $PORT_OUT_FILE";
+tpl_ld(drv,cxx) -> " $PORT_IN_FILES $LDFLAGS $DRV_LDFLAGS -o $PORT_OUT_FILE";
+tpl_ld(exe,cc)  -> " $PORT_IN_FILES $LDFLAGS $EXE_LDFLAGS -o $PORT_OUT_FILE";
+tpl_ld(exe,cxx) -> " $PORT_IN_FILES $LDFLAGS $EXE_LDFLAGS -o $PORT_OUT_FILE".
+
+erl_ldflag() -> concat([ei_dir(include), erts_dir(include), " "]).
+
+default_env() ->
+    Arch = os:getenv("REBAR_TARGET_ARCH"),
+    Vsn = os:getenv("REBAR_TARGET_ARCH_VSN"),
+    [
+     {"darwin", "DRV_LDFLAGS", "-bundle -flat_namespace -undefined suppress " ++ei_dir(lib) ++" -lerl_interface -lei"},
+     {"DRV_CFLAGS" , "-g -Wall -fPIC -MMD " ++ erl_ldflag()},
+     {"DRV_LDFLAGS", "-shared " ++ erl_ldflag()},
+     {"EXE_CFLAGS" , "-g -Wall -fPIC -MMD " ++ erl_ldflag()},
+     {"EXE_LDFLAGS", ei_dir(lib)++" -lerl_interface -lei"},
+     {"ERL_EI_LIBDIR", ei_dir(lib)}
+    ].
+
+compiler(".cc")  -> "$CXX";
+compiler(".cp")  -> "$CXX";
+compiler(".cxx") -> "$CXX";
+compiler(".cpp") -> "$CXX";
+compiler(".CPP") -> "$CXX";
+compiler(".c++") -> "$CXX";
+compiler(".C")   -> "$CXX";
+compiler(cxx)    -> "$CXX";
+compiler(cc)     -> "$CC";
+compiler(_)      -> "$CC".