-
Notifications
You must be signed in to change notification settings - Fork 7
FwTemplateErlangWalkthrough
fw-template-erlang is the framewerk Erlang template. It features:
- cover integration with 'make check'
- edoc integration for documentation.
- eunit integration with 'make check'
- generates an otp compliant application file by scanning the source code
- standard make rules to drive the erlang compiler
- erlrc integration
This walkthrough demonstrates fw-template-erlang.
It's very helpful to have done the framewerk walkthrough.
First, set up the project with fw-init in the usual way.
% env CVSROOT="YOURCVSROOT" fw-init --name myproject --template erlang --revision cvs
Changing directory into the project,
% cd myproject/
% cvs -n -q up
A .cvsignore
A AUTHORS
A ChangeLog
A Makefile.am.local
A NEWS
A README
A bootstrap
A configure.ac.local
A doc/.cvsignore
A doc/Makefile.am.local
A doc/overview.edoc
A fw-pkgin/.cvsignore
A fw-pkgin/Makefile.am.local
A fw-pkgin/config
A fw-pkgin/post-install
A fw-pkgin/post-remove
A fw-pkgin/pre-install
A fw-pkgin/pre-remove
A fw-pkgin/start
A fw-pkgin/stop
A src/.cvsignore
A src/Makefile.am.local
A src/myapp.erl
A tests/.cvsignore
A tests/Makefile.am.local
The root directory of the project now looks like:
% ls
AUTHORS ChangeLog NEWS bootstrap doc fw-pkgin tests
CVS Makefile.am.local README configure.ac.local fw src
Here's a breakdown:
-
AUTHORS, CVS, ChangeLog, NEWS, README, bootstrap, fw, fw-pkgin, configure.ac.local, Makefile.am.local
: these have the same meanings as in other framewerk templates. -
src, tests
: Erlang source code (.erl, .hrl) is placed insrc/
, and unit tests intests/
.
As with other framewerk templates, fw-pkgin/config
is used to configure the project. However some new variables are available with this template.
% cat fw-pkgin/config
# The FW_PACKAGE_MAINTAINER field is populated with the
# environment variable FW_PACKAGE_DEFAULT_MAINTAINER if non-empty
FW_PACKAGE_NAME="myproject"
FW_PACKAGE_VERSION="0.0.0"
FW_PACKAGE_MAINTAINER="root <[email protected]>"
FW_PACKAGE_SHORT_DESCRIPTION="A short description."
FW_PACKAGE_DESCRIPTION=`cat README`
FW_PACKAGE_ARCHITECTURE_DEPENDENT="0"
# Dependency information. The native syntax corresponds to Debian,
# http://www.debian.org/doc/debian-policy/ch-relationships.html
# Section 7.1 "Syntax of Relationship Fields"
#
# For other packaging systems, the syntax is translated for you.
FW_PACKAGE_DEPENDS=""
FW_PACKAGE_CONFLICTS=""
FW_PACKAGE_PROVIDES=""
FW_PACKAGE_REPLACES=""
FW_PACKAGE_BUILD_DEPENDS=""
FW_PACKAGE_BUILD_CONFLICTS=""
# uncomment and set manually if autodetection of modules is incorrect
# FW_ERL_APP_MODULES=""
# uncomment and set manually if autodetection of registered processes is incorrect
# FW_ERL_APP_REGISTERED=""
# uncomment and set manually if autodetection of start module is incorrect
# FW_ERL_APP_START_MODULE=""
# uncomment to define start args to the start module. should be an erlang
# expression which evaluates to a list.
# FW_ERL_APP_START_ARGS="[]"
# uncomment if the module line being generated is incorrect and you want
# to override it.
# FW_ERL_APP_MOD_LINE="{ mod, { $FW_ERL_APP_START_MODULE, $FW_ERL_APP_START_ARGS } },"
# uncomment to define the application environment variables. should be an
# erlang expression which evaluates to a list.
# FW_ERL_APP_ENVIRONMENT="[]"
The extra variables are mostly related to creation of an otp compliant application file. This mostly just works but in case it doesn't you have override control via these variables.
Build the project the usual way,
% ./bootstrap && ./build
Now there should be a Makefile.otp
in the root directory of the project.[2]
% cat Makefile.otp
erlappdir="@ERLAPPDIR@"
erlappsrcdir="$(erlappdir)/src"
erlappebindir="$(erlappdir)/ebin"
erlappprivdir="$(erlappdir)/priv"
erlappincludedir="$(erlappdir)/include"
erldocdir="@ERLDOCDIR@"
SUFFIXES = .beam .erl .P
ERLCFLAGS ?= +debug_info -pa ../src -I ../src
# put an overly broad dependency on .hrl for now,
# which will cause some spurious extra compiles
# TODO: depgen for erlang
%.beam: %.erl $(wildcard *.hrl)
erlc ${ERLCFLAGS} ${$*_ERLCFLAGS} $<
%.P: %.erl $(wildcard *.hrl)
erlc +"'P'" ${ERLCFLAGS} ${$*_ERLCFLAGS} $<
.%.beam_ok: %.beam
dialyzer -c $*.beam
touch $@
.%.erl_ok: %.erl
dialyzer --src -c $*.erl
touch $@
.dialyzer_ok: $(wildcard *.erl)
dialyzer ${DIALYZERFLAGS} --src -c .
touch $@
CLEANFILES += \
$(wildcard *.P) \
$(wildcard *.beam) \
$(wildcard .*.beam_ok) \
$(wildcard .*.erl_ok) \
.dialyzer_ok \
erl_crash.dump
include $(top_srcdir)/fw/build/automake/check-shell.am
include $(top_srcdir)/fw/build/automake/gnu-make-check.am
Notes:
- The standard directory targets erlappsrc, erlappebin, erlapppriv, and erlappinclude are defined, corresponding to the otp application directory structure.
- Automatic rules for building a
.beam
(or a.P
) from the corresponding.erl
file. These are parametrized by${ERLCFLAGS}
globally and${$\
*_`ERLCFLAGS}` per target. In other words, foo.beam can be built from foo.erl, and the compilation line would be
erlc ${ERLCFLAGS} ${foo_ERLCFLAGS} foo.erl
- Unless otherwise set, ERLCFLAGS defaults to something reasonable.
- Some rules are defined to drive the dialyzer.
The src/
directory should contain something like
% ls src
CVS Makefile.am.local fw-erl-app-template.app.in myproject.app
Makefile Makefile.in myapp.beam
Makefile.am fw-erl-app-template.app myapp.erl
Here's the breakdown:
-
CVS
: revision control specific -
Makefile.in, Makefile
: generated by automake/autoconf -
Makefile.am
: a link to the Makefile.am installed with fw-template-erlang -
Makefile.am.local
: this is where you can put any additional (auto)make commands beyond what is supplied by the template. -
fw-erl-app-template.app, fw-erl-template-app.in
: intermediate files in the automatic generation of the otp compliant application file. -
myproject.app
: the automatically generated otp compliant application file. -
myapp.erl
: simple example application installed with the template -
myapp.beam
: compiled version of myapp.erl -
myproject.app
: autogenerated otp compliant application file.
```no-highlightsrc/myproject.app` is autogenerated by scanning source.
% cat src/myproject.app
{ application, myproject,
[
{ description, "A short description." },
{ vsn, "0.0.0" },
{ modules, [ myapp ] },
{ registered, [ hello_world ] },
{ applications, [ kernel, stdlib ] },
{ mod, { myapp, [] } },
{ env, [] }
]
}.
The template assumes that the project contains at most one application and
generates a .app
file by scanning the contents of src/
. By
inspecting fw-erl-app-template.app.in
you can get an idea of how it works.
% cat src/fw-erl-app-template.app.in
{ application, @FW_PACKAGE_NAME@,
[
{ description, "@FW_PACKAGE_SHORT_DESCRIPTION@" },
{ vsn, "@FW_PACKAGE_VERSION@" },
{ modules, [ @FW_ERL_APP_MODULES@ ] },
{ registered, [ @FW_ERL_APP_REGISTERED@ ] },
{ applications, [ kernel, stdlib @FW_ERL_PREREQ_APPLICATIONS@ @FW_ERL_PREREQ_APPLICATIONS_EXTRA@ ] },
@FW_ERL_APP_MOD_LINE@
{ env, @FW_ERL_APP_ENVIRONMENT@ }
@FW_ERL_APP_EXTRA@
]
}.
Some notes:
- the application named is forced to be the package name.
- the version is forced to be the package version.
- the modules are autodetected, but setting FW_ERL_APP_MODULES in
fw-pkgin/config
takes precedence. - registered processes are autodetected, but setting FW_ERL_APP_REGISTERED in
fw-pkgin/config
take precedence. - FW_ERL_PREREQ_APPLICATIONS is reserved for an attempt to detect dependent applications automatically, but currently does nothing.
- FW_ERL_PREREQ_APPLICATIONS_EXTRA is only set via
fw-pkgin/config
. - FW_ERL_APP_MOD_LINE defaults to { mod, { @FW_ERL_APP_START_MODULE@, @FW_ERL_APP_START_ARGS@ } }, both of which are individually overridden by values in
fw-pkgin/config
. in addition if the situation is totally borked, you can set FW_ERL_APP_MOD_LINE infw-pkgin/config
and that takes precedence. - FW_ERL_APP_ENVIRONMENT defaults to [] but can be set in
fw-pkgin/config
. - FW_ERL_APP_EXTRA can be anything you want. this is a good place to put included applications directives.
- to override everything, rm the
src/fw-erl-app-template.app.in
link, write your own file in it's place, and check into revision control. the template will not link over something that already exists.
```no-highlightsrc/Makefile.am.local` is initialized with some reasonable rules.
% cat src/Makefile.am.local
# put whatever (auto)make commands here, they will be included from Makefile.am
dist_erlappsrc_DATA = \
$(wildcard *.erl)
dist_erlappinclude_DATA = \
$(wildcard *.hrl)
erlappebin_SCRIPTS = \
@[email protected] \
$(patsubst %.erl, %.beam, $(dist_erlappsrc_DATA))
check_DATA = \
.dialyzer_ok
Basically:
- put all
.erl
files intoOTPROOT/application-version/src
- put all
.hrl
files intoOTPROOT/application-version/include
- make a
.beam
for each.erl
- put
.beam
files intoOTPROOT/application-version/ebin
- put
.app
file intoOTPROOT/application-version/ebin
- run the dialyzer on all the source files during 'make check'
This last rule is usually the one that requires customization. DIALYZERFLAGS can be set to pass flags to the dialyzer. Sometimes a custom rule which only analyzes some of the source code is necessary. Look to Makefile.otp for inspiration.
% ls tests/
CVS Makefile.am Makefile.am.local Makefile.in otp-test-wrapper.sh
```no-highlighttests/otp-test-wrapper.shis used to run the tests. It recognizes tests of the form
module-foo` and interprets that
as a directive to run foo:test/0 and then run coverage analysis on
foo.[1] Output is contained in foo.test.out in case of snafu.
Thus
% cat tests/Makefile.am.local
TESTS = \
module-myapp
runs myapp:test/0 and outputs coverage information. Tests not of the form module-foo are executed directly, although artifacts of cover analysis generated from such tests are attempted to be detected. Check out ```no-highlighttests/otp-test-wrapper.sh` if you're curious.
Making a package is done the usual way, as is releasing a package.
Congratulations! You've made it through the fw-template-erlang walkthrough. Hopefully you found it helpful.
Here's a summary of interesting changes since this walkthrough was written.
- There's a parse transform that is run by default during compilation that adds a -vsn attribute to files that lack one (using FW_PACKAGE_VERSION). This is useful for hot code upgrade. See Makefile.otp for details.
- escript is now a recognized interpreter and causes 'escript -s' to be run.
module:test/0 is the method autogenerated by eunit , so this counts as eunit integration (and cover integration).
You do not edit Makefile.otp
directly; it is included in the Makefiles in src/
and tests/
, and you can include it in other Makefiles as necessary.