able-nls --disable-multilib --with-local-prefix=/home/andrew/x-tools/arm-cortex_a8-linux-gnueabihf/arm-cortex_a8-linux-gnueabihf/sysroot --enable-long-long
Thread model: posix
Supported LTO compression algorithms: zlib
gcc version 11.2.0 (crosstool-NG 1.25.0)
值得注意的是以下内容:
- --with-sysroot=/home/frank/x-tools/arm-cortex_a8-linux-gnueabihf/arm-cortex_a8-linux-gnueabihf/sysroot: 这是默认的sysroot目录;请看下面的解释。
- --enable-languages=c,c++: 使用这个,我们同时启用了C和C++ 。
- --with-cpu=cortex-a8: 代码是为ARM Cortex A8内核生成的。
- --with-float=hard:为浮点单元生成操作代码,并使用VFP寄存器作为参数。
- --enable-threads=posix:这将启用POSIX线程。
这些是编译器的默认设置。你可以在gcc命令行中覆盖其中的大部分。例如,如果你想为不同的CPU编译,你可以通过在命令行中加入-mcpu来覆盖配置的设置--with-cpu,如下所示:
$ arm-cortex_a8-linux-gnueabihf-gcc -mcpu=cortex-a5 helloworld.c -o helloworld
你可以使用 --target-help 打印出可用的特定架构选项的范围,如下所示:
$ arm-cortex_a8-linux-gnueabihf-gcc --target-help
果你计划为每个目标创建工具链,那么在一开始就设置好是有意义的,因为这将减少以后出错的风险。另一方面,如果你想构建通用的工具链,并且准备在为特定目标构建时提供正确的设置,那么你应该使基础工具链通用化,这就是Yocto项目处理事情的方式。前面的例子都是遵循Buildroot的理念。
sysroot、库和头文件
工具链的系sysroot是包含库、头文件和其他配置文件的子目录的目录。它可以在配置工具链时通过 --with-sysroot= 设置,也可以在命令行中通过 --sysroot= 设置。 你可以通过使用 -print-sysroot 看到默认的系统根目录的位置:
$ arm-cortex_a8-linux-gnueabihf-gcc -print-sysroot
/home/andrew/x-tools/arm-cortex_a8-linux-gnueabihf/arm-cortex_a8-linux-gnueabihf/sysroot
你会在sysroot中找到以下子目录:
- lib: 包含C库和动态链接器/加载器的共享对象,ld-linux
- usr/lib: C库的静态库存档文件,以及随后可能安装的任何其他库。
- usr/include: 包含所有库的头文件
- usr/bin: 包含在目标机上运行的实用程序,如ldd命令
- usr/share: 用来进行本地化和国际化
- sbin: 提供ldconfig工具,用于优化库的加载路径。
很明显,这些工具中的一些在开发主机上需要用来编译程序,而另一些,例如共享库和ld-linux,在运行时需要在目标上使用。
工具链中的其他工具
下面是调用GNU工具链中其他各种组件的命令列表,并附有简要说明:
- addr2line: 通过读取可执行文件中的调试符号表,将程序地址转换为文件名和数字。在对系统崩溃报告中打印出来的地址进行解码时,它非常有用。
- ar: 归档工具,用于创建静态库。
- as: 这是GNU的汇编程序。
- c++filt: 这是用来拆解C++和Java的符号。
- cpp: 这是C语言的预处理器,用于扩展#define、#include和其他类似的指令。你很少需要单独使用它。
- elfedit: 这是用来更新ELF文件的ELF头。
- g++: 这是GNU的C++前端,它假定源文件中含有C++代码。
- gcc: 这是 GNU C 前端,它假定源文件包含 C 代码。
- gcov: 代码覆盖工具。
- gdb: 这是 GNU 调试器。
- gprof: 程序剖析工具。
- ld: 这是GNU的连接器。
- nm: 它列出对象文件中的符号。
- objcopy: 用来复制和翻译对象文件。
- objdump: 用来显示对象文件的信息。
- ranlib: 它在静态库中创建或修改索引,使链接阶段更快。
- readelf: 它显示ELF对象格式的文件信息。
- size: 这列出了部分大小和总大小。
- strings: 这显示文件中的可打印字符的字符串。
- strip: 用于剥离调试符号表的对象文件,从而使其更小。通常情况下,你会剥离所有被放到目标上的可执行代码。
C库
C库不是单一的库文件。它由四个主要部分组成,共同实现POSIX API:
- libc:主C库,包含众所周知的POSIX函数,如printf、open、close、read、write,等等。
- libm: 包含数学函数,如cos、exp和log
- libpthread: 包含了所有的POSIX线程函数,名称以pthread开头的POSIX线程函数。
- librt: 拥有POSIX的实时扩展,包括共享内存和异步I/O
第一个库,libc,总是被链接进去的,但其他库必须用-l选项明确地链接。-l的参数是去掉lib后的库名。例如,通过调用sin()来计算正弦函数的程序可以用-lm链接到libm:
$ arm-cortex_a8-linux-gnueabihf-gcc myprog.c -o myprog -lm
你可以通过使用readelf命令来验证哪些库已经在这个或其他程序中被链接:
$ arm-cortex_a8-linux-gnueabihf-readelf -a code/helloworld | grep "Shared library"
0x00000001 (NEEDED) Shared library: [libc.so.6]
共享库需要运行时链接器:
$ arm-cortex_a8-linux-gnueabihf-readelf -a code/helloworld | grep "program interpreter"
[Requesting program interpreter: /lib/ld-linux-armhf.so.3]
链接库
你为Linux编写的任何应用程序,无论是C语言还是C++语言,都会与lic 库链接。你甚至不需要告诉gcc或g++去做,因为它总是链接libc。其他你可能想要链接的库必须通过-l选项明确指定。
库的代码可以用两种不同的方式连接:静态的,意味着你的应用程序所调用的所有库函数和它们的依赖关系都是从库的归档文件中提取并绑定到你的可执行文件中;动态的,意味着对库文件和这些文件中的函数的引用是在代码中生成的,但实际的连接是在运行时动态进行的。
静态库
如果你正在构建小程序,静态链接会更简单,避免复制运行