diff options
Diffstat (limited to 'core')
-rw-r--r-- | core/core.mk | 71 | ||||
-rw-r--r-- | core/deps.mk | 85 | ||||
-rw-r--r-- | core/docs.mk | 19 | ||||
-rw-r--r-- | core/erlc.mk | 59 | ||||
-rw-r--r-- | core/test.mk | 48 |
5 files changed, 249 insertions, 33 deletions
diff --git a/core/core.mk b/core/core.mk index d25897b..5cb0b54 100644 --- a/core/core.mk +++ b/core/core.mk @@ -1,4 +1,4 @@ -# Copyright (c) 2013-2014, Loïc Hoguin <[email protected]> +# Copyright (c) 2013-2015, Loïc Hoguin <[email protected]> # # Permission to use, copy, modify, and/or distribute this software for any # purpose with or without fee is hereby granted, provided that the above @@ -12,7 +12,7 @@ # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -.PHONY: all deps app rel docs tests clean distclean help +.PHONY: all deps app rel docs install-docs tests check clean distclean help erlang-mk ERLANG_MK_VERSION = 1 @@ -28,12 +28,32 @@ V ?= 0 gen_verbose_0 = @echo " GEN " $@; gen_verbose = $(gen_verbose_$(V)) +# "erl" command. + +ERL = erl +A0 -noinput -boot start_clean + # Core targets. -all:: deps app rel +ifneq ($(words $(MAKECMDGOALS)),1) +.NOTPARALLEL: +endif + +all:: deps + @$(MAKE) --no-print-directory app + @$(MAKE) --no-print-directory rel + +# Noop to avoid a Make warning when there's nothing to do. +rel:: + @echo -n + +check:: clean app tests + +clean:: clean-crashdump -clean:: +clean-crashdump: +ifneq ($(wildcard erl_crash.dump),) $(gen_verbose) rm -f erl_crash.dump +endif distclean:: clean @@ -42,26 +62,47 @@ help:: "erlang.mk (version $(ERLANG_MK_VERSION)) is distributed under the terms of the ISC License." \ "Copyright (c) 2013-2014 Loïc Hoguin <[email protected]>" \ "" \ - "Usage: [V=1] make [target]" \ + "Usage: [V=1] make [-jNUM] [target]" \ "" \ "Core targets:" \ - " all Run deps, app and rel targets in that order" \ - " deps Fetch dependencies (if needed) and compile them" \ - " app Compile the project" \ - " rel Build a release for this project, if applicable" \ - " docs Build the documentation for this project" \ - " tests Run the tests for this project" \ - " clean Delete temporary and output files from most targets" \ - " distclean Delete all temporary and output files" \ - " help Display this help and exit" \ + " all Run deps, app and rel targets in that order" \ + " deps Fetch dependencies (if needed) and compile them" \ + " app Compile the project" \ + " rel Build a release for this project, if applicable" \ + " docs Build the documentation for this project" \ + " install-docs Install the man pages for this project" \ + " tests Run the tests for this project" \ + " check Compile and run all tests and analysis for this project" \ + " clean Delete temporary and output files from most targets" \ + " distclean Delete all temporary and output files" \ + " help Display this help and exit" \ "" \ "The target clean only removes files that are commonly removed." \ "Dependencies and releases are left untouched." \ "" \ - "Setting V=1 when calling make enables verbose mode." + "Setting V=1 when calling make enables verbose mode." \ + "Parallel execution is supported through the -j Make flag." # Core functions. +ifeq ($(shell which wget 2>/dev/null | wc -l), 1) define core_http_get wget --no-check-certificate -O $(1) $(2)|| rm $(1) endef +else +define core_http_get + $(ERL) -eval 'ssl:start(), inets:start(), case httpc:request(get, {"$(2)", []}, [{autoredirect, true}], []) of {ok, {{_, 200, _}, _, Body}} -> case file:write_file("$(1)", Body) of ok -> ok; {error, R1} -> halt(R1) end; {error, R2} -> halt(R2) end, halt(0).' +endef +endif + +# Automated update. + +ERLANG_MK_BUILD_CONFIG ?= build.config +ERLANG_MK_BUILD_DIR ?= .erlang.mk.build + +erlang-mk: + git clone https://github.com/ninenines/erlang.mk $(ERLANG_MK_BUILD_DIR) + if [ -f $(ERLANG_MK_BUILD_CONFIG) ]; then cp $(ERLANG_MK_BUILD_CONFIG) $(ERLANG_MK_BUILD_DIR); fi + cd $(ERLANG_MK_BUILD_DIR) && make + cp $(ERLANG_MK_BUILD_DIR)/erlang.mk ./erlang.mk + rm -rf $(ERLANG_MK_BUILD_DIR) diff --git a/core/deps.mk b/core/deps.mk index f15ae74..3b18ce9 100644 --- a/core/deps.mk +++ b/core/deps.mk @@ -1,10 +1,13 @@ -# Copyright (c) 2013-2014, Loïc Hoguin <[email protected]> +# Copyright (c) 2013-2015, Loïc Hoguin <[email protected]> # This file is part of erlang.mk and subject to the terms of the ISC License. .PHONY: distclean-deps distclean-pkg pkg-list pkg-search # Configuration. +AUTOPATCH ?= edown gen_leader gproc +export AUTOPATCH + DEPS_DIR ?= $(CURDIR)/deps export DEPS_DIR @@ -27,26 +30,85 @@ export PKG_FILE2 PKG_FILE_URL ?= https://raw.githubusercontent.com/ninenines/erlang.mk/master/packages.v2.tsv +# Verbosity. + +dep_verbose_0 = @echo " DEP " $(1); +dep_verbose = $(dep_verbose_$(V)) + # Core targets. +ifneq ($(SKIP_DEPS),) +deps:: +else deps:: $(ALL_DEPS_DIRS) @for dep in $(ALL_DEPS_DIRS) ; do \ if [ -f $$dep/GNUmakefile ] || [ -f $$dep/makefile ] || [ -f $$dep/Makefile ] ; then \ - $(MAKE) -C $$dep ; \ + $(MAKE) -C $$dep || exit $$? ; \ else \ - echo "include $(CURDIR)/erlang.mk" | $(MAKE) -f - -C $$dep ; \ + echo "ERROR: No makefile to build dependency $$dep. Consider adding it to AUTOPATCH." ; \ + exit 1 ; \ fi ; \ done +endif distclean:: distclean-deps distclean-pkg # Deps related targets. +define dep_autopatch + $(ERL) -eval " \ +DepDir = \"$(DEPS_DIR)/$(1)/\", \ +fun() -> \ + {ok, Conf} = case file:consult(DepDir ++ \"rebar.config\") of \ + {error, enoent} -> {ok, []}; Res -> Res end, \ + File = case lists:keyfind(deps, 1, Conf) of false -> []; {_, Deps} -> \ + [begin {Method, Repo, Commit} = case Repos of \ + {git, R} -> {git, R, master}; \ + {M, R, {branch, C}} -> {M, R, C}; \ + {M, R, {tag, C}} -> {M, R, C}; \ + {M, R, C} -> {M, R, C} \ + end, \ + io_lib:format(\"DEPS += ~s\ndep_~s = ~s ~s ~s~n\", [Name, Name, Method, Repo, Commit]) \ + end || {Name, _, Repos} <- Deps] \ + end, \ + First = case lists:keyfind(erl_first_files, 1, Conf) of false -> []; {_, Files} -> \ + Names = [[\" \", begin \"lre.\" ++ R = lists:reverse(F), lists:reverse(R) end] \ + || \"src/\" ++ F <- Files], \ + io_lib:format(\"COMPILE_FIRST +=~s\n\", [Names]) \ + end, \ + ok = file:write_file(\"$(DEPS_DIR)/$(1)/Makefile\", [\"ERLC_OPTS = +debug_info\n\n\", File, First, \"\ninclude erlang.mk\"]) \ +end(), \ +AppSrcOut = \"$(DEPS_DIR)/$(1)/src/$(1).app.src\", \ +AppSrcIn = case filelib:is_regular(AppSrcOut) of false -> \"$(DEPS_DIR)/$(1)/ebin/$(1).app\"; true -> AppSrcOut end, \ +fun() -> \ + {ok, [{application, $(1), L}]} = file:consult(AppSrcIn), \ + L2 = case lists:keyfind(modules, 1, L) of {_, _} -> L; false -> [{modules, []}|L] end, \ + L3 = case lists:keyfind(vsn, 1, L2) of {vsn, git} -> lists:keyreplace(vsn, 1, L2, {vsn, \"git\"}); _ -> L2 end, \ + ok = file:write_file(AppSrcOut, io_lib:format(\"~p.~n\", [{application, $(1), L3}])) \ +end(), \ +case AppSrcOut of AppSrcIn -> ok; _ -> ok = file:delete(AppSrcIn) end, \ +halt()." +endef + +ifeq ($(V),0) +define dep_autopatch_verbose + @echo " PATCH " $(1); +endef +endif + define dep_fetch if [ "$$$$VS" = "git" ]; then \ - git clone -n -- $$$$REPO $(DEPS_DIR)/$(1); \ + git clone -q -n -- $$$$REPO $(DEPS_DIR)/$(1); \ cd $(DEPS_DIR)/$(1) && git checkout -q $$$$COMMIT; \ + elif [ "$$$$VS" = "hg" ]; then \ + hg clone -q -U $$$$REPO $(DEPS_DIR)/$(1); \ + cd $(DEPS_DIR)/$(1) && hg update -q $$$$COMMIT; \ + elif [ "$$$$VS" = "svn" ]; then \ + svn checkout -q $$$$REPO $(DEPS_DIR)/$(1); \ + elif [ "$$$$VS" = "cp" ]; then \ + cp -R $$$$REPO $(DEPS_DIR)/$(1); \ else \ + echo "Unknown or invalid dependency: $(1). Please consult the erlang.mk README for instructions." >&2; \ exit 78; \ fi endef @@ -54,19 +116,24 @@ endef define dep_target $(DEPS_DIR)/$(1): @mkdir -p $(DEPS_DIR) - @if [ ! -f $(PKG_FILE2) ]; then $(call core_http_get,$(PKG_FILE2),$(PKG_FILE_URL)); fi ifeq (,$(dep_$(1))) - DEPPKG=$$$$(awk 'BEGIN { FS = "\t" }; $$$$1 == "$(1)" { print $$$$2 " " $$$$3 " " $$$$4 }' $(PKG_FILE2);) \ + @if [ ! -f $(PKG_FILE2) ]; then $(call core_http_get,$(PKG_FILE2),$(PKG_FILE_URL)); fi + $(dep_verbose) DEPPKG=$$$$(awk 'BEGIN { FS = "\t" }; $$$$1 == "$(1)" { print $$$$2 " " $$$$3 " " $$$$4 }' $(PKG_FILE2);); \ VS=$$$$(echo $$$$DEPPKG | cut -d " " -f1); \ REPO=$$$$(echo $$$$DEPPKG | cut -d " " -f2); \ COMMIT=$$$$(echo $$$$DEPPKG | cut -d " " -f3); \ $(call dep_fetch,$(1)) else - VS=$(word 1,$(dep_$(1))); \ + $(dep_verbose) VS=$(word 1,$(dep_$(1))); \ REPO=$(word 2,$(dep_$(1))); \ COMMIT=$(word 3,$(dep_$(1))); \ $(call dep_fetch,$(1)) endif +ifneq ($(filter $(1),$(AUTOPATCH)),) + $(call dep_autopatch_verbose,$(1)) \ + $(call dep_autopatch,$(1)); \ + cd $(DEPS_DIR)/$(1)/ && ln -s ../../erlang.mk +endif endef $(foreach dep,$(DEPS),$(eval $(call dep_target,$(dep)))) @@ -77,7 +144,7 @@ distclean-deps: # Packages related targets. $(PKG_FILE2): - $(call core_http_get,$(PKG_FILE2),$(PKG_FILE_URL)) + @$(call core_http_get,$(PKG_FILE2),$(PKG_FILE_URL)) pkg-list: $(PKG_FILE2) @cat $(PKG_FILE2) | awk 'BEGIN { FS = "\t" }; { print \ @@ -98,8 +165,10 @@ pkg-search: $(error Usage: make pkg-search q=STRING) endif +ifeq ($(PKG_FILE2),$(CURDIR)/.erlang.mk.packages.v2) distclean-pkg: $(gen_verbose) rm -f $(PKG_FILE2) +endif help:: @printf "%s\n" "" \ diff --git a/core/docs.mk b/core/docs.mk new file mode 100644 index 0000000..e1e2d0e --- /dev/null +++ b/core/docs.mk @@ -0,0 +1,19 @@ +# Copyright (c) 2015, Viktor Söderqvist <[email protected]> +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: docs-deps + +# Configuration. + +ALL_DOC_DEPS_DIRS = $(addprefix $(DEPS_DIR)/,$(DOC_DEPS)) + +# Targets. + +$(foreach dep,$(DOC_DEPS),$(eval $(call dep_target,$(dep)))) + +ifneq ($(SKIP_DEPS),) +doc-deps: +else +doc-deps: $(ALL_DOC_DEPS_DIRS) + @for dep in $(ALL_DOC_DEPS_DIRS) ; do $(MAKE) -C $$dep; done +endif diff --git a/core/erlc.mk b/core/erlc.mk index 87d10d8..dc488a5 100644 --- a/core/erlc.mk +++ b/core/erlc.mk @@ -1,38 +1,66 @@ -# Copyright (c) 2013-2014, Loïc Hoguin <[email protected]> +# Copyright (c) 2013-2015, Loïc Hoguin <[email protected]> # This file is part of erlang.mk and subject to the terms of the ISC License. .PHONY: clean-app # Configuration. -ERLC_OPTS ?= -Werror +debug_info +warn_export_all +warn_export_vars \ - +warn_shadow_vars +warn_obsolete_guard # +bin_opt_info +warn_missing_spec +ERLC_OPTS ?= -Werror +debug_info +warn_export_vars +warn_shadow_vars \ + +warn_obsolete_guard # +bin_opt_info +warn_export_all +warn_missing_spec COMPILE_FIRST ?= COMPILE_FIRST_PATHS = $(addprefix src/,$(addsuffix .erl,$(COMPILE_FIRST))) +ERLC_EXCLUDE ?= +ERLC_EXCLUDE_PATHS = $(addprefix src/,$(addsuffix .erl,$(ERLC_EXCLUDE))) + +ERLC_MIB_OPTS ?= +COMPILE_MIB_FIRST ?= +COMPILE_MIB_FIRST_PATHS = $(addprefix mibs/,$(addsuffix .mib,$(COMPILE_MIB_FIRST))) # Verbosity. appsrc_verbose_0 = @echo " APP " $(PROJECT).app.src; appsrc_verbose = $(appsrc_verbose_$(V)) -erlc_verbose_0 = @echo " ERLC " $(filter %.erl %.core,$(?F)); +erlc_verbose_0 = @echo " ERLC " $(filter-out $(patsubst %,%.erl,$(ERLC_EXCLUDE)),\ + $(filter %.erl %.core,$(?F))); erlc_verbose = $(erlc_verbose_$(V)) xyrl_verbose_0 = @echo " XYRL " $(filter %.xrl %.yrl,$(?F)); xyrl_verbose = $(xyrl_verbose_$(V)) -# Core targets. +mib_verbose_0 = @echo " MIB " $(filter %.bin %.mib,$(?F)); +mib_verbose = $(mib_verbose_$(V)) + +# Targets. -app:: ebin/$(PROJECT).app +ifeq ($(wildcard ebin/test),) +app:: app-build +else +app:: clean app-build +endif + +app-build: erlc-include ebin/$(PROJECT).app $(eval MODULES := $(shell find ebin -type f -name \*.beam \ | sed "s/ebin\//'/;s/\.beam/',/" | sed '$$s/.$$//')) + @if [ -z "$$(grep -E '^[^%]*{modules,' src/$(PROJECT).app.src)" ]; then \ + echo "Empty modules entry not found in $(PROJECT).app.src. Please consult the erlang.mk README for instructions." >&2; \ + exit 1; \ + fi + $(eval GITDESCRIBE := $(shell git describe --dirty --abbrev=7 --tags --always --first-parent 2>/dev/null || true)) $(appsrc_verbose) cat src/$(PROJECT).app.src \ | sed "s/{modules,[[:space:]]*\[\]}/{modules, \[$(MODULES)\]}/" \ + | sed "s/{id,[[:space:]]*\"git\"}/{id, \"$(GITDESCRIBE)\"}/" \ > ebin/$(PROJECT).app +erlc-include: + -@if [ -d ebin/ ]; then \ + find include/ src/ -type f -name \*.hrl -newer ebin -exec touch $(shell find src/ -type f -name "*.erl") \; 2>/dev/null || printf ''; \ + fi + define compile_erl $(erlc_verbose) erlc -v $(ERLC_OPTS) -o ebin/ \ - -pa ebin/ -I include/ $(COMPILE_FIRST_PATHS) $(1) + -pa ebin/ -I include/ $(filter-out $(ERLC_EXCLUDE_PATHS),\ + $(COMPILE_FIRST_PATHS) $(1)) endef define compile_xyrl @@ -41,10 +69,22 @@ define compile_xyrl @rm ebin/*.erl endef +define compile_mib + $(mib_verbose) erlc -v $(ERLC_MIB_OPTS) -o priv/mibs/ \ + -I priv/mibs/ $(COMPILE_MIB_FIRST_PATHS) $(1) + $(mib_verbose) erlc -o include/ -- priv/mibs/*.bin +endef + ifneq ($(wildcard src/),) ebin/$(PROJECT).app:: @mkdir -p ebin/ +ifneq ($(wildcard mibs/),) +ebin/$(PROJECT).app:: $(shell find mibs -type f -name \*.mib) + @mkdir -p priv/mibs/ include + $(if $(strip $?),$(call compile_mib,$?)) +endif + ebin/$(PROJECT).app:: $(shell find src -type f -name \*.erl) \ $(shell find src -type f -name \*.core) $(if $(strip $?),$(call compile_erl,$?)) @@ -56,7 +96,6 @@ endif clean:: clean-app -# Extra targets. - clean-app: - $(gen_verbose) rm -rf ebin/ + $(gen_verbose) rm -rf ebin/ priv/mibs/ \ + $(addprefix include/,$(addsuffix .hrl,$(notdir $(basename $(wildcard mibs/*.mib))))) diff --git a/core/test.mk b/core/test.mk new file mode 100644 index 0000000..7dd5d61 --- /dev/null +++ b/core/test.mk @@ -0,0 +1,48 @@ +# Copyright (c) 2015, Loïc Hoguin <[email protected]> +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: test-deps test-dir test-build clean-test-dir + +# Configuration. + +TEST_DIR ?= $(CURDIR)/test + +ALL_TEST_DEPS_DIRS = $(addprefix $(DEPS_DIR)/,$(TEST_DEPS)) + +TEST_ERLC_OPTS ?= +debug_info +warn_export_vars +warn_shadow_vars +warn_obsolete_guard +TEST_ERLC_OPTS += -DTEST=1 + +# Targets. + +$(foreach dep,$(TEST_DEPS),$(eval $(call dep_target,$(dep)))) + +ifneq ($(SKIP_DEPS),) +test-deps: +else +test-deps: $(ALL_TEST_DEPS_DIRS) + @for dep in $(ALL_TEST_DEPS_DIRS) ; do $(MAKE) -C $$dep; done +endif + +ifneq ($(strip $(TEST_DIR)),) +test-dir: + $(gen_verbose) erlc -v $(TEST_ERLC_OPTS) -I include/ -o $(TEST_DIR) \ + $(wildcard $(TEST_DIR)/*.erl $(TEST_DIR)/*/*.erl) -pa ebin/ +endif + +ifeq ($(wildcard ebin/test),) +test-build:: ERLC_OPTS=$(TEST_ERLC_OPTS) +test-build:: clean deps test-deps + @$(MAKE) --no-print-directory app-build test-dir ERLC_OPTS="$(TEST_ERLC_OPTS)" + $(gen_verbose) touch ebin/test +else +test-build:: ERLC_OPTS=$(TEST_ERLC_OPTS) +test-build:: deps test-deps + @$(MAKE) --no-print-directory app-build test-dir ERLC_OPTS="$(TEST_ERLC_OPTS)" +endif + +clean:: clean-test-dir + +clean-test-dir: +ifneq ($(wildcard $(TEST_DIR)/*.beam),) + $(gen_verbose) rm -f $(TEST_DIR)/*.beam +endif |