Skip to content
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
223 changes: 124 additions & 99 deletions llvm/docs/HowToCrossCompileBuiltinsOnArm.rst
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,9 @@ using as many of the LLVM tools as we can, but it is possible to use GNU
equivalents.

You will need:
* A build of LLVM for the llvm-tools and ``llvm-config``.
* A build of LLVM for the llvm-tools and LLVM CMake files.
* A clang executable with support for the ``ARM`` target.
* compiler-rt sources.
* ``compiler-rt`` sources.
* The ``qemu-arm`` user mode emulator.
* An ``arm-linux-gnueabihf`` sysroot.

Expand All @@ -52,78 +52,94 @@ toolchain from https://developer.arm.com/open-source/gnu-toolchain/gnu-a/downloa
Building compiler-rt builtins for Arm
=====================================

We will be doing a standalone build of compiler-rt using the following cmake
options::
We will be doing a standalone build of compiler-rt. The command is shown below.
Shell variables are used to simplify some of the options::

cmake path/to/compiler-rt \
LLVM_TOOLCHAIN=<path-to-llvm-install>/
TARGET_TRIPLE=arm-none-linux-gnueabihf
GCC_TOOLCHAIN=<path-to-gcc-toolchain>
SYSROOT=${GCC_TOOLCHAIN}/${TARGET_TRIPLE}/libc
COMPILE_FLAGS="-march=armv7-a"

cmake ../llvm-project/compiler-rt \
-G Ninja \
-DCMAKE_AR=/path/to/llvm-ar \
-DCMAKE_ASM_COMPILER_TARGET="arm-linux-gnueabihf" \
-DCMAKE_ASM_FLAGS="build-c-flags" \
-DCMAKE_C_COMPILER=/path/to/clang \
-DCMAKE_C_COMPILER_TARGET="arm-linux-gnueabihf" \
-DCMAKE_C_FLAGS="build-c-flags" \
-DCMAKE_AR=${LLVM_TOOLCHAIN}/bin/llvm-ar \
-DCMAKE_NM=${LLVM_TOOLCHAIN}/bin/llvm-nm \
-DCMAKE_RANLIB=${LLVM_TOOLCHAIN}/bin/llvm-ranlib \
-DLLVM_CMAKE_DIR="${LLVM_TOOLCHAIN}/lib/cmake/llvm" \
-DCMAKE_SYSROOT="${SYSROOT}" \
-DCMAKE_ASM_COMPILER_TARGET="${TARGET_TRIPLE}" \
-DCMAKE_ASM_FLAGS="${COMPILE_FLAGS}" \
-DCMAKE_C_COMPILER_TARGET="${TARGET_TRIPLE}" \
-DCMAKE_C_COMPILER_EXTERNAL_TOOLCHAIN=${GCC_TOOLCHAIN} \
-DCMAKE_C_COMPILER=${LLVM_TOOLCHAIN}/bin/clang \
-DCMAKE_C_FLAGS="${COMPILE_FLAGS}" \
-DCMAKE_CXX_COMPILER_TARGET="${TARGET_TRIPLE}" \
-DCMAKE_CXX_COMPILER_EXTERNAL_TOOLCHAIN=${GCC_TOOLCHAIN} \
-DCMAKE_CXX_COMPILER=${LLVM_TOOLCHAIN}/bin/clang \
-DCMAKE_CXX_FLAGS="${COMPILE_FLAGS}" \
-DCMAKE_EXE_LINKER_FLAGS="-fuse-ld=lld" \
-DCMAKE_NM=/path/to/llvm-nm \
-DCMAKE_RANLIB=/path/to/llvm-ranlib \
-DCOMPILER_RT_BUILD_BUILTINS=ON \
-DCOMPILER_RT_BUILD_LIBFUZZER=OFF \
-DCOMPILER_RT_BUILD_MEMPROF=OFF \
-DCOMPILER_RT_BUILD_PROFILE=OFF \
-DCOMPILER_RT_BUILD_CTX_PROFILE=OFF \
-DCOMPILER_RT_BUILD_SANITIZERS=OFF \
-DCOMPILER_RT_BUILD_XRAY=OFF \
-DCOMPILER_RT_BUILD_ORC=OFF \
-DCOMPILER_RT_BUILD_CRT=OFF \
-DCOMPILER_RT_DEFAULT_TARGET_ONLY=ON \
-DLLVM_CONFIG_PATH=/path/to/llvm-config
-DCOMPILER_RT_EMULATOR="qemu-arm -L ${SYSROOT}" \
-DCOMPILER_RT_INCLUDE_TESTS=ON \
-DCOMPILER_RT_TEST_COMPILER=${LLVM_TOOLCHAIN}/bin/clang \
-DCOMPILER_RT_TEST_COMPILER_CFLAGS="--target=${TARGET_TRIPLE} ${COMPILE_FLAGS} --gcc-toolchain=${GCC_TOOLCHAIN} --sysroot=${SYSROOT} -fuse-ld=lld"

