Makefile简介
- 初学C/C++时,我们编译源文件时,通常直接敲命令去进行编译。但在实际项目中,源文件非常多,直接敲命令编译就不现实了,这时候就需要用到Makefile,Makefile是一个文本文件,我们只需要提前在Makefile中写好源文件的编译规则,然后直接执行make命令,就可以自动编译。
- 现在使用cmake的比较多,cmake相比于makefile,语法更加简洁,学习门槛更低,实现相同的编译功能,Makefile可能需要几十行脚本来完成,cmake只需要几行脚本就可以搞定。但鉴于可能有些老项目或者部分公司依旧使用makefile,所以我们还是得对此熟悉。
Makefile语法
- Makefile有三大要素:目标、依赖、规则命令
- 目标:我们要生成的最终文件
- 依赖:生成目标文件要依赖的文件
- 规则命令:要生成目标文件所执行的命令
- 语法
-
目标:依赖 规则命令 - 注:规则命令前面必须要有Tab键
-
简单使用
- 目前有以下源文件
-
├── main.cpp ├── Makefile ├── myadd.cpp ├── myadd.h ├── myminus.cpp └── myminus.h
版本一
-
# 生成最终可执行文件的文件名和需要的依赖文件 res:main.o myadd.o myminus.o # 生成最终可执行文件需要执行的命令 g++ main.o myadd.o myminus.o -o res # 生成中间文件main.o需要的源文件 main.o:main.cpp # 生成中间文件main.o需要执行的命令 g++ -c main.cpp myadd.o:myadd.cpp g++ -c myadd.cpp myminus.o:myminus.cpp g++ -c myminus.cpp # 执行清理操作 clean: rm *.o - 直接执行make命令就可以生成最终可执行文件res
-
root@ubuntu:/home/lng/makefiledir# make g++ -c main.cpp g++ -c myadd.cpp g++ -c myminus.cpp g++ main.o myadd.o myminus.o -o res root@ubuntu:/home/lng/makefiledir# ls main.cpp main.o Makefile myadd.cpp myadd.h myadd.o myminus.cpp myminus.h myminus.o res root@ubuntu:/home/lng/makefiledir# - 一般*.o文件是不需要的,可以执行make clean命令来清除*.o文件
-
root@ubuntu:/home/lng/makefiledir# make clean rm *.o root@ubuntu:/home/lng/makefiledir# ls main.cpp Makefile myadd.cpp myadd.h myminus.cpp myminus.h res root@ubuntu:/home/lng/makefiledir# - 备注
- 可能有人会有疑问,为什么一定要生成中间文件*.o, 我们平常使用命令编译时,都是直接用源文件生成可执行文件。
- 当然可以不用生成*.o文件,使用以下命令,直接用源文件生成可执行文件
-
res:main.cpp myadd.cpp myminus.cpp g++ main.cpp myadd.cpp myminus.cpp -o res - 但这样就会存在一个问题,一旦我们修改任何一个源文件,所有的文件都重新编译。在一些大型项目中,编译是非常耗时的,每修改一个源文件,都去重新编译,这将大大降低工作效率。因此我们通常都是先生成中间文件*.o, 当我们修改其中一个源文件时,只需要编译修改的文件,其他文件都不需要重新编译。
版本二
- 在makefile中允许我们使用变量,可以对Makefile内容进行简化
-
# 对变量赋值 Target=res Objs=main.o myadd.o myminus.o Src=main.cpp myadd.cpp myminus.cpp # 取出变量中的值 $(Target):$(Objs) g++ $(Objs) -o $(Target) $(Objs):$(Src) g++ -c $(Src) clean: rm *.o - 这个版本的Makefile与版本一的效果完全一样,但代码量更少,也更简洁。
版本三
- 目前还存在一个问题,就是我们一旦要添加新的源文件,必须修改Makefile,有没有一种写法,在添加源文件时不需要修改Makefile?当然也有。
- 首先需要介绍两个函数和四个变量
- 函数
- wildcard:进行文件匹配
- patsubst:内容替换
- 变量
- $@ : 目标
- $^ : 全部依赖
- $< : 第一个依赖
- $? : 第一个变化的
-
Target=res # 获取当前目录下所有源文件 Src:=$(wildcard *.cpp) # 将所有*.cpp文件替换为*.o文件。Objs变量中就保存了所有*.o文件名 Objs:=$(patsubst %.cpp,%.o, $(Src)) $(Target):$(Objs) g++ $(Objs) -o $(Target) *.o:*.cpp # 相当于 g++ -c *.cpp -o *.o g++ -c $< -o $@ clean: rm *.o - 通过变量和函数我们就可以自动获取文件名,不用再去手动进行赋值。
指定头文件和库文件
- 目录结构如下
-
├── include │ ├── myadd.h │ ├── myminus.h │ └── mymult.h ├── lib │ └── libmymult.so ├── Makefile └── src ├── main.cpp ├── myadd.cpp └── myminus.cpp - Makefile
-
# 指定编译器 CC=g++ #指定编译选项 CFLAGS=-Wall -g Target=res Src:=$(wildcard ./src/*.cpp) Objs:=$(patsubst %.cpp,%.o, $(Src)) #指定头文件位置 INCLUDES = -I ./include #指定库文件 LIBS=-L ./lib -lmymult $(Target):$(Objs) echo $(Objs) @mkdir -p output $(CC) $(Objs) $(LIBS) -o output/$(Target) %.o:%.cpp $(CC) $(INCLUDES) $(CFLAGS) -c $< -o $@ clean: rm $(Objs)

Makefile是用于自动化编译的工具,当C/C++项目源文件较多时,通过编写Makefile预设编译规则,执行make命令即可批量编译。相对于直接使用命令行,Makefile节省时间,尤其是大型项目。文章介绍了Makefile的基本语法,包括目标、依赖和规则命令,并通过不同版本的示例展示其使用,包括如何简化Makefile、处理源文件变化以及添加新文件的情况。此外,还提及了cmake作为更现代的替代选择。

2244

被折叠的 条评论
为什么被折叠?



