注:开发板以IMX6ULL PRO开发板为例!!!
正文
一、交叉编译hello.c
1、准备工作:
要在板上运行,还是安装使用NFS会比较方便
解压工具链、设置PATH环境变量、确定编译器名称;然后才可以编译
2、gcc编译器只适合编译在Ubuntu上远行的程序
3、不同am板上的编译器名称 不同,工具链位置也不同,不同版本的编译器前缀不一样(xxx-gcc等),可以去交叉编译目录中查看
4、参考网络置指南。
5、gcc编译器的头文件默认路径为/usr/ include,arm编译器的头文件在交叉编泽器目录下的 include目录中
6、指定头文件编译的方法:
①#include “头文件” :用双引号进行头文件声明,表明在当前目录下查找头文件
或②仍使用<>声明头文件,将头文件加入默认查找路径
或③仍使用<>声明头文件,编译命令末尾加上“-I 【头件所在录】”
7、函数库的位置:
gcc编译器的库在/lib和/usr/lib中。
交叉编器中库的默认路径:进入交又编泽的目录里,执行 find -name lib可以得到 xxx/lib、xxx/usr/lib,一般来说这两个目录就是要找的路径。
二、GCC编译器
1、把c文件编译成可执行程序的过程:
.c文件 → 预处理:将要包含的头文件插入原文件中、将宏定义展开、根据条件编译命令选择要使用的代码
→ 编泽:将高级语言翻译成汇编语言,工具:ccl,x86有自己的cc1命令,ARM板也有自己的cc1命令。
→ 汇编:将汇编代码翻译成一定格式的机器代码,在Linux系统上一般表现为ELF目标文件(OBJ文件),用到的工具为as。x86有自己的as命令,ARM版也有自己的as命令,也可能是 xxxx-as(比如arm-linux-as)。
→ 链接:将上步生成的OBJ文件和系统库的OBJ文件、库文件链接起来,最终生成了可以在特定平台运行的可执行文件,用到的工具为ld或collect2。
2、gcc编译过程:
(1)用ccl命令预处理和编译.c文件,得到包含汇编码的.s文件
(2)用as命令把.s文件汇编得到.o文件,.o文件包含机器码
(3)用collect2命令将多个.o文文件和其它库文件链接起来得到可执行程序(APP)
3、编泽多个文件的方法:
①一起编译和链接:gcc -o test main.c sub.c
②分开编译,统一链接:
gcc -c -o main.o main.c
gcc -c -o sub.o sub.c
gcc -o test main.o sub.o
注意:
(1)gcc -c命令:一次性完成预处理,编译、汇编三个步聚,得到.o文件
gcc-o 命令:既可以多个.o文件链接在一起得到程序,也可以一次性对多个.c文件完成所有的四步骤得到程序(即第①方法)
(2)文件数量多时采用第②种方法
原因:当有文件到更改时,如果对全部文件重新编译一遍会很耗费时间。只需要重新编更改的文件得到新的.o文件,再链接在一起。
4、gcc常用选项:
常用选项 | 描述 |
-E | 预处理,开发过程中想快速确定某个宏可以使用“-E -dM” |
-c | 把预处理、编译、汇编都做了,但是不链接 |
-o | 指定输出文件 |
-I | 指定头文件目录 |
-L | 指定链接时库文件目录 |
-l | 指定链接哪一个库文件 |
很有用的几个参数:
gcc -E main.c // 查看预处理结果,比如头文件是哪个
gcc -E -dM main.c > 1.txt // 把所有的宏展开,存在1.txt里(方便查看)
gcc -Wp,-MD,abc.dep -c -o main.o main.c // 生成依赖文件abc.dep,后面Makefile会用
5、制作和使用动态库:
(1)在交叉编译器目录下找到交叉编译命令的前缀,如arch64 -linux -gnu-xxx
(2)进行编译:
前缀-gcc-c-o main.o main.c
前缀 -gcc -c -o sub.o sub.c
(3)生成动态库:
前缀 -gcc -shared -o libsub.so sub.o(可以是多个.o文件)
(4)使用动态库.:
前缀-gcc-o test main.o -lsub-L 【libsub.so所在目录】
注:-shared:表示输出结果是共享库类型的,-l参数:指定动态库名称,-L参数:指定库的路径
(5)运行程序test:
执行该程序时需要将动态库放在当前系统中库的默认路径中,如Ubuntu为/lib或/usr/lib;
或者改变PATH变量,把当前动态库所在目录添加进去:
export LD_LIBRARY_PATH=LD_LIBRARY_PATH:/a
注:/a为库所在路径
6、制作和使用静态库:
与动态库不同之处:
(1)生成动态库: ar crs libsub.a sub.o
(2)使用动态库:前缀-gcc-o test main.o libsub.a
如果.a文件不在当前目录下,需要指定它的路径(-L参数)
(3)运行程序:不需要把静态库放在板子上。
7、动态库与静态库
(1)通俗地讲就是把所用到的函数的目标文件打包在一起,提供相的函数的接口,供程序员使用。
(2)后缀:
Windows下,.dll后缀为动态库,.lib后缀为静态库
Linux下,.so后缀为动态库,.a后缀为静态库
(3)库的命名格式:lib+“库名称”+后缀
如 libsub.a就是一个叫sub的静态库
(4)静态库:如库文件stdio.h,是很多目标文件经过压缩打包后形成的文件。
对静态库,只需在链接时将库文件链接到可执行文件中,程序运行时就不再需要库文件了。
静态库的缺点:
①占用内存和磁盘空间:库文件需要被用到多少次,就占用多少相应的内存(n × 文件大小)
②更新麻烦:静态库变动就要更新整个文件。
(5)动态库:
程序在运行时才去链接动态库的代码,多个程序共享库的代码。一个与动态库链接的可执行文件仅仅包含它用到的函数入口地址的一个表,而不是外部函数所在目标文件的整个机器码。
基本实现思想是把程序按照模块拆分成各个相对独立部分,在程序运行时才将他们链接在一起形成一个完整的程序。
如运行程序1时,系统首先加载程序1,当发现需要Lib.o文件时,也同样加载到内存,再去加载程序2当发现也同样需要用到Lib.o文件时,则不需要重新加载Lib.o,只需要将程序2和Lib.o文件链接起来即可,内存中始终只存在一份Lib.o文件。
可使用ldd命令查看该可执行文件所依靠的动态库。
优点:
①毋庸置疑的就是节省内存;
②减少物理页面的换入换出;
③在升级某个模块时,理论上只需要将对应旧的目标文件覆盖掉即可。新版本的目标文件会被自动装载到内存中并且链接起来;
④程序在运行时可以动态的选择加载各种程序模块,实现程序的扩展。