diff options
-rw-r--r-- | erlang.mk | 1007 |
1 files changed, 720 insertions, 287 deletions
@@ -17,16 +17,16 @@ ERLANG_MK_FILENAME := $(realpath $(lastword $(MAKEFILE_LIST))) export ERLANG_MK_FILENAME -ERLANG_MK_VERSION = 6c8664c +ERLANG_MK_VERSION = a187726 ERLANG_MK_WITHOUT = # Make 3.81 and 3.82 are deprecated. -ifeq ($(MAKE_VERSION),3.81) +ifeq ($(MAKELEVEL)$(MAKE_VERSION),03.81) $(warning Please upgrade to GNU Make 4 or later: https://erlang.mk/guide/installation.html) endif -ifeq ($(MAKE_VERSION),3.82) +ifeq ($(MAKELEVEL)$(MAKE_VERSION),03.82) $(warning Please upgrade to GNU Make 4 or later: https://erlang.mk/guide/installation.html) endif @@ -47,10 +47,18 @@ verbose_0 = @ verbose_2 = set -x; verbose = $(verbose_$(V)) +ifeq ($(V),3) +SHELL := $(SHELL) -x +endif + gen_verbose_0 = @echo " GEN " $@; gen_verbose_2 = set -x; gen_verbose = $(gen_verbose_$(V)) +gen_verbose_esc_0 = @echo " GEN " $$@; +gen_verbose_esc_2 = set -x; +gen_verbose_esc = $(gen_verbose_esc_$(V)) + # Temporary files directory. ERLANG_MK_TMP ?= $(CURDIR)/.erlang.mk @@ -58,7 +66,7 @@ export ERLANG_MK_TMP # "erl" command. -ERL = erl +A0 -noinput -boot start_clean +ERL = erl +A1 -noinput -boot no_dot_erlang # Platform detection. @@ -111,6 +119,9 @@ endif distclean:: clean distclean-tmp +$(ERLANG_MK_TMP): + $(verbose) mkdir -p $(ERLANG_MK_TMP) + distclean-tmp: $(gen_verbose) rm -rf $(ERLANG_MK_TMP) @@ -164,7 +175,7 @@ $(ERL) $2 -pz $(ERLANG_MK_TMP)/rebar/ebin -eval "$(subst $(newline),,$(call esca endef ifeq ($(PLATFORM),msys2) -core_native_path = $(subst \,\\\\,$(shell cygpath -w $1)) +core_native_path = $(shell cygpath -m $1) else core_native_path = $1 endif @@ -173,7 +184,8 @@ core_http_get = curl -Lf$(if $(filter-out 0,$(V)),,s)o $(call core_native_path,$ core_eq = $(and $(findstring $(1),$(2)),$(findstring $(2),$(1))) -core_find = $(if $(wildcard $1),$(shell find $(1:%/=%) -type f -name $(subst *,\*,$2))) +# We skip files that contain spaces because they end up causing issues. +core_find = $(if $(wildcard $1),$(shell find $(1:%/=%) \( -type l -o -type f \) -name $(subst *,\*,$2) | grep -v " ")) core_lc = $(subst A,a,$(subst B,b,$(subst C,c,$(subst D,d,$(subst E,e,$(subst F,f,$(subst G,g,$(subst H,h,$(subst I,i,$(subst J,j,$(subst K,k,$(subst L,l,$(subst M,m,$(subst N,n,$(subst O,o,$(subst P,p,$(subst Q,q,$(subst R,r,$(subst S,s,$(subst T,t,$(subst U,u,$(subst V,v,$(subst W,w,$(subst X,x,$(subst Y,y,$(subst Z,z,$(1))))))))))))))))))))))))))) @@ -182,6 +194,10 @@ core_ls = $(filter-out $(1),$(shell echo $(1))) # @todo Use a solution that does not require using perl. core_relpath = $(shell perl -e 'use File::Spec; print File::Spec->abs2rel(@ARGV) . "\n"' $1 $2) +define core_render + printf -- '$(subst $(newline),\n,$(subst %,%%,$(subst ','\'',$(subst $(tab),$(WS),$(call $(1))))))\n' > $(2) +endef + # Automated update. ERLANG_MK_REPO ?= https://github.com/ninenines/erlang.mk @@ -192,15 +208,16 @@ ERLANG_MK_BUILD_DIR ?= .erlang.mk.build erlang-mk: WITHOUT ?= $(ERLANG_MK_WITHOUT) erlang-mk: ifdef ERLANG_MK_COMMIT - git clone $(ERLANG_MK_REPO) $(ERLANG_MK_BUILD_DIR) - cd $(ERLANG_MK_BUILD_DIR) && git checkout $(ERLANG_MK_COMMIT) + $(verbose) git clone $(ERLANG_MK_REPO) $(ERLANG_MK_BUILD_DIR) + $(verbose) cd $(ERLANG_MK_BUILD_DIR) && git checkout $(ERLANG_MK_COMMIT) else - git clone --depth 1 $(ERLANG_MK_REPO) $(ERLANG_MK_BUILD_DIR) + $(verbose) git clone --depth 1 $(ERLANG_MK_REPO) $(ERLANG_MK_BUILD_DIR) endif - if [ -f $(ERLANG_MK_BUILD_CONFIG) ]; then cp $(ERLANG_MK_BUILD_CONFIG) $(ERLANG_MK_BUILD_DIR)/build.config; fi - $(MAKE) -C $(ERLANG_MK_BUILD_DIR) WITHOUT='$(strip $(WITHOUT))' - cp $(ERLANG_MK_BUILD_DIR)/erlang.mk ./erlang.mk - rm -rf $(ERLANG_MK_BUILD_DIR) + $(verbose) if [ -f $(ERLANG_MK_BUILD_CONFIG) ]; then cp $(ERLANG_MK_BUILD_CONFIG) $(ERLANG_MK_BUILD_DIR)/build.config; fi + $(gen_verbose) $(MAKE) --no-print-directory -C $(ERLANG_MK_BUILD_DIR) WITHOUT='$(strip $(WITHOUT))' UPGRADE=1 + $(verbose) cp $(ERLANG_MK_BUILD_DIR)/erlang.mk ./erlang.mk + $(verbose) rm -rf $(ERLANG_MK_BUILD_DIR) + $(verbose) rm -rf $(ERLANG_MK_TMP) # The erlang.mk package index is bundled in the default erlang.mk build. # Search for the string "copyright" to skip to the rest of the code. @@ -216,6 +233,8 @@ ifeq ($(strip $(KERL)),) KERL := $(ERLANG_MK_TMP)/kerl/kerl endif +KERL_DIR = $(ERLANG_MK_TMP)/kerl + export KERL KERL_GIT ?= https://github.com/kerl/kerl @@ -226,24 +245,25 @@ KERL_MAKEFLAGS ?= OTP_GIT ?= https://github.com/erlang/otp define kerl_otp_target -ifeq ($(wildcard $(KERL_INSTALL_DIR)/$(1)),) $(KERL_INSTALL_DIR)/$(1): $(KERL) - MAKEFLAGS="$(KERL_MAKEFLAGS)" $(KERL) build git $(OTP_GIT) $(1) $(1) - $(KERL) install $(1) $(KERL_INSTALL_DIR)/$(1) -endif + $(verbose) if [ ! -d $$@ ]; then \ + MAKEFLAGS="$(KERL_MAKEFLAGS)" $(KERL) build git $(OTP_GIT) $(1) $(1); \ + $(KERL) install $(1) $(KERL_INSTALL_DIR)/$(1); \ + fi endef define kerl_hipe_target -ifeq ($(wildcard $(KERL_INSTALL_DIR)/$1-native),) $(KERL_INSTALL_DIR)/$1-native: $(KERL) - KERL_CONFIGURE_OPTIONS=--enable-native-libs \ - MAKEFLAGS="$(KERL_MAKEFLAGS)" $(KERL) build git $(OTP_GIT) $1 $1-native - $(KERL) install $1-native $(KERL_INSTALL_DIR)/$1-native -endif + $(verbose) if [ ! -d $$@ ]; then \ + KERL_CONFIGURE_OPTIONS=--enable-native-libs \ + MAKEFLAGS="$(KERL_MAKEFLAGS)" $(KERL) build git $(OTP_GIT) $1 $1-native; \ + $(KERL) install $1-native $(KERL_INSTALL_DIR)/$1-native; \ + fi endef -$(KERL): - $(verbose) mkdir -p $(ERLANG_MK_TMP) +$(KERL): $(KERL_DIR) + +$(KERL_DIR): | $(ERLANG_MK_TMP) $(gen_verbose) git clone --depth 1 $(KERL_GIT) $(ERLANG_MK_TMP)/kerl $(verbose) cd $(ERLANG_MK_TMP)/kerl && git checkout $(KERL_COMMIT) $(verbose) chmod +x $(KERL) @@ -251,12 +271,14 @@ $(KERL): distclean:: distclean-kerl distclean-kerl: - $(gen_verbose) rm -rf $(KERL) + $(gen_verbose) rm -rf $(KERL_DIR) # Allow users to select which version of Erlang/OTP to use for a project. ifneq ($(strip $(LATEST_ERLANG_OTP)),) -ERLANG_OTP := $(notdir $(lastword $(sort $(filter-out $(KERL_INSTALL_DIR)/OTP_R%,\ +# In some environments it is necessary to filter out master. +ERLANG_OTP := $(notdir $(lastword $(sort\ + $(filter-out $(KERL_INSTALL_DIR)/master $(KERL_INSTALL_DIR)/OTP_R%,\ $(filter-out %-rc1 %-rc2 %-rc3,$(wildcard $(KERL_INSTALL_DIR)/*[^-native])))))) endif @@ -283,9 +305,9 @@ SHELL := env PATH=$(PATH) $(SHELL) $(eval $(call kerl_hipe_target,$(ERLANG_HIPE))) # Build Erlang/OTP only if it doesn't already exist. -ifeq ($(wildcard $(KERL_INSTALL_DIR)/$(ERLANG_HIPE))$(BUILD_ERLANG_OTP),) +ifeq ($(wildcard $(KERL_INSTALL_DIR)/$(ERLANG_HIPE)-native)$(BUILD_ERLANG_OTP),) $(info Building HiPE-enabled Erlang/OTP $(ERLANG_OTP)... Please wait...) -$(shell $(MAKE) $(KERL_INSTALL_DIR)/$(ERLANG_HIPE) ERLANG_HIPE=$(ERLANG_HIPE) BUILD_ERLANG_OTP=1 >&2) +$(shell $(MAKE) $(KERL_INSTALL_DIR)/$(ERLANG_HIPE)-native ERLANG_HIPE=$(ERLANG_HIPE) BUILD_ERLANG_OTP=1 >&2) endif endif @@ -1203,12 +1225,20 @@ pkg_eleveldb_fetch = git pkg_eleveldb_repo = https://github.com/basho/eleveldb pkg_eleveldb_commit = master +PACKAGES += elixir +pkg_elixir_name = elixir +pkg_elixir_description = Elixir is a dynamic, functional language designed for building scalable and maintainable applications +pkg_elixir_homepage = https://elixir-lang.org/ +pkg_elixir_fetch = git +pkg_elixir_repo = https://github.com/elixir-lang/elixir +pkg_elixir_commit = master + PACKAGES += elli pkg_elli_name = elli pkg_elli_description = Simple, robust and performant Erlang web server -pkg_elli_homepage = https://github.com/knutin/elli +pkg_elli_homepage = https://github.com/elli-lib/elli pkg_elli_fetch = git -pkg_elli_repo = https://github.com/knutin/elli +pkg_elli_repo = https://github.com/elli-lib/elli pkg_elli_commit = master PACKAGES += elvis @@ -1603,6 +1633,14 @@ pkg_escalus_fetch = git pkg_escalus_repo = https://github.com/esl/escalus pkg_escalus_commit = master +PACKAGES += esh_mk +pkg_esh_mk_name = esh_mk +pkg_esh_mk_description = esh template engine plugin for erlang.mk +pkg_esh_mk_homepage = https://github.com/crownedgrouse/esh.mk +pkg_esh_mk_fetch = git +pkg_esh_mk_repo = https://github.com/crownedgrouse/esh.mk.git +pkg_esh_mk_commit = master + PACKAGES += espec pkg_espec_name = espec pkg_espec_description = ESpec: Behaviour driven development framework for Erlang @@ -1899,6 +1937,14 @@ pkg_gen_icmp_fetch = git pkg_gen_icmp_repo = https://github.com/msantos/gen_icmp pkg_gen_icmp_commit = master +PACKAGES += gen_leader +pkg_gen_leader_name = gen_leader +pkg_gen_leader_description = leader election behavior +pkg_gen_leader_homepage = https://github.com/garret-smith/gen_leader_revival +pkg_gen_leader_fetch = git +pkg_gen_leader_repo = https://github.com/garret-smith/gen_leader_revival +pkg_gen_leader_commit = master + PACKAGES += gen_nb_server pkg_gen_nb_server_name = gen_nb_server pkg_gen_nb_server_description = OTP behavior for writing non-blocking servers @@ -1915,6 +1961,14 @@ pkg_gen_paxos_fetch = git pkg_gen_paxos_repo = https://github.com/gburd/gen_paxos pkg_gen_paxos_commit = master +PACKAGES += gen_rpc +pkg_gen_rpc_name = gen_rpc +pkg_gen_rpc_description = A scalable RPC library for Erlang-VM based languages +pkg_gen_rpc_homepage = https://github.com/priestjim/gen_rpc.git +pkg_gen_rpc_fetch = git +pkg_gen_rpc_repo = https://github.com/priestjim/gen_rpc.git +pkg_gen_rpc_commit = master + PACKAGES += gen_smtp pkg_gen_smtp_name = gen_smtp pkg_gen_smtp_description = A generic Erlang SMTP server and client that can be extended via callback modules @@ -2765,11 +2819,11 @@ pkg_myproto_commit = master PACKAGES += mysql pkg_mysql_name = mysql -pkg_mysql_description = Erlang MySQL Driver (from code.google.com) -pkg_mysql_homepage = https://github.com/dizzyd/erlang-mysql-driver +pkg_mysql_description = MySQL client library for Erlang/OTP +pkg_mysql_homepage = https://github.com/mysql-otp/mysql-otp pkg_mysql_fetch = git -pkg_mysql_repo = https://github.com/dizzyd/erlang-mysql-driver -pkg_mysql_commit = master +pkg_mysql_repo = https://github.com/mysql-otp/mysql-otp +pkg_mysql_commit = 1.5.1 PACKAGES += n2o pkg_n2o_name = n2o @@ -2979,6 +3033,14 @@ pkg_parsexml_fetch = git pkg_parsexml_repo = https://github.com/maxlapshin/parsexml pkg_parsexml_commit = master +PACKAGES += partisan +pkg_partisan_name = partisan +pkg_partisan_description = High-performance, high-scalability distributed computing with Erlang and Elixir. +pkg_partisan_homepage = http://partisan.cloud +pkg_partisan_fetch = git +pkg_partisan_repo = https://github.com/lasp-lang/partisan +pkg_partisan_commit = master + PACKAGES += pegjs pkg_pegjs_name = pegjs pkg_pegjs_description = An implementation of PEG.js grammar for Erlang. @@ -2995,6 +3057,14 @@ pkg_percept2_fetch = git pkg_percept2_repo = https://github.com/huiqing/percept2 pkg_percept2_commit = master +PACKAGES += pgo +pkg_pgo_name = pgo +pkg_pgo_description = Erlang Postgres client and connection pool +pkg_pgo_homepage = https://github.com/erleans/pgo.git +pkg_pgo_fetch = git +pkg_pgo_repo = https://github.com/erleans/pgo.git +pkg_pgo_commit = master + PACKAGES += pgsql pkg_pgsql_name = pgsql pkg_pgsql_description = Erlang PostgreSQL driver @@ -3091,6 +3161,14 @@ pkg_procket_fetch = git pkg_procket_repo = https://github.com/msantos/procket pkg_procket_commit = master +PACKAGES += prometheus +pkg_prometheus_name = prometheus +pkg_prometheus_description = Prometheus.io client in Erlang +pkg_prometheus_homepage = https://github.com/deadtrickster/prometheus.erl +pkg_prometheus_fetch = git +pkg_prometheus_repo = https://github.com/deadtrickster/prometheus.erl +pkg_prometheus_commit = master + PACKAGES += prop pkg_prop_name = prop pkg_prop_description = An Erlang code scaffolding and generator system. @@ -4253,6 +4331,9 @@ export DEPS_DIR REBAR_DEPS_DIR = $(DEPS_DIR) export REBAR_DEPS_DIR +REBAR_GIT ?= https://github.com/rebar/rebar +REBAR_COMMIT ?= 576e12171ab8d69b048b827b92aa65d067deea01 + # External "early" plugins (see core/plugins.mk for regular plugins). # They both use the core_dep_plugin macro. @@ -4273,15 +4354,78 @@ $(foreach p,$(DEP_EARLY_PLUGINS),\ $(call core_dep_plugin,$p,$(firstword $(subst /, ,$p))),\ $(call core_dep_plugin,$p/early-plugins.mk,$p)))) -dep_name = $(if $(dep_$(1)),$(1),$(if $(pkg_$(1)_name),$(pkg_$(1)_name),$(1))) -dep_repo = $(patsubst git://github.com/%,https://github.com/%, \ - $(if $(dep_$(1)),$(word 2,$(dep_$(1))),$(pkg_$(1)_repo))) -dep_commit = $(if $(dep_$(1)_commit),$(dep_$(1)_commit),$(if $(dep_$(1)),$(word 3,$(dep_$(1))),$(pkg_$(1)_commit))) +# Query functions. + +query_fetch_method = $(if $(dep_$(1)),$(call _qfm_dep,$(word 1,$(dep_$(1)))),$(call _qfm_pkg,$(1))) +_qfm_dep = $(if $(dep_fetch_$(1)),$(1),$(if $(IS_DEP),legacy,fail)) +_qfm_pkg = $(if $(pkg_$(1)_fetch),$(pkg_$(1)_fetch),fail) + +query_name = $(if $(dep_$(1)),$(1),$(if $(pkg_$(1)_name),$(pkg_$(1)_name),$(1))) + +query_repo = $(call _qr,$(1),$(call query_fetch_method,$(1))) +_qr = $(if $(query_repo_$(2)),$(call query_repo_$(2),$(1)),$(call dep_repo,$(1))) + +query_repo_default = $(if $(dep_$(1)),$(word 2,$(dep_$(1))),$(pkg_$(1)_repo)) +query_repo_git = $(patsubst git://github.com/%,https://github.com/%,$(call query_repo_default,$(1))) +query_repo_git-subfolder = $(call query_repo_git,$(1)) +query_repo_git-submodule = - +query_repo_hg = $(call query_repo_default,$(1)) +query_repo_svn = $(call query_repo_default,$(1)) +query_repo_cp = $(call query_repo_default,$(1)) +query_repo_ln = $(call query_repo_default,$(1)) +query_repo_hex = https://hex.pm/packages/$(if $(word 3,$(dep_$(1))),$(word 3,$(dep_$(1))),$(1)) +query_repo_fail = - +query_repo_legacy = - + +query_version = $(call _qv,$(1),$(call query_fetch_method,$(1))) +_qv = $(if $(query_version_$(2)),$(call query_version_$(2),$(1)),$(call dep_commit,$(1))) + +query_version_default = $(if $(dep_$(1)_commit),$(dep_$(1)_commit),$(if $(dep_$(1)),$(word 3,$(dep_$(1))),$(pkg_$(1)_commit))) +query_version_git = $(call query_version_default,$(1)) +query_version_git-subfolder = $(call query_version_git,$(1)) +query_version_git-submodule = - +query_version_hg = $(call query_version_default,$(1)) +query_version_svn = - +query_version_cp = - +query_version_ln = - +query_version_hex = $(if $(dep_$(1)_commit),$(dep_$(1)_commit),$(if $(dep_$(1)),$(word 2,$(dep_$(1))),$(pkg_$(1)_commit))) +query_version_fail = - +query_version_legacy = - + +query_extra = $(call _qe,$(1),$(call query_fetch_method,$(1))) +_qe = $(if $(query_extra_$(2)),$(call query_extra_$(2),$(1)),-) + +query_extra_git = - +query_extra_git-subfolder = $(if $(dep_$(1)),subfolder=$(word 4,$(dep_$(1))),-) +query_extra_git-submodule = - +query_extra_hg = - +query_extra_svn = - +query_extra_cp = - +query_extra_ln = - +query_extra_hex = $(if $(dep_$(1)),package-name=$(word 3,$(dep_$(1))),-) +query_extra_fail = - +query_extra_legacy = - + +query_absolute_path = $(addprefix $(DEPS_DIR)/,$(call query_name,$(1))) + +# Deprecated legacy query functions. +dep_fetch = $(call query_fetch_method,$(1)) +dep_name = $(call query_name,$(1)) +dep_repo = $(call query_repo_git,$(1)) +dep_commit = $(if $(dep_$(1)_commit),$(dep_$(1)_commit),$(if $(dep_$(1)),$(if $(filter hex,$(word 1,$(dep_$(1)))),$(word 2,$(dep_$(1))),$(word 3,$(dep_$(1)))),$(pkg_$(1)_commit))) LOCAL_DEPS_DIRS = $(foreach a,$(LOCAL_DEPS),$(if $(wildcard $(APPS_DIR)/$(a)),$(APPS_DIR)/$(a))) -ALL_APPS_DIRS = $(if $(wildcard $(APPS_DIR)/),$(filter-out $(APPS_DIR),$(shell find $(APPS_DIR) -maxdepth 1 -type d))) ALL_DEPS_DIRS = $(addprefix $(DEPS_DIR)/,$(foreach dep,$(filter-out $(IGNORE_DEPS),$(BUILD_DEPS) $(DEPS)),$(call dep_name,$(dep)))) +# When we are calling an app directly we don't want to include it here +# otherwise it'll be treated both as an apps and a top-level project. +ALL_APPS_DIRS = $(if $(wildcard $(APPS_DIR)/),$(filter-out $(APPS_DIR),$(shell find $(APPS_DIR) -maxdepth 1 -type d))) +ifdef ROOT_DIR +ifndef IS_APP +ALL_APPS_DIRS := $(filter-out $(APPS_DIR)/$(notdir $(CURDIR)),$(ALL_APPS_DIRS)) +endif +endif + ifeq ($(filter $(APPS_DIR) $(DEPS_DIR),$(subst :, ,$(ERL_LIBS))),) ifeq ($(ERL_LIBS),) ERL_LIBS = $(APPS_DIR):$(DEPS_DIR) @@ -4299,50 +4443,82 @@ dep_verbose_0 = @echo " DEP $1 ($(call dep_commit,$1))"; dep_verbose_2 = set -x; dep_verbose = $(dep_verbose_$(V)) -# Core targets. +# Optimization: don't recompile deps unless truly necessary. -apps:: $(ALL_APPS_DIRS) clean-tmp-deps.log -ifeq ($(IS_APP)$(IS_DEP),) - $(verbose) rm -f $(ERLANG_MK_TMP)/apps.log +ifndef IS_DEP +ifneq ($(MAKELEVEL),0) +$(shell rm -f ebin/dep_built) endif - $(verbose) mkdir -p $(ERLANG_MK_TMP) +endif + +# Core targets. + +ALL_APPS_DIRS_TO_BUILD = $(if $(LOCAL_DEPS_DIRS)$(IS_APP),$(LOCAL_DEPS_DIRS),$(ALL_APPS_DIRS)) + +apps:: $(ALL_APPS_DIRS) clean-tmp-deps.log | $(ERLANG_MK_TMP) # Create ebin directory for all apps to make sure Erlang recognizes them # as proper OTP applications when using -include_lib. This is a temporary # fix, a proper fix would be to compile apps/* in the right order. ifndef IS_APP +ifneq ($(ALL_APPS_DIRS),) $(verbose) set -e; for dep in $(ALL_APPS_DIRS) ; do \ mkdir -p $$dep/ebin; \ done endif -# at the toplevel: if LOCAL_DEPS is defined with at least one local app, only -# compile that list of apps. otherwise, compile everything. -# within an app: compile all LOCAL_DEPS that are (uncompiled) local apps - $(verbose) set -e; for dep in $(if $(LOCAL_DEPS_DIRS)$(IS_APP),$(LOCAL_DEPS_DIRS),$(ALL_APPS_DIRS)) ; do \ +endif +# At the toplevel: if LOCAL_DEPS is defined with at least one local app, only +# compile that list of apps. Otherwise, compile everything. +# Within an app: compile all LOCAL_DEPS that are (uncompiled) local apps. +ifneq ($(ALL_APPS_DIRS_TO_BUILD),) + $(verbose) set -e; for dep in $(ALL_APPS_DIRS_TO_BUILD); do \ if grep -qs ^$$dep$$ $(ERLANG_MK_TMP)/apps.log; then \ :; \ else \ echo $$dep >> $(ERLANG_MK_TMP)/apps.log; \ - $(MAKE) -C $$dep IS_APP=1; \ + $(MAKE) -C $$dep $(if $(IS_TEST),test-build-app) IS_APP=1; \ fi \ done +endif clean-tmp-deps.log: ifeq ($(IS_APP)$(IS_DEP),) - $(verbose) rm -f $(ERLANG_MK_TMP)/deps.log + $(verbose) rm -f $(ERLANG_MK_TMP)/apps.log $(ERLANG_MK_TMP)/deps.log +endif + +# Erlang.mk does not rebuild dependencies after they were compiled +# once. If a developer is working on the top-level project and some +# dependencies at the same time, he may want to change this behavior. +# There are two solutions: +# 1. Set `FULL=1` so that all dependencies are visited and +# recursively recompiled if necessary. +# 2. Set `FORCE_REBUILD=` to the specific list of dependencies that +# should be recompiled (instead of the whole set). + +FORCE_REBUILD ?= + +ifeq ($(origin FULL),undefined) +ifneq ($(strip $(force_rebuild_dep)$(FORCE_REBUILD)),) +define force_rebuild_dep +echo "$(FORCE_REBUILD)" | grep -qw "$$(basename "$1")" +endef +endif endif ifneq ($(SKIP_DEPS),) deps:: else -deps:: $(ALL_DEPS_DIRS) apps clean-tmp-deps.log - $(verbose) mkdir -p $(ERLANG_MK_TMP) - $(verbose) set -e; for dep in $(ALL_DEPS_DIRS) ; do \ +deps:: $(ALL_DEPS_DIRS) apps clean-tmp-deps.log | $(ERLANG_MK_TMP) +ifneq ($(ALL_DEPS_DIRS),) + $(verbose) set -e; for dep in $(ALL_DEPS_DIRS); do \ if grep -qs ^$$dep$$ $(ERLANG_MK_TMP)/deps.log; then \ :; \ else \ echo $$dep >> $(ERLANG_MK_TMP)/deps.log; \ - if [ -f $$dep/GNUmakefile ] || [ -f $$dep/makefile ] || [ -f $$dep/Makefile ]; then \ + if [ -z "$(strip $(FULL))" ] $(if $(force_rebuild_dep),&& ! ($(call force_rebuild_dep,$$dep)),) && [ ! -L $$dep ] && [ -f $$dep/ebin/dep_built ]; then \ + :; \ + elif [ -f $$dep/GNUmakefile ] || [ -f $$dep/makefile ] || [ -f $$dep/Makefile ]; then \ $(MAKE) -C $$dep IS_DEP=1; \ + if [ ! -L $$dep ] && [ -d $$dep/ebin ]; then touch $$dep/ebin/dep_built; fi; \ else \ echo "Error: No Makefile to build dependency $$dep." >&2; \ exit 2; \ @@ -4350,6 +4526,7 @@ deps:: $(ALL_DEPS_DIRS) apps clean-tmp-deps.log fi \ done endif +endif # Deps related targets. @@ -4422,13 +4599,23 @@ define dep_autopatch_gen "include ../../erlang.mk" > $(DEPS_DIR)/$(1)/Makefile endef +# We use flock/lockf when available to avoid concurrency issues. define dep_autopatch_fetch_rebar - mkdir -p $(ERLANG_MK_TMP); \ + if command -v flock >/dev/null; then \ + flock $(ERLANG_MK_TMP)/rebar.lock sh -c "$(call dep_autopatch_fetch_rebar2)"; \ + elif command -v lockf >/dev/null; then \ + lockf $(ERLANG_MK_TMP)/rebar.lock sh -c "$(call dep_autopatch_fetch_rebar2)"; \ + else \ + $(call dep_autopatch_fetch_rebar2); \ + fi +endef + +define dep_autopatch_fetch_rebar2 if [ ! -d $(ERLANG_MK_TMP)/rebar ]; then \ - git clone -q -n -- https://github.com/rebar/rebar $(ERLANG_MK_TMP)/rebar; \ + git clone -q -n -- $(REBAR_GIT) $(ERLANG_MK_TMP)/rebar; \ cd $(ERLANG_MK_TMP)/rebar; \ - git checkout -q 576e12171ab8d69b048b827b92aa65d067deea01; \ - $(MAKE); \ + git checkout -q $(REBAR_COMMIT); \ + ./bootstrap; \ cd -; \ fi endef @@ -4501,7 +4688,7 @@ define dep_autopatch_rebar.erl end, Write("\n") end(), - GetHexVsn = fun(N) -> + GetHexVsn = fun(N, NP) -> case file:consult("$(call core_native_path,$(DEPS_DIR)/$1/rebar.lock)") of {ok, Lock} -> io:format("~p~n", [Lock]), @@ -4511,7 +4698,7 @@ define dep_autopatch_rebar.erl case lists:keyfind(atom_to_binary(N, latin1), 1, LockPkgs) of {_, {pkg, _, Vsn}, _} -> io:format("~p~n", [Vsn]), - {N, {hex, binary_to_list(Vsn)}}; + {N, {hex, NP, binary_to_list(Vsn)}}; _ -> false end; @@ -4522,13 +4709,28 @@ define dep_autopatch_rebar.erl false end end, + SemVsn = fun + ("~>" ++ S0) -> + S = case S0 of + " " ++ S1 -> S1; + _ -> S0 + end, + case length([ok || $$. <- S]) of + 0 -> S ++ ".0.0"; + 1 -> S ++ ".0"; + _ -> S + end; + (S) -> S + end, fun() -> File = case lists:keyfind(deps, 1, Conf) of false -> []; {_, Deps} -> [begin case case Dep of - N when is_atom(N) -> GetHexVsn(N); - {N, S} when is_atom(N), is_list(S) -> {N, {hex, S}}; + N when is_atom(N) -> GetHexVsn(N, N); + {N, S} when is_atom(N), is_list(S) -> {N, {hex, N, SemVsn(S)}}; + {N, {pkg, NP}} when is_atom(N) -> GetHexVsn(N, NP); + {N, S, {pkg, NP}} -> {N, {hex, NP, S}}; {N, S} when is_tuple(S) -> {N, S}; {N, _, S} -> {N, S}; {N, _, S, _} -> {N, S}; @@ -4537,7 +4739,7 @@ define dep_autopatch_rebar.erl false -> ok; {Name, Source} -> {Method, Repo, Commit} = case Source of - {hex, V} -> {hex, V, undefined}; + {hex, NPV, V} -> {hex, V, NPV}; {git, R} -> {git, R, master}; {M, R, {branch, C}} -> {M, R, C}; {M, R, {ref, C}} -> {M, R, C}; @@ -4554,6 +4756,8 @@ define dep_autopatch_rebar.erl {_, Files} -> Names = [[" ", case lists:reverse(F) of "lre." ++ Elif -> lists:reverse(Elif); + "lrx." ++ Elif -> lists:reverse(Elif); + "lry." ++ Elif -> lists:reverse(Elif); Elif -> lists:reverse(Elif) end] || "src/" ++ F <- Files], Write(io_lib:format("COMPILE_FIRST +=~s\n", [Names])) @@ -4591,9 +4795,10 @@ define dep_autopatch_rebar.erl end || H <- Hooks] end end(), - ShellToMk = fun(V) -> - re:replace(re:replace(V, "(\\\\$$)(\\\\w*)", "\\\\1(\\\\2)", [global]), - "-Werror\\\\b", "", [{return, list}, global]) + ShellToMk = fun(V0) -> + V1 = re:replace(V0, "[$$][(]", "$$\(shell ", [global]), + V = re:replace(V1, "([$$])(?![(])(\\\\w*)", "\\\\1(\\\\2)", [global]), + re:replace(V, "-Werror\\\\b", "", [{return, list}, global]) end, PortSpecs = fun() -> case lists:keyfind(port_specs, 1, Conf) of @@ -4626,7 +4831,7 @@ define dep_autopatch_rebar.erl case PortSpecs of [] -> ok; _ -> - Write("\npre-app::\n\t$$\(MAKE) -f c_src/Makefile.erlang.mk\n"), + Write("\npre-app::\n\t@$$\(MAKE) --no-print-directory -f c_src/Makefile.erlang.mk\n"), PortSpecWrite(io_lib:format("ERL_CFLAGS ?= -finline-functions -Wall -fPIC -I \\"~s/erts-~s/include\\" -I \\"~s\\"\n", [code:root_dir(), erlang:system_info(version), code:lib_dir(erl_interface, include)])), PortSpecWrite(io_lib:format("ERL_LDFLAGS ?= -L \\"~s\\" -lerl_interface -lei\n", @@ -4663,7 +4868,7 @@ define dep_autopatch_rebar.erl darwin -> "\n\nLDFLAGS += -flat_namespace -undefined suppress"; _ -> "" end, - "\n\nall:: ", Output, "\n\n", + "\n\nall:: ", Output, "\n\t@:\n\n", "%.o: %.c\n\t$$\(CC) -c -o $$\@ $$\< $$\(CFLAGS) $$\(ERL_CFLAGS) $$\(DRV_CFLAGS) $$\(EXE_CFLAGS)\n\n", "%.o: %.C\n\t$$\(CXX) -c -o $$\@ $$\< $$\(CXXFLAGS) $$\(ERL_CFLAGS) $$\(DRV_CFLAGS) $$\(EXE_CFLAGS)\n\n", "%.o: %.cc\n\t$$\(CXX) -c -o $$\@ $$\< $$\(CXXFLAGS) $$\(ERL_CFLAGS) $$\(DRV_CFLAGS) $$\(EXE_CFLAGS)\n\n", @@ -4680,6 +4885,17 @@ define dep_autopatch_rebar.erl end, [PortSpec(S) || S <- PortSpecs] end, + fun() -> + case lists:keyfind(plugins, 1, Conf) of + false -> ok; + {_, Plugins0} -> + Plugins = [P || P <- Plugins0, is_tuple(P)], + case lists:keyfind('lfe-compile', 1, Plugins) of + false -> ok; + _ -> Write("\nBUILD_DEPS = lfe lfe.mk\ndep_lfe.mk = git https://github.com/ninenines/lfe.mk master\nDEP_PLUGINS = lfe.mk\n") + end + end + end(), Write("\ninclude $$\(if $$\(ERLANG_MK_FILENAME),$$\(ERLANG_MK_FILENAME),erlang.mk)"), RunPlugin = fun(Plugin, Step) -> case erlang:function_exported(Plugin, Step, 2) of @@ -4694,7 +4910,8 @@ define dep_autopatch_rebar.erl fun() -> case lists:keyfind(plugins, 1, Conf) of false -> ok; - {_, Plugins} -> + {_, Plugins0} -> + Plugins = [P || P <- Plugins0, is_atom(P)], [begin case lists:keyfind(deps, 1, Conf) of false -> ok; @@ -4752,7 +4969,7 @@ define dep_autopatch_appsrc.erl {ok, [{application, $(1), L0}]} = file:consult(AppSrcIn), L1 = lists:keystore(modules, 1, L0, {modules, []}), L2 = case lists:keyfind(vsn, 1, L1) of - {_, git} -> lists:keyreplace(vsn, 1, L1, {vsn, "git"}); + {_, git} -> lists:keyreplace(vsn, 1, L1, {vsn, lists:droplast(os:cmd("git -C $(DEPS_DIR)/$1 describe --dirty --tags --always"))}); {_, {cmd, _}} -> lists:keyreplace(vsn, 1, L1, {vsn, "cmd"}); _ -> L1 end, @@ -4768,6 +4985,16 @@ define dep_fetch_git cd $(DEPS_DIR)/$(call dep_name,$(1)) && git checkout -q $(call dep_commit,$(1)); endef +define dep_fetch_git-subfolder + mkdir -p $(ERLANG_MK_TMP)/git-subfolder; \ + git clone -q -n -- $(call dep_repo,$1) \ + $(ERLANG_MK_TMP)/git-subfolder/$(call dep_name,$1); \ + cd $(ERLANG_MK_TMP)/git-subfolder/$(call dep_name,$1) \ + && git checkout -q $(call dep_commit,$1); \ + ln -s $(ERLANG_MK_TMP)/git-subfolder/$(call dep_name,$1)/$(word 4,$(dep_$(1))) \ + $(DEPS_DIR)/$(call dep_name,$1); +endef + define dep_fetch_git-submodule git submodule update --init -- $(DEPS_DIR)/$1; endef @@ -4793,7 +5020,7 @@ endef define dep_fetch_hex mkdir -p $(ERLANG_MK_TMP)/hex $(DEPS_DIR)/$1; \ $(call core_http_get,$(ERLANG_MK_TMP)/hex/$1.tar,\ - https://repo.hex.pm/tarballs/$1-$(strip $(word 2,$(dep_$1))).tar); \ + https://repo.hex.pm/tarballs/$(if $(word 3,$(dep_$1)),$(word 3,$(dep_$1)),$1)-$(strip $(word 2,$(dep_$1))).tar); \ tar -xOf $(ERLANG_MK_TMP)/hex/$1.tar contents.tar.gz | tar -C $(DEPS_DIR)/$1 -xzf -; endef @@ -4809,20 +5036,10 @@ define dep_fetch_legacy cd $(DEPS_DIR)/$(1) && git checkout -q $(if $(word 2,$(dep_$(1))),$(word 2,$(dep_$(1))),master); endef -define dep_fetch - $(if $(dep_$(1)), \ - $(if $(dep_fetch_$(word 1,$(dep_$(1)))), \ - $(word 1,$(dep_$(1))), \ - $(if $(IS_DEP),legacy,fail)), \ - $(if $(filter $(1),$(PACKAGES)), \ - $(pkg_$(1)_fetch), \ - fail)) -endef - define dep_target -$(DEPS_DIR)/$(call dep_name,$1): +$(DEPS_DIR)/$(call dep_name,$1): | $(ERLANG_MK_TMP) $(eval DEP_NAME := $(call dep_name,$1)) - $(eval DEP_STR := $(if $(filter-out $1,$(DEP_NAME)),$1,"$1 ($(DEP_NAME))")) + $(eval DEP_STR := $(if $(filter $1,$(DEP_NAME)),$1,"$1 ($(DEP_NAME))")) $(verbose) if test -d $(APPS_DIR)/$(DEP_NAME); then \ echo "Error: Dependency" $(DEP_STR) "conflicts with application found in $(APPS_DIR)/$(DEP_NAME)." >&2; \ exit 17; \ @@ -4831,7 +5048,7 @@ $(DEPS_DIR)/$(call dep_name,$1): $(dep_verbose) $(call dep_fetch_$(strip $(call dep_fetch,$(1))),$(1)) $(verbose) if [ -f $(DEPS_DIR)/$(1)/configure.ac -o -f $(DEPS_DIR)/$(1)/configure.in ] \ && [ ! -f $(DEPS_DIR)/$(1)/configure ]; then \ - echo " AUTO " $(1); \ + echo " AUTO " $(DEP_STR); \ cd $(DEPS_DIR)/$(1) && autoreconf -Wall -vif -I m4; \ fi - $(verbose) if [ -f $(DEPS_DIR)/$(DEP_NAME)/configure ]; then \ @@ -4839,6 +5056,12 @@ $(DEPS_DIR)/$(call dep_name,$1): cd $(DEPS_DIR)/$(DEP_NAME) && ./configure; \ fi ifeq ($(filter $(1),$(NO_AUTOPATCH)),) + $(verbose) $$(MAKE) --no-print-directory autopatch-$(DEP_NAME) +endif + +.PHONY: autopatch-$(call dep_name,$1) + +autopatch-$(call dep_name,$1):: $(verbose) if [ "$(1)" = "amqp_client" -a "$(RABBITMQ_CLIENT_PATCH)" ]; then \ if [ ! -d $(DEPS_DIR)/rabbitmq-codegen ]; then \ echo " PATCH Downloading rabbitmq-codegen"; \ @@ -4854,10 +5077,11 @@ ifeq ($(filter $(1),$(NO_AUTOPATCH)),) echo " PATCH Downloading rabbitmq-codegen"; \ git clone https://github.com/rabbitmq/rabbitmq-codegen.git $(DEPS_DIR)/rabbitmq-codegen; \ fi \ + elif [ "$1" = "elixir" -a "$(ELIXIR_PATCH)" ]; then \ + ln -s lib/elixir/ebin $(DEPS_DIR)/elixir/; \ else \ - $$(call dep_autopatch,$(DEP_NAME)) \ + $$(call dep_autopatch,$(call dep_name,$1)) \ fi -endif endef $(foreach dep,$(BUILD_DEPS) $(DEPS),$(eval $(call dep_target,$(dep)))) @@ -4894,36 +5118,11 @@ ERLANG_MK_RECURSIVE_REL_DEPS_LIST = $(ERLANG_MK_TMP)/recursive-rel-deps-list.log ERLANG_MK_RECURSIVE_TEST_DEPS_LIST = $(ERLANG_MK_TMP)/recursive-test-deps-list.log ERLANG_MK_RECURSIVE_SHELL_DEPS_LIST = $(ERLANG_MK_TMP)/recursive-shell-deps-list.log -# Copyright (c) 2015-2016, Loïc Hoguin <[email protected]> -# This file is part of erlang.mk and subject to the terms of the ISC License. - -# Verbosity. - -proto_verbose_0 = @echo " PROTO " $(filter %.proto,$(?F)); -proto_verbose = $(proto_verbose_$(V)) - -# Core targets. - -define compile_proto - $(verbose) mkdir -p ebin/ include/ - $(proto_verbose) $(call erlang,$(call compile_proto.erl,$(1))) - $(proto_verbose) erlc +debug_info -o ebin/ ebin/*.erl - $(verbose) rm ebin/*.erl -endef - -define compile_proto.erl - [begin - protobuffs_compile:generate_source(F, - [{output_include_dir, "./include"}, - {output_src_dir, "./ebin"}]) - end || F <- string:tokens("$(1)", " ")], - halt(). -endef - -ifneq ($(wildcard src/),) -ebin/$(PROJECT).app:: $(sort $(call core_find,src/,*.proto)) - $(if $(strip $?),$(call compile_proto,$?)) -endif +ERLANG_MK_QUERY_DEPS_FILE = $(ERLANG_MK_TMP)/query-deps.log +ERLANG_MK_QUERY_DOC_DEPS_FILE = $(ERLANG_MK_TMP)/query-doc-deps.log +ERLANG_MK_QUERY_REL_DEPS_FILE = $(ERLANG_MK_TMP)/query-rel-deps.log +ERLANG_MK_QUERY_TEST_DEPS_FILE = $(ERLANG_MK_TMP)/query-test-deps.log +ERLANG_MK_QUERY_SHELL_DEPS_FILE = $(ERLANG_MK_TMP)/query-shell-deps.log # Copyright (c) 2013-2016, Loïc Hoguin <[email protected]> # This file is part of erlang.mk and subject to the terms of the ISC License. @@ -4980,13 +5179,9 @@ ifneq ($(wildcard src/),) # Targets. -ifeq ($(wildcard ebin/test),) -app:: deps $(PROJECT).d +app:: $(if $(wildcard ebin/test),clean) deps + $(verbose) $(MAKE) --no-print-directory $(PROJECT).d $(verbose) $(MAKE) --no-print-directory app-build -else -app:: clean deps $(PROJECT).d - $(verbose) $(MAKE) --no-print-directory app-build -endif ifeq ($(wildcard src/$(PROJECT_MOD).erl),) define app_file @@ -5035,7 +5230,7 @@ define compile_asn1 $(verbose) mkdir -p include/ $(asn1_verbose) erlc -v -I include/ -o asn1/ +noobj $(ERLC_ASN1_OPTS) $(1) $(verbose) mv asn1/*.erl src/ - $(verbose) mv asn1/*.hrl include/ + -$(verbose) mv asn1/*.hrl include/ $(verbose) mv asn1/*.asn1db include/ endef @@ -5172,8 +5367,10 @@ define makedep.erl end, [begin Mod = list_to_atom(filename:basename(F, ".erl")), - {ok, Fd} = file:open(F, [read]), - MakeDepend(MakeDepend, Fd, Mod,0) + case file:open(F, [read]) of + {ok, Fd} -> MakeDepend(MakeDepend, Fd, Mod,0); + {error, enoent} -> ok + end end || F <- ErlFiles], Depend = sofs:to_external(sofs:relation_to_family(sofs:relation(ets:tab2list(E)))), CompileFirst = [X || X <- lists:reverse(digraph_utils:topsort(G)), [] =/= digraph:in_neighbours(G, X)], @@ -5185,10 +5382,11 @@ define makedep.erl string:join(DirSubname ++ [atom_to_list(Target)], "/") end end, - ok = file:write_file("$(1)", [ + ok = file:write_file("$(1)", unicode:characters_to_binary([ + "# Generated by Erlang.mk. Edit at your own risk!\n\n", [[F, "::", [[" ", D] || D <- Deps], "; @touch \$$@\n"] || {F, Deps} <- Depend], "\nCOMPILE_FIRST +=", [[" ", TargetPath(CF)] || CF <- CompileFirst], "\n" - ]), + ])), halt() endef @@ -5197,10 +5395,10 @@ $(PROJECT).d:: $(ERL_FILES) $(call core_find,include/,*.hrl) $(MAKEFILE_LIST) $(makedep_verbose) $(call erlang,$(call makedep.erl,$@)) endif +ifeq ($(IS_APP)$(IS_DEP),) ifneq ($(words $(ERL_FILES) $(CORE_FILES) $(ASN1_FILES) $(MIB_FILES) $(XRL_FILES) $(YRL_FILES)),0) # Rebuild everything when the Makefile changes. -$(ERLANG_MK_TMP)/last-makefile-change: $(MAKEFILE_LIST) - $(verbose) mkdir -p $(ERLANG_MK_TMP) +$(ERLANG_MK_TMP)/last-makefile-change: $(MAKEFILE_LIST) | $(ERLANG_MK_TMP) $(verbose) if test -f $@; then \ touch $(ERL_FILES) $(CORE_FILES) $(ASN1_FILES) $(MIB_FILES) $(XRL_FILES) $(YRL_FILES); \ touch -c $(PROJECT).d; \ @@ -5210,6 +5408,10 @@ $(ERLANG_MK_TMP)/last-makefile-change: $(MAKEFILE_LIST) $(ERL_FILES) $(CORE_FILES) $(ASN1_FILES) $(MIB_FILES) $(XRL_FILES) $(YRL_FILES):: $(ERLANG_MK_TMP)/last-makefile-change ebin/$(PROJECT).app:: $(ERLANG_MK_TMP)/last-makefile-change endif +endif + +$(PROJECT).d:: + $(verbose) : include $(wildcard $(PROJECT).d) @@ -5223,18 +5425,31 @@ define compile_erl -pa ebin/ -I include/ $(filter-out $(ERLC_EXCLUDE_PATHS),$(COMPILE_FIRST_PATHS) $(1)) endef +define validate_app_file + case file:consult("ebin/$(PROJECT).app") of + {ok, _} -> halt(); + _ -> halt(1) + end +endef + ebin/$(PROJECT).app:: $(ERL_FILES) $(CORE_FILES) $(wildcard src/$(PROJECT).app.src) $(eval FILES_TO_COMPILE := $(filter-out src/$(PROJECT).app.src,$?)) $(if $(strip $(FILES_TO_COMPILE)),$(call compile_erl,$(FILES_TO_COMPILE))) - $(eval GITDESCRIBE := $(shell git describe --dirty --abbrev=7 --tags --always --first-parent 2>/dev/null || true)) +# Older git versions do not have the --first-parent flag. Do without in that case. + $(eval GITDESCRIBE := $(shell git describe --dirty --abbrev=7 --tags --always --first-parent 2>/dev/null \ + || git describe --dirty --abbrev=7 --tags --always 2>/dev/null || true)) $(eval MODULES := $(patsubst %,'%',$(sort $(notdir $(basename \ $(filter-out $(ERLC_EXCLUDE_PATHS),$(ERL_FILES) $(CORE_FILES) $(BEAM_FILES))))))) ifeq ($(wildcard src/$(PROJECT).app.src),) $(app_verbose) printf '$(subst %,%%,$(subst $(newline),\n,$(subst ','\'',$(call app_file,$(GITDESCRIBE),$(MODULES)))))' \ > ebin/$(PROJECT).app + $(verbose) if ! $(call erlang,$(call validate_app_file)); then \ + echo "The .app file produced is invalid. Please verify the value of PROJECT_ENV." >&2; \ + exit 1; \ + fi else $(verbose) if [ -z "$$(grep -e '^[^%]*{\s*modules\s*,' src/$(PROJECT).app.src)" ]; then \ - echo "Empty modules entry not found in $(PROJECT).app.src. Please consult the erlang.mk README for instructions." >&2; \ + echo "Empty modules entry not found in $(PROJECT).app.src. Please consult the erlang.mk documentation for instructions." >&2; \ exit 1; \ fi $(appsrc_verbose) cat src/$(PROJECT).app.src \ @@ -5242,6 +5457,9 @@ else | sed "s/{id,[[:space:]]*\"git\"}/{id, \"$(subst /,\/,$(GITDESCRIBE))\"}/" \ > ebin/$(PROJECT).app endif +ifneq ($(wildcard src/$(PROJECT).appup),) + $(verbose) cp src/$(PROJECT).appup ebin/ +endif clean:: clean-app @@ -5317,29 +5535,50 @@ ifneq ($(SKIP_DEPS),) test-deps: else test-deps: $(ALL_TEST_DEPS_DIRS) - $(verbose) set -e; for dep in $(ALL_TEST_DEPS_DIRS) ; do $(MAKE) -C $$dep IS_DEP=1; done + $(verbose) set -e; for dep in $(ALL_TEST_DEPS_DIRS) ; do \ + if [ -z "$(strip $(FULL))" ] && [ ! -L $$dep ] && [ -f $$dep/ebin/dep_built ]; then \ + :; \ + else \ + $(MAKE) -C $$dep IS_DEP=1; \ + if [ ! -L $$dep ] && [ -d $$dep/ebin ]; then touch $$dep/ebin/dep_built; fi; \ + fi \ + done endif ifneq ($(wildcard $(TEST_DIR)),) test-dir: - $(gen_verbose) erlc -v $(TEST_ERLC_OPTS) -I include/ -o $(TEST_DIR) \ - $(call core_find,$(TEST_DIR)/,*.erl) -pa ebin/ + $(gen_verbose) erlc -v $(TEST_ERLC_OPTS) -o $(TEST_DIR) \ + -pa ebin/ -I include/ $(call core_find,$(TEST_DIR)/,*.erl) endif -ifeq ($(wildcard src),) +test-build:: IS_TEST=1 test-build:: ERLC_OPTS=$(TEST_ERLC_OPTS) -test-build:: clean deps test-deps +test-build:: $(if $(wildcard src),$(if $(wildcard ebin/test),,clean)) $(if $(IS_APP),,deps test-deps) +# We already compiled everything when IS_APP=1. +ifndef IS_APP +ifneq ($(wildcard src),) + $(verbose) $(MAKE) --no-print-directory $(PROJECT).d ERLC_OPTS="$(call escape_dquotes,$(TEST_ERLC_OPTS))" + $(verbose) $(MAKE) --no-print-directory app-build ERLC_OPTS="$(call escape_dquotes,$(TEST_ERLC_OPTS))" + $(gen_verbose) touch ebin/test +endif +ifneq ($(wildcard $(TEST_DIR)),) $(verbose) $(MAKE) --no-print-directory test-dir ERLC_OPTS="$(call escape_dquotes,$(TEST_ERLC_OPTS))" -else -ifeq ($(wildcard ebin/test),) -test-build:: ERLC_OPTS=$(TEST_ERLC_OPTS) -test-build:: clean deps test-deps $(PROJECT).d - $(verbose) $(MAKE) --no-print-directory app-build test-dir ERLC_OPTS="$(call escape_dquotes,$(TEST_ERLC_OPTS))" +endif +endif + +# Roughly the same as test-build, but when IS_APP=1. +# We only care about compiling the current application. +ifdef IS_APP +test-build-app:: ERLC_OPTS=$(TEST_ERLC_OPTS) +test-build-app:: deps test-deps +ifneq ($(wildcard src),) + $(verbose) $(MAKE) --no-print-directory $(PROJECT).d ERLC_OPTS="$(call escape_dquotes,$(TEST_ERLC_OPTS))" + $(verbose) $(MAKE) --no-print-directory app-build ERLC_OPTS="$(call escape_dquotes,$(TEST_ERLC_OPTS))" $(gen_verbose) touch ebin/test -else -test-build:: ERLC_OPTS=$(TEST_ERLC_OPTS) -test-build:: deps test-deps $(PROJECT).d - $(verbose) $(MAKE) --no-print-directory app-build test-dir ERLC_OPTS="$(call escape_dquotes,$(TEST_ERLC_OPTS))" +endif +ifneq ($(wildcard $(TEST_DIR)),) + $(verbose) $(MAKE) --no-print-directory test-dir ERLC_OPTS="$(call escape_dquotes,$(TEST_ERLC_OPTS))" +endif endif clean:: clean-test-dir @@ -5348,7 +5587,6 @@ clean-test-dir: ifneq ($(wildcard $(TEST_DIR)/*.beam),) $(gen_verbose) rm -f $(TEST_DIR)/*.beam endif -endif # Copyright (c) 2015-2016, Loïc Hoguin <[email protected]> # This file is part of erlang.mk and subject to the terms of the ISC License. @@ -5380,11 +5618,8 @@ $(call comma_list,$(foreach d,$(DEPS),\ {erl_opts, $(call compat_erlc_opts_to_list,$(ERLC_OPTS))}. endef -$(eval _compat_rebar_config = $$(compat_rebar_config)) -$(eval export _compat_rebar_config) - rebar.config: - $(gen_verbose) echo "$${_compat_rebar_config}" > rebar.config + $(gen_verbose) $(call core_render,compat_rebar_config,rebar.config) # Copyright (c) 2015-2016, Loïc Hoguin <[email protected]> # This file is part of erlang.mk and subject to the terms of the ISC License. @@ -5454,8 +5689,8 @@ endef asciidoc-manual:: doc-deps asciidoc-manual:: $(ASCIIDOC_MANUAL_FILES) - $(call erlang,$(call asciidoc2man.erl,$?)) - $(foreach s,$(MAN_SECTIONS),mkdir -p doc/man$s/ && mv doc/src/manual/*.$s.gz doc/man$s/;) + $(gen_verbose) $(call erlang,$(call asciidoc2man.erl,$?)) + $(verbose) $(foreach s,$(MAN_SECTIONS),mkdir -p doc/man$s/ && mv doc/src/manual/*.$s.gz doc/man$s/;) install-docs:: install-asciidoc @@ -5522,31 +5757,30 @@ endef # To prevent autocompletion issues with ZSH, we add "include erlang.mk" # separately during the actual bootstrap. -ifdef SP define bs_Makefile PROJECT = $p PROJECT_DESCRIPTION = New project PROJECT_VERSION = 0.1.0 - +$(if $(SP), # Whitespace to be used when creating files from templates. SP = $(SP) - +) endef -else -define bs_Makefile -PROJECT = $p -PROJECT_DESCRIPTION = New project -PROJECT_VERSION = 0.1.0 - -endef -endif define bs_apps_Makefile PROJECT = $p PROJECT_DESCRIPTION = New project PROJECT_VERSION = 0.1.0 +$(if $(SP), +# Whitespace to be used when creating files from templates. +SP = $(SP) +) +# Make sure we know where the applications are located. +ROOT_DIR ?= $(call core_relpath,$(dir $(ERLANG_MK_FILENAME)),$(APPS_DIR)/app) +APPS_DIR ?= .. +DEPS_DIR ?= $(call core_relpath,$(DEPS_DIR),$(APPS_DIR)/app) -include $(call core_relpath,$(dir $(ERLANG_MK_FILENAME)),$(APPS_DIR)/app)/erlang.mk +include $$(ROOT_DIR)/erlang.mk endef define bs_app @@ -5566,8 +5800,8 @@ endef define bs_relx_config {release, {$p_release, "1"}, [$p, sasl, runtime_tools]}. {extended_start_script, true}. -{sys_config, "rel/sys.config"}. -{vm_args, "rel/vm.args"}. +{sys_config, "config/sys.config"}. +{vm_args, "config/vm.args"}. endef define bs_sys_config @@ -5870,10 +6104,6 @@ endef # Plugin-specific targets. -define render_template - $(verbose) printf -- '$(subst $(newline),\n,$(subst %,%%,$(subst ','\'',$(subst $(tab),$(WS),$(call $(1))))))\n' > $(2) -endef - ifndef WS ifdef SP WS = $(subst a,,a $(wordlist 1,$(SP),a a a a a a a a a a a a a a a a a a a a)) @@ -5887,40 +6117,44 @@ ifneq ($(wildcard src/),) $(error Error: src/ directory already exists) endif $(eval p := $(PROJECT)) + $(if $(shell echo $p | LC_ALL=C grep -x "[a-z0-9_]*"),,\ + $(error Error: Invalid characters in the application name)) $(eval n := $(PROJECT)_sup) - $(call render_template,bs_Makefile,Makefile) + $(verbose) $(call core_render,bs_Makefile,Makefile) $(verbose) echo "include erlang.mk" >> Makefile $(verbose) mkdir src/ ifdef LEGACY - $(call render_template,bs_appsrc,src/$(PROJECT).app.src) + $(verbose) $(call core_render,bs_appsrc,src/$(PROJECT).app.src) endif - $(call render_template,bs_app,src/$(PROJECT)_app.erl) - $(call render_template,tpl_supervisor,src/$(PROJECT)_sup.erl) + $(verbose) $(call core_render,bs_app,src/$(PROJECT)_app.erl) + $(verbose) $(call core_render,tpl_supervisor,src/$(PROJECT)_sup.erl) bootstrap-lib: ifneq ($(wildcard src/),) $(error Error: src/ directory already exists) endif $(eval p := $(PROJECT)) - $(call render_template,bs_Makefile,Makefile) + $(if $(shell echo $p | LC_ALL=C grep -x "[a-z0-9_]*"),,\ + $(error Error: Invalid characters in the application name)) + $(verbose) $(call core_render,bs_Makefile,Makefile) $(verbose) echo "include erlang.mk" >> Makefile $(verbose) mkdir src/ ifdef LEGACY - $(call render_template,bs_appsrc_lib,src/$(PROJECT).app.src) + $(verbose) $(call core_render,bs_appsrc_lib,src/$(PROJECT).app.src) endif bootstrap-rel: ifneq ($(wildcard relx.config),) $(error Error: relx.config already exists) endif -ifneq ($(wildcard rel/),) - $(error Error: rel/ directory already exists) +ifneq ($(wildcard config/),) + $(error Error: config/ directory already exists) endif $(eval p := $(PROJECT)) - $(call render_template,bs_relx_config,relx.config) - $(verbose) mkdir rel/ - $(call render_template,bs_sys_config,rel/sys.config) - $(call render_template,bs_vm_args,rel/vm.args) + $(verbose) $(call core_render,bs_relx_config,relx.config) + $(verbose) mkdir config/ + $(verbose) $(call core_render,bs_sys_config,config/sys.config) + $(verbose) $(call core_render,bs_vm_args,config/vm.args) new-app: ifndef in @@ -5930,14 +6164,16 @@ ifneq ($(wildcard $(APPS_DIR)/$in),) $(error Error: Application $in already exists) endif $(eval p := $(in)) + $(if $(shell echo $p | LC_ALL=C grep -x "[a-z0-9_]*"),,\ + $(error Error: Invalid characters in the application name)) $(eval n := $(in)_sup) $(verbose) mkdir -p $(APPS_DIR)/$p/src/ - $(call render_template,bs_apps_Makefile,$(APPS_DIR)/$p/Makefile) + $(verbose) $(call core_render,bs_apps_Makefile,$(APPS_DIR)/$p/Makefile) ifdef LEGACY - $(call render_template,bs_appsrc,$(APPS_DIR)/$p/src/$p.app.src) + $(verbose) $(call core_render,bs_appsrc,$(APPS_DIR)/$p/src/$p.app.src) endif - $(call render_template,bs_app,$(APPS_DIR)/$p/src/$p_app.erl) - $(call render_template,tpl_supervisor,$(APPS_DIR)/$p/src/$p_sup.erl) + $(verbose) $(call core_render,bs_app,$(APPS_DIR)/$p/src/$p_app.erl) + $(verbose) $(call core_render,tpl_supervisor,$(APPS_DIR)/$p/src/$p_sup.erl) new-lib: ifndef in @@ -5947,10 +6183,12 @@ ifneq ($(wildcard $(APPS_DIR)/$in),) $(error Error: Application $in already exists) endif $(eval p := $(in)) + $(if $(shell echo $p | LC_ALL=C grep -x "[a-z0-9_]*"),,\ + $(error Error: Invalid characters in the application name)) $(verbose) mkdir -p $(APPS_DIR)/$p/src/ - $(call render_template,bs_apps_Makefile,$(APPS_DIR)/$p/Makefile) + $(verbose) $(call core_render,bs_apps_Makefile,$(APPS_DIR)/$p/Makefile) ifdef LEGACY - $(call render_template,bs_appsrc_lib,$(APPS_DIR)/$p/src/$p.app.src) + $(verbose) $(call core_render,bs_appsrc_lib,$(APPS_DIR)/$p/src/$p.app.src) endif new: @@ -5964,9 +6202,9 @@ ifndef n $(error Usage: $(MAKE) new t=TEMPLATE n=NAME [in=APP]) endif ifdef in - $(call render_template,tpl_$(t),$(APPS_DIR)/$(in)/src/$(n).erl) + $(verbose) $(call core_render,tpl_$(t),$(APPS_DIR)/$(in)/src/$(n).erl) else - $(call render_template,tpl_$(t),src/$(n).erl) + $(verbose) $(call core_render,tpl_$(t),src/$(n).erl) endif list-templates: @@ -6010,8 +6248,8 @@ ifeq ($(PLATFORM),msys2) CXXFLAGS ?= -O3 -finline-functions -Wall else ifeq ($(PLATFORM),darwin) CC ?= cc - CFLAGS ?= -O3 -std=c99 -arch x86_64 -finline-functions -Wall -Wmissing-prototypes - CXXFLAGS ?= -O3 -arch x86_64 -finline-functions -Wall + CFLAGS ?= -O3 -std=c99 -arch x86_64 -Wall -Wmissing-prototypes + CXXFLAGS ?= -O3 -arch x86_64 -Wall LDFLAGS ?= -arch x86_64 -flat_namespace -undefined suppress else ifeq ($(PLATFORM),freebsd) CC ?= cc @@ -6031,7 +6269,7 @@ endif CFLAGS += -I"$(ERTS_INCLUDE_DIR)" -I"$(ERL_INTERFACE_INCLUDE_DIR)" CXXFLAGS += -I"$(ERTS_INCLUDE_DIR)" -I"$(ERL_INTERFACE_INCLUDE_DIR)" -LDLIBS += -L"$(ERL_INTERFACE_LIB_DIR)" -lerl_interface -lei +LDLIBS += -L"$(ERL_INTERFACE_LIB_DIR)" -lei # Verbosity. @@ -6073,11 +6311,13 @@ app:: $(C_SRC_ENV) $(C_SRC_OUTPUT_FILE) test-build:: $(C_SRC_ENV) $(C_SRC_OUTPUT_FILE) $(C_SRC_OUTPUT_FILE): $(OBJECTS) - $(verbose) mkdir -p priv/ + $(verbose) mkdir -p $(dir $@) $(link_verbose) $(CC) $(OBJECTS) \ $(LDFLAGS) $(if $(filter $(C_SRC_TYPE),shared),-shared) $(LDLIBS) \ -o $(C_SRC_OUTPUT_FILE) +$(OBJECTS): $(MAKEFILE_LIST) $(C_SRC_ENV) + %.o: %.c $(COMPILE_C) $(OUTPUT_OPTION) $< @@ -6098,12 +6338,16 @@ clean-c_src: endif ifneq ($(wildcard $(C_SRC_DIR)),) +ERL_ERTS_DIR = $(shell $(ERL) -eval 'io:format("~s~n", [code:lib_dir(erts)]), halt().') + $(C_SRC_ENV): $(verbose) $(ERL) -eval "file:write_file(\"$(call core_native_path,$(C_SRC_ENV))\", \ io_lib:format( \ + \"# Generated by Erlang.mk. Edit at your own risk!~n~n\" \ \"ERTS_INCLUDE_DIR ?= ~s/erts-~s/include/~n\" \ \"ERL_INTERFACE_INCLUDE_DIR ?= ~s~n\" \ - \"ERL_INTERFACE_LIB_DIR ?= ~s~n\", \ + \"ERL_INTERFACE_LIB_DIR ?= ~s~n\" \ + \"ERTS_DIR ?= $(ERL_ERTS_DIR)~n\", \ [code:root_dir(), erlang:system_info(version), \ code:lib_dir(erl_interface, include), \ code:lib_dir(erl_interface, lib)])), \ @@ -6115,6 +6359,10 @@ distclean-c_src-env: $(gen_verbose) rm -f $(C_SRC_ENV) -include $(C_SRC_ENV) + +ifneq ($(ERL_ERTS_DIR),$(ERTS_DIR)) +$(shell rm -f $(C_SRC_ENV)) +endif endif # Templates. @@ -6200,12 +6448,15 @@ endif ifneq ($(wildcard src/$n.erl),) $(error Error: src/$n.erl already exists) endif +ifndef n + $(error Usage: $(MAKE) new-nif n=NAME [in=APP]) +endif ifdef in $(verbose) $(MAKE) -C $(APPS_DIR)/$(in)/ new-nif n=$n in= else $(verbose) mkdir -p $(C_SRC_DIR) src/ - $(call render_template,bs_c_nif,$(C_SRC_DIR)/$n.c) - $(call render_template,bs_erl_nif,src/$n.erl) + $(verbose) $(call core_render,bs_c_nif,$(C_SRC_DIR)/$n.c) + $(verbose) $(call core_render,bs_erl_nif,src/$n.erl) endif # Copyright (c) 2015-2017, Loïc Hoguin <[email protected]> @@ -6234,15 +6485,17 @@ ci:: $(addprefix ci-,$(CI_OTP) $(addsuffix -native,$(CI_HIPE)) $(addsuffix -erll ci-prepare: $(addprefix $(KERL_INSTALL_DIR)/,$(CI_OTP) $(addsuffix -native,$(CI_HIPE))) ci-setup:: + $(verbose) : ci-extra:: + $(verbose) : ci_verbose_0 = @echo " CI " $(1); ci_verbose = $(ci_verbose_$(V)) define ci_target ci-$1: $(KERL_INSTALL_DIR)/$2 - $(verbose) $(MAKE) --no-print-directory clean distclean-c_src-env + $(verbose) $(MAKE) --no-print-directory clean $(ci_verbose) \ PATH="$(KERL_INSTALL_DIR)/$2/bin:$(PATH)" \ CI_OTP_RELEASE="$1" \ @@ -6256,8 +6509,8 @@ $(foreach otp,$(CI_OTP),$(eval $(call ci_target,$(otp),$(otp),otp))) $(foreach otp,$(CI_HIPE),$(eval $(call ci_target,$(otp)-native,$(otp)-native,native))) $(foreach otp,$(CI_ERLLVM),$(eval $(call ci_target,$(otp)-erllvm,$(otp)-native,erllvm))) -$(foreach otp,$(CI_OTP),$(eval $(call kerl_otp_target,$(otp)))) -$(foreach otp,$(sort $(CI_HIPE) $(CI_ERLLLVM)),$(eval $(call kerl_hipe_target,$(otp)))) +$(foreach otp,$(filter-out $(ERLANG_OTP),$(CI_OTP)),$(eval $(call kerl_otp_target,$(otp)))) +$(foreach otp,$(filter-out $(ERLANG_HIPE),$(sort $(CI_HIPE) $(CI_ERLLLVM))),$(eval $(call kerl_hipe_target,$(otp)))) help:: $(verbose) printf "%s\n" "" \ @@ -6290,7 +6543,9 @@ CT_LOGS_DIR ?= $(CURDIR)/logs tests:: ct +ifndef KEEP_LOGS distclean:: distclean-ct +endif help:: $(verbose) printf "%s\n" "" \ @@ -6305,16 +6560,16 @@ help:: CT_RUN = ct_run \ -no_auto_compile \ -noinput \ - -pa $(CURDIR)/ebin $(DEPS_DIR)/*/ebin $(APPS_DIR)/*/ebin $(TEST_DIR) \ + -pa $(CURDIR)/ebin $(TEST_DIR) \ -dir $(TEST_DIR) \ -logdir $(CT_LOGS_DIR) ifeq ($(CT_SUITES),) -ct: $(if $(IS_APP),,apps-ct) +ct: $(if $(IS_APP)$(ROOT_DIR),,apps-ct) else # We do not run tests if we are in an apps/* with no test directory. ifneq ($(IS_APP)$(wildcard $(TEST_DIR)),1) -ct: test-build $(if $(IS_APP),,apps-ct) +ct: test-build $(if $(IS_APP)$(ROOT_DIR),,apps-ct) $(verbose) mkdir -p $(CT_LOGS_DIR) $(gen_verbose) $(CT_RUN) -sname ct_$(PROJECT) -suite $(addsuffix _SUITE,$(CT_SUITES)) $(CT_OPTS) endif @@ -6322,30 +6577,34 @@ endif ifneq ($(ALL_APPS_DIRS),) define ct_app_target -apps-ct-$1: - $(MAKE) -C $1 ct IS_APP=1 +apps-ct-$1: test-build + $$(MAKE) -C $1 ct IS_APP=1 endef $(foreach app,$(ALL_APPS_DIRS),$(eval $(call ct_app_target,$(app)))) -apps-ct: test-build $(addprefix apps-ct-,$(ALL_APPS_DIRS)) +apps-ct: $(addprefix apps-ct-,$(ALL_APPS_DIRS)) endif -ifndef t -CT_EXTRA = -else +ifdef t ifeq (,$(findstring :,$t)) CT_EXTRA = -group $t else t_words = $(subst :, ,$t) CT_EXTRA = -group $(firstword $(t_words)) -case $(lastword $(t_words)) endif +else +ifdef c +CT_EXTRA = -case $c +else +CT_EXTRA = +endif endif define ct_suite_target ct-$(1): test-build $(verbose) mkdir -p $(CT_LOGS_DIR) - $(gen_verbose) $(CT_RUN) -sname ct_$(PROJECT) -suite $(addsuffix _SUITE,$(1)) $(CT_EXTRA) $(CT_OPTS) + $(gen_verbose_esc) $(CT_RUN) -sname ct_$(PROJECT) -suite $(addsuffix _SUITE,$(1)) $(CT_EXTRA) $(CT_OPTS) endef $(foreach test,$(CT_SUITES),$(eval $(call ct_suite_target,$(test)))) @@ -6397,11 +6656,17 @@ define filter_opts.erl halt(). endef +# DIALYZER_PLT is a variable understood directly by Dialyzer. +# +# We append the path to erts at the end of the PLT. This works +# because the PLT file is in the external term format and the +# function binary_to_term/1 ignores any trailing data. $(DIALYZER_PLT): deps app $(eval DEPS_LOG := $(shell test -f $(ERLANG_MK_TMP)/deps.log && \ while read p; do test -d $$p/ebin && echo $$p/ebin; done <$(ERLANG_MK_TMP)/deps.log)) $(verbose) dialyzer --build_plt $(DIALYZER_PLT_OPTS) --apps \ erts kernel stdlib $(PLT_APPS) $(OTP_DEPS) $(LOCAL_DEPS) $(DEPS_LOG) || test $$? -eq 2 + $(verbose) $(ERL) -eval 'io:format("~n~s~n", [code:lib_dir(erts)]), halt().' >> $@ plt: $(DIALYZER_PLT) @@ -6409,11 +6674,18 @@ distclean-plt: $(gen_verbose) rm -f $(DIALYZER_PLT) ifneq ($(wildcard $(DIALYZER_PLT)),) -dialyze: +dialyze: $(if $(filter --src,$(DIALYZER_DIRS)),,deps app) + $(verbose) if ! tail -n1 $(DIALYZER_PLT) | \ + grep -q "^`$(ERL) -eval 'io:format("~s", [code:lib_dir(erts)]), halt().'`$$"; then \ + rm $(DIALYZER_PLT); \ + $(MAKE) plt; \ + fi else dialyze: $(DIALYZER_PLT) endif - $(verbose) dialyzer --no_native `$(ERL) -eval "$(subst $(newline),,$(call escape_dquotes,$(call filter_opts.erl)))" -extra $(ERLC_OPTS)` $(DIALYZER_DIRS) $(DIALYZER_OPTS) + $(verbose) dialyzer --no_native `$(ERL) \ + -eval "$(subst $(newline),,$(call escape_dquotes,$(call filter_opts.erl)))" \ + -extra $(ERLC_OPTS)` $(DIALYZER_DIRS) $(DIALYZER_OPTS) $(if $(wildcard ebin/),-pa ebin/) # Copyright (c) 2013-2016, Loïc Hoguin <[email protected]> # This file is part of erlang.mk and subject to the terms of the ISC License. @@ -6429,7 +6701,7 @@ EDOC_OUTPUT ?= doc define edoc.erl SrcPaths = lists:foldl(fun(P, Acc) -> filelib:wildcard(atom_to_list(P) ++ "/{src,c_src}") ++ Acc - end, [], [$(call comma_list,$(patsubst %,'%',$(EDOC_SRC_DIRS)))]), + end, [], [$(call comma_list,$(patsubst %,'%',$(call core_native_path,$(EDOC_SRC_DIRS))))]), DefaultOpts = [{dir, "$(EDOC_OUTPUT)"}, {source_path, SrcPaths}, {subpackages, false}], edoc:application($(1), ".", [$(2)] ++ DefaultOpts), halt(0). @@ -6458,6 +6730,7 @@ distclean-edoc: DTL_FULL_PATH ?= DTL_PATH ?= templates/ +DTL_PREFIX ?= DTL_SUFFIX ?= _dtl DTL_OPTS ?= @@ -6473,18 +6746,17 @@ DTL_FILES := $(sort $(call core_find,$(DTL_PATH),*.dtl)) ifneq ($(DTL_FILES),) -DTL_NAMES = $(addsuffix $(DTL_SUFFIX),$(DTL_FILES:$(DTL_PATH)/%.dtl=%)) +DTL_NAMES = $(addprefix $(DTL_PREFIX),$(addsuffix $(DTL_SUFFIX),$(DTL_FILES:$(DTL_PATH)/%.dtl=%))) DTL_MODULES = $(if $(DTL_FULL_PATH),$(subst /,_,$(DTL_NAMES)),$(notdir $(DTL_NAMES))) BEAM_FILES += $(addsuffix .beam,$(addprefix ebin/,$(DTL_MODULES))) ifneq ($(words $(DTL_FILES)),0) # Rebuild templates when the Makefile changes. -$(ERLANG_MK_TMP)/last-makefile-change-erlydtl: $(MAKEFILE_LIST) - @mkdir -p $(ERLANG_MK_TMP) - @if test -f $@; then \ +$(ERLANG_MK_TMP)/last-makefile-change-erlydtl: $(MAKEFILE_LIST) | $(ERLANG_MK_TMP) + $(verbose) if test -f $@; then \ touch $(DTL_FILES); \ fi - @touch $@ + $(verbose) touch $@ ebin/$(PROJECT).app:: $(ERLANG_MK_TMP)/last-makefile-change-erlydtl endif @@ -6495,10 +6767,10 @@ define erlydtl_compile.erl "" -> filename:basename(F, ".dtl"); _ -> - "$(DTL_PATH)/" ++ F2 = filename:rootname(F, ".dtl"), + "$(call core_native_path,$(DTL_PATH))/" ++ F2 = filename:rootname(F, ".dtl"), re:replace(F2, "/", "_", [{return, list}, global]) end, - Module = list_to_atom(string:to_lower(Module0) ++ "$(DTL_SUFFIX)"), + Module = list_to_atom("$(DTL_PREFIX)" ++ string:to_lower(Module0) ++ "$(DTL_SUFFIX)"), case erlydtl:compile(F, Module, [$(DTL_OPTS)] ++ [{out_dir, "ebin/"}, return_errors]) of ok -> ok; {ok, _} -> ok @@ -6510,7 +6782,7 @@ endef ebin/$(PROJECT).app:: $(DTL_FILES) | ebin/ $(if $(strip $?),\ $(dtl_verbose) $(call erlang,$(call erlydtl_compile.erl,$(call core_native_path,$?)),\ - -pa ebin/ $(DEPS_DIR)/erlydtl/ebin/)) + -pa ebin/)) endif @@ -6543,13 +6815,15 @@ help:: # Plugin-specific targets. +escript-zip:: FULL=1 escript-zip:: deps app $(verbose) mkdir -p $(dir $(ESCRIPT_ZIP)) $(verbose) rm -f $(ESCRIPT_ZIP_FILE) $(gen_verbose) cd .. && $(ESCRIPT_ZIP) $(ESCRIPT_ZIP_FILE) $(PROJECT)/ebin/* ifneq ($(DEPS),) $(verbose) cd $(DEPS_DIR) && $(ESCRIPT_ZIP) $(ESCRIPT_ZIP_FILE) \ - `cat $(ERLANG_MK_TMP)/deps.log | sed 's/^$(subst /,\/,$(DEPS_DIR))\///' | sed 's/$$/\/ebin\/\*/'` + $(subst $(DEPS_DIR)/,,$(addsuffix /*,$(wildcard \ + $(addsuffix /ebin,$(shell cat $(ERLANG_MK_TMP)/deps.log))))) endif escript:: escript-zip @@ -6586,32 +6860,17 @@ help:: # Plugin-specific targets. define eunit.erl - Enabled = case "$(COVER)" of - "" -> false; - _ -> - case filelib:is_dir("ebin") of - false -> false; - true -> - case cover:compile_beam_directory("ebin") of - {error, _} -> halt(1); - _ -> true - end - end - end, + $(call cover.erl) + CoverSetup(), case eunit:test($1, [$(EUNIT_OPTS)]) of ok -> ok; error -> halt(2) end, - case {Enabled, "$(COVER)"} of - {false, _} -> ok; - {_, ""} -> ok; - _ -> - cover:export("$(COVER_DATA_DIR)/eunit.coverdata") - end, + CoverExport("$(call core_native_path,$(COVER_DATA_DIR))/eunit.coverdata"), halt() endef -EUNIT_ERL_OPTS += -pa $(TEST_DIR) $(DEPS_DIR)/*/ebin $(APPS_DIR)/*/ebin $(CURDIR)/ebin +EUNIT_ERL_OPTS += -pa $(TEST_DIR) $(CURDIR)/ebin ifdef t ifeq (,$(findstring :,$(t))) @@ -6628,11 +6887,13 @@ EUNIT_TEST_MODS = $(notdir $(basename $(call core_find,$(TEST_DIR)/,*.erl))) EUNIT_MODS = $(foreach mod,$(EUNIT_EBIN_MODS) $(filter-out \ $(patsubst %,%_tests,$(EUNIT_EBIN_MODS)),$(EUNIT_TEST_MODS)),'$(mod)') -eunit: test-build $(if $(IS_APP),,apps-eunit) cover-data-dir +eunit: test-build $(if $(IS_APP)$(ROOT_DIR),,apps-eunit) cover-data-dir +ifneq ($(wildcard src/ $(TEST_DIR)),) $(gen_verbose) $(call erlang,$(call eunit.erl,[$(call comma_list,$(EUNIT_MODS))]),$(EUNIT_ERL_OPTS)) +endif ifneq ($(ALL_APPS_DIRS),) -apps-eunit: +apps-eunit: test-build $(verbose) eunit_retcode=0 ; for app in $(ALL_APPS_DIRS); do $(MAKE) -C $$app eunit IS_APP=1; \ [ $$? -ne 0 ] && eunit_retcode=1 ; done ; \ exit $$eunit_retcode @@ -6650,6 +6911,7 @@ ifeq ($(filter proper,$(DEPS) $(TEST_DEPS)),proper) tests:: proper define proper_check.erl + $(call cover.erl) code:add_pathsa([ "$(call core_native_path,$(CURDIR)/ebin)", "$(call core_native_path,$(DEPS_DIR)/*/ebin)", @@ -6665,13 +6927,16 @@ define proper_check.erl end || {F, 0} <- M:module_info(exports)]) end, - try - case $(1) of + try begin + CoverSetup(), + Res = case $(1) of all -> [true] =:= lists:usort([Module(M) || M <- [$(call comma_list,$(3))]]); module -> Module($(2)); function -> proper:quickcheck($(2), nocolors) - end - of + end, + CoverExport("$(COVER_DATA_DIR)/proper.coverdata"), + Res + end of true -> halt(0); _ -> halt(1) catch error:undef -> @@ -6682,21 +6947,81 @@ endef ifdef t ifeq (,$(findstring :,$(t))) -proper: test-build +proper: test-build cover-data-dir $(verbose) $(call erlang,$(call proper_check.erl,module,$(t))) else -proper: test-build +proper: test-build cover-data-dir $(verbose) echo Testing $(t)/0 $(verbose) $(call erlang,$(call proper_check.erl,function,$(t)())) endif else -proper: test-build +proper: test-build cover-data-dir $(eval MODULES := $(patsubst %,'%',$(sort $(notdir $(basename \ $(wildcard ebin/*.beam) $(call core_find,$(TEST_DIR)/,*.beam)))))) $(gen_verbose) $(call erlang,$(call proper_check.erl,all,undefined,$(MODULES))) endif endif +# Copyright (c) 2015-2016, Loïc Hoguin <[email protected]> +# This file is part of erlang.mk and subject to the terms of the ISC License. + +# Verbosity. + +proto_verbose_0 = @echo " PROTO " $(filter %.proto,$(?F)); +proto_verbose = $(proto_verbose_$(V)) + +# Core targets. + +ifneq ($(wildcard src/),) +ifneq ($(filter gpb protobuffs,$(BUILD_DEPS) $(DEPS)),) +PROTO_FILES := $(filter %.proto,$(ALL_SRC_FILES)) +ERL_FILES += $(addprefix src/,$(patsubst %.proto,%_pb.erl,$(notdir $(PROTO_FILES)))) + +ifeq ($(PROTO_FILES),) +$(ERLANG_MK_TMP)/last-makefile-change-protobuffs: + $(verbose) : +else +# Rebuild proto files when the Makefile changes. +# We exclude $(PROJECT).d to avoid a circular dependency. +$(ERLANG_MK_TMP)/last-makefile-change-protobuffs: $(filter-out $(PROJECT).d,$(MAKEFILE_LIST)) | $(ERLANG_MK_TMP) + $(verbose) if test -f $@; then \ + touch $(PROTO_FILES); \ + fi + $(verbose) touch $@ + +$(PROJECT).d:: $(ERLANG_MK_TMP)/last-makefile-change-protobuffs +endif + +ifeq ($(filter gpb,$(BUILD_DEPS) $(DEPS)),) +define compile_proto.erl + [begin + protobuffs_compile:generate_source(F, [ + {output_include_dir, "./include"}, + {output_src_dir, "./src"}]) + end || F <- string:tokens("$1", " ")], + halt(). +endef +else +define compile_proto.erl + [begin + gpb_compile:file(F, [ + {include_as_lib, true}, + {module_name_suffix, "_pb"}, + {o_hrl, "./include"}, + {o_erl, "./src"}]) + end || F <- string:tokens("$1", " ")], + halt(). +endef +endif + +ifneq ($(PROTO_FILES),) +$(PROJECT).d:: $(PROTO_FILES) + $(verbose) mkdir -p ebin/ include/ + $(if $(strip $?),$(proto_verbose) $(call erlang,$(call compile_proto.erl,$?))) +endif +endif +endif + # Copyright (c) 2013-2016, Loïc Hoguin <[email protected]> # This file is part of erlang.mk and subject to the terms of the ISC License. @@ -6707,7 +7032,7 @@ endif RELX ?= $(ERLANG_MK_TMP)/relx RELX_CONFIG ?= $(CURDIR)/relx.config -RELX_URL ?= https://erlang.mk/res/relx-v3.26.0 +RELX_URL ?= https://erlang.mk/res/relx-v3.27.0 RELX_OPTS ?= RELX_OUTPUT_DIR ?= _rel RELX_REL_EXT ?= @@ -6737,20 +7062,29 @@ distclean:: distclean-relx-rel # Plugin-specific targets. -$(RELX): - $(verbose) mkdir -p $(ERLANG_MK_TMP) +$(RELX): | $(ERLANG_MK_TMP) $(gen_verbose) $(call core_http_get,$(RELX),$(RELX_URL)) $(verbose) chmod +x $(RELX) relx-rel: $(RELX) rel-deps app - $(verbose) $(RELX) -c $(RELX_CONFIG) $(RELX_OPTS) release $(if $(filter 1,$(RELX_TAR)),tar) + $(verbose) $(RELX) $(if $(filter 1,$V),-V 3) -c $(RELX_CONFIG) $(RELX_OPTS) release + $(verbose) $(MAKE) relx-post-rel +ifeq ($(RELX_TAR),1) + $(verbose) $(RELX) $(if $(filter 1,$V),-V 3) -c $(RELX_CONFIG) $(RELX_OPTS) tar +endif relx-relup: $(RELX) rel-deps app - $(verbose) $(RELX) -c $(RELX_CONFIG) $(RELX_OPTS) release relup $(if $(filter 1,$(RELX_TAR)),tar) + $(verbose) $(RELX) $(if $(filter 1,$V),-V 3) -c $(RELX_CONFIG) $(RELX_OPTS) release + $(MAKE) relx-post-rel + $(verbose) $(RELX) $(if $(filter 1,$V),-V 3) -c $(RELX_CONFIG) $(RELX_OPTS) relup $(if $(filter 1,$(RELX_TAR)),tar) distclean-relx-rel: $(gen_verbose) rm -rf $(RELX_OUTPUT_DIR) +# Default hooks. +relx-post-rel:: + $(verbose) : + # Run target. ifeq ($(wildcard $(RELX_CONFIG)),) @@ -6766,20 +7100,25 @@ define get_relx_release.erl {semver, _} -> ""; VsnStr -> Vsn0 end, - io:format("~s ~s", [Name, Vsn]), + Extended = case lists:keyfind(extended_start_script, 1, Config) of + {_, true} -> "1"; + _ -> "" + end, + io:format("~s ~s ~s", [Name, Vsn, Extended]), halt(0). endef RELX_REL := $(shell $(call erlang,$(get_relx_release.erl))) RELX_REL_NAME := $(word 1,$(RELX_REL)) RELX_REL_VSN := $(word 2,$(RELX_REL)) +RELX_REL_CMD := $(if $(word 3,$(RELX_REL)),console) ifeq ($(PLATFORM),msys2) RELX_REL_EXT := .cmd endif run:: all - $(verbose) $(RELX_OUTPUT_DIR)/$(RELX_REL_NAME)/bin/$(RELX_REL_NAME)$(RELX_REL_EXT) console + $(verbose) $(RELX_OUTPUT_DIR)/$(RELX_REL_NAME)/bin/$(RELX_REL_NAME)$(RELX_REL_EXT) $(RELX_REL_CMD) ifdef RELOAD rel:: @@ -6804,7 +7143,7 @@ endif # Configuration. SHELL_ERL ?= erl -SHELL_PATHS ?= $(CURDIR)/ebin $(APPS_DIR)/*/ebin $(DEPS_DIR)/*/ebin $(TEST_DIR) +SHELL_PATHS ?= $(CURDIR)/ebin $(TEST_DIR) SHELL_OPTS ?= ALL_SHELL_DEPS_DIRS = $(addprefix $(DEPS_DIR)/,$(SHELL_DEPS)) @@ -6820,10 +7159,21 @@ help:: $(foreach dep,$(SHELL_DEPS),$(eval $(call dep_target,$(dep)))) +ifneq ($(SKIP_DEPS),) +build-shell-deps: +else build-shell-deps: $(ALL_SHELL_DEPS_DIRS) - $(verbose) set -e; for dep in $(ALL_SHELL_DEPS_DIRS) ; do $(MAKE) -C $$dep ; done + $(verbose) set -e; for dep in $(ALL_SHELL_DEPS_DIRS) ; do \ + if [ -z "$(strip $(FULL))" ] && [ ! -L $$dep ] && [ -f $$dep/ebin/dep_built ]; then \ + :; \ + else \ + $(MAKE) -C $$dep IS_DEP=1; \ + if [ ! -L $$dep ] && [ -d $$dep/ebin ]; then touch $$dep/ebin/dep_built; fi; \ + fi \ + done +endif -shell: build-shell-deps +shell:: build-shell-deps $(gen_verbose) $(SHELL_ERL) -pa $(SHELL_PATHS) $(SHELL_OPTS) # Copyright 2017, Stanislaw Klekot <[email protected]> @@ -6914,17 +7264,21 @@ ifeq ($(filter triq,$(DEPS) $(TEST_DEPS)),triq) tests:: triq define triq_check.erl + $(call cover.erl) code:add_pathsa([ "$(call core_native_path,$(CURDIR)/ebin)", "$(call core_native_path,$(DEPS_DIR)/*/ebin)", "$(call core_native_path,$(TEST_DIR))"]), - try - case $(1) of + try begin + CoverSetup(), + Res = case $(1) of all -> [true] =:= lists:usort([triq:check(M) || M <- [$(call comma_list,$(3))]]); module -> triq:check($(2)); function -> triq:check($(2)) - end - of + end, + CoverExport("$(COVER_DATA_DIR)/triq.coverdata"), + Res + end of true -> halt(0); _ -> halt(1) catch error:undef -> @@ -6935,15 +7289,15 @@ endef ifdef t ifeq (,$(findstring :,$(t))) -triq: test-build +triq: test-build cover-data-dir $(verbose) $(call erlang,$(call triq_check.erl,module,$(t))) else -triq: test-build +triq: test-build cover-data-dir $(verbose) echo Testing $(t)/0 $(verbose) $(call erlang,$(call triq_check.erl,function,$(t)())) endif else -triq: test-build +triq: test-build cover-data-dir $(eval MODULES := $(patsubst %,'%',$(sort $(notdir $(basename \ $(wildcard ebin/*.beam) $(call core_find,$(TEST_DIR)/,*.beam)))))) $(gen_verbose) $(call erlang,$(call triq_check.erl,all,undefined,$(MODULES))) @@ -6995,9 +7349,14 @@ distclean-xref: # This file is part of erlang.mk and subject to the terms of the ISC License. COVER_REPORT_DIR ?= cover -COVER_DATA_DIR ?= $(CURDIR) +COVER_DATA_DIR ?= $(COVER_REPORT_DIR) + +ifdef COVER +COVER_APPS ?= $(notdir $(ALL_APPS_DIRS)) +COVER_DEPS ?= +endif -# Hook in coverage to ct +# Code coverage for Common Test. ifdef COVER ifdef CT_RUN @@ -7007,13 +7366,44 @@ test-build:: $(TEST_DIR)/ct.cover.spec $(TEST_DIR)/ct.cover.spec: cover-data-dir $(gen_verbose) printf "%s\n" \ "{incl_app, '$(PROJECT)', details}." \ - '{export,"$(abspath $(COVER_DATA_DIR))/ct.coverdata"}.' > $@ + "{incl_dirs, '$(PROJECT)', [\"$(call core_native_path,$(CURDIR)/ebin)\" \ + $(foreach a,$(COVER_APPS),$(comma) \"$(call core_native_path,$(APPS_DIR)/$a/ebin)\") \ + $(foreach d,$(COVER_DEPS),$(comma) \"$(call core_native_path,$(DEPS_DIR)/$d/ebin)\")]}." \ + '{export,"$(call core_native_path,$(abspath $(COVER_DATA_DIR))/ct.coverdata)"}.' > $@ CT_RUN += -cover $(TEST_DIR)/ct.cover.spec endif endif endif +# Code coverage for other tools. + +ifdef COVER +define cover.erl + CoverSetup = fun() -> + Dirs = ["$(call core_native_path,$(CURDIR)/ebin)" + $(foreach a,$(COVER_APPS),$(comma) "$(call core_native_path,$(APPS_DIR)/$a/ebin)") + $(foreach d,$(COVER_DEPS),$(comma) "$(call core_native_path,$(DEPS_DIR)/$d/ebin)")], + [begin + case filelib:is_dir(Dir) of + false -> false; + true -> + case cover:compile_beam_directory(Dir) of + {error, _} -> halt(1); + _ -> true + end + end + end || Dir <- Dirs] + end, + CoverExport = fun(Filename) -> cover:export(Filename) end, +endef +else +define cover.erl + CoverSetup = fun() -> ok end, + CoverExport = fun(_) -> ok end, +endef +endif + # Core targets ifdef COVER @@ -7073,7 +7463,9 @@ ifneq ($(COVER_REPORT_DIR),) cover-report-clean: $(gen_verbose) rm -rf $(COVER_REPORT_DIR) +ifneq ($(COVER_REPORT_DIR),$(COVER_DATA_DIR)) $(if $(shell ls -A $(COVER_DATA_DIR)/),,$(verbose) rmdir $(COVER_DATA_DIR)) +endif ifeq ($(COVERDATA),) cover-report: @@ -7163,7 +7555,7 @@ __ARCHIVE_BELOW__ endef sfx: - $(call render_template,sfx_stub,$(SFX_OUTPUT_FILE)) + $(verbose) $(call core_render,sfx_stub,$(SFX_OUTPUT_FILE)) $(gen_verbose) cat $(SFX_ARCHIVE) >> $(SFX_OUTPUT_FILE) $(verbose) chmod +x $(SFX_OUTPUT_FILE) @@ -7182,6 +7574,11 @@ $(foreach p,$(DEP_PLUGINS),\ $(call core_dep_plugin,$p,$(firstword $(subst /, ,$p))),\ $(call core_dep_plugin,$p/plugins.mk,$p)))) +help:: help-plugins + +help-plugins:: + $(verbose) : + # Copyright (c) 2013-2015, Loïc Hoguin <[email protected]> # Copyright (c) 2015-2016, Jean-Sébastien Pédron <[email protected]> # This file is part of erlang.mk and subject to the terms of the ISC License. @@ -7216,11 +7613,11 @@ else # # $(ALL_DEPS_DIRS) includes $(BUILD_DEPS). -$(ERLANG_MK_RECURSIVE_DEPS_LIST): $(ALL_DEPS_DIRS) -$(ERLANG_MK_RECURSIVE_DOC_DEPS_LIST): $(ALL_DEPS_DIRS) $(ALL_DOC_DEPS_DIRS) -$(ERLANG_MK_RECURSIVE_REL_DEPS_LIST): $(ALL_DEPS_DIRS) $(ALL_REL_DEPS_DIRS) -$(ERLANG_MK_RECURSIVE_TEST_DEPS_LIST): $(ALL_DEPS_DIRS) $(ALL_TEST_DEPS_DIRS) -$(ERLANG_MK_RECURSIVE_SHELL_DEPS_LIST): $(ALL_DEPS_DIRS) $(ALL_SHELL_DEPS_DIRS) +$(ERLANG_MK_RECURSIVE_DEPS_LIST): $(LOCAL_DEPS_DIRS) $(ALL_DEPS_DIRS) +$(ERLANG_MK_RECURSIVE_DOC_DEPS_LIST): $(LOCAL_DEPS_DIRS) $(ALL_DEPS_DIRS) $(ALL_DOC_DEPS_DIRS) +$(ERLANG_MK_RECURSIVE_REL_DEPS_LIST): $(LOCAL_DEPS_DIRS) $(ALL_DEPS_DIRS) $(ALL_REL_DEPS_DIRS) +$(ERLANG_MK_RECURSIVE_TEST_DEPS_LIST): $(LOCAL_DEPS_DIRS) $(ALL_DEPS_DIRS) $(ALL_TEST_DEPS_DIRS) +$(ERLANG_MK_RECURSIVE_SHELL_DEPS_LIST): $(LOCAL_DEPS_DIRS) $(ALL_DEPS_DIRS) $(ALL_SHELL_DEPS_DIRS) # Allow to use fetch-deps and $(DEP_TYPES) to fetch multiple types of # dependencies with a single target. @@ -7237,24 +7634,16 @@ ifneq ($(filter shell,$(DEP_TYPES)),) $(ERLANG_MK_RECURSIVE_DEPS_LIST): $(ALL_SHELL_DEPS_DIRS) endif -ERLANG_MK_RECURSIVE_TMP_LIST := $(abspath $(ERLANG_MK_TMP)/recursive-tmp-deps.log) +ERLANG_MK_RECURSIVE_TMP_LIST := $(abspath $(ERLANG_MK_TMP)/recursive-tmp-deps-$(shell echo $$PPID).log) $(ERLANG_MK_RECURSIVE_DEPS_LIST) \ $(ERLANG_MK_RECURSIVE_DOC_DEPS_LIST) \ $(ERLANG_MK_RECURSIVE_REL_DEPS_LIST) \ $(ERLANG_MK_RECURSIVE_TEST_DEPS_LIST) \ -$(ERLANG_MK_RECURSIVE_SHELL_DEPS_LIST): +$(ERLANG_MK_RECURSIVE_SHELL_DEPS_LIST): | $(ERLANG_MK_TMP) ifeq ($(IS_APP)$(IS_DEP),) - $(verbose) mkdir -p $(ERLANG_MK_TMP) $(verbose) rm -f $(ERLANG_MK_RECURSIVE_TMP_LIST) endif -ifndef IS_APP - $(verbose) set -e; for dep in $(ALL_APPS_DIRS) ; do \ - $(MAKE) -C $$dep $@ \ - IS_APP=1 \ - ERLANG_MK_RECURSIVE_TMP_LIST=$(ERLANG_MK_RECURSIVE_TMP_LIST); \ - done -endif $(verbose) set -e; for dep in $^ ; do \ if ! grep -qs ^$$dep$$ $(ERLANG_MK_RECURSIVE_TMP_LIST); then \ echo $$dep >> $(ERLANG_MK_RECURSIVE_TMP_LIST); \ @@ -7267,7 +7656,11 @@ endif fi \ done ifeq ($(IS_APP)$(IS_DEP),) - $(verbose) sort < $(ERLANG_MK_RECURSIVE_TMP_LIST) | uniq > $@ + $(verbose) sort < $(ERLANG_MK_RECURSIVE_TMP_LIST) | \ + uniq > $(ERLANG_MK_RECURSIVE_TMP_LIST).sorted + $(verbose) cmp -s $(ERLANG_MK_RECURSIVE_TMP_LIST).sorted $@ \ + || mv $(ERLANG_MK_RECURSIVE_TMP_LIST).sorted $@ + $(verbose) rm -f $(ERLANG_MK_RECURSIVE_TMP_LIST).sorted $(verbose) rm $(ERLANG_MK_RECURSIVE_TMP_LIST) endif endif # ifneq ($(SKIP_DEPS),) @@ -7285,3 +7678,43 @@ list-shell-deps: $(ERLANG_MK_RECURSIVE_SHELL_DEPS_LIST) list-deps list-doc-deps list-rel-deps list-test-deps list-shell-deps: $(verbose) cat $^ + +# Query dependencies recursively. + +.PHONY: query-deps query-doc-deps query-rel-deps query-test-deps \ + query-shell-deps + +QUERY ?= name fetch_method repo version + +define query_target +$(1): $(2) clean-tmp-query.log +ifeq ($(IS_APP)$(IS_DEP),) + $(verbose) rm -f $(4) +endif + $(verbose) $(foreach dep,$(3),\ + echo $(PROJECT): $(foreach q,$(QUERY),$(call query_$(q),$(dep))) >> $(4) ;) + $(if $(filter-out query-deps,$(1)),,\ + $(verbose) set -e; for dep in $(3) ; do \ + if grep -qs ^$$$$dep$$$$ $(ERLANG_MK_TMP)/query.log; then \ + :; \ + else \ + echo $$$$dep >> $(ERLANG_MK_TMP)/query.log; \ + $(MAKE) -C $(DEPS_DIR)/$$$$dep $$@ QUERY="$(QUERY)" IS_DEP=1 || true; \ + fi \ + done) +ifeq ($(IS_APP)$(IS_DEP),) + $(verbose) touch $(4) + $(verbose) cat $(4) +endif +endef + +clean-tmp-query.log: +ifeq ($(IS_DEP),) + $(verbose) rm -f $(ERLANG_MK_TMP)/query.log +endif + +$(eval $(call query_target,query-deps,$(ERLANG_MK_RECURSIVE_DEPS_LIST),$(BUILD_DEPS) $(DEPS),$(ERLANG_MK_QUERY_DEPS_FILE))) +$(eval $(call query_target,query-doc-deps,$(ERLANG_MK_RECURSIVE_DOC_DEPS_LIST),$(DOC_DEPS),$(ERLANG_MK_QUERY_DOC_DEPS_FILE))) +$(eval $(call query_target,query-rel-deps,$(ERLANG_MK_RECURSIVE_REL_DEPS_LIST),$(REL_DEPS),$(ERLANG_MK_QUERY_REL_DEPS_FILE))) +$(eval $(call query_target,query-test-deps,$(ERLANG_MK_RECURSIVE_TEST_DEPS_LIST),$(TEST_DEPS),$(ERLANG_MK_QUERY_TEST_DEPS_FILE))) +$(eval $(call query_target,query-shell-deps,$(ERLANG_MK_RECURSIVE_SHELL_DEPS_LIST),$(SHELL_DEPS),$(ERLANG_MK_QUERY_SHELL_DEPS_FILE))) |