diff options
85 files changed, 2701 insertions, 1003 deletions
@@ -61,3 +61,10 @@ clean: docs: $(MAKE) -f core/core.mk -f core/docs.mk -f plugins/asciidoc.mk asciidoc + +up: + git clone [email protected]:ninenines/erlang.mk.git gh-pages + cd gh-pages && git checkout gh-pages + cd gh-pages && make + cd gh-pages && git push origin gh-pages + rm -rf gh-pages diff --git a/README.asciidoc b/README.asciidoc new file mode 100644 index 0000000..c397291 --- /dev/null +++ b/README.asciidoc @@ -0,0 +1,18 @@ += Erlang.mk + +A build tool for Erlang that just works. + +http://erlang.mk/ - http://erlang.mk/guide/[User guide] + +Embrace the power and simplicity of Makefiles. + +[source,make] +PROJECT = webchat +DEPS = cowboy +include erlang.mk + +http://erlang.mk/guide/getting_started.html[Get started] + +Tested and supported on +http://erlang.mk/guide/installation.html#_on_unix[Linux, FreeBSD, OSX] +and http://erlang.mk/guide/installation.html#_on_windows[Windows]. diff --git a/README.legacy.md b/README.legacy.md new file mode 100644 index 0000000..a992977 --- /dev/null +++ b/README.legacy.md @@ -0,0 +1,137 @@ +Old Erlang.mk documentation +=========================== + +This documentation reminds here until it gets moved to the +official documentation on http://erlang.mk/guide/. + +Extending Erlang.mk +------------------- + +You may add additional operations to them by using the double +colons. Make will run all targets sharing the same name when +invoked. + +``` Makefile +clean:: + @rm anotherfile +``` + +You can enable verbose mode by calling Make with the variable +`V` set to 1. + +``` bash +$ make V=1 +``` + +Parallel execution +------------------ + +*Parallel execution is currently enabled (experimental).* + +Parallel execution can be enabled through the use of the +`-j` option. The following output showcases concurrent +downloading of dependencies. + +``` bash +$ make -j32 +Cloning into '/home/essen/ninenines/cowboy/deps/ranch'... +Cloning into '/home/essen/ninenines/cowboy/deps/cowlib'... +``` + +The `-O` option will ensure that output from different +targets is grouped, which is particularly useful when +running tests with different frameworks at the same time. +The disadvantage of this option however is that there is +no output until the target is completed. + +The``MAKEFLAGS` variable can be used to set it permanently +on your system. It can be set in your `.zshrc`, `.bashrc` +or equivalent file. + +``` bash +MAKEFLAGS="-j32 -O" +``` + +EDoc plugin +----------- + +This plugin is available by default. + +EDoc options can be specified in Erlang format by defining +the `EDOC_OPTS` variable. For more information please see +`erl -man edoc`. + +ErlyDTL plugin +-------------- + +This plugin is available by default. It adds automatic +compilation of ErlyDTL templates found in `templates/*.dtl` +or any subdirectory. + +By default it ignores names of subdirectories and compiles +`a/b/templatename.dtl` into `templatename_dtl.beam`. To include +subdirectories names in the compiled module name add +`DTL_FULL_PATH=1` into your Makefile - `a/b/templatename.dtl` +will be compiled into `a_b_templatename_dtl.beam`. + +Escript plugin +-------------- + +This plugin is available by default. It adds the following +target: + +`escript` which creates a shell-executable archive named +the same as your `$(PROJECT)`, containing the following files +from your application and its dependencies: + +* `*.beam` +* contents of `priv/` +* `sys.config` for your application + +There are a number of optional configuration parameters: + +* `ESCRIPT_NAME` if a different output file is required +* `ESCRIPT_COMMENT` to alter the comment line in the escript header +* `ESCRIPT_BEAMS` for the paths searched for `*.beam` files to include +* `ESCRIPT_SYS_CONFIG` defaults to `rel/sys.config` +* `ESCRIPT_EMU_ARGS` for the parameters used to start the VM +* `ESCRIPT_SHEBANG` for the line used by your shell to start `escript` +* `ESCRIPT_STATIC` for non-beam directories to be included as well + +Refer to http://www.erlang.org/doc/man/escript.html for +more information on `escript` functionality in general. + +Triq plugin +----------- + +This plugin is available by default. It adds the following +target: + +`triq` will check all the properties found in `ebin` or +the test directory specified in `TEST_DIR`. + +You can use the `t` variable to give a specific module +or function to run, for example: + +``` bash +$ make triq t=cow_http_hd +``` + +Or: + +``` bash +$ make triq t=cow_http_hd:prop_parse_accept +``` + +Xref plugin +------------ + +This plugin is available by default. It adds the following +target: + +`xref` Erlang Xref Runner (inspired in rebar's rebar_xref) + +The `XREF_CONFIG` variable specifies the location of the +configuration file which holds the checks to be applied. +If there is no `xref.config` all `xref` checks will be +applied to the binaries located in the `/ebin` directory. diff --git a/README.md b/README.md deleted file mode 100644 index 600ce50..0000000 --- a/README.md +++ /dev/null @@ -1,353 +0,0 @@ -erlang.mk -========= - -A build tool for Erlang that just works. - -[Check out our upcoming user guide!](doc/src/guide/book.asciidoc) - -The README only contains legacy documentation that was not moved to -the guide yet. Check there if you don't find what you're looking for. - -Requirements ------------- - -`erlang.mk` requires GNU Make and expects to be ran in a standard -unix environment with Erlang installed and in the `$PATH`. - -Common workflow ---------------- - -A common workflow when editing a file would be to run `make` regularly -to see if it compiles (or less often `make clean app` if you want to -recompile everything), followed by `make dialyze` to see if there are -any type errors and then `make tests` to run the test suites. The -result of the test runs can be browsed from the `logs/index.html` file. - -Compiling and dependencies --------------------------- - -Gone! [Check out our upcoming user guide!](doc/src/guide/book.asciidoc) - -Releases --------- - -If a `relx.config` file is present, erlang.mk will download `relx` -automatically and build the release into the `_rel` folder. This -is the default command when the file exists. - -No special configuration is required for this to work. - -Extending Erlang.mk -------------------- - -You may add additional operations to them by using the double -colons. Make will run all targets sharing the same name when -invoked. - -``` Makefile -clean:: - @rm anotherfile -``` - -You can enable verbose mode by calling Make with the variable -`V` set to 1. - -``` bash -$ make V=1 -``` - -Parallel execution ------------------- - -*Parallel execution is currently disabled.* - -Parallel execution can be enabled through the use of the -`-j` option. The following output showcases concurrent -downloading of dependencies. - -``` bash -$ make -j32 -Cloning into '/home/essen/ninenines/cowboy/deps/ranch'... -Cloning into '/home/essen/ninenines/cowboy/deps/cowlib'... -``` - -The `-O` option will ensure that output from different -targets is grouped, which is particularly useful when -running tests with different frameworks at the same time. -The disadvantage of this option however is that there is -no output until the target is completed. - -The``MAKEFLAGS` variable can be used to set it permanently -on your system. It can be set in your `.zshrc`, `.bashrc` -or equivalent file. - -``` bash -MAKEFLAGS="-j32 -O" -``` - -C/C++ compiler plugin ---------------------- - -This plugin is available by default. It is meant to -simplify the management of projects that include C -and/or C++ source code, like NIFs for example. - -If the file `$(C_SRC_DIR)/Makefile` exists, then the plugin -simply calls it when needed. Otherwise it tries to compile -it directly. - -You can use a different directory than `./c_src` by setting -the `C_SRC_DIR` variable. - -You can override the output file by setting the `C_SRC_OUTPUT` -variable. - -You can override the temporary file containing information -about Erlang's environment by setting the `C_SRC_ENV` variable. -This file is automatically generated on first run. - -The `CC`, `CXX`, `CFLAGS`, `CXXFLAGS`, `LDLIBS` and `LDFLAGS` variables -may be modified or replaced with any value of your choosing. -The defaults are system dependent. - -Common_test plugin ------------------- - -This plugin is available by default. It adds the following -target: - -`ct` runs all test suites for this application. - -There is nothing to configure to use it, simply create your -test suites in the `./test/` directory and erlang.mk will -figure everything out automatically. - -You can override the list of suites that will run when using -`make tests` by setting the `CT_SUITES` variable. - -You can add extra `ct_run` options by defining the `CT_OPTS` -variable. For more information please see `erl -man ct_run`. - -You can run an individual test suite by using the special `ct-*` -targets. For example if you have a common_test suite named `spdy` -and you want to run only this suite and not the others, you can -use the `make ct-spdy` command. - -Dialyzer plugin ---------------- - -This plugin is available by default. It adds the following -targets: - -`plt` builds the PLT file for this application. - -`dialyze` runs Dialyzer. - -The PLT file is built in `./$(PROJECT).plt` by default. -You can override this location by setting the `DIALYZER_PLT` -variable. - -The `PLT_APPS` variable lists the applications that will be -included in the PLT file. There is no need to specify `erts`, -`kernel`, `stdlib` or the project's dependencies here, as they -are automatically added. - -Dialyzer options can be modified by defining the `DIALYZER_OPTS` -variable. The directories to be analyzed can be overriden using -the `DIALYZER_DIRS` variable. It defaults to analyzing source -files recursively found in `src/`. For more information please -see `erl -man dialyzer`. - -EDoc plugin ------------ - -This plugin is available by default. - -EDoc options can be specified in Erlang format by defining -the `EDOC_OPTS` variable. For more information please see -`erl -man edoc`. - -Elvis plugin ------------- - -This plugin is available by default. It adds the following -target: - -`elvis` runs Elvis style checker for this application. - -The `ELVIS_CONFIG` variable specifies the location of the -configuration file which holds the rules to be applied. -If there's no `elvis.config` file the default one will be -downloaded. When the `ELVIS` variable points to a non-existing -file then the `elvis` executable will be downloaded as well. -Any other option should go in the `ELVIS_OPTS` variable. - -ErlyDTL plugin --------------- - -This plugin is available by default. It adds automatic -compilation of ErlyDTL templates found in `templates/*.dtl` -or any subdirectory. - -By default it ignores names of subdirectories and compiles -`a/b/templatename.dtl` into `templatename_dtl.beam`. To include -subdirectories names in the compiled module name add -`DTL_FULL_PATH=1` into your Makefile - `a/b/templatename.dtl` -will be compiled into `a_b_templatename_dtl.beam`. - -Escript plugin --------------- - -This plugin is available by default. It adds the following -target: - -`escript` which creates a shell-executable archive named -the same as your `$(PROJECT)`, containing the following files -from your application and its dependencies: - -* `*.beam` -* contents of `priv/` -* `sys.config` for your application - -There are a number of optional configuration parameters: - -* `ESCRIPT_NAME` if a different output file is required -* `ESCRIPT_COMMENT` to alter the comment line in the escript header -* `ESCRIPT_BEAMS` for the paths searched for `*.beam` files to include -* `ESCRIPT_SYS_CONFIG` defaults to `rel/sys.config` -* `ESCRIPT_EMU_ARGS` for the parameters used to start the VM -* `ESCRIPT_SHEBANG` for the line used by your shell to start `escript` -* `ESCRIPT_STATIC` for non-beam directories to be included as well - -Refer to http://www.erlang.org/doc/man/escript.html for -more information on `escript` functionality in general. - -EUnit plugin ------------- - -This plugin is available by default. It adds the following -target: - -`eunit` which runs all the EUnit tests found in `ebin` or -the test directory specified in `TEST_DIR`. - -`EUNIT_OPTS` can be used to specify EUnit-specific options -(e.g. `verbose`) that will be used when calling -`eunit:test/2`. This configuration parameter is empty -by default.. Note that EUnit options are specified as -a comma-separated list of options. - -Relx plugin ------------ - -This plugin is available by default. - -You can change the location of the `relx` executable -(downloaded automatically) by defining the `RELX` variable, -and the location of the configuration file by defining -the `RELX_CONFIG` variable. - -The URL used to download `relx` can be overriden by setting -the `RELX_URL` variable. - -You can change the generated releases location by setting -the `RELX_OUTPUT_DIR` variable. Any other option should go -in the `RELX_OPTS` variable. - -If `RELX_OPTS` includes the `-o` option (instead of using -`RELX_OUTPUT_DIR`, then that option must be the first in -the list, otherwise erlang.mk will fail to find it and -will not be able to clean up the release directory. - -Shell plugin ------------- - -This plugin is available by default. - -`SHELL_DEPS` adds the specified modules only when `make shell` -or `make build-shell-deps` is run. For example, to include a module -reloader and TDD test runner, one might add `SHELL_DEPS = tddreloader` -to the Makefile. - -You can add extra `erl` options by defining the `SHELL_OPTS` variable. -For more information please see `erl -man erl`. - -`SHELL_PATH` adds paths to the shell's library search path. By default -this option sets the paths to `-pa ../$(PROJECT)/ebin $(DEPS_DIR)/*/ebin`. - -Triq plugin ------------ - -This plugin is available by default. It adds the following -target: - -`triq` will check all the properties found in `ebin` or -the test directory specified in `TEST_DIR`. - -You can use the `t` variable to give a specific module -or function to run, for example: - -``` bash -$ make triq t=cow_http_hd -``` - -Or: - -``` bash -$ make triq t=cow_http_hd:prop_parse_accept -``` - -Xref plugin ------------- - -This plugin is available by default. It adds the following -target: - -`xref` Erlang Xref Runner (inspired in rebar's rebar_xref) - -The `XREF_CONFIG` variable specifies the location of the -configuration file which holds the checks to be applied. -If there is no `xref.config` all `xref` checks will be -applied to the binaries located in the `/ebin` directory. - -Contributing ------------- - -You can contribute by providing feedback, creating patches, -adding packages to the index or new features as plugins. - -To add a package to the index, please use the `pkg_add.sh` -script. To use it, first fork the repository, then please -follow the example below: - -``` bash -$ git clone https://github.com/$YOURUSERNAME/erlang.mk -$ cd erlang.mk -$ ./pkg_add.sh cowboy git https://github.com/ninenines/cowboy 1.0.0 http://ninenines.eu "Small, fast and modular HTTP server." -$ git push origin master -``` - -Then open a pull request. The arguments given to the script -are, in order, the project name, the download method used, -the repository URL, the commit/tag/branch/version to pull, -a link to the package's website and finally its description. -Make sure to put double quotes around the description. - -You can submit as many packages as you want in one pull -request as long as you follow the instructions above. - -For patches or plugins, you have to edit the `core/*.mk` -or `plugins/*.mk` files. If you submit a new plugin, you also -need to add it to the `build.config` file. - -Make sure to keep the commit title short, to have a single -commit per package/feature/fix and you're good to submit -a pull request! And again, please don't forget to run make -and to commit the updated erlang.mk or index files along -with your other changes. Thanks! - -Support -------- - - * Official IRC Channel: #ninenines on irc.freenode.net - * [Mailing Lists](http://lists.ninenines.eu) diff --git a/appveyor.yml b/appveyor.yml index b82bcd3..3df8dff 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -3,5 +3,5 @@ build_script: - C:\msys64\usr\bin\bash -lc "pacman --noconfirm -Sy" - C:\msys64\usr\bin\bash -lc "pacman --noconfirm -S gcc git make" test_script: -- C:\msys64\usr\bin\bash -lc "cd $APPVEYOR_BUILD_FOLDER && make -j 32 -k check" -- C:\msys64\usr\bin\bash -lc "cd $APPVEYOR_BUILD_FOLDER && make -j 32 -k check LEGACY=1" +- C:\msys64\usr\bin\bash -lc "cd $APPVEYOR_BUILD_FOLDER && make -j 8 -k check" +- C:\msys64\usr\bin\bash -lc "cd $APPVEYOR_BUILD_FOLDER && make -j 8 -k check LEGACY=1" diff --git a/build.config b/build.config index 674035e..41c2f0f 100644 --- a/build.config +++ b/build.config @@ -10,6 +10,7 @@ core/index core/deps # Plugins that must run before Erlang code gets compiled. +plugins/erlydtl plugins/protobuffs # Core modules, continued. @@ -27,8 +28,6 @@ plugins/ci plugins/ct plugins/dialyzer plugins/edoc -plugins/elvis -plugins/erlydtl plugins/escript plugins/eunit plugins/relx @@ -1,6 +1,7 @@ general: - artifacts: - - "test/pkgs.log" + branches: + ignore: + - gh-pages dependencies: cache_directories: @@ -9,13 +10,13 @@ dependencies: pre: - sudo apt-get update - - sudo apt-get install autoconf2.59 gcc + - sudo apt-get install autoconf2.59 gcc parallel - cd $HOME/bin && ln -s /usr/bin/autoconf2.59 autoconf - cd $HOME/bin && ln -s /usr/bin/autoheader2.59 autoheader - - CI_OTP=OTP-18.0.2 make -f core/core.mk -f plugins/ci.mk ci-prepare: + - CI_OTP=OTP-18.2.1 make -f core/core.mk -f plugins/ci.mk ci-prepare: timeout: 3600 test: override: - - source $HOME/erlang/OTP-18.0.2/activate && make -j 32 -k check - - source $HOME/erlang/OTP-18.0.2/activate && make -j 32 -k check LEGACY=1 + - source $HOME/erlang/OTP-18.2.1/activate && make -j 32 -k check + - source $HOME/erlang/OTP-18.2.1/activate && make -j 32 -k check LEGACY=1 diff --git a/core/compat.mk b/core/compat.mk index f936768..eff4915 100644 --- a/core/compat.mk +++ b/core/compat.mk @@ -6,7 +6,7 @@ # We strip out -Werror because we don't want to fail due to # warnings when used as a dependency. -compat_prepare_erlc_opts = $(shell echo "$1" | sed 's/, */,/') +compat_prepare_erlc_opts = $(shell echo "$1" | sed 's/, */,/g') define compat_convert_erlc_opts $(if $(filter-out -Werror,$1),\ @@ -14,11 +14,18 @@ $(if $(filter-out -Werror,$1),\ $(shell echo $1 | cut -b 2-))) endef +define compat_erlc_opts_to_list +[$(call comma_list,$(foreach o,$(call compat_prepare_erlc_opts,$1),$(call compat_convert_erlc_opts,$o)))] +endef + define compat_rebar_config -{deps, [$(call comma_list,$(foreach d,$(DEPS),\ - {$(call dep_name,$d),".*",{git,"$(call dep_repo,$d)","$(call dep_commit,$d)"}}))]}. -{erl_opts, [$(call comma_list,$(foreach o,$(call compat_prepare_erlc_opts,$(ERLC_OPTS)),\ - $(call compat_convert_erlc_opts,$o)))]}. +{deps, [ +$(call comma_list,$(foreach d,$(DEPS),\ + $(if $(filter hex,$(call dep_fetch,$d)),\ + {$(call dep_name,$d)$(comma)"$(call dep_repo,$d)"},\ + {$(call dep_name,$d)$(comma)".*"$(comma){git,"$(call dep_repo,$d)"$(comma)"$(call dep_commit,$d)"}}))) +]}. +{erl_opts, $(call compat_erlc_opts_to_list,$(ERLC_OPTS))}. endef $(eval _compat_rebar_config = $$(compat_rebar_config)) diff --git a/core/core.mk b/core/core.mk index 407b940..5733496 100644 --- a/core/core.mk +++ b/core/core.mk @@ -30,9 +30,11 @@ PROJECT_VERSION ?= rolling V ?= 0 verbose_0 = @ +verbose_2 = set -x; verbose = $(verbose_$(V)) gen_verbose_0 = @echo " GEN " $@; +gen_verbose_2 = set -x; gen_verbose = $(gen_verbose_$(V)) # Temporary files directory. @@ -76,15 +78,13 @@ endif # Core targets. -.NOTPARALLEL: - all:: deps app rel # Noop to avoid a Make warning when there's nothing to do. rel:: - $(verbose) echo -n + $(verbose) : -check:: clean app tests +check:: tests clean:: clean-crashdump @@ -192,8 +192,11 @@ ERLANG_MK_BUILD_DIR ?= .erlang.mk.build erlang-mk: git clone $(ERLANG_MK_REPO) $(ERLANG_MK_BUILD_DIR) +ifdef ERLANG_MK_COMMIT + cd $(ERLANG_MK_BUILD_DIR) && git checkout $(ERLANG_MK_COMMIT) +endif if [ -f $(ERLANG_MK_BUILD_CONFIG) ]; then cp $(ERLANG_MK_BUILD_CONFIG) $(ERLANG_MK_BUILD_DIR)/build.config; fi - cd $(ERLANG_MK_BUILD_DIR) && $(if $(ERLANG_MK_COMMIT),git checkout $(ERLANG_MK_COMMIT) &&) $(MAKE) + $(MAKE) -C $(ERLANG_MK_BUILD_DIR) cp $(ERLANG_MK_BUILD_DIR)/erlang.mk ./erlang.mk rm -rf $(ERLANG_MK_BUILD_DIR) diff --git a/core/deps.mk b/core/deps.mk index 76f54d7..16a2f88 100644 --- a/core/deps.mk +++ b/core/deps.mk @@ -43,6 +43,7 @@ export NO_AUTOPATCH # Verbosity. dep_verbose_0 = @echo " DEP " $(1); +dep_verbose_2 = set -x; dep_verbose = $(dep_verbose_$(V)) # Core targets. @@ -62,7 +63,7 @@ endif $(verbose) mkdir -p $(ERLANG_MK_TMP) $(verbose) for dep in $(ALL_DEPS_DIRS) ; do \ if grep -qs ^$$dep$$ $(ERLANG_MK_TMP)/deps.log; then \ - echo -n; \ + :; \ else \ echo $$dep >> $(ERLANG_MK_TMP)/deps.log; \ if [ -f $$dep/GNUmakefile ] || [ -f $$dep/makefile ] || [ -f $$dep/Makefile ]; then \ @@ -81,7 +82,10 @@ endif # While Makefile file could be GNUmakefile or makefile, # in practice only Makefile is needed so far. define dep_autopatch - if [ -f $(DEPS_DIR)/$(1)/Makefile ]; then \ + if [ -f $(DEPS_DIR)/$(1)/erlang.mk ]; then \ + $(call erlang,$(call dep_autopatch_appsrc.erl,$(1))); \ + $(call dep_autopatch_erlang_mk,$(1)); \ + elif [ -f $(DEPS_DIR)/$(1)/Makefile ]; then \ if [ 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 \ @@ -89,12 +93,7 @@ define dep_autopatch elif [ -n "`find $(DEPS_DIR)/$(1)/ -type f -name \*.mk -not -name erlang.mk -exec grep -i rebar '{}' \;`" ]; then \ $(call dep_autopatch2,$(1)); \ else \ - if [ -f $(DEPS_DIR)/$(1)/erlang.mk ]; then \ - $(call erlang,$(call dep_autopatch_appsrc.erl,$(1))); \ - $(call dep_autopatch_erlang_mk,$(1)); \ - else \ - $(call erlang,$(call dep_autopatch_app.erl,$(1))); \ - fi \ + $(call erlang,$(call dep_autopatch_app.erl,$(1))); \ fi \ else \ if [ ! -d $(DEPS_DIR)/$(1)/src/ ]; then \ @@ -106,8 +105,11 @@ define dep_autopatch endef define dep_autopatch2 + if [ -f $(DEPS_DIR)/$1/src/$1.app.src.script ]; then \ + $(call erlang,$(call dep_autopatch_appsrc_script.erl,$(1))); \ + fi; \ $(call erlang,$(call dep_autopatch_appsrc.erl,$(1))); \ - if [ -f $(DEPS_DIR)/$(1)/rebar.config -o -f $(DEPS_DIR)/$(1)/rebar.config.script ]; then \ + if [ -f $(DEPS_DIR)/$(1)/rebar -o -f $(DEPS_DIR)/$(1)/rebar.config -o -f $(DEPS_DIR)/$(1)/rebar.config.script ]; then \ $(call dep_autopatch_fetch_rebar); \ $(call dep_autopatch_rebar,$(1)); \ else \ @@ -127,7 +129,7 @@ define dep_autopatch_erlang_mk endef else define dep_autopatch_erlang_mk - echo -n + : endef endif @@ -179,7 +181,7 @@ define dep_autopatch_rebar.erl file:write_file("$(call core_native_path,$(DEPS_DIR)/$1/Makefile)", Text, [append]) end, Escape = fun (Text) -> - re:replace(Text, "\\\\$$$$", "\$$$$$$$$", [global, {return, list}]) + re:replace(Text, "\\\\$$", "\$$$$", [global, {return, list}]) end, Write("IGNORE_DEPS += edown eper eunit_formatters meck node_package " "rebar_lock_deps_plugin rebar_vsn_plugin reltool_util\n"), @@ -245,67 +247,16 @@ define dep_autopatch_rebar.erl Write(io_lib:format("COMPILE_FIRST +=~s\n", [Names])) end end(), - FindFirst = fun(F, Fd) -> - case io:parse_erl_form(Fd, undefined) of - {ok, {attribute, _, compile, {parse_transform, PT}}, _} -> - [PT, F(F, Fd)]; - {ok, {attribute, _, compile, CompileOpts}, _} when is_list(CompileOpts) -> - case proplists:get_value(parse_transform, CompileOpts) of - undefined -> [F(F, Fd)]; - PT -> [PT, F(F, Fd)] - end; - {ok, {attribute, _, include, Hrl}, _} -> - case file:open("$(call core_native_path,$(DEPS_DIR)/$1/include/)" ++ Hrl, [read]) of - {ok, HrlFd} -> [F(F, HrlFd), F(F, Fd)]; - _ -> - case file:open("$(call core_native_path,$(DEPS_DIR)/$1/src/)" ++ Hrl, [read]) of - {ok, HrlFd} -> [F(F, HrlFd), F(F, Fd)]; - _ -> [F(F, Fd)] - end - end; - {ok, {attribute, _, include_lib, "$(1)/include/" ++ Hrl}, _} -> - {ok, HrlFd} = file:open("$(call core_native_path,$(DEPS_DIR)/$1/include/)" ++ Hrl, [read]), - [F(F, HrlFd), F(F, Fd)]; - {ok, {attribute, _, include_lib, Hrl}, _} -> - case file:open("$(call core_native_path,$(DEPS_DIR)/$1/include/)" ++ Hrl, [read]) of - {ok, HrlFd} -> [F(F, HrlFd), F(F, Fd)]; - _ -> [F(F, Fd)] - end; - {ok, {attribute, _, import, {Imp, _}}, _} -> - case file:open("$(call core_native_path,$(DEPS_DIR)/$1/src/)" ++ atom_to_list(Imp) ++ ".erl", [read]) of - {ok, ImpFd} -> [Imp, F(F, ImpFd), F(F, Fd)]; - _ -> [F(F, Fd)] - end; - {eof, _} -> - file:close(Fd), - []; - _ -> - F(F, Fd) - end - end, - fun() -> - ErlFiles = filelib:wildcard("$(call core_native_path,$(DEPS_DIR)/$1/src/)*.erl"), - First0 = lists:usort(lists:flatten([begin - {ok, Fd} = file:open(F, [read]), - FindFirst(FindFirst, Fd) - end || F <- ErlFiles])), - First = lists:flatten([begin - {ok, Fd} = file:open("$(call core_native_path,$(DEPS_DIR)/$1/src/)" ++ atom_to_list(M) ++ ".erl", [read]), - FindFirst(FindFirst, Fd) - end || M <- First0, lists:member("$(call core_native_path,$(DEPS_DIR)/$1/src/)" ++ atom_to_list(M) ++ ".erl", ErlFiles)]) ++ First0, - Write(["COMPILE_FIRST +=", [[" ", atom_to_list(M)] || M <- First, - lists:member("$(call core_native_path,$(DEPS_DIR)/$1/src/)" ++ atom_to_list(M) ++ ".erl", ErlFiles)], "\n"]) - 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) -> case Cmd of - "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); + "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); _ -> Escape(Cmd) end end, @@ -317,10 +268,10 @@ define dep_autopatch_rebar.erl {'get-deps', Cmd} -> Write("\npre-deps::\n\t" ++ PatchHook(Cmd) ++ "\n"); {compile, Cmd} -> - Write("\npre-app::\n\tCC=$$$$\(CC) " ++ PatchHook(Cmd) ++ "\n"); + Write("\npre-app::\n\tCC=$$\(CC) " ++ PatchHook(Cmd) ++ "\n"); {Regex, compile, Cmd} -> case rebar_utils:is_arch(Regex) of - true -> Write("\npre-app::\n\tCC=$$$$\(CC) " ++ PatchHook(Cmd) ++ "\n"); + true -> Write("\npre-app::\n\tCC=$$\(CC) " ++ PatchHook(Cmd) ++ "\n"); false -> ok end; _ -> ok @@ -328,7 +279,7 @@ define dep_autopatch_rebar.erl end end(), ShellToMk = fun(V) -> - re:replace(re:replace(V, "(\\\\$$$$)(\\\\w*)", "\\\\1(\\\\2)", [global]), + re:replace(re:replace(V, "(\\\\$$)(\\\\w*)", "\\\\1(\\\\2)", [global]), "-Werror\\\\b", "", [{return, list}, global]) end, PortSpecs = fun() -> @@ -362,10 +313,10 @@ define dep_autopatch_rebar.erl case PortSpecs of [] -> ok; _ -> - Write("\npre-app::\n\t$$$$\(MAKE) -f c_src/Makefile.erlang.mk\n"), - PortSpecWrite(io_lib:format("ERL_CFLAGS = -finline-functions -Wall -fPIC -I ~s/erts-~s/include -I ~s\n", + Write("\npre-app::\n\t$$\(MAKE) -f c_src/Makefile.erlang.mk\n"), + PortSpecWrite(io_lib:format("ERL_CFLAGS = -finline-functions -Wall -fPIC -I \\"~s/erts-~s/include\\" -I \\"~s\\"\n", [code:root_dir(), erlang:system_info(version), code:lib_dir(erl_interface, include)])), - PortSpecWrite(io_lib:format("ERL_LDFLAGS = -L ~s -lerl_interface -lei\n", + PortSpecWrite(io_lib:format("ERL_LDFLAGS = -L \\"~s\\" -lerl_interface -lei\n", [code:lib_dir(erl_interface, lib)])), [PortSpecWrite(["\n", E, "\n"]) || E <- OsEnv], FilterEnv = fun(Env) -> @@ -400,17 +351,18 @@ define dep_autopatch_rebar.erl _ -> "" end, "\n\nall:: ", Output, "\n\n", - "%.o: %.c\n\t$$$$\(CC) -c -o $$$$\@ $$$$\< $$$$\(CFLAGS) $$$$\(ERL_CFLAGS) $$$$\(DRV_CFLAGS) $$$$\(EXE_CFLAGS)\n\n", - "%.o: %.C\n\t$$$$\(CXX) -c -o $$$$\@ $$$$\< $$$$\(CXXFLAGS) $$$$\(ERL_CFLAGS) $$$$\(DRV_CFLAGS) $$$$\(EXE_CFLAGS)\n\n", - "%.o: %.cc\n\t$$$$\(CXX) -c -o $$$$\@ $$$$\< $$$$\(CXXFLAGS) $$$$\(ERL_CFLAGS) $$$$\(DRV_CFLAGS) $$$$\(EXE_CFLAGS)\n\n", - "%.o: %.cpp\n\t$$$$\(CXX) -c -o $$$$\@ $$$$\< $$$$\(CXXFLAGS) $$$$\(ERL_CFLAGS) $$$$\(DRV_CFLAGS) $$$$\(EXE_CFLAGS)\n\n", + "%.o: %.c\n\t$$\(CC) -c -o $$\@ $$\< $$\(CFLAGS) $$\(ERL_CFLAGS) $$\(DRV_CFLAGS) $$\(EXE_CFLAGS)\n\n", + "%.o: %.C\n\t$$\(CXX) -c -o $$\@ $$\< $$\(CXXFLAGS) $$\(ERL_CFLAGS) $$\(DRV_CFLAGS) $$\(EXE_CFLAGS)\n\n", + "%.o: %.cc\n\t$$\(CXX) -c -o $$\@ $$\< $$\(CXXFLAGS) $$\(ERL_CFLAGS) $$\(DRV_CFLAGS) $$\(EXE_CFLAGS)\n\n", + "%.o: %.cpp\n\t$$\(CXX) -c -o $$\@ $$\< $$\(CXXFLAGS) $$\(ERL_CFLAGS) $$\(DRV_CFLAGS) $$\(EXE_CFLAGS)\n\n", [[Output, ": ", K, " = ", ShellToMk(V), "\n"] || {K, V} <- lists:reverse(MergeEnv(FilterEnv(Env)))], - Output, ": $$$$\(foreach ext,.c .C .cc .cpp,", - "$$$$\(patsubst %$$$$\(ext),%.o,$$$$\(filter %$$$$\(ext),$$$$\(wildcard", Input, "))))\n", - "\t$$$$\(CC) -o $$$$\@ $$$$\? $$$$\(LDFLAGS) $$$$\(ERL_LDFLAGS) $$$$\(DRV_LDFLAGS) $$$$\(EXE_LDFLAGS)", - case filename:extension(Output) of - [] -> "\n"; - _ -> " -shared\n" + Output, ": $$\(foreach ext,.c .C .cc .cpp,", + "$$\(patsubst %$$\(ext),%.o,$$\(filter %$$\(ext),$$\(wildcard", Input, "))))\n", + "\t$$\(CC) -o $$\@ $$\? $$\(LDFLAGS) $$\(ERL_LDFLAGS) $$\(DRV_LDFLAGS) $$\(EXE_LDFLAGS)", + case {filename:extension(Output), $(PLATFORM)} of + {[], _} -> "\n"; + {_, darwin} -> "\n"; + _ -> " -shared\n" end]) end, [PortSpec(S) || S <- PortSpecs] @@ -469,7 +421,7 @@ define dep_autopatch_app.erl false -> ok; true -> {ok, [{application, '$(1)', L0}]} = file:consult(App), - Mods = filelib:fold_files("$(call core_native_path,$(DEPS_DIR)/$1/src)", "\\\\.erl$$$$", true, + Mods = filelib:fold_files("$(call core_native_path,$(DEPS_DIR)/$1/src)", "\\\\.erl$$", true, fun (F, Acc) -> [list_to_atom(filename:rootname(filename:basename(F)))|Acc] end, []), L = lists:keystore(modules, 1, L0, {modules, Mods}), ok = file:write_file(App, io_lib:format("~p.~n", [{application, '$(1)', L}])) @@ -479,6 +431,15 @@ define dep_autopatch_app.erl halt() endef +define dep_autopatch_appsrc_script.erl + AppSrc = "$(call core_native_path,$(DEPS_DIR)/$1/src/$1.app.src)", + AppSrcScript = AppSrc ++ ".script", + Bindings = erl_eval:new_bindings(), + {ok, Conf} = file:script(AppSrcScript, Bindings), + ok = file:write_file(AppSrc, io_lib:format("~p.~n", [Conf])), + halt() +endef + define dep_autopatch_appsrc.erl 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, @@ -565,10 +526,11 @@ $(DEPS_DIR)/$(call dep_name,$1): exit 17; \ fi $(verbose) mkdir -p $(DEPS_DIR) - $(dep_verbose) $(call dep_fetch_$(strip $(call dep_fetch,$1)),$1) - $(verbose) if [ -f $(DEPS_DIR)/$(DEP_NAME)/configure.ac -o -f $(DEPS_DIR)/$(DEP_NAME)/configure.in ]; then \ - echo " AUTO " $(DEP_STR); \ - cd $(DEPS_DIR)/$(DEP_NAME) && autoreconf -Wall -vif -I m4; \ + $(dep_verbose) $(call dep_fetch_$(strip $(call dep_fetch,$(1))),$(1)) + $(verbose) if [ -f $(DEPS_DIR)/$(1)/configure.ac -o -f $(DEPS_DIR)/$(1)/configure.in ] \ + && [ ! -f $(DEPS_DIR)/$(1)/configure ]; then \ + echo " AUTO " $(1); \ + cd $(DEPS_DIR)/$(1) && autoreconf -Wall -vif -I m4; \ fi - $(verbose) if [ -f $(DEPS_DIR)/$(DEP_NAME)/configure ]; then \ echo " CONF " $(DEP_STR); \ @@ -591,7 +553,7 @@ ifeq ($(filter $(1),$(NO_AUTOPATCH)),) git clone https://github.com/rabbitmq/rabbitmq-codegen.git $(DEPS_DIR)/rabbitmq-codegen; \ fi \ else \ - $(call dep_autopatch,$(DEP_NAME)) \ + $$(call dep_autopatch,$(DEP_NAME)) \ fi endif endef diff --git a/core/erlc.mk b/core/erlc.mk index 02524b4..695cc83 100644 --- a/core/erlc.mk +++ b/core/erlc.mk @@ -19,25 +19,32 @@ COMPILE_MIB_FIRST_PATHS = $(addprefix mibs/,$(addsuffix .mib,$(COMPILE_MIB_FIRST # Verbosity. app_verbose_0 = @echo " APP " $(PROJECT); +app_verbose_2 = set -x; app_verbose = $(app_verbose_$(V)) appsrc_verbose_0 = @echo " APP " $(PROJECT).app.src; +appsrc_verbose_2 = set -x; appsrc_verbose = $(appsrc_verbose_$(V)) makedep_verbose_0 = @echo " DEPEND" $(PROJECT).d; +makedep_verbose_2 = set -x; makedep_verbose = $(makedep_verbose_$(V)) erlc_verbose_0 = @echo " ERLC " $(filter-out $(patsubst %,%.erl,$(ERLC_EXCLUDE)),\ $(filter %.erl %.core,$(?F))); +erlc_verbose_2 = set -x; erlc_verbose = $(erlc_verbose_$(V)) xyrl_verbose_0 = @echo " XYRL " $(filter %.xrl %.yrl,$(?F)); +xyrl_verbose_2 = set -x; xyrl_verbose = $(xyrl_verbose_$(V)) asn1_verbose_0 = @echo " ASN1 " $(filter %.asn1,$(?F)); +asn1_verbose_2 = set -x; asn1_verbose = $(asn1_verbose_$(V)) mib_verbose_0 = @echo " MIB " $(filter %.bin %.mib,$(?F)); +mib_verbose_2 = set -x; mib_verbose = $(mib_verbose_$(V)) ifneq ($(wildcard src/),) @@ -45,10 +52,10 @@ ifneq ($(wildcard src/),) # Targets. ifeq ($(wildcard ebin/test),) -app:: $(PROJECT).d +app:: deps $(PROJECT).d $(verbose) $(MAKE) --no-print-directory app-build else -app:: clean $(PROJECT).d +app:: clean deps $(PROJECT).d $(verbose) $(MAKE) --no-print-directory app-build endif @@ -78,7 +85,7 @@ endef endif app-build: ebin/$(PROJECT).app - $(verbose) echo -n + $(verbose) : # Source files. @@ -130,51 +137,79 @@ $(PROJECT).d:: $(XRL_FILES) $(YRL_FILES) # Erlang and Core Erlang files. define makedep.erl + E = ets:new(makedep, [bag]), + G = digraph:new([acyclic]), ErlFiles = lists:usort(string:tokens("$(ERL_FILES)", " ")), - Modules = [{filename:basename(F, ".erl"), F} || F <- ErlFiles], - Add = fun (Dep, Acc) -> - case lists:keyfind(atom_to_list(Dep), 1, Modules) of - {_, DepFile} -> [DepFile|Acc]; - false -> Acc + 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) end end, - AddHd = fun (Dep, Acc) -> - case {Dep, lists:keymember(Dep, 2, Modules)} of - {"src/" ++ _, false} -> [Dep|Acc]; - {"include/" ++ _, false} -> [Dep|Acc]; - _ -> Acc + AddHd = fun (F, Mod, DepFile) -> + case file:open(DepFile, [read]) of + {error, enoent} -> ok; + {ok, Fd} -> + F(F, Fd, Mod), + {_, ModFile} = lists:keyfind(Mod, 1, Modules), + ets:insert(E, {ModFile, DepFile}) end end, - CompileFirst = fun (Deps) -> - First0 = [case filename:extension(D) of - ".erl" -> filename:basename(D, ".erl"); - _ -> [] - end || D <- Deps], - case lists:usort(First0) of - [] -> []; - [[]] -> []; - First -> ["COMPILE_FIRST +=", [[" ", F] || F <- First], "\n"] - end + Attr = fun + (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) -> + case proplists:get_value(parse_transform, Opts) of + undefined -> ok; + Dep -> Add(Mod, Dep) + end; + (F, Mod, include, Hrl) -> + case filelib:is_file("include/" ++ Hrl) of + true -> AddHd(F, Mod, "include/" ++ Hrl); + false -> + case filelib:is_file("src/" ++ Hrl) of + true -> AddHd(F, Mod, "src/" ++ Hrl); + false -> false + end + end; + (F, Mod, include_lib, "$1/include/" ++ Hrl) -> AddHd(F, Mod, "include/" ++ Hrl); + (F, Mod, include_lib, Hrl) -> AddHd(F, Mod, "include/" ++ Hrl); + (F, Mod, import, {Imp, _}) -> + case filelib:is_file("src/" ++ atom_to_list(Imp) ++ ".erl") of + false -> ok; + true -> Add(Mod, Imp) + end; + (_, _, _, _) -> ok end, - Depend = [begin - case epp:parse_file(F, ["include/"], []) of - {ok, Forms} -> - Deps = lists:usort(lists:foldl(fun - ({attribute, _, behavior, Dep}, Acc) -> Add(Dep, Acc); - ({attribute, _, behaviour, Dep}, Acc) -> Add(Dep, Acc); - ({attribute, _, compile, {parse_transform, Dep}}, Acc) -> Add(Dep, Acc); - ({attribute, _, file, {Dep, _}}, Acc) -> AddHd(Dep, Acc); - (_, Acc) -> Acc - end, [], Forms)), - case Deps of - [] -> ""; - _ -> [F, "::", [[" ", D] || D <- Deps], "; @touch \$$@\n", CompileFirst(Deps)] - end; - {error, enoent} -> - [] + MakeDepend = fun(F, Fd, Mod) -> + case io:parse_erl_form(Fd, undefined) of + {ok, {attribute, _, Key, Value}, _} -> + Attr(F, Mod, Key, Value), + F(F, Fd, Mod); + {eof, _} -> + file:close(Fd); + _ -> + F(F, Fd, Mod) end + end, + [begin + Mod = list_to_atom(filename:basename(F, ".erl")), + {ok, Fd} = file:open(F, [read]), + MakeDepend(MakeDepend, Fd, Mod) end || F <- ErlFiles], - ok = file:write_file("$(1)", Depend), + 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)], + ok = file:write_file("$(1)", [ + [[F, "::", [[" ", D] || D <- Deps], "; @touch \$$@\n"] || {F, Deps} <- Depend], + "\nCOMPILE_FIRST +=", [[" ", atom_to_list(CF)] || CF <- CompileFirst], "\n" + ]), halt() endef @@ -209,13 +244,13 @@ ifeq ($(wildcard src/$(PROJECT).app.src),) $(app_verbose) printf "$(subst $(newline),\n,$(subst ",\",$(call app_file,$(GITDESCRIBE),$(MODULES))))" \ > ebin/$(PROJECT).app else - $(verbose) if [ -z "$$(grep -E '^[^%]*{\s*modules\s*,' src/$(PROJECT).app.src)" ]; then \ + $(verbose) if [ -z "$$(grep -e '^[^%]*{\s*modules\s*,' src/$(PROJECT).app.src)" ]; then \ echo "Empty modules entry not found in $(PROJECT).app.src. Please consult the erlang.mk README for instructions." >&2; \ exit 1; \ fi $(appsrc_verbose) cat src/$(PROJECT).app.src \ | sed "s/{[[:space:]]*modules[[:space:]]*,[[:space:]]*\[\]}/{modules, \[$(call comma_list,$(MODULES))\]}/" \ - | sed "s/{id,[[:space:]]*\"git\"}/{id, \"$(GITDESCRIBE)\"}/" \ + | sed "s/{id,[[:space:]]*\"git\"}/{id, \"$(subst /,\/,$(GITDESCRIBE))\"}/" \ > ebin/$(PROJECT).app endif diff --git a/core/test.mk b/core/test.mk index d7b0bfe..12ff208 100644 --- a/core/test.mk +++ b/core/test.mk @@ -29,6 +29,11 @@ test-dir: $(call core_find,$(TEST_DIR)/,*.erl) -pa ebin/ endif +ifeq ($(wildcard src),) +test-build:: ERLC_OPTS=$(TEST_ERLC_OPTS) +test-build:: clean deps test-deps + $(verbose) $(MAKE) --no-print-directory test-dir ERLC_OPTS="$(TEST_ERLC_OPTS)" +else ifeq ($(wildcard ebin/test),) test-build:: ERLC_OPTS=$(TEST_ERLC_OPTS) test-build:: clean deps test-deps $(PROJECT).d @@ -46,3 +51,4 @@ clean-test-dir: ifneq ($(wildcard $(TEST_DIR)/*.beam),) $(gen_verbose) rm -f $(TEST_DIR)/*.beam endif +endif diff --git a/doc/src/guide/app.asciidoc b/doc/src/guide/app.asciidoc index 1320577..99ff052 100644 --- a/doc/src/guide/app.asciidoc +++ b/doc/src/guide/app.asciidoc @@ -1,3 +1,4 @@ +[[building]] == Building Erlang.mk can do a lot of things, but it is, first and @@ -5,7 +6,7 @@ foremost, a build tool. In this chapter we will cover the basics of building a project with Erlang.mk. For most of this chapter, we will assume that you are -using a project link:getting_started.asciidoc[generated by Erlang.mk]. +using a project xref:getting_started[generated by Erlang.mk]. === How to build @@ -46,13 +47,18 @@ up generating releases. ==== Application -You can build your application specifically, without -looking at handling dependencies or generating a release, -by running the following command: +You can build your application and dependencies without +generating a release by running the following command: [source,bash] $ make app +To build your application without touching dependencies +at all, you can use the `SKIP_DEPS` variable: + +[source,bash] +$ make app SKIP_DEPS=1 + This command is very useful if you have a lot of dependencies and develop on a machine with slow file access, like the Raspberry Pi and many other embedded devices. @@ -71,27 +77,26 @@ $ make deps This will fetch and compile all dependencies and their dependencies, recursively. -link:deps.asciidoc[Packages and dependencies] are covered +xref:deps[Packages and dependencies] are covered in the next chapter. ==== Release -You can generate the release, skipping the steps for building -the application and dependencies, by running the following -command: +It is not possible to build the release without at least +building the application itself, unless of course if there's +no application to begin with. + +To generate the release, `make` will generally suffice with +a normal Erlang.mk. A separate target is however available, +and will take care of building the release, after building +the application and all dependencies: [source,bash] $ make rel -This command can be useful if nothing changed except the -release configuration files. - -Consult the link:relx.asciidoc[Releases] chapter for more +Consult the xref:relx[Releases] chapter for more information about what releases are and how they are generated. -Note that this command may fail if a required dependency -is missing. - === Application resource file When building your application, Erlang.mk will generate the @@ -147,7 +152,7 @@ DEPS = cowlib ranch Any space before and after the value is dropped. -link:deps.asciidoc[Dependencies] are covered in details in +xref:deps[Dependencies] are covered in details in the next chapter. ==== Legacy method @@ -220,7 +225,7 @@ then built normally. In addition, Erlang.mk keeps track of header files (`.hrl`) as described at the end of this chapter. It can also compile -C code, as described in the link:ports.asciidoc[NIFs and port drivers] +C code, as described in the xref:ports[NIFs and port drivers] chapter. Erlang.mk also comes with plugins for the following formats: diff --git a/doc/src/guide/architecture.asciidoc b/doc/src/guide/architecture.asciidoc deleted file mode 100644 index f96606b..0000000 --- a/doc/src/guide/architecture.asciidoc +++ /dev/null @@ -1,5 +0,0 @@ -== Architecture - -// @todo Write it. - -Placeholder chapter. diff --git a/doc/src/guide/asciidoc.asciidoc b/doc/src/guide/asciidoc.asciidoc index 6ba43ec..cc8336b 100644 --- a/doc/src/guide/asciidoc.asciidoc +++ b/doc/src/guide/asciidoc.asciidoc @@ -1,5 +1,82 @@ -== Asciidoc documentation +[[asciidoc]] +== AsciiDoc documentation -// @todo Write it. +Erlang.mk provides rules for generating documentation from +AsciiDoc files. It can automatically build a user guide PDF, +chunked HTML documentation and Unix manual pages. -Placeholder chapter. +=== Requirements + +It is necessary to have http://asciidoc.org/[AsciiDoc], +http://xmlsoft.org/XSLT/xsltproc2.html[xsltproc] and +http://dblatex.sourceforge.net/[dblatex] installed on your +system for Erlang.mk to generate documentation from AsciiDoc sources. + +=== Writing AsciiDoc documentation + +http://asciidoc.org/[AsciiDoc] is a text document format for +writing notes, documentation, articles, books, ebooks, slideshows, +web pages, man pages and blogs. AsciiDoc files can be translated +to many formats including HTML, PDF, EPUB, man page. + +The http://asciidoc.org/userguide.html[AsciiDoc user guide] +describes the AsciiDoc syntax. + +The https://github.com/ninenines/erlang.mk/tree/master/doc/src/guide[Erlang.mk user guide] +is written in AsciiDoc and can be used as an example. The entry +file is https://github.com/ninenines/erlang.mk/blob/master/doc/src/guide/book.asciidoc[book.asciidoc]. + +Erlang.mk expects you to put your documentation in a specific +location. This is 'doc/src/guide/' for the user guide, and +'doc/src/manual/' for the function reference. In the case of +the user guide, the entry point is always 'doc/src/guide/book.asciidoc'. + +For manual pages, it is good practice to use section 3 for +modules, and section 7 for the application itself. + +=== Configuration + +All of the AsciiDoc related configuration can be done directly +inside the files themselves. + +=== Usage + +To build all documentation: + +[source,bash] +$ make docs + +To build only the AsciiDoc documentation: + +[source,bash] +$ make asciidoc + +To build only the user guide: + +[source,bash] +$ make asciidoc-guide + +To build only the manual: + +[source,bash] +$ make asciidoc-manual + +To install man pages on Unix: + +[source,bash] +$ make install-docs + +Erlang.mk allows customizing the installation path and sections +of the man pages to be installed. The `MAN_INSTALL_PATH` variable +defines where man pages will be installed. It defaults to +'/usr/local/share/man'. The `MAN_SECTIONS` variable defines +which manual sections are to be installed. It defaults to `3 7`. + +To install man pages to a custom location: + +[source,bash] +$ make install-docs MAN_INSTALL_PATH=/opt/share/man + +Note that you may need to run the install commands using +`sudo` or equivalent if the location is not writeable by +your user. diff --git a/doc/src/guide/book.asciidoc b/doc/src/guide/book.asciidoc index f084e6f..a39b907 100644 --- a/doc/src/guide/book.asciidoc +++ b/doc/src/guide/book.asciidoc @@ -1,4 +1,5 @@ // a2x: --dblatex-opts "-P latex.output.revhistory=0 -P doc.publisher.show=0 -P index.numbered=0" +// a2x: --xsltproc-opts "--stringparam use.id.as.filename 1" // a2x: -d book --attribute tabsize=4 = Erlang.mk User Guide @@ -14,6 +15,7 @@ include::updating.asciidoc[Updating Erlang.mk] include::limitations.asciidoc[Limitations] +[[code]] = Code include::app.asciidoc[Building] @@ -28,12 +30,14 @@ include::escripts.asciidoc[Escripts] include::compat.asciidoc[Compatibility with other build tools] +[[docs]] = Documentation include::asciidoc.asciidoc[Asciidoc documentation] include::edoc.asciidoc[EDoc comments] +[[tests]] = Tests include::shell.asciidoc[Erlang shell] @@ -42,8 +46,6 @@ include::eunit.asciidoc[EUnit] include::common_test.asciidoc[Common Test] -include::property_based_testing.asciidoc[Property based testing] - include::coverage.asciidoc[Code coverage] include::ci.asciidoc[Continuous integration] @@ -52,16 +54,18 @@ include::dialyzer.asciidoc[Dialyzer] include::xref.asciidoc[Xref] +[[plugins]] = Third-party plugins include::external_plugins.asciidoc[External plugins] +include::external_plugins_list.asciidoc[List of plugins] + +[[about]] = About Erlang.mk include::why.asciidoc[Why erlang.mk?] include::history.asciidoc[Short history] -include::architecture.asciidoc[Architecture] - include::contributing.asciidoc[Contributing] diff --git a/doc/src/guide/ci.asciidoc b/doc/src/guide/ci.asciidoc index 8a96ed4..24cfc05 100644 --- a/doc/src/guide/ci.asciidoc +++ b/doc/src/guide/ci.asciidoc @@ -1,3 +1,4 @@ +[[ci]] == Continuous integration // @todo Write it. diff --git a/doc/src/guide/common_test.asciidoc b/doc/src/guide/common_test.asciidoc index 7daeae5..aec8747 100644 --- a/doc/src/guide/common_test.asciidoc +++ b/doc/src/guide/common_test.asciidoc @@ -1,5 +1,91 @@ +[[ct]] == Common Test -// @todo Write it. +Common Test is Erlang's functional testing framework. +Erlang.mk automates the discovery and running of Common +Test suites. -Placeholder chapter. +=== Writing tests + +The http://www.erlang.org/doc/apps/common_test/write_test_chapter.html[Common Test user guide] +is the best place to learn how to write tests. Erlang.mk +requires that file names for test suites end with '_SUITE.erl' +and that the files be located in the '$(TEST_DIR)' directory. +This defaults to 'test/'. + +=== Configuration + +The `CT_OPTS` variable allows you to set extra Common Test +options. Options are documented in the +http://www.erlang.org/doc/apps/common_test/run_test_chapter.html[Common Test user guide]. +You can use it to set Common Test hooks, for example: + +[source,make] +CT_OPTS = -ct_hooks cowboy_ct_hook + +The `CT_SUITES` variable can be used to override what +Common Test suites Erlang.mk will be aware of. It does +not normally need to be set as Erlang.mk will find the +test suites automatically. + +The name of the suite is the part before `_SUITE.erl`. +If the file is named 'http_SUITE.erl', the test suite +is `http`: + +[source,make] +CT_SUITES = http ws + +=== Usage + +To run all tests (including Common Test): + +[source,bash] +$ make tests + +To run all tests and static checks (including Common Test): + +[source,bash] +$ make check + +You can also run Common Test separately: + +[source,bash] +$ make ct + +Erlang.mk will create targets for all test suites it finds. +If you have a file named 'test/http_SUITE.erl', then the +target `ct-http` will run that specific test suite: + +[source,bash] +$ make ct-http + +Erlang.mk provides a convenient way to run a specific +group or a specific test case within a specific group, +using the variable `t`. Note that this only applies to +suite-specific targets, like the `ct-http` example above. + +To run all tests from the `http_compress` group in the +`http_SUITE` test suite, write: + +[source,bash] +$ make ct-http t=http_compress + +Similarly, to run a specific test case in that group: + +[source,bash] +$ make ct-http t=http_compress:headers_dupe + +To do the same against a multi-application repository, +you can use the `-C` option: + +[source,bash] +$ make -C apps/my_app ct-http t=my_group:my_case + +Note that this also applies to dependencies. When using Cowboy +as a dependency, you can run the following directly: + +[source,bash] +$ make -C deps/cowboy ct-http t=http_compress + +Finally, xref:coverage[code coverage] is available, +but covered in its own chapter. diff --git a/doc/src/guide/compat.asciidoc b/doc/src/guide/compat.asciidoc index 61386e7..8c8f935 100644 --- a/doc/src/guide/compat.asciidoc +++ b/doc/src/guide/compat.asciidoc @@ -1,3 +1,4 @@ +[[compat]] == Compatibility with other build tools Erlang.mk tries its best to be compatible with the other Erlang @@ -20,7 +21,7 @@ and adds a Makefile to the project that Erlang.mk can then use for building: _Autoload_ is documented in more details in the -link:deps.asciidoc[Packages and dependencies] chapter. +xref:deps[Packages and dependencies] chapter. === Erlang.mk projects as Rebar dependencies @@ -49,11 +50,12 @@ the `DEPS` and `ERLC_OPTS` variables, among others. This means that the Rebar family builds your project much the same way as Erlang.mk. +// @todo Sanity check chapter. Careful though! Different build tools have different fetching strategies. If some applications provide differing dependencies, they might be fetched differently by other build tools. Check -the link:sanity_check.asciidoc[Sanity check] chapter to find -out how to detect such issues. +the upcoming Sanity check chapter to find out how to detect such +issues. You can automatically generate this file when you build your application, by making it a dependency of the `app` diff --git a/doc/src/guide/contributing.asciidoc b/doc/src/guide/contributing.asciidoc index e712788..58e5de6 100644 --- a/doc/src/guide/contributing.asciidoc +++ b/doc/src/guide/contributing.asciidoc @@ -1,5 +1,116 @@ +[[contributing]] == Contributing -// @todo Write it. +You are welcome and encouraged to contribute. -Placeholder chapter. +This is how. + +=== Priorities + +From the most important to the least important: + +* Bugs +* Package issues/additions +* Refactoring +* Features + +=== Bugs + +If you have found a bug, you should open a ticket. Include +everything relevant including the command you used, output, +a link to the code that triggers the issue, why you think +this is a bug, etc. + +If you think you have found a bug but you are not sure, you +should open a ticket as previously explained. + +If you have found a bug and you need it to be solved RIGHT +NOW, open a ticket as previously explained. + +Once you have opened a ticket, be patient, try to answer +questions in a timely manner and confirm that the bug was +indeed fixed when it is. + +If you can't be patient, either try to solve the bug and +contribute the fix back or become a paying customer. + +=== Code + +The code is located in the 'core/\*.mk' and 'plugins/\*.mk' files. +The tests are located in the 'test/Makefile' and 'test/*.mk' files. + +If you have a fix or a hack for a bug, you should open a +pull request. Any fix should include a test case that fails +before the fix and is working after. + +If you have a test case that reproduces a bug, but no fix for +it, you should open a pull request. + +Changes need to be tested with at least the `make check` +command. A specific test case can be tested using `make check c=CASE` +with `CASE` the name of the target to run. Output can be +modulated using the `V` variable, which is an integer +from 0 to 4. A typical use would be `make check c=dialyzer V=3`. +The value 4 is particular and shows expanded commands right +before they are executed. + +To run tests in parallel, use the `-j` option. It is generally +a good idea to also use the `-k` option to run all tests even +if one fails. For example: `make check -j 32 -k`. + +Some changes should be tested against all packages. Continue +reading for more details on testing them. + +=== Packages + +You can search existing packages using the `make search q=STRING` +command. This can be done both from an Erlang.mk project or +directly from the Erlang.mk repository. + +Packages can be added to the index using the `pkg_add.sh` script. + +[source,bash] +---- +$ git clone https://github.com/$YOURUSERNAME/erlang.mk +$ cd erlang.mk +$ ./pkg_add.sh cowboy git https://github.com/ninenines/cowboy 1.0.0 + http://ninenines.eu "Small, fast and modular HTTP server." +$ git push origin master +---- + +Before sending a pull request, you should test your package. +You can use the following command: `make check p=PACKAGE`, +where `PACKAGE` is the name of the package, for example +`cowboy`. + +To test all packages, the `make packages` command can be used. +This can take a long time. Some packages will fail with certain +versions of Erlang, or if a prerequisite is missing from your system. +You can of course speed things up using the `-j` and `-k` flags. + +After all packages have been tested, you can run the command +`make summary` to know what changed since the previous run. + +=== Documentation + +The documentation is always right. + +If you think you have found a mistake in the documentation, +this is a bug. You can either open a ticket or send a pull +request. + +To make sure that the documentation changes work, install +the listed xref:asciidoc[Requirements] on your system and +run `make docs`. + +=== Feature requests + +If you have an awesome idea or need something that Erlang.mk +doesn't provide yet, open a ticket. Provide as much detail as +possible. + +If you have code, great! Open a pull request as previously +explained. + +If not, you can still improve your feature request by writing +the related documentation. diff --git a/doc/src/guide/coverage.asciidoc b/doc/src/guide/coverage.asciidoc index 5e74f36..f33f878 100644 --- a/doc/src/guide/coverage.asciidoc +++ b/doc/src/guide/coverage.asciidoc @@ -1,3 +1,4 @@ +[[coverage]] == Code coverage // @todo Write it. diff --git a/doc/src/guide/deps.asciidoc b/doc/src/guide/deps.asciidoc index 9335439..eb6f2f0 100644 --- a/doc/src/guide/deps.asciidoc +++ b/doc/src/guide/deps.asciidoc @@ -1,3 +1,4 @@ +[[deps]] == Packages and dependencies Erlang.mk can fetch and compile the dependencies that your @@ -72,7 +73,7 @@ dep_leveldb = git https://github.com/basho/leveldb 2.1.3 This dependency will be built before your application, so you could easily copy the resulting shared file into your 'priv/' directory as part of the build process. More information -about that in the link:ports.asciidoc[NIFs and port drivers] +about that in the xref:ports[NIFs and port drivers] chapter. Another variable, `LOCAL_DEPS`, allows specifying runtime @@ -333,7 +334,7 @@ Erlang.mk will also export the `REBAR_DEPS_DIR` variable for compatibility with Rebar build tools, as long as they are recent enough. -=== Dependencies local to the repository +=== Many applications in one repository In addition to the dependencies that are fetched, Erlang.mk also allows you to have dependencies local to your repository. diff --git a/doc/src/guide/dialyzer.asciidoc b/doc/src/guide/dialyzer.asciidoc index 7377c82..58fe53f 100644 --- a/doc/src/guide/dialyzer.asciidoc +++ b/doc/src/guide/dialyzer.asciidoc @@ -1,5 +1,73 @@ +[[dialyzer]] == Dialyzer -// @todo Write it. +Dialyzer is a tool that will detect discrepancies in your +program. It does so using a technique known as success +typing analysis which has the advantage of providing no +false positives. Dialyzer is able to detect type errors, +dead code and more. -Placeholder chapter. +Erlang.mk provides a wrapper around Dialyzer. + +=== How it works + +Dialyzer requires a PLT file to work. The PLT file contains +the analysis information from all applications which are not +expected to change, or rarely do. These would be all the +dependencies of the application or applications you are +currently working on, including standard applications in +Erlang/OTP itself. + +Dialyzer can generate this PLT file. Erlang.mk includes rules +to automatically generate the PLT file when it is missing. + +Once the PLT file is generated, Dialyzer can perform the +analysis in record time. + +=== Configuration + +In a typical usage scenario, no variable needs to be set. +The defaults should be enough. Do note however that the +dependencies need to be set properly using the `DEPS` and +`LOCAL_DEPS` variables. + +The `DIALYZER_PLT` file indicates where the PLT file will +be written to (and read from). By default this is +'$(PROJECT).plt' in the project's directory. Note that +the `DIALYZER_PLT` variable is exported and is understood +by Dialyzer directly. + +The `PLT_APPS` variable can be used to add additional +applications to the PLT. You can either list application +names or paths to these applications. + +Erlang.mk defines two variables for specifying options +for the analysis: `DIALYZER_DIRS` and `DIALYZER_OPTS`. +The former one defines which directories should be part +of the analysis. The latter defines what extra warnings +Dialyzer should report. + +Note that Erlang.mk enables the race condition warnings +by default. As it can take considerably large resources +to run, you may want to disable it on larger projects. + +=== Usage + +To perform an analysis, run the following command: + +[source,bash] +$ make dialyze + +This will create the PLT file if it doesn't exist. + +The analysis will also be performed when you run the +following command, alongside tests: + +[source,bash] +$ make check + +You can use the `plt` target to create the PLT file if +it doesn't exist. This is normally not necessary as +Dialyzer creates it automatically. + +The PLT file will be removed when you run `make distclean`. diff --git a/doc/src/guide/edoc.asciidoc b/doc/src/guide/edoc.asciidoc index f54d447..9fc1a74 100644 --- a/doc/src/guide/edoc.asciidoc +++ b/doc/src/guide/edoc.asciidoc @@ -1,5 +1,48 @@ +[[edoc]] == EDoc comments -// @todo Write it. +Erlang.mk provides a thin wrapper on top of EDoc, an application +that generates documentation based on comments found in modules. -Placeholder chapter. +=== Writing EDoc comments + +The http://www.erlang.org/doc/apps/edoc/chapter.html[EDoc user guide] +explains everything you need to know about EDoc comments. + +=== Configuration + +The `EDOC_OPTS` variable allows you to specify additional +EDoc options. Options are documented in the +http://www.erlang.org/doc/man/edoc.html#run-2[EDoc manual]. + +A common use for this variable is to enable Markdown in doc +comments, using the `edown` application: + +[source,make] +DOC_DEPS = edown +EDOC_OPTS = {doclet, edown_doclet} + +=== Usage + +To build all documentation, you would typically use: + +[source,bash] +$ make docs + +Do note, however, that EDoc comments will only be generated +automatically if the 'doc/overview.edoc' file exists. If you +do not want that file and still want to generate doc comments, +two solutions are available. + +You can generate EDoc documentation directly: + +[source,bash] +$ make edoc + +You can enable automatic generation on `make docs` by adding +the following to your Makefile: + +[source,make] +---- +docs:: edoc +---- diff --git a/doc/src/guide/escripts.asciidoc b/doc/src/guide/escripts.asciidoc index fcc6080..3d68c77 100644 --- a/doc/src/guide/escripts.asciidoc +++ b/doc/src/guide/escripts.asciidoc @@ -1,3 +1,4 @@ +[[escript]] == Escripts // @todo Write it. diff --git a/doc/src/guide/eunit.asciidoc b/doc/src/guide/eunit.asciidoc index 1a16776..496b674 100644 --- a/doc/src/guide/eunit.asciidoc +++ b/doc/src/guide/eunit.asciidoc @@ -1,5 +1,122 @@ +[[eunit]] == EUnit -// @todo Write it. +EUnit is the tool of choice for unit testing. Erlang.mk +automates a few things on top of EUnit, including the +discovery and running of unit tests. -Placeholder chapter. +=== Writing tests + +The http://www.erlang.org/doc/apps/eunit/chapter.html[EUnit user guide] +is the best place to learn how to write tests. Of note is +that all functions ending with `_test` or `_test_` will be +picked up as EUnit test cases. + +Erlang.mk will automatically pick up tests found in any of +the Erlang modules of your application. It will also pick up +tests located in the '$(TEST_DIR)' directory, which defaults +to 'test/'. + +It is generally a good practice to hide test code from +the code you ship to production. With Erlang.mk, you can +do this thanks to the `TEST` macro. It is only defined +when running tests: + +[source,erlang] +---- +-ifdef(TEST). + +%% Insert tests here. + +-endif. +---- + +Be careful, however, if you include the EUnit header file, +as it also defines the `TEST` macro. Make sure to only include +it inside an `ifdef` block, otherwise tests will always be +compiled. + +[source,erlang] +---- +-ifdef(TEST). + +-include_lib(\"eunit/include/eunit.hrl\"). + +%% Insert tests here. + +-endif. +---- + +Erlang.mk will automatically recompile your code when you +perform a normal build after running tests, and vice versa. + +=== Configuration + +The `EUNIT_OPTS` variable allows you to specify additional +EUnit options. Options are documented in the +http://www.erlang.org/doc/man/eunit.html#test-2[EUnit manual]. +At the time of writing, the only available option is `verbose`: + +[source,make] +EUNIT_OPTS = verbose + +The `EUNIT_ERL_OPTS` variable allows you to specify options +to be passed to `erl` when running EUnit tests. For example, +you can load the 'vm.args' and 'sys.config' files: + +[source,make] +EUNIT_ERL_OPTS = -args_file rel/vm.args -config rel/sys.config + +=== Usage + +To run all tests (including EUnit): + +[source,bash] +$ make tests + +To run all tests and static checks (including EUnit): + +[source,bash] +$ make check + +You can also run EUnit separately: + +[source,bash] +$ make eunit + +EUnit will be quiet by default, only outputting errors. +You can easily make it verbose for a single invocation: + +[source,bash] +$ make eunit EUNIT_OPTS=verbose + +Erlang.mk allows you to run all tests from a specific +module, or a specific test case from that module, using +the variable `t`. + +For example, to run all tests from the `cow_http_hd` +module (instead of all tests from the entire project), +one could write: + +[source,bash] +$ make eunit t=cow_http_hd + +Similarly, to run a specific test case: + +[source,bash] +$ make eunit t=cow_http_hd:parse_accept_test_ + +To do the same against a multi-application repository, +you can use the `-C` option: + +[source,bash] +$ make -C apps/my_app eunit t=my_module:hello_test + +Note that this also applies to dependencies. From Cowboy, +you can run the following directly: + +[source,bash] +$ make -C deps/cowlib eunit t=cow_http_hd + +Finally, xref:coverage[code coverage] is available, +but covered in its own chapter. diff --git a/doc/src/guide/external_plugins.asciidoc b/doc/src/guide/external_plugins.asciidoc index 027b1b9..d3dafaa 100644 --- a/doc/src/guide/external_plugins.asciidoc +++ b/doc/src/guide/external_plugins.asciidoc @@ -1,3 +1,4 @@ +[[plugins_usage]] == External plugins It is often convenient to be able to keep the build files @@ -60,7 +61,7 @@ the recommended way is to create one file per plugin in the 'mk/' folder in your repository, and then include those individual plugins in 'plugins.mk'. -For eaxmple, if you have two plugins 'mk/dist.mk' and +For example, if you have two plugins 'mk/dist.mk' and 'mk/templates.mk', you could write the following 'plugins.mk' file: diff --git a/doc/src/guide/external_plugins_list.asciidoc b/doc/src/guide/external_plugins_list.asciidoc new file mode 100644 index 0000000..f30797f --- /dev/null +++ b/doc/src/guide/external_plugins_list.asciidoc @@ -0,0 +1,48 @@ +[[plugins_list]] +== List of plugins + +This is a non-exhaustive list of Erlang.mk plugins, sorted +alphabetically. + +=== efene.mk + +An https://github.com/ninenines/efene.mk[Efene plugin] for Erlang.mk. +http://efene.org/[Efene] is an alternative language for the BEAM. + +=== elixir.mk + +An https://github.com/botsunit/elixir.mk[Elixir plugin] for +Erlang.mk. http://elixir-lang.org/[Elixir] is an alternative +language for the BEAM. + +=== elvis.mk + +An https://github.com/inaka/elvis.mk[Elvis plugin] for Erlang.mk. +Elvis is an https://github.com/inaka/elvis[Erlang style reviewer]. + +=== geas + +https://github.com/crownedgrouse/geas[Geas] gives aggregated +information on a project and its dependencies, and is available +as an Erlang.mk plugin. + +=== hexer.mk + +An https://github.com/inaka/hexer.mk[Hex plugin] for Erlang.mk. +Hex is a https://hex.pm/[package manager for the Elixir ecosystem]. + +=== lfe.mk + +An https://github.com/ninenines/lfe.mk[LFE plugin] for Erlang.mk. +LFE, or http://lfe.io/[Lisp Flavoured Erlang], is an alternative +language for the BEAM. + +=== mix.mk + +A https://github.com/botsunit/mix.mk[Mix plugin] for Erlang.mk, +to generate a compatible configuration file for +http://elixir-lang.org/getting-started/mix-otp/introduction-to-mix.html[Mix]. + +=== reload.mk + +A https://github.com/bullno1/reload.mk[live reload plugin] for Erlang.mk. diff --git a/doc/src/guide/getting_started.asciidoc b/doc/src/guide/getting_started.asciidoc index 34280d1..ef2f6e8 100644 --- a/doc/src/guide/getting_started.asciidoc +++ b/doc/src/guide/getting_started.asciidoc @@ -1,3 +1,4 @@ +[[getting_started]] == Getting started This chapter explains how to get started using Erlang.mk. @@ -74,7 +75,7 @@ rm -rf .erlang.mk.build This is Erlang.mk bootstrapping itself. Indeed, the file you initially downloaded contains nothing more than the code needed to bootstrap. This operation is done only once. Consult the -link:updating.asciidoc[Updating Erlang.mk] chapter for more +xref:updating[Updating Erlang.mk] chapter for more information. Of course, the generated project can now be compiled: @@ -125,7 +126,7 @@ $ make -f erlang.mk bootstrap-lib bootstrap-rel It is often very useful to keep the top-level project for commands useful during operations, and put the components of the system in separate applications that you will then -depend on. Consult the link:deps.asciidoc[Packages and dependencies] +depend on. Consult the xref:deps[Packages and dependencies] chapter for more information. When you run `make` from now on, Erlang.mk will compile your @@ -150,7 +151,7 @@ _relx_, the release building tool. So don't worry if you see more output than above. If building the release is slow, no need to upgrade your -hardware just yet. Just consult the link:relx.asciidoc[Releases] +hardware just yet. Just consult the xref:relx[Releases] chapter for various tips to speed up build time during development. @@ -183,6 +184,25 @@ Eshell V7.0 (abort with ^G) Simple as that! +=== Using spaces instead of tabs + +Erlang.mk defaults to tabs when creating files from templates. +This is in part because of a personal preference, and in part +because it is much easier to convert tabs to spaces than the +opposite. + +Use the `SP` variable if you prefer spaces. Set it to the number +of spaces per indentation level you want. + +For example, if you prefer two spaces per indentation level: + +[source,bash] +$ make -f erlang.mk bootstrap SP=2 + +When you bootstrap the project initially, the variable automatically +gets added to the Makefile, so you only need to provide it when +you get started. + === Using templates It is no secret that Erlang's OTP behaviors tend to have some @@ -217,6 +237,23 @@ $ make All that's left to do is to open it in your favorite editor and make it do something! +=== Hiding Erlang.mk from git + +Erlang.mk is a large text file. It can easily take a large part of +a `git diff` or a `git grep` command. You can avoid this by telling +Git that 'erlang.mk' is a binary file. + +Add this to your '.gitattributes' file. This is a file that you +can create at the root of your repository: + +---- +erlang.mk -diff +---- + +The 'erlang.mk' file will still appear in diffs and greps, but +as a binary file, meaning its contents won't be shown by default +anymore. + === Getting help During development, if you don't remember the name of a target, diff --git a/doc/src/guide/history.asciidoc b/doc/src/guide/history.asciidoc index 41eec09..9202743 100644 --- a/doc/src/guide/history.asciidoc +++ b/doc/src/guide/history.asciidoc @@ -1,5 +1,66 @@ +[[history]] == Short history -// @todo Write it. +This chapter aims to be a brief record of the life of the +Erlang.mk project. -Placeholder chapter. +=== Before Erlang.mk + +Erlang.mk originates from the Cowboy project. Cowboy started +as a Rebar project and I, Loïc Hoguin, was very happy with it +for a couple years. Over time however I started getting annoyed +and frustrated by a number of things, including bad defaults, +changing defaults and overall slowness. + +In particular, at the time I gave up on Rebar, the Cowboy +test suite was taking about five minutes to run. A quick experiment +showed I could get much lower times by simply invoking `ct_run` +directly. On January 4th, 2013, the Cowboy test suite took less +than a minute to complete. + +Following this success I started removing a little more and, +on the fateful day of January 5th, 2013, removed the dependency +on Rebar entirely. Rebar, and in particular the concept of +dependencies, was, and still is, a pretty strong influence. + +Erlang.mk was conceived. + +A few months passed and, on May 1st, 2013, the Erlang.mk +repository was created. Erlang.mk was born. + +Little did I know how much it would grow. + +=== Lifetime of the project + +Erlang.mk would eventually become a much larger file able to +deal with many more projects than just Cowboy. From the birth +of the project, the biggest force for growth was user contributions, +because Erlang.mk appealed to a variety of people with different +needs, needs that Erlang.mk was not fulfilling yet. + +The project was split into smaller files focused on a different +feature each, and a build script was written to build the single +Erlang.mk file. + +A test suite was contributed by a user, and later taken as a basis +for the current, much more complete test suite. Turns out testing +a Makefile is pretty straightforward. + +A package index was added to solve the problem of discovering +Erlang projects. + +After trying to see if Erlang build tools could cooperate, the +decision was made to improve compatibility with existing Rebar +projects by patching Rebar out, using Rebar. This feature, called +autopatch, proved very successful and made Erlang.mk compatible +with more than 90% of all Erlang projects. + +Erlang.mk documentation was much improved and the Erlang.mk website +was created in the summer of 2015. + +Over the year of 2015, Erlang.mk went from curiosity to a serious +alternative to other Erlang build tools. The user base increased +immensely and large projects started using it, including RabbitMQ +from the 3.6.0 release onward. + +A bright future lies ahead. diff --git a/doc/src/guide/installation.asciidoc b/doc/src/guide/installation.asciidoc index f03dafa..cc18e7f 100644 --- a/doc/src/guide/installation.asciidoc +++ b/doc/src/guide/installation.asciidoc @@ -1,3 +1,4 @@ +[[installation]] == Installation This chapter explains how to setup your system in @@ -95,6 +96,13 @@ to find all packages related to GCC: [source,bash] $ pacman -Ss gcc +If you are going to compile C/C++ code, you will need to +install this package, as Erlang.mk cannot use the normal +"gcc" package: + +[source,bash] +$ pacman -S mingw-w64-x86_64-gcc + You can also run commands under the MSYS2 environment from the Windows command line or batch files. This command will install GNU Make and Git: diff --git a/doc/src/guide/limitations.asciidoc b/doc/src/guide/limitations.asciidoc index 86ca918..1bf33d2 100644 --- a/doc/src/guide/limitations.asciidoc +++ b/doc/src/guide/limitations.asciidoc @@ -1,3 +1,4 @@ +[[limitations]] == Limitations No software is perfect. diff --git a/doc/src/guide/overview.asciidoc b/doc/src/guide/overview.asciidoc index a81dd7a..8fa57fe 100644 --- a/doc/src/guide/overview.asciidoc +++ b/doc/src/guide/overview.asciidoc @@ -1,3 +1,4 @@ +[[overview]] == Overview Now that you know how to get started, let's take a look at @@ -9,20 +10,20 @@ Erlang.mk is first and foremost a build tool. It is especially tailored for Erlang developers and follows widely accepted practices in the Erlang community. -Erlang.mk will happily build all link:app.asciidoc[Erlang-specific files] +Erlang.mk will happily build all xref:building[Erlang-specific files] you throw at it. Other kinds of files too, like C or C++ code -when you are working on link:ports.asciidoc[a NIF or a port driver]. +when you are working on xref:ports[a NIF or a port driver]. -Erlang.mk embraces the concept of link:deps.asciidoc[source dependencies]. +Erlang.mk embraces the concept of xref:deps[source dependencies]. It can fetch dependency source code using a variety of mechanisms, including fetching from Git, Mercurial or SVN. -Erlang.mk will automatically link:relx.asciidoc[generate releases] -when applicable. It can also link:escripts.asciidoc[generate escripts]. +Erlang.mk will automatically xref:relx[generate releases] +when applicable. It can also xref:escript[generate escripts]. === Exploring the package index -Erlang.mk comes with a link:deps.asciidoc[built-in package index]. +Erlang.mk comes with a xref:deps[built-in package index]. It is built as an extension of the dependency system and is meant to be used for discovery purposes. @@ -46,14 +47,14 @@ $ make search q=cowboy Erlang.mk supports _EDoc_ and _Asciidoc_. -link:edoc.asciidoc[EDoc] generates HTML documentation directly from +xref:edoc[EDoc] generates HTML documentation directly from your source code. While it is convenient, ask yourself: if all the documentation is inside the source code, why not just open the source code directly? That's where _Asciidoc_ comes in. -The link:asciidoc.asciidoc[Asciidoc] plugin expects all documentation +The xref:asciidoc[Asciidoc] plugin expects all documentation to be separate from source. It will generate HTML, PDF, man pages and more from the documentation you write in the 'doc/src/' folder in your repository. @@ -63,26 +64,24 @@ your repository. Erlang.mk supports a lot of different testing and static analysis tools. -The link:shell.asciidoc[make shell] command allows you +The xref:shell[make shell] command allows you to test your project manually. You can automate these -unit tests with link:eunit.asciidoc[EUnit] and test -your entire system with link:common_test.asciidoc[Common Test]. -link:property_based_testing.asciidoc[Property based testing] -with Triq is a strong alternative to writing unit tests -manually. link:coverage.asciidoc[Code coverage] can of course +unit tests with xref:eunit[EUnit] and test +your entire system with xref:ct[Common Test]. +xref:coverage[Code coverage] can of course be enabled during tests. Erlang.mk comes with features to make your life easier when -setting up and using link:ci.asciidoc[Continuous integration]. +setting up and using xref:ci[Continuous integration]. On the static analysis side of things, Erlang.mk comes with -support for link:dialyzer.asciidoc[Dialyzer], link:xref.asciidoc[Xref] -and link:elvis.asciidoc[Elvis], performing success typing -analysis, cross reference and style reviewing. +support for xref:dialyzer[Dialyzer] and xref:xref[Xref], +to perform success typing analysis and cross referencing +of the code. === Need more? -Not convinced yet? You can read about link:why.asciidoc[why you should use Erlang.mk] -and its link:history.asciidoc[history]. And if you're still not +Not convinced yet? You can read about xref:why[why you should use Erlang.mk] +and its xref:history[history]. And if you're still not convinced after that, it's OK! The world would be boring if everyone agreed on everything all the time. diff --git a/doc/src/guide/ports.asciidoc b/doc/src/guide/ports.asciidoc index b4527fb..02c636f 100644 --- a/doc/src/guide/ports.asciidoc +++ b/doc/src/guide/ports.asciidoc @@ -1,3 +1,4 @@ +[[ports]] == NIFs and port drivers Erlang.mk can not only build Erlang projects, but also the C code @@ -35,8 +36,6 @@ It contains a few variable definitions for the environment used for the build: `ERL_INTERFACE_LIB_DIR`:: Path to the Erl_Interface static libraries. -// @todo We should remove this file on clean, not distclean. - === Using a custom Makefile Erlang.mk will automatically run `make` if it detects a Makefile @@ -66,9 +65,19 @@ before including Erlang.mk: [source,make] C_SRC_TYPE = executable -The generated file will be saved to '$(C_SRC_OUTPUT)'. It -defaults to '$(CURDIR)/priv/$(PROJECT).so', the filename -adequately fitting a Unix shared library. +The generated file name varies depending on the type of project +you have (shared library or executable) and on the platform you +build the project on. + +For shared libraries, the generated file name will be +'$(C_SRC_OUTPUT)$(C_SRC_SHARED_EXTENSION)', with the default +being '$(CURDIR)/priv/$(PROJECT)' followed by the extension: +`.dll` on Windows, `.so` everywhere else. + +For executables, the generated file name is +'$(C_SRC_OUTPUT)$(C_SRC_EXECUTABLE_EXTENSION)', with the same +default except for the extension: `.exe` on Windows, and otherwise +nothing. Erlang.mk sets appropriate compile and linker flags by default. These flags vary depending on the platform, and can of course diff --git a/doc/src/guide/property_based_testing.asciidoc b/doc/src/guide/property_based_testing.asciidoc deleted file mode 100644 index c652b2b..0000000 --- a/doc/src/guide/property_based_testing.asciidoc +++ /dev/null @@ -1,5 +0,0 @@ -== Property based testing - -// @todo Write it. - -Placeholder chapter. diff --git a/doc/src/guide/releases.asciidoc b/doc/src/guide/releases.asciidoc index e7b1333..46183e6 100644 --- a/doc/src/guide/releases.asciidoc +++ b/doc/src/guide/releases.asciidoc @@ -1,3 +1,4 @@ +[[relx]] == Releases Erlang.mk relies on _Relx_ for generating releases. This diff --git a/doc/src/guide/shell.asciidoc b/doc/src/guide/shell.asciidoc index 083c160..a527253 100644 --- a/doc/src/guide/shell.asciidoc +++ b/doc/src/guide/shell.asciidoc @@ -1,3 +1,4 @@ +[[shell]] == Erlang shell Erlang.mk provides a convenient target for starting a shell diff --git a/doc/src/guide/updating.asciidoc b/doc/src/guide/updating.asciidoc index ecd4a70..61d913d 100644 --- a/doc/src/guide/updating.asciidoc +++ b/doc/src/guide/updating.asciidoc @@ -1,3 +1,4 @@ +[[updating]] == Updating Erlang.mk This chapter describes how to update the 'erlang.mk' file diff --git a/doc/src/guide/why.asciidoc b/doc/src/guide/why.asciidoc index 3a84940..e91b64c 100644 --- a/doc/src/guide/why.asciidoc +++ b/doc/src/guide/why.asciidoc @@ -1,7 +1,8 @@ +[[why]] == Why Erlang.mk Why would you choose Erlang.mk, if not for its -link:overview.asciidoc[many features]? This chapter will +xref:overview[many features]? This chapter will attempt to answer that. === Erlang.mk is fast diff --git a/doc/src/guide/xref.asciidoc b/doc/src/guide/xref.asciidoc index 889aa41..44ed190 100644 --- a/doc/src/guide/xref.asciidoc +++ b/doc/src/guide/xref.asciidoc @@ -1,3 +1,4 @@ +[[xref]] == Xref // @todo Write it. diff --git a/index/bitcask.mk b/index/bitcask.mk index 2bc7af8..31930f3 100644 --- a/index/bitcask.mk +++ b/index/bitcask.mk @@ -4,4 +4,4 @@ pkg_bitcask_description = because you need another a key/value storage engine pkg_bitcask_homepage = https://github.com/basho/bitcask pkg_bitcask_fetch = git pkg_bitcask_repo = https://github.com/basho/bitcask -pkg_bitcask_commit = master +pkg_bitcask_commit = develop diff --git a/index/brod.mk b/index/brod.mk new file mode 100644 index 0000000..2650f2c --- /dev/null +++ b/index/brod.mk @@ -0,0 +1,7 @@ +PACKAGES += brod +pkg_brod_name = brod +pkg_brod_description = Kafka client in Erlang +pkg_brod_homepage = https://github.com/klarna/brod +pkg_brod_fetch = git +pkg_brod_repo = https://github.com/klarna/brod.git +pkg_brod_commit = master diff --git a/index/bullet.mk b/index/bullet.mk index 32f07dd..e365674 100644 --- a/index/bullet.mk +++ b/index/bullet.mk @@ -3,5 +3,5 @@ pkg_bullet_name = bullet pkg_bullet_description = Simple, reliable, efficient streaming for Cowboy. pkg_bullet_homepage = http://ninenines.eu pkg_bullet_fetch = git -pkg_bullet_repo = https://github.com/extend/bullet +pkg_bullet_repo = https://github.com/ninenines/bullet pkg_bullet_commit = master diff --git a/index/dhtcrawler.mk b/index/dhtcrawler.mk deleted file mode 100644 index 0d15138..0000000 --- a/index/dhtcrawler.mk +++ /dev/null @@ -1,7 +0,0 @@ -PACKAGES += dhtcrawler -pkg_dhtcrawler_name = dhtcrawler -pkg_dhtcrawler_description = dhtcrawler is a DHT crawler written in erlang. It can join a DHT network and crawl many P2P torrents. -pkg_dhtcrawler_homepage = https://github.com/kevinlynx/dhtcrawler -pkg_dhtcrawler_fetch = git -pkg_dhtcrawler_repo = https://github.com/kevinlynx/dhtcrawler -pkg_dhtcrawler_commit = master diff --git a/index/elvis.mk b/index/elvis.mk index ac6d76a..b9ca83d 100644 --- a/index/elvis.mk +++ b/index/elvis.mk @@ -4,4 +4,4 @@ pkg_elvis_description = Erlang Style Reviewer pkg_elvis_homepage = https://github.com/inaka/elvis pkg_elvis_fetch = git pkg_elvis_repo = https://github.com/inaka/elvis -pkg_elvis_commit = 0.2.4 +pkg_elvis_commit = master diff --git a/index/gen_coap.mk b/index/gen_coap.mk new file mode 100644 index 0000000..58c9799 --- /dev/null +++ b/index/gen_coap.mk @@ -0,0 +1,7 @@ +PACKAGES += gen_coap +pkg_gen_coap_name = gen_coap +pkg_gen_coap_description = Generic Erlang CoAP Client/Server +pkg_gen_coap_homepage = https://github.com/gotthardp/gen_coap +pkg_gen_coap_fetch = git +pkg_gen_coap_repo = https://github.com/gotthardp/gen_coap +pkg_gen_coap_commit = master diff --git a/index/geode.mk b/index/geode.mk new file mode 100644 index 0000000..4eaec34 --- /dev/null +++ b/index/geode.mk @@ -0,0 +1,7 @@ +PACKAGES += geode +pkg_geode_name = geode +pkg_geode_description = geohash/proximity lookup in pure, uncut erlang. +pkg_geode_homepage = https://github.com/bradfordw/geode +pkg_geode_fetch = git +pkg_geode_repo = https://github.com/bradfordw/geode +pkg_geode_commit = master diff --git a/index/i18n.mk b/index/i18n.mk new file mode 100644 index 0000000..f3f2c89 --- /dev/null +++ b/index/i18n.mk @@ -0,0 +1,7 @@ +PACKAGES += i18n +pkg_i18n_name = i18n +pkg_i18n_description = International components for unicode from Erlang (unicode, date, string, number, format, locale, localization, transliteration, icu4e) +pkg_i18n_homepage = https://github.com/erlang-unicode/i18n +pkg_i18n_fetch = git +pkg_i18n_repo = https://github.com/erlang-unicode/i18n +pkg_i18n_commit = master diff --git a/index/itweet.mk b/index/itweet.mk deleted file mode 100644 index 704362b..0000000 --- a/index/itweet.mk +++ /dev/null @@ -1,7 +0,0 @@ -PACKAGES += itweet -pkg_itweet_name = itweet -pkg_itweet_description = Twitter Stream API on ibrowse -pkg_itweet_homepage = http://inaka.github.com/itweet/ -pkg_itweet_fetch = git -pkg_itweet_repo = https://github.com/inaka/itweet -pkg_itweet_commit = v2.0 diff --git a/index/jesse.mk b/index/jesse.mk index ae96908..b36b699 100644 --- a/index/jesse.mk +++ b/index/jesse.mk @@ -1,7 +1,7 @@ PACKAGES += jesse pkg_jesse_name = jesse pkg_jesse_description = jesse (JSon Schema Erlang) is an implementation of a json schema validator for Erlang. -pkg_jesse_homepage = https://github.com/klarna/jesse +pkg_jesse_homepage = https://github.com/for-GET/jesse pkg_jesse_fetch = git -pkg_jesse_repo = https://github.com/klarna/jesse +pkg_jesse_repo = https://github.com/for-GET/jesse pkg_jesse_commit = master diff --git a/index/jsone.mk b/index/jsone.mk new file mode 100644 index 0000000..cf7378e --- /dev/null +++ b/index/jsone.mk @@ -0,0 +1,7 @@ +PACKAGES += jsone +pkg_jsone_name = jsone +pkg_jsone_description = An Erlang library for encoding, decoding JSON data. +pkg_jsone_homepage = https://github.com/sile/jsone.git +pkg_jsone_fetch = git +pkg_jsone_repo = https://github.com/sile/jsone.git +pkg_jsone_commit = master diff --git a/index/kafka_protocol.mk b/index/kafka_protocol.mk new file mode 100644 index 0000000..8a9fb2f --- /dev/null +++ b/index/kafka_protocol.mk @@ -0,0 +1,7 @@ +PACKAGES += kafka_protocol +pkg_kafka_protocol_name = kafka_protocol +pkg_kafka_protocol_description = Kafka protocol Erlang library +pkg_kafka_protocol_homepage = https://github.com/klarna/kafka_protocol +pkg_kafka_protocol_fetch = git +pkg_kafka_protocol_repo = https://github.com/klarna/kafka_protocol.git +pkg_kafka_protocol_commit = master diff --git a/index/mimerl.mk b/index/mimerl.mk new file mode 100644 index 0000000..6a613d1 --- /dev/null +++ b/index/mimerl.mk @@ -0,0 +1,7 @@ +PACKAGES += mimerl +pkg_mimerl_name = mimerl +pkg_mimerl_description = library to handle mimetypes +pkg_mimerl_homepage = https://github.com/benoitc/mimerl +pkg_mimerl_fetch = git +pkg_mimerl_repo = https://github.com/benoitc/mimerl +pkg_mimerl_commit = master diff --git a/index/nksip.mk b/index/nksip.mk new file mode 100644 index 0000000..b74ccfc --- /dev/null +++ b/index/nksip.mk @@ -0,0 +1,7 @@ +PACKAGES += nksip +pkg_nksip_name = nksip +pkg_nksip_description = Erlang SIP application server +pkg_nksip_homepage = https://github.com/kalta/nksip +pkg_nksip_fetch = git +pkg_nksip_repo = https://github.com/kalta/nksip +pkg_nksip_commit = master diff --git a/index/oauth2c.mk b/index/oauth2c.mk deleted file mode 100644 index 101e45d..0000000 --- a/index/oauth2c.mk +++ /dev/null @@ -1,7 +0,0 @@ -PACKAGES += oauth2c -pkg_oauth2c_name = oauth2c -pkg_oauth2c_description = Erlang OAuth2 Client -pkg_oauth2c_homepage = https://github.com/kivra/oauth2_client -pkg_oauth2c_fetch = git -pkg_oauth2c_repo = https://github.com/kivra/oauth2_client -pkg_oauth2c_commit = master diff --git a/index/ptrackerl.mk b/index/ptrackerl.mk deleted file mode 100644 index fe7061e..0000000 --- a/index/ptrackerl.mk +++ /dev/null @@ -1,7 +0,0 @@ -PACKAGES += ptrackerl -pkg_ptrackerl_name = ptrackerl -pkg_ptrackerl_description = Pivotal Tracker API Client written in Erlang -pkg_ptrackerl_homepage = https://github.com/inaka/ptrackerl -pkg_ptrackerl_fetch = git -pkg_ptrackerl_repo = https://github.com/inaka/ptrackerl -pkg_ptrackerl_commit = master diff --git a/index/slack.mk b/index/slack.mk new file mode 100644 index 0000000..f01bd1c --- /dev/null +++ b/index/slack.mk @@ -0,0 +1,7 @@ +PACKAGES += slack +pkg_slack_name = slack +pkg_slack_description = Minimal slack notification OTP library. +pkg_slack_homepage = https://github.com/DonBranson/slack +pkg_slack_fetch = git +pkg_slack_repo = https://github.com/DonBranson/slack.git +pkg_slack_commit = 1.0.0 diff --git a/index/supervisor3.mk b/index/supervisor3.mk new file mode 100644 index 0000000..09356f6 --- /dev/null +++ b/index/supervisor3.mk @@ -0,0 +1,7 @@ +PACKAGES += supervisor3 +pkg_supervisor3_name = supervisor3 +pkg_supervisor3_description = OTP supervisor with additional strategies +pkg_supervisor3_homepage = https://github.com/klarna/supervisor3 +pkg_supervisor3_fetch = git +pkg_supervisor3_repo = https://github.com/klarna/supervisor3.git +pkg_supervisor3_commit = master diff --git a/index/xref_runner.mk b/index/xref_runner.mk index 80ebce4..b058d6a 100644 --- a/index/xref_runner.mk +++ b/index/xref_runner.mk @@ -4,4 +4,4 @@ pkg_xref_runner_description = Erlang Xref Runner (inspired in rebar xref) pkg_xref_runner_homepage = https://github.com/inaka/xref_runner pkg_xref_runner_fetch = git pkg_xref_runner_repo = https://github.com/inaka/xref_runner -pkg_xref_runner_commit = 0.2.0 +pkg_xref_runner_commit = 0.2.3 diff --git a/plugins/asciidoc.mk b/plugins/asciidoc.mk index baf4d3b..ab7fa4b 100644 --- a/plugins/asciidoc.mk +++ b/plugins/asciidoc.mk @@ -8,12 +8,12 @@ MAN_SECTIONS ?= 3 7 docs:: asciidoc -asciidoc: distclean-asciidoc doc-deps asciidoc-guide asciidoc-manual +asciidoc: asciidoc-guide asciidoc-manual ifeq ($(wildcard doc/src/guide/book.asciidoc),) asciidoc-guide: else -asciidoc-guide: +asciidoc-guide: distclean-asciidoc 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/ endif @@ -21,7 +21,7 @@ endif ifeq ($(wildcard doc/src/manual/*.asciidoc),) asciidoc-manual: else -asciidoc-manual: +asciidoc-manual: distclean-asciidoc doc-deps for f in doc/src/manual/*.asciidoc ; do \ a2x -v -f manpage $$f ; \ done @@ -36,7 +36,7 @@ install-docs:: install-asciidoc install-asciidoc: asciidoc-manual for s in $(MAN_SECTIONS); do \ mkdir -p $(MAN_INSTALL_PATH)/man$$s/ ; \ - install -g 0 -o 0 -m 0644 doc/man$$s/*.gz $(MAN_INSTALL_PATH)/man$$s/ ; \ + install -g `id -u` -o `id -g` -m 0644 doc/man$$s/*.gz $(MAN_INSTALL_PATH)/man$$s/ ; \ done endif diff --git a/plugins/bootstrap.mk b/plugins/bootstrap.mk index dbd115f..d608d28 100644 --- a/plugins/bootstrap.mk +++ b/plugins/bootstrap.mk @@ -11,8 +11,8 @@ help:: " 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 n=NAME Create a new local OTP application NAME" \ - " new-lib n=NAME Create a new local OTP library NAME" \ + " 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" @@ -49,6 +49,8 @@ define bs_appsrc_lib ]}. endef +# To prevent autocompletion issues with ZSH, we add "include erlang.mk" +# separately during the actual bootstrap. ifdef SP define bs_Makefile PROJECT = $p @@ -58,17 +60,21 @@ PROJECT_VERSION = 0.0.1 # Whitespace to be used when creating files from templates. SP = $(SP) -include erlang.mk endef else define bs_Makefile PROJECT = $p -include erlang.mk +PROJECT_DESCRIPTION = New project +PROJECT_VERSION = 0.0.1 + endef endif define bs_apps_Makefile PROJECT = $p +PROJECT_DESCRIPTION = New project +PROJECT_VERSION = 0.0.1 + include $(call core_relpath,$(dir $(ERLANG_MK_FILENAME)),$(APPS_DIR)/app)/erlang.mk endef @@ -166,6 +172,11 @@ code_change(_OldVsn, State, _Extra) -> {ok, State}. endef +define tpl_module +-module($(n)). +-export([]). +endef + define tpl_cowboy_http -module($(n)). -behaviour(cowboy_http_handler). @@ -344,7 +355,7 @@ endef # Plugin-specific targets. define render_template - $(verbose) echo "$${_$(1)}" > $(2) + $(verbose) printf -- '$(subst $(newline),\n,$(subst %,%%,$(subst ','\'',$(subst $(tab),$(WS),$(call $(1))))))\n' > $(2) endef ifndef WS @@ -355,10 +366,6 @@ WS = $(tab) endif endif -$(foreach template,$(filter bs_% tpl_%,$(.VARIABLES)), \ - $(eval _$(template) = $$(subst $$(tab),$$(WS),$$($(template)))) \ - $(eval export _$(template))) - bootstrap: ifneq ($(wildcard src/),) $(error Error: src/ directory already exists) @@ -366,6 +373,7 @@ endif $(eval p := $(PROJECT)) $(eval n := $(PROJECT)_sup) $(call render_template,bs_Makefile,Makefile) + $(verbose) echo "include erlang.mk" >> Makefile $(verbose) mkdir src/ ifdef LEGACY $(call render_template,bs_appsrc,src/$(PROJECT).app.src) @@ -379,6 +387,7 @@ ifneq ($(wildcard src/),) endif $(eval p := $(PROJECT)) $(call render_template,bs_Makefile,Makefile) + $(verbose) echo "include erlang.mk" >> Makefile $(verbose) mkdir src/ ifdef LEGACY $(call render_template,bs_appsrc_lib,src/$(PROJECT).app.src) diff --git a/plugins/c_src.mk b/plugins/c_src.mk index a74d945..518ba9e 100644 --- a/plugins/c_src.mk +++ b/plugins/c_src.mk @@ -7,12 +7,33 @@ C_SRC_DIR ?= $(CURDIR)/c_src C_SRC_ENV ?= $(C_SRC_DIR)/env.mk -C_SRC_OUTPUT ?= $(CURDIR)/priv/$(PROJECT).so +C_SRC_OUTPUT ?= $(CURDIR)/priv/$(PROJECT) C_SRC_TYPE ?= shared # System type and C compiler/flags. -ifeq ($(PLATFORM),darwin) +ifeq ($(PLATFORM),msys2) + C_SRC_OUTPUT_EXECUTABLE_EXTENSION ?= .exe + C_SRC_OUTPUT_SHARED_EXTENSION ?= .dll +else + C_SRC_OUTPUT_EXECUTABLE_EXTENSION ?= + C_SRC_OUTPUT_SHARED_EXTENSION ?= .so +endif + +ifeq ($(C_SRC_TYPE),shared) + C_SRC_OUTPUT_FILE = $(C_SRC_OUTPUT)$(C_SRC_OUTPUT_SHARED_EXTENSION) +else + C_SRC_OUTPUT_FILE = $(C_SRC_OUTPUT)$(C_SRC_OUTPUT_EXECUTABLE_EXTENSION) +endif + +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 + export CC + CFLAGS ?= -O3 -std=c99 -finline-functions -Wall -Wmissing-prototypes + CXXFLAGS ?= -O3 -finline-functions -Wall +else ifeq ($(PLATFORM),darwin) CC ?= cc CFLAGS ?= -O3 -std=c99 -arch x86_64 -finline-functions -Wall -Wmissing-prototypes CXXFLAGS ?= -O3 -arch x86_64 -finline-functions -Wall @@ -27,10 +48,15 @@ else ifeq ($(PLATFORM),linux) CXXFLAGS ?= -O3 -finline-functions -Wall endif -CFLAGS += -fPIC -I $(ERTS_INCLUDE_DIR) -I $(ERL_INTERFACE_INCLUDE_DIR) -CXXFLAGS += -fPIC -I $(ERTS_INCLUDE_DIR) -I $(ERL_INTERFACE_INCLUDE_DIR) +ifneq ($(PLATFORM),msys2) + CFLAGS += -fPIC + CXXFLAGS += -fPIC +endif -LDLIBS += -L $(ERL_INTERFACE_LIB_DIR) -lerl_interface -lei +CFLAGS += -I"$(ERTS_INCLUDE_DIR)" -I"$(ERL_INTERFACE_INCLUDE_DIR)" +CXXFLAGS += -I"$(ERTS_INCLUDE_DIR)" -I"$(ERL_INTERFACE_INCLUDE_DIR)" + +LDLIBS += -L"$(ERL_INTERFACE_LIB_DIR)" -lerl_interface -lei # Verbosity. @@ -67,15 +93,15 @@ OBJECTS = $(addsuffix .o, $(basename $(SOURCES))) COMPILE_C = $(c_verbose) $(CC) $(CFLAGS) $(CPPFLAGS) -c COMPILE_CPP = $(cpp_verbose) $(CXX) $(CXXFLAGS) $(CPPFLAGS) -c -app:: $(C_SRC_ENV) $(C_SRC_OUTPUT) +app:: $(C_SRC_ENV) $(C_SRC_OUTPUT_FILE) -test-build:: $(C_SRC_ENV) $(C_SRC_OUTPUT) +test-build:: $(C_SRC_ENV) $(C_SRC_OUTPUT_FILE) -$(C_SRC_OUTPUT): $(OBJECTS) +$(C_SRC_OUTPUT_FILE): $(OBJECTS) $(verbose) mkdir -p priv/ $(link_verbose) $(CC) $(OBJECTS) \ $(LDFLAGS) $(if $(filter $(C_SRC_TYPE),shared),-shared) $(LDLIBS) \ - -o $(C_SRC_OUTPUT) + -o $(C_SRC_OUTPUT_FILE) %.o: %.c $(COMPILE_C) $(OUTPUT_OPTION) $< @@ -92,13 +118,13 @@ $(C_SRC_OUTPUT): $(OBJECTS) clean:: clean-c_src clean-c_src: - $(gen_verbose) rm -f $(C_SRC_OUTPUT) $(OBJECTS) + $(gen_verbose) rm -f $(C_SRC_OUTPUT_FILE) $(OBJECTS) endif ifneq ($(wildcard $(C_SRC_DIR)),) $(C_SRC_ENV): - $(verbose) $(ERL) -eval "file:write_file(\"$(C_SRC_ENV)\", \ + $(verbose) $(ERL) -eval "file:write_file(\"$(call core_native_path,$(C_SRC_ENV))\", \ io_lib:format( \ \"ERTS_INCLUDE_DIR ?= ~s/erts-~s/include/~n\" \ \"ERL_INTERFACE_INCLUDE_DIR ?= ~s~n\" \ @@ -115,3 +141,94 @@ distclean-c_src-env: -include $(C_SRC_ENV) endif + +# 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 +ifdef in + $(verbose) $(MAKE) -C $(APPS_DIR)/$(in)/ new-nif n=$n in= +else + $(verbose) mkdir -p $(C_SRC_DIR) src/ + $(call render_template,bs_c_nif,$(C_SRC_DIR)/$n.c) + $(call render_template,bs_erl_nif,src/$n.erl) +endif diff --git a/plugins/ct.mk b/plugins/ct.mk index fb4b1ca..4d0c020 100644 --- a/plugins/ct.mk +++ b/plugins/ct.mk @@ -1,7 +1,7 @@ # Copyright (c) 2013-2015, Loïc Hoguin <[email protected]> # This file is part of erlang.mk and subject to the terms of the ISC License. -.PHONY: ct distclean-ct +.PHONY: ct apps-ct distclean-ct # Configuration. @@ -31,22 +31,44 @@ help:: CT_RUN = ct_run \ -no_auto_compile \ -noinput \ - -pa $(CURDIR)/ebin $(DEPS_DIR)/*/ebin $(TEST_DIR) \ + -pa $(CURDIR)/ebin $(DEPS_DIR)/*/ebin $(APPS_DIR)/*/ebin $(TEST_DIR) \ -dir $(TEST_DIR) \ -logdir $(CURDIR)/logs ifeq ($(CT_SUITES),) -ct: +ct: $(if $(IS_APP),,apps-ct) else -ct: test-build +ct: test-build $(if $(IS_APP),,apps-ct) $(verbose) mkdir -p $(CURDIR)/logs/ - $(gen_verbose) $(CT_RUN) -suite $(addsuffix _SUITE,$(CT_SUITES)) $(CT_OPTS) + $(gen_verbose) $(CT_RUN) -sname ct_$(PROJECT) -suite $(addsuffix _SUITE,$(CT_SUITES)) $(CT_OPTS) +endif + +ifneq ($(ALL_APPS_DIRS),) +define ct_app_target +apps-ct-$1: + $(MAKE) -C $1 ct IS_APP=1 +endef + +$(foreach app,$(ALL_APPS_DIRS),$(eval $(call ct_app_target,$(app)))) + +apps-ct: test-build $(addprefix apps-ct-,$(ALL_APPS_DIRS)) +endif + +ifndef t +CT_EXTRA = +else +ifeq (,$(findstring :,$t)) +CT_EXTRA = -group $t +else +t_words = $(subst :, ,$t) +CT_EXTRA = -group $(firstword $(t_words)) -case $(lastword $(t_words)) +endif endif define ct_suite_target ct-$(1): test-build $(verbose) mkdir -p $(CURDIR)/logs/ - $(gen_verbose) $(CT_RUN) -suite $(addsuffix _SUITE,$(1)) $(CT_OPTS) + $(gen_verbose) $(CT_RUN) -sname ct_$(PROJECT) -suite $(addsuffix _SUITE,$(1)) $(CT_EXTRA) $(CT_OPTS) endef $(foreach test,$(CT_SUITES),$(eval $(call ct_suite_target,$(test)))) diff --git a/plugins/dialyzer.mk b/plugins/dialyzer.mk index 709b43f..8c2710f 100644 --- a/plugins/dialyzer.mk +++ b/plugins/dialyzer.mk @@ -9,9 +9,8 @@ DIALYZER_PLT ?= $(CURDIR)/.$(PROJECT).plt export DIALYZER_PLT PLT_APPS ?= -DIALYZER_DIRS ?= --src -r src -DIALYZER_OPTS ?= -Werror_handling -Wrace_conditions \ - -Wunmatched_returns # -Wunderspecs +DIALYZER_DIRS ?= --src -r $(wildcard src) $(ALL_APPS_DIRS) +DIALYZER_OPTS ?= -Werror_handling -Wrace_conditions -Wunmatched_returns # -Wunderspecs # Core targets. @@ -27,6 +26,18 @@ help:: # Plugin-specific targets. +define filter_opts.erl + Opts = binary:split(<<"$1">>, <<"-">>, [global]), + Filtered = lists:reverse(lists:foldl(fun + (O = <<"pa ", _/bits>>, Acc) -> [O|Acc]; + (O = <<"D ", _/bits>>, Acc) -> [O|Acc]; + (O = <<"I ", _/bits>>, Acc) -> [O|Acc]; + (_, Acc) -> Acc + end, [], Opts)), + io:format("~s~n", [[["-", O] || O <- Filtered]]), + halt(). +endef + $(DIALYZER_PLT): deps app $(verbose) dialyzer --build_plt --apps erts kernel stdlib $(PLT_APPS) $(OTP_DEPS) $(LOCAL_DEPS) $(DEPS) @@ -40,4 +51,4 @@ dialyze: else dialyze: $(DIALYZER_PLT) endif - $(verbose) dialyzer --no_native $(DIALYZER_DIRS) $(DIALYZER_OPTS) + $(verbose) dialyzer --no_native `$(call erlang,$(call filter_opts.erl,$(ERLC_OPTS)))` $(DIALYZER_DIRS) $(DIALYZER_OPTS) diff --git a/plugins/edoc.mk b/plugins/edoc.mk index 6f0a82d..7b4331b 100644 --- a/plugins/edoc.mk +++ b/plugins/edoc.mk @@ -9,13 +9,15 @@ EDOC_OPTS ?= # Core targets. -docs:: distclean-edoc edoc +ifneq ($(wildcard doc/overview.edoc),) +docs:: edoc +endif distclean:: distclean-edoc # Plugin-specific targets. -edoc: doc-deps +edoc: distclean-edoc doc-deps $(gen_verbose) $(ERL) -eval 'edoc:application($(PROJECT), ".", [$(EDOC_OPTS)]), halt().' distclean-edoc: diff --git a/plugins/elvis.mk b/plugins/elvis.mk deleted file mode 100644 index 58823b5..0000000 --- a/plugins/elvis.mk +++ /dev/null @@ -1,39 +0,0 @@ -# Copyright (c) 2015, Erlang Solutions Ltd. -# This file is part of erlang.mk and subject to the terms of the ISC License. - -.PHONY: elvis distclean-elvis - -# Configuration. - -ELVIS_CONFIG ?= $(CURDIR)/elvis.config - -ELVIS ?= $(CURDIR)/elvis -export ELVIS - -ELVIS_URL ?= https://github.com/inaka/elvis/releases/download/0.2.5/elvis -ELVIS_CONFIG_URL ?= https://github.com/inaka/elvis/releases/download/0.2.5/elvis.config -ELVIS_OPTS ?= - -# Core targets. - -help:: - $(verbose) printf "%s\n" "" \ - "Elvis targets:" \ - " elvis Run Elvis using the local elvis.config or download the default otherwise" - -distclean:: distclean-elvis - -# Plugin-specific targets. - -$(ELVIS): - $(gen_verbose) $(call core_http_get,$(ELVIS),$(ELVIS_URL)) - $(verbose) chmod +x $(ELVIS) - -$(ELVIS_CONFIG): - $(verbose) $(call core_http_get,$(ELVIS_CONFIG),$(ELVIS_CONFIG_URL)) - -elvis: $(ELVIS) $(ELVIS_CONFIG) - $(verbose) $(ELVIS) rock -c $(ELVIS_CONFIG) $(ELVIS_OPTS) - -distclean-elvis: - $(gen_verbose) rm -rf $(ELVIS) diff --git a/plugins/erlydtl.mk b/plugins/erlydtl.mk index 072da50..5fde292 100644 --- a/plugins/erlydtl.mk +++ b/plugins/erlydtl.mk @@ -14,6 +14,20 @@ dtl_verbose = $(dtl_verbose_$(V)) # Core targets. +DTL_FILES = $(sort $(call core_find,$(DTL_PATH),*.dtl)) + +ifneq ($(DTL_FILES),) + +ifdef DTL_FULL_PATH +BEAM_FILES += $(addprefix ebin/,$(patsubst %.dtl,%_dtl.beam,$(subst /,_,$(DTL_FILES:$(DTL_PATH)%=%)))) +else +BEAM_FILES += $(addprefix ebin/,$(patsubst %.dtl,%_dtl.beam,$(notdir $(DTL_FILES)))) +endif + +# Rebuild templates when the Makefile changes. +$(DTL_FILES): $(MAKEFILE_LIST) + @touch $@ + define erlydtl_compile.erl [begin Module0 = case "$(strip $(DTL_FULL_PATH))" of @@ -32,21 +46,8 @@ define erlydtl_compile.erl halt(). endef -ifneq ($(wildcard src/),) - -DTL_FILES = $(sort $(call core_find,$(DTL_PATH),*.dtl)) - -ifdef DTL_FULL_PATH -BEAM_FILES += $(addprefix ebin/,$(patsubst %.dtl,%_dtl.beam,$(subst /,_,$(DTL_FILES:$(DTL_PATH)%=%)))) -else -BEAM_FILES += $(addprefix ebin/,$(patsubst %.dtl,%_dtl.beam,$(notdir $(DTL_FILES)))) -endif - -# Rebuild templates when the Makefile changes. -$(DTL_FILES): $(MAKEFILE_LIST) - @touch $@ - -ebin/$(PROJECT).app:: $(DTL_FILES) +ebin/$(PROJECT).app:: $(DTL_FILES) | ebin/ $(if $(strip $?),\ - $(dtl_verbose) $(call erlang,$(call erlydtl_compile.erl,$?,-pa ebin/ $(DEPS_DIR)/erlydtl/ebin/))) + $(dtl_verbose) $(call erlang,$(call erlydtl_compile.erl,$?),-pa ebin/ $(DEPS_DIR)/erlydtl/ebin/)) + endif diff --git a/plugins/escript.mk b/plugins/escript.mk index 42133eb..16f8ba6 100644 --- a/plugins/escript.mk +++ b/plugins/escript.mk @@ -6,6 +6,8 @@ # Configuration. ESCRIPT_NAME ?= $(PROJECT) +ESCRIPT_FILE ?= $(ESCRIPT_NAME) + ESCRIPT_COMMENT ?= This is an -*- erlang -*- file ESCRIPT_BEAMS ?= "ebin/*", "deps/*/ebin/*" @@ -51,7 +53,7 @@ define ESCRIPT_RAW ' ]),'\ ' file:change_mode(Escript, 8#755)'\ 'end,'\ -'Ez("$(ESCRIPT_NAME)"),'\ +'Ez("$(ESCRIPT_FILE)"),'\ 'halt().' endef diff --git a/plugins/eunit.mk b/plugins/eunit.mk index 2adf4a6..a2e22ff 100644 --- a/plugins/eunit.mk +++ b/plugins/eunit.mk @@ -2,11 +2,12 @@ # Copyright (c) 2015, Loïc Hoguin <[email protected]> # This file is contributed to erlang.mk and subject to the terms of the ISC License. -.PHONY: eunit +.PHONY: eunit apps-eunit # Configuration EUNIT_OPTS ?= +EUNIT_ERL_OPTS ?= # Core targets. @@ -28,7 +29,7 @@ define eunit.erl _ -> ok end end, - case eunit:test([$(call comma_list,$(1))], [$(EUNIT_OPTS)]) of + case eunit:test($1, [$(EUNIT_OPTS)]) of ok -> ok; error -> halt(2) end, @@ -40,11 +41,28 @@ define eunit.erl halt() endef -EUNIT_EBIN_MODS = $(notdir $(basename $(call core_find,ebin/,*.beam))) -EUNIT_TEST_MODS = $(notdir $(basename $(call core_find,$(TEST_DIR)/,*.beam))) -EUNIT_MODS = $(foreach mod,$(EUNIT_EBIN_MODS) $(filter-out \ - $(patsubst %,%_tests,$(EUNIT_EBIN_MODS)),$(EUNIT_TEST_MODS)),{module,'$(mod)'}) +EUNIT_ERL_OPTS += -pa $(TEST_DIR) $(DEPS_DIR)/*/ebin $(APPS_DIR)/*/ebin ebin +ifdef t +ifeq (,$(findstring :,$(t))) +eunit: test-build + $(gen_verbose) $(call erlang,$(call eunit.erl,['$(t)']),$(EUNIT_ERL_OPTS)) +else eunit: test-build - $(gen_verbose) $(ERL) -pa $(TEST_DIR) $(DEPS_DIR)/*/ebin ebin \ - -eval "$(subst $(newline),,$(subst ",\",$(call eunit.erl,$(EUNIT_MODS))))" + $(gen_verbose) $(call erlang,$(call eunit.erl,fun $(t)/0),$(EUNIT_ERL_OPTS)) +endif +else +EUNIT_EBIN_MODS = $(notdir $(basename $(ERL_FILES) $(BEAM_FILES))) +EUNIT_TEST_MODS = $(notdir $(basename $(call core_find,$(TEST_DIR)/,*.erl))) + +EUNIT_MODS = $(foreach mod,$(EUNIT_EBIN_MODS) $(filter-out \ + $(patsubst %,%_tests,$(EUNIT_EBIN_MODS)),$(EUNIT_TEST_MODS)),'$(mod)') + +eunit: test-build $(if $(IS_APP),,apps-eunit) + $(gen_verbose) $(call erlang,$(call eunit.erl,[$(call comma_list,$(EUNIT_MODS))]),$(EUNIT_ERL_OPTS)) + +ifneq ($(ALL_APPS_DIRS),) +apps-eunit: + $(verbose) for app in $(ALL_APPS_DIRS); do $(MAKE) -C $$app eunit IS_APP=1; done +endif +endif diff --git a/plugins/relx.mk b/plugins/relx.mk index 5aa6196..a27992d 100644 --- a/plugins/relx.mk +++ b/plugins/relx.mk @@ -22,7 +22,7 @@ endif ifeq ($(IS_DEP),) ifneq ($(wildcard $(RELX_CONFIG)),) -rel:: distclean-relx-rel relx-rel +rel:: relx-rel endif endif @@ -34,7 +34,7 @@ $(RELX): $(gen_verbose) $(call core_http_get,$(RELX),$(RELX_URL)) $(verbose) chmod +x $(RELX) -relx-rel: $(RELX) rel-deps +relx-rel: $(RELX) rel-deps app $(verbose) $(RELX) -c $(RELX_CONFIG) $(RELX_OPTS) distclean-relx-rel: diff --git a/test/Makefile b/test/Makefile index 4779c9f..f01e3ab 100644 --- a/test/Makefile +++ b/test/Makefile @@ -12,8 +12,7 @@ endif # Temporary application name, taken from rule name. -APP = $(subst -,_,$@) -APP_TO_CLEAN = $(subst -,_,$(patsubst clean-%,%,$@)) +APP = test_$(subst -,_,$@) # Erlang, quickly! @@ -61,6 +60,7 @@ OTP_MASTER = https://raw.githubusercontent.com/erlang/otp/master # V=1: Show test commands. # V=2: Also show normal Erlang.mk output. # V=3: Also show verbose Erlang.mk output. +# V=4: Also show a trace of each command after expansion. V ?= 0 @@ -82,7 +82,7 @@ else ifeq ($V,2) i = @echo == $@: else t = - v = V=1 + v = V=$(shell echo $$(($(V)-2))) i = @echo == $@: endif @@ -92,8 +92,8 @@ endif all:: core -clean:: clean-core - $t rm -rf erl_crash.dump packages/ +clean:: + $t rm -rf erl_crash.dump packages/ test_*/ build: $i "Generate a bleeding edge Erlang.mk" @@ -101,11 +101,10 @@ build: # Core. -.PHONY: core clean-core +.PHONY: core define include_core core:: core-$1 -clean-core:: clean-core-$1 include core_$1.mk @@ -117,7 +116,6 @@ $(eval $(foreach t,$(patsubst %.mk,%,$(patsubst core_%,%,$(wildcard core_*.mk))) define include_plugin all:: $1 -clean:: clean-$1 include plugin_$1.mk @@ -128,14 +126,10 @@ $(eval $(foreach t,$(patsubst %.mk,%,$(patsubst plugin_%,%,$(wildcard plugin_*.m # Tests that don't easily fit into other categories. core:: core-clean-crash-dump core-distclean-tmp core-help -clean-core:: clean-core-clean-crash-dump clean-core-distclean-tmp clean-core-help -.PHONY: core-clean-crash-dump core-distclean-tmp core-help clean-core-clean-crash-dump clean-core-distclean-tmp clean-core-help +.PHONY: core-clean-crash-dump core-distclean-tmp core-help -clean-core-clean-crash-dump clean-core-distclean-tmp clean-core-help: - $t rm -rf $(APP_TO_CLEAN)/ - -core-clean-crash-dump: build clean-core-clean-crash-dump +core-clean-crash-dump: build clean $i "Bootstrap a new OTP library named $(APP)" $t mkdir $(APP)/ @@ -151,7 +145,7 @@ core-clean-crash-dump: build clean-core-clean-crash-dump $i "Check that the crash dump is removed" $t test ! -e $(APP)/erl_crash.dump -core-distclean-tmp: build clean-core-distclean-tmp +core-distclean-tmp: build clean $i "Bootstrap a new OTP application named $(APP)" $t mkdir $(APP)/ @@ -167,7 +161,7 @@ core-distclean-tmp: build clean-core-distclean-tmp $i "Check that .erlang.mk directory got removed" $t test ! -e $(APP)/.erlang.mk -core-help: build clean-core-help +core-help: build clean $i "Bootstrap a new OTP library named $(APP)" $t mkdir $(APP)/ @@ -180,13 +174,14 @@ core-help: build clean-core-help # Packages. PACKAGES = $(foreach pkg,$(sort $(wildcard ../index/*.mk)),$(notdir $(basename $(pkg)))) +EXCLUDE_FROM_CHECK = [rabbitmq_codegen] packages: $(addprefix pkg-,$(PACKAGES)) define pkg_target .PHONY: pkg-$1 -pkg-$1: clean build +pkg-$1: build clean # Make sure $@ is defined inside the define. $(eval @ = pkg-$1) @@ -202,14 +197,6 @@ pkg-$1: clean build $i "Add package $1 to the Makefile" $t perl -ni.bak -e 'print;if ($$$$.==1) {print "DEPS = $1\n"}' packages/$1_pkg/Makefile - $(if $(filter amqp_client,$1), - $i "Set RABBITMQ_CLIENT_PATCH" - $(eval PATCHES := RABBITMQ_CLIENT_PATCH=1)) - - $(if $(filter rabbit,$1), - $i "Set RABBITMQ_SERVER_PATCH" - $(eval PATCHES := RABBITMQ_SERVER_PATCH=1)) - $i "Compile package $1" $t if ! ( cd packages/$1_pkg/ && $(MAKE) $(PATCHES) $v ); then \ echo "$1: compile error" >> packages/errors.log; \ @@ -224,8 +211,9 @@ pkg-$1: clean build $i "Check that all applications and their modules can be loaded" $t if ! ( cd packages/$1_pkg/ && $(ERL) -pa deps/*/ebin/ -eval " \ - Apps = [list_to_atom(App) || \"deps/\" ++ App \ + Apps0 = [list_to_atom(App) || \"deps/\" ++ App \ <- filelib:wildcard(\"deps/*\")], \ + Apps = [App || App <- Apps0, not lists:member(App, $(EXCLUDE_FROM_CHECK))], \ [begin \ io:format(\"Loading application ~p~n\", [App]), \ case application:load(App) of \ @@ -257,8 +245,9 @@ pkg-$1: clean build $i "Check that all applications and their modules can still be loaded" $t if ! ( cd packages/$1_pkg/ && $(ERL) -pa deps/*/ebin/ -eval " \ - Apps = [list_to_atom(App) || \"deps/\" ++ App \ + Apps0 = [list_to_atom(App) || \"deps/\" ++ App \ <- filelib:wildcard(\"deps/*\")], \ + Apps = [App || App <- Apps0, not lists:member(App, $(EXCLUDE_FROM_CHECK))], \ [begin \ io:format(\"Loading application ~p~n\", [App]), \ case application:load(App) of \ @@ -314,92 +303,13 @@ endef # The following tests are slowly being converted. # Do NOT use -j with legacy tests. -.PHONY: legacy clean-legacy ct eunit tests-cover docs +.PHONY: legacy clean-legacy tests-cover -legacy: clean-legacy ct eunit tests-cover docs pkgs +legacy: clean-legacy tests-cover clean-legacy: $t rm -rf app1 -ct: app1 - $i "ct: Testing ct and related targets." - $i "Setting up test suite." - $t mkdir -p app1/test - $t printf "%s\n" \ - "-module(m_SUITE)." \ - "-export([all/0, testcase1/1])." \ - "all() -> [testcase1]." \ - "testcase1(_) -> 2 = m:succ(1)." \ - > app1/test/m_SUITE.erl - $t $(MAKE) -C app1 ct $v - $i "Checking files created by '$(MAKE) ct'." - $t [ -e app1/test/m_SUITE.beam ] - $t [ -e app1/ebin/m.beam ] - $t [ -e app1/logs ] - $i "Checking that '$(MAKE) clean' does not delete logs." - $t $(MAKE) -C app1 clean $v - $t [ -e app1/logs ] - $i "Testing target 'ct-mysuite' where mysuite_SUITE is a test suite." - $t $(MAKE) -C app1 ct-m $v - $i "Checking that '$(MAKE) ct' returns non-zero for a failing suite." - $t printf "%s\n" \ - "-module(failing_SUITE)." \ - "-export([all/0, testcase1/1])." \ - "all() -> [testcase1]." \ - "testcase1(_) -> 42 = m:succ(1)." \ - > app1/test/failing_SUITE.erl - $t ! $(MAKE) -C app1 ct-failing $v - $i "Checking that '$(MAKE) distclean-ct' deletes logs." - $t $(MAKE) -C app1 distclean-ct $v - $t [ ! -e app1/logs ] - $t [ -e app1/ebin/m.beam ] - $i "Cleaning up test data." - $t rm -rf app1/test - $i "Test 'ct' passed." - -eunit: app1 - $i "eunit: Testing the 'eunit' target." - $i "Running eunit test case inside module src/t.erl" - $t $(call create-module-t) - $t $(MAKE) -C app1 distclean $v - $t $(MAKE) -C app1 eunit $v - $i "Checking that the eunit test in module t." - $t echo t | cmp app1/test-eunit.log - - $t rm app1/test-eunit.log - $i "Running eunit tests in a separate directory." - $t mkdir -p app1/eunit - $t printf '%s\n' \ - '-module(t_tests).' \ - '-include_lib("eunit/include/eunit.hrl").' \ - 'succ_test() ->' \ - ' ?assertEqual(2, t:succ(1)),' \ - ' os:cmd("echo t_tests >> test-eunit.log").' \ - > app1/eunit/t_tests.erl - $t printf '%s\n' \ - '-module(x_tests).' \ - '-include_lib("eunit/include/eunit.hrl").' \ - 'succ_test() ->' \ - ' ?assertEqual(2, t:succ(1)),' \ - ' os:cmd("echo x_tests >> test-eunit.log").' \ - > app1/eunit/x_tests.erl - $t $(MAKE) -C app1 distclean TEST_DIR=eunit $v - $t $(MAKE) -C app1 eunit TEST_DIR=eunit $v - $i "Checking that '$(MAKE) eunit' didn't run the tests in t_tests twice, etc." - $t printf "%s\n" t t_tests x_tests | cmp app1/test-eunit.log - - $t rm app1/test-eunit.log - $i "Checking that '$(MAKE) eunit' returns non-zero for a failing test." - $t rm -f app1/eunit/* - $t printf "%s\n" \ - "-module(t_tests)." \ - '-include_lib("eunit/include/eunit.hrl").' \ - "succ_test() ->" \ - " ?assertEqual(42, t:succ(1))." \ - > app1/eunit/t_tests.erl - $t $(MAKE) -C app1 distclean TEST_DIR=eunit $v - $t ! $(MAKE) -C app1 eunit TEST_DIR=eunit $v - $t rm -rf app1/eunit app1/src/t.erl app1/test-eunit.log - $i "Test 'eunit' passed." - # TODO: do coverage for 'tests' instead of 'eunit ct' when triq is fixed tests-cover: app1 $i "tests-cover: Testing 'eunit' and 'ct' with COVER=1" @@ -435,29 +345,6 @@ tests-cover: app1 $t $(MAKE) -C app1 clean $v $i "Test 'tests-cover' passed." -docs: app1 - $i "docs: Testing EDoc including DOC_DEPS." - $t printf "%s\n" \ - "PROJECT = app1" \ - "DOC_DEPS = edown" \ - "dep_edown = git https://github.com/uwiger/edown.git 0.7" \ - "EDOC_OPTS = {doclet, edown_doclet}" \ - "include erlang.mk" \ - "distclean:: distclean-doc-md" \ - "distclean-doc-md:" \ - " rm -rf doc/*.md" \ - > app1/Makefile-doc - $i "Downloading doc deps (edown) and building docs." - $t $(MAKE) -C app1 -f Makefile-doc docs $v - $i "Checking that '$(MAKE) docs' using edown generated a markdown file." - $t [ -e app1/doc/m.md ] - $i "Checking that '$(MAKE) distclean' deletes all generated doc files." - $t $(MAKE) -C app1 -f Makefile-doc distclean $v - $t [ "`ls app1/doc/`" = "" ] - $i "Cleaning up test data." - $t rm app1/Makefile-doc - $i "Test 'docs' passed." - define app1_setup $i "Setting up app." $t mkdir -p app1 diff --git a/test/core_app.mk b/test/core_app.mk index 0f1af19..4570d9d 100644 --- a/test/core_app.mk +++ b/test/core_app.mk @@ -2,19 +2,13 @@ CORE_APP_CASES = appsrc-change asn1 auto-git-id erlc-exclude erlc-opts erlc-opts-filter error generate-erl generate-erl-include generate-erl-prepend hrl hrl-recursive makefile-change mib no-app no-makedep pt pt-erlc-opts xrl xrl-include yrl yrl-include CORE_APP_TARGETS = $(addprefix core-app-,$(CORE_APP_CASES)) -CORE_APP_CLEAN_TARGETS = $(addprefix clean-,$(CORE_APP_TARGETS)) -.PHONY: core-app $(CORE_APP_TARGETS) clean-core-app $(CORE_APP_CLEAN_TARGETS) - -clean-core-app: $(CORE_APP_CLEAN_TARGETS) - -$(CORE_APP_CLEAN_TARGETS): - $t rm -rf $(APP_TO_CLEAN)/ +.PHONY: core-app $(CORE_APP_TARGETS) core-app: $(CORE_APP_TARGETS) ifdef LEGACY -core-app-appsrc-change: build clean-core-app-appsrc-change +core-app-appsrc-change: build clean $i "Bootstrap a new OTP application named $(APP)" $t mkdir $(APP)/ @@ -34,7 +28,7 @@ core-app-appsrc-change: build clean-core-app-appsrc-change $t rm $(APP)/EXPECT endif -core-app-asn1: build clean-core-app-asn1 +core-app-asn1: build clean $i "Bootstrap a new OTP library named $(APP)" $t mkdir $(APP)/ @@ -155,7 +149,7 @@ endif [{module, M} = code:load_file(M) || M <- Mods], \ halt()" -core-app-auto-git-id: build clean-core-app-auto-git-id +core-app-auto-git-id: build clean $i "Bootstrap a new OTP library named $(APP)" $t mkdir $(APP)/ @@ -203,7 +197,7 @@ endif true = ID =/= [], \ halt()" -core-app-erlc-exclude: build clean-core-app-erlc-exclude +core-app-erlc-exclude: build clean $i "Bootstrap a new OTP library named $(APP)" $t mkdir $(APP)/ @@ -231,7 +225,7 @@ core-app-erlc-exclude: build clean-core-app-erlc-exclude [{module, M} = code:load_file(M) || M <- Mods], \ halt()" -core-app-erlc-opts: build clean-core-app-erlc-opts +core-app-erlc-opts: build clean $i "Bootstrap a new OTP library named $(APP)" $t mkdir $(APP)/ @@ -258,7 +252,7 @@ core-app-erlc-opts: build clean-core-app-erlc-opts false = proplists:is_defined(debug_info, proplists:get_value(options, girl:module_info(compile))), \ halt()" -core-app-erlc-opts-filter: build clean-core-app-erlc-opts-filter +core-app-erlc-opts-filter: build clean $i "Bootstrap a new OTP library named $(APP)" $t mkdir $(APP)/ @@ -285,7 +279,7 @@ core-app-erlc-opts-filter: build clean-core-app-erlc-opts-filter false = proplists:is_defined(debug_info, proplists:get_value(options, girl:module_info(compile))), \ halt()" -core-app-error: build clean-core-app-error +core-app-error: build clean $i "Bootstrap a new OTP library named $(APP)" $t mkdir $(APP)/ @@ -302,7 +296,7 @@ core-app-error: build clean-core-app-error $i "Check that trying to build returns non-zero" $t ! $(MAKE) -C $(APP) $v -core-app-generate-erl: build clean-core-app-generate-erl +core-app-generate-erl: build clean $i "Bootstrap a new OTP library named $(APP)" $t mkdir $(APP)/ @@ -408,7 +402,7 @@ endif [{module, M} = code:load_file(M) || M <- Mods], \ halt()" -core-app-generate-erl-include: build clean-core-app-generate-erl-include +core-app-generate-erl-include: build clean $i "Bootstrap a new OTP library named $(APP)" $t mkdir $(APP)/ @@ -470,7 +464,7 @@ core-app-generate-erl-include: build clean-core-app-generate-erl-include [{module, M} = code:load_file(M) || M <- Mods], \ halt()" -core-app-generate-erl-prepend: build clean-core-app-generate-erl-prepend +core-app-generate-erl-prepend: build clean $i "Bootstrap a new OTP library named $(APP)" $t mkdir $(APP)/ @@ -579,7 +573,7 @@ endif [{module, M} = code:load_file(M) || M <- Mods], \ halt()" -core-app-hrl: build clean-core-app-hrl +core-app-hrl: build clean $i "Bootstrap a new OTP library named $(APP)" $t mkdir $(APP)/ @@ -668,7 +662,7 @@ endif [{module, M} = code:load_file(M) || M <- Mods], \ halt()" -core-app-hrl-recursive: build clean-core-app-hrl-recursive +core-app-hrl-recursive: build clean $i "Bootstrap a new OTP library named $(APP)" $t mkdir $(APP)/ @@ -759,7 +753,7 @@ endif [{module, M} = code:load_file(M) || M <- Mods], \ halt()" -core-app-makefile-change: build clean-core-app-makefile-change +core-app-makefile-change: build clean $i "Bootstrap a new OTP application named $(APP)" $t mkdir $(APP)/ @@ -784,7 +778,7 @@ core-app-makefile-change: build clean-core-app-makefile-change $t find $(APP) -type f -newer $(APP)/Makefile | sort | diff $(APP)/EXPECT - $t rm $(APP)/EXPECT -core-app-mib: build clean-core-app-mib +core-app-mib: build clean $i "Bootstrap a new OTP library named $(APP)" $t mkdir $(APP)/ @@ -892,7 +886,7 @@ endif [{module, M} = code:load_file(M) || M <- Mods], \ halt()" -core-app-no-app: build clean-core-app-no-app +core-app-no-app: build clean $i "Bootstrap a project without an OTP library" $t mkdir $(APP)/ @@ -903,7 +897,7 @@ core-app-no-app: build clean-core-app-no-app $i "Build the project" $t $(MAKE) -C $(APP) $v -core-app-no-makedep: build clean-core-app-no-makedep +core-app-no-makedep: build clean $i "Bootstrap a new OTP library named $(APP)" $t mkdir $(APP)/ @@ -1016,7 +1010,7 @@ endif [{module, M} = code:load_file(M) || M <- Mods], \ halt()" -core-app-pt: build clean-core-app-pt +core-app-pt: build clean $i "Bootstrap a new OTP library named $(APP)" $t mkdir $(APP)/ @@ -1049,7 +1043,7 @@ core-app-pt: build clean-core-app-pt [{module, M} = code:load_file(M) || M <- Mods], \ halt()" -core-app-pt-erlc-opts: build clean-core-app-pt-erlc-opts +core-app-pt-erlc-opts: build clean $i "Bootstrap a new OTP library named $(APP)" $t mkdir $(APP)/ @@ -1089,7 +1083,7 @@ core-app-pt-erlc-opts: build clean-core-app-pt-erlc-opts [{module, M} = code:load_file(M) || M <- Mods], \ halt()" -core-app-xrl: build clean-core-app-xrl +core-app-xrl: build clean $i "Bootstrap a new OTP library named $(APP)" $t mkdir $(APP)/ @@ -1190,7 +1184,7 @@ endif [{module, M} = code:load_file(M) || M <- Mods], \ halt()" -core-app-xrl-include: build clean-core-app-xrl-include +core-app-xrl-include: build clean $i "Bootstrap a new OTP library named $(APP)" $t mkdir $(APP)/ @@ -1334,7 +1328,7 @@ endif [{module, M} = code:load_file(M) || M <- Mods], \ halt()" -core-app-yrl: build clean-core-app-yrl +core-app-yrl: build clean $i "Bootstrap a new OTP library named $(APP)" $t mkdir $(APP)/ @@ -1432,7 +1426,7 @@ endif [{module, M} = code:load_file(M) || M <- Mods], \ halt()" -core-app-yrl-include: build clean-core-app-yrl-include +core-app-yrl-include: build clean $i "Bootstrap a new OTP library named $(APP)" $t mkdir $(APP)/ diff --git a/test/core_compat.mk b/test/core_compat.mk index 06d5211..8d6cabc 100644 --- a/test/core_compat.mk +++ b/test/core_compat.mk @@ -2,22 +2,17 @@ # # Note: autopatch functionality is covered separately. -CORE_COMPAT_CASES = auto-rebar rebar rebar-deps rebar-deps-pkg rebar-erlc-opts rebar-pt +CORE_COMPAT_CASES = auto-rebar rebar rebar-deps-git rebar-deps-hex rebar-deps-pkg rebar-erlc-opts rebar-pt CORE_COMPAT_TARGETS = $(addprefix core-compat-,$(CORE_COMPAT_CASES)) -CORE_COMPAT_CLEAN_TARGETS = $(addprefix clean-,$(CORE_COMPAT_TARGETS)) REBAR_BINARY = https://github.com/rebar/rebar/releases/download/2.6.0/rebar +REBAR3_BINARY = https://s3.amazonaws.com/rebar3/rebar3 -.PHONY: core-compat $(CORE_COMPAT_TARGETS) clean-core-compat $(CORE_COMPAT_CLEAN_TARGETS) - -clean-core-compat: $(CORE_COMPAT_CLEAN_TARGETS) - -$(CORE_COMPAT_CLEAN_TARGETS): - $t rm -rf $(APP_TO_CLEAN)/ +.PHONY: core-compat $(CORE_COMPAT_TARGETS) core-compat: $(CORE_COMPAT_TARGETS) -core-compat-auto-rebar: build clean-core-compat-auto-rebar +core-compat-auto-rebar: build clean $i "Bootstrap a new OTP library named $(APP)" $t mkdir $(APP)/ @@ -59,7 +54,7 @@ core-compat-auto-rebar: build clean-core-compat-auto-rebar $i "Use rebar to build the application" $t cd $(APP) && ./rebar compile $v -core-compat-rebar: build clean-core-compat-rebar +core-compat-rebar: build clean $i "Bootstrap a new OTP library named $(APP)" $t mkdir $(APP)/ @@ -98,7 +93,7 @@ core-compat-rebar: build clean-core-compat-rebar $i "Use rebar to build the application" $t cd $(APP) && ./rebar compile $v -core-compat-rebar-deps: build clean-core-compat-rebar-deps +core-compat-rebar-deps-git: build clean $i "Bootstrap a new OTP library named $(APP)" $t mkdir $(APP)/ @@ -130,7 +125,39 @@ core-compat-rebar-deps: build clean-core-compat-rebar-deps $i "Use rebar to build the application" $t cd $(APP) && ./rebar get-deps compile $v -core-compat-rebar-deps-pkg: build clean-core-compat-rebar-deps-pkg +core-compat-rebar-deps-hex: build clean + + $i "Bootstrap a new OTP library named $(APP)" + $t mkdir $(APP)/ + $t cp ../erlang.mk $(APP)/ + $t $(MAKE) -C $(APP) -f erlang.mk bootstrap-lib $v + + $i "Add Cowboy as a dependency" + $t perl -ni.bak -e 'print;if ($$.==1) {print "DEPS = cowboy\ndep_cowboy = hex 1.0.0\n"}' $(APP)/Makefile + + $i "Run 'make rebar.config'" + $t $(MAKE) -C $(APP) rebar.config $v + + $i "Check that rebar.config was created" + $t test -f $(APP)/rebar.config + + $i "Check that Cowboy is listed in rebar.config" + $t $(ERL) -eval " \ + {ok, C} = file:consult(\"$(APP)/rebar.config\"), \ + {_, [{cowboy, \"1.0.0\"}]} = lists:keyfind(deps, 1, C), \ + halt()" + + $i "Distclean the application" + $t $(MAKE) -C $(APP) distclean $v + + $i "Download rebar3" + $t curl -s -L -o $(APP)/rebar3 $(REBAR3_BINARY) + $t chmod +x $(APP)/rebar3 + + $i "Use rebar to build the application" + $t cd $(APP) && ./rebar3 compile $v + +core-compat-rebar-deps-pkg: build clean $i "Bootstrap a new OTP library named $(APP)" $t mkdir $(APP)/ @@ -162,7 +189,7 @@ core-compat-rebar-deps-pkg: build clean-core-compat-rebar-deps-pkg $i "Use rebar to build the application" $t cd $(APP) && ./rebar get-deps compile $v -core-compat-rebar-erlc-opts: build clean-core-compat-rebar-erlc-opts +core-compat-rebar-erlc-opts: build clean $i "Bootstrap a new OTP library named $(APP)" $t mkdir $(APP)/ @@ -211,7 +238,7 @@ core-compat-rebar-erlc-opts: build clean-core-compat-rebar-erlc-opts $i "Use rebar to build the application" $t cd $(APP) && ./rebar compile $v -core-compat-rebar-pt: build clean-core-compat-rebar-pt +core-compat-rebar-pt: build clean $i "Bootstrap a new OTP library named $(APP)" $t mkdir $(APP)/ @@ -226,7 +253,7 @@ core-compat-rebar-pt: build clean-core-compat-rebar-pt $t perl -ni.bak -e 'print;if ($$.==1) {print "DEPS = lager\n"}' $(APP)/Makefile $i "Add the lager_transform parse_transform to ERLC_OPTS" - $t echo "ERLC_OPTS += +'{parse_transform, lager_transform}'" >> $(APP)/Makefile + $t echo "ERLC_OPTS += +'{parse_transform, lager_transform}' +'{lager_truncation_size, 1234}'" >> $(APP)/Makefile $i "Build the application" $t $(MAKE) -C $(APP) $v @@ -242,6 +269,7 @@ core-compat-rebar-pt: build clean-core-compat-rebar-pt {ok, C} = file:consult(\"$(APP)/rebar.config\"), \ {_, Opts} = lists:keyfind(erl_opts, 1, C), \ true = lists:member({parse_transform, lager_transform}, Opts), \ + true = lists:member({lager_truncation_size, 1234}, Opts), \ halt()" # For the new build method, we have to simulate keeping the .app file diff --git a/test/core_deps.mk b/test/core_deps.mk index 4c734f9..f145754 100644 --- a/test/core_deps.mk +++ b/test/core_deps.mk @@ -1,25 +1,13 @@ # Core: Packages and dependencies. -CORE_DEPS_CASES = apps apps-conflict apps-deep-conflict apps-dir apps-new-app apps-new-lib apps-new-tpl apps-only build-c-8cc build-c-imagejs build-erl build-js dep-commit dir doc fetch-cp fetch-custom fetch-fail-bad fetch-fail-unknown fetch-git fetch-git-submodule fetch-hex fetch-hg fetch-legacy fetch-svn ignore mv mv-rebar no-autopatch no-autopatch-erlang-mk no-autopatch-rebar order-first order-top otp pkg rel search shell skip test +CORE_DEPS_CASES = apps apps-conflict apps-deep-conflict apps-dir apps-new-app apps-new-lib apps-new-tpl apps-only autopatch-rebar build-c-8cc build-c-imagejs build-erl build-js dep-commit dir doc fetch-cp fetch-custom fetch-fail-bad fetch-fail-unknown fetch-git fetch-git-submodule fetch-hex fetch-hg fetch-legacy fetch-svn ignore mv mv-rebar no-autopatch no-autopatch-erlang-mk no-autopatch-rebar order-first order-top otp pkg rel search shell skip test CORE_DEPS_TARGETS = $(addprefix core-deps-,$(CORE_DEPS_CASES)) -CORE_DEPS_CLEAN_TARGETS = $(addprefix clean-,$(CORE_DEPS_TARGETS)) -.PHONY: core-deps $(CORE_DEPS_TARGETS) clean-core-deps $(CORE_DEPS_CLEAN_TARGETS) - -clean-core-deps: $(CORE_DEPS_CLEAN_TARGETS) clean-core-deps-mv-moved clean-core-deps-mv-rebar-moved - -$(CORE_DEPS_CLEAN_TARGETS): - $t rm -rf $(APP_TO_CLEAN)/ - -clean-core-deps-mv-moved: - $t rm -rf core_deps_mv-moved/ - -clean-core-deps-mv-rebar-moved: - $t rm -rf core_deps_mv_rebar-moved/ +.PHONY: core-deps $(CORE_DEPS_TARGETS) core-deps: $(CORE_DEPS_TARGETS) -core-deps-apps: build clean-core-deps-apps +core-deps-apps: build clean $i "Bootstrap a new OTP library named $(APP)" $t mkdir $(APP)/ @@ -113,7 +101,7 @@ endif [{module, M} = code:load_file(M) || M <- Mods], \ halt()" -core-deps-apps-conflict: build clean-core-deps-apps-conflict +core-deps-apps-conflict: build clean $i "Bootstrap a new OTP library named $(APP)" $t mkdir $(APP)/ @@ -132,7 +120,7 @@ core-deps-apps-conflict: build clean-core-deps-apps-conflict $i "Check that Cowlib wasn't fetched" $t test ! -e $(APP)/deps/cowlib -core-deps-apps-deep-conflict: build clean-core-deps-apps-deep-conflict +core-deps-apps-deep-conflict: build clean $i "Bootstrap a new OTP library named $(APP)" $t mkdir $(APP)/ @@ -151,7 +139,7 @@ core-deps-apps-deep-conflict: build clean-core-deps-apps-deep-conflict $i "Check that Cowlib wasn't fetched" $t test ! -e $(APP)/deps/cowlib -core-deps-apps-dir: build clean-core-deps-apps-dir +core-deps-apps-dir: build clean $i "Bootstrap a new OTP library named $(APP)" $t mkdir $(APP)/ @@ -222,7 +210,7 @@ endif $i "Check that all relevant files were removed" $t test ! -e $(APP)/deps -core-deps-apps-new-app: build clean-core-deps-apps-new-app +core-deps-apps-new-app: build clean $i "Bootstrap a new OTP library named $(APP)" $t mkdir $(APP)/ @@ -267,7 +255,7 @@ endif {module, my_server} = code:load_file(my_server), \ halt()" -core-deps-apps-new-lib: build clean-core-deps-apps-new-lib +core-deps-apps-new-lib: build clean $i "Bootstrap a new OTP library named $(APP)" $t mkdir $(APP)/ @@ -306,7 +294,7 @@ endif {module, my_server} = code:load_file(my_server), \ halt()" -core-deps-apps-new-tpl: build clean-core-deps-apps-new-tpl +core-deps-apps-new-tpl: build clean $i "Bootstrap a new OTP library named $(APP)" $t mkdir $(APP)/ @@ -338,7 +326,7 @@ core-deps-apps-new-tpl: build clean-core-deps-apps-new-tpl [{module, M} = code:load_file(M) || M <- Mods], \ halt()" -core-deps-apps-only: build clean-core-deps-apps-only +core-deps-apps-only: build clean $i "Create a multi application repository with no root application" $t mkdir $(APP)/ @@ -391,8 +379,28 @@ core-deps-apps-only: build clean-core-deps-apps-only $i "Check that all relevant files were removed" $t test ! -e $(APP)/deps +core-deps-autopatch-rebar: build clean + + $i "Bootstrap a new OTP library named $(APP)" + $t mkdir $(APP)/ + $t cp ../erlang.mk $(APP)/ + $t $(MAKE) -C $(APP) -f erlang.mk bootstrap-lib $v + + $i "Add erlsha2 to the list of dependencies" + $t perl -ni.bak -e 'print;if ($$.==1) {print "DEPS = erlsha2\n"}' $(APP)/Makefile + + $i "Build the application" + $t $(MAKE) -C $(APP) $v + + $i "Check that erlsha2 was fetched and built" + $t test -d $(APP)/deps/erlsha2 + $t test -f $(APP)/deps/erlsha2/ebin/erlsha2.beam +ifneq ($(PLATFORM),msys2) + $t test -f $(APP)/deps/erlsha2/priv/erlsha2_nif.so +endif + ifneq ($(PLATFORM),msys2) -core-deps-build-c-8cc: build clean-core-deps-build-c-8cc +core-deps-build-c-8cc: build clean $i "Bootstrap a new OTP library named $(APP)" $t mkdir $(APP)/ @@ -420,7 +428,7 @@ core-deps-build-c-8cc: build clean-core-deps-build-c-8cc endif ifneq ($(PLATFORM),freebsd) -core-deps-build-c-imagejs: build clean-core-deps-build-c-imagejs +core-deps-build-c-imagejs: build clean $i "Bootstrap a new OTP library named $(APP)" $t mkdir $(APP)/ @@ -448,7 +456,7 @@ core-deps-build-c-imagejs: build clean-core-deps-build-c-imagejs halt()" endif -core-deps-build-erl: build clean-core-deps-build-erl +core-deps-build-erl: build clean $i "Bootstrap a new OTP library named $(APP)" $t mkdir $(APP)/ @@ -471,7 +479,7 @@ core-deps-build-erl: build clean-core-deps-build-erl false = lists:member(cowlib, Deps), \ halt()" -core-deps-build-js: build clean-core-deps-build-js +core-deps-build-js: build clean $i "Bootstrap a new OTP library named $(APP)" $t mkdir $(APP)/ @@ -494,7 +502,7 @@ core-deps-build-js: build clean-core-deps-build-js false = lists:member(jquery, Deps), \ halt()" -core-deps-dep-commit: build clean-core-deps-dep-commit +core-deps-dep-commit: build clean $i "Bootstrap a new OTP library named $(APP)" $t mkdir $(APP)/ @@ -525,7 +533,7 @@ endif {ok, \"1.0.0\"} = application:get_key(cowboy, vsn), \ halt()" -core-deps-dir: build clean-core-deps-dir +core-deps-dir: build clean $i "Bootstrap a new OTP library named $(APP)" $t mkdir $(APP)/ @@ -555,7 +563,7 @@ endif true = lists:member(cowboy, Deps), \ halt()" -core-deps-doc: build clean-core-deps-doc +core-deps-doc: build clean $i "Bootstrap a new OTP library named $(APP)" $t mkdir $(APP)/ @@ -583,7 +591,7 @@ core-deps-doc: build clean-core-deps-doc halt()" $i "Build the application documentation" - $t $(MAKE) -C $(APP) docs $v + $t $(MAKE) -C $(APP) edoc $v $i "Check that documentation dependencies were fetched" $t test -d $(APP)/deps/edown @@ -592,7 +600,7 @@ core-deps-doc: build clean-core-deps-doc $t test -f $(APP)/doc/boy.md $t test -f $(APP)/doc/girl.md -core-deps-fetch-cp: build clean-core-deps-fetch-cp +core-deps-fetch-cp: build clean $i "Bootstrap a new OTP library named $(APP)" $t mkdir $(APP)/ @@ -625,7 +633,7 @@ endif true = lists:member(my_dep, Deps), \ halt()" -core-deps-fetch-custom: build clean-core-deps-fetch-custom +core-deps-fetch-custom: build clean $i "Bootstrap a new OTP library named $(APP)" $t mkdir $(APP)/ @@ -653,7 +661,7 @@ endif true = lists:member(boop, Deps), \ halt()" -core-deps-fetch-fail-bad: build clean-core-deps-fetch-fail-bad +core-deps-fetch-fail-bad: build clean $i "Bootstrap a new OTP library named $(APP)" $t mkdir $(APP)/ @@ -666,7 +674,7 @@ core-deps-fetch-fail-bad: build clean-core-deps-fetch-fail-bad $i "Check that building the application fails" $t ! $(MAKE) -C $(APP) $v -core-deps-fetch-fail-unknown: build clean-core-deps-fetch-fail-unknown +core-deps-fetch-fail-unknown: build clean $i "Bootstrap a new OTP library named $(APP)" $t mkdir $(APP)/ @@ -679,7 +687,7 @@ core-deps-fetch-fail-unknown: build clean-core-deps-fetch-fail-unknown $i "Check that building the application fails" $t ! $(MAKE) -C $(APP) $v -core-deps-fetch-git: build clean-core-deps-fetch-git +core-deps-fetch-git: build clean $i "Bootstrap a new OTP library named $(APP)" $t mkdir $(APP)/ @@ -710,7 +718,7 @@ endif {ok, \"1.0.0\"} = application:get_key(cowboy, vsn), \ halt()" -core-deps-fetch-git-submodule: build clean-core-deps-fetch-git-submodule +core-deps-fetch-git-submodule: build clean $i "Bootstrap a new OTP library named $(APP)" $t mkdir $(APP)/ @@ -764,7 +772,7 @@ endif true = lists:member(my_dep, Deps), \ halt()" -core-deps-fetch-hex: build clean-core-deps-fetch-hex +core-deps-fetch-hex: build clean $i "Bootstrap a new OTP library named $(APP)" $t mkdir $(APP)/ @@ -795,7 +803,7 @@ endif {ok, \"1.0.0\"} = application:get_key(cowboy, vsn), \ halt()" -core-deps-fetch-hg: build clean-core-deps-fetch-hg +core-deps-fetch-hg: build clean $i "Bootstrap a new OTP library named $(APP)" $t mkdir $(APP)/ @@ -825,7 +833,7 @@ endif halt()" # Legacy must fail for the top-level application, but work for dependencies. -core-deps-fetch-legacy: build clean-core-deps-fetch-legacy +core-deps-fetch-legacy: build clean $i "Bootstrap a new OTP library named $(APP)" $t mkdir $(APP)/ @@ -841,7 +849,7 @@ core-deps-fetch-legacy: build clean-core-deps-fetch-legacy $i "Check that building the application works with IS_DEP=1" $t $(MAKE) -C $(APP) IS_DEP=1 $v -core-deps-fetch-svn: build clean-core-deps-fetch-svn +core-deps-fetch-svn: build clean $i "Bootstrap a new OTP library named $(APP)" $t mkdir $(APP)/ @@ -870,7 +878,7 @@ endif {ok, \"1.0.0\"} = application:get_key(cowlib, vsn), \ halt()" -core-deps-ignore: build clean-core-deps-ignore +core-deps-ignore: build clean $i "Bootstrap a new OTP library named $(APP)" $t mkdir $(APP)/ @@ -899,7 +907,7 @@ endif $i "Check that the correct dependencies were fetched" $t test -d $(APP)/deps/ranch -core-deps-mv: build clean-core-deps-mv clean-core-deps-mv-moved +core-deps-mv: build clean $i "Bootstrap a new OTP library named $(APP)" $t mkdir $(APP)/ @@ -921,7 +929,7 @@ core-deps-mv: build clean-core-deps-mv clean-core-deps-mv-moved $i "Build the application" $t $(MAKE) -C $(APP)-moved $v -core-deps-mv-rebar: build clean-core-deps-mv-rebar clean-core-deps-mv-rebar-moved +core-deps-mv-rebar: build clean $i "Bootstrap a new OTP library named $(APP)" $t mkdir $(APP)/ @@ -946,7 +954,7 @@ core-deps-mv-rebar: build clean-core-deps-mv-rebar clean-core-deps-mv-rebar-move # A lower-level dependency of the first dependency always # wins over a lower-level dependency of the second dependency. -core-deps-order-first: build clean-core-deps-order-first +core-deps-order-first: build clean $i "Bootstrap a new OTP library named $(APP)" $t mkdir $(APP)/ @@ -987,7 +995,7 @@ endif halt()" # A higher-level dependency always wins. -core-deps-order-top: build clean-core-deps-order-top +core-deps-order-top: build clean $i "Bootstrap a new OTP library named $(APP)" $t mkdir $(APP)/ @@ -1018,7 +1026,7 @@ endif {ok, \"1.0.0\"} = application:get_key(cowlib, vsn), \ halt()" -core-deps-no-autopatch: build clean-core-deps-no-autopatch +core-deps-no-autopatch: build clean $i "Bootstrap a new OTP library named $(APP)" $t mkdir $(APP)/ @@ -1039,7 +1047,7 @@ core-deps-no-autopatch: build clean-core-deps-no-autopatch $i "Check that Cowlib was not autopatched" $t grep -q Hoguin $(APP)/deps/cowlib/erlang.mk -core-deps-no-autopatch-erlang-mk: build clean-core-deps-no-autopatch-erlang-mk +core-deps-no-autopatch-erlang-mk: build clean $i "Bootstrap a new OTP library named $(APP)" $t mkdir $(APP)/ @@ -1058,7 +1066,7 @@ core-deps-no-autopatch-erlang-mk: build clean-core-deps-no-autopatch-erlang-mk $i "Check that Erlang.mk was not autopatched" $t grep -q Hoguin $(APP)/deps/cowlib/erlang.mk -core-deps-no-autopatch-rebar: build clean-core-deps-no-autopatch-rebar +core-deps-no-autopatch-rebar: build clean $i "Bootstrap a new OTP library named $(APP)" $t mkdir $(APP)/ @@ -1080,7 +1088,7 @@ core-deps-no-autopatch-rebar: build clean-core-deps-no-autopatch-rebar $t if grep -q erlang\.mk $(APP)/deps/lager/Makefile; then false; fi ifndef LEGACY -core-deps-otp: build clean-core-deps-otp +core-deps-otp: build clean $i "Bootstrap a new OTP library named $(APP)" $t mkdir $(APP)/ @@ -1104,7 +1112,7 @@ core-deps-otp: build clean-core-deps-otp halt()" endif -core-deps-pkg: build clean-core-deps-pkg +core-deps-pkg: build clean $i "Bootstrap a new OTP library named $(APP)" $t mkdir $(APP)/ @@ -1134,7 +1142,7 @@ endif true = lists:member(cowboy, Deps), \ halt()" -core-deps-rel: build clean-core-deps-rel +core-deps-rel: build clean $i "Bootstrap a new release-enabled OTP library named $(APP)" $t mkdir $(APP)/ @@ -1195,7 +1203,7 @@ else $t $(APP)/_rel/$(APP)_release/bin/$(APP)_release stop $v endif -core-deps-search: build clean-core-deps-search +core-deps-search: build clean $i "Bootstrap a new OTP library named $(APP)" $t mkdir $(APP)/ @@ -1208,7 +1216,7 @@ core-deps-search: build clean-core-deps-search $i "Run 'make search q=cowboy' and check that it prints packages" $t test -n "`$(MAKE) -C $(APP) search q=cowboy`" -core-deps-shell: build clean-core-deps-shell +core-deps-shell: build clean $i "Bootstrap a new OTP library named $(APP)" $t mkdir $(APP)/ @@ -1247,7 +1255,7 @@ core-deps-shell: build clean-core-deps-shell false = lists:member(tddreloader, Deps), \ halt()" -core-deps-skip: build clean-core-deps-skip +core-deps-skip: build clean $i "Bootstrap a new OTP library named $(APP)" $t mkdir $(APP)/ @@ -1284,7 +1292,7 @@ endif $t test -d $(APP)/deps/cowboy $t test -d $(APP)/deps/ranch -core-deps-test: build clean-core-deps-test +core-deps-test: build clean $i "Bootstrap a new OTP library named $(APP)" $t mkdir $(APP)/ diff --git a/test/core_plugins.mk b/test/core_plugins.mk index 184c08f..6d10f2a 100644 --- a/test/core_plugins.mk +++ b/test/core_plugins.mk @@ -2,18 +2,12 @@ CORE_PLUGINS_CASES = all one CORE_PLUGINS_TARGETS = $(addprefix core-plugins-,$(CORE_PLUGINS_CASES)) -CORE_PLUGINS_CLEAN_TARGETS = $(addprefix clean-,$(CORE_PLUGINS_TARGETS)) -.PHONY: core-plugins $(CORE_PLUGINS_TARGETS) clean-core-plugins $(CORE_PLUGINS_CLEAN_TARGETS) - -clean-core-plugins: $(CORE_PLUGINS_CLEAN_TARGETS) - -$(CORE_PLUGINS_CLEAN_TARGETS): - $t rm -rf $(APP_TO_CLEAN)/ +.PHONY: core-plugins $(CORE_PLUGINS_TARGETS) core-plugins: $(CORE_PLUGINS_TARGETS) -core-plugins-all: build clean-core-plugins-all +core-plugins-all: build clean $i "Bootstrap a new OTP library named $(APP)" $t mkdir $(APP)/ @@ -45,7 +39,7 @@ core-plugins-all: build clean-core-plugins-all $i "Run 'make plugin2' and check that it prints plugin2" $t test -n "`$(MAKE) -C $(APP) plugin2 | grep plugin2`" -core-plugins-one: build clean-core-plugins-one +core-plugins-one: build clean $i "Bootstrap a new OTP library named $(APP)" $t mkdir $(APP)/ diff --git a/test/core_upgrade.mk b/test/core_upgrade.mk index c4a8725..64a8b5d 100644 --- a/test/core_upgrade.mk +++ b/test/core_upgrade.mk @@ -1,19 +1,42 @@ # Core: Erlang.mk upgrade. -CORE_UPGRADE_CASES = custom-build-dir custom-config custom-repo no-config renamed-config +CORE_UPGRADE_CASES = conflicting-configs custom-build-dir custom-config custom-repo no-config renamed-config CORE_UPGRADE_TARGETS = $(addprefix core-upgrade-,$(CORE_UPGRADE_CASES)) -CORE_UPGRADE_CLEAN_TARGETS = $(addprefix clean-,$(CORE_UPGRADE_TARGETS)) -.PHONY: core-upgrade $(CORE_UPGRADE_TARGETS) clean-core-upgrade $(CORE_UPGRADE_CLEAN_TARGETS) +.PHONY: core-upgrade $(CORE_UPGRADE_TARGETS) -clean-core-upgrade: $(CORE_UPGRADE_CLEAN_TARGETS) +core-upgrade: $(CORE_UPGRADE_TARGETS) -$(CORE_UPGRADE_CLEAN_TARGETS): - $t rm -rf $(APP_TO_CLEAN)/ +core-upgrade-conflicting-configs: build clean -core-upgrade: $(CORE_UPGRADE_TARGETS) + $i "Bootstrap a new OTP library named $(APP)" + $t mkdir $(APP)/ + $t cp ../erlang.mk $(APP)/ + $t $(MAKE) -C $(APP) -f erlang.mk bootstrap-lib $v + + $i "Fork erlang.mk locally and modify it" + $t git clone -q https://github.com/ninenines/erlang.mk $(APP)/alt-erlangmk-repo + $t echo core/core > $(APP)/alt-erlangmk-repo/build.config + $t (cd $(APP)/alt-erlangmk-repo && \ + git checkout -q -b test-modified-build.config && \ + git config user.email "[email protected]" && \ + git config user.name "test suite" && \ + git commit -q -a -m 'Modify build.config' && \ + git checkout master) + + $i "Point application to an alternate erlang.mk repository" + $t perl -ni.bak -e 'print;if ($$.==1) {print "ERLANG_MK_REPO = file://$(abspath $(APP)/alt-erlangmk-repo)\nERLANG_MK_COMMIT = test-modified-build.config\n"}' $(APP)/Makefile + + $i "Create a custom build.config file without plugins" + $t echo "core/*" > $(APP)/build.config + + $i "Upgrade Erlang.mk" + $t $(MAKE) -C $(APP) erlang-mk $v + + $i "Check that the bootstrap plugin is gone" + $t ! $(MAKE) -C $(APP) list-templates $v -core-upgrade-custom-build-dir: build clean-core-upgrade-custom-build-dir +core-upgrade-custom-build-dir: build clean $i "Bootstrap a new OTP library named $(APP)" $t mkdir $(APP)/ @@ -39,7 +62,7 @@ core-upgrade-custom-build-dir: build clean-core-upgrade-custom-build-dir $i "Check that the custom build directory is gone" $t test ! -d $(APP)/custom/ -core-upgrade-custom-config: build clean-core-upgrade-custom-config +core-upgrade-custom-config: build clean $i "Bootstrap a new OTP library named $(APP)" $t mkdir $(APP)/ @@ -55,7 +78,7 @@ core-upgrade-custom-config: build clean-core-upgrade-custom-config $i "Check that the bootstrap plugin is gone" $t ! $(MAKE) -C $(APP) list-templates $v -core-upgrade-custom-repo: build clean-core-upgrade-custom-repo +core-upgrade-custom-repo: build clean $i "Bootstrap a new OTP library named $(APP)" $t mkdir $(APP)/ @@ -69,7 +92,8 @@ core-upgrade-custom-repo: build clean-core-upgrade-custom-repo git checkout -q -b test-copyright && \ git config user.email "[email protected]" && \ git config user.name "test suite" && \ - git commit -q -a -m 'Add Testsuite copyright') + git commit -q -a -m 'Add Testsuite copyright' && \ + git checkout master) $i "Point application to an alternate erlang.mk repository" $t perl -ni.bak -e 'print;if ($$.==1) {print "ERLANG_MK_REPO = file://$(abspath $(APP)/alt-erlangmk-repo)\nERLANG_MK_COMMIT = test-copyright\n"}' $(APP)/Makefile @@ -80,7 +104,7 @@ core-upgrade-custom-repo: build clean-core-upgrade-custom-repo $i "Check our modification is there" $t grep -q "# Copyright (c) erlang.mk Testsuite!" $(APP)/erlang.mk -core-upgrade-no-config: build clean-core-upgrade-no-config +core-upgrade-no-config: build clean $i "Bootstrap a new OTP library named $(APP)" $t mkdir $(APP)/ @@ -99,7 +123,7 @@ core-upgrade-no-config: build clean-core-upgrade-no-config $i "Check that the rule is gone" $t ! $(MAKE) -C $(APP) erlang_mk_upgrade_test_rule $v -core-upgrade-renamed-config: build clean-core-upgrade-renamed-config +core-upgrade-renamed-config: build clean $i "Bootstrap a new OTP library named $(APP)" $t mkdir $(APP)/ diff --git a/test/plugin_asciidoc.mk b/test/plugin_asciidoc.mk new file mode 100644 index 0000000..a583585 --- /dev/null +++ b/test/plugin_asciidoc.mk @@ -0,0 +1,158 @@ +# AsciiDoc plugin. + +ASCIIDOC_CASES = build docs guide install manual +ASCIIDOC_TARGETS = $(addprefix asciidoc-,$(ASCIIDOC_CASES)) + +.PHONY: asciidoc $(ASCIIDOC_TARGETS) + +asciidoc: $(ASCIIDOC_TARGETS) + +asciidoc-build: build clean + + $i "Bootstrap a new OTP application named $(APP)" + $t mkdir $(APP)/ + $t cp ../erlang.mk $(APP)/ + $t $(MAKE) -C $(APP) -f erlang.mk bootstrap $v + + $i "Only enable man pages section 3" + $t perl -ni.bak -e 'print;if ($$.==1) {print "MAN_SECTIONS = 3\n"}' $(APP)/Makefile + + $i "Run AsciiDoc" + $t $(MAKE) -C $(APP) asciidoc $v + + $i "Check that no documentation was generated" + $t test ! -e $(APP)/doc/guide.pdf + $t test ! -e $(APP)/doc/html/ + $t test ! -e $(APP)/doc/man3/ + + $i "Generate AsciiDoc documentation" + $t mkdir -p $(APP)/doc/src/guide/ $(APP)/doc/src/manual/ + $t printf "%s\n" \ + "= Erlang.mk tests" "" \ + "Hello world!" > $(APP)/doc/src/guide/book.asciidoc + $t printf "%s\n" \ + "= erlang_mk(3)" "" \ + "== Name" "" \ + "erlang_mk - Erlang.mk test" "" \ + "== Description" "" \ + "Hello world!" > $(APP)/doc/src/manual/erlang_mk.asciidoc + + $i "Run AsciiDoc" + $t $(MAKE) -C $(APP) asciidoc $v + + $i "Check that the documentation was generated" + $t test -f $(APP)/doc/guide.pdf + $t test -d $(APP)/doc/html/ + $t test -f $(APP)/doc/man3/erlang_mk.3.gz + + $i "Distclean the application" + $t $(MAKE) -C $(APP) distclean $v + + $i "Check that the generated documentation was removed" + $t test ! -e $(APP)/doc/guide.pdf + $t test ! -e $(APP)/doc/html/ + $t test ! -e $(APP)/doc/man3/ + + $i "Generate an invalid AsciiDoc file" + $t printf "%s\n" \ + "= fail(3)" "" \ + "This will fail because the Name section is missing." > $(APP)/doc/src/manual/fail.asciidoc + + $i "Check that AsciiDoc errors out" + $t ! $(MAKE) -C $(APP) asciidoc $v + +asciidoc-docs: build clean + + $i "Bootstrap a new OTP application named $(APP)" + $t mkdir $(APP)/ + $t cp ../erlang.mk $(APP)/ + $t $(MAKE) -C $(APP) -f erlang.mk bootstrap $v + + $i "Generate AsciiDoc documentation" + $t mkdir -p $(APP)/doc/src/guide/ + $t printf "%s\n" \ + "= Erlang.mk tests" "" \ + "Hello world!" > $(APP)/doc/src/guide/book.asciidoc + + $i "Check that AsciiDoc runs on 'make docs'" + $t $(MAKE) -C $(APP) docs $v + $t test -f $(APP)/doc/guide.pdf + $t test -d $(APP)/doc/html/ + +asciidoc-guide: build clean + + $i "Bootstrap a new OTP application named $(APP)" + $t mkdir $(APP)/ + $t cp ../erlang.mk $(APP)/ + $t $(MAKE) -C $(APP) -f erlang.mk bootstrap $v + + $i "Generate AsciiDoc documentation" + $t mkdir -p $(APP)/doc/src/guide/ $(APP)/doc/src/manual/ + $t printf "%s\n" \ + "= Erlang.mk tests" "" \ + "Hello world!" > $(APP)/doc/src/guide/book.asciidoc + $t printf "%s\n" \ + "= erlang_mk(3)" "" \ + "== Name" "" \ + "erlang_mk - Erlang.mk test" "" \ + "== Description" "" \ + "Hello world!" > $(APP)/doc/src/manual/erlang_mk.asciidoc + + $i "Check that only the guide is generated on 'make asciidoc-guide'" + $t $(MAKE) -C $(APP) asciidoc-guide $v + $t test -f $(APP)/doc/guide.pdf + $t test -d $(APP)/doc/html/ + $t test ! -e $(APP)/doc/man3/ + +asciidoc-install: build clean + + $i "Bootstrap a new OTP application named $(APP)" + $t mkdir $(APP)/ + $t cp ../erlang.mk $(APP)/ + $t $(MAKE) -C $(APP) -f erlang.mk bootstrap $v + + $i "Only enable man pages section 3" + $t perl -ni.bak -e 'print;if ($$.==1) {print "MAN_SECTIONS = 3\n"}' $(APP)/Makefile + + $i "Generate AsciiDoc documentation" + $t mkdir -p $(APP)/doc/src/manual/ + $t printf "%s\n" \ + "= erlang_mk(3)" "" \ + "== Name" "" \ + "erlang_mk - Erlang.mk test" "" \ + "== Description" "" \ + "Hello world!" > $(APP)/doc/src/manual/erlang_mk.asciidoc + + $i "Build and install the man pages to $(APP)/installed/" + $t $(MAKE) -C $(APP) install-docs MAN_INSTALL_PATH=installed/share $v + + $i "Check that the documentation was installed properly" + $t test -f $(APP)/installed/share/man3/erlang_mk.3.gz + +asciidoc-manual: build clean + + $i "Bootstrap a new OTP application named $(APP)" + $t mkdir $(APP)/ + $t cp ../erlang.mk $(APP)/ + $t $(MAKE) -C $(APP) -f erlang.mk bootstrap $v + + $i "Only enable man pages section 3" + $t perl -ni.bak -e 'print;if ($$.==1) {print "MAN_SECTIONS = 3\n"}' $(APP)/Makefile + + $i "Generate AsciiDoc documentation" + $t mkdir -p $(APP)/doc/src/guide/ $(APP)/doc/src/manual/ + $t printf "%s\n" \ + "= Erlang.mk tests" "" \ + "Hello world!" > $(APP)/doc/src/guide/book.asciidoc + $t printf "%s\n" \ + "= erlang_mk(3)" "" \ + "== Name" "" \ + "erlang_mk - Erlang.mk test" "" \ + "== Description" "" \ + "Hello world!" > $(APP)/doc/src/manual/erlang_mk.asciidoc + + $i "Check that only the manual is generated on 'make asciidoc-manual'" + $t $(MAKE) -C $(APP) asciidoc-manual $v + $t test ! -e $(APP)/doc/guide.pdf + $t test ! -e $(APP)/doc/html/ + $t test -f $(APP)/doc/man3/erlang_mk.3.gz diff --git a/test/plugin_bootstrap.mk b/test/plugin_bootstrap.mk index 16bfb58..2b62b6f 100644 --- a/test/plugin_bootstrap.mk +++ b/test/plugin_bootstrap.mk @@ -1,19 +1,13 @@ # Bootstrap plugin. -BOOTSTRAP_CASES = app lib rel templates +BOOTSTRAP_CASES = app lib rel sp tab templates BOOTSTRAP_TARGETS = $(addprefix bootstrap-,$(BOOTSTRAP_CASES)) -BOOTSTRAP_CLEAN_TARGETS = $(addprefix clean-,$(BOOTSTRAP_TARGETS)) -.PHONY: bootstrap $(BOOTSTRAP_TARGETS) clean-bootstrap $(BOOTSTRAP_CLEAN_TARGETS) - -clean-bootstrap: $(BOOTSTRAP_CLEAN_TARGETS) - -$(BOOTSTRAP_CLEAN_TARGETS): - $t rm -rf $(APP_TO_CLEAN)/ +.PHONY: bootstrap $(BOOTSTRAP_TARGETS) bootstrap: $(BOOTSTRAP_TARGETS) -bootstrap-app: build clean-bootstrap-app +bootstrap-app: build clean $i "Bootstrap a new OTP application named $(APP)" $t mkdir $(APP)/ @@ -44,7 +38,7 @@ endif {module, $(APP)_sup} = code:load_file($(APP)_sup), \ halt()" -bootstrap-lib: build clean-bootstrap-lib +bootstrap-lib: build clean $i "Bootstrap a new OTP library named $(APP)" $t mkdir $(APP)/ @@ -69,7 +63,7 @@ endif {ok, []} = application:get_key($(APP), modules), \ halt()" -bootstrap-rel: build clean-bootstrap-rel +bootstrap-rel: build clean $i "Bootstrap a new release-enabled OTP application named $(APP)" $t mkdir $(APP)/ @@ -116,7 +110,68 @@ endif $i "Check that there's no erl_crash.dump file" $t test ! -f $(APP)/_rel/$(APP)_release/erl_crash.dump -bootstrap-templates: build clean-bootstrap-templates +bootstrap-sp: build clean + + $i "Bootstrap a new OTP application named $(APP)" + $t mkdir $(APP)/ + $t cp ../erlang.mk $(APP)/ + $t $(MAKE) -C $(APP) -f erlang.mk bootstrap SP=2 $v + + $i "Check that all bootstrapped files exist" + $t test -f $(APP)/Makefile +ifdef LEGACY + $t test -f $(APP)/src/$(APP).app.src +endif + $t test -f $(APP)/src/$(APP)_app.erl + $t test -f $(APP)/src/$(APP)_sup.erl + + $i "Check that bootstrapped files have no tabs" +ifdef LEGACY + $t test -z "`awk -F "\t" 'NF > 1' $(APP)/src/$(APP).app.src`" +endif + $t test -z "`awk -F "\t" 'NF > 1' $(APP)/src/$(APP)_app.erl`" + $t test -z "`awk -F "\t" 'NF > 1' $(APP)/src/$(APP)_sup.erl`" + +# Everything looks OK, but let's compile the application to make sure. + $i "Build the application" + $t $(MAKE) -C $(APP) $v + + $i "Check that all compiled files exist" + $t test -f $(APP)/ebin/$(APP).app + $t test -f $(APP)/ebin/$(APP)_app.beam + $t test -f $(APP)/ebin/$(APP)_sup.beam + + $i "Check that the application was compiled correctly" + $t $(ERL) -pa $(APP)/ebin/ -eval " \ + ok = application:start($(APP)), \ + {ok, [$(APP)_app, $(APP)_sup]} = application:get_key($(APP), modules), \ + {module, $(APP)_app} = code:load_file($(APP)_app), \ + {module, $(APP)_sup} = code:load_file($(APP)_sup), \ + halt()" + +bootstrap-tab: build clean + + $i "Bootstrap a new OTP application named $(APP)" + $t mkdir $(APP)/ + $t cp ../erlang.mk $(APP)/ + $t $(MAKE) -C $(APP) -f erlang.mk bootstrap $v + + $i "Check that all bootstrapped files exist" + $t test -f $(APP)/Makefile +ifdef LEGACY + $t test -f $(APP)/src/$(APP).app.src +endif + $t test -f $(APP)/src/$(APP)_app.erl + $t test -f $(APP)/src/$(APP)_sup.erl + + $i "Check that bootstrapped files have tabs" +ifdef LEGACY + $t test "`awk -F "\t" 'NF > 1' $(APP)/src/$(APP).app.src`" +endif + $t test "`awk -F "\t" 'NF > 1' $(APP)/src/$(APP)_app.erl`" + $t test "`awk -F "\t" 'NF > 1' $(APP)/src/$(APP)_sup.erl`" + +bootstrap-templates: build clean $i "Bootstrap a new OTP library named $(APP)" $t mkdir $(APP)/ @@ -135,6 +190,7 @@ bootstrap-templates: build clean-bootstrap-templates $t $(MAKE) -C $(APP) --no-print-directory new t=cowboy_rest n=my_rest $t $(MAKE) -C $(APP) --no-print-directory new t=cowboy_ws n=my_ws $t $(MAKE) -C $(APP) --no-print-directory new t=ranch_protocol n=my_protocol + $t $(MAKE) -C $(APP) --no-print-directory new t=module n=my_module # Here we disable warnings because templates contain missing behaviors. $i "Build the application" @@ -145,11 +201,12 @@ bootstrap-templates: build clean-bootstrap-templates $t test -f $(APP)/ebin/my_fsm.beam $t test -f $(APP)/ebin/my_server.beam $t test -f $(APP)/ebin/my_sup.beam + $t test -f $(APP)/ebin/my_module.beam $i "Check that all the modules can be loaded" $t $(ERL) -pa $(APP)/ebin/ -eval " \ ok = application:start($(APP)), \ - {ok, Mods = [my_fsm, my_http, my_loop, my_protocol, my_rest, my_server, my_sup, my_ws]} \ + {ok, Mods = [my_fsm, my_http, my_loop, my_module, my_protocol, my_rest, my_server, my_sup, my_ws]} \ = application:get_key($(APP), modules), \ [{module, M} = code:load_file(M) || M <- Mods], \ halt()" diff --git a/test/plugin_c_src.mk b/test/plugin_c_src.mk new file mode 100644 index 0000000..5e4e7fe --- /dev/null +++ b/test/plugin_c_src.mk @@ -0,0 +1,89 @@ +# C source plugin. + +C_SRC_CASES = cpp custom dir env nif port +C_SRC_TARGETS = $(addprefix c-src-,$(C_SRC_CASES)) + +.PHONY: c-src $(C_SRC_TARGETS) + +c-src: $(C_SRC_TARGETS) +c_src: c-src + +c-src-nif: build clean + + $i "Bootstrap a new OTP library named $(APP)" + $t mkdir $(APP)/ + $t cp ../erlang.mk $(APP)/ + $t $(MAKE) -C $(APP) -f erlang.mk bootstrap-lib $v + + $i "Generate a NIF from templates" + $t $(MAKE) -C $(APP) new-nif n=$(APP) $v + + $i "Build the application" + $t $(MAKE) -C $(APP) $v + + $i "Check that all compiled files exist" + $t test -f $(APP)/$(APP).d + $t test -f $(APP)/c_src/$(APP).o + $t test -f $(APP)/c_src/env.mk + $t test -f $(APP)/ebin/$(APP).app + $t test -f $(APP)/ebin/$(APP).beam +ifeq ($(PLATFORM),msys2) + $t test -f $(APP)/priv/$(APP).dll +else + $t test -f $(APP)/priv/$(APP).so +endif + + $i "Check that the application was compiled correctly" + $t $(ERL) -pa $(APP)/ebin/ -eval " \ + ok = application:start($(APP)), \ + {ok, [$(APP)]} = application:get_key($(APP), modules), \ + {module, $(APP)} = code:load_file($(APP)), \ + {hello, joe} = $(APP):hello(joe), \ + {hello, mike} = $(APP):hello(mike), \ + {hello, robert} = $(APP):hello(robert), \ + halt()" + + $i "Re-build the application" + $t $(MAKE) -C $(APP) $v + + $i "Check that all compiled files exist" + $t test -f $(APP)/$(APP).d + $t test -f $(APP)/c_src/$(APP).o + $t test -f $(APP)/c_src/env.mk + $t test -f $(APP)/ebin/$(APP).app + $t test -f $(APP)/ebin/$(APP).beam +ifeq ($(PLATFORM),msys2) + $t test -f $(APP)/priv/$(APP).dll +else + $t test -f $(APP)/priv/$(APP).so +endif + + $i "Check that the application was compiled correctly" + $t $(ERL) -pa $(APP)/ebin/ -eval " \ + ok = application:start($(APP)), \ + {ok, [$(APP)]} = application:get_key($(APP), modules), \ + {module, $(APP)} = code:load_file($(APP)), \ + {hello, joe} = $(APP):hello(joe), \ + {hello, mike} = $(APP):hello(mike), \ + {hello, robert} = $(APP):hello(robert), \ + halt()" + + $i "Clean the application" + $t $(MAKE) -C $(APP) clean $v + + $i "Check that all intermediate files were removed" + $t test ! -e $(APP)/$(APP).d + $t test ! -e $(APP)/c_src/$(APP).o + $t test ! -e $(APP)/ebin/$(APP).app + $t test ! -e $(APP)/ebin/$(APP).beam +ifeq ($(PLATFORM),msys2) + $t test ! -e $(APP)/priv/$(APP).dll +else + $t test ! -e $(APP)/priv/$(APP).so +endif + + $i "Distclean the application" + $t $(MAKE) -C $(APP) distclean $v + + $i "Check that all files were removed" + $t test ! -e $(APP)/c_src/env.mk diff --git a/test/plugin_ct.mk b/test/plugin_ct.mk new file mode 100644 index 0000000..c32fa36 --- /dev/null +++ b/test/plugin_ct.mk @@ -0,0 +1,226 @@ +# Common Test plugin. + +CT_CASES = all apps-only case check group opts suite tests +CT_TARGETS = $(addprefix ct-,$(CT_CASES)) + +.PHONY: ct $(CT_TARGETS) + +ct: $(CT_TARGETS) + +ct-all: build clean + + $i "Bootstrap a new OTP application named $(APP)" + $t mkdir $(APP)/ + $t cp ../erlang.mk $(APP)/ + $t $(MAKE) -C $(APP) -f erlang.mk bootstrap $v + + $i "Check that Common Test detects no tests" + $t $(MAKE) -C $(APP) ct | grep -q "Nothing to be done for 'ct'." + + $i "Generate a Common Test suite" + $t mkdir $(APP)/test + $t printf "%s\n" \ + "-module($(APP)_SUITE)." \ + "-export([all/0, ok/1])." \ + "all() -> [ok]." \ + "ok(_) -> ok." > $(APP)/test/$(APP)_SUITE.erl + + $i "Check that Common Test runs tests" +# We can't pipe CT's output without it crashing, so let's check that +# the command succeeds and log files are created instead. + $t test ! -e $(APP)/logs/index.html + $t $(MAKE) -C $(APP) ct $v + $t test -f $(APP)/logs/index.html + + $i "Generate a Common Test suite with a failing test case" + $t printf "%s\n" \ + "-module($(APP)_fail_SUITE)." \ + "-export([all/0, fail/1])." \ + "all() -> [fail]." \ + "fail(_) -> throw(fail)." > $(APP)/test/$(APP)_fail_SUITE.erl + + $i "Check that Common Test errors out" + $t ! $(MAKE) -C $(APP) ct $v + + $i "Check that logs are kept on clean" + $t $(MAKE) -C $(APP) clean $v + $t test -f $(APP)/logs/index.html + + $i "Check that logs are deleted on distclean" + $t $(MAKE) -C $(APP) distclean $v + $t test ! -e $(APP)/logs/index.html + +ct-apps-only: build clean + + $i "Create a multi application repository with no root application" + $t mkdir $(APP)/ + $t cp ../erlang.mk $(APP)/ + $t echo "include erlang.mk" > $(APP)/Makefile + + $i "Create a new application named my_app" + $t $(MAKE) -C $(APP) new-app in=my_app $v + + $i "Create a new library named my_lib" + $t $(MAKE) -C $(APP) new-lib in=my_lib $v + + $i "Populate my_lib" + $t printf "%s\n" \ + "-module(my_lib)." \ + "-export([random_int/0])." \ + "random_int() -> 4." > $(APP)/apps/my_lib/src/my_lib.erl + + $i "Check that Common Test detects no tests" + $t $(MAKE) -C $(APP) ct | grep -q "Nothing to be done for 'ct'." + + $i "Generate a Common Test suite in my_app" + $t mkdir $(APP)/apps/my_app/test + $t printf "%s\n" \ + "-module(my_app_SUITE)." \ + "-export([all/0, ok/1, call_my_lib/1])." \ + "all() -> [ok, call_my_lib]." \ + "ok(_) -> ok." \ + "call_my_lib(_) -> 4 = my_lib:random_int()." > $(APP)/apps/my_app/test/my_app_SUITE.erl + + $i "Generate a Common Test suite in my_lib" + $t mkdir $(APP)/apps/my_lib/test + $t printf "%s\n" \ + "-module(my_lib_SUITE)." \ + "-export([all/0, ok/1])." \ + "all() -> [ok]." \ + "ok(_) -> ok." > $(APP)/apps/my_lib/test/my_lib_SUITE.erl + + $i "Check that Common Test runs tests" +# We can't pipe CT's output without it crashing, so let's check that +# the command succeeds and log files are created instead. + $t test ! -e $(APP)/apps/my_app/logs/index.html + $t test ! -e $(APP)/apps/my_lib/logs/index.html + $t $(MAKE) -C $(APP) ct $v + $t test -f $(APP)/apps/my_app/logs/index.html + $t test -f $(APP)/apps/my_lib/logs/index.html + +ct-case: build clean + + $i "Bootstrap a new OTP application named $(APP)" + $t mkdir $(APP)/ + $t cp ../erlang.mk $(APP)/ + $t $(MAKE) -C $(APP) -f erlang.mk bootstrap $v + + $i "Generate a Common Test suite with two cases" + $t mkdir $(APP)/test + $t printf "%s\n" \ + "-module($(APP)_SUITE)." \ + "-export([all/0, groups/0, ok/1, bad/1])." \ + "all() -> [{group, mygroup}]." \ + "groups() -> [{mygroup, [ok, bad]}]." \ + "ok(_) -> ok." \ + "bad(_) -> throw(fail)." > $(APP)/test/$(APP)_SUITE.erl + + $i "Check that we can run Common Test on a specific test case" + $t $(MAKE) -C $(APP) ct-$(APP) t=mygroup:ok $v + +ct-check: build clean + + $i "Bootstrap a new OTP application named $(APP)" + $t mkdir $(APP)/ + $t cp ../erlang.mk $(APP)/ + $t $(MAKE) -C $(APP) -f erlang.mk bootstrap $v + + $i "Generate a Common Test suite" + $t mkdir $(APP)/test + $t printf "%s\n" \ + "-module($(APP)_SUITE)." \ + "-export([all/0, ok/1])." \ + "all() -> [ok]." \ + "ok(_) -> ok." > $(APP)/test/$(APP)_SUITE.erl + + $i "Check that Common Test runs on 'make check'" + $t test ! -e $(APP)/logs/index.html + $t $(MAKE) -C $(APP) check $v + $t test -f $(APP)/logs/index.html + +ct-group: build clean + + $i "Bootstrap a new OTP application named $(APP)" + $t mkdir $(APP)/ + $t cp ../erlang.mk $(APP)/ + $t $(MAKE) -C $(APP) -f erlang.mk bootstrap $v + + $i "Generate a Common Test suite with two groups" + $t mkdir $(APP)/test + $t printf "%s\n" \ + "-module($(APP)_SUITE)." \ + "-export([all/0, groups/0, ok/1, bad/1])." \ + "all() -> [{group, okgroup}, {group, badgroup}]." \ + "groups() -> [{okgroup, [ok]}, {badgroup, [bad]}]." \ + "ok(_) -> ok." \ + "bad(_) -> throw(fail)." > $(APP)/test/$(APP)_SUITE.erl + + $i "Check that we can run Common Test on a specific group" + $t $(MAKE) -C $(APP) ct-$(APP) t=okgroup $v + +ct-opts: build clean + + $i "Bootstrap a new OTP application named $(APP)" + $t mkdir $(APP)/ + $t cp ../erlang.mk $(APP)/ + $t $(MAKE) -C $(APP) -f erlang.mk bootstrap $v + + $i "Set CT_OPTS in the Makefile" + $t perl -ni.bak -e 'print;if ($$.==1) {print "CT_OPTS = -label hello_ct_opts\n"}' $(APP)/Makefile + + $i "Generate a Common Test suite" + $t mkdir $(APP)/test + $t printf "%s\n" \ + "-module($(APP)_SUITE)." \ + "-export([all/0, ok/1])." \ + "all() -> [ok]." \ + "ok(_) -> ok." > $(APP)/test/$(APP)_SUITE.erl + + $i "Run Common Test" + $t $(MAKE) -C $(APP) ct $v + + $i "Check that Common Test uses options from CT_OPTS" + $t grep -q hello_ct_opts $(APP)/logs/index.html + +ct-suite: build clean + + $i "Bootstrap a new OTP application named $(APP)" + $t mkdir $(APP)/ + $t cp ../erlang.mk $(APP)/ + $t $(MAKE) -C $(APP) -f erlang.mk bootstrap $v + + $i "Generate two Common Test suites" + $t mkdir $(APP)/test + $t printf "%s\n" \ + "-module($(APP)_ok_SUITE)." \ + "-export([all/0, ok/1])." \ + "all() -> [ok]." \ + "ok(_) -> ok." > $(APP)/test/$(APP)_ok_SUITE.erl + $t printf "%s\n" \ + "-module($(APP)_fail_SUITE)." \ + "-export([all/0, bad/1])." \ + "all() -> [bad]." \ + "bad(_) -> throw(fail)." > $(APP)/test/$(APP)_fail_SUITE.erl + + $i "Check that we can run Common Test on a specific test suite" + $t $(MAKE) -C $(APP) ct-$(APP)_ok $v + +ct-tests: build clean + + $i "Bootstrap a new OTP application named $(APP)" + $t mkdir $(APP)/ + $t cp ../erlang.mk $(APP)/ + $t $(MAKE) -C $(APP) -f erlang.mk bootstrap $v + + $i "Generate a Common Test suite" + $t mkdir $(APP)/test + $t printf "%s\n" \ + "-module($(APP)_SUITE)." \ + "-export([all/0, ok/1])." \ + "all() -> [ok]." \ + "ok(_) -> ok." > $(APP)/test/$(APP)_SUITE.erl + + $i "Check that Common Test runs on 'make tests'" + $t test ! -e $(APP)/logs/index.html + $t $(MAKE) -C $(APP) tests $v + $t test -f $(APP)/logs/index.html diff --git a/test/plugin_dialyzer.mk b/test/plugin_dialyzer.mk new file mode 100644 index 0000000..3143319 --- /dev/null +++ b/test/plugin_dialyzer.mk @@ -0,0 +1,240 @@ +# Dialyzer plugin. + +DIALYZER_CASES = app apps-only apps-with-local-deps check custom-plt deps erlc-opts local-deps opts plt-apps +DIALYZER_TARGETS = $(addprefix dialyzer-,$(DIALYZER_CASES)) + +ifneq ($(shell which sem 2>/dev/null),) + DIALYZER_MUTEX = sem --fg --id dialyzer +endif + +.PHONY: dialyzer $(C_SRC_TARGETS) + +dialyzer: $(DIALYZER_TARGETS) + +dialyzer-app: build clean + + $i "Bootstrap a new OTP application named $(APP)" + $t mkdir $(APP)/ + $t cp ../erlang.mk $(APP)/ + $t $(MAKE) -C $(APP) -f erlang.mk bootstrap $v + + $i "Run Dialyzer" + $t $(DIALYZER_MUTEX) $(MAKE) -C $(APP) dialyze $v + + $i "Check that the PLT file was created" + $t test -f $(APP)/.$(APP).plt + + $i "Create a module with a function that has no local return" + $t printf "%s\n" \ + "-module(warn_me)." \ + "doit() -> 1 = 2, ok." > $(APP)/src/warn_me.erl + + $i "Confirm that Dialyzer errors out" + $t ! $(DIALYZER_MUTEX) $(MAKE) -C $(APP) dialyze $v + + $i "Distclean the application" + $t $(MAKE) -C $(APP) distclean $v + + $i "Check that the PLT file was removed" + $t test ! -e $(APP)/.$(APP).plt + +dialyzer-apps-only: build clean + + $i "Create a multi application repository with no root application" + $t mkdir $(APP)/ + $t cp ../erlang.mk $(APP)/ + $t echo "include erlang.mk" > $(APP)/Makefile + + $i "Create a new application my_app" + $t $(MAKE) -C $(APP) new-app in=my_app $v + + $i "Create a module my_server from gen_server template in my_app" + $t $(MAKE) -C $(APP) new t=gen_server n=my_server in=my_app $v + + $i "Add Cowlib to the list of dependencies" + $t perl -ni.bak -e 'print;if ($$.==1) {print "DEPS = cowlib\n"}' $(APP)/apps/my_app/Makefile + + $i "Run Dialyzer" + $t $(DIALYZER_MUTEX) $(MAKE) -C $(APP) dialyze $v + + $i "Check that the PLT file was created automatically" + $t test -f $(APP)/.$(APP).plt + + $i "Confirm that Cowlib was included in the PLT" + $t dialyzer --plt_info --plt $(APP)/.$(APP).plt | grep -q cowlib + + $i "Create a module with a function that has no local return" + $t printf "%s\n" \ + "-module(warn_me)." \ + "doit() -> 1 = 2, ok." > $(APP)/apps/my_app/src/warn_me.erl + + $i "Confirm that Dialyzer errors out" + $t ! $(DIALYZER_MUTEX) $(MAKE) -C $(APP) dialyze $v + +dialyzer-apps-with-local-deps: build clean + + $i "Create a multi application repository with no root application" + $t mkdir $(APP)/ + $t cp ../erlang.mk $(APP)/ + $t echo "include erlang.mk" > $(APP)/Makefile + + $i "Create a new application my_app" + $t $(MAKE) -C $(APP) new-app in=my_app $v + + $i "Create a new application my_core_app" + $t $(MAKE) -C $(APP) new-app in=my_core_app $v + + $i "Add my_core_app to the list of local dependencies for my_app" + $t perl -ni.bak -e 'print;if ($$.==1) {print "LOCAL_DEPS = my_core_app\n"}' $(APP)/apps/my_app/Makefile + + $i "Run Dialyzer" + $t $(DIALYZER_MUTEX) $(MAKE) -C $(APP) dialyze $v + + $i "Check that the PLT file was created automatically" + $t test -f $(APP)/.$(APP).plt + + $i "Confirm that my_core_app was NOT included in the PLT" + $t ! dialyzer --plt_info --plt $(APP)/.$(APP).plt | grep -q my_core_app + +dialyzer-check: build clean + + $i "Bootstrap a new OTP application named $(APP)" + $t mkdir $(APP)/ + $t cp ../erlang.mk $(APP)/ + $t $(MAKE) -C $(APP) -f erlang.mk bootstrap $v + + $i "Run 'make check'" + $t $(DIALYZER_MUTEX) $(MAKE) -C $(APP) check $v + + $i "Check that the PLT file was created" + $t test -f $(APP)/.$(APP).plt + + $i "Create a module with a function that has no local return" + $t printf "%s\n" \ + "-module(warn_me)." \ + "doit() -> 1 = 2, ok." > $(APP)/src/warn_me.erl + + $i "Confirm that Dialyzer errors out on 'make check'" + $t ! $(DIALYZER_MUTEX) $(MAKE) -C $(APP) check $v + +dialyzer-custom-plt: build clean + + $i "Bootstrap a new OTP application named $(APP)" + $t mkdir $(APP)/ + $t cp ../erlang.mk $(APP)/ + $t $(MAKE) -C $(APP) -f erlang.mk bootstrap $v + + $i "Set a custom DIALYZER_PLT location" + $t perl -ni.bak -e 'print;if ($$.==1) {print "DIALYZER_PLT = custom.plt\n"}' $(APP)/Makefile + + $i "Run Dialyzer" + $t $(DIALYZER_MUTEX) $(MAKE) -C $(APP) dialyze $v + + $i "Check that the PLT file was created" + $t test -f $(APP)/custom.plt + + $i "Distclean the application" + $t $(MAKE) -C $(APP) distclean $v + + $i "Check that the PLT file was removed" + $t test ! -e $(APP)/custom.plt + +dialyzer-deps: build clean + + $i "Bootstrap a new OTP application named $(APP)" + $t mkdir $(APP)/ + $t cp ../erlang.mk $(APP)/ + $t $(MAKE) -C $(APP) -f erlang.mk bootstrap $v + + $i "Add Cowlib to the list of dependencies" + $t perl -ni.bak -e 'print;if ($$.==1) {print "DEPS = cowlib\n"}' $(APP)/Makefile + + $i "Run Dialyzer" + $t $(DIALYZER_MUTEX) $(MAKE) -C $(APP) dialyze $v + + $i "Check that the PLT file was created" + $t test -f $(APP)/.$(APP).plt + + $i "Confirm that Cowlib was included in the PLT" + $t dialyzer --plt_info --plt $(APP)/.$(APP).plt | grep -q cowlib + +dialyzer-erlc-opts: build clean + + $i "Bootstrap a new OTP application named $(APP)" + $t mkdir $(APP)/ + $t cp ../erlang.mk $(APP)/ + $t $(MAKE) -C $(APP) -f erlang.mk bootstrap $v + + $i "Create a header file in a non-standard directory" + $t mkdir $(APP)/exotic/ + $t touch $(APP)/exotic/dialyze.hrl + + $i "Create a module that includes this header" + $t printf "%s\n" \ + "-module(no_warn)." \ + "-export([doit/0])." \ + "-include(\"dialyze.hrl\")." \ + "doit() -> ok." > $(APP)/src/no_warn.erl + + $i "Point ERLC_OPTS to the non-standard include directory" + $t perl -ni.bak -e 'print;if ($$.==1) {print "ERLC_OPTS += -I exotic\n"}' $(APP)/Makefile + + $i "Run Dialyzer" + $t $(DIALYZER_MUTEX) $(MAKE) -C $(APP) dialyze $v + +dialyzer-local-deps: build clean + + $i "Bootstrap a new OTP application named $(APP)" + $t mkdir $(APP)/ + $t cp ../erlang.mk $(APP)/ + $t $(MAKE) -C $(APP) -f erlang.mk bootstrap $v + + $i "Add runtime_tools to the list of local dependencies" + $t perl -ni.bak -e 'print;if ($$.==1) {print "LOCAL_DEPS = runtime_tools\n"}' $(APP)/Makefile + + $i "Build the PLT" + $t $(DIALYZER_MUTEX) $(MAKE) -C $(APP) plt $v + + $i "Confirm that runtime_tools was included in the PLT" + $t dialyzer --plt_info --plt $(APP)/.$(APP).plt | grep -q runtime_tools + +dialyzer-opts: build clean + + $i "Bootstrap a new OTP application named $(APP)" + $t mkdir $(APP)/ + $t cp ../erlang.mk $(APP)/ + $t $(MAKE) -C $(APP) -f erlang.mk bootstrap $v + + $i "Make Dialyzer save output to a file" + $t perl -ni.bak -e 'print;if ($$.==1) {print "DIALYZER_OPTS = -o output.txt\n"}' $(APP)/Makefile + + $i "Create a module with a function that has no local return" + $t printf "%s\n" \ + "-module(warn_me)." \ + "-export([doit/0])." \ + "doit() -> gen_tcp:connect(a, b, c), ok." > $(APP)/src/warn_me.erl + + $i "Run Dialyzer" + $t ! $(DIALYZER_MUTEX) $(MAKE) -C $(APP) dialyze $v + + $i "Check that the PLT file was created" + $t test -f $(APP)/.$(APP).plt + + $i "Check that the output file was created" + $t test -f $(APP)/output.txt + +dialyzer-plt-apps: build clean + + $i "Bootstrap a new OTP application named $(APP)" + $t mkdir $(APP)/ + $t cp ../erlang.mk $(APP)/ + $t $(MAKE) -C $(APP) -f erlang.mk bootstrap $v + + $i "Add runtime_tools to PLT_APPS" + $t perl -ni.bak -e 'print;if ($$.==1) {print "PLT_APPS = runtime_tools\n"}' $(APP)/Makefile + + $i "Build the PLT" + $t $(DIALYZER_MUTEX) $(MAKE) -C $(APP) plt $v + + $i "Confirm that runtime_tools was included in the PLT" + $t dialyzer --plt_info --plt $(APP)/.$(APP).plt | grep -q runtime_tools diff --git a/test/plugin_edoc.mk b/test/plugin_edoc.mk new file mode 100644 index 0000000..33f3d0f --- /dev/null +++ b/test/plugin_edoc.mk @@ -0,0 +1,112 @@ +# EDoc plugin. + +EDOC_CASES = build docs no-overview opts +EDOC_TARGETS = $(addprefix edoc-,$(EDOC_CASES)) + +.PHONY: edoc $(EDOC_TARGETS) + +edoc: $(EDOC_TARGETS) + +edoc-build: build clean + + $i "Bootstrap a new OTP application named $(APP)" + $t mkdir $(APP)/ + $t cp ../erlang.mk $(APP)/ + $t $(MAKE) -C $(APP) -f erlang.mk bootstrap $v + + $i "Run EDoc" + $t $(MAKE) -C $(APP) edoc $v + + $i "Check that documentation was generated" + $t test -f $(APP)/doc/index.html + $t test -f $(APP)/doc/$(APP)_app.html + $t test -f $(APP)/doc/$(APP)_sup.html + + $i "Distclean the application" + $t $(MAKE) -C $(APP) distclean $v + + $i "Check that the generated documentation was removed" + $t test ! -e $(APP)/doc/index.html + $t test ! -e $(APP)/doc/$(APP)_app.html + $t test ! -e $(APP)/doc/$(APP)_sup.html + + $i "Generate a module with EDoc comments" + $t printf "%s\n" \ + "%% @doc erlang-mk-edoc-module" \ + "-module($(APP))." \ + "-export([ok/0])." \ + "" \ + "%% @doc erlang-mk-edoc-function" \ + "ok() -> ok." > $(APP)/src/$(APP).erl + + $i "Run EDoc" + $t $(MAKE) -C $(APP) edoc $v + + $i "Check that the new module's documentation was generated" + $t test -f $(APP)/doc/$(APP).html + + $i "Check that the EDoc comments are in the generated documentation" + $t grep -q erlang-mk-edoc-module $(APP)/doc/$(APP).html + $t grep -q erlang-mk-edoc-function $(APP)/doc/$(APP).html + + $i "Generate a module with an invalid EDoc comment" + $t printf "%s\n" \ + "-module($(APP)_fail)." \ + "-export([fail/0])." \ + "%% @spec lol" \ + "fail() -> fail." > $(APP)/src/$(APP)_fail.erl + + $i "Check that EDoc errors out" + $t ! $(MAKE) -C $(APP) edoc $v + +edoc-docs: build clean + + $i "Bootstrap a new OTP application named $(APP)" + $t mkdir $(APP)/ + $t cp ../erlang.mk $(APP)/ + $t $(MAKE) -C $(APP) -f erlang.mk bootstrap $v + + $i "Generate a doc/overview.edoc file" + $t mkdir $(APP)/doc + $t printf "%s\n" \ + "@author R. J. Hacker <[email protected]>" \ + "@copyright 2007 R. J. Hacker" \ + "@version 1.0.0" \ + "@title Welcome to the 'frob' application!" \ + "@doc 'frob' is a highly advanced frobnicator with low latency," > $(APP)/doc/overview.edoc + + $i "Check that EDoc runs on 'make docs'" + $t $(MAKE) -C $(APP) docs $v + $t test -f $(APP)/doc/index.html + + $i "Check that the overview.edoc file was used" + $t grep -q frobnicator $(APP)/doc/overview-summary.html + +edoc-no-overview: build clean + + $i "Bootstrap a new OTP application named $(APP)" + $t mkdir $(APP)/ + $t cp ../erlang.mk $(APP)/ + $t $(MAKE) -C $(APP) -f erlang.mk bootstrap $v + + $i "Check that EDoc doesn't run on 'make docs'" + $t $(MAKE) -C $(APP) docs $v + $t test ! -e $(APP)/doc/index.html + +edoc-opts: build clean + + $i "Bootstrap a new OTP application named $(APP)" + $t mkdir $(APP)/ + $t cp ../erlang.mk $(APP)/ + $t $(MAKE) -C $(APP) -f erlang.mk bootstrap $v + + $i "Add edown doclet for EDoc" + $t perl -ni.bak -e 'print;if ($$.==1) {print "DOC_DEPS = edown\nEDOC_OPTS = {doclet, edown_doclet}\n"}' $(APP)/Makefile + + $i "Run EDoc" + $t $(MAKE) -C $(APP) edoc $v + + $i "Check that the Markdown documentation was generated" + $t test -f $(APP)/doc/README.md + $t test -f $(APP)/doc/$(APP)_app.md + $t test -f $(APP)/doc/$(APP)_sup.md diff --git a/test/plugin_erlydtl.mk b/test/plugin_erlydtl.mk index acfd74c..b96596d 100644 --- a/test/plugin_erlydtl.mk +++ b/test/plugin_erlydtl.mk @@ -2,18 +2,12 @@ ERLYDTL_CASES = compile full-path ERLYDTL_TARGETS = $(addprefix erlydtl-,$(ERLYDTL_CASES)) -ERLYDTL_CLEAN_TARGETS = $(addprefix clean-,$(ERLYDTL_TARGETS)) -.PHONY: erlydtl $(ERLYDTL_TARGETS) clean-erlydtl $(ERLYDTL_CLEAN_TARGETS) - -clean-erlydtl: $(ERLYDTL_CLEAN_TARGETS) - -$(ERLYDTL_CLEAN_TARGETS): - $t rm -rf $(APP_TO_CLEAN)/ +.PHONY: erlydtl $(ERLYDTL_TARGETS) erlydtl: $(ERLYDTL_TARGETS) -erlydtl-compile: build clean-erlydtl-compile +erlydtl-compile: build clean $i "Bootstrap a new OTP library named $(APP)" $t mkdir $(APP)/ @@ -41,7 +35,7 @@ erlydtl-compile: build clean-erlydtl-compile {ok, [$(APP_)_one_dtl, $(APP)_two_dtl]} = application:get_key($(APP), modules), \ halt()" -erlydtl-full-path: build clean-erlydtl-full-path +erlydtl-full-path: build clean $i "Bootstrap a new OTP library named $(APP)" $t mkdir $(APP)/ diff --git a/test/plugin_eunit.mk b/test/plugin_eunit.mk new file mode 100644 index 0000000..c25484b --- /dev/null +++ b/test/plugin_eunit.mk @@ -0,0 +1,210 @@ +# EUnit plugin. + +EUNIT_CASES = all apps-only check erl-opts fun mod test-dir tests +EUNIT_TARGETS = $(addprefix eunit-,$(EUNIT_CASES)) + +.PHONY: eunit $(EUNIT_TARGETS) + +eunit: $(EUNIT_TARGETS) + +eunit-all: build clean + + $i "Bootstrap a new OTP application named $(APP)" + $t mkdir $(APP)/ + $t cp ../erlang.mk $(APP)/ + $t $(MAKE) -C $(APP) -f erlang.mk bootstrap $v + + $i "Check that EUnit detects no tests" + $t $(MAKE) -C $(APP) eunit | grep -q "There were no tests to run." + + $i "Generate a module containing EUnit tests" + $t printf "%s\n" \ + "-module($(APP))." \ + "-ifdef(TEST)." \ + "-include_lib(\"eunit/include/eunit.hrl\")." \ + "ok_test() -> ok." \ + "-endif." > $(APP)/src/$(APP).erl + + $i "Build the project cleanly" + $t $(MAKE) -C $(APP) clean $v + $t $(MAKE) -C $(APP) $v + + $i "Check that no EUnit test cases were exported" + $t $(ERL) -pa $(APP)/ebin -eval 'code:load_file($(APP)), false = erlang:function_exported($(APP), ok_test, 0), halt()' + + $i "Check that EUnit runs tests" + $t $(MAKE) -C $(APP) eunit | grep -q "Test passed." + + $i "Add a failing test to the module" + $t printf "%s\n" \ + "-ifdef(TEST)." \ + "bad_test() -> throw(fail)." \ + "-endif." >> $(APP)/src/$(APP).erl + + $i "Check that EUnit errors out" + $t ! $(MAKE) -C $(APP) eunit $v + +eunit-apps-only: build clean + + $i "Create a multi application repository with no root application" + $t mkdir $(APP)/ + $t cp ../erlang.mk $(APP)/ + $t echo "include erlang.mk" > $(APP)/Makefile + + $i "Create a new application named my_app" + $t $(MAKE) -C $(APP) new-app in=my_app $v + + $i "Create a new library named my_lib" + $t $(MAKE) -C $(APP) new-lib in=my_lib $v + + $i "Check that EUnit detects no tests" + $t $(MAKE) -C $(APP) eunit | grep -q "There were no tests to run." + + $i "Generate a module containing EUnit tests in my_app" + $t printf "%s\n" \ + "-module(my_app)." \ + "-ifdef(TEST)." \ + "-include_lib(\"eunit/include/eunit.hrl\")." \ + "ok_test() -> ok." \ + "-endif." > $(APP)/apps/my_app/src/my_app.erl + + $i "Generate a module containing EUnit tests in my_lib" + $t printf "%s\n" \ + "-module(my_lib)." \ + "-ifdef(TEST)." \ + "-include_lib(\"eunit/include/eunit.hrl\")." \ + "ok_test() -> ok." \ + "-endif." > $(APP)/apps/my_lib/src/my_lib.erl + + $i "Check that EUnit runs tests" + $t $(MAKE) -C $(APP) eunit | grep -q "Test passed." + +eunit-check: build clean + + $i "Bootstrap a new OTP application named $(APP)" + $t mkdir $(APP)/ + $t cp ../erlang.mk $(APP)/ + $t $(MAKE) -C $(APP) -f erlang.mk bootstrap $v + + $i "Generate a module containing EUnit tests" + $t printf "%s\n" \ + "-module($(APP))." \ + "-ifdef(TEST)." \ + "-include_lib(\"eunit/include/eunit.hrl\")." \ + "ok_test() -> ok." \ + "-endif." > $(APP)/src/$(APP).erl + + $i "Check that EUnit runs on 'make check'" + $t $(MAKE) -C $(APP) check | grep -q "Test passed." + +eunit-erl-opts: build clean + + $i "Bootstrap a new OTP application named $(APP)" + $t mkdir $(APP)/ + $t cp ../erlang.mk $(APP)/ + $t $(MAKE) -C $(APP) -f erlang.mk bootstrap $v + + $i "Set EUNIT_ERL_OPTS in the Makefile" + $t perl -ni.bak -e 'print;if ($$.==1) {print "EUNIT_ERL_OPTS = -eval \"erlang:display(hello).\" \n"}' $(APP)/Makefile + + $i "Generate a module containing EUnit tests" + $t printf "%s\n" \ + "-module($(APP))." \ + "-ifdef(TEST)." \ + "-include_lib(\"eunit/include/eunit.hrl\")." \ + "ok_test() -> ok." \ + "-endif." > $(APP)/src/$(APP).erl + + $i "Check that EUnit uses EUNIT_ERL_OPTS" + $t $(MAKE) -C $(APP) eunit | grep -q "hello" + +eunit-fun: build clean + + $i "Bootstrap a new OTP application named $(APP)" + $t mkdir $(APP)/ + $t cp ../erlang.mk $(APP)/ + $t $(MAKE) -C $(APP) -f erlang.mk bootstrap $v + + $i "Generate a module containing EUnit tests" + $t printf "%s\n" \ + "-module($(APP))." \ + "-ifdef(TEST)." \ + "-include_lib(\"eunit/include/eunit.hrl\")." \ + "ok_test() -> ok." \ + "bad_test() -> throw(fail)." \ + "-endif." > $(APP)/src/$(APP).erl + + $i "Check that we can run EUnit on a specific test" + $t $(MAKE) -C $(APP) eunit t=$(APP):ok_test $v + +eunit-mod: build clean + + $i "Bootstrap a new OTP application named $(APP)" + $t mkdir $(APP)/ + $t cp ../erlang.mk $(APP)/ + $t $(MAKE) -C $(APP) -f erlang.mk bootstrap $v + + $i "Generate a module containing EUnit tests" + $t printf "%s\n" \ + "-module($(APP))." \ + "-ifdef(TEST)." \ + "-include_lib(\"eunit/include/eunit.hrl\")." \ + "ok_test() -> ok." \ + "-endif." > $(APP)/src/$(APP).erl + + $i "Generate a module containing failing EUnit tests" + $t printf "%s\n" \ + "-module($(APP)_fail)." \ + "-ifdef(TEST)." \ + "-include_lib(\"eunit/include/eunit.hrl\")." \ + "bad_test() -> throw(fail)." \ + "-endif." > $(APP)/src/$(APP)_fail.erl + + $i "Check that we can run EUnit on a specific module" + $t $(MAKE) -C $(APP) eunit t=$(APP) $v + +eunit-test-dir: build clean + + $i "Bootstrap a new OTP application named $(APP)" + $t mkdir $(APP)/ + $t cp ../erlang.mk $(APP)/ + $t $(MAKE) -C $(APP) -f erlang.mk bootstrap $v + + $i "Generate a module containing EUnit tests" + $t printf "%s\n" \ + "-module($(APP))." \ + "-ifdef(TEST)." \ + "-include_lib(\"eunit/include/eunit.hrl\")." \ + "log_test() -> os:cmd(\"echo $(APP) >> eunit.log\")." \ + "-endif." > $(APP)/src/$(APP).erl + + $i "Generate a module containing EUnit tests in TEST_DIR" + $t mkdir $(APP)/test + $t printf "%s\n" \ + "-module($(APP)_tests)." \ + "-include_lib(\"eunit/include/eunit.hrl\")." \ + "log_test() -> os:cmd(\"echo $(APP)_tests >> eunit.log\")." > $(APP)/test/$(APP)_tests.erl + + $i "Check that EUnit runs both tests" + $t $(MAKE) -C $(APP) eunit | grep -q "2 tests passed." + + $i "Check that tests were both run only once" + $t printf "%s\n" $(APP) $(APP)_tests | cmp $(APP)/eunit.log - + +eunit-tests: build clean + + $i "Bootstrap a new OTP application named $(APP)" + $t mkdir $(APP)/ + $t cp ../erlang.mk $(APP)/ + $t $(MAKE) -C $(APP) -f erlang.mk bootstrap $v + + $i "Generate a module containing EUnit tests" + $t printf "%s\n" \ + "-module($(APP))." \ + "-ifdef(TEST)." \ + "-include_lib(\"eunit/include/eunit.hrl\")." \ + "ok_test() -> ok." \ + "-endif." > $(APP)/src/$(APP).erl + + $i "Check that EUnit runs on 'make tests'" + $t $(MAKE) -C $(APP) tests | grep -q "Test passed." diff --git a/test/plugin_shell.mk b/test/plugin_shell.mk index 474ef92..3db7bba 100644 --- a/test/plugin_shell.mk +++ b/test/plugin_shell.mk @@ -2,18 +2,12 @@ SHELL_CASES = default kjell SHELL_TARGETS = $(addprefix shell-,$(SHELL_CASES)) -SHELL_CLEAN_TARGETS = $(addprefix clean-,$(SHELL_TARGETS)) -.PHONY: shell $(C_SRC_TARGETS) clean-shell $(SHELL_CLEAN_TARGETS) - -clean-shell: $(SHELL_CLEAN_TARGETS) - -$(SHELL_CLEAN_TARGETS): - $t rm -rf $(APP_TO_CLEAN)/ +.PHONY: shell $(C_SRC_TARGETS) shell: $(SHELL_TARGETS) -shell-default: build clean-shell-default +shell-default: build clean $i "Bootstrap a new OTP library named $(APP)" $t mkdir $(APP)/ @@ -23,7 +17,7 @@ shell-default: build clean-shell-default $i "Run the shell" $t $(MAKE) -C $(APP) shell SHELL_OPTS="-eval 'halt()'" $v -shell-kjell: build clean-shell-kjell +shell-kjell: build clean $i "Bootstrap a new OTP library named $(APP)" $t mkdir $(APP)/ |