The ``build-c-flags`` need to be sufficient to pass the C-make compiler check,
compile compiler-rt, and if you are running the tests, compile and link the
tests. When cross-compiling with clang we will need to pass sufficient
information to generate code for the Arm architecture we are targeting.
.. note::
The command above also enables tests. Enabling tests is not required, more details
in the testing section.

We will need to select:
* The Arm target and Armv7-A architecture with ``--target=arm-linux-gnueabihf -march=armv7a``.
* Whether to generate Arm (the default) or Thumb instructions (``-mthumb``).
``CMAKE_<LANGUAGE>_<OPTION>`` options are set so that the correct ``--target``,
``--sysroot``, ``--gcc-toolchain`` and ``-march`` options will be given to the
compilers.

When using a GCC ``arm-linux-gnueabihf`` toolchain the following flags are
needed to pick up the includes and libraries:
The combination of these settings needs to be enough to pass CMake's compiler
checks, compile compiler-rt and build the test cases.

* ``--gcc-toolchain=/path/to/dir/toolchain``
* ``--sysroot=/path/to/toolchain/arm-linux-gnueabihf/libc``
The flags need to select:
* The Arm target (``--target arm-none-linux-gnueabihf``)
* The Arm architecture level (``-march=armv7-a``)
* Whether to generate Arm (``-marm``, the default) or Thumb (``-mthumb``) instructions.

In this example we will be adding all of the command line options to both
``CMAKE_C_FLAGS`` and ``CMAKE_ASM_FLAGS``. There are cmake flags to pass some of
these options individually which can be used to simplify the ``build-c-flags``::
It is possible to pass all these flags to CMake using ``CMAKE_<LANGUAGE>_FLAGS``,
but the command above uses standard CMake options instead. If you need to
add flags that CMake cannot generate automatically, add them to
``CMAKE_<LANGUAGE>_FLAGS``.

-DCMAKE_C_COMPILER_TARGET="arm-linux-gnueabihf"
-DCMAKE_ASM_COMPILER_TARGET="arm-linux-gnueabihf"
-DCMAKE_C_COMPILER_EXTERNAL_TOOLCHAIN=/path/to/dir/toolchain
-DCMAKE_SYSROOT=/path/to/dir/toolchain/arm-linux-gnueabihf/libc
When CMake has finished, build with Ninja::

Once cmake has completed the builtins can be built with ``ninja builtins``
ninja builtins

Testing compiler-rt builtins using qemu-arm
===========================================

To test the builtins library we need to add a few more cmake flags to enable
testing and set up the compiler and flags for test case. We must also tell
cmake that we wish to run the tests on ``qemu-arm``::
The following options are required to enable tests::

