diff --git a/.github/workflows/ci_tests.yml b/.github/workflows/ci_tests.yml index d6b9c64f..351cb387 100644 --- a/.github/workflows/ci_tests.yml +++ b/.github/workflows/ci_tests.yml @@ -40,9 +40,9 @@ jobs: "tests": [ { "stdlibs": ["libstdc++"], "tests": [ - "Debug.Default", "Release.Default", - "Release.MaxSan", "Debug.Werror", - "Debug.Dynamic", "Debug.Coverage" + "Debug.Default", "Debug.Coverage", + "Debug.MaxSan", "Debug.Werror", + "Release.Default", "Release.Dynamic" ] } ] @@ -67,8 +67,8 @@ jobs: "tests": [ { "stdlibs": ["libc++"], "tests": [ - "Debug.Default", "Release.Default", "Release.MaxSan", - "Debug.Dynamic" + "Debug.Default", "Debug.MaxSan", + "Release.Default", "Release.Dynamic" ] } ] @@ -96,7 +96,10 @@ jobs: { "cxxversions": ["c++23"], "tests": [ { "stdlibs": ["stl"], - "tests": ["Debug.Default", "Release.Default", "Release.MaxSan"] + "tests": [ + "Debug.Default", "Debug.MaxSan", + "Release.Default", "Release.Dynamic" + ] } ] } diff --git a/CMakeLists.txt b/CMakeLists.txt index 095c67d2..99c13228 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -21,40 +21,45 @@ set(TARGETS_EXPORT_NAME ${PROJECT_NAME}-targets) # NOTE: must be set, is importa #=============================================================================== if(BEMAN_USE_MODULES) + set(CMAKE_CXX_SCAN_FOR_MODULES ON) set(CMAKE_CXX_VISIBILITY_PRESET hidden) - set(CMAKE_VISIBILITY_INLINES_HIDDEN TRUE) + set(CMAKE_VISIBILITY_INLINES_HIDDEN ON) + + find_package(Threads REQUIRED) # CMake requires the language standard to be specified as compile feature # when a target provides C++23 modules and the target will be installed - add_library(beman.execution STATIC) - add_library(beman::execution ALIAS beman.execution) + add_library(${TARGET_PREFIX} STATIC) + add_library(beman::execution ALIAS ${TARGET_PREFIX}) target_compile_features( - beman.execution + ${TARGET_PREFIX} PUBLIC cxx_std_${CMAKE_CXX_STANDARD} ) include(GenerateExportHeader) - generate_export_header( - beman.execution - BASE_NAME beman.execution + ${TARGET_PREFIX} + BASE_NAME ${TARGET_PREFIX} EXPORT_FILE_NAME beman/execution/modules_export.hpp ) target_sources( - beman.execution + ${TARGET_PREFIX} PUBLIC FILE_SET HEADERS BASE_DIRS include ${CMAKE_CURRENT_BINARY_DIR} FILES ${CMAKE_CURRENT_BINARY_DIR}/beman/execution/modules_export.hpp ) - # FIXME: target_compile_definitions(beman.execution PUBLIC BEMAN_HAS_MODULES) + target_compile_definitions(${TARGET_PREFIX} PUBLIC BEMAN_HAS_MODULES) + target_link_libraries(${TARGET_PREFIX} PUBLIC Threads::Threads) +else() + set(CMAKE_CXX_SCAN_FOR_MODULES OFF) endif() if(BEMAN_USE_MODULES AND CMAKE_CXX_MODULE_STD) - target_compile_definitions(beman.execution PUBLIC BEMAN_HAS_IMPORT_STD) -else() - message(WARNING "Missing support for CMAKE_CXX_MODULE_STD!") + target_compile_definitions(${TARGET_PREFIX} PUBLIC BEMAN_HAS_IMPORT_STD) +elseif(BEMAN_USE_MODULES) + message(WARNING "Missing or disabled support for CMAKE_CXX_MODULE_STD!") endif() #=============================================================================== @@ -72,13 +77,19 @@ option( add_subdirectory(src/beman/execution) +#=============================================================================== # NOTE: this must be done before tests! CK -include(./cmake/beman-install-library-config.cmake) -beman_install_library(${TARGET_PREFIX} headers) +include(./cmake/beman-install-library.cmake) +beman_install_library(${TARGET_PREFIX} TARGETS ${TARGET_NAME} ${TARGET_PREFIX} + # FIXME: DEPENDENCIES [===[beman.inplace_vector 1.0.0]===] [===[beman.scope 0.0.1 EXACT]===] fmt + # TODO(CK): XXX OR XXX DEPENDENCIES "beman.inplace_vector 1.0.0;beman.scope 0.0.1 EXACT" + DEPENDENCIES Threads +) +#=============================================================================== -if(BEMAN_EXECUTION_ENABLE_TESTING) - enable_testing() +enable_testing() +if(BEMAN_EXECUTION_ENABLE_TESTING) add_subdirectory(tests/beman/execution) endif() diff --git a/CMakePresets.json b/CMakePresets.json index 5bc75f84..eccfd3f6 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -7,9 +7,9 @@ "generator": "Ninja", "binaryDir": "${sourceDir}/build/${presetName}", "cacheVariables": { + "BEMAN_USE_MODULES": true, "CMAKE_CXX_STANDARD": "23", "CMAKE_CXX_EXTENSIONS": true, - "CMAKE_CXX_SCAN_FOR_MODULES": true, "CMAKE_CXX_STANDARD_REQUIRED": true, "CMAKE_EXPORT_COMPILE_COMMANDS": true, "CMAKE_SKIP_TEST_ALL_DEPENDENCY": false, @@ -19,6 +19,17 @@ { "name": "_debug-base", "hidden": true, + "warnings": { + "dev": true, + "deprecated": true, + "uninitialized": true, + "unusedCli": true, + "systemVars": false + }, + "errors": { + "dev": false, + "deprecated": false + }, "cacheVariables": { "CMAKE_BUILD_TYPE": "Debug", "BEMAN_BUILDSYS_SANITIZER": "MaxSan" @@ -62,6 +73,10 @@ ], "cacheVariables": { "CMAKE_TOOLCHAIN_FILE": "infra/cmake/llvm-libc++-toolchain.cmake" + }, + "environment": { + "CXX": "clang++", + "CMAKE_CXX_FLAGS": "-stdlib=libc++" } }, { @@ -73,6 +88,10 @@ ], "cacheVariables": { "CMAKE_TOOLCHAIN_FILE": "infra/cmake/llvm-libc++-toolchain.cmake" + }, + "environment": { + "CXX": "clang++", + "CMAKE_CXX_FLAGS": "-stdlib=libc++" } }, { @@ -83,7 +102,7 @@ "_debug-base" ], "cacheVariables": { - "CMAKE_CXX_SCAN_FOR_MODULES": false, + "BEMAN_USE_MODULES": false, "CMAKE_TOOLCHAIN_FILE": "infra/cmake/appleclang-toolchain.cmake" } }, @@ -95,7 +114,7 @@ "_release-base" ], "cacheVariables": { - "CMAKE_CXX_SCAN_FOR_MODULES": false, + "BEMAN_USE_MODULES": false, "CMAKE_TOOLCHAIN_FILE": "infra/cmake/appleclang-toolchain.cmake" } }, diff --git a/Makefile b/Makefile index 6549b0d8..a2dd4e7e 100644 --- a/Makefile +++ b/Makefile @@ -14,7 +14,7 @@ SANITIZERS := run # SANITIZERS += asan # TODO: tsan msan # endif -.PHONY: default release debug doc run update check ce todo distclean clean codespell clang-tidy build test install all format unstage $(SANITIZERS) module build-module test-module +.PHONY: default release debug doc run update check ce todo distclean clean codespell clang-tidy build test install all format unstage $(SANITIZERS) module build-module test-module build-interface SYSROOT ?= TOOLCHAIN ?= @@ -28,6 +28,9 @@ ifeq ($(CXX_BASE),clang++) COMPILER=clang++ endif +# NOTE default gmake use this flags! +# COMPILE.cc = $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c +# LINK.cc = $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(LDFLAGS) $(TARGET_ARCH) LDFLAGS ?= SAN_FLAGS ?= CXX_FLAGS ?= -g @@ -56,7 +59,8 @@ ifeq (${hostSystemName},Darwin) # export GCC_DIR:=$(shell realpath ${GCC_PREFIX}) # XXX export CMAKE_CXX_STDLIB_MODULES_JSON=${GCC_DIR}/lib/gcc/current/libstdc++.modules.json - ifeq ($(CXX),) + ifeq ($(origin CXX),default) + $(info CXX is using the built-in default: $(CXX)) export CXX=g++-15 export CXXFLAGS=-stdlib=libstdc++ endif @@ -99,7 +103,7 @@ endif # TODO: beman.execution.examples.modules # FIXME: beman.execution.execution-module.test beman.execution.stop-token-module.test -default: release +default: module all: $(SANITIZERS) @@ -116,19 +120,21 @@ doc: # ========================================================== # NOTE: cmake configure to only test without modules! CK # ========================================================== -build: +build build-interface: cmake -G Ninja -S $(SOURCEDIR) -B $(BUILD) $(TOOLCHAIN) $(SYSROOT) \ -D CMAKE_EXPORT_COMPILE_COMMANDS=ON \ -D CMAKE_SKIP_INSTALL_RULES=ON \ -D CMAKE_CXX_STANDARD=23 \ -D CMAKE_CXX_EXTENSIONS=ON \ -D CMAKE_CXX_STANDARD_REQUIRED=ON \ - -D CMAKE_CXX_SCAN_FOR_MODULES=OFF \ -D BEMAN_USE_MODULES=OFF \ + -D BEMAN_USE_STD_MODULE=OFF \ -D CMAKE_BUILD_TYPE=Release \ - -D CMAKE_CXX_COMPILER=$(CXX) --log-level=VERBOSE - cmake --build $(BUILD) -# XXX --fresh -D CMAKE_CXX_FLAGS="$(CXX_FLAGS) $(SAN_FLAGS)" + -D CMAKE_SKIP_TEST_ALL_DEPENDENCY=OFF \ + -D CMAKE_CXX_COMPILER=$(CXX) --log-level=VERBOSE --fresh + # XXX -D CMAKE_CXX_FLAGS="$(CXX_FLAGS) $(SAN_FLAGS)" + cmake --build $(BUILD) --target all_verify_interface_header_sets + cmake --build $(BUILD) --target all # NOTE: without install, see CMAKE_SKIP_INSTALL_RULES! CK test: build @@ -137,12 +143,14 @@ test: build module build-module: cmake -G Ninja -S $(SOURCEDIR) -B $(BUILD) $(TOOLCHAIN) $(SYSROOT) \ -D CMAKE_EXPORT_COMPILE_COMMANDS=ON \ - -D CMAKE_SKIP_INSTALL_RULES=ON \ + -D CMAKE_SKIP_INSTALL_RULES=OFF \ -D CMAKE_CXX_STANDARD=23 \ -D CMAKE_CXX_EXTENSIONS=ON \ -D CMAKE_CXX_STANDARD_REQUIRED=ON \ - -D CMAKE_CXX_SCAN_FOR_MODULES=ON \ -D BEMAN_USE_MODULES=ON \ + -D BEMAN_USE_STD_MODULE=ON \ + -D CMAKE_BUILD_TYPE=Release \ + -D CMAKE_INSTALL_MESSAGE=LAZY \ -D CMAKE_BUILD_TYPE=Release \ -D CMAKE_CXX_COMPILER=$(CXX) --log-level=VERBOSE cmake --build $(BUILD) diff --git a/cmake/Config.cmake.in b/cmake/Config.cmake.in new file mode 100644 index 00000000..81adf800 --- /dev/null +++ b/cmake/Config.cmake.in @@ -0,0 +1,12 @@ +# cmake/Config.cmake.in -*-makefile-*- +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +include(CMakeFindDependencyMacro) + +@BEMAN_FIND_DEPENDENCIES@ + +@PACKAGE_INIT@ + +include(${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@-targets.cmake) + +check_required_components(@PROJECT_NAME@) diff --git a/cmake/README.md b/cmake/README.md new file mode 100644 index 00000000..6c7e2723 --- /dev/null +++ b/cmake/README.md @@ -0,0 +1,388 @@ + + +# CMake Support for Header-Only Libraries and C++ Modules + +This directory provides a small set of CMake helper modules that make it easier +to **build and install a library that works both with and without C++20 +modules**. + +The helpers wrap CMake’s evolving support for `FILE_SET CXX_MODULE` and package +installation so that: + +- consumers can use the library in **classic header-only mode**, or + +- consumers with a compatible toolchain can use **C++ modules**, including + optional `import std;` support. + +The goal is to keep project `CMakeLists.txt` files readable while hiding most of +the platform- and compiler-specific complexity. + +--- + +## Motivation + +Today, supporting C++ modules often requires duplicating targets and custom +install logic: + +- one target for headers only, +- another target that owns module interface units, +- conditional logic depending on compiler and CMake version, +- non-trivial install/export rules. + +The helpers in this directory centralize that logic and provide a single, +consistent API for projects that want to offer both usage models. + +--- + +## Provided CMake Modules + +The following modules are expected to live in `infra/cmake`: + +- `prelude.cmake` + Common project setup and option handling. + +- `cxx-modules-rules.cmake` + Compiler and CMake feature checks related to C++ modules. + +- `beman-install-library.cmake` + High-level helper to install libraries, headers, module interface units, and CMake package files. + +- `Config.cmake.in` + Template used to generate the `-config.cmake` file for consumers. + +--- + +## New Configuration Options + + * BEMAN_USE_MODULES:BOOL=ON + * BEMAN_USE_STD_MODULE:BOOL=OFF + * BEMAN_HAS_IMPORT_STD::BOOL=${CMAKE_CXX_SCAN_FOR_MODULES} # only if toolchain supports it. + +### The recommended usage in CMake code + +```cmake +if(CMAKE_CXX_STANDARD GREATER_EQUAL 20) + option(BEMAN_USE_MODULES "Build CXX_MODULES" ${CMAKE_CXX_SCAN_FOR_MODULES}) +endif() +if(BEMAN_USE_MODULES) + target_compile_definitions(beman.execution PUBLIC BEMAN_HAS_MODULES) +endif() + +BEMAN_USE_STD_MODULE:BOOL=ON +# -> "Check if 'import std;' is possible with the toolchain?" + +if(BEMAN_USE_MODULES AND CMAKE_CXX_MODULE_STD) + target_compile_definitions(beman.execution PUBLIC BEMAN_HAS_IMPORT_STD) +endif() +``` + +Typical projects will only toggle `BEMAN_USE_MODULES`; the remaining options are +detected automatically. + +--- + +## Installing a Library + +Installation is handled by the `beman_install_library()` helper. + +### Function Signature + +```cmake +beman_install_library(name + TARGETS [ ...] + [DEPENDENCIES [ ...]] + [NAMESPACE ] + [EXPORT_NAME ] + [DESTINATION ] +) +``` + +### Arguments + +- **name** + Logical package name (e.g. "beman.utility"). + Used to derive config file names and cache variable prefixes. + +- **TARGETS** + Targets to install and export. + +- **DEPENDENCIES (optional)** + Semicolon-separated list, one dependency per entry. + Each entry is a valid `find_dependency()` argument list. + + **NOTE:** you must use the bracket form for quoting if not only a package name is used! + + `"[===[beman.inplace_vector 1.0.0]===] [===[beman.scope 0.0.1 EXACT]===] fmt"` + +- **NAMESPACE (optional)** + Namespace for imported targets. + Defaults to "beman::". + +- **EXPORT_NAME (optional)** + Name of the generated CMake export set. + Defaults to "-targets". + +- **DESTINATION (optional)** + Installation directory for C++ module interface units. + Defaults to `${CMAKE_INSTALL_INCLUDEDIR}/beman/modules`. + +This function installs the specified project TARGETS and its `FILE_SET +TYPE HEADERS` to the default CMAKE install destination. + +It also handles the installation of the CMake config package files if +needed. If the given targets has `FILE_SET TYPE CXX_MODULE`, it will also +installed to the given DESTINATION + +- ***Used Cache variables** + +`BEMAN_INSTALL_CONFIG_FILE_PACKAGES` + List of package names for which config files should be installed. + +`_INSTALL_CONFIG_FILE_PACKAGE` + Per-package override to enable/disable config file installation. + is the uppercased package name with dots replaced by underscores. + +### Caveats + +**Only one `FILE_SET of each TYPE` is supported to install with this function yet!** + +--- + +## The possible usage in CMakeLists.txt + +```cmake +cmake_minimum_required(VERSION 3.30...4.2) + +include(./cmake/prelude.cmake) +project(beman.execution VERSION 0.2.0 LANGUAGES CXX) +include(./cmake/cxx-modules-rules.cmake) + +set(TARGET_PREFIX ${PROJECT_NAME}) + +#=============================================================================== +if(BEMAN_USE_MODULES) + set(CMAKE_CXX_VISIBILITY_PRESET hidden) + set(CMAKE_VISIBILITY_INLINES_HIDDEN TRUE) + + # CMake requires the language standard to be specified as compile feature + # when a target provides C++23 modules and the target will be installed + add_library(${TARGET_PREFIX} STATIC) + add_library(beman::execution ALIAS ${TARGET_PREFIX}) + target_compile_features( + ${TARGET_PREFIX} + PUBLIC cxx_std_${CMAKE_CXX_STANDARD} + ) + + include(GenerateExportHeader) + generate_export_header( + ${TARGET_PREFIX} + BASE_NAME ${TARGET_PREFIX} + EXPORT_FILE_NAME beman/execution/modules_export.hpp + ) + target_sources( + ${TARGET_PREFIX} + PUBLIC + FILE_SET HEADERS + BASE_DIRS include ${CMAKE_CURRENT_BINARY_DIR} + FILES + ${CMAKE_CURRENT_BINARY_DIR}/beman/execution/modules_export.hpp + ) + target_compile_definitions(${TARGET_PREFIX} PUBLIC BEMAN_HAS_MODULES) +endif() + +if(BEMAN_USE_MODULES AND CMAKE_CXX_MODULE_STD) + target_compile_definitions(${TARGET_PREFIX} PUBLIC BEMAN_HAS_IMPORT_STD) +else() + message(WARNING "Missing support for CMAKE_CXX_MODULE_STD!") +endif() +#=============================================================================== + +# ... + +# NOTE: this must be done before tests! CK +include(beman-install-library) +beman_install_library(${PROJECT_NAME} TARGETS ${TARGET_PREFIX} beman.exemplar_headers # + # TODO(add): DEPENDENCIES [===[beman.inplace_vector 1.0.0]===] [===[beman.scope 0.0.1 EXACT]===] fmt +) +``` + +--- + +## Possible cmake config output + +**NOTE:** Exact output depend on the build host, used toolchain, and +whether module support is enabled and supported. + +```bash +bash-5.3$ make test-module +cmake -G Ninja -S /Users/clausklein/Workspace/cpp/beman-project/execution26 -B build/Darwin/default \ + -D CMAKE_EXPORT_COMPILE_COMMANDS=ON \ + -D CMAKE_SKIP_INSTALL_RULES=OFF \ + -D CMAKE_CXX_STANDARD=23 \ + -D CMAKE_CXX_EXTENSIONS=ON \ + -D CMAKE_CXX_STANDARD_REQUIRED=ON \ + -D CMAKE_CXX_SCAN_FOR_MODULES=ON \ + -D BEMAN_USE_MODULES=ON \ + -D CMAKE_BUILD_TYPE=Release \ + -D CMAKE_INSTALL_MESSAGE=LAZY \ + -D CMAKE_BUILD_TYPE=Release \ + -D CMAKE_CXX_COMPILER=clang++ --log-level=VERBOSE +-- use ccache +-- CXXFLAGS=-stdlib=libc++ +'brew' '--prefix' 'llvm' +-- LLVM_DIR=/usr/local/Cellar/llvm/21.1.8 +-- CMAKE_CXX_STDLIB_MODULES_JSON=/usr/local/Cellar/llvm/21.1.8/lib/c++/libc++.modules.json +-- CMAKE_CXX_IMPLICIT_INCLUDE_DIRECTORIES=/usr/local/Cellar/llvm/21.1.8/include/c++/v1;/usr/local/Cellar/llvm/21.1.8/lib/clang/21/include;/Library/Developer/CommandLineTools/SDKs/MacOSX14.sdk/usr/include +-- CMAKE_CXX_STDLIB_MODULES_JSON=/usr/local/Cellar/llvm/21.1.8/lib/c++/libc++.modules.json +-- BEMAN_USE_STD_MODULE=ON +-- CMAKE_CXX_COMPILER_IMPORT_STD=23;26 +-- CMAKE_CXX_MODULE_STD=ON +-- BEMAN_HAS_IMPORT_STD=ON +-- BEMAN_USE_MODULES=ON +-- CMAKE_CXX_SCAN_FOR_MODULES=ON +-- Performing Test COMPILER_HAS_HIDDEN_VISIBILITY +-- Performing Test COMPILER_HAS_HIDDEN_VISIBILITY - Success +-- Performing Test COMPILER_HAS_HIDDEN_INLINE_VISIBILITY +-- Performing Test COMPILER_HAS_HIDDEN_INLINE_VISIBILITY - Success +-- Performing Test COMPILER_HAS_DEPRECATED_ATTR +-- Performing Test COMPILER_HAS_DEPRECATED_ATTR - Success +-- beman_install_library(beman.execution): COMPONENT execution_headers for TARGET 'beman.execution_headers' +-- beman-install-library(beman.execution): 'beman.execution_headers' has INTERFACE_HEADER_SETS=public_headers +-- beman_install_library(beman.execution): COMPONENT execution for TARGET 'beman.execution' +-- beman-install-library(beman.execution): 'beman.execution' has INTERFACE_HEADER_SETS=HEADERS +-- beman-install-library(beman.execution): 'beman.execution' has CXX_MODULE_SETS=CXX_MODULES +-- Configuring done (3.1s) +CMake Warning (dev) in CMakeLists.txt: + CMake's support for `import std;` in C++23 and newer is experimental. It + is meant only for experimentation and feedback to CMake developers. +This warning is for project developers. Use -Wno-dev to suppress it. + +-- Generating done (0.4s) +-- Build files have been written to: /Users/clausklein/Workspace/cpp/beman-project/execution26/build/Darwin/default +bash-5.3$ +``` + +--- + +## Possible cmake export config package + +**NOTE:** Exact contents depend on the build host, used toolchain, and +whether module support is enabled. + +```bash +cmake --install build/Darwin/default --prefix $PWD/stagedir + +bash-5.3$ cd stagedir/ +bash-5.3$ tree lib/ +lib/ +├── cmake +│   └── beman.execution +│   ├── beman.execution-config-version.cmake +│   ├── beman.execution-config.cmake +│   ├── beman.execution-targets-debug.cmake +│   ├── beman.execution-targets-relwithdebinfo.cmake +│   ├── beman.execution-targets.cmake +│   ├── bmi-GNU_Debug +│   │   └── beman.execution.gcm +│   ├── bmi-GNU_RelWithDebInfo +│   │   └── beman.execution.gcm +│   ├── cxx-modules +│   │   ├── cxx-modules-beman.execution-Debug.cmake +│   │   ├── cxx-modules-beman.execution-RelWithDebInfo.cmake +│   │   ├── cxx-modules-beman.execution.cmake +│   │   ├── target-execution-Debug.cmake +│   │   └── target-execution-RelWithDebInfo.cmake +│   └── modules +│   └── execution.cppm +├── libbeman.execution.a +└── libbeman.execution_d.a + +7 directories, 15 files +bash-5.3$ +``` + +--- + +## The recommended usage in implementation + +```cpp +// identity.cppm +module; + +#ifdef BEMAN_HAS_IMPORT_STD +import std; +#else +#include +#endif + +export module beman.exemplar; + +export namespace beman::exemplar { +struct __is_transparent; + +struct identity { + template + constexpr T&& operator()(T&& t) const noexcept { + return std::forward(t); + } + + using is_transparent = __is_transparent; +}; +} // namespace beman::exemplar +``` + +--- + +## The possible usage in user code + +```cpp +// example-usage.cpp + +#ifdef BEMAN_HAS_IMPORT_STD +import std; +#else +#include +#endif + +#ifdef BEMAN_HAS_MODULES +import beman.exemplar; +#else +#include +#endif + +int main() { + beman::exemplar::identity id; + + int x = 42; + int y = id(x); // y == 42 + + std::cout << y << '\n'; + return 0; +} +``` + +--- + +## Notes on CMake and Modules + +- `FILE_SET CXX_MODULE` support is still evolving and depends on the compiler + and CMake version. + +- Not all toolchains support installing or consuming prebuilt module interface + units yet. + +- These helpers aim to provide a pragmatic, forward-compatible structure rather + than a final standard solution. + +--- + +## Summary + +The helpers in this directory provide a structured way to: + +- build header-only and module-based libraries side by side, +- hide compiler- and platform-specific complexity, +- install and export targets in a consistent, consumer-friendly way. + +They are intended for projects that want to experiment with C++ modules today +while remaining usable on traditional toolchains. diff --git a/cmake/beman-install-library-config.cmake b/cmake/beman-install-library-config.cmake deleted file mode 100644 index 4ad27ff2..00000000 --- a/cmake/beman-install-library-config.cmake +++ /dev/null @@ -1,251 +0,0 @@ -# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -include_guard(GLOBAL) - -# This file defines the function `beman_install_library` which is used to -# install a library target and its headers, along with optional CMake -# configuration files. -# -# The function is designed to be reusable across different Beman libraries. - -function(beman_install_library name interface) - # Usage - # ----- - # - # beman_install_library(NAME INTERFACE) - # - # Brief - # ----- - # - # This function installs the specified library target and its headers. - # It also handles the installation of the CMake configuration files if needed. - # - # CMake variables - # --------------- - # - # Note that configuration of the installation is generally controlled by CMake - # cache variables so that they can be controlled by the user or tool running the - # `cmake` command. Neither `CMakeLists.txt` nor `*.cmake` files should set these - # variables directly. - # - # - BEMAN_INSTALL_CONFIG_FILE_PACKAGES: - # List of packages that require config file installation. - # If the package name is in this list, it will install the config file. - # - # - _INSTALL_CONFIG_FILE_PACKAGE: - # Boolean to control config file installation for the specific library. - # The prefix `` is the uppercased name of the library with dots - # replaced by underscores. - # - - # if(NOT TARGET "${name}") - # message(FATAL_ERROR "Target '${name}' does not exist.") - # endif() - - # if(NOT ARGN STREQUAL "") - # message( - # FATAL_ERROR - # "beman_install_library does not accept extra arguments: ${ARGN}" - # ) - # endif() - - # Given foo.bar, the component name is bar - string(REPLACE "." ";" name_parts "${name}") - # fail if the name doesn't look like foo.bar - list(LENGTH name_parts name_parts_length) - if(NOT name_parts_length EQUAL 2) - message( - FATAL_ERROR - "beman_install_library expects a name of the form 'beman.', got '${name}'" - ) - endif() - - set(target_name "${name}") - - # COMPONENT - # Specify an installation component name with which the install rule is associated, - # such as Runtime or Development. - set(install_component_name "${name}") # TODO(CK): this is not common name! - - set(export_name "${name}") - set(package_name "${name}") - list(GET name_parts -1 component_name) - - include(GNUInstallDirs) - - set(package_install_dir "${CMAKE_INSTALL_LIBDIR}/cmake/${package_name}") - - set(target_list) - if(TARGET "${target_name}") - set_target_properties( - "${target_name}" - PROPERTIES EXPORT_NAME "${component_name}" - ) - message( - VERBOSE - "beman-install-library: COMPONENT ${component_name} for TARGET '${target_name}'" - ) - list(APPEND target_list "${target_name}") - - get_target_property( - INTERFACE_CXX_MODULE_SETS - ${target_name} - INTERFACE_CXX_MODULE_SETS - ) - if(INTERFACE_CXX_MODULE_SETS) - message( - VERBOSE - "beman-install-library: '${target_name}' has INTERFACE_CXX_MODULE_SETS=${INTERFACE_CXX_MODULE_SETS}" - ) - set(__INSTALL_CXX_MODULES - FILE_SET - ${INTERFACE_CXX_MODULE_SETS} - DESTINATION - ${package_install_dir}/modules - ) - endif() - endif() - - if(interface AND TARGET "${target_name}_${interface}") - set_target_properties( - "${target_name}_${interface}" - PROPERTIES EXPORT_NAME "${component_name}_${interface}" - ) - message( - VERBOSE - "beman-install-library: COMPONENT ${component_name} for TARGET '${name}_${interface}'" - ) - list(APPEND target_list "${target_name}_${interface}") - - get_target_property( - INTERFACE_HEADER_SETS - ${target_name}_${interface} - INTERFACE_HEADER_SETS - ) - if(INTERFACE_HEADER_SETS) - message( - VERBOSE - "beman-install-library: '${target_name}_${interface}' has INTERFACE_HEADER_SETS=${INTERFACE_HEADER_SETS}" - ) - set(__INSTALL_HEADER_SETS FILE_SET ${INTERFACE_HEADER_SETS}) - endif() - endif() - - if(CMAKE_SKIP_INSTALL_RULES) - message( - WARNING - "beman-install-library: not installing targets '${target_list}' due to CMAKE_SKIP_INSTALL_RULES" - ) - return() - endif() - - # ============================================================ - install( - TARGETS ${target_list} - COMPONENT "${install_component_name}" - EXPORT "${export_name}" - FILE_SET HEADERS - ${__INSTALL_HEADER_SETS} - # FILE_SET CXX_MODULES - # DESTINATION ${package_install_dir}/modules - ${__INSTALL_CXX_MODULES} - # There's currently no convention for this location - CXX_MODULES_BMI - DESTINATION - ${package_install_dir}/bmi-${CMAKE_CXX_COMPILER_ID}_$ - ) - # ============================================================ - - # Determine the prefix for project-specific variables - string(TOUPPER "${name}" project_prefix) - string(REPLACE "." "_" project_prefix "${project_prefix}") - - option( - ${project_prefix}_INSTALL_CONFIG_FILE_PACKAGE - "Enable creating and installing a CMake config-file package. Default: ON. Values: { ON, OFF }." - ON - ) - - # By default, install the config package - set(install_config_package ON) - - # Turn OFF installation of config package by default if, - # in order of precedence: - # 1. The specific package variable is set to OFF - # 2. The package name is not in the list of packages to install config files - if(DEFINED BEMAN_INSTALL_CONFIG_FILE_PACKAGES) - if( - NOT "${install_component_name}" - IN_LIST - BEMAN_INSTALL_CONFIG_FILE_PACKAGES - ) - set(install_config_package OFF) - endif() - endif() - if(DEFINED ${project_prefix}_INSTALL_CONFIG_FILE_PACKAGE) - set(install_config_package - ${${project_prefix}_INSTALL_CONFIG_FILE_PACKAGE} - ) - endif() - - if(install_config_package) - message( - VERBOSE - "beman-install-library: Export cmake config to ${package_install_dir} for '${name}'" - ) - - include(CMakePackageConfigHelpers) - - find_file( - config_file_template - NAMES "${package_name}-config.cmake.in" - PATHS "${PROJECT_SOURCE_DIR}/cmake" - NO_DEFAULT_PATH - NO_CACHE - REQUIRED - ) - set(config_package_file - "${CMAKE_CURRENT_BINARY_DIR}/${package_name}-config.cmake" - ) - configure_package_config_file( - "${config_file_template}" - "${config_package_file}" - INSTALL_DESTINATION "${package_install_dir}" - PATH_VARS PROJECT_NAME PROJECT_VERSION - ) - - set(config_version_file - "${CMAKE_CURRENT_BINARY_DIR}/${package_name}-config-version.cmake" - ) - write_basic_package_version_file( - "${config_version_file}" - VERSION "${PROJECT_VERSION}" - COMPATIBILITY ExactVersion - ) - - install( - FILES "${config_package_file}" "${config_version_file}" - DESTINATION "${package_install_dir}" - COMPONENT "${install_component_name}" - ) - - # NOTE: must be same value as ${TARGETS_EXPORT_NAME}.cmake! CK - set(config_targets_file "${package_name}-targets.cmake") - install( - EXPORT "${export_name}" - DESTINATION "${package_install_dir}" - NAMESPACE beman:: - FILE "${config_targets_file}" - CXX_MODULES_DIRECTORY - cxx-modules - COMPONENT "${install_component_name}" - ) - else() - message( - WARNING - "beman-install-library: Not installing a config package for '${name}'" - ) - endif() -endfunction() - -set(CPACK_GENERATOR TGZ) -include(CPack) diff --git a/cmake/beman-install-library.cmake b/cmake/beman-install-library.cmake new file mode 100644 index 00000000..5b90d9d3 --- /dev/null +++ b/cmake/beman-install-library.cmake @@ -0,0 +1,290 @@ +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +cmake_minimum_required(VERSION 3.30) + +include_guard(GLOBAL) + +include(CMakePackageConfigHelpers) +include(GNUInstallDirs) + +# beman_install_library +# ===================== +# +# Installs a library (or set of targets) along with headers, C++ modules, +# and optional CMake package configuration files. +# +# Usage: +# ------ +# beman_install_library( +# TARGETS [ ...] +# [DEPENDENCIES [ ...]] +# [NAMESPACE ] +# [EXPORT_NAME ] +# [DESTINATION ] +# ) +# +# Arguments: +# ---------- +# name +# Logical package name (e.g. "beman.utility"). +# Used to derive config file names and cache variable prefixes. +# +# TARGETS (required) +# List of CMake targets to install. +# +# DEPENDENCIES (optional) +# Semicolon-separated list, one dependency per entry. +# Each entry is a valid find_dependency() argument list. +# Note: you must use the bracket form for quoting if not only a package name is used! +# "[===[beman.inplace_vector 1.0.0]===] [===[beman.scope 0.0.1 EXACT]===] fmt" +# +# NAMESPACE (optional) +# Namespace for exported targets. +# Defaults to "beman::". +# +# EXPORT_NAME (optional) +# Name of the CMake export set. +# Defaults to "-targets". +# +# DESTINATION (optional) +# The install destination for CXX_MODULES. +# Defaults to ${CMAKE_INSTALL_LIBDIR}/cmake/${name}/modules. +# +# Brief +# ----- +# +# This function installs the specified project TARGETS and its FILE_SET +# HEADERS to the default CMAKE install destination. +# +# It also handles the installation of the CMake config package files if +# needed. If the given targets has FILE_SET CXX_MODULE, it will also +# installed to the given DESTINATION +# +# Cache variables: +# ---------------- +# BEMAN_INSTALL_CONFIG_FILE_PACKAGES +# List of package names for which config files should be installed. +# +# _INSTALL_CONFIG_FILE_PACKAGE +# Per-package override to enable/disable config file installation. +# is the uppercased package name with dots replaced by underscores. +# +function(beman_install_library name) + # ---------------------------- + # Argument parsing + # ---------------------------- + set(options) + set(oneValueArgs NAMESPACE EXPORT_NAME DESTINATION) + set(multiValueArgs TARGETS DEPENDENCIES) + + cmake_parse_arguments( + BEMAN + "${options}" + "${oneValueArgs}" + "${multiValueArgs}" + ${ARGN} + ) + + if(NOT BEMAN_TARGETS) + message( + FATAL_ERROR + "beman_install_library(${name}): TARGETS must be specified" + ) + endif() + + if(CMAKE_SKIP_INSTALL_RULES) + message( + WARNING + "beman_install_library(${name}): not installing targets '${BEMAN_TARGETS}' due to CMAKE_SKIP_INSTALL_RULES" + ) + return() + endif() + + set(_config_install_dir "${CMAKE_INSTALL_LIBDIR}/cmake/${name}") + + # ---------------------------- + # Defaults + # ---------------------------- + if(NOT BEMAN_NAMESPACE) + set(BEMAN_NAMESPACE "beman::") + endif() + + if(NOT BEMAN_EXPORT_NAME) + set(BEMAN_EXPORT_NAME "${name}-targets") + endif() + + if(NOT BEMAN_DESTINATION) + set(BEMAN_DESTINATION "${_config_install_dir}/modules") + endif() + + string(REPLACE "beman." "" install_component_name "${name}") + + # -------------------------------------------------- + # Install each target with all of its file sets + # -------------------------------------------------- + foreach(_tgt IN LISTS BEMAN_TARGETS) + if(NOT TARGET "${_tgt}") + message( + WARNING + "beman_install_library(${name}): '${_tgt}' is not a target" + ) + continue() + endif() + + # Given foo.bar, the component name is bar + string(REPLACE "." ";" name_parts "${_tgt}") + # fail if the name doesn't look like foo.bar + list(LENGTH name_parts name_parts_length) + if(NOT name_parts_length EQUAL 2) + message( + FATAL_ERROR + "beman_install_library(${name}): expects a name of the form 'beman.', got '${_tgt}'" + ) + endif() + list(GET name_parts -1 component_name) + set_target_properties( + "${_tgt}" + PROPERTIES EXPORT_NAME "${component_name}" + ) + message( + VERBOSE + "beman_install_library(${name}): COMPONENT ${component_name} for TARGET '${_tgt}'" + ) + + # Get the list of interface header sets, exact one expected! + get_target_property(_header_sets ${_tgt} INTERFACE_HEADER_SETS) + if(_header_sets) + message( + VERBOSE + "beman-install-library(${name}): '${_tgt}' has INTERFACE_HEADER_SETS=${_header_sets}" + ) + else() + set(_header_sets HEADERS) # Note: empty FILE_SET in this case! CK + endif() + + # Detect presence of C++ module file sets, exact one expected! + get_target_property(_module_sets "${_tgt}" CXX_MODULE_SETS) + if(_module_sets) + message( + VERBOSE + "beman-install-library(${name}): '${_tgt}' has CXX_MODULE_SETS=${_module_sets}" + ) + install( + TARGETS "${_tgt}" + COMPONENT "${install_component_name}" + EXPORT ${BEMAN_EXPORT_NAME} + ARCHIVE # DESTINATION ${CMAKE_INSTALL_LIBDIR} + LIBRARY # DESTINATION ${CMAKE_INSTALL_LIBDIR} + RUNTIME # DESTINATION ${CMAKE_INSTALL_BINDIR} + FILE_SET + ${_header_sets} # DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} + FILE_SET ${_module_sets} DESTINATION "${BEMAN_DESTINATION}" + # NOTE: There's currently no convention for this location! CK + CXX_MODULES_BMI + # TODO(CK): DESTINATION ${_config_install_dir}/bmi-${CMAKE_CXX_COMPILER_ID}_$ + ) + else() + install( + TARGETS "${_tgt}" + COMPONENT "${install_component_name}" + EXPORT ${BEMAN_EXPORT_NAME} + ARCHIVE # DESTINATION ${CMAKE_INSTALL_LIBDIR} + LIBRARY # DESTINATION ${CMAKE_INSTALL_LIBDIR} + RUNTIME # DESTINATION ${CMAKE_INSTALL_BINDIR} + FILE_SET + ${_header_sets} # DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} + ) + endif() + endforeach() + + # -------------------------------------------------- + # Export targets + # -------------------------------------------------- + install( + EXPORT ${BEMAN_EXPORT_NAME} + NAMESPACE ${BEMAN_NAMESPACE} + CXX_MODULES_DIRECTORY + cxx-modules + DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${name} + COMPONENT "${install_component_name}" + ) + + # ---------------------------------------- + # Config file installation logic + # ---------------------------------------- + string(TOUPPER "${name}" _pkg_upper) + string(REPLACE "." "_" _pkg_prefix "${_pkg_upper}") + + option( + ${_pkg_prefix}_INSTALL_CONFIG_FILE_PACKAGE + "Enable creating and installing a CMake config-file package. Default: ON. Values: { ON, OFF }." + ON + ) + + set(_pkg_var "${_pkg_prefix}_INSTALL_CONFIG_FILE_PACKAGE") + + if(NOT DEFINED ${_pkg_var}) + set(${_pkg_var} + OFF + CACHE BOOL + "Install CMake package config files for ${name}" + ) + endif() + + set(_install_config OFF) + + if(${_pkg_var}) + set(_install_config ON) + elseif(BEMAN_INSTALL_CONFIG_FILE_PACKAGES) + list(FIND BEMAN_INSTALL_CONFIG_FILE_PACKAGES "${name}" _idx) + if(NOT _idx EQUAL -1) + set(_install_config ON) + endif() + endif() + + # ---------------------------------------- + # expand dependencies + # ---------------------------------------- + set(_beman_find_deps "") + foreach(dep IN ITEMS ${BEMAN_DEPENDENCIES}) + message( + VERBOSE + "beman-install-library(${name}): Add find_dependency(${dep})" + ) + string(APPEND _beman_find_deps "find_dependency(${dep})\n") + endforeach() + set(BEMAN_FIND_DEPENDENCIES "${_beman_find_deps}") + + # ---------------------------------------- + # Generate + install config files + # ---------------------------------------- + if(_install_config) + configure_package_config_file( + "${CMAKE_CURRENT_FUNCTION_LIST_DIR}/Config.cmake.in" + "${CMAKE_CURRENT_BINARY_DIR}/${name}-config.cmake" + INSTALL_DESTINATION ${_config_install_dir} + ) + + write_basic_package_version_file( + "${CMAKE_CURRENT_BINARY_DIR}/${name}-config-version.cmake" + VERSION ${PROJECT_VERSION} + COMPATIBILITY SameMajorVersion + ) + + install( + FILES + "${CMAKE_CURRENT_BINARY_DIR}/${name}-config.cmake" + "${CMAKE_CURRENT_BINARY_DIR}/${name}-config-version.cmake" + DESTINATION ${_config_install_dir} + COMPONENT "${install_component_name}" + ) + else() + message( + WARNING + "beman-install-library(${name}): Not installing a config package for '${name}'" + ) + endif() +endfunction() + +set(CPACK_GENERATOR TGZ) +include(CPack) diff --git a/cmake/beman.execution-config.cmake.in b/cmake/beman.execution-config.cmake.in deleted file mode 100644 index 40463a38..00000000 --- a/cmake/beman.execution-config.cmake.in +++ /dev/null @@ -1,7 +0,0 @@ -# cmake/Config.cmake.in -*-makefile-*- -# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - -@PACKAGE_INIT@ - -include("${CMAKE_CURRENT_LIST_DIR}/@TARGETS_EXPORT_NAME@.cmake") -check_required_components("@TARGET_LIBRARY@") diff --git a/cmake/cxx-modules-rules.cmake b/cmake/cxx-modules-rules.cmake index 498131d1..91939b36 100644 --- a/cmake/cxx-modules-rules.cmake +++ b/cmake/cxx-modules-rules.cmake @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception # # A CMake language file to be included as the last step of all project() command calls. # This file must be included/used as CMAKE_PROJECT_INCLUDE -> after project() @@ -89,6 +90,11 @@ if(NOT DEFINED CMAKE_CXX_MODULE_STD) set(CMAKE_CXX_MODULE_STD OFF) endif() +if(CMAKE_CXX_STANDARD GREATER_EQUAL 20) + option(BEMAN_USE_MODULES "Build CXX_MODULES" ${CMAKE_CXX_SCAN_FOR_MODULES}) +endif() +message(STATUS "BEMAN_USE_MODULES=${BEMAN_USE_MODULES}") + option( BEMAN_USE_STD_MODULE "Check if 'import std;' is possible with the toolchain?" @@ -96,7 +102,7 @@ option( ) message(STATUS "BEMAN_USE_STD_MODULE=${BEMAN_USE_STD_MODULE}") -if(BEMAN_USE_STD_MODULE) +if(BEMAN_USE_MODULES AND BEMAN_USE_STD_MODULE) # ------------------------------------------------------------------------- # Tell CMake that we explicitly want `import std`. # This will initialize the property on all targets declared after this to 1 @@ -121,11 +127,6 @@ if(BEMAN_USE_STD_MODULE) message(STATUS "BEMAN_HAS_IMPORT_STD=${BEMAN_HAS_IMPORT_STD}") endif() -if(CMAKE_CXX_STANDARD GREATER_EQUAL 20) - option(BEMAN_USE_MODULES "Build CXX_MODULES" ${CMAKE_CXX_SCAN_FOR_MODULES}) -endif() -message(STATUS "BEMAN_USE_MODULES=${BEMAN_USE_MODULES}") - if(NOT BEMAN_USE_MODULES) set(CMAKE_CXX_SCAN_FOR_MODULES OFF) endif() diff --git a/cmake/prelude.cmake b/cmake/prelude.cmake index c7b86338..588e608c 100644 --- a/cmake/prelude.cmake +++ b/cmake/prelude.cmake @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception # # This file must be included/used as CMAKE_PROJECT_TOP_LEVEL_INCLUDES -> before project() is called! # @@ -14,35 +15,36 @@ if(CMAKE_SOURCE_DIR STREQUAL CMAKE_BINARY_DIR) ) endif() -if(PROJECT_NAME) - message( - FATAL_ERROR - "This CMake file has to be included before first project() command call!" - ) -endif() +list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_LIST_DIR}) -# gersemi: off -# --------------------------------------------------------------------------- -# use ccache if found # --------------------------------------------------------------------------- -find_program(CCACHE_EXECUTABLE "ccache" HINTS /usr/local/bin /opt/local/bin) -if(CCACHE_EXECUTABLE) - message(STATUS "use ccache") - set(CMAKE_CXX_COMPILER_LAUNCHER "${CCACHE_EXECUTABLE}" CACHE PATH "ccache") - set(CMAKE_C_COMPILER_LAUNCHER "${CCACHE_EXECUTABLE}" CACHE PATH "ccache") +if(NOT BEMAN_USE_STD_MODULE OR CMAKE_VERSION VERSION_GREATER_EQUAL 4.3) + return() endif() +# --------------------------------------------------------------------------- -list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_LIST_DIR}) - +# gersemi: off # --------------------------------------------------------------------------- # check if import std; is supported by CMAKE_CXX_COMPILER # --------------------------------------------------------------------------- if(CMAKE_VERSION VERSION_GREATER_EQUAL 4.2) + if(PROJECT_NAME) + message( + WARNING + "This CMake file has to be included before first project() command call!" + ) + endif() + set(CMAKE_EXPERIMENTAL_CXX_IMPORT_STD "d0edc3af-4c50-42ea-a356-e2862fe7a444") endif() # gersemi: on -# FIXME: on APPLE with clang++ still needs to export CXX=clang++ +# TODO(CK): Do we need this HACK for linux too? +# if(NOT APPLE) +# return() +# endif() + +# FIXME: clang++ we still needs to export CXX=clang++ if("$ENV{CXX}" STREQUAL "" AND CMAKE_CXX_COMPILER) message(WARNING "\$CXX is not set") set(ENV{CXX} ${CMAKE_CXX_COMPILER}) @@ -80,7 +82,7 @@ if( elseif(LINUX) execute_process( OUTPUT_VARIABLE LLVM_MODULES - COMMAND clang++ -print-file-name=c++/libc++.modules.json + COMMAND clang++ -print-file-name=libc++.modules.json COMMAND_ECHO STDOUT OUTPUT_STRIP_TRAILING_WHITESPACE ) @@ -107,7 +109,7 @@ if( # gersemi: on else() message( - WARNING + FATAL_ERROR "File does NOT EXISTS! ${CMAKE_CXX_STDLIB_MODULES_JSON}" ) endif() diff --git a/cmake/presets/CMakeGenericPresets.json b/cmake/presets/CMakeGenericPresets.json index df2d2045..e86aea1e 100644 --- a/cmake/presets/CMakeGenericPresets.json +++ b/cmake/presets/CMakeGenericPresets.json @@ -12,9 +12,9 @@ "type": "path", "value": "${sourceDir}/stagedir" }, + "BEMAN_USE_MODULES": true, "CMAKE_CXX_STANDARD": "23", "CMAKE_CXX_EXTENSIONS": true, - "CMAKE_CXX_SCAN_FOR_MODULES": true, "CMAKE_CXX_STANDARD_REQUIRED": true, "CMAKE_EXPORT_COMPILE_COMMANDS": true, "CMAKE_INSTALL_MESSAGE": "LAZY", diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index c68e6e17..958b6df0 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -43,7 +43,6 @@ foreach(EXAMPLE ${EXAMPLES}) add_executable(${EXAMPLE_TARGET}) target_sources(${EXAMPLE_TARGET} PRIVATE ${EXAMPLE}.cpp) if(BEMAN_USE_MODULES) - # target_compile_definitions(${EXAMPLE_TARGET} PUBLIC BEMAN_HAS_MODULES) target_link_libraries(${EXAMPLE_TARGET} PRIVATE beman::execution) else() target_link_libraries( diff --git a/infra/cmake/appleclang-toolchain.cmake b/infra/cmake/appleclang-toolchain.cmake index 70ef548e..451c86b6 100644 --- a/infra/cmake/appleclang-toolchain.cmake +++ b/infra/cmake/appleclang-toolchain.cmake @@ -32,7 +32,7 @@ endif() set(CMAKE_C_FLAGS_DEBUG_INIT "${SANITIZER_FLAGS}") set(CMAKE_CXX_FLAGS_DEBUG_INIT "${SANITIZER_FLAGS}") -set(RELEASE_FLAGS "-O3 ${SANITIZER_FLAGS}") +set(RELEASE_FLAGS "-O3") set(CMAKE_C_FLAGS_RELWITHDEBINFO_INIT "${RELEASE_FLAGS}") set(CMAKE_CXX_FLAGS_RELWITHDEBINFO_INIT "${RELEASE_FLAGS}") @@ -41,4 +41,4 @@ set(CMAKE_C_FLAGS_RELEASE_INIT "${RELEASE_FLAGS}") set(CMAKE_CXX_FLAGS_RELEASE_INIT "${RELEASE_FLAGS}") # Add this dir to the module path so that `find_package(beman-install-library)` works -list(APPEND CMAKE_PREFIX_PATH "${CMAKE_CURRENT_LIST_DIR}") +# NO! list(APPEND CMAKE_PREFIX_PATH "${CMAKE_CURRENT_LIST_DIR}") diff --git a/infra/cmake/gnu-toolchain.cmake b/infra/cmake/gnu-toolchain.cmake index d3b9f92d..a946349d 100644 --- a/infra/cmake/gnu-toolchain.cmake +++ b/infra/cmake/gnu-toolchain.cmake @@ -29,7 +29,7 @@ endif() set(CMAKE_C_FLAGS_DEBUG_INIT "${SANITIZER_FLAGS}") set(CMAKE_CXX_FLAGS_DEBUG_INIT "${SANITIZER_FLAGS}") -set(RELEASE_FLAGS "-O3 ${SANITIZER_FLAGS}") +set(RELEASE_FLAGS "-O3") set(CMAKE_C_FLAGS_RELWITHDEBINFO_INIT "${RELEASE_FLAGS}") set(CMAKE_CXX_FLAGS_RELWITHDEBINFO_INIT "${RELEASE_FLAGS}") @@ -38,4 +38,4 @@ set(CMAKE_C_FLAGS_RELEASE_INIT "${RELEASE_FLAGS}") set(CMAKE_CXX_FLAGS_RELEASE_INIT "${RELEASE_FLAGS}") # Add this dir to the module path so that `find_package(beman-install-library)` works -list(APPEND CMAKE_PREFIX_PATH "${CMAKE_CURRENT_LIST_DIR}") +# NO! list(APPEND CMAKE_PREFIX_PATH "${CMAKE_CURRENT_LIST_DIR}") diff --git a/infra/cmake/llvm-toolchain.cmake b/infra/cmake/llvm-toolchain.cmake index f1623b7e..b0ca3bdb 100644 --- a/infra/cmake/llvm-toolchain.cmake +++ b/infra/cmake/llvm-toolchain.cmake @@ -29,7 +29,7 @@ endif() set(CMAKE_C_FLAGS_DEBUG_INIT "${SANITIZER_FLAGS}") set(CMAKE_CXX_FLAGS_DEBUG_INIT "${SANITIZER_FLAGS}") -set(RELEASE_FLAGS "-O3 ${SANITIZER_FLAGS}") +set(RELEASE_FLAGS "-O3") set(CMAKE_C_FLAGS_RELWITHDEBINFO_INIT "${RELEASE_FLAGS}") set(CMAKE_CXX_FLAGS_RELWITHDEBINFO_INIT "${RELEASE_FLAGS}") @@ -38,4 +38,4 @@ set(CMAKE_C_FLAGS_RELEASE_INIT "${RELEASE_FLAGS}") set(CMAKE_CXX_FLAGS_RELEASE_INIT "${RELEASE_FLAGS}") # Add this dir to the module path so that `find_package(beman-install-library)` works -list(APPEND CMAKE_PREFIX_PATH "${CMAKE_CURRENT_LIST_DIR}") +# NO! list(APPEND CMAKE_PREFIX_PATH "${CMAKE_CURRENT_LIST_DIR}") diff --git a/infra/cmake/msvc-toolchain.cmake b/infra/cmake/msvc-toolchain.cmake index bdc24de9..7bd82279 100644 --- a/infra/cmake/msvc-toolchain.cmake +++ b/infra/cmake/msvc-toolchain.cmake @@ -29,7 +29,7 @@ endif() set(CMAKE_CXX_FLAGS_DEBUG_INIT "/EHsc /permissive- ${SANITIZER_FLAGS}") set(CMAKE_C_FLAGS_DEBUG_INIT "/EHsc /permissive- ${SANITIZER_FLAGS}") -set(RELEASE_FLAGS "/EHsc /permissive- /O2 ${SANITIZER_FLAGS}") +set(RELEASE_FLAGS "/EHsc /permissive- /O2") set(CMAKE_C_FLAGS_RELWITHDEBINFO_INIT "${RELEASE_FLAGS}") set(CMAKE_CXX_FLAGS_RELWITHDEBINFO_INIT "${RELEASE_FLAGS}") @@ -38,4 +38,4 @@ set(CMAKE_C_FLAGS_RELEASE_INIT "${RELEASE_FLAGS}") set(CMAKE_CXX_FLAGS_RELEASE_INIT "${RELEASE_FLAGS}") # Add this dir to the module path so that `find_package(beman-install-library)` works -list(APPEND CMAKE_PREFIX_PATH "${CMAKE_CURRENT_LIST_DIR}") +# NO! list(APPEND CMAKE_PREFIX_PATH "${CMAKE_CURRENT_LIST_DIR}") diff --git a/src/beman/execution/CMakeLists.txt b/src/beman/execution/CMakeLists.txt index 10774bac..1558ca95 100644 --- a/src/beman/execution/CMakeLists.txt +++ b/src/beman/execution/CMakeLists.txt @@ -200,8 +200,8 @@ if(BEMAN_USE_MODULES) execution.cpp # TODO(CK): check if really needed! PUBLIC FILE_SET CXX_MODULES - BASE_DIRS ${PROJECT_SOURCE_DIR}/src/beman/execution - FILES ${PROJECT_SOURCE_DIR}/src/beman/execution/execution.cppm + BASE_DIRS ${CMAKE_CURRENT_SOURCE_DIR} + FILES execution.cppm ) target_link_libraries(${TARGET_PREFIX} PUBLIC ${TARGET_NAME}) endif() diff --git a/tests/beman/execution/CMakeLists.txt b/tests/beman/execution/CMakeLists.txt index 65238e5c..0bbfea16 100644 --- a/tests/beman/execution/CMakeLists.txt +++ b/tests/beman/execution/CMakeLists.txt @@ -122,6 +122,13 @@ foreach(test ${execution_tests}) add_test(NAME ${TEST_EXE} COMMAND $) endforeach() +if(CMAKE_BUILD_TYPE STREQUAL "Debug") + return() +endif() + +#====================================================================== +# NOTE: Only for Release build with enabled install rules useful! CK +#====================================================================== if(BEMAN_EXECUTION_INSTALL_CONFIG_FILE_PACKAGE AND NOT CMAKE_SKIP_INSTALL_RULES) # test if the targets are usable from the install directory add_test( @@ -141,11 +148,11 @@ if(BEMAN_EXECUTION_INSTALL_CONFIG_FILE_PACKAGE AND NOT CMAKE_SKIP_INSTALL_RULES) --build-makeprogram ${CMAKE_MAKE_PROGRAM} # --build-options # "-D BEMAN_USE_MODULES=${BEMAN_USE_MODULES}" + "-D BEMAN_USE_STD_MODULE=${BEMAN_USE_STD_MODULE}" "-D CMAKE_BUILD_TYPE=$" "-D CMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}" "-D CMAKE_CXX_EXTENSIONS=${CMAKE_CXX_EXTENSIONS}" "-D CMAKE_CXX_MODULE_STD=${CMAKE_CXX_MODULE_STD}" - "-D CMAKE_CXX_SCAN_FOR_MODULES=${CMAKE_CXX_SCAN_FOR_MODULES}" "-D CMAKE_CXX_STANDARD=${CMAKE_CXX_STANDARD}" "-D CMAKE_CXX_STANDARD_REQUIRED=${CMAKE_CXX_STANDARD_REQUIRED}" "-D CMAKE_PREFIX_PATH=${CMAKE_BINARY_DIR}/stagedir"