博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Linux之Makefile
阅读量:5235 次
发布时间:2019-06-14

本文共 2944 字,大约阅读时间需要 9 分钟。

Makefile文件的作用是指导make程序该如何工作。

 

make的工作原理

当我们只输入make命令的工作流程是:

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

如果在找寻的过程中,出现了被依赖的文件找不到的错误,那么make就会直接退出,并报错。

如果在一条依赖链中,比如:A依赖B,B依赖C,C依赖D。那么当D更新后,make发现D比C新则会重新构建C,以此类推,最终A也会被更新。

 

Makefile文件的语法组成

基本的结构形式:

1 target: prerequisites2     command3     command4     ...

说明:

target:可以是任何类型的文件,也可以是一个标签(Label),或叫作“伪目标”,这个我们一会儿再讲。
prerequisites:就是要生成target所需要的文件、目标。
command:当prerequisites比target要新,就会执行这里定义的动作(任意的Shell命令)

其实就是一个文件的依赖关系处理,也就是说,target目标依赖于prerequisites中的文件,其生成规则定义在command中。说白一点就是说,prerequisites中如果有任何一个及以上的文件比target文件要新的话,command所定义的命令就会被执行。这就是Makefile的规则。也是Makefile中最核心的内容。

 

Makefile中使用变量

我们通过脚本实验来了解定义变量的几种形式:

1 .PHONY: target 2  3 VAR_0:=$(VAR) 4 VAR_1=$(VAR) 5 VAR="hello world" 6 VAR2:=$(VAR) 7 VAR="hello world2" 8 VAR3="hello world3" 9 VAR3?=$(VAR)10 VAR_0+="abc"11 VAR_1+="abc"12 13 target:14     @echo $(VAR_0)15     @echo $(VAR_1)16     @echo $(VAR)17     @echo $(VAR2)18     @echo $(VAR3)

$ make

abc
hello world2 abc
hello world2
hello world
hello world3
=   直接赋值,比较直观。值得说的是当赋值的是变量时,如果引用的变量不存在,那么赋值的是空字符串。
:=  延迟引用变量,也就是说只有当脚本中使用到VAR2变量时,make才会去找被引用的VAR变量的值。
?= 条件赋值,被称为条件赋值是因为:只有此变量在之前没有被赋值的情况下才会对这个变量进行赋值。
+= 追加赋值,上面的例子的输出很明显了。

Makefile中也可以直接使用shell进程的环境变量,比如可以在Makefile中输出@echo $(PATH)等等。

make自动推导
首先让我在本地创建几个文件:

$ vim lib1.h

1 #ifndef __LIB1_H__2 #define __LIB1_H__3 void lib1();4 #endif

$ vim lib1.c

1 #include 
2 void lib1()3 {4 printf("this is lib1\n");5 }

$ vim lib2.h

1 #ifndef __LIB2_H__2 #define __LIB2_H__3 void lib2();4 #endif

$ vim lib2.c

1 #include 
2 void lib2()3 {4 printf("this is lib2\n");5 }

$ vim main.c

1 #include "lib1.h"2 #include "lib2.h"3 4 int main(int argc, char *argv[]) {5     lib1();6     lib2();7     return 0;8 }

$ vim Makefile

1 .PHONY: clean 2  3 CC=gcc 4 CFLAGS=-O3 5 OBJS=main.o lib1.o lib2.o 6 LIB=libtest.a 7 BIN=main 8  9 $(BIN): $(LIB) $(BIN).o 10     $(CC) $(CFLAGS) -o $@ $(BIN).o -L. -Wl,-Bstatic -ltest  -Wl,-Bdynamic11     echo $?12 13 %.o: %.c 14     $(CC) -c -o $*.o $*.c15 16 $(LIB): lib1.o lib2.o17     ar crv $@ $^18 19 clean:20     rm -rf $(BIN)21     rm -rf $(OBJS)22     rm -rf $(LIB)

$ make

大家可以自行改动代码进行测试!

说一下.PHONY的作用,.PHONY后面写的是伪目标,也就是说这种目标只是占用一个符号一个名字而已,无论当前目录下是否有clean文件,不会对比是否最新,只要执行make clean,clean目标下面定义的命令永远都会执行!

$@:表示目标文件名称
$<:prerequisites依赖列表中的第一个依赖的名字
$?:所有比目标新的依赖文件名称的集合,以空格分隔
$^:当前目标中依赖的所有文件,它并不关心这些文件是不是比目标文件新。然而,重复的依赖文件名会被移除。这会在你需要将所有的依赖文件输出到屏幕时变得非常有用
$+:很像$^,也是所有依赖文件的集合,但是它不去除重复的依赖
$*:匹配目标模式中“%”之前的部分

好方法和技巧:
1. 引入外部Makefile
2. 变量值替换
从一个已有的宏创建一个新宏并非不可能。例如宏SRC代表一系列的源文件,你希望生成一个对应的目标文件宏OBJ。要这样做,你只需要指定OBJ = SRC,除了扩展名不同以外:OBJ = $(SRC:.c=.o)

陷阱:
1. 环境变量 MAKEFILES
2. 万能通配符的陷阱
3. 环境变量 VPATH

 

本文会继续不断打磨、完善!

转载于:https://www.cnblogs.com/yuyifeiyang/p/9455809.html

你可能感兴趣的文章
【BZOJ4516】生成魔咒(后缀自动机)
查看>>
【BZOJ3052】【UOJ#58】【WC2013】糖果公园(树上莫队)
查看>>
荷兰国旗问题
查看>>
Process 启动参数问题
查看>>
提高PHP性能的10条建议
查看>>
我,不会吵,不会闹,心痛了用沉默代替
查看>>
svn“Previous operation has not finished; run 'cleanup' if it was interrupted“报错的解决方法...
查看>>
项目经理面试中可能遇到的问题(持续更新)
查看>>
【转】总结前端面试过程中最容易出现的问题
查看>>
Java- 简单了解线程 生产者与消费者问题(三)
查看>>
[转]EXCEL如何使用动态公式
查看>>
NopCommerce Alipay 支付插件
查看>>
centos rancher 通过本机 docker images 新增container
查看>>
[转]ASP.NET MVC Domain Routing
查看>>
自媒体
查看>>
Linux文件系统结构
查看>>
深入理解Java虚拟机
查看>>
(算法)等概率选出m个整数
查看>>
jvm内存溢出的三种情况以及解决办法
查看>>
两个UIView添加同一个手势只有最后一个有用
查看>>