aboutsummaryrefslogtreecommitdiffstats
path: root/guide/building.html
diff options
context:
space:
mode:
Diffstat (limited to 'guide/building.html')
-rw-r--r--guide/building.html223
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&gt; 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>