GCC Cross-Compiler: Difference between revisions

[unchecked revision][unchecked revision]
Content deleted Content added
mNo edit summary
Solar (talk | contribs)
Major reorganization.
Line 5:
Generally spoken, a cross-compiler is a compiler that runs on platform A (the "host"), but generates executables for platform B (the "target"). The two "platforms" might differ in CPU, operating system, and/or [[:Category:Executable Formats|executable format]].
 
=== WhatAre isyou aat "Canadianthe Cross"right place? ===
 
If...
The black magic of cross-compiling: On platform A, compile a cross-compiler to run on platform B that generates executables for platform C.
 
* ...you are using Gentoo Linux,
* ...you want to do a cross-compiler for 64-bit (x86_64),
* ...you want to do a Canadian Cross,
* ...you want a cross-compiler for compiling ''applications'' (as opposed to hobbyist OS development covered here),
 
...please check the "Related Stuff" section at the bottom of this page.
 
=== Why an OS developer should build a cross-compiler ===
 
Creating a dedicated (cross-) compiler for your OS development work can save you many headaches. If...
Doing Step 1 below to get a dedicated (cross-) compiler for your OS development work can save you many headaches. When your system compiler drags in references to alloca() or other OS-dependent things, your compiler and your assembler can't agree on binary formats, or your bootloader stubbornly insists that it cannot read your kernel binary, the easiest solution could be setting up a dedicated Step 1 cross-compiler. If anything, it places you on the same playground as other users: You can rest assured that any problems you might yet encounter are not specific to your compiler setup.
 
* ...your system compiler drags in references to alloca() or other OS-dependent things,
* ...Cygwin complains about "PE operation on non-PE file",
* ...your compiler and your assembler can't agree on binary formats ("unresolved reference to _kmain()"), or
* ...your bootloader stubbornly insists that it cannot read your kernel binary,
 
the most effective solution is setting up a dedicated cross-compiler. If anything, it places you on the same playground as other users: You can rest assured that any problems you might yet encounter are not specific to your compiler setup.
 
Don't fear, it's easier than you might think.
How this document is organized
 
=== How this document is organized ===
We describe a sequence of steps, starting with nothing but your system compiler and ending with a native compiler for the target system. You might not need all those steps (when you want to compile your hobbyist OS into a binary, Step 1 is all you need).
 
We describe a sequence of steps, starting with nothing but your system compiler and ending with a native compiler for the target system. You might not need all those steps (when you want to compile your hobbyist OS into a binary, Step 1 is all you need). Actually, at this point only Step 1 is actually covered.
 
