一、系统与编译器,及编译过程:(https://wenku.baidu.com/view/000a79ff04a1b0717fd5dded.html)
预处理:gcc -E -o hello.i hello.c (生成预处理文件.i)
编译: gcc -S -o hello.s hello.i (生成汇编文件.s。-o选项可省略)
汇编: gcc -c -o hello.o hello.s (生成对象文件.o。预处理+编译+汇编。-o选项可省略)
1、(Linux下的链接 - 生成可执行文件)
链接: gcc -o hello hello. o (生成可执行文件。预处理+编译+汇编+链接。-o命名,可省略。-static链接静态库。ldd查看可执行文件的动态链接库。)
2、(SOC下的链接 - 生成bin文件)
使用链接脚本并生成elf格式文件:arm-linux-ld -T xxx.lds a.o b.o c.o -o xxx.elf (elf文件含有地址信息)
将elf文件转换成二进制bin文件:arm-linux-objcopy -O binary -S xxx.elf xxx.bin(bin文件不含地址信息)
(反汇编文件,用于调试:arm-linux-objdump -D xxx.elf > xxx.dis)
二、makefile:
1、执行make命令后,系统在当前目录找到名为makefile的文件并执行。不带( -f )参数时,默认从首个没有通配符的目标进行构造。make命令会读取整个makefile进去分析。make命令之后可带参数。用来传递参数,或直接修改makefile里面的参数值。makefile只能有一个终极目标。如果要生成多个目标,可以添加假想目表all并执行命令:make all,表示从此开始执行。all依赖于需要生成的目标,但没有规则。
2、核心规则: 当"目标文件"不存在或某个依赖文件比目标文件新,则: 执行"命令"。目标和命令的参数用空格分割。若改动头文件,则编译引用此头文件的所有文件。规则如下:
target: 依赖1 依赖2 ... ...
[TAB]命令
3、其他规则:
makefile中执行的shell命令,一行创建一个进程来执行。
可以通过接续符" ; "将多个命令组合成一个。组合的命令依次在同一个进程中被执行。
set -e指定发生错误后立即退出执行。
4、语法:
" / ":换行符。使代码易读
" % ":通配符。与*类似,可以使用$(wildcard *)来代替。
" $@ ":目标。
" $< ":第1个依赖文件。
" $^ ":所有依赖文件。
" $? ":构造所需文件列表中更新过的文件。
" $(objects) ":变量。用" = "为变量objects赋值。
" .PHONY ":假想目标。其修饰的目标,只有规则没有依赖。没有依赖的文件,makefile会忽视其规则。clean之后是没有依赖的。如果在makefile文件相同路径下有名为clean的文件,会因无法判断目标与依赖的时间关系,导致无法执行下面规则。.PHONY : clean
" export ":导出变量,路径等。同一级的另外一个makefile,无法得到export声明的内容。
" A:=xxx ":即时变量。A的值在定义时即刻确定。
" A=xxx ":延时变量。A的值在使用时确定。延时变量的值为整个makefile最后赋的值。
" A?=xxx ":延时变量。首次定义起效。如果前面已定义则忽略。
" A+=xxx ":附加。它是即时变量还是延时变量取决于前面的定义。
" echo ":显示输出,输出:命令+结果。
" @echo ":隐式输出,输出:结果。
" include xxx ":将其他文件内容原封不动的搬入当前文件,类似C语言。
5、关键词:
" VPATH = path1 : path2 : ... ":make在当前目录找不到依赖文件和目标文件的情况下,到所指定的目录中去找寻文件。
" vpath <pattern> <directories> ":为符合模式<pattern>的文件指定搜索目录<directories>。
" vpath <pattern> ":清除符合模式<pattern>的文件的搜索目录。
" vpath ":清除所有已被设置好了的文件搜索目录。
6、函数:
" $(foreach var, list,text) ":var中存放list每个值。text内必须包含“var”字段。并把每个var字段用text声明的格式替换。
" $(filter pattern...,text) ":从text中取出,符合patten格式的值。
" $(filter-out pattern...,text) ":从text中取出,不符合patten格式的值。
" $(wildcard file) ":从当前目录中,寻找与file格式或名字匹配的文件。
" $(basename file) ":取得文件的名字file(即去掉后缀)。
" $(notdir dir) ":把展开的文件dir去掉路径信息。
" $(patsubst pattern, replacement, $(list)) ":依次从列表list中取值与pattern对比。格式符合则用replacement替换。
" $(addprefix fixstring,string1 string2 ...) ":fixstring 是要添加的前缀,逗号后是一个或多个要添加前缀的子字符串。
三、简化makefile与自动生成依赖关系:
1. 大多C/C++ 编译器都支持“ -M ”等选项,自动寻找源文件中包含的头文件,生成一个依赖关系。即告诉预处理器输出适合make的规则,来描述目标文件的依赖关系。
2. 参数:
" -M ":生成文件依赖关系,包含标准库的头文件。规则显示在标准输出,需要重定向。-M会默认打开 -E 选项,作用是使得编译器在预处理结束时就停止编译。
" -MM ":生成文件依赖关系,不包含标准库的头文件。
" -MG ":要求把缺失的头文件按存在对待,并且假定他们和源程序文件在同一目录下。必须和" -M "一起使用。
" -MF file ":与" -M "或" -MM "一同使用,则把依赖关系写入名为" file "的文件中。若与" -MD "或" -MMD ",“-MF” 将覆盖写入。
" -MD ":等于" -M -MF File ",但默认关闭" -E "选项。输出文件名基于" -o "选项,并添加 .d 后缀。若没有" -o ",则使用输入的文件名。
" -MMD ":类似于" -MD ".不包含标准库的头文件。
" -MP ":生成的依赖文件里面,依赖规则中的所有.h依赖项都会在该文件中生成一个伪目标,其不依赖任何其他依赖项。该伪规则避免了删除对应的头文件但没有更新“Makefile” 来匹配新的依赖关系,导致make出错的结果。
" -MT ":在生成的依赖文件中,指定依赖规则中的目标。
如下面的例子:
%.d : %.c
@set -e; \
gcc -MM $@ > $@.$$$$; \
sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \
rm -f $@.$$$$
-include seq.d
分析:
1. @set -e:@关键字告诉make不输出该行命令;set -e表示当后面命令的返回值非0时立即退出。
2. gcc -MM $< > $@.$$$$:根据源文件生成依赖关系,并保存到临时文件中。" $< "为第一个依赖文件。" $$$$ "为字符串" $$ "。makefile中" $ "为特殊字符(即使在单引号中)。需要用" $$ "来转义,来得到" $ "。" $$ "是shell的特殊变量,它的值为当前进程号。为保证创建文件的唯一性(包括临时变量),一般使用进程号做后缀。
3. sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@:将目标文件加入依赖关系目录列表中,并保存到目标文件。" $* "为第一个依赖文件去掉后缀的名称。