【问题标题】:How to write makefile for a target that includes a header file?如何为包含头文件的目标编写makefile?
【发布时间】:2020-02-08 20:46:12
【问题描述】:

我有两个文件“create-exercise.cpp”和“exercise.hpp”。我想编写一个 makefile 来使用 gnu++17 和 g++ 来编译它们。 exercise.hpp 包含在 create-exercise.cpp 中。我只想从 create-exercise.cpp 中获取二进制文件。我会使用的命令是g++ -std=gnu++17 create-exercise.cpp -o create-exercise,它运行良好。我尝试在make文件中使用以下内容。

CXXFLAGS=-Wall -std=gnu++17

create-exercise: create-exercise.cpp exercise.hpp

但生成了以下 g++ -Wall -std=gnu++17 create-exercise.cpp exercise.hpp -o create-exercise 我不希望 exercise.hpp 包含在编译命令中。我也尝试改用以下内容。

CXXFLAGS=-Wall -std=gnu++17

create-exercise.o: create-exercise.cpp exercise.hpp

生成g++ -Wall -std=gnu++17 -c -o create-exercise.o create-exercise.cpp。我不想要-c 标志。因为当我尝试运行create-exercise.o 时会导致权限被拒绝错误。我也尝试了以下方法:

CXXFLAGS=-Wall -std=gnu++17

create-exercise.o: create-exercise.cpp exercise.hpp
    $(CXX) $(CXXFLAGS) create-exercise.cpp -o create-exercise.o

但是当我编辑exercise.hpp 时,make 会说'create-exercise.o' is up to date. 并且不会重新编译它。我该怎么办?

【问题讨论】:

    标签: c++ c++11 makefile gnu-make


    【解决方案1】:

    在你的 makefile 中写入的规则是:

    create-exercise.o: exercise.hpp
    

    这是一条没有配方的规则,它只是向目标 create-exercise.o 添加了一个先决条件 (exercise.hpp),即,每当 exercise.hpp 发生变化时,都应该重建 create-exercise.o。

    但是,提供该规则时的问题是 GNU Make 假定 create-exercise.o 是在构建 create-exercise 时从 C 源文件生成的目标文件。因此,它不链接 C++ 库而是链接 C 库,这就是为什么您会遇到未定义引用 std::cout 的喜欢错误。

    GNU Make 具有以下从 C++ 源文件生成可执行文件的隐含规则:

    %: %.cpp
    #  commands to execute (built-in):
       $(LINK.cpp) $^ $(LOADLIBES) $(LDLIBS) -o $@
    

    您可以使用该规则的配方从creating-exercise.o 构建create-exercise,并且仍然将creating-exercise.o 视为从C++ 源文件生成的目标文件:

    create-exercise: create-exercise.o
        $(LINK.cpp) $^ $(LOADLIBES) $(LDLIBS) -o $@
    

    整个 makefile 将是:

    CXXFLAGS = -Wall -std=gnu++17 
    
    create-exercise: create-exercise.o
        $(LINK.cpp) $^ $(LOADLIBES) $(LDLIBS) -o $@
    
    create-exercise.o: exercise.hpp
    

    目标create-exercise 也成为默认目标,因为它是makefile 中的第一条规则。如果您不指定任何 make,它就是要构建的目标。

    【讨论】:

    • 两个sn-ps我都试过了,但没有用。生成的命令是cc create-exercise.o -o create-exercise。如果您想尝试,这里有一个github gist 与这两个文件。
    • @kerolloz 有什么问题?
    • 出现如下错误pastebin.com/raw/1yR0veRW
    • @kerolloz 我想我找到了问题所在。它链接到 C 库。查看我的编辑。
    • @kerolloz touch 更改文件的修改时间。如果您删除配方(即 touch 命令),它仅表示“create-exercise.cpp 需要构建文件 exercise.hpp”,只要 exercise.hpp 存在,一切都很好,而使用配方,它的意思是“如果exercise.hpp 比create-exercise.o 更新,那么create-exercise.cpp 已经过时”。然后执行配方以更新create-exercise.cpp。这种过时的情况会传播到create-exercise.o 和create-exercise。
    【解决方案2】:

    你可以这样做:

    CXXFLAGS = -Wall -std=gnu++17
    
    create-exercise: create-exercise.o
            $(LINK.cpp) $^ $(LDLIBS) -o $@
    
    create-exercise.o: exercise.hpp
    

    这表示:从目标文件 create-exercise.o 构建 create-exercise,如果它已更改。如果头文件exercise.hpp发生变化,它会说重建create-exercise.o;如果标头更改,则修改或重建 源文件 是不正确的。 目标文件依赖于头文件。

    Make 有许多内置规则。其中包括知道如何链接程序的规则,但不幸的是假设您的目标文件是从 C 文件构建的,因此如果您使用 C++,则必须创建特定的配方。但是你仍然可以使用 GNU make 的默认变量。

    它还知道如何自己从.cpp 文件构建.o 文件:您无需编写该配方。

    【讨论】:

    • 谢谢。这就是我最初表达的意思,问题是 GNU Make 将 create-exercise.o 视为从 C 文件生成的对象并链接到 C 库。
    【解决方案3】:

    我不确定,但也许尝试包含 .hpp 文件而不是与其他文件一起编译它。您可以通过使用 g++ *.cpp -I *.hpp -o output

    来做到这一点

    试试看,如果它适合你,请告诉我。

    【讨论】:

    • -I 指定包含文件夹,而不是头文件。
    猜你喜欢
    • 1970-01-01
    • 2012-07-06
    • 1970-01-01
    • 2014-04-28
    • 1970-01-01
    • 2016-04-13
    • 2014-07-12
    • 2018-06-24
    • 1970-01-01
    相关资源
    最近更新 更多