aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLoïc Hoguin <[email protected]>2015-10-26 22:40:04 +0100
committerLoïc Hoguin <[email protected]>2015-10-26 22:40:04 +0100
commit9bd5ec4f4797f0c11df4e75f78b10208e1287c03 (patch)
tree21633adfaf469be73c01595a0c4f6787f3ac2873
parentd7b4e589f1716e2de5087a491ea1701d294dccbc (diff)
downloaderlang.mk-9bd5ec4f4797f0c11df4e75f78b10208e1287c03.tar.gz
erlang.mk-9bd5ec4f4797f0c11df4e75f78b10208e1287c03.tar.bz2
erlang.mk-9bd5ec4f4797f0c11df4e75f78b10208e1287c03.zip
Add new-nif target and related tests
Pushing this now so I can figure out Windows.
-rw-r--r--plugins/c_src.mk95
-rw-r--r--test/plugin_c_src.mk82
2 files changed, 177 insertions, 0 deletions
diff --git a/plugins/c_src.mk b/plugins/c_src.mk
index a74d945..5cfdeef 100644
--- a/plugins/c_src.mk
+++ b/plugins/c_src.mk
@@ -115,3 +115,98 @@ distclean-c_src-env:
-include $(C_SRC_ENV)
endif
+
+# Templates.
+
+define bs_c_nif
+#include "erl_nif.h"
+
+static int loads = 0;
+
+static int load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info)
+{
+ /* Initialize private data. */
+ *priv_data = NULL;
+
+ loads++;
+
+ return 0;
+}
+
+static int upgrade(ErlNifEnv* env, void** priv_data, void** old_priv_data, ERL_NIF_TERM load_info)
+{
+ /* Convert the private data to the new version. */
+ *priv_data = *old_priv_data;
+
+ loads++;
+
+ return 0;
+}
+
+static void unload(ErlNifEnv* env, void* priv_data)
+{
+ if (loads == 1) {
+ /* Destroy the private data. */
+ }
+
+ loads--;
+}
+
+static ERL_NIF_TERM hello(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{
+ if (enif_is_atom(env, argv[0])) {
+ return enif_make_tuple2(env,
+ enif_make_atom(env, "hello"),
+ argv[0]);
+ }
+
+ return enif_make_tuple2(env,
+ enif_make_atom(env, "error"),
+ enif_make_atom(env, "badarg"));
+}
+
+static ErlNifFunc nif_funcs[] = {
+ {"hello", 1, hello}
+};
+
+ERL_NIF_INIT($n, nif_funcs, load, NULL, upgrade, unload)
+endef
+
+define bs_erl_nif
+-module($n).
+
+-export([hello/1]).
+
+-on_load(on_load/0).
+on_load() ->
+ PrivDir = case code:priv_dir(?MODULE) of
+ {error, _} ->
+ AppPath = filename:dirname(filename:dirname(code:which(?MODULE))),
+ filename:join(AppPath, "priv");
+ Path ->
+ Path
+ end,
+ erlang:load_nif(filename:join(PrivDir, atom_to_list(?MODULE)), 0).
+
+hello(_) ->
+ erlang:nif_error({not_loaded, ?MODULE}).
+endef
+
+$(foreach template,bs_c_nif bs_erl_nif, \
+ $(eval _$(template) = $$(subst $$(tab),$$(WS),$$($(template)))) \
+ $(eval export _$(template)))
+
+new-nif:
+ifneq ($(wildcard $(C_SRC_DIR)/$n.c),)
+ $(error Error: $(C_SRC_DIR)/$n.c already exists)
+endif
+ifneq ($(wildcard src/$n.erl),)
+ $(error Error: src/$n.erl already exists)
+endif
+ifdef in
+ $(verbose) $(MAKE) -C $(APPS_DIR)/$(in)/ new-nif n=$n in=
+else
+ $(verbose) mkdir -p $(C_SRC_DIR) src/
+ $(call render_template,bs_c_nif,$(C_SRC_DIR)/$n.c)
+ $(call render_template,bs_erl_nif,src/$n.erl)
+endif
diff --git a/test/plugin_c_src.mk b/test/plugin_c_src.mk
new file mode 100644
index 0000000..bedbc3f
--- /dev/null
+++ b/test/plugin_c_src.mk
@@ -0,0 +1,82 @@
+# C source plugin.
+
+C_SRC_CASES = cpp custom dir env nif port
+C_SRC_TARGETS = $(addprefix c-src-,$(C_SRC_CASES))
+C_SRC_CLEAN_TARGETS = $(addprefix clean-,$(C_SRC_TARGETS))
+
+.PHONY: c-src $(C_SRC_TARGETS) clean-c-src $(C_SRC_CLEAN_TARGETS)
+
+clean-c-src: $(C_SRC_CLEAN_TARGETS)
+
+$(C_SRC_CLEAN_TARGETS):
+ $t rm -rf $(APP_TO_CLEAN)/
+
+c-src: $(C_SRC_TARGETS)
+
+c-src-nif: build clean-c-src-nif
+
+ $i "Bootstrap a new OTP library named $(APP)"
+ $t mkdir $(APP)/
+ $t cp ../erlang.mk $(APP)/
+ $t $(MAKE) -C $(APP) -f erlang.mk bootstrap-lib $v
+
+ $i "Generate a NIF from templates"
+ $t $(MAKE) -C $(APP) new-nif n=$(APP) $v
+
+ $i "Build the application"
+ $t $(MAKE) -C $(APP) $v
+
+ $i "Check that all compiled files exist"
+ $t test -f $(APP)/$(APP).d
+ $t test -f $(APP)/c_src/$(APP).o
+ $t test -f $(APP)/c_src/env.mk
+ $t test -f $(APP)/ebin/$(APP).app
+ $t test -f $(APP)/ebin/$(APP).beam
+ $t test -f $(APP)/priv/$(APP).so
+
+ $i "Check that the application was compiled correctly"
+ $t $(ERL) -pa $(APP)/ebin/ -eval " \
+ ok = application:start($(APP)), \
+ {ok, [$(APP)]} = application:get_key($(APP), modules), \
+ {module, $(APP)} = code:load_file($(APP)), \
+ {hello, joe} = $(APP):hello(joe), \
+ {hello, mike} = $(APP):hello(mike), \
+ {hello, robert} = $(APP):hello(robert), \
+ halt()"
+
+ $i "Re-build the application"
+ $t $(MAKE) -C $(APP) $v
+
+ $i "Check that all compiled files exist"
+ $t test -f $(APP)/$(APP).d
+ $t test -f $(APP)/c_src/$(APP).o
+ $t test -f $(APP)/c_src/env.mk
+ $t test -f $(APP)/ebin/$(APP).app
+ $t test -f $(APP)/ebin/$(APP).beam
+ $t test -f $(APP)/priv/$(APP).so
+
+ $i "Check that the application was compiled correctly"
+ $t $(ERL) -pa $(APP)/ebin/ -eval " \
+ ok = application:start($(APP)), \
+ {ok, [$(APP)]} = application:get_key($(APP), modules), \
+ {module, $(APP)} = code:load_file($(APP)), \
+ {hello, joe} = $(APP):hello(joe), \
+ {hello, mike} = $(APP):hello(mike), \
+ {hello, robert} = $(APP):hello(robert), \
+ halt()"
+
+ $i "Clean the application"
+ $t $(MAKE) -C $(APP) clean $v
+
+ $i "Check that all intermediate files were removed"
+ $t test ! -e $(APP)/$(APP).d
+ $t test ! -e $(APP)/c_src/$(APP).o
+ $t test ! -e $(APP)/ebin/$(APP).app
+ $t test ! -e $(APP)/ebin/$(APP).beam
+ $t test ! -e $(APP)/priv/$(APP).so
+
+ $i "Distclean the application"
+ $t $(MAKE) -C $(APP) distclean $v
+
+ $i "Check that all files were removed"
+ $t test ! -e $(APP)/c_src/env.mk