cb424d7448
verify-patch-sanity.py validates every active recipe .patch has internally- consistent hunk line counts — catching the 'malformed patch at line N' failure at commit/CI/preflight time instead of hours into a cook. This cycle hit that class three times (qtwaylandscanner, sddm, xwayland), each only discovered when cookbook tried to apply the patch. Running it across the repo found 29 latent malformed patches (validated against GNU patch: e.g. relibc/P3-sysv-ipc reproduces 'malformed patch at line 22'). They were harmless only because they sit in vendored recipes (baked, not re- applied) — but would fail on any version-bump re-derivation. --fix recounts the hunk headers (body untouched) and repaired all 29. Wired into build-preflight.sh (Phase 1.0D) and redbear-ci.yml, with a unit test (test-patch-sanity.sh). Skips archived/legacy trees and unvalidatable formats (empty placeholders, bare-@@ git hunks).
204 lines
9.3 KiB
ReStructuredText
204 lines
9.3 KiB
ReStructuredText
===================================================================
|
|
Cross-compilation using Clang
|
|
===================================================================
|
|
|
|
Introduction
|
|
============
|
|
|
|
This document will guide you in choosing the right Clang options
|
|
for cross-compiling your code to a different architecture. It assumes you
|
|
already know how to compile the code in question for the host architecture,
|
|
and that you know how to choose additional include and library paths.
|
|
|
|
However, this document is *not* a "how to" and won't help you setting your
|
|
build system or Makefiles, nor choosing the right CMake options, etc.
|
|
Also, it does not cover all the possible options, nor does it contain
|
|
specific examples for specific architectures. For a concrete example, the
|
|
`instructions for cross-compiling LLVM itself
|
|
<https://llvm.org/docs/HowToCrossCompileLLVM.html>`_ may be of interest.
|
|
|
|
After reading this document, you should be familiar with the main issues
|
|
related to cross-compilation, and what main compiler options Clang provides
|
|
for performing cross-compilation.
|
|
|
|
Cross compilation issues
|
|
========================
|
|
|
|
In GCC world, every host/target combination has its own set of binaries,
|
|
headers, libraries, etc. So, it's usually simple to download a package
|
|
with all files in, unzip to a directory and point the build system to
|
|
that compiler, that will know about its location and find all it needs to
|
|
when compiling your code.
|
|
|
|
On the other hand, Clang/LLVM is natively a cross-compiler, meaning that
|
|
one set of programs can compile to all targets by setting the ``-target``
|
|
option. That makes it a lot easier for programmers wishing to compile to
|
|
different platforms and architectures, and for compiler developers that
|
|
only have to maintain one build system, and for OS distributions, that
|
|
need only one set of main packages.
|
|
|
|
But, as is true to any cross-compiler, and given the complexity of
|
|
different architectures, OS's and options, it's not always easy finding
|
|
the headers, libraries or binutils to generate target specific code.
|
|
So you'll need special options to help Clang understand what target
|
|
you're compiling to, where your tools are, etc.
|
|
|
|
Another problem is that compilers come with standard libraries only (like
|
|
``compiler-rt``, ``libcxx``, ``libgcc``, ``libm``, etc), so you'll have to
|
|
find and make available to the build system, every other library required
|
|
to build your software, that is specific to your target. It's not enough to
|
|
have your host's libraries installed.
|
|
|
|
Finally, not all toolchains are the same, and consequently, not every Clang
|
|
option will work magically. Some options, like ``--sysroot`` (which
|
|
effectively changes the logical root for headers and libraries), assume
|
|
all your binaries and libraries are in the same directory, which may not
|
|
true when your cross-compiler was installed by the distribution's package
|
|
management. So, for each specific case, you may use more than one
|
|
option, and in most cases, you'll end up setting include paths (``-I``) and
|
|
library paths (``-L``) manually.
|
|
|
|
To sum up, different toolchains can:
|
|
* be host/target specific or more flexible
|
|
* be in a single directory, or spread out across your system
|
|
* have different sets of libraries and headers by default
|
|
* need special options, which your build system won't be able to figure
|
|
out by itself
|
|
|
|
General Cross-Compilation Options in Clang
|
|
==========================================
|
|
|
|
Target Triple
|
|
-------------
|
|
|
|
The basic option is to define the target architecture. For that, use
|
|
``-target <triple>``. If you don't specify the target, CPU names won't
|
|
match (since Clang assumes the host triple), and the compilation will
|
|
go ahead, creating code for the host platform, which will break later
|
|
on when assembling or linking.
|
|
|
|
The triple has the general format ``<arch><sub>-<vendor>-<sys>-<env>``, where:
|
|
* ``arch`` = ``x86_64``, ``i386``, ``arm``, ``thumb``, ``mips``, etc.
|
|
* ``sub`` = for ex. on ARM: ``v5``, ``v6m``, ``v7a``, ``v7m``, etc.
|
|
* ``vendor`` = ``pc``, ``apple``, ``nvidia``, ``ibm``, etc.
|
|
* ``sys`` = ``none``, ``linux``, ``win32``, ``darwin``, ``cuda``, etc.
|
|
* ``env`` = ``eabi``, ``gnu``, ``android``, ``macho``, ``elf``, etc.
|
|
|
|
The sub-architecture options are available for their own architectures,
|
|
of course, so "x86v7a" doesn't make sense. The vendor needs to be
|
|
specified only if there's a relevant change, for instance between PC
|
|
and Apple. Most of the time it can be omitted (and Unknown)
|
|
will be assumed, which sets the defaults for the specified architecture.
|
|
The system name is generally the OS (linux, darwin), but could be special
|
|
like the bare-metal "none".
|
|
|
|
When a parameter is not important, it can be omitted, or you can
|
|
choose ``unknown`` and the defaults will be used. If you choose a parameter
|
|
that Clang doesn't know, like ``blerg``, it'll ignore and assume
|
|
``unknown``, which is not always desired, so be careful.
|
|
|
|
Finally, the env (environment) option is something that will pick default
|
|
CPU/FPU, define the specific behaviour of your code (PCS, extensions),
|
|
and also choose the correct library calls, etc.
|
|
|
|
CPU, FPU, ABI
|
|
-------------
|
|
|
|
Once your target is specified, it's time to pick the hardware you'll
|
|
be compiling to. For every architecture, a default set of CPU/FPU/ABI
|
|
will be chosen, so you'll almost always have to change it via flags.
|
|
|
|
Typical flags include:
|
|
* ``-mcpu=<cpu-name>``, like x86-64, swift, cortex-a15
|
|
* ``-mfpu=<fpu-name>``, like SSE3, NEON, controlling the FP unit available
|
|
* ``-mfloat-abi=<fabi>``, like soft, hard, controlling which registers
|
|
to use for floating-point
|
|
|
|
The default is normally the common denominator, so that Clang doesn't
|
|
generate code that breaks. But that also means you won't get the best
|
|
code for your specific hardware, which may mean orders of magnitude
|
|
slower than you expect.
|
|
|
|
For example, if your target is ``arm-none-eabi``, the default CPU will
|
|
be ``arm7tdmi`` using soft float, which is extremely slow on modern cores,
|
|
whereas if your triple is ``armv7a-none-eabi``, it'll be Cortex-A8 with
|
|
NEON, but still using soft-float, which is much better, but still not
|
|
great.
|
|
|
|
Toolchain Options
|
|
-----------------
|
|
|
|
There are three main options to control access to your cross-compiler:
|
|
``--sysroot``, ``-I``, and ``-L``. The two last ones are well known,
|
|
but they're particularly important for additional libraries
|
|
and headers that are specific to your target.
|
|
|
|
There are two main ways to have a cross-compiler:
|
|
|
|
#. When you have extracted your cross-compiler from a zip file into
|
|
a directory, you have to use ``--sysroot=<path>``. The path is the
|
|
root directory where you have unpacked your file, and Clang will
|
|
look for the directories ``bin``, ``lib``, ``include`` in there.
|
|
|
|
In this case, your setup should be pretty much done (if no
|
|
additional headers or libraries are needed), as Clang will find
|
|
all binaries it needs (assembler, linker, etc) in there.
|
|
|
|
#. When you have installed via a package manager (modern Linux
|
|
distributions have cross-compiler packages available), make
|
|
sure the target triple you set is *also* the prefix of your
|
|
cross-compiler toolchain.
|
|
|
|
In this case, Clang will find the other binaries (assembler,
|
|
linker), but not always where the target headers and libraries
|
|
are. People add system-specific clues to Clang often, but as
|
|
things change, it's more likely that it won't find than the
|
|
other way around.
|
|
|
|
So, here, you'll be a lot safer if you specify the include/library
|
|
directories manually (via ``-I`` and ``-L``).
|
|
|
|
Target-Specific Libraries
|
|
=========================
|
|
|
|
All libraries that you compile as part of your build will be
|
|
cross-compiled to your target, and your build system will probably
|
|
find them in the right place. But all dependencies that are
|
|
normally checked against (like ``libxml`` or ``libz`` etc) will match
|
|
against the host platform, not the target.
|
|
|
|
So, if the build system is not aware that you want to cross-compile
|
|
your code, it will get every dependency wrong, and your compilation
|
|
will fail during build time, not configure time.
|
|
|
|
Also, finding the libraries for your target are not as easy
|
|
as for your host machine. There aren't many cross-libraries available
|
|
as packages to most OS's, so you'll have to either cross-compile them
|
|
from source, or download the package for your target platform,
|
|
extract the libraries and headers, put them in specific directories
|
|
and add ``-I`` and ``-L`` pointing to them.
|
|
|
|
Also, some libraries have different dependencies on different targets,
|
|
so configuration tools to find dependencies in the host can get the
|
|
list wrong for the target platform. This means that the configuration
|
|
of your build can get things wrong when setting their own library
|
|
paths, and you'll have to augment it via additional flags (configure,
|
|
Make, CMake, etc).
|
|
|
|
Multilibs
|
|
---------
|
|
|
|
When you want to cross-compile to more than one configuration, for
|
|
example hard-float-ARM and soft-float-ARM, you'll have to have multiple
|
|
copies of your libraries and (possibly) headers.
|
|
|
|
Some Linux distributions have support for Multilib, which handle that
|
|
for you in an easier way, but if you're not careful and, for instance,
|
|
forget to specify ``-ccc-gcc-name armv7l-linux-gnueabihf-gcc`` (which
|
|
uses hard-float), Clang will pick the ``armv7l-linux-gnueabi-ld``
|
|
(which uses soft-float) and linker errors will happen.
|
|
|
|
The same is true if you're compiling for different environments, like
|
|
``gnueabi`` and ``androideabi``, and might even link and run, but produce
|
|
run-time errors, which are much harder to track down and fix.
|