编译和链接
一个完整的 C 语言项目可能包含多个 .c 源文件,项目的运行需要经过“编译”和“链接”两个过程:
- 编译:由编译器逐个对 所有源文件 做词法分析、语法分析、语义分析等操作,最终生成 多个目标文件。每个目标文件都是二进制文件,但由于它们会相互调用对方的函数或变量,还可能会调用某些链接库文件中的函数或变量,编译器无法跨文件找到它们确切的存储地址,所以这些目标文件无法单独执行。
- 链接:对于各个目标文件中缺失的函数和变量的存储地址(后续简称“缺失的地址”),由链接器负责修复,并最终将所有的目标文件和链接库组织成一个可执行文件。
库和库的链接
- 静态函数库(static libraries):在编译期间(compile-time)静态链接库会全部拷贝进编译对象中。
- 动态函数库(shared libraries):在程序启动的时候加载到程序中,它可以被不同的程序共享。
预编译的时候要处理头文件,因此gcc -E的时候需要通过 -l大写的i 来指定头文件搜索路径。
查找路径链接的时候需要各个库,因此gcc -o的时候需要通过**-L指定库文件搜索路径**,以及-l(小写的L)来指定具体的库文件名称。
编译时,加上“-L <库文件目录>”这样的选项,用来指定库目录;
编译时,加上“-labc”这样的选项,用来指定库文件libabc.so。
所以说自己写的头文件和主函数放在一起,然后编译、链接是不会出错的,这是因为""的头文件就默认寻找范围就是当前文件夹,所以找得到;如果你把头文件放在另外一个文件夹中,就需要通过-L dir去指定一下库文件位置。
路径相关总结:
默认当前路径下,可指定
链接时库文件在哪?系统目录:交叉编译工具链的某个lib目录;
运行时库文件在哪?就是板子上/lib、/usr/lib目录,运行程序用环境变量LD_LIBRARY_PATH指定。
缺啥补啥
在编程过程中,程序代码往往被拆成很多部分,每部分放在一个独立的源文件中,而不是将所有的代码放在一个源文件中。考虑一个简单的小例子:程序中有两个函数main()和abc()。main()函数位于main.cpp,abc()函数位于abc.cpp,main()函数中调用abc()函数。在编译阶段,由于编译是对单个文件进行编译,所以编译main.cpp时,编译器不知道是否存在abc()函数以及abc()调用是否正确,因此需要头文件辅助。
库文件中包含一系列的子程序。例如abc.cpp 源文件中实现了abc()函数,我们假设abc()函数是包含重要算法的函数,我们需要将abc()函数提供给客户使用,但是不希望客户看到算法源代码。为了达到这一目的,我们可以将abc.cpp编译成库文件,库文件是二进制的,在库文件中是看不到原始的源代码的。库和可执行文件的区别是,库不是独立程序,他们是向其他程序提供服务的代码。当然使用库文件的好处不仅仅是对源代码进行保密,使用库文件还可以减少重复编译的时间,增强程序的模块化。将库文件连接到程序中,有两种方式,一种是静态连接库,另一种是动态连接库。
简单来说abc.h是头文件,在编译的时候他是啥编译器也不知道,一般只是包含函数的声明;abc.c主要为abc()的定义,在编译后形成二进制的库文件;在链接的时候将主程序中的abc()用二进制库文件代替执行。
在linux下头文件有头文件的目录,如果缺少头文件,就把头文件加到这个目录,主程序编译时会自动搜索。库文件也有自己的目录,里面全是.so文件;储存函数的.c文件编译后的二进制文件;可以把.so文件放在这个目录下,主程序链接时会自动去搜索。
交叉编译工具链
就是实现在Ubuntu下编译别的架构能跑的APP。
设置交叉编译工具主要是设置 PATH, ARCH和CROSS_COMPILE三个环境变量。
- ARCH:编译给什么架构用;
- CROSS_COMPILE:交叉编译,需要和ARCH保持一致;
- PATH:搜索路径,他用于保存一系列的路径。当你程序编译时,所用的库文件、头文件的默认路径。
echo 'main(){}'| arm-buildroot-linux-gnueabihf-gcc -E -v -
用于查看 当前编译模式(给arm编译的) 下头文件和库文件的路径
头文件路径:
库文件路径:
修改
修改给ARM使用的,临时性修改:
export ARCH=arm
export CROSS_COMPILE=arm-buildroot-linux-gnueabihf-
export PATH=$PATH:/home/book/100ask_imx6ull-sdk/ToolChain/arm-buildroot-linux-gnueabihf_sdk-buildroot/bin
设置完毕后,要执行 source ~/.bashrc 命令使其生效,这条命令是加载这些设置的环境变量。
万能交叉编译命令
如果交叉编辑工具链的前缀是arm-buildroot-linux-gnueabihf-,比如arm-buildroot-linux-gnueabihf-gcc,交叉编译开源软件时,如果它里面有configure,万能命令如下:
./configure --host=arm-buildroot-linux-gnueabihf --prefix=$PWD(当前目录)/tmp
(将头文件、库文件放到当前目录下的tmp;它会生成一个Makefile,之后才能make)
make
make install
就可以在当前目录的tmp目录下看见bin, lib, include等目录,里面存有可执行程序、库、头文件。
./configure --prefix=/ 的作用是:编译的时候用来指定程序存放路径
不指定prefix,可执行文件默认放在/usr /local/bin,库文件默认放在/usr/local/lib,配置文件默认放在/usr/local/etc,其它的资源文件放在/usr /local/share。
如果指定了路径,在make install时没有再说明就默认在prefix下安装文件(一般不会再指定,除非Makefile有需求);如果指定就在prefix目录下再创建目录安装文件。
查看工具链:
echo ‘main(){}’| arm-buildroot-linux-gnueabihf-gcc -E -v -
include目录:
/home/book/100ask_imx6ull-sdk/ToolChain/arm-buildroot-linux-gnueabihf_sdk-buildroot/arm-buildroot-linux-gnueabihf/sysroot/usr/include
lib目录:
/home/book/100ask_imx6ull-sdk/ToolChain/arm-buildroot-linux-gnueabihf_sdk-buildroot/arm-buildroot-linux-gnueabihf/sysroot/usr/lib/