Browse Source

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.
Loïc Hoguin 10 years ago
parent
commit
004ae229a1
2 changed files with 92 additions and 98 deletions
  1. 86 92
      core/deps.mk
  2. 6 6
      plugins/c_src.mk

+ 86 - 92
core/deps.mk

@@ -136,14 +136,15 @@ define dep_autopatch_rebar.erl
 		{ok, Conf0} -> Conf0;
 		{ok, Conf0} -> Conf0;
 		_ -> []
 		_ -> []
 	end,
 	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 ->
 		true ->
 			Bindings0 = erl_eval:new_bindings(),
 			Bindings0 = erl_eval:new_bindings(),
 			Bindings1 = erl_eval:add_binding('CONFIG', Conf1, Bindings0),
 			Bindings1 = erl_eval:add_binding('CONFIG', Conf1, Bindings0),
 			Bindings = erl_eval:add_binding('SCRIPT', "$(DEPS_DIR)/$(1)/rebar.config.script", Bindings1),
 			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),
 			{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,
 	end,
 	Write = fun (Text) ->
 	Write = fun (Text) ->
 		file:write_file("$(DEPS_DIR)/$(1)/Makefile", Text, [append])
 		file:write_file("$(DEPS_DIR)/$(1)/Makefile", Text, [append])
@@ -153,6 +154,8 @@ define dep_autopatch_rebar.erl
 	end,
 	end,
 	Write("IGNORE_DEPS = edown eper eunit_formatters meck node_package "
 	Write("IGNORE_DEPS = edown eper eunit_formatters meck node_package "
 		"rebar_lock_deps_plugin rebar_vsn_plugin reltool_util\n\n"),
 		"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() ->
 	fun() ->
 		Write("ERLC_OPTS = +debug_info\n"),
 		Write("ERLC_OPTS = +debug_info\n"),
 		case lists:keyfind(erl_opts, 1, Conf) of
 		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,
 		Write(["COMPILE_FIRST +=", [[" ", atom_to_list(M)] || M <- First,
 			lists:member("$(DEPS_DIR)/$(1)/src/" ++ atom_to_list(M) ++ ".erl", ErlFiles)], "\n"])
 			lists:member("$(DEPS_DIR)/$(1)/src/" ++ atom_to_list(M) ++ ".erl", ErlFiles)], "\n"])
 	end(),
 	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("\n\nrebar_dep: pre-deps deps pre-app app\n"),
 	Write("\npre-deps::\n"),
 	Write("\npre-deps::\n"),
 	Write("\npre-app::\n"),
 	Write("\npre-app::\n"),
@@ -348,21 +270,93 @@ define dep_autopatch_rebar.erl
 				end || H <- Hooks]
 				end || H <- Hooks]
 		end
 		end
 	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
 	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() ->
 	fun() ->
 		case lists:keyfind(plugins, 1, Conf) of
 		case lists:keyfind(plugins, 1, Conf) of
 			{_, [Plugin]} when is_atom(Plugin) ->
 			{_, [Plugin]} when is_atom(Plugin) ->
 				ErlFile = "$(DEPS_DIR)/$(1)/plugins/" ++ atom_to_list(Plugin) ++ ".erl",
 				ErlFile = "$(DEPS_DIR)/$(1)/plugins/" ++ atom_to_list(Plugin) ++ ".erl",
 				try
 				try
-					{ok, PF} = file:read_file(ErlFile),
-					ok = file:write_file(ErlFile, PF),
 					{ok, Mod, Bin} = compile:file(ErlFile, [binary]),
 					{ok, Mod, Bin} = compile:file(ErlFile, [binary]),
 					{module, Mod} = code:load_binary(Mod, ErlFile, Bin),
 					{module, Mod} = code:load_binary(Mod, ErlFile, Bin),
 					c:cd("$(DEPS_DIR)/$(1)/"),
 					c:cd("$(DEPS_DIR)/$(1)/"),

+ 6 - 6
plugins/c_src.mk

@@ -5,9 +5,10 @@
 
 
 # Configuration.
 # Configuration.
 
 
-C_SRC_DIR = $(CURDIR)/c_src
+C_SRC_DIR ?= $(CURDIR)/c_src
 C_SRC_ENV ?= $(C_SRC_DIR)/env.mk
 C_SRC_ENV ?= $(C_SRC_DIR)/env.mk
 C_SRC_OUTPUT ?= $(CURDIR)/priv/$(PROJECT).so
 C_SRC_OUTPUT ?= $(CURDIR)/priv/$(PROJECT).so
+C_SRC_TYPE ?= shared
 
 
 # System type and C compiler/flags.
 # System type and C compiler/flags.
 
 
@@ -30,7 +31,10 @@ CFLAGS += -fPIC -I $(ERTS_INCLUDE_DIR) -I $(ERL_INTERFACE_INCLUDE_DIR)
 CXXFLAGS += -fPIC -I $(ERTS_INCLUDE_DIR) -I $(ERL_INTERFACE_INCLUDE_DIR)
 CXXFLAGS += -fPIC -I $(ERTS_INCLUDE_DIR) -I $(ERL_INTERFACE_INCLUDE_DIR)
 
 
 LDLIBS += -L $(ERL_INTERFACE_LIB_DIR) -lerl_interface -lei
 LDLIBS += -L $(ERL_INTERFACE_LIB_DIR) -lerl_interface -lei
+
+ifeq ($(C_SRC_TYPE),shared)
 LDFLAGS += -shared
 LDFLAGS += -shared
+endif
 
 
 # Verbosity.
 # Verbosity.
 
 
@@ -52,11 +56,7 @@ app:: app-c_src
 test-build:: app-c_src
 test-build:: app-c_src
 
 
 app-c_src:
 app-c_src:
-	$(MAKE) -C $(C_SRC_DIR) \
-		CFLAGS="$(CFLAGS)" \
-		CXXFLAGS="$(CXXFLAGS)" \
-		LDLIBS="$(LDLIBS)" \
-		LDFLAGS="$(LDFLAGS)"
+	$(MAKE) -C $(C_SRC_DIR)
 
 
 clean::
 clean::
 	$(MAKE) -C $(C_SRC_DIR) clean
 	$(MAKE) -C $(C_SRC_DIR) clean