Makefile文件编写
Makefile
概念
基本格式:
目标:依赖命令target:prerequistise comand
使用@符号可以省略终端输出的命令,只输出结果,不输出执行的命令
如果不指定target,直接使用make会使用makefile文件中的第一个target
伪目标:
作用:为了避免文件名和所使用命令重名的情况出现
.PHONY : clean debug # 将需要避免的命令写到.PHONY后面,再执行就可以顺利执行了。
预定义的变量:
$@ 所有的target的完整名称$< 第一个依赖文件的名称$^ 所有依赖文件,以空格分开,不包含重复依赖文件?= 条件复制操作符,当该变量没有被赋值或者为空时,才会进行赋值。
1. origin版本
world.out : hello.o main.og++ -o kitty.out hello.o main.ohello.o : hello.cppg++ -c hello.cppmain.o : main.cppg++ -c main.cppclean:rm -f *.o *.out
2. 进阶1——隐式规则
使用 隐式规则(implicit rule)自动生成hello.o main.o
world.out : hello.o main.o # 使用(implicit rule)自动生成hello.o main.og++ -o world.out hello.o main.oclean:rm -f *.o *.out
哪些情况不能使用隐式规则:
(1)不同的编译选项
显式指定不同文件的编译选项
foo.o: foo.cppg++ -O2 -c foo.cpp -o foo.obar.o: bar.cppg++ -O0 -c bar.cpp -o bar.o
(2)项目结构复杂
手动指定文件路径和编译规则,显示规则
obj/%.o: src/%.cppg++ -c $< -o $@
等等,总之不是这种类型的均不可适用:
hello.o : hello.cppg++ -c hello.cppmain.o : main.cppg++ -c main.cpp
3. 进阶2——使用变量
使用变量替换重复出现的值
变量的定义 变量名 = 值 或者 变量名 := 值 ,变量名为全大写。引用变量使用 **$(变量名) **
OBJS := hello.o main.o
TARGET := world.out # 使用变量替换重复出现的值
$(TARGET) : $(OBJS)g++ -o $(TARGET) $(OBJS)clean:rm -f $(OBJS) $(TARGET)
4. 进阶3——使用函数
使用函数
OBJS := $(patsubst %.cpp,%.o,$(wildcard *.cpp)) # 获取所有的.cpp文件,将.cpp的文件,替换为.o文件。
TARGET := kitty.out$(TARGET) : $(OBJS)g++ -o $(TARGET) $(OBJS)clean:rm -f $(OBJS) $(TARGET)
5. 进阶4——使用自动变量
使用自动变量 $@ $^
OBJS := $(patsubst %.cpp, %.o, $(wildcard *.cpp))
TARGET := kitty.out$(TARGET) : $(OBJS)@echo '$$@ = $@' # 第一个@省略了命令echo输出到终端g++ -o $(@) $(^)clean:rm -f $(OBJS) $(TARGET)
6. 进阶5——适用模式匹配
使用模式匹配规则(pattern rule)
OBJS = $(patsubst %.cpp, %.o, $(wildcard *.cpp))
TARGET = kitty.out$(TARGET): $(OBJS)g++ -o $(TARGET) $(OBJS)# 模式匹配规则:当make需要目标 xyz.o 时,自动生成一条 xyz.o: xyz.cpp 规则:
%.o: %.cpp@echo 'compiling $<...'g++ -c -o $@ $<clean:rm -f *.o $(TARGET)
用到的源文件
hello.cpp文件
#include <stdio.h>void hello()
{printf("hello kitty!\n");
}
hello.h文件
void hello();
main.cpp文件
#include <stdio.h>
#include "hello.h"int main(int argc, char const *argv[])
{printf("start...\n");hello();printf("exit.\n");return 0;
}