Skip to content

CXX-3103 bump minimum required C Driver version to 2.0.0 #1379

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 20 commits into from
Apr 18, 2025

Conversation

eramongodb
Copy link
Contributor

@eramongodb eramongodb commented Apr 8, 2025

Resolves CXX-3103. Followup to CDRIVER-4742.

Bumps the minimum required C Driver version from 1.30.0 to 2.0.0.

Additionally sets the CMake "maximum policy version" to 4.0 to communicate CMake 4.0 compatibility and test coverage.

Important

These changes do NOT cause API or ABI breaking changes for the C++ Driver libraries themselves. However, they do change dynamic linking requirements for dependent code (e.g. libbson-1.0.so.0 -> bson2.so.2 for libbsoncxx.so._noabi).


References to CMake package names and targets are updated for C Driver v2 compatibility:

  • find_package(bson-${LIBBSON_REQUIRED_ABI_VERSION}) -> find_package(bson).
    • The ${LIBBSON_REQUIRED_ABI_VERSION} variable is removed: no reason to parameterize on ABI version number given API == ABI equivalent going forward for the C Driver.

Note

Considered adding CONFIG to find_package() for C Driver packages, but decided against to allow users to customize lookup using module search mode (defining their own Findbson.cmake) when necessary for their circumstances.

  • find_dependency(bson-1.0 REQUIRED) -> find_dependency(bson 2.0.0 REQUIRED).
    • The API version requirement is now included to guard against selection of incompatible (older) packages, as well as to detect bugs such as BUILD_VERSION inheritance addressed by CXX-3266 avoid inheriting BUILD_VERSION by auto-downloaded C Driver #1373 (e.g. a dependent project would fail configuration due to finding bson 0.0.0 instead of the expected bson 2.0.0).
    • This includes find_dependency(bsoncxx 4.0.0 REQUIRED) in the mongocxx-config.cmake file.

Important

To allow find_dependency(bsoncxx @BSONCXX_VERSION_NO_EXTRA@ REQUIRED), BSONCXX_VERSION and BSONCXX_VERSION_NO_EXTRA (+ mongocxx equivalents) are now internal cache variables so they are accessible across project scopes. All references use $CACHE{VARNAME} syntax to clearly communicate the variable type and to avoid potential conflict/confusion with normal variables. Note INTERNAL implies FORCE (user override is not supported).

  • Replace mongo::bson_shared and mongo::bson_static with bson::shared and bson::static when referencing targets imported by find_package().
    • bson_static and bson_shared are still used to reference targets imported via add_subdirectory().

Note

Considered refactoring the C++ Driver CMake config to support the bson::bson target (per BSON_DEFAULT_IMPORTED_LIBRARY_TYPE), but decided against to avoid complicating the current configuration which still distinguishes shared vs. static linkage via BUILD_SHARED_LIBS_WITH_STATIC_MONGOC.

  • Rename references to C Driver libraries without "lib-" prefix for consistency.
    • ${LIBBSON_REQUIRED_VERSION} -> ${BSON_REQUIRED_VERSION}
    • ${LIBMONGOC_REQUIRED_VERSION} -> ${MONGOC_REQUIRED_VERSION}
    • ${LIBMONGOC_DOWNLOAD_VERSION} -> ${MONGOC_DOWNLOAD_VERSION}
    • ${libbson_target} -> ${bson_target}
    • ${libmongoc_target} -> ${mongoc_target}

Note

Considered a similar rename of C++ Driver targets, libraries, and package config files, but decided against to avoid introducing too many significant build system breaking changes. These changes can be addressed in a subsequent release (v5?).

  • Rename required pkg-config dependency from libbson-static-${LIBBSON_REQUIRED_ABI_VERSION} to bson2.

CMake configuration messages are also updated to better communicate behavior pertaining to how C Driver libraries are imported, as well as to avoid being excessively descriptive about the method by which the required libraries are found (considering the numerous options which can control find_package() and FetchContent behavior beyond just CMAKE_PREFIX_PATHS). e.g. given find_package() success:

-- bsoncxx version: 4.1.0-pre
-- Found bson: [...]/lib64/cmake/bson-2.0.0 (found version "2.0.0")
-- mongocxx version: 4.1.0-pre
-- Found mongoc: [...]/lib64/cmake/mongoc-2.0.0 (found version "2.0.0")

and given find_package() failure and subsequent auto-download behavior:

 -- find_package(bson 2.0.0) did not succeed
 -- find_package(mongoc 2.0.0) did not succeed
 -- Required MongoDB C Driver libraries not found via find_package()
 -- MongoDB C Driver library sources will be downloaded from GitHub
 -- Downloading and configuring MongoDB C Driver 2.0.0...
 -- Downloading and configuring MongoDB C Driver 2.0.0... done.
 -- bsoncxx version: 4.1.0-pre
 -- Using bson targets imported via add_subdirectory() without version checks
 -- mongocxx version: 4.1.0-pre
 -- Using mongoc targets imported via add_subdirectory() without version checks

