Makefile基本使用

在Linux下使用makefile,可以实现自动化编译。基makfile定义了一系列的规则来指定,哪些文件需
要先编译,哪些要后编译。

如下图,我的文件下有两个.c文件,一个.h文件。
在这里插入图片描述
内容如下。
在这里插入图片描述

正常在命令行下,可以使用下面的命令:

gcc main.c list.c -o mian.out

生成可执行文件。
在这里插入图片描述
如果要生成.o文件或其它文件,会敲很多的命令。来一步步生成,makefile可以让我们把所有生成文件的命令都放在一个文件下。到时候只需要输入命令make就可以完成。

基本使用和规则

在与文件同级目录下创建一个makefile文件或Makefile文件。格式如下。

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

target是目标文件(obj),也可以是一个执行文件,还可以是一个标签(label)。

target这一个或多个目标文件依赖于prerequisites中的文件,其生成规则定义在command中。

prerequisites中如果有一个以上的文件比target文件要新的话,command所定义的命令就会被执行。

现在我的文件下有三个文件,main.c、list.c、head.h,要生成一个可执行文件main和两个二进制文件list.o、main.o。

main: main.o list.o
	gcc main.o list.o -o main
main.o: main.c
	gcc -c main.c -o main.o
list.o: list.c
	gcc -c list.c -o list.o

冒号前面的叫目标文件,冒号后面的是依赖文件,整句就是一个依赖关系。

把最终要生成的文件放在开头,这里是main,main的生成依赖main.o和list.o。main.o也是目标文件依赖main.c。

定义好一个依赖关系后,后面就是如何根据依赖文件生成目标文件的命令(这里是三个gcc),这个命令一定要以一个Tab键开头。(用vim的时候不能设置~/.vimrc中的set expandtab 这样会使人的tab制表变成空格,要用set noexpandtab要不然make的时候会得到***分隔符缺失。停止。)
在这里插入图片描述

输入make
在这里插入图片描述
可以看到了生成两个.o文件,一个可执行文件main。运行main和main.out效果一样。

make是如何工作的?

当我们输入完make命令后:

  1. make 先在当前目录下找makefile或Makefile文件
  2. 如果找到,它就会找了Makefile文件中的第一个目标文件(target),上例就是main文件,并把这个文件作为最终的文件。
  3. 如果main文件不存在,或者说你的main的依赖更改过(体现为日期更新),那它就会去执行后面的命令来生成main
  4. 然后发现main.o和list.o不存在,那就去找它们的依赖关系。直到你的文件存在,例子中就是.c文件是存在的。

由.c 文件生成了.o文件,由.o文件生成可执行文件。make后面的三句话体现了这一点。是不是有点像递归?

clean

好了,现在你生成完了,你要是想把这三个文件删除岂不是很麻烦,makefile也可以帮你。你可以在最后加上一行。

main: main.o list.o
	gcc main.o list.o -o main
main.o: main.c
	gcc -c main.c -o main.o
list.o: list.c
	gcc -c list.c -o list.o
clean:
	rm -i main.o list.o main

这里有一个不同点,就是clean也是目标,但是我们不需要生成clean这个文件,我们管这种目标叫伪目标。它一般没有依赖文件。
执行clean,要把clean在make后写出来:

make clean

在这里插入图片描述
为了将伪目标与要生成为文件的目标作一个区分,可以用一个声明来声明,它是一个伪目标。要不然搞不好会给你生成一个伪目标的文件。或者你本身目录下就有与这个伪目标同名的文件。

main: main.o list.o
	gcc main.o list.o -o main
main.o: main.c
	gcc -c main.c -o main.o
list.o: list.c
	gcc -c list.c -o list.o

.PHONY: clean
clean:
	rm -i main.o list.o main

.PHONY: 伪目标名,就表示这个目标是一个伪目标。

自动推导

可见,我们的.o文件生成,只依赖.c文件,好像所有的文件都是这样,所以make提供了自动推导这种功能。找.o文件时会通过.c文件自动生成,也就是不需要你再去写相关的命令了。

main: main.o list.o
	gcc main.o list.o -o main
	
.PHONY: clean
clean:
	rm -i main.o list.o main

在这里插入图片描述
可以看出make给我自动生成了两个所需要的.o文件。

变量

自定义变量

可以将文件名给一些变量,这样就不用每次用都写文件名了。

  1. 变量要在声明时给初值,可以是多个值
  2. 使用时在变量前加上$,这时最好将变量用()包起来
默认变量

在Makefile中
CC = gcc

自动化变量
$@:表示目标文件集合
$<:表示依赖文件中的第一个
$^:表示依赖文件集合

makefile里的变量与C语言中的宏一样,都是直接替换。下面的$(target)就是直接替换成了main。

objects = main.o list.o
target = main

$(target):  $(objects)
    $(CC) $^ -o $@

.PHONY: clean
clean:
    rm -i main.o list.o main

