前备知识
- gcc是开源编译器,功能强大支持交叉编译
- make是项目管理工具,方便自定义源、依赖、与目标 类似于批处理。参考链接:http://wiki.ubuntu.org.cn/%E8%B7%9F%E6%88%91%E4%B8%80%E8%B5%B7%E5%86%99Makefile:%E6%A6%82%E8%BF%B0
- .so与.a动态与静态链接库
- /xxx表示根目录下的xxx,xxx表示当前目录下的xxx,XXX/表示XXX目录下的什么,.表示当前目录
gcc的使用
gcc 文件.c -o 目标名
直接编译
分步有4步:
预处理:-E 生成.i .h都在这里处理
编译:-S 生成.s汇编代码
汇编:-c 生成.o目标文件,一个c文件对应生成一个o
链接: 可执行文件 这步导入库,实现所使用函数定义的查找
多个文件:gcc -o 目标 1.o 2.o 3.o 一个c对应一个o
静态库
编译:
为了在编译程序中正确找到库文件,静态库必须按照 lib[name].a 的规则命名,如下例中[name]=pr
先用gcc -c 编译出 .o文件
用ar进行打包:.a就是.o的打包
ar -rsv libpr.a pr1.o pr2.o
ar参数意义:
r:在库中插入模块(替换)。当插入的模块名已经在库中存在,则替换同名的模块。
s:写入一个目标文件索引到库中,或者更新一个存在的目标文件索引。
v:该选项用来显示执行操作选项的附加信息。
t:显示库的模块表清单。一般只显示模块名。
使用:
-l连接
gcc -o main main.c -L./ -lpr
-L 及 -l 参数放在后面。其中,-L 加载库文件路径,-l 指明库文件名字,-l会对名字加前后缀。默认为动态连接找libxx.so,无时静态用.a
直接连接
gcc main.c libpr.a 将俩文件链接
动态库
编译:
gcc -fPIC -shared -o xxx.so pr1.c
-shared 表示生成动态链接库 不加默认生成可执行文件
源需要.c
-fPIC表示位置独立的代码,实现完全动态
隐式使用:
直接连接
gcc -o main main.c xxx.so
-l连接,同样省略了前后缀,.a与.so同时存在的话默认.so
gcc main.c -L. -lmylib
如果目录下同时有static与shared library的话,会以shared为主。 使用-static参数可以使用静态连结。注意-Bstatic就是-static,用于直接全部静态连接。但-shared却是生成动态库。
默认是动态连接,使用-static是强制为静态连接。是连接方式
默认是生成可执行文件,-shared是生成动态连接文件(so)。是生成目的
所以这俩不是你字面理解的全针对连接,而是针对文件形态,不代替默认。
这种运行时去哪里寻找.so全看系统设置的查找路径,当然可自己针对linker连接时设置
make的使用
make通过当前目录下的makefile中指定的方式编译项目
makefile的名字可以自己设定make -f
使用时明确目标在每个规则中的概念,一开始只有一个目标,后来逐渐检查中产生多目标
make规则
基本示例
A:B C
(注意是tab) 指令
A是目标文件,文件中最上层的是最终目标,如果B,C中的任意一个比A新就执行下面的处理语句。在检查B、C时,会往下查找把B、C作为目标的规则。
也就是说B、C的检查是必须的,A是基准,检查不断向下,检查结果都是语句是否执行,检查结果再层层返回向上。
类似树状结构,规则是否被处理全看上层有没有依赖它
规则查找时是全文件查找,不是只向下。
其它用法:
all : exec1 exec2
下面不加生成all的语句,用于生成多个可执行文件。
不论all存不存在,all作为目标时每次都会检查1与2的最新,只不过不存在all时最终结果一定是执行语句,可没有语句所以在不在无所谓
规则如果不位于文件最开始,能不能被执行全看上层的规则是否依赖这个规则,但如果名确make XXXX 。就会把XXXX作为主目标而不是第一个,可用来提供些命令
特殊下规则被需要检查时:
A:B C
当A不存在时,一定执行。
当A存在时,正常比较
A:
当A不存在时,一定执行
当A存在时,一定不执行
.PHONY : A用于指定A用于假想不用检查是否存在一定更新
make命令
每条规则中的命令和操作系统Shell的命令行是一致的。make会按顺序一条一条的执行命令,每条命令的开头必须以[Tab]键开头,除非,命令是紧跟在依赖规则后面的分号后的。在命令行之间中的空格或是空行会被忽略,但是如果该空格或空行是以Tab键开头的,那么make会认为其是一个空命令。
当我们用“@”字符在命令行前,那么,这个命令将不被make显示出来
当依赖目标新于目标时,也就是当规则的目标需要被更新时,make会一条一条的执行其后的命令。需要注意的是,如果你要让上一条命令的结果应用在下一条命令时,你应该使用分号分隔这两条命令。比如你的第一条命令是cd命令,你希望第二条命令得在cd之后的基础上运行,那么你就不能把这两条命令写在两行上,而应该把这两条命令写在一行上,用分号分隔
make变量
基本可以理解为存了一串字符
环境变量在 make 过程中被解释成 make 的变量。这些变量是大小写敏感的
声明:A=XXXXXX
使用:$(A)
make与c之间define变量互通的
定义好的内部变量:
$@:当前规则的目的文件名
$<:依靠列表中的第一个依靠文件
$^:整个依靠的列表
在命令中可替代,比如上面的:
同时,可以在使用make命令时指定参数的值:
make的时候,打印信息是age=12
当你使用make AGE=20时,打印的信息就是:age=20
make函数
使用函数:
$(函数名 参1,参2,….)
常用的:
$(wildcard *.c)
返回所有.c结尾的文件
$(patsubst %.c,%.o,变量X)
第一个是一个需要匹配的 式样,第二个表示用什么来替换它,第三个是一个需要被处理的由空格分隔的字列。在这里.o替换.c。注意这里的 % 符号将匹 配一个或多个字符,而它每次所匹配的字串叫做一个‘柄’(stem) 。在第二个参数里, % 被解读成用第一参数所匹配的那个柄。
make隐含规则
“隐含规则”会使用一些我们系统变量,我们可以改变这些系统变量的值来定制隐含规则的运行时的参数。
当目标规则不存在时,make会在自己的“隐含规则”库中寻找可以用的规则,如果找到,那么就会使用。如果找不到规则且文件存在,就会判断,否则报错。
|
|
这俩句不必要写,自动使用
其它
include
include 文件名
用于包含一个文件,同时检查文件(纳入目标)。
gcc -M
gcc -M main.c
输出一个用于make的规则,该规则描述了这个源文件的依赖关系。预编译器输出的这个make规则包含名字与原文件相同的目标文件,冒号和自己与所有include文件的名字
\用于换行
-MM
与-M相似,只是不包含系统头文件
:=
A = foo
B = $(A)
现在 B 是 $(A) ,而 $(A) 是 ‘foo’ 。
A = bar
现在 B 仍然是 $(A) ,但它的值已随着变成 ‘bar’ 了。
B := $(A)
现在 B 的值是 ‘bar’ 。
A = foo
B 的值仍然是 ‘bar’ 。
#
make 会忽略在 # 符号后面直到那一行结束的所有文字。
示例
|
|