c_src.mk 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233
  1. # Copyright (c) 2014-2015, 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. CFLAGS ?= -O3 -std=c99 -finline-functions -Wall -Wmissing-prototypes
  27. CXXFLAGS ?= -O3 -finline-functions -Wall
  28. else ifeq ($(PLATFORM),darwin)
  29. CC ?= cc
  30. CFLAGS ?= -O3 -std=c99 -arch x86_64 -finline-functions -Wall -Wmissing-prototypes
  31. CXXFLAGS ?= -O3 -arch x86_64 -finline-functions -Wall
  32. LDFLAGS ?= -arch x86_64 -flat_namespace -undefined suppress
  33. else ifeq ($(PLATFORM),freebsd)
  34. CC ?= cc
  35. CFLAGS ?= -O3 -std=c99 -finline-functions -Wall -Wmissing-prototypes
  36. CXXFLAGS ?= -O3 -finline-functions -Wall
  37. else ifeq ($(PLATFORM),linux)
  38. CC ?= gcc
  39. CFLAGS ?= -O3 -std=c99 -finline-functions -Wall -Wmissing-prototypes
  40. CXXFLAGS ?= -O3 -finline-functions -Wall
  41. endif
  42. ifneq ($(PLATFORM),msys2)
  43. CFLAGS += -fPIC
  44. CXXFLAGS += -fPIC
  45. endif
  46. CFLAGS += -I"$(ERTS_INCLUDE_DIR)" -I"$(ERL_INTERFACE_INCLUDE_DIR)"
  47. CXXFLAGS += -I"$(ERTS_INCLUDE_DIR)" -I"$(ERL_INTERFACE_INCLUDE_DIR)"
  48. LDLIBS += -L"$(ERL_INTERFACE_LIB_DIR)" -lerl_interface -lei
  49. # Verbosity.
  50. c_verbose_0 = @echo " C " $(?F);
  51. c_verbose = $(c_verbose_$(V))
  52. cpp_verbose_0 = @echo " CPP " $(?F);
  53. cpp_verbose = $(cpp_verbose_$(V))
  54. link_verbose_0 = @echo " LD " $(@F);
  55. link_verbose = $(link_verbose_$(V))
  56. # Targets.
  57. ifeq ($(wildcard $(C_SRC_DIR)),)
  58. else ifneq ($(wildcard $(C_SRC_DIR)/Makefile),)
  59. app:: app-c_src
  60. test-build:: app-c_src
  61. app-c_src:
  62. $(MAKE) -C $(C_SRC_DIR)
  63. clean::
  64. $(MAKE) -C $(C_SRC_DIR) clean
  65. else
  66. ifeq ($(SOURCES),)
  67. SOURCES := $(sort $(foreach pat,*.c *.C *.cc *.cpp,$(call core_find,$(C_SRC_DIR)/,$(pat))))
  68. endif
  69. OBJECTS = $(addsuffix .o, $(basename $(SOURCES)))
  70. COMPILE_C = $(c_verbose) $(CC) $(CFLAGS) $(CPPFLAGS) -c
  71. COMPILE_CPP = $(cpp_verbose) $(CXX) $(CXXFLAGS) $(CPPFLAGS) -c
  72. app:: $(C_SRC_ENV) $(C_SRC_OUTPUT_FILE)
  73. test-build:: $(C_SRC_ENV) $(C_SRC_OUTPUT_FILE)
  74. $(C_SRC_OUTPUT_FILE): $(OBJECTS)
  75. $(verbose) mkdir -p priv/
  76. $(link_verbose) $(CC) $(OBJECTS) \
  77. $(LDFLAGS) $(if $(filter $(C_SRC_TYPE),shared),-shared) $(LDLIBS) \
  78. -o $(C_SRC_OUTPUT_FILE)
  79. %.o: %.c
  80. $(COMPILE_C) $(OUTPUT_OPTION) $<
  81. %.o: %.cc
  82. $(COMPILE_CPP) $(OUTPUT_OPTION) $<
  83. %.o: %.C
  84. $(COMPILE_CPP) $(OUTPUT_OPTION) $<
  85. %.o: %.cpp
  86. $(COMPILE_CPP) $(OUTPUT_OPTION) $<
  87. clean:: clean-c_src
  88. clean-c_src:
  89. $(gen_verbose) rm -f $(C_SRC_OUTPUT_FILE) $(OBJECTS)
  90. endif
  91. ifneq ($(wildcard $(C_SRC_DIR)),)
  92. $(C_SRC_ENV):
  93. $(verbose) $(ERL) -eval "file:write_file(\"$(call core_native_path,$(C_SRC_ENV))\", \
  94. io_lib:format( \
  95. \"ERTS_INCLUDE_DIR ?= ~s/erts-~s/include/~n\" \
  96. \"ERL_INTERFACE_INCLUDE_DIR ?= ~s~n\" \
  97. \"ERL_INTERFACE_LIB_DIR ?= ~s~n\", \
  98. [code:root_dir(), erlang:system_info(version), \
  99. code:lib_dir(erl_interface, include), \
  100. code:lib_dir(erl_interface, lib)])), \
  101. halt()."
  102. distclean:: distclean-c_src-env
  103. distclean-c_src-env:
  104. $(gen_verbose) rm -f $(C_SRC_ENV)
  105. -include $(C_SRC_ENV)
  106. endif
  107. # Templates.
  108. define bs_c_nif
  109. #include "erl_nif.h"
  110. static int loads = 0;
  111. static int load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info)
  112. {
  113. /* Initialize private data. */
  114. *priv_data = NULL;
  115. loads++;
  116. return 0;
  117. }
  118. static int upgrade(ErlNifEnv* env, void** priv_data, void** old_priv_data, ERL_NIF_TERM load_info)
  119. {
  120. /* Convert the private data to the new version. */
  121. *priv_data = *old_priv_data;
  122. loads++;
  123. return 0;
  124. }
  125. static void unload(ErlNifEnv* env, void* priv_data)
  126. {
  127. if (loads == 1) {
  128. /* Destroy the private data. */
  129. }
  130. loads--;
  131. }
  132. static ERL_NIF_TERM hello(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
  133. {
  134. if (enif_is_atom(env, argv[0])) {
  135. return enif_make_tuple2(env,
  136. enif_make_atom(env, "hello"),
  137. argv[0]);
  138. }
  139. return enif_make_tuple2(env,
  140. enif_make_atom(env, "error"),
  141. enif_make_atom(env, "badarg"));
  142. }
  143. static ErlNifFunc nif_funcs[] = {
  144. {"hello", 1, hello}
  145. };
  146. ERL_NIF_INIT($n, nif_funcs, load, NULL, upgrade, unload)
  147. endef
  148. define bs_erl_nif
  149. -module($n).
  150. -export([hello/1]).
  151. -on_load(on_load/0).
  152. on_load() ->
  153. PrivDir = case code:priv_dir(?MODULE) of
  154. {error, _} ->
  155. AppPath = filename:dirname(filename:dirname(code:which(?MODULE))),
  156. filename:join(AppPath, "priv");
  157. Path ->
  158. Path
  159. end,
  160. erlang:load_nif(filename:join(PrivDir, atom_to_list(?MODULE)), 0).
  161. hello(_) ->
  162. erlang:nif_error({not_loaded, ?MODULE}).
  163. endef
  164. new-nif:
  165. ifneq ($(wildcard $(C_SRC_DIR)/$n.c),)
  166. $(error Error: $(C_SRC_DIR)/$n.c already exists)
  167. endif
  168. ifneq ($(wildcard src/$n.erl),)
  169. $(error Error: src/$n.erl already exists)
  170. endif
  171. ifdef in
  172. $(verbose) $(MAKE) -C $(APPS_DIR)/$(in)/ new-nif n=$n in=
  173. else
  174. $(verbose) mkdir -p $(C_SRC_DIR) src/
  175. $(call render_template,bs_c_nif,$(C_SRC_DIR)/$n.c)
  176. $(call render_template,bs_erl_nif,src/$n.erl)
  177. endif