makefile全知道
Posted 城子特讯
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了makefile全知道相关的知识,希望对你有一定的参考价值。
一、makefile概念
大型的项目开发一般都有许多头文件、源文件等,其中,其按类型、功能、模块分别放在若干个目录中。这时,就需要用到makefile对这些代码进行编译,makefile定义了一系列的规则来指定哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,甚至于进行更复杂的功能操作。最后,整个项目通过make命令完成编译等功能。
个人对于makefile的命名一般都设定为Makefile_X(X表示项目英文名),不过这个仅个人习惯。
使用的时候如下设定:
make -f Makefile_X(X表示项目英文名)
二、makefile基础知识
1、makefile原理和规则
makefile规则如下:
目标:依赖
(tab)规则 //每条规则处不能使用空格,需要会用tab,否则会出问题。
目标——生成的目标文件
依赖——生成目标所需文件
规则——由依赖文件生成目标文件的命令,如规则:gcc fun.c -o fun
目标文件生成中,1、检测依赖文件存在与否,若不存在,查找是否有规则生成依赖文件。
下面以开发并联机器人项目为例:
parallelrobot:Main.o Speed.o Initial.o Kinematics.o Trajectory.o ...
gcc main.o Speed.o ....-0 prallelrobot
Main.o: main.c
...
//整个流程是向右寻找依赖,再向左执行命令,生成目标
//为了按规则生成目标文件,可使用下面命令
make -f Makefile_parellelrobot // 参数-f 使得文件名可以随意设定
如果在编译过程中,不希望产生中间的X.o文件可以使用make clean;
特殊情况:当前文件中如果有clean文件可以使用伪目标申明
.PHONY: clean
2、变量和函数
变量可通过直接赋值设定,如
PATH=./path/robot/
变量取值
OUTPUT=$(PATH)
./*.c //表示在当前目录下的素有.c文件
系统中默认值
LDFLAGS:链接库使用的选项 -L -l
CFLAGS:编译使用的选项 -Wall -g -c
CPPFLAGS:预处理使用的选项 -l
等等
另外,makefile有三个非常常用的自动变量,如下
$@: 规则中的目标
$^:规则中所有的依赖文件
$<:规则中第一个依赖文件
当项目中的依赖文件很多时,一个一个输入即容易输错又耗时,则可以采用模式规则,采用%匹配目录下的所有文件。
%.o:%.c
gcc -c $< -o $@
makefile为我们提供了一些函数,这里引入较为常用的几个函数作举例分析,如在下面的开发目录中有main.c、robotmotion.c、robotspeed.c文件
wildcard:查找相应目录下的指定类型的文件。
Source=$(wildcard ./source/*.c )
//查找当前目录下所有.c的文件并赋值给Source,得到的Source的值为 main.c
robotmotion.c robotspeed.c
patsubst: 相应文件的相互替换
object=$(patsubst ./%.c,./%.o,$(Source))
//将Source当中的.c文件替换为当前目录的.o文件,则object=main.o robotmotion.o robotspeed.o
3、makefile用例
1、当项目中的文件较少的情况下考虑,使用简单的makefile方法,如
parallelrobot: main.c function1.c function2.c
gcc main.c function1.c function2.c -o parallelrobot
这个代码的缺点是任何文件稍微修改就需要重新编译。因此需要再进行优化,以生成的中间文件,解决这个问题。优化如下:
parallelrobot: main.o function1.o function2.o
gcc main.o function1.o function2.o -o parallelrobot
main.o: main.c
gcc -c main.c -o main.o
function1.o: function1.c
gcc -c function.c -o function.o
function2.o: function2.c
gcc -c function2.c -o function.o
优化后的这个版本虽然解决了重新编译的问题,但是代码出现了重复,其仅适用于超小型项目文件。
2、使用模式规则的makefile的方法
模式规则为
object = main.o function1.o function2.o
target = parallelrobot
CC = gcc
$(target): $(object)
$(CC) $(object) -o $(target)
%.o: %.c
$(CC) -c $< -o $@
使用这种模式规则减少了代码重复,但是在依赖文件较多时,其工作量还是相对较大,因此需要引入使用wildcard和patsubst的优化版本。
3、优化的makefile方法(较好)
source = $(wildcard ./*.c)
object = $(patsubst %.c, %.o, $(source))
target = parallelrobot
CC = gcc
$(target): $(object)
$(CC) $(object) -o $(target)
%.o: %.c
$(CC) -c $< -o $@
#.PHONY是声明clean是一个伪目标,这样我们通过执行make clean命令
# 就是将中间文件如.o文件及目标文件全部删除。
.PHONY: clean
clean:
rm -rf $(object) $(target)
4、编译共用文件的案例
有2个应用程序application1.c和application1.h、application2.c和application2.h,2程序共用application3.c和application3.h。针对这个问题,我们可以把共用的程序放在一个文件内,另外每个程序各自单独一个程序。
则makefile可表示如下:
APP1 = application1
APP2 = application2
Target = $(APP1) $(APP2)
Source_APP3 = $(wildcard ./Application3/*.c)
Source_APP1 = $(Source_APP3) $(wildcard ./Application1/*.c)
Source_APP2 = $(Source_APP3) $(wildcard ./Application2/*.c)
Object1 = $(patsubst %.c, %.o, $(Source_APP1))
Obejct2 = $(patsubst %.c, %.o, $(Source_APP2))
INCLUDE = -I ./Application3/
CFLAGS = -Wall -c
CC = gcc
#注:生成两个可执行文件(两个目标)。由于makefile只能有一个目标,
# 所以可以构造一个没有规则的终极目标all,并以这两个可执行文件作为依赖
all: $(Target )
$(APP1): $(Object1)
@mkdir -p out/ //@后的命令只执行不回显
$(CC) $(Object1) -o out/$(APP1)
$(APP2): $(Obejct2)
@mkdir -p out/ //@后的命令只执行不回显
$(CC) $(Obejct2) -o out/$(APP2)
%.o: %.c
$(CC) $(INCLUDE) $(CFLAGS) $< -o $@
.PHONY: clean
clean:
rm -rf $(Object1) $(Object2) out/
三、总结
以上是博主今天的分享,如果您喜欢博主的文章,请留下关注和点赞,您的关注是我写作和分享的动力。感谢!
以上是关于makefile全知道的主要内容,如果未能解决你的问题,请参考以下文章
Yuchuan_Linux_C编程之六 Makefile项目管理