03.编译 & makefile

2019-06-01  本文已影响0人  柏666

一、系统与编译器,及编译过程:(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' < $@.$$$$ > $@:将目标文件加入依赖关系目录列表中,并保存到目标文件。" $* "为第一个依赖文件去掉后缀的名称。


GNU make: http://www.gnu.org/software/make/manual/make.html

上一篇 下一篇

猜你喜欢

热点阅读