c++ - 如何使用 cmake 创建在共享库中定义但在其他目标中声明的外部方法?

标签 c++ cmake c++14

问题如下:你有两个文件,一个是库文件,一个是可执行文件,你想调用库中定义但在可执行文件中声明的方法:

lib.cpp:

extern void Method();


void DoStuff() {
    Method();
}

ma​​in.cpp:

#include <iostream>

void Method() {
    std::cout << "Do Stuff" << std::endl;
}

int main() {
    Method();
    return 0;
}

现在使用 cmake 我基本上只是想告诉库 DoStuff 方法的声明在可执行目标中。

使用这个简单的 CMakeLists.txt 会导致 undefined symbol 链接器错误:

Undefined symbols for architecture x86_64:
  "Method()", referenced from:
     DoStuff() in lib.cpp.o

CMakeLists.txt

cmake_minimum_required(VERSION 3.14)
project(extern)

set(CMAKE_CXX_STANDARD 14)

add_library(myLib SHARED lib.cpp)    
add_executable(exe main.cpp)

target_link_libraries(exe myLib)

我发现的唯一方法是通过一个临时静态库并将我的共享库与那个静态库链接起来,我认为这很讨厌,因为我很快向可执行文件添加了更多类,我得到了重复的符号(这完全有道理因为它们是重复的)

add_library(tmpLib STATIC main.cpp)
target_link_libraries(myLib tmpLib)

我已经在互联网上浏览了两个晚上,现在正在寻找一种方法来做到这一点,但我仍然完全没有头绪。

最佳答案

错误发生在链接目标文件以创建库文件的过程中。尝试 OBJECT add_library 中的关键字,而不是 SHARED。这将创建目标文件,但不会链接它们。然后,您可以使用 target_link_libraries 以相同的方式将这些目标文件链接到您的可执行文件。由于链接器将运行一次以创建您的可执行文件,并且您的可执行文件包含 Method 的定义,因此链接器不应该提示。

此外,extern 说明符在这里不是必需的,因为默认情况下函数具有外部链接。

根据您的链接器,可能有一种晦涩的方式告诉它忽略未解析的符号,但这是非常不合常规的、违反直觉的、出乎意料的,并且会让其他用户/开发人员和您 future 的自己感到困惑,因此您应该避免它不惜一切代价使用真实代码。参见 this询问详情。

注意:您的代码在使用 g++ 8.3.0、GNU ld 2.32.1 的 Debian 10 x64 上可以正常工作。

关于c++ - 如何使用 cmake 创建在共享库中定义但在其他目标中声明的外部方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57468669/

相关文章:

c++ - 生成随机约束图

c++ - C++11 目标构造函数是否允许我从模板构造函数安全地初始化派生类?

binary - CMake 的可移植可执行文件

c++ - boost foreach 和运算符重载

c++ - 如何检查 C++ 编译器是否使用 IEEE 754 浮点标准

c++ - 在库中使用 Qt5

c++ - 在Linux上构建Ogre时出错: narrowing conversion

c++ - 用户定义的转换无法指定返回类型

c++ - 运行时检查失败 #2 - 变量 'numberchoices' 周围的堆栈已损坏

c++ - 派生类不调用基类的成员函数