makefile学习 (1)

网友投稿 632 2022-08-26

makefile学习 (1)

makefile学习 (1)

学习自《跟我一起写Makefile》,《linux网络编程》 生成可执行文件的过程分为编译,汇编,链接等阶段,make工程管理器可以根据文件的时间戳发现更新后的文件有选择的编译,通过读入规则文件来执行编译工作。在整个过程中,make工程管理器调用了gcc编译器。

编译和链接

target ... : prerequisites ... command ... ...

prerequisites(依赖文件)中如果有一个以上的文件比target文件要新的话,command所定义的命令就会被执行。make会比较targets文件和prerequisites文件的修改日期,如果prerequisites文件的日期要比targets文件的日期要新,或者target不存在的话,那么,make就会执行后续定义的命令。 clean不是一个文件,它只不过是一个动作名字。要执行其后的命令(不仅用于clean,其他lable同样适用),就要在make命令后明显得指出这个lable的名字。我们可以在一个makefile中定义程序的打包,程序的备份,等等。 注意:第一行的target是总的目标,后面的都是进行依赖处理。

gcc的-c和-o

gcc -c test.c #编译test.c文件得到test.ogcc -c test.c -o test.o #同上gcc -o test test.o #链接test.o可执行文件gcc -o test test.c #将test.c编译并连接成可执行文件gcc test.c -o test #同上

make工作方式

输入make命令后: 1. make会在当前目录下找名字叫“Makefile”或“makefile”的文件。 2. 如果找到,它会找文件中的第一个目标文件(target),并把这个文件作为最终的目标文件。 3. 如果target文件不存在,或是所依赖的后面的 .o 文件的文件修改时间要比target文件新,那么,他就会执行后面所定义的命令来生成target文件。 4. 如果target所依赖的.o文件也不存在,那么make会在当前文件中找目标为.o文件的依赖性,如果找到则再根据那一个规则生成.o文件。(这有点像一个堆栈的过程)

make只管文件的依赖性, 如果出现错误,比如最后被依赖的文件找不到,那么make就会直接退出,并报错

make变量

3 个预定义变量介绍:

1. $@ 表示要生成的目标 2. $^ 表示全部的依赖文件 3. $<

4个参数:

1. -o 指定目标文件gcc sources/main.c -o bin/main2. -c 编译的时候只生产目标文件不链接gcc -c sources/main.c -o obj/main.o3. -I 主要指定头文件的搜索路径gcc -I headers -c main.c -o main.o4. -l 指定静态库gcc -lpthread

使用$(var)来代替变量var的值,用“$$”来表示$。 变量可以嵌套$($(x)) 可以使用“+=”操作符给变量追加值。 更多变量说明,

makefile的注释:

单行: 行首# 多行: 行首# 行尾\ 比如:

#PWD := $(shell pwd)#INC := $(PWD)/inc\DEBUG := -g\MAIN_OBJ := $(PWD)/*.o\ADD_OBJ := $(PWD)/add/*.o\SUB_OBJ := $(PWD)/sub/*.o\OBJ := $(SUB_OBJ) $(ADD_OBJ) $(MAIN_OBJ)\\main: $(OBJ)\ cc -o main $(OBJ) \\$(MAIN_OBJ) : $(PWD)/*.c $(INC)/*.h\$(ADD_OBJ) : $(PWD)/add/*.c\$SUB_OBJ) : $(PWD)/sub/*.c\

make自动推导

make的“隐晦规则”: 只要make看到一个[.o]文件,它就会自动的把[.c]文件加在依赖关系中,并推导出相关的命令。

关于tab缩进

在编写makefile的过程中,某一行出现红色那就要小心了,因为出现了错误。 编写makefile相关的vimrc配置:

set noexpandtabset softtabstop=4

来自《linux网络编程》的一个加法、减法的工程例子:

文件目录稍作改动。

相关代码

add_float.c

