makefile-项目的编译管理

 黑马学习资源:

05-makefile基础规则_哔哩哔哩_bilibili05-makefile基础规则是黑马程序员-Linux系统编程的第41集视频,该合集共计184集,视频收藏或关注UP主,及时了解更多相关视频内容。icon-default.png?t=N7T8https://www.bilibili.com/video/BV1KE411q7ee?p=41&vd_source=f443c8140671d1c361aa817ad1193312

makefile语法:

        本质是一个脚本文件,一系列命令的集合写在一个文件中,批量处理--->把写的代码(之间是有依赖的)组织起来,通过makefile工具管理和生成可执行文件

1 基本语法:

  目标:依赖条件
  ​	命令(注意:前面是一个Tab缩进!!!)
示例先行: 一个makefile最简单的示例:

1、在maketest目录下 写一个hello.c

2、在maketest目录下 touch makefile (这个不能改,才能使用make命令)

3、vi makefile

# 一个最简单的makefile
hello:hello.c
    gcc hello.c -o hello

4、在maketest目录下执行  make

2 一个规则:

1.若想生成目标,检查规则中的依赖条件是否存在,如不存在,则寻找是否有规则用来生成该依赖文件。
2.检查规则中的目标是否需要更新,必须先检查它的所有依赖,依赖中有人一个被更新,则目标必须更新

针对上面示例,makefile稍微扩展一下,解释一个规则中第一点

hello:hello.o
	gcc hello.o -o hello
hello.o:hello.c
	gcc -c hello.c -o hello.o

也就是说,如果项目目录中没有 hello.c,但是是有hello.o,项目也可以编译成功。

下面针对项目多文件情况,解释下 一个规则中第一点 的好处:

假如有一个项目,每人负责项目中一个 .c,makefile这样写,如下:

hello:hello.c
	gcc hello.c add.c sub.c div1.c -o hello

项目开发完之后,一块编出hello。

假如后期,项目调试过程中,add.c要改;那么按照这个makefile规则,整个项目要重新编译一遍!!!如果项目过大,每次编译会花费巨长的时间。

“一个规则”把规则中间文件做细,后期没动的c文件就不用重新编译,就可以直接用第一次生成的 .o文件了

因此,下面只需要把一个makefile文件做细,就可以解决上面问题。

hello:hello.o add.o sub.o div1.o
	gcc hello.o add.o sub.o div1.o -o hello

hello.o:hello.c
	gcc -c hello.c -o hello.o

add.o:add.c
	gcc -c add.c -o add.o

sub.o:sub.c
	gcc -c sub.c -o sub.o

div1.o:div1.c
	gcc -c div1.c -o div1.o

验证:

编译工程只做了下面这两行

3 两个函数: 

makefile的2个函数

#wildcard 函数
​
函数Wildcard语法如下:
$(wildcard pattern) # pattern定义了文件名的格式, wildcard取出其中存在的文件,并把名字赋给左边的变量。这个函数wildcard会以pattern这个格式,去寻找存在的文件,返回存在文件的名字。

