简体   繁体   English

CMake 共享库来自 object 库和 DLL 导出

[英]CMake shared library from object library & DLL exports

Background背景

I use cmake to build an open-source library .我使用 cmake 来构建一个开源库

The project is setup to do the following:该项目设置为执行以下操作:

  • Build a cmake OBJECT library named gpds-objs构建一个名为gpds-objs objs 的 cmake OBJECT
  • Build a STATIC library named gpds-static from gpds-objsgpds-objs objs 构建一个名为gpds-staticSTATIC
  • Build a SHARED library named gpds-shared from gpds-objsgpds-objs objs 构建一个名为gpds-sharedSHARED

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问题

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM