diff options
Diffstat (limited to 'guide/building.html')
-rw-r--r-- | guide/building.html | 223 |
1 files changed, 223 insertions, 0 deletions
diff --git a/guide/building.html b/guide/building.html new file mode 100644 index 0000000..903cc9f --- /dev/null +++ b/guide/building.html @@ -0,0 +1,223 @@ +<!DOCTYPE html> +<html lang="en"> +<head> +<meta charset="utf-8"/> +<title>Erlang.mk User Guide</title> +<style type="text/css"><!-- +body{background:white;color:black;font-family:"Open Sans", "Helvetica Neue", Helvetica, Arial, sans-serif;justify-content:center;margin:0 auto;padding:0;width:600px} +header {align-items:center;display:flex;justify-content:center} +header nav.left{text-align:right;width:150px} +header nav.right{text-align:left;width:150px} +header nav a{display:block;margin:1.5em 1em} +main{margin-top:2em;text-align:justify} +main h2, main h3{margin-top:2em} +a{color:#d9230f;text-decoration:none} +a:hover{text-decoration:underline} +h1, h2, h3{font-weight:normal} +div.navfooter{margin-bottom:1em} +--></style> +</head> +<body> +<header> + <nav class="left"> + <a href="index.html">User guide</a> + <a href="ch02.html">Tutorials</a> + </nav> + <a href="/" class="logo"><img src="../res/logo-small.png" alt="Erlang.mk" title="Erlang.mk: A build tool for Erlang that just works" height="200" width="206"/></a> + <nav class="right"> + <a href="https://github.com/ninenines/erlang.mk/tree/master/index">470+ packages</a> + <a href="https://github.com/ninenines/erlang.mk/issues">Issues?</a> + </nav> +</header> +<main> + +<div class="navheader"><table width="100%" summary="Navigation header"><tr><td width="20%" align="left"><a accesskey="p" href="code.html">Prev</a> </td><th width="60%" align="center"> </th><td width="20%" align="right"> <a accesskey="n" href="deps.html">Next</a></td></tr></table><hr /></div><div class="chapter"><div class="titlepage"><div><div><h2 class="title"><a id="building"></a>Chapter 6. Building</h2></div></div></div><p>Erlang.mk can do a lot of things, but it is, first and +foremost, a build tool. In this chapter we will cover +the basics of building a project with Erlang.mk.</p><p>For most of this chapter, we will assume that you are +using a project <a class="ulink" href="getting_started.asciidoc" target="_top">generated by Erlang.mk</a>.</p><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="_how_to_build"></a>6.1. How to build</h2></div></div></div><p>To build a project, all you have to do is type <code class="literal">make</code>:</p><pre class="programlisting">$ make</pre><p>It will work regardless of your project: OTP applications, +library applications, NIFs, port drivers or even releases. +Erlang.mk also automatically downloads and compiles the +dependencies for your project.</p><p>All this is possible thanks to a combination of configuration +and conventions. Most of the conventions come from Erlang/OTP +itself so any seasoned Erlang developers should feel right at +home.</p></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="_what_to_build"></a>6.2. What to build</h2></div></div></div><p>Erlang.mk gives you control over three steps of the build +process, allowing you to do a partial build if needed.</p><p>A build has three phases: first any dependency is fetched +and built, then the project itself is built and finally a +release may be generated when applicable. A release is only +generated for projects specifically configured to do so.</p><p>Erlang.mk handles those three phases automatically when you +type <code class="literal">make</code>. But sometimes you just want to repeat one or +two of them.</p><p>The commands detailed in this section are most useful after +you have a successful build as they allow you to quickly +redo a step instead of going through everything. This is +especially useful for large projects or projects that end +up generating releases.</p><div class="section"><div class="titlepage"><div><div><h3 class="title"><a id="_application"></a>6.2.1. Application</h3></div></div></div><p>You can build your application and dependencies without +generating a release by running the following command:</p><pre class="programlisting">$ make app</pre><p>To build your application without touching dependencies +at all, you can use the <code class="literal">SKIP_DEPS</code> variable:</p><pre class="programlisting">$ make app SKIP_DEPS=1</pre><p>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.</p><p>Note that this command may fail if a required dependency +is missing.</p></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a id="_dependencies"></a>6.2.2. Dependencies</h3></div></div></div><p>You can build all dependencies, and nothing else, by +running the following command:</p><pre class="programlisting">$ make deps</pre><p>This will fetch and compile all dependencies and their +dependencies, recursively.</p><p><a class="ulink" href="deps.asciidoc" target="_top">Packages and dependencies</a> are covered +in the next chapter.</p></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a id="_release"></a>6.2.3. Release</h3></div></div></div><p>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.</p><p>To generate the release, <code class="literal">make</code> 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:</p><pre class="programlisting">$ make rel</pre><p>Consult the <a class="ulink" href="relx.asciidoc" target="_top">Releases</a> chapter for more +information about what releases are and how they are generated.</p></div></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="_application_resource_file"></a>6.3. Application resource file</h2></div></div></div><p>When building your application, Erlang.mk will generate the +<a class="ulink" href="http://www.erlang.org/doc/man/app.html" target="_top">application resource file</a>. +This file is mandatory for all Erlang applications and is +found in <span class="emphasis"><em>ebin/$(PROJECT).app</em></span>.</p><p><code class="literal">PROJECT</code> is a variable defined in your Makefile and taken +from the name of the directory when Erlang.mk bootstraps +your project.</p><p>Erlang.mk can build the <span class="emphasis"><em>ebin/$(PROJECT).app</em></span> in two different +ways: from the configuration found in the Makefile, or from +the <span class="emphasis"><em>src/$(PROJECT).app.src</em></span> file.</p><div class="section"><div class="titlepage"><div><div><h3 class="title"><a id="_application_configuration"></a>6.3.1. Application configuration</h3></div></div></div><p>Erlang.mk automatically fills the <code class="literal">PROJECT</code> variable when +bootstrapping a new project, but everything else is up to +you. None of the values are required to build your project, +although it is recommended to fill everything relevant to +your situation.</p><div class="variablelist"><dl class="variablelist"><dt><span class="term"> +<code class="literal">PROJECT</code> +</span></dt><dd> + The name of the OTP application or library. +</dd><dt><span class="term"> +<code class="literal">PROJECT_DESCRIPTION</code> +</span></dt><dd> + Short description of the project. +</dd><dt><span class="term"> +<code class="literal">PROJECT_VERSION</code> +</span></dt><dd> + Current version of the project. +</dd><dt><span class="term"> +<code class="literal">PROJECT_REGISTERED</code> +</span></dt><dd> + List of the names of all registered processes. +</dd><dt><span class="term"> +<code class="literal">LOCAL_DEPS</code> +</span></dt><dd> + List of Erlang/OTP applications this project depends on, + excluding <code class="literal">erts</code>, <code class="literal">kernel</code> and <code class="literal">stdlib</code>, or list of + dependencies local to this repository (in <code class="literal">APPS_DIR</code>). +</dd><dt><span class="term"> +<code class="literal">DEPS</code> +</span></dt><dd> + List of applications this project depends on that need + to be fetched by Erlang.mk. +</dd></dl></div><p>There’s no need for quotes or anything. The relevant part of +the Cowboy Makefile follows, if you need an example:</p><pre class="programlisting">PROJECT = cowboy +PROJECT_DESCRIPTION = Small, fast, modular HTTP server. +PROJECT_VERSION = 2.0.0-pre.2 +PROJECT_REGISTERED = cowboy_clock + +LOCAL_DEPS = crypto +DEPS = cowlib ranch</pre><p>Any space before and after the value is dropped.</p><p><a class="ulink" href="deps.asciidoc" target="_top">Dependencies</a> are covered in details in +the next chapter.</p></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a id="_legacy_method"></a>6.3.2. Legacy method</h3></div></div></div><p>The <span class="emphasis"><em>src/$(PROJECT).app.src</em></span> file is a legacy method of +building Erlang applications. It was introduced by the original +<code class="literal">rebar</code> build tool, of which Erlang.mk owes a great deal as it +is its main inspiration.</p><p>The <span class="emphasis"><em>.app.src</em></span> file serves as a template to generate the <span class="emphasis"><em>.app</em></span> +file. Erlang.mk will take it, fill in the <code class="literal">modules</code> value +dynamically, and save the result in <span class="emphasis"><em>ebin/$(PROJECT).app</em></span>.</p><p>When using this method, Erlang.mk cannot fill the <code class="literal">applications</code> +key from dependencies automatically, which means you need to +add them to Erlang.mk and to the <span class="emphasis"><em>.app.src</em></span> at the same time, +duplicating the work.</p><p>If you really can’t live without the legacy method, for one +reason or another, worry not; Erlang.mk will support it. And +if you need to create a new project that uses this method, you +just have to say so when bootstrapping:</p><pre class="programlisting">$ make -f erlang.mk bootstrap-lib LEGACY=1</pre></div></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="_automatic_application_resource_file_values"></a>6.4. Automatic application resource file values</h2></div></div></div><p>When building the application resource file, Erlang.mk may +automatically add an <code class="literal">id</code> key with information about the +Git commit (if using Git), or an empty string otherwise. +It will only do this under specific conditions:</p><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem"> +The application was built as a dependency of another, or +</li><li class="listitem"> +The legacy method was used, and the <span class="emphasis"><em>.app.src</em></span> file contained <code class="literal">{id, "git"}</code> +</li></ul></div><p>This value is most useful when you need to help your users, +as it allows you to know which version they run exactly by +asking them to look in the file, or by running a simple +command on their production server:</p><pre class="programlisting">1> application:get_all_key(cowboy). +{ok,[{description,"Small, fast, modular HTTP server."}, + {id,"2.0.0-pre.2-25-g0ffde50-dirty"},</pre></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="_file_formats"></a>6.5. File formats</h2></div></div></div><p>Erlang.mk supports a variety of different source file formats. +The following formats are supported natively:</p><div class="informaltable"><table cellpadding="4px" style="border-collapse: collapse;border-top: 3px solid #527bbd; border-bottom: 3px solid #527bbd; border-left: 3px solid #527bbd; border-right: 3px solid #527bbd; "><colgroup><col class="col_1" /><col class="col_2" /><col class="col_3" /><col class="col_4" /></colgroup><thead><tr><th style="border-right: 1px solid #527bbd; border-bottom: 1px solid #527bbd; " align="left" valign="top"> Extension </th><th style="border-right: 1px solid #527bbd; border-bottom: 1px solid #527bbd; " align="center" valign="top"> Location </th><th style="border-right: 1px solid #527bbd; border-bottom: 1px solid #527bbd; " align="center" valign="top"> Description </th><th style="border-bottom: 1px solid #527bbd; " align="center" valign="top"> Output</th></tr></thead><tbody><tr><td style="border-right: 1px solid #527bbd; border-bottom: 1px solid #527bbd; " align="left" valign="top"><p>.erl</p></td><td style="border-right: 1px solid #527bbd; border-bottom: 1px solid #527bbd; " align="center" valign="top"><p>src/</p></td><td style="border-right: 1px solid #527bbd; border-bottom: 1px solid #527bbd; " align="center" valign="top"><p>Erlang source</p></td><td style="border-bottom: 1px solid #527bbd; " align="center" valign="top"><p>ebin/*.beam</p></td></tr><tr><td style="border-right: 1px solid #527bbd; border-bottom: 1px solid #527bbd; " align="left" valign="top"><p>.core</p></td><td style="border-right: 1px solid #527bbd; border-bottom: 1px solid #527bbd; " align="center" valign="top"><p>src/</p></td><td style="border-right: 1px solid #527bbd; border-bottom: 1px solid #527bbd; " align="center" valign="top"><p>Core Erlang source</p></td><td style="border-bottom: 1px solid #527bbd; " align="center" valign="top"><p>ebin/*.beam</p></td></tr><tr><td style="border-right: 1px solid #527bbd; border-bottom: 1px solid #527bbd; " align="left" valign="top"><p>.xrl</p></td><td style="border-right: 1px solid #527bbd; border-bottom: 1px solid #527bbd; " align="center" valign="top"><p>src/</p></td><td style="border-right: 1px solid #527bbd; border-bottom: 1px solid #527bbd; " align="center" valign="top"><p>Leex source</p></td><td style="border-bottom: 1px solid #527bbd; " align="center" valign="top"><p>src/*.erl</p></td></tr><tr><td style="border-right: 1px solid #527bbd; border-bottom: 1px solid #527bbd; " align="left" valign="top"><p>.yrl</p></td><td style="border-right: 1px solid #527bbd; border-bottom: 1px solid #527bbd; " align="center" valign="top"><p>src/</p></td><td style="border-right: 1px solid #527bbd; border-bottom: 1px solid #527bbd; " align="center" valign="top"><p>Yecc source</p></td><td style="border-bottom: 1px solid #527bbd; " align="center" valign="top"><p>src/*.erl</p></td></tr><tr><td style="border-right: 1px solid #527bbd; border-bottom: 1px solid #527bbd; " align="left" valign="top"><p>.asn1</p></td><td style="border-right: 1px solid #527bbd; border-bottom: 1px solid #527bbd; " align="center" valign="top"><p>asn1/</p></td><td style="border-right: 1px solid #527bbd; border-bottom: 1px solid #527bbd; " align="center" valign="top"><p>ASN.1 files</p></td><td style="border-bottom: 1px solid #527bbd; " align="center" valign="top"><p>include/<span class="strong"><strong>.hrl include/</strong></span>.asn1db src/*.erl</p></td></tr><tr><td style="border-right: 1px solid #527bbd; " align="left" valign="top"><p>.mib</p></td><td style="border-right: 1px solid #527bbd; " align="center" valign="top"><p>mibs/</p></td><td style="border-right: 1px solid #527bbd; " align="center" valign="top"><p>SNMP MIB files</p></td><td style="" align="center" valign="top"><p>include/<span class="strong"><strong>.hrl priv/mibs/</strong></span>.bin</p></td></tr></tbody></table></div><p>Files are always searched recursively.</p><p>The build is ordered, so that files that generate Erlang source +files are run before, and the resulting Erlang source files are +then built normally.</p><p>In addition, Erlang.mk keeps track of header files (<code class="literal">.hrl</code>) +as described at the end of this chapter. It can also compile +C code, as described in the <a class="ulink" href="ports.asciidoc" target="_top">NIFs and port drivers</a> +chapter.</p><p>Erlang.mk also comes with plugins for the following formats:</p><div class="informaltable"><table cellpadding="4px" style="border-collapse: collapse;border-top: 3px solid #527bbd; border-bottom: 3px solid #527bbd; border-left: 3px solid #527bbd; border-right: 3px solid #527bbd; "><colgroup><col class="col_1" /><col class="col_2" /><col class="col_3" /><col class="col_4" /></colgroup><thead><tr><th style="border-right: 1px solid #527bbd; border-bottom: 1px solid #527bbd; " align="left" valign="top"> Extension </th><th style="border-right: 1px solid #527bbd; border-bottom: 1px solid #527bbd; " align="center" valign="top"> Location </th><th style="border-right: 1px solid #527bbd; border-bottom: 1px solid #527bbd; " align="center" valign="top"> Description </th><th style="border-bottom: 1px solid #527bbd; " align="center" valign="top"> Output</th></tr></thead><tbody><tr><td style="border-right: 1px solid #527bbd; border-bottom: 1px solid #527bbd; " align="left" valign="top"><p>.dtl</p></td><td style="border-right: 1px solid #527bbd; border-bottom: 1px solid #527bbd; " align="center" valign="top"><p>templates/</p></td><td style="border-right: 1px solid #527bbd; border-bottom: 1px solid #527bbd; " align="center" valign="top"><p>Django templates</p></td><td style="border-bottom: 1px solid #527bbd; " align="center" valign="top"><p>ebin/*.beam</p></td></tr><tr><td style="border-right: 1px solid #527bbd; " align="left" valign="top"><p>.proto</p></td><td style="border-right: 1px solid #527bbd; " align="center" valign="top"><p>src/</p></td><td style="border-right: 1px solid #527bbd; " align="center" valign="top"><p>Protocol buffers</p></td><td style="" align="center" valign="top"><p>ebin/*.beam</p></td></tr></tbody></table></div></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="_compilation_options"></a>6.6. Compilation options</h2></div></div></div><p>Erlang.mk provides a few variables that you can use to customize +the build process and the resulting files.</p><div class="section"><div class="titlepage"><div><div><h3 class="title"><a id="_erlc_opts"></a>6.6.1. ERLC_OPTS</h3></div></div></div><p><code class="literal">ERLC_OPTS</code> can be used to pass some options to <code class="literal">erlc</code>, the Erlang +compiler. Erlang.mk does not restrict any option. Please refer to +the <a class="ulink" href="http://www.erlang.org/doc/man/erlc.html" target="_top">erlc Manual</a> for the +full list.</p><p>By default, Erlang.mk will set the following options:</p><pre class="programlisting">ERLC_OPTS = -Werror +debug_info +warn_export_vars +warn_shadow_vars +warn_obsolete_guard</pre><p>In other words: warnings as errors, debug info (recommended) and +enable warnings for exported variables, shadow variables and +obsolete guard functions.</p><p>You can redefine this variable in your Makefile to change it +completely, either before or after including Erlang.mk:</p><pre class="programlisting">ERLC_OPTS = +debug_info</pre><p>You can also filter out some options from the defaults Erlang.mk +sets, by defining ERLC_OPTS after including Erlang.mk using the +<code class="literal">:=</code> operator.</p><pre class="programlisting">include erlang.mk + +ERLC_OPTS := $(filter-out -Werror,$(ERLC_OPTS))</pre></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a id="_erlc_exclude"></a>6.6.2. ERLC_EXCLUDE</h3></div></div></div><p><code class="literal">ERLC_EXCLUDE</code> can be used to exclude some modules from the +compilation. It’s there for handling special cases, you should +not normally need it.</p><p>To exclude a module, simply list it in the variable, either +before or after including Erlang.mk:</p><pre class="programlisting">ERLC_EXCLUDE = cowboy_http2</pre></div></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="_cold_and_hot_builds"></a>6.7. Cold and hot builds</h2></div></div></div><p>The first time you run <code class="literal">make</code>, Erlang.mk will build everything.</p><p>The second time you run <code class="literal">make</code>, and all subsequent times, Erlang.mk +will only rebuild what changed. Erlang.mk has been optimized for +this use case, as it is the most common during development.</p><p>Erlang.mk figures out what changed by using the dependency tracking +feature of Make. Make automatically rebuilds a target if one of its +dependency has changed (for example if a header file has changed, +all the source files that include it will be rebuilt), and Erlang.mk +leverages this feature to cut down on rebuild times.</p><p>Note that this applies only to building; some other features of +Erlang.mk will run every time they are called regardless of files +changed.</p></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="_dependency_tracking"></a>6.8. Dependency tracking</h2></div></div></div><div class="note" style="margin-left: 0; margin-right: 10%;"><h3 class="title">Note</h3><p>This section is about the dependency tracking between files +inside your project, not application dependencies.</p></div><p>Erlang.mk keeps track of the dependencies between the different +files in your project. This information is kept in the <span class="emphasis"><em>$(PROJECT).d</em></span> +file in your directory. It is generated if missing, and will be +generated again after every file change, by default.</p><p>Dependency tracking is what allows Erlang.mk to know when to +rebuild Erlang files when header files, behaviors or parse +transforms have changed. Erlang.mk also automatically keeps +track of which files should be compiled first, for example +when you have behaviors used by other modules in your project.</p><p>If your project is stable, you may want to disable generating +the dependency tracking file every time you compile. You can +do this by adding the following line to your <span class="emphasis"><em>Makefile</em></span>:</p><pre class="programlisting">NO_MAKEDEP ?= 1</pre><p>As you can see, the snippet above uses <code class="literal">?=</code> instead of a +simple equal sign. This is to allow you to temporarily override +this value when you do make substantial changes to your project +(including a new header file, new module with dependencies, etc.) +and want to rebuild the dependency tracking file. You’ll be +able to use the following command:</p><pre class="programlisting">$ NO_MAKEDEP= make</pre><p>Otherwise, <code class="literal">make clean app</code> will of course force the +recompilation of your project.</p><p>Erlang.mk can also keep track of the source files generated +by other means, for example if you generate code from a data +file in your repository.</p></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="_generating_erlang_source"></a>6.9. Generating Erlang source</h2></div></div></div><p>Erlang.mk provides hooks at different stages of the build process. +When your goal is to generate Erlang source files, you can +add your own rules before or after the dependency tracking +file is generated. To do this, you would add your hook before +or after including the <span class="emphasis"><em>erlang.mk</em></span> file.</p><p>The easiest way is after:</p><pre class="programlisting">PROJECT = example + +include erlang.mk + +$(PROJECT).d:: src/generated_mod.erl + +src/generated_mod.erl:: gen-mod.sh + $(gen_verbose) ./gen-mod.sh $@</pre><p>In this case we use <code class="literal">$(gen_verbose)</code> to hide the details of +the build by default. Erlang.mk will simply say what file +is it currently generating.</p><p>When using an external script to generate the Erlang source +file, it is recommended to depend on that script, so that +the source file gets generated again when the script gets +modified.</p><p>If for whatever reason you prefer to hook before including +Erlang.mk, don’t forget to set the <code class="literal">.DEFAULT_GOAL</code> variable, +otherwise nothing will get built:</p><pre class="programlisting">PROJECT = example + +.DEFAULT_GOAL = all + +$(PROJECT).d:: src/generated_mod.erl + +include erlang.mk + +src/generated_mod.erl:: gen-mod.sh + $(gen_verbose) ./gen-mod.sh $@</pre></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="_cleaning"></a>6.10. Cleaning</h2></div></div></div><p>Building typically involves creating a lot of new files. Some +are reused in rebuilds, some are simply replaced. All can be +removed safely.</p><p>Erlang.mk provides two commands to remove them: <code class="literal">clean</code> and +<code class="literal">distclean</code>. <code class="literal">clean</code> removes all the intermediate files that +were created as a result of building, including the BEAM files, +the dependency tracking file and the generated documentation. +<code class="literal">distclean</code> removes these and more, including the downloaded +dependencies, Dialyzer’s PLT file and the generated release, +putting your directory back to the state it was before you +started working on it.</p><p>To clean:</p><pre class="programlisting">$ make clean</pre><p>Or distclean:</p><pre class="programlisting">$ make distclean</pre><p>That is the question.</p><p>Note that Erlang.mk will automatically clean some files as +part of other targets, but it will never run <code class="literal">distclean</code> if +you don’t explicitly use it.</p></div></div><div class="navfooter"><hr /><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="code.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="code.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="deps.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top"> </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> </td></tr></table></div> +</main> +</body> +</html> |