根据替换原则:$^=main.o list.o $@=main

$(target):  $(objects) = main: main.o list.o
    $(CC) $^ -o $@ = gcc main.o list.o -o main

在这里插入图片描述

函数

当然,人类的极致就是追求懒。如果有很多.o文件不得敲死我,怎么办,有没有什么办法。自动给我找到所有的.o文件?

真有:
这里有两个函数:

  1. wildcard 通配符函数
  2. patsubst 模式字符串替换函数
obj = $(wildcard *.c)
objects = $(patsubst %.c, %.o, $(obj))
target = main

$(target):  $(objects)
    $(CC) $^ -o $@

.PHONY: clean
clean:
    rm -i main.o list.o main
  • 函数在使用时,要用$(函数)包起来,函数名后面是空格,参数之间用逗号隔开。
  • wildcard *c 函数的意思是找到当前目录下所有.c文件,这个*是一个通配符,可以理解为任意字符。

可能有人想既然*表示通配符为什么不能这么写呢?

obj = *.c

这样obj就是所有的以.c为后缀的文件了吗?
不对,因为makefile里的变量就相当于c语言中的宏,所以$(obj) = *.c
所以才需要函数。

  • patsubst %.c, %o, $(obj)意思是把obj里所有的.c替换成.o。%与*有点像,意思是匹配零或若干个字符。但是%只找makefile文件中符合条件的,*找系统目录中符合条件的。

所有这两句在例子中等于

obj = $(wildcard *.c) = main.c list.c
objects = $(patsubst %.c, %.o, $(obj)) = main.o list.o

在这里插入图片描述
Makefile里少了.o的生成规则总是觉得少了什么。但又不想一个个敲可以用静态模式。

静态模式

<targets> : <target-pattern> : <prereq-patterns...>
	<commands>
	...
  1. targets定义了一系列的目标文件,可以有通配符,是目标的一个集合
  2. target-pattern指明了targets的模式,也就是目标的一个集合的模式、
  3. prereq-patterns是目标的依赖模式,它对target-pattern再进行一次依赖目标的定义

比如:

$(objects) : %.o : %.c
	$(CC) -c $< -o $@

意思是目标集合在objects中找,找全部是以.o结尾的文件构成了目标集合。依赖就是对.o这个目标集合的二次定义,就是将.o换成.c的一个集合构成了依赖集合。

上面的规则展开等价于下面的规则。

main.o: main.c
	gcc -c main.c -o main.o
list.o: list.c
	gcc -c list.c -o list.o

目标模式和依赖模式都应该有%。

obj = $(wildcard *.c)
objects = $(patsubst %.c, %.o, $(obj))
target = main

$(target):  $(objects)
    $(CC) $^ -o $@

$(objects): %.o: %.c 
    $(CC) -c $< -o $@

.PHONY: clean
clean:
    rm -i main.o list.o main

在这里插入图片描述

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Makefile 是一种用于自动化构建和管理项目的工具,它通过定义规则和依赖关系来编译和链接程序。下面是一些常见的 Makefile 基本操作: 1. 定义规则:在 Makefile 中,可以使用规则来指定如何生成目标文件。规则通常由目标、依赖和命令组成。例如: ```makefile target: dependency1 dependency2 <tab>command ``` 其中 `<tab>` 表示一个制表符,而不是空格。 2. 指定默认目标:可以在 Makefile 中指定一个默认目标,以便在运行 make 命令时自动执行。例如: ```makefile all: target1 target2 ``` 默认情况下,make 命令将执行第一个目标(在这个例子中是 `target1`)。 3. 定义变量:可以在 Makefile 中定义变量,以便在多个地方重复使用。例如: ```makefile CC = gcc CFLAGS = -Wall -O2 target: dependency $(CC) $(CFLAGS) -o target dependency ``` 在这个例子中,`CC` 和 `CFLAGS` 是两个变量,可以在命令中使用 `$()` 语法来引用它们。 4. 使用通配符:可以使用通配符来匹配多个文件。例如: ```makefile sources = $(wildcard *.c) objects = $(sources:.c=.o) target: $(objects) $(CC) $(CFLAGS) -o target $(objects) ``` 在这个例子中,`$(wildcard *.c)` 将匹配当前目录下的所有 `.c` 文件,而 `$(sources:.c=.o)` 将把所有 `.c` 文件的扩展名替换为 `.o`。 5. 使用伪目标:可以定义伪目标来执行一些特殊的操作,而不是生成一个文件。例如: ```makefile .PHONY: clean clean: rm -f target $(objects) ``` 在这个例子中,`.PHONY` 声明了 `clean` 是一个伪目标,`rm -f target $(objects)` 命令将在执行 `make clean` 时执行,用于删除生成的目标文件。 这些是 Makefile 的一些基本操作,你可以根据实际需求和项目结构进行进一步的定制和扩展。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

CCPigSnail

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值