From 004ae229a1c8e9d066b058097bda14d7a9a57b50 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Hoguin?= Date: Fri, 22 May 2015 11:21:15 +0300 Subject: Handle executable ports Previously we only did shared libraries, now we allow executables. Also improve greatly the handling of autopatched rebar projects by relying once again on the rebar_utils module. --- core/deps.mk | 178 +++++++++++++++++++++++++++++------------------------------ 1 file changed, 86 insertions(+), 92 deletions(-) (limited to 'core/deps.mk') diff --git a/core/deps.mk b/core/deps.mk index c1e3862..228bef5 100644 --- a/core/deps.mk +++ b/core/deps.mk @@ -136,14 +136,15 @@ define dep_autopatch_rebar.erl {ok, Conf0} -> Conf0; _ -> [] end, - Conf = case filelib:is_file("$(DEPS_DIR)/$(1)/rebar.config.script") of - false -> Conf1; + {Conf, OsEnv} = case filelib:is_file("$(DEPS_DIR)/$(1)/rebar.config.script") of + false -> {Conf1, []}; true -> Bindings0 = erl_eval:new_bindings(), Bindings1 = erl_eval:add_binding('CONFIG', Conf1, Bindings0), Bindings = erl_eval:add_binding('SCRIPT', "$(DEPS_DIR)/$(1)/rebar.config.script", Bindings1), + Before = os:getenv(), {ok, Conf2} = file:script("$(DEPS_DIR)/$(1)/rebar.config.script", Bindings), - Conf2 + {Conf2, lists:foldl(fun(E, Acc) -> lists:delete(E, Acc) end, os:getenv(), Before)} end, Write = fun (Text) -> file:write_file("$(DEPS_DIR)/$(1)/Makefile", Text, [append]) @@ -153,6 +154,8 @@ define dep_autopatch_rebar.erl end, Write("IGNORE_DEPS = edown eper eunit_formatters meck node_package " "rebar_lock_deps_plugin rebar_vsn_plugin reltool_util\n\n"), + Write("C_SRC_DIR = /path/do/not/exist\n\n"), + Write("DRV_CFLAGS = -fPIC\nexport DRV_CFLAGS\n\n"), fun() -> Write("ERLC_OPTS = +debug_info\n"), case lists:keyfind(erl_opts, 1, Conf) of @@ -237,87 +240,6 @@ define dep_autopatch_rebar.erl Write(["COMPILE_FIRST +=", [[" ", atom_to_list(M)] || M <- First, lists:member("$(DEPS_DIR)/$(1)/src/" ++ atom_to_list(M) ++ ".erl", ErlFiles)], "\n"]) end(), - PortSpecWrite = fun(Name, Output, Input, Env) -> - filelib:ensure_dir("$(DEPS_DIR)/$(1)/" ++ Output), - file:write_file("$(DEPS_DIR)/$(1)/c_src/Makefile." ++ Name, [ - [["override ", K, " = $$$$\(shell echo ", Escape(V), "\)\n"] - || {_, K, V} <- Env], - "\nall:\n\t$$$$\(CC\) $$$$\(CFLAGS\) $$$$\(LDLIBS\) $$$$\(LDFLAGS\) ", - "-o $(DEPS_DIR)/$(1)/", Output, - [[" ../", F] || F <- Input] - ]) - end, - PortSpecNoop = fun(Name) -> file:write_file("$(DEPS_DIR)/$(1)/c_src/Makefile." ++ Name, "noop:\n") end, - PortSpec = fun - (Name, {Output, Input}) -> - PortSpecWrite(Name, Output, Input, []); - (Name, {Regex, Output, Input}) -> - case rebar_utils:is_arch(Regex) of - true -> PortSpecWrite(Name, Output, Input, []); - false -> PortSpecNoop(Name) - end; - (Name, {Regex, Output, Input, [{env, Env}]}) -> - case rebar_utils:is_arch(Regex) of - true -> PortSpecWrite(Name, Output, Input, Env); - false -> PortSpecNoop(Name) - end - end, - fun() -> - case filelib:is_dir("$(DEPS_DIR)/$(1)/c_src") of - false -> ok; - true -> - Sources = filelib:fold_files("$(DEPS_DIR)/$(1)/c_src", ".*\\\\.(c|C|cc|cpp)$$$$", true, fun(F, Acc) -> [F|Acc] end, []), - Write(io_lib:format("SOURCES :=~s\n", [[[" ", S] || S <- Sources]])) - end - end(), - fun() -> - case lists:keyfind(port_specs, 1, Conf) of - {_, [{Output, Wildcards}]} -> - filelib:ensure_dir("$(DEPS_DIR)/$(1)/" ++ Output), - Write("C_SRC_OUTPUT = " ++ Escape(Output) ++ "\n"), - Sources = [[[" ", S] || S <- filelib:wildcard("$(DEPS_DIR)/$(1)/" ++ W)] || W <- Wildcards], - Write(io_lib:format("SOURCES :=~s\n", [Sources])); - {_, [First, Second]} -> - PortSpec("1", First), - PortSpec("2", Second), - file:write_file("$(DEPS_DIR)/$(1)/c_src/Makefile", - "all:\n\t$$$$\(MAKE\) -f Makefile.1\n\t$$$$\(MAKE\) -f Makefile.2\n"); - _ -> ok - end - end(), - EnvValue = fun(V) -> - Escape(re:replace(V, "\\\\$$$$\ERLANG_ARCH", rebar_utils:wordsize(), [{return, list}])) - end, - fun() -> - case lists:keyfind(port_env, 1, Conf) of - {_, Vars} -> - lists:foldl(fun - ({K, V}, Acc) -> - case lists:member(K, Acc) of - true -> Acc; - false -> - Write(K ++ " = $$$$\(shell echo " ++ EnvValue(V) ++ "\)\n"), - [K|Acc] - end; - ({Regex, K, V}, Acc) -> - case lists:member(K, Acc) of - true -> Acc; - false -> - case rebar_utils:is_arch(Regex) of - true -> - Write(K ++ " = $$$$\(shell echo " ++ EnvValue(V) ++ "\)\n"), - [K|Acc]; - false -> - Acc - end - end - end, [], Vars), - Write("CFLAGS += $$$$\(DRV_CFLAGS\)\n"), - Write("CXXFLAGS += $$$$\(DRV_CFLAGS\)\n"), - Write("LDFLAGS += $$$$\(DRV_LDFLAGS\)\n"); - _ -> ok - end - end(), Write("\n\nrebar_dep: pre-deps deps pre-app app\n"), Write("\npre-deps::\n"), Write("\npre-app::\n"), @@ -348,21 +270,93 @@ define dep_autopatch_rebar.erl end || H <- Hooks] end end(), - Write("\ninclude ../../erlang.mk"), - fun() -> - case filelib:is_dir("$(DEPS_DIR)/$(1)/c_src") of - false -> ok; - true -> - Write("\n\nCFLAGS := $$$$\(filter-out -std=c99 -Wmissing-prototypes,$$$$\(CFLAGS\)\)\n") + ShellToMk = fun(V) -> + re:replace(V, "(\\\\$$$$)(\\\\w*)", "\\\\1(\\\\2)", [{return, list}, global]) + end, + PortSpecs = fun() -> + case lists:keyfind(port_specs, 1, Conf) of + false -> + case filelib:wildcard("$(DEPS_DIR)/$(1)/c_src/*.c") of + [] -> []; + Src -> [{"priv/$(1)_drv.so", ["c_src/*.c"], []}] + end; + {_, Specs} -> + lists:flatten([case S of + {Output, Input} -> {ShellToMk(Output), Input, []}; + {Regex, Output, Input} -> + case rebar_utils:is_arch(Regex) of + true -> {ShellToMk(Output), Input, []}; + false -> [] + end; + {Regex, Output, Input, [{env, Env}]} -> + case rebar_utils:is_arch(Regex) of + true -> {ShellToMk(Output), Input, Env}; + false -> [] + end + end || S <- Specs]) end end(), + PortSpecWrite = fun (Text) -> + file:write_file("$(DEPS_DIR)/$(1)/c_src/Makefile.erlang.mk", Text, [append]) + end, + case PortSpecs of + [] -> ok; + _ -> + Write("\npre-app::\n\t$$$$\(MAKE) -f c_src/Makefile.erlang.mk\n"), + PortSpecWrite(io_lib:format("ERL_CFLAGS = -finline-functions -Wall -fPIC -I ~s/erts-~s/include -I ~s\n", + [code:root_dir(), erlang:system_info(version), code:lib_dir(erl_interface, include)])), + PortSpecWrite(io_lib:format("ERL_LDFLAGS = -L ~s -lerl_interface -lei\n", + [code:lib_dir(erl_interface, lib)])), + PortSpecWrite(["\nERLANG_ARCH = ", rebar_utils:wordsize(), "\n"]), + [PortSpecWrite(["\n", E, "\n"]) || E <- OsEnv], + FilterEnv = fun(Env) -> + lists:flatten([case E of + {_, _} -> E; + {Regex, K, V} -> + case rebar_utils:is_arch(Regex) of + true -> {K, V}; + false -> [] + end + end || E <- Env]) + end, + MergeEnv = fun(Env) -> + lists:foldl(fun ({K, V}, Acc) -> + case lists:keyfind(K, 1, Acc) of + false -> [{K, rebar_utils:expand_env_variable(V, K, "")}|Acc]; + {_, V0} -> [{K, rebar_utils:expand_env_variable(V, K, V0)}|Acc] + end + end, [], Env) + end, + PortEnv = case lists:keyfind(port_env, 1, Conf) of + false -> []; + {_, PortEnv0} -> FilterEnv(PortEnv0) + end, + PortSpec = fun ({Output, Input0, Env}) -> + filelib:ensure_dir("$(DEPS_DIR)/$(1)/" ++ Output), + Input = [[" ", I] || I <- Input0], + PortSpecWrite([ + [["\n", K, " = ", ShellToMk(V)] || {K, V} <- lists:reverse(MergeEnv(PortEnv ++ FilterEnv(Env)))], + "\n\nall:: ", Output, "\n\n", + "%.o: %.c\n\t$$$$\(CC) -c -o $$$$\@ $$$$\< $$$$\(CFLAGS) $$$$\(ERL_CFLAGS) $$$$\(DRV_CFLAGS) $$$$\(EXE_CFLAGS)\n\n", + "%.o: %.C\n\t$$$$\(CXX) -c -o $$$$\@ $$$$\< $$$$\(CXXFLAGS) $$$$\(ERL_CFLAGS) $$$$\(DRV_CFLAGS) $$$$\(EXE_CFLAGS)\n\n", + "%.o: %.cc\n\t$$$$\(CXX) -c -o $$$$\@ $$$$\< $$$$\(CXXFLAGS) $$$$\(ERL_CFLAGS) $$$$\(DRV_CFLAGS) $$$$\(EXE_CFLAGS)\n\n", + "%.o: %.cpp\n\t$$$$\(CXX) -c -o $$$$\@ $$$$\< $$$$\(CXXFLAGS) $$$$\(ERL_CFLAGS) $$$$\(DRV_CFLAGS) $$$$\(EXE_CFLAGS)\n\n", + Output, ": $$$$\(foreach ext,.c .C .cc .cpp,", + "$$$$\(patsubst %$$$$\(ext),%.o,$$$$\(filter %$$$$\(ext),$$$$\(wildcard", Input, "))))\n", + "\t$$$$\(CC) -o $$$$\@ $$$$\? $$$$\(LDFLAGS) $$$$\(ERL_LDFLAGS) $$$$\(DRV_LDFLAGS) $$$$\(EXE_LDFLAGS)", + case filename:extension(Output) of + [] -> "\n"; + _ -> " -shared\n" + end]) + end, + [PortSpec(S) || S <- PortSpecs] + end, + Write("\ninclude ../../erlang.mk"), fun() -> case lists:keyfind(plugins, 1, Conf) of {_, [Plugin]} when is_atom(Plugin) -> ErlFile = "$(DEPS_DIR)/$(1)/plugins/" ++ atom_to_list(Plugin) ++ ".erl", try - {ok, PF} = file:read_file(ErlFile), - ok = file:write_file(ErlFile, PF), {ok, Mod, Bin} = compile:file(ErlFile, [binary]), {module, Mod} = code:load_binary(Mod, ErlFile, Bin), c:cd("$(DEPS_DIR)/$(1)/"), -- cgit v1.2.3