c_src.mk 6.4 KB

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