Fossil

Artifact [abe8dccc49]
Login

Artifact abe8dccc49cd7f9e579a72bc10823ff65befd33201f135a80207f2772c01d029:


<title>Compiling and Installing Fossil</title>

<h2>0.0 Using A Pre-compiled Binary</h2>

<p>[/uv/download.html|Pre-compiled binaries] are available for recent
releases. Just download
the appropriate executable for your platform
and put it on your $PATH.
To uninstall, simply delete the executable.
To upgrade from an older release, just overwrite the older binary with
the newer one.</p>

<p>For details about how those binaries are built, see
[/wiki?name=Release+Build+How-To | the Release Build How-To wiki page].</p>


<h2>0.1 Executive Summary</h2>

<p>Building and installing is very simple.  Three steps:</p>

<ol>
<li> Download and unpack a source tarball or ZIP.
<li> <b>./configure; make</b>
<li> Move the resulting "fossil" or "fossil.exe" executable to someplace on
your $PATH.
</ol>

<p><hr>

<h2>1.0 Obtaining The Source Code</h2>

<p>Fossil is self-hosting, so you can obtain a ZIP archive or tarball
containing a snapshot of the <em>latest</em> version directly from
Fossil's own fossil repository. Additionally, source archives of
<em>released</em> versions of
fossil are available from the [/uv/download.html|downloads page].
To obtain a development version of fossil, follow these steps:</p>

