嵌入式linux开发-交叉编译的一些tips
嵌入式linux开发-交叉编译的一些tips
时间:20201013,版本:V0.1
1.交叉编译工具链的组成
交叉编译工具链是一个由编译器、连接器和解释器组成的综合开发环境,交叉编译工具链主要由binutils、gcc和glibc三个部分组成。有时出于减小 libc 库大小的考虑,也可以用别的 c 库来代替 glibc,例如 uClibc和 newlib。
2.交叉编译工具的获取
(1)可以去下别人厂商提供的或者别人制作好的。
(2)交叉编译工具的制作可以参考这个文章:How to Build a GCC Cross-Compiler
https://preshing.com/20141119/how-to-build-a-gcc-cross-compiler/
以及《嵌入式linux系统开发教程 第二版》(图6-1),过程说的很清楚。制作过程比较繁琐,主要是因为为了生成完整版的gcc,需要先编译一个辅助版的不依赖glibc的编译器,再用辅助gcc编译libc,再生成完整的gcc。
(3)从头做一个太麻烦,可以使用工具。我们这里采用buildroot生成的。Buildroot使用见本站其文章。
3.交叉编译链工具的命名规则
交叉编译知识解析(二) —— 交叉编译器的名字的命名规则
https://blog.csdn.net/zqixiao_09/article/details/51823165
4.交叉编译器引用头文件的位置
交叉编译器默认引用的.h文件和lib文件的位置,可以使用如下的命令查看:
(这里的mipsel-linux-gcc是使用buildroot生成的。)
./mipsel-linux-gcc -print-search-dirs
打印出搜索路径。一堆挤在一起的路径,很难看。
网上大家貌似更喜欢另一个命令:
$ echo 'main(){}' | ./mipsel-linux-gcc -E -v -x c -
参数-E:
只进行预处理步骤,这个不生成文件, 需要把它重定向到一个输出文件里面。
参数-v:
使用 gcc -v 可以查看默认开启的选项。编译这个工具时所使用的configure 参数配置。
参数 - (只有一个短线):
这个参数需要特殊说明一下。短线的意思是 Specify input file as stdin, 在这里就是从管道接收输入了。-x c 的意思是以c语言来编译接收的文件。因为接收的是字符流,没有文件名,所指告知gcc是c语言。Gcc默认也是c。
命令输出的结果中会包含搜索路径,并说明这些配置是记录在编译器的 built-in specs。
我的电脑上,路径是:
#include <...> search starts here:
/home/jack/worktable/buildroot/output/host/lib/gcc/mipsel-buildroot-linux-uclibc/8.4.0/include
/home/jack/worktable/buildroot/output/host/lib/gcc/mipsel-buildroot-linux-uclibc/8.4.0/include-fixed
/home/jack/worktable/buildroot/output/host/mipsel-buildroot-linux-uclibc/sysroot/usr/include
End of search list.
可以看到,交叉编译工具的搜索目录一般就在安装目录了。
5.源码包交叉编译的一般过程(configure的常用参数的含义)
源码包和普通的linux程序的编译差不多,configure、make、make install。
这里需要注意的是参数和环境变量。
configure是autotools生成的配置脚本,用于生成makefile。
./configure --help 查看相关的参数。
重要的参数有:
--prefix
安装路径前缀,指使用make install 后,是指生成的可执行文件安装在哪个目录,这个目录需要根据实际情况作选择。如果该目录不存在,会自动创建。
例如:
./configure --prefix=$home/work/
--build
执行代码编译的主机,正常的话就是你的主机系统。这个参数一般由config.guess来猜就可以。当然自己指定也可以。
--host
编译出来的二进制程序所运行于的主机,因为绝大多数是本机编译,本机执行,所以这个值就等于build。只有交叉编译的时候(也就是本机编译,其他系统机器执行)才会build和host不同。用host指定运行平台。
--target
被编译的程序生成的程序将运行于的平台。这个选项只有在建立交叉编译环境(制作交叉编译工具)的时候用到,正常编译和交叉编译都不会用到。他用build主机上的编译器,编译一个新的编译工具(binutils, gcc,gdb等),这个新的编译器运行于host,它(新的编译器)编译出来的其他程序将运行在target系统上。
在前文中生成的mips平台的工具,执行:
$ mipsel-linux-gcc -v
输出中就会显示生成此工具时的configure参数:
Configured with: ./configure ..--target=mipsel-buildroot-linux-uclibc ..
举个栗子:
./configure --host=arm-unknown-linux-gnueabi --target=arm-unknown-linux-gnueabi --build=i686-pc-linux --prefix=$DIST/libnet
问题是,到哪里精确的获取这几个平台值呢?交叉编译的时候我一般用编译工具的名称去掉工具名称。例如工具是mips-robotech-linux-gcc,那么--host就设置成:
--host=mips-robotech-linux
这里其实最重要的是--host参数了,configure使用--host参数寻找交叉编译工具。前提是在path环境变量里设置了交叉编译工具的路径。编译器也可以用环境变量CC指定。
--with-sysroot
https://answerywj.com/2019/04/26/what-is-sysroot/
重要的环境变量:
CC
指定编译器,默认为gcc、cc或者HOST-gcc
例如:
./configure CC=/home/path/mips-linux-gcc
或者使用export指定
$export CC=/home/path/mips-linux-gcc
两种写法有什么区别呢?使用export应该是正规的方式,有的configure脚本可能不支持第一种方式。
所以,指定编译器既可以通过--host去关联也可以通过CC指定,怎样更合适呢?一般./configure --help里会告诉你,环境变量优先级更高,能够覆盖掉./configure脚本自己的推断。
CFLAGS、 CPPFLAGS
C compiler flags,最常用是指定(非标准默认的)头文件的路径。以及其他的编译标志。
例如:
export CFLAGS=-I$WDIR/arm-unknown-linux-gnueabi/include -mhard-float -mfpu=vfpv3-d16
LDFLAGS
linker flags, 例如.指定库文件的路径 -L<lib dir>, if you have libraries in a nonstandard directory <lib dir>。
例如:
export LDFLAGS=-L$WDIR/arm-unknown-linux-gnueabi/lib
LIBS
libraries to pass to the linker, e.g. -l<library>。
-l后面紧接着库名,链接时在搜索目录中寻找库文件,搜索名为libxxx.a 或 libxxx.so
LDFLAGS告诉链接器从哪里寻找库文件,LIBS告诉链接器要链接哪些库文件。
参考:
https://blog.csdn.net/xhoufei2010/article/details/82768995
https://unix.stackexchange.com/questions/149359/what-is-the-correct-syntax-to-add-cflags-and-ldflags-to-configure
https://blog.csdn.net/zqixiao_09/article/details/51823165