|
| 1 | +# Copyright (c) 2013-2014, Loïc Hoguin <[email protected]> |
| 2 | +# |
| 3 | +# Permission to use, copy, modify, and/or distribute this software for any |
| 4 | +# purpose with or without fee is hereby granted, provided that the above |
| 5 | +# copyright notice and this permission notice appear in all copies. |
| 6 | +# |
| 7 | +# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
| 8 | +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
| 9 | +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
| 10 | +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
| 11 | +# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
| 12 | +# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
| 13 | +# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
| 14 | + |
| 15 | +# Project. |
| 16 | + |
| 17 | +PROJECT ?= $(notdir $(CURDIR)) |
| 18 | + |
| 19 | +# Packages database file. |
| 20 | + |
| 21 | +PKG_FILE ?= $(CURDIR)/.erlang.mk.packages.v1 |
| 22 | +export PKG_FILE |
| 23 | + |
| 24 | +PKG_FILE_URL ?= https://raw.github.com/extend/erlang.mk/master/packages.v1.tsv |
| 25 | + |
| 26 | +define get_pkg_file |
| 27 | + wget --no-check-certificate -O $(PKG_FILE) $(PKG_FILE_URL) || rm $(PKG_FILE) |
| 28 | +endef |
| 29 | + |
| 30 | +# Verbosity and tweaks. |
| 31 | + |
| 32 | +V ?= 0 |
| 33 | + |
| 34 | +appsrc_verbose_0 = @echo " APP " $(PROJECT).app.src; |
| 35 | +appsrc_verbose = $(appsrc_verbose_$(V)) |
| 36 | + |
| 37 | +erlc_verbose_0 = @echo " ERLC " $(filter %.erl %.core,$(?F)); |
| 38 | +erlc_verbose = $(erlc_verbose_$(V)) |
| 39 | + |
| 40 | +xyrl_verbose_0 = @echo " XYRL " $(filter %.xrl %.yrl,$(?F)); |
| 41 | +xyrl_verbose = $(xyrl_verbose_$(V)) |
| 42 | + |
| 43 | +dtl_verbose_0 = @echo " DTL " $(filter %.dtl,$(?F)); |
| 44 | +dtl_verbose = $(dtl_verbose_$(V)) |
| 45 | + |
| 46 | +gen_verbose_0 = @echo " GEN " $@; |
| 47 | +gen_verbose = $(gen_verbose_$(V)) |
| 48 | + |
| 49 | +.PHONY: rel clean-rel all clean-all app clean deps clean-deps \ |
| 50 | + docs clean-docs build-tests tests build-plt dialyze |
| 51 | + |
| 52 | +# Release. |
| 53 | + |
| 54 | +RELX_CONFIG ?= $(CURDIR)/relx.config |
| 55 | + |
| 56 | +ifneq ($(wildcard $(RELX_CONFIG)),) |
| 57 | + |
| 58 | +RELX ?= $(CURDIR)/relx |
| 59 | +export RELX |
| 60 | + |
| 61 | +RELX_URL ?= https://github.com/erlware/relx/releases/download/v0.6.0/relx |
| 62 | +RELX_OPTS ?= |
| 63 | + |
| 64 | +define get_relx |
| 65 | + wget -O $(RELX) $(RELX_URL) || rm $(RELX) |
| 66 | + chmod +x $(RELX) |
| 67 | +endef |
| 68 | + |
| 69 | +rel: clean-rel all $(RELX) |
| 70 | + @$(RELX) -c $(RELX_CONFIG) $(RELX_OPTS) |
| 71 | + |
| 72 | +$(RELX): |
| 73 | + @$(call get_relx) |
| 74 | + |
| 75 | +clean-rel: |
| 76 | + @rm -rf _rel |
| 77 | + |
| 78 | +endif |
| 79 | + |
| 80 | +# Deps directory. |
| 81 | + |
| 82 | +DEPS_DIR ?= $(CURDIR)/deps |
| 83 | +export DEPS_DIR |
| 84 | + |
| 85 | +REBAR_DEPS_DIR = $(DEPS_DIR) |
| 86 | +export REBAR_DEPS_DIR |
| 87 | + |
| 88 | +ALL_DEPS_DIRS = $(addprefix $(DEPS_DIR)/,$(DEPS)) |
| 89 | +ALL_TEST_DEPS_DIRS = $(addprefix $(DEPS_DIR)/,$(TEST_DEPS)) |
| 90 | + |
| 91 | +# Application. |
| 92 | + |
| 93 | +ifeq ($(filter $(DEPS_DIR),$(subst :, ,$(ERL_LIBS))),) |
| 94 | +ifeq ($(ERL_LIBS),) |
| 95 | + ERL_LIBS = $(DEPS_DIR) |
| 96 | +else |
| 97 | + ERL_LIBS := $(ERL_LIBS):$(DEPS_DIR) |
| 98 | +endif |
| 99 | +endif |
| 100 | +export ERL_LIBS |
| 101 | + |
| 102 | +ERLC_OPTS ?= -Werror +debug_info +warn_export_all +warn_export_vars \ |
| 103 | + +warn_shadow_vars +warn_obsolete_guard # +bin_opt_info +warn_missing_spec |
| 104 | +COMPILE_FIRST ?= |
| 105 | +COMPILE_FIRST_PATHS = $(addprefix src/,$(addsuffix .erl,$(COMPILE_FIRST))) |
| 106 | + |
| 107 | +all: deps app |
| 108 | + |
| 109 | +clean-all: clean clean-deps clean-docs |
| 110 | + $(gen_verbose) rm -rf .$(PROJECT).plt $(DEPS_DIR) logs |
| 111 | + |
| 112 | +app: ebin/$(PROJECT).app |
| 113 | + $(eval MODULES := $(shell find ebin -type f -name \*.beam \ |
| 114 | + | sed 's/ebin\///;s/\.beam/,/' | sed '$$s/.$$//')) |
| 115 | + $(appsrc_verbose) cat src/$(PROJECT).app.src \ |
| 116 | + | sed 's/{modules,[[:space:]]*\[\]}/{modules, \[$(MODULES)\]}/' \ |
| 117 | + > ebin/$(PROJECT).app |
| 118 | + |
| 119 | +define compile_erl |
| 120 | + $(erlc_verbose) erlc -v $(ERLC_OPTS) -o ebin/ \ |
| 121 | + -pa ebin/ -I include/ $(COMPILE_FIRST_PATHS) $(1) |
| 122 | +endef |
| 123 | + |
| 124 | +define compile_xyrl |
| 125 | + $(xyrl_verbose) erlc -v -o ebin/ $(1) |
| 126 | + $(xyrl_verbose) erlc $(ERLC_OPTS) -o ebin/ ebin/*.erl |
| 127 | + @rm ebin/*.erl |
| 128 | +endef |
| 129 | + |
| 130 | +define compile_dtl |
| 131 | + $(dtl_verbose) erl -noshell -pa ebin/ $(DEPS_DIR)/erlydtl/ebin/ -eval ' \ |
| 132 | + Compile = fun(F) -> \ |
| 133 | + Module = list_to_atom( \ |
| 134 | + string:to_lower(filename:basename(F, ".dtl")) ++ "_dtl"), \ |
| 135 | + erlydtl:compile(F, Module, [{out_dir, "ebin/"}]) \ |
| 136 | + end, \ |
| 137 | + _ = [Compile(F) || F <- string:tokens("$(1)", " ")], \ |
| 138 | + init:stop()' |
| 139 | +endef |
| 140 | + |
| 141 | +ebin/$(PROJECT).app: $(shell find src -type f -name \*.erl) \ |
| 142 | + $(shell find src -type f -name \*.core) \ |
| 143 | + $(shell find src -type f -name \*.xrl) \ |
| 144 | + $(shell find src -type f -name \*.yrl) \ |
| 145 | + $(shell find templates -type f -name \*.dtl 2>/dev/null) |
| 146 | + @mkdir -p ebin/ |
| 147 | + $(if $(strip $(filter %.erl %.core,$?)), \ |
| 148 | + $(call compile_erl,$(filter %.erl %.core,$?))) |
| 149 | + $(if $(strip $(filter %.xrl %.yrl,$?)), \ |
| 150 | + $(call compile_xyrl,$(filter %.xrl %.yrl,$?))) |
| 151 | + $(if $(strip $(filter %.dtl,$?)), \ |
| 152 | + $(call compile_dtl,$(filter %.dtl,$?))) |
| 153 | + |
| 154 | +clean: |
| 155 | + $(gen_verbose) rm -rf ebin/ test/*.beam erl_crash.dump |
| 156 | + |
| 157 | +# Dependencies. |
| 158 | + |
| 159 | +define get_dep |
| 160 | + @mkdir -p $(DEPS_DIR) |
| 161 | +ifeq (,$(findstring pkg://,$(word 1,$(dep_$(1))))) |
| 162 | + git clone -n -- $(word 1,$(dep_$(1))) $(DEPS_DIR)/$(1) |
| 163 | +else |
| 164 | + @if [ ! -f $(PKG_FILE) ]; then $(call get_pkg_file); fi |
| 165 | + git clone -n -- `awk 'BEGIN { FS = "\t" }; \ |
| 166 | + $$$$1 == "$(subst pkg://,,$(word 1,$(dep_$(1))))" { print $$$$2 }' \ |
| 167 | + $(PKG_FILE)` $(DEPS_DIR)/$(1) |
| 168 | +endif |
| 169 | + cd $(DEPS_DIR)/$(1) ; git checkout -q $(word 2,$(dep_$(1))) |
| 170 | +endef |
| 171 | + |
| 172 | +define dep_target |
| 173 | +$(DEPS_DIR)/$(1): |
| 174 | + $(call get_dep,$(1)) |
| 175 | +endef |
| 176 | + |
| 177 | +$(foreach dep,$(DEPS),$(eval $(call dep_target,$(dep)))) |
| 178 | + |
| 179 | +deps: $(ALL_DEPS_DIRS) |
| 180 | + @for dep in $(ALL_DEPS_DIRS) ; do \ |
| 181 | + if [ -f $$dep/Makefile ] ; then \ |
| 182 | + $(MAKE) -C $$dep ; \ |
| 183 | + else \ |
| 184 | + echo "include $(CURDIR)/erlang.mk" | $(MAKE) -f - -C $$dep ; \ |
| 185 | + fi ; \ |
| 186 | + done |
| 187 | + |
| 188 | +clean-deps: |
| 189 | + @for dep in $(ALL_DEPS_DIRS) ; do \ |
| 190 | + if [ -f $$dep/Makefile ] ; then \ |
| 191 | + $(MAKE) -C $$dep clean ; \ |
| 192 | + else \ |
| 193 | + echo "include $(CURDIR)/erlang.mk" | $(MAKE) -f - -C $$dep clean ; \ |
| 194 | + fi ; \ |
| 195 | + done |
| 196 | + |
| 197 | +# Documentation. |
| 198 | + |
| 199 | +EDOC_OPTS ?= |
| 200 | + |
| 201 | +docs: clean-docs |
| 202 | + $(gen_verbose) erl -noshell \ |
| 203 | + -eval 'edoc:application($(PROJECT), ".", [$(EDOC_OPTS)]), init:stop().' |
| 204 | + |
| 205 | +clean-docs: |
| 206 | + $(gen_verbose) rm -f doc/*.css doc/*.html doc/*.png doc/edoc-info |
| 207 | + |
| 208 | +# Tests. |
| 209 | + |
| 210 | +$(foreach dep,$(TEST_DEPS),$(eval $(call dep_target,$(dep)))) |
| 211 | + |
| 212 | +TEST_ERLC_OPTS ?= +debug_info +warn_export_vars +warn_shadow_vars +warn_obsolete_guard |
| 213 | +TEST_ERLC_OPTS += -DTEST=1 -DEXTRA=1 +'{parse_transform, eunit_autoexport}' |
| 214 | + |
| 215 | +build-test-deps: $(ALL_TEST_DEPS_DIRS) |
| 216 | + @for dep in $(ALL_TEST_DEPS_DIRS) ; do $(MAKE) -C $$dep; done |
| 217 | + |
| 218 | +build-tests: build-test-deps |
| 219 | + $(gen_verbose) erlc -v $(TEST_ERLC_OPTS) -o test/ \ |
| 220 | + $(wildcard test/*.erl test/*/*.erl) -pa ebin/ |
| 221 | + |
| 222 | +CT_OPTS ?= |
| 223 | +CT_RUN = ct_run \ |
| 224 | + -no_auto_compile \ |
| 225 | + -noshell \ |
| 226 | + -pa $(realpath ebin) $(DEPS_DIR)/*/ebin \ |
| 227 | + -dir test \ |
| 228 | + -logdir logs \ |
| 229 | + $(CT_OPTS) |
| 230 | + |
| 231 | +CT_SUITES ?= |
| 232 | + |
| 233 | +define test_target |
| 234 | +test_$(1): ERLC_OPTS = $(TEST_ERLC_OPTS) |
| 235 | +test_$(1): clean deps app build-tests |
| 236 | + @if [ -d "test" ] ; \ |
| 237 | + then \ |
| 238 | + mkdir -p logs/ ; \ |
| 239 | + $(CT_RUN) -suite $(addsuffix _SUITE,$(1)) ; \ |
| 240 | + fi |
| 241 | + $(gen_verbose) rm -f test/*.beam |
| 242 | +endef |
| 243 | + |
| 244 | +$(foreach test,$(CT_SUITES),$(eval $(call test_target,$(test)))) |
| 245 | + |
| 246 | +tests: ERLC_OPTS = $(TEST_ERLC_OPTS) |
| 247 | +tests: clean deps app build-tests |
| 248 | + @if [ -d "test" ] ; \ |
| 249 | + then \ |
| 250 | + mkdir -p logs/ ; \ |
| 251 | + $(CT_RUN) -suite $(addsuffix _SUITE,$(CT_SUITES)) ; \ |
| 252 | + fi |
| 253 | + $(gen_verbose) rm -f test/*.beam |
| 254 | + |
| 255 | +# Dialyzer. |
| 256 | + |
| 257 | +DIALYZER_PLT ?= $(CURDIR)/.$(PROJECT).plt |
| 258 | +export DIALYZER_PLT |
| 259 | + |
| 260 | +PLT_APPS ?= |
| 261 | +DIALYZER_OPTS ?= -Werror_handling -Wrace_conditions \ |
| 262 | + -Wunmatched_returns # -Wunderspecs |
| 263 | + |
| 264 | +build-plt: deps app |
| 265 | + @dialyzer --build_plt --apps erts kernel stdlib $(PLT_APPS) $(ALL_DEPS_DIRS) |
| 266 | + |
| 267 | +dialyze: |
| 268 | + @dialyzer --src src --no_native $(DIALYZER_OPTS) |
| 269 | + |
| 270 | +# Packages. |
| 271 | + |
| 272 | +$(PKG_FILE): |
| 273 | + @$(call get_pkg_file) |
| 274 | + |
| 275 | +pkg-list: $(PKG_FILE) |
| 276 | + @cat $(PKG_FILE) | awk 'BEGIN { FS = "\t" }; { print \ |
| 277 | + "Name:\t\t" $$1 "\n" \ |
| 278 | + "Repository:\t" $$2 "\n" \ |
| 279 | + "Website:\t" $$3 "\n" \ |
| 280 | + "Description:\t" $$4 "\n" }' |
| 281 | + |
| 282 | +ifdef q |
| 283 | +pkg-search: $(PKG_FILE) |
| 284 | + @cat $(PKG_FILE) | grep -i ${q} | awk 'BEGIN { FS = "\t" }; { print \ |
| 285 | + "Name:\t\t" $$1 "\n" \ |
| 286 | + "Repository:\t" $$2 "\n" \ |
| 287 | + "Website:\t" $$3 "\n" \ |
| 288 | + "Description:\t" $$4 "\n" }' |
| 289 | +else |
| 290 | +pkg-search: |
| 291 | + @echo "Usage: make pkg-search q=STRING" |
| 292 | +endif |
0 commit comments