如何在 CMake 中使用动态链接库?

Nim*_*rab 8 c++ windows cmake dynamic-linking

我有简单的程序如下:

CMakeLists.txt:

cmake_minimum_required(VERSION 3.5)

project(test LANGUAGES CXX)

set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

LINK_DIRECTORIES(${PROJECT_SOURCE_DIR})

add_executable(test main.cpp)
target_include_directories(test PRIVATE ${PROJECT_SOURCE_DIR})    
target_link_libraries(test PRIVATE power.dll)
Run Code Online (Sandbox Code Playgroud)

主.cpp:

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

using namespace std;

int main()
{
    cout << "Hello World!" << endl;
    power(4.);
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

功率.h:

#ifndef POWER_H
#define POWER_H

double power(double number) noexcept;

#endif // POWER_H
Run Code Online (Sandbox Code Playgroud)

的实现power.h在一个名为 .dll 的文件中power.dll。如果我用 MinGW 7.3.0 X64 编译这个项目说:

error: undefined reference to `power(double)'
Run Code Online (Sandbox Code Playgroud)

如果我用 MSVC 2017 X64 编译它说:

error: LNK1104: cannot open file 'power.lib'
Run Code Online (Sandbox Code Playgroud)

这两个错误都表明power.dll链接器无法检测到。我做了很多搜索,但没有一个解决方案对我有用!任何人都可以帮助解决这个问题吗?提前致谢!

Com*_*sMS 5

您对动态库的建模在 CMake 和源代码级别都不正确。

作为起点,尝试将 dll 构建为与消费可执行文件相同的 CMake 项目的一部分:

cmake_minimum_required(VERSION 3.5)

project(test LANGUAGES CXX)

set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

include(GenerateExportHeader)
add_library(power SHARED power_sources.cpp power.h)
generate_export_header(power)
target_include_directories(power PUBLIC ${PROJECT_BINARY_DIR} ${PROJECT_SOURCE_DIR})

add_executable(test main.cpp)
target_link_libraries(test PRIVATE power)
Run Code Online (Sandbox Code Playgroud)

请注意该generate_export_header函数的使用,它指示 CMake 生成宏,以便以可移植的方式导出共享库接口上的函数。由于生成的文件进入二进制目录树,我们必须相应地调整库的包含目录。

为确保函数被正确导出,请按如下方式更改标题:

#ifndef POWER_H
#define POWER_H

#include <power_export.h>

POWER_EXPORT double power(double number) noexcept;

#endif // POWER_H
Run Code Online (Sandbox Code Playgroud)

请注意,它generare_export_header允许您广泛自定义生成的导出标题。

确保您从该基线构建和运行项目。

如果你想在外部构建 dll(这不是绝对必要的,但因为这就是你的问题......),我们必须将 CMake 文件修改为:

cmake_minimum_required(VERSION 3.5)

project(test LANGUAGES CXX)

set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

find_package(power)

add_executable(test main.cpp)
target_link_libraries(test PRIVATE power)
Run Code Online (Sandbox Code Playgroud)

所有的魔法都发生在find_package通话中。该调用现在负责提供以前由用于构建库的行处理的所有信息:

  • power通过target_link_libraries电话提供进口的消费目标
  • power.lib通过导入目标关联导入库(文件)的库名
  • 公众曝光包括目录 power.hpower_export.h经由进口目标

您可以在查找脚本中手动构建这样一个导入的目标,或者让 CMake 为您完成。在第一种情况下,创建一个FindPower.cmake脚本文件,确保它的位置是其中的一部分,CMAKE_MODULE_PATH并编写用于查找库和头文件并在其中构建导入目标的代码。请注意,以可移植的方式正确处理此问题可能非常棘手,并且远远超出了 StackOverflow 问题的范围。在第二种情况下,让构建power的 CMake 脚本执行安装步骤,在此期间将生成一个配置文件包,然后您的库可以使用它本身不是用 CMake 构建的,因此在这种情况下,您将有坚持第一个选择。test项目。请注意,如果power