[英]CMake shared library from object library & DLL exports
I use cmake to build an open-source library .我使用 cmake 来构建一个开源库。
The project is setup to do the following:该项目设置为执行以下操作:
OBJECT
library named gpds-objs
gpds-objs
objs 的 cmake OBJECT
库STATIC
library named gpds-static
from gpds-objs
gpds-objs
objs 构建一个名为gpds-static
的STATIC
库SHARED
library named gpds-shared
from gpds-objs
gpds-objs
objs 构建一个名为gpds-shared
的SHARED
库Furthermore, I'm using cmake's generate_export_header()
to generate the necessary export macros.此外,我正在使用 cmake 的
generate_export_header()
来生成必要的导出宏。
The relevant parts of the cmake script looks like this: cmake 脚本的相关部分如下所示:
# 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:库中的 class 定义如下所示:
#include "gpds_export.hpp"
namespace gpds
{
class GPDS_EXPORT container
{
// ...
};
}
For completeness, here's the relevant part of gpds_export.hpp
which gets generated by cmake's generate_export_header()
:为了完整起见,这里是由 cmake 的
generate_export_header()
生成的gpds_export.hpp
的相关部分:
#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
The problem I'm running into is when building gpds-objs
I am presented with the following messages:我遇到的问题是在构建
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.我不确定如何正确解决这个问题。
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
).据我了解,问题在于构建
gpds-objs
目标没有定义任何相关的导出宏(既没有GPDS_STATIC_DEFINE
也没有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_EXPORT
被定义为__declspec(dllimport)
,这是不正确的,因为我们没有使用gpds-objs
目标构建共享库。
One solution I can think of is defining gpds_shared_EXPORTS
on the gpds-objs
target instead of the gpds-shared
target.我能想到的一种解决方案是在
gpds-objs
目标而不是gpds-shared
目标上定义gpds_shared_EXPORTS
。 However, this would mean that it's also defined when building the gpds-static
target.但是,这意味着它也在构建
gpds-static
目标时定义。 This might be fine as long as gpds-static
defines GPDS_STATIC_DEFINE
.只要
gpds-static
定义了GPDS_STATIC_DEFINE
了。
What is the correct way of handling this?处理这个的正确方法是什么?
You cannot use the same OBJECT library both for shared and static libraries.您不能对共享库和 static 库使用相同的 OBJECT 库。
An OBJECT library determines how the source files should be compiled. OBJECT 库确定应如何编译源文件。 But source files should be compiled differently for a static and for a shared libraries.
但是对于 static 和共享库,源文件的编译方式应该不同。
Documentation for GenerateExportHeader describes, how the same generated header file could be used for static and shared libraries: GenerateExportHeader 的文档描述了相同生成的 header 文件如何用于 static 和共享库:
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.这里为共享库生成了导出 header,并且static库具有额外的编译定义,以便重用 header。 Note again, that different compile options, used for shared and static libraries, mean that you cannot reuse object files between these libraries.
再次注意,用于共享库和 static 库的不同编译选项意味着您不能在这些库之间重用object文件。 You could only reuse sources .
您只能重复使用sources 。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.