diff --git a/CMakeLists.txt b/CMakeLists.txt index 58de2a65..0444f743 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,7 +3,7 @@ # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception # gersemi: on -cmake_minimum_required(VERSION 3.30...4.3) +cmake_minimum_required(VERSION 3.30...4.4) include(./cmake/prelude.cmake) diff --git a/CMakePresets.json b/CMakePresets.json index 61065330..224619b9 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -10,12 +10,12 @@ "BEMAN_USE_MODULES": true, "BEMAN_USE_STD_MODULE": true, "CMAKE_CXX_STANDARD": "23", - "CMAKE_CXX_EXTENSIONS": true, + "CMAKE_CXX_EXTENSIONS": false, "CMAKE_CXX_STANDARD_REQUIRED": true, "CMAKE_EXPORT_COMPILE_COMMANDS": true, "CMAKE_INSTALL_MESSAGE": "LAZY", "CMAKE_SKIP_TEST_ALL_DEPENDENCY": false, - "CMAKE_PROJECT_TOP_LEVEL_INCLUDES": "infra/cmake/use-fetch-content.cmake" + "CMAKE_PROJECT_TOP_LEVEL_INCLUDES": "${sourceDir}/infra/cmake/use-fetch-content.cmake" } }, { @@ -52,7 +52,7 @@ "_debug-base" ], "cacheVariables": { - "CMAKE_TOOLCHAIN_FILE": "infra/cmake/gnu-toolchain.cmake" + "CMAKE_TOOLCHAIN_FILE": "${sourceDir}/infra/cmake/gnu-toolchain.cmake" } }, { @@ -63,7 +63,7 @@ "_release-base" ], "cacheVariables": { - "CMAKE_TOOLCHAIN_FILE": "infra/cmake/gnu-toolchain.cmake" + "CMAKE_TOOLCHAIN_FILE": "${sourceDir}/infra/cmake/gnu-toolchain.cmake" } }, { @@ -74,8 +74,8 @@ "_debug-base" ], "cacheVariables": { - "BEMAN_USE_STD_MODULE": false, - "CMAKE_TOOLCHAIN_FILE": "infra/cmake/llvm-libc++-toolchain.cmake" + "BEMAN_USE_STD_MODULE": true, + "CMAKE_TOOLCHAIN_FILE": "${sourceDir}/infra/cmake/llvm-libc++-toolchain.cmake" }, "environment": { "CXX": "clang++", @@ -91,7 +91,7 @@ ], "cacheVariables": { "BEMAN_USE_STD_MODULE": false, - "CMAKE_TOOLCHAIN_FILE": "infra/cmake/llvm-libc++-toolchain.cmake" + "CMAKE_TOOLCHAIN_FILE": "${sourceDir}/infra/cmake/llvm-libc++-toolchain.cmake" }, "environment": { "CXX": "clang++", @@ -109,7 +109,7 @@ "cacheVariables": { "BEMAN_USE_STD_MODULE": false, "BEMAN_USE_MODULES": false, - "CMAKE_TOOLCHAIN_FILE": "infra/cmake/appleclang-toolchain.cmake" + "CMAKE_TOOLCHAIN_FILE": "${sourceDir}/infra/cmake/appleclang-toolchain.cmake" } }, { @@ -123,7 +123,7 @@ "cacheVariables": { "BEMAN_USE_STD_MODULE": false, "BEMAN_USE_MODULES": false, - "CMAKE_TOOLCHAIN_FILE": "infra/cmake/appleclang-toolchain.cmake" + "CMAKE_TOOLCHAIN_FILE": "${sourceDir}/infra/cmake/appleclang-toolchain.cmake" } }, { @@ -134,7 +134,7 @@ "_debug-base" ], "cacheVariables": { - "CMAKE_TOOLCHAIN_FILE": "infra/cmake/msvc-toolchain.cmake" + "CMAKE_TOOLCHAIN_FILE": "${sourceDir}/infra/cmake/msvc-toolchain.cmake" }, "condition": { "type": "equals", @@ -150,7 +150,7 @@ "_release-base" ], "cacheVariables": { - "CMAKE_TOOLCHAIN_FILE": "infra/cmake/msvc-toolchain.cmake" + "CMAKE_TOOLCHAIN_FILE": "${sourceDir}/infra/cmake/msvc-toolchain.cmake" }, "condition": { "type": "equals", diff --git a/Makefile b/Makefile index 6bd96c88..218730ec 100644 --- a/Makefile +++ b/Makefile @@ -163,7 +163,7 @@ build build-interface: -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_EXTENSIONS=OFF \ -D CMAKE_CXX_STANDARD_REQUIRED=ON \ -D BEMAN_USE_MODULES=OFF \ -D BEMAN_USE_STD_MODULE=OFF \ @@ -184,7 +184,7 @@ module build-module: -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_EXTENSIONS=OFF \ -D CMAKE_CXX_STANDARD_REQUIRED=ON \ -D BEMAN_USE_MODULES=ON \ -D BEMAN_USE_STD_MODULE=ON \ @@ -204,13 +204,13 @@ CMakeUserPresets.json:: cmake/CMakeUserPresets.json ln -s $< $@ # ========================================================== -appleclang-release llvm-release release: +appleclang-release llvm-release gcc-release release: cmake --preset $@ --log-level=TRACE # XXX --fresh ln -fs $(BUILDROOT)/$@/compile_commands.json . cmake --workflow --preset $@ # ========================================================== -appleclang-debug llvm-debug debug: +appleclang-debug llvm-debug gcc-debug debug: cmake --preset $@ --log-level=TRACE # XXX --fresh ln -fs $(BUILDROOT)build/$@/compile_commands.json . cmake --workflow --preset $@ diff --git a/cmake/prelude.cmake b/cmake/prelude.cmake index cdc58981..de91a0b5 100644 --- a/cmake/prelude.cmake +++ b/cmake/prelude.cmake @@ -39,25 +39,19 @@ if(CMAKE_VERSION VERSION_GREATER_EQUAL 4.2 AND CMAKE_VERSION VERSION_LESS 4.4) ) endif() endif() - -# --------------------------------------------------------------------------- -# check if import std; is supported by CMAKE_CXX_COMPILER -# --------------------------------------------------------------------------- -if(CMAKE_VERSION VERSION_GREATER_EQUAL 4.3 AND CMAKE_VERSION VERSION_LESS 4.4) - set(CMAKE_EXPERIMENTAL_CXX_IMPORT_STD "451f2fe2-a8a2-47c3-bc32-94786d8fc91b") -elseif(CMAKE_VERSION VERSION_GREATER_EQUAL 4.2 AND CMAKE_VERSION VERSION_LESS 4.3) - set(CMAKE_EXPERIMENTAL_CXX_IMPORT_STD "d0edc3af-4c50-42ea-a356-e2862fe7a444") -endif() # gersemi: on -# --------------------------------------------------------------------------- -# TODO(CK): Do we need this HACK still for linux too? -# --------------------------------------------------------------------------- +include( + ${CMAKE_CURRENT_LIST_DIR}/../infra/cmake/enable-experimental-import-std.cmake +) + 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}) diff --git a/cmake/presets/CMakeGenericPresets.json b/cmake/presets/CMakeGenericPresets.json index 645c009e..0c5ab5c2 100644 --- a/cmake/presets/CMakeGenericPresets.json +++ b/cmake/presets/CMakeGenericPresets.json @@ -15,7 +15,7 @@ "BEMAN_USE_MODULES": true, "BEMAN_USE_STD_MODULE": true, "CMAKE_CXX_STANDARD": "23", - "CMAKE_CXX_EXTENSIONS": true, + "CMAKE_CXX_EXTENSIONS": false, "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 c27226bc..aba158af 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -3,7 +3,7 @@ # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception # gersemi: on -cmake_minimum_required(VERSION 3.30...4.3) +cmake_minimum_required(VERSION 3.30...4.4) include(../cmake/prelude.cmake) diff --git a/infra/.beman_submodule b/infra/.beman_submodule index 28a06000..628b5d0d 100644 --- a/infra/.beman_submodule +++ b/infra/.beman_submodule @@ -1,3 +1,3 @@ [beman_submodule] remote=https://github.com/bemanproject/infra.git -commit_hash=63cb577f6484f13ce3349de49ad5ce27e20bf1da +commit_hash=7b66b858d7f48428fca936184aef2bd246ccc81a diff --git a/infra/.github/CODEOWNERS b/infra/.github/CODEOWNERS index 4ff90a43..439303d4 100644 --- a/infra/.github/CODEOWNERS +++ b/infra/.github/CODEOWNERS @@ -1 +1 @@ -* @ednolan @neatudarius @rishyak @wusatosi @JeffGarland +* @ednolan @rishyak @wusatosi @JeffGarland diff --git a/infra/.github/workflows/pre-commit.yml b/infra/.github/workflows/pre-commit.yml index 96468311..7051c132 100644 --- a/infra/.github/workflows/pre-commit.yml +++ b/infra/.github/workflows/pre-commit.yml @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception name: Lint Check (pre-commit) on: diff --git a/infra/.pre-commit-config.yaml b/infra/.pre-commit-config.yaml index bc4dd844..6fe1e857 100644 --- a/infra/.pre-commit-config.yaml +++ b/infra/.pre-commit-config.yaml @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception repos: - repo: https://github.com/pre-commit/pre-commit-hooks rev: v6.0.0 @@ -8,13 +9,13 @@ repos: - id: check-added-large-files - repo: https://github.com/codespell-project/codespell - rev: v2.4.1 + rev: v2.4.2 hooks: - id: codespell # CMake linting and formatting - - repo: https://github.com/BlankSpruce/gersemi - rev: 0.22.3 + - repo: https://github.com/BlankSpruce/gersemi-pre-commit + rev: 0.27.2 hooks: - id: gersemi name: CMake linting diff --git a/infra/README.md b/infra/README.md index a869e462..6cb8dd68 100644 --- a/infra/README.md +++ b/infra/README.md @@ -22,7 +22,7 @@ This repository is intended to be used as a beman-submodule in other Beman repos #### `beman_install_library` The CMake modules in this repository are intended to be used by Beman libraries. Use the -`beman_add_install_library_config()` function to install your library, along with header +`beman_install_library()` function to install your library, along with header files, any metadata files, and a CMake config file for `find_package()` support. ```cmake @@ -31,7 +31,7 @@ add_library(beman::something ALIAS beman.something) # ... configure your target as needed ... -find_package(beman-install-library REQUIRED) +include(infra/cmake/beman-install-library.cmake) beman_install_library(beman.something) ``` @@ -52,3 +52,37 @@ Some options for the project and target will also be supported: * `BEMAN_INSTALL_CONFIG_FILE_PACKAGES` - a list of package names (e.g., `beman.something`) for which to install the config file (default: all packages) * `_INSTALL_CONFIG_FILE_PACKAGE` - a per-project option to enable/disable config file installation (default: `ON` if the project is top-level, `OFF` otherwise). For instance for `beman.something`, the option would be `BEMAN_SOMETHING_INSTALL_CONFIG_FILE_PACKAGE`. + +# BuildTelemetry + +The cmake modules in this library provide access to CMake instrumentation data in Google Trace format which is visualizable with chrome://tracing and https://ui.perfetto.dev. + +Telemetry may be enabled in several ways: + +## `include` + +```cmake +include (infra/cmake/BuildTelemetry.cmake) +configure_build_telemetry() +``` + +## `find_package` + +```cmake +find_package(BuildTelemetry) +configure_build_telemetry() +``` + +as long as [BuildTelemetryConfig.cmake](./cmake/BuildTelemetryConfig.cmake) is in your module path. + +## `CMAKE_PROJECT_TOP_LEVEL_INCLUDES` +A non-invasive way to inject this telemetry into a CMake build you do not want to modify. +Add: +```sh +-DCMAKE_PROJECT_TOP_LEVEL_INCLUDES=infra/cmake/BuildTelemetry.cmake +``` +To the cmake invocation. + +In any form, CMake will call `telemetry.sh` which will copy the trace data in json format into a `.trace` subdirectory within the build directory. + +Multiple calls to `configure_build_telemetry` will only configure the callback hooks once, so it is safe to enable multiple times, including by TOP_LEVEL_INCLUDE. diff --git a/infra/cmake/BuildTelemetry.cmake b/infra/cmake/BuildTelemetry.cmake new file mode 100755 index 00000000..cc94f409 --- /dev/null +++ b/infra/cmake/BuildTelemetry.cmake @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +include_guard(GLOBAL) + +include(${CMAKE_CURRENT_LIST_DIR}/BuildTelemetryConfig.cmake) +configure_build_telemetry() diff --git a/infra/cmake/BuildTelemetryConfig.cmake b/infra/cmake/BuildTelemetryConfig.cmake new file mode 100755 index 00000000..2160c349 --- /dev/null +++ b/infra/cmake/BuildTelemetryConfig.cmake @@ -0,0 +1,59 @@ +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +include_guard(GLOBAL) + +set(BUILD_TELEMETRY_DIR ${CMAKE_CURRENT_LIST_DIR}) + +function(configure_build_telemetry) + if(NOT BUILD_TELEMETRY_CONFIGURATION) + # Check if the CMake version is at least 4.3 + if(CMAKE_VERSION VERSION_LESS "4.3") + message( + STATUS + "CMake version is less than 4.3, configuring cmake_instrumentation is unavailable." + ) + return() + else() + message(STATUS "Configuring Build Telemetry") + endif() + + # Find bash and jq for the telemetry callback script. + # On Windows, Git for Windows provides bash if available. + find_program(BEMAN_BASH bash) + find_program(BEMAN_JQ jq) + if(NOT BEMAN_BASH OR NOT BEMAN_JQ) + message( + STATUS + "bash or jq not found, build telemetry disabled on this platform." + ) + return() + endif() + + # Telemetry query + cmake_instrumentation( + API_VERSION 1 + DATA_VERSION 1 + OPTIONS staticSystemInformation dynamicSystemInformation trace + HOOKS + postGenerate + preBuild + postBuild + preCMakeBuild + postCMakeBuild + postCMakeInstall + postCTest + CALLBACK ${BEMAN_BASH} + ${BUILD_TELEMETRY_DIR}/telemetry.sh + ) + message( + DEBUG + "using callback script ${BUILD_TELEMETRY_DIR}/telemetry.sh via ${BEMAN_BASH}" + ) + + # Mark configuration as done in cache + set(BUILD_TELEMETRY_CONFIGURATION + TRUE + CACHE INTERNAL + "Flag to ensure Build Telemetry configured only once" + ) + endif() +endfunction(configure_build_telemetry) diff --git a/infra/cmake/Config.cmake.in b/infra/cmake/Config.cmake.in index 81adf800..df903cfc 100644 --- a/infra/cmake/Config.cmake.in +++ b/infra/cmake/Config.cmake.in @@ -1,12 +1,12 @@ -# cmake/Config.cmake.in -*-makefile-*- # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +# cmake/Config.cmake.in -*-makefile-*- include(CMakeFindDependencyMacro) -@BEMAN_FIND_DEPENDENCIES@ +@BEMAN_INSTALL_FIND_DEPENDENCIES@ @PACKAGE_INIT@ -include(${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@-targets.cmake) +include(${CMAKE_CURRENT_LIST_DIR}/@BEMAN_INSTALL_BASE_PKG_NAME@-targets.cmake) -check_required_components(@PROJECT_NAME@) +check_required_components(@BEMAN_INSTALL_BASE_PKG_NAME@) diff --git a/infra/cmake/beman-install-library.cmake b/infra/cmake/beman-install-library.cmake index 8a6c5a1a..df2dbe9e 100644 --- a/infra/cmake/beman-install-library.cmake +++ b/infra/cmake/beman-install-library.cmake @@ -56,7 +56,7 @@ include(GNUInstallDirs) # 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 +# needed. If the given targets has a PUBLIC FILE_SET CXX_MODULE, it will also # installed to the given DESTINATION # # Cache variables: @@ -72,7 +72,7 @@ include(GNUInstallDirs) # Caveats # ------- # -# **Only one `FILE_SET CXX_MODULES` is yet supported to install with this +# **Only one `PUBLIC FILE_SET CXX_MODULES` is yet supported to install with this # function!** # # **Only header files contained in a `PUBLIC FILE_SET TYPE HEADERS` will be @@ -86,14 +86,14 @@ function(beman_install_library name) set(multiValueArgs TARGETS DEPENDENCIES) cmake_parse_arguments( - BEMAN + BEMAN_INSTALL "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN} ) - if(NOT BEMAN_TARGETS) + if(NOT BEMAN_INSTALL_TARGETS) message( FATAL_ERROR "beman_install_library(${name}): TARGETS must be specified" @@ -103,7 +103,7 @@ function(beman_install_library name) if(CMAKE_SKIP_INSTALL_RULES) message( WARNING - "beman_install_library(${name}): not installing targets '${BEMAN_TARGETS}' due to CMAKE_SKIP_INSTALL_RULES" + "beman_install_library(${name}): not installing targets '${BEMAN_INSTALL_TARGETS}' due to CMAKE_SKIP_INSTALL_RULES" ) return() endif() @@ -113,16 +113,18 @@ function(beman_install_library name) # ---------------------------- # Defaults # ---------------------------- - if(NOT BEMAN_NAMESPACE) - set(BEMAN_NAMESPACE "beman::") + if(NOT BEMAN_INSTALL_NAMESPACE) + set(BEMAN_INSTALL_NAMESPACE "beman::") endif() - if(NOT BEMAN_EXPORT_NAME) - set(BEMAN_EXPORT_NAME "${name}-targets") + if(NOT BEMAN_INSTALL_EXPORT_NAME) + set(BEMAN_INSTALL_EXPORT_NAME "${name}-targets") endif() - if(NOT BEMAN_DESTINATION) - set(BEMAN_DESTINATION "${_config_install_dir}/modules") + if(NOT BEMAN_INSTALL_DESTINATION) + set(BEMAN_INSTALL_DESTINATION + "${CMAKE_INSTALL_DATADIR}/${name}/modules" + ) endif() string(REPLACE "beman." "" install_component_name "${name}") @@ -134,7 +136,7 @@ function(beman_install_library name) # -------------------------------------------------- # Install each target with all of its file sets # -------------------------------------------------- - foreach(_tgt IN LISTS BEMAN_TARGETS) + foreach(_tgt IN LISTS BEMAN_INSTALL_TARGETS) if(NOT TARGET "${_tgt}") message( WARNING @@ -177,8 +179,7 @@ function(beman_install_library name) ) foreach(_install_header_set IN LISTS _available_header_sets) list( - APPEND - _install_header_set_args + APPEND _install_header_set_args FILE_SET "${_install_header_set}" COMPONENT @@ -189,16 +190,16 @@ function(beman_install_library name) set(_install_header_set_args FILE_SET 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) + # Detect presence of PUBLIC C++ module file sets. Note: exact one is expected! + get_target_property(_module_sets "${_tgt}" INTERFACE_CXX_MODULE_SETS) if(_module_sets) message( VERBOSE - "beman-install-library(${name}): '${_tgt}' has CXX_MODULE_SETS=${_module_sets}" + "beman-install-library(${name}): '${_tgt}' has INTERFACE_CXX_MODULE_SETS=${_module_sets}" ) install( TARGETS "${_tgt}" - EXPORT ${BEMAN_EXPORT_NAME} + EXPORT ${BEMAN_INSTALL_EXPORT_NAME} ARCHIVE COMPONENT "${install_component_name}_Development" LIBRARY COMPONENT "${install_component_name}_Runtime" @@ -206,18 +207,18 @@ function(beman_install_library name) RUNTIME COMPONENT "${install_component_name}_Runtime" ${_install_header_set_args} FILE_SET ${_module_sets} - DESTINATION "${BEMAN_DESTINATION}" + DESTINATION "${BEMAN_INSTALL_DESTINATION}" COMPONENT "${install_component_name}_Development" # NOTE: There's currently no convention for this location! CK CXX_MODULES_BMI DESTINATION - ${_config_install_dir}/bmi-${CMAKE_CXX_COMPILER_ID}_$ + ${CMAKE_INSTALL_DATADIR}/${name}/bmi-${CMAKE_CXX_COMPILER_ID}_$ COMPONENT "${install_component_name}_Development" ) else() install( TARGETS "${_tgt}" - EXPORT ${BEMAN_EXPORT_NAME} + EXPORT ${BEMAN_INSTALL_EXPORT_NAME} ARCHIVE COMPONENT "${install_component_name}_Development" LIBRARY COMPONENT "${install_component_name}_Runtime" @@ -233,8 +234,8 @@ function(beman_install_library name) # -------------------------------------------------- # gersemi: off install( - EXPORT ${BEMAN_EXPORT_NAME} - NAMESPACE ${BEMAN_NAMESPACE} + EXPORT ${BEMAN_INSTALL_EXPORT_NAME} + NAMESPACE ${BEMAN_INSTALL_NAMESPACE} CXX_MODULES_DIRECTORY cxx-modules DESTINATION ${_config_install_dir} COMPONENT "${install_component_name}_Development" @@ -279,19 +280,20 @@ function(beman_install_library name) # expand dependencies # ---------------------------------------- set(_beman_find_deps "") - foreach(dep IN LISTS BEMAN_DEPENDENCIES) + foreach(dep IN LISTS BEMAN_INSTALL_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}") + set(BEMAN_INSTALL_FIND_DEPENDENCIES "${_beman_find_deps}") # ---------------------------------------- # Generate + install config files # ---------------------------------------- if(_install_config) + set(BEMAN_INSTALL_BASE_PKG_NAME ${name}) configure_package_config_file( "${CMAKE_CURRENT_FUNCTION_LIST_DIR}/Config.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/${name}-config.cmake" diff --git a/infra/cmake/enable-experimental-import-std.cmake b/infra/cmake/enable-experimental-import-std.cmake new file mode 100644 index 00000000..e41a5f7c --- /dev/null +++ b/infra/cmake/enable-experimental-import-std.cmake @@ -0,0 +1,24 @@ +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +if(CMAKE_VERSION VERSION_GREATER_EQUAL "4.3.0") + set(CMAKE_EXPERIMENTAL_CXX_IMPORT_STD + "451f2fe2-a8a2-47c3-bc32-94786d8fc91b" + ) +elseif(CMAKE_VERSION VERSION_GREATER_EQUAL "3.30.0") + if(CMAKE_VERSION VERSION_LESS "3.31.8") + set(CMAKE_EXPERIMENTAL_CXX_IMPORT_STD + "0e5b6991-d74f-4b3d-a41c-cf096e0b2508" + ) + elseif(CMAKE_VERSION VERSION_LESS "4.0.0") + set(CMAKE_EXPERIMENTAL_CXX_IMPORT_STD + "d0edc3af-4c50-42ea-a356-e2862fe7a444" + ) + elseif(CMAKE_VERSION VERSION_LESS "4.0.3") + set(CMAKE_EXPERIMENTAL_CXX_IMPORT_STD + "a9e1cf81-9932-4810-974b-6eccaf14e457" + ) + elseif(CMAKE_VERSION VERSION_LESS "4.3.0") + set(CMAKE_EXPERIMENTAL_CXX_IMPORT_STD + "d0edc3af-4c50-42ea-a356-e2862fe7a444" + ) + endif() +endif() diff --git a/infra/cmake/llvm-libc++-toolchain.cmake b/infra/cmake/llvm-libc++-toolchain.cmake index 76264c69..eabf3631 100644 --- a/infra/cmake/llvm-libc++-toolchain.cmake +++ b/infra/cmake/llvm-libc++-toolchain.cmake @@ -1,4 +1,4 @@ -# SPDX-License-Identifier: BSL-1.0 +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception # This toolchain file is not meant to be used directly, # but to be invoked by CMake preset and GitHub CI. diff --git a/infra/cmake/telemetry.sh b/infra/cmake/telemetry.sh new file mode 100755 index 00000000..cb5fd881 --- /dev/null +++ b/infra/cmake/telemetry.sh @@ -0,0 +1,119 @@ +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +#!/usr/bin/env bash + +set -o nounset +set -o errexit +trap 'echo "Aborting due to errexit on line $LINENO. Exit code: $?" >&2' ERR +set -o errtrace +set -o pipefail +IFS=$'\n\t' + +############################################################################### +# Environment +############################################################################### + +# $_ME +# +# This program's basename. +_ME="$(basename "${0}")" + +############################################################################### +# Help +############################################################################### + +# _print_help() +# +# Usage: +# _print_help +# +# Print the program help information. +_print_help() { + cat <] + ${_ME} -h | --help + +Options: + -h --help Show this screen. + +Environment: + Setting DEBUG_TELEMETRY in the environment will enable DEBUG logging +HEREDOC +} + +############################################################################### +# Program Functions +############################################################################### +_debug_print() { + if [[ -n "${DEBUG_TELEMETRY:-}" ]]; then + printf "[DEBUG] $(date +'%H:%M:%S'): %s \n" "$1" >&2 + fi +} + +_check_file_exists() { + local file="$1" + if [[ ! -f "${file}" ]]; then + echo "Error: File not found: ${file}" >&2 + exit 1 # Exit the entire script with a non-zero status + fi +} + +_process_index() { + indexFile=${1:-} + _check_file_exists "${indexFile}" + _debug_print "$(cat "${indexFile}")" + + local buildDir + buildDir=$(jq -r '.buildDir' "${1:-}") + _debug_print "$(printf "buildDir is |%q|" "${buildDir}")" + + local dataDir + dataDir=$(jq -r '.dataDir' "${1:-}") + _debug_print "$(printf "dataDir is |%q|" "${dataDir}")" + + local hook + hook=$(jq -r '.hook' "${1:-}") + _debug_print "$(printf "hook is |%q|" "${hook}")" + + local trace + trace=$(jq -r '.trace' "${1:-}") + _debug_print "$(printf "trace is |%q|" "${trace}")" + + local outputDir + outputDir="${buildDir}/.trace" + _debug_print "$(printf "Copy trace to |%q|" "${outputDir}")" + mkdir -p "${outputDir}" + + local traceDestFile + traceDestFile="${outputDir}/${hook}-$(basename "${trace}")" + _debug_print "$(printf "traceDestFile: |%q|" "${traceDestFile}")" + cp "${dataDir}/${trace}" "${outputDir}/${hook}-$(basename "${trace}")" +} + +############################################################################### +# Main +############################################################################### + +# _main() +# +# Usage: +# _main [] [] +# +# Description: +# Entry point for the program, handling basic option parsing and dispatching. +_main() { + # Avoid complex option parsing when only one program option is expected. + if [[ "${1:-}" =~ ^-h|--help$ ]] + then + _print_help + else + _process_index "$@" + fi +} + +# Call `_main` after everything has been defined. +_main "$@" diff --git a/infra/cmake/use-fetch-content.cmake b/infra/cmake/use-fetch-content.cmake index 4ed48397..3c7136de 100644 --- a/infra/cmake/use-fetch-content.cmake +++ b/infra/cmake/use-fetch-content.cmake @@ -1,185 +1,203 @@ +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception cmake_minimum_required(VERSION 3.24) include(FetchContent) -if(NOT BEMAN_EXEMPLAR_LOCKFILE) - set(BEMAN_EXEMPLAR_LOCKFILE +if(NOT BEMAN_LOCKFILE) + set(BEMAN_LOCKFILE "lockfile.json" CACHE FILEPATH - "Path to the dependency lockfile for the Beman Exemplar." + "Path to the dependency lockfile for the Beman project." ) endif() -set(BemanExemplar_projectDir "${CMAKE_CURRENT_LIST_DIR}/../..") -message(TRACE "BemanExemplar_projectDir=\"${BemanExemplar_projectDir}\"") +set(Beman_projectDir "${CMAKE_CURRENT_LIST_DIR}/../..") +message(TRACE "Beman_projectDir=\"${Beman_projectDir}\"") -message(TRACE "BEMAN_EXEMPLAR_LOCKFILE=\"${BEMAN_EXEMPLAR_LOCKFILE}\"") +message(TRACE "BEMAN_LOCKFILE=\"${BEMAN_LOCKFILE}\"") file( - REAL_PATH - "${BEMAN_EXEMPLAR_LOCKFILE}" - BemanExemplar_lockfile - BASE_DIRECTORY "${BemanExemplar_projectDir}" + REAL_PATH "${BEMAN_LOCKFILE}" + Beman_lockfile + BASE_DIRECTORY "${Beman_projectDir}" EXPAND_TILDE ) -message(DEBUG "Using lockfile: \"${BemanExemplar_lockfile}\"") +message(DEBUG "Using lockfile: \"${Beman_lockfile}\"") # Force CMake to reconfigure the project if the lockfile changes set_property( - DIRECTORY "${BemanExemplar_projectDir}" + DIRECTORY "${Beman_projectDir}" APPEND - PROPERTY CMAKE_CONFIGURE_DEPENDS "${BemanExemplar_lockfile}" + PROPERTY CMAKE_CONFIGURE_DEPENDS "${Beman_lockfile}" ) # For more on the protocol for this function, see: # https://cmake.org/cmake/help/latest/command/cmake_language.html#provider-commands -function(BemanExemplar_provideDependency method package_name) +function(Beman_provideDependency method package_name) # Read the lockfile - file(READ "${BemanExemplar_lockfile}" BemanExemplar_rootObj) + file(READ "${Beman_lockfile}" Beman_rootObj) - # Get the "dependencies" field and store it in BemanExemplar_dependenciesObj + # Get the "dependencies" field and store it in Beman_dependenciesObj string( - JSON - BemanExemplar_dependenciesObj - ERROR_VARIABLE BemanExemplar_error - GET "${BemanExemplar_rootObj}" + JSON Beman_dependenciesObj + ERROR_VARIABLE Beman_error + GET "${Beman_rootObj}" "dependencies" ) - if(BemanExemplar_error) - message(FATAL_ERROR "${BemanExemplar_lockfile}: ${BemanExemplar_error}") + if(Beman_error) + message(FATAL_ERROR "${Beman_lockfile}: ${Beman_error}") endif() - # Get the length of the libraries array and store it in BemanExemplar_dependenciesObj + # Get the length of the libraries array and store it in Beman_dependenciesObj string( - JSON - BemanExemplar_numDependencies - ERROR_VARIABLE BemanExemplar_error - LENGTH "${BemanExemplar_dependenciesObj}" + JSON Beman_numDependencies + ERROR_VARIABLE Beman_error + LENGTH "${Beman_dependenciesObj}" ) - if(BemanExemplar_error) - message(FATAL_ERROR "${BemanExemplar_lockfile}: ${BemanExemplar_error}") + if(Beman_error) + message(FATAL_ERROR "${Beman_lockfile}: ${Beman_error}") endif() - if(BemanExemplar_numDependencies EQUAL 0) + if(Beman_numDependencies EQUAL 0) return() endif() # Loop over each dependency object - math(EXPR BemanExemplar_maxIndex "${BemanExemplar_numDependencies} - 1") - foreach(BemanExemplar_index RANGE "${BemanExemplar_maxIndex}") - set(BemanExemplar_errorPrefix - "${BemanExemplar_lockfile}, dependency ${BemanExemplar_index}" - ) + math(EXPR Beman_maxIndex "${Beman_numDependencies} - 1") + foreach(Beman_index RANGE "${Beman_maxIndex}") + set(Beman_errorPrefix "${Beman_lockfile}, dependency ${Beman_index}") - # Get the dependency object at BemanExemplar_index - # and store it in BemanExemplar_depObj + # Get the dependency object at Beman_index + # and store it in Beman_depObj string( - JSON - BemanExemplar_depObj - ERROR_VARIABLE BemanExemplar_error - GET "${BemanExemplar_dependenciesObj}" - "${BemanExemplar_index}" + JSON Beman_depObj + ERROR_VARIABLE Beman_error + GET "${Beman_dependenciesObj}" + "${Beman_index}" ) - if(BemanExemplar_error) - message( - FATAL_ERROR - "${BemanExemplar_errorPrefix}: ${BemanExemplar_error}" - ) + if(Beman_error) + message(FATAL_ERROR "${Beman_errorPrefix}: ${Beman_error}") endif() - # Get the "name" field and store it in BemanExemplar_name + # Get the "name" field and store it in Beman_name string( - JSON - BemanExemplar_name - ERROR_VARIABLE BemanExemplar_error - GET "${BemanExemplar_depObj}" + JSON Beman_name + ERROR_VARIABLE Beman_error + GET "${Beman_depObj}" "name" ) - if(BemanExemplar_error) - message( - FATAL_ERROR - "${BemanExemplar_errorPrefix}: ${BemanExemplar_error}" - ) + if(Beman_error) + message(FATAL_ERROR "${Beman_errorPrefix}: ${Beman_error}") endif() - # Get the "package_name" field and store it in BemanExemplar_pkgName + # Get the "package_name" field and store it in Beman_pkgName string( - JSON - BemanExemplar_pkgName - ERROR_VARIABLE BemanExemplar_error - GET "${BemanExemplar_depObj}" + JSON Beman_pkgName + ERROR_VARIABLE Beman_error + GET "${Beman_depObj}" "package_name" ) - if(BemanExemplar_error) - message( - FATAL_ERROR - "${BemanExemplar_errorPrefix}: ${BemanExemplar_error}" - ) + if(Beman_error) + message(FATAL_ERROR "${Beman_errorPrefix}: ${Beman_error}") endif() - # Get the "git_repository" field and store it in BemanExemplar_repo + # Get the "git_repository" field and store it in Beman_repo string( - JSON - BemanExemplar_repo - ERROR_VARIABLE BemanExemplar_error - GET "${BemanExemplar_depObj}" + JSON Beman_repo + ERROR_VARIABLE Beman_error + GET "${Beman_depObj}" "git_repository" ) - if(BemanExemplar_error) - message( - FATAL_ERROR - "${BemanExemplar_errorPrefix}: ${BemanExemplar_error}" - ) + if(Beman_error) + message(FATAL_ERROR "${Beman_errorPrefix}: ${Beman_error}") endif() - # Get the "git_tag" field and store it in BemanExemplar_tag + # Get the "git_tag" field and store it in Beman_tag string( - JSON - BemanExemplar_tag - ERROR_VARIABLE BemanExemplar_error - GET "${BemanExemplar_depObj}" + JSON Beman_tag + ERROR_VARIABLE Beman_error + GET "${Beman_depObj}" "git_tag" ) - if(BemanExemplar_error) - message( - FATAL_ERROR - "${BemanExemplar_errorPrefix}: ${BemanExemplar_error}" - ) + if(Beman_error) + message(FATAL_ERROR "${Beman_errorPrefix}: ${Beman_error}") endif() if(method STREQUAL "FIND_PACKAGE") - if(package_name STREQUAL BemanExemplar_pkgName) + if(package_name STREQUAL Beman_pkgName) string( - APPEND - BemanExemplar_debug - "Redirecting find_package calls for ${BemanExemplar_pkgName} " + APPEND Beman_debug + "Redirecting find_package calls for ${Beman_pkgName} " "to FetchContent logic.\n" ) string( - APPEND - BemanExemplar_debug - "Fetching ${BemanExemplar_repo} at " - "${BemanExemplar_tag} according to ${BemanExemplar_lockfile}." + APPEND Beman_debug + "Fetching ${Beman_repo} at " + "${Beman_tag} according to ${Beman_lockfile}." ) - message(DEBUG "${BemanExemplar_debug}") + message(DEBUG "${Beman_debug}") FetchContent_Declare( - "${BemanExemplar_name}" - GIT_REPOSITORY "${BemanExemplar_repo}" - GIT_TAG "${BemanExemplar_tag}" + "${Beman_name}" + GIT_REPOSITORY "${Beman_repo}" + GIT_TAG "${Beman_tag}" EXCLUDE_FROM_ALL ) - set(INSTALL_GTEST OFF) # Disable GoogleTest installation - FetchContent_MakeAvailable("${BemanExemplar_name}") + + # Apply per-dependency cmake_args from the lockfile + string( + JSON Beman_cmakeArgs + ERROR_VARIABLE Beman_cmakeArgsError + GET "${Beman_depObj}" + "cmake_args" + ) + if(NOT Beman_cmakeArgsError) + string(JSON Beman_numCmakeArgs LENGTH "${Beman_cmakeArgs}") + if(Beman_numCmakeArgs GREATER 0) + math(EXPR Beman_maxArgIndex "${Beman_numCmakeArgs} - 1") + foreach(Beman_argIndex RANGE "${Beman_maxArgIndex}") + string( + JSON Beman_argKey + MEMBER "${Beman_cmakeArgs}" + "${Beman_argIndex}" + ) + string( + JSON Beman_argValue + GET "${Beman_cmakeArgs}" + "${Beman_argKey}" + ) + message( + DEBUG + "Setting ${Beman_argKey}=${Beman_argValue} for ${Beman_name}" + ) + set("${Beman_argKey}" "${Beman_argValue}") + endforeach() + endif() + endif() + + FetchContent_MakeAvailable("${Beman_name}") + + # Catch2's CTest integration module isn't on CMAKE_MODULE_PATH + # when brought in via FetchContent. Add it so that + # `include(Catch)` works. + if(Beman_pkgName STREQUAL "Catch2") + list( + APPEND CMAKE_MODULE_PATH + "${${Beman_name}_SOURCE_DIR}/extras" + ) + set(CMAKE_MODULE_PATH "${CMAKE_MODULE_PATH}" PARENT_SCOPE) + endif() # Important! _FOUND tells CMake that `find_package` is # not needed for this package anymore - set("${BemanExemplar_pkgName}_FOUND" TRUE PARENT_SCOPE) + set("${Beman_pkgName}_FOUND" TRUE PARENT_SCOPE) endif() endif() endforeach() endfunction() +set(BEMAN_USE_FETCH_CONTENT_ENABLED ON) + cmake_language( - SET_DEPENDENCY_PROVIDER BemanExemplar_provideDependency + SET_DEPENDENCY_PROVIDER Beman_provideDependency SUPPORTED_METHODS FIND_PACKAGE ) diff --git a/src/beman/execution/basic_sender.cppm b/src/beman/execution/basic_sender.cppm index eeaf4a7e..9533df28 100644 --- a/src/beman/execution/basic_sender.cppm +++ b/src/beman/execution/basic_sender.cppm @@ -14,11 +14,11 @@ export using beman::execution::detail::basic_sender; #ifdef _MSC_VER namespace std { -export template +template struct tuple_size<::beman::execution::detail::basic_sender> : ::std::integral_constant {}; -export template <::std::size_t I, typename... T> +template <::std::size_t I, typename... T> struct tuple_element> { using type = ::std::decay_t>().template get())>; diff --git a/src/beman/execution/product_type.cppm b/src/beman/execution/product_type.cppm index 0c64ad22..2c04d234 100644 --- a/src/beman/execution/product_type.cppm +++ b/src/beman/execution/product_type.cppm @@ -16,9 +16,9 @@ export using beman::execution::detail::product_type; #ifdef _MSC_VER namespace std { -export template +template struct tuple_size<::beman::execution::detail::product_type>; -export template <::std::size_t I, typename... T> +template <::std::size_t I, typename... T> struct tuple_element>; } // namespace std #endif