float add_float(float a, float b){ return

add_int.c

int add_int(int a, int b){ return

sub_float.c

float sub_float(float a, float b){ return

sub_int.c:

int sub_int(int a, int b){ return

add.h

#ifndef __ADD_H__#defineextern int add_int(int a, int b);extern float add_float(float a, float b);#endif

sub.h

#ifndef __SUB_H__#defineextern float sub_float(float a, float b);extern int sub_int(int a, int b);#endif

main.c

#include #include "./inc/add.h"#include "./inc/sub.h"int main(void){ int input = 0; int a = 10, b = 12; float x= 1.23456,y = 9.87654321; printf("int a+b IS:%d %d\n",a+b,add_int(a,b)); printf("int a-b IS:%d %d\n",a-b,sub_int(a,b)); printf("float x+y IS:%f %f\n",x+y,add_float(x,y)); printf("float x-y IS:%f %f\n",x-y,sub_float(x,y)); return 0; }

现在,写一个简单的makefile,使得产生的.o文件都在mkfl下,然后链接即可。

PWD := $(shell pwd)INC := $(PWD)/incADD := $(PWD)/addSUB := $(PWD)/subDEBUG := -gOBJ := $(PWD)/*.o.PHONY: allall: lib gcc -o main $(OBJ).PHONY: liblib: cc -c $(ADD)/*.c cc -c $(SUB)/*.c cc -c $(PWD)/main.c $(INC)/*.h.PHONY:cleanclean:#make clean -C $(PWD)

清洁文件

删除命令: ​​​-rm -f main *.o​​​ 在rm命令前面加了一个小减号的意思就是,也许某些文件出现问题,但不要管,继续做后面的事。clean从来都是放在文件的最后

makefile的规则

显式规则:各种依赖关系和命令 隐式规则:利用make的自动推导

特定的makefile文件

例如写了一个makefile_special 那么可以提示make寻找并解释它 ​​​make -f makefile_special​​

makefile的嵌套

​​include ​​​ 可以在本makefile中引入其他makefile。 在include前面加上’-‘也能暂时屏蔽掉错误信息,继续执行后面的东西。

通配符的展开和替换

如果想要通配符在变量中展开,那么我们需要关键字 wildcard(拓展通配符). 确定所有的.o文件 ​​​object := $(wildcard *.o)​​​ 如果想要进行通配集合的替换,那么需要关键字patsubst 确定所有.c文件对应的.o文件 ​​​object := $(pubsubst %.c, %.o, $(wildcard *.c))​​​ [%为makefile的规则通配符]

文件搜索

​​vpath ​​​ 关键字vpath用于搜索符合pattern模式的文件,且在指定的路径下进行搜索。 比如 ​​​vpath %.c ./src​​​ 在src文件夹中查找所有的.c文件。 如果需要指定多个路径,那么我们可以一一列出。

vpath %.c dir1vpath %.c dir2vpath %.c

那么make将会先搜索dir1, 让然后是dir2, 最后是dir3

伪目标

使用​​.PHONY​​​来指定伪目标,它不是文件,仅仅是一个标签。我们可以显示的指定来进行make。 比如上面加减例子中的makefile,如果使用命令​​​make lib​​​,那么我们将生成所有的.o文件,但是可执行文件main是不会产生的。 利用伪目标生成多个可执行文件:

all : enjoy hello love.PHONY: allenjoy: enjoy.o cc enjoy.c -o enjoyhello: hello.o cc hello.c -o hello love: love.o cc love.c -o love.PHONY: cleanclean: rm -f *.o

第一行指明终极目标,后面又指出这个all是个伪目标,所以不会产生all文件。但是其依赖的三个文件被创建出来了。 当然,你也可以写一个shell脚本,来几行​​​gcc -o ...​​,这样也行。

自动搜索依赖头文件

gcc -M main.c #这会将库文件也打出来 gcc -MM main.c #仅输出include的头文件 还是以上面的加减例子做说明

cc -MM main.cmain.o: main.c inc/add.h inc/sub.h

[.d]文件中就存放对应[.c]文件的依赖关系

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:《乔丹传奇》 留下深刻印象的文字
下一篇:ANSI C (3) —— 常用系统函数
相关文章

 发表评论

暂时没有评论,来抢沙发吧~