-DCOMPILER_RT_EMULATOR="qemu-arm -L ${SYSROOT}" \
-DCOMPILER_RT_INCLUDE_TESTS=ON \
-DCOMPILER_RT_TEST_COMPILER=${LLVM_TOOLCHAIN}/bin/clang \
-DCOMPILER_RT_TEST_COMPILER_CFLAGS="--target=${TARGET_TRIPLE} -march=armv7-a --gcc-toolchain=${GCC_TOOLCHAIN} --sysroot=${SYSROOT} -fuse-ld=lld"

-DCOMPILER_RT_EMULATOR="qemu-arm -L /path/to/armhf/sysroot"
-DCOMPILER_RT_INCLUDE_TESTS=ON
-DCOMPILER_RT_TEST_COMPILER="/path/to/clang"
-DCOMPILER_RT_TEST_COMPILER_CFLAGS="test-c-flags"
This tells compiler-rt that we want to run tests on ``qemu-arm``. If you do not
want to run tests, remove these options from the CMake command.

The ``/path/to/armhf/sysroot`` should be the same as the one passed to
``--sysroot`` in the ``build-c-flags``.
Note that ``COMPILER_RT_TEST_COMPILER_CFLAGS`` contains the equivalent of the
options CMake generated for us with the first command. We must pass them
manually here because standard options like ``CMAKE_C_COMPILER_EXTERNAL_TOOLCHAIN``
do not apply here.

The ``test-c-flags`` need to include the target, architecture, gcc-toolchain,
sysroot and Arm/Thumb state. The additional cmake defines such as
``CMAKE_C_COMPILER_EXTERNAL_TOOLCHAIN`` do not apply when building the tests. If
you have put all of these in ``build-c-flags`` then these can be repeated. If you
wish to use lld to link the tests then add ``-fuse-ld=lld``.
When CMake has finished, run the tests::

Once cmake has completed the tests can be built and run using
``ninja check-builtins``
ninja check-builtins

Troubleshooting
===============
Expand All @@ -133,9 +149,10 @@ The cmake try compile stage fails
At an early stage cmake will attempt to compile and link a simple C program to
test if the toolchain is working.

This stage can often fail at link time if the ``--sysroot=`` and
This stage can often fail at link time if the ``--sysroot=``, ``--target`` or
``--gcc-toolchain=`` options are not passed to the compiler. Check the
``CMAKE_C_FLAGS`` and ``CMAKE_C_COMPILER_TARGET`` flags.
``CMAKE_<LANGUAGE>_FLAGS`` and ``CMAKE_<LANGAUGE>_COMPILER_TARGET`` flags along
with any of the specific CMake sysroot and toolchain options.

It can be useful to build a simple example outside of cmake with your toolchain
to make sure it is working. For example::
Expand Down Expand Up @@ -179,10 +196,10 @@ The flags used to build the tests are not the same as those used to build the
builtins. The c flags are provided by ``COMPILER_RT_TEST_COMPILE_CFLAGS`` and
the ``CMAKE_C_COMPILER_TARGET``, ``CMAKE_ASM_COMPILER_TARGET``,
``CMAKE_C_COMPILER_EXTERNAL_TOOLCHAIN`` and ``CMAKE_SYSROOT`` flags are not
applied.
applied to tests.

Make sure that ``COMPILER_RT_TEST_COMPILE_CFLAGS`` contains all the necessary
information.
flags.


Modifications for other Targets
Expand All @@ -206,13 +223,13 @@ You will need to use an ``arm-linux-gnueabi`` GNU toolchain for soft-float.
AArch64 Target
--------------
The instructions for Arm can be used for AArch64 by substituting AArch64
equivalents for the sysroot, emulator and target.
equivalents for the sysroot, emulator and target::

* ``-DCMAKE_C_COMPILER_TARGET=aarch64-linux-gnu``
* ``-DCOMPILER_RT_EMULATOR="qemu-aarch64 -L /path/to/aarch64/sysroot``
-DCMAKE_C_COMPILER_TARGET=aarch64-linux-gnu
-DCOMPILER_RT_EMULATOR="qemu-aarch64 -L /path/to/aarch64/sysroot

