c_src.mk 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247
  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 -Wall -Wmissing-prototypes
  32. CXXFLAGS ?= -O3 -Wall
  33. LDFLAGS ?= -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)" -lei
  50. # Verbosity.
  51. c_verbose_0 = @echo " C " $(filter-out $(notdir $(MAKEFILE_LIST) $(C_SRC_ENV)),$(^F));
  52. c_verbose = $(c_verbose_$(V))
  53. cpp_verbose_0 = @echo " CPP " $(filter-out $(notdir $(MAKEFILE_LIST) $(C_SRC_ENV)),$(^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 $(dir $@)
  77. $(link_verbose) $(CC) $(OBJECTS) \
  78. $(LDFLAGS) $(if $(filter $(C_SRC_TYPE),shared),-shared) $(LDLIBS) \
  79. -o $(C_SRC_OUTPUT_FILE)
  80. $(OBJECTS): $(MAKEFILE_LIST) $(C_SRC_ENV)
  81. %.o: %.c
  82. $(COMPILE_C) $(OUTPUT_OPTION) $<
  83. %.o: %.cc
  84. $(COMPILE_CPP) $(OUTPUT_OPTION) $<
  85. %.o: %.C
  86. $(COMPILE_CPP) $(OUTPUT_OPTION) $<
  87. %.o: %.cpp
  88. $(COMPILE_CPP) $(OUTPUT_OPTION) $<
  89. clean:: clean-c_src
  90. clean-c_src:
  91. $(gen_verbose) rm -f $(C_SRC_OUTPUT_FILE) $(OBJECTS)
  92. endif
  93. ifneq ($(wildcard $(C_SRC_DIR)),)
  94. ERL_ERTS_DIR = $(shell $(ERL) -eval 'io:format("~s~n", [code:lib_dir(erts)]), halt().')
  95. $(C_SRC_ENV):
  96. $(verbose) $(ERL) -eval "file:write_file(\"$(call core_native_path,$(C_SRC_ENV))\", \
  97. io_lib:format( \
  98. \"# Generated by Erlang.mk. Edit at your own risk!~n~n\" \
  99. \"ERTS_INCLUDE_DIR ?= ~s/erts-~s/include/~n\" \
  100. \"ERL_INTERFACE_INCLUDE_DIR ?= ~s~n\" \
  101. \"ERL_INTERFACE_LIB_DIR ?= ~s~n\" \
  102. \"ERTS_DIR ?= $(ERL_ERTS_DIR)~n\", \
  103. [code:root_dir(), erlang:system_info(version), \
  104. code:lib_dir(erl_interface, include), \
  105. code:lib_dir(erl_interface, lib)])), \
  106. halt()."
  107. distclean:: distclean-c_src-env
  108. distclean-c_src-env:
  109. $(gen_verbose) rm -f $(C_SRC_ENV)
  110. -include $(C_SRC_ENV)
  111. ifneq ($(ERL_ERTS_DIR),$(ERTS_DIR))
  112. $(shell rm -f $(C_SRC_ENV))
  113. endif
  114. endif
  115. # Templates.
  116. define bs_c_nif
  117. #include "erl_nif.h"
  118. static int loads = 0;
  119. static int load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info)
  120. {
  121. /* Initialize private data. */
  122. *priv_data = NULL;
  123. loads++;
  124. return 0;
  125. }
  126. static int upgrade(ErlNifEnv* env, void** priv_data, void** old_priv_data, ERL_NIF_TERM load_info)
  127. {
  128. /* Convert the private data to the new version. */
  129. *priv_data = *old_priv_data;
  130. loads++;
  131. return 0;
  132. }
  133. static void unload(ErlNifEnv* env, void* priv_data)
  134. {
  135. if (loads == 1) {
  136. /* Destroy the private data. */
  137. }
  138. loads--;
  139. }
  140. static ERL_NIF_TERM hello(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
  141. {
  142. if (enif_is_atom(env, argv[0])) {
  143. return enif_make_tuple2(env,
  144. enif_make_atom(env, "hello"),
  145. argv[0]);
  146. }
  147. return enif_make_tuple2(env,
  148. enif_make_atom(env, "error"),
  149. enif_make_atom(env, "badarg"));
  150. }
  151. static ErlNifFunc nif_funcs[] = {
  152. {"hello", 1, hello}
  153. };
  154. ERL_NIF_INIT($n, nif_funcs, load, NULL, upgrade, unload)
  155. endef
  156. define bs_erl_nif
  157. -module($n).
  158. -export([hello/1]).
  159. -on_load(on_load/0).
  160. on_load() ->
  161. PrivDir = case code:priv_dir(?MODULE) of
  162. {error, _} ->
  163. AppPath = filename:dirname(filename:dirname(code:which(?MODULE))),
  164. filename:join(AppPath, "priv");
  165. Path ->
  166. Path
  167. end,
  168. erlang:load_nif(filename:join(PrivDir, atom_to_list(?MODULE)), 0).
  169. hello(_) ->
  170. erlang:nif_error({not_loaded, ?MODULE}).
  171. endef
  172. new-nif:
  173. ifneq ($(wildcard $(C_SRC_DIR)/$n.c),)
  174. $(error Error: $(C_SRC_DIR)/$n.c already exists)
  175. endif
  176. ifneq ($(wildcard src/$n.erl),)
  177. $(error Error: src/$n.erl already exists)
  178. endif
  179. ifndef n
  180. $(error Usage: $(MAKE) new-nif n=NAME [in=APP])
  181. endif
  182. ifdef in
  183. $(verbose) $(MAKE) -C $(APPS_DIR)/$(in)/ new-nif n=$n in=
  184. else
  185. $(verbose) mkdir -p $(C_SRC_DIR) src/
  186. $(verbose) $(call core_render,bs_c_nif,$(C_SRC_DIR)/$n.c)
  187. $(verbose) $(call core_render,bs_erl_nif,src/$n.erl)
  188. endif