=== Requirements ===
Line 24 ⟶ 39:
Note: [[Cygwin]] includes your Windows path in its bash path. This means that if you were using DJGPP before switching to [[Cygwin]] (in most cases, that is why you would want to build a [[GCC]] Cross-Compiler), you must either uninstall DJGPP first, or at least remove it from your PATH environment variable so the [[Cygwin]] tools get called instead of DJGPP. (After uninstalling DJGPP, you should delete the DJGPP environment variable and clear the C:\djgpp (or wherever you installed it) entry in your PATH to make sure everything's going to be all right.)
 
=== Tested on... ===
 
This has been tested to work with the below combinations of binutils and gcc:
Line 102 ⟶ 117:
--disable-nls tells binutils not to include native language support. This is basically optional, but reduces dependencies and compile time. It will also result in English-language diagnostics, which the people on the [http://www.osdev.org/phpBB2/ Forum] understand when you ask your questions. ;-)
 
=== GCCgcc ===
 
Now, you can bootstrap [[GCC]]. (Use v3.3 or later - [[GCC]] 3v3.2.x has a bug with internal __malloc declarations resulting in an error during compilation. This could be fixed by patching four occurrences in three different source files, but I lost the diff output and am not in a mind of re-checking. ;-) )
 
cd /usr/src/build-gcc
Line 111 ⟶ 126:
--enable-languages=c,c++ --without-headers --with-newlib
make all-gcc install-gcc
 
=== Explanation of Options ===
 
The path has to be extended since [[GCC]] needs the binutils we built earlier at some point of the build process. You might want to add these extensions to your $PATH permanently, so you won't have to use fully qualified path names every time you call your cross-compiler.
 
'''--disable-nls''' is the same as for binutils above.
 
'''--without-headers''' tells [[GCC]] not to rely on any C library (standard or runtime) being present for the target.
 
'''--with-newlib''' is only necessary if you are compiling [[GCC]] <= 3.3.x. That version has [http://gcc.gnu.org/bugzilla/show_bug.cgi?id=8180 a known bug] that keeps --without-headers from working correctly. Additionally setting --with-newlib is a workaround for that bug.
 
'''--enable-languages''' tells [[GCC]] not to compile all the other language frontends it supports, but only C (and optionally C++).
 
==== Summary ====
 
Now you have a "naked" cross-compiler. It does not have access to a C library or C runtime yet, so you cannot use any of the standard includes or create runable binaries. But it is quite sufficient to compile your self-made kernel.
 
==== Usage ====
 
Once you are finished, your toolset resides in /usr/cross. For example, you have a gcc executable in /usr/cross/bin/$TARGET-gcc (and /usr/cross/$TARGET/gcc as well), which spits out binaries for your TARGET. Add /usr/cross/bin to your PATH environment variable, so that gcc invokes your system compiler, and $TARGET-gcc invokes your cross-compiler.
Line 182 ⟶ 195:
...to be extended. This is the only place where --disable-shared really makes sense.
 
== The --disable-shared option ==
== x86_64 ==
 
This is an option to the [[GCC]] configure process that you might or might not use. It's a bit tricky...
Creating a cross-compiler to a different CPU is harder than just targeting a different binary format. To add insult to injury, x86_64 is a special case since it does not support a plain ELF target (yet?). Binutils works fine, but [[GCC]] causes problems when trying to build it as --target=x86_64-elf, so we have to trick our way around it.
 
=== with --disable-shared... ===
Patches for the toolchain are available [http://sourceware.org/ml/binutils/2005-03/msg00353.html on sourceware] and [from http://gcc.gnu.org/ml/gcc-patches/2005-03/msg01286.html the GCC website]. The binutils patch (on SourceWare) is applied by default in 2.17, so if you use 2.17 you don't need that patch. The [[GCC]] patch isn't applied in any publically released version (as of 4.1.1 and lower that is), so you'll probably need that.
 
...every single executable in your cross-compiler environment will be statically linked, which makes them huge. On the other hand, you can move around those executables, as there are no dependencies (which is what you want in step 4 above, to "bootstrap" your first native compiler). However, if you compiled any of the libraries that are linked in with a more advanced -march, the resulting executable is going to be only for that arch or better. This is usually no problem - unless you're doing a [[Canadian Cross]] where you might want to put the executable on a slower (less-featured) machine. Bad luck...
* note - you are very strongly encouraged to use these patches. You might need to modify the sources instead (but then again, if you're making a compiler you should be able to).
 
=== without --disable-shared... ===
Lots of thanks go to Mikkel Krautz for creating & submitting these patches.
 
...the executables will use dynamic linking, and will be much smaller. Now comes the tricky part: Not only the system libraries are dynamically linked, but also those implementing generic functionality of the cross-compilation environment. This is done by hard-coding the library paths into the executables... meaning that you can not move them to another directory. This is usually not necessary - unless you're doing a [[Canadian Cross]] where you might want to build the executables in a directory different from the one you want to install them in (e.g. due to access limitations on the build machine). Bad luck...
=== Preparation ===
With patches:
 
For a [[Canadian Cross]], the best idea is not to use the option, and to copy the file to the exact same directory.
mkdir /usr/cross
export PREFIX=/usr/cross
export TARGET=x86_64-pc-elf
cd /usr/src
mkdir build-binutils build-gcc
 
== Related Stuff ==
Without patches:
 
[[GCC Cross-Compiler for x86_64]] - making things 64-bit.
mkdir /usr/cross
export PREFIX=/usr/cross
export TARGET=x86_64-pc-linux
cd /usr/src
mkdir build-binutils build-gcc
 
[[Canadian Cross]] - making things yet more complicated.
This is the same as in the generic how-to above, save for the different TARGET.
 
[[GCC Cross-Compiler on Gentoo]] - making things much easier.
=== Binutils ===
 
cd /usr/src/build-binutils
../binutils-x.xx/configure --target=$TARGET --prefix=$PREFIX --enable-64-bit-bfd
make all install
 
Compiling binutils is again nearly identical; note however the additional option --enable-64-bit-bfd.
 
The BFD library is the method all binutils programs use to access files, and it grows considerably larger and slower if you add 64-bit support to it. Since there are very few systems that use 64-bit, they don't want to add it by default, and for some reason they don't add it depending on the host, so you have to add it manually. Note, the binutils do not actually do anything with the target, they work with binary files, not code. In the binary files special codes are used to specify what needs to be done, in a way that the code doesn't have to be understood or in most cases even read.
 
=== GCC ===
 
Compiling [[GCC]] with patches is pretty much equal to the normal FAQ. Without the patches, however, compiling requires use of -k and ignoring errors. The compiler stubbornly tries to compile some libraries that require a normal environment (such as linux) that you don't have (or haven't specified).
 
Both with and without patches you'll use all-gcc and install-gcc. The installer tries to make a few libraries if you don't and will fail at this. When your platform gets to a reasonable size of userbase support, you can try to use plain all and install instead, for a more complete [[GCC]] environment.
With patches:
 
cd /usr/src/build-gcc
export PATH=$PATH:$PREFIX/bin
../gcc-x.x.x/configure --target=$TARGET --prefix=$PREFIX \
--disable-nls --enable-languages=c,c++ --with-newlib --without-headers
make all-gcc install-gcc
 
Without patches:
 
cd /usr/src/build-gcc
export PATH=$PATH:$PREFIX/bin
../gcc-x.x.x/configure --target=$TARGET --prefix=$PREFIX \
--disable-nls --enable-languages=c,c++ --with-newlib --without-headers
make -k all-gcc install-gcc
 
Since we could not select a plain ELF target, [[GCC]] stubbornly insists on compiling some OS dependent libraries, which of course does not work because we don't have them in our OS. The use of the -k option to make forces the build process to continue nevertheless, ignoring the errors. So far, this seems to work.
 
== Other Things ==
 
--disable-shared
 
This is an option to the [[GCC]] configure process that you might or might not use. It's a bit tricky...
with --disable-shared...
 
...every single executable in your cross-compiler environment will be statically linked, which makes them huge. On the other hand, you can move around those executables, as there are no dependencies (which is what you want in step 4 above, to "bootstrap" your first native compiler). However, if you compiled any of the libraries that are linked in with a more advanced -march, the resulting executable is going to be only for that arch or better. This is usually no problem - unless you're doing a Canadian Cross where you might want to put the executable on a slower (less-featured) machine. Bad luck...
without --disable-shared...
 
...the executables will use dynamic linking, and will be much smaller. Now comes the tricky part: Not only the system libraries are dynamically linked, but also those implementing generic functionality of the cross-compilation environment. This is done by hard-coding the library paths into the executables... meaning that you can not move them to another directory. This is usually not necessary - unless you're doing a Canadian Cross where you might want to build the executables in a directory different from the one you want to install them in (e.g. due to access limitations on the build machine). Bad luck...
 
For a [[Canadian Cross]], the best idea is not to use the option, and to copy the file to the exact same directory.
Related Stuff
 
http://kegel.com/crosstool has a popular example of a script that automatically downloads, patches, and builds binutils, gcc, and glibc for known platforms.
Line 266 ⟶ 224:
 
http://www.libsdl.org/extras/win32/cross/README.txt - dito
 
[[Canadian Cross]] - making things yet more complicated.
 
== Authors ==
 
The entire default procedure and the moderation of the page is done by [[User:MartinBaute|MartinBaute]], while [[User:DasCandy|DasCandy]] takes care of the [[Canadian Cross]] and x86-64 (amd64) sections.
 
[[Category:Compilers]]