make和makefile入门学习记录

由于Cmake是一种自动化构建工具,在了解Cmake前我们首先需要了解什么是构建,以及make和makefile的使用方法。

在软件工程中,构建是一种将源码文件资源文件转换成可执行文件的过程。

当项目变得庞大复杂,有成百上千个源文件、头文件和库文件时,手动编译就变得不太现实了。

这时候就可以利用一些自动化的构建工具来完成整个构建过程

make和cmake是c语言中最常用的构建工具。cmake是自动化的构建工具。


一个最简单的c语言项目的构建过程:
gcc编译器编译main.c源文件生成可执行文件hello

了解Makefile

使用make和makefile构建一个简单项目

如图:

makefile基本格式规则
目标文件 : 依赖文件
    要执行的命令
    ...

 根据上面的格式我们可以写一个简单的makefile文件如下:

 hello : main.c message.c
	gcc main.c message.c -o hello

之后可以使用make hello或make来构建得到hello可执行文件。

注意,make一次后,再次使用make时会检查依赖文件是否有更新,如果没有更新就不进行任何操作,并给予提示。

这样一来,我们每次执行make都只会重新编译修改的源文件,节约了时间和计算资源。

然而上面的写法并不能达到这样的效果。(任何一个源文件更新都会把所有源文件都重新编译)

所以,规范的写法是把  编译  和  链接  分开写

hello : main.o message.o
	gcc main.o message.o -o hello

main.o : main.c
	gcc -c main.c
	
message.o : message.c
	gcc -c message.c

这样写的好处就是当我们修改了其中一个源文件后,再次make时,只需要重新编译修改了的源文件,然后再链接就可以了,而不是把所有源文件都重新编译一遍。

执行make后可以看到,先把两个源文件编译成目标文件,最后再链接。如图:

伪目标(.PHONY)

有的时候我们需要进行一些不生成文件的操作,例如清理临时文件,生成文档,打包等。这时可以使用伪目标来定义这些规则。

clean

clean是最常见的伪目标,用于清理编译过程中生成的临时文件和可执行文件。

修改makefile为如下:

hello : main.o message.o
	gcc main.o message.o -o hello

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

message.o : message.c
	gcc -c message.c

clean :
	rm -f *.o hello

以下是使用makefile中预设的clean实现清理-o目标文件和hello文件的操作

但是如果此时目录下已经有名为clean的文件存在,make clean命令会判定这里的clean是一个文件名,从而出现下面的结果(clean已经是最新的了,不会再编译):

然而,我们不能保证makefile文件中的所有 规则名 都不和当前目录下的 文件名 有重名发生。

为了避免这种现象,我们使用伪目标.PHONY来显式地告诉make clean就是一个伪目标。

.PHONY: clean

hello : main.o message.o
        gcc main.o message.o -o hello

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

message.o : message.c
        gcc -c message.c

clean :
        rm -f *.o hello

再次使用make clean,结果如下:

all

除了clean,还有一个常见地伪目标all,当我们执行make地时候,make会默认执行第一个目标(如果没有指定目标的话),但是如果我们想生成的文件不止一个的话就可以使用all。

.PHONY: clean all

all : hello world
        @echo "all done."
hello : main.o message.o
        gcc main.o message.o -o hello

world : main.- message.o
        gcc main.o message.o -o world

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

message.o : message.c
        gcc -c message.c

clean :
        rm -f *.o hello

重新编写makefile如上图。由此可以使用make all(或者如果all在makefile中是第一个目标的话,可以直接执行make,上述代码就是)直接创建两个可执行文件(否则要分别执行make hello 和make world)。

得到的结果如下:

执行make,一次创建了hello和world两个可执行文件。

变量

定义变量

在makefile中还可以定义变量,于是在后面编译命令时就可以直接使用这个变量,而不用重复写。

例如,我们使用CFLAG把一些编译选项定义成一个变量CFLAGS:-Wall -g -O2

一般也会把目标文件、源文件、中间文件等也都定义为变量,如我们可以把上面的

hello和world定义为targets

main.c message.c定义为sources

main.o message.o定义为objects

(-Wall -g -O2 是一个常见的编译器选项组合,它旨在在不牺牲调试能力的情况下,生成警告信息并优化程序性能。这是一个适合开发和测试阶段的编译选项,因为它提供了足够的调试信息,同时还能提高程序的运行效率。)

接下来我们就可以直接使用这些变量了,使用的方法为

$(变量名)

具体使用方法如下

.PHONY: clean all

CFLAGS = -Wall -g -O2
targets = hello world
sources = main.c message.c
objects = main.o message.o

all : $(targets)
        @echo "all done."
$(targets) : $(objects)
        gcc $(CFLAGS) $(objects) -o $@

main.o : main.c
        gcc $(CFLAGS) -c main.c

message.o : message.c
        gcc $(CFLAGS) -c message.c

clean :
        rm -f *.o hello

结果如下:

可以发现是可以正常编译运行的

makefile中还有一种特殊的变量叫自动变量

$@:目标文件

$<:第一个依赖文件

$^:所有依赖文件

变量的使用方法都类似,就不再演示。

利用通配符简化规则
main.o : main.c
        gcc $(CFLAGS) -c main.c

message.o : message.c
        gcc $(CFLAGS) -c message.c
这两个规则生成规则相同,只是目标文件和依赖文件不同,
而目标文件和依赖文件之间只是拓展名不相同,文件名是相同的

此时我们可以把上述规则简化为

%.o : %.c
        gcc $(CFLAGS) -c $<

执行make得到

可见修改后,make使用依然正常。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值