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编写的主要内容,如果未能解决你的问题,请参考以下文章

Linux——makefile编写

Linux下makefile文件的编写问题!

如何编写Makefile,一份由浅入深的Makefile全攻略(转)

如何编写Makefile,一份由浅入深的Makefile全攻略(转)

GCC学习 如何编写makefile

makefile编写--引用