2016-11-05 14:17:30 +02:00
|
|
|
# Copyright (c) 2013-2016, Loïc Hoguin <essen@ninenines.eu>
|
2013-04-30 20:51:37 +02:00
|
|
|
#
|
|
|
|
# Permission to use, copy, modify, and/or distribute this software for any
|
|
|
|
# purpose with or without fee is hereby granted, provided that the above
|
|
|
|
# copyright notice and this permission notice appear in all copies.
|
|
|
|
#
|
|
|
|
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
|
|
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
|
|
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
|
|
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
|
|
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
|
|
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
|
|
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
|
|
|
2016-11-05 14:17:30 +02:00
|
|
|
.PHONY: all app apps deps search rel relup docs install-docs check tests clean distclean help erlang-mk
|
2014-08-01 14:26:51 +02:00
|
|
|
|
2015-07-21 17:16:11 +02:00
|
|
|
ERLANG_MK_FILENAME := $(realpath $(lastword $(MAKEFILE_LIST)))
|
2017-07-14 21:44:39 +02:00
|
|
|
export ERLANG_MK_FILENAME
|
2015-07-21 17:16:11 +02:00
|
|
|
|
2025-02-11 16:02:10 +01:00
|
|
|
ERLANG_MK_VERSION = 2022.05.31-116-g0206e84-dirty
|
2017-07-14 21:44:39 +02:00
|
|
|
ERLANG_MK_WITHOUT =
|
2016-11-05 14:17:30 +02:00
|
|
|
|
|
|
|
# Make 3.81 and 3.82 are deprecated.
|
|
|
|
|
2020-03-29 15:45:51 +02:00
|
|
|
ifeq ($(MAKELEVEL)$(MAKE_VERSION),03.81)
|
2016-11-05 14:17:30 +02:00
|
|
|
$(warning Please upgrade to GNU Make 4 or later: https://erlang.mk/guide/installation.html)
|
|
|
|
endif
|
|
|
|
|
2020-03-29 15:45:51 +02:00
|
|
|
ifeq ($(MAKELEVEL)$(MAKE_VERSION),03.82)
|
2016-11-05 14:17:30 +02:00
|
|
|
$(warning Please upgrade to GNU Make 4 or later: https://erlang.mk/guide/installation.html)
|
|
|
|
endif
|
2014-08-01 14:26:51 +02:00
|
|
|
|
|
|
|
# Core configuration.
|
2013-08-24 10:48:59 +02:00
|
|
|
|
|
|
|
PROJECT ?= $(notdir $(CURDIR))
|
2014-08-01 14:26:51 +02:00
|
|
|
PROJECT := $(strip $(PROJECT))
|
2013-08-24 10:48:59 +02:00
|
|
|
|
2015-07-21 17:16:11 +02:00
|
|
|
PROJECT_VERSION ?= rolling
|
2016-11-05 14:17:30 +02:00
|
|
|
PROJECT_MOD ?= $(PROJECT)_app
|
|
|
|
PROJECT_ENV ?= []
|
2015-07-21 17:16:11 +02:00
|
|
|
|
2014-08-01 14:26:51 +02:00
|
|
|
# Verbosity.
|
2013-08-24 10:48:59 +02:00
|
|
|
|
2014-08-01 14:26:51 +02:00
|
|
|
V ?= 0
|
2013-08-24 10:48:59 +02:00
|
|
|
|
2015-07-21 17:16:11 +02:00
|
|
|
verbose_0 = @
|
2016-01-14 13:35:25 +01:00
|
|
|
verbose_2 = set -x;
|
2015-07-21 17:16:11 +02:00
|
|
|
verbose = $(verbose_$(V))
|
|
|
|
|
2025-02-11 16:02:10 +01:00
|
|
|
ifeq ($V,3)
|
2020-03-29 15:45:51 +02:00
|
|
|
SHELL := $(SHELL) -x
|
|
|
|
endif
|
|
|
|
|
2014-08-01 14:26:51 +02:00
|
|
|
gen_verbose_0 = @echo " GEN " $@;
|
2016-01-14 13:35:25 +01:00
|
|
|
gen_verbose_2 = set -x;
|
2014-08-01 14:26:51 +02:00
|
|
|
gen_verbose = $(gen_verbose_$(V))
|
2013-08-24 10:48:59 +02:00
|
|
|
|
2020-03-29 15:45:51 +02:00
|
|
|
gen_verbose_esc_0 = @echo " GEN " $$@;
|
|
|
|
gen_verbose_esc_2 = set -x;
|
|
|
|
gen_verbose_esc = $(gen_verbose_esc_$(V))
|
|
|
|
|
2015-06-11 17:04:21 +02:00
|
|
|
# Temporary files directory.
|
|
|
|
|
|
|
|
ERLANG_MK_TMP ?= $(CURDIR)/.erlang.mk
|
|
|
|
export ERLANG_MK_TMP
|
|
|
|
|
2015-05-05 19:59:37 +03:00
|
|
|
# "erl" command.
|
|
|
|
|
2025-02-11 16:02:10 +01:00
|
|
|
ERL = erl -noinput -boot no_dot_erlang -kernel start_distribution false +P 1024 +Q 1024
|
2015-05-05 19:59:37 +03:00
|
|
|
|
2015-06-11 17:04:21 +02:00
|
|
|
# Platform detection.
|
|
|
|
|
|
|
|
ifeq ($(PLATFORM),)
|
|
|
|
UNAME_S := $(shell uname -s)
|
|
|
|
|
|
|
|
ifeq ($(UNAME_S),Linux)
|
|
|
|
PLATFORM = linux
|
|
|
|
else ifeq ($(UNAME_S),Darwin)
|
|
|
|
PLATFORM = darwin
|
|
|
|
else ifeq ($(UNAME_S),SunOS)
|
|
|
|
PLATFORM = solaris
|
|
|
|
else ifeq ($(UNAME_S),GNU)
|
|
|
|
PLATFORM = gnu
|
|
|
|
else ifeq ($(UNAME_S),FreeBSD)
|
|
|
|
PLATFORM = freebsd
|
|
|
|
else ifeq ($(UNAME_S),NetBSD)
|
|
|
|
PLATFORM = netbsd
|
|
|
|
else ifeq ($(UNAME_S),OpenBSD)
|
|
|
|
PLATFORM = openbsd
|
2015-11-16 23:08:24 +01:00
|
|
|
else ifeq ($(UNAME_S),DragonFly)
|
|
|
|
PLATFORM = dragonfly
|
|
|
|
else ifeq ($(shell uname -o),Msys)
|
|
|
|
PLATFORM = msys2
|
2015-06-11 17:04:21 +02:00
|
|
|
else
|
|
|
|
$(error Unable to detect platform. Please open a ticket with the output of uname -a.)
|
|
|
|
endif
|
|
|
|
|
|
|
|
export PLATFORM
|
|
|
|
endif
|
|
|
|
|
2014-08-01 14:26:51 +02:00
|
|
|
# Core targets.
|
|
|
|
|
2015-11-16 23:08:24 +01:00
|
|
|
all:: deps app rel
|
2015-05-05 19:59:37 +03:00
|
|
|
|
|
|
|
# Noop to avoid a Make warning when there's nothing to do.
|
|
|
|
rel::
|
2016-01-14 13:35:25 +01:00
|
|
|
$(verbose) :
|
2015-05-05 19:59:37 +03:00
|
|
|
|
2016-11-05 14:17:30 +02:00
|
|
|
relup:: deps app
|
|
|
|
|
2016-01-14 13:35:25 +01:00
|
|
|
check:: tests
|
2015-06-11 17:04:21 +02:00
|
|
|
|
2015-05-05 19:59:37 +03:00
|
|
|
clean:: clean-crashdump
|
|
|
|
|
|
|
|
clean-crashdump:
|
|
|
|
ifneq ($(wildcard erl_crash.dump),)
|
2014-08-01 14:26:51 +02:00
|
|
|
$(gen_verbose) rm -f erl_crash.dump
|
2015-05-05 19:59:37 +03:00
|
|
|
endif
|
2014-08-01 14:26:51 +02:00
|
|
|
|
2015-11-16 23:08:24 +01:00
|
|
|
distclean:: clean distclean-tmp
|
|
|
|
|
2020-03-29 15:45:51 +02:00
|
|
|
$(ERLANG_MK_TMP):
|
|
|
|
$(verbose) mkdir -p $(ERLANG_MK_TMP)
|
|
|
|
|
2015-11-16 23:08:24 +01:00
|
|
|
distclean-tmp:
|
|
|
|
$(gen_verbose) rm -rf $(ERLANG_MK_TMP)
|
2014-08-01 14:26:51 +02:00
|
|
|
|
|
|
|
help::
|
2015-07-21 17:16:11 +02:00
|
|
|
$(verbose) printf "%s\n" \
|
2014-08-01 14:26:51 +02:00
|
|
|
"erlang.mk (version $(ERLANG_MK_VERSION)) is distributed under the terms of the ISC License." \
|
2016-11-05 14:17:30 +02:00
|
|
|
"Copyright (c) 2013-2016 Loïc Hoguin <essen@ninenines.eu>" \
|
2014-08-01 14:26:51 +02:00
|
|
|
"" \
|
2015-11-16 23:08:24 +01:00
|
|
|
"Usage: [V=1] $(MAKE) [target]..." \
|
2014-08-01 14:26:51 +02:00
|
|
|
"" \
|
|
|
|
"Core targets:" \
|
2015-06-11 17:04:21 +02:00
|
|
|
" all Run deps, app and rel targets in that order" \
|
|
|
|
" app Compile the project" \
|
2015-07-21 17:16:11 +02:00
|
|
|
" deps Fetch dependencies (if needed) and compile them" \
|
2016-11-05 14:17:30 +02:00
|
|
|
" fetch-deps Fetch dependencies recursively (if needed) without compiling them" \
|
|
|
|
" list-deps List dependencies recursively on stdout" \
|
2015-07-21 17:16:11 +02:00
|
|
|
" search q=... Search for a package in the built-in index" \
|
2015-06-11 17:04:21 +02:00
|
|
|
" 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" \
|
|
|
|
" check Compile and run all tests and analysis for this project" \
|
2015-07-21 17:16:11 +02:00
|
|
|
" tests Run the tests for this project" \
|
2015-06-11 17:04:21 +02:00
|
|
|
" clean Delete temporary and output files from most targets" \
|
|
|
|
" distclean Delete all temporary and output files" \
|
|
|
|
" help Display this help and exit" \
|
2015-07-21 17:16:11 +02:00
|
|
|
" erlang-mk Update erlang.mk to the latest version"
|
2014-08-01 14:26:51 +02:00
|
|
|
|
|
|
|
# Core functions.
|
|
|
|
|
2015-07-21 17:16:11 +02:00
|
|
|
empty :=
|
|
|
|
space := $(empty) $(empty)
|
|
|
|
tab := $(empty) $(empty)
|
|
|
|
comma := ,
|
|
|
|
|
2015-06-11 17:04:21 +02:00
|
|
|
define newline
|
|
|
|
|
|
|
|
|
|
|
|
endef
|
|
|
|
|
2015-07-21 17:16:11 +02:00
|
|
|
define comma_list
|
2025-02-11 16:02:10 +01:00
|
|
|
$(subst $(space),$(comma),$(strip $1))
|
2015-07-21 17:16:11 +02:00
|
|
|
endef
|
|
|
|
|
2018-05-16 12:28:55 +02:00
|
|
|
define escape_dquotes
|
|
|
|
$(subst ",\",$1)
|
|
|
|
endef
|
|
|
|
|
2015-06-11 17:04:21 +02:00
|
|
|
# Adding erlang.mk to make Erlang scripts who call init:get_plain_arguments() happy.
|
|
|
|
define erlang
|
2023-11-24 11:39:55 +01:00
|
|
|
$(ERL) $2 -pz $(ERLANG_MK_TMP)/rebar3/_build/prod/lib/*/ebin/ -eval "$(subst $(newline),,$(call escape_dquotes,$1))" -- erlang.mk
|
2015-06-11 17:04:21 +02:00
|
|
|
endef
|
|
|
|
|
2015-11-16 23:08:24 +01:00
|
|
|
ifeq ($(PLATFORM),msys2)
|
2020-03-29 15:45:51 +02:00
|
|
|
core_native_path = $(shell cygpath -m $1)
|
2015-11-16 23:08:24 +01:00
|
|
|
else
|
|
|
|
core_native_path = $1
|
|
|
|
endif
|
|
|
|
|
2025-02-11 16:02:10 +01:00
|
|
|
core_http_get = curl -Lf$(if $(filter-out 0,$V),,s)o $(call core_native_path,$1) $2
|
2013-08-24 10:48:59 +02:00
|
|
|
|
2025-02-11 16:02:10 +01:00
|
|
|
core_eq = $(and $(findstring $1,$2),$(findstring $2,$1))
|
2015-07-21 17:16:11 +02:00
|
|
|
|
2024-11-06 16:33:39 +01:00
|
|
|
# We skip files that contain spaces because they end up causing issues.
|
|
|
|
# Files that begin with a dot are already ignored by the wildcard function.
|
|
|
|
core_find = $(foreach f,$(wildcard $(1:%/=%)/*),$(if $(wildcard $f/.),$(call core_find,$f,$2),$(if $(filter $(subst *,%,$2),$f),$(if $(wildcard $f),$f))))
|
2015-07-21 17:16:11 +02:00
|
|
|
|
2025-02-11 16:02:10 +01:00
|
|
|
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))))))))))))))))))))))))))
|
2015-07-21 17:16:11 +02:00
|
|
|
|
2025-02-11 16:02:10 +01:00
|
|
|
core_ls = $(filter-out $1,$(shell echo $1))
|
2015-07-21 17:16:11 +02:00
|
|
|
|
2015-11-16 23:08:24 +01:00
|
|
|
# @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)
|
|
|
|
|
2020-03-29 15:45:51 +02:00
|
|
|
define core_render
|
2025-02-11 16:02:10 +01:00
|
|
|
printf -- '$(subst $(newline),\n,$(subst %,%%,$(subst ','\'',$(subst $(tab),$(WS),$(call $1)))))\n' > $2
|
2020-03-29 15:45:51 +02:00
|
|
|
endef
|
|
|
|
|
2014-11-07 14:25:34 +02:00
|
|
|
# Automated update.
|
|
|
|
|
2015-11-16 23:08:24 +01:00
|
|
|
ERLANG_MK_REPO ?= https://github.com/ninenines/erlang.mk
|
|
|
|
ERLANG_MK_COMMIT ?=
|
2014-11-07 14:25:34 +02:00
|
|
|
ERLANG_MK_BUILD_CONFIG ?= build.config
|
|
|
|
ERLANG_MK_BUILD_DIR ?= .erlang.mk.build
|
|
|
|
|
2017-07-14 21:44:39 +02:00
|
|
|
erlang-mk: WITHOUT ?= $(ERLANG_MK_WITHOUT)
|
2014-11-07 14:25:34 +02:00
|
|
|
erlang-mk:
|
2016-01-14 13:35:25 +01:00
|
|
|
ifdef ERLANG_MK_COMMIT
|
2020-03-29 15:45:51 +02:00
|
|
|
$(verbose) git clone $(ERLANG_MK_REPO) $(ERLANG_MK_BUILD_DIR)
|
|
|
|
$(verbose) cd $(ERLANG_MK_BUILD_DIR) && git checkout $(ERLANG_MK_COMMIT)
|
2018-05-02 18:23:03 +02:00
|
|
|
else
|
2020-03-29 15:45:51 +02:00
|
|
|
$(verbose) git clone --depth 1 $(ERLANG_MK_REPO) $(ERLANG_MK_BUILD_DIR)
|
2016-01-14 13:35:25 +01:00
|
|
|
endif
|
2020-03-29 15:45:51 +02:00
|
|
|
$(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)
|
2014-11-07 14:25:34 +02:00
|
|
|
|
2015-07-21 17:16:11 +02:00
|
|
|
# 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.
|
|
|
|
|
2017-11-19 13:25:54 +01:00
|
|
|
# Copyright (c) 2015-2017, Loïc Hoguin <essen@ninenines.eu>
|
|
|
|
# This file is part of erlang.mk and subject to the terms of the ISC License.
|
|
|
|
|
|
|
|
.PHONY: distclean-kerl
|
|
|
|
|
|
|
|
KERL_INSTALL_DIR ?= $(HOME)/erlang
|
|
|
|
|
|
|
|
ifeq ($(strip $(KERL)),)
|
|
|
|
KERL := $(ERLANG_MK_TMP)/kerl/kerl
|
|
|
|
endif
|
|
|
|
|
2018-09-12 14:59:35 +02:00
|
|
|
KERL_DIR = $(ERLANG_MK_TMP)/kerl
|
|
|
|
|
2017-11-19 13:25:54 +01:00
|
|
|
export KERL
|
|
|
|
|
|
|
|
KERL_GIT ?= https://github.com/kerl/kerl
|
|
|
|
KERL_COMMIT ?= master
|
|
|
|
|
|
|
|
KERL_MAKEFLAGS ?=
|
|
|
|
|
|
|
|
OTP_GIT ?= https://github.com/erlang/otp
|
|
|
|
|
|
|
|
define kerl_otp_target
|
2025-02-11 16:02:10 +01:00
|
|
|
$(KERL_INSTALL_DIR)/$1: $(KERL)
|
2020-03-29 15:45:51 +02:00
|
|
|
$(verbose) if [ ! -d $$@ ]; then \
|
2025-02-11 16:02:10 +01:00
|
|
|
MAKEFLAGS="$(KERL_MAKEFLAGS)" $(KERL) build git $(OTP_GIT) $1 $1; \
|
|
|
|
$(KERL) install $1 $(KERL_INSTALL_DIR)/$1; \
|
2020-03-29 15:45:51 +02:00
|
|
|
fi
|
2017-11-19 13:25:54 +01:00
|
|
|
endef
|
|
|
|
|
2018-09-12 14:59:35 +02:00
|
|
|
$(KERL): $(KERL_DIR)
|
|
|
|
|
2020-03-29 15:45:51 +02:00
|
|
|
$(KERL_DIR): | $(ERLANG_MK_TMP)
|
2017-11-19 13:25:54 +01:00
|
|
|
$(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)
|
|
|
|
|
|
|
|
distclean:: distclean-kerl
|
|
|
|
|
|
|
|
distclean-kerl:
|
2018-09-12 14:59:35 +02:00
|
|
|
$(gen_verbose) rm -rf $(KERL_DIR)
|
2017-11-19 13:25:54 +01:00
|
|
|
|
|
|
|
# Allow users to select which version of Erlang/OTP to use for a project.
|
|
|
|
|
2018-05-02 18:23:03 +02:00
|
|
|
ifneq ($(strip $(LATEST_ERLANG_OTP)),)
|
2020-03-29 15:45:51 +02:00
|
|
|
# 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%,\
|
2018-08-13 08:38:49 +02:00
|
|
|
$(filter-out %-rc1 %-rc2 %-rc3,$(wildcard $(KERL_INSTALL_DIR)/*[^-native]))))))
|
2018-05-02 18:23:03 +02:00
|
|
|
endif
|
|
|
|
|
2017-11-19 13:25:54 +01:00
|
|
|
ERLANG_OTP ?=
|
|
|
|
|
|
|
|
# Use kerl to enforce a specific Erlang/OTP version for a project.
|
|
|
|
ifneq ($(strip $(ERLANG_OTP)),)
|
2023-11-24 11:39:55 +01:00
|
|
|
|
2017-11-19 13:25:54 +01:00
|
|
|
export PATH := $(KERL_INSTALL_DIR)/$(ERLANG_OTP)/bin:$(PATH)
|
|
|
|
SHELL := env PATH=$(PATH) $(SHELL)
|
|
|
|
$(eval $(call kerl_otp_target,$(ERLANG_OTP)))
|
|
|
|
|
|
|
|
# Build Erlang/OTP only if it doesn't already exist.
|
|
|
|
ifeq ($(wildcard $(KERL_INSTALL_DIR)/$(ERLANG_OTP))$(BUILD_ERLANG_OTP),)
|
|
|
|
$(info Building Erlang/OTP $(ERLANG_OTP)... Please wait...)
|
|
|
|
$(shell $(MAKE) $(KERL_INSTALL_DIR)/$(ERLANG_OTP) ERLANG_OTP=$(ERLANG_OTP) BUILD_ERLANG_OTP=1 >&2)
|
|
|
|
endif
|
|
|
|
|
|
|
|
endif
|
|
|
|
|
2016-11-05 14:17:30 +02:00
|
|
|
PACKAGES += asciideck
|
|
|
|
pkg_asciideck_name = asciideck
|
|
|
|
pkg_asciideck_description = Asciidoc for Erlang.
|
|
|
|
pkg_asciideck_homepage = https://ninenines.eu
|
|
|
|
pkg_asciideck_fetch = git
|
|
|
|
pkg_asciideck_repo = https://github.com/ninenines/asciideck
|
|
|
|
pkg_asciideck_commit = master
|
2016-01-14 13:35:25 +01:00
|
|
|
|
|
|
|
PACKAGES += cowboy
|
|
|
|
pkg_cowboy_name = cowboy
|
|
|
|
pkg_cowboy_description = Small, fast and modular HTTP server.
|
|
|
|
pkg_cowboy_homepage = http://ninenines.eu
|
|
|
|
pkg_cowboy_fetch = git
|
|
|
|
pkg_cowboy_repo = https://github.com/ninenines/cowboy
|
2025-02-11 16:02:10 +01:00
|
|
|
pkg_cowboy_commit = master
|
2016-01-14 13:35:25 +01:00
|
|
|
|
|
|
|
PACKAGES += cowlib
|
|
|
|
pkg_cowlib_name = cowlib
|
|
|
|
pkg_cowlib_description = Support library for manipulating Web protocols.
|
|
|
|
pkg_cowlib_homepage = http://ninenines.eu
|
|
|
|
pkg_cowlib_fetch = git
|
|
|
|
pkg_cowlib_repo = https://github.com/ninenines/cowlib
|
2025-02-11 16:02:10 +01:00
|
|
|
pkg_cowlib_commit = master
|
2016-01-14 13:35:25 +01:00
|
|
|
|
|
|
|
PACKAGES += erlydtl
|
|
|
|
pkg_erlydtl_name = erlydtl
|
|
|
|
pkg_erlydtl_description = Django Template Language for Erlang.
|
|
|
|
pkg_erlydtl_homepage = https://github.com/erlydtl/erlydtl
|
|
|
|
pkg_erlydtl_fetch = git
|
|
|
|
pkg_erlydtl_repo = https://github.com/erlydtl/erlydtl
|
|
|
|
pkg_erlydtl_commit = master
|
|
|
|
|
|
|
|
PACKAGES += gpb
|
|
|
|
pkg_gpb_name = gpb
|
|
|
|
pkg_gpb_description = A Google Protobuf implementation for Erlang
|
|
|
|
pkg_gpb_homepage = https://github.com/tomas-abrahamsson/gpb
|
|
|
|
pkg_gpb_fetch = git
|
|
|
|
pkg_gpb_repo = https://github.com/tomas-abrahamsson/gpb
|
|
|
|
pkg_gpb_commit = master
|
|
|
|
|
|
|
|
PACKAGES += gun
|
|
|
|
pkg_gun_name = gun
|
|
|
|
pkg_gun_description = Asynchronous SPDY, HTTP and Websocket client written in Erlang.
|
|
|
|
pkg_gun_homepage = http//ninenines.eu
|
|
|
|
pkg_gun_fetch = git
|
|
|
|
pkg_gun_repo = https://github.com/ninenines/gun
|
|
|
|
pkg_gun_commit = master
|
|
|
|
|
2025-02-11 16:02:10 +01:00
|
|
|
PACKAGES += hex_core
|
|
|
|
pkg_hex_core_name = hex_core
|
|
|
|
pkg_hex_core_description = Reference implementation of Hex specifications
|
|
|
|
pkg_hex_core_homepage = https://github.com/hexpm/hex_core
|
|
|
|
pkg_hex_core_fetch = git
|
|
|
|
HEX_CORE_GIT ?= https://github.com/hexpm/hex_core
|
|
|
|
pkg_hex_core_repo = $(HEX_CORE_GIT)
|
|
|
|
pkg_hex_core_commit = e57b4fb15cde710b3ae09b1d18f148f6999a63cc
|
2016-01-14 13:35:25 +01:00
|
|
|
|
2016-12-02 19:23:19 +01:00
|
|
|
PACKAGES += proper
|
|
|
|
pkg_proper_name = proper
|
|
|
|
pkg_proper_description = PropEr: a QuickCheck-inspired property-based testing tool for Erlang.
|
|
|
|
pkg_proper_homepage = http://proper.softlab.ntua.gr
|
|
|
|
pkg_proper_fetch = git
|
|
|
|
pkg_proper_repo = https://github.com/manopapad/proper
|
|
|
|
pkg_proper_commit = master
|
|
|
|
|
2016-01-14 13:35:25 +01:00
|
|
|
PACKAGES += ranch
|
|
|
|
pkg_ranch_name = ranch
|
|
|
|
pkg_ranch_description = Socket acceptor pool for TCP protocols.
|
|
|
|
pkg_ranch_homepage = http://ninenines.eu
|
|
|
|
pkg_ranch_fetch = git
|
|
|
|
pkg_ranch_repo = https://github.com/ninenines/ranch
|
2025-02-11 16:02:10 +01:00
|
|
|
pkg_ranch_commit = master
|
2016-01-14 13:35:25 +01:00
|
|
|
|
|
|
|
PACKAGES += relx
|
|
|
|
pkg_relx_name = relx
|
|
|
|
pkg_relx_description = Sane, simple release creation for Erlang
|
|
|
|
pkg_relx_homepage = https://github.com/erlware/relx
|
|
|
|
pkg_relx_fetch = git
|
|
|
|
pkg_relx_repo = https://github.com/erlware/relx
|
2022-09-19 14:17:37 +02:00
|
|
|
pkg_relx_commit = main
|
2016-01-14 13:35:25 +01:00
|
|
|
|
|
|
|
PACKAGES += triq
|
|
|
|
pkg_triq_name = triq
|
|
|
|
pkg_triq_description = Trifork QuickCheck
|
2018-08-13 08:38:49 +02:00
|
|
|
pkg_triq_homepage = https://triq.gitlab.io
|
2016-01-14 13:35:25 +01:00
|
|
|
pkg_triq_fetch = git
|
2018-08-13 08:38:49 +02:00
|
|
|
pkg_triq_repo = https://gitlab.com/triq/triq.git
|
2016-01-14 13:35:25 +01:00
|
|
|
pkg_triq_commit = master
|
|
|
|
|
2016-11-05 14:17:30 +02:00
|
|
|
# Copyright (c) 2015-2016, Loïc Hoguin <essen@ninenines.eu>
|
2016-01-14 13:35:25 +01:00
|
|
|
# This file is part of erlang.mk and subject to the terms of the ISC License.
|
|
|
|
|
|
|
|
.PHONY: search
|
|
|
|
|
|
|
|
define pkg_print
|
|
|
|
$(verbose) printf "%s\n" \
|
2025-02-11 16:02:10 +01:00
|
|
|
$(if $(call core_eq,$1,$(pkg_$(1)_name)),,"Pkg name: $1") \
|
2016-01-14 13:35:25 +01:00
|
|
|
"App name: $(pkg_$(1)_name)" \
|
|
|
|
"Description: $(pkg_$(1)_description)" \
|
|
|
|
"Home page: $(pkg_$(1)_homepage)" \
|
|
|
|
"Fetch with: $(pkg_$(1)_fetch)" \
|
|
|
|
"Repository: $(pkg_$(1)_repo)" \
|
|
|
|
"Commit: $(pkg_$(1)_commit)" \
|
|
|
|
""
|
|
|
|
|
|
|
|
endef
|
|
|
|
|
|
|
|
search:
|
|
|
|
ifdef q
|
|
|
|
$(foreach p,$(PACKAGES), \
|
2025-02-11 16:02:10 +01:00
|
|
|
$(if $(findstring $(call core_lc,$q),$(call core_lc,$(pkg_$(p)_name) $(pkg_$(p)_description))), \
|
|
|
|
$(call pkg_print,$p)))
|
2016-01-14 13:35:25 +01:00
|
|
|
else
|
2025-02-11 16:02:10 +01:00
|
|
|
$(foreach p,$(PACKAGES),$(call pkg_print,$p))
|
2016-01-14 13:35:25 +01:00
|
|
|
endif
|
|
|
|
|
2016-11-05 14:17:30 +02:00
|
|
|
# Copyright (c) 2013-2016, Loïc Hoguin <essen@ninenines.eu>
|
2014-08-01 14:26:51 +02:00
|
|
|
# This file is part of erlang.mk and subject to the terms of the ISC License.
|
2013-04-30 20:51:37 +02:00
|
|
|
|
2017-07-14 21:44:39 +02:00
|
|
|
.PHONY: distclean-deps clean-tmp-deps.log
|
2013-04-30 20:51:37 +02:00
|
|
|
|
2014-08-01 14:26:51 +02:00
|
|
|
# Configuration.
|
2013-04-30 20:51:37 +02:00
|
|
|
|
2015-11-16 23:08:24 +01:00
|
|
|
ifdef OTP_DEPS
|
|
|
|
$(warning The variable OTP_DEPS is deprecated in favor of LOCAL_DEPS.)
|
|
|
|
endif
|
|
|
|
|
2015-06-11 17:04:21 +02:00
|
|
|
IGNORE_DEPS ?=
|
2015-11-16 23:08:24 +01:00
|
|
|
export IGNORE_DEPS
|
|
|
|
|
|
|
|
APPS_DIR ?= $(CURDIR)/apps
|
|
|
|
export APPS_DIR
|
2015-05-05 19:59:37 +03:00
|
|
|
|
2014-08-01 14:26:51 +02:00
|
|
|
DEPS_DIR ?= $(CURDIR)/deps
|
|
|
|
export DEPS_DIR
|
2013-04-30 20:51:37 +02:00
|
|
|
|
2014-08-01 14:26:51 +02:00
|
|
|
REBAR_DEPS_DIR = $(DEPS_DIR)
|
|
|
|
export REBAR_DEPS_DIR
|
2013-08-24 10:48:59 +02:00
|
|
|
|
2024-11-06 16:33:39 +01:00
|
|
|
# When testing Erlang.mk and updating these, make sure
|
|
|
|
# to delete test/test_rebar_git before running tests again.
|
2023-11-24 11:39:55 +01:00
|
|
|
REBAR3_GIT ?= https://github.com/erlang/rebar3
|
2024-11-06 16:33:39 +01:00
|
|
|
REBAR3_COMMIT ?= bde4b54248d16280b2c70a244aca3bb7566e2033 # 3.23.0
|
2023-11-24 11:39:55 +01:00
|
|
|
|
|
|
|
CACHE_DEPS ?= 0
|
|
|
|
|
|
|
|
CACHE_DIR ?= $(if $(XDG_CACHE_HOME),$(XDG_CACHE_HOME),$(HOME)/.cache)/erlang.mk
|
|
|
|
export CACHE_DIR
|
2020-03-29 15:45:51 +02:00
|
|
|
|
2025-02-11 16:02:10 +01:00
|
|
|
HEX_CONFIG ?=
|
|
|
|
|
|
|
|
define hex_config.erl
|
|
|
|
begin
|
|
|
|
Config0 = hex_core:default_config(),
|
|
|
|
Config0$(HEX_CONFIG)
|
|
|
|
end
|
|
|
|
endef
|
|
|
|
|
2017-07-14 21:44:39 +02:00
|
|
|
# External "early" plugins (see core/plugins.mk for regular plugins).
|
|
|
|
# They both use the core_dep_plugin macro.
|
|
|
|
|
|
|
|
define core_dep_plugin
|
2025-02-11 16:02:10 +01:00
|
|
|
ifeq ($2,$(PROJECT))
|
|
|
|
-include $$(patsubst $(PROJECT)/%,%,$1)
|
2017-07-14 21:44:39 +02:00
|
|
|
else
|
2025-02-11 16:02:10 +01:00
|
|
|
-include $(DEPS_DIR)/$1
|
2017-07-14 21:44:39 +02:00
|
|
|
|
2025-02-11 16:02:10 +01:00
|
|
|
$(DEPS_DIR)/$1: $(DEPS_DIR)/$2 ;
|
2017-07-14 21:44:39 +02:00
|
|
|
endif
|
|
|
|
endef
|
|
|
|
|
|
|
|
DEP_EARLY_PLUGINS ?=
|
|
|
|
|
|
|
|
$(foreach p,$(DEP_EARLY_PLUGINS),\
|
|
|
|
$(eval $(if $(findstring /,$p),\
|
|
|
|
$(call core_dep_plugin,$p,$(firstword $(subst /, ,$p))),\
|
|
|
|
$(call core_dep_plugin,$p/early-plugins.mk,$p))))
|
|
|
|
|
2020-03-29 15:45:51 +02:00
|
|
|
# Query functions.
|
|
|
|
|
2025-02-11 16:02:10 +01:00
|
|
|
query_fetch_method = $(if $(dep_$(1)),$(call _qfm_dep,$(word 1,$(dep_$(1)))),$(call _qfm_pkg,$1))
|
|
|
|
_qfm_dep = $(if $(dep_fetch_$(1)),$1,fail)
|
2020-03-29 15:45:51 +02:00
|
|
|
_qfm_pkg = $(if $(pkg_$(1)_fetch),$(pkg_$(1)_fetch),fail)
|
|
|
|
|
2025-02-11 16:02:10 +01:00
|
|
|
query_name = $(if $(dep_$(1)),$1,$(if $(pkg_$(1)_name),$(pkg_$(1)_name),$1))
|
2020-03-29 15:45:51 +02:00
|
|
|
|
2025-02-11 16:02:10 +01:00
|
|
|
query_repo = $(call _qr,$1,$(call query_fetch_method,$1))
|
|
|
|
_qr = $(if $(query_repo_$(2)),$(call query_repo_$(2),$1),$(call query_repo_git,$1))
|
2020-03-29 15:45:51 +02:00
|
|
|
|
|
|
|
query_repo_default = $(if $(dep_$(1)),$(word 2,$(dep_$(1))),$(pkg_$(1)_repo))
|
2025-02-11 16:02:10 +01:00
|
|
|
query_repo_git = $(patsubst git://github.com/%,https://github.com/%,$(call query_repo_default,$1))
|
|
|
|
query_repo_git-subfolder = $(call query_repo_git,$1)
|
2020-03-29 15:45:51 +02:00
|
|
|
query_repo_git-submodule = -
|
2025-02-11 16:02:10 +01:00
|
|
|
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)
|
2020-03-29 15:45:51 +02:00
|
|
|
query_repo_fail = -
|
|
|
|
|
2025-02-11 16:02:10 +01:00
|
|
|
query_version = $(call _qv,$1,$(call query_fetch_method,$1))
|
|
|
|
_qv = $(if $(query_version_$(2)),$(call query_version_$(2),$1),$(call query_version_default,$1))
|
2020-03-29 15:45:51 +02:00
|
|
|
|
|
|
|
query_version_default = $(if $(dep_$(1)_commit),$(dep_$(1)_commit),$(if $(dep_$(1)),$(word 3,$(dep_$(1))),$(pkg_$(1)_commit)))
|
2025-02-11 16:02:10 +01:00
|
|
|
query_version_git = $(call query_version_default,$1)
|
|
|
|
query_version_git-subfolder = $(call query_version_default,$1)
|
2020-03-29 15:45:51 +02:00
|
|
|
query_version_git-submodule = -
|
2025-02-11 16:02:10 +01:00
|
|
|
query_version_hg = $(call query_version_default,$1)
|
2020-03-29 15:45:51 +02:00
|
|
|
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 = -
|
|
|
|
|
2025-02-11 16:02:10 +01:00
|
|
|
query_extra = $(call _qe,$1,$(call query_fetch_method,$1))
|
|
|
|
_qe = $(if $(query_extra_$(2)),$(call query_extra_$(2),$1),-)
|
2020-03-29 15:45:51 +02:00
|
|
|
|
|
|
|
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 = -
|
|
|
|
|
2025-02-11 16:02:10 +01:00
|
|
|
query_absolute_path = $(addprefix $(DEPS_DIR)/,$(call query_name,$1))
|
2020-03-29 15:45:51 +02:00
|
|
|
|
2025-02-11 16:02:10 +01:00
|
|
|
# Deprecated legacy query function. Used by RabbitMQ and its third party plugins.
|
|
|
|
# Can be removed once RabbitMQ has been updated and enough time has passed.
|
2020-03-29 15:45:51 +02:00
|
|
|
dep_name = $(call query_name,$(1))
|
2013-06-19 16:35:51 +02:00
|
|
|
|
2025-02-11 16:02:10 +01:00
|
|
|
# Application directories.
|
|
|
|
|
|
|
|
LOCAL_DEPS_DIRS = $(foreach a,$(LOCAL_DEPS),$(if $(wildcard $(APPS_DIR)/$a),$(APPS_DIR)/$a))
|
|
|
|
ALL_DEPS_DIRS = $(addprefix $(DEPS_DIR)/,$(foreach dep,$(filter-out $(IGNORE_DEPS),$(BUILD_DEPS) $(DEPS)),$(call query_name,$(dep))))
|
2015-11-16 23:08:24 +01:00
|
|
|
|
2020-03-29 15:45:51 +02:00
|
|
|
# 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
|
|
|
|
|
2015-11-16 23:08:24 +01:00
|
|
|
ifeq ($(filter $(APPS_DIR) $(DEPS_DIR),$(subst :, ,$(ERL_LIBS))),)
|
2014-08-01 14:26:51 +02:00
|
|
|
ifeq ($(ERL_LIBS),)
|
2015-11-16 23:08:24 +01:00
|
|
|
ERL_LIBS = $(APPS_DIR):$(DEPS_DIR)
|
2014-08-01 14:26:51 +02:00
|
|
|
else
|
2015-11-16 23:08:24 +01:00
|
|
|
ERL_LIBS := $(ERL_LIBS):$(APPS_DIR):$(DEPS_DIR)
|
2014-08-01 14:26:51 +02:00
|
|
|
endif
|
|
|
|
endif
|
|
|
|
export ERL_LIBS
|
2013-04-30 20:51:37 +02:00
|
|
|
|
2015-11-16 23:08:24 +01:00
|
|
|
export NO_AUTOPATCH
|
|
|
|
|
2015-06-11 17:04:21 +02:00
|
|
|
# Verbosity.
|
|
|
|
|
2025-02-11 16:02:10 +01:00
|
|
|
dep_verbose_0 = @echo " DEP $1 ($(call query_version,$1))";
|
2016-01-14 13:35:25 +01:00
|
|
|
dep_verbose_2 = set -x;
|
2015-06-11 17:04:21 +02:00
|
|
|
dep_verbose = $(dep_verbose_$(V))
|
|
|
|
|
2020-03-29 15:45:51 +02:00
|
|
|
# Optimization: don't recompile deps unless truly necessary.
|
2013-10-14 16:05:19 +02:00
|
|
|
|
2020-03-29 15:45:51 +02:00
|
|
|
ifndef IS_DEP
|
|
|
|
ifneq ($(MAKELEVEL),0)
|
|
|
|
$(shell rm -f ebin/dep_built)
|
2016-11-05 14:17:30 +02:00
|
|
|
endif
|
2020-03-29 15:45:51 +02:00
|
|
|
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)
|
2016-11-05 14:17:30 +02:00
|
|
|
# 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.
|
2017-07-14 21:44:39 +02:00
|
|
|
ifndef IS_APP
|
2020-03-29 15:45:51 +02:00
|
|
|
ifneq ($(ALL_APPS_DIRS),)
|
2017-07-14 21:44:39 +02:00
|
|
|
$(verbose) set -e; for dep in $(ALL_APPS_DIRS) ; do \
|
|
|
|
mkdir -p $$dep/ebin; \
|
2016-11-05 14:17:30 +02:00
|
|
|
done
|
2017-07-14 21:44:39 +02:00
|
|
|
endif
|
2020-03-29 15:45:51 +02:00
|
|
|
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 \
|
2016-11-05 14:17:30 +02:00
|
|
|
if grep -qs ^$$dep$$ $(ERLANG_MK_TMP)/apps.log; then \
|
|
|
|
:; \
|
|
|
|
else \
|
|
|
|
echo $$dep >> $(ERLANG_MK_TMP)/apps.log; \
|
2020-03-29 15:45:51 +02:00
|
|
|
$(MAKE) -C $$dep $(if $(IS_TEST),test-build-app) IS_APP=1; \
|
2016-11-05 14:17:30 +02:00
|
|
|
fi \
|
2015-11-16 23:08:24 +01:00
|
|
|
done
|
2020-03-29 15:45:51 +02:00
|
|
|
endif
|
2017-07-14 21:44:39 +02:00
|
|
|
|
|
|
|
clean-tmp-deps.log:
|
|
|
|
ifeq ($(IS_APP)$(IS_DEP),)
|
2020-03-29 15:45:51 +02:00
|
|
|
$(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
|
2015-11-16 23:08:24 +01:00
|
|
|
endif
|
2016-11-05 14:17:30 +02:00
|
|
|
|
|
|
|
ifneq ($(SKIP_DEPS),)
|
|
|
|
deps::
|
|
|
|
else
|
2020-03-29 15:45:51 +02:00
|
|
|
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 \
|
2015-07-21 17:16:11 +02:00
|
|
|
if grep -qs ^$$dep$$ $(ERLANG_MK_TMP)/deps.log; then \
|
2016-01-14 13:35:25 +01:00
|
|
|
:; \
|
2014-08-01 14:26:51 +02:00
|
|
|
else \
|
2015-07-21 17:16:11 +02:00
|
|
|
echo $$dep >> $(ERLANG_MK_TMP)/deps.log; \
|
2020-03-29 15:45:51 +02:00
|
|
|
if [ -z "$(strip $(FULL))" ] $(if $(force_rebuild_dep),&& ! ($(call force_rebuild_dep,$$dep)),) && [ ! -L $$dep ] && [ -f $$dep/ebin/dep_built ]; then \
|
|
|
|
:; \
|
2023-11-24 11:39:55 +01:00
|
|
|
elif [ "$$dep" = "$(DEPS_DIR)/hut" -a "$(HUT_PATCH)" ]; then \
|
|
|
|
$(MAKE) -C $$dep app IS_DEP=1; \
|
|
|
|
if [ ! -L $$dep ] && [ -d $$dep/ebin ]; then touch $$dep/ebin/dep_built; fi; \
|
2020-03-29 15:45:51 +02:00
|
|
|
elif [ -f $$dep/GNUmakefile ] || [ -f $$dep/makefile ] || [ -f $$dep/Makefile ]; then \
|
2017-07-14 21:44:39 +02:00
|
|
|
$(MAKE) -C $$dep IS_DEP=1; \
|
2020-03-29 15:45:51 +02:00
|
|
|
if [ ! -L $$dep ] && [ -d $$dep/ebin ]; then touch $$dep/ebin/dep_built; fi; \
|
2015-07-21 17:16:11 +02:00
|
|
|
else \
|
2017-07-14 21:44:39 +02:00
|
|
|
echo "Error: No Makefile to build dependency $$dep." >&2; \
|
2015-11-16 23:08:24 +01:00
|
|
|
exit 2; \
|
2015-07-21 17:16:11 +02:00
|
|
|
fi \
|
|
|
|
fi \
|
2014-08-01 14:26:51 +02:00
|
|
|
done
|
2015-06-11 17:04:21 +02:00
|
|
|
endif
|
2020-03-29 15:45:51 +02:00
|
|
|
endif
|
2013-10-14 16:05:19 +02:00
|
|
|
|
2014-08-01 14:26:51 +02:00
|
|
|
# Deps related targets.
|
2014-06-30 10:14:05 +02:00
|
|
|
|
2015-06-11 17:04:21 +02:00
|
|
|
# @todo rename GNUmakefile and makefile into Makefile first, if they exist
|
|
|
|
# While Makefile file could be GNUmakefile or makefile,
|
|
|
|
# in practice only Makefile is needed so far.
|
2015-05-05 19:59:37 +03:00
|
|
|
define dep_autopatch
|
2025-02-11 16:02:10 +01:00
|
|
|
if [ -f $(DEPS_DIR)/$1/erlang.mk ]; then \
|
2016-12-02 19:23:19 +01:00
|
|
|
rm -rf $(DEPS_DIR)/$1/ebin/; \
|
2025-02-11 16:02:10 +01:00
|
|
|
$(call erlang,$(call dep_autopatch_appsrc.erl,$1)); \
|
|
|
|
$(call dep_autopatch_erlang_mk,$1); \
|
|
|
|
elif [ -f $(DEPS_DIR)/$1/Makefile ]; then \
|
2017-07-14 21:44:39 +02:00
|
|
|
if [ -f $(DEPS_DIR)/$1/rebar.lock ]; then \
|
|
|
|
$(call dep_autopatch2,$1); \
|
2025-02-11 16:02:10 +01:00
|
|
|
elif [ 0 != `grep -c "include ../\w*\.mk" $(DEPS_DIR)/$1/Makefile` ]; then \
|
|
|
|
$(call dep_autopatch2,$1); \
|
|
|
|
elif [ 0 != `grep -ci "^[^#].*rebar" $(DEPS_DIR)/$1/Makefile` ]; then \
|
|
|
|
$(call dep_autopatch2,$1); \
|
|
|
|
elif [ -n "`find $(DEPS_DIR)/$1/ -type f -name \*.mk -not -name erlang.mk -exec grep -i "^[^#].*rebar" '{}' \;`" ]; then \
|
|
|
|
$(call dep_autopatch2,$1); \
|
2015-06-11 17:04:21 +02:00
|
|
|
fi \
|
|
|
|
else \
|
2025-02-11 16:02:10 +01:00
|
|
|
if [ ! -d $(DEPS_DIR)/$1/src/ ]; then \
|
|
|
|
$(call dep_autopatch_noop,$1); \
|
2015-06-11 17:04:21 +02:00
|
|
|
else \
|
2025-02-11 16:02:10 +01:00
|
|
|
$(call dep_autopatch2,$1); \
|
2015-06-11 17:04:21 +02:00
|
|
|
fi \
|
|
|
|
fi
|
2015-05-05 19:59:37 +03:00
|
|
|
endef
|
|
|
|
|
2015-06-11 17:04:21 +02:00
|
|
|
define dep_autopatch2
|
2017-07-14 21:44:39 +02:00
|
|
|
! test -f $(DEPS_DIR)/$1/ebin/$1.app || \
|
2016-12-02 19:23:19 +01:00
|
|
|
mv -n $(DEPS_DIR)/$1/ebin/$1.app $(DEPS_DIR)/$1/src/$1.app.src; \
|
|
|
|
rm -f $(DEPS_DIR)/$1/ebin/$1.app; \
|
2016-01-14 13:35:25 +01:00
|
|
|
if [ -f $(DEPS_DIR)/$1/src/$1.app.src.script ]; then \
|
2025-02-11 16:02:10 +01:00
|
|
|
$(call erlang,$(call dep_autopatch_appsrc_script.erl,$1)); \
|
2016-01-14 13:35:25 +01:00
|
|
|
fi; \
|
2025-02-11 16:02:10 +01:00
|
|
|
$(call erlang,$(call dep_autopatch_appsrc.erl,$1)); \
|
|
|
|
if [ -f $(DEPS_DIR)/$1/rebar -o -f $(DEPS_DIR)/$1/rebar.config -o -f $(DEPS_DIR)/$1/rebar.config.script -o -f $(DEPS_DIR)/$1/rebar.lock ]; then \
|
2015-06-11 17:04:21 +02:00
|
|
|
$(call dep_autopatch_fetch_rebar); \
|
2025-02-11 16:02:10 +01:00
|
|
|
$(call dep_autopatch_rebar,$1); \
|
2015-06-11 17:04:21 +02:00
|
|
|
else \
|
2025-02-11 16:02:10 +01:00
|
|
|
$(call dep_autopatch_gen,$1); \
|
2015-06-11 17:04:21 +02:00
|
|
|
fi
|
|
|
|
endef
|
|
|
|
|
|
|
|
define dep_autopatch_noop
|
2025-02-11 16:02:10 +01:00
|
|
|
printf "noop:\n" > $(DEPS_DIR)/$1/Makefile
|
2015-06-11 17:04:21 +02:00
|
|
|
endef
|
|
|
|
|
2017-07-14 21:44:39 +02:00
|
|
|
# Replace "include erlang.mk" with a line that will load the parent Erlang.mk
|
|
|
|
# if given. Do it for all 3 possible Makefile file names.
|
2015-06-11 17:04:21 +02:00
|
|
|
ifeq ($(NO_AUTOPATCH_ERLANG_MK),)
|
|
|
|
define dep_autopatch_erlang_mk
|
2017-11-19 13:25:54 +01:00
|
|
|
for f in Makefile makefile GNUmakefile; do \
|
2017-07-14 21:44:39 +02:00
|
|
|
if [ -f $(DEPS_DIR)/$1/$$f ]; then \
|
|
|
|
sed -i.bak s/'include *erlang.mk'/'include $$(if $$(ERLANG_MK_FILENAME),$$(ERLANG_MK_FILENAME),erlang.mk)'/ $(DEPS_DIR)/$1/$$f; \
|
|
|
|
fi \
|
|
|
|
done
|
2015-06-11 17:04:21 +02:00
|
|
|
endef
|
|
|
|
else
|
|
|
|
define dep_autopatch_erlang_mk
|
2016-01-14 13:35:25 +01:00
|
|
|
:
|
2015-05-05 19:59:37 +03:00
|
|
|
endef
|
|
|
|
endif
|
|
|
|
|
2015-06-11 17:04:21 +02:00
|
|
|
define dep_autopatch_gen
|
|
|
|
printf "%s\n" \
|
|
|
|
"ERLC_OPTS = +debug_info" \
|
2025-02-11 16:02:10 +01:00
|
|
|
"include ../../erlang.mk" > $(DEPS_DIR)/$1/Makefile
|
2015-06-11 17:04:21 +02:00
|
|
|
endef
|
|
|
|
|
2020-03-29 15:45:51 +02:00
|
|
|
# We use flock/lockf when available to avoid concurrency issues.
|
2015-06-11 17:04:21 +02:00
|
|
|
define dep_autopatch_fetch_rebar
|
2020-03-29 15:45:51 +02:00
|
|
|
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
|
2023-11-24 11:39:55 +01:00
|
|
|
if [ ! -d $(ERLANG_MK_TMP)/rebar3 ]; then \
|
|
|
|
git clone -q -n -- $(REBAR3_GIT) $(ERLANG_MK_TMP)/rebar3; \
|
|
|
|
cd $(ERLANG_MK_TMP)/rebar3; \
|
|
|
|
git checkout -q $(REBAR3_COMMIT); \
|
2020-03-29 15:45:51 +02:00
|
|
|
./bootstrap; \
|
2015-06-11 17:04:21 +02:00
|
|
|
cd -; \
|
|
|
|
fi
|
|
|
|
endef
|
|
|
|
|
|
|
|
define dep_autopatch_rebar
|
2025-02-11 16:02:10 +01:00
|
|
|
if [ -f $(DEPS_DIR)/$1/Makefile ]; then \
|
|
|
|
mv $(DEPS_DIR)/$1/Makefile $(DEPS_DIR)/$1/Makefile.orig.mk; \
|
2015-06-11 17:04:21 +02:00
|
|
|
fi; \
|
2025-02-11 16:02:10 +01:00
|
|
|
$(call erlang,$(call dep_autopatch_rebar.erl,$1)); \
|
|
|
|
rm -f $(DEPS_DIR)/$1/ebin/$1.app
|
2015-06-11 17:04:21 +02:00
|
|
|
endef
|
|
|
|
|
|
|
|
define dep_autopatch_rebar.erl
|
2015-11-16 23:08:24 +01:00
|
|
|
application:load(rebar),
|
2015-06-11 17:04:21 +02:00
|
|
|
application:set_env(rebar, log_level, debug),
|
2023-11-24 11:39:55 +01:00
|
|
|
{module, rebar3} = c:l(rebar3),
|
2015-11-16 23:08:24 +01:00
|
|
|
Conf1 = case file:consult("$(call core_native_path,$(DEPS_DIR)/$1/rebar.config)") of
|
2015-06-11 17:04:21 +02:00
|
|
|
{ok, Conf0} -> Conf0;
|
|
|
|
_ -> []
|
|
|
|
end,
|
|
|
|
{Conf, OsEnv} = fun() ->
|
2015-11-16 23:08:24 +01:00
|
|
|
case filelib:is_file("$(call core_native_path,$(DEPS_DIR)/$1/rebar.config.script)") of
|
2015-06-11 17:04:21 +02:00
|
|
|
false -> {Conf1, []};
|
|
|
|
true ->
|
|
|
|
Bindings0 = erl_eval:new_bindings(),
|
|
|
|
Bindings1 = erl_eval:add_binding('CONFIG', Conf1, Bindings0),
|
2015-11-16 23:08:24 +01:00
|
|
|
Bindings = erl_eval:add_binding('SCRIPT', "$(call core_native_path,$(DEPS_DIR)/$1/rebar.config.script)", Bindings1),
|
2015-06-11 17:04:21 +02:00
|
|
|
Before = os:getenv(),
|
2015-11-16 23:08:24 +01:00
|
|
|
{ok, Conf2} = file:script("$(call core_native_path,$(DEPS_DIR)/$1/rebar.config.script)", Bindings),
|
2015-06-11 17:04:21 +02:00
|
|
|
{Conf2, lists:foldl(fun(E, Acc) -> lists:delete(E, Acc) end, os:getenv(), Before)}
|
|
|
|
end
|
|
|
|
end(),
|
|
|
|
Write = fun (Text) ->
|
2015-11-16 23:08:24 +01:00
|
|
|
file:write_file("$(call core_native_path,$(DEPS_DIR)/$1/Makefile)", Text, [append])
|
2015-06-11 17:04:21 +02:00
|
|
|
end,
|
|
|
|
Escape = fun (Text) ->
|
2016-01-14 13:35:25 +01:00
|
|
|
re:replace(Text, "\\\\$$", "\$$$$", [global, {return, list}])
|
2015-06-11 17:04:21 +02:00
|
|
|
end,
|
2015-11-16 23:08:24 +01:00
|
|
|
Write("IGNORE_DEPS += edown eper eunit_formatters meck node_package "
|
2015-06-11 17:04:21 +02:00
|
|
|
"rebar_lock_deps_plugin rebar_vsn_plugin reltool_util\n"),
|
|
|
|
Write("C_SRC_DIR = /path/do/not/exist\n"),
|
2015-11-16 23:08:24 +01:00
|
|
|
Write("C_SRC_TYPE = rebar\n"),
|
2015-06-11 17:04:21 +02:00
|
|
|
Write("DRV_CFLAGS = -fPIC\nexport DRV_CFLAGS\n"),
|
|
|
|
Write(["ERLANG_ARCH = ", rebar_utils:wordsize(), "\nexport ERLANG_ARCH\n"]),
|
2017-11-19 13:25:54 +01:00
|
|
|
ToList = fun
|
|
|
|
(V) when is_atom(V) -> atom_to_list(V);
|
|
|
|
(V) when is_list(V) -> "'\\"" ++ V ++ "\\"'"
|
|
|
|
end,
|
2015-06-11 17:04:21 +02:00
|
|
|
fun() ->
|
2023-11-24 11:39:55 +01:00
|
|
|
Write("ERLC_OPTS = +debug_info\n"),
|
2015-06-11 17:04:21 +02:00
|
|
|
case lists:keyfind(erl_opts, 1, Conf) of
|
|
|
|
false -> ok;
|
|
|
|
{_, ErlOpts} ->
|
|
|
|
lists:foreach(fun
|
|
|
|
({d, D}) ->
|
2017-11-19 13:25:54 +01:00
|
|
|
Write("ERLC_OPTS += -D" ++ ToList(D) ++ "=1\n");
|
|
|
|
({d, DKey, DVal}) ->
|
|
|
|
Write("ERLC_OPTS += -D" ++ ToList(DKey) ++ "=" ++ ToList(DVal) ++ "\n");
|
2015-06-11 17:04:21 +02:00
|
|
|
({i, I}) ->
|
|
|
|
Write(["ERLC_OPTS += -I ", I, "\n"]);
|
|
|
|
({platform_define, Regex, D}) ->
|
|
|
|
case rebar_utils:is_arch(Regex) of
|
2017-11-19 13:25:54 +01:00
|
|
|
true -> Write("ERLC_OPTS += -D" ++ ToList(D) ++ "=1\n");
|
2015-06-11 17:04:21 +02:00
|
|
|
false -> ok
|
|
|
|
end;
|
|
|
|
({parse_transform, PT}) ->
|
2017-11-19 13:25:54 +01:00
|
|
|
Write("ERLC_OPTS += +'{parse_transform, " ++ ToList(PT) ++ "}'\n");
|
2015-06-11 17:04:21 +02:00
|
|
|
(_) -> ok
|
|
|
|
end, ErlOpts)
|
|
|
|
end,
|
|
|
|
Write("\n")
|
|
|
|
end(),
|
2023-11-24 11:39:55 +01:00
|
|
|
GetHexVsn2 = fun(N, NP) ->
|
2018-05-02 18:23:03 +02:00
|
|
|
case file:consult("$(call core_native_path,$(DEPS_DIR)/$1/rebar.lock)") of
|
|
|
|
{ok, Lock} ->
|
|
|
|
io:format("~p~n", [Lock]),
|
2021-05-12 10:24:40 +02:00
|
|
|
LockPkgs = case lists:keyfind("1.2.0", 1, Lock) of
|
|
|
|
{_, LP} ->
|
|
|
|
LP;
|
|
|
|
_ ->
|
|
|
|
case lists:keyfind("1.1.0", 1, Lock) of
|
|
|
|
{_, LP} ->
|
|
|
|
LP;
|
|
|
|
_ ->
|
|
|
|
false
|
|
|
|
end
|
|
|
|
end,
|
|
|
|
if
|
|
|
|
is_list(LockPkgs) ->
|
2018-05-02 18:23:03 +02:00
|
|
|
io:format("~p~n", [LockPkgs]),
|
|
|
|
case lists:keyfind(atom_to_binary(N, latin1), 1, LockPkgs) of
|
|
|
|
{_, {pkg, _, Vsn}, _} ->
|
|
|
|
io:format("~p~n", [Vsn]),
|
2020-03-29 15:45:51 +02:00
|
|
|
{N, {hex, NP, binary_to_list(Vsn)}};
|
2018-05-02 18:23:03 +02:00
|
|
|
_ ->
|
|
|
|
false
|
|
|
|
end;
|
2021-05-12 10:24:40 +02:00
|
|
|
true ->
|
2018-05-02 18:23:03 +02:00
|
|
|
false
|
|
|
|
end;
|
|
|
|
_ ->
|
|
|
|
false
|
|
|
|
end
|
|
|
|
end,
|
2023-11-24 11:39:55 +01:00
|
|
|
GetHexVsn3Common = fun(N, NP, S0) ->
|
|
|
|
case GetHexVsn2(N, NP) of
|
|
|
|
false ->
|
|
|
|
S2 = case S0 of
|
|
|
|
" " ++ S1 -> S1;
|
|
|
|
_ -> S0
|
|
|
|
end,
|
|
|
|
S = case length([ok || $$. <- S2]) of
|
|
|
|
0 -> S2 ++ ".0.0";
|
|
|
|
1 -> S2 ++ ".0";
|
|
|
|
_ -> S2
|
|
|
|
end,
|
|
|
|
{N, {hex, NP, S}};
|
|
|
|
NameSource ->
|
|
|
|
NameSource
|
|
|
|
end
|
|
|
|
end,
|
|
|
|
GetHexVsn3 = fun
|
|
|
|
(N, NP, "~>" ++ S0) ->
|
|
|
|
GetHexVsn3Common(N, NP, S0);
|
|
|
|
(N, NP, ">=" ++ S0) ->
|
|
|
|
GetHexVsn3Common(N, NP, S0);
|
|
|
|
(N, NP, S) -> {N, {hex, NP, S}}
|
2020-03-29 15:45:51 +02:00
|
|
|
end,
|
2025-02-11 16:02:10 +01:00
|
|
|
ConvertCommit = fun
|
|
|
|
({branch, C}) -> C;
|
|
|
|
({ref, C}) -> C;
|
|
|
|
({tag, C}) -> C;
|
|
|
|
(C) -> C
|
|
|
|
end,
|
2015-06-11 17:04:21 +02:00
|
|
|
fun() ->
|
|
|
|
File = case lists:keyfind(deps, 1, Conf) of
|
|
|
|
false -> [];
|
|
|
|
{_, Deps} ->
|
|
|
|
[begin case case Dep of
|
2023-11-24 11:39:55 +01:00
|
|
|
N when is_atom(N) -> GetHexVsn2(N, N);
|
|
|
|
{N, S} when is_atom(N), is_list(S) -> GetHexVsn3(N, N, S);
|
|
|
|
{N, {pkg, NP}} when is_atom(N) -> GetHexVsn2(N, NP);
|
|
|
|
{N, S, {pkg, NP}} -> GetHexVsn3(N, NP, S);
|
2015-06-11 17:04:21 +02:00
|
|
|
{N, S} when is_tuple(S) -> {N, S};
|
|
|
|
{N, _, S} -> {N, S};
|
|
|
|
{N, _, S, _} -> {N, S};
|
|
|
|
_ -> false
|
|
|
|
end of
|
|
|
|
false -> ok;
|
2025-02-11 16:02:10 +01:00
|
|
|
{Name, {git_subdir, Repo, Commit, SubDir}} ->
|
|
|
|
Write(io_lib:format("DEPS += ~s\ndep_~s = git-subfolder ~s ~s ~s~n", [Name, Name, Repo, ConvertCommit(Commit), SubDir]));
|
2015-06-11 17:04:21 +02:00
|
|
|
{Name, Source} ->
|
|
|
|
{Method, Repo, Commit} = case Source of
|
2020-03-29 15:45:51 +02:00
|
|
|
{hex, NPV, V} -> {hex, V, NPV};
|
2015-06-11 17:04:21 +02:00
|
|
|
{git, R} -> {git, R, master};
|
|
|
|
{M, R, C} -> {M, R, C}
|
|
|
|
end,
|
2025-02-11 16:02:10 +01:00
|
|
|
Write(io_lib:format("DEPS += ~s\ndep_~s = ~s ~s ~s~n", [Name, Name, Method, Repo, ConvertCommit(Commit)]))
|
2015-06-11 17:04:21 +02:00
|
|
|
end end || Dep <- Deps]
|
|
|
|
end
|
|
|
|
end(),
|
|
|
|
fun() ->
|
|
|
|
case lists:keyfind(erl_first_files, 1, Conf) of
|
|
|
|
false -> ok;
|
2023-11-24 11:39:55 +01:00
|
|
|
{_, Files0} ->
|
|
|
|
Files = [begin
|
|
|
|
hd(filelib:wildcard("$(call core_native_path,$(DEPS_DIR)/$1/src/)**/" ++ filename:rootname(F) ++ ".*rl"))
|
|
|
|
end || "src/" ++ F <- Files0],
|
2015-06-11 17:04:21 +02:00
|
|
|
Names = [[" ", case lists:reverse(F) of
|
|
|
|
"lre." ++ Elif -> lists:reverse(Elif);
|
2020-03-29 15:45:51 +02:00
|
|
|
"lrx." ++ Elif -> lists:reverse(Elif);
|
|
|
|
"lry." ++ Elif -> lists:reverse(Elif);
|
2015-06-11 17:04:21 +02:00
|
|
|
Elif -> lists:reverse(Elif)
|
2023-11-24 11:39:55 +01:00
|
|
|
end] || "$(call core_native_path,$(DEPS_DIR)/$1/src/)" ++ F <- Files],
|
2015-06-11 17:04:21 +02:00
|
|
|
Write(io_lib:format("COMPILE_FIRST +=~s\n", [Names]))
|
|
|
|
end
|
|
|
|
end(),
|
|
|
|
Write("\n\nrebar_dep: preprocess pre-deps deps pre-app app\n"),
|
|
|
|
Write("\npreprocess::\n"),
|
|
|
|
Write("\npre-deps::\n"),
|
|
|
|
Write("\npre-app::\n"),
|
|
|
|
PatchHook = fun(Cmd) ->
|
2018-05-02 18:23:03 +02:00
|
|
|
Cmd2 = re:replace(Cmd, "^([g]?make)(.*)( -C.*)", "\\\\1\\\\3\\\\2", [{return, list}]),
|
|
|
|
case Cmd2 of
|
2016-01-14 13:35:25 +01:00
|
|
|
"make -C" ++ Cmd1 -> "$$\(MAKE) -C" ++ Escape(Cmd1);
|
|
|
|
"gmake -C" ++ Cmd1 -> "$$\(MAKE) -C" ++ Escape(Cmd1);
|
|
|
|
"make " ++ Cmd1 -> "$$\(MAKE) -f Makefile.orig.mk " ++ Escape(Cmd1);
|
|
|
|
"gmake " ++ Cmd1 -> "$$\(MAKE) -f Makefile.orig.mk " ++ Escape(Cmd1);
|
2015-06-11 17:04:21 +02:00
|
|
|
_ -> Escape(Cmd)
|
|
|
|
end
|
|
|
|
end,
|
|
|
|
fun() ->
|
|
|
|
case lists:keyfind(pre_hooks, 1, Conf) of
|
|
|
|
false -> ok;
|
|
|
|
{_, Hooks} ->
|
|
|
|
[case H of
|
|
|
|
{'get-deps', Cmd} ->
|
|
|
|
Write("\npre-deps::\n\t" ++ PatchHook(Cmd) ++ "\n");
|
|
|
|
{compile, Cmd} ->
|
2016-01-14 13:35:25 +01:00
|
|
|
Write("\npre-app::\n\tCC=$$\(CC) " ++ PatchHook(Cmd) ++ "\n");
|
2023-11-24 11:39:55 +01:00
|
|
|
{{pc, compile}, Cmd} ->
|
|
|
|
Write("\npre-app::\n\tCC=$$\(CC) " ++ PatchHook(Cmd) ++ "\n");
|
2015-06-11 17:04:21 +02:00
|
|
|
{Regex, compile, Cmd} ->
|
|
|
|
case rebar_utils:is_arch(Regex) of
|
2016-01-14 13:35:25 +01:00
|
|
|
true -> Write("\npre-app::\n\tCC=$$\(CC) " ++ PatchHook(Cmd) ++ "\n");
|
2015-06-11 17:04:21 +02:00
|
|
|
false -> ok
|
|
|
|
end;
|
|
|
|
_ -> ok
|
|
|
|
end || H <- Hooks]
|
|
|
|
end
|
|
|
|
end(),
|
2020-03-29 15:45:51 +02:00
|
|
|
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])
|
2015-06-11 17:04:21 +02:00
|
|
|
end,
|
|
|
|
PortSpecs = fun() ->
|
|
|
|
case lists:keyfind(port_specs, 1, Conf) of
|
|
|
|
false ->
|
2015-11-16 23:08:24 +01:00
|
|
|
case filelib:is_dir("$(call core_native_path,$(DEPS_DIR)/$1/c_src)") of
|
2015-06-11 17:04:21 +02:00
|
|
|
false -> [];
|
|
|
|
true ->
|
|
|
|
[{"priv/" ++ proplists:get_value(so_name, Conf, "$(1)_drv.so"),
|
|
|
|
proplists:get_value(port_sources, Conf, ["c_src/*.c"]), []}]
|
|
|
|
end;
|
|
|
|
{_, Specs} ->
|
|
|
|
lists:flatten([case S of
|
|
|
|
{Output, Input} -> {ShellToMk(Output), Input, []};
|
|
|
|
{Regex, Output, Input} ->
|
|
|
|
case rebar_utils:is_arch(Regex) of
|
|
|
|
true -> {ShellToMk(Output), Input, []};
|
|
|
|
false -> []
|
|
|
|
end;
|
|
|
|
{Regex, Output, Input, [{env, Env}]} ->
|
|
|
|
case rebar_utils:is_arch(Regex) of
|
|
|
|
true -> {ShellToMk(Output), Input, Env};
|
|
|
|
false -> []
|
|
|
|
end
|
|
|
|
end || S <- Specs])
|
|
|
|
end
|
|
|
|
end(),
|
|
|
|
PortSpecWrite = fun (Text) ->
|
2015-11-16 23:08:24 +01:00
|
|
|
file:write_file("$(call core_native_path,$(DEPS_DIR)/$1/c_src/Makefile.erlang.mk)", Text, [append])
|
2015-06-11 17:04:21 +02:00
|
|
|
end,
|
|
|
|
case PortSpecs of
|
|
|
|
[] -> ok;
|
|
|
|
_ ->
|
2020-03-29 15:45:51 +02:00
|
|
|
Write("\npre-app::\n\t@$$\(MAKE) --no-print-directory -f c_src/Makefile.erlang.mk\n"),
|
2016-11-05 14:17:30 +02:00
|
|
|
PortSpecWrite(io_lib:format("ERL_CFLAGS ?= -finline-functions -Wall -fPIC -I \\"~s/erts-~s/include\\" -I \\"~s\\"\n",
|
2015-06-11 17:04:21 +02:00
|
|
|
[code:root_dir(), erlang:system_info(version), code:lib_dir(erl_interface, include)])),
|
2020-10-07 13:44:24 +02:00
|
|
|
PortSpecWrite(io_lib:format("ERL_LDFLAGS ?= -L \\"~s\\" -lei\n",
|
2015-06-11 17:04:21 +02:00
|
|
|
[code:lib_dir(erl_interface, lib)])),
|
|
|
|
[PortSpecWrite(["\n", E, "\n"]) || E <- OsEnv],
|
|
|
|
FilterEnv = fun(Env) ->
|
|
|
|
lists:flatten([case E of
|
|
|
|
{_, _} -> E;
|
|
|
|
{Regex, K, V} ->
|
|
|
|
case rebar_utils:is_arch(Regex) of
|
|
|
|
true -> {K, V};
|
|
|
|
false -> []
|
|
|
|
end
|
|
|
|
end || E <- Env])
|
|
|
|
end,
|
|
|
|
MergeEnv = fun(Env) ->
|
|
|
|
lists:foldl(fun ({K, V}, Acc) ->
|
|
|
|
case lists:keyfind(K, 1, Acc) of
|
|
|
|
false -> [{K, rebar_utils:expand_env_variable(V, K, "")}|Acc];
|
|
|
|
{_, V0} -> [{K, rebar_utils:expand_env_variable(V, K, V0)}|Acc]
|
|
|
|
end
|
|
|
|
end, [], Env)
|
|
|
|
end,
|
|
|
|
PortEnv = case lists:keyfind(port_env, 1, Conf) of
|
|
|
|
false -> [];
|
|
|
|
{_, PortEnv0} -> FilterEnv(PortEnv0)
|
|
|
|
end,
|
|
|
|
PortSpec = fun ({Output, Input0, Env}) ->
|
2015-11-16 23:08:24 +01:00
|
|
|
filelib:ensure_dir("$(call core_native_path,$(DEPS_DIR)/$1/)" ++ Output),
|
2015-06-11 17:04:21 +02:00
|
|
|
Input = [[" ", I] || I <- Input0],
|
|
|
|
PortSpecWrite([
|
|
|
|
[["\n", K, " = ", ShellToMk(V)] || {K, V} <- lists:reverse(MergeEnv(PortEnv))],
|
|
|
|
case $(PLATFORM) of
|
|
|
|
darwin -> "\n\nLDFLAGS += -flat_namespace -undefined suppress";
|
|
|
|
_ -> ""
|
|
|
|
end,
|
2020-03-29 15:45:51 +02:00
|
|
|
"\n\nall:: ", Output, "\n\t@:\n\n",
|
2016-01-14 13:35:25 +01:00
|
|
|
"%.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",
|
|
|
|
"%.o: %.cpp\n\t$$\(CXX) -c -o $$\@ $$\< $$\(CXXFLAGS) $$\(ERL_CFLAGS) $$\(DRV_CFLAGS) $$\(EXE_CFLAGS)\n\n",
|
2016-11-05 14:17:30 +02:00
|
|
|
[[Output, ": ", K, " += ", ShellToMk(V), "\n"] || {K, V} <- lists:reverse(MergeEnv(FilterEnv(Env)))],
|
2016-01-14 13:35:25 +01:00
|
|
|
Output, ": $$\(foreach ext,.c .C .cc .cpp,",
|
|
|
|
"$$\(patsubst %$$\(ext),%.o,$$\(filter %$$\(ext),$$\(wildcard", Input, "))))\n",
|
2023-11-24 11:39:55 +01:00
|
|
|
"\t$$\(CC) -o $$\@ $$\? $$\(LDFLAGS) $$\(ERL_LDFLAGS) $$\(DRV_LDFLAGS) $$\(LDLIBS) $$\(EXE_LDFLAGS)",
|
2016-01-14 13:35:25 +01:00
|
|
|
case {filename:extension(Output), $(PLATFORM)} of
|
|
|
|
{[], _} -> "\n";
|
2023-11-24 11:39:55 +01:00
|
|
|
{".so", darwin} -> " -shared\n";
|
|
|
|
{".dylib", darwin} -> " -shared\n";
|
2016-01-14 13:35:25 +01:00
|
|
|
{_, darwin} -> "\n";
|
|
|
|
_ -> " -shared\n"
|
2015-06-11 17:04:21 +02:00
|
|
|
end])
|
|
|
|
end,
|
|
|
|
[PortSpec(S) || S <- PortSpecs]
|
|
|
|
end,
|
2020-03-29 15:45:51 +02:00
|
|
|
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(),
|
2017-07-14 21:44:39 +02:00
|
|
|
Write("\ninclude $$\(if $$\(ERLANG_MK_FILENAME),$$\(ERLANG_MK_FILENAME),erlang.mk)"),
|
2015-06-11 17:04:21 +02:00
|
|
|
RunPlugin = fun(Plugin, Step) ->
|
|
|
|
case erlang:function_exported(Plugin, Step, 2) of
|
|
|
|
false -> ok;
|
|
|
|
true ->
|
2015-11-16 23:08:24 +01:00
|
|
|
c:cd("$(call core_native_path,$(DEPS_DIR)/$1/)"),
|
2015-06-11 17:04:21 +02:00
|
|
|
Ret = Plugin:Step({config, "", Conf, dict:new(), dict:new(), dict:new(),
|
|
|
|
dict:store(base_dir, "", dict:new())}, undefined),
|
|
|
|
io:format("rebar plugin ~p step ~p ret ~p~n", [Plugin, Step, Ret])
|
|
|
|
end
|
|
|
|
end,
|
|
|
|
fun() ->
|
|
|
|
case lists:keyfind(plugins, 1, Conf) of
|
|
|
|
false -> ok;
|
2020-03-29 15:45:51 +02:00
|
|
|
{_, Plugins0} ->
|
|
|
|
Plugins = [P || P <- Plugins0, is_atom(P)],
|
2015-06-11 17:04:21 +02:00
|
|
|
[begin
|
|
|
|
case lists:keyfind(deps, 1, Conf) of
|
|
|
|
false -> ok;
|
|
|
|
{_, Deps} ->
|
|
|
|
case lists:keyfind(P, 1, Deps) of
|
|
|
|
false -> ok;
|
|
|
|
_ ->
|
2015-11-16 23:08:24 +01:00
|
|
|
Path = "$(call core_native_path,$(DEPS_DIR)/)" ++ atom_to_list(P),
|
|
|
|
io:format("~s", [os:cmd("$(MAKE) -C $(call core_native_path,$(DEPS_DIR)/$1) " ++ Path)]),
|
2015-06-11 17:04:21 +02:00
|
|
|
io:format("~s", [os:cmd("$(MAKE) -C " ++ Path ++ " IS_DEP=1")]),
|
|
|
|
code:add_patha(Path ++ "/ebin")
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end || P <- Plugins],
|
|
|
|
[case code:load_file(P) of
|
|
|
|
{module, P} -> ok;
|
|
|
|
_ ->
|
|
|
|
case lists:keyfind(plugin_dir, 1, Conf) of
|
|
|
|
false -> ok;
|
|
|
|
{_, PluginsDir} ->
|
2015-11-16 23:08:24 +01:00
|
|
|
ErlFile = "$(call core_native_path,$(DEPS_DIR)/$1/)" ++ PluginsDir ++ "/" ++ atom_to_list(P) ++ ".erl",
|
2015-06-11 17:04:21 +02:00
|
|
|
{ok, P, Bin} = compile:file(ErlFile, [binary]),
|
|
|
|
{module, P} = code:load_binary(P, ErlFile, Bin)
|
|
|
|
end
|
|
|
|
end || P <- Plugins],
|
|
|
|
[RunPlugin(P, preprocess) || P <- Plugins],
|
2015-11-16 23:08:24 +01:00
|
|
|
[RunPlugin(P, pre_compile) || P <- Plugins],
|
|
|
|
[RunPlugin(P, compile) || P <- Plugins]
|
2015-06-11 17:04:21 +02:00
|
|
|
end
|
|
|
|
end(),
|
|
|
|
halt()
|
|
|
|
endef
|
|
|
|
|
2016-01-14 13:35:25 +01:00
|
|
|
define dep_autopatch_appsrc_script.erl
|
|
|
|
AppSrc = "$(call core_native_path,$(DEPS_DIR)/$1/src/$1.app.src)",
|
|
|
|
AppSrcScript = AppSrc ++ ".script",
|
2022-09-19 14:17:37 +02:00
|
|
|
Conf1 = case file:consult(AppSrc) of
|
|
|
|
{ok, Conf0} -> Conf0;
|
|
|
|
{error, enoent} -> []
|
|
|
|
end,
|
2017-11-19 13:25:54 +01:00
|
|
|
Bindings0 = erl_eval:new_bindings(),
|
2022-09-19 14:17:37 +02:00
|
|
|
Bindings1 = erl_eval:add_binding('CONFIG', Conf1, Bindings0),
|
2017-11-19 13:25:54 +01:00
|
|
|
Bindings = erl_eval:add_binding('SCRIPT', AppSrcScript, Bindings1),
|
2018-05-02 18:23:03 +02:00
|
|
|
Conf = case file:script(AppSrcScript, Bindings) of
|
|
|
|
{ok, [C]} -> C;
|
|
|
|
{ok, C} -> C
|
|
|
|
end,
|
2016-01-14 13:35:25 +01:00
|
|
|
ok = file:write_file(AppSrc, io_lib:format("~p.~n", [Conf])),
|
|
|
|
halt()
|
|
|
|
endef
|
|
|
|
|
2015-06-11 17:04:21 +02:00
|
|
|
define dep_autopatch_appsrc.erl
|
2015-11-16 23:08:24 +01:00
|
|
|
AppSrcOut = "$(call core_native_path,$(DEPS_DIR)/$1/src/$1.app.src)",
|
|
|
|
AppSrcIn = case filelib:is_regular(AppSrcOut) of false -> "$(call core_native_path,$(DEPS_DIR)/$1/ebin/$1.app)"; true -> AppSrcOut end,
|
2015-06-11 17:04:21 +02:00
|
|
|
case filelib:is_regular(AppSrcIn) of
|
|
|
|
false -> ok;
|
|
|
|
true ->
|
2025-02-11 16:02:10 +01:00
|
|
|
{ok, [{application, $1, L0}]} = file:consult(AppSrcIn),
|
2015-06-11 17:04:21 +02:00
|
|
|
L1 = lists:keystore(modules, 1, L0, {modules, []}),
|
2017-11-19 13:25:54 +01:00
|
|
|
L2 = case lists:keyfind(vsn, 1, L1) of
|
2020-03-29 15:45:51 +02:00
|
|
|
{_, git} -> lists:keyreplace(vsn, 1, L1, {vsn, lists:droplast(os:cmd("git -C $(DEPS_DIR)/$1 describe --dirty --tags --always"))});
|
2017-11-19 13:25:54 +01:00
|
|
|
{_, {cmd, _}} -> lists:keyreplace(vsn, 1, L1, {vsn, "cmd"});
|
|
|
|
_ -> L1
|
|
|
|
end,
|
2015-07-21 17:16:11 +02:00
|
|
|
L3 = case lists:keyfind(registered, 1, L2) of false -> [{registered, []}|L2]; _ -> L2 end,
|
2025-02-11 16:02:10 +01:00
|
|
|
ok = file:write_file(AppSrcOut, io_lib:format("~p.~n", [{application, $1, L3}])),
|
2015-06-11 17:04:21 +02:00
|
|
|
case AppSrcOut of AppSrcIn -> ok; _ -> ok = file:delete(AppSrcIn) end
|
|
|
|
end,
|
|
|
|
halt()
|
|
|
|
endef
|
|
|
|
|
2023-11-24 11:39:55 +01:00
|
|
|
ifeq ($(CACHE_DEPS),1)
|
|
|
|
|
|
|
|
define dep_cache_fetch_git
|
|
|
|
mkdir -p $(CACHE_DIR)/git; \
|
2025-02-11 16:02:10 +01:00
|
|
|
if test -d "$(join $(CACHE_DIR)/git/,$(call query_name,$1))"; then \
|
|
|
|
cd $(join $(CACHE_DIR)/git/,$(call query_name,$1)); \
|
|
|
|
if ! git checkout -q $(call query_version,$1); then \
|
|
|
|
git remote set-url origin $(call query_repo_git,$1) && \
|
2023-11-24 11:39:55 +01:00
|
|
|
git pull --all && \
|
2025-02-11 16:02:10 +01:00
|
|
|
git cat-file -e $(call query_version_git,$1) 2>/dev/null; \
|
2023-11-24 11:39:55 +01:00
|
|
|
fi; \
|
|
|
|
else \
|
2025-02-11 16:02:10 +01:00
|
|
|
git clone -q -n -- $(call query_repo_git,$1) $(join $(CACHE_DIR)/git/,$(call query_name,$1)); \
|
2023-11-24 11:39:55 +01:00
|
|
|
fi; \
|
2025-02-11 16:02:10 +01:00
|
|
|
git clone -q --single-branch -- $(join $(CACHE_DIR)/git/,$(call query_name,$1)) $2; \
|
|
|
|
cd $2 && git checkout -q $(call query_version_git,$1)
|
2023-11-24 11:39:55 +01:00
|
|
|
endef
|
|
|
|
|
|
|
|
define dep_fetch_git
|
2025-02-11 16:02:10 +01:00
|
|
|
$(call dep_cache_fetch_git,$1,$(DEPS_DIR)/$(call query_name,$1));
|
2023-11-24 11:39:55 +01:00
|
|
|
endef
|
|
|
|
|
|
|
|
define dep_fetch_git-subfolder
|
|
|
|
mkdir -p $(ERLANG_MK_TMP)/git-subfolder; \
|
2025-02-11 16:02:10 +01:00
|
|
|
$(call dep_cache_fetch_git,$1,$(ERLANG_MK_TMP)/git-subfolder/$(call query_name,$1)); \
|
|
|
|
ln -s $(ERLANG_MK_TMP)/git-subfolder/$(call query_name,$1)/$(word 4,$(dep_$1)) \
|
|
|
|
$(DEPS_DIR)/$(call query_name,$1);
|
2023-11-24 11:39:55 +01:00
|
|
|
endef
|
|
|
|
|
|
|
|
else
|
|
|
|
|
2015-11-16 23:08:24 +01:00
|
|
|
define dep_fetch_git
|
2025-02-11 16:02:10 +01:00
|
|
|
git clone -q -n -- $(call query_repo_git,$1) $(DEPS_DIR)/$(call query_name,$1); \
|
|
|
|
cd $(DEPS_DIR)/$(call query_name,$1) && git checkout -q $(call query_version_git,$1);
|
2015-11-16 23:08:24 +01:00
|
|
|
endef
|
|
|
|
|
2020-03-29 15:45:51 +02:00
|
|
|
define dep_fetch_git-subfolder
|
|
|
|
mkdir -p $(ERLANG_MK_TMP)/git-subfolder; \
|
2025-02-11 16:02:10 +01:00
|
|
|
git clone -q -n -- $(call query_repo_git-subfolder,$1) \
|
|
|
|
$(ERLANG_MK_TMP)/git-subfolder/$(call query_name,$1); \
|
|
|
|
cd $(ERLANG_MK_TMP)/git-subfolder/$(call query_name,$1) \
|
|
|
|
&& git checkout -q $(call query_version_git-subfolder,$1); \
|
|
|
|
ln -s $(ERLANG_MK_TMP)/git-subfolder/$(call query_name,$1)/$(word 4,$(dep_$1)) \
|
|
|
|
$(DEPS_DIR)/$(call query_name,$1);
|
2020-03-29 15:45:51 +02:00
|
|
|
endef
|
|
|
|
|
2023-11-24 11:39:55 +01:00
|
|
|
endif
|
|
|
|
|
2015-11-16 23:08:24 +01:00
|
|
|
define dep_fetch_git-submodule
|
|
|
|
git submodule update --init -- $(DEPS_DIR)/$1;
|
|
|
|
endef
|
|
|
|
|
|
|
|
define dep_fetch_hg
|
2025-02-11 16:02:10 +01:00
|
|
|
hg clone -q -U $(call query_repo_hg,$1) $(DEPS_DIR)/$(call query_name,$1); \
|
|
|
|
cd $(DEPS_DIR)/$(call query_name,$1) && hg update -q $(call query_version_hg,$1);
|
2015-11-16 23:08:24 +01:00
|
|
|
endef
|
|
|
|
|
|
|
|
define dep_fetch_svn
|
2025-02-11 16:02:10 +01:00
|
|
|
svn checkout -q $(call query_repo_svn,$1) $(DEPS_DIR)/$(call query_name,$1);
|
2015-11-16 23:08:24 +01:00
|
|
|
endef
|
|
|
|
|
|
|
|
define dep_fetch_cp
|
2025-02-11 16:02:10 +01:00
|
|
|
cp -R $(call query_repo_cp,$1) $(DEPS_DIR)/$(call query_name,$1);
|
2015-11-16 23:08:24 +01:00
|
|
|
endef
|
|
|
|
|
2017-07-14 21:44:39 +02:00
|
|
|
define dep_fetch_ln
|
2025-02-11 16:02:10 +01:00
|
|
|
ln -s $(call query_repo_ln,$1) $(DEPS_DIR)/$(call query_name,$1);
|
|
|
|
endef
|
|
|
|
|
|
|
|
define hex_get_tarball.erl
|
|
|
|
{ok, _} = application:ensure_all_started(ssl),
|
|
|
|
{ok, _} = application:ensure_all_started(inets),
|
|
|
|
Config = $(hex_config.erl),
|
|
|
|
case hex_repo:get_tarball(Config, <<"$1">>, <<"$(strip $2)">>) of
|
|
|
|
{ok, {200, _, Tarball}} ->
|
|
|
|
ok = file:write_file("$3", Tarball),
|
|
|
|
halt(0);
|
|
|
|
{ok, {Status, _, Errors}} ->
|
|
|
|
io:format("Error ~b: ~0p~n", [Status, Errors]),
|
|
|
|
halt(79)
|
|
|
|
end
|
2017-07-14 21:44:39 +02:00
|
|
|
endef
|
|
|
|
|
2023-11-24 11:39:55 +01:00
|
|
|
ifeq ($(CACHE_DEPS),1)
|
|
|
|
|
|
|
|
# Hex only has a package version. No need to look in the Erlang.mk packages.
|
|
|
|
define dep_fetch_hex
|
|
|
|
mkdir -p $(CACHE_DIR)/hex $(DEPS_DIR)/$1; \
|
2025-02-11 16:02:10 +01:00
|
|
|
$(eval hex_pkg_name := $(if $(word 3,$(dep_$1)),$(word 3,$(dep_$1)),$1)) \
|
|
|
|
$(eval hex_tar_name := $(hex_pkg_name)-$(strip $(word 2,$(dep_$1))).tar) \
|
|
|
|
$(if $(wildcard $(CACHE_DIR)/hex/$(hex_tar_name)),,\
|
|
|
|
$(call erlang,$(call hex_get_tarball.erl,$(hex_pkg_name),$(word 2,$(dep_$1)),$(CACHE_DIR)/hex/$(hex_tar_name)));) \
|
2023-11-24 11:39:55 +01:00
|
|
|
tar -xOf $(CACHE_DIR)/hex/$(hex_tar_name) contents.tar.gz | tar -C $(DEPS_DIR)/$1 -xzf -;
|
|
|
|
endef
|
|
|
|
|
|
|
|
else
|
|
|
|
|
2015-11-16 23:08:24 +01:00
|
|
|
# Hex only has a package version. No need to look in the Erlang.mk packages.
|
|
|
|
define dep_fetch_hex
|
2016-11-05 14:17:30 +02:00
|
|
|
mkdir -p $(ERLANG_MK_TMP)/hex $(DEPS_DIR)/$1; \
|
2025-02-11 16:02:10 +01:00
|
|
|
$(call erlang,$(call hex_get_tarball.erl,$(if $(word 3,$(dep_$1)),$(word 3,$(dep_$1)),$1),$(word 2,$(dep_$1)),$(ERLANG_MK_TMP)/hex/$1.tar)); \
|
2016-11-05 14:17:30 +02:00
|
|
|
tar -xOf $(ERLANG_MK_TMP)/hex/$1.tar contents.tar.gz | tar -C $(DEPS_DIR)/$1 -xzf -;
|
2015-11-16 23:08:24 +01:00
|
|
|
endef
|
|
|
|
|
2023-11-24 11:39:55 +01:00
|
|
|
endif
|
|
|
|
|
2015-11-16 23:08:24 +01:00
|
|
|
define dep_fetch_fail
|
2025-02-11 16:02:10 +01:00
|
|
|
echo "Error: Unknown or invalid dependency: $1." >&2; \
|
2015-11-16 23:08:24 +01:00
|
|
|
exit 78;
|
|
|
|
endef
|
|
|
|
|
2014-08-01 14:26:51 +02:00
|
|
|
define dep_target
|
2025-02-11 16:02:10 +01:00
|
|
|
$(DEPS_DIR)/$(call query_name,$1): | $(if $(filter hex,$(call query_fetch_method,$1)),hex-core) $(ERLANG_MK_TMP)
|
|
|
|
$(eval DEP_NAME := $(call query_name,$1))
|
2020-03-29 15:45:51 +02:00
|
|
|
$(eval DEP_STR := $(if $(filter $1,$(DEP_NAME)),$1,"$1 ($(DEP_NAME))"))
|
2015-11-16 23:08:24 +01:00
|
|
|
$(verbose) if test -d $(APPS_DIR)/$(DEP_NAME); then \
|
2017-07-14 21:44:39 +02:00
|
|
|
echo "Error: Dependency" $(DEP_STR) "conflicts with application found in $(APPS_DIR)/$(DEP_NAME)." >&2; \
|
2015-11-16 23:08:24 +01:00
|
|
|
exit 17; \
|
|
|
|
fi
|
2015-07-21 17:16:11 +02:00
|
|
|
$(verbose) mkdir -p $(DEPS_DIR)
|
2025-02-11 16:02:10 +01:00
|
|
|
$(dep_verbose) $(call dep_fetch_$(strip $(call query_fetch_method,$1)),$1)
|
|
|
|
$(verbose) if [ -f $(DEPS_DIR)/$1/configure.ac -o -f $(DEPS_DIR)/$1/configure.in ] \
|
|
|
|
&& [ ! -f $(DEPS_DIR)/$1/configure ]; then \
|
2020-03-29 15:45:51 +02:00
|
|
|
echo " AUTO " $(DEP_STR); \
|
2025-02-11 16:02:10 +01:00
|
|
|
cd $(DEPS_DIR)/$1 && autoreconf -Wall -vif -I m4; \
|
2015-06-11 17:04:21 +02:00
|
|
|
fi
|
2015-11-16 23:08:24 +01:00
|
|
|
- $(verbose) if [ -f $(DEPS_DIR)/$(DEP_NAME)/configure ]; then \
|
|
|
|
echo " CONF " $(DEP_STR); \
|
|
|
|
cd $(DEPS_DIR)/$(DEP_NAME) && ./configure; \
|
2015-05-05 19:59:37 +03:00
|
|
|
fi
|
2025-02-11 16:02:10 +01:00
|
|
|
ifeq ($(filter $1,$(NO_AUTOPATCH)),)
|
2020-03-29 15:45:51 +02:00
|
|
|
$(verbose) $$(MAKE) --no-print-directory autopatch-$(DEP_NAME)
|
|
|
|
endif
|
|
|
|
|
2025-02-11 16:02:10 +01:00
|
|
|
.PHONY: autopatch-$(call query_name,$1)
|
2020-03-29 15:45:51 +02:00
|
|
|
|
2025-02-11 16:02:10 +01:00
|
|
|
autopatch-$(call query_name,$1)::
|
2023-11-24 11:39:55 +01:00
|
|
|
$(verbose) if [ "$1" = "elixir" -a "$(ELIXIR_PATCH)" ]; then \
|
2020-03-29 15:45:51 +02:00
|
|
|
ln -s lib/elixir/ebin $(DEPS_DIR)/elixir/; \
|
2015-07-21 17:16:11 +02:00
|
|
|
else \
|
2025-02-11 16:02:10 +01:00
|
|
|
$$(call dep_autopatch,$(call query_name,$1)) \
|
2015-07-21 17:16:11 +02:00
|
|
|
fi
|
2013-10-14 16:05:19 +02:00
|
|
|
endef
|
|
|
|
|
2025-02-11 16:02:10 +01:00
|
|
|
# We automatically depend on hex_core when the project isn't already.
|
|
|
|
$(if $(filter hex_core,$(DEPS) $(BUILD_DEPS) $(DOC_DEPS) $(REL_DEPS) $(TEST_DEPS)),,\
|
|
|
|
$(eval $(call dep_target,hex_core)))
|
|
|
|
|
|
|
|
.PHONY: hex-core
|
|
|
|
|
|
|
|
hex-core: $(DEPS_DIR)/hex_core
|
|
|
|
$(verbose) if [ ! -e $(DEPS_DIR)/hex_core/ebin/dep_built ]; then \
|
|
|
|
$(MAKE) -C $(DEPS_DIR)/hex_core IS_DEP=1; \
|
|
|
|
touch $(DEPS_DIR)/hex_core/ebin/dep_built; \
|
|
|
|
fi
|
|
|
|
|
2015-11-16 23:08:24 +01:00
|
|
|
$(foreach dep,$(BUILD_DEPS) $(DEPS),$(eval $(call dep_target,$(dep))))
|
|
|
|
|
|
|
|
ifndef IS_APP
|
|
|
|
clean:: clean-apps
|
|
|
|
|
|
|
|
clean-apps:
|
2017-07-14 21:44:39 +02:00
|
|
|
$(verbose) set -e; for dep in $(ALL_APPS_DIRS) ; do \
|
|
|
|
$(MAKE) -C $$dep clean IS_APP=1; \
|
2015-11-16 23:08:24 +01:00
|
|
|
done
|
|
|
|
|
|
|
|
distclean:: distclean-apps
|
|
|
|
|
|
|
|
distclean-apps:
|
2017-07-14 21:44:39 +02:00
|
|
|
$(verbose) set -e; for dep in $(ALL_APPS_DIRS) ; do \
|
|
|
|
$(MAKE) -C $$dep distclean IS_APP=1; \
|
2015-11-16 23:08:24 +01:00
|
|
|
done
|
|
|
|
endif
|
|
|
|
|
|
|
|
ifndef SKIP_DEPS
|
|
|
|
distclean:: distclean-deps
|
2013-10-14 16:05:19 +02:00
|
|
|
|
2014-08-01 14:26:51 +02:00
|
|
|
distclean-deps:
|
|
|
|
$(gen_verbose) rm -rf $(DEPS_DIR)
|
2015-11-16 23:08:24 +01:00
|
|
|
endif
|
|
|
|
|
2023-11-24 11:39:55 +01:00
|
|
|
ifeq ($(CACHE_DEPS),1)
|
|
|
|
cacheclean:: cacheclean-git cacheclean-hex
|
|
|
|
|
|
|
|
cacheclean-git:
|
|
|
|
$(gen_verbose) rm -rf $(CACHE_DIR)/git
|
|
|
|
|
|
|
|
cacheclean-hex:
|
|
|
|
$(gen_verbose) rm -rf $(CACHE_DIR)/hex
|
|
|
|
endif
|
|
|
|
|
2016-11-05 14:17:30 +02:00
|
|
|
# Forward-declare variables used in core/deps-tools.mk. This is required
|
|
|
|
# in case plugins use them.
|
|
|
|
|
|
|
|
ERLANG_MK_RECURSIVE_DEPS_LIST = $(ERLANG_MK_TMP)/recursive-deps-list.log
|
|
|
|
ERLANG_MK_RECURSIVE_DOC_DEPS_LIST = $(ERLANG_MK_TMP)/recursive-doc-deps-list.log
|
|
|
|
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
|
|
|
|
|
2020-03-29 15:45:51 +02:00
|
|
|
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
|
2015-06-11 17:04:21 +02:00
|
|
|
|
2024-11-06 16:33:39 +01:00
|
|
|
# Copyright (c) 2024, Loïc Hoguin <essen@ninenines.eu>
|
|
|
|
# This file is part of erlang.mk and subject to the terms of the ISC License.
|
|
|
|
|
|
|
|
.PHONY: beam-cache-restore-app beam-cache-restore-test clean-beam-cache distclean-beam-cache
|
|
|
|
|
|
|
|
BEAM_CACHE_DIR ?= $(ERLANG_MK_TMP)/beam-cache
|
|
|
|
PROJECT_BEAM_CACHE_DIR = $(BEAM_CACHE_DIR)/$(PROJECT)
|
|
|
|
|
|
|
|
clean:: clean-beam-cache
|
|
|
|
|
|
|
|
clean-beam-cache:
|
|
|
|
$(verbose) rm -rf $(PROJECT_BEAM_CACHE_DIR)
|
|
|
|
|
|
|
|
distclean:: distclean-beam-cache
|
|
|
|
|
|
|
|
$(PROJECT_BEAM_CACHE_DIR):
|
|
|
|
$(verbose) mkdir -p $(PROJECT_BEAM_CACHE_DIR)
|
|
|
|
|
|
|
|
distclean-beam-cache:
|
|
|
|
$(gen_verbose) rm -rf $(BEAM_CACHE_DIR)
|
|
|
|
|
|
|
|
beam-cache-restore-app: | $(PROJECT_BEAM_CACHE_DIR)
|
|
|
|
$(verbose) rm -rf $(PROJECT_BEAM_CACHE_DIR)/ebin-test
|
|
|
|
ifneq ($(wildcard ebin/),)
|
|
|
|
$(verbose) mv ebin/ $(PROJECT_BEAM_CACHE_DIR)/ebin-test
|
|
|
|
endif
|
|
|
|
ifneq ($(wildcard $(PROJECT_BEAM_CACHE_DIR)/ebin-app),)
|
|
|
|
$(gen_verbose) mv $(PROJECT_BEAM_CACHE_DIR)/ebin-app ebin/
|
|
|
|
else
|
|
|
|
$(verbose) $(MAKE) --no-print-directory clean-app
|
|
|
|
endif
|
|
|
|
|
|
|
|
beam-cache-restore-test: | $(PROJECT_BEAM_CACHE_DIR)
|
|
|
|
$(verbose) rm -rf $(PROJECT_BEAM_CACHE_DIR)/ebin-app
|
|
|
|
ifneq ($(wildcard ebin/),)
|
|
|
|
$(verbose) mv ebin/ $(PROJECT_BEAM_CACHE_DIR)/ebin-app
|
|
|
|
endif
|
|
|
|
ifneq ($(wildcard $(PROJECT_BEAM_CACHE_DIR)/ebin-test),)
|
|
|
|
$(gen_verbose) mv $(PROJECT_BEAM_CACHE_DIR)/ebin-test ebin/
|
|
|
|
else
|
|
|
|
$(verbose) $(MAKE) --no-print-directory clean-app
|
|
|
|
endif
|
|
|
|
|
2016-11-05 14:17:30 +02:00
|
|
|
# Copyright (c) 2013-2016, Loïc Hoguin <essen@ninenines.eu>
|
2014-08-01 14:26:51 +02:00
|
|
|
# This file is part of erlang.mk and subject to the terms of the ISC License.
|
2013-04-30 20:51:37 +02:00
|
|
|
|
2014-08-01 14:26:51 +02:00
|
|
|
.PHONY: clean-app
|
|
|
|
|
|
|
|
# Configuration.
|
2013-08-24 10:48:59 +02:00
|
|
|
|
2015-05-05 19:59:37 +03:00
|
|
|
ERLC_OPTS ?= -Werror +debug_info +warn_export_vars +warn_shadow_vars \
|
|
|
|
+warn_obsolete_guard # +bin_opt_info +warn_export_all +warn_missing_spec
|
2013-04-30 20:51:37 +02:00
|
|
|
COMPILE_FIRST ?=
|
|
|
|
COMPILE_FIRST_PATHS = $(addprefix src/,$(addsuffix .erl,$(COMPILE_FIRST)))
|
2015-05-05 19:59:37 +03:00
|
|
|
ERLC_EXCLUDE ?=
|
|
|
|
ERLC_EXCLUDE_PATHS = $(addprefix src/,$(addsuffix .erl,$(ERLC_EXCLUDE)))
|
|
|
|
|
2017-07-14 21:44:39 +02:00
|
|
|
ERLC_ASN1_OPTS ?=
|
|
|
|
|
2015-05-05 19:59:37 +03:00
|
|
|
ERLC_MIB_OPTS ?=
|
|
|
|
COMPILE_MIB_FIRST ?=
|
|
|
|
COMPILE_MIB_FIRST_PATHS = $(addprefix mibs/,$(addsuffix .mib,$(COMPILE_MIB_FIRST)))
|
2013-04-30 20:51:37 +02:00
|
|
|
|
2014-08-01 14:26:51 +02:00
|
|
|
# Verbosity.
|
|
|
|
|
2015-07-21 17:16:11 +02:00
|
|
|
app_verbose_0 = @echo " APP " $(PROJECT);
|
2016-01-14 13:35:25 +01:00
|
|
|
app_verbose_2 = set -x;
|
2015-07-21 17:16:11 +02:00
|
|
|
app_verbose = $(app_verbose_$(V))
|
|
|
|
|
2014-08-01 14:26:51 +02:00
|
|
|
appsrc_verbose_0 = @echo " APP " $(PROJECT).app.src;
|
2016-01-14 13:35:25 +01:00
|
|
|
appsrc_verbose_2 = set -x;
|
2014-08-01 14:26:51 +02:00
|
|
|
appsrc_verbose = $(appsrc_verbose_$(V))
|
2013-04-30 20:51:37 +02:00
|
|
|
|
2015-11-16 23:08:24 +01:00
|
|
|
makedep_verbose_0 = @echo " DEPEND" $(PROJECT).d;
|
2016-01-14 13:35:25 +01:00
|
|
|
makedep_verbose_2 = set -x;
|
2015-11-16 23:08:24 +01:00
|
|
|
makedep_verbose = $(makedep_verbose_$(V))
|
|
|
|
|
2015-05-05 19:59:37 +03:00
|
|
|
erlc_verbose_0 = @echo " ERLC " $(filter-out $(patsubst %,%.erl,$(ERLC_EXCLUDE)),\
|
|
|
|
$(filter %.erl %.core,$(?F)));
|
2016-01-14 13:35:25 +01:00
|
|
|
erlc_verbose_2 = set -x;
|
2014-08-01 14:26:51 +02:00
|
|
|
erlc_verbose = $(erlc_verbose_$(V))
|
|
|
|
|
|
|
|
xyrl_verbose_0 = @echo " XYRL " $(filter %.xrl %.yrl,$(?F));
|
2016-01-14 13:35:25 +01:00
|
|
|
xyrl_verbose_2 = set -x;
|
2014-08-01 14:26:51 +02:00
|
|
|
xyrl_verbose = $(xyrl_verbose_$(V))
|
2013-04-30 20:51:37 +02:00
|
|
|
|
2015-06-11 17:04:21 +02:00
|
|
|
asn1_verbose_0 = @echo " ASN1 " $(filter %.asn1,$(?F));
|
2016-01-14 13:35:25 +01:00
|
|
|
asn1_verbose_2 = set -x;
|
2015-06-11 17:04:21 +02:00
|
|
|
asn1_verbose = $(asn1_verbose_$(V))
|
|
|
|
|
2015-05-05 19:59:37 +03:00
|
|
|
mib_verbose_0 = @echo " MIB " $(filter %.bin %.mib,$(?F));
|
2016-01-14 13:35:25 +01:00
|
|
|
mib_verbose_2 = set -x;
|
2015-05-05 19:59:37 +03:00
|
|
|
mib_verbose = $(mib_verbose_$(V))
|
|
|
|
|
2015-11-16 23:08:24 +01:00
|
|
|
ifneq ($(wildcard src/),)
|
|
|
|
|
2015-05-05 19:59:37 +03:00
|
|
|
# Targets.
|
|
|
|
|
2024-11-06 16:33:39 +01:00
|
|
|
app:: $(if $(wildcard ebin/test),beam-cache-restore-app) deps
|
2020-03-29 15:45:51 +02:00
|
|
|
$(verbose) $(MAKE) --no-print-directory $(PROJECT).d
|
2015-11-16 23:08:24 +01:00
|
|
|
$(verbose) $(MAKE) --no-print-directory app-build
|
2014-08-01 14:26:51 +02:00
|
|
|
|
2016-11-05 14:17:30 +02:00
|
|
|
ifeq ($(wildcard src/$(PROJECT_MOD).erl),)
|
2015-07-21 17:16:11 +02:00
|
|
|
define app_file
|
2017-01-02 19:28:48 +01:00
|
|
|
{application, '$(PROJECT)', [
|
2015-07-21 17:16:11 +02:00
|
|
|
{description, "$(PROJECT_DESCRIPTION)"},
|
2015-11-16 23:08:24 +01:00
|
|
|
{vsn, "$(PROJECT_VERSION)"},$(if $(IS_DEP),
|
2025-02-11 16:02:10 +01:00
|
|
|
{id$(comma)$(space)"$1"}$(comma))
|
|
|
|
{modules, [$(call comma_list,$2)]},
|
2015-07-21 17:16:11 +02:00
|
|
|
{registered, []},
|
2025-02-11 16:02:10 +01:00
|
|
|
{applications, [$(call comma_list,kernel stdlib $(OTP_DEPS) $(LOCAL_DEPS) $(OPTIONAL_DEPS) $(foreach dep,$(DEPS),$(call query_name,$(dep))))]},
|
2023-11-24 11:39:55 +01:00
|
|
|
{optional_applications, [$(call comma_list,$(OPTIONAL_DEPS))]},
|
2016-11-05 14:17:30 +02:00
|
|
|
{env, $(subst \,\\,$(PROJECT_ENV))}$(if $(findstring {,$(PROJECT_APP_EXTRA_KEYS)),$(comma)$(newline)$(tab)$(subst \,\\,$(PROJECT_APP_EXTRA_KEYS)),)
|
2015-07-21 17:16:11 +02:00
|
|
|
]}.
|
|
|
|
endef
|
|
|
|
else
|
|
|
|
define app_file
|
2017-01-02 19:28:48 +01:00
|
|
|
{application, '$(PROJECT)', [
|
2015-07-21 17:16:11 +02:00
|
|
|
{description, "$(PROJECT_DESCRIPTION)"},
|
2015-11-16 23:08:24 +01:00
|
|
|
{vsn, "$(PROJECT_VERSION)"},$(if $(IS_DEP),
|
2025-02-11 16:02:10 +01:00
|
|
|
{id$(comma)$(space)"$1"}$(comma))
|
|
|
|
{modules, [$(call comma_list,$2)]},
|
2015-07-21 17:16:11 +02:00
|
|
|
{registered, [$(call comma_list,$(PROJECT)_sup $(PROJECT_REGISTERED))]},
|
2025-02-11 16:02:10 +01:00
|
|
|
{applications, [$(call comma_list,kernel stdlib $(OTP_DEPS) $(LOCAL_DEPS) $(OPTIONAL_DEPS) $(foreach dep,$(DEPS),$(call query_name,$(dep))))]},
|
2023-11-24 11:39:55 +01:00
|
|
|
{optional_applications, [$(call comma_list,$(OPTIONAL_DEPS))]},
|
2016-11-05 14:17:30 +02:00
|
|
|
{mod, {$(PROJECT_MOD), []}},
|
|
|
|
{env, $(subst \,\\,$(PROJECT_ENV))}$(if $(findstring {,$(PROJECT_APP_EXTRA_KEYS)),$(comma)$(newline)$(tab)$(subst \,\\,$(PROJECT_APP_EXTRA_KEYS)),)
|
2015-07-21 17:16:11 +02:00
|
|
|
]}.
|
|
|
|
endef
|
|
|
|
endif
|
|
|
|
|
2015-11-16 23:08:24 +01:00
|
|
|
app-build: ebin/$(PROJECT).app
|
2016-01-14 13:35:25 +01:00
|
|
|
$(verbose) :
|
2013-04-30 20:51:37 +02:00
|
|
|
|
2015-11-16 23:08:24 +01:00
|
|
|
# Source files.
|
2015-05-05 19:59:37 +03:00
|
|
|
|
Initial commit with connection/streams
Breaking changes with previous commit. This is a very large change,
and I am giving up on making a single commit that fixes everything.
More commits will follow slowly adding back features, introducing
new tests and fixing the documentation.
This change contains most of the work toward unifying the interface
for handling both HTTP/1.1 and HTTP/2. HTTP/1.1 connections are now
no longer 1 process per connection; instead by default 1 process per
request is also created. This has a number of pros and cons.
Because it has cons, we also allow users to use a lower-level API
that acts on "streams" (requests/responses) directly at the connection
process-level. If performance is a concern, one can always write a
stream handler. The performance in this case will be even greater
than with Cowboy 1, although all the special handlers are unavailable.
When switching to Websocket, after the handler returns from init/2,
Cowboy stops the stream and the Websocket protocol takes over the
connection process. Websocket then calls websocket_init/2 for any
additional initialization such as timers, because the process is
different in init/2 and websocket_*/* functions. This however would
allow us to use websocket_init/2 for sending messages on connect,
instead of sending ourselves a message and be subject to races.
Note that websocket_init/2 is optional.
This is all a big change and while most of the tests pass, some
functionality currently doesn't. SPDY is broken and will be removed
soon in favor of HTTP/2. Automatic compression is currently disabled.
The cowboy_req interface probably still have a few functions that
need to be updated. The docs and examples do not refer the current
functionality anymore.
Everything will be fixed over time. Feedback is more than welcome.
Open a ticket!
2016-02-10 17:28:32 +01:00
|
|
|
ALL_SRC_FILES := $(sort $(call core_find,src/,*))
|
|
|
|
|
|
|
|
ERL_FILES := $(filter %.erl,$(ALL_SRC_FILES))
|
|
|
|
CORE_FILES := $(filter %.core,$(ALL_SRC_FILES))
|
2013-08-24 10:48:59 +02:00
|
|
|
|
2015-11-16 23:08:24 +01:00
|
|
|
# ASN.1 files.
|
2013-06-19 16:35:51 +02:00
|
|
|
|
2015-11-16 23:08:24 +01:00
|
|
|
ifneq ($(wildcard asn1/),)
|
|
|
|
ASN1_FILES = $(sort $(call core_find,asn1/,*.asn1))
|
|
|
|
ERL_FILES += $(addprefix src/,$(patsubst %.asn1,%.erl,$(notdir $(ASN1_FILES))))
|
2015-06-11 17:04:21 +02:00
|
|
|
|
2015-11-16 23:08:24 +01:00
|
|
|
define compile_asn1
|
|
|
|
$(verbose) mkdir -p include/
|
2025-02-11 16:02:10 +01:00
|
|
|
$(asn1_verbose) erlc -v -I include/ -o asn1/ +noobj $(ERLC_ASN1_OPTS) $1
|
2015-11-16 23:08:24 +01:00
|
|
|
$(verbose) mv asn1/*.erl src/
|
2020-03-29 15:45:51 +02:00
|
|
|
-$(verbose) mv asn1/*.hrl include/
|
2015-11-16 23:08:24 +01:00
|
|
|
$(verbose) mv asn1/*.asn1db include/
|
2015-05-05 19:59:37 +03:00
|
|
|
endef
|
|
|
|
|
2015-11-16 23:08:24 +01:00
|
|
|
$(PROJECT).d:: $(ASN1_FILES)
|
2015-06-11 17:04:21 +02:00
|
|
|
$(if $(strip $?),$(call compile_asn1,$?))
|
|
|
|
endif
|
|
|
|
|
2015-11-16 23:08:24 +01:00
|
|
|
# SNMP MIB files.
|
|
|
|
|
2015-05-05 19:59:37 +03:00
|
|
|
ifneq ($(wildcard mibs/),)
|
2015-11-16 23:08:24 +01:00
|
|
|
MIB_FILES = $(sort $(call core_find,mibs/,*.mib))
|
|
|
|
|
|
|
|
$(PROJECT).d:: $(COMPILE_MIB_FIRST_PATHS) $(MIB_FILES)
|
|
|
|
$(verbose) mkdir -p include/ priv/mibs/
|
|
|
|
$(mib_verbose) erlc -v $(ERLC_MIB_OPTS) -o priv/mibs/ -I priv/mibs/ $?
|
|
|
|
$(mib_verbose) erlc -o include/ -- $(addprefix priv/mibs/,$(patsubst %.mib,%.bin,$(notdir $?)))
|
2015-05-05 19:59:37 +03:00
|
|
|
endif
|
|
|
|
|
2015-11-16 23:08:24 +01:00
|
|
|
# Leex and Yecc files.
|
|
|
|
|
Initial commit with connection/streams
Breaking changes with previous commit. This is a very large change,
and I am giving up on making a single commit that fixes everything.
More commits will follow slowly adding back features, introducing
new tests and fixing the documentation.
This change contains most of the work toward unifying the interface
for handling both HTTP/1.1 and HTTP/2. HTTP/1.1 connections are now
no longer 1 process per connection; instead by default 1 process per
request is also created. This has a number of pros and cons.
Because it has cons, we also allow users to use a lower-level API
that acts on "streams" (requests/responses) directly at the connection
process-level. If performance is a concern, one can always write a
stream handler. The performance in this case will be even greater
than with Cowboy 1, although all the special handlers are unavailable.
When switching to Websocket, after the handler returns from init/2,
Cowboy stops the stream and the Websocket protocol takes over the
connection process. Websocket then calls websocket_init/2 for any
additional initialization such as timers, because the process is
different in init/2 and websocket_*/* functions. This however would
allow us to use websocket_init/2 for sending messages on connect,
instead of sending ourselves a message and be subject to races.
Note that websocket_init/2 is optional.
This is all a big change and while most of the tests pass, some
functionality currently doesn't. SPDY is broken and will be removed
soon in favor of HTTP/2. Automatic compression is currently disabled.
The cowboy_req interface probably still have a few functions that
need to be updated. The docs and examples do not refer the current
functionality anymore.
Everything will be fixed over time. Feedback is more than welcome.
Open a ticket!
2016-02-10 17:28:32 +01:00
|
|
|
XRL_FILES := $(filter %.xrl,$(ALL_SRC_FILES))
|
2015-11-16 23:08:24 +01:00
|
|
|
XRL_ERL_FILES = $(addprefix src/,$(patsubst %.xrl,%.erl,$(notdir $(XRL_FILES))))
|
|
|
|
ERL_FILES += $(XRL_ERL_FILES)
|
|
|
|
|
Initial commit with connection/streams
Breaking changes with previous commit. This is a very large change,
and I am giving up on making a single commit that fixes everything.
More commits will follow slowly adding back features, introducing
new tests and fixing the documentation.
This change contains most of the work toward unifying the interface
for handling both HTTP/1.1 and HTTP/2. HTTP/1.1 connections are now
no longer 1 process per connection; instead by default 1 process per
request is also created. This has a number of pros and cons.
Because it has cons, we also allow users to use a lower-level API
that acts on "streams" (requests/responses) directly at the connection
process-level. If performance is a concern, one can always write a
stream handler. The performance in this case will be even greater
than with Cowboy 1, although all the special handlers are unavailable.
When switching to Websocket, after the handler returns from init/2,
Cowboy stops the stream and the Websocket protocol takes over the
connection process. Websocket then calls websocket_init/2 for any
additional initialization such as timers, because the process is
different in init/2 and websocket_*/* functions. This however would
allow us to use websocket_init/2 for sending messages on connect,
instead of sending ourselves a message and be subject to races.
Note that websocket_init/2 is optional.
This is all a big change and while most of the tests pass, some
functionality currently doesn't. SPDY is broken and will be removed
soon in favor of HTTP/2. Automatic compression is currently disabled.
The cowboy_req interface probably still have a few functions that
need to be updated. The docs and examples do not refer the current
functionality anymore.
Everything will be fixed over time. Feedback is more than welcome.
Open a ticket!
2016-02-10 17:28:32 +01:00
|
|
|
YRL_FILES := $(filter %.yrl,$(ALL_SRC_FILES))
|
2015-11-16 23:08:24 +01:00
|
|
|
YRL_ERL_FILES = $(addprefix src/,$(patsubst %.yrl,%.erl,$(notdir $(YRL_FILES))))
|
|
|
|
ERL_FILES += $(YRL_ERL_FILES)
|
2013-04-30 20:51:37 +02:00
|
|
|
|
2015-11-16 23:08:24 +01:00
|
|
|
$(PROJECT).d:: $(XRL_FILES) $(YRL_FILES)
|
2016-11-05 14:17:30 +02:00
|
|
|
$(if $(strip $?),$(xyrl_verbose) erlc -v -o src/ $(YRL_ERLC_OPTS) $?)
|
2015-11-16 23:08:24 +01:00
|
|
|
|
|
|
|
# Erlang and Core Erlang files.
|
|
|
|
|
|
|
|
define makedep.erl
|
2016-01-14 13:35:25 +01:00
|
|
|
E = ets:new(makedep, [bag]),
|
|
|
|
G = digraph:new([acyclic]),
|
2015-11-16 23:08:24 +01:00
|
|
|
ErlFiles = lists:usort(string:tokens("$(ERL_FILES)", " ")),
|
2018-05-16 12:28:55 +02:00
|
|
|
DepsDir = "$(call core_native_path,$(DEPS_DIR))",
|
|
|
|
AppsDir = "$(call core_native_path,$(APPS_DIR))",
|
|
|
|
DepsDirsSrc = "$(if $(wildcard $(DEPS_DIR)/*/src), $(call core_native_path,$(wildcard $(DEPS_DIR)/*/src)))",
|
|
|
|
DepsDirsInc = "$(if $(wildcard $(DEPS_DIR)/*/include), $(call core_native_path,$(wildcard $(DEPS_DIR)/*/include)))",
|
|
|
|
AppsDirsSrc = "$(if $(wildcard $(APPS_DIR)/*/src), $(call core_native_path,$(wildcard $(APPS_DIR)/*/src)))",
|
|
|
|
AppsDirsInc = "$(if $(wildcard $(APPS_DIR)/*/include), $(call core_native_path,$(wildcard $(APPS_DIR)/*/include)))",
|
|
|
|
DepsDirs = lists:usort(string:tokens(DepsDirsSrc++DepsDirsInc, " ")),
|
|
|
|
AppsDirs = lists:usort(string:tokens(AppsDirsSrc++AppsDirsInc, " ")),
|
2016-01-14 13:35:25 +01:00
|
|
|
Modules = [{list_to_atom(filename:basename(F, ".erl")), F} || F <- ErlFiles],
|
|
|
|
Add = fun (Mod, Dep) ->
|
|
|
|
case lists:keyfind(Dep, 1, Modules) of
|
|
|
|
false -> ok;
|
|
|
|
{_, DepFile} ->
|
|
|
|
{_, ModFile} = lists:keyfind(Mod, 1, Modules),
|
|
|
|
ets:insert(E, {ModFile, DepFile}),
|
|
|
|
digraph:add_vertex(G, Mod),
|
|
|
|
digraph:add_vertex(G, Dep),
|
|
|
|
digraph:add_edge(G, Mod, Dep)
|
2015-11-16 23:08:24 +01:00
|
|
|
end
|
|
|
|
end,
|
2016-01-14 13:35:25 +01:00
|
|
|
AddHd = fun (F, Mod, DepFile) ->
|
|
|
|
case file:open(DepFile, [read]) of
|
2018-05-16 12:28:55 +02:00
|
|
|
{error, enoent} ->
|
|
|
|
ok;
|
2016-01-14 13:35:25 +01:00
|
|
|
{ok, Fd} ->
|
|
|
|
{_, ModFile} = lists:keyfind(Mod, 1, Modules),
|
2018-05-16 12:28:55 +02:00
|
|
|
case ets:match(E, {ModFile, DepFile}) of
|
|
|
|
[] ->
|
|
|
|
ets:insert(E, {ModFile, DepFile}),
|
|
|
|
F(F, Fd, Mod,0);
|
|
|
|
_ -> ok
|
|
|
|
end
|
2015-11-16 23:08:24 +01:00
|
|
|
end
|
|
|
|
end,
|
2018-05-16 12:28:55 +02:00
|
|
|
SearchHrl = fun
|
|
|
|
F(_Hrl, []) -> {error,enoent};
|
|
|
|
F(Hrl, [Dir|Dirs]) ->
|
|
|
|
HrlF = filename:join([Dir,Hrl]),
|
|
|
|
case filelib:is_file(HrlF) of
|
|
|
|
true ->
|
|
|
|
{ok, HrlF};
|
|
|
|
false -> F(Hrl,Dirs)
|
|
|
|
end
|
|
|
|
end,
|
2016-01-14 13:35:25 +01:00
|
|
|
Attr = fun
|
2018-05-16 12:28:55 +02:00
|
|
|
(_F, Mod, behavior, Dep) ->
|
|
|
|
Add(Mod, Dep);
|
|
|
|
(_F, Mod, behaviour, Dep) ->
|
|
|
|
Add(Mod, Dep);
|
|
|
|
(_F, Mod, compile, {parse_transform, Dep}) ->
|
|
|
|
Add(Mod, Dep);
|
|
|
|
(_F, Mod, compile, Opts) when is_list(Opts) ->
|
2016-01-14 13:35:25 +01:00
|
|
|
case proplists:get_value(parse_transform, Opts) of
|
|
|
|
undefined -> ok;
|
|
|
|
Dep -> Add(Mod, Dep)
|
|
|
|
end;
|
|
|
|
(F, Mod, include, Hrl) ->
|
2018-05-16 12:28:55 +02:00
|
|
|
case SearchHrl(Hrl, ["src", "include",AppsDir,DepsDir]++AppsDirs++DepsDirs) of
|
|
|
|
{ok, FoundHrl} -> AddHd(F, Mod, FoundHrl);
|
|
|
|
{error, _} -> false
|
|
|
|
end;
|
|
|
|
(F, Mod, include_lib, Hrl) ->
|
|
|
|
case SearchHrl(Hrl, ["src", "include",AppsDir,DepsDir]++AppsDirs++DepsDirs) of
|
|
|
|
{ok, FoundHrl} -> AddHd(F, Mod, FoundHrl);
|
|
|
|
{error, _} -> false
|
2016-01-14 13:35:25 +01:00
|
|
|
end;
|
|
|
|
(F, Mod, import, {Imp, _}) ->
|
2017-07-14 21:44:39 +02:00
|
|
|
IsFile =
|
|
|
|
case lists:keyfind(Imp, 1, Modules) of
|
|
|
|
false -> false;
|
|
|
|
{_, FilePath} -> filelib:is_file(FilePath)
|
|
|
|
end,
|
|
|
|
case IsFile of
|
2016-01-14 13:35:25 +01:00
|
|
|
false -> ok;
|
|
|
|
true -> Add(Mod, Imp)
|
|
|
|
end;
|
|
|
|
(_, _, _, _) -> ok
|
2015-11-16 23:08:24 +01:00
|
|
|
end,
|
2018-05-16 12:28:55 +02:00
|
|
|
MakeDepend = fun
|
|
|
|
(F, Fd, Mod, StartLocation) ->
|
|
|
|
case io:parse_erl_form(Fd, undefined, StartLocation) of
|
|
|
|
{ok, AbsData, EndLocation} ->
|
|
|
|
case AbsData of
|
|
|
|
{attribute, _, Key, Value} ->
|
|
|
|
Attr(F, Mod, Key, Value),
|
|
|
|
F(F, Fd, Mod, EndLocation);
|
|
|
|
_ -> F(F, Fd, Mod, EndLocation)
|
|
|
|
end;
|
|
|
|
{eof, _ } -> file:close(Fd);
|
|
|
|
{error, ErrorDescription } ->
|
|
|
|
file:close(Fd);
|
|
|
|
{error, ErrorInfo, ErrorLocation} ->
|
|
|
|
F(F, Fd, Mod, ErrorLocation)
|
|
|
|
end,
|
|
|
|
ok
|
2016-01-14 13:35:25 +01:00
|
|
|
end,
|
|
|
|
[begin
|
|
|
|
Mod = list_to_atom(filename:basename(F, ".erl")),
|
2020-03-29 15:45:51 +02:00
|
|
|
case file:open(F, [read]) of
|
|
|
|
{ok, Fd} -> MakeDepend(MakeDepend, Fd, Mod,0);
|
|
|
|
{error, enoent} -> ok
|
|
|
|
end
|
2015-11-16 23:08:24 +01:00
|
|
|
end || F <- ErlFiles],
|
2016-01-14 13:35:25 +01:00
|
|
|
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)],
|
2017-07-14 21:44:39 +02:00
|
|
|
TargetPath = fun(Target) ->
|
|
|
|
case lists:keyfind(Target, 1, Modules) of
|
|
|
|
false -> "";
|
|
|
|
{_, DepFile} ->
|
|
|
|
DirSubname = tl(string:tokens(filename:dirname(DepFile), "/")),
|
|
|
|
string:join(DirSubname ++ [atom_to_list(Target)], "/")
|
|
|
|
end
|
|
|
|
end,
|
2020-10-07 13:44:24 +02:00
|
|
|
Output0 = [
|
2020-03-29 15:45:51 +02:00
|
|
|
"# Generated by Erlang.mk. Edit at your own risk!\n\n",
|
2016-01-14 13:35:25 +01:00
|
|
|
[[F, "::", [[" ", D] || D <- Deps], "; @touch \$$@\n"] || {F, Deps} <- Depend],
|
2017-07-14 21:44:39 +02:00
|
|
|
"\nCOMPILE_FIRST +=", [[" ", TargetPath(CF)] || CF <- CompileFirst], "\n"
|
2020-10-07 13:44:24 +02:00
|
|
|
],
|
|
|
|
Output = case "é" of
|
|
|
|
[233] -> unicode:characters_to_binary(Output0);
|
|
|
|
_ -> Output0
|
|
|
|
end,
|
2025-02-11 16:02:10 +01:00
|
|
|
ok = file:write_file("$1", Output),
|
2015-11-16 23:08:24 +01:00
|
|
|
halt()
|
|
|
|
endef
|
|
|
|
|
|
|
|
ifeq ($(if $(NO_MAKEDEP),$(wildcard $(PROJECT).d),),)
|
2016-11-05 14:17:30 +02:00
|
|
|
$(PROJECT).d:: $(ERL_FILES) $(call core_find,include/,*.hrl) $(MAKEFILE_LIST)
|
2015-11-16 23:08:24 +01:00
|
|
|
$(makedep_verbose) $(call erlang,$(call makedep.erl,$@))
|
|
|
|
endif
|
|
|
|
|
2020-03-29 15:45:51 +02:00
|
|
|
ifeq ($(IS_APP)$(IS_DEP),)
|
2016-11-05 14:17:30 +02:00
|
|
|
ifneq ($(words $(ERL_FILES) $(CORE_FILES) $(ASN1_FILES) $(MIB_FILES) $(XRL_FILES) $(YRL_FILES)),0)
|
2015-11-16 23:08:24 +01:00
|
|
|
# Rebuild everything when the Makefile changes.
|
2020-03-29 15:45:51 +02:00
|
|
|
$(ERLANG_MK_TMP)/last-makefile-change: $(MAKEFILE_LIST) | $(ERLANG_MK_TMP)
|
2016-11-05 14:17:30 +02:00
|
|
|
$(verbose) if test -f $@; then \
|
|
|
|
touch $(ERL_FILES) $(CORE_FILES) $(ASN1_FILES) $(MIB_FILES) $(XRL_FILES) $(YRL_FILES); \
|
|
|
|
touch -c $(PROJECT).d; \
|
|
|
|
fi
|
|
|
|
$(verbose) touch $@
|
|
|
|
|
|
|
|
$(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
|
2020-03-29 15:45:51 +02:00
|
|
|
endif
|
|
|
|
|
|
|
|
$(PROJECT).d::
|
|
|
|
$(verbose) :
|
2015-11-16 23:08:24 +01:00
|
|
|
|
2017-07-14 21:44:39 +02:00
|
|
|
include $(wildcard $(PROJECT).d)
|
2015-11-16 23:08:24 +01:00
|
|
|
|
|
|
|
ebin/$(PROJECT).app:: ebin/
|
|
|
|
|
|
|
|
ebin/:
|
|
|
|
$(verbose) mkdir -p ebin/
|
|
|
|
|
|
|
|
define compile_erl
|
|
|
|
$(erlc_verbose) erlc -v $(if $(IS_DEP),$(filter-out -Werror,$(ERLC_OPTS)),$(ERLC_OPTS)) -o ebin/ \
|
2025-02-11 16:02:10 +01:00
|
|
|
-pa ebin/ -I include/ $(filter-out $(ERLC_EXCLUDE_PATHS),$(COMPILE_FIRST_PATHS) $1)
|
2015-11-16 23:08:24 +01:00
|
|
|
endef
|
|
|
|
|
2020-03-29 15:45:51 +02:00
|
|
|
define validate_app_file
|
|
|
|
case file:consult("ebin/$(PROJECT).app") of
|
|
|
|
{ok, _} -> halt();
|
|
|
|
_ -> halt(1)
|
|
|
|
end
|
|
|
|
endef
|
|
|
|
|
2015-11-16 23:08:24 +01:00
|
|
|
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)))
|
2020-03-29 15:45:51 +02:00
|
|
|
# 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))
|
2015-11-16 23:08:24 +01:00
|
|
|
$(eval MODULES := $(patsubst %,'%',$(sort $(notdir $(basename \
|
|
|
|
$(filter-out $(ERLC_EXCLUDE_PATHS),$(ERL_FILES) $(CORE_FILES) $(BEAM_FILES)))))))
|
|
|
|
ifeq ($(wildcard src/$(PROJECT).app.src),)
|
2016-11-05 14:17:30 +02:00
|
|
|
$(app_verbose) printf '$(subst %,%%,$(subst $(newline),\n,$(subst ','\'',$(call app_file,$(GITDESCRIBE),$(MODULES)))))' \
|
2015-11-16 23:08:24 +01:00
|
|
|
> ebin/$(PROJECT).app
|
2020-03-29 15:45:51 +02:00
|
|
|
$(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
|
2015-11-16 23:08:24 +01:00
|
|
|
else
|
2016-11-05 14:17:30 +02:00
|
|
|
$(verbose) if [ -z "$$(grep -e '^[^%]*{\s*modules\s*,' src/$(PROJECT).app.src)" ]; then \
|
2020-03-29 15:45:51 +02:00
|
|
|
echo "Empty modules entry not found in $(PROJECT).app.src. Please consult the erlang.mk documentation for instructions." >&2; \
|
2015-11-16 23:08:24 +01:00
|
|
|
exit 1; \
|
|
|
|
fi
|
|
|
|
$(appsrc_verbose) cat src/$(PROJECT).app.src \
|
|
|
|
| sed "s/{[[:space:]]*modules[[:space:]]*,[[:space:]]*\[\]}/{modules, \[$(call comma_list,$(MODULES))\]}/" \
|
2016-11-05 14:17:30 +02:00
|
|
|
| sed "s/{id,[[:space:]]*\"git\"}/{id, \"$(subst /,\/,$(GITDESCRIBE))\"}/" \
|
2015-11-16 23:08:24 +01:00
|
|
|
> ebin/$(PROJECT).app
|
2014-08-01 14:26:51 +02:00
|
|
|
endif
|
2020-03-29 15:45:51 +02:00
|
|
|
ifneq ($(wildcard src/$(PROJECT).appup),)
|
|
|
|
$(verbose) cp src/$(PROJECT).appup ebin/
|
|
|
|
endif
|
2013-04-30 20:51:37 +02:00
|
|
|
|
2014-08-01 14:26:51 +02:00
|
|
|
clean:: clean-app
|
|
|
|
|
2015-05-05 19:59:37 +03:00
|
|
|
clean-app:
|
2015-11-16 23:08:24 +01:00
|
|
|
$(gen_verbose) rm -rf $(PROJECT).d ebin/ priv/mibs/ $(XRL_ERL_FILES) $(YRL_ERL_FILES) \
|
|
|
|
$(addprefix include/,$(patsubst %.mib,%.hrl,$(notdir $(MIB_FILES)))) \
|
|
|
|
$(addprefix include/,$(patsubst %.asn1,%.hrl,$(notdir $(ASN1_FILES)))) \
|
|
|
|
$(addprefix include/,$(patsubst %.asn1,%.asn1db,$(notdir $(ASN1_FILES)))) \
|
|
|
|
$(addprefix src/,$(patsubst %.asn1,%.erl,$(notdir $(ASN1_FILES))))
|
|
|
|
|
|
|
|
endif
|
2014-08-01 14:26:51 +02:00
|
|
|
|
2016-11-05 14:17:30 +02:00
|
|
|
# Copyright (c) 2016, Loïc Hoguin <essen@ninenines.eu>
|
2015-06-11 17:04:21 +02:00
|
|
|
# Copyright (c) 2015, Viktor Söderqvist <viktor@zuiderkwast.se>
|
|
|
|
# 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)
|
2018-08-13 08:38:49 +02:00
|
|
|
$(verbose) set -e; for dep in $(ALL_DOC_DEPS_DIRS) ; do $(MAKE) -C $$dep IS_DEP=1; done
|
2015-06-11 17:04:21 +02:00
|
|
|
endif
|
|
|
|
|
2016-11-05 14:17:30 +02:00
|
|
|
# Copyright (c) 2015-2016, Loïc Hoguin <essen@ninenines.eu>
|
2015-05-05 19:59:37 +03:00
|
|
|
# This file is part of erlang.mk and subject to the terms of the ISC License.
|
2014-10-04 15:52:41 +03:00
|
|
|
|
2016-01-14 13:35:25 +01:00
|
|
|
.PHONY: rel-deps
|
|
|
|
|
|
|
|
# Configuration.
|
|
|
|
|
|
|
|
ALL_REL_DEPS_DIRS = $(addprefix $(DEPS_DIR)/,$(REL_DEPS))
|
|
|
|
|
|
|
|
# Targets.
|
|
|
|
|
|
|
|
$(foreach dep,$(REL_DEPS),$(eval $(call dep_target,$(dep))))
|
|
|
|
|
|
|
|
ifneq ($(SKIP_DEPS),)
|
|
|
|
rel-deps:
|
|
|
|
else
|
|
|
|
rel-deps: $(ALL_REL_DEPS_DIRS)
|
2017-07-14 21:44:39 +02:00
|
|
|
$(verbose) set -e; for dep in $(ALL_REL_DEPS_DIRS) ; do $(MAKE) -C $$dep; done
|
2016-01-14 13:35:25 +01:00
|
|
|
endif
|
|
|
|
|
2016-11-05 14:17:30 +02:00
|
|
|
# Copyright (c) 2015-2016, Loïc Hoguin <essen@ninenines.eu>
|
2016-01-14 13:35:25 +01:00
|
|
|
# This file is part of erlang.mk and subject to the terms of the ISC License.
|
|
|
|
|
2015-05-05 19:59:37 +03:00
|
|
|
.PHONY: test-deps test-dir test-build clean-test-dir
|
|
|
|
|
|
|
|
# Configuration.
|
|
|
|
|
2015-06-11 17:04:21 +02:00
|
|
|
TEST_DIR ?= $(CURDIR)/test
|
2015-05-05 19:59:37 +03:00
|
|
|
|
|
|
|
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))))
|
|
|
|
|
2015-06-11 17:04:21 +02:00
|
|
|
ifneq ($(SKIP_DEPS),)
|
|
|
|
test-deps:
|
|
|
|
else
|
2015-05-05 19:59:37 +03:00
|
|
|
test-deps: $(ALL_TEST_DEPS_DIRS)
|
2020-03-29 15:45:51 +02:00
|
|
|
$(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
|
2015-06-11 17:04:21 +02:00
|
|
|
endif
|
2015-05-05 19:59:37 +03:00
|
|
|
|
2015-07-21 17:16:11 +02:00
|
|
|
ifneq ($(wildcard $(TEST_DIR)),)
|
2020-10-07 13:44:24 +02:00
|
|
|
test-dir: $(ERLANG_MK_TMP)/$(PROJECT).last-testdir-build
|
|
|
|
@:
|
|
|
|
|
|
|
|
test_erlc_verbose_0 = @echo " ERLC " $(filter-out $(patsubst %,%.erl,$(ERLC_EXCLUDE)),\
|
|
|
|
$(filter %.erl %.core,$(notdir $(FILES_TO_COMPILE))));
|
|
|
|
test_erlc_verbose_2 = set -x;
|
|
|
|
test_erlc_verbose = $(test_erlc_verbose_$(V))
|
|
|
|
|
|
|
|
define compile_test_erl
|
|
|
|
$(test_erlc_verbose) erlc -v $(TEST_ERLC_OPTS) -o $(TEST_DIR) \
|
2025-02-11 16:02:10 +01:00
|
|
|
-pa ebin/ -I include/ $1
|
2020-10-07 13:44:24 +02:00
|
|
|
endef
|
|
|
|
|
|
|
|
ERL_TEST_FILES = $(call core_find,$(TEST_DIR)/,*.erl)
|
2024-11-06 16:33:39 +01:00
|
|
|
|
2020-10-07 13:44:24 +02:00
|
|
|
$(ERLANG_MK_TMP)/$(PROJECT).last-testdir-build: $(ERL_TEST_FILES) $(MAKEFILE_LIST)
|
2024-11-06 16:33:39 +01:00
|
|
|
# When we have to recompile files in src/ the .d file always gets rebuilt.
|
|
|
|
# Therefore we want to ignore it when rebuilding test files.
|
|
|
|
$(eval FILES_TO_COMPILE := $(if $(filter $(filter-out $(PROJECT).d,$(MAKEFILE_LIST)),$?),$(filter $(ERL_TEST_FILES),$^),$(filter $(ERL_TEST_FILES),$?)))
|
2020-10-07 13:44:24 +02:00
|
|
|
$(if $(strip $(FILES_TO_COMPILE)),$(call compile_test_erl,$(FILES_TO_COMPILE)) && touch $@)
|
2015-05-05 19:59:37 +03:00
|
|
|
endif
|
|
|
|
|
2020-03-29 15:45:51 +02:00
|
|
|
test-build:: IS_TEST=1
|
2016-01-14 13:35:25 +01:00
|
|
|
test-build:: ERLC_OPTS=$(TEST_ERLC_OPTS)
|
2024-11-06 16:33:39 +01:00
|
|
|
test-build:: $(if $(wildcard src),$(if $(wildcard ebin/test),,beam-cache-restore-test)) $(if $(IS_APP),,deps test-deps)
|
2020-03-29 15:45:51 +02:00
|
|
|
# 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))"
|
2015-05-05 19:59:37 +03:00
|
|
|
$(gen_verbose) touch ebin/test
|
2020-03-29 15:45:51 +02:00
|
|
|
endif
|
2020-10-07 13:44:24 +02:00
|
|
|
ifneq ($(wildcard $(TEST_DIR)),)
|
|
|
|
$(verbose) $(MAKE) --no-print-directory test-dir ERLC_OPTS="$(call escape_dquotes,$(TEST_ERLC_OPTS))"
|
|
|
|
endif
|
2020-03-29 15:45:51 +02:00
|
|
|
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
|
|
|
|
endif
|
2020-10-07 13:44:24 +02:00
|
|
|
ifneq ($(wildcard $(TEST_DIR)),)
|
|
|
|
$(verbose) $(MAKE) --no-print-directory test-dir ERLC_OPTS="$(call escape_dquotes,$(TEST_ERLC_OPTS))"
|
|
|
|
endif
|
2015-05-05 19:59:37 +03:00
|
|
|
endif
|
|
|
|
|
|
|
|
clean:: clean-test-dir
|
|
|
|
|
|
|
|
clean-test-dir:
|
|
|
|
ifneq ($(wildcard $(TEST_DIR)/*.beam),)
|
2020-10-07 13:44:24 +02:00
|
|
|
$(gen_verbose) rm -f $(TEST_DIR)/*.beam $(ERLANG_MK_TMP)/$(PROJECT).last-testdir-build
|
2015-05-05 19:59:37 +03:00
|
|
|
endif
|
2016-01-14 13:35:25 +01:00
|
|
|
|
2016-11-05 14:17:30 +02:00
|
|
|
# Copyright (c) 2015-2016, Loïc Hoguin <essen@ninenines.eu>
|
2016-01-14 13:35:25 +01:00
|
|
|
# This file is part of erlang.mk and subject to the terms of the ISC License.
|
|
|
|
|
|
|
|
.PHONY: rebar.config
|
|
|
|
|
2025-02-11 16:02:10 +01:00
|
|
|
compat_ref = {$(shell (git -C $(DEPS_DIR)/$1 show-ref -q --verify "refs/heads/$2" && echo branch) || (git -C $(DEPS_DIR)/$1 show-ref -q --verify "refs/tags/$2" && echo tag) || echo ref),"$2"}
|
|
|
|
|
2016-01-14 13:35:25 +01:00
|
|
|
# We strip out -Werror because we don't want to fail due to
|
|
|
|
# warnings when used as a dependency.
|
|
|
|
|
2016-11-05 14:17:30 +02:00
|
|
|
compat_prepare_erlc_opts = $(shell echo "$1" | sed 's/, */,/g')
|
2016-01-14 13:35:25 +01:00
|
|
|
|
|
|
|
define compat_convert_erlc_opts
|
|
|
|
$(if $(filter-out -Werror,$1),\
|
|
|
|
$(if $(findstring +,$1),\
|
|
|
|
$(shell echo $1 | cut -b 2-)))
|
|
|
|
endef
|
|
|
|
|
|
|
|
define compat_erlc_opts_to_list
|
2016-01-15 13:48:35 +01:00
|
|
|
[$(call comma_list,$(foreach o,$(call compat_prepare_erlc_opts,$1),$(call compat_convert_erlc_opts,$o)))]
|
2016-01-14 13:35:25 +01:00
|
|
|
endef
|
|
|
|
|
|
|
|
define compat_rebar_config
|
2016-11-05 14:17:30 +02:00
|
|
|
{deps, [
|
|
|
|
$(call comma_list,$(foreach d,$(DEPS),\
|
2025-02-11 16:02:10 +01:00
|
|
|
$(if $(filter hex,$(call query_fetch_method,$d)),\
|
|
|
|
{$(call query_name,$d)$(comma)"$(call query_version_hex,$d)"},\
|
|
|
|
{$(call query_name,$d)$(comma)".*"$(comma){git,"$(call query_repo,$d)"$(comma)$(call compat_ref,$(call query_name,$d),$(call query_version,$d))}})))
|
2016-11-05 14:17:30 +02:00
|
|
|
]}.
|
2016-01-14 13:35:25 +01:00
|
|
|
{erl_opts, $(call compat_erlc_opts_to_list,$(ERLC_OPTS))}.
|
|
|
|
endef
|
|
|
|
|
2025-02-11 16:02:10 +01:00
|
|
|
rebar.config: deps
|
2020-03-29 15:45:51 +02:00
|
|
|
$(gen_verbose) $(call core_render,compat_rebar_config,rebar.config)
|
2014-08-01 14:26:51 +02:00
|
|
|
|
2025-02-11 16:02:10 +01:00
|
|
|
define tpl_application.app.src
|
|
|
|
{application, project_name, [
|
2015-06-11 17:04:21 +02:00
|
|
|
{description, ""},
|
|
|
|
{vsn, "0.1.0"},
|
|
|
|
{id, "git"},
|
|
|
|
{modules, []},
|
|
|
|
{registered, []},
|
|
|
|
{applications, [
|
|
|
|
kernel,
|
|
|
|
stdlib
|
|
|
|
]},
|
2025-02-11 16:02:10 +01:00
|
|
|
{mod, {project_name_app, []}},
|
2015-06-11 17:04:21 +02:00
|
|
|
{env, []}
|
|
|
|
]}.
|
|
|
|
endef
|
|
|
|
|
2025-02-11 16:02:10 +01:00
|
|
|
define tpl_application
|
|
|
|
-module(project_name_app).
|
2015-06-11 17:04:21 +02:00
|
|
|
-behaviour(application).
|
|
|
|
|
|
|
|
-export([start/2]).
|
|
|
|
-export([stop/1]).
|
|
|
|
|
|
|
|
start(_Type, _Args) ->
|
2025-02-11 16:02:10 +01:00
|
|
|
project_name_sup:start_link().
|
2015-06-11 17:04:21 +02:00
|
|
|
|
|
|
|
stop(_State) ->
|
|
|
|
ok.
|
|
|
|
endef
|
|
|
|
|
2025-02-11 16:02:10 +01:00
|
|
|
define tpl_apps_Makefile
|
|
|
|
PROJECT = project_name
|
|
|
|
PROJECT_DESCRIPTION = New project
|
|
|
|
PROJECT_VERSION = 0.1.0
|
|
|
|
template_sp
|
|
|
|
# Make sure we know where the applications are located.
|
|
|
|
ROOT_DIR ?= rel_root_dir
|
|
|
|
APPS_DIR ?= ..
|
|
|
|
DEPS_DIR ?= rel_deps_dir
|
2015-06-11 17:04:21 +02:00
|
|
|
|
2025-02-11 16:02:10 +01:00
|
|
|
include rel_root_dir/erlang.mk
|
2015-06-11 17:04:21 +02:00
|
|
|
endef
|
|
|
|
|
2025-02-11 16:02:10 +01:00
|
|
|
define tpl_cowboy_http_h
|
|
|
|
-module(template_name).
|
|
|
|
-behaviour(cowboy_http_handler).
|
2015-06-11 17:04:21 +02:00
|
|
|
|
2025-02-11 16:02:10 +01:00
|
|
|
-export([init/3]).
|
|
|
|
-export([handle/2]).
|
|
|
|
-export([terminate/3]).
|
2015-06-11 17:04:21 +02:00
|
|
|
|
2025-02-11 16:02:10 +01:00
|
|
|
-record(state, {
|
|
|
|
}).
|
2015-06-11 17:04:21 +02:00
|
|
|
|
2025-02-11 16:02:10 +01:00
|
|
|
init(_, Req, _Opts) ->
|
|
|
|
{ok, Req, #state{}}.
|
2015-06-11 17:04:21 +02:00
|
|
|
|
2025-02-11 16:02:10 +01:00
|
|
|
handle(Req, State=#state{}) ->
|
|
|
|
{ok, Req2} = cowboy_req:reply(200, Req),
|
|
|
|
{ok, Req2, State}.
|
2015-06-11 17:04:21 +02:00
|
|
|
|
2025-02-11 16:02:10 +01:00
|
|
|
terminate(_Reason, _Req, _State) ->
|
|
|
|
ok.
|
2015-06-11 17:04:21 +02:00
|
|
|
endef
|
|
|
|
|
2025-02-11 16:02:10 +01:00
|
|
|
define tpl_cowboy_loop_h
|
|
|
|
-module(template_name).
|
|
|
|
-behaviour(cowboy_loop_handler).
|
2015-06-11 17:04:21 +02:00
|
|
|
|
2025-02-11 16:02:10 +01:00
|
|
|
-export([init/3]).
|
|
|
|
-export([info/3]).
|
|
|
|
-export([terminate/3]).
|
2015-06-11 17:04:21 +02:00
|
|
|
|
|
|
|
-record(state, {
|
|
|
|
}).
|
|
|
|
|
2025-02-11 16:02:10 +01:00
|
|
|
init(_, Req, _Opts) ->
|
|
|
|
{loop, Req, #state{}, 5000, hibernate}.
|
2015-06-11 17:04:21 +02:00
|
|
|
|
2025-02-11 16:02:10 +01:00
|
|
|
info(_Info, Req, State) ->
|
|
|
|
{loop, Req, State, hibernate}.
|
2015-06-11 17:04:21 +02:00
|
|
|
|
2025-02-11 16:02:10 +01:00
|
|
|
terminate(_Reason, _Req, _State) ->
|
|
|
|
ok.
|
|
|
|
endef
|
2015-06-11 17:04:21 +02:00
|
|
|
|
2025-02-11 16:02:10 +01:00
|
|
|
define tpl_cowboy_rest_h
|
|
|
|
-module(template_name).
|
2015-06-11 17:04:21 +02:00
|
|
|
|
2025-02-11 16:02:10 +01:00
|
|
|
-export([init/3]).
|
|
|
|
-export([content_types_provided/2]).
|
|
|
|
-export([get_html/2]).
|
2015-06-11 17:04:21 +02:00
|
|
|
|
2025-02-11 16:02:10 +01:00
|
|
|
init(_, _Req, _Opts) ->
|
|
|
|
{upgrade, protocol, cowboy_rest}.
|
2015-06-11 17:04:21 +02:00
|
|
|
|
2025-02-11 16:02:10 +01:00
|
|
|
content_types_provided(Req, State) ->
|
|
|
|
{[{{<<"text">>, <<"html">>, '*'}, get_html}], Req, State}.
|
2015-06-11 17:04:21 +02:00
|
|
|
|
2025-02-11 16:02:10 +01:00
|
|
|
get_html(Req, State) ->
|
|
|
|
{<<"<html><body>This is REST!</body></html>">>, Req, State}.
|
2016-11-05 14:17:30 +02:00
|
|
|
endef
|
|
|
|
|
2025-02-11 16:02:10 +01:00
|
|
|
define tpl_cowboy_websocket_h
|
|
|
|
-module(template_name).
|
|
|
|
-behaviour(cowboy_websocket_handler).
|
2015-06-11 17:04:21 +02:00
|
|
|
|
|
|
|
-export([init/3]).
|
2025-02-11 16:02:10 +01:00
|
|
|
-export([websocket_init/3]).
|
|
|
|
-export([websocket_handle/3]).
|
|
|
|
-export([websocket_info/3]).
|
|
|
|
-export([websocket_terminate/3]).
|
2015-06-11 17:04:21 +02:00
|
|
|
|
|
|
|
-record(state, {
|
|
|
|
}).
|
|
|
|
|
2025-02-11 16:02:10 +01:00
|
|
|
init(_, _, _) ->
|
|
|
|
{upgrade, protocol, cowboy_websocket}.
|
2015-06-11 17:04:21 +02:00
|
|
|
|
2025-02-11 16:02:10 +01:00
|
|
|
websocket_init(_, Req, _Opts) ->
|
|
|
|
Req2 = cowboy_req:compact(Req),
|
|
|
|
{ok, Req2, #state{}}.
|
2015-06-11 17:04:21 +02:00
|
|
|
|
2025-02-11 16:02:10 +01:00
|
|
|
websocket_handle({text, Data}, Req, State) ->
|
|
|
|
{reply, {text, Data}, Req, State};
|
|
|
|
websocket_handle({binary, Data}, Req, State) ->
|
|
|
|
{reply, {binary, Data}, Req, State};
|
|
|
|
websocket_handle(_Frame, Req, State) ->
|
|
|
|
{ok, Req, State}.
|
|
|
|
|
|
|
|
websocket_info(_Info, Req, State) ->
|
|
|
|
{ok, Req, State}.
|
|
|
|
|
|
|
|
websocket_terminate(_Reason, _Req, _State) ->
|
2015-06-11 17:04:21 +02:00
|
|
|
ok.
|
|
|
|
endef
|
|
|
|
|
|
|
|
define tpl_gen_fsm
|
2025-02-11 16:02:10 +01:00
|
|
|
-module(template_name).
|
2015-06-11 17:04:21 +02:00
|
|
|
-behaviour(gen_fsm).
|
|
|
|
|
|
|
|
%% API.
|
|
|
|
-export([start_link/0]).
|
|
|
|
|
|
|
|
%% gen_fsm.
|
|
|
|
-export([init/1]).
|
|
|
|
-export([state_name/2]).
|
|
|
|
-export([handle_event/3]).
|
|
|
|
-export([state_name/3]).
|
|
|
|
-export([handle_sync_event/4]).
|
|
|
|
-export([handle_info/3]).
|
|
|
|
-export([terminate/3]).
|
|
|
|
-export([code_change/4]).
|
|
|
|
|
|
|
|
-record(state, {
|
|
|
|
}).
|
|
|
|
|
|
|
|
%% API.
|
|
|
|
|
|
|
|
-spec start_link() -> {ok, pid()}.
|
|
|
|
start_link() ->
|
|
|
|
gen_fsm:start_link(?MODULE, [], []).
|
|
|
|
|
|
|
|
%% gen_fsm.
|
|
|
|
|
|
|
|
init([]) ->
|
|
|
|
{ok, state_name, #state{}}.
|
|
|
|
|
|
|
|
state_name(_Event, StateData) ->
|
|
|
|
{next_state, state_name, StateData}.
|
|
|
|
|
|
|
|
handle_event(_Event, StateName, StateData) ->
|
|
|
|
{next_state, StateName, StateData}.
|
|
|
|
|
|
|
|
state_name(_Event, _From, StateData) ->
|
|
|
|
{reply, ignored, state_name, StateData}.
|
|
|
|
|
|
|
|
handle_sync_event(_Event, _From, StateName, StateData) ->
|
|
|
|
{reply, ignored, StateName, StateData}.
|
|
|
|
|
|
|
|
handle_info(_Info, StateName, StateData) ->
|
|
|
|
{next_state, StateName, StateData}.
|
|
|
|
|
|
|
|
terminate(_Reason, _StateName, _StateData) ->
|
|
|
|
ok.
|
|
|
|
|
|
|
|
code_change(_OldVsn, StateName, StateData, _Extra) ->
|
|
|
|
{ok, StateName, StateData}.
|
|
|
|
endef
|
|
|
|
|
2025-02-11 16:02:10 +01:00
|
|
|
define tpl_gen_server
|
|
|
|
-module(template_name).
|
|
|
|
-behaviour(gen_server).
|
|
|
|
|
|
|
|
%% API.
|
|
|
|
-export([start_link/0]).
|
|
|
|
|
|
|
|
%% gen_server.
|
|
|
|
-export([init/1]).
|
|
|
|
-export([handle_call/3]).
|
|
|
|
-export([handle_cast/2]).
|
|
|
|
-export([handle_info/2]).
|
|
|
|
-export([terminate/2]).
|
|
|
|
-export([code_change/3]).
|
|
|
|
|
|
|
|
-record(state, {
|
|
|
|
}).
|
|
|
|
|
|
|
|
%% API.
|
|
|
|
|
|
|
|
-spec start_link() -> {ok, pid()}.
|
|
|
|
start_link() ->
|
|
|
|
gen_server:start_link(?MODULE, [], []).
|
|
|
|
|
|
|
|
%% gen_server.
|
|
|
|
|
|
|
|
init([]) ->
|
|
|
|
{ok, #state{}}.
|
|
|
|
|
|
|
|
handle_call(_Request, _From, State) ->
|
|
|
|
{reply, ignored, State}.
|
|
|
|
|
|
|
|
handle_cast(_Msg, State) ->
|
|
|
|
{noreply, State}.
|
|
|
|
|
|
|
|
handle_info(_Info, State) ->
|
|
|
|
{noreply, State}.
|
|
|
|
|
|
|
|
terminate(_Reason, _State) ->
|
|
|
|
ok.
|
|
|
|
|
|
|
|
code_change(_OldVsn, State, _Extra) ->
|
|
|
|
{ok, State}.
|
|
|
|
endef
|
|
|
|
|
2018-05-02 18:23:03 +02:00
|
|
|
define tpl_gen_statem
|
2025-02-11 16:02:10 +01:00
|
|
|
-module(template_name).
|
2018-05-02 18:23:03 +02:00
|
|
|
-behaviour(gen_statem).
|
|
|
|
|
|
|
|
%% API.
|
|
|
|
-export([start_link/0]).
|
|
|
|
|
|
|
|
%% gen_statem.
|
|
|
|
-export([callback_mode/0]).
|
|
|
|
-export([init/1]).
|
|
|
|
-export([state_name/3]).
|
|
|
|
-export([handle_event/4]).
|
|
|
|
-export([terminate/3]).
|
|
|
|
-export([code_change/4]).
|
|
|
|
|
|
|
|
-record(state, {
|
|
|
|
}).
|
|
|
|
|
|
|
|
%% API.
|
|
|
|
|
|
|
|
-spec start_link() -> {ok, pid()}.
|
|
|
|
start_link() ->
|
|
|
|
gen_statem:start_link(?MODULE, [], []).
|
|
|
|
|
|
|
|
%% gen_statem.
|
|
|
|
|
|
|
|
callback_mode() ->
|
|
|
|
state_functions.
|
|
|
|
|
|
|
|
init([]) ->
|
|
|
|
{ok, state_name, #state{}}.
|
|
|
|
|
|
|
|
state_name(_EventType, _EventData, StateData) ->
|
|
|
|
{next_state, state_name, StateData}.
|
|
|
|
|
|
|
|
handle_event(_EventType, _EventData, StateName, StateData) ->
|
|
|
|
{next_state, StateName, StateData}.
|
|
|
|
|
|
|
|
terminate(_Reason, _StateName, _StateData) ->
|
|
|
|
ok.
|
|
|
|
|
|
|
|
code_change(_OldVsn, StateName, StateData, _Extra) ->
|
|
|
|
{ok, StateName, StateData}.
|
|
|
|
endef
|
|
|
|
|
2025-02-11 16:02:10 +01:00
|
|
|
define tpl_library.app.src
|
|
|
|
{application, project_name, [
|
|
|
|
{description, ""},
|
|
|
|
{vsn, "0.1.0"},
|
|
|
|
{id, "git"},
|
|
|
|
{modules, []},
|
|
|
|
{registered, []},
|
|
|
|
{applications, [
|
|
|
|
kernel,
|
|
|
|
stdlib
|
|
|
|
]}
|
|
|
|
]}.
|
2015-06-11 17:04:21 +02:00
|
|
|
endef
|
|
|
|
|
2025-02-11 16:02:10 +01:00
|
|
|
define tpl_module
|
|
|
|
-module(template_name).
|
|
|
|
-export([]).
|
2015-06-11 17:04:21 +02:00
|
|
|
endef
|
|
|
|
|
|
|
|
define tpl_ranch_protocol
|
2025-02-11 16:02:10 +01:00
|
|
|
-module(template_name).
|
2015-06-11 17:04:21 +02:00
|
|
|
-behaviour(ranch_protocol).
|
|
|
|
|
|
|
|
-export([start_link/4]).
|
|
|
|
-export([init/4]).
|
|
|
|
|
|
|
|
-type opts() :: [].
|
|
|
|
-export_type([opts/0]).
|
|
|
|
|
|
|
|
-record(state, {
|
|
|
|
socket :: inet:socket(),
|
|
|
|
transport :: module()
|
|
|
|
}).
|
|
|
|
|
|
|
|
start_link(Ref, Socket, Transport, Opts) ->
|
|
|
|
Pid = spawn_link(?MODULE, init, [Ref, Socket, Transport, Opts]),
|
|
|
|
{ok, Pid}.
|
|
|
|
|
|
|
|
-spec init(ranch:ref(), inet:socket(), module(), opts()) -> ok.
|
|
|
|
init(Ref, Socket, Transport, _Opts) ->
|
|
|
|
ok = ranch:accept_ack(Ref),
|
|
|
|
loop(#state{socket=Socket, transport=Transport}).
|
|
|
|
|
|
|
|
loop(State) ->
|
|
|
|
loop(State).
|
|
|
|
endef
|
2014-08-01 14:26:51 +02:00
|
|
|
|
2025-02-11 16:02:10 +01:00
|
|
|
define tpl_relx.config
|
|
|
|
{release, {project_name_release, "1"}, [project_name, sasl, runtime_tools]}.
|
|
|
|
{dev_mode, false}.
|
|
|
|
{include_erts, true}.
|
|
|
|
{extended_start_script, true}.
|
|
|
|
{sys_config, "config/sys.config"}.
|
|
|
|
{vm_args, "config/vm.args"}.
|
|
|
|
endef
|
|
|
|
|
|
|
|
define tpl_supervisor
|
|
|
|
-module(template_name).
|
|
|
|
-behaviour(supervisor).
|
|
|
|
|
|
|
|
-export([start_link/0]).
|
|
|
|
-export([init/1]).
|
|
|
|
|
|
|
|
start_link() ->
|
|
|
|
supervisor:start_link({local, ?MODULE}, ?MODULE, []).
|
|
|
|
|
|
|
|
init([]) ->
|
|
|
|
Procs = [],
|
|
|
|
{ok, {{one_for_one, 1, 5}, Procs}}.
|
|
|
|
endef
|
|
|
|
|
|
|
|
define tpl_sys.config
|
|
|
|
[
|
|
|
|
].
|
|
|
|
endef
|
|
|
|
|
|
|
|
define tpl_top_Makefile
|
|
|
|
PROJECT = project_name
|
|
|
|
PROJECT_DESCRIPTION = New project
|
|
|
|
PROJECT_VERSION = 0.1.0
|
|
|
|
template_sp
|
|
|
|
include erlang.mk
|
|
|
|
endef
|
|
|
|
|
|
|
|
define tpl_vm.args
|
|
|
|
-name project_name@127.0.0.1
|
|
|
|
-setcookie project_name
|
|
|
|
-heart
|
|
|
|
endef
|
|
|
|
|
|
|
|
|
|
|
|
# Copyright (c) 2015-2016, Loïc Hoguin <essen@ninenines.eu>
|
|
|
|
# This file is part of erlang.mk and subject to the terms of the ISC License.
|
|
|
|
|
|
|
|
ifeq ($(filter asciideck,$(DEPS) $(DOC_DEPS)),asciideck)
|
|
|
|
|
|
|
|
.PHONY: asciidoc asciidoc-guide asciidoc-manual install-asciidoc distclean-asciidoc-guide distclean-asciidoc-manual
|
|
|
|
|
|
|
|
# Core targets.
|
|
|
|
|
|
|
|
docs:: asciidoc
|
|
|
|
|
|
|
|
distclean:: distclean-asciidoc-guide distclean-asciidoc-manual
|
|
|
|
|
|
|
|
# Plugin-specific targets.
|
|
|
|
|
|
|
|
asciidoc: asciidoc-guide asciidoc-manual
|
|
|
|
|
|
|
|
# User guide.
|
|
|
|
|
|
|
|
ifeq ($(wildcard doc/src/guide/book.asciidoc),)
|
|
|
|
asciidoc-guide:
|
|
|
|
else
|
|
|
|
asciidoc-guide: distclean-asciidoc-guide doc-deps
|
|
|
|
a2x -v -f pdf doc/src/guide/book.asciidoc && mv doc/src/guide/book.pdf doc/guide.pdf
|
|
|
|
a2x -v -f chunked doc/src/guide/book.asciidoc && mv doc/src/guide/book.chunked/ doc/html/
|
|
|
|
|
|
|
|
distclean-asciidoc-guide:
|
|
|
|
$(gen_verbose) rm -rf doc/html/ doc/guide.pdf
|
|
|
|
endif
|
|
|
|
|
|
|
|
# Man pages.
|
|
|
|
|
|
|
|
ASCIIDOC_MANUAL_FILES := $(wildcard doc/src/manual/*.asciidoc)
|
|
|
|
|
|
|
|
ifeq ($(ASCIIDOC_MANUAL_FILES),)
|
|
|
|
asciidoc-manual:
|
|
|
|
else
|
|
|
|
|
|
|
|
# Configuration.
|
|
|
|
|
|
|
|
MAN_INSTALL_PATH ?= /usr/local/share/man
|
|
|
|
MAN_SECTIONS ?= 3 7
|
|
|
|
MAN_PROJECT ?= $(shell echo $(PROJECT) | sed 's/^./\U&\E/')
|
|
|
|
MAN_VERSION ?= $(PROJECT_VERSION)
|
|
|
|
|
|
|
|
# Plugin-specific targets.
|
|
|
|
|
|
|
|
define asciidoc2man.erl
|
|
|
|
try
|
|
|
|
[begin
|
|
|
|
io:format(" ADOC ~s~n", [F]),
|
|
|
|
ok = asciideck:to_manpage(asciideck:parse_file(F), #{
|
|
|
|
compress => gzip,
|
|
|
|
outdir => filename:dirname(F),
|
|
|
|
extra2 => "$(MAN_PROJECT) $(MAN_VERSION)",
|
|
|
|
extra3 => "$(MAN_PROJECT) Function Reference"
|
|
|
|
})
|
|
|
|
end || F <- [$(shell echo $(addprefix $(comma)\",$(addsuffix \",$1)) | sed 's/^.//')]],
|
|
|
|
halt(0)
|
|
|
|
catch C:E$(if $V,:S) ->
|
|
|
|
io:format("Exception: ~p:~p~n$(if $V,Stacktrace: ~p~n)", [C, E$(if $V,$(comma) S)]),
|
|
|
|
halt(1)
|
|
|
|
end.
|
|
|
|
endef
|
|
|
|
|
|
|
|
asciidoc-manual:: doc-deps
|
|
|
|
|
|
|
|
asciidoc-manual:: $(ASCIIDOC_MANUAL_FILES)
|
|
|
|
$(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
|
|
|
|
|
|
|
|
install-asciidoc: asciidoc-manual
|
|
|
|
$(foreach s,$(MAN_SECTIONS),\
|
|
|
|
mkdir -p $(MAN_INSTALL_PATH)/man$s/ && \
|
|
|
|
install -g `id -g` -o `id -u` -m 0644 doc/man$s/*.gz $(MAN_INSTALL_PATH)/man$s/;)
|
|
|
|
|
|
|
|
distclean-asciidoc-manual:
|
|
|
|
$(gen_verbose) rm -rf $(addprefix doc/man,$(MAN_SECTIONS))
|
|
|
|
endif
|
|
|
|
endif
|
|
|
|
|
|
|
|
# Copyright (c) 2014-2016, Loïc Hoguin <essen@ninenines.eu>
|
|
|
|
# This file is part of erlang.mk and subject to the terms of the ISC License.
|
|
|
|
|
|
|
|
.PHONY: bootstrap bootstrap-lib bootstrap-rel new list-templates
|
|
|
|
|
|
|
|
# Core targets.
|
|
|
|
|
|
|
|
help::
|
|
|
|
$(verbose) printf "%s\n" "" \
|
|
|
|
"Bootstrap targets:" \
|
|
|
|
" bootstrap Generate a skeleton of an OTP application" \
|
|
|
|
" bootstrap-lib Generate a skeleton of an OTP library" \
|
|
|
|
" bootstrap-rel Generate the files needed to build a release" \
|
|
|
|
" new-app in=NAME Create a new local OTP application NAME" \
|
|
|
|
" new-lib in=NAME Create a new local OTP library NAME" \
|
|
|
|
" new t=TPL n=NAME Generate a module NAME based on the template TPL" \
|
|
|
|
" new t=T n=N in=APP Generate a module NAME based on the template TPL in APP" \
|
|
|
|
" list-templates List available templates"
|
|
|
|
|
2014-08-01 14:26:51 +02:00
|
|
|
# Plugin-specific targets.
|
|
|
|
|
2015-07-21 17:16:11 +02:00
|
|
|
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))
|
|
|
|
else
|
|
|
|
WS = $(tab)
|
|
|
|
endif
|
|
|
|
endif
|
|
|
|
|
2025-02-11 16:02:10 +01:00
|
|
|
ifdef SP
|
|
|
|
define template_sp
|
|
|
|
|
|
|
|
# By default templates indent with a single tab per indentation
|
|
|
|
# level. Set this variable to the number of spaces you prefer:
|
|
|
|
SP = $(SP)
|
|
|
|
|
|
|
|
endef
|
|
|
|
else
|
|
|
|
template_sp =
|
|
|
|
endif
|
|
|
|
|
|
|
|
# @todo Additional template placeholders could be added.
|
|
|
|
subst_template = $(subst rel_root_dir,$(call core_relpath,$(dir $(ERLANG_MK_FILENAME)),$(APPS_DIR)/app),$(subst rel_deps_dir,$(call core_relpath,$(DEPS_DIR),$(APPS_DIR)/app),$(subst template_sp,$(template_sp),$(subst project_name,$p,$(subst template_name,$n,$1)))))
|
|
|
|
|
|
|
|
define core_render_template
|
|
|
|
$(eval define _tpl_$(1)$(newline)$(call subst_template,$(tpl_$(1)))$(newline)endef)
|
|
|
|
$(verbose) $(call core_render,_tpl_$(1),$2)
|
|
|
|
endef
|
|
|
|
|
2014-08-01 14:26:51 +02:00
|
|
|
bootstrap:
|
|
|
|
ifneq ($(wildcard src/),)
|
|
|
|
$(error Error: src/ directory already exists)
|
2013-08-24 10:48:59 +02:00
|
|
|
endif
|
2015-11-16 23:08:24 +01:00
|
|
|
$(eval p := $(PROJECT))
|
2020-03-29 15:45:51 +02:00
|
|
|
$(if $(shell echo $p | LC_ALL=C grep -x "[a-z0-9_]*"),,\
|
|
|
|
$(error Error: Invalid characters in the application name))
|
2015-11-16 23:08:24 +01:00
|
|
|
$(eval n := $(PROJECT)_sup)
|
2025-02-11 16:02:10 +01:00
|
|
|
$(verbose) $(call core_render_template,top_Makefile,Makefile)
|
2015-07-21 17:16:11 +02:00
|
|
|
$(verbose) mkdir src/
|
2015-11-16 23:08:24 +01:00
|
|
|
ifdef LEGACY
|
2025-02-11 16:02:10 +01:00
|
|
|
$(verbose) $(call core_render_template,application.app.src,src/$(PROJECT).app.src)
|
2015-11-16 23:08:24 +01:00
|
|
|
endif
|
2025-02-11 16:02:10 +01:00
|
|
|
$(verbose) $(call core_render_template,application,src/$(PROJECT)_app.erl)
|
|
|
|
$(verbose) $(call core_render_template,supervisor,src/$(PROJECT)_sup.erl)
|
2014-08-01 14:26:51 +02:00
|
|
|
|
|
|
|
bootstrap-lib:
|
|
|
|
ifneq ($(wildcard src/),)
|
|
|
|
$(error Error: src/ directory already exists)
|
|
|
|
endif
|
2015-11-16 23:08:24 +01:00
|
|
|
$(eval p := $(PROJECT))
|
2020-03-29 15:45:51 +02:00
|
|
|
$(if $(shell echo $p | LC_ALL=C grep -x "[a-z0-9_]*"),,\
|
|
|
|
$(error Error: Invalid characters in the application name))
|
2025-02-11 16:02:10 +01:00
|
|
|
$(verbose) $(call core_render_template,top_Makefile,Makefile)
|
2015-07-21 17:16:11 +02:00
|
|
|
$(verbose) mkdir src/
|
2015-11-16 23:08:24 +01:00
|
|
|
ifdef LEGACY
|
2025-02-11 16:02:10 +01:00
|
|
|
$(verbose) $(call core_render_template,library.app.src,src/$(PROJECT).app.src)
|
2015-11-16 23:08:24 +01:00
|
|
|
endif
|
2013-04-30 20:51:37 +02:00
|
|
|
|
2014-08-01 14:26:51 +02:00
|
|
|
bootstrap-rel:
|
|
|
|
ifneq ($(wildcard relx.config),)
|
|
|
|
$(error Error: relx.config already exists)
|
|
|
|
endif
|
2020-03-29 15:45:51 +02:00
|
|
|
ifneq ($(wildcard config/),)
|
|
|
|
$(error Error: config/ directory already exists)
|
2014-08-01 14:26:51 +02:00
|
|
|
endif
|
2015-11-16 23:08:24 +01:00
|
|
|
$(eval p := $(PROJECT))
|
2025-02-11 16:02:10 +01:00
|
|
|
$(verbose) $(call core_render_template,relx.config,relx.config)
|
2020-03-29 15:45:51 +02:00
|
|
|
$(verbose) mkdir config/
|
2025-02-11 16:02:10 +01:00
|
|
|
$(verbose) $(call core_render_template,sys.config,config/sys.config)
|
|
|
|
$(verbose) $(call core_render_template,vm.args,config/vm.args)
|
2024-11-06 16:33:39 +01:00
|
|
|
$(verbose) awk '/^include erlang.mk/ && !ins {print "REL_DEPS += relx";ins=1};{print}' Makefile > Makefile.bak
|
2022-09-19 14:17:37 +02:00
|
|
|
$(verbose) mv Makefile.bak Makefile
|
2014-08-01 14:26:51 +02:00
|
|
|
|
2015-11-16 23:08:24 +01:00
|
|
|
new-app:
|
|
|
|
ifndef in
|
|
|
|
$(error Usage: $(MAKE) new-app in=APP)
|
|
|
|
endif
|
|
|
|
ifneq ($(wildcard $(APPS_DIR)/$in),)
|
|
|
|
$(error Error: Application $in already exists)
|
|
|
|
endif
|
|
|
|
$(eval p := $(in))
|
2020-03-29 15:45:51 +02:00
|
|
|
$(if $(shell echo $p | LC_ALL=C grep -x "[a-z0-9_]*"),,\
|
|
|
|
$(error Error: Invalid characters in the application name))
|
2015-11-16 23:08:24 +01:00
|
|
|
$(eval n := $(in)_sup)
|
|
|
|
$(verbose) mkdir -p $(APPS_DIR)/$p/src/
|
2025-02-11 16:02:10 +01:00
|
|
|
$(verbose) $(call core_render_template,apps_Makefile,$(APPS_DIR)/$p/Makefile)
|
2015-11-16 23:08:24 +01:00
|
|
|
ifdef LEGACY
|
2025-02-11 16:02:10 +01:00
|
|
|
$(verbose) $(call core_render_template,application.app.src,$(APPS_DIR)/$p/src/$p.app.src)
|
2015-11-16 23:08:24 +01:00
|
|
|
endif
|
2025-02-11 16:02:10 +01:00
|
|
|
$(verbose) $(call core_render_template,application,$(APPS_DIR)/$p/src/$p_app.erl)
|
|
|
|
$(verbose) $(call core_render_template,supervisor,$(APPS_DIR)/$p/src/$p_sup.erl)
|
2015-11-16 23:08:24 +01:00
|
|
|
|
|
|
|
new-lib:
|
|
|
|
ifndef in
|
|
|
|
$(error Usage: $(MAKE) new-lib in=APP)
|
|
|
|
endif
|
|
|
|
ifneq ($(wildcard $(APPS_DIR)/$in),)
|
|
|
|
$(error Error: Application $in already exists)
|
|
|
|
endif
|
|
|
|
$(eval p := $(in))
|
2020-03-29 15:45:51 +02:00
|
|
|
$(if $(shell echo $p | LC_ALL=C grep -x "[a-z0-9_]*"),,\
|
|
|
|
$(error Error: Invalid characters in the application name))
|
2015-11-16 23:08:24 +01:00
|
|
|
$(verbose) mkdir -p $(APPS_DIR)/$p/src/
|
2025-02-11 16:02:10 +01:00
|
|
|
$(verbose) $(call core_render_template,apps_Makefile,$(APPS_DIR)/$p/Makefile)
|
2015-11-16 23:08:24 +01:00
|
|
|
ifdef LEGACY
|
2025-02-11 16:02:10 +01:00
|
|
|
$(verbose) $(call core_render_template,library.app.src,$(APPS_DIR)/$p/src/$p.app.src)
|
2015-11-16 23:08:24 +01:00
|
|
|
endif
|
|
|
|
|
2025-02-11 16:02:10 +01:00
|
|
|
# These are not necessary because we don't expose those as "normal" templates.
|
|
|
|
BOOTSTRAP_TEMPLATES = apps_Makefile top_Makefile \
|
|
|
|
application.app.src library.app.src application \
|
|
|
|
relx.config sys.config vm.args
|
|
|
|
|
|
|
|
# Templates may override the path they will be written to when using 'new'.
|
|
|
|
# Only special template paths must be listed. Default is src/template_name.erl
|
|
|
|
# Substitution is also applied to the paths. Examples:
|
|
|
|
#
|
|
|
|
#tplp_top_Makefile = Makefile
|
|
|
|
#tplp_application.app.src = src/project_name.app.src
|
|
|
|
#tplp_application = src/project_name_app.erl
|
|
|
|
#tplp_relx.config = relx.config
|
|
|
|
|
|
|
|
# Erlang.mk bundles its own templates at build time into the erlang.mk file.
|
|
|
|
|
2014-08-01 14:26:51 +02:00
|
|
|
new:
|
2025-02-11 16:02:10 +01:00
|
|
|
$(if $(t),,$(error Usage: $(MAKE) new t=TEMPLATE n=NAME [in=APP]))
|
|
|
|
$(if $(n),,$(error Usage: $(MAKE) new t=TEMPLATE n=NAME [in=APP]))
|
|
|
|
$(if $(tpl_$(t)),,$(error Error: $t template does not exist; try $(Make) list-templates))
|
|
|
|
$(eval dest := $(if $(in),$(APPS_DIR)/$(in)/)$(call subst_template,$(if $(tplp_$(t)),$(tplp_$(t)),src/template_name.erl)))
|
|
|
|
$(if $(wildcard $(dir $(dest))),,$(error Error: $(dir $(dest)) directory does not exist))
|
|
|
|
$(if $(wildcard $(dest)),$(error Error: The file $(dest) already exists))
|
|
|
|
$(eval p := $(PROJECT))
|
|
|
|
$(call core_render_template,$(t),$(dest))
|
2013-04-30 20:51:37 +02:00
|
|
|
|
2014-08-01 14:26:51 +02:00
|
|
|
list-templates:
|
2018-05-16 12:28:55 +02:00
|
|
|
$(verbose) @echo Available templates:
|
2025-02-11 16:02:10 +01:00
|
|
|
$(verbose) printf " %s\n" $(sort $(filter-out $(BOOTSTRAP_TEMPLATES),$(patsubst tpl_%,%,$(filter tpl_%,$(.VARIABLES)))))
|
2013-04-30 20:51:37 +02:00
|
|
|
|
2016-11-05 14:17:30 +02:00
|
|
|
# Copyright (c) 2014-2016, Loïc Hoguin <essen@ninenines.eu>
|
2014-08-01 14:26:51 +02:00
|
|
|
# This file is part of erlang.mk and subject to the terms of the ISC License.
|
2013-04-30 20:51:37 +02:00
|
|
|
|
2015-05-05 19:59:37 +03:00
|
|
|
.PHONY: clean-c_src distclean-c_src-env
|
|
|
|
|
|
|
|
# Configuration.
|
|
|
|
|
2015-06-11 17:04:21 +02:00
|
|
|
C_SRC_DIR ?= $(CURDIR)/c_src
|
2015-05-05 19:59:37 +03:00
|
|
|
C_SRC_ENV ?= $(C_SRC_DIR)/env.mk
|
2016-01-14 13:35:25 +01:00
|
|
|
C_SRC_OUTPUT ?= $(CURDIR)/priv/$(PROJECT)
|
2015-06-11 17:04:21 +02:00
|
|
|
C_SRC_TYPE ?= shared
|
2015-05-05 19:59:37 +03:00
|
|
|
|
|
|
|
# System type and C compiler/flags.
|
|
|
|
|
2016-01-14 13:35:25 +01:00
|
|
|
ifeq ($(PLATFORM),msys2)
|
|
|
|
C_SRC_OUTPUT_EXECUTABLE_EXTENSION ?= .exe
|
|
|
|
C_SRC_OUTPUT_SHARED_EXTENSION ?= .dll
|
2023-11-24 11:39:55 +01:00
|
|
|
C_SRC_OUTPUT_STATIC_EXTENSION ?= .lib
|
2016-01-14 13:35:25 +01:00
|
|
|
else
|
|
|
|
C_SRC_OUTPUT_EXECUTABLE_EXTENSION ?=
|
|
|
|
C_SRC_OUTPUT_SHARED_EXTENSION ?= .so
|
2023-11-24 11:39:55 +01:00
|
|
|
C_SRC_OUTPUT_STATIC_EXTENSION ?= .a
|
2016-01-14 13:35:25 +01:00
|
|
|
endif
|
|
|
|
|
|
|
|
ifeq ($(C_SRC_TYPE),shared)
|
|
|
|
C_SRC_OUTPUT_FILE = $(C_SRC_OUTPUT)$(C_SRC_OUTPUT_SHARED_EXTENSION)
|
2023-11-24 11:39:55 +01:00
|
|
|
else ifeq ($(C_SRC_TYPE),static)
|
|
|
|
C_SRC_OUTPUT_FILE = $(C_SRC_OUTPUT)$(C_SRC_OUTPUT_STATIC_EXTENSION)
|
2016-01-14 13:35:25 +01:00
|
|
|
else
|
|
|
|
C_SRC_OUTPUT_FILE = $(C_SRC_OUTPUT)$(C_SRC_OUTPUT_EXECUTABLE_EXTENSION)
|
|
|
|
endif
|
|
|
|
|
2023-11-24 11:39:55 +01:00
|
|
|
RANLIB ?= ranlib
|
|
|
|
ARFLAGS ?= cr
|
|
|
|
|
2016-01-14 13:35:25 +01:00
|
|
|
ifeq ($(PLATFORM),msys2)
|
|
|
|
# We hardcode the compiler used on MSYS2. The default CC=cc does
|
|
|
|
# not produce working code. The "gcc" MSYS2 package also doesn't.
|
|
|
|
CC = /mingw64/bin/gcc
|
2016-11-05 14:17:30 +02:00
|
|
|
export CC
|
2016-01-14 13:35:25 +01:00
|
|
|
CFLAGS ?= -O3 -std=c99 -finline-functions -Wall -Wmissing-prototypes
|
|
|
|
CXXFLAGS ?= -O3 -finline-functions -Wall
|
|
|
|
else ifeq ($(PLATFORM),darwin)
|
2015-05-05 19:59:37 +03:00
|
|
|
CC ?= cc
|
2022-09-19 14:17:37 +02:00
|
|
|
CFLAGS ?= -O3 -std=c99 -Wall -Wmissing-prototypes
|
|
|
|
CXXFLAGS ?= -O3 -Wall
|
|
|
|
LDFLAGS ?= -flat_namespace -undefined suppress
|
2015-06-11 17:04:21 +02:00
|
|
|
else ifeq ($(PLATFORM),freebsd)
|
2015-05-05 19:59:37 +03:00
|
|
|
CC ?= cc
|
|
|
|
CFLAGS ?= -O3 -std=c99 -finline-functions -Wall -Wmissing-prototypes
|
|
|
|
CXXFLAGS ?= -O3 -finline-functions -Wall
|
2015-06-11 17:04:21 +02:00
|
|
|
else ifeq ($(PLATFORM),linux)
|
2015-05-05 19:59:37 +03:00
|
|
|
CC ?= gcc
|
|
|
|
CFLAGS ?= -O3 -std=c99 -finline-functions -Wall -Wmissing-prototypes
|
|
|
|
CXXFLAGS ?= -O3 -finline-functions -Wall
|
|
|
|
endif
|
|
|
|
|
2016-01-14 13:35:25 +01:00
|
|
|
ifneq ($(PLATFORM),msys2)
|
|
|
|
CFLAGS += -fPIC
|
|
|
|
CXXFLAGS += -fPIC
|
|
|
|
endif
|
|
|
|
|
2023-11-24 11:39:55 +01:00
|
|
|
ifeq ($(C_SRC_TYPE),static)
|
|
|
|
CFLAGS += -DSTATIC_ERLANG_NIF=1
|
|
|
|
CXXFLAGS += -DSTATIC_ERLANG_NIF=1
|
|
|
|
endif
|
|
|
|
|
2016-01-14 13:35:25 +01:00
|
|
|
CFLAGS += -I"$(ERTS_INCLUDE_DIR)" -I"$(ERL_INTERFACE_INCLUDE_DIR)"
|
|
|
|
CXXFLAGS += -I"$(ERTS_INCLUDE_DIR)" -I"$(ERL_INTERFACE_INCLUDE_DIR)"
|
2015-05-05 19:59:37 +03:00
|
|
|
|
2020-03-29 15:45:51 +02:00
|
|
|
LDLIBS += -L"$(ERL_INTERFACE_LIB_DIR)" -lei
|
2015-06-11 17:04:21 +02:00
|
|
|
|
2015-05-05 19:59:37 +03:00
|
|
|
# Verbosity.
|
|
|
|
|
2020-10-07 13:44:24 +02:00
|
|
|
c_verbose_0 = @echo " C " $(filter-out $(notdir $(MAKEFILE_LIST) $(C_SRC_ENV)),$(^F));
|
2015-05-05 19:59:37 +03:00
|
|
|
c_verbose = $(c_verbose_$(V))
|
|
|
|
|
2020-10-07 13:44:24 +02:00
|
|
|
cpp_verbose_0 = @echo " CPP " $(filter-out $(notdir $(MAKEFILE_LIST) $(C_SRC_ENV)),$(^F));
|
2015-05-05 19:59:37 +03:00
|
|
|
cpp_verbose = $(cpp_verbose_$(V))
|
|
|
|
|
|
|
|
link_verbose_0 = @echo " LD " $(@F);
|
|
|
|
link_verbose = $(link_verbose_$(V))
|
|
|
|
|
2023-11-24 11:39:55 +01:00
|
|
|
ar_verbose_0 = @echo " AR " $(@F);
|
|
|
|
ar_verbose = $(ar_verbose_$(V))
|
|
|
|
|
|
|
|
ranlib_verbose_0 = @echo " RANLIB" $(@F);
|
|
|
|
ranlib_verbose = $(ranlib_verbose_$(V))
|
|
|
|
|
2015-05-05 19:59:37 +03:00
|
|
|
# Targets.
|
|
|
|
|
|
|
|
ifeq ($(wildcard $(C_SRC_DIR)),)
|
|
|
|
else ifneq ($(wildcard $(C_SRC_DIR)/Makefile),)
|
2015-06-11 17:04:21 +02:00
|
|
|
app:: app-c_src
|
|
|
|
|
|
|
|
test-build:: app-c_src
|
|
|
|
|
|
|
|
app-c_src:
|
2015-05-05 19:59:37 +03:00
|
|
|
$(MAKE) -C $(C_SRC_DIR)
|
|
|
|
|
|
|
|
clean::
|
|
|
|
$(MAKE) -C $(C_SRC_DIR) clean
|
|
|
|
|
|
|
|
else
|
2015-06-11 17:04:21 +02:00
|
|
|
|
|
|
|
ifeq ($(SOURCES),)
|
2015-11-16 23:08:24 +01:00
|
|
|
SOURCES := $(sort $(foreach pat,*.c *.C *.cc *.cpp,$(call core_find,$(C_SRC_DIR)/,$(pat))))
|
2015-06-11 17:04:21 +02:00
|
|
|
endif
|
2015-05-05 19:59:37 +03:00
|
|
|
OBJECTS = $(addsuffix .o, $(basename $(SOURCES)))
|
|
|
|
|
|
|
|
COMPILE_C = $(c_verbose) $(CC) $(CFLAGS) $(CPPFLAGS) -c
|
|
|
|
COMPILE_CPP = $(cpp_verbose) $(CXX) $(CXXFLAGS) $(CPPFLAGS) -c
|
|
|
|
|
2016-01-14 13:35:25 +01:00
|
|
|
app:: $(C_SRC_ENV) $(C_SRC_OUTPUT_FILE)
|
2015-05-05 19:59:37 +03:00
|
|
|
|
2016-01-14 13:35:25 +01:00
|
|
|
test-build:: $(C_SRC_ENV) $(C_SRC_OUTPUT_FILE)
|
2015-06-11 17:04:21 +02:00
|
|
|
|
2023-11-24 11:39:55 +01:00
|
|
|
ifneq ($(C_SRC_TYPE),static)
|
2016-01-14 13:35:25 +01:00
|
|
|
$(C_SRC_OUTPUT_FILE): $(OBJECTS)
|
2020-03-29 15:45:51 +02:00
|
|
|
$(verbose) mkdir -p $(dir $@)
|
2015-11-16 23:08:24 +01:00
|
|
|
$(link_verbose) $(CC) $(OBJECTS) \
|
|
|
|
$(LDFLAGS) $(if $(filter $(C_SRC_TYPE),shared),-shared) $(LDLIBS) \
|
2016-01-14 13:35:25 +01:00
|
|
|
-o $(C_SRC_OUTPUT_FILE)
|
2023-11-24 11:39:55 +01:00
|
|
|
else
|
|
|
|
$(C_SRC_OUTPUT_FILE): $(OBJECTS)
|
|
|
|
$(verbose) mkdir -p $(dir $@)
|
|
|
|
$(ar_verbose) $(AR) $(ARFLAGS) $(C_SRC_OUTPUT_FILE) $(OBJECTS)
|
|
|
|
$(ranlib_verbose) $(RANLIB) $(C_SRC_OUTPUT_FILE)
|
|
|
|
endif
|
|
|
|
|
2015-05-05 19:59:37 +03:00
|
|
|
|
2020-03-29 15:45:51 +02:00
|
|
|
$(OBJECTS): $(MAKEFILE_LIST) $(C_SRC_ENV)
|
|
|
|
|
2015-05-05 19:59:37 +03:00
|
|
|
%.o: %.c
|
|
|
|
$(COMPILE_C) $(OUTPUT_OPTION) $<
|
|
|
|
|
|
|
|
%.o: %.cc
|
|
|
|
$(COMPILE_CPP) $(OUTPUT_OPTION) $<
|
|
|
|
|
|
|
|
%.o: %.C
|
|
|
|
$(COMPILE_CPP) $(OUTPUT_OPTION) $<
|
|
|
|
|
|
|
|
%.o: %.cpp
|
|
|
|
$(COMPILE_CPP) $(OUTPUT_OPTION) $<
|
|
|
|
|
2015-06-11 17:04:21 +02:00
|
|
|
clean:: clean-c_src
|
|
|
|
|
|
|
|
clean-c_src:
|
2016-01-14 13:35:25 +01:00
|
|
|
$(gen_verbose) rm -f $(C_SRC_OUTPUT_FILE) $(OBJECTS)
|
2015-06-11 17:04:21 +02:00
|
|
|
|
|
|
|
endif
|
|
|
|
|
|
|
|
ifneq ($(wildcard $(C_SRC_DIR)),)
|
2020-03-29 15:45:51 +02:00
|
|
|
ERL_ERTS_DIR = $(shell $(ERL) -eval 'io:format("~s~n", [code:lib_dir(erts)]), halt().')
|
|
|
|
|
2015-05-05 19:59:37 +03:00
|
|
|
$(C_SRC_ENV):
|
2016-01-14 13:35:25 +01:00
|
|
|
$(verbose) $(ERL) -eval "file:write_file(\"$(call core_native_path,$(C_SRC_ENV))\", \
|
2015-05-05 19:59:37 +03:00
|
|
|
io_lib:format( \
|
2020-03-29 15:45:51 +02:00
|
|
|
\"# Generated by Erlang.mk. Edit at your own risk!~n~n\" \
|
2015-05-05 19:59:37 +03:00
|
|
|
\"ERTS_INCLUDE_DIR ?= ~s/erts-~s/include/~n\" \
|
|
|
|
\"ERL_INTERFACE_INCLUDE_DIR ?= ~s~n\" \
|
2020-03-29 15:45:51 +02:00
|
|
|
\"ERL_INTERFACE_LIB_DIR ?= ~s~n\" \
|
|
|
|
\"ERTS_DIR ?= $(ERL_ERTS_DIR)~n\", \
|
2015-05-05 19:59:37 +03:00
|
|
|
[code:root_dir(), erlang:system_info(version), \
|
|
|
|
code:lib_dir(erl_interface, include), \
|
|
|
|
code:lib_dir(erl_interface, lib)])), \
|
|
|
|
halt()."
|
|
|
|
|
|
|
|
distclean:: distclean-c_src-env
|
|
|
|
|
|
|
|
distclean-c_src-env:
|
|
|
|
$(gen_verbose) rm -f $(C_SRC_ENV)
|
|
|
|
|
|
|
|
-include $(C_SRC_ENV)
|
2020-03-29 15:45:51 +02:00
|
|
|
|
|
|
|
ifneq ($(ERL_ERTS_DIR),$(ERTS_DIR))
|
|
|
|
$(shell rm -f $(C_SRC_ENV))
|
|
|
|
endif
|
2015-05-05 19:59:37 +03:00
|
|
|
endif
|
|
|
|
|
2015-11-16 23:08:24 +01:00
|
|
|
# Templates.
|
|
|
|
|
|
|
|
define bs_c_nif
|
|
|
|
#include "erl_nif.h"
|
|
|
|
|
|
|
|
static int loads = 0;
|
|
|
|
|
|
|
|
static int load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info)
|
|
|
|
{
|
|
|
|
/* Initialize private data. */
|
|
|
|
*priv_data = NULL;
|
|
|
|
|
|
|
|
loads++;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int upgrade(ErlNifEnv* env, void** priv_data, void** old_priv_data, ERL_NIF_TERM load_info)
|
|
|
|
{
|
|
|
|
/* Convert the private data to the new version. */
|
|
|
|
*priv_data = *old_priv_data;
|
|
|
|
|
|
|
|
loads++;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void unload(ErlNifEnv* env, void* priv_data)
|
|
|
|
{
|
|
|
|
if (loads == 1) {
|
|
|
|
/* Destroy the private data. */
|
|
|
|
}
|
|
|
|
|
|
|
|
loads--;
|
|
|
|
}
|
|
|
|
|
|
|
|
static ERL_NIF_TERM hello(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
|
|
|
|
{
|
|
|
|
if (enif_is_atom(env, argv[0])) {
|
|
|
|
return enif_make_tuple2(env,
|
|
|
|
enif_make_atom(env, "hello"),
|
|
|
|
argv[0]);
|
|
|
|
}
|
|
|
|
|
|
|
|
return enif_make_tuple2(env,
|
|
|
|
enif_make_atom(env, "error"),
|
|
|
|
enif_make_atom(env, "badarg"));
|
|
|
|
}
|
|
|
|
|
|
|
|
static ErlNifFunc nif_funcs[] = {
|
|
|
|
{"hello", 1, hello}
|
|
|
|
};
|
|
|
|
|
|
|
|
ERL_NIF_INIT($n, nif_funcs, load, NULL, upgrade, unload)
|
|
|
|
endef
|
|
|
|
|
|
|
|
define bs_erl_nif
|
|
|
|
-module($n).
|
|
|
|
|
|
|
|
-export([hello/1]).
|
|
|
|
|
|
|
|
-on_load(on_load/0).
|
|
|
|
on_load() ->
|
|
|
|
PrivDir = case code:priv_dir(?MODULE) of
|
|
|
|
{error, _} ->
|
|
|
|
AppPath = filename:dirname(filename:dirname(code:which(?MODULE))),
|
|
|
|
filename:join(AppPath, "priv");
|
|
|
|
Path ->
|
|
|
|
Path
|
|
|
|
end,
|
|
|
|
erlang:load_nif(filename:join(PrivDir, atom_to_list(?MODULE)), 0).
|
|
|
|
|
|
|
|
hello(_) ->
|
|
|
|
erlang:nif_error({not_loaded, ?MODULE}).
|
|
|
|
endef
|
|
|
|
|
|
|
|
new-nif:
|
|
|
|
ifneq ($(wildcard $(C_SRC_DIR)/$n.c),)
|
|
|
|
$(error Error: $(C_SRC_DIR)/$n.c already exists)
|
|
|
|
endif
|
|
|
|
ifneq ($(wildcard src/$n.erl),)
|
|
|
|
$(error Error: src/$n.erl already exists)
|
|
|
|
endif
|
2020-03-29 15:45:51 +02:00
|
|
|
ifndef n
|
|
|
|
$(error Usage: $(MAKE) new-nif n=NAME [in=APP])
|
|
|
|
endif
|
2015-11-16 23:08:24 +01:00
|
|
|
ifdef in
|
|
|
|
$(verbose) $(MAKE) -C $(APPS_DIR)/$(in)/ new-nif n=$n in=
|
|
|
|
else
|
|
|
|
$(verbose) mkdir -p $(C_SRC_DIR) src/
|
2020-03-29 15:45:51 +02:00
|
|
|
$(verbose) $(call core_render,bs_c_nif,$(C_SRC_DIR)/$n.c)
|
|
|
|
$(verbose) $(call core_render,bs_erl_nif,src/$n.erl)
|
2015-11-16 23:08:24 +01:00
|
|
|
endif
|
|
|
|
|
2017-11-19 13:25:54 +01:00
|
|
|
# Copyright (c) 2015-2017, Loïc Hoguin <essen@ninenines.eu>
|
2015-06-11 17:04:21 +02:00
|
|
|
# This file is part of erlang.mk and subject to the terms of the ISC License.
|
|
|
|
|
2017-11-19 13:25:54 +01:00
|
|
|
.PHONY: ci ci-prepare ci-setup
|
2016-01-15 14:44:26 +01:00
|
|
|
|
Initial commit with connection/streams
Breaking changes with previous commit. This is a very large change,
and I am giving up on making a single commit that fixes everything.
More commits will follow slowly adding back features, introducing
new tests and fixing the documentation.
This change contains most of the work toward unifying the interface
for handling both HTTP/1.1 and HTTP/2. HTTP/1.1 connections are now
no longer 1 process per connection; instead by default 1 process per
request is also created. This has a number of pros and cons.
Because it has cons, we also allow users to use a lower-level API
that acts on "streams" (requests/responses) directly at the connection
process-level. If performance is a concern, one can always write a
stream handler. The performance in this case will be even greater
than with Cowboy 1, although all the special handlers are unavailable.
When switching to Websocket, after the handler returns from init/2,
Cowboy stops the stream and the Websocket protocol takes over the
connection process. Websocket then calls websocket_init/2 for any
additional initialization such as timers, because the process is
different in init/2 and websocket_*/* functions. This however would
allow us to use websocket_init/2 for sending messages on connect,
instead of sending ourselves a message and be subject to races.
Note that websocket_init/2 is optional.
This is all a big change and while most of the tests pass, some
functionality currently doesn't. SPDY is broken and will be removed
soon in favor of HTTP/2. Automatic compression is currently disabled.
The cowboy_req interface probably still have a few functions that
need to be updated. The docs and examples do not refer the current
functionality anymore.
Everything will be fixed over time. Feedback is more than welcome.
Open a ticket!
2016-02-10 17:28:32 +01:00
|
|
|
CI_OTP ?=
|
2016-11-05 14:17:30 +02:00
|
|
|
|
2023-11-24 11:39:55 +01:00
|
|
|
ifeq ($(strip $(CI_OTP)),)
|
Initial commit with connection/streams
Breaking changes with previous commit. This is a very large change,
and I am giving up on making a single commit that fixes everything.
More commits will follow slowly adding back features, introducing
new tests and fixing the documentation.
This change contains most of the work toward unifying the interface
for handling both HTTP/1.1 and HTTP/2. HTTP/1.1 connections are now
no longer 1 process per connection; instead by default 1 process per
request is also created. This has a number of pros and cons.
Because it has cons, we also allow users to use a lower-level API
that acts on "streams" (requests/responses) directly at the connection
process-level. If performance is a concern, one can always write a
stream handler. The performance in this case will be even greater
than with Cowboy 1, although all the special handlers are unavailable.
When switching to Websocket, after the handler returns from init/2,
Cowboy stops the stream and the Websocket protocol takes over the
connection process. Websocket then calls websocket_init/2 for any
additional initialization such as timers, because the process is
different in init/2 and websocket_*/* functions. This however would
allow us to use websocket_init/2 for sending messages on connect,
instead of sending ourselves a message and be subject to races.
Note that websocket_init/2 is optional.
This is all a big change and while most of the tests pass, some
functionality currently doesn't. SPDY is broken and will be removed
soon in favor of HTTP/2. Automatic compression is currently disabled.
The cowboy_req interface probably still have a few functions that
need to be updated. The docs and examples do not refer the current
functionality anymore.
Everything will be fixed over time. Feedback is more than welcome.
Open a ticket!
2016-02-10 17:28:32 +01:00
|
|
|
ci::
|
|
|
|
else
|
|
|
|
|
2023-11-24 11:39:55 +01:00
|
|
|
ci:: $(addprefix ci-,$(CI_OTP))
|
2015-07-21 17:43:37 +02:00
|
|
|
|
2023-11-24 11:39:55 +01:00
|
|
|
ci-prepare: $(addprefix ci-prepare-,$(CI_OTP))
|
2015-06-11 17:04:21 +02:00
|
|
|
|
|
|
|
ci-setup::
|
2020-03-29 15:45:51 +02:00
|
|
|
$(verbose) :
|
2015-06-11 17:04:21 +02:00
|
|
|
|
2016-11-05 14:17:30 +02:00
|
|
|
ci-extra::
|
2020-03-29 15:45:51 +02:00
|
|
|
$(verbose) :
|
2016-11-05 14:17:30 +02:00
|
|
|
|
2025-02-11 16:02:10 +01:00
|
|
|
ci_verbose_0 = @echo " CI " $1;
|
2015-06-11 17:04:21 +02:00
|
|
|
ci_verbose = $(ci_verbose_$(V))
|
|
|
|
|
|
|
|
define ci_target
|
2023-11-24 11:39:55 +01:00
|
|
|
ci-prepare-$1: $(KERL_INSTALL_DIR)/$2
|
|
|
|
$(verbose) :
|
|
|
|
|
|
|
|
ci-$1: ci-prepare-$1
|
2020-03-29 15:45:51 +02:00
|
|
|
$(verbose) $(MAKE) --no-print-directory clean
|
2015-07-21 21:05:58 +02:00
|
|
|
$(ci_verbose) \
|
2017-11-19 13:25:54 +01:00
|
|
|
PATH="$(KERL_INSTALL_DIR)/$2/bin:$(PATH)" \
|
2016-11-05 14:17:30 +02:00
|
|
|
CI_OTP_RELEASE="$1" \
|
|
|
|
CT_OPTS="-label $1" \
|
|
|
|
CI_VM="$3" \
|
|
|
|
$(MAKE) ci-setup tests
|
|
|
|
$(verbose) $(MAKE) --no-print-directory ci-extra
|
2015-06-11 17:04:21 +02:00
|
|
|
endef
|
|
|
|
|
2016-11-05 14:17:30 +02:00
|
|
|
$(foreach otp,$(CI_OTP),$(eval $(call ci_target,$(otp),$(otp),otp)))
|
2015-06-11 17:04:21 +02:00
|
|
|
|
2020-03-29 15:45:51 +02:00
|
|
|
$(foreach otp,$(filter-out $(ERLANG_OTP),$(CI_OTP)),$(eval $(call kerl_otp_target,$(otp))))
|
2015-06-11 17:04:21 +02:00
|
|
|
|
|
|
|
help::
|
2015-07-21 17:16:11 +02:00
|
|
|
$(verbose) printf "%s\n" "" \
|
2015-06-11 17:04:21 +02:00
|
|
|
"Continuous Integration targets:" \
|
|
|
|
" ci Run '$(MAKE) tests' on all configured Erlang versions." \
|
|
|
|
"" \
|
|
|
|
"The CI_OTP variable must be defined with the Erlang versions" \
|
|
|
|
"that must be tested. For example: CI_OTP = OTP-17.3.4 OTP-17.5.3"
|
|
|
|
|
|
|
|
endif
|
|
|
|
|
2020-10-07 13:44:24 +02:00
|
|
|
# Copyright (c) 2020, Loïc Hoguin <essen@ninenines.eu>
|
|
|
|
# This file is part of erlang.mk and subject to the terms of the ISC License.
|
|
|
|
|
|
|
|
ifdef CONCUERROR_TESTS
|
|
|
|
|
|
|
|
.PHONY: concuerror distclean-concuerror
|
|
|
|
|
|
|
|
# Configuration
|
|
|
|
|
|
|
|
CONCUERROR_LOGS_DIR ?= $(CURDIR)/logs
|
|
|
|
CONCUERROR_OPTS ?=
|
|
|
|
|
|
|
|
# Core targets.
|
|
|
|
|
|
|
|
check:: concuerror
|
|
|
|
|
|
|
|
ifndef KEEP_LOGS
|
|
|
|
distclean:: distclean-concuerror
|
|
|
|
endif
|
|
|
|
|
|
|
|
# Plugin-specific targets.
|
|
|
|
|
|
|
|
$(ERLANG_MK_TMP)/Concuerror/bin/concuerror: | $(ERLANG_MK_TMP)
|
|
|
|
$(verbose) git clone https://github.com/parapluu/Concuerror $(ERLANG_MK_TMP)/Concuerror
|
|
|
|
$(verbose) $(MAKE) -C $(ERLANG_MK_TMP)/Concuerror
|
|
|
|
|
|
|
|
$(CONCUERROR_LOGS_DIR):
|
|
|
|
$(verbose) mkdir -p $(CONCUERROR_LOGS_DIR)
|
|
|
|
|
|
|
|
define concuerror_html_report
|
|
|
|
<!DOCTYPE html>
|
|
|
|
<html lang="en">
|
|
|
|
<head>
|
|
|
|
<meta charset="utf-8">
|
|
|
|
<title>Concuerror HTML report</title>
|
|
|
|
</head>
|
|
|
|
<body>
|
|
|
|
<h1>Concuerror HTML report</h1>
|
|
|
|
<p>Generated on $(concuerror_date)</p>
|
|
|
|
<ul>
|
|
|
|
$(foreach t,$(concuerror_targets),<li><a href="$(t).txt">$(t)</a></li>)
|
|
|
|
</ul>
|
|
|
|
</body>
|
|
|
|
</html>
|
|
|
|
endef
|
|
|
|
|
|
|
|
concuerror: $(addprefix concuerror-,$(subst :,-,$(CONCUERROR_TESTS)))
|
|
|
|
$(eval concuerror_date := $(shell date))
|
|
|
|
$(eval concuerror_targets := $^)
|
|
|
|
$(verbose) $(call core_render,concuerror_html_report,$(CONCUERROR_LOGS_DIR)/concuerror.html)
|
|
|
|
|
|
|
|
define concuerror_target
|
|
|
|
.PHONY: concuerror-$1-$2
|
|
|
|
|
|
|
|
concuerror-$1-$2: test-build | $(ERLANG_MK_TMP)/Concuerror/bin/concuerror $(CONCUERROR_LOGS_DIR)
|
|
|
|
$(ERLANG_MK_TMP)/Concuerror/bin/concuerror \
|
|
|
|
--pa $(CURDIR)/ebin --pa $(TEST_DIR) \
|
|
|
|
-o $(CONCUERROR_LOGS_DIR)/concuerror-$1-$2.txt \
|
|
|
|
$$(CONCUERROR_OPTS) -m $1 -t $2
|
|
|
|
endef
|
|
|
|
|
|
|
|
$(foreach test,$(CONCUERROR_TESTS),$(eval $(call concuerror_target,$(firstword $(subst :, ,$(test))),$(lastword $(subst :, ,$(test))))))
|
|
|
|
|
|
|
|
distclean-concuerror:
|
|
|
|
$(gen_verbose) rm -rf $(CONCUERROR_LOGS_DIR)
|
|
|
|
|
|
|
|
endif
|
|
|
|
|
2016-11-05 14:17:30 +02:00
|
|
|
# Copyright (c) 2013-2016, Loïc Hoguin <essen@ninenines.eu>
|
2015-05-05 19:59:37 +03:00
|
|
|
# This file is part of erlang.mk and subject to the terms of the ISC License.
|
|
|
|
|
2016-01-14 13:35:25 +01:00
|
|
|
.PHONY: ct apps-ct distclean-ct
|
2013-04-30 20:51:37 +02:00
|
|
|
|
2014-08-01 14:26:51 +02:00
|
|
|
# Configuration.
|
2013-04-30 20:51:37 +02:00
|
|
|
|
2014-08-01 14:26:51 +02:00
|
|
|
CT_OPTS ?=
|
Initial commit with connection/streams
Breaking changes with previous commit. This is a very large change,
and I am giving up on making a single commit that fixes everything.
More commits will follow slowly adding back features, introducing
new tests and fixing the documentation.
This change contains most of the work toward unifying the interface
for handling both HTTP/1.1 and HTTP/2. HTTP/1.1 connections are now
no longer 1 process per connection; instead by default 1 process per
request is also created. This has a number of pros and cons.
Because it has cons, we also allow users to use a lower-level API
that acts on "streams" (requests/responses) directly at the connection
process-level. If performance is a concern, one can always write a
stream handler. The performance in this case will be even greater
than with Cowboy 1, although all the special handlers are unavailable.
When switching to Websocket, after the handler returns from init/2,
Cowboy stops the stream and the Websocket protocol takes over the
connection process. Websocket then calls websocket_init/2 for any
additional initialization such as timers, because the process is
different in init/2 and websocket_*/* functions. This however would
allow us to use websocket_init/2 for sending messages on connect,
instead of sending ourselves a message and be subject to races.
Note that websocket_init/2 is optional.
This is all a big change and while most of the tests pass, some
functionality currently doesn't. SPDY is broken and will be removed
soon in favor of HTTP/2. Automatic compression is currently disabled.
The cowboy_req interface probably still have a few functions that
need to be updated. The docs and examples do not refer the current
functionality anymore.
Everything will be fixed over time. Feedback is more than welcome.
Open a ticket!
2016-02-10 17:28:32 +01:00
|
|
|
|
2015-05-05 19:59:37 +03:00
|
|
|
ifneq ($(wildcard $(TEST_DIR)),)
|
Initial commit with connection/streams
Breaking changes with previous commit. This is a very large change,
and I am giving up on making a single commit that fixes everything.
More commits will follow slowly adding back features, introducing
new tests and fixing the documentation.
This change contains most of the work toward unifying the interface
for handling both HTTP/1.1 and HTTP/2. HTTP/1.1 connections are now
no longer 1 process per connection; instead by default 1 process per
request is also created. This has a number of pros and cons.
Because it has cons, we also allow users to use a lower-level API
that acts on "streams" (requests/responses) directly at the connection
process-level. If performance is a concern, one can always write a
stream handler. The performance in this case will be even greater
than with Cowboy 1, although all the special handlers are unavailable.
When switching to Websocket, after the handler returns from init/2,
Cowboy stops the stream and the Websocket protocol takes over the
connection process. Websocket then calls websocket_init/2 for any
additional initialization such as timers, because the process is
different in init/2 and websocket_*/* functions. This however would
allow us to use websocket_init/2 for sending messages on connect,
instead of sending ourselves a message and be subject to races.
Note that websocket_init/2 is optional.
This is all a big change and while most of the tests pass, some
functionality currently doesn't. SPDY is broken and will be removed
soon in favor of HTTP/2. Automatic compression is currently disabled.
The cowboy_req interface probably still have a few functions that
need to be updated. The docs and examples do not refer the current
functionality anymore.
Everything will be fixed over time. Feedback is more than welcome.
Open a ticket!
2016-02-10 17:28:32 +01:00
|
|
|
ifndef CT_SUITES
|
|
|
|
CT_SUITES := $(sort $(subst _SUITE.erl,,$(notdir $(call core_find,$(TEST_DIR)/,*_SUITE.erl))))
|
2014-08-01 14:26:51 +02:00
|
|
|
endif
|
Initial commit with connection/streams
Breaking changes with previous commit. This is a very large change,
and I am giving up on making a single commit that fixes everything.
More commits will follow slowly adding back features, introducing
new tests and fixing the documentation.
This change contains most of the work toward unifying the interface
for handling both HTTP/1.1 and HTTP/2. HTTP/1.1 connections are now
no longer 1 process per connection; instead by default 1 process per
request is also created. This has a number of pros and cons.
Because it has cons, we also allow users to use a lower-level API
that acts on "streams" (requests/responses) directly at the connection
process-level. If performance is a concern, one can always write a
stream handler. The performance in this case will be even greater
than with Cowboy 1, although all the special handlers are unavailable.
When switching to Websocket, after the handler returns from init/2,
Cowboy stops the stream and the Websocket protocol takes over the
connection process. Websocket then calls websocket_init/2 for any
additional initialization such as timers, because the process is
different in init/2 and websocket_*/* functions. This however would
allow us to use websocket_init/2 for sending messages on connect,
instead of sending ourselves a message and be subject to races.
Note that websocket_init/2 is optional.
This is all a big change and while most of the tests pass, some
functionality currently doesn't. SPDY is broken and will be removed
soon in favor of HTTP/2. Automatic compression is currently disabled.
The cowboy_req interface probably still have a few functions that
need to be updated. The docs and examples do not refer the current
functionality anymore.
Everything will be fixed over time. Feedback is more than welcome.
Open a ticket!
2016-02-10 17:28:32 +01:00
|
|
|
endif
|
|
|
|
CT_SUITES ?=
|
2016-12-02 19:23:19 +01:00
|
|
|
CT_LOGS_DIR ?= $(CURDIR)/logs
|
2013-05-01 18:20:56 +02:00
|
|
|
|
2014-08-01 14:26:51 +02:00
|
|
|
# Core targets.
|
2013-05-01 18:20:56 +02:00
|
|
|
|
2015-05-05 19:59:37 +03:00
|
|
|
tests:: ct
|
2014-08-01 14:26:51 +02:00
|
|
|
|
2020-03-29 15:45:51 +02:00
|
|
|
ifndef KEEP_LOGS
|
2014-08-01 14:26:51 +02:00
|
|
|
distclean:: distclean-ct
|
2020-03-29 15:45:51 +02:00
|
|
|
endif
|
2014-08-01 14:26:51 +02:00
|
|
|
|
|
|
|
help::
|
2015-07-21 17:16:11 +02:00
|
|
|
$(verbose) printf "%s\n" "" \
|
2015-05-05 19:59:37 +03:00
|
|
|
"Common_test targets:" \
|
|
|
|
" ct Run all the common_test suites for this project" \
|
|
|
|
"" \
|
2014-08-01 14:26:51 +02:00
|
|
|
"All your common_test suites have their associated targets." \
|
|
|
|
"A suite named http_SUITE can be ran using the ct-http target."
|
|
|
|
|
|
|
|
# Plugin-specific targets.
|
|
|
|
|
2013-04-30 20:51:37 +02:00
|
|
|
CT_RUN = ct_run \
|
|
|
|
-no_auto_compile \
|
2015-05-05 19:59:37 +03:00
|
|
|
-noinput \
|
2020-03-29 15:45:51 +02:00
|
|
|
-pa $(CURDIR)/ebin $(TEST_DIR) \
|
2015-05-05 19:59:37 +03:00
|
|
|
-dir $(TEST_DIR) \
|
2016-12-02 19:23:19 +01:00
|
|
|
-logdir $(CT_LOGS_DIR)
|
2013-04-30 20:51:37 +02:00
|
|
|
|
2015-05-05 19:59:37 +03:00
|
|
|
ifeq ($(CT_SUITES),)
|
2020-03-29 15:45:51 +02:00
|
|
|
ct: $(if $(IS_APP)$(ROOT_DIR),,apps-ct)
|
2015-05-05 19:59:37 +03:00
|
|
|
else
|
2017-07-14 21:44:39 +02:00
|
|
|
# We do not run tests if we are in an apps/* with no test directory.
|
|
|
|
ifneq ($(IS_APP)$(wildcard $(TEST_DIR)),1)
|
2020-03-29 15:45:51 +02:00
|
|
|
ct: test-build $(if $(IS_APP)$(ROOT_DIR),,apps-ct)
|
2016-12-02 19:23:19 +01:00
|
|
|
$(verbose) mkdir -p $(CT_LOGS_DIR)
|
Initial commit with connection/streams
Breaking changes with previous commit. This is a very large change,
and I am giving up on making a single commit that fixes everything.
More commits will follow slowly adding back features, introducing
new tests and fixing the documentation.
This change contains most of the work toward unifying the interface
for handling both HTTP/1.1 and HTTP/2. HTTP/1.1 connections are now
no longer 1 process per connection; instead by default 1 process per
request is also created. This has a number of pros and cons.
Because it has cons, we also allow users to use a lower-level API
that acts on "streams" (requests/responses) directly at the connection
process-level. If performance is a concern, one can always write a
stream handler. The performance in this case will be even greater
than with Cowboy 1, although all the special handlers are unavailable.
When switching to Websocket, after the handler returns from init/2,
Cowboy stops the stream and the Websocket protocol takes over the
connection process. Websocket then calls websocket_init/2 for any
additional initialization such as timers, because the process is
different in init/2 and websocket_*/* functions. This however would
allow us to use websocket_init/2 for sending messages on connect,
instead of sending ourselves a message and be subject to races.
Note that websocket_init/2 is optional.
This is all a big change and while most of the tests pass, some
functionality currently doesn't. SPDY is broken and will be removed
soon in favor of HTTP/2. Automatic compression is currently disabled.
The cowboy_req interface probably still have a few functions that
need to be updated. The docs and examples do not refer the current
functionality anymore.
Everything will be fixed over time. Feedback is more than welcome.
Open a ticket!
2016-02-10 17:28:32 +01:00
|
|
|
$(gen_verbose) $(CT_RUN) -sname ct_$(PROJECT) -suite $(addsuffix _SUITE,$(CT_SUITES)) $(CT_OPTS)
|
2015-05-05 19:59:37 +03:00
|
|
|
endif
|
2017-07-14 21:44:39 +02:00
|
|
|
endif
|
2013-04-30 20:51:37 +02:00
|
|
|
|
2016-01-14 13:35:25 +01:00
|
|
|
ifneq ($(ALL_APPS_DIRS),)
|
2016-11-05 14:17:30 +02:00
|
|
|
define ct_app_target
|
2020-03-29 15:45:51 +02:00
|
|
|
apps-ct-$1: test-build
|
|
|
|
$$(MAKE) -C $1 ct IS_APP=1
|
2016-11-05 14:17:30 +02:00
|
|
|
endef
|
|
|
|
|
|
|
|
$(foreach app,$(ALL_APPS_DIRS),$(eval $(call ct_app_target,$(app))))
|
|
|
|
|
2020-03-29 15:45:51 +02:00
|
|
|
apps-ct: $(addprefix apps-ct-,$(ALL_APPS_DIRS))
|
2016-01-14 13:35:25 +01:00
|
|
|
endif
|
|
|
|
|
2020-03-29 15:45:51 +02:00
|
|
|
ifdef t
|
2016-01-14 13:35:25 +01:00
|
|
|
ifeq (,$(findstring :,$t))
|
|
|
|
CT_EXTRA = -group $t
|
|
|
|
else
|
|
|
|
t_words = $(subst :, ,$t)
|
|
|
|
CT_EXTRA = -group $(firstword $(t_words)) -case $(lastword $(t_words))
|
|
|
|
endif
|
2020-03-29 15:45:51 +02:00
|
|
|
else
|
|
|
|
ifdef c
|
|
|
|
CT_EXTRA = -case $c
|
|
|
|
else
|
|
|
|
CT_EXTRA =
|
|
|
|
endif
|
2016-01-14 13:35:25 +01:00
|
|
|
endif
|
|
|
|
|
2014-08-01 14:26:51 +02:00
|
|
|
define ct_suite_target
|
2023-11-24 11:39:55 +01:00
|
|
|
ct-$1: test-build
|
|
|
|
$$(verbose) mkdir -p $$(CT_LOGS_DIR)
|
|
|
|
$$(gen_verbose_esc) $$(CT_RUN) -sname ct_$$(PROJECT) -suite $$(addsuffix _SUITE,$1) $$(CT_EXTRA) $$(CT_OPTS)
|
2014-08-01 14:26:51 +02:00
|
|
|
endef
|
|
|
|
|
|
|
|
$(foreach test,$(CT_SUITES),$(eval $(call ct_suite_target,$(test))))
|
|
|
|
|
|
|
|
distclean-ct:
|
2016-12-02 19:23:19 +01:00
|
|
|
$(gen_verbose) rm -rf $(CT_LOGS_DIR)
|
2014-08-01 14:26:51 +02:00
|
|
|
|
2016-11-05 14:17:30 +02:00
|
|
|
# Copyright (c) 2013-2016, Loïc Hoguin <essen@ninenines.eu>
|
2014-08-01 14:26:51 +02:00
|
|
|
# This file is part of erlang.mk and subject to the terms of the ISC License.
|
|
|
|
|
|
|
|
.PHONY: plt distclean-plt dialyze
|
|
|
|
|
|
|
|
# Configuration.
|
2013-04-30 20:51:37 +02:00
|
|
|
|
2014-03-24 14:06:11 +01:00
|
|
|
DIALYZER_PLT ?= $(CURDIR)/.$(PROJECT).plt
|
|
|
|
export DIALYZER_PLT
|
|
|
|
|
2013-04-30 20:51:37 +02:00
|
|
|
PLT_APPS ?=
|
2016-01-14 13:35:25 +01:00
|
|
|
DIALYZER_DIRS ?= --src -r $(wildcard src) $(ALL_APPS_DIRS)
|
2022-09-19 14:17:37 +02:00
|
|
|
DIALYZER_OPTS ?= -Werror_handling -Wunmatched_returns # -Wunderspecs
|
2018-05-16 12:28:55 +02:00
|
|
|
DIALYZER_PLT_OPTS ?=
|
2013-04-30 20:51:37 +02:00
|
|
|
|
2014-08-01 14:26:51 +02:00
|
|
|
# Core targets.
|
|
|
|
|
2015-06-11 17:04:21 +02:00
|
|
|
check:: dialyze
|
|
|
|
|
2014-08-01 14:26:51 +02:00
|
|
|
distclean:: distclean-plt
|
|
|
|
|
|
|
|
help::
|
2015-07-21 17:16:11 +02:00
|
|
|
$(verbose) printf "%s\n" "" \
|
2014-08-01 14:26:51 +02:00
|
|
|
"Dialyzer targets:" \
|
|
|
|
" plt Build a PLT file for this project" \
|
|
|
|
" dialyze Analyze the project using Dialyzer"
|
|
|
|
|
|
|
|
# Plugin-specific targets.
|
|
|
|
|
2016-01-14 13:35:25 +01:00
|
|
|
define filter_opts.erl
|
2016-11-05 14:17:30 +02:00
|
|
|
Opts = init:get_plain_arguments(),
|
|
|
|
{Filtered, _} = lists:foldl(fun
|
|
|
|
(O, {Os, true}) -> {[O|Os], false};
|
|
|
|
(O = "-D", {Os, _}) -> {[O|Os], true};
|
|
|
|
(O = [\\$$-, \\$$D, _ | _], {Os, _}) -> {[O|Os], false};
|
|
|
|
(O = "-I", {Os, _}) -> {[O|Os], true};
|
|
|
|
(O = [\\$$-, \\$$I, _ | _], {Os, _}) -> {[O|Os], false};
|
|
|
|
(O = "-pa", {Os, _}) -> {[O|Os], true};
|
|
|
|
(_, Acc) -> Acc
|
|
|
|
end, {[], false}, Opts),
|
|
|
|
io:format("~s~n", [string:join(lists:reverse(Filtered), " ")]),
|
2016-01-14 13:35:25 +01:00
|
|
|
halt().
|
|
|
|
endef
|
|
|
|
|
2020-03-29 15:45:51 +02:00
|
|
|
# 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.
|
2014-10-04 15:52:41 +03:00
|
|
|
$(DIALYZER_PLT): deps app
|
2016-12-02 19:23:19 +01:00
|
|
|
$(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))
|
2018-05-16 12:28:55 +02:00
|
|
|
$(verbose) dialyzer --build_plt $(DIALYZER_PLT_OPTS) --apps \
|
2018-08-13 08:38:49 +02:00
|
|
|
erts kernel stdlib $(PLT_APPS) $(OTP_DEPS) $(LOCAL_DEPS) $(DEPS_LOG) || test $$? -eq 2
|
2020-03-29 15:45:51 +02:00
|
|
|
$(verbose) $(ERL) -eval 'io:format("~n~s~n", [code:lib_dir(erts)]), halt().' >> $@
|
2013-04-30 20:51:37 +02:00
|
|
|
|
2014-10-04 15:52:41 +03:00
|
|
|
plt: $(DIALYZER_PLT)
|
|
|
|
|
2014-08-01 14:26:51 +02:00
|
|
|
distclean-plt:
|
|
|
|
$(gen_verbose) rm -f $(DIALYZER_PLT)
|
|
|
|
|
2014-10-04 15:52:41 +03:00
|
|
|
ifneq ($(wildcard $(DIALYZER_PLT)),)
|
2020-03-29 15:45:51 +02:00
|
|
|
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
|
2014-10-04 15:52:41 +03:00
|
|
|
else
|
|
|
|
dialyze: $(DIALYZER_PLT)
|
|
|
|
endif
|
2023-11-24 11:39:55 +01:00
|
|
|
$(verbose) dialyzer `$(ERL) \
|
2020-03-29 15:45:51 +02:00
|
|
|
-eval "$(subst $(newline),,$(call escape_dquotes,$(call filter_opts.erl)))" \
|
|
|
|
-extra $(ERLC_OPTS)` $(DIALYZER_DIRS) $(DIALYZER_OPTS) $(if $(wildcard ebin/),-pa ebin/)
|
2013-08-24 10:48:59 +02:00
|
|
|
|
2016-11-05 14:17:30 +02:00
|
|
|
# Copyright (c) 2013-2016, Loïc Hoguin <essen@ninenines.eu>
|
2014-08-01 14:26:51 +02:00
|
|
|
# This file is part of erlang.mk and subject to the terms of the ISC License.
|
2013-08-24 10:48:59 +02:00
|
|
|
|
2016-01-14 13:35:25 +01:00
|
|
|
.PHONY: distclean-edoc edoc
|
2015-05-05 19:59:37 +03:00
|
|
|
|
|
|
|
# Configuration.
|
|
|
|
|
2016-01-14 13:35:25 +01:00
|
|
|
EDOC_OPTS ?=
|
2017-07-14 21:44:39 +02:00
|
|
|
EDOC_SRC_DIRS ?=
|
2017-11-19 13:25:54 +01:00
|
|
|
EDOC_OUTPUT ?= doc
|
2017-07-14 21:44:39 +02:00
|
|
|
|
|
|
|
define edoc.erl
|
|
|
|
SrcPaths = lists:foldl(fun(P, Acc) ->
|
2023-11-24 11:39:55 +01:00
|
|
|
filelib:wildcard(atom_to_list(P) ++ "/{src,c_src}")
|
|
|
|
++ lists:filter(fun(D) ->
|
|
|
|
filelib:is_dir(D)
|
|
|
|
end, filelib:wildcard(atom_to_list(P) ++ "/{src,c_src}/**"))
|
|
|
|
++ Acc
|
2020-03-29 15:45:51 +02:00
|
|
|
end, [], [$(call comma_list,$(patsubst %,'%',$(call core_native_path,$(EDOC_SRC_DIRS))))]),
|
2017-11-19 13:25:54 +01:00
|
|
|
DefaultOpts = [{dir, "$(EDOC_OUTPUT)"}, {source_path, SrcPaths}, {subpackages, false}],
|
2017-07-14 21:44:39 +02:00
|
|
|
edoc:application($(1), ".", [$(2)] ++ DefaultOpts),
|
|
|
|
halt(0).
|
|
|
|
endef
|
2015-05-05 19:59:37 +03:00
|
|
|
|
|
|
|
# Core targets.
|
|
|
|
|
2017-07-14 21:44:39 +02:00
|
|
|
ifneq ($(strip $(EDOC_SRC_DIRS)$(wildcard doc/overview.edoc)),)
|
2016-01-14 13:35:25 +01:00
|
|
|
docs:: edoc
|
|
|
|
endif
|
2015-05-05 19:59:37 +03:00
|
|
|
|
2016-01-14 13:35:25 +01:00
|
|
|
distclean:: distclean-edoc
|
2015-05-05 19:59:37 +03:00
|
|
|
|
|
|
|
# Plugin-specific targets.
|
|
|
|
|
2016-01-14 13:35:25 +01:00
|
|
|
edoc: distclean-edoc doc-deps
|
2017-07-14 21:44:39 +02:00
|
|
|
$(gen_verbose) $(call erlang,$(call edoc.erl,$(PROJECT),$(EDOC_OPTS)))
|
2015-05-05 19:59:37 +03:00
|
|
|
|
2016-01-14 13:35:25 +01:00
|
|
|
distclean-edoc:
|
2017-11-19 13:25:54 +01:00
|
|
|
$(gen_verbose) rm -f $(EDOC_OUTPUT)/*.css $(EDOC_OUTPUT)/*.html $(EDOC_OUTPUT)/*.png $(EDOC_OUTPUT)/edoc-info
|
2014-08-01 14:26:51 +02:00
|
|
|
|
2017-07-14 21:44:39 +02:00
|
|
|
# Copyright (c) 2013-2016, Loïc Hoguin <essen@ninenines.eu>
|
|
|
|
# This file is part of erlang.mk and subject to the terms of the ISC License.
|
|
|
|
|
|
|
|
# Configuration.
|
|
|
|
|
|
|
|
DTL_FULL_PATH ?=
|
|
|
|
DTL_PATH ?= templates/
|
2020-03-29 15:45:51 +02:00
|
|
|
DTL_PREFIX ?=
|
2017-07-14 21:44:39 +02:00
|
|
|
DTL_SUFFIX ?= _dtl
|
|
|
|
DTL_OPTS ?=
|
|
|
|
|
|
|
|
# Verbosity.
|
|
|
|
|
|
|
|
dtl_verbose_0 = @echo " DTL " $(filter %.dtl,$(?F));
|
|
|
|
dtl_verbose = $(dtl_verbose_$(V))
|
|
|
|
|
|
|
|
# Core targets.
|
|
|
|
|
|
|
|
DTL_PATH := $(abspath $(DTL_PATH))
|
|
|
|
DTL_FILES := $(sort $(call core_find,$(DTL_PATH),*.dtl))
|
|
|
|
|
|
|
|
ifneq ($(DTL_FILES),)
|
|
|
|
|
2020-03-29 15:45:51 +02:00
|
|
|
DTL_NAMES = $(addprefix $(DTL_PREFIX),$(addsuffix $(DTL_SUFFIX),$(DTL_FILES:$(DTL_PATH)/%.dtl=%)))
|
2017-07-14 21:44:39 +02:00
|
|
|
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.
|
2020-03-29 15:45:51 +02:00
|
|
|
$(ERLANG_MK_TMP)/last-makefile-change-erlydtl: $(MAKEFILE_LIST) | $(ERLANG_MK_TMP)
|
|
|
|
$(verbose) if test -f $@; then \
|
2017-07-14 21:44:39 +02:00
|
|
|
touch $(DTL_FILES); \
|
|
|
|
fi
|
2020-03-29 15:45:51 +02:00
|
|
|
$(verbose) touch $@
|
2017-07-14 21:44:39 +02:00
|
|
|
|
|
|
|
ebin/$(PROJECT).app:: $(ERLANG_MK_TMP)/last-makefile-change-erlydtl
|
|
|
|
endif
|
|
|
|
|
|
|
|
define erlydtl_compile.erl
|
|
|
|
[begin
|
|
|
|
Module0 = case "$(strip $(DTL_FULL_PATH))" of
|
|
|
|
"" ->
|
|
|
|
filename:basename(F, ".dtl");
|
|
|
|
_ ->
|
2020-03-29 15:45:51 +02:00
|
|
|
"$(call core_native_path,$(DTL_PATH))/" ++ F2 = filename:rootname(F, ".dtl"),
|
2017-07-14 21:44:39 +02:00
|
|
|
re:replace(F2, "/", "_", [{return, list}, global])
|
|
|
|
end,
|
2020-03-29 15:45:51 +02:00
|
|
|
Module = list_to_atom("$(DTL_PREFIX)" ++ string:to_lower(Module0) ++ "$(DTL_SUFFIX)"),
|
2017-07-14 21:44:39 +02:00
|
|
|
case erlydtl:compile(F, Module, [$(DTL_OPTS)] ++ [{out_dir, "ebin/"}, return_errors]) of
|
|
|
|
ok -> ok;
|
|
|
|
{ok, _} -> ok
|
|
|
|
end
|
|
|
|
end || F <- string:tokens("$(1)", " ")],
|
|
|
|
halt().
|
|
|
|
endef
|
|
|
|
|
|
|
|
ebin/$(PROJECT).app:: $(DTL_FILES) | ebin/
|
|
|
|
$(if $(strip $?),\
|
|
|
|
$(dtl_verbose) $(call erlang,$(call erlydtl_compile.erl,$(call core_native_path,$?)),\
|
2020-03-29 15:45:51 +02:00
|
|
|
-pa ebin/))
|
2017-07-14 21:44:39 +02:00
|
|
|
|
|
|
|
endif
|
|
|
|
|
2016-11-05 14:17:30 +02:00
|
|
|
# Copyright (c) 2016, Loïc Hoguin <essen@ninenines.eu>
|
|
|
|
# Copyright (c) 2014, Dave Cottlehuber <dch@skunkwerks.at>
|
2015-05-05 19:59:37 +03:00
|
|
|
# This file is part of erlang.mk and subject to the terms of the ISC License.
|
|
|
|
|
2016-11-05 14:17:30 +02:00
|
|
|
.PHONY: distclean-escript escript escript-zip
|
2015-05-05 19:59:37 +03:00
|
|
|
|
|
|
|
# Configuration.
|
|
|
|
|
|
|
|
ESCRIPT_NAME ?= $(PROJECT)
|
2016-11-05 14:17:30 +02:00
|
|
|
ESCRIPT_FILE ?= $(ESCRIPT_NAME)
|
2015-05-05 19:59:37 +03:00
|
|
|
|
|
|
|
ESCRIPT_SHEBANG ?= /usr/bin/env escript
|
2016-11-05 14:17:30 +02:00
|
|
|
ESCRIPT_COMMENT ?= This is an -*- erlang -*- file
|
|
|
|
ESCRIPT_EMU_ARGS ?= -escript main $(ESCRIPT_NAME)
|
|
|
|
|
|
|
|
ESCRIPT_ZIP ?= 7z a -tzip -mx=9 -mtc=off $(if $(filter-out 0,$(V)),,> /dev/null)
|
|
|
|
ESCRIPT_ZIP_FILE ?= $(ERLANG_MK_TMP)/escript.zip
|
2015-05-05 19:59:37 +03:00
|
|
|
|
|
|
|
# Core targets.
|
|
|
|
|
|
|
|
distclean:: distclean-escript
|
|
|
|
|
|
|
|
help::
|
2015-07-21 17:16:11 +02:00
|
|
|
$(verbose) printf "%s\n" "" \
|
2015-05-05 19:59:37 +03:00
|
|
|
"Escript targets:" \
|
|
|
|
" escript Build an executable escript archive" \
|
|
|
|
|
|
|
|
# Plugin-specific targets.
|
|
|
|
|
2020-03-29 15:45:51 +02:00
|
|
|
escript-zip:: FULL=1
|
2016-11-05 14:17:30 +02:00
|
|
|
escript-zip:: deps app
|
2023-11-24 11:39:55 +01:00
|
|
|
$(verbose) mkdir -p $(dir $(abspath $(ESCRIPT_ZIP_FILE)))
|
|
|
|
$(verbose) rm -f $(abspath $(ESCRIPT_ZIP_FILE))
|
|
|
|
$(gen_verbose) cd .. && $(ESCRIPT_ZIP) $(abspath $(ESCRIPT_ZIP_FILE)) $(PROJECT)/ebin/*
|
2016-11-05 14:17:30 +02:00
|
|
|
ifneq ($(DEPS),)
|
2023-11-24 11:39:55 +01:00
|
|
|
$(verbose) cd $(DEPS_DIR) && $(ESCRIPT_ZIP) $(abspath $(ESCRIPT_ZIP_FILE)) \
|
2020-03-29 15:45:51 +02:00
|
|
|
$(subst $(DEPS_DIR)/,,$(addsuffix /*,$(wildcard \
|
|
|
|
$(addsuffix /ebin,$(shell cat $(ERLANG_MK_TMP)/deps.log)))))
|
2016-11-05 14:17:30 +02:00
|
|
|
endif
|
2015-05-05 19:59:37 +03:00
|
|
|
|
2016-11-05 14:17:30 +02:00
|
|
|
escript:: escript-zip
|
|
|
|
$(gen_verbose) printf "%s\n" \
|
|
|
|
"#!$(ESCRIPT_SHEBANG)" \
|
|
|
|
"%% $(ESCRIPT_COMMENT)" \
|
|
|
|
"%%! $(ESCRIPT_EMU_ARGS)" > $(ESCRIPT_FILE)
|
2023-11-24 11:39:55 +01:00
|
|
|
$(verbose) cat $(abspath $(ESCRIPT_ZIP_FILE)) >> $(ESCRIPT_FILE)
|
2016-11-05 14:17:30 +02:00
|
|
|
$(verbose) chmod +x $(ESCRIPT_FILE)
|
2015-05-05 19:59:37 +03:00
|
|
|
|
|
|
|
distclean-escript:
|
2023-11-24 11:39:55 +01:00
|
|
|
$(gen_verbose) rm -f $(ESCRIPT_FILE) $(abspath $(ESCRIPT_ZIP_FILE))
|
2015-05-05 19:59:37 +03:00
|
|
|
|
2016-11-05 14:17:30 +02:00
|
|
|
# Copyright (c) 2015-2016, Loïc Hoguin <essen@ninenines.eu>
|
2015-05-05 19:59:37 +03:00
|
|
|
# Copyright (c) 2014, Enrique Fernandez <enrique.fernandez@erlang-solutions.com>
|
|
|
|
# This file is contributed to erlang.mk and subject to the terms of the ISC License.
|
|
|
|
|
2016-01-14 13:35:25 +01:00
|
|
|
.PHONY: eunit apps-eunit
|
2015-05-05 19:59:37 +03:00
|
|
|
|
|
|
|
# Configuration
|
|
|
|
|
|
|
|
EUNIT_OPTS ?=
|
2016-01-14 13:35:25 +01:00
|
|
|
EUNIT_ERL_OPTS ?=
|
2023-11-24 11:39:55 +01:00
|
|
|
EUNIT_TEST_SPEC ?= $1
|
2015-05-05 19:59:37 +03:00
|
|
|
|
|
|
|
# Core targets.
|
|
|
|
|
|
|
|
tests:: eunit
|
|
|
|
|
|
|
|
help::
|
2015-07-21 17:16:11 +02:00
|
|
|
$(verbose) printf "%s\n" "" \
|
2015-05-05 19:59:37 +03:00
|
|
|
"EUnit targets:" \
|
|
|
|
" eunit Run all the EUnit tests for this project"
|
|
|
|
|
|
|
|
# Plugin-specific targets.
|
|
|
|
|
2015-07-21 17:16:11 +02:00
|
|
|
define eunit.erl
|
2020-03-29 15:45:51 +02:00
|
|
|
$(call cover.erl)
|
|
|
|
CoverSetup(),
|
2023-11-24 11:39:55 +01:00
|
|
|
case eunit:test($(call EUNIT_TEST_SPEC,$1), [$(EUNIT_OPTS)]) of
|
2015-07-21 17:16:11 +02:00
|
|
|
ok -> ok;
|
|
|
|
error -> halt(2)
|
|
|
|
end,
|
2020-03-29 15:45:51 +02:00
|
|
|
CoverExport("$(call core_native_path,$(COVER_DATA_DIR))/eunit.coverdata"),
|
2015-07-21 17:16:11 +02:00
|
|
|
halt()
|
|
|
|
endef
|
|
|
|
|
2020-03-29 15:45:51 +02:00
|
|
|
EUNIT_ERL_OPTS += -pa $(TEST_DIR) $(CURDIR)/ebin
|
2016-01-14 13:35:25 +01:00
|
|
|
|
|
|
|
ifdef t
|
|
|
|
ifeq (,$(findstring :,$(t)))
|
2017-11-19 13:25:54 +01:00
|
|
|
eunit: test-build cover-data-dir
|
2016-01-14 13:35:25 +01:00
|
|
|
$(gen_verbose) $(call erlang,$(call eunit.erl,['$(t)']),$(EUNIT_ERL_OPTS))
|
|
|
|
else
|
2017-11-19 13:25:54 +01:00
|
|
|
eunit: test-build cover-data-dir
|
2016-01-14 13:35:25 +01:00
|
|
|
$(gen_verbose) $(call erlang,$(call eunit.erl,fun $(t)/0),$(EUNIT_ERL_OPTS))
|
|
|
|
endif
|
|
|
|
else
|
Initial commit with connection/streams
Breaking changes with previous commit. This is a very large change,
and I am giving up on making a single commit that fixes everything.
More commits will follow slowly adding back features, introducing
new tests and fixing the documentation.
This change contains most of the work toward unifying the interface
for handling both HTTP/1.1 and HTTP/2. HTTP/1.1 connections are now
no longer 1 process per connection; instead by default 1 process per
request is also created. This has a number of pros and cons.
Because it has cons, we also allow users to use a lower-level API
that acts on "streams" (requests/responses) directly at the connection
process-level. If performance is a concern, one can always write a
stream handler. The performance in this case will be even greater
than with Cowboy 1, although all the special handlers are unavailable.
When switching to Websocket, after the handler returns from init/2,
Cowboy stops the stream and the Websocket protocol takes over the
connection process. Websocket then calls websocket_init/2 for any
additional initialization such as timers, because the process is
different in init/2 and websocket_*/* functions. This however would
allow us to use websocket_init/2 for sending messages on connect,
instead of sending ourselves a message and be subject to races.
Note that websocket_init/2 is optional.
This is all a big change and while most of the tests pass, some
functionality currently doesn't. SPDY is broken and will be removed
soon in favor of HTTP/2. Automatic compression is currently disabled.
The cowboy_req interface probably still have a few functions that
need to be updated. The docs and examples do not refer the current
functionality anymore.
Everything will be fixed over time. Feedback is more than welcome.
Open a ticket!
2016-02-10 17:28:32 +01:00
|
|
|
EUNIT_EBIN_MODS = $(notdir $(basename $(ERL_FILES) $(BEAM_FILES)))
|
|
|
|
EUNIT_TEST_MODS = $(notdir $(basename $(call core_find,$(TEST_DIR)/,*.erl)))
|
|
|
|
|
2015-07-21 17:16:11 +02:00
|
|
|
EUNIT_MODS = $(foreach mod,$(EUNIT_EBIN_MODS) $(filter-out \
|
2016-01-14 13:35:25 +01:00
|
|
|
$(patsubst %,%_tests,$(EUNIT_EBIN_MODS)),$(EUNIT_TEST_MODS)),'$(mod)')
|
2015-05-05 19:59:37 +03:00
|
|
|
|
2020-03-29 15:45:51 +02:00
|
|
|
eunit: test-build $(if $(IS_APP)$(ROOT_DIR),,apps-eunit) cover-data-dir
|
|
|
|
ifneq ($(wildcard src/ $(TEST_DIR)),)
|
2016-01-14 13:35:25 +01:00
|
|
|
$(gen_verbose) $(call erlang,$(call eunit.erl,[$(call comma_list,$(EUNIT_MODS))]),$(EUNIT_ERL_OPTS))
|
2020-03-29 15:45:51 +02:00
|
|
|
endif
|
2016-01-14 13:35:25 +01:00
|
|
|
|
|
|
|
ifneq ($(ALL_APPS_DIRS),)
|
2020-03-29 15:45:51 +02:00
|
|
|
apps-eunit: test-build
|
2017-07-14 21:44:39 +02:00
|
|
|
$(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
|
|
|
|
endif
|
|
|
|
endif
|
|
|
|
|
2021-05-12 10:24:40 +02:00
|
|
|
# Copyright (c) 2020, Loïc Hoguin <essen@ninenines.eu>
|
|
|
|
# This file is part of erlang.mk and subject to the terms of the ISC License.
|
|
|
|
|
|
|
|
define hex_user_create.erl
|
|
|
|
{ok, _} = application:ensure_all_started(ssl),
|
|
|
|
{ok, _} = application:ensure_all_started(inets),
|
|
|
|
Config = $(hex_config.erl),
|
|
|
|
case hex_api_user:create(Config, <<"$(strip $1)">>, <<"$(strip $2)">>, <<"$(strip $3)">>) of
|
|
|
|
{ok, {201, _, #{<<"email">> := Email, <<"url">> := URL, <<"username">> := Username}}} ->
|
|
|
|
io:format("User ~s (~s) created at ~s~n"
|
|
|
|
"Please check your inbox for a confirmation email.~n"
|
|
|
|
"You must confirm before you are allowed to publish packages.~n",
|
|
|
|
[Username, Email, URL]),
|
|
|
|
halt(0);
|
|
|
|
{ok, {Status, _, Errors}} ->
|
|
|
|
io:format("Error ~b: ~0p~n", [Status, Errors]),
|
|
|
|
halt(80)
|
|
|
|
end
|
|
|
|
endef
|
|
|
|
|
|
|
|
# The $(info ) call inserts a new line after the password prompt.
|
|
|
|
hex-user-create: hex-core
|
|
|
|
$(if $(HEX_USERNAME),,$(eval HEX_USERNAME := $(shell read -p "Username: " username; echo $$username)))
|
|
|
|
$(if $(HEX_PASSWORD),,$(eval HEX_PASSWORD := $(shell stty -echo; read -p "Password: " password; stty echo; echo $$password) $(info )))
|
|
|
|
$(if $(HEX_EMAIL),,$(eval HEX_EMAIL := $(shell read -p "Email: " email; echo $$email)))
|
|
|
|
$(gen_verbose) $(call erlang,$(call hex_user_create.erl,$(HEX_USERNAME),$(HEX_PASSWORD),$(HEX_EMAIL)))
|
|
|
|
|
|
|
|
define hex_key_add.erl
|
|
|
|
{ok, _} = application:ensure_all_started(ssl),
|
|
|
|
{ok, _} = application:ensure_all_started(inets),
|
|
|
|
Config = $(hex_config.erl),
|
|
|
|
ConfigF = Config#{api_key => iolist_to_binary([<<"Basic ">>, base64:encode(<<"$(strip $1):$(strip $2)">>)])},
|
|
|
|
Permissions = [
|
|
|
|
case string:split(P, <<":">>) of
|
|
|
|
[D] -> #{domain => D};
|
|
|
|
[D, R] -> #{domain => D, resource => R}
|
|
|
|
end
|
|
|
|
|| P <- string:split(<<"$(strip $4)">>, <<",">>, all)],
|
|
|
|
case hex_api_key:add(ConfigF, <<"$(strip $3)">>, Permissions) of
|
|
|
|
{ok, {201, _, #{<<"secret">> := Secret}}} ->
|
|
|
|
io:format("Key ~s created for user ~s~nSecret: ~s~n"
|
|
|
|
"Please store the secret in a secure location, such as a password store.~n"
|
|
|
|
"The secret will be requested for most Hex-related operations.~n",
|
|
|
|
[<<"$(strip $3)">>, <<"$(strip $1)">>, Secret]),
|
|
|
|
halt(0);
|
|
|
|
{ok, {Status, _, Errors}} ->
|
|
|
|
io:format("Error ~b: ~0p~n", [Status, Errors]),
|
|
|
|
halt(81)
|
|
|
|
end
|
|
|
|
endef
|
|
|
|
|
|
|
|
hex-key-add: hex-core
|
|
|
|
$(if $(HEX_USERNAME),,$(eval HEX_USERNAME := $(shell read -p "Username: " username; echo $$username)))
|
|
|
|
$(if $(HEX_PASSWORD),,$(eval HEX_PASSWORD := $(shell stty -echo; read -p "Password: " password; stty echo; echo $$password) $(info )))
|
|
|
|
$(gen_verbose) $(call erlang,$(call hex_key_add.erl,$(HEX_USERNAME),$(HEX_PASSWORD),\
|
|
|
|
$(if $(name),$(name),$(shell hostname)-erlang-mk),\
|
|
|
|
$(if $(perm),$(perm),api)))
|
|
|
|
|
|
|
|
HEX_TARBALL_EXTRA_METADATA ?=
|
|
|
|
|
|
|
|
# @todo Check that we can += files
|
|
|
|
HEX_TARBALL_FILES ?= \
|
|
|
|
$(wildcard early-plugins.mk) \
|
|
|
|
$(wildcard ebin/$(PROJECT).app) \
|
|
|
|
$(wildcard ebin/$(PROJECT).appup) \
|
|
|
|
$(wildcard $(notdir $(ERLANG_MK_FILENAME))) \
|
|
|
|
$(sort $(call core_find,include/,*.hrl)) \
|
|
|
|
$(wildcard LICENSE*) \
|
|
|
|
$(wildcard Makefile) \
|
|
|
|
$(wildcard plugins.mk) \
|
|
|
|
$(sort $(call core_find,priv/,*)) \
|
|
|
|
$(wildcard README*) \
|
|
|
|
$(wildcard rebar.config) \
|
2025-02-11 16:02:10 +01:00
|
|
|
$(sort $(if $(LEGACY),$(filter-out src/$(PROJECT).app.src,$(call core_find,src/,*)),$(call core_find,src/,*)))
|
2021-05-12 10:24:40 +02:00
|
|
|
|
|
|
|
HEX_TARBALL_OUTPUT_FILE ?= $(ERLANG_MK_TMP)/$(PROJECT).tar
|
|
|
|
|
|
|
|
# @todo Need to check for rebar.config and/or the absence of DEPS to know
|
|
|
|
# whether a project will work with Rebar.
|
|
|
|
#
|
|
|
|
# @todo contributors licenses links in HEX_TARBALL_EXTRA_METADATA
|
|
|
|
|
|
|
|
# In order to build the requirements metadata we look into DEPS.
|
|
|
|
# We do not require that the project use Hex dependencies, however
|
|
|
|
# Hex.pm does require that the package name and version numbers
|
|
|
|
# correspond to a real Hex package.
|
|
|
|
define hex_tarball_create.erl
|
|
|
|
Files0 = [$(call comma_list,$(patsubst %,"%",$(HEX_TARBALL_FILES)))],
|
|
|
|
Requirements0 = #{
|
|
|
|
$(foreach d,$(DEPS),
|
|
|
|
<<"$(if $(subst hex,,$(call query_fetch_method,$d)),$d,$(if $(word 3,$(dep_$d)),$(word 3,$(dep_$d)),$d))">> => #{
|
|
|
|
<<"app">> => <<"$d">>,
|
|
|
|
<<"optional">> => false,
|
2025-02-11 16:02:10 +01:00
|
|
|
<<"requirement">> => <<"$(if $(hex_req_$d),$(strip $(hex_req_$d)),$(call query_version,$d))">>
|
2021-05-12 10:24:40 +02:00
|
|
|
},)
|
|
|
|
$(if $(DEPS),dummy => dummy)
|
|
|
|
},
|
|
|
|
Requirements = maps:remove(dummy, Requirements0),
|
|
|
|
Metadata0 = #{
|
|
|
|
app => <<"$(strip $(PROJECT))">>,
|
|
|
|
build_tools => [<<"make">>, <<"rebar3">>],
|
|
|
|
description => <<"$(strip $(PROJECT_DESCRIPTION))">>,
|
|
|
|
files => [unicode:characters_to_binary(F) || F <- Files0],
|
|
|
|
name => <<"$(strip $(PROJECT))">>,
|
|
|
|
requirements => Requirements,
|
|
|
|
version => <<"$(strip $(PROJECT_VERSION))">>
|
|
|
|
},
|
|
|
|
Metadata = Metadata0$(HEX_TARBALL_EXTRA_METADATA),
|
|
|
|
Files = [case file:read_file(F) of
|
|
|
|
{ok, Bin} ->
|
|
|
|
{F, Bin};
|
|
|
|
{error, Reason} ->
|
|
|
|
io:format("Error trying to open file ~0p: ~0p~n", [F, Reason]),
|
|
|
|
halt(82)
|
|
|
|
end || F <- Files0],
|
|
|
|
case hex_tarball:create(Metadata, Files) of
|
|
|
|
{ok, #{tarball := Tarball}} ->
|
|
|
|
ok = file:write_file("$(strip $(HEX_TARBALL_OUTPUT_FILE))", Tarball),
|
|
|
|
halt(0);
|
|
|
|
{error, Reason} ->
|
|
|
|
io:format("Error ~0p~n", [Reason]),
|
|
|
|
halt(83)
|
|
|
|
end
|
|
|
|
endef
|
|
|
|
|
|
|
|
hex_tar_verbose_0 = @echo " TAR $(notdir $(ERLANG_MK_TMP))/$(@F)";
|
|
|
|
hex_tar_verbose_2 = set -x;
|
|
|
|
hex_tar_verbose = $(hex_tar_verbose_$(V))
|
|
|
|
|
|
|
|
$(HEX_TARBALL_OUTPUT_FILE): hex-core app
|
|
|
|
$(hex_tar_verbose) $(call erlang,$(call hex_tarball_create.erl))
|
|
|
|
|
|
|
|
hex-tarball-create: $(HEX_TARBALL_OUTPUT_FILE)
|
|
|
|
|
|
|
|
define hex_release_publish_summary.erl
|
|
|
|
{ok, Tarball} = erl_tar:open("$(strip $(HEX_TARBALL_OUTPUT_FILE))", [read]),
|
|
|
|
ok = erl_tar:extract(Tarball, [{cwd, "$(ERLANG_MK_TMP)"}, {files, ["metadata.config"]}]),
|
|
|
|
{ok, Metadata} = file:consult("$(ERLANG_MK_TMP)/metadata.config"),
|
|
|
|
#{
|
|
|
|
<<"name">> := Name,
|
|
|
|
<<"version">> := Version,
|
|
|
|
<<"files">> := Files,
|
|
|
|
<<"requirements">> := Deps
|
|
|
|
} = maps:from_list(Metadata),
|
|
|
|
io:format("Publishing ~s ~s~n Dependencies:~n", [Name, Version]),
|
|
|
|
case Deps of
|
|
|
|
[] ->
|
|
|
|
io:format(" (none)~n");
|
|
|
|
_ ->
|
|
|
|
[begin
|
|
|
|
#{<<"app">> := DA, <<"requirement">> := DR} = maps:from_list(D),
|
|
|
|
io:format(" ~s ~s~n", [DA, DR])
|
|
|
|
end || {_, D} <- Deps]
|
|
|
|
end,
|
|
|
|
io:format(" Included files:~n"),
|
|
|
|
[io:format(" ~s~n", [F]) || F <- Files],
|
|
|
|
io:format("You may also review the contents of the tarball file.~n"
|
|
|
|
"Please enter your secret key to proceed.~n"),
|
|
|
|
halt(0)
|
|
|
|
endef
|
|
|
|
|
|
|
|
define hex_release_publish.erl
|
|
|
|
{ok, _} = application:ensure_all_started(ssl),
|
|
|
|
{ok, _} = application:ensure_all_started(inets),
|
|
|
|
Config = $(hex_config.erl),
|
|
|
|
ConfigF = Config#{api_key => <<"$(strip $1)">>},
|
|
|
|
{ok, Tarball} = file:read_file("$(strip $(HEX_TARBALL_OUTPUT_FILE))"),
|
|
|
|
case hex_api_release:publish(ConfigF, Tarball, [{replace, $2}]) of
|
|
|
|
{ok, {200, _, #{}}} ->
|
|
|
|
io:format("Release replaced~n"),
|
|
|
|
halt(0);
|
|
|
|
{ok, {201, _, #{}}} ->
|
|
|
|
io:format("Release published~n"),
|
|
|
|
halt(0);
|
|
|
|
{ok, {Status, _, Errors}} ->
|
|
|
|
io:format("Error ~b: ~0p~n", [Status, Errors]),
|
|
|
|
halt(84)
|
|
|
|
end
|
|
|
|
endef
|
|
|
|
|
|
|
|
hex-release-tarball: hex-core $(HEX_TARBALL_OUTPUT_FILE)
|
|
|
|
$(verbose) $(call erlang,$(call hex_release_publish_summary.erl))
|
|
|
|
|
|
|
|
hex-release-publish: hex-core hex-release-tarball
|
|
|
|
$(if $(HEX_SECRET),,$(eval HEX_SECRET := $(shell stty -echo; read -p "Secret: " secret; stty echo; echo $$secret) $(info )))
|
|
|
|
$(gen_verbose) $(call erlang,$(call hex_release_publish.erl,$(HEX_SECRET),false))
|
|
|
|
|
|
|
|
hex-release-replace: hex-core hex-release-tarball
|
|
|
|
$(if $(HEX_SECRET),,$(eval HEX_SECRET := $(shell stty -echo; read -p "Secret: " secret; stty echo; echo $$secret) $(info )))
|
|
|
|
$(gen_verbose) $(call erlang,$(call hex_release_publish.erl,$(HEX_SECRET),true))
|
|
|
|
|
|
|
|
define hex_release_delete.erl
|
|
|
|
{ok, _} = application:ensure_all_started(ssl),
|
|
|
|
{ok, _} = application:ensure_all_started(inets),
|
|
|
|
Config = $(hex_config.erl),
|
|
|
|
ConfigF = Config#{api_key => <<"$(strip $1)">>},
|
|
|
|
case hex_api_release:delete(ConfigF, <<"$(strip $(PROJECT))">>, <<"$(strip $(PROJECT_VERSION))">>) of
|
|
|
|
{ok, {204, _, _}} ->
|
|
|
|
io:format("Release $(strip $(PROJECT_VERSION)) deleted~n"),
|
|
|
|
halt(0);
|
|
|
|
{ok, {Status, _, Errors}} ->
|
|
|
|
io:format("Error ~b: ~0p~n", [Status, Errors]),
|
|
|
|
halt(85)
|
|
|
|
end
|
|
|
|
endef
|
|
|
|
|
|
|
|
hex-release-delete: hex-core
|
|
|
|
$(if $(HEX_SECRET),,$(eval HEX_SECRET := $(shell stty -echo; read -p "Secret: " secret; stty echo; echo $$secret) $(info )))
|
|
|
|
$(gen_verbose) $(call erlang,$(call hex_release_delete.erl,$(HEX_SECRET)))
|
|
|
|
|
|
|
|
define hex_release_retire.erl
|
|
|
|
{ok, _} = application:ensure_all_started(ssl),
|
|
|
|
{ok, _} = application:ensure_all_started(inets),
|
|
|
|
Config = $(hex_config.erl),
|
|
|
|
ConfigF = Config#{api_key => <<"$(strip $1)">>},
|
|
|
|
Params = #{<<"reason">> => <<"$(strip $3)">>, <<"message">> => <<"$(strip $4)">>},
|
|
|
|
case hex_api_release:retire(ConfigF, <<"$(strip $(PROJECT))">>, <<"$(strip $2)">>, Params) of
|
|
|
|
{ok, {204, _, _}} ->
|
|
|
|
io:format("Release $(strip $2) has been retired~n"),
|
|
|
|
halt(0);
|
|
|
|
{ok, {Status, _, Errors}} ->
|
|
|
|
io:format("Error ~b: ~0p~n", [Status, Errors]),
|
|
|
|
halt(86)
|
|
|
|
end
|
|
|
|
endef
|
|
|
|
|
|
|
|
hex-release-retire: hex-core
|
|
|
|
$(if $(HEX_SECRET),,$(eval HEX_SECRET := $(shell stty -echo; read -p "Secret: " secret; stty echo; echo $$secret) $(info )))
|
|
|
|
$(gen_verbose) $(call erlang,$(call hex_release_retire.erl,$(HEX_SECRET),\
|
|
|
|
$(if $(HEX_VERSION),$(HEX_VERSION),$(PROJECT_VERSION)),\
|
|
|
|
$(if $(HEX_REASON),$(HEX_REASON),invalid),\
|
|
|
|
$(HEX_MESSAGE)))
|
|
|
|
|
|
|
|
define hex_release_unretire.erl
|
|
|
|
{ok, _} = application:ensure_all_started(ssl),
|
|
|
|
{ok, _} = application:ensure_all_started(inets),
|
|
|
|
Config = $(hex_config.erl),
|
|
|
|
ConfigF = Config#{api_key => <<"$(strip $1)">>},
|
|
|
|
case hex_api_release:unretire(ConfigF, <<"$(strip $(PROJECT))">>, <<"$(strip $2)">>) of
|
|
|
|
{ok, {204, _, _}} ->
|
|
|
|
io:format("Release $(strip $2) is not retired anymore~n"),
|
|
|
|
halt(0);
|
|
|
|
{ok, {Status, _, Errors}} ->
|
|
|
|
io:format("Error ~b: ~0p~n", [Status, Errors]),
|
|
|
|
halt(87)
|
|
|
|
end
|
|
|
|
endef
|
|
|
|
|
|
|
|
hex-release-unretire: hex-core
|
|
|
|
$(if $(HEX_SECRET),,$(eval HEX_SECRET := $(shell stty -echo; read -p "Secret: " secret; stty echo; echo $$secret) $(info )))
|
|
|
|
$(gen_verbose) $(call erlang,$(call hex_release_unretire.erl,$(HEX_SECRET),\
|
|
|
|
$(if $(HEX_VERSION),$(HEX_VERSION),$(PROJECT_VERSION))))
|
|
|
|
|
|
|
|
HEX_DOCS_DOC_DIR ?= doc/
|
|
|
|
HEX_DOCS_TARBALL_FILES ?= $(sort $(call core_find,$(HEX_DOCS_DOC_DIR),*))
|
|
|
|
HEX_DOCS_TARBALL_OUTPUT_FILE ?= $(ERLANG_MK_TMP)/$(PROJECT)-docs.tar.gz
|
|
|
|
|
|
|
|
$(HEX_DOCS_TARBALL_OUTPUT_FILE): hex-core app docs
|
|
|
|
$(hex_tar_verbose) tar czf $(HEX_DOCS_TARBALL_OUTPUT_FILE) -C $(HEX_DOCS_DOC_DIR) \
|
|
|
|
$(HEX_DOCS_TARBALL_FILES:$(HEX_DOCS_DOC_DIR)%=%)
|
|
|
|
|
|
|
|
hex-docs-tarball-create: $(HEX_DOCS_TARBALL_OUTPUT_FILE)
|
|
|
|
|
|
|
|
define hex_docs_publish.erl
|
|
|
|
{ok, _} = application:ensure_all_started(ssl),
|
|
|
|
{ok, _} = application:ensure_all_started(inets),
|
|
|
|
Config = $(hex_config.erl),
|
|
|
|
ConfigF = Config#{api_key => <<"$(strip $1)">>},
|
|
|
|
{ok, Tarball} = file:read_file("$(strip $(HEX_DOCS_TARBALL_OUTPUT_FILE))"),
|
|
|
|
case hex_api:post(ConfigF,
|
|
|
|
["packages", "$(strip $(PROJECT))", "releases", "$(strip $(PROJECT_VERSION))", "docs"],
|
|
|
|
{"application/octet-stream", Tarball}) of
|
|
|
|
{ok, {Status, _, _}} when Status >= 200, Status < 300 ->
|
|
|
|
io:format("Docs published~n"),
|
|
|
|
halt(0);
|
|
|
|
{ok, {Status, _, Errors}} ->
|
|
|
|
io:format("Error ~b: ~0p~n", [Status, Errors]),
|
|
|
|
halt(88)
|
|
|
|
end
|
|
|
|
endef
|
|
|
|
|
|
|
|
hex-docs-publish: hex-core hex-docs-tarball-create
|
|
|
|
$(if $(HEX_SECRET),,$(eval HEX_SECRET := $(shell stty -echo; read -p "Secret: " secret; stty echo; echo $$secret) $(info )))
|
|
|
|
$(gen_verbose) $(call erlang,$(call hex_docs_publish.erl,$(HEX_SECRET)))
|
|
|
|
|
|
|
|
define hex_docs_delete.erl
|
|
|
|
{ok, _} = application:ensure_all_started(ssl),
|
|
|
|
{ok, _} = application:ensure_all_started(inets),
|
|
|
|
Config = $(hex_config.erl),
|
|
|
|
ConfigF = Config#{api_key => <<"$(strip $1)">>},
|
|
|
|
case hex_api:delete(ConfigF,
|
|
|
|
["packages", "$(strip $(PROJECT))", "releases", "$(strip $2)", "docs"]) of
|
|
|
|
{ok, {Status, _, _}} when Status >= 200, Status < 300 ->
|
|
|
|
io:format("Docs removed~n"),
|
|
|
|
halt(0);
|
|
|
|
{ok, {Status, _, Errors}} ->
|
|
|
|
io:format("Error ~b: ~0p~n", [Status, Errors]),
|
|
|
|
halt(89)
|
|
|
|
end
|
|
|
|
endef
|
|
|
|
|
|
|
|
hex-docs-delete: hex-core
|
|
|
|
$(if $(HEX_SECRET),,$(eval HEX_SECRET := $(shell stty -echo; read -p "Secret: " secret; stty echo; echo $$secret) $(info )))
|
|
|
|
$(gen_verbose) $(call erlang,$(call hex_docs_delete.erl,$(HEX_SECRET),\
|
|
|
|
$(if $(HEX_VERSION),$(HEX_VERSION),$(PROJECT_VERSION))))
|
|
|
|
|
2017-07-14 21:44:39 +02:00
|
|
|
# Copyright (c) 2015-2017, Loïc Hoguin <essen@ninenines.eu>
|
|
|
|
# This file is part of erlang.mk and subject to the terms of the ISC License.
|
|
|
|
|
|
|
|
ifeq ($(filter proper,$(DEPS) $(TEST_DEPS)),proper)
|
|
|
|
.PHONY: proper
|
|
|
|
|
|
|
|
# Targets.
|
|
|
|
|
|
|
|
tests:: proper
|
|
|
|
|
|
|
|
define proper_check.erl
|
2020-03-29 15:45:51 +02:00
|
|
|
$(call cover.erl)
|
2018-05-16 12:28:55 +02:00
|
|
|
code:add_pathsa([
|
|
|
|
"$(call core_native_path,$(CURDIR)/ebin)",
|
|
|
|
"$(call core_native_path,$(DEPS_DIR)/*/ebin)",
|
|
|
|
"$(call core_native_path,$(TEST_DIR))"]),
|
2017-07-14 21:44:39 +02:00
|
|
|
Module = fun(M) ->
|
|
|
|
[true] =:= lists:usort([
|
|
|
|
case atom_to_list(F) of
|
|
|
|
"prop_" ++ _ ->
|
|
|
|
io:format("Testing ~p:~p/0~n", [M, F]),
|
2017-11-19 13:25:54 +01:00
|
|
|
proper:quickcheck(M:F(), nocolors);
|
2017-07-14 21:44:39 +02:00
|
|
|
_ ->
|
|
|
|
true
|
|
|
|
end
|
|
|
|
|| {F, 0} <- M:module_info(exports)])
|
|
|
|
end,
|
2020-03-29 15:45:51 +02:00
|
|
|
try begin
|
|
|
|
CoverSetup(),
|
|
|
|
Res = case $(1) of
|
2017-07-14 21:44:39 +02:00
|
|
|
all -> [true] =:= lists:usort([Module(M) || M <- [$(call comma_list,$(3))]]);
|
|
|
|
module -> Module($(2));
|
2017-11-19 13:25:54 +01:00
|
|
|
function -> proper:quickcheck($(2), nocolors)
|
2020-03-29 15:45:51 +02:00
|
|
|
end,
|
|
|
|
CoverExport("$(COVER_DATA_DIR)/proper.coverdata"),
|
|
|
|
Res
|
|
|
|
end of
|
2017-07-14 21:44:39 +02:00
|
|
|
true -> halt(0);
|
|
|
|
_ -> halt(1)
|
2023-11-24 11:39:55 +01:00
|
|
|
catch error:undef$(if $V,:Stacktrace) ->
|
|
|
|
io:format("Undefined property or module?~n$(if $V,~p~n)", [$(if $V,Stacktrace)]),
|
2017-07-14 21:44:39 +02:00
|
|
|
halt(0)
|
|
|
|
end.
|
|
|
|
endef
|
|
|
|
|
|
|
|
ifdef t
|
|
|
|
ifeq (,$(findstring :,$(t)))
|
2020-03-29 15:45:51 +02:00
|
|
|
proper: test-build cover-data-dir
|
2017-07-14 21:44:39 +02:00
|
|
|
$(verbose) $(call erlang,$(call proper_check.erl,module,$(t)))
|
|
|
|
else
|
2020-03-29 15:45:51 +02:00
|
|
|
proper: test-build cover-data-dir
|
2017-07-14 21:44:39 +02:00
|
|
|
$(verbose) echo Testing $(t)/0
|
|
|
|
$(verbose) $(call erlang,$(call proper_check.erl,function,$(t)()))
|
|
|
|
endif
|
|
|
|
else
|
2020-03-29 15:45:51 +02:00
|
|
|
proper: test-build cover-data-dir
|
2018-05-16 12:28:55 +02:00
|
|
|
$(eval MODULES := $(patsubst %,'%',$(sort $(notdir $(basename \
|
|
|
|
$(wildcard ebin/*.beam) $(call core_find,$(TEST_DIR)/,*.beam))))))
|
2017-07-14 21:44:39 +02:00
|
|
|
$(gen_verbose) $(call erlang,$(call proper_check.erl,all,undefined,$(MODULES)))
|
2016-01-14 13:35:25 +01:00
|
|
|
endif
|
|
|
|
endif
|
2015-05-05 19:59:37 +03:00
|
|
|
|
2020-03-29 15:45:51 +02:00
|
|
|
# Copyright (c) 2015-2016, Loïc Hoguin <essen@ninenines.eu>
|
|
|
|
# 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, [
|
2023-11-24 11:39:55 +01:00
|
|
|
$(foreach i,$(sort $(dir $(PROTO_FILES))),{i$(comma) "$i"}$(comma))
|
2020-03-29 15:45:51 +02:00
|
|
|
{include_as_lib, true},
|
|
|
|
{module_name_suffix, "_pb"},
|
|
|
|
{o_hrl, "./include"},
|
2023-11-24 11:39:55 +01:00
|
|
|
{o_erl, "./src"},
|
|
|
|
{use_packages, true}
|
|
|
|
])
|
2020-03-29 15:45:51 +02:00
|
|
|
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
|
|
|
|
|
2016-11-05 14:17:30 +02:00
|
|
|
# Copyright (c) 2013-2016, Loïc Hoguin <essen@ninenines.eu>
|
2014-08-01 14:26:51 +02:00
|
|
|
# This file is part of erlang.mk and subject to the terms of the ISC License.
|
|
|
|
|
2022-09-19 14:17:37 +02:00
|
|
|
ifeq ($(filter relx,$(BUILD_DEPS) $(DEPS) $(REL_DEPS)),relx)
|
2016-11-05 14:17:30 +02:00
|
|
|
.PHONY: relx-rel relx-relup distclean-relx-rel run
|
2014-08-01 14:26:51 +02:00
|
|
|
|
|
|
|
# Configuration.
|
|
|
|
|
2015-11-16 23:08:24 +01:00
|
|
|
RELX_CONFIG ?= $(CURDIR)/relx.config
|
2023-11-24 11:39:55 +01:00
|
|
|
RELX_CONFIG_SCRIPT ?= $(CURDIR)/relx.config.script
|
2014-08-01 14:26:51 +02:00
|
|
|
|
|
|
|
RELX_OUTPUT_DIR ?= _rel
|
2017-07-14 21:44:39 +02:00
|
|
|
RELX_REL_EXT ?=
|
|
|
|
RELX_TAR ?= 1
|
|
|
|
|
|
|
|
ifdef SFX
|
|
|
|
RELX_TAR = 1
|
|
|
|
endif
|
2014-08-01 14:26:51 +02:00
|
|
|
|
|
|
|
# Core targets.
|
|
|
|
|
2015-06-11 17:04:21 +02:00
|
|
|
ifeq ($(IS_DEP),)
|
2023-11-24 11:39:55 +01:00
|
|
|
ifneq ($(wildcard $(RELX_CONFIG))$(wildcard $(RELX_CONFIG_SCRIPT)),)
|
2016-01-14 13:35:25 +01:00
|
|
|
rel:: relx-rel
|
2016-11-05 14:17:30 +02:00
|
|
|
|
|
|
|
relup:: relx-relup
|
2014-10-04 15:52:41 +03:00
|
|
|
endif
|
2015-06-11 17:04:21 +02:00
|
|
|
endif
|
2014-08-01 14:26:51 +02:00
|
|
|
|
2016-11-05 14:17:30 +02:00
|
|
|
distclean:: distclean-relx-rel
|
2014-08-01 14:26:51 +02:00
|
|
|
|
|
|
|
# Plugin-specific targets.
|
|
|
|
|
2023-11-24 11:39:55 +01:00
|
|
|
define relx_get_config.erl
|
|
|
|
(fun() ->
|
|
|
|
Config0 =
|
|
|
|
case file:consult("$(call core_native_path,$(RELX_CONFIG))") of
|
|
|
|
{ok, Terms} ->
|
|
|
|
Terms;
|
|
|
|
{error, _} ->
|
|
|
|
[]
|
|
|
|
end,
|
|
|
|
case filelib:is_file("$(call core_native_path,$(RELX_CONFIG_SCRIPT))") of
|
|
|
|
true ->
|
|
|
|
Bindings = erl_eval:add_binding('CONFIG', Config0, erl_eval:new_bindings()),
|
|
|
|
{ok, Config1} = file:script("$(call core_native_path,$(RELX_CONFIG_SCRIPT))", Bindings),
|
|
|
|
Config1;
|
|
|
|
false ->
|
|
|
|
Config0
|
|
|
|
end
|
|
|
|
end)()
|
|
|
|
endef
|
|
|
|
|
2022-09-19 14:17:37 +02:00
|
|
|
define relx_release.erl
|
2023-11-24 11:39:55 +01:00
|
|
|
Config = $(call relx_get_config.erl),
|
2022-09-19 14:17:37 +02:00
|
|
|
{release, {Name, Vsn0}, _} = lists:keyfind(release, 1, Config),
|
|
|
|
Vsn = case Vsn0 of
|
|
|
|
{cmd, Cmd} -> os:cmd(Cmd);
|
|
|
|
semver -> "";
|
|
|
|
{semver, _} -> "";
|
2023-11-24 11:39:55 +01:00
|
|
|
{git, short} -> string:trim(os:cmd("git rev-parse --short HEAD"), both, "\n");
|
|
|
|
{git, long} -> string:trim(os:cmd("git rev-parse HEAD"), both, "\n");
|
2022-09-19 14:17:37 +02:00
|
|
|
VsnStr -> Vsn0
|
|
|
|
end,
|
2023-11-24 11:39:55 +01:00
|
|
|
{ok, _} = relx:build_release(#{name => Name, vsn => Vsn}, Config ++ [{output_dir, "$(RELX_OUTPUT_DIR)"}]),
|
2022-09-19 14:17:37 +02:00
|
|
|
halt(0).
|
|
|
|
endef
|
|
|
|
|
|
|
|
define relx_tar.erl
|
2023-11-24 11:39:55 +01:00
|
|
|
Config = $(call relx_get_config.erl),
|
2022-09-19 14:17:37 +02:00
|
|
|
{release, {Name, Vsn0}, _} = lists:keyfind(release, 1, Config),
|
|
|
|
Vsn = case Vsn0 of
|
|
|
|
{cmd, Cmd} -> os:cmd(Cmd);
|
|
|
|
semver -> "";
|
|
|
|
{semver, _} -> "";
|
2023-11-24 11:39:55 +01:00
|
|
|
{git, short} -> string:trim(os:cmd("git rev-parse --short HEAD"), both, "\n");
|
|
|
|
{git, long} -> string:trim(os:cmd("git rev-parse HEAD"), both, "\n");
|
2022-09-19 14:17:37 +02:00
|
|
|
VsnStr -> Vsn0
|
|
|
|
end,
|
2023-11-24 11:39:55 +01:00
|
|
|
{ok, _} = relx:build_tar(#{name => Name, vsn => Vsn}, Config ++ [{output_dir, "$(RELX_OUTPUT_DIR)"}]),
|
2022-09-19 14:17:37 +02:00
|
|
|
halt(0).
|
|
|
|
endef
|
|
|
|
|
|
|
|
define relx_relup.erl
|
2023-11-24 11:39:55 +01:00
|
|
|
Config = $(call relx_get_config.erl),
|
2022-09-19 14:17:37 +02:00
|
|
|
{release, {Name, Vsn0}, _} = lists:keyfind(release, 1, Config),
|
|
|
|
Vsn = case Vsn0 of
|
|
|
|
{cmd, Cmd} -> os:cmd(Cmd);
|
|
|
|
semver -> "";
|
|
|
|
{semver, _} -> "";
|
2023-11-24 11:39:55 +01:00
|
|
|
{git, short} -> string:trim(os:cmd("git rev-parse --short HEAD"), both, "\n");
|
|
|
|
{git, long} -> string:trim(os:cmd("git rev-parse HEAD"), both, "\n");
|
2022-09-19 14:17:37 +02:00
|
|
|
VsnStr -> Vsn0
|
|
|
|
end,
|
|
|
|
{ok, _} = relx:build_relup(Name, Vsn, undefined, Config ++ [{output_dir, "$(RELX_OUTPUT_DIR)"}]),
|
|
|
|
halt(0).
|
|
|
|
endef
|
2014-08-01 14:26:51 +02:00
|
|
|
|
2022-09-19 14:17:37 +02:00
|
|
|
relx-rel: rel-deps app
|
|
|
|
$(call erlang,$(call relx_release.erl),-pa ebin/)
|
2020-03-29 15:45:51 +02:00
|
|
|
$(verbose) $(MAKE) relx-post-rel
|
2025-02-11 16:02:10 +01:00
|
|
|
$(if $(filter-out 0,$(RELX_TAR)),$(call erlang,$(call relx_tar.erl),-pa ebin/))
|
2016-11-05 14:17:30 +02:00
|
|
|
|
2022-09-19 14:17:37 +02:00
|
|
|
relx-relup: rel-deps app
|
|
|
|
$(call erlang,$(call relx_release.erl),-pa ebin/)
|
2020-03-29 15:45:51 +02:00
|
|
|
$(MAKE) relx-post-rel
|
2022-09-19 14:17:37 +02:00
|
|
|
$(call erlang,$(call relx_relup.erl),-pa ebin/)
|
2025-02-11 16:02:10 +01:00
|
|
|
$(if $(filter-out 0,$(RELX_TAR)),$(call erlang,$(call relx_tar.erl),-pa ebin/))
|
2014-10-04 15:52:41 +03:00
|
|
|
|
|
|
|
distclean-relx-rel:
|
|
|
|
$(gen_verbose) rm -rf $(RELX_OUTPUT_DIR)
|
2013-08-24 10:48:59 +02:00
|
|
|
|
2020-03-29 15:45:51 +02:00
|
|
|
# Default hooks.
|
|
|
|
relx-post-rel::
|
|
|
|
$(verbose) :
|
|
|
|
|
2015-06-11 17:04:21 +02:00
|
|
|
# Run target.
|
|
|
|
|
2023-11-24 11:39:55 +01:00
|
|
|
ifeq ($(wildcard $(RELX_CONFIG))$(wildcard $(RELX_CONFIG_SCRIPT)),)
|
2017-11-19 13:25:54 +01:00
|
|
|
run::
|
2015-06-11 17:04:21 +02:00
|
|
|
else
|
|
|
|
|
|
|
|
define get_relx_release.erl
|
2023-11-24 11:39:55 +01:00
|
|
|
Config = $(call relx_get_config.erl),
|
2017-07-14 21:44:39 +02:00
|
|
|
{release, {Name, Vsn0}, _} = lists:keyfind(release, 1, Config),
|
|
|
|
Vsn = case Vsn0 of
|
|
|
|
{cmd, Cmd} -> os:cmd(Cmd);
|
|
|
|
semver -> "";
|
|
|
|
{semver, _} -> "";
|
2023-11-24 11:39:55 +01:00
|
|
|
{git, short} -> string:trim(os:cmd("git rev-parse --short HEAD"), both, "\n");
|
|
|
|
{git, long} -> string:trim(os:cmd("git rev-parse HEAD"), both, "\n");
|
2017-07-14 21:44:39 +02:00
|
|
|
VsnStr -> Vsn0
|
|
|
|
end,
|
2020-03-29 15:45:51 +02:00
|
|
|
Extended = case lists:keyfind(extended_start_script, 1, Config) of
|
|
|
|
{_, true} -> "1";
|
|
|
|
_ -> ""
|
|
|
|
end,
|
|
|
|
io:format("~s ~s ~s", [Name, Vsn, Extended]),
|
2015-06-11 17:04:21 +02:00
|
|
|
halt(0).
|
|
|
|
endef
|
|
|
|
|
2016-11-05 14:17:30 +02:00
|
|
|
RELX_REL := $(shell $(call erlang,$(get_relx_release.erl)))
|
|
|
|
RELX_REL_NAME := $(word 1,$(RELX_REL))
|
|
|
|
RELX_REL_VSN := $(word 2,$(RELX_REL))
|
2020-03-29 15:45:51 +02:00
|
|
|
RELX_REL_CMD := $(if $(word 3,$(RELX_REL)),console)
|
2015-06-11 17:04:21 +02:00
|
|
|
|
2017-07-14 21:44:39 +02:00
|
|
|
ifeq ($(PLATFORM),msys2)
|
|
|
|
RELX_REL_EXT := .cmd
|
|
|
|
endif
|
|
|
|
|
2025-02-11 16:02:10 +01:00
|
|
|
run:: RELX_TAR := 0
|
2017-11-19 13:25:54 +01:00
|
|
|
run:: all
|
2020-03-29 15:45:51 +02:00
|
|
|
$(verbose) $(RELX_OUTPUT_DIR)/$(RELX_REL_NAME)/bin/$(RELX_REL_NAME)$(RELX_REL_EXT) $(RELX_REL_CMD)
|
2015-06-11 17:04:21 +02:00
|
|
|
|
2018-08-13 08:38:49 +02:00
|
|
|
ifdef RELOAD
|
|
|
|
rel::
|
|
|
|
$(verbose) $(RELX_OUTPUT_DIR)/$(RELX_REL_NAME)/bin/$(RELX_REL_NAME)$(RELX_REL_EXT) ping
|
|
|
|
$(verbose) $(RELX_OUTPUT_DIR)/$(RELX_REL_NAME)/bin/$(RELX_REL_NAME)$(RELX_REL_EXT) \
|
2023-11-24 11:39:55 +01:00
|
|
|
eval "io:format(\"~p~n\", [c:lm()])."
|
2018-08-13 08:38:49 +02:00
|
|
|
endif
|
|
|
|
|
2015-06-11 17:04:21 +02:00
|
|
|
help::
|
2015-07-21 17:16:11 +02:00
|
|
|
$(verbose) printf "%s\n" "" \
|
2015-06-11 17:04:21 +02:00
|
|
|
"Relx targets:" \
|
|
|
|
" run Compile the project, build the release and run it"
|
|
|
|
|
|
|
|
endif
|
2022-09-19 14:17:37 +02:00
|
|
|
endif
|
2015-06-11 17:04:21 +02:00
|
|
|
|
2016-11-05 14:17:30 +02:00
|
|
|
# Copyright (c) 2015-2016, Loïc Hoguin <essen@ninenines.eu>
|
2014-10-04 15:52:41 +03:00
|
|
|
# Copyright (c) 2014, M Robert Martin <rob@version2beta.com>
|
|
|
|
# This file is contributed to erlang.mk and subject to the terms of the ISC License.
|
|
|
|
|
|
|
|
.PHONY: shell
|
|
|
|
|
|
|
|
# Configuration.
|
|
|
|
|
2015-11-16 23:08:24 +01:00
|
|
|
SHELL_ERL ?= erl
|
2020-03-29 15:45:51 +02:00
|
|
|
SHELL_PATHS ?= $(CURDIR)/ebin $(TEST_DIR)
|
2014-10-04 15:52:41 +03:00
|
|
|
SHELL_OPTS ?=
|
|
|
|
|
|
|
|
ALL_SHELL_DEPS_DIRS = $(addprefix $(DEPS_DIR)/,$(SHELL_DEPS))
|
|
|
|
|
|
|
|
# Core targets
|
|
|
|
|
|
|
|
help::
|
2015-07-21 17:16:11 +02:00
|
|
|
$(verbose) printf "%s\n" "" \
|
2014-10-04 15:52:41 +03:00
|
|
|
"Shell targets:" \
|
2015-06-11 17:04:21 +02:00
|
|
|
" shell Run an erlang shell with SHELL_OPTS or reasonable default"
|
2014-10-04 15:52:41 +03:00
|
|
|
|
|
|
|
# Plugin-specific targets.
|
|
|
|
|
|
|
|
$(foreach dep,$(SHELL_DEPS),$(eval $(call dep_target,$(dep))))
|
|
|
|
|
2020-03-29 15:45:51 +02:00
|
|
|
ifneq ($(SKIP_DEPS),)
|
|
|
|
build-shell-deps:
|
|
|
|
else
|
2014-10-04 15:52:41 +03:00
|
|
|
build-shell-deps: $(ALL_SHELL_DEPS_DIRS)
|
2020-03-29 15:45:51 +02:00
|
|
|
$(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
|
2014-10-04 15:52:41 +03:00
|
|
|
|
2020-03-29 15:45:51 +02:00
|
|
|
shell:: build-shell-deps
|
2015-11-16 23:08:24 +01:00
|
|
|
$(gen_verbose) $(SHELL_ERL) -pa $(SHELL_PATHS) $(SHELL_OPTS)
|
2015-05-05 19:59:37 +03:00
|
|
|
|
2018-05-02 18:23:03 +02:00
|
|
|
# Copyright 2017, Stanislaw Klekot <dozzie@jarowit.net>
|
|
|
|
# This file is part of erlang.mk and subject to the terms of the ISC License.
|
|
|
|
|
|
|
|
.PHONY: distclean-sphinx sphinx
|
|
|
|
|
|
|
|
# Configuration.
|
|
|
|
|
|
|
|
SPHINX_BUILD ?= sphinx-build
|
|
|
|
SPHINX_SOURCE ?= doc
|
|
|
|
SPHINX_CONFDIR ?=
|
|
|
|
SPHINX_FORMATS ?= html
|
|
|
|
SPHINX_DOCTREES ?= $(ERLANG_MK_TMP)/sphinx.doctrees
|
|
|
|
SPHINX_OPTS ?=
|
|
|
|
|
|
|
|
#sphinx_html_opts =
|
|
|
|
#sphinx_html_output = html
|
|
|
|
#sphinx_man_opts =
|
|
|
|
#sphinx_man_output = man
|
|
|
|
#sphinx_latex_opts =
|
|
|
|
#sphinx_latex_output = latex
|
|
|
|
|
|
|
|
# Helpers.
|
|
|
|
|
|
|
|
sphinx_build_0 = @echo " SPHINX" $1; $(SPHINX_BUILD) -N -q
|
|
|
|
sphinx_build_1 = $(SPHINX_BUILD) -N
|
|
|
|
sphinx_build_2 = set -x; $(SPHINX_BUILD)
|
|
|
|
sphinx_build = $(sphinx_build_$(V))
|
|
|
|
|
|
|
|
define sphinx.build
|
|
|
|
$(call sphinx_build,$1) -b $1 -d $(SPHINX_DOCTREES) $(if $(SPHINX_CONFDIR),-c $(SPHINX_CONFDIR)) $(SPHINX_OPTS) $(sphinx_$1_opts) -- $(SPHINX_SOURCE) $(call sphinx.output,$1)
|
|
|
|
|
|
|
|
endef
|
|
|
|
|
|
|
|
define sphinx.output
|
|
|
|
$(if $(sphinx_$1_output),$(sphinx_$1_output),$1)
|
|
|
|
endef
|
|
|
|
|
|
|
|
# Targets.
|
|
|
|
|
|
|
|
ifneq ($(wildcard $(if $(SPHINX_CONFDIR),$(SPHINX_CONFDIR),$(SPHINX_SOURCE))/conf.py),)
|
|
|
|
docs:: sphinx
|
|
|
|
distclean:: distclean-sphinx
|
|
|
|
endif
|
|
|
|
|
|
|
|
help::
|
|
|
|
$(verbose) printf "%s\n" "" \
|
|
|
|
"Sphinx targets:" \
|
|
|
|
" sphinx Generate Sphinx documentation." \
|
|
|
|
"" \
|
|
|
|
"ReST sources and 'conf.py' file are expected in directory pointed by" \
|
|
|
|
"SPHINX_SOURCE ('doc' by default). SPHINX_FORMATS lists formats to build (only" \
|
|
|
|
"'html' format is generated by default); target directory can be specified by" \
|
|
|
|
'setting sphinx_$${format}_output, for example: sphinx_html_output = output/html' \
|
|
|
|
"Additional Sphinx options can be set in SPHINX_OPTS."
|
|
|
|
|
|
|
|
# Plugin-specific targets.
|
|
|
|
|
|
|
|
sphinx:
|
|
|
|
$(foreach F,$(SPHINX_FORMATS),$(call sphinx.build,$F))
|
|
|
|
|
|
|
|
distclean-sphinx:
|
|
|
|
$(gen_verbose) rm -rf $(filter-out $(SPHINX_SOURCE),$(foreach F,$(SPHINX_FORMATS),$(call sphinx.output,$F)))
|
|
|
|
|
2017-07-14 21:44:39 +02:00
|
|
|
# Copyright (c) 2017, Jean-Sébastien Pédron <jean-sebastien@rabbitmq.com>
|
|
|
|
# This file is contributed to erlang.mk and subject to the terms of the ISC License.
|
|
|
|
|
|
|
|
.PHONY: show-ERL_LIBS show-ERLC_OPTS show-TEST_ERLC_OPTS
|
|
|
|
|
|
|
|
show-ERL_LIBS:
|
|
|
|
@echo $(ERL_LIBS)
|
|
|
|
|
|
|
|
show-ERLC_OPTS:
|
|
|
|
@$(foreach opt,$(ERLC_OPTS) -pa ebin -I include,echo "$(opt)";)
|
|
|
|
|
|
|
|
show-TEST_ERLC_OPTS:
|
|
|
|
@$(foreach opt,$(TEST_ERLC_OPTS) -pa ebin -I include,echo "$(opt)";)
|
|
|
|
|
2016-11-05 14:17:30 +02:00
|
|
|
# Copyright (c) 2015-2016, Loïc Hoguin <essen@ninenines.eu>
|
2015-05-05 19:59:37 +03:00
|
|
|
# This file is part of erlang.mk and subject to the terms of the ISC License.
|
|
|
|
|
2015-11-16 23:08:24 +01:00
|
|
|
ifeq ($(filter triq,$(DEPS) $(TEST_DEPS)),triq)
|
2015-05-05 19:59:37 +03:00
|
|
|
.PHONY: triq
|
|
|
|
|
|
|
|
# Targets.
|
|
|
|
|
|
|
|
tests:: triq
|
|
|
|
|
2015-06-11 17:04:21 +02:00
|
|
|
define triq_check.erl
|
2020-03-29 15:45:51 +02:00
|
|
|
$(call cover.erl)
|
2017-11-19 13:25:54 +01:00
|
|
|
code:add_pathsa([
|
|
|
|
"$(call core_native_path,$(CURDIR)/ebin)",
|
|
|
|
"$(call core_native_path,$(DEPS_DIR)/*/ebin)",
|
|
|
|
"$(call core_native_path,$(TEST_DIR))"]),
|
2020-03-29 15:45:51 +02:00
|
|
|
try begin
|
|
|
|
CoverSetup(),
|
|
|
|
Res = case $(1) of
|
2015-07-21 17:16:11 +02:00
|
|
|
all -> [true] =:= lists:usort([triq:check(M) || M <- [$(call comma_list,$(3))]]);
|
2015-06-11 17:04:21 +02:00
|
|
|
module -> triq:check($(2));
|
|
|
|
function -> triq:check($(2))
|
2020-03-29 15:45:51 +02:00
|
|
|
end,
|
|
|
|
CoverExport("$(COVER_DATA_DIR)/triq.coverdata"),
|
|
|
|
Res
|
|
|
|
end of
|
2015-06-11 17:04:21 +02:00
|
|
|
true -> halt(0);
|
|
|
|
_ -> halt(1)
|
2023-11-24 11:39:55 +01:00
|
|
|
catch error:undef$(if $V,:Stacktrace) ->
|
|
|
|
io:format("Undefined property or module?~n$(if $V,~p~n)", [$(if $V,Stacktrace)]),
|
2015-06-11 17:04:21 +02:00
|
|
|
halt(0)
|
|
|
|
end.
|
2015-05-05 19:59:37 +03:00
|
|
|
endef
|
|
|
|
|
|
|
|
ifdef t
|
|
|
|
ifeq (,$(findstring :,$(t)))
|
2020-03-29 15:45:51 +02:00
|
|
|
triq: test-build cover-data-dir
|
2015-07-21 17:16:11 +02:00
|
|
|
$(verbose) $(call erlang,$(call triq_check.erl,module,$(t)))
|
2015-05-05 19:59:37 +03:00
|
|
|
else
|
2020-03-29 15:45:51 +02:00
|
|
|
triq: test-build cover-data-dir
|
2015-07-21 17:16:11 +02:00
|
|
|
$(verbose) echo Testing $(t)/0
|
|
|
|
$(verbose) $(call erlang,$(call triq_check.erl,function,$(t)()))
|
2015-05-05 19:59:37 +03:00
|
|
|
endif
|
|
|
|
else
|
2020-03-29 15:45:51 +02:00
|
|
|
triq: test-build cover-data-dir
|
2017-11-19 13:25:54 +01:00
|
|
|
$(eval MODULES := $(patsubst %,'%',$(sort $(notdir $(basename \
|
|
|
|
$(wildcard ebin/*.beam) $(call core_find,$(TEST_DIR)/,*.beam))))))
|
2015-07-21 17:16:11 +02:00
|
|
|
$(gen_verbose) $(call erlang,$(call triq_check.erl,all,undefined,$(MODULES)))
|
2015-06-11 17:04:21 +02:00
|
|
|
endif
|
|
|
|
endif
|
|
|
|
|
2022-09-19 14:17:37 +02:00
|
|
|
# Copyright (c) 2022, Loïc Hoguin <essen@ninenines.eu>
|
2015-06-11 17:04:21 +02:00
|
|
|
# This file is part of erlang.mk and subject to the terms of the ISC License.
|
|
|
|
|
2022-09-19 14:17:37 +02:00
|
|
|
.PHONY: xref
|
2015-06-11 17:04:21 +02:00
|
|
|
|
|
|
|
# Configuration.
|
|
|
|
|
2022-09-19 14:17:37 +02:00
|
|
|
# We do not use locals_not_used or deprecated_function_calls
|
|
|
|
# because the compiler will error out by default in those
|
|
|
|
# cases with Erlang.mk. Deprecated functions may make sense
|
|
|
|
# in some cases but few libraries define them. We do not
|
|
|
|
# use exports_not_used by default because it hinders more
|
|
|
|
# than it helps library projects such as Cowboy. Finally,
|
|
|
|
# undefined_functions provides little that undefined_function_calls
|
|
|
|
# doesn't already provide, so it's not enabled by default.
|
|
|
|
XREF_CHECKS ?= [undefined_function_calls]
|
|
|
|
|
|
|
|
# Instead of predefined checks a query can be evaluated
|
|
|
|
# using the Xref DSL. The $q variable is used in that case.
|
|
|
|
|
|
|
|
# The scope is a list of keywords that correspond to
|
|
|
|
# application directories, being essentially an easy way
|
|
|
|
# to configure which applications to analyze. With:
|
|
|
|
#
|
|
|
|
# - app: .
|
|
|
|
# - apps: $(ALL_APPS_DIRS)
|
|
|
|
# - deps: $(ALL_DEPS_DIRS)
|
|
|
|
# - otp: Built-in Erlang/OTP applications.
|
|
|
|
#
|
|
|
|
# The default is conservative (app) and will not be
|
|
|
|
# appropriate for all types of queries (for example
|
|
|
|
# application_call requires adding all applications
|
|
|
|
# that might be called or they will not be found).
|
|
|
|
XREF_SCOPE ?= app # apps deps otp
|
|
|
|
|
|
|
|
# If the above is not enough, additional application
|
|
|
|
# directories can be configured.
|
|
|
|
XREF_EXTRA_APP_DIRS ?=
|
2015-06-11 17:04:21 +02:00
|
|
|
|
2022-09-19 14:17:37 +02:00
|
|
|
# As well as additional non-application directories.
|
|
|
|
XREF_EXTRA_DIRS ?=
|
2015-06-11 17:04:21 +02:00
|
|
|
|
2022-09-19 14:17:37 +02:00
|
|
|
# Erlang.mk supports -ignore_xref([...]) with forms
|
|
|
|
# {M, F, A} | {F, A} | M, the latter ignoring whole
|
|
|
|
# modules. Ignores can also be provided project-wide.
|
|
|
|
XREF_IGNORE ?= []
|
|
|
|
|
|
|
|
# All callbacks may be ignored. Erlang.mk will ignore
|
|
|
|
# them automatically for exports_not_used (unless it
|
|
|
|
# is explicitly disabled by the user).
|
|
|
|
XREF_IGNORE_CALLBACKS ?=
|
2015-06-11 17:04:21 +02:00
|
|
|
|
|
|
|
# Core targets.
|
|
|
|
|
|
|
|
help::
|
2017-07-14 21:44:39 +02:00
|
|
|
$(verbose) printf '%s\n' '' \
|
|
|
|
'Xref targets:' \
|
2022-09-19 14:17:37 +02:00
|
|
|
' xref Analyze the project using Xref' \
|
|
|
|
' xref q=QUERY Evaluate an Xref query'
|
2015-06-11 17:04:21 +02:00
|
|
|
|
|
|
|
# Plugin-specific targets.
|
|
|
|
|
2022-09-19 14:17:37 +02:00
|
|
|
define xref.erl
|
|
|
|
{ok, Xref} = xref:start([]),
|
|
|
|
Scope = [$(call comma_list,$(XREF_SCOPE))],
|
|
|
|
AppDirs0 = [$(call comma_list,$(foreach d,$(XREF_EXTRA_APP_DIRS),"$d"))],
|
|
|
|
AppDirs1 = case lists:member(otp, Scope) of
|
|
|
|
false -> AppDirs0;
|
|
|
|
true ->
|
|
|
|
RootDir = code:root_dir(),
|
|
|
|
AppDirs0 ++ [filename:dirname(P) || P <- code:get_path(), lists:prefix(RootDir, P)]
|
|
|
|
end,
|
|
|
|
AppDirs2 = case lists:member(deps, Scope) of
|
|
|
|
false -> AppDirs1;
|
|
|
|
true -> [$(call comma_list,$(foreach d,$(ALL_DEPS_DIRS),"$d"))] ++ AppDirs1
|
|
|
|
end,
|
|
|
|
AppDirs3 = case lists:member(apps, Scope) of
|
|
|
|
false -> AppDirs2;
|
|
|
|
true -> [$(call comma_list,$(foreach d,$(ALL_APPS_DIRS),"$d"))] ++ AppDirs2
|
|
|
|
end,
|
|
|
|
AppDirs = case lists:member(app, Scope) of
|
|
|
|
false -> AppDirs3;
|
|
|
|
true -> ["../$(notdir $(CURDIR))"|AppDirs3]
|
|
|
|
end,
|
|
|
|
[{ok, _} = xref:add_application(Xref, AppDir, [{builtins, true}]) || AppDir <- AppDirs],
|
|
|
|
ExtraDirs = [$(call comma_list,$(foreach d,$(XREF_EXTRA_DIRS),"$d"))],
|
|
|
|
[{ok, _} = xref:add_directory(Xref, ExtraDir, [{builtins, true}]) || ExtraDir <- ExtraDirs],
|
|
|
|
ok = xref:set_library_path(Xref, code:get_path() -- (["ebin", "."] ++ AppDirs ++ ExtraDirs)),
|
|
|
|
Checks = case {$1, is_list($2)} of
|
|
|
|
{check, true} -> $2;
|
|
|
|
{check, false} -> [$2];
|
|
|
|
{query, _} -> [$2]
|
|
|
|
end,
|
|
|
|
FinalRes = [begin
|
|
|
|
IsInformational = case $1 of
|
|
|
|
query -> true;
|
|
|
|
check ->
|
|
|
|
is_tuple(Check) andalso
|
|
|
|
lists:member(element(1, Check),
|
|
|
|
[call, use, module_call, module_use, application_call, application_use])
|
|
|
|
end,
|
|
|
|
{ok, Res0} = case $1 of
|
|
|
|
check -> xref:analyze(Xref, Check);
|
|
|
|
query -> xref:q(Xref, Check)
|
|
|
|
end,
|
|
|
|
Res = case IsInformational of
|
|
|
|
true -> Res0;
|
|
|
|
false ->
|
|
|
|
lists:filter(fun(R) ->
|
|
|
|
{Mod, InMFA, MFA} = case R of
|
|
|
|
{InMFA0 = {M, _, _}, MFA0} -> {M, InMFA0, MFA0};
|
|
|
|
{M, _, _} -> {M, R, R}
|
|
|
|
end,
|
|
|
|
Attrs = try
|
|
|
|
Mod:module_info(attributes)
|
|
|
|
catch error:undef ->
|
|
|
|
[]
|
|
|
|
end,
|
|
|
|
InlineIgnores = lists:flatten([
|
|
|
|
[case V of
|
|
|
|
M when is_atom(M) -> {M, '_', '_'};
|
|
|
|
{F, A} -> {Mod, F, A};
|
|
|
|
_ -> V
|
|
|
|
end || V <- Values]
|
|
|
|
|| {ignore_xref, Values} <- Attrs]),
|
|
|
|
BuiltinIgnores = [
|
|
|
|
{eunit_test, wrapper_test_exported_, 0}
|
|
|
|
],
|
|
|
|
DoCallbackIgnores = case {Check, "$(strip $(XREF_IGNORE_CALLBACKS))"} of
|
|
|
|
{exports_not_used, ""} -> true;
|
|
|
|
{_, "0"} -> false;
|
|
|
|
_ -> true
|
|
|
|
end,
|
|
|
|
CallbackIgnores = case DoCallbackIgnores of
|
|
|
|
false -> [];
|
|
|
|
true ->
|
|
|
|
Behaviors = lists:flatten([
|
|
|
|
[BL || {behavior, BL} <- Attrs],
|
|
|
|
[BL || {behaviour, BL} <- Attrs]
|
|
|
|
]),
|
|
|
|
[{Mod, CF, CA} || B <- Behaviors, {CF, CA} <- B:behaviour_info(callbacks)]
|
|
|
|
end,
|
|
|
|
WideIgnores = if
|
|
|
|
is_list($(XREF_IGNORE)) ->
|
|
|
|
[if is_atom(I) -> {I, '_', '_'}; true -> I end
|
|
|
|
|| I <- $(XREF_IGNORE)];
|
|
|
|
true -> [$(XREF_IGNORE)]
|
|
|
|
end,
|
|
|
|
Ignores = InlineIgnores ++ BuiltinIgnores ++ CallbackIgnores ++ WideIgnores,
|
|
|
|
not (lists:member(InMFA, Ignores)
|
|
|
|
orelse lists:member(MFA, Ignores)
|
|
|
|
orelse lists:member({Mod, '_', '_'}, Ignores))
|
|
|
|
end, Res0)
|
|
|
|
end,
|
|
|
|
case Res of
|
|
|
|
[] -> ok;
|
|
|
|
_ when IsInformational ->
|
|
|
|
case Check of
|
|
|
|
{call, {CM, CF, CA}} ->
|
|
|
|
io:format("Functions that ~s:~s/~b calls:~n", [CM, CF, CA]);
|
|
|
|
{use, {CM, CF, CA}} ->
|
|
|
|
io:format("Function ~s:~s/~b is called by:~n", [CM, CF, CA]);
|
|
|
|
{module_call, CMod} ->
|
|
|
|
io:format("Modules that ~s calls:~n", [CMod]);
|
|
|
|
{module_use, CMod} ->
|
|
|
|
io:format("Module ~s is used by:~n", [CMod]);
|
|
|
|
{application_call, CApp} ->
|
|
|
|
io:format("Applications that ~s calls:~n", [CApp]);
|
|
|
|
{application_use, CApp} ->
|
|
|
|
io:format("Application ~s is used by:~n", [CApp]);
|
|
|
|
_ when $1 =:= query ->
|
|
|
|
io:format("Query ~s returned:~n", [Check])
|
|
|
|
end,
|
|
|
|
[case R of
|
|
|
|
{{InM, InF, InA}, {M, F, A}} ->
|
|
|
|
io:format("- ~s:~s/~b called by ~s:~s/~b~n",
|
|
|
|
[M, F, A, InM, InF, InA]);
|
|
|
|
{M, F, A} ->
|
|
|
|
io:format("- ~s:~s/~b~n", [M, F, A]);
|
|
|
|
ModOrApp ->
|
|
|
|
io:format("- ~s~n", [ModOrApp])
|
|
|
|
end || R <- Res],
|
|
|
|
ok;
|
|
|
|
_ ->
|
|
|
|
[case {Check, R} of
|
|
|
|
{undefined_function_calls, {{InM, InF, InA}, {M, F, A}}} ->
|
|
|
|
io:format("Undefined function ~s:~s/~b called by ~s:~s/~b~n",
|
|
|
|
[M, F, A, InM, InF, InA]);
|
|
|
|
{undefined_functions, {M, F, A}} ->
|
|
|
|
io:format("Undefined function ~s:~s/~b~n", [M, F, A]);
|
|
|
|
{locals_not_used, {M, F, A}} ->
|
|
|
|
io:format("Unused local function ~s:~s/~b~n", [M, F, A]);
|
|
|
|
{exports_not_used, {M, F, A}} ->
|
|
|
|
io:format("Unused exported function ~s:~s/~b~n", [M, F, A]);
|
|
|
|
{deprecated_function_calls, {{InM, InF, InA}, {M, F, A}}} ->
|
|
|
|
io:format("Deprecated function ~s:~s/~b called by ~s:~s/~b~n",
|
|
|
|
[M, F, A, InM, InF, InA]);
|
|
|
|
{deprecated_functions, {M, F, A}} ->
|
|
|
|
io:format("Deprecated function ~s:~s/~b~n", [M, F, A]);
|
|
|
|
_ ->
|
|
|
|
io:format("~p: ~p~n", [Check, R])
|
|
|
|
end || R <- Res],
|
|
|
|
error
|
|
|
|
end
|
|
|
|
end || Check <- Checks],
|
|
|
|
stopped = xref:stop(Xref),
|
|
|
|
case lists:usort(FinalRes) of
|
|
|
|
[ok] -> halt(0);
|
|
|
|
_ -> halt(1)
|
|
|
|
end
|
|
|
|
endef
|
2015-06-11 17:04:21 +02:00
|
|
|
|
2022-09-19 14:17:37 +02:00
|
|
|
xref: deps app
|
|
|
|
ifdef q
|
|
|
|
$(verbose) $(call erlang,$(call xref.erl,query,"$q"),-pa ebin/)
|
|
|
|
else
|
|
|
|
$(verbose) $(call erlang,$(call xref.erl,check,$(XREF_CHECKS)),-pa ebin/)
|
|
|
|
endif
|
2015-06-11 17:04:21 +02:00
|
|
|
|
2016-11-05 14:17:30 +02:00
|
|
|
# Copyright (c) 2016, Loïc Hoguin <essen@ninenines.eu>
|
|
|
|
# Copyright (c) 2015, Viktor Söderqvist <viktor@zuiderkwast.se>
|
2015-06-11 17:04:21 +02:00
|
|
|
# This file is part of erlang.mk and subject to the terms of the ISC License.
|
|
|
|
|
2017-11-19 13:25:54 +01:00
|
|
|
COVER_REPORT_DIR ?= cover
|
2020-03-29 15:45:51 +02:00
|
|
|
COVER_DATA_DIR ?= $(COVER_REPORT_DIR)
|
|
|
|
|
|
|
|
ifdef COVER
|
|
|
|
COVER_APPS ?= $(notdir $(ALL_APPS_DIRS))
|
|
|
|
COVER_DEPS ?=
|
2023-11-24 11:39:55 +01:00
|
|
|
COVER_EXCLUDE_MODS ?=
|
2020-03-29 15:45:51 +02:00
|
|
|
endif
|
2015-06-11 17:04:21 +02:00
|
|
|
|
2020-03-29 15:45:51 +02:00
|
|
|
# Code coverage for Common Test.
|
2015-06-11 17:04:21 +02:00
|
|
|
|
|
|
|
ifdef COVER
|
|
|
|
ifdef CT_RUN
|
2017-07-14 21:44:39 +02:00
|
|
|
ifneq ($(wildcard $(TEST_DIR)),)
|
2015-06-11 17:04:21 +02:00
|
|
|
test-build:: $(TEST_DIR)/ct.cover.spec
|
|
|
|
|
2017-11-19 13:25:54 +01:00
|
|
|
$(TEST_DIR)/ct.cover.spec: cover-data-dir
|
2015-06-11 17:04:21 +02:00
|
|
|
$(gen_verbose) printf "%s\n" \
|
2017-11-19 13:25:54 +01:00
|
|
|
"{incl_app, '$(PROJECT)', details}." \
|
2020-03-29 15:45:51 +02:00
|
|
|
"{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)\")]}." \
|
2023-11-24 11:39:55 +01:00
|
|
|
'{export,"$(call core_native_path,$(abspath $(COVER_DATA_DIR))/ct.coverdata)"}.' \
|
|
|
|
"{excl_mods, '$(PROJECT)', [$(call comma_list,$(COVER_EXCLUDE_MODS))]}." > $@
|
2015-06-11 17:04:21 +02:00
|
|
|
|
|
|
|
CT_RUN += -cover $(TEST_DIR)/ct.cover.spec
|
|
|
|
endif
|
|
|
|
endif
|
2017-07-14 21:44:39 +02:00
|
|
|
endif
|
2015-06-11 17:04:21 +02:00
|
|
|
|
2020-03-29 15:45:51 +02:00
|
|
|
# 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)")],
|
2023-11-24 11:39:55 +01:00
|
|
|
Excludes = [$(call comma_list,$(foreach e,$(COVER_EXCLUDE_MODS),"$e"))],
|
|
|
|
[case file:list_dir(Dir) of
|
|
|
|
{error, enotdir} -> false;
|
|
|
|
{error, _} -> halt(2);
|
|
|
|
{ok, Files} ->
|
|
|
|
BeamFiles = [filename:join(Dir, File) ||
|
|
|
|
File <- Files,
|
|
|
|
not lists:member(filename:basename(File, ".beam"), Excludes),
|
|
|
|
filename:extension(File) =:= ".beam"],
|
|
|
|
case cover:compile_beam(BeamFiles) of
|
|
|
|
{error, _} -> halt(1);
|
|
|
|
_ -> true
|
2020-03-29 15:45:51 +02:00
|
|
|
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
|
|
|
|
|
2015-06-11 17:04:21 +02:00
|
|
|
# Core targets
|
|
|
|
|
|
|
|
ifdef COVER
|
|
|
|
ifneq ($(COVER_REPORT_DIR),)
|
|
|
|
tests::
|
2015-07-21 17:16:11 +02:00
|
|
|
$(verbose) $(MAKE) --no-print-directory cover-report
|
2015-06-11 17:04:21 +02:00
|
|
|
endif
|
2017-11-19 13:25:54 +01:00
|
|
|
|
|
|
|
cover-data-dir: | $(COVER_DATA_DIR)
|
|
|
|
|
|
|
|
$(COVER_DATA_DIR):
|
|
|
|
$(verbose) mkdir -p $(COVER_DATA_DIR)
|
|
|
|
else
|
|
|
|
cover-data-dir:
|
2015-06-11 17:04:21 +02:00
|
|
|
endif
|
|
|
|
|
|
|
|
clean:: coverdata-clean
|
|
|
|
|
|
|
|
ifneq ($(COVER_REPORT_DIR),)
|
|
|
|
distclean:: cover-report-clean
|
2015-05-05 19:59:37 +03:00
|
|
|
endif
|
2015-06-11 17:04:21 +02:00
|
|
|
|
|
|
|
help::
|
2015-07-21 17:16:11 +02:00
|
|
|
$(verbose) printf "%s\n" "" \
|
2015-06-11 17:04:21 +02:00
|
|
|
"Cover targets:" \
|
|
|
|
" cover-report Generate a HTML coverage report from previously collected" \
|
|
|
|
" cover data." \
|
2017-07-14 21:44:39 +02:00
|
|
|
" all.coverdata Merge all coverdata files into all.coverdata." \
|
2015-06-11 17:04:21 +02:00
|
|
|
"" \
|
|
|
|
"If COVER=1 is set, coverage data is generated by the targets eunit and ct. The" \
|
|
|
|
"target tests additionally generates a HTML coverage report from the combined" \
|
|
|
|
"coverdata files from each of these testing tools. HTML reports can be disabled" \
|
|
|
|
"by setting COVER_REPORT_DIR to empty."
|
|
|
|
|
|
|
|
# Plugin specific targets
|
|
|
|
|
2017-11-19 13:25:54 +01:00
|
|
|
COVERDATA = $(filter-out $(COVER_DATA_DIR)/all.coverdata,$(wildcard $(COVER_DATA_DIR)/*.coverdata))
|
2015-06-11 17:04:21 +02:00
|
|
|
|
|
|
|
.PHONY: coverdata-clean
|
|
|
|
coverdata-clean:
|
2017-11-19 13:25:54 +01:00
|
|
|
$(gen_verbose) rm -f $(COVER_DATA_DIR)/*.coverdata $(TEST_DIR)/ct.cover.spec
|
2015-06-11 17:04:21 +02:00
|
|
|
|
|
|
|
# Merge all coverdata files into one.
|
2017-07-14 21:44:39 +02:00
|
|
|
define cover_export.erl
|
|
|
|
$(foreach f,$(COVERDATA),cover:import("$(f)") == ok orelse halt(1),)
|
2017-11-19 13:25:54 +01:00
|
|
|
cover:export("$(COVER_DATA_DIR)/$@"), halt(0).
|
2017-07-14 21:44:39 +02:00
|
|
|
endef
|
|
|
|
|
2017-11-19 13:25:54 +01:00
|
|
|
all.coverdata: $(COVERDATA) cover-data-dir
|
2017-07-14 21:44:39 +02:00
|
|
|
$(gen_verbose) $(call erlang,$(cover_export.erl))
|
2015-06-11 17:04:21 +02:00
|
|
|
|
|
|
|
# These are only defined if COVER_REPORT_DIR is non-empty. Set COVER_REPORT_DIR to
|
|
|
|
# empty if you want the coverdata files but not the HTML report.
|
|
|
|
ifneq ($(COVER_REPORT_DIR),)
|
|
|
|
|
|
|
|
.PHONY: cover-report-clean cover-report
|
|
|
|
|
|
|
|
cover-report-clean:
|
|
|
|
$(gen_verbose) rm -rf $(COVER_REPORT_DIR)
|
2020-03-29 15:45:51 +02:00
|
|
|
ifneq ($(COVER_REPORT_DIR),$(COVER_DATA_DIR))
|
2017-11-19 13:25:54 +01:00
|
|
|
$(if $(shell ls -A $(COVER_DATA_DIR)/),,$(verbose) rmdir $(COVER_DATA_DIR))
|
2020-03-29 15:45:51 +02:00
|
|
|
endif
|
2015-06-11 17:04:21 +02:00
|
|
|
|
|
|
|
ifeq ($(COVERDATA),)
|
|
|
|
cover-report:
|
|
|
|
else
|
|
|
|
|
|
|
|
# Modules which include eunit.hrl always contain one line without coverage
|
|
|
|
# because eunit defines test/0 which is never called. We compensate for this.
|
|
|
|
EUNIT_HRL_MODS = $(subst $(space),$(comma),$(shell \
|
2017-07-14 21:44:39 +02:00
|
|
|
grep -H -e '^\s*-include.*include/eunit\.hrl"' src/*.erl \
|
2015-06-11 17:04:21 +02:00
|
|
|
| sed "s/^src\/\(.*\)\.erl:.*/'\1'/" | uniq))
|
|
|
|
|
|
|
|
define cover_report.erl
|
|
|
|
$(foreach f,$(COVERDATA),cover:import("$(f)") == ok orelse halt(1),)
|
|
|
|
Ms = cover:imported_modules(),
|
|
|
|
[cover:analyse_to_file(M, "$(COVER_REPORT_DIR)/" ++ atom_to_list(M)
|
|
|
|
++ ".COVER.html", [html]) || M <- Ms],
|
|
|
|
Report = [begin {ok, R} = cover:analyse(M, module), R end || M <- Ms],
|
|
|
|
EunitHrlMods = [$(EUNIT_HRL_MODS)],
|
|
|
|
Report1 = [{M, {Y, case lists:member(M, EunitHrlMods) of
|
|
|
|
true -> N - 1; false -> N end}} || {M, {Y, N}} <- Report],
|
|
|
|
TotalY = lists:sum([Y || {_, {Y, _}} <- Report1]),
|
|
|
|
TotalN = lists:sum([N || {_, {_, N}} <- Report1]),
|
2016-11-05 14:17:30 +02:00
|
|
|
Perc = fun(Y, N) -> case Y + N of 0 -> 100; S -> round(100 * Y / S) end end,
|
|
|
|
TotalPerc = Perc(TotalY, TotalN),
|
2015-06-11 17:04:21 +02:00
|
|
|
{ok, F} = file:open("$(COVER_REPORT_DIR)/index.html", [write]),
|
|
|
|
io:format(F, "<!DOCTYPE html><html>~n"
|
|
|
|
"<head><meta charset=\"UTF-8\">~n"
|
|
|
|
"<title>Coverage report</title></head>~n"
|
|
|
|
"<body>~n", []),
|
|
|
|
io:format(F, "<h1>Coverage</h1>~n<p>Total: ~p%</p>~n", [TotalPerc]),
|
|
|
|
io:format(F, "<table><tr><th>Module</th><th>Coverage</th></tr>~n", []),
|
|
|
|
[io:format(F, "<tr><td><a href=\"~p.COVER.html\">~p</a></td>"
|
|
|
|
"<td>~p%</td></tr>~n",
|
2016-11-05 14:17:30 +02:00
|
|
|
[M, M, Perc(Y, N)]) || {M, {Y, N}} <- Report1],
|
2015-06-11 17:04:21 +02:00
|
|
|
How = "$(subst $(space),$(comma)$(space),$(basename $(COVERDATA)))",
|
|
|
|
Date = "$(shell date -u "+%Y-%m-%dT%H:%M:%SZ")",
|
|
|
|
io:format(F, "</table>~n"
|
|
|
|
"<p>Generated using ~s and erlang.mk on ~s.</p>~n"
|
|
|
|
"</body></html>", [How, Date]),
|
|
|
|
halt().
|
|
|
|
endef
|
|
|
|
|
|
|
|
cover-report:
|
2017-07-14 21:44:39 +02:00
|
|
|
$(verbose) mkdir -p $(COVER_REPORT_DIR)
|
2015-06-11 17:04:21 +02:00
|
|
|
$(gen_verbose) $(call erlang,$(cover_report.erl))
|
|
|
|
|
2015-05-05 19:59:37 +03:00
|
|
|
endif
|
2015-06-11 17:04:21 +02:00
|
|
|
endif # ifneq ($(COVER_REPORT_DIR),)
|
2016-11-05 14:17:30 +02:00
|
|
|
|
|
|
|
# Copyright (c) 2016, Loïc Hoguin <essen@ninenines.eu>
|
|
|
|
# This file is part of erlang.mk and subject to the terms of the ISC License.
|
|
|
|
|
|
|
|
.PHONY: sfx
|
|
|
|
|
|
|
|
ifdef RELX_REL
|
|
|
|
ifdef SFX
|
|
|
|
|
|
|
|
# Configuration.
|
|
|
|
|
|
|
|
SFX_ARCHIVE ?= $(RELX_OUTPUT_DIR)/$(RELX_REL_NAME)/$(RELX_REL_NAME)-$(RELX_REL_VSN).tar.gz
|
|
|
|
SFX_OUTPUT_FILE ?= $(RELX_OUTPUT_DIR)/$(RELX_REL_NAME).run
|
|
|
|
|
|
|
|
# Core targets.
|
|
|
|
|
|
|
|
rel:: sfx
|
|
|
|
|
|
|
|
# Plugin-specific targets.
|
|
|
|
|
|
|
|
define sfx_stub
|
|
|
|
#!/bin/sh
|
|
|
|
|
|
|
|
TMPDIR=`mktemp -d`
|
|
|
|
ARCHIVE=`awk '/^__ARCHIVE_BELOW__$$/ {print NR + 1; exit 0;}' $$0`
|
|
|
|
FILENAME=$$(basename $$0)
|
|
|
|
REL=$${FILENAME%.*}
|
|
|
|
|
|
|
|
tail -n+$$ARCHIVE $$0 | tar -xzf - -C $$TMPDIR
|
|
|
|
|
|
|
|
$$TMPDIR/bin/$$REL console
|
|
|
|
RET=$$?
|
|
|
|
|
|
|
|
rm -rf $$TMPDIR
|
|
|
|
|
|
|
|
exit $$RET
|
|
|
|
|
|
|
|
__ARCHIVE_BELOW__
|
|
|
|
endef
|
|
|
|
|
|
|
|
sfx:
|
2020-03-29 15:45:51 +02:00
|
|
|
$(verbose) $(call core_render,sfx_stub,$(SFX_OUTPUT_FILE))
|
2016-11-05 14:17:30 +02:00
|
|
|
$(gen_verbose) cat $(SFX_ARCHIVE) >> $(SFX_OUTPUT_FILE)
|
|
|
|
$(verbose) chmod +x $(SFX_OUTPUT_FILE)
|
|
|
|
|
|
|
|
endif
|
|
|
|
endif
|
|
|
|
|
2017-07-14 21:44:39 +02:00
|
|
|
# Copyright (c) 2013-2017, Loïc Hoguin <essen@ninenines.eu>
|
|
|
|
# This file is part of erlang.mk and subject to the terms of the ISC License.
|
|
|
|
|
|
|
|
# External plugins.
|
|
|
|
|
|
|
|
DEP_PLUGINS ?=
|
|
|
|
|
|
|
|
$(foreach p,$(DEP_PLUGINS),\
|
|
|
|
$(eval $(if $(findstring /,$p),\
|
|
|
|
$(call core_dep_plugin,$p,$(firstword $(subst /, ,$p))),\
|
|
|
|
$(call core_dep_plugin,$p/plugins.mk,$p))))
|
|
|
|
|
2020-03-29 15:45:51 +02:00
|
|
|
help:: help-plugins
|
|
|
|
|
|
|
|
help-plugins::
|
|
|
|
$(verbose) :
|
|
|
|
|
2016-11-05 14:17:30 +02:00
|
|
|
# Copyright (c) 2013-2015, Loïc Hoguin <essen@ninenines.eu>
|
|
|
|
# Copyright (c) 2015-2016, Jean-Sébastien Pédron <jean-sebastien@rabbitmq.com>
|
|
|
|
# This file is part of erlang.mk and subject to the terms of the ISC License.
|
|
|
|
|
|
|
|
# Fetch dependencies recursively (without building them).
|
|
|
|
|
|
|
|
.PHONY: fetch-deps fetch-doc-deps fetch-rel-deps fetch-test-deps \
|
|
|
|
fetch-shell-deps
|
|
|
|
|
|
|
|
.PHONY: $(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)
|
|
|
|
|
|
|
|
fetch-deps: $(ERLANG_MK_RECURSIVE_DEPS_LIST)
|
|
|
|
fetch-doc-deps: $(ERLANG_MK_RECURSIVE_DOC_DEPS_LIST)
|
|
|
|
fetch-rel-deps: $(ERLANG_MK_RECURSIVE_REL_DEPS_LIST)
|
|
|
|
fetch-test-deps: $(ERLANG_MK_RECURSIVE_TEST_DEPS_LIST)
|
|
|
|
fetch-shell-deps: $(ERLANG_MK_RECURSIVE_SHELL_DEPS_LIST)
|
|
|
|
|
|
|
|
ifneq ($(SKIP_DEPS),)
|
|
|
|
$(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):
|
|
|
|
$(verbose) :> $@
|
|
|
|
else
|
|
|
|
# By default, we fetch "normal" dependencies. They are also included no
|
|
|
|
# matter the type of requested dependencies.
|
|
|
|
#
|
|
|
|
# $(ALL_DEPS_DIRS) includes $(BUILD_DEPS).
|
|
|
|
|
2020-03-29 15:45:51 +02:00
|
|
|
$(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)
|
2016-11-05 14:17:30 +02:00
|
|
|
|
|
|
|
# Allow to use fetch-deps and $(DEP_TYPES) to fetch multiple types of
|
|
|
|
# dependencies with a single target.
|
|
|
|
ifneq ($(filter doc,$(DEP_TYPES)),)
|
|
|
|
$(ERLANG_MK_RECURSIVE_DEPS_LIST): $(ALL_DOC_DEPS_DIRS)
|
|
|
|
endif
|
|
|
|
ifneq ($(filter rel,$(DEP_TYPES)),)
|
|
|
|
$(ERLANG_MK_RECURSIVE_DEPS_LIST): $(ALL_REL_DEPS_DIRS)
|
|
|
|
endif
|
|
|
|
ifneq ($(filter test,$(DEP_TYPES)),)
|
|
|
|
$(ERLANG_MK_RECURSIVE_DEPS_LIST): $(ALL_TEST_DEPS_DIRS)
|
|
|
|
endif
|
|
|
|
ifneq ($(filter shell,$(DEP_TYPES)),)
|
|
|
|
$(ERLANG_MK_RECURSIVE_DEPS_LIST): $(ALL_SHELL_DEPS_DIRS)
|
|
|
|
endif
|
|
|
|
|
2020-03-29 15:45:51 +02:00
|
|
|
ERLANG_MK_RECURSIVE_TMP_LIST := $(abspath $(ERLANG_MK_TMP)/recursive-tmp-deps-$(shell echo $$PPID).log)
|
2016-11-05 14:17:30 +02:00
|
|
|
|
|
|
|
$(ERLANG_MK_RECURSIVE_DEPS_LIST) \
|
|
|
|
$(ERLANG_MK_RECURSIVE_DOC_DEPS_LIST) \
|
|
|
|
$(ERLANG_MK_RECURSIVE_REL_DEPS_LIST) \
|
|
|
|
$(ERLANG_MK_RECURSIVE_TEST_DEPS_LIST) \
|
2020-03-29 15:45:51 +02:00
|
|
|
$(ERLANG_MK_RECURSIVE_SHELL_DEPS_LIST): | $(ERLANG_MK_TMP)
|
2016-11-05 14:17:30 +02:00
|
|
|
ifeq ($(IS_APP)$(IS_DEP),)
|
|
|
|
$(verbose) rm -f $(ERLANG_MK_RECURSIVE_TMP_LIST)
|
|
|
|
endif
|
2020-10-07 13:44:24 +02:00
|
|
|
$(verbose) touch $(ERLANG_MK_RECURSIVE_TMP_LIST)
|
2017-07-14 21:44:39 +02:00
|
|
|
$(verbose) set -e; for dep in $^ ; do \
|
2016-11-05 14:17:30 +02:00
|
|
|
if ! grep -qs ^$$dep$$ $(ERLANG_MK_RECURSIVE_TMP_LIST); then \
|
|
|
|
echo $$dep >> $(ERLANG_MK_RECURSIVE_TMP_LIST); \
|
2017-07-14 21:44:39 +02:00
|
|
|
if grep -qs -E "^[[:blank:]]*include[[:blank:]]+(erlang\.mk|.*/erlang\.mk|.*ERLANG_MK_FILENAME.*)$$" \
|
2016-11-05 14:17:30 +02:00
|
|
|
$$dep/GNUmakefile $$dep/makefile $$dep/Makefile; then \
|
|
|
|
$(MAKE) -C $$dep fetch-deps \
|
|
|
|
IS_DEP=1 \
|
2017-07-14 21:44:39 +02:00
|
|
|
ERLANG_MK_RECURSIVE_TMP_LIST=$(ERLANG_MK_RECURSIVE_TMP_LIST); \
|
2016-11-05 14:17:30 +02:00
|
|
|
fi \
|
|
|
|
fi \
|
|
|
|
done
|
|
|
|
ifeq ($(IS_APP)$(IS_DEP),)
|
2020-03-29 15:45:51 +02:00
|
|
|
$(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
|
2016-11-05 14:17:30 +02:00
|
|
|
$(verbose) rm $(ERLANG_MK_RECURSIVE_TMP_LIST)
|
|
|
|
endif
|
|
|
|
endif # ifneq ($(SKIP_DEPS),)
|
|
|
|
|
|
|
|
# List dependencies recursively.
|
|
|
|
|
|
|
|
.PHONY: list-deps list-doc-deps list-rel-deps list-test-deps \
|
|
|
|
list-shell-deps
|
|
|
|
|
|
|
|
list-deps: $(ERLANG_MK_RECURSIVE_DEPS_LIST)
|
|
|
|
list-doc-deps: $(ERLANG_MK_RECURSIVE_DOC_DEPS_LIST)
|
|
|
|
list-rel-deps: $(ERLANG_MK_RECURSIVE_REL_DEPS_LIST)
|
|
|
|
list-test-deps: $(ERLANG_MK_RECURSIVE_TEST_DEPS_LIST)
|
|
|
|
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 $^
|
2020-03-29 15:45:51 +02:00
|
|
|
|
|
|
|
# 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
|
2025-02-11 16:02:10 +01:00
|
|
|
$1: $2 clean-tmp-query.log
|
2020-03-29 15:45:51 +02:00
|
|
|
ifeq ($(IS_APP)$(IS_DEP),)
|
2025-02-11 16:02:10 +01:00
|
|
|
$(verbose) rm -f $4
|
2020-03-29 15:45:51 +02:00
|
|
|
endif
|
2025-02-11 16:02:10 +01:00
|
|
|
$(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 \
|
2020-03-29 15:45:51 +02:00
|
|
|
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),)
|
2025-02-11 16:02:10 +01:00
|
|
|
$(verbose) touch $4
|
|
|
|
$(verbose) cat $4
|
2020-03-29 15:45:51 +02:00
|
|
|
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)))
|