Configuring CROSSTOOL

Overview

This tutorial uses an example scenario to describe how to configure CROSSTOOL
for a project. It’s based on an
example C++ project
that builds error-free using gcc, clang, and msvc.

In this tutorial, you configure a CROSSTOOL file so that Bazel can build the
application with emscripten. The expected outcome is to run
bazel build --config=asmjs test/helloworld.js on a Linux machine and build the
C++ application using emscripten
targeting asm.js.

Setting up the build environment

This tutorial assumes you are on Linux on which you have successfully built
C++ applications - in other words, we assume that appropriate tooling and
libraries have been installed.

In this example, we are using the --cpu flag as a differentiator, since
emscripten can target both asmjs and Web assembly. We are not configuring a
Web assembly toolchain, however. Since Bazel uses many internal tools written in
C++, such as process-wrapper, we are specifying a “sane” C++ toolchain for the
host platform.

Configuring the C++ toolchain

To configure the C++ toolchain, repeatedly build the application and eliminate
each error one by one as described below.

Note: This tutorial assumes you’re using Bazel 0.19 or later. If you’re
using an older release of Bazel, the build errors listed may appear in a
different order, but the configuration procedure is the same.

Run the build with the following command:

bazel build --config=asmjs helloworld.js

Because you specified --crosstool_top=//toolchain:emscripten in the
.bazelrc file, Bazel throws the following error:

No such package `toolchain`: BUILD file not found on package path.

In the workspace directory, create the toolchain directory for the package
and an empty BUILD file inside the toolchain directory.

Run the build again. Because the toolchain package does not yet define the
emscripten target, Bazel throws the following error:

No such target '//toolchain:emscripten': target 'emscripten' not declared in
package 'toolchain' defined by .../toolchain/BUILD

The toolchains attribute automatically maps the --cpu (and also
--compiler when specified) values to cc_toolchain. You have not yet
defined any cc_toolchain targets and Bazel will complain about that
shortly.

Run the build again. Bazel throws the following error:

The crosstool_top you specified was resolved to '//toolchain:emscripten',
which does not contain a CROSSTOOL file.

Bazel read the CROSSTOOL file and found nothing inside. Populate the
CROSTOOL file as follows:

major_version: "1"
minor_version: "0"
default_target_cpu: "asmjs"

Run the build again. Bazel throws the following error:

The label '//toolchain:asmjs_toolchain' is not a cc_toolchain rule.

This is an important milestone in which you define cc_toolchain targets
for every toolchain in the CROSSTOOL file. This is where you specify the
files that comprise the toolchain so that Bazel can set up sandboxing. Add
the following to the toolchain/BUILD file:

Since you have specified --crosstool_top and --cpu in the .bazelrc
file, //toolchain:asmjs_toolchain is selected. Because we specify
toolchain_identifier = "asmjs-toolchain", we need to create a toolchain
definition with this identifier. Add the following to the CROSTOOL file:

At this point, Bazel has enough information to attempt building the code but
it still does not know what tools to use to complete the required build
actions. Add the following to your CROSSTOOL file to tell Bazel what tools
to use:

Paths specified in the CROSSTOOL file are relative to the location of the
CROSSTOOL file itself.

The emcc.py file does not yet exist in the workspace directory. To obtain
it, you can either check the emscripten toolchain in with your project or
pull it from its GitHub repository. This tutorial uses the latter approach.
To pull the toolchain from the GitHub repository, add the following
new_http_archive repository definitions to your WORKSPACE file:

You may notice that the targets simply parse all of the files contained in
the archives pulled by the new_http_archive repository rules. In a real
world scenario, you would likely want to be more selective and granular by
only parsing the files needed by the build and splitting them by action,
such as compilation, linking, and so on. For the sake of simplicity, this
tutorial omits this step.

Run the build again. Bazel throws the following error:

"execvp(toolchain/emcc.sh, 0x12bd0e0)": No such file or directory

You now need to make Bazel aware of the artifacts you added in the previous
step. In particular, the emcc.sh script must also be explicitly listed as
a dependency of the corresponding cc_toolchain rule. Modify the
toolchain/BUILD file to look as follows:

Since emscripten caches standard library files, you can save time by not
compiling stdlib for every action and also prevent it from storing
temporary data in random place, check in the precompiled bitcode files into
the toolchain/emscript_cache directory. You can create them by calling
the following from the emscripten_clang repository (or let emscripten
create them in ~/.emscripten_cache):

..../BUILD:1:1: undeclared inclusion(s) in rule '//:helloworld.js':
this rule is missing dependency declarations for the following files included by 'helloworld.cc':
'.../external/emscripten_toolchain/system/include/libcxx/stdio.h'
'.../external/emscripten_toolchain/system/include/libcxx/__config'
'.../external/emscripten_toolchain/system/include/libc/stdio.h'
'.../external/emscripten_toolchain/system/include/libc/features.h'
'.../external/emscripten_toolchain/system/include/libc/bits/alltypes.h'

At this point you have successfully compiled the example C++ code. The
error above occurs because Bazel uses a .d file produced by the compiler
to verify that all includes have been declared and to prune action inputs.

In the .d file, Bazel discovered that our source code references system
headers that have not been explicitly declared in the BUILD file. This in
and of itself is not a problem and you can easily fix this by adding the
target folders as -isystem directories to the toolchain definition in the
CROSSTOOL file as follows: