c_src.mk 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234
  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. \"ERTS_INCLUDE_DIR ?= ~s/erts-~s/include/~n\" \
  97. \"ERL_INTERFACE_INCLUDE_DIR ?= ~s~n\" \
  98. \"ERL_INTERFACE_LIB_DIR ?= ~s~n\", \
  99. [code:root_dir(), erlang:system_info(version), \
  100. code:lib_dir(erl_interface, include), \
  101. code:lib_dir(erl_interface, lib)])), \
  102. halt()."
  103. distclean:: distclean-c_src-env
  104. distclean-c_src-env:
  105. $(gen_verbose) rm -f $(C_SRC_ENV)
  106. -include $(C_SRC_ENV)
  107. endif
  108. # Templates.
  109. define bs_c_nif
  110. #include "erl_nif.h"
  111. static int loads = 0;
  112. static int load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info)
  113. {
  114. /* Initialize private data. */
  115. *priv_data = NULL;
  116. loads++;
  117. return 0;
  118. }
  119. static int upgrade(ErlNifEnv* env, void** priv_data, void** old_priv_data, ERL_NIF_TERM load_info)
  120. {
  121. /* Convert the private data to the new version. */
  122. *priv_data = *old_priv_data;
  123. loads++;
  124. return 0;
  125. }
  126. static void unload(ErlNifEnv* env, void* priv_data)
  127. {
  128. if (loads == 1) {
  129. /* Destroy the private data. */
  130. }
  131. loads--;
  132. }
  133. static ERL_NIF_TERM hello(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
  134. {
  135. if (enif_is_atom(env, argv[0])) {
  136. return enif_make_tuple2(env,
  137. enif_make_atom(env, "hello"),
  138. argv[0]);
  139. }
  140. return enif_make_tuple2(env,
  141. enif_make_atom(env, "error"),
  142. enif_make_atom(env, "badarg"));
  143. }
  144. static ErlNifFunc nif_funcs[] = {
  145. {"hello", 1, hello}
  146. };
  147. ERL_NIF_INIT($n, nif_funcs, load, NULL, upgrade, unload)
  148. endef
  149. define bs_erl_nif
  150. -module($n).
  151. -export([hello/1]).
  152. -on_load(on_load/0).
  153. on_load() ->
  154. PrivDir = case code:priv_dir(?MODULE) of
  155. {error, _} ->
  156. AppPath = filename:dirname(filename:dirname(code:which(?MODULE))),
  157. filename:join(AppPath, "priv");
  158. Path ->
  159. Path
  160. end,
  161. erlang:load_nif(filename:join(PrivDir, atom_to_list(?MODULE)), 0).
  162. hello(_) ->
  163. erlang:nif_error({not_loaded, ?MODULE}).
  164. endef
  165. new-nif:
  166. ifneq ($(wildcard $(C_SRC_DIR)/$n.c),)
  167. $(error Error: $(C_SRC_DIR)/$n.c already exists)
  168. endif
  169. ifneq ($(wildcard src/$n.erl),)
  170. $(error Error: src/$n.erl already exists)
  171. endif
  172. ifdef in
  173. $(verbose) $(MAKE) -C $(APPS_DIR)/$(in)/ new-nif n=$n in=
  174. else
  175. $(verbose) mkdir -p $(C_SRC_DIR) src/
  176. $(call render_template,bs_c_nif,$(C_SRC_DIR)/$n.c)
  177. $(call render_template,bs_erl_nif,src/$n.erl)
  178. endif