diff options
author | Loïc Hoguin <[email protected]> | 2015-10-26 22:40:04 +0100 |
---|---|---|
committer | Loïc Hoguin <[email protected]> | 2015-10-26 22:40:04 +0100 |
commit | 9bd5ec4f4797f0c11df4e75f78b10208e1287c03 (patch) | |
tree | 21633adfaf469be73c01595a0c4f6787f3ac2873 | |
parent | d7b4e589f1716e2de5087a491ea1701d294dccbc (diff) | |
download | erlang.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.mk | 95 | ||||
-rw-r--r-- | test/plugin_c_src.mk | 82 |
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 |