【问题标题】:Using a class and a function from different header files C++ and CMake使用来自不同头文件 C++ 和 CMake 的类和函数
【发布时间】:2020-12-25 18:04:33
【问题描述】:

我正在波恩大学的一门课程中学习现代 C++。 我在grass.h 文件中声明了一个类,并在相应的grass.cpp 文件中实现了它。同样,在另一个tools.h-tools.cpp 声明-实现对中是一个函数,它接受对上面定义的类对象的引用。最后,main.cpp 文件从第一对初始化一个 Grass 对象,并将其从第二对传递给函数。我能够编译main.cpp 并从这些命令行指令中获得所需的输出:

c++ -std=c++11 -g -c grass.cpp -o grass.o
c++ -std=c++11 -g -c tools.cpp -o tools.o
c++ -std=c++11 -g main.cpp grass.o tools.o -o main

但无法使用 CMake 执行此操作。我不知道命令行指令叫什么(链接和编译?)。

这里是代码示例“grass.h”:

#include <string>
#pragma once

class Grass
{
private:
    int green_;
    std::string name_;
public:
    Grass(int green, std::string name): green_{green}, name_{name} {}

    int get_green() const;                        // getter functions for 
    const std::string& get_green_name() const;    // both private members
};

这些函数只是返回值并在“grass.cpp”中实现。

然后我有一个“tools.h”:

#include <iostream>
#include "grass.h"

#pragma once

void PrintGrass(Grass& grObj);

这个函数只是打印来自 Grass 的 getter 函数的值。

最后,main.cpp 包含:

int main ()
{
    Grass grObj{10, "ABC"};
    PrintGrass(grObj);
    cout << endl;
    return 0;
}

CMake 错误发生在 100% Linking CXX executable main.错误在 tools.cpp 中: undefined reference to `Grass::get_green_name[abi:cxx11]()'undefined reference to `Grass::get_green()'。 这意味着程序无法找到这些函数的定义,对吧? CMake 文件如下所示:

set(CMAKE_CXX_STANDARD 11)
set(CMAKE_BUILD_TYPE Debug)
set(CMAKE_CXX_FLAGS "-Wall")
set(CMAKE_CXX_FLAGS_DEBUG "-g -O0")
add_library(grass grass.cpp)
add_library(tools tools.cpp)
add_executable(main main.cpp)
target_link_libraries(main grass tools)

如何使用 CMake 完成这项工作?非常感谢您的帮助。

【问题讨论】:

  • 这不是 CMake 错误。它是一个链接器错误,抱怨未定义的引用。这意味着您已经在grass.h 中声明了get_green()get_green_name(),但您还没有在grass.cpp 文件中实现它们。
  • 我对cmake了解不多,但我猜target_link_libraries和gcc中的常规-l标志一样脆弱,它会丢弃当时不使用的库。请改用target_link_libraries(main tools grass)
  • 或者只是不使用库,我不确定你为什么选择这条路线。 add_executable(main main.cpp grass.cpp tools.cpp) 会起作用。
  • 您的工作版本不构建库并与它们链接。除非您真的打算为每个文件构建一个库,否则您只需要 set 行和 add_executable(main main.cpp grass.cpp tools.cpp)
  • @Yksisarvinen CMake 能够在已知依赖关系的情况下解决链接排序问题。在此示例中,tools 库依赖于 grass 库,但未在任何地方指定。解决此问题的正确方法是添加另一行target_link_libraries(tools grass)。 PS。我建议使用target_link_libraries(x PUBLIC y),以便 CMake 知道我们使用的是现代语法。

标签: c++ c++11 cmake


【解决方案1】:

我通过将包含文件也添加到 add_library 中解决了类似的问题:

add_library(grass Grass.cpp Grass.h)

试试这个,看看它是否有效

【讨论】:

    【解决方案2】:

    我将总结 cmets 部分并根据 @pptaszni 的建议将整个代码和详细错误放在这里:
    整个代码按依赖顺序排列:

    1. grass.hgrass.cpp:
    #include <string>
    #pragma once
    
    class Grass
    {
    public:
        Grass(int green, std::string name): green_{green}, name_{name} {}
    
        int get_green ();
        std::string get_green_name ();
    private:
        int green_ = 100;
        std::string name_ = "Joe";
    };
    

    #include "grass.h"
    
    Grass::Grass(int green, std::string name): green_{green}, name_{name}{}
    
    int Grass::get_green() {
        return green_;  
    }
    
    std::string Grass::get_green_name() { 
        return name_;
    }
    
    1. tools.htools.cpp:
    #include <iostream>
    #include "grass.h"
    
    #pragma once
    
    void PrintGrass(Grass& grObj);
    

    #include <iostream>
    #include "grass.h"
    #include "tools.h"
    
    void PrintGrass(Grass& grObj)
    {
        std::cout << grObj.get_green_name() << ", " << grObj.get_green() << " ";
    }
    
    1. main.cpp
    #include <iostream>
    #include "grass.h"
    #include "tools.h"
    #include <string>
    
    using std::string;
    using std::cout;
    using std::endl;
    
    
    int main ()
    {
        Grass grObj{10, "Jane"};
        PrintGrass(grObj);
        cout << endl;
        return 0;
    }
    
    1. CMakeLists.txt
    project(Grasses)
    cmake_minimum_required(VERSION 3.0)
    set(CMAKE_CXX_STANDARD 11)
    set(CMAKE_BUILD_TYPE Debug)
    set(CMAKE_CXX_FLAGS "-Wall")
    set(CMAKE_CXX_FLAGS_DEBUG "-g -O0")
    add_library(grass grass.cpp)
    add_library(tools tools.cpp)
    add_executable(main main.cpp)
    target_link_libraries(main grass tools)
    

    make VERBOSE=1 的错误 outputverbose,已粘贴到 Github Gist 中,以免这篇文章比现在长。

    总结
    什么有效?写作

    target_link_libraries(main tools grass)
    

    而不是

    target_link_libraries(main grass tools).
    

    @Yksisarvinen 给出的解释中的要点是始终将没有任何依赖关系的库放在最后。这是因为编译器可能会查看这些库并丢弃它们,如果它在处理它的时候没有发现它有任何用处。

    另一件有效的事情是只使用add_executable(main main.cpp grass.cpp tools.cpp),而不是添加库然后链接它们。这是@molbdnilo 和@Yksisarvinen 建议的。

    感谢大家帮助我更好地理解 C++。

    【讨论】:

    • 真正的问题是tools 库依赖于grass 库,但它没有在任何地方指定。解决此问题的正确方法是添加另一行 target_link_libraries(tools grass)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-06-05
    • 2018-04-02
    • 1970-01-01
    • 2020-10-02
    • 1970-01-01
    • 1970-01-01
    • 2017-08-31
    相关资源
    最近更新 更多