makefile编写
Posted that-boy-done
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了makefile编写相关的知识,希望对你有一定的参考价值。
刚看了一整套完整的makefile的编写规则来总结一下吧
1.makefile 的编写
Makefile 是一个描述“如何生成整个项目”的脚本文件
有很多规则
每一条规则格式为:
Target:dependencies
[TAB]system command1
[TAB]system command2
.....
Target: 目标
Dependencies: 依赖
<TAB>:每行命令前面都需要加一个TAB
System command:系统命令
读作要完成目标target 必须执行命令 commands...
Clean:
Rm -rf *.o helloworld
可以有多条规则,每条规则可以有多条命令
但是输入make命令是,同时显示指定要执行那一条规则rule 如make clean
注: make命令默认只执行一条规则,其他默认不执行
2.增量编译(针对一个项目中有很多个源文件 a.cpp b.cpp c.cpp, 当只有某个文件改变了,只需要编译其中一个文件 称为增量编译)
Helloworld: main.cpp other.cpp other.h
G++ main.cpp other.cpp -o helloworld
在目标的后面加上所依赖的文件,就会实现增量编译,只编译有变化的文件,必须加上依赖文件才会增量编译,否则都不会编译,永远是最新的可执行文件
Main:main.o other.o
G++ main.o other.o -o main
Main.o mian.cpp other.h
G++ -c main.cpp -o main.o
Other.o:other.cpp other.h
G++ -c other.cpp -o other.o
3.Makefile 中的注释
以#开头的行,为注释行
4.Makefile 中的支持的变量
SUBDIR = src xml
Test:
Echo$(SUBDIR)
定义一个变量SUBDIR
(1)用等号=赋值(等号两边可以加空格)
(2)用+=追加字符串
(3)用$(SUBDIR)取到变量的值(要加小括号)
注:如果不想让命令复现 则在Echo$(SUBDIR) 前面加上@就可以了
特殊变量
$@指代target
$^指代dependencies依赖 项列表
$< 指代依赖项的第一项 这三中特殊的变量经常用到
Test2:main.cpp other.cpp
Echo $^ 则代表main.cpp other.cpp
Echo$@ 则代表 test2
Echo$< 则代表 main.cpp
Makefile 中还有一些预定义的函数
$(函数名 参数列表)
函数名:Makefile内部自带的函数
参数列表:以逗号分开
注:函数名和列表参数之间是以空格分开的 PWD=$(shell pwd)
Shell 为Makefile的函数 pwd为参数 PWD为一个变量
CXX_SOURCE=$(wildcard ./*.cpp)
Wildcard 写出该目录下的文件名 ./表示当前目录 *.cpp为通配符
5. 优化Makefile
优化方向:针对大量CPP文件,减少手工编辑操作,争取最大化的自动化
原则:保持增量编译的功能
(1)使用通配符
%.o:%.cpp
G++ -c $< -o $@ 可以将多个目标 使用一句话 .cpp编译生成.o文件
$@ 指目标
$< 指第一个依赖项
可以代替
Main.o: main.cpp other.h
G++ -c main.cpp -o main.o
Other.o:other.cpp other.h
G++ -c other.cpp -o other.o (-o 是生成目标)
(2) 自动罗列.o文件
CXX_SOURCES = $(wildcard*.cpp)
CXX_OBJECTS=$(patsubst %.cpp,%.o,$(CXX_SOURCES))
patsubst函数: 将所有的源文件转化为.o为文件 并将.o文件赋值给变量CXX_OBJECTS
源格式 目标格式 文件名列表
wildcard*.cpp 使当前文件下的*.cpp罗列出
Helloworld:$(CXX_OBJECTS)
G++ $(CXX_OBJECTS) -o helloworld
(3)设置EXE变量,表示输出程序的名字
(4)头文件依赖(增量编译必须考虑头文件的更新)
使用编译选项 -MMD
g++/gcc 在编译的xxx.cpp 的时候,可以提取里面包含的头文件(双引号包含的头文件)
然后生成对应.d文件,包含.cpp里面包含的头文件
G++ -c -MMD main.cpp -o main.o 则在生成一个main.o 的同时生成一个main.d文件
优化后的Makefile
EXE=helloworld
CXX_SOURCES=$(wildcard *.cpp)//所有源文件
CXX_OBJECTS=$(patsubst %.cpp, %.o $(CXX_SOURCES))//所有.o文件
DEP_FILES=$(patsubst %.cpp, %..d $(CXX_OBJECTS)//所有.d文件
$(EXE) :$(CXX_OBJECTS)
g++ $(CXX_OBJECTS) -O $(EXE)
%.o:%.cpp
g++ -c -MMD $< -o $(EXE)
-include $(DEP_FILES)
clean:
rm *.o $(EXE)
6. 支持子目录编译的makefile
(1)支持子目录
(2).o .d文件与.cpp文件混在一起,比较乱
一个项目通常是有多个子目录的
Foreach 便利子目录 三个参数
SUBDIR = src object (src object为两个目录)
CXX_SOURCES = $(foreach dir,$(SUBDIR), $(wildcard $(dir) /*.cpp))
将CXX_SOURCES=$(wildcard *.cpp)//所有源文件
换成
SUBDIR = src object (src object为两个目录)
CXX_SOURCES = $(foreach dir,$(SUBDIR), $(wildcard $(dir) /*.cpp))
就可以支持子目录的Makefile
以下是一套完整的makefile(支持增量编译,子目录编译)
EXE=helloworld
//CXX_SOURCES=$(wildcard *.cpp)//所有源文件
SUBDIR = src object (src object为两个目录) --该项目所有
CXX_SOURCES = $(foreach dir,$(SUBDIR), $(wildcard $(dir) /*.cpp))//所有目录的.CPP
CXX_OBJECTS=$(patsubst %.cpp, %.o $(CXX_SOURCES))//所有.o文件
DEP_FILES=$(patsubst %.cpp, %..d $(CXX_OBJECTS)//所有.d文件
$(EXE) :$(CXX_OBJECTS)
g++ $(CXX_OBJECTS) -O $(EXE)
%.o:%.cpp
g++ -c -MMD $< -o $(EXE)
clean:
rm -rf *.o $(EXE)
-include $(DEP_FILES)
以上是关于makefile编写的主要内容,如果未能解决你的问题,请参考以下文章
如何编写Makefile,一份由浅入深的Makefile全攻略(转)