我有一个简单的程序,如下所示:
CMakeLists.txt:
shellComponent
main.cpp:
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)
power.h:
#include <iostream>
#include "power.h"
using namespace std;
int main()
{
cout << "Hello World!" << endl;
power(4.);
return 0;
}
#ifndef POWER_H
#define POWER_H
double power(double number) noexcept;
#endif // POWER_H
的实现位于名为power.h
的.dll中。
如果我使用MinGW 7.3.0 X64编译该项目,则说:
power.dll
如果我使用MSVC 2017 X64进行编译说:
error: undefined reference to `power(double)'
两个错误均表明链接器无法检测到error: LNK1104: cannot open file 'power.lib'
。
我进行了很多搜索,但是没有一种解决方案适合我!
有人可以帮忙吗?
预先感谢!
答案 0 :(得分:1)
您在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)
请注意使用generate_export_header
函数,该函数指示CMake以可移植的方式生成宏,以便在共享库接口上导出函数。由于生成的文件进入二进制目录树,因此我们必须相应地调整库的包含目录。
要确保正确导出函数,请按如下所示更改标头:
#ifndef POWER_H
#define POWER_H
#include <power_export.h>
POWER_EXPORT double power(double number) noexcept;
#endif // POWER_H
请注意,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)
find_package
调用中发生了所有不可思议的事情。现在,该调用负责提供以前由构建库的行处理过的所有信息:
power
以供target_link_libraries
调用使用power.lib
文件)的库名power.h
和power_export.h
的目录您可以在查找脚本中手动构造这样的导入目标,也可以让CMake为您完成。在第一种情况下,创建一个FindPower.cmake
脚本文件,确保其位置是CMAKE_MODULE_PATH
的一部分,并编写代码以查找库和头文件并在其中构建导入的目标。请注意,以可移植的方式正确完成此操作可能非常棘手,并且远远超出了StackOverflow问题的范围。在第二种情况下,请构建power
库的CMake脚本 执行安装步骤,在此过程中将生成a config file package,然后您的{{1 }}项目。请注意,如果test
库本身不是使用CMake构建的,则这种方法不可行,因此在这种情况下,您将不得不坚持第一种选择。
答案 1 :(得分:0)
Windows中的动态链接要求使用关键字__declspec
声明外部可见的符号。您的标头“ power.h”应进行修改:
#ifndef POWER_H
#define POWER_H
#if defined(__WIN32__) && !defined(__CYGWIN__)
# if (defined(_MSC_VER) || defined(__MINGW32__)) && defined(BUILD_DLL)
# define POWERAPI __declspec(dllexport)
# elif (defined(_MSC_VER) || defined(__MINGW32__))
# define POWERAPI __declspec(dllimport)
# endif
#endif
POWERAPI double power(double number) noexcept;
#endif // POWER_H
在使用CMake构建DLL power.dll的项目中,您应该define the symbol BUILD_DLL:
add_definitions(-DBUILD_DLL)
然后,当MSVC编译器和使用MINGW时,它应该生成power.lib文件。不要在使用DLL的项目中定义BUILD_DLL,它应该可以工作。