<ol>
<li><p>Point your web browser to [https://fossil-scm.org/]</li>

<li><p>Click on the [/timeline|Timeline]
link at the top of the page.</p></li>

<li><p>Select a version of of Fossil you want to download.  The latest
version on the trunk branch is usually a good choice.  Click on its
link.</p></li>

<li><p>Finally, click on one of the
"Zip Archive" or "Tarball" links, according to your preference.
These link will build a ZIP archive or a gzip-compressed tarball of the
complete source code and download it to your computer.
</ol>

<h2>Aside: Is it really safe to use an unreleased development version of
the Fossil source code?</h2>

Yes!  Any check-in on the
[/timeline?t=trunk | trunk branch] of the Fossil
[http://fossil-scm.org/home/timeline | Fossil self-hosting repository]
will work fine.  (Dodgy code is always on a branch.)  In the unlikely
event that you pick a version with a serious bug, it still won't
clobber your files.  Fossil uses several
[./selfcheck.wiki | self-checks] prior to committing any
repository change that prevent loss-of-work due to bugs.

The Fossil [./selfhost.wiki | self-hosting repositories], especially
the one at [http://fossil-scm.org/home], usually run a version
of trunk that is less than a week or two old.  Look at the bottom
left-hand corner of this screen (to the right of "This page was
generated in...") to see exactly which version of Fossil is
rendering this page.  It is always safe to use whatever version
of the Fossil code you find running on the main Fossil website.

<h2>2.0 Compiling</h2>

<ol>
<li value="5">
<p>Unpack the ZIP or tarball you downloaded then
<b>cd</b> into the directory created.</p></li>

<li><i>(Optional, Debian-compatible Linux only)</i>
Make sure you have all the necessary tools and libraries at hand by running:
<b>sudo apt install tcl-dev tk libssl-dev zlib1g-dev</b>.

<li><i>(Optional, Unix only)</i>
Run <b>./configure</b> to construct a makefile.

<ol type="a">
<li><p>
The build system for Fossil on Unix-like systems assumes that the
OpenSSL development and runtime files are available on your system,
because unprotected repositories are trivial to attack otherwise.
Indeed, some public Fossil repositories — including Fossil's own — today
run in an HTTPS-only mode, so that you can't even do an anonymous clone
from them without using the TLS features added to Fossil by OpenSSL. To
weaken that stance could allow a
[https://en.wikipedia.org/wiki/Man-in-the-middle_attack|man in the
middle attack], such as one that substitutes malicious code into your
Fossil repository clone.</p>

<p>You can force the Fossil build system to avoid searching for, building
against, and linking to the OpenSSL library by passing
<b>--with-openssl=none</b> to the <tt>configure</tt> script.</p>

<p>If you do not have the OpenSSL development libraries on your system,
we recommend that you install them, typically via your OS's package
manager. The Fossil build system goes to a lot of effort to seek these
out wherever they may be found, so that is typically all you need to
do.</p>

<p>For more advanced use cases, see the [./ssl.wiki#openssl-bin|OpenSSL
discussion in the "TLS and Fossil" document].</p>

<li><p>
To build a statically linked binary (suitable for use inside a chroot
jail) add the <b>--static</b> option. (See the [#docker | Docker section
below].)

<li><p>
To enable the native [./th1.md#tclEval | Tcl integration feature] feature,
add the <b>--with-tcl=1</b> and <b>--with-tcl-private-stubs=1</b> options.

<li><p>
Other configuration options can be seen by running
<b>./configure --help</b>
</ol>

<li><p>Run "<b>make</b>" to build the "fossil" or "fossil.exe" executable.
The details depend on your platform and compiler.

<ol type="a">
<li><p><i>Unix</i> → the configure-generated Makefile should work on
all Unix and Unix-like systems.  Simply type "<b>make</b>".

<li><p><i>Unix without running "configure"</i> → if you prefer to avoid
running configure, you can also use: <b>make -f Makefile.classic</b>.  You may
want to make minor edits to Makefile.classic to configure the build for your
system.

<li><p><i>MinGW / MinGW-w64</i> → The best-supported path is to build
via the MinGW specific Makefile under a POSIX build of GNU make:
"<b>make -f win/Makefile.mingw</b>".

There is limited support for building under MinGW's native Windows port
of GNU Make instead by defining the <tt>USE_WINDOWS=1</tt> variable, but
it's better to build under MSYS, Cygwin, or WSL on Windows since this
mode doesn't take care of cases such as the "openssl" target, which
depends on <tt>sed</tt>. We've gone as far down this path as is
practical short of breaking cross-compilation under Linux, macOS, and so
forth, as we'd have to do to make everything work under
<tt>cmd.exe</tt>.

Unless you're building under MSYS where commands like "<tt>gcc</tt>"
give MinGW's GCC and not some other version, you will need to make minor
edits to win/Makefile.mingw to configure the cross-compilation
environment. It should suffice to switch to one of the predefined
<tt>PREFIX</tt> values, causing the build to be done using
"<tt>x86_64-w64-mingw32-gcc</tt>" for example, yielding a 64-bit native
Windows binary.

To enable the native [./th1.md#tclEval | Tcl integration feature], use a
command line like the following (all on one line):

<b>make -f win/Makefile.mingw FOSSIL_ENABLE_TCL=1 FOSSIL_ENABLE_TCL_STUBS=1 FOSSIL_ENABLE_TCL_PRIVATE_STUBS=1</b>

Alternatively, running <b>./configure</b> under MSYS should give a
suitable top-level Makefile. However, options passed to configure that are
not applicable on Windows may cause the configuration or compilation to fail
(e.g. fusefs, internal-sqlite, etc).

<li><p><i>MSVC</i> → Use the MSVC makefile.  

Run all of the following from a "x64 Native Tools Command Prompt". 

First
change to the "win/" subdirectory ("<b>cd win</b>") then run
"<b>nmake /f Makefile.msc</b>".<br><br>Alternatively, the batch
file "<b>win\buildmsvc.bat</b>" may be used and it will attempt to
detect and use the latest installed version of MSVC.<br><br>To enable
the optional <a href="https://www.openssl.org/">OpenSSL</a> support,
first <a href="https://www.openssl.org/source/">download the official
source code for OpenSSL</a> and extract it to an appropriately named
"<b>openssl</b>" subdirectory within the local
[/tree?ci=trunk&name=compat | compat] directory then make sure that some recent
<a href="http://www.perl.org/">Perl</a> binaries are installed locally,
and finally run one of the following commands:
<blockquote><pre>
nmake /f Makefile.msc FOSSIL_ENABLE_SSL=1 FOSSIL_BUILD_SSL=1 PERLDIR=C:\full\path\to\Perl\bin
</pre></blockquote>
<blockquote><pre>
buildmsvc.bat FOSSIL_ENABLE_SSL=1 FOSSIL_BUILD_SSL=1 PERLDIR=C:\full\path\to\Perl\bin
</pre></blockquote>
To enable the optional native [./th1.md#tclEval | Tcl integration feature],
run one of the following commands or add the &quot;FOSSIL_ENABLE_TCL=1&quot;
argument to one of the other NMAKE command lines:
<blockquote><pre>
nmake /f Makefile.msc FOSSIL_ENABLE_TCL=1
</pre></blockquote>
<blockquote><pre>
buildmsvc.bat FOSSIL_ENABLE_TCL=1
</pre></blockquote>

<li><p><i>Cygwin</i> → The same as other Unix-like systems. It is
recommended to configure using: "<b>configure --disable-internal-sqlite</b>",
making sure you have the "libsqlite3-devel" , "zlib-devel" and
"openssl-devel" packages installed first.
</ol>
</ol>

<h2>3.0 Installing</h2>

<ol>
<li value="9">
<p>The finished binary is named "fossil" (or "fossil.exe" on Windows).
Put this binary in a
directory that is somewhere on your PATH environment variable.
It does not matter where.</p>

<li>
<p><b>(Optional:)</b>
To uninstall, just delete the binary.</p>
</ol>

<h2>4.0 Additional Considerations</h2>

<ul>
<li><p>
  If the makefiles that come with Fossil do not work for
  you, or for some other reason you want to know how to build
  Fossil manually, then refer to the
  [./makefile.wiki | Fossil Build Process] document which describes
  in detail what the makefiles do behind the scenes.

<li><p>
  The fossil executable is self-contained and stand-alone and usually
  requires no special libraries or other software to be installed.  However,
  the "--tk" option to the [/help/diff|diff command] requires that Tcl/Tk
  be installed on the local machine.  You can get Tcl/Tk from
  [http://www.activestate.com/activetcl|ActiveState].

<li><p>
  To build on older Macs (circa 2002, MacOS 10.2) edit the Makefile
  generated by configure to add the following lines:
  <blockquote><pre>
  TCC += -DSQLITE_WITHOUT_ZONEMALLOC
  TCC += -D_BSD_SOURCE
  TCC += -DWITHOUT_ICONV
  TCC += -Dsocketlen_t=int
  TCC += -DSQLITE_MAX_MMAP_SIZE=0
</pre></blockquote>
</ul>


<h2 id="docker">5.0 Building a Docker Container</h2>

Fossil ships a <tt>Dockerfile</tt> at the top of its source tree which
you can build like so:

<pre><code>  $ docker build -t fossil .</code></pre>

If the image built successfully, you can create a container from it and
test that it runs:

<pre><code>  $ docker run --name fossil -p 9999:8080/tcp fossil</code></pre>

This shows us remapping the internal TCP listening port as 9999 on the
host. As a rule, there's little point to using the "<tt>fossil server
--port</tt>" feature inside a Docker container. Let it default to 8080
internally, then remap it to wherever you want it on the host instead.

Our stock <tt>Dockerfile</tt> configures Fossil with the default feature
set, so you may wish to modify the <tt>Dockerfile</tt> to add
configuration options, add APK packages to support those options, and so
forth. It also strips out all but the default and darkmode skins to save
executable space.

There are two convenience targets for you, <tt>make container-image</tt>
and <tt>make container-run</tt>. The first creates a versioned container
image, and the second does that and then launches a fresh container
based on that image. You can pass extra arguments to the first command
via the Makefile's <tt>DBFLAGS</tt> variable and to the second with the
<tt>DRFLAGS</tt> variable. To get the custom port setting as in second
command above, say:

<pre><code>  $ make container-run DRFLAGS='-p 9999:8080/tcp'</code></pre>

Contrast the raw "<tt>docker</tt>" commands above, which create an
<i>unversioned</i> image called <tt>fossil:latest</tt> and from that a
container simply called <tt>fossil</tt>. The unversioned names are more
convenient for interactive use, while the versioned ones are good for
CI/CD type applications since they avoid a conflict with past versions;
it lets you keep old containers around for quick roll-backs while
replacing them with fresh ones.


<h3 id="docker-storage">5.1 Repository Storage Options</h3>

If you want the container to serve an existing repository, there are at
least two right ways to do it.

The wrong way is to use the <tt>Dockerfile COPY</tt> command to bake it
into the image at build time. It will become one of the image's base
layers, so that each time you build a container from that image, the
repo gets reset to its build-time state. Worse, restarting the container
will do the same thing, since the base image layers are immutable in
Docker. This is almost certainly not what you want.

The correct ways put the repo into the <i>container</i> created from the
<i>image</i>, not in the image itself.


<h4>5.1.1 Storing the Repo Inside the Container</h4>

The simplest method is to stop the container if it was running,
then say:

<pre><code>  $ docker cp /path/to/my-project.fossil fossil:/jail/museum/repo.fossil
  $ docker start fossil
  $ docker exec fossil chown -R 499 /jail/museum</code></pre>

That copies the local Fossil repo into the container where the server
expects to find it, so that the "start" command causes it to serve from
that copied-in file instead. Since it lives atop the immutable base layers, it
persists as part of the container proper, surviving restarts.

Notice that the copy command changes the name of the repository database.
The container configuration expects it to be called
<tt>repo.fossil</tt>, which it almost certainly was not out on the host
system. This is because there is only one repository inside this
container, so we don't have to name it after the project it contains, as
is traditional. A generic name lets us hard-code the server start
command.

If you skip the "chown" command above and put "http://localhost:9999/" into
your browser, expecting to see the copied-in repo's home page, you will
get an opaque "Not Found" error. This is because the user and
group ID of the file will be that of your local user on the container's
host machine, which is unlikely to map to anything in the container's
<tt>/etc/passwd</tt> and <tt>/etc/group</tt> files, effectively
preventing the server from reading the copied-in repository file.
499 is the default "fossil" user ID inside the container, causing Fossil to run
with that user's privileges after it enters the chroot.
(See [#docker-args | below] for how to change this default.)
You don't have to restart the server after fixing this with
<tt>chmod</tt>: simply reload the browser, and Fossil will try again.


<h4>5.1.2 Storing the Repo Outside the Container</h4>

The simple storage method above has a problem: Docker containers are designed to be
killed off at the slightest cause, rebuilt, and redeployed. If you do
that with the repo inside the container, it gets destroyed, too. The
solution is to replace the "run" command above with the following:

<pre><code>  $ docker run \
    --name fossil-bind-mount -p 9999:8080 \
    -v ~/museum:/jail/museum fossil
</code></pre>

Because this bind mount maps a host-side directory (<tt>~/museum</tt>)
into the container, you don't need to <tt>docker cp</tt> the repo into
the container at all.  It still expects to find the repository as
<tt>repo.fossil</tt> under that directory, but now both the host and the
container can see that file.  (Beware: This may create a
[https://www.sqlite.org/howtocorrupt.html | risk of data corruption] due
to SQLite locking issues if you try to modify the DB from both sides at
once.)

Instead of a bind mount, you could instead set up
a separate [https://docs.docker.com/storage/volumes/ | Docker volume],
at which point you <i>would</i> need to <tt>docker cp</tt> the repo file
into the container.

Either way, files in these mounted directories have a lifetime independent
of the container(s) they're mounted into.  When you need to
rebuild the container or its underlying image — such as to upgrade to a newer version of Fossil
— the external directory remains behind and gets remapped into the new container
when you recreate it with <tt>-v</tt>.


<h3 id="docker-chroot">5.2 Why Chroot?</h3>

A potentially surprising feature of this container is that it runs
Fossil as root. Since that causes [./chroot.md | Fossil's chroot jail
feature] to kick in, and a Docker container is a type of über-jail
already, you may be wondering why we don't either:

  #  run <tt>fossil server --nojail</tt> to skip the internal chroot; or
  #  set "<tt>USER fossil</tt>" in the Dockerfile so it starts Fossil as
     that user instead

The reason is, although this container is quite stripped-down by today's
standards, it's based on the [https://www.busybox.net/BusyBox.html |
surprisingly powerful Busybox project].  (This author made a living for
years in the early 1990s using Unix systems that were less powerful than
this container.) If someone ever figured out how to make a Fossil binary
execute arbitrary commands on the host or to open up a remote shell,
they'd likely be able to island-hop from there into the rest of your
network. We need this cute double-jail dance to keep the Fossil instance
from accessing the Busybox features.

We deem this risk low since a) it's never happened, that we know of;
and b) we've turned off all of the risky features like TH1 docs.
Nevertheless, we believe in defense-in-depth.

If you shell into the container and do a <tt>ps</tt>, you'll find
<tt>fossil</tt> running as <tt>root</tt> even though the chroot feature
is documented as causing Fossil to drop its root privileges in favor of
the owner of the repository database or its containing folder.
If the repo file is owned by "fossil," why is it still running as root?
It's because you're likley seeing only the parent
process, which may need to do rootly things like listening on port 80 or
443. Fossil's chroot feature only takes effect in the child processes,
the ones forked off to handle each HTTP/CGI hit. This is why you can fix broken
permissions with <tt>chown</tt> after the container is already running,
without restarting it: each hit reevaluates the repository file
permissions when deciding what user to become when dropping root
privileges.


<h3 id="docker-static">5.3 Extracting a Static Binary</h3>

Our 2-stage build process uses Alpine Linux only as a build host. Once
we've got everything reduced to the two key static binaries — Fossil and
Busybox — we throw all the rest of it away.

A secondary benefit falls out of this process for free: it's arguably
the easiest way to build a purely static Fossil binary for Linux. Most
modern Linux distros make this surprisingly difficult, but Alpine's
back-to-basics nature makes static builds work the way they used to,
back in the day. If that's what you're after, you can skip the "run"
command above and create a temporary container from the image, then
extract the executable from it instead:

<pre><code>  $ docker create --name fossil-static-tmp fossil
  $ docker cp fossil-static-tmp:/jail/bin/fossil .
  $ docker container rm fossil-static-tmp
</code></pre>

The resulting binary is the single largest file inside that container,
at about 6 MiB. (It's built stripped.)


<h3 id="docker-args">5.4 Container Build Arguments</h3>

<h4>5.4.1 Package Versions</h4>

You can override the default versions of Fossil and BusyBox that get
fetched in the build step.  To get the latest-and-greatest of
everything, you could say:

<pre><code>  $ docker build -t fossil \
    --build-arg FSLVER=trunk \
    --build-arg BBXVER=master .</code></pre>

(But don't, for reasons we will get to.)

Because the BusyBox configuration file we ship was created with and
tested against a specific stable release, that's the version we pull by
default. It does try to merge the defaults for any new configuration
settings into the stock set, but since it's possible this will fail, we
don't blindly update the BusyBox version merely because a new release
came out.  Someone needs to get around to vetting it against our stock
configuration first.

As for Fossil, it defaults to fetching the same version as the checkout
you're running the build command from, based on checkin ID. The most
common reason to override this is to get a release version:

<pre><code>  $ docker build -t fossil \
    --build-arg FSLVER=version-2.19 .</code></pre>

It's best to use a specific version number rather than the generic
"release" tag because Docker caches downloaded files and tries to reuse
them across builds. If you ask for "release" before a new version is
tagged and then immediately after, you expect to get two different
tarballs, but because the URL hasn't changed, if you have an old release
tarball in your Docker cache, you'll get the old version even if you
pass the "docker build --no-cache" option.

This is why we default to a checkin ID rather than a generic tag like
"trunk": so the URL will change each time you update your Fossil source
tree, forcing Docker to pull a fresh tarball.

<h4>5.4.2 User & Group IDs</h4>

The "fossil" user and group IDs inside the container default to 499.
Why?  Regular user IDs start at 500 or 1000 on most Unix type systems,
leaving those below it for "system" users like this Fossil daemon owner.
Since standard OS system users start at 0 and go upward, we started at
500 and went down one to reduce the chance of a conflict to as close to
zero as we can manage.

To change it to something else, say:

<pre><code>  $ docker build -t fossil --build-arg UID=501 .</code></pre>

This is particularly useful if you're putting your repository on a
Docker volume since the IDs "leak" out into the host environment via
file permissions.  You may therefore wish them to mean something on both
sides of the container barrier rather than have "499" appear on the host
in "<tt>ls -l</tt>" output.


<h2>6.0 Building on/for Android</h2>

<h3>6.1 Cross-compiling from Linux</h3>

The following instructions for building Fossil for Android via Linux,
without requiring a rooted OS, are adapted from
[https://fossil-scm.org/forum/forumpost/e0e9de4a7e | forumpost/e0e9de4a7e].

On the development machine, from the fossil source tree:

<pre><code>export CC=$NDK_PATH/toolchains/llvm/prebuilt/linux-x86_64/bin/armv7a-linux-androideabi21-clang
./configure --with-openssl=none
make
</code></pre>


On the Android device, enable the <em>USB debugging</em> option from
Developer menu in Device Options. Connect the device to the development
system with USB. If it's configured and connected properly,
the device should show up in the output of <code>adb devices</code>:

<pre><code>sudo adb devices
</code></pre>

Copy the resulting fossil binary onto the device...

<pre><code>sudo adb push fossil /data/local/tmp
</code></pre>

And run it from an <code>adb</code> shell:

<pre><code>sudo adb shell
&gt; cd /data/local/tmp
# Fossil requires a HOME directory to work with:
&gt; export HOME=$PWD
&gt; export PATH=$PWD:$PATH
&gt; fossil version
This is fossil version 2.11 &#91;e5653a4ceb] 2020-03-26 18:54:02 UTC
</code></pre>

The output might, or might not, include warnings such as:

<pre><code>WARNING: linker: ./fossil: unused DT entry: type 0x6ffffef5 arg 0x1464
WARNING: linker: ./fossil: unused DT entry: type 0x6ffffffe arg 0x1ba8
WARNING: linker: ./fossil: unused DT entry: type 0x6fffffff arg 0x2
</code></pre>

The source of such warnings is not 100% certain.
Some information about these (reportedly harmless) warnings can
be found
[https://stackoverflow.com/a/41900551 | on this StackOverflow post].


<a id='fuzzer'></a>
<h2>7.0 Building for Fuzz Testing</h2>

This feature is primarily intended for fossil's developers and may
change at any time. It is only known to work on Linux systems and has
been seen to work on x86/64 and ARM.

Fossil has builtin support for processing specific features using
<tt>libfuzzer</tt>. The features which can be tested this way are
found in the help text for the [/help?cmd=test-fuzz|test-fuzz
command].

Fuzzing requires:

  *  Customizing the build of fossil a small bit.
  *  The clang C compiler.
  *  libfuzzer. On Ubuntu-derived systems, it can be installed with
     <tt>apt install libfuzzer-XYZ</tt>, where XYZ is a version number
     (several versions may be available on any given system)


First, modify the top-level <tt>Makefile.in</tt>:

  *  Extend the <tt>TCCFLAGS</tt> variable with: <tt>-fsanitize=fuzzer
   -DFOSSIL_FUZZ</tt> (and see [/finfo/src/fuzz.c | src/fuzz.c] for
   more options).
  *  Rename <tt>APPNAME</tt> from <tt>fossil</tt> to <tt>fossil-fuzz</tt>.

Then rebuild:

<pre></code>$ make clean
$ ./configure CC=/path/to/clang
$ make
</code></pre>

If clang is your default compiler, the <tt>CC</tt> configure option is
not required.

The resulting <tt>fossil-fuzz</tt> binary differs from the standard
one primarily in that it runs the <tt>test-fuzz</tt> command by
default. It needs to be told what to fuzz and needs to be given a
directory of input files to seed the fuzzer with:


<pre></code>$ mkdir cases
  # Copy input files into ./cases. e.g. when fuzzing the markdown
  # processor, copy any to-be-tested .md files into that directory.
  # Then start the fuzzer:
$ ./fossil-fuzz --fuzztype markdown cases
</code></pre>

As it works, it writes its mutated test files into the test-input
directory, each one named in the form of a hash. When it finds a
problem it will produce a stack trace for the offending code, will
output the name of the file which triggered the crash (named
<tt>cases/SOME_HASH</tt>) and may, depending on the nature of the
problem, produce a file named <tt>crash-SOMETHING</tt>.  In theory the
crash file can be fed directly back into the fuzzer to reproduce the
problem:

<pre></code>$ ./fossil-fuzz --fuzztype markdown crash-SOMETHING
</code></pre>

But whether or not it will genuinely crash may depend on static
app-level state which might not trigger the crash when running an
individual test.

For a detailed information about the fuzzer's flags and features, see:

  *  [https://llvm.org/docs/LibFuzzer.html]
  *  [https://github.com/google/fuzzing/blob/master/tutorial/libFuzzerTutorial.md]
 
Flags for the fuzzer can be passed directly to fossil,
e.g. <tt>-jobs=4</tt> to start four fuzzer jobs in parallel, but doing
so may cause the fuzzer to <em>strip the --fuzztype flag</em>, leading
to it testing the wrong thing. When passing on fuzzer-specific flags
along with <tt>--fuzztype</tt>, be sure to check your system's process
list to ensure that your <tt>--fuzztype</tt> flag is there.


<a id='wasm'></a>
<h2>8.0 Building WebAssembly Components</h2>

As of version 2.19, fossil uses one component built as
[https://developer.mozilla.org/en-US/docs/WebAssembly | WebAssembly]
a.k.a. WASM. Because compiling WASM code requires non-trivial
client-side tooling, the repository includes compiled copies of these
pieces. Most Fossil hackers should never need to concern themselves
with the WASM parts, but this section describes how to for those who
want or need to do so.

<strong>The bits described in this section are necessary when updating
<tt>extsrc/pikchr.c</tt></strong> from the upstream source, or the
fossil binary will use a different version of pikchr than
[/pikchrshow] does (as the latter runs the WASM build of pikchr).

These instructions have only ever been tested on Linux systems. They
"should" work on any Unix-like system supported by Emscripten. The
fossil makefiles for Windows builds <em>do not</em> include any of the
WASM-related components (patches to add that would be welcomed, of
course).

The first step is to configure the tree with support for
[https://emscripten.org/|Emscripten]. This requires that the system
has the Emscripten SDK (a.k.a. emsdk) installed, as documented at:

[https://emscripten.org/docs/getting_started/downloads.html]

For instructions on keeping the SDK up to date, see:

[https://emscripten.org/docs/tools_reference/emsdk.html]

    Sidebar: getting Emscripten up and running is trivial and
    painless, at least on Linux systems, but the installer downloads
    many hundreds of megabytes of tools and dependencies, all of which
    will be installed under the single SDK directory (as opposed to
    being installed at the system level). It does, however, require
    that python3 be installed at the system level and it can
    optionally make use of a system-level cmake for certain tasks
    unrelated to how fossil uses the SDK.

After installing the SDK, configure the fossil tree with emsdk
support:

<pre><code>$ ./configure --with-emsdk=/path/to/emsdk ...other options...
</code></pre>

If the <tt>--with-emsdk</tt> flag is not provided, the configure
script will check for the environment variable <tt>EMSDK</tt>, which
is one of the standard variables the SDK environment uses. If that
variable is found, its value will implicitly be used in place of the
missing <tt>--with-emsdk</tt> flag. Thus, if the <tt>emsdk_env.sh</tt>
script is sourced into the shell before running the configure script,
the SDK will be detected even without the config flag.

The configure script installs some makefile variables which tell the
build where to find the SDK and it generates a script named
<tt>tools/emcc.sh</tt> (from the template file
<tt>[/file/tools/emcc.sh.in|/tools/emcc.sh.in]</tt>), which is a
wrapper around the Emscripten C compiler (<tt>emcc</tt>). The wrapper
script uses the configure-time state to attempt to set up the various
environment variables which are required by <tt>emcc</tt> and will
fail if it cannot do so. Once it's set up the environment, it passes
on all of its arguments to <tt>emcc</tt>.

The WASM-related build parts are set up such that none of them should
ever trigger implicity (e.g. via dependencies resolution) in a normal
build cycle. They are instead explicitly built as described below.

From the top of the source tree, all WASM-related components can be
built with:

<pre><code>$ make wasm</code></pre>

As of this writing, those parts include:

   *  <tt>extsrc/pikchr.wasm</tt> is a WASM-compiled form of
      <tt>extsrc/pikchr.c</tt>.
   *  <tt>extsrc/pikchr.js</tt> is JS/WASM glue code generated by Emscripten
      to give JS code access to the API exported by the WASM file.

    Sidebar: The file
    <tt>[/file/extsrc/pikcher-worker.js|extsrc/pikcher-worker.js]</tt>
    is hand-coded and intended to be loaded as a "Worker" in
    JavaScript. That file loads the main module and provides an
    interface via which a main JavaScript thread can communicate with
    pikchr running in a Worker thread. The file
    <tt>[/file/src/fossil.page.pikchrshowasm.js|src/fossil.page.pikchrshowasm.js]</tt>
    implements the [/pikchrshow] app and demonstrates how
    <tt>pikchr-worker.js</tt> is used.

When a new version of <tt>extsrc/pikchr.c</tt> is installed, the
files <tt>pikchr.{js,wasm}</tt> will need to be recompiled to account
for that. Running <tt>make wasm</tt> will, if the build is set up for
the emsdk, recompile those:

<pre><code>$ make wasm
./tools/emcc.sh -o extsrc/pikchr.js ...
$ ls -la extsrc/pikchr.{js,wasm}
-rw-rw-r-- 1 stephan stephan 17263 Jun  8 03:59 extsrc/pikchr.js
-rw-rw-r-- 1 stephan stephan 97578 Jun  8 03:59 extsrc/pikchr.wasm
</code></pre>

<blockquote>Sidebar: if that fails with a message along the lines of:

<pre><code>setting `EXPORTED_RUNTIME_METHODS` expects `<class 'list'>` but got `<class 'str'>`</code></pre>

then the emcc being invoked is too old: emcc changed the format of
list-type arguments at some point. The required minimum version is
unknown, but any SDK version from May 2022 or later "should" (as of
this writing) suffice. Any older version may or may not work.
</blockquote>

After that succeeds, we need to run the normal build so that those
generated files can be compiled in to the fossil binary, accessible
via the [/help?cmd=/builtin|/builtin page]:

<pre><code>$ make</code></pre>

Before checking in those newly-built files, they need to be tested by
running the [/pikchrshow] page. If that page loads, the compilation
process fundamentally worked (a load failure will be made obvious to
the viewer). If it fails to load then the browser's dev tools console
likely provides at least a small hint (and <em>sometimes</em> a useful
hint) about the nature of the problem. Don't check those files in
until [/pikchrshow] runs, though!

Should pikchr's C interface ever change, <tt>pikchr-worker.js</tt>
will need to be updated to accommodate it, but such modification is
typically trivial.

<h3>8.1 Solutions other than Emscripten?</h3>

Emscripten is not the only option for building C as WASM, but it
provides a complete toolchain which eliminates many other steps which
must otherwise be accounted for on a per-project basis.  Despite its
convenience, it behooves us to explore other build options for the
sake of portability and avoiding what amounts to vendor lock-in.

For later refererence, here are articles specifically covering
building WASM projects without using Emscripten:

   *  [https://surma.dev/things/c-to-webassembly/]
   *  [https://schellcode.github.io/webassembly-without-emscripten]