Makefile的个人理解以及简单例子

makefile的作用

用来进行条件编译来实现对工程编译的优化

基本规则

TARGET...:DEPENDENCE ...

                   COMMAND

                    ...

  • 目标:target程序产生的文件,如可执行那个文件和目标文件;目标也可以是要执行的动作,如:“clean”
  • 依赖:dependence是用来产生目标的输入文件,一个目标通常依赖于多个文件。

  • 命令:command是make执行的动作,一个target可以有多个命令。

Attention:每个命令必须只占一行,而且必须要以TAB键开头(固定格式)

makefile的核心内容

如果dependence中有一个或多个文件更新的话,command就要执行

make的工作方式

  1. 找到文件“Makefile”或者“makefile”
  2. 最终目标为第一个目标(也就是生成main)
  3. 如果main文件不存在或者是有.o文件有更新,那么它会执行后面的指令来生产main文件
  4. 看看哪个.o更新了,找到相应的target的command执行得到.o文件,最后执行终极目标生成main。

伪目标

".PHONY"它的作用主要是防止文件名和自己的指令名重合,如果重合只执行为目标的命令。

.PHONY:clean

由例子来说明Makefile

#这是一个最简陋的makefile的表达
main:main.o add.o minus.o    
#首先就是查看下面的目标有没有生成,生成之后最后将所有生成main工程的.o文件找到(main.o add.o subtract.o)生成main工程。
	gcc main.o add.o minus.o -o main 
main.o:main.c add.h minus.h     #首先将头文件和c文件列出来
	gcc -c main.c -o main.o     #每一个.o文件都需要编译生成
add.o:add.c add.h
	gcc -c add.c -o add.o
minus.o: minus.c minus.h
    gcc -c minus.c -o minus.o
.PHONY:clean   #伪指令防止重名
clean:
	rm -f main main.o add.o minus.o #对工程进行清理

上面的makefile是最复杂的那种,此处说的复杂是需要每次手动加入相应的新文件和它们的依赖。不可取。

三个自动化变量

  1. $@  规则的目标文件名

  2. $<   规则的第一个依赖文件名

  3. $^   规则的所有依赖文件列表

makefile使用变量

#定义变量
object=main.o add.o minus.o #脚本语言不需要变量类型 
main:$(object) #在使用变量之前需要加$(变量名)

Makefile自动推导

GNU的make命令很厉害,可以根据要生成的.o文件的名字找到相应的c文件,并且也会自己推倒命令。所以我们可以将上面的一些命令去掉,剩下就是需要包含的一些头文件。

#这个是自动推导指令的makefile公式
object=main.o add.o minus.o 
main:$(object)    
	gcc $(object) -o main 
main.o: add.h minus.h     #只要头文件
add.o: add.h
minus.o:minus.h

.PHONY:clean   #伪指令防止重名
clean:
	rm -f main main.o add.o minus.o

但是每一次创建一个新的文件之后还是要将新的文件加到object里面,最后我们可以使用一些好用的Makefile函数

Makefile函数

  • wildcard函数 :当前目录下匹配模式的文件,因为makefile会将通配符当成一个宏定义,也就是想要获取文件的时候就不能使用通配符,但是我们可以通过wildcard函数,使用通配符      例如:src=$(wildcard *.c) 就是将所有的文件夹内部的c文件获取给src
  • notdir函数 :去除路径   例如:$(notdir $src)
  • patsubst函数 :模式匹配替换 可以将搜索到的.c文件替换成.o文件      例如:$(patsubst%.c,%.o,$src) 
  • 等价于$(src:.c=.o)
  • shell函数  : 执行shell命令 例如:$(shell ls –d */)
ELF=main
CC=gcc
src=$(wildcard *.c)  #通过wildcard找到所有的
objects=$(src:.c=.o) #找到src里面所有的c文件所对应的.o文件
$(ELF):$(objects)
    $(CC) $^ -o $@ 
$(objects):
clean:
    rm -f $(objects) $(ELF)

最后一个完整版的makefile,有许多的IDE都有专门帮你生成makefile的文件的功能,像是Qt的Qmake,你打开它们内部生成的一些makefile或者是.mk文件,你就会发现,人家写的很清晰(变量用的规范,好看)

为了好看,也为了学习,我就自己也模仿了一个

CXX = g++

CXXFLAG = -o2 -g -Wall 

LDFLAGS =   #这里一般写一些库的路径,可以配合pkg-config

SRC  += $(wildcard *.cpp)

#按道理讲人家会都把你添加到工程的.o文件罗列在这里,但是我比较懒就用函数了
OBJS = $(patsubst %.cpp,%.o,$(SRC)) #之前这里的SRC写成小写的了,导致错误


LIBS += -lpthread \    
        -lboost_system

HEADER_DIR = -I.

TARGET = myserver

$(TARGET):$(OBJS)
	$(CXX)  $(OBJS) $(HEADER_DIR) -o $(TARGET) $(LIBS)

%.o:%.cpp
	$(CXX)  -c $< -o $@ $(LIBS)

$(OBJS): #关键不要忘记写了 , 不然会出现问题生成不了OBJ

.PHONY:clean
clean:
	rm -f $(OBJ) $(TARGET) 

遇到一个bug就是居然找不到依赖也就是编译的时候使用$^找不到,后来发现是伪指令声明上面没有加$(OBJS):,其实只是会写也不太懂具体是为什么会导致这个错误,总之要记一下。

猜你喜欢

转载自blog.csdn.net/weixin_42427338/article/details/83690504
今日推荐