I have created four example projects for demonstrating several aspects of import/export with cmake. Description is here: https://habla.news/u/purplekarrot.net/cmake-import-export
Most beman libraries are header only, but you may find some information useful nevertheless.
Definitely a few interesting points there:
Note that Qux does not set any value that begins with CMAKE_. Those variables are not meant to be set by projects. Setting them as cache variables would leak into the parent project, while setting them as non-cache variables would prevent injection from the parent project or from the packager.
This seems to be a fundamental point about cmake usage that is never been communicated clearly – although even clear communication about cmake has been obsoleted so it’s difficult to follow best practices. For Beman this should probably be in our guidelines.
Consider a C++ library that requires C++23 internally, but it has a C API, so C++23 is not a usage requirement.
I don’t think there’s anything in c++23 that would be abi incompatible with earlier versions – maybe contracts leaks in for 26, but I’m not even sure on that.
I see only c code? With CXX_MODULES there are also many points to know.
i.e.: C++20 Modules, CMake, And Shared Libraries - Crascit
And CXX_MODULES can’t be an interface library today!
see Linker error with CXX_MODULES - Development - CMake Discourse
That is not always true, i.e. from scope
# Modules opt in only on compilers that support it: msvc, g++-15 and clang-20+
if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 20)
set(CMAKE_CXX_SCAN_FOR_MODULES 1)
elseif (CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 15)
set(CMAKE_CXX_SCAN_FOR_MODULES 1)
elseif(MSVC)
set(CMAKE_CXX_SCAN_FOR_MODULES 1)
else()
set(CMAKE_CXX_SCAN_FOR_MODULES 0)
endif()
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
set(CMAKE_CXX_VISIBILITY_PRESET hidden)
set(CMAKE_VISIBILITY_INLINES_HIDDEN TRUE)
or from Professional CMake book
set(stageDir ${CMAKE_CURRENT_BINARY_DIR}/stage)
include(GNUInstallDirs)
if(NOT CMAKE_RUNTIME_OUTPUT_DIRECTORY)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${stageDir}/${CMAKE_INSTALL_BINDIR})
endif()
if(NOT CMAKE_LIBRARY_OUTPUT_DIRECTORY)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${stageDir}/${CMAKE_INSTALL_LIBDIR})
endif()
if(NOT CMAKE_ARCHIVE_OUTPUT_DIRECTORY)
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${stageDir}/${CMAKE_INSTALL_LIBDIR})
endif()
if(PROJECT_IS_TOP_LEVEL)
set(CMAKE_EXPORT_COMPILE_COMMANDS TRUE)
find_program(CLANG_TIDY_EXECUTABLE clang-tidy REQUIRED)
find_program(RUN_CLANG_TIDY_EXECUTABLE run-clang-tidy REQUIRED)
add_custom_target(run-clang-tidy
COMMAND ${RUN_CLANG_TIDY_EXECUTABLE}
-clang-tidy-binary ${CLANG_TIDY_EXECUTABLE}
-p ${CMAKE_BINARY_DIR}
)
endif()
and
cmake_minimum_required(VERSION 3.21)
project(coverage_example LANGUAGES CXX)
enable_testing()
if(PROJECT_IS_TOP_LEVEL AND CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang")
set(CMAKE_CXX_FLAGS_COVERAGE "-g -O0 --coverage")
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
string(APPEND CMAKE_CXX_FLAGS_COVERAGE " -fprofile-abs-path")
endif()
set(CMAKE_EXE_LINKER_FLAGS_COVERAGE "--coverage")
set(CMAKE_SHARED_LINKER_FLAGS_COVERAGE "--coverage")
set(CMAKE_MODULE_LINKER_FLAGS_COVERAGE "--coverage")
endif()
add_subdirectory(src)