Removed obsolete branches which supported old C Driver CMake package config files:

  • Legacy calls to find_package(libbson-1.0) are removed following CDRIVER-3414.
  • ${BSONCXX_PKG_DEP} is no longer necessary: dependency specification is now the same regardless of how C Driver libraries are imported.
  • ${libbson_include_directories} and ${libbson_definitions} are no longer necessary: only CMake target properties are required and used.

The C++ Driver CMake config now sets <policy_max> in its call to cmake_minimum_required(). This feature is supported since 3.12; we require 3.15 or newer.

The "maximum policy version" is set to 4.0, which is now tested by the new "cmake-compat" EVG task matrix. These tasks test various CMake configurations (currently: polyfill selection x C Driver import method x C++ Driver import method) against our minimum supported CMake version (3.15), the latest CMake v3 version (3.31), and the latest CMake version (4.0). This task coverage (which enables -Werror=dev and -Werror=deprecated) should help us detect CMake compatibility issues as well as (minimally) verify correct CMake package config file behavior (i.e. the addition of API version requirements in calls to find_dependency()).

The current combination of minimum and maximum policy versions permits the following changes:

  • CMP0025 is obsolete (since 3.0). Removed related handlers.
  • CMP0012 is obsolete (since 2.8). Removed related handlers.
  • CMP0141 is relevant since 3.25. Prefer setting the policy within our project scope via <policy_max> rather than using command line flags.
  • CMP0148 is relevant since 3.27. Replace FindPythonInterp (likely not provided by newer CMake releases) with FindPython3 to satisfy the Python requirement for running etc/calc_release_version.py.

Note

Removal of the calc_release_version.py script as done in CDRIVER-5932 is deferred.

  • The FATAL_ERROR argument to cmake_minimum_required() is obsolete since 2.6. Removed from example project CMake config files.

Important

Setting <policy_max> means all CMake policies which apply up to <policy_max> are set to NEW. This means cmake_policy() should only be used to deliberately set a specific policy to OLD.


This PR also adds regression tests for the BUILD_VERSION inheritance bug addressed by #1373, which now assert that the bson and mongoc libraries have the expected API version number using both the bson_get_* API as well as the BSON_VERSION_S macro (which currently use slightly different methods to obtain their value, as noted in the PR description for #1373; this accounts for both cases):

-------------------------------------------------------------------------------
bson version numbers
-------------------------------------------------------------------------------
src/bsoncxx/test/version.cpp:45
...............................................................................

src/bsoncxx/test/version.cpp:55: FAILED:
  CHECK( bson_get_major_version() == expect[0] )
with expansion:
  0 == 2
with message:
  expect_str := 2.0.0

The bsoncxx/private/version.hh component is added to support reuse of the split_version() helper function by both bsoncxx and mongocxx test binaries. It is not currently used by the library itself (similar to the mongocxx/private/mock.hh component).

@eramongodb eramongodb self-assigned this Apr 8, 2025
Comment on lines 60 to 66
message(STATUS "Using bson targets imported via add_subdirectory() without version checks")

if(NOT BSONCXX_LINK_WITH_STATIC_MONGOC)
set(libbson_target bson_shared)
if(BSONCXX_LINK_WITH_STATIC_MONGOC)
set(bson_target bson_static)
else()
set(libbson_target bson_static)
set(bson_target bson_shared)
endif()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The newer C driver CMake projects define bson::static, bson::shared, mongoc::static, and mongoc::shared ALIAS targets for uniformity with the installed target names, so those names can be used without the branch.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought it would be preferable to refer to targets which can only be imported via add_subdirectory() in the case when they are made available, rather than using bson::* targets, which then imply they were imported via find_package(). That is, the idea was:

  • bson_shared: bson library was imported via add_subdirectory().
  • bson::shared: bson library was imported via find_package().

Would you prefer the use of bson::* targets for ${bson_target} regardless (limiting use of bson_shared to add vs. find detection only)?

Copy link
Contributor

@vector-of-bool vector-of-bool Apr 10, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would prefer it for uniformity, but it's not really a sticking point at this time. Either way, the installed C++ targets will link to the bson:: and mongoc:: names because the subproject targets have an EXPORT_NAME set to match the aliases. There's also the option of skipping the branch and target name indirection and replacing it with a genex: $<IF:$<BOOL:${BSONCXX_LINK_WITH_STATIC_MONGOC}>,bson::static,bson::shared>, but I won't commit to saying that's definitely better, as there may be other reason to use the indirection through ${bson_target}.

Aside: While working on amongoc, I studied more on using FetchContent and find_package and it may be preferrable from packagers' perspective that we modify the automatic fetching of mongoc/bson/catch2 to rely on FetchContent redirection for find_package rather than our custom fetching modules, and make the rest of the project agnostic to whether it is downloaded on-the-fly or imported from an installation, but that's all a bigger change that would take more investigation. (Refer: DeclareFetchContentDeps.cmake)

Copy link
Contributor Author

@eramongodb eramongodb Apr 10, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would prefer it for uniformity, but it's not really a sticking point at this time

I suppose it wouldn't hurt to use the alias targets so we get better target_link_libraries() behavior.

There's also the option of skipping the branch and target name indirection and replacing it with a genex.

