视频:https://www.bilibili.com/video/BV1dW411n7vk?from=search&seid=13869936161616988114
可以试想一下,有一个上百个文件的代码构成的项目,如果其中只有一个或几个文件进行修改,需要从头到尾将每一个文件都重新编译是一个比较繁琐的过程。
为此,引入了Make工程管理器的概念,工程管理器指管理较多文件,自动根据文件时间自动发现更新过的文件而减少编译的工作量,同时通过读入Makefile文件来执行大量的编译工作。
makefile规则
规则:用于说明如何生成一个或多个目标文件
makefile文件里面可以有很多规则,但是第一个规则是最终生成的文件规则。
规则格式:
target: dependency_files // 目标项:依赖项
<tab>command // 必须以tab开头,command编译命令
规则就是为了生成某一个文件的。
目标项:这个就是你要生成的文件名
依赖项:要生成目标项需要的文件
编译命令:如果有依赖项生成目标项;必须以TAB开头
在mekefile中,规则的顺序是很重要的。因为,Makefile中只应该有一个最终目标,其他的目标都是被这个目标所连带出来的,所以一定要让make知道你的最终目标是什么。一般来说,定义在Makefile中的目标可能会有很多,但是第一条规则中的目标将被确立为最终的目标
归结:
- 目标文件不存在,执行命令
- 文件已经更新了,执行命令
- Makefile的第一条规则为最终的目标。
例1:单文件
#include <stdio.h>
int main(int argc, int **argv)
{
printf("hello world\n");
return 0;
}
写成makefile如下
- 创建名称为makefile或者Makefile的文档
- 在文档中输入相应的内容
test:test.c gcc -o test test.c
- 运行makefile文件
命令行输入make
如果马上再执行make命令
这是因为,make命令会对比源文件的修改时间,如果早于目标文件,说明源文件没有修改,就不会帮你再次编译了。
例2:多文件
test.c
#include <stdio.h>
extern void sort(int *arr, int len);
extern void show(int *arr, int len);
int main(int argc, int **argv)
{
int arr[] = {
3, 2, 1, 5, 9, 8, 7};
int len = sizeof(arr) / sizeof(arr[0]);
sort(arr, len);
show(arr, len);
return 0;
}
void show(int *arr, int len)
{
for (int i = 0; i < len; i++)
{
printf("%d ", arr[i]);
}
printf("\n");
}
sequence.c
void sort(int *arr, int len)
{
for (int i = 0; i < len; i++)
{
for (int j = i; j < len; j++)
{
if (arr[i] > arr[j])
{
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
}
}
makefile
test:test.o sequence.o
gcc -o test test.o sequence.o
test.o:test.c
gcc -o test.o -c test.c
sequence.o:sequence.c
gcc -o sequence.o -c sequence.c
Makefile中特殊处理与伪目标
.PHONY
是makefile文件中的关键字,表示它后面列表中的目标均为伪目标。
如:
.PHONY:b
b:
echo 'b' # 通常用@echo "hello"
伪目标通常用在清理文件、强制重新编译等情况下。一般伪目标没有时间的检查,一旦指明了就会执行。
如:
.PHONY:clean //".PHONY"将"clean"目标声明为伪目标
clean:
rm -f hello main.c func1.o func2.o
例3
继续例子2
修改Makefile文件
test:test.o sequence.o
gcc -o test test.o sequence.o
test.o:test.c
gcc -o test.o -c test.c
sequence.o:sequence.c
gcc -o sequence.o -c sequence.c
.PHONY:clean rebuild
clean:
rm -f test.o sequence.o test
rebuild:clean test
注意文件创建时间
Makefile的变量、规则与内置函数
变量
随着软件项目的变大、变复杂,源文件也越来越多,如果采用前面的方式写makefile文件,将会使makefile也变得复杂而难于维护。
通过make支持的变量定义、规则和内置函数,可以写出通用性较强的makefile文件,使得同一个makefile文件能够适应不同的项目。
变量:用来代替一个文本字符串
定义变量的2种方法:
变量名=变量值 递归变量展开(几个变量共享一个值) // 不常用
变量名:=变量值 简单变量展开(类似与C++的赋值) // 通常采用这种形式
使用变量的一般方法:
$(变量名)=??? // 赋值
???=$(变量名) // 引用
变量分为:用户自定义变量、自动变量、预定义变量、环境变量
用户自定义变量
如:
OBJS:=test.o add.o
EXE:=test.exe
$(EXE):$(OBJS)
gcc -o $(EXE) $(OBJS)
test.o:test.c
gccc -c test.c
add.o:add.c
gcc -c add.c
.PHONY:rebuild clean
rebuild:clean $(EXE)
clean:
rm -rf $(EXE) $(OBJS)
上面的例子就是用户自定义变量。
自动变量
值在使用的时候,自动用特定的值替换。
如:
OBJS:=test.o add.o
EXE:=test.exe
$(EXE):$(OBJS)
gcc -o $@ $^
test.o:test.c
gcc -c $^
add.o:add.c
gcc -c $^
.PHONY:rebuild clean
rebuild:clean $(EXE)
clean:
rm -rf $(EXE) $(OBJS)
预定义变量、环境变量(查看环境变量export)
内部事先定义好的变量,但是它的值是固定的,并且有些值是为空的。
根据内部变量,可以将makefile改写为:TEST_file3文件夹。
OBJS:=test.o add.
EXE:=test.exe
$(EXE):$(OBJS)
$(CC) -o $@ $^
test.o:test.c
$(CC) -c $^
add.o:add.c
$(CC) -c $^
.PHONY:rebuild clean
rebuild:clean $(EXE)
clean:
$(RM) $(EXE) $(OBJS)
规则:普通规则,隐含规则,模式规则
1、 普通规则
普通规则即基本语法规则
另外
- makefile里面的注释使用
#
- 命令如果不想显示到终端,加
@
2、隐含规则
例如:*.o
文件自动依赖*.c
或*.cc
文件,所以可以忽略main.o:main.c
等
OBJS:=test.o add.o
EXE:=test.exe
$(EXE):$(OBJS)
$(CC) -o $@ $^
.PHONY:rebuild clean
rebuild:clean $(EXE)
clean:
$(RM) $(EXE) $(OBJS)
省略了
3、模式规则
通过匹配模式找字符串,%
匹配1或多个任意字符串。
%.o:%.cpp
表示任何目标文件的依赖文件是与目标文件同名的并且扩展名为.cpp
的文件
OBJS:=main.o fun.o
main.exe:$(OBJS)
gcc $^ -o $@
%.o:%.cpp
gcc -o $@ -c $^
另外还可以指定将*.o
、*.exe
、*.a
、*.so
等编译到指定目录中
DIR:=./Debug/
EXE:=main.exe
OBJS:=main.o
$(DIR)$(EXE):$(DIR)$(OBJS)
gcc -o $@ $< -L ./ -1func
$(DIR)main.o:main.c
gcc -o $@ -c $^
.PHONY:rebuild clean
rebuild:clean $(DIR)$(EXE)
clean:
rm -rf $(DIR)*.0 $(DIR)*.exe
注意:
当OBJS里面有多项的时候,此时$(DIR)$(OBJS)
只能影响到OBJS第一个,后面的全部无效,因此需要全部列出来
函数
wildcard(搜索文件函数)
搜索当前目录下文件名,展开成一列所有符合由其参数描述的文件名,文件间以空格隔开
SOURCES=$(wildcard *.cpp)
// 把当前目录下所有.cpp文件存入变量SOURCES里
patsubst(字符替换函数)
格式:$(patsubst 要查找的子串, 替换后的目标子串, 源字符串)
将源字符串(以空格分隔)中的所有要查找的子串替换成目标子串
如:
OBJS=$(patsubst %.cvpp,%.o,$(SOURCES))
把SOURCES中.cpp
替换为.o
然后把替换后的字符串存入变量OBJS中
addprefix(加前缀函数)
格式:$(addprefix 前缀, 源字符串)
该函数把第二个参数列表里的每一项前缀加上第一个参数值。
make的命令行选项
其他
《GNU make 中文手册.pdf》
DIR:=./build/
OBJS=tt.o ConfigFile.o
DEPENDENCES:=$(addprefix $(DIR), $(OBJS))
EXE:=main
RM:=rm -rf
$(EXE):$(DEPENDENCES)
gcc -o $(EXE) $(DEPENDENCES)
$(DIR)%.o:%.c
gcc -o $@ -g -c $^
.PHONY:rebuild clean
rebuild:clean $(EXE)
clean:
$(RM) $(DIR)* $(EXE)
今天的文章makefile c++11_makefile编写规则分享到此就结束了,感谢您的阅读。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/63814.html