GCC Cross-Compiler: Difference between revisions

add maintenance template
[unchecked revision][unchecked revision]
(Fix spelling error)
(add maintenance template)
 
(14 intermediate revisions by 10 users not shown)
Line 1:
{{FirstPerson}}{{You}}
{{rating|1}}
This tutorial focuses on creating a GCC cross-compiler for your own operating system. This compiler that we build here will have a generic target (i686-elf) whatthat allows you to leave the current operating system behind, meaning that no headers or libraries of yourthe host operating system will be used. YouWithout ''need''using a cross-compiler for operating system development, otherwise a lot of unexpected things can happen because the compiler assumes that yourthe code is running on yourthe host operating system.
 
== Introduction ==
 
Generally speaking, a cross-compiler is a compiler that runs on platform A (the '''host'''), but generates executables for platform B (the '''target'''). These two platforms may (but do not need to) differ in CPU, operating system, and/or [[:Category:Executable Formats|executable format]]. In our case, the host platform is your current operating system and the target platform is the operating system you are about to make. It is important to realize that these two platforms are not the same; the operating system you are developing is always going to be different from the operating system you currently use. This is why we need to build a cross-compiler first, you will most certainly run into trouble otherwise.
 
=== Why cross-compilers are necessary ===
{{Main|Why do I need a Cross Compiler?}}
 
You need to use a cross-compiler ''unless'' you are developing on your own operating system. The compiler must know the correct target platform (CPU, operating system), otherwise you will run into trouble. If you use theThe compiler that comes with yourthe host system, thendoes thenot compilerknow won'tby knowdefault that it is compiling something else entirely., Some tutorials suggest using your system compiler and passingunless a lot of problematic options are passed to theit, compiler. Thiswhich will certainly give youcreate a lot of problems in the future. and theThe solution is build a cross-compiler. If you have already attempted to make an operating system without usingbuild a cross-compiler, please read the article [[Why do I need a Cross Compiler?]].
 
=== Which compiler version to choose ===
{{Main|Building GCC}}
 
The newest [[GCC]] is recommended as it is the latest and greatest release. For instance, you may run into trouble if you useusing GCC 4.6.3 to build a GCC 4.8.0 cross-compiler. Ifwould youcreate aretroubles. notHere usingis thehow latest major GCC release for your system compiler, we recommend that youto [[Building GCC|build the newest GCC as your system compiler]].
 
You can also use older releases as they are usually reasonably good. If your local system compiler isn't too terribly old (at least GCC 4.6.0), you may wish to save yourself the trouble and just pick the latest minor release (such as 4.6.3 if your system compiler is 4.6.1) for your cross-compiler.
 
YouThis cancommand viewprints yourthe current compiler version by invoking:
 
<sourcesyntaxhighlight lang="bash">gcc --version</source>
gcc --version
</syntaxhighlight>
 
You may be able to use an older major GCC release to build a cross-compiler of a newer major GCC release. For instance, GCC 4.7.3 may be able to build a GCC 4.8.0 cross-compiler. However, if you want to use the latest and greatest GCC version for your cross-compiler, we recommend that you [[Building GCC|bootstrap the newest GCC]] as your system compiler first. Individuals using OS X 10.7 or earlier might want to invest in either building a system GCC (that outputs native Mach-O), or upgrading the local LLVM/Clang installation. Users with 10.8 and above should install the Command Line Tools from Apple's developer website and use Clang to cross-compile GCC.
Line 27 ⟶ 29:
=== Which binutils version to choose ===
{{Main|Cross-Compiler Successful Builds}}
We recommend that you use theThe latest and greatest [[Binutils]] release is recommended. Note, however, that not all combinations of GCC and Binutils work. If you run into trouble, use a Binutils that was released at roughly the same time as your desired compiler version. You probably need at least Binutils 2.22, or preferably the latest 2.23.2 release. It doesn't matter what Binutils version you have installed on your current operating system. YouThis cancommand find outprints the binutils version for example by this command:
<sourcesyntaxhighlight lang="bash">ld --version</source>
ld --version
</syntaxhighlight>
 
=== Deciding on the target platform ===
Line 36 ⟶ 40:
 
=== Note on arm-none-eabi-gcc ===
There is the prebuilt package gcc-arm-none-eabi on apt-get for DebiabDebian/Ubuntu, but you shouldn't use it because it neither contains a libgcc.a nor freestanding C header files like stdint.h.<br>
Instead you should build it yourself with <tt>arm-none-eabi</tt> being the $TARGET.
 
Line 53 ⟶ 57:
=== Preparation ===
 
<sourcesyntaxhighlight lang="bash">
export PREFIX="$HOME/opt/cross"
export TARGET=i686-elf
export PATH="$PREFIX/bin:$PATH"
</syntaxhighlight>
</source>
 
We add the installation prefix to the <tt>PATH</tt> of the current shell session. This ensures that the compiler build is able to detect our new binutils once we have built them.
Line 71 ⟶ 75:
# But reconsider: You should just get the development packages from your OS.
-->
<sourcesyntaxhighlight lang="bash">
cd $HOME/src
 
Line 79 ⟶ 83:
make
make install
</syntaxhighlight>
</source>
 
This compiles the binutils (assembler, disassembler, and various other useful stuff), runnable on your system but handling code in the format specified by $TARGET.
Line 89 ⟶ 93:
=== GDB ===
 
