makefile
基本语法
void print_hello(); int factorial(int n);
#include "functions.h" int factorial(int n){ if (n!=1) return n * factorial(n-1); else return 1; }
#include <iostream> void print_hello() { std::cout << "hello world" << std::endl; }
# include <iostream> # include "functions.h" int main() { print_hello(); std::cout << "this is main" << std::endl; std::cout << "The factorial of 5 is " << factorial(5) << std::endl; return 0; }
定义目标
-
目标文件:依赖文件
定义了文件之间的依赖关系。 -
依赖关系下一行用
TAB
缩进,是任务是执行命令。
CC = g++ SRC_DIR = src OUT_DIR = out CFLAGS = -c -Wall LFLAGS = -Wall CYGLIB = -static-libgcc -static-libstdc++ all: $(OUT_DIR)/hello $(OUT_DIR)/hello: $(OUT_DIR)/main.o $(OUT_DIR)/function1.o $(OUT_DIR)/function2.o $(CC) $(LFLAGS) $(CYGLIB) $(OUT_DIR)/main.o $(OUT_DIR)/function1.o $(OUT_DIR)/function2.o -o $(OUT_DIR)/hello $(OUT_DIR)/main.o: $(SRC_DIR)/main.cpp $(CC) $(CFLAGS) $(CYGLIB) -c $(SRC_DIR)/main.cpp -o $(OUT_DIR)/main.o $(OUT_DIR)/function1.o: $(SRC_DIR)/function1.cpp $(CC) $(CFLAGS) $(CYGLIB) -c $(SRC_DIR)/function1.cpp -o $(OUT_DIR)/function1.o $(OUT_DIR)/function2.o: $(SRC_DIR)/function2.cpp $(CC) $(CFLAGS) $(CYGLIB) -c $(SRC_DIR)/function2.cpp -o $(OUT_DIR)/function2.o clean: rm -rf $(OUT_DIR)/*.o $(OUT_DIR)/hello
变量代替目标与依赖文件
内置变量可以作为目标与依赖的缩写:
-
$@
: 指代 all ,即 target -
$<
: 指代 第一个 dependency -
$^
: 指代 所有的 dependencies
CC = g++ SRC_DIR = src OUT_DIR = out CFLAGS = -c -Wall LFLAGS = -Wall CYGLIB = -static-libgcc -static-libstdc++ all: $(OUT_DIR)/hello $(OUT_DIR)/hello: $(OUT_DIR)/main.o $(OUT_DIR)/function1.o $(OUT_DIR)/function2.o $(CC) $(LFLAGS) $(CYGLIB) $^ -o $@ $(OUT_DIR)/main.o: $(SRC_DIR)/main.cpp $(CC) $(CFLAGS) $(CYGLIB) $^ -o $@ $(OUT_DIR)/function1.o: $(SRC_DIR)/function1.cpp $(CC) $(CFLAGS) $(CYGLIB) $^ -o $@ $(OUT_DIR)/function2.o: $(SRC_DIR)/function2.cpp $(CC) $(CFLAGS) $(CYGLIB) $^ -o $@ clean: rm -rf $(OUT_DIR)/*.o $(OUT_DIR)/hello
文件名查找与替换
wildcard用来查找指定目录下指定类型的文件:
SOURCE_DIR = . # 如果是当前目录,也可以不指定 SOURCE_FILE = $(wildcard $(SOURCE_DIR)/*.cpp) target: @echo $(SOURCE_FILE)
其中@echo
前加@
是为了避免命令回显。
patsubst 应该是 pattern substitution 的缩写。用它可以方便地将.cpp
文件的后缀换成.o
。
它的基本语法是:$(patsubst 原模式,目标模式,文件列表)
。
SOURCES = main.cpp function1.cpp function2.cpp OBJS = $(patsubst %.cpp, %.o, $(SOURCES)) target: @echo $(SOURCES) @echo $(OBJS)
新版本:
CC = g++ SRC_DIR = src OUT_DIR = out OBJS = $(patsubst $(SRC_DIR)/%.cpp, $(OUT_DIR)/%.o, $(wildcard $(SRC_DIR)/*.cpp)) CFLAGS = -c -Wall LFLAGS = -Wall CYGLIB = -static-libgcc -static-libstdc++ all: $(OUT_DIR)/hello $(OUT_DIR)/hello: $(OBJS) $(CC) $(LFLAGS) $(CYGLIB) $^ -o $@ $(OUT_DIR)/main.o: $(SRC_DIR)/main.cpp $(CC) $(CFLAGS) $(CYGLIB) $^ -o $@ $(OUT_DIR)/function1.o: $(SRC_DIR)/function1.cpp $(CC) $(CFLAGS) $(CYGLIB) $^ -o $@ $(OUT_DIR)/function2.o: $(SRC_DIR)/function2.cpp $(CC) $(CFLAGS) $(CYGLIB) $^ -o $@ clean: rm -rf $(OUT_DIR)/*.o $(OUT_DIR)/hello
静态替换
Static Pattern Rule,其语法为:targets: target-pattern: prereq-patterns
-
其中
targets
不再是一个目标文件了,而是一组目标文件。 -
而
target-pattern
则表示目标文件的特征。例如目标文件都是.o
结尾的,那么就将其表示为%.o
-
prereq-patterns
表示依赖文件的特征,例如依赖文件都是.cpp
结尾的,那么就将其表示为%.cpp
。
通过上面的方式,可以对 targets 列表中任何一个元素,找到它对应的依赖文件,
例如通过targets
中的main.o
,可以锁定到main.cpp
。
CC = g++ SRC_DIR = src OUT_DIR = out OBJS = $(patsubst $(SRC_DIR)/%.cpp, $(OUT_DIR)/%.o, $(wildcard $(SRC_DIR)/*.cpp)) CFLAGS = -c -Wall LFLAGS = -Wall CYGLIB = -static-libgcc -static-libstdc++ all: $(OUT_DIR)/hello $(OUT_DIR)/hello: $(OBJS) $(CC) $(LFLAGS) $(CYGLIB) $^ -o $@ $(OBJS): $(OUT_DIR)/%.o : $(SRC_DIR)/%.cpp $(CC) $(CFLAGS) $(CYGLIB) $< -o $@ clean: rm -rf $(OUT_DIR)/*.o $(OUT_DIR)/hello
增加功能
递归编译子目录下的源代码
wildcard
方法不能递归遍历出子目录下的文件,所以要自己写一个rwildcard
方法,
通过递归地调用自身来一级一级列出所有子目录下的文件:
rwildcard=$(wildcard $1$2) $(foreach d,$(wildcard $1*),$(call rwildcard,$d/,$2))
找c++源代码就:
$(call rwildcard,src/,*.cpp)
gcc不能自动创建目录,调用gcc前要事先把目录创建好:
$(OBJS): $(OUT_DIR)/%.o : $(SRC_DIR)/%.cpp @mkdir -p $(@D) $(CC) $(CFLAGS) $(CYGLIB) $< -o $@
这样有多个层级源代码的makefile:
CC = g++ SRC_DIR = src OUT_DIR = out rwildcard=$(wildcard $1$2) $(foreach d,$(wildcard $1*),$(call rwildcard,$d/,$2)) OBJS = $(patsubst $(SRC_DIR)/%.cpp, $(OUT_DIR)/%.o, $(call rwildcard,src/,*.cpp)) CFLAGS = -c -Wall LFLAGS = -Wall CYGLIB = -static-libgcc -static-libstdc++ all: $(OUT_DIR)/hello $(OUT_DIR)/hello: $(OBJS) $(CC) $(LFLAGS) $(CYGLIB) $^ -o $@ $(OBJS): $(OUT_DIR)/%.o : $(SRC_DIR)/%.cpp @mkdir -p $(@D) $(CC) $(CFLAGS) $(CYGLIB) $< -o $@ clean: rm -rf $(OUT_DIR)/* $(OUT_DIR)/hello