Skip to content

CXX-2803 Add ABI tag to library filenames on Windows #1081

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 10 commits into from
Jan 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Note: user-defined forward declarations of any library entity has not been, and is still not, supported.
To obtain the declaration or definition of a library entity, always include the corresponding header.

### Changed

- Library filenames, when compiled with MSVC (as detected by [CMake's MSVC variable](https://cmake.org/cmake/help/v3.15/variable/MSVC.html)), are now embedded with an ABI tag string, e.g. `bsoncxx-v_noabi-rhs-x64-v142-md.lib`.
- This new behavior is enabled by default; disable by setting `ENABLE_ABI_TAG_IN_LIBRARY_FILENAMES=OFF` when configuring the CXX Driver.
- The ABI tag string can also be embedded in pkg-config metadata filenames, e.g. `libbsoncxx-v_noabi-rhs-x64-v142-md.pc`. This is disabled by default; enable by setting `ENABLE_ABI_TAG_IN_PKGCONFIG_FILENAMES=ON` (requires `ENABLE_ABI_TAG_IN_LIBRARY_FILENAMES=ON`).

### Removed

- Deprecated CMake package config files.
Expand Down
56 changes: 40 additions & 16 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,7 @@ endif()
set(CMAKE_CXX_EXTENSIONS OFF)

# Include the required modules
include(CMakeDependentOption)
include(GenerateExportHeader)
include(InstallRequiredSystemLibraries)

Expand All @@ -156,6 +157,22 @@ option(BUILD_SHARED_LIBS_WITH_STATIC_MONGOC
OFF
)

if(DEFINED CACHE{ENABLE_ABI_TAG_IN_LIBRARY_FILENAMES} AND NOT MSVC)
message(WARNING "ENABLE_ABI_TAG_IN_LIBRARY_FILENAMES is an MSVC-only option and will be ignored by the current configuration")
unset(ENABLE_ABI_TAG_IN_LIBRARY_FILENAMES CACHE)
endif()

if(DEFINED CACHE{ENABLE_ABI_TAG_IN_PKGCONFIG_FILENAMES} AND NOT $CACHE{ENABLE_ABI_TAG_IN_LIBRARY_FILENAMES})
message(WARNING "ENABLE_ABI_TAG_IN_PKGCONFIG_FILENAMES requires ENABLE_ABI_TAG_IN_LIBRARY_FILENAMES=ON and will be ignored by the current configuration")
unset(ENABLE_ABI_TAG_IN_PKGCONFIG_FILENAMES CACHE)
endif()

# Allow user to disable embedding of ABI tag in library filenames (MSVC only).
cmake_dependent_option(ENABLE_ABI_TAG_IN_LIBRARY_FILENAMES "Embed ABI tag in library filenames" ON "MSVC" OFF)

# Allow user to enable embedding of ABI tag in pkg-config metadata filenames (MSVC only).
cmake_dependent_option(ENABLE_ABI_TAG_IN_PKGCONFIG_FILENAMES "Embed ABI tag in pkg-config metadata filenames" OFF "ENABLE_ABI_TAG_IN_LIBRARY_FILENAMES" OFF)

option(ENABLE_UNINSTALL "Enable creation of uninstall script and associated uninstall build target." ON)

# Allow the user to enable code coverage
Expand Down Expand Up @@ -430,26 +447,33 @@ if(NOT(TARGET dist OR TARGET distcheck))

# Ensure distcheck inherits polyfill library selection.
set(polyfill_flags "")
if (NOT "${CMAKE_CXX_STANDARD}" STREQUAL "")
list(APPEND polyfill_flags "-DCMAKE_CXX_STANDARD=${CMAKE_CXX_STANDARD}")
endif ()
if (NOT "${BOOST_ROOT}" STREQUAL "")
list(APPEND polyfill_flags "-DBOOST_ROOT=${BOOST_ROOT}")
endif ()
if (NOT "${BSONCXX_POLY_USE_MNMLSTC}" STREQUAL "")
list(APPEND polyfill_flags "-DBSONCXX_POLY_USE_MNMLSTC=${BSONCXX_POLY_USE_MNMLSTC}")

if(NOT "${CMAKE_CXX_STANDARD}" STREQUAL "")
list(APPEND polyfill_flags "-DCMAKE_CXX_STANDARD=${CMAKE_CXX_STANDARD}")
endif()
if (NOT "${BSONCXX_POLY_USE_STD_EXPERIMENTAL}" STREQUAL "")
list(APPEND polyfill_flags "-DBSONCXX_POLY_USE_STD_EXPERIMENTAL=${BSONCXX_POLY_USE_STD_EXPERIMENTAL}")

if(NOT "${BOOST_ROOT}" STREQUAL "")
list(APPEND polyfill_flags "-DBOOST_ROOT=${BOOST_ROOT}")
endif()
if (NOT "${BSONCXX_POLY_USE_SYSTEM_MNMLSTC}" STREQUAL "")
list(APPEND polyfill_flags "-DBSONCXX_POLY_USE_SYSTEM_MNMLSTC=${BSONCXX_POLY_USE_SYSTEM_MNMLSTC}")

if(NOT "${BSONCXX_POLY_USE_MNMLSTC}" STREQUAL "")
list(APPEND polyfill_flags "-DBSONCXX_POLY_USE_MNMLSTC=${BSONCXX_POLY_USE_MNMLSTC}")
endif()

if(NOT "${BSONCXX_POLY_USE_STD_EXPERIMENTAL}" STREQUAL "")
list(APPEND polyfill_flags "-DBSONCXX_POLY_USE_STD_EXPERIMENTAL=${BSONCXX_POLY_USE_STD_EXPERIMENTAL}")
endif()
if (NOT "${BSONCXX_POLY_USE_BOOST}" STREQUAL "")
list(APPEND polyfill_flags "-DBSONCXX_POLY_USE_BOOST=${BSONCXX_POLY_USE_BOOST}")

if(NOT "${BSONCXX_POLY_USE_SYSTEM_MNMLSTC}" STREQUAL "")
list(APPEND polyfill_flags "-DBSONCXX_POLY_USE_SYSTEM_MNMLSTC=${BSONCXX_POLY_USE_SYSTEM_MNMLSTC}")
endif()
if (NOT "${BSONCXX_POLY_USE_STD}" STREQUAL "")
list(APPEND polyfill_flags "-DBSONCXX_POLY_USE_STD=${BSONCXX_POLY_USE_STD}")

if(NOT "${BSONCXX_POLY_USE_BOOST}" STREQUAL "")
list(APPEND polyfill_flags "-DBSONCXX_POLY_USE_BOOST=${BSONCXX_POLY_USE_BOOST}")
endif()

if(NOT "${BSONCXX_POLY_USE_STD}" STREQUAL "")
list(APPEND polyfill_flags "-DBSONCXX_POLY_USE_STD=${BSONCXX_POLY_USE_STD}")
endif()

add_custom_target(distcheck DEPENDS dist
Expand Down
120 changes: 118 additions & 2 deletions cmake/BsoncxxUtil.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,133 @@ function(bsoncxx_add_library TARGET OUTPUT_NAME LINK_TYPE)
${bsoncxx_sources}
)

# Full ABI tag string to append to library output name.
# The value is determined at generator-time when using a multi-config generator.
# Otherwise, the value is determined at configure-time.
set(abi_tag "")

# ABI tag and properties.
if(1)
# Enforce ABI compatibility in dependent targets.
set_property(TARGET ${TARGET} APPEND PROPERTY COMPATIBLE_INTERFACE_STRING
BSONCXX_ABI_TAG_MONGOC_LINK_TYPE
BSONCXX_ABI_TAG_POLYFILL_LIBRARY
)

# ABI version number. Only necessary for shared library targets.
if(LINK_TYPE STREQUAL "SHARED")
set(soversion _noabi)
set_target_properties(${TARGET} PROPERTIES SOVERSION ${soversion})
string(APPEND abi_tag "-v${soversion}")
endif()

# Build type:
# - 'd' for debug.
# - 'r' for release (including RelWithDebInfo and MinSizeRel).
# - 'u' for unknown (e.g. to allow user-defined configurations).
# Compatibility is handled via CMake's IMPORTED_CONFIGURATIONS rather than interface properties.
string(APPEND abi_tag "-$<IF:$<CONFIG:Debug>,d,$<IF:$<OR:$<CONFIG:Release>,$<CONFIG:RelWithDebInfo>,$<CONFIG:MinSizeRel>>,r,u>>")

# Link type with libmongoc.
# - 'h' for shared.
# - 't' for static.
if(1)
if(BSONCXX_LINK_WITH_STATIC_MONGOC)
set(mongoc_link_type "t")
else()
set(mongoc_link_type "h")
endif()

set_target_properties(${TARGET} PROPERTIES INTERFACE_BSONCXX_ABI_TAG_MONGOC_LINK_TYPE ${mongoc_link_type})

string(APPEND abi_tag "${mongoc_link_type}")
endif()

# Library used for C++17 polyfills:
# - 'm' for mnmlstc/core.
# - 'b' for Boost.
# - 'x' for experimental standard library.
# - 'i' for bsoncxx implementations.
# - 's' for standard library (no polyfill).
if(1)
if(BSONCXX_POLY_USE_MNMLSTC)
set(polyfill "m")
elseif(BSONCXX_POLY_USE_BOOST)
set(polyfill "b")
elseif(BSONCXX_POLY_USE_STD_EXPERIMENTAL)
set(polyfill "x")
elseif(0) # CXX-2796: reserved for bsoncxx implementations as polyfill.
set(polyfill "i")
elseif(BSONCXX_POLY_USE_STD)
set(polyfill "s")
else()
message(FATAL_ERROR "could not determine polyfill library: must be one of [mbxis]")
endif()

set_target_properties(${TARGET} PROPERTIES INTERFACE_BSONCXX_ABI_TAG_POLYFILL_LIBRARY ${polyfill})

string(APPEND abi_tag "${polyfill}")
endif()

# MSVC-specific ABI tag suffixes.
if(MSVC)
set(vs_suffix "")

# Include the target architecture if applicable (Win32, x64, etc.).
if(CMAKE_VS_PLATFORM_NAME)
string(APPEND vs_suffix "-$<LOWER_CASE:${CMAKE_VS_PLATFORM_NAME}>")
endif()

# Include the platform toolset version if applicable (v140, v142, etc.).
if(CMAKE_VS_PLATFORM_TOOLSET)
string(APPEND vs_suffix "-$<LOWER_CASE:${CMAKE_VS_PLATFORM_TOOLSET}>")
endif()

# Include the C runtime if applicable.
if(1)
get_target_property(runtime ${TARGET} MSVC_RUNTIME_LIBRARY)

if(runtime)
if(runtime STREQUAL "MultiThreaded")
set(runtime_str "mt")
elseif(runtime STREQUAL "MultiThreadedDebug")
set(runtime_str "mtd")
elseif(runtime STREQUAL "MultiThreadedDLL")
set(runtime_str "md")
elseif(runtime STREQUAL "MultiThreadedDebugDLL")
set(runtime_str "mdd")
endif()
else()
# Per CMake documentation: if MSVC_RUNTIME_LIBRARY is not set, then
# CMake uses the default value MultiThreaded$<$<CONFIG:Debug>:Debug>DLL
# to select a MSVC runtime library.
set(runtime_str "m$<$<CONFIG:Debug>:d>d")
endif()

string(APPEND vs_suffix "-${runtime_str}")
endif()

set_target_properties(${TARGET} PROPERTIES BSONCXX_ABI_TAG_VS_SUFFIX ${vs_suffix})

string(APPEND abi_tag "${vs_suffix}")
endif()
endif()

set_target_properties(${TARGET} PROPERTIES
OUTPUT_NAME ${OUTPUT_NAME}
VERSION ${BSONCXX_VERSION}
DEFINE_SYMBOL BSONCXX_EXPORT
)

if(ENABLE_ABI_TAG_IN_LIBRARY_FILENAMES)
set_target_properties(${TARGET} PROPERTIES OUTPUT_NAME ${OUTPUT_NAME}${abi_tag})
else()
set_target_properties(${TARGET} PROPERTIES OUTPUT_NAME ${OUTPUT_NAME})
endif()

if(LINK_TYPE STREQUAL "SHARED")
set_target_properties(${TARGET} PROPERTIES
CXX_VISIBILITY_PRESET hidden
VISIBILITY_INLINES_HIDDEN ON
SOVERSION _noabi
)
endif()

Expand Down
77 changes: 75 additions & 2 deletions cmake/MongocxxUtil.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,90 @@ function(mongocxx_add_library TARGET OUTPUT_NAME LINK_TYPE)
${mongocxx_sources}
)

# Full ABI tag string to append to library output name.
# The value is determined at generator-time when using a multi-config generator.
# Otherwise, the value is determined at configure-time.
set(abi_tag "")

# ABI tag and properties.
if(1)
# Many ABI tag fields are inherited from bsoncxx (must be consistent).
if(BSONCXX_BUILD_SHARED)
set(bsoncxx_target bsoncxx_shared)
else()
set(bsoncxx_target bsoncxx_static)
endif()

# ABI version number. Only necessary for shared library targets.
if(LINK_TYPE STREQUAL "SHARED")
set(soversion _noabi)
set_target_properties(${TARGET} PROPERTIES SOVERSION ${soversion})
string(APPEND abi_tag "-v${soversion}")
endif()

# Build type. Inherit from bsoncxx.
if(1)
get_target_property(build_type ${bsoncxx_target} INTERFACE_BSONCXX_ABI_TAG_BUILD_TYPE)

set_target_properties(${TARGET} PROPERTIES
BSONCXX_ABI_TAG_BUILD_TYPE ${build_type}
INTERFACE_BSONCXX_ABI_TAG_BUILD_TYPE ${build_type}
)

string(APPEND abi_tag "-${build_type}")
endif()

# Link type with libmongoc. Inherit from bsoncxx.
if(1)
get_target_property(mongoc_link_type ${bsoncxx_target} INTERFACE_BSONCXX_ABI_TAG_MONGOC_LINK_TYPE)

set_target_properties(${TARGET} PROPERTIES
BSONCXX_ABI_TAG_MONGOC_LINK_TYPE ${mongoc_link_type}
INTERFACE_BSONCXX_ABI_TAG_MONGOC_LINK_TYPE ${mongoc_link_type}
)

string(APPEND abi_tag "${mongoc_link_type}")
endif()

# Library used for C++17 polyfills. Inherit from bsoncxx.
if(1)
get_target_property(polyfill ${bsoncxx_target} INTERFACE_BSONCXX_ABI_TAG_POLYFILL_LIBRARY)

set_target_properties(${TARGET} PROPERTIES
BSONCXX_ABI_TAG_POLYFILL_LIBRARY ${polyfill}
INTERFACE_BSONCXX_ABI_TAG_POLYFILL_LIBRARY ${polyfill}
)

string(APPEND abi_tag "${polyfill}")
endif()

# MSVC-specific ABI tag suffixes. Inherit from bsoncxx.
if(MSVC)
get_target_property(vs_suffix ${bsoncxx_target} BSONCXX_ABI_TAG_VS_SUFFIX)
set_target_properties(${TARGET} PROPERTIES
BSONCXX_ABI_TAG_VS_SUFFIX ${vs_suffix}
INTERFACE_BSONCXX_ABI_TAG_VS_SUFFIX ${vs_suffix}
)

string(APPEND abi_tag "${vs_suffix}")
endif()
endif()

set_target_properties(${TARGET} PROPERTIES
OUTPUT_NAME ${OUTPUT_NAME}
VERSION ${MONGOCXX_VERSION}
DEFINE_SYMBOL MONGOCXX_EXPORTS
)

if(ENABLE_ABI_TAG_IN_LIBRARY_FILENAMES)
set_target_properties(${TARGET} PROPERTIES OUTPUT_NAME ${OUTPUT_NAME}${abi_tag})
else()
set_target_properties(${TARGET} PROPERTIES OUTPUT_NAME ${OUTPUT_NAME})
endif()

if(LINK_TYPE STREQUAL "SHARED")
set_target_properties(${TARGET} PROPERTIES
CXX_VISIBILITY_PRESET hidden
VISIBILITY_INLINES_HIDDEN ON
SOVERSION _noabi
)
endif()

Expand Down
32 changes: 32 additions & 0 deletions docs/content/mongocxx-v3/api-abi-versioning.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,38 @@ title = "API and ABI versioning"

*DSO = Dynamic Shared Object, to use Ulrich Drepper's terminology*

### Windows (MSVC only)

Since version 3.10.0, the physical filename for CXX Driver libraries is different
from other platforms when built with the MSVC toolchain on Windows
(even when the CMake generator is not Visual Studio).
To restore prior behavior, which is similar to other platforms, set `ENABLE_ABI_TAG_IN_LIBRARY_FILENAMES=OFF`.

* Physical filename for a DSO is `mongocxx-$ABI-$TAG.dll`
* Physical filename for a static library is `mongocxx-static-$TAG.lib`

Where `$TAG` is a triplet of letters indicating:

* Build Type
* mongoc Link Type
* Polyfill Library

followed by a suffix describing the toolset and runtime library used to build the library.

Some examples of common DSO filenames expected to be generated include:

* mongocxx-v_noabi-rhs-x64-v142-md.dll (release build configuration)
* mongocxx-v_noabi-dhs-x64-v142-mdd.dll (debug build configuration)
* mongocxx-v_noabi-rts-x64-v142-md.dll (link with mongoc statically)
* mongocxx-v_noabi-rhm-x64-v142-md.dll (mnmlstc/core polyfill library)
* mongocxx-v_noabi-rhb-x64-v142-md.dll (Boost polyfill library)

This allows libraries built with different build configurations (and different runtime library requirements) to be built and installed without conflicting with each other.

See references to `ENABLE_ABI_TAG_IN_LIBRARY_FILENAMES` and related code in the CMake configuration for more details.

### Other Platforms (Linux, MacOS)

* Physical filename for a DSO is `libmongocxx.so.$MAJOR.$MINOR.$PATCH`

Note that the physical filename is disconnected from ABI version/soname.
Expand Down
Loading