c_src.mk 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  1. # Copyright (c) 2014-2016, Loïc Hoguin <essen@ninenines.eu>
  2. # This file is part of erlang.mk and subject to the terms of the ISC License.
  3. .PHONY: clean-c_src distclean-c_src-env
  4. # Configuration.
  5. C_SRC_DIR ?= $(CURDIR)/c_src
  6. C_SRC_ENV ?= $(C_SRC_DIR)/env.mk
  7. C_SRC_OUTPUT ?= $(CURDIR)/priv/$(PROJECT)
  8. C_SRC_TYPE ?= shared
  9. # System type and C compiler/flags.
  10. ifeq ($(PLATFORM),msys2)
  11. C_SRC_OUTPUT_EXECUTABLE_EXTENSION ?= .exe
  12. C_SRC_OUTPUT_SHARED_EXTENSION ?= .dll
  13. else
  14. C_SRC_OUTPUT_EXECUTABLE_EXTENSION ?=
  15. C_SRC_OUTPUT_SHARED_EXTENSION ?= .so
  16. endif
  17. ifeq ($(C_SRC_TYPE),shared)
  18. C_SRC_OUTPUT_FILE = $(C_SRC_OUTPUT)$(C_SRC_OUTPUT_SHARED_EXTENSION)
  19. else
  20. C_SRC_OUTPUT_FILE = $(C_SRC_OUTPUT)$(C_SRC_OUTPUT_EXECUTABLE_EXTENSION)
  21. endif
  22. ifeq ($(PLATFORM),msys2)
  23. # We hardcode the compiler used on MSYS2. The default CC=cc does
  24. # not produce working code. The "gcc" MSYS2 package also doesn't.
  25. CC = /mingw64/bin/gcc
  26. export CC
  27. CFLAGS ?= -O3 -std=c99 -finline-functions -Wall -Wmissing-prototypes
  28. CXXFLAGS ?= -O3 -finline-functions -Wall
  29. else ifeq ($(PLATFORM),darwin)
  30. CC ?= cc
  31. CFLAGS ?= -O3 -std=c99 -arch x86_64 -finline-functions -Wall -Wmissing-prototypes
  32. CXXFLAGS ?= -O3 -arch x86_64 -finline-functions -Wall
  33. LDFLAGS ?= -arch x86_64 -flat_namespace -undefined suppress
  34. else ifeq ($(PLATFORM),freebsd)
  35. CC ?= cc
  36. CFLAGS ?= -O3 -std=c99 -finline-functions -Wall -Wmissing-prototypes
  37. CXXFLAGS ?= -O3 -finline-functions -Wall
  38. else ifeq ($(PLATFORM),linux)
  39. CC ?= gcc
  40. CFLAGS ?= -O3 -std=c99 -finline-functions -Wall -Wmissing-prototypes
  41. CXXFLAGS ?= -O3 -finline-functions -Wall
  42. endif
  43. ifneq ($(PLATFORM),msys2)
  44. CFLAGS += -fPIC
  45. CXXFLAGS += -fPIC
  46. endif
  47. CFLAGS += -I"$(ERTS_INCLUDE_DIR)" -I"$(ERL_INTERFACE_INCLUDE_DIR)"
  48. CXXFLAGS += -I"$(ERTS_INCLUDE_DIR)" -I"$(ERL_INTERFACE_INCLUDE_DIR)"
  49. LDLIBS += -L"$(ERL_INTERFACE_LIB_DIR)" -lerl_interface -lei
  50. # Verbosity.
  51. c_verbose_0 = @echo " C " $(?F);
  52. c_verbose = $(c_verbose_$(V))
  53. cpp_verbose_0 = @echo " CPP " $(?F);
  54. cpp_verbose = $(cpp_verbose_$(V))
  55. link_verbose_0 = @echo " LD " $(@F);
  56. link_verbose = $(link_verbose_$(V))
  57. # Targets.
  58. ifeq ($(wildcard $(C_SRC_DIR)),)
  59. else ifneq ($(wildcard $(C_SRC_DIR)/Makefile),)
  60. app:: app-c_src
  61. test-build:: app-c_src
  62. app-c_src:
  63. $(MAKE) -C $(C_SRC_DIR)
  64. clean::
  65. $(MAKE) -C $(C_SRC_DIR) clean
  66. else
  67. ifeq ($(SOURCES),)
  68. SOURCES := $(sort $(foreach pat,*.c *.C *.cc *.cpp,$(call core_find,$(C_SRC_DIR)/,$(pat))))
  69. endif
  70. OBJECTS = $(addsuffix .o, $(basename $(SOURCES)))
  71. COMPILE_C = $(c_verbose) $(CC) $(CFLAGS) $(CPPFLAGS) -c
  72. COMPILE_CPP = $(cpp_verbose) $(CXX) $(CXXFLAGS) $(CPPFLAGS) -c
  73. app:: $(C_SRC_ENV) $(C_SRC_OUTPUT_FILE)
  74. test-build:: $(C_SRC_ENV) $(C_SRC_OUTPUT_FILE)
  75. $(C_SRC_OUTPUT_FILE): $(OBJECTS)
  76. $(verbose) mkdir -p priv/
  77. $(link_verbose) $(CC) $(OBJECTS) \
  78. $(LDFLAGS) $(if $(filter $(C_SRC_TYPE),shared),-shared) $(LDLIBS) \
  79. -o $(C_SRC_OUTPUT_FILE)
  80. %.o: %.c
  81. $(COMPILE_C) $(OUTPUT_OPTION) $<
  82. %.o: %.cc
  83. $(COMPILE_CPP) $(OUTPUT_OPTION) $<
  84. %.o: %.C
  85. $(COMPILE_CPP) $(OUTPUT_OPTION) $<
  86. %.o: %.cpp
  87. $(COMPILE_CPP) $(OUTPUT_OPTION) $<
  88. clean:: clean-c_src
  89. clean-c_src:
  90. $(gen_verbose) rm -f $(C_SRC_OUTPUT_FILE) $(OBJECTS)
  91. endif
  92. ifneq ($(wildcard $(C_SRC_DIR)),)
  93. $(C_SRC_ENV):
  94. $(verbose) $(ERL) -eval "file:write_file(\"$(call core_native_path,$(C_SRC_ENV))\", \
  95. io_lib:format( \
  96. \"# Generated by Erlang.mk. Edit at your own risk!~n~n\" \
  97. \"ERTS_INCLUDE_DIR ?= ~s/erts-~s/include/~n\" \
  98. \"ERL_INTERFACE_INCLUDE_DIR ?= ~s~n\" \
  99. \"ERL_INTERFACE_LIB_DIR ?= ~s~n\", \
  100. [code:root_dir(), erlang:system_info(version), \
  101. code:lib_dir(erl_interface, include), \
  102. code:lib_dir(erl_interface, lib)])), \
  103. halt()."
  104. distclean:: distclean-c_src-env
  105. distclean-c_src-env:
  106. $(gen_verbose) rm -f $(C_SRC_ENV)
  107. -include $(C_SRC_ENV)
  108. endif
  109. # Templates.
  110. define bs_c_nif
  111. #include "erl_nif.h"
  112. static int loads = 0;
  113. static int load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info)
  114. {
  115. /* Initialize private data. */
  116. *priv_data = NULL;
  117. loads++;
  118. return 0;
  119. }
  120. static int upgrade(ErlNifEnv* env, void** priv_data, void** old_priv_data, ERL_NIF_TERM load_info)
  121. {
  122. /* Convert the private data to the new version. */
  123. *priv_data = *old_priv_data;
  124. loads++;
  125. return 0;
  126. }
  127. static void unload(ErlNifEnv* env, void* priv_data)
  128. {
  129. if (loads == 1) {
  130. /* Destroy the private data. */
  131. }
  132. loads--;
  133. }
  134. static ERL_NIF_TERM hello(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
  135. {
  136. if (enif_is_atom(env, argv[0])) {
  137. return enif_make_tuple2(env,
  138. enif_make_atom(env, "hello"),
  139. argv[0]);
  140. }
  141. return enif_make_tuple2(env,
  142. enif_make_atom(env, "error"),
  143. enif_make_atom(env, "badarg"));
  144. }
  145. static ErlNifFunc nif_funcs[] = {
  146. {"hello", 1, hello}
  147. };
  148. ERL_NIF_INIT($n, nif_funcs, load, NULL, upgrade, unload)
  149. endef
  150. define bs_erl_nif
  151. -module($n).
  152. -export([hello/1]).
  153. -on_load(on_load/0).
  154. on_load() ->
  155. PrivDir = case code:priv_dir(?MODULE) of
  156. {error, _} ->
  157. AppPath = filename:dirname(filename:dirname(code:which(?MODULE))),
  158. filename:join(AppPath, "priv");
  159. Path ->
  160. Path
  161. end,
  162. erlang:load_nif(filename:join(PrivDir, atom_to_list(?MODULE)), 0).
  163. hello(_) ->
  164. erlang:nif_error({not_loaded, ?MODULE}).
  165. endef
  166. new-nif:
  167. ifneq ($(wildcard $(C_SRC_DIR)/$n.c),)
  168. $(error Error: $(C_SRC_DIR)/$n.c already exists)
  169. endif
  170. ifneq ($(wildcard src/$n.erl),)
  171. $(error Error: src/$n.erl already exists)
  172. endif
  173. ifndef n
  174. $(error Usage: $(MAKE) new-nif n=NAME [in=APP])
  175. endif
  176. ifdef in
  177. $(verbose) $(MAKE) -C $(APPS_DIR)/$(in)/ new-nif n=$n in=
  178. else
  179. $(verbose) mkdir -p $(C_SRC_DIR) src/
  180. $(call render_template,bs_c_nif,$(C_SRC_DIR)/$n.c)
  181. $(call render_template,bs_erl_nif,src/$n.erl)
  182. endif