我已经为此苦苦挣扎了一个小时,并通过它与 ChatGPT 进行了彻底的交谈,但它并不擅长解释/本身犯了很多错误,我并没有真正前进。
我的问题是,如果我使用变量(HEADER),在其中放入所有 .hpp 文件并在 main.exe 中使用 $(HEADER) 调用它,则我的 makefile 不起作用: main.o $(HEADER) 。 ..规则。
如果我使用: main.exe: main.o 1.hpp 2.hpp 3.hpp ..... 这对我来说根本没有任何意义。
所以我对makefile的理解当然是结合大量的.hpp / .cpp -> .o文件来创建一个可执行文件。
我正在做一个练习,我必须创建一堆类、子类等,并在 main.cpp 中用它做一些事情。
因此,在做练习时,我深入研究了解决方案,我发现我的教授甚至没有使用 .cpp 文件来定义类函数,而是在 .hpp 文件中完成了这一切,因为每个文件只有几行代码班级。我接受了这一点,因为它会创建不必要的(.cpp)文件。
我已经完成了所有工作,然后开始编写我的 Makefile,当我启动它时,我遇到了错误。 这是我的 Makefile:
COMPILER=g++ -c
COMPILER_FLAGS=-std=c++14 -Wall -Wextra -pedantic -O3
LINKER=g++
HEADER = function.hpp integral.hpp polynom.hpp trigonom.hpp riemann.hpp montecarlo.hpp
all: main.exe
main.exe: main.o $(HEADER)
$(LINKER) $^ -o$@
%.o: %.cpp
$(COMPILER) $(COMPILER_FLAGS) $< -o$@
clean:
rm -f *.o
.PHONY: all clean
它不起作用,所以我想好吧,也许.hpp文件没有转换为.o文件,所以我添加了
%.o: %.hpp
$(COMPILER) $(COMPILER_FLAGS) $< -o$@
这实际上使它起作用了。我已经意识到,从技术上讲,这可能会导致问题,因为我的文件中已经有 %.o : %.cpp...
此时我变得越来越困惑,当我查看解决方案 makefile 时,它看起来像这样:
COMPILER=g++ -c
COMPILER_FLAGS=-std=c++14 -Wall -Wextra -pedantic -O3
LINKER=g++
all: main.exe
main.exe : main.o function.hpp integral.hpp polynom.hpp trigonom.hpp riemann.hpp montecarlo.hpp
$(LINKER) $< -o$@
%.o : %.cpp
$(COMPILER) $(COMPILER_FLAGS) $< -o$@
clean:
rm -f *.o
.PHONY: all clean
我真的什么都不明白了。为什么如果将 .hpp 文件放在 main.exe 规则内的 main.o 后面,它会起作用,但如果我将变量 $(HEADER) 放在该规则内的 main.o 文件后面,它就不起作用。区别在哪里???为什么它以一种方式起作用而为什么不以另一种方式起作用? 另外,在只使用头文件 (.hpp) 文件的情况下,执行 Makefile 的目的是什么?从技术上讲,我也可以只编译 main.cpp,因为我将所有 .hpp 文件包含在顶部的 main.cpp 中,例如使用#include“montecarlo.hpp”。
我知道,如果我调用规则 main.exe,它将获取所有对象文件并将它们绑定在一起以创建 .exe 文件。我尝试了一些其他变体,将 main.o 也放入 HEADER 变量内,或者将所有 .hpp 结尾更改为 .o 内的 HEADER 变量。没成功。
希望大家能帮忙,抱歉文字太长。谢谢!
就
make
而言,这两个片段之间没有区别:
main.exe : main.o function.hpp integral.hpp polynom.hpp trigonom.hpp riemann.hpp montecarlo.hpp
$(LINKER) $^ -o$@
和
HEADER = function.hpp integral.hpp polynom.hpp trigonom.hpp riemann.hpp montecarlo.hpp
main.exe: main.o $(HEADER)
$(LINKER) $^ -o$@
将标头放入规则依赖项中的目的使得
make
如果规则的输入发生更改,则重新运行规则。
但是,你的教授犯了一个大错误:由于 main.cpp
#include
是所有头文件,并且它是唯一翻译单元,因此每次标头更改时,你必须重新编译 main.cpp。所述规则仅重新链接但不重新编译main.cpp...
正确的解决方案是让main.o依赖于头文件,然后就可以大大简化main.exe的规则:
main.o: $(HEADER)
main.exe: main.o
$(LINKER) $< -o $@
makefile 中的
%.o: %.cpp
规则将提供配方,但您始终可以添加额外的依赖项,如我所示。
最后,Make 附带了一个用于编译 .cpp 文件的内置规则,该规则使用
$(CXX)
和 $(CXXFLAGS)
变量,因此,如果您只定义预期的变量,您可以使用更少的变量。
Makefile 的最终版本可以像这样简单:
CXX = g++
CXXFLAGS = -std=c++14 -Wall -Wextra -pedantic -O3
HEADER = function.hpp integral.hpp polynom.hpp trigonom.hpp riemann.hpp montecarlo.hpp
all: main.exe
main.exe: main.o
$(CXX) $< -o $@
main.o: $(HEADER)
clean:
-rm -f *.o
.PHONY: all clean