如何编写含头文件依赖的Makefile?用g++编译生成可执行文件
解决你的Makefile编译问题
我来帮你一步步搞定这些Makefile的坑,先直接给你能正常工作的版本,再解释每个部分对应解决你的问题:
# 定义编译器和编译标准 CXX = g++ CXXFLAGS = -std=gnu++17 # 最终要生成的可执行文件名称 TARGET = create-exercise # 项目里的C++源文件(只放.cpp,.hpp是依赖不是编译输入) SOURCES = create-exercise.cpp # 自动推导对应的目标文件(每个.cpp生成一个.o) OBJECTS = $(SOURCES:.cpp=.o) # 默认执行的目标:生成可执行文件 all: $(TARGET) # 链接生成可执行文件:依赖是所有编译好的.o文件 $(TARGET): $(OBJECTS) $(CXX) $(CXXFLAGS) $^ -o $@ # 编译单个.cpp到.o:每个.o依赖对应的.cpp和exercise.hpp %.o: %.cpp exercise.hpp $(CXX) $(CXXFLAGS) -c $< -o $@ # 清理生成的中间文件和可执行文件 clean: rm -f $(OBJECTS) $(TARGET)
接下来逐个解决你遇到的问题:
问题1:把exercise.hpp加入依赖后被当成编译输入
你之前应该是把.hpp直接放到了可执行文件的依赖里,然后用$^(所有依赖)传给g++,导致g把.hpp也当成了要编译的源文件。现在我们把.hpp放到目标文件(.o)的依赖里,编译.o的时候只用$<(第一个依赖,也就是对应的.cpp文件)作为输入,这样g就不会处理.hpp文件了——毕竟.hpp已经被.cpp包含进去了,不需要单独编译。
问题2:生成.o时自动加-c导致无法运行
-c参数本来就是用来生成目标文件(.o)的,这是正常的编译步骤——目标文件本身就是不可直接运行的中间产物。我们把流程拆成两步:
- 用
-c编译.cpp到.o(这一步是编译源码到机器码,但还没链接) - 把所有.o文件链接成可执行文件(这一步不用
-c,最终产物就是能直接运行的程序)
这样就不会出现“生成的文件不能运行”的问题了。
问题3:修改exercise.hpp时Make提示文件已最新
这是因为之前的规则里没有把.hpp作为编译的依赖项,Make不知道.hpp变化需要重新编译。现在我们给.cpp -> .o的规则加上了exercise.hpp作为依赖,只要这个头文件有修改,Make就会自动重新编译对应的.o,然后重新链接成新的可执行文件。
如果之后你添加了更多头文件,只需要把它们加到%.o规则的依赖列表里就行,比如:
%.o: %.cpp exercise.hpp another-header.hpp $(CXX) $(CXXFLAGS) -c $< -o $@
现在你只需要在终端运行make就能自动编译,修改头文件或者源文件后再运行make都会自动重新编译对应的部分,运行make clean可以清理生成的文件。
内容的提问来源于stack exchange,提问作者kerolloz
相关产品推荐
相关产品推荐

