Makefile 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390
  1. # Copyright (c) 2015-2016, Loïc Hoguin <essen@ninenines.eu>
  2. # Copyright (c) 2014, Viktor Söderqvist <viktor@zuiderkwast.se>
  3. # This file is part of erlang.mk and subject to the terms of the ISC License.
  4. # ZSH users have a more modern shell which doesn't need to
  5. # have the same safeguards as other shells. To use ZSH instead
  6. # of the default shell, set ZSH=1.
  7. ifdef ZSH
  8. SHELL := $(shell which zsh)
  9. endif
  10. # Temporary application name, taken from rule name.
  11. APP = test_$(subst -,_,$@)
  12. # Erlang, quickly!
  13. ERL = erl +A0 -noinput -boot no_dot_erlang
  14. # Platform detection, condensed version.
  15. UNAME_S := $(shell uname -s)
  16. ifeq ($(UNAME_S),Darwin)
  17. PLATFORM = darwin
  18. else ifeq ($(UNAME_S),FreeBSD)
  19. PLATFORM = freebsd
  20. else ifeq ($(shell uname -o),Msys)
  21. PLATFORM = msys2
  22. else
  23. PLATFORM = unix
  24. endif
  25. # Some systems do not have sub-second file times resolution.
  26. # This is the case for older systems like OSX that uses the HFS+
  27. # file system. HFS+ has a 1 second time resolution. This is a
  28. # problem because the Erlang.mk tests rely on file modification
  29. # times to ensure files were rebuilt. To fix this issue, we
  30. # detect here whether the system supports sub-second resolution,
  31. # and maybe sleep during test execution.
  32. #
  33. # Also see:
  34. # * http://arstechnica.com/apple/2011/07/mac-os-x-10-7/12/#hfs-problems
  35. # * https://apple.stackexchange.com/questions/51650/linus-torvalds-and-the-os-x-filesystem
  36. ifeq ($(shell touch a; sleep 0.01; touch b; sleep 0.01; touch c; test c -nt b -a b -nt a; echo $$?; rm a b c),1)
  37. SLEEP = sleep 1
  38. else ifeq ($(shell touch a; touch b; touch c; test c -nt b -a b -nt a; echo $$?; rm a b c),1)
  39. SLEEP = sleep 0.01
  40. else
  41. SLEEP =
  42. endif
  43. # In some cases it is more appropriate to wait until a command succeeds or fails.
  44. # These functions run the given command every second and gives up after 10 tries.
  45. define wait_for_success
  46. count=10; \
  47. until [ $$count = 0 ] || $1; do \
  48. count=`expr $$count - 1`; \
  49. sleep 1; \
  50. done; \
  51. if [ $$count = 0 ]; then \
  52. false; \
  53. fi
  54. endef
  55. define wait_for_failure
  56. count=10; \
  57. while [ $$count != 0 ] && $1; do \
  58. count=`expr $$count - 1`; \
  59. sleep 1; \
  60. done; \
  61. if [ $$count = 0 ]; then \
  62. false; \
  63. fi
  64. endef
  65. # OTP master, for downloading files for testing.
  66. OTP_MASTER = https://raw.githubusercontent.com/erlang/otp/master
  67. # Verbosity.
  68. #
  69. # V=0: Show info messages only.
  70. # V=1: Show test commands.
  71. # V=2: Also show normal Erlang.mk output.
  72. # V=3: Also show verbose Erlang.mk output.
  73. # V=4: Also show a trace of each command after expansion.
  74. V ?= 0
  75. # t: Verbosity control for tests.
  76. # v: Verbosity control for erlang.mk.
  77. # i: Command to display (or suppress) info messages.
  78. ifeq ($V,0)
  79. t = @
  80. v = V=0 >/dev/null 2>&1
  81. i = @echo $@:
  82. else ifeq ($V,1)
  83. t =
  84. v = V=0 >/dev/null 2>&1
  85. i = @echo == $@:
  86. else ifeq ($V,2)
  87. t = @echo " TEST " $@;
  88. v = V=0
  89. i = @echo == $@:
  90. else
  91. t =
  92. v = V=$(shell echo $$(($(V)-2)))
  93. i = @echo == $@:
  94. endif
  95. # Automatic listing of targets from test files.
  96. define list_targets
  97. $(sort $(shell grep ^$1- $(lastword $(MAKEFILE_LIST)) | cut -d: -f1))
  98. endef
  99. # Main targets.
  100. .PHONY: all clean init
  101. all:: core
  102. clean::
  103. $t rm -rf erl_crash.dump packages/ $(filter-out test_rebar_git/,$(wildcard test_*/))
  104. init: clean
  105. $i "Prefetch Rebar if necessary"
  106. $t if [ ! -d test_rebar_git ]; then \
  107. git clone -q -n -- https://github.com/erlang/rebar3 test_rebar_git; \
  108. fi
  109. $i "Generate a bleeding edge Erlang.mk"
  110. $t cd .. && $(MAKE) $v
  111. REBAR3_GIT = file://$(CURDIR)/test_rebar_git
  112. export REBAR3_GIT
  113. # Core.
  114. .PHONY: core
  115. define include_core
  116. core:: core-$1
  117. include core_$1.mk
  118. endef
  119. $(eval $(foreach t,$(patsubst %.mk,%,$(patsubst core_%,%,$(wildcard core_*.mk))),$(call include_core,$t)))
  120. # Plugins.
  121. define include_plugin
  122. all:: $1
  123. include plugin_$1.mk
  124. endef
  125. $(eval $(foreach t,$(patsubst %.mk,%,$(patsubst plugin_%,%,$(wildcard plugin_*.mk))),$(call include_plugin,$t)))
  126. # Packages.
  127. PACKAGES = $(foreach pkg,$(sort $(wildcard ../index/*.mk)),$(notdir $(basename $(pkg))))
  128. PATCHES = ELIXIR_PATCH=1 HUT_PATCH=1
  129. EXCLUDE_FROM_CHECK = ['ci.erlang.mk', elvis_mk, esh_mk, hexer_mk, inaka_mk, 'lfe.mk', pmod_transform, rust_mk]
  130. EXCLUDE_FROM_APP_CHECK = esh_mk pmod_transform rust_mk
  131. packages: $(addprefix pkg-,$(PACKAGES))
  132. define pkg_target
  133. .PHONY: pkg-$1
  134. pkg-$1: init
  135. # Make sure $@ is defined inside the define.
  136. $(eval @ = pkg-$1)
  137. # Get the real application's name.
  138. $(eval APP_NAME := $(shell sed '2!d;s/pkg_$1_name = //' ../index/$1.mk))
  139. $i "Bootstrap a new OTP library in packages/$1_pkg"
  140. $t mkdir -p packages/$1_pkg/
  141. $t cp ../erlang.mk packages/$1_pkg/
  142. $t cd packages/$1_pkg/ && $(MAKE) -f erlang.mk bootstrap-lib $v
  143. $i "Add package $1 to the Makefile"
  144. $t perl -ni.bak -e 'print;if ($$$$.==1) {print "DEPS = $1\n"}' packages/$1_pkg/Makefile
  145. $i "Compile package $1"
  146. $t if ! ( cd packages/$1_pkg/ && $(MAKE) $(PATCHES) $v ); then \
  147. echo "$1: compile error" >> packages/errors.log; \
  148. false; \
  149. fi
  150. $(if $(filter $1,$(EXCLUDE_FROM_APP_CHECK)),,
  151. $i "Check that $1 has a .app file"
  152. $t if ! test -f packages/$1_pkg/deps/$(APP_NAME)/ebin/$(APP_NAME).app; then \
  153. echo "$1: no .app file" >> packages/errors.log; \
  154. false; \
  155. fi)
  156. $i "Check that all applications and their modules can be loaded"
  157. $t if ! ( cd packages/$1_pkg/ && $(ERL) -pa deps/*/ebin/ -eval " \
  158. Apps0 = [list_to_atom(App) || \"deps/\" ++ App \
  159. <- filelib:wildcard(\"deps/*\")], \
  160. Apps = [App || App <- Apps0, not lists:member(App, $(EXCLUDE_FROM_CHECK))], \
  161. [begin \
  162. io:format(\"Loading application ~p~n\", [App]), \
  163. case application:load(App) of \
  164. ok -> ok; \
  165. {error, {already_loaded, App}} -> ok \
  166. end, \
  167. {ok, Mods} = application:get_key(App, modules), \
  168. [try io:format(\" Loading module ~p~n\", [Mod]), \
  169. {module, Mod} = code:load_file(Mod) \
  170. catch C:R -> timer:sleep(500), erlang:C(R) \
  171. end || Mod <- Mods] \
  172. end || App <- Apps], \
  173. halt()." ); then \
  174. echo "$1: load error" >> packages/errors.log; \
  175. false; \
  176. fi
  177. $i "Recompile package $1"
  178. $t if ! ( cd packages/$1_pkg/ && $(MAKE) $(PATCHES) FULL=1 $v ); then \
  179. echo "$(1): recompile error" >> packages/errors.log; \
  180. false; \
  181. fi
  182. $(if $(filter $1,$(EXCLUDE_FROM_APP_CHECK)),,
  183. $i "Check that $1 has a .app file"
  184. $t if ! test -f packages/$1_pkg/deps/$(APP_NAME)/ebin/$(APP_NAME).app; then \
  185. echo "$1: no .app file" >> packages/errors.log; \
  186. false; \
  187. fi)
  188. $i "Check that all applications and their modules can still be loaded"
  189. $t if ! ( cd packages/$1_pkg/ && $(ERL) -pa deps/*/ebin/ -eval " \
  190. Apps0 = [list_to_atom(App) || \"deps/\" ++ App \
  191. <- filelib:wildcard(\"deps/*\")], \
  192. Apps = [App || App <- Apps0, not lists:member(App, $(EXCLUDE_FROM_CHECK))], \
  193. [begin \
  194. io:format(\"Loading application ~p~n\", [App]), \
  195. case application:load(App) of \
  196. ok -> ok; \
  197. {error, {already_loaded, App}} -> ok \
  198. end, \
  199. {ok, Mods} = application:get_key(App, modules), \
  200. [try io:format(\" Loading module ~p~n\", [Mod]), \
  201. {module, Mod} = code:load_file(Mod) \
  202. catch C:R -> timer:sleep(500), erlang:C(R) \
  203. end || Mod <- Mods] \
  204. end || App <- Apps], \
  205. halt()." ); then \
  206. echo "$1: recompile+load error" >> packages/errors.log; \
  207. false; \
  208. fi
  209. $i "Check that no erl_crash.dump file exists"
  210. $t if ( ! find packages/$1_pkg/ -type f -name erl_crash.dump ); then \
  211. echo "$(1): erl_crash.dump found" >> packages/errors.log; \
  212. fi
  213. $(if $(KEEP_BUILDS),,
  214. $i "OK; delete the build directory"
  215. $t rm -rf packages/$1_pkg/)
  216. endef
  217. $(foreach pkg,$(PACKAGES),$(eval $(call pkg_target,$(pkg))))
  218. # Hex.pm packages.
  219. ifdef HEXPM
  220. HEXPM_PACKAGES =
  221. define hexpm_pkg_target
  222. HEXPM_PACKAGES += $1
  223. .PHONY: hexpm-pkg-$1
  224. hexpm-pkg-$1: init
  225. # Make sure $@ is defined inside the define.
  226. $(eval @ = hexpm-pkg-$1)
  227. # @todo Get the real application's name. How?
  228. $(eval APP_NAME := $1)
  229. $i "Bootstrap a new OTP library in packages/$1_pkg"
  230. $t mkdir -p packages/$1_pkg/
  231. $t cp ../erlang.mk packages/$1_pkg/
  232. $t cd packages/$1_pkg/ && $(MAKE) -f erlang.mk bootstrap-lib $v
  233. $i "Add package $1 to the Makefile"
  234. $t perl -ni.bak -e 'print;if ($$$$.==1) {print "DEPS = $1\ndep_$1 = hex $2\n"}' packages/$1_pkg/Makefile
  235. $i "Compile package $1"
  236. $t if ! ( cd packages/$1_pkg/ && $(MAKE) $(PATCHES) $v ); then \
  237. echo "$1: compile error" >> packages/errors.log; \
  238. false; \
  239. fi
  240. # $(if $(filter $1,$(EXCLUDE_FROM_APP_CHECK)),,
  241. $i "Check that $1 has a .app file"
  242. $t if ! test -f packages/$1_pkg/deps/$(APP_NAME)/ebin/$(APP_NAME).app; then \
  243. echo "$1: no .app file" >> packages/errors.log; \
  244. false; \
  245. fi
  246. # )
  247. $i "Check that all applications and their modules can be loaded"
  248. $t if ! ( cd packages/$1_pkg/ && $(ERL) -pa deps/*/ebin/ -eval " \
  249. Apps0 = [list_to_atom(App) || \"deps/\" ++ App \
  250. <- filelib:wildcard(\"deps/*\")], \
  251. Apps = [App || App <- Apps0, not lists:member(App, $(EXCLUDE_FROM_CHECK))], \
  252. [begin \
  253. io:format(\"Loading application ~p~n\", [App]), \
  254. case application:load(App) of \
  255. ok -> ok; \
  256. {error, {already_loaded, App}} -> ok \
  257. end, \
  258. {ok, Mods} = application:get_key(App, modules), \
  259. [try io:format(\" Loading module ~p~n\", [Mod]), \
  260. {module, Mod} = code:load_file(Mod) \
  261. catch C:R -> timer:sleep(500), erlang:C(R) \
  262. end || Mod <- Mods] \
  263. end || App <- Apps], \
  264. halt()." ); then \
  265. echo "$1: load error" >> packages/errors.log; \
  266. false; \
  267. fi
  268. $i "Recompile package $1"
  269. $t if ! ( cd packages/$1_pkg/ && $(MAKE) $(PATCHES) FULL=1 $v ); then \
  270. echo "$(1): recompile error" >> packages/errors.log; \
  271. false; \
  272. fi
  273. # $(if $(filter $1,$(EXCLUDE_FROM_APP_CHECK)),,
  274. $i "Check that $1 has a .app file"
  275. $t if ! test -f packages/$1_pkg/deps/$(APP_NAME)/ebin/$(APP_NAME).app; then \
  276. echo "$1: no .app file" >> packages/errors.log; \
  277. false; \
  278. fi
  279. # )
  280. $i "Check that all applications and their modules can still be loaded"
  281. $t if ! ( cd packages/$1_pkg/ && $(ERL) -pa deps/*/ebin/ -eval " \
  282. Apps0 = [list_to_atom(App) || \"deps/\" ++ App \
  283. <- filelib:wildcard(\"deps/*\")], \
  284. Apps = [App || App <- Apps0, not lists:member(App, $(EXCLUDE_FROM_CHECK))], \
  285. [begin \
  286. io:format(\"Loading application ~p~n\", [App]), \
  287. case application:load(App) of \
  288. ok -> ok; \
  289. {error, {already_loaded, App}} -> ok \
  290. end, \
  291. {ok, Mods} = application:get_key(App, modules), \
  292. [try io:format(\" Loading module ~p~n\", [Mod]), \
  293. {module, Mod} = code:load_file(Mod) \
  294. catch C:R -> timer:sleep(500), erlang:C(R) \
  295. end || Mod <- Mods] \
  296. end || App <- Apps], \
  297. halt()." ); then \
  298. echo "$1: recompile+load error" >> packages/errors.log; \
  299. false; \
  300. fi
  301. $i "Check that no erl_crash.dump file exists"
  302. $t if ( ! find packages/$1_pkg/ -type f -name erl_crash.dump ); then \
  303. echo "$(1): erl_crash.dump found" >> packages/errors.log; \
  304. fi
  305. $(if $(KEEP_BUILDS),,
  306. $i "OK; delete the build directory"
  307. $t rm -rf packages/$1_pkg/)
  308. endef
  309. $(foreach pkg,$(shell grep -v '^#' hexpm_packages.txt | sed 's/ /@/'),$(eval $(call hexpm_pkg_target,$(firstword $(subst @, ,$(pkg))),$(lastword $(subst @, ,$(pkg))))))
  310. hexpm-packages: $(addprefix hexpm-pkg-,$(HEXPM_PACKAGES))
  311. endif