The CMAKE_C_FLAGS and COMPILER_RT_TEST_COMPILER_CFLAGS may also need:
``"--sysroot=/path/to/aarch64/sysroot --gcc-toolchain=/path/to/gcc-toolchain"``
You will also have to update any use of the target triple in compiler flags.
For instance in ``CMAKE_C_FLAGS`` and ``COMPILER_RT_TEST_COMPILER_CFLAGS``.

Armv6-m, Armv7-m and Armv7E-M targets
-------------------------------------
Expand All @@ -235,31 +252,55 @@ into a binary and execute the tests correctly but it will not catch if the
builtins use instructions that are supported on Armv7-A but not Armv6-M,
Armv7-M and Armv7E-M.

To get the cmake compile test to pass you will need to pass the libraries
needed to successfully link the cmake test via ``CMAKE_CFLAGS``::

-DCMAKE_TRY_COMPILE_TARGET_TYPE=STATIC_LIBRARY \
-DCOMPILER_RT_OS_DIR="baremetal" \
-DCOMPILER_RT_BUILD_BUILTINS=ON \
-DCOMPILER_RT_BUILD_SANITIZERS=OFF \
-DCOMPILER_RT_BUILD_XRAY=OFF \
-DCOMPILER_RT_BUILD_LIBFUZZER=OFF \
-DCOMPILER_RT_BUILD_PROFILE=OFF \
-DCMAKE_C_COMPILER=${host_install_dir}/bin/clang \
-DCMAKE_C_COMPILER_TARGET="your *-none-eabi target" \
-DCMAKE_ASM_COMPILER_TARGET="your *-none-eabi target" \
-DCMAKE_AR=/path/to/llvm-ar \
-DCMAKE_NM=/path/to/llvm-nm \
-DCMAKE_RANLIB=/path/to/llvm-ranlib \
-DCOMPILER_RT_BAREMETAL_BUILD=ON \
-DCOMPILER_RT_DEFAULT_TARGET_ONLY=ON \
-DLLVM_CONFIG_PATH=/path/to/llvm-config \
-DCMAKE_C_FLAGS="build-c-flags" \
-DCMAKE_ASM_FLAGS="build-c-flags" \
-DCOMPILER_RT_EMULATOR="qemu-arm -L /path/to/armv7-A/sysroot" \
-DCOMPILER_RT_INCLUDE_TESTS=ON \
-DCOMPILER_RT_TEST_COMPILER="/path/to/clang" \
-DCOMPILER_RT_TEST_COMPILER_CFLAGS="test-c-flags"
Below is an example that builds the builtins for Armv7-M, but runs the tests
as Armv7-A. It is presented in full, but is very similar to the earlier
command for Armv7-A build and test::

LLVM_TOOLCHAIN=<path-to-llvm-install>/
TARGET_TRIPLE=arm-none-eabi
GCC_TOOLCHAIN=<path-to-gcc-toolchain>
SYSROOT=${GCC_TOOLCHAIN}/${TARGET_TRIPLE}/libc
COMPILE_FLAGS="-march=armv7-m -mfpu=vfpv2"

