# Copyright 2009-present MongoDB, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. cmake_minimum_required(VERSION 3.15...4.0) project(MONGO_CXX_DRIVER LANGUAGES CXX) set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${PROJECT_SOURCE_DIR}/cmake ${PROJECT_SOURCE_DIR}/cmake/make_dist ) option(BUILD_TESTING "When ENABLE_TESTS=ON, include test targets in the \"all\" target") if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") # https://gcc.gnu.org/onlinedocs/libstdc++/manual/status.html # https://gcc.gnu.org/projects/cxx-status.html # https://gcc.gnu.org/releases.html if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS "8.1") message(FATAL_ERROR "GCC 8.1 or newer is required") endif() elseif(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") # https://en.wikipedia.org/wiki/Microsoft_Visual_C%2B%2B#Internal_version_numbering # https://learn.microsoft.com/en-us/cpp/overview/compiler-versions # https://learn.microsoft.com/en-us/cpp/overview/visual-cpp-language-conformance if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS "19.0.24210") message(FATAL_ERROR "Visual Studio 13 2015 Update 3 or newer is required") endif() if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS "19.10.25017") message(DEPRECATION "Visual Studio 2017 version 15.0 or newer will be required") # TODO(CXX-3215) replace DEPRECATION with: # message(FATAL_ERROR "Visual Studio 2017 version 15.0 or newer is required") endif() elseif(CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang") # https://developer.apple.com/xcode/cpp/ # https://en.wikipedia.org/wiki/Xcode#Version_comparison_table # https://trac.macports.org/wiki/XcodeVersionInfo if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS "13.1") message(FATAL_ERROR "Xcode 13.4.1 or newer is required") endif() elseif(CMAKE_CXX_COMPILER_ID STREQUAL "Clang") # https://releases.llvm.org/ # https://clang.llvm.org/cxx_status.html # https://libcxx.llvm.org/#c-standards-conformance if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS "3.8") message(FATAL_ERROR "Clang 3.8 or newer is required") endif() else() message(WARNING "Unknown compiler... recklessly proceeding without a version check") endif() # Also update etc/purls.txt. set(BSON_REQUIRED_VERSION 2.3.1) set(MONGOC_REQUIRED_VERSION 2.3.1) set(MONGOC_DOWNLOAD_VERSION 2.3.1) # All of our target compilers support the deprecated # attribute. Normally, we would just let the GenerateExportHeader # subsystem do this via configure check, but there appears to be a # CMake bug where if -Werror is set on the command line, it breaks the # configure check, and we end up not configuring the macro. That means # that we end up not being able to turn deprecation warnings into # errors. Instead, since we know all our platforms offer the feature, # just hard enable it here. if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") set(COMPILER_HAS_DEPRECATED true) else() set(COMPILER_HAS_DEPRECATED_ATTR true) endif() set(CMAKE_SKIP_BUILD_RPATH false) set(CMAKE_BUILD_WITH_INSTALL_RPATH false) set(CMAKE_INSTALL_RPATH_USE_LINK_PATH true) # Ensure that RPATH is used on OSX set(CMAKE_MACOSX_RPATH 1) # Enforce the C++ standard, and disable extensions if(NOT DEFINED CMAKE_CXX_STANDARD) set(CMAKE_CXX_STANDARD 11) endif() set(CMAKE_CXX_EXTENSIONS OFF) # Include the required modules include(CMakeDependentOption) include(GenerateExportHeader) include(InstallRequiredSystemLibraries) # Allow the user to decide whether to build the shared libaries or the static libraries. option(BUILD_SHARED_LIBS "Build shared libraries" ON) set(BUILD_VERSION "0.0.0" CACHE STRING "Library version (for both bsoncxx and mongocxx)") # Allow the user to decide whether to also build static libraries option(BUILD_SHARED_AND_STATIC_LIBS "Build static libraries" OFF) # Allow the user to decide whether to use shared libraries or static libraries # for the mongo-c-driver option(BUILD_SHARED_LIBS_WITH_STATIC_MONGOC "Use static mongo-c-driver libraries with shared mongo-cxx-driver libraries" 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 option(ENABLE_CODE_COVERAGE "Enable code coverage." OFF) # Disambiguate our options into clear flags if(BUILD_SHARED_LIBS) set(BSONCXX_BUILD_SHARED ON CACHE INTERNAL "") set(MONGOCXX_BUILD_SHARED ON CACHE INTERNAL "") if(BUILD_SHARED_AND_STATIC_LIBS) set(BSONCXX_BUILD_STATIC ON CACHE INTERNAL "") set(MONGOCXX_BUILD_STATIC ON CACHE INTERNAL "") else() set(BSONCXX_BUILD_STATIC OFF CACHE INTERNAL "") set(MONGOCXX_BUILD_STATIC OFF CACHE INTERNAL "") endif() if(BUILD_SHARED_LIBS_WITH_STATIC_MONGOC) set(BSONCXX_LINK_WITH_STATIC_MONGOC ON CACHE INTERNAL "") set(MONGOCXX_LINK_WITH_STATIC_MONGOC ON CACHE INTERNAL "") else() set(BSONCXX_LINK_WITH_STATIC_MONGOC OFF CACHE INTERNAL "") set(MONGOCXX_LINK_WITH_STATIC_MONGOC OFF CACHE INTERNAL "") endif() else() # Give a fatal error if we have a non-sensical combination if(BUILD_SHARED_AND_STATIC_LIBS) message(FATAL_ERROR "BUILD_SHARED_LIBS is OFF but BUILD_SHARED_AND_STATIC_LIBS is ON. \ To build static libraries only, set both BUILD_SHARED_LIBS and BUILD_SHARED_AND_STATIC_LIBS to OFF" ) endif() set(BSONCXX_BUILD_SHARED OFF CACHE INTERNAL "") set(MONGOCXX_BUILD_SHARED OFF CACHE INTERNAL "") set(BSONCXX_BUILD_STATIC ON CACHE INTERNAL "") set(MONGOCXX_BUILD_STATIC ON CACHE INTERNAL "") set(BSONCXX_LINK_WITH_STATIC_MONGOC ON CACHE INTERNAL "") set(MONGOCXX_LINK_WITH_STATIC_MONGOC ON CACHE INTERNAL "") endif() include(GNUInstallDirs) include(ParseVersion) set(MONGOCXX_INCLUDE_VERSION_FILE_IN_DIST OFF) set(MONGOCXX_CURRENT_VERSION_FILE "") if(BUILD_VERSION STREQUAL "0.0.0") if(EXISTS ${CMAKE_BINARY_DIR}/VERSION_CURRENT) file(STRINGS ${CMAKE_BINARY_DIR}/VERSION_CURRENT BUILD_VERSION) if("${CMAKE_BINARY_DIR}" STREQUAL "${PROJECT_SOURCE_DIR}/build") # If `CMAKE_BINARY_DIR` is the `build` directory, include `VERSION_CURRENT` in the release tarball. set(MONGOCXX_INCLUDE_VERSION_FILE_IN_DIST ON) set(MONGOCXX_CURRENT_VERSION_FILE build/VERSION_CURRENT) endif () elseif(EXISTS ${PROJECT_SOURCE_DIR}/build/VERSION_CURRENT) set(MONGOCXX_INCLUDE_VERSION_FILE_IN_DIST ON) set(MONGOCXX_CURRENT_VERSION_FILE build/VERSION_CURRENT) file(STRINGS ${MONGOCXX_CURRENT_VERSION_FILE} BUILD_VERSION) else() find_package(Python3 COMPONENTS Interpreter) if(Python3_Interpreter_FOUND) execute_process( COMMAND ${Python3_EXECUTABLE} etc/calc_release_version.py WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} OUTPUT_VARIABLE CALC_RELEASE_VERSION RESULT_VARIABLE CALC_RELEASE_VERSION_RESULT OUTPUT_STRIP_TRAILING_WHITESPACE ) if(NOT CALC_RELEASE_VERSION_RESULT STREQUAL 0) # If python failed above, stderr would tell the user about it message(FATAL_ERROR "BUILD_VERSION not specified and could not be calculated\ (script invocation failed); specify in CMake command, -DBUILD_VERSION=" ) else() set(BUILD_VERSION ${CALC_RELEASE_VERSION}) file(WRITE ${CMAKE_BINARY_DIR}/VERSION_CURRENT ${CALC_RELEASE_VERSION}) endif() else() message(FATAL_ERROR "BUILD_VERSION not specified and could not be calculated\ (Python was not found on the system); specify in CMake command, -DBUILD_VERSION=" ) endif() endif() endif() get_property(isMultiConfig GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) if(NOT CMAKE_BUILD_TYPE AND NOT isMultiConfig) # Do not override CMAKE_BUILD_TYPE if generator is multi config. CMAKE_BUILD_TYPE is ignored for multi-config generators. message(STATUS "No build type selected, default is Release") set(CMAKE_BUILD_TYPE "Release") endif() if(ENABLE_CODE_COVERAGE) if(NOT CMAKE_BUILD_TYPE STREQUAL "Debug") message(WARNING "Code coverage results with an optimized (non-Debug) build may be misleading") endif() if(CMAKE_CXX_COMPILER_ID MATCHES "GNU") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O0 -g --coverage") elseif(CMAKE_CXX_COMPILER_ID MATCHES "(Apple)?[Cc]lang") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fprofile-instr-generate -fcoverage-mapping") else() message(FATAL_ERROR "Code coverage requires Clang or GCC. Aborting.") endif() endif() set(CMAKE_EXPORT_COMPILE_COMMANDS ON) unset(dist_generated CACHE) unset(dist_generated_depends CACHE) set(BUILD_SOURCE_DIR ${CMAKE_BINARY_DIR}) include(MakeDistFiles) add_custom_target(hugo_dir COMMAND ${CMAKE_COMMAND} -E make_directory hugo ) add_custom_target(hugo DEPENDS hugo_dir WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/docs COMMAND hugo VERBATIM ) add_custom_target(hugo-deploy DEPENDS hugo WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} COMMAND etc/deploy-to-ghpages.pl --hugo git@github.com:mongodb/mongo-cxx-driver VERBATIM ) add_custom_target(doxygen-install-headers VERBATIM # Clear any existing files in the target directory. COMMAND ${CMAKE_COMMAND} -E remove_directory ${MONGO_CXX_DRIVER_SOURCE_DIR}/build/doxygen/install # Manually "install" all headers without requiring compilation. COMMAND ${CMAKE_COMMAND} -E copy_directory ${MONGO_CXX_DRIVER_SOURCE_DIR}/src/bsoncxx/include ${MONGO_CXX_DRIVER_BINARY_DIR}/src/bsoncxx/lib ${MONGO_CXX_DRIVER_SOURCE_DIR}/build/doxygen/install/include COMMAND ${CMAKE_COMMAND} -E copy_directory ${MONGO_CXX_DRIVER_SOURCE_DIR}/src/mongocxx/include ${MONGO_CXX_DRIVER_BINARY_DIR}/src/mongocxx/lib ${MONGO_CXX_DRIVER_SOURCE_DIR}/build/doxygen/install/include ) add_custom_target(doxygen-current WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} COMMAND ${CMAKE_COMMAND} -E env DOXYGEN_USE_CURRENT=1 etc/generate-latest-apidocs.sh VERBATIM ) add_custom_target(doxygen-latest WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} COMMAND etc/generate-latest-apidocs.sh VERBATIM ) add_custom_target(doxygen-deploy DEPENDS doxygen-latest WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} COMMAND etc/deploy-to-ghpages.pl --doxygen git@github.com:mongodb/mongo-cxx-driver VERBATIM ) add_custom_target(format python ${CMAKE_SOURCE_DIR}/etc/clang_format.py format VERBATIM ) add_custom_target(format-lint python ${CMAKE_SOURCE_DIR}/etc/clang_format.py lint VERBATIM ) add_custom_target(docs DEPENDS hugo doxygen-current ) set(THIRD_PARTY_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/src/third_party) set(DATA_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/data) option(ENABLE_TESTS "Enable building test targets." OFF) option(ENABLE_MACRO_GUARD_TESTS "When ENABLE_TESTS=ON, enable macro guard test targets." OFF) if(BUILD_TESTING AND NOT ENABLE_TESTS) message(WARNING "BUILD_TESTING is enabled without also setting ENABLE_TESTS. Set ENABLE_TESTS=ON to building test targets.") endif() if(ENABLE_TESTS) enable_testing() endif() include(FetchMongoC) add_subdirectory(src) add_subdirectory(examples EXCLUDE_FROM_ALL) add_subdirectory(benchmark EXCLUDE_FROM_ALL) # Implement 'dist' target # # CMake does not implement anything like 'dist' from autotools. # This implementation is based on the one in GnuCash. add_subdirectory(cmake) add_subdirectory(data) add_subdirectory(docs) add_subdirectory(etc) set(PACKAGE_PREFIX "mongo-cxx-driver-r${BUILD_VERSION}") set(DIST_FILE "${PACKAGE_PREFIX}.tar.gz") set(top_DIST_local CMakeLists.txt CONTRIBUTING.md CREDITS.json LICENSE README.md THIRD-PARTY-NOTICES build/.gitignore ${MONGOCXX_CURRENT_VERSION_FILE} # This sub-directory is added later, so manually include here generate_uninstall/CMakeLists.txt ) set_local_dist(top_DIST ${top_DIST_local}) set(ALL_DIST ${top_DIST} ${benchmark_DIST} ${cmake_DIST} ${docs_DIST} ${data_DIST} ${etc_DIST} ${examples_DIST} ${src_DIST} ) # Write a dist manifest string(REPLACE ";" "\n" ALL_DIST_LINES "${ALL_DIST}") file(WRITE ${CMAKE_BINARY_DIR}/dist_manifest.txt ${ALL_DIST_LINES}) install(FILES LICENSE README.md THIRD-PARTY-NOTICES DESTINATION ${CMAKE_INSTALL_DATADIR}/mongo-cxx-driver ) # This is the command that produces the distribution tarball add_custom_command(OUTPUT ${DIST_FILE} COMMAND ${CMAKE_COMMAND} -D "CMAKE_MODULE_PATH=${PROJECT_SOURCE_DIR}/cmake/make_dist" -D "PACKAGE_PREFIX=${PACKAGE_PREFIX}" -D "MONGOCXX_SOURCE_DIR=${CMAKE_SOURCE_DIR}" -D "BUILD_SOURCE_DIR=${BUILD_SOURCE_DIR}" -D "SHELL=${SHELL}" -D "dist_generated=${dist_generated}" -P ${PROJECT_SOURCE_DIR}/cmake/make_dist/MakeDist.cmake DEPENDS ${ALL_DIST} ${dist_generated_depends} ) if(NOT(TARGET dist OR TARGET distcheck)) add_custom_target(dist DEPENDS ${DIST_FILE}) # 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 "${BSONCXX_POLY_USE_IMPLS}" STREQUAL "") list(APPEND polyfill_flags "-DBSONCXX_POLY_USE_IMPLS=${BSONCXX_POLY_USE_IMPLS}") 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 COMMAND ${CMAKE_COMMAND} -D CMAKE_MODULE_PATH=${PROJECT_SOURCE_DIR}/cmake/make_dist -D CMAKE_PREFIX_PATH=${CMAKE_PREFIX_PATH} -D PACKAGE_PREFIX=${PACKAGE_PREFIX} ${polyfill_flags} -P ${PROJECT_SOURCE_DIR}/cmake/make_dist/MakeDistCheck.cmake ) endif() if(ENABLE_UNINSTALL) if(WIN32) set(UNINSTALL_PROG "uninstall.cmd") else() set(UNINSTALL_PROG "uninstall.sh") endif() set(UNINSTALL_PROG_DIR "${CMAKE_INSTALL_DATADIR}/mongo-cxx-driver") # Create uninstall program and associated uninstall target # # This needs to be last (after all other add_subdirectory calls) to ensure # that the generated uninstall program is complete and correct add_subdirectory(generate_uninstall) endif() # Spit out some information regarding the generated build system message(STATUS "Build files generated for:") message(STATUS "\tbuild system: ${CMAKE_GENERATOR}") if(CMAKE_GENERATOR_INSTANCE) message(STATUS "\tinstance: ${CMAKE_GENERATOR_INSTANCE}") endif() if(CMAKE_GENERATOR_PLATFORM) message(STATUS "\tinstance: ${CMAKE_GENERATOR_PLATFORM}") endif() if(CMAKE_GENERATOR_TOOLSET) message(STATUS "\tinstance: ${CMAKE_GENERATOR_TOOLSET}") endif()