一句话总结:注意头文件的依赖,熟悉常用的技巧。
直接上实例
zjy@ubuntu:~/makefile$ ls
fun main.cpp makefile
zjy@ubuntu:~/makefile$ ls fun/
fun.cpp fun.h
zjy@ubuntu:~/makefile$ make
--------DEPS=main.d fun/fun.d
--------generate obj
--------fileter: main.cpp
g++ -o main.o -c main.cpp
--------DEPS=main.d fun/fun.d
--------generate obj
--------fileter: fun/fun.cpp
g++ -o fun/fun.o -c fun/fun.cpp
SRCS=main.cpp fun/fun.cpp
OBJS=main.o fun/fun.o
DEPS=main.d fun/fun.d
Building main
g++ -o main main.o fun/fun.o
--------DEPS=main.d fun/fun.d
g++ -MM main.cpp > main.d
--------DEPS=main.d fun/fun.d
g++ -MM fun/fun.cpp > fun/fun.d
zjy@ubuntu:~/makefile$ ls
fun main main.cpp main.d main.o makefile
zjy@ubuntu:~/makefile$ ./main
print fun
zjy@ubuntu:~/makefile$ make clean
rm main main.o fun/fun.o main.d fun/fun.d
zjy@ubuntu:~/makefile$ ls
fun main.cpp makefile
zjy@ubuntu:~/makefile$ cat makefile
.PHONY:all
SRCS = $(wildcard *.cpp fun/*.cpp)
OBJS = $(SRCS:.cpp=.o)
DEPS = $(SRCS:.cpp=.d)
BIN = main
all: $(BIN) $(DEPS)
ifneq ("$(wildcard $(DEPS))", "")
include $(DEPS)
endif
$(BIN):$(OBJS)
@echo "SRCS=$(SRCS)"
@echo "OBJS=$(OBJS)"
@echo "DEPS=$(DEPS)"
@echo Building $@
g++ -o $@ $^
%.o:%.cpp
@echo "--------DEPS=$(DEPS)"
@echo "--------generate obj"
@echo "--------fileter: $(filter %.cpp,$^)"
g++ -o $@ -c $(filter %.cpp,$^)
%.d:%.cpp
@echo "--------DEPS=$(DEPS)"
g++ -MM $^ > $@
clean:
rm $(BIN) $(OBJS) $(DEPS)
zjy@ubuntu:~/makefile$
.PHONY: all clean
SRCS = $(wildcard *.cpp fun/*.cpp)#扫描工程中所有cpp文件
OBJS = $(SRCS:.cpp=.o) #将扫描到所有cpp文件SRCS换成.o文件,相当于获取所有obj文件
DEPS = $(SRCS:.cpp=.d) #获取到所有.d文件
BIN = main
all: $(BIN) $(DEPS) #all目标依赖于BIN和DEPS
#include $(DEPS) #运行阶段产生,运行前没有文件,直接包含会失败
ifneq ("$(wildcard $(DEPS))", "") #如果搜索到DEPS,则非空,可以包含,否则找不到的
include $(DEPS)
endif
$(BIN):$(OBJS)
@echo "SRCS=$(SRCS)" #打印
@echo "OBJS=$(OBJS)"
@echo Building $@ #打印编译目标
g++ -o $@ $^ #$@代表目标,即是$(BIN);$^代表所有依赖对象,即是$(OBJS)
#%.o:%.cpp #%.o:%.cpp 用目录下的点cpp文件生成点o文件
#g++ -o $@ -c $^
%.o:%.cpp #上面的就用不到了
@echo "--------$(filter %.cpp,$^)"
#$(filter PATTERN…,TEXT)
#函数名称:过滤函数—filter。
#函数功能:过滤掉字串“TEXT”中所有不符合模式“PATTERN”的单词,保留所有符合此模式的单词。
g++ -o $@ -c $(filter %.cpp,$^)
%.d:%.cpp #%.d:%.cpp 用目录下的点cpp文件生成点d文件
g++ -MM $^ > $@ #-MM表示打印出文件的依赖对象,>代表重定向,表示输出到目标文件中
clean:
rm -f $(BIN) $(OBJS) $(DEPS)
ifneq ("$(wildcard $(DEPS))", "") #如果搜索到DEPS,则非空,可以包含,否则找不到的
include $(DEPS)
endif
%.d:%.cpp #%.d:%.cpp 用目录下的点cpp文件生成点d文件
g++ -MM $^ > $@ #-MM表示打印出文件的依赖对象,>代表重定向,表示输出到目标文件中
-MM可以找到cpp文件依赖的文件,运行前包含文件找不到报错,加上判断。
zjy@ubuntu:~/makefile$ make
makefile:9: main.d: No such file or directory
makefile:9: fun/fun.d: No such file or directory
--------DEPS=main.d fun/fun.d
g++ -MM fun/fun.cpp > fun/fun.d
--------DEPS=main.d fun/fun.d
g++ -MM main.cpp > main.d
--------DEPS=main.d fun/fun.d
--------generate obj
--------fileter: main.cpp
g++ -o main.o -c main.cpp
--------DEPS=main.d fun/fun.d
--------generate obj
--------fileter: fun/fun.cpp
g++ -o fun/fun.o -c fun/fun.cpp
SRCS=main.cpp fun/fun.cpp
OBJS=main.o fun/fun.o
DEPS=main.d fun/fun.d
Building main
g++ -o main main.o fun/fun.o
大多数c/c++编译器提供了-M选项,可自动寻找源文件依赖的头文件,并生成依赖规则。对于gcc,需要使用-MM选项,否则它会把系统依赖的头文件也包含进来。
%.d:%.cpp #%.d:%.cpp 用目录下的点cpp文件生成点d文件
g++ -MM $^ > $@ #-MM表示打印出文件的依赖对象,>代表重定向,表示输出到目标文件中
去掉该选项后,修改头文件不重新编译。