cmake ../llvm-project/compiler-rt \
-G Ninja \
-DCMAKE_AR=${LLVM_TOOLCHAIN}/bin/llvm-ar \
-DCMAKE_NM=${LLVM_TOOLCHAIN}/bin/llvm-nm \
-DCMAKE_RANLIB=${LLVM_TOOLCHAIN}/bin/llvm-ranlib \
-DLLVM_CMAKE_DIR="${LLVM_TOOLCHAIN}/lib/cmake/llvm" \
-DCMAKE_SYSROOT="${SYSROOT}" \
-DCMAKE_ASM_COMPILER_TARGET="${TARGET_TRIPLE}" \
-DCMAKE_ASM_FLAGS="${COMPILE_FLAGS}" \
-DCMAKE_C_COMPILER_TARGET="${TARGET_TRIPLE}" \
-DCMAKE_C_COMPILER_EXTERNAL_TOOLCHAIN=${GCC_TOOLCHAIN} \
-DCMAKE_C_COMPILER=${LLVM_TOOLCHAIN}/bin/clang \
-DCMAKE_C_FLAGS="${COMPILE_FLAGS}" \
-DCMAKE_CXX_COMPILER_TARGET="${TARGET_TRIPLE}" \
-DCMAKE_CXX_COMPILER_EXTERNAL_TOOLCHAIN=${GCC_TOOLCHAIN} \
-DCMAKE_CXX_COMPILER=${LLVM_TOOLCHAIN}/bin/clang \
-DCMAKE_CXX_FLAGS="${COMPILE_FLAGS}" \
-DCMAKE_EXE_LINKER_FLAGS="-fuse-ld=lld" \
-DCOMPILER_RT_BUILD_BUILTINS=ON \
-DCOMPILER_RT_BUILD_LIBFUZZER=OFF \
-DCOMPILER_RT_BUILD_MEMPROF=OFF \
-DCOMPILER_RT_BUILD_PROFILE=OFF \
-DCOMPILER_RT_BUILD_CTX_PROFILE=OFF \
-DCOMPILER_RT_BUILD_SANITIZERS=OFF \
-DCOMPILER_RT_BUILD_XRAY=OFF \
-DCOMPILER_RT_BUILD_ORC=OFF \
-DCOMPILER_RT_BUILD_CRT=OFF \
-DCOMPILER_RT_DEFAULT_TARGET_ONLY=ON \
-DCOMPILER_RT_EMULATOR="qemu-arm -L <path to arm-none-linux-gnueabihf toolchain>/arm-none-linux-gnueabihf/libc" \
-DCOMPILER_RT_INCLUDE_TESTS=ON \
-DCOMPILER_RT_TEST_COMPILER=${LLVM_TOOLCHAIN}/bin/clang \
-DCOMPILER_RT_TEST_COMPILER_CFLAGS="--target=arm-none-linux-gnueabihf -march=armv7-a --gcc-toolchain=<path to arm-none-linux-gnueabihf toolchain> --sysroot=<path to arm-none-linux-gnueabihf toolchain>/arm-none-linux-gnueabihf/libc -fuse-ld=lld" \
-DCMAKE_TRY_COMPILE_TARGET_TYPE=STATIC_LIBRARY \
-DCOMPILER_RT_OS_DIR="baremetal" \
-DCOMPILER_RT_BAREMETAL_BUILD=ON

.. note::
The sysroot used for compiling the tests is ``arm-linux-gnueabihf``, not
``arm-none-eabi`` which is used when compiling the builtins.

The Armv6-M builtins will use the soft-float ABI. When compiling the tests for
Armv7-A we must include ``"-mthumb -mfloat-abi=soft -mfpu=none"`` in the
Expand All @@ -270,19 +311,3 @@ mismatches between the M-profile objects from compiler-rt and the A-profile
objects from the test. The lld linker does not check the profile
BuildAttribute so it can be used to link the tests by adding ``-fuse-ld=lld`` to the
``COMPILER_RT_TEST_COMPILER_CFLAGS``.

Alternative using a cmake cache
-------------------------------
If you wish to build, but not test compiler-rt for Armv6-M, Armv7-M or Armv7E-M
the easiest way is to use the ``BaremetalARM.cmake`` recipe in ``clang/cmake/caches``.

You will need a bare metal sysroot such as that provided by the GNU ARM Embedded
toolchain.

The libraries can be built with the cmake options::

-DBAREMETAL_ARMV6M_SYSROOT=/path/to/bare/metal/toolchain/arm-none-eabi \
-DBAREMETAL_ARMV7M_SYSROOT=/path/to/bare/metal/toolchain/arm-none-eabi \
-DBAREMETAL_ARMV7EM_SYSROOT=/path/to/bare/metal/toolchain/arm-none-eabi \
-C /path/to/llvm/source/tools/clang/cmake/caches/BaremetalARM.cmake \
/path/to/llvm
Loading