Chapter 3: Cross compiler
A compiler that is capable of producing code that is executable on a platform that is different from the one on which the compiler is now operating is referred to as a cross compiler. One example of a cross compiler is a compiler that is designed to run on a personal computer but also generates code that can be executed on Android devices.
In order to compile code for different platforms from a single development host, a cross compiler is an extremely useful tool. Direct compilation on the target platform might not be possible, for instance on embedded devices that have a restricted amount of CPU resources.
Comparisons between source-to-source compilers and cross compilers are not the same. The difference between a source-to-source compiler and a cross compiler is that the former is used to generate machine code for cross-platform applications, while the latter is used to translate text code from one programming language to another. The two are both tools for programming.
One of the most fundamental applications of a cross compiler is to enable the separation of the target environment and the build environment. This is helpful in a number of different situations:
One of the reasons that cross compilers were developed was to overcome some of the problems that were caused by the use of virtual machines, such as Java's JVM. The virtual machine paradigm makes it possible to use the same compiler output across many target systems. However, this is not always the best option because virtual machines are typically slower than other types of computers, and the compiled program can only be executed on computers that have that virtual machine.
However, cross-compilation can also be utilized when only the operating system environment is different, such as when compiling a FreeBSD program under Linux, or even just the system library, such as when compiling programs with uClibc on a glibc host. In most cases, the hardware architecture is different (for example, when coding a program that is intended for the MIPS architecture on an x86 computer).
One method for constructing cross compilers for different machines is known as the Canadian Cross. This method is utilized in situations where the originating machine is significantly slower or less convenient than the target computer. A cross compiler is constructed by using machine A (for example, running Windows XP on an IA-32 processor) to develop a cross compiler that runs on machine B (for example, running macOS on an x86-64 processor) to create executables for machine C (for example, running Android on an ARM processor). A cross compiler is used to create executables for machine C. Machine A is slow but has a proprietary compiler, Machine B is fast but has no compiler at all, and Machine C is impractically slow to utilize for compilation. The practical advantage in this example is that Machine A has a specific compiler that is not available to other machines.
When the Canadian Cross is used in conjunction with GCC, as seen in this example, there may be a total of four compilers available.
Although the end-result cross compiler (4) will not be able to run on build machine A, it will be able to run on machine B in order to compile an application into executable code. This code would then be copied to machine C and executed on machine C.
For example, NetBSD has a POSIX Unix shell script that is called build.sh. This script will initially construct its own toolchain by utilizing the host's compiler. This toolchain will then be utilized to construct the cross compiler, which will be utilized to construct the entire system.
Because there were three national political parties in Canada at the time that these concerns were being discussed, the term "Canadian Cross" came into existence.
The GCC, which is a collection of free software compilers, can be configured to perform cross-compilation. Many different languages and platforms are supported by it.
A compiled version of binutils must be accessible for each platform that is being targeted, as this is a requirement of GCC. In particular, the GNU Assembler is of great significance. Therefore, the first step is to ensure that binutils is compiled successfully by sending the switch --target=some-target to the configure script. Additionally, the --target option needs to be specified whenever GCC is being used. After that, GCC can be executed normally, assuming that the tools that binutils generates are present in the path. This can be accomplished by using the following (on operating systems that are similar to UNIX and use bash):
When using GCC for cross-compilation, it is necessary for the host platform to have access to a subset of the C standard library that is used by the target platform. There is a possibility that the programmer will decide to compile the entire C library; however, this decision might not be reliable. The alternative is to make use of newlib, which is a compact C library that only includes the components that are absolutely necessary for the compilation of C source code.
It is possible to employ the concepts of a build platform, a host platform, and a target platform while working with the GNU Autotools packages, which include autoconf, automake, and libtool. During the compilation process, the compiler is really compiled on the build platform. It is recommended that build be left undefined in the majority of situations (it will default from host). It is always the host platform that will be responsible for executing the output artifacts from the compiler, regardless of whether the output is also produced by another compiler or not. When cross-compiling cross compilers, the target platform is utilized; it is a representation of the type of object code that the package will generate; in other cases, the target platform option is useless. Consider, for instance, the possibility of cross-compiling a video game such that it can be played on a Dreamcast. While the Dreamcast serves as the host platform, the build platform refers to the system that is responsible for the compilation of the game. According to the compiler that is being used, the names host and target are related to one another and can be changed like son and grandson.
The combination of GCC compilers with specific sandboxes such as Scratchbox and Scratchbox 2, or PRoot, is yet another way that is frequently utilized by developers working with embedded Linux. The use of these tools results in the creation of a "chrooted" sandbox, which allows the programmer to construct critical tools, libc, and libraries without the need to define additional paths. Additionally, facilities are provided to "deceive" the runtime so that it "believes" it is truly operating on the intended target CPU (for example, an ARM architecture). This enables configuration scripts and other similar scripts to run without any errors. When compared to "non-chrooted" approaches, Scratchbox is run more slowly, and in order for the majority of tools that are now installed on the host to function, they need to be relocated inside Scratchbox.
Beginning in the 1980s, Manx Software Systems, based in Shrewsbury, New Jersey, began producing C compilers with the intention of catering to professional developers for a wide range of platforms, including IBM PC compatibles and Macs.
The Aztec C programming language was made available for use on a number of different systems, such as MS-DOS, Apple II, DOS 3.3 and ProDOS, Commodore 64, Mac 68k, and Amiga.
The MS-DOS version of Aztec C was available for use as a native mode compiler and as a cross compiler for other platforms with different processors, such as the Commodore 64 and the Apple II, beginning in the 1980s and continuing through the 1990s until Manx Software Systems went out of business. Internet distributions for Aztec C, including their MS-DOS-based cross compilers, are still available today. The use of them continues to this day.
In addition to being a native mode 8086 MS-DOS compiler, Manx's Aztec C86 utilized cross-compilation capabilities. Even while it did not generate code for a different CPU, such as their Aztec C65 6502 cross compilers for the Commodore 64 and Apple II, it did build binary executables for operating systems that were considered to be legacy at the time. These executables were designed for the 16-bit 8086 family of processors.
When the IBM Personal Computer was first debuted, it was offered with a selection of operating systems, including CP/M-86 and PC DOS, which were two of the available options. Link libraries were made available to Aztec C86 so that it could generate code for both computer operating systems used by IBM PCs. As the 1980s progressed, further versions of Aztec C86 (3.xx, 4.xx, and 5.xx) gained support for MS-DOS "transitory" versions 1 and 2. These versions were less robust than the "baseline" MS-DOS version 3 and later, which Aztec C86 targeted until its end. During this time, Aztec C86 was able to handle these versions.
Last but not least, Aztec C86 gave developers of the C programming language the ability to generate ROM-able "HEX" code, which could subsequently be transferred to an 8086-based processor by means of a ROM burner. The practice of developing low-level ROM code was more prevalent per capita during those years when device driver development was frequently done by application programmers for particular programs and new devices amounted to a cottage industry. Although paravirtualization may be more widespread today, the practice of creating low-level ROM code was more common per capita during those years. In the past, it was not unusual for application programmers to connect directly with hardware without receiving...