I think I would prefer to avoid using generator expressions unless they are strictly necessary (such that using a generator expression implies the property/variable/flag/etc. must be evaluated at build-time rather than config-time). BSONCXX_LINK_WITH_STATIC_MONGOC does not depend on the build configuration.

there may be other reason to use the indirection through ${bson_target}.

I opted to leave things mostly as-is for now (still a variable) for easier PR diff. The reason that came to mind was that the normal variable has the benefit of function/directory scope, unlike targets which have the "globally unique" requirement (i.e. the uninstall custom target problem from a while back: mongodb/mongo-c-driver#1352). We might consider doing something similar to _mongoc-*-prefixed internal library targets, but we can defer this work to a PR that is more focused on refactors the CMake configuration.

it may be preferrable from packagers' perspective that we [...] rely on FetchContent redirection for find_package

I've also thought about this (e.g. using FETCHCONTENT_TRY_FIND_PACKAGE_MODE), but decided against pursuing it atm due to requiring a comparatively recent version of CMake (3.24 and newer), the quirk that we need to find_package() two packages (bson + mongoc) for a single FetchContent_Declare(mongo-c-driver) (haven't investigated how to implement this in depth), and (AFAIK) the lack of package-specific opt-in/opt-out mechanisms for the preferred dependency resolution method (e.g. one user may prefer/require find_package(), another may prefer/require add_subdirectory(); at least atm users have the option to override each behavior via CMAKE_DISABLE_FIND_PACKAGE_<PackageName> or FETCHCONTENT_SOURCE_DIR_<uppercaseName>).

@eramongodb
Copy link
Contributor Author

eramongodb commented Apr 14, 2025

Opted to avoid specifying the patch number in CMake version requirements, since they are not expected to contain any notable changes to features (primarily bug fixes or internal, non-user-facing updates). However, the patch number is still required to specify the exact CMake binary version to be downloaded by our scripts.

Copy link
Collaborator

@kevinAlbs kevinAlbs left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The CMake compatibility tests and message improvements are much appreciated.

@eramongodb eramongodb requested a review from kevinAlbs April 15, 2025 16:13
@@ -67,7 +67,7 @@ echo "Test next minor version ... begin"
# failed, then it is probably because a new major/minor release was made.
# Update the expected output to represent the correct next version.
# XXX NOTE XXX NOTE XXX
assert_eq "$got" "3.10.0-$DATE+git$CURRENT_SHORTREF"
assert_eq "$got" "4.1.0-$DATE+git$CURRENT_SHORTREF"
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Noticed when validating this commit in #1381.

@eramongodb eramongodb requested a review from a team as a code owner April 17, 2025 20:08
Copy link
Contributor

@vector-of-bool vector-of-bool left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM with minor comments

Comment on lines 66 to 77
commands = [
Setup.call(), InstallUV.call()
] + ([InstallCDriver.call() if install_c_driver else FetchCDriverSource.call()]) + [
CMakeCompat.call(
vars={
'CMAKE_MAJOR_VERSION': version[0],
'CMAKE_MINOR_VERSION': version[1],
'CMAKE_PATCH_VERSION': version[2],
'INSTALL_C_DRIVER': 1 if install_c_driver else 0,
},
),
]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can this be simplified to?

Suggested change
commands = [
Setup.call(), InstallUV.call()
] + ([InstallCDriver.call() if install_c_driver else FetchCDriverSource.call()]) + [
CMakeCompat.call(
vars={
'CMAKE_MAJOR_VERSION': version[0],
'CMAKE_MINOR_VERSION': version[1],
'CMAKE_PATCH_VERSION': version[2],
'INSTALL_C_DRIVER': 1 if install_c_driver else 0,
},
),
]
commands = [
Setup.call(),
InstallUV.call(),
(InstallCDriver.call() if install_c_driver else FetchCDriverSource.call()),
CMakeCompat.call(
vars={
'CMAKE_MAJOR_VERSION': version[0],
'CMAKE_MINOR_VERSION': version[1],
'CMAKE_PATCH_VERSION': version[2],
'INSTALL_C_DRIVER': 1 if install_c_driver else 0,
},
),
]

You can also rewrite 1 if foo else 0 to int(foo) if foo is just a plain boolean.

@@ -1,3 +1,3 @@
include(CMakeFindDependencyMacro)
@BSONCXX_PKG_DEP@
find_dependency(bson @BSON_REQUIRED_VERSION@ REQUIRED)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The REQUIRED keyword is not necessary for find_dependency, IIUC

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I admit I don't understand how this is meant to work per docs:

find_dependency forwards the correct parameters for QUIET and REQUIRED which were passed to the original find_package() call.

I do not see how this call to find_dependency() can know what the original parameters to a find_package() would have been, so I included REQUIRED for assurance. However, local testing appears to enforce the REQUIRED behavior even without it being included in this command, so I am fine with removing it.

@eramongodb eramongodb merged commit 69c5fc2 into mongodb:master Apr 18, 2025
21 checks passed
@eramongodb eramongodb deleted the cxx-3103 branch April 18, 2025 19:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants