嵌入式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

https://www.crifan.com/files/doc/docbook/cross_compile/release/html/cross_compile.html#crosscompiler_naming_rule

 

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

https://www.crifan.com/files/doc/docbook/cross_compile/release/html/cross_compile.html#crosscompiler_naming_rule