来自对象库的 CMake 共享库 &DLL 导出 [英] CMake shared library from object library & DLL exports
问题描述
我使用 cmake 构建了一个 开源库.
I use cmake to build an open-source library.
该项目设置为执行以下操作:
The project is setup to do the following:
- 构建一个名为
gpds-objs
的 cmake - 从
gpds-objs
构建一个名为 - 从
gpds-objs
构建一个名为
OBJECT
库gpds-static
的STATIC
库gpds-shared
的SHARED
库此外,我使用 cmake 的 generate_export_header()
来生成必要的导出宏.
Furthermore, I'm using cmake's generate_export_header()
to generate the necessary export macros.
cmake 脚本的相关部分如下所示:
The relevant parts of the cmake script looks like this:
# Set project information
project(gpds
VERSION 1.0.0
LANGUAGES CXX
HOMEPAGE_URL "https://gpds.simulton.com"
)
# Some bacis cmake configuration
set(CMAKE_INCLUDE_CURRENT_DIR ON)
set(CMAKE_INCLUDE_CURRENT_DIR_IN_INTERFACE ON)
# List of private source files
set(SOURCES_PRIVATE
# ...
)
# List of private header files
set(HEADERS_PRIVATE
# ...
)
# List of public header files
set(HEADERS_PUBLIC
# ...
)
# Define targets
set(NAME gpds)
set(TARGET-OBJS ${NAME}-objs)
set(TARGET-STATIC ${NAME}-static)
set(TARGET-SHARED ${NAME}-shared)
################################################################################
# Object library #
################################################################################
add_library(${TARGET-OBJS} OBJECT)
target_compile_features(
gpds-objs
PUBLIC
cxx_std_17
)
target_sources(
${TARGET-OBJS}
PRIVATE
${SOURCES_PRIVATE}
${HEADERS_PRIVATE}
)
target_include_directories(
${TARGET-OBJS}
INTERFACE
$<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/include>
PRIVATE
$<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/include/gpds>
)
################################################################################
# Shared library #
################################################################################
add_library(${TARGET-SHARED} SHARED)
target_link_libraries(
${TARGET-SHARED}
PUBLIC
gpds-objs
)
target_compile_definitions(
${TARGET-SHARED}
PRIVATE
gpds_shared_EXPORTS # We're building this library!
)
################################################################################
# Static library #
################################################################################
add_library(${TARGET-STATIC} STATIC)
target_link_libraries(
${TARGET-STATIC}
PUBLIC
gpds-objs
)
target_compile_definitions(
${TARGET-STATIC}
PUBLIC
GPDS_STATIC_DEFINE
)
# Common library properties
set_target_properties(
${TARGET-OBJS}
${TARGET-STATIC}
${TARGET-SHARED}
PROPERTIES
OUTPUT_NAME "gpds"
ARCHIVE_OUTPUT_NAME "gpds"
VERSION ${PROJECT_VERSION}
POSITION_INDEPENDENT_CODE 1
)
################################################################################
# Export header #
################################################################################
include(GenerateExportHeader)
generate_export_header(
${TARGET-SHARED}
BASE_NAME gpds
EXPORT_FILE_NAME gpds_export.hpp
DEPRECATED_MACRO_NAME "GPDS_DEPRECATED"
NO_DEPRECATED_MACRO_NAME "GPDS_NO_DEPRECATED"
EXPORT_MACRO_NAME "GPDS_EXPORT"
NO_EXPORT_MACRO_NAME "GPDS_NO_EXPORT"
STATIC_DEFINE "GPDS_STATIC_DEFINE"
DEFINE_NO_DEPRECATED
)
库中的类定义如下所示:
A class definition within the library looks like this:
#include "gpds_export.hpp"
namespace gpds
{
class GPDS_EXPORT container
{
// ...
};
}
为了完整起见,这是由 cmake 的 generate_export_header()
生成的 gpds_export.hpp
的相关部分:
For completeness, here's the relevant part of gpds_export.hpp
which gets generated by cmake's generate_export_header()
:
#ifdef GPDS_STATIC_DEFINE
# define GPDS_EXPORT
# define GPDS_NO_EXPORT
#else
# ifndef GPDS_EXPORT
# ifdef gpds_shared_EXPORTS
/* We are building this library */
# define GPDS_EXPORT __declspec(dllexport)
# else
/* We are using this library */
# define GPDS_EXPORT __declspec(dllimport)
# endif
# endif
# ifndef GPDS_NO_EXPORT
# define GPDS_NO_EXPORT
# endif
#endif
问题
我遇到的问题是在构建 gpds-objs
时我看到以下消息:
C:\Users\joel\Documents\projects\gpds\lib\src\value.cpp:7:1: warning: 'gpds::value::value(const gpds::value&)' redeclared without dllimport attribute: previous dllimport ignored [-Wattributes]
7 | value::value(const value& other) :
| ^~~~~
C:\Users\joel\Documents\projects\gpds\lib\src\value.cpp:17:1: warning: 'gpds::value::value(gpds::value&&)' redeclared without dllimport attribute: previous dllimport ignored [-Wattributes]
17 | value::value(value&& other) :
| ^~~~~
C:\Users\joel\Documents\projects\gpds\lib\src\value.cpp:25:1: warning: 'virtual gpds::value::~value()' redeclared without dllimport attribute: previous dllimport ignored [-Wattributes]
25 | value::~value() noexcept
| ^~~~~
C:\Users\joel\Documents\projects\gpds\lib\src\value.cpp:33:6: warning: 'void gpds::value::from_string(std::string&&)' redeclared without dllimport attribute: previous dllimport ignored [-Wattributes]
33 | void value::from_string(std::string&& string)
我不确定如何正确解决这个问题.
I am unsure how to solve this properly.
据我所知,问题在于构建 gpds-objs
目标没有定义任何相关的导出宏(GPDS_STATIC_DEFINE
和 gpds_shared_EXPORTS
代码>).因此,GPDS_EXPORT
被定义为 __declspec(dllimport)
,这是不正确的,因为我们没有使用 gpds-objs
目标构建共享库.
From what I understand the problem is that building the gpds-objs
target does not define any of the relevant export macros (neither GPDS_STATIC_DEFINE
nor gpds_shared_EXPORTS
). Therefore, GPDS_EXPORT
gets defined to __declspec(dllimport)
which is incorrect as we're not building a shared library with the gpds-objs
target.
我能想到的一种解决方案是在 gpds-objs
目标而不是 gpds-shared
目标上定义 gpds_shared_EXPORTS
.然而,这意味着它也在构建 gpds-static
目标时被定义.这可能没问题,只要 gpds-static
定义了 GPDS_STATIC_DEFINE
.
One solution I can think of is defining gpds_shared_EXPORTS
on the gpds-objs
target instead of the gpds-shared
target. However, this would mean that it's also defined when building the gpds-static
target. This might be fine as long as gpds-static
defines GPDS_STATIC_DEFINE
.
处理这个问题的正确方法是什么?
What is the correct way of handling this?
推荐答案
您不能对共享库和静态库使用相同的 OBJECT 库.
You cannot use the same OBJECT library both for shared and static libraries.
OBJECT 库决定了源文件的编译方式.但是对于静态库和共享库,源文件应该以不同方式编译.
An OBJECT library determines how the source files should be compiled. But source files should be compiled differently for a static and for a shared libraries.
GenerateExportHeader 的文档 描述了如何生成相同的头文件可用于静态和共享库:
Documentation for GenerateExportHeader describes, how the same generated header file could be used for static and shared libraries:
add_library(shared_variant SHARED ${lib_SRCS})
add_library(static_variant ${lib_SRCS})
generate_export_header(shared_variant BASE_NAME libshared_and_static)
set_target_properties(static_variant PROPERTIES
COMPILE_FLAGS -DLIBSHARED_AND_STATIC_STATIC_DEFINE)
这里为共享库生成了导出头文件,静态库有额外的编译定义以重用该头文件.再次注意,用于共享库和静态库的不同编译选项意味着您不能在这些库之间重用对象文件.您只能重复使用来源.
Here the export header is generated for the shared library, and the static library has additional compile definition for reuse that header. Note again, that different compile options, used for shared and static libraries, mean that you cannot reuse object files between these libraries. You could only reuse sources.
这篇关于来自对象库的 CMake 共享库 &DLL 导出的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!