Makefile语法:
targets : prerequisites
command
为了演示Makefile,这里创建一个工程。工程结构如下:
源代码如下:
// ./src/aa.hpp void func_a(); // ./src/aa.cpp void func_a() { printf("call func_a "); } // ./src/base/bb.hpp void func_b(); struct Person { int age; // double score; // double weight; }; // ./src/base/bb.cpp void func_b() { printf("call func_b "); } // ./src/main.cpp #include <iostream> #include "aa.hpp" #include "base/bb.hpp" using namespace std; int main(int argc, const char * argv[]) { func_a(); func_b(); Person person; cout << "person size: " << sizeof(person) << endl; return 0; }
Makefile内容如下:
BIN_NAME := foo CXX ?= g++ SRC_EXT = cpp SRC_PATH = ./src BUILD_PATH = ./build SHELL = /bin/bash SOURCES := $(shell find $(SRC_PATH) -name '*.$(SRC_EXT)') OBJECTS = $(SOURCES:$(SRC_PATH)/%.$(SRC_EXT)=$(BUILD_PATH)/%.o) .PHONY: all dirs clean all: dirs $(BIN_NAME) dirs: mkdir -p $(dir $(OBJECTS)) $(BIN_NAME): $(OBJECTS) @echo "compiling $@" $(CXX) -o $@ $^ $(BUILD_PATH)/%.o: $(SRC_PATH)/%.$(SRC_EXT) @echo "compiling $@" $(CXX) -c $< -o $@ test: @echo $(SOURCES) @echo $(OBJECTS) clean: @$(RM) $(BIN_NAME) @$(RM) -r $(BUILD_PATH)
虽然这个Makefile能用,但是有一个问题:如果修改了头文件,再次make无效。
改进版:
BIN_NAME := foo CXX ?= g++ SRC_EXT = cpp SRC_PATH = ./src BUILD_PATH = ./build SHELL = /bin/bash SOURCES := $(shell find $(SRC_PATH) -name '*.$(SRC_EXT)') OBJECTS = $(SOURCES:$(SRC_PATH)/%.$(SRC_EXT)=$(BUILD_PATH)/%.o) DEPS = $(OBJECTS:.o=.d) .PHONY: all dirs clean all: dirs $(BIN_NAME) dirs: mkdir -p $(dir $(OBJECTS)) $(BIN_NAME): $(OBJECTS) @echo "compiling $@" $(CXX) -o $@ $^ -include $(DEPS) $(BUILD_PATH)/%.o: $(SRC_PATH)/%.$(SRC_EXT) @echo "compiling $@" $(CXX) -MP -MMD -c $< -o $@ test: @echo $(SOURCES) @echo $(OBJECTS) clean: @$(RM) $(BIN_NAME) @$(RM) -r $(BUILD_PATH)
修改的地方用绿色标明了。 此时,如果修改头文件,再次make有效。
关于gcc的编译选项,啰嗦几句:
-M,列出文件需要的头文件,输出中包含系统头文件
-MM,列出文件需要的头文件,但不包含系统头文件
-MMD, 与-o结合使用,将文件的依赖关系输出到.d文件中
-MP, 为文件的依赖文件建立一个target,
来个实战,不带-MP:
g++ -MMD -c main.cpp -o main.o
目录下会生成main.d文件,其中内容为:
main.o: main.cpp aa.hpp base/bb.hpp
如果带-MP:
g++ -MP -MMD -c main.cpp -o main.o
main.d中的内容就会变成:
main.o: main.cpp aa.hpp base/bb.hpp aa.hpp: base/bb.hpp:
参考资料: