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