官术网_书友最值得收藏!

Types of toolchain - native versus cross toolchain

For our purposes, there are two types of toolchain:

  • Native: This toolchain runs on the same type of system, sometimes the same actual system, as the programs it generates. This is the usual case for desktops and servers, and it is becoming popular on certain classes of embedded devices. The Raspberry Pi running Debian for ARM, for example, has self-hosted native compilers.
  • Cross: This toolchain runs on a different type of system than the target, allowing the development to be done on a fast desktop PC and then loaded onto the embedded target for testing.

Almost all embedded Linux development is done using a cross development toolchain, partly because most embedded devices are not well suited to program development since they lack computing power, memory, and storage, but also because it keeps the host and target environments separate. The latter point is especially important when the host and the target are using the same architecture, X86_64, for example. In this case, it is tempting to compile natively on the host and simply copy the binaries to the target. This works up to a point but it is likely that the host distribution will receive updates more often than the target, that different engineers building code for the target will have slightly different versions of the host development libraries and so you will violate the principle that the toolchain should remain constant throughout the life of the project. You can make this approach work if you ensure that the host and target build environments are in lockstep with each other, but a much better approach is to keep the host and the target separate, and a cross toolchain is a way to do that.

However, there is a counter argument in favor of native development. Cross development creates the burden of cross-compiling all the libraries and tools that you need for your target. We will see later on in this chapter that cross-compiling is not always simple because most open source packages are not designed to be built in this way. Integrated build tools, including Buildroot and the Yocto Project, help by encapsulating the rules to cross compile a range of packages that you need in typical embedded systems but, if you want to compile a large number of additional packages, then it is better to natively compile them. For example, to provide a Debian distribution for the Raspberry Pi or BeagleBone using a cross compiler is impossible, they have to be natively compiled. Creating a native build environment from scratch is not easy and involves creating a cross compiler first to bootstrap a native build environment on the target and using that to build packages. You would need a build farm of well-provisioned target boards or you may be able to use QEMU to emulate the target. If you want to look into this further, you may want to look at the Scratchbox project, now in its second incarnation as Scratchbox2 (Maemo Linux operating system, and is used today by the Mer project and the Tizen project, among others.

Meanwhile, in this chapter, I will focus on the more mainstream cross compiler environment, which is relatively easy to set up and administer.

CPU architectures

The toolchain has to be built according to the capabilities of the target CPU, which includes:

  • CPU architecture: arm, mips, x86_64, and so on
  • Big- or little-endian operation: Some CPUs can operate in both modes, but the machine code is different for each
  • Floating point support: Not all versions of embedded processors implement a hardware floating point unit, in which case, the toolchain can be configured to call a software floating point library instead
  • Application Binary Interface (ABI): The calling convention used for passing parameters between function calls

With many architectures, the ABI is constant across the family of processors. One notable exception is ARM. The ARM architecture transitioned to the Extended Application Binary Interface (EABI) in the late 2000's, resulting in the previous ABI being named the Old Application Binary Interface (OABI). While the OABI is now obsolete, you continue to see references to EABI. Since then, the EABI has split into two, based on the way that floating point parameters are passed. The original EABI uses general purpose (integer) registers while the newer EABIHF uses floating point registers. The EABIHF is significantly faster at floating point operations since it removes the need for copying between integer and floating point registers, but it is not compatible with CPUs that do not have a floating point unit. The choice, then, is between two incompatible ABIs: you cannot mix and match the two and so you have to decide at this stage.

GNU uses a prefix to the tools to identify the various combinations that can be generated, consisting of a tuple of three or four components separated by dashes, as described here:

  • CPU: The CPU architecture, such as arm, mips, or x86_64. If the CPU has both endian modes, they may be differentiated by adding el for little-endian, or eb for big-endian. Good examples are little-endian MIPS, mipsel and big-endian ARM, armeb.
  • Vendor: This identifies the provider of the toolchain. Examples include buildroot, poky, or just unknown. Sometimes it is left out altogether.
  • Kernel: For our purposes, it is always 'linux'.
  • Operating system: A name for the user space component, which might be gnu or uclibcgnu. The ABI may be appended here as well so, for ARM toolchains, you may see gnueabi, gnueabihf, uclibcgnueabi, or uclibcgnueabihf.

You can find the tuple used when building the toolchain by using the -dumpmachine option of gcc. For example, you may see the following on the host computer:

$ gcc -dumpmachine
x86_64-linux-gnu

Note

When a native compiler is installed on a machine, it is normal to create links to each of the tools in the toolchain with no prefixes so that you can call the compiler with the command gcc.

Here is an example using a cross compiler:

$ mipsel-unknown-linux-gnu-gcc -dumpmachine
mipsel-unknown-linux-gnu
主站蜘蛛池模板: 南木林县| 杭锦旗| 河曲县| 昌邑市| 崇文区| 额尔古纳市| 曲水县| 旬阳县| 彭州市| 乌鲁木齐县| 岳阳县| 沽源县| 彭水| 托克托县| 仙居县| 邯郸县| 长沙市| 德阳市| 镇沅| 清流县| 凤冈县| 东乌珠穆沁旗| 双辽市| 东兴市| 肥乡县| 宿州市| 张北县| 兖州市| 海门市| 黎川县| 靖边县| 杭锦后旗| 神木县| 金乡县| 盖州市| 当雄县| 项城市| 万盛区| 建瓯市| 昌吉市| 普宁市|