It may be worth noting that if you wish to use ```'''GDB```''', and you are running on a different computer architecture than youyour OS (most common case is developing for ARM on x86_64 or x86_64 on ARM), you need to cross-compile GDB separately. While technically a part of Binutils, it resides in a separate repository.
 
The protocol for building GDB to target a different architecture is very similar to that of regular Binutils:
 
<sourcesyntaxhighlight lang="bash">
../gdb.x.y.z/configure --target=$TARGET --prefix="$PREFIX" --disable-werror
make all-gdb
make install-gdb
</syntaxhighlight>
</source>
 
The ```<tt>'''--disable-nls```'''</tt> and ```<tt>'''--with-sysroot``'''</tt> options don't seem to have any effect.
 
=== GCC ===
Line 117 ⟶ 121:
-->
 
<sourcesyntaxhighlight lang="bash">
cd $HOME/src
 
Line 130 ⟶ 134:
make install-gcc
make install-target-libgcc
</syntaxhighlight>
</source>
 
We build [[libgcc]], a low-level support library that the compiler expects available at compile time. Linking against [[libgcc]] provides integer, floating point, decimal, stack unwinding (useful for exception handling) and other support functions. Note how we are ''not'' simply running <tt>make && make install</tt> as that would build way too much, not all components of gcc are ready to target your unfinished operating system.
Line 146 ⟶ 150:
== Using the new Compiler ==
 
Now you have a "naked" cross-compiler. It does not have access to a C library or C runtime yet, so you cannot use anymost of the standard includes or create runnable binaries. But it is quite sufficient to compile the kernel you will be making shortly. Your toolset resides in $HOME/opt/cross (or what you set <tt>$PREFIX</tt> to). For example, you have a GCC executable installed as <tt>$HOME/opt/cross/bin/$TARGET-gcc</tt>, which creates programs for your TARGET.
 
You can now run your new compiler by invoking something like:
 
<syntaxhighlight lang="bash">
<source lang="bash">$HOME/opt/cross/bin/$TARGET-gcc --version</source>
</syntaxhighlight>
 
Note how this compiler is ''not'' able to compile normal C programs. The cross-compiler will spit errors whenever you want to #include any of the standard headers (except for a select few that actually are platform-independent, and generated by the compiler itself). This is quite correct - you don't have a standard library for the target system yet!
 
The C standard defines two different kinds of executing environments - "freestanding" and "hosted". While the definition might be rather fuzzy for the average application programmer, it is pretty clear-cut when you're doing OS development: A kernel is "freestanding", everything you do in user space is "hosted". A "freestanding" environment needs to provide only a subset of the C library: <tt>float.h</tt>, <tt>iso646.h</tt>, <tt>limits.h</tt>, <tt>stdalign.h</tt>, <tt>stdarg.h</tt>, <tt>stdbool.h</tt>, <tt>stddef.h</tt>, <tt>stdint.h</tt> and <tt>stdnoreturn.h</tt> (as of C11). All of these consist of typedef s and #define s "only", so you can implement them without a single .c file in sight.
 
Note that to have these compiler-provided includes work properly, you need to build your kernel with the <tt>-ffreestanding</tt> flag. Otherwise, they might attempt including your standard library's copy of the headers, which isn't gonna work if you don't have a standard library.
 
To use your new compiler simply by invoking <tt>$TARGET-gcc</tt>, add <tt>$HOME/opt/cross/bin</tt> to your <tt>$PATH</tt> by typing:
 
<syntaxhighlight lang="bash">
<source lang="bash">export PATH="$HOME/opt/cross/bin:$PATH"</source>
</syntaxhighlight>
 
This command will add your new compiler to your PATH for this shell session. If you wish to use it permanently, add the PATH command to your <tt>~/.profile</tt> configuration shell script or similar. Consult your shell documentation for more information.
Line 183 ⟶ 193:
 
The solution is simply to create the empty folders:
<sourcesyntaxhighlight lang="bash">
mkdir -p $SYSROOT/mingw/include
mkdir -p $SYSROOT/mingw/lib
</syntaxhighlight>
</source>
 
This will allow the build to proceed. The reason this happens is that the <tt>mingw32</tt> (and mingw itself) configures <tt>INCLUDE_PATH</tt> and <tt>LIBRARY_PATH</tt> to be, as can be guessed, <tt>/mingw/include</tt> and <tt>/mingw/lib</tt>, instead of the defaults <tt>/usr/include</tt> and <tt>/usr/lib</tt>. Why the build fails even though nothing is required in those folders, and why it doesn't just make them, is beyond me.
Line 267 ⟶ 277:
* [https://drive.google.com/file/d/0B85K_c7mx3QjUnZuaFRPWlBIcXM/edit?usp=sharing i686-elf 4.8.2 target]
* [https://mega.co.nz/#F!bBxA3SKJ!TDL4i1NjaZKd4YMo9p2U7g x86_64-elf 5.1.0 target]
* [https://github.com/lordmilko/i686-elf-tools i686-/x86_64-elf 713.12.0 target + GDB (Windows/Linux/WSL)]
 
'''For Windows Subsystem for Linux (Beta) host'''
* [http://www.bin-os.com/i686-elf-6.1.0.tar.gz i686-elf 6.1.0 target] (extracts to a directory called "cross", don't forget to install 'make' - I would recommend "apt-get install build-essential" to also add additional useful tools)
 
'''For Windows Subsytem for Linux host'''
* [https://drive.google.com/file/d/1zn37YmyVrtsPOfe88jZRZ_-_3_jzpXBP/view?usp=sharing i686-elf 13.1.0 target] ('''Important: extracts to a directory called "cross-tk"''')
 
'''For macOS host'''