摘要:本文主要介绍了嵌入式应用程序开发中,与头文件、库文件相关的知识。例如:默认的头文件路径、默认的库文件路径、指定头文件路径、指定库文件路径、编译静态库&动态库。
1. 开发环境
本文使用的是百问网研发的 IMX6ULL_PRO 板的开发环境。
操作系统:Ubuntu 18.04
交叉编译工具链:arm-buildroot-linux-gnueabihf-gcc
linux@ubuntu:~$ arm-buildroot-linux-gnueabihf-gcc -v
Using built-in specs.
COLLECT_GCC=/home/linux/100ask/100ask_imx6ull-sdk/ToolChain/arm-buildroot-linux-gnueabihf_sdk-buildroot/bin/arm-buildroot-linux-gnueabihf-gcc.br_real
COLLECT_LTO_WRAPPER=/home/linux/100ask/100ask_imx6ull-sdk/ToolChain/arm-buildroot-linux-gnueabihf_sdk-buildroot/bin/../libexec/gcc/arm-buildroot-linux-gnueabihf/7.5.0/lto-wrapper
Target: arm-buildroot-linux-gnueabihf
Configured with: ./configure --prefix=/home/book/100ask_imx6ull-sdk/Buildroot_2020.02.x/output/host --sysconfdir=/home/book/100ask_imx6ull-sdk/Buildroot_2020.02.x/output/host/etc --enable-static --target=arm-buildroot-linux-gnueabihf --with-sysroot=/home/book/100ask_imx6ull-sdk/Buildroot_2020.02.x/output/host/arm-buildroot-linux-gnueabihf/sysroot --enable-__cxa_atexit --with-gnu-ld --disable-libssp --disable-multilib --disable-decimal-float --with-gmp=/home/book/100ask_imx6ull-sdk/Buildroot_2020.02.x/output/host --with-mpc=/home/book/100ask_imx6ull-sdk/Buildroot_2020.02.x/output/host --with-mpfr=/home/book/100ask_imx6ull-sdk/Buildroot_2020.02.x/output/host --with-pkgversion='Buildroot 2020.02-gee85cab' --with-bugurl=http://bugs.buildroot.net/ --disable-libquadmath --enable-tls --enable-plugins --enable-lto --enable-threads --with-isl=/home/book/100ask_imx6ull-sdk/Buildroot_2020.02.x/output/host --with-abi=aapcs-linux --with-cpu=cortex-a7 --with-fpu=neon-vfpv4 --with-float=hard --with-mode=arm --enable-languages=c,c++,fortran --with-build-time-tools=/home/book/100ask_imx6ull-sdk/Buildroot_2020.02.x/output/host/arm-buildroot-linux-gnueabihf/bin --enable-shared --enable-libgomp
Thread model: posix
gcc version 7.5.0 (Buildroot 2020.02-gee85cab)
2. 查询默认路径
编译器有自己默认搜索的头文件路径和库文件路径。我们可以通过echo 'main(){}'| arm-buildroot-linux-gnueabihf-gcc -E -v -
命令获取这些默认路径的信息。
linux@ubuntu:~$ echo 'main(){}'| arm-buildroot-linux-gnueabihf-gcc -E -v -
... 省略 ...
#include "..." search starts here:
#include <...> search starts here:
/home/linux/100ask/100ask_imx6ull-sdk/ToolChain/arm-buildroot-linux-gnueabihf_sdk-buildroot/bin/../lib/gcc/arm-buildroot-linux-gnueabihf/7.5.0/include
/home/linux/100ask/100ask_imx6ull-sdk/ToolChain/arm-buildroot-linux-gnueabihf_sdk-buildroot/bin/../lib/gcc/arm-buildroot-linux-gnueabihf/7.5.0/include-fixed
/home/linux/100ask/100ask_imx6ull-sdk/ToolChain/arm-buildroot-linux-gnueabihf_sdk-buildroot/bin/../lib/gcc/arm-buildroot-linux-gnueabihf/7.5.0/../../../../arm-buildroot-linux-gnueabihf/include
/home/linux/100ask/100ask_imx6ull-sdk/ToolChain/arm-buildroot-linux-gnueabihf_sdk-buildroot/arm-buildroot-linux-gnueabihf/sysroot/usr/include
End of search list.
... 省略 ...
LIBRARY_PATH=/home/linux/100ask/100ask_imx6ull-sdk/ToolChain/arm-buildroot-linux-gnueabihf_sdk-buildroot/bin/../lib/gcc/arm-buildroot-linux-gnueabihf/7.5.0/:/home/linux/100ask/100ask_imx6ull-sdk/ToolChain/arm-buildroot-linux-gnueabihf_sdk-buildroot/bin/../lib/gcc/:/home/linux/100ask/100ask_imx6ull-sdk/ToolChain/arm-buildroot-linux-gnueabihf_sdk-buildroot/bin/../lib/gcc/arm-buildroot-linux-gnueabihf/7.5.0/../../../../arm-buildroot-linux-gnueabihf/lib/:/home/linux/100ask/100ask_imx6ull-sdk/ToolChain/arm-buildroot-linux-gnueabihf_sdk-buildroot/arm-buildroot-linux-gnueabihf/sysroot/lib/:/home/linux/100ask/100ask_imx6ull-sdk/ToolChain/arm-buildroot-linux-gnueabihf_sdk-buildroot/arm-buildroot-linux-gnueabihf/sysroot/usr/lib/
... 省略 ...
在命令的执行结果中:
-
#include <...> search starts here:
和End of search list.
之间的信息就是编译器默认搜索的头文件路径 -
LIBRARY_PATH=
后面的信息就是编译器默认搜索的库文件路径。
3. 指定头文件路径
如果我们的头文件没有放在编译器默认的搜索路径下,那么就需要使用-I
参数指定头文件所在的路径。
假设我们源代码文件hello.c
使用的头文件分别位于/home/linux/include
和/mnt/include
两个路径下,那么在编译时需要添加-I /home/linux/include -I /mnt/include
参数。
编译命令如下:
arm-buildroot-linux-gnueabihf-gcc -I /home/linux/include -I /mnt/include -o hello hello.c
4. 指定库文件路径
如果我们的库文件没有放在编译器默认的搜索路径下,那么就需要使用-L
参数指定库文件所在的路径。
假设我们源代码文件hello.c
使用的库文件分别位于/home/linux/lib
和/mnt/lib
两个路径下,那么在编译时需要添加-L /home/linux/lib -L /mnt/lib
参数。
arm-buildroot-linux-gnueabihf-gcc -L /home/linux/lib -L /mnt/lib -o hello hello.c
5. 编译&使用自己的库文件
5.1 静态库 VS. 静态库
静态库(Static Library)和动态库(Dynamic Library)是两种常见的库类型,它们的主要区别在于编译时期和运行时期的行为不同。
静态库是在编译时期被链接到程序中的,也就是说,静态库的代码被复制到了程序中,成为程序的一部分。这意味着,程序在运行时不需要再加载静态库,因此静态库的执行速度较快。另外,静态库在程序中的使用也比较简单,只需要在编译时将其链接到程序中即可。
动态库是在程序运行时期被加载的,也就是说,动态库的代码不会被复制到程序中,而是在程序运行时从磁盘加载到内存中。这意味着,动态库的执行速度相对较慢,但是多个程序可以共享同一个动态库,从而节省内存。此外,动态库的更新和维护也更加方便,因为只需要替换动态库文件即可,不需要重新编译程序。
综上所述,静态库的优点是速度快、使用简单,缺点是占用空间较大,不便于更新和维护;动态库的优点是节省内存、方便更新和维护,缺点是速度相对较慢。
5.2 编译&使用静态库
-
假设我们要将
sub.c
和add.c
两个源文件编译成名为libnum.a
的静态库,需要执行的命令如下:arm-buildroot-linux-gnueabihf-gcc -c sub.c -o sub.o arm-buildroot-linux-gnueabihf-gcc -c add.c -o add.o arm-buildroot-linux-gnueabihf-ar rcs libnum.a sub.o add.o
静态库的命名需要是
lib[功能名称].a
,例如libnum.a
,libmath.a
等等。 -
接下来,我们在编译
hello.c
时通过-l
参数指定使用libnum.a
,同时还需要-L
参数指明libnum.a
所在的目录。arm-buildroot-linux-gnueabihf-gcc -o hello hello.c -lnum -L . (.表示libnum.a位于当前目录)
需要注意的是,使用
-l
参数时不要使用库文件的全名,只需要功能名称
即可。例如,libnum.a
对应的是num
,libmath.a
对应的是math
。 -
最后,将可执行文件
hello
拷贝到开发板上即可执行(不需要拷贝libnum.a
文件)。
5.3 编译&使用动态库
-
假设我们要将
sub.c
和add.c
两个源文件编译成名为libnum.so
的动态库,需要执行的命令如下:arm-buildroot-linux-gnueabihf-gcc -c sub.c -o sub.o arm-buildroot-linux-gnueabihf-gcc -c add.c -o add.o arm-buildroot-linux-gnueabihf-gcc -shared -o libnum.so sub.o add.o
动态库的命名需要是
lib[功能名称].so
,例如libnum.so
,libmath.so
等等。 -
接下来,我们在编译
hello.c
时通过-l
参数指定使用libnum.so
,同时还需要-L
参数指明libnum.so
所在的目录。arm-buildroot-linux-gnueabihf-gcc -o hello hello.c -lnum -L . (.表示libnum.so位于当前目录)
需要注意的是,使用
-l
参数时不要使用库文件的全名,只需要功能名称
即可。例如,libnum.so
对应的是num
,libmath.so
对应的是math
。 -
最后,需要将可执行文件
hello
和libnum.so
都拷贝到开发板上才可以执行。注意:
libsum.so
可以放到/lib
目录下,系统执行hello
时会自动去该目录下获取libsum.so
。如果想要把libsum.so
放到其他目录,那么需要将lissum.so
所在的目录添加到开发板的LD_LIBRARY_PATH
环境变量中。例如,我们把libsum.so
放到/home/linux/hello_lib
目录下,那么需要执行如下命令修改LD_LIBRARY_PATH
环境变量:export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/linux/hello_lib