在 C++ MAKEFILES 中包含头文件(.hpp)

问题描述 投票:0回答:1

我已经为此苦苦挣扎了一个小时,并通过它与 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 变量。没成功。

希望大家能帮忙,抱歉文字太长。谢谢!

c++ makefile g++ header-files
1个回答
0
投票

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
© www.soinside.com 2019 - 2024. All rights reserved.