|
| 1 | +=================================================================== |
| 2 | +Cross-compilation using Clang/LLVM |
| 3 | +=================================================================== |
| 4 | + |
| 5 | +Introduction |
| 6 | +============ |
| 7 | + |
| 8 | +This document will guide you in choosing the right cross-compilation options |
| 9 | +to hopefully help you target your code to a different architecture. It assumes |
| 10 | +you already know how to compile the code in question for the host architecture, |
| 11 | +and that you know how to choose additional include and library paths. |
| 12 | + |
| 13 | +However, this document is `not` a `HowTo` and wont help you setting your build |
| 14 | +system or Makefiles, nor choosing the right CMake options. Also, it does not |
| 15 | +cover all the possible options, nor it contains specific examples for specific |
| 16 | +architectures. There are other documents in LLVM that do that in greater |
| 17 | +details (ex. http://llvm.org/docs/HowToCrossCompileLLVM.html). |
| 18 | + |
| 19 | +After reading this document, you should be familiar with the main issues |
| 20 | +related to, and what main compiler options Clang provides for performing |
| 21 | +cross-compilation. |
| 22 | + |
| 23 | +Cross compilation issues |
| 24 | +======================== |
| 25 | + |
| 26 | +In GCC world, every host/target combination has its own set of binaries, |
| 27 | +headers, libraries, etc. So, it's usually simple to download a package |
| 28 | +with all files in, unzip to a directory and point the build system to |
| 29 | +that compiler, that will know about its location and find all it needs to |
| 30 | +when compiling your code. |
| 31 | + |
| 32 | +On the other hand, Clang/LLVM is natively a cross-compiler, meaning that |
| 33 | +one set of programs can compile to all targets by setting the -target |
| 34 | +option. That makes it a lot easier to programers wishing to compile to |
| 35 | +different platforms and architectures, and to compiler developers that |
| 36 | +only have to maintain one build system, and to OS distributions, that |
| 37 | +need only one set of main packages. |
| 38 | + |
| 39 | +But, as is true to any cross-compiler, and given the complexity of |
| 40 | +different architectures, OSs and options, it's not always easy finding |
| 41 | +the headers, libraries or binutils to generate target specific code. |
| 42 | +So you'll need special options to help Clang understand what target |
| 43 | +you're compiling to, where are your tools, etc. |
| 44 | + |
| 45 | +Another problem is that compilers come with standard libraries only (like |
| 46 | +icompiler-rt, libcxx, libgcc, libm, etc), so you'll have to find and make |
| 47 | +available to the build system, every other library required to build your |
| 48 | +software, that is specific to your target. It's not enough to have your |
| 49 | +host's libraries installed. |
| 50 | + |
| 51 | +Finally, not all toolchains are the same, and consequently, not every Clang |
| 52 | +option will work magically. Some options, like --sysroot (which |
| 53 | +effectively changes the logical root for headers and libraries), assume |
| 54 | +all your binaries and libraries are in the same directory, which may not |
| 55 | +true when your cross-compiler was installed by the distribution's package |
| 56 | +management. So, for each specific case, you may use more than one |
| 57 | +option, and in most cases, you'll end up setting include paths (-I) and |
| 58 | +library paths (-L) manually. |
| 59 | + |
| 60 | +To sum up, different toolchains can: |
| 61 | + * be host/target specific or more flexible |
| 62 | + * be in a single directory, or spread out your system |
| 63 | + * have different sets of libraries and headers by default |
| 64 | + * need special options, which your build system won't be able to figure |
| 65 | + out by itself |
| 66 | + |
| 67 | +General Cross-Compilation Options in Clang |
| 68 | +========================================== |
| 69 | + |
| 70 | +Target Triple |
| 71 | +------------- |
| 72 | + |
| 73 | +The basic option is to define the target architecture. For that, use |
| 74 | +``-target <triple>``. If you don't specify the target, CPU names won't |
| 75 | +match (since Clang assumes the host triple), and the compilation will |
| 76 | +go ahead, creating code for the host platform, which will break later |
| 77 | +on when assembling or linking. |
| 78 | + |
| 79 | +The triple has the general format ``<arch><sub>-<vendor>-<sys>-<abi>``, where: |
| 80 | + * ``arch`` = x86, arm, thumb, mips, etc. |
| 81 | + * ``sub`` = for ex. on ARM: v5, v6m, v7a, v7m, etc. |
| 82 | + * ``vendor`` = pc, apple, nvidia, ibm, etc. |
| 83 | + * ``sys`` = none, linux, win32, darwin, cuda, etc. |
| 84 | + * ``abi`` = eabi, gnu, android, macho, elf, etc. |
| 85 | + |
| 86 | +The sub-architecture options are available for their own architectures, |
| 87 | +of course, so "x86v7a" doesn't make sense. The vendor needs to be |
| 88 | +specified only if there's a relevant change, for instance between PC |
| 89 | +and Apple. Most of the time it can be omitted (and Unknown) |
| 90 | +will be assumed, which sets the defaults for the specified architecture. |
| 91 | +The system name is generally the OS (linux, darwin), but could be special |
| 92 | +like the bare-metal "none". |
| 93 | + |
| 94 | +When a parameter is not important, they can be omitted, or you can |
| 95 | +choose "unknown" and the defaults will be used. If you choose a parameter |
| 96 | +that Clang doesn't know, like "blerg", it'll ignore and assume `Unknown`, |
| 97 | +which is not always desired, so be careful. |
| 98 | + |
| 99 | +Finally, the ABI option is something that will pick default CPU/FPU, |
| 100 | +define the specific behaviour of your code (PCS, extensions), |
| 101 | +and also choose the correct library calls, etc. |
| 102 | + |
| 103 | +CPU, FPU, ABI |
| 104 | +------------- |
| 105 | + |
| 106 | +Once your target is specified, it's time to pick the hardware you'll |
| 107 | +be compiling to. For every architecture, a default set of CPU/FPU/ABI |
| 108 | +will be chosen, so you'll almost always have to change it via flags. |
| 109 | + |
| 110 | +Typical flags include: |
| 111 | + * ``-mcpu=<cpu-name>``, like x86-64, swift, cortex-a15 |
| 112 | + * ``-fpu=<fpu-name>``, like SSE3, NEON, controlling the FP unit available |
| 113 | + * ``-mfloat-abi=<fabi>``, like soft, hard, controlling which registers |
| 114 | + to use for floating-point |
| 115 | + |
| 116 | +The default is normally the common denominator, so that Clang doesn't |
| 117 | +generate code that breaks. But that also means you won't get the best |
| 118 | +code for your specific hardware, which may mean orders of magnitude |
| 119 | +slower than you expect. |
| 120 | + |
| 121 | +For example, if your target is "arm-none-eabi", the default CPU will |
| 122 | +be "arm7tdmi" using soft float, which is extremely slow on modern cores, |
| 123 | +whereas if your triple is "armv7a-none-eabi", it'll be Cortex-A8 with |
| 124 | +NEON, but still using soft-float, which is much better, but still not |
| 125 | +great. |
| 126 | + |
| 127 | +Toolchain Options |
| 128 | +----------------- |
| 129 | + |
| 130 | +There are four main options to control access to your cross-compiler: |
| 131 | +``--sysroot``, ``-I`` and ``-L``. The two last ones are well known, |
| 132 | +but they're particularly important for additional libraries |
| 133 | +and headers that are specific to your target. |
| 134 | + |
| 135 | +There are two main ways to have a cross-compiler: |
| 136 | + |
| 137 | +#. When you have extracted your cross-compiler from a zip file into |
| 138 | + a directory, you have to use ``--sysroot=<path>``. The path is the |
| 139 | + root directory where you have unpacked your file, and Clang will |
| 140 | + look for the directories ``bin``, ``lib``, ``include`` in there. |
| 141 | + |
| 142 | + In this case, your setup should be pretty much done (if no |
| 143 | + additional headers or libraries are needed), as Clang will find |
| 144 | + all binaries it needs (assembler, linker, etc) in there. |
| 145 | + |
| 146 | +#. When you have installed via a package manager (modern Linux |
| 147 | + distributions have cross-compiler packages available), make |
| 148 | + sure the target triple you set is `also` the prefix of your |
| 149 | + cross-compiler toolchain. |
| 150 | + |
| 151 | + In this case, Clang will find the other binaries (assembler, |
| 152 | + linker), but not always where the target headers and libraries |
| 153 | + are. People add system-specific clues to Clang often, but as |
| 154 | + things change, it's more likely that it won't find than the |
| 155 | + other way around. |
| 156 | + |
| 157 | + So, here, you'll be a lot safer if you specify the include/library |
| 158 | + directories manually (via ``-I`` and ``-L``). |
| 159 | + |
| 160 | +Target-Specific Libraries |
| 161 | +========================= |
| 162 | + |
| 163 | +All libraries that you compile as part of your build will be |
| 164 | +cross-compiled to your target, and your build system will probably |
| 165 | +find them in the right place. But all dependencies that are |
| 166 | +normally checked against (like libxml or libz etc) will match |
| 167 | +against the host platform, not the target. |
| 168 | + |
| 169 | +So, if the build system is not aware that you want to cross-compile |
| 170 | +your code, it will get every dependency wrong, and your compilation |
| 171 | +will fail during build time, not configure time. |
| 172 | + |
| 173 | +Also, finding the libraries for your target are not as easy |
| 174 | +as for your host machine. There aren't many cross-libraries available |
| 175 | +as packages to most OSs, so you'll have to either cross-compile them |
| 176 | +from source, or download the package for your target platform, |
| 177 | +extract the libraries and headers, put them in specific directories |
| 178 | +and add ``-I`` and ``-L`` pointing to them. |
| 179 | + |
| 180 | +Also, some libraries have different dependencies on different targets, |
| 181 | +so configuration tools to find dependencies in the host can get the |
| 182 | +list wrong for the target platform. This means that the configuration |
| 183 | +of your build can get things wrong when setting their own library |
| 184 | +paths, and you'll have to augment it via additional flags (configure, |
| 185 | +Make, CMake, etc). |
| 186 | + |
| 187 | +Multilibs |
| 188 | +--------- |
| 189 | + |
| 190 | +When you want to cross-compile to more than one configuration, for |
| 191 | +example hard-float-ARM and soft-float-ARM, you'll have to have multiple |
| 192 | +copies of you libraries and (possibly) headers. |
| 193 | + |
| 194 | +Some Linux distributions have support for Multilib, which handle that |
| 195 | +for you in an easier way, but if you're not careful and, for instance, |
| 196 | +forget to specify ``-ccc-gcc-name armv7l-linux-gnueabihf-gcc`` (which |
| 197 | +uses hard-float), Clang will pick the ``armv7l-linux-gnueabi-ld`` |
| 198 | +(which uses soft-float) and linker errors will happen. |
| 199 | + |
| 200 | +The same is true if you're compiling for different ABIs, like ``gnueabi`` |
| 201 | +and ``androideabi``, and might even link and run, but produce run-time |
| 202 | +errors, which are much harder to track and fix. |
| 203 | + |
0 commit comments