​示例:
src=$(wildcard ./*.c)
//匹配当前目录下的所有.c源文件,赋值给变量src(与shell类似,变量只有字符串类型)


# patsubst 函数
obj=$(patsubst %.c,%.o,$(src))
//将参数3中包含参数1的部分替换为参数2
//在例子中,就是将src中的c文件名列表替换为 .o后缀

应用这两个函数将原来的makefile优化

优化前:

hello:hello.o add.o sub.o div1.o
	gcc hello.o add.o sub.o div1.o -o hello

hello.o:hello.c
	gcc -c hello.c -o hello.o

add.o:add.c
	gcc -c add.c -o add.o

sub.o:sub.c
	gcc -c sub.c -o sub.o

div1.o:div1.c
	gcc -c div1.c -o div1.o

优化后:

src=$(wildcard ./*.c)
obj=$(patsubst %.c,%.o,$(src))

ALL:hello
hello:$(obj)
	gcc $(obj) -o hello

hello.o:hello.c
	gcc -c hello.c -o hello.o
add.o:add.c
	gcc -c add.c -o add.o
sub.o:sub.c
	gcc -c sub.c -o sub.o	
div1.o:div1.c
	gcc -c div1.c -o div1.o

clean:
	-rm -rf $(obj) hello

ps:ALL和clean

ALL:指定makefile要生成的终极目标

make只会认为第一行是自己的最终目标, 如果最终目标没有写在第一行, 通过ALL来指定。

观察下面程序,如果不写ALL:hello,makefile生成hello.o就结束。因为hello:,,,没在第一行

ALL:hello

hello.o:hello.c
	gcc -c hello.c -o hello.o
add.o:add.c
	gcc -c add.c -o add.o
sub.o:sub.c
	gcc -c sub.c -o sub.o	
div1.o:div1.c
	gcc -c div1.c -o div1.o

hello:hello.o add.o sub.o div1.o
	gcc hello.o add.o sub.o div1.o -o hello

clean:执行完make后,把 -rm -rf后面的文件删除(一般是删除中间文件,留下最终可执行文件)

clean:
	-rm -rf $(obj) hello

用法:make clean -n

(上面的clean可以认为是目标名),也可以不带,如果不带目标名的话它就想生成第一个规则里面的第一个目标。我们直接输入make的时候,会在makefile里面找到第一个目标然后执行下面的指令生成第一个目标。而当我们输入make clean的时候,就会在Makefile里面找到clean这个目标,然后执行里面的命令。

小注意:

-n 表示预执行,将将要执行的删除命令显示在命令行,先执行下这个是,为了防止删除原码。

rm前面的横杠表示出错(文件不存在)仍然执行

4 三个自动变量: 

  目标:依赖条件
  ​	命令(注意:前面是一个Tab缩进!!!)
  • $@:用于在规则的命令部分中,表示规则中的目标
  • $^:用于在规则的命令部分中,表示所有依赖条件
  • $<:用于在规则的命令部分中,表示第一个依赖条件

那进一步优化上面“两个函数部分”的makefile

应用优化前:

src=$(wildcard ./*.c)
obj=$(patsubst %.c,%.o,$(src))

ALL:hello
hello:$(obj)
	gcc $(obj) -o hello

hello.o:hello.c
	gcc -c hello.c -o hello.o
add.o:add.c
	gcc -c add.c -o add.o
sub.o:sub.c
	gcc -c sub.c -o sub.o	
div1.o:div1.c
	gcc -c div1.c -o div1.o

clean:
	-rm -rf $(obj) hello

应用优化后:

 
src=$(wildcard ./*.c)
obj=$(patsubst %.c,%.o,$(src))

ALL:hello
hello:$(obj)
	gcc $^ -o $@			#目标依赖于所有依赖条件

hello.o:hello.c
	gcc -c $< -o $@			#目标依赖于第一个(唯一一个)依赖条件
add.o:add.c
	gcc -c $< -o $@			#目标依赖于第一个(唯一一个)依赖条件
sub.o:sub.c
	gcc -c $< -o $@			#目标依赖于第一个(唯一一个)依赖条件
div1.o:div1.c
	gcc -c $< -o $@			#目标依赖于第一个(唯一一个)依赖条件

clean:
	-rm -rf $(obj) hello

模式规则

鉴于上面的都是某个.o文件依赖于某个.c文件的形式,可以将其总结为一个模式规则:

%.o:%.c
	gcc -c $< -o $@

应用模式规则后,makefile优化如下:

src=$(wildcard ./*.c)
obj=$(patsubst %.c,%.o,$(src))

ALL:hello
hello:$(obj)
	gcc $^ -o $@

%.o:%.c
	gcc -c $< -o $@

clean:
	-rm -rf $(obj) hello
模式规则扩展:

我们这个例子中的模式规则知识针对当前例子。更复杂的项目或许有不止一个模式规则。这个时候应该指定模式规则的使用范围。

(1)静态模式规则(制定了模式规则给谁用):

$(obj): %.o: %.c	gcc -c $< -o $@

其他

(1)加入伪目标(为了防止目录下可能有clean和ALL的同名文件,导致make认为makefile中的clean已经生成出来了,而不执行clean中的命令。给一个伪目标,让其不受干扰的执行):

 我们在该目录下创建一个名为“clean”的文件,然后重新执行:make然后make clean,结果(会有下面的提示:):

make: `clean' is up to date.(MD,clean文件已经是最新啦!!!)

它根本没有执行我们的删除操作,这是为什么呢?

我们之前说,一个规则能够执行的条件:

1).目标文件直接就不存在

2).依赖文件比目标新。
现在我们的目录里面有名为“clean”的文件,目标文件是有的,并且没有依赖文件,没有办法判断依赖文件的时间。这种写法会导致:有同名的"clean"文件时,就不会执行make clean操作。

解决办法:我们需要把clean定义为假想目标,用关键字PHONY。

.PHONY: clean	  //把clean定义为假想目标。既然是假想的目标,意思就是想说,目标clean还不存在,因此他就不用判断名为“clean”的文件是否存在,而直接执行下面的命令

然后在Makfile结尾添加.PHONY: clean语句,重新执行:make clean,就会执行删除操作。而且如果makefile中有名为clean的目标文件的话,写法不一样,也不会造成冲突。

ALL也同理

.PHONY:clean ALL

(2)加入常用参数(-Wall, -I, -l, -L, -g),形成了最终版本:

我们之前在学习使用gcc编译的时候,有一些参数。这些参数如何在makefile中使用?

src=$(wildcard ./*.c)
obj=$(patsubst %.c,%.o,$(src))

myArgs=-Wall -g

ALL:hello
hello:$(obj)
	gcc $^ -o $@ $(myArgs)

%.o:%.c
	gcc -c $< -o $@ $(myArgs)
clean:
	-rm -rf $(obj) hello

.PHONY:clean ALL

makefile学习【实操】

源码结构:

gyw@gyw-virtual-machine:~/桌面/动态库制作练习/LD_TEST$ tree
.
├── include
│   └── ld_test.h
├── makefile
├── object
└── source
    ├── add.c
    ├── ld_test.c
    └── sub.c

3 directories, 5 files

  编写makefile

      1 src=$(wildcard ./source/*.c)
      2 obj=$(patsubst ./source/%.c,./object/%.o,$(src))
      3 
      4 FALGS=-Wall -g
        INLUCDE_PATH=include
      5 
      6 ALL:comput
      7 comput:$(obj)
      8     gcc $^ -o $@ ${FALGS}
      9 
     10 $(obj):./object/%.o:./source/%.c
     11     gcc -c $< -o $@ ${FALGS} -I ${INLUCDE_PATH}
     12 clean:
     13     #-rm -rf $(obj) comput
     14 
     15 .PHONY:clean ALL

注意:line 2:对 函数使用,%通配符方面的理解,前面带目录

make

查看工程

gyw@gyw-virtual-machine:~/桌面/动态库制作练习/LD_TEST$ tree
.
├── comput
├── include
│   └── ld_test.h
├── makefile
├── object
│   ├── add.o
│   ├── ld_test.o
│   └── sub.o
└── source
    ├── add.c
    ├── ld_test.c
    └── sub.c

3 directories, 9 files

总结:make和makefile的关系

       在开发一个系统时,一般是将一个系统分成几个模块,这样做提高了系统的可维护性,但由于各个模块间不可避免存在关联,所以当一个模块改动后,其他模块也许会有所更新,这种开发方法对小系统来说,手工编译连接是没问题,但是如果是一个大系统,存在很多个模块,那么手工编译的方法就不适用了,过于繁琐。

        为此,在Linux系统中,专门提供了一个make命令来自动维护目标文件。

        与手工编译和连接相比,make命令的优点在于他只重新编译修改过的源文件(在Linux中,一个文件被创建或更新后有一个最后修改时间,make命令就是通过这个最后修改时间来判断此文件是否被修改),而对没修改的文件则置之不理,并且make命令不会漏掉一个需要更新的文件。

makefile中主要写:文件间依赖关系,目标文件,编译命令。      

         make和makefile的关系是:make是一个命令工具,是一个解释makefile中指令的命令工具,一般来说,大多数的IDE都有这个命令。

        当你需要在一些源文件改变后运行或更新一个任务时,通常会用到 make 工具。make 工具需要读取一个 Makefile(或 makefile)文件,在该文件中定义了一系列需要执行的任务。

        makefile就像一首歌的乐谱,make工具就像指挥家,指挥家根据乐谱指挥整个乐团怎么样演奏,make工具就根据makefile中的命令进行编译和链接的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值