mediamtx: 1.9.2 -> 1.9.3 (#352624)
[NixPkgs.git] / doc / old / cross.txt
blob0f958e772b782bd1f8bb7c67cc1bb8671b60932f
1 Setting up a cross compiler with Nix
3 "Cross compilation" means compiling a program on one machine for another
4 type of machine. A typical use of cross compilation is to compile programs
5 for embedded devices. These devices often don't have the computing power
6 and memory to compile programs natively.
8 For a fully working cross compiler the following are needed:
10 * cross binutils: assembler, archiver, linker, etcetera that understand
11 the format of the target system
13 * cross compiler: a compiler that can generate binary code and object files
14 for the target platform
16 * cross C library: a library to link object files with to create fully
17 functional programs
19 Cross compilers are difficult to set up. A lot of people report that they
20 cannot succeed in building a cross toolchain successfully. The answers
21 usually consist of "download this pre-built toolchain", which is equally
22 unhelpful.
24 A toolchain is set up in five steps:
26 1. build binutils to that can run on the host platform, but generate code
27 for the target platform
29 2. build Linux kernel headers for the target platform
31 3. build a minimal C only version of GCC, that can run on the host platform
32 and generate code for the target platform
34 4. build a C library for the target platform. This includes the dynamic
35 linker, C library, etc.
37 5. build a full GCC
39 ****
40 NB:
42 Keep in mind that many programs are not very well suited for cross
43 compilation. Either they are not intended to run on other platforms,
44 because the code is highly platform specific, or the configuration process
45 is not written with cross compilation in mind.
47 Nix will not solve these problems for you!
48 ***
50 This document describes to set up a cross compiler to generate code for
51 arm-linux with uClibc and runs on i686-linux. The "stdenv" used is the
52 default from the standard Nix packages collection.
54 Step 1: build binutils for arm-linux in the stdenv for i686-linux
56 ---
57 {stdenv, fetchurl, noSysDirs}:
59 stdenv.mkDerivation {
60   name = "binutils-2.16.1-arm";
61   builder = ./builder.sh;
62   src = fetchurl {
63     url = "http://ftp.nluug.nl/gnu/binutils/binutils-2.16.1.tar.bz2";
64     hash = "sha256-14pv+YKrL3NyFwbnv9MoWsZHgEZk5+pHhuZtAfkcVsU=";
65   };
66   inherit noSysDirs;
67   configureFlags = [ "--target=arm-linux" ];
69 ---
71 This will compile binutils that will run on i686-linux, but knows the
72 format used by arm-linux.
74 Step 2: build kernel headers for the target architecture
76   default.nix for kernel-headers-arm:
78 ---
79 {stdenv, fetchurl}:
81 assert stdenv.buildPlatform.system == "i686-linux";
83 stdenv.mkDerivation {
84   name = "linux-headers-2.6.13.1-arm";
85   builder = ./builder.sh;
86   src = fetchurl {
87     url = "http://www.kernel.org/pub/linux/kernel/v2.6/linux-2.6.13.1.tar.bz2";
88     hash = "sha256-qtICDjfiA1HxWBrHqtB5DCv9s9/HyznKV1C6IxCrHYs=";
89   };
91 ---
93   builder.sh for kernel-headers-arm:
95 ---
96 source $stdenv/setup
99 buildPhase() {
100     make include/linux/version.h
103 buildPhase=buildPhase
106 installPhase() {
107     mkdir $out
108     mkdir $out/include
109     #cd $out/include
110     #ln -s asm-arm asm
111     make include/asm ARCH=arm
112     cp -prvd include/linux include/asm include/asm-arm include/asm-generic $out/include
113     echo -n > $out/include/linux/autoconf.h
116 installPhase=installPhase
119 genericBuild
122 Step 3: build a minimal GCC
124 Extra/different parameters include the target platform and the kernel
125 headers argument (this needs a major cleanup, as well as the name, it
126 needs to be different!). Profiled compilers are disabled. The tarball
127 used here is just gcc-core. For some reason it doesn't install nicely
128 if the whole tarball is used (or is this some braino on my side? -- AH).
130 Only C is used, because for other languages (such as C++) extra libraries
131 need to be compiled, for which libraries compiled for the target system
132 are needed.
134 There is a bit of evilness going on. The cross compiled utilities need
135 to be either copied to or be linked from the output tree of the compiler.
136 (Is this really true? Back this up with arguments! -- AH)
138 Symbolic links are not something we want inside the Nix store.
141 { stdenv, fetchurl, noSysDirs
142 , langC ? true, langCC ? true, langF77 ? false
143 , profiledCompiler ? false
144 , binutilsArm
145 , kernelHeadersArm
148 assert langC;
150 stdenv.mkDerivation {
151   name = "gcc-4.0.2-arm";
152   builder = ./builder.sh;
153   src = fetchurl {
154     url = "ftp://ftp.nluug.nl/pub/gnu/gcc/gcc-4.0.2/gcc-core-4.0.2.tar.bz2";
155     hash = "sha256-LANmXRS7/fN2zF5JUJVd8OjNA5aCDsGLQKhSpxWA3Qk=";
156   };
157   # !!! apply only if noSysDirs is set
158   patches = [./no-sys-dirs.patch ./gcc-inhibit.patch];
159   inherit noSysDirs langC langCC langF77 profiledCompiler;
160   buildInputs = [binutilsArm];
161   inherit kernelHeadersArm binutilsArm;
162   platform = "arm-linux";
166 The builder.sh for a cross-compiler. Note that the binutils are prefixed
167 with the architecture name, so arm-linux-ld instead of ld, etc. This is
168 necessary because when we cross-compile a lot of programs look for these
169 tools with these specific names. The standard gcc-wrapper does not take this
170 into account yet.
173 source $stdenv/setup
176 export NIX_FIXINC_DUMMY=$NIX_BUILD_TOP/dummy
177 mkdir $NIX_FIXINC_DUMMY
180 if test "$noSysDirs" = "1"; then
182     if test "$noSysDirs" = "1"; then
183         # Figure out what extra flags to pass to the gcc compilers
184         # being generated to make sure that they use our glibc.
185         if test -e $NIX_CC/nix-support/orig-glibc; then
186             glibc=$(cat $NIX_CC/nix-support/orig-glibc)
187             # Ugh.  Copied from gcc-wrapper/builder.sh.  We can't just
188             # source in $NIX_CC/nix-support/add-flags, since that
189             # would cause *this* GCC to be linked against the
190             # *previous* GCC.  Need some more modularity there.
191             extraCFlags="-B$glibc/lib -isystem $glibc/include"
192             extraLDFlags="-B$glibc/lib -L$glibc/lib -Wl,-s \
193               -Wl,-dynamic-linker,$glibc/lib/ld-linux.so.2"
195             # Oh, what a hack.  I should be shot for this.
196             # In stage 1, we should link against the previous GCC, but
197             # not afterwards.  Otherwise we retain a dependency.
198             # However, ld-wrapper, which adds the linker flags for the
199             # previous GCC, is also used in stage 2/3.  We can prevent
200             # it from adding them by NIX_GLIBC_FLAGS_SET, but then
201             # gcc-wrapper will also not add them, thereby causing
202             # stage 1 to fail.  So we use a trick to only set the
203             # flags in gcc-wrapper.
204             hook=$(pwd)/ld-wrapper-hook
205             echo "NIX_GLIBC_FLAGS_SET=1" > $hook
206             export NIX_LD_WRAPPER_START_HOOK=$hook
207         fi
209         export NIX_EXTRA_CFLAGS=$extraCFlags
210         export NIX_EXTRA_LDFLAGS=$extraLDFlags
211         export CFLAGS=$extraCFlags
212         export CXXFLAGS=$extraCFlags
213         export LDFLAGS=$extraLDFlags
214     fi
216 else
217     patches=""
221 preConfigure=preConfigure
222 preConfigure() {
224     # Determine the frontends to build.
225     langs="c"
226     if test -n "$langCC"; then
227         langs="$langs,c++"
228     fi
229     if test -n "$langF77"; then
230         langs="$langs,f77"
231     fi
233     # Cross compiler evilness
234     mkdir -p $out
235     mkdir -p $out/arm-linux
236     mkdir -p $out/arm-linux/bin
237     ln -s $binutilsArm/arm-linux/bin/as $out/arm-linux/bin/as
238     ln -s $binutilsArm/arm-linux/bin/ld $out/arm-linux/bin/ld
239     ln -s $binutilsArm/arm-linux/bin/ar $out/arm-linux/bin/ar
240     ln -s $binutilsArm/arm-linux/bin/ranlib $out/arm-linux/bin/ranlib
242     # Perform the build in a different directory.
243     mkdir ../build
244     cd ../build
246     configureScript=../$sourceRoot/configure
247     configureFlags="--enable-languages=$langs --target=$platform --disable-threads --disable-libmudflap --disable-shared --with-headers=$kernelHeadersArm/include --disable-multilib"
251 postInstall=postInstall
252 postInstall() {
253     # Remove precompiled headers for now.  They are very big and
254     # probably not very useful yet.
255     find $out/include -name "*.gch" -exec rm -rf {} \; -prune
257     # Remove `fixincl' to prevent a retained dependency on the
258     # previous gcc.
259     rm -rf $out/libexec/gcc/*/*/install-tools
263 #if test -z "$profiledCompiler"; then
264     #makeFlags="bootstrap"
265 #else
266     #makeFlags="profiledbootstrap"
269 genericBuild
272 Step 4: build a C library for the target platform.
274 The previous steps are enough to compile a C library. In our case we take
275 uClibc. It's intended to be a small sized replacement for glibc. It is widely
276 used in embedded environments.
280 Step 5: Build a compiler to link with the newly built C library.
284 If we restrict the compiler to just C programs it is relatively easy,
285 since we only need to wrap the GCC we built in the previous step with all
286 the right tools and the right C library. Successfully compiled programs with
287 this compiler and verified to be working on a HP Jornada 820 running Linux
288 are "patch", "make" and "wget".
290 If we want to build C++ programs it gets a lot more difficult. GCC has a
291 three step compilation process. In the first step a simple compiler, called
292 xgcc, that can compile only C programs is built. With that compiler it
293 compiles itself two more times: one time to build a full compiler, and another
294 time to build a full compiler once again with the freshly built compiler from
295 step 2. In the second and third step support for C++ is compiled, if this
296 is configured.
298 One of the libraries that has to be built for C++ support step is libstdc++.
299 This library uses xgcc, even when cross compiling, since libstdc++ has to be
300 compiled for arm-linux.
302 One of the compiler flags that GCC uses for this compiler is called X_CFLAGS.
303 This is used by the Nix build process to set the dynamic linker, glibc
304 in the case of i686-linux using the default Nix packages collection.
306 Obviously, since we need to compile libstc++ for arm-linux with uClibc linking
307 will not be done correctly: you can't link object files built for arm-linux
308 with a glibc built for i686-linux.
310 Setting X_CFLAGS to use the uClibc libraries and dynamic linker will fail
311 too. Earlier on in the build process these flags are used to compile important
312 files like libgcc.a by the host system gcc, which does need to be linked
313 to glibc. To make this work correctly you will need to carefully juggle
314 with compilation flags. This is still work in progress for Nix.
319 After successfully completing the whole toolchain you can start building
320 packages with the newly built tools. To make everything build correctly
321 you will need a stdenv for your target platform. Setting up this platform
322 will take some effort. Right now there is a very experimental setup for
323 arm-linux, which needs to be cleaned up before it is production ready.
325 Please note that many packages are not well suited for cross-compilation.
326 Even though the package itself might be very well portable often the
327 buildscripts are not. One thing that we have seen that causes frequent
328 build failures is the use of the LD variable. This is often set to 'ld'
329 and not $(CROSS)-ld.