来自对象库的 CMake 共享库 &DLL 导出 [英] CMake shared library from object library & DLL exports

查看:89
本文介绍了来自对象库的 CMake 共享库 &DLL 导出的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用 cmake 构建了一个 开源库.

I use cmake to build an open-source library.

该项目设置为执行以下操作:

The project is setup to do the following:

  • 构建一个名为 gpds-objs
  • 的 cmake OBJECT
  • gpds-objs
  • 构建一个名为gpds-staticSTATIC
  • gpds-objs
  • 构建一个名为gpds-sharedSHARED

此外,我使用 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_DEFINEgpds_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 共享库 &amp;DLL 导出的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