From 84fcc36ea942475c59f787ddcf441692c4b0fde9 Mon Sep 17 00:00:00 2001 From: Guillaume Lagrange Date: Wed, 25 Mar 2026 16:29:07 +0100 Subject: [PATCH 1/4] fix: fix clang 19 compilation error --- core/include/measurement.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/include/measurement.hpp b/core/include/measurement.hpp index 1644415..6daf7eb 100644 --- a/core/include/measurement.hpp +++ b/core/include/measurement.hpp @@ -54,9 +54,9 @@ ALWAYS_INLINE uint64_t measurement_current_timestamp() { return instrument_hooks_current_timestamp(); } -ALWAYS_INLINE int8_t measurement_add_marker(uint8_t marker_type, +ALWAYS_INLINE uint8_t measurement_add_marker(uint8_t marker_type, uint64_t timestamp) { - auto pid = getpid(); + auto pid = static_cast(getpid()); return instrument_hooks_add_marker(g_hooks, pid, marker_type, timestamp); } From a9eac4693e6bab76e86c5b89e3e01561f7f0e943 Mon Sep 17 00:00:00 2001 From: Guillaume Lagrange Date: Wed, 25 Mar 2026 16:31:00 +0100 Subject: [PATCH 2/4] feat: add toolchain environment collection to CMake build --- core/CMakeLists.txt | 21 ++++++++++++++++++++- core/include/measurement.hpp | 21 ++++++++++++++++++++- core/instrument-hooks | 2 +- 3 files changed, 41 insertions(+), 3 deletions(-) diff --git a/core/CMakeLists.txt b/core/CMakeLists.txt index 8a7eca0..8efe9d4 100644 --- a/core/CMakeLists.txt +++ b/core/CMakeLists.txt @@ -15,7 +15,7 @@ include(FetchContent) FetchContent_Declare( instrument_hooks_repo GIT_REPOSITORY https://github.com/CodSpeedHQ/instrument-hooks - GIT_TAG 89fb72a076ec71c9eca6eee9bca98bada4b4dfb4 + GIT_TAG e86719c70c9c0b1646db182a7c748230e243dace ) FetchContent_MakeAvailable(instrument_hooks_repo) FetchContent_GetProperties(instrument_hooks_repo) @@ -96,6 +96,25 @@ target_link_libraries(codspeed PRIVATE instrument_hooks) # Version add_compile_definitions(CODSPEED_VERSION="${CODSPEED_VERSION}") +# Collect compiler toolchain information for environment reporting +execute_process( + COMMAND ${CMAKE_CXX_COMPILER} --version + OUTPUT_VARIABLE CODSPEED_CXX_COMPILER_FULL_VERSION + OUTPUT_STRIP_TRAILING_WHITESPACE + ERROR_QUIET +) +# Extract first line only +if(CODSPEED_CXX_COMPILER_FULL_VERSION) + string(REGEX REPLACE "\n.*" "" CODSPEED_CXX_COMPILER_FULL_VERSION "${CODSPEED_CXX_COMPILER_FULL_VERSION}") +endif() + +target_compile_definitions(codspeed PRIVATE + CODSPEED_CXX_COMPILER_ID="${CMAKE_CXX_COMPILER_ID}" + CODSPEED_CXX_COMPILER_VERSION="${CMAKE_CXX_COMPILER_VERSION}" + CODSPEED_CXX_COMPILER_FULL_VERSION="${CODSPEED_CXX_COMPILER_FULL_VERSION}" + CODSPEED_BUILD_TYPE="${CMAKE_BUILD_TYPE}" +) + # Specify the include directories for users of the library target_include_directories( codspeed diff --git a/core/include/measurement.hpp b/core/include/measurement.hpp index 6daf7eb..20f211a 100644 --- a/core/include/measurement.hpp +++ b/core/include/measurement.hpp @@ -35,6 +35,25 @@ inline bool measurement_is_instrumented() { inline void measurement_set_metadata() { std::string version = get_version(); instrument_hooks_set_integration(g_hooks, "codspeed-cpp", version.c_str()); + + // Report C++ toolchain information +#ifdef CODSPEED_CXX_COMPILER_ID + instrument_hooks_set_environment(g_hooks, "C++ Compiler", "compiler_id", + CODSPEED_CXX_COMPILER_ID); +#endif +#ifdef CODSPEED_CXX_COMPILER_VERSION + instrument_hooks_set_environment(g_hooks, "C++ Compiler", "version", + CODSPEED_CXX_COMPILER_VERSION); +#endif +#ifdef CODSPEED_CXX_COMPILER_FULL_VERSION + instrument_hooks_set_environment(g_hooks, "C++ Compiler", "build", + CODSPEED_CXX_COMPILER_FULL_VERSION); +#endif +#ifdef CODSPEED_BUILD_TYPE + instrument_hooks_set_environment(g_hooks, "C++ Compiler", "build_type", + CODSPEED_BUILD_TYPE); +#endif + instrument_hooks_write_environment(g_hooks, static_cast(getpid())); } ALWAYS_INLINE void measurement_start() { @@ -55,7 +74,7 @@ ALWAYS_INLINE uint64_t measurement_current_timestamp() { } ALWAYS_INLINE uint8_t measurement_add_marker(uint8_t marker_type, - uint64_t timestamp) { + uint64_t timestamp) { auto pid = static_cast(getpid()); return instrument_hooks_add_marker(g_hooks, pid, marker_type, timestamp); } diff --git a/core/instrument-hooks b/core/instrument-hooks index 89fb72a..e86719c 160000 --- a/core/instrument-hooks +++ b/core/instrument-hooks @@ -1 +1 @@ -Subproject commit 89fb72a076ec71c9eca6eee9bca98bada4b4dfb4 +Subproject commit e86719c70c9c0b1646db182a7c748230e243dace From 1c7f3ecab184ed66abaec4b22ab82e0e7ce0167c Mon Sep 17 00:00:00 2001 From: Guillaume Lagrange Date: Wed, 25 Mar 2026 17:14:53 +0100 Subject: [PATCH 3/4] feat: add toolchain environment collection to bazel --- core/BUILD | 54 ++++++++++++++++++++++++++++++++++++++++++- core/src/codspeed.cpp | 4 ++++ 2 files changed, 57 insertions(+), 1 deletion(-) diff --git a/core/BUILD b/core/BUILD index 3d366b3..70cc48d 100644 --- a/core/BUILD +++ b/core/BUILD @@ -68,6 +68,58 @@ cc_library( ) +# Generate a header with C++ toolchain information +genrule( + name = "toolchain_info_gen", + outs = ["toolchain_info.h"], + cmd = """ +set -e +COMPILER="$(CC)" +FULL_VERSION=$$($$COMPILER --version 2>/dev/null | head -n1) || FULL_VERSION="unknown" + +COMPILER_ID="unknown" +COMPILER_VERSION="unknown" + +if echo "$$FULL_VERSION" | grep -qi "clang"; then + COMPILER_ID="Clang" + COMPILER_VERSION=$$(echo "$$FULL_VERSION" | grep -oP '\\d+\\.\\d+\\.\\d+' | head -n1) || COMPILER_VERSION="unknown" +elif echo "$$FULL_VERSION" | grep -qi "gcc\\|g++\\|GNU"; then + COMPILER_ID="GNU" + COMPILER_VERSION=$$(echo "$$FULL_VERSION" | grep -oP '\\d+\\.\\d+\\.\\d+' | head -n1) || COMPILER_VERSION="unknown" +elif echo "$$FULL_VERSION" | grep -qi "MSVC\\|Microsoft"; then + COMPILER_ID="MSVC" + COMPILER_VERSION=$$(echo "$$FULL_VERSION" | grep -oP '\\d+\\.\\d+\\.\\d+' | head -n1) || COMPILER_VERSION="unknown" +fi + +case "$(COMPILATION_MODE)" in + opt) BUILD_TYPE="Release" ;; + dbg) BUILD_TYPE="Debug" ;; + fastbuild) BUILD_TYPE="FastBuild" ;; + *) BUILD_TYPE="$(COMPILATION_MODE)" ;; +esac + +cat > $@ << HEADER_EOF +// Auto-generated by Bazel - do not edit +#ifndef CODSPEED_TOOLCHAIN_INFO_H +#define CODSPEED_TOOLCHAIN_INFO_H + +#define CODSPEED_CXX_COMPILER_ID "$$COMPILER_ID" +#define CODSPEED_CXX_COMPILER_VERSION "$$COMPILER_VERSION" +#define CODSPEED_CXX_COMPILER_FULL_VERSION "$$FULL_VERSION" +#define CODSPEED_BUILD_TYPE "$$BUILD_TYPE" + +#endif // CODSPEED_TOOLCHAIN_INFO_H +HEADER_EOF +""", + toolchains = ["@bazel_tools//tools/cpp:current_cc_toolchain"], +) + +cc_library( + name = "toolchain_info", + hdrs = [":toolchain_info_gen"], + includes = ["."], +) + # Define the codspeed library cc_library( name = "codspeed", @@ -87,7 +139,7 @@ cc_library( ":walltime_mode": ["CODSPEED_ENABLED", "CODSPEED_WALLTIME", "CODSPEED_MODE_DISPLAY=\\\"walltime\\\""], "//conditions:default": [], }), - deps = [":instrument_hooks"], + deps = [":instrument_hooks", ":toolchain_info"], visibility = ["//visibility:public"], ) diff --git a/core/src/codspeed.cpp b/core/src/codspeed.cpp index d82d074..0791b6f 100644 --- a/core/src/codspeed.cpp +++ b/core/src/codspeed.cpp @@ -4,6 +4,10 @@ #include #include +#if __has_include("toolchain_info.h") +#include "toolchain_info.h" +#endif + #include "measurement.hpp" namespace codspeed { From af894172c0c9245943e927f49e7f1cdb05b1b01b Mon Sep 17 00:00:00 2001 From: Guillaume Lagrange Date: Thu, 26 Mar 2026 17:41:33 +0100 Subject: [PATCH 4/4] chore: use the same logic for toolchain detection --- .github/workflows/ci.yml | 9 ++- core/BUILD | 33 +-------- core/CMakeLists.txt | 23 +++--- core/scripts/detect_toolchain.sh | 40 ++++++++++ core/scripts/test_detect_toolchain.sh | 101 ++++++++++++++++++++++++++ 5 files changed, 161 insertions(+), 45 deletions(-) create mode 100755 core/scripts/detect_toolchain.sh create mode 100755 core/scripts/test_detect_toolchain.sh diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b20dfdd..ce9eac9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -19,9 +19,16 @@ jobs: with: extra_args: --all-files + toolchain-detection-tests: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Run toolchain detection tests + run: bash core/scripts/test_detect_toolchain.sh + tests: runs-on: ubuntu-latest - steps: + steps: - name: Checkout code uses: actions/checkout@v3 with: diff --git a/core/BUILD b/core/BUILD index 70cc48d..0e1a575 100644 --- a/core/BUILD +++ b/core/BUILD @@ -71,45 +71,16 @@ cc_library( # Generate a header with C++ toolchain information genrule( name = "toolchain_info_gen", + srcs = ["scripts/detect_toolchain.sh"], outs = ["toolchain_info.h"], cmd = """ -set -e -COMPILER="$(CC)" -FULL_VERSION=$$($$COMPILER --version 2>/dev/null | head -n1) || FULL_VERSION="unknown" - -COMPILER_ID="unknown" -COMPILER_VERSION="unknown" - -if echo "$$FULL_VERSION" | grep -qi "clang"; then - COMPILER_ID="Clang" - COMPILER_VERSION=$$(echo "$$FULL_VERSION" | grep -oP '\\d+\\.\\d+\\.\\d+' | head -n1) || COMPILER_VERSION="unknown" -elif echo "$$FULL_VERSION" | grep -qi "gcc\\|g++\\|GNU"; then - COMPILER_ID="GNU" - COMPILER_VERSION=$$(echo "$$FULL_VERSION" | grep -oP '\\d+\\.\\d+\\.\\d+' | head -n1) || COMPILER_VERSION="unknown" -elif echo "$$FULL_VERSION" | grep -qi "MSVC\\|Microsoft"; then - COMPILER_ID="MSVC" - COMPILER_VERSION=$$(echo "$$FULL_VERSION" | grep -oP '\\d+\\.\\d+\\.\\d+' | head -n1) || COMPILER_VERSION="unknown" -fi - case "$(COMPILATION_MODE)" in opt) BUILD_TYPE="Release" ;; dbg) BUILD_TYPE="Debug" ;; fastbuild) BUILD_TYPE="FastBuild" ;; *) BUILD_TYPE="$(COMPILATION_MODE)" ;; esac - -cat > $@ << HEADER_EOF -// Auto-generated by Bazel - do not edit -#ifndef CODSPEED_TOOLCHAIN_INFO_H -#define CODSPEED_TOOLCHAIN_INFO_H - -#define CODSPEED_CXX_COMPILER_ID "$$COMPILER_ID" -#define CODSPEED_CXX_COMPILER_VERSION "$$COMPILER_VERSION" -#define CODSPEED_CXX_COMPILER_FULL_VERSION "$$FULL_VERSION" -#define CODSPEED_BUILD_TYPE "$$BUILD_TYPE" - -#endif // CODSPEED_TOOLCHAIN_INFO_H -HEADER_EOF +bash $(location scripts/detect_toolchain.sh) "$(CC)" "$$BUILD_TYPE" > $@ """, toolchains = ["@bazel_tools//tools/cpp:current_cc_toolchain"], ) diff --git a/core/CMakeLists.txt b/core/CMakeLists.txt index 8efe9d4..1ef46df 100644 --- a/core/CMakeLists.txt +++ b/core/CMakeLists.txt @@ -97,23 +97,20 @@ target_link_libraries(codspeed PRIVATE instrument_hooks) add_compile_definitions(CODSPEED_VERSION="${CODSPEED_VERSION}") # Collect compiler toolchain information for environment reporting +# Use the shared detect_toolchain.sh script (same as Bazel) for consistent output execute_process( - COMMAND ${CMAKE_CXX_COMPILER} --version - OUTPUT_VARIABLE CODSPEED_CXX_COMPILER_FULL_VERSION + COMMAND bash "${CMAKE_CURRENT_SOURCE_DIR}/scripts/detect_toolchain.sh" + "${CMAKE_CXX_COMPILER}" "${CMAKE_BUILD_TYPE}" + OUTPUT_VARIABLE CODSPEED_TOOLCHAIN_HEADER OUTPUT_STRIP_TRAILING_WHITESPACE - ERROR_QUIET + RESULT_VARIABLE DETECT_TOOLCHAIN_RESULT ) -# Extract first line only -if(CODSPEED_CXX_COMPILER_FULL_VERSION) - string(REGEX REPLACE "\n.*" "" CODSPEED_CXX_COMPILER_FULL_VERSION "${CODSPEED_CXX_COMPILER_FULL_VERSION}") +if(DETECT_TOOLCHAIN_RESULT EQUAL 0) + file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/toolchain_info.h" "${CODSPEED_TOOLCHAIN_HEADER}\n") +else() + message(WARNING "detect_toolchain.sh failed, toolchain info will not be available") endif() - -target_compile_definitions(codspeed PRIVATE - CODSPEED_CXX_COMPILER_ID="${CMAKE_CXX_COMPILER_ID}" - CODSPEED_CXX_COMPILER_VERSION="${CMAKE_CXX_COMPILER_VERSION}" - CODSPEED_CXX_COMPILER_FULL_VERSION="${CODSPEED_CXX_COMPILER_FULL_VERSION}" - CODSPEED_BUILD_TYPE="${CMAKE_BUILD_TYPE}" -) +target_include_directories(codspeed PRIVATE "${CMAKE_CURRENT_BINARY_DIR}") # Specify the include directories for users of the library target_include_directories( diff --git a/core/scripts/detect_toolchain.sh b/core/scripts/detect_toolchain.sh new file mode 100755 index 0000000..2d9014b --- /dev/null +++ b/core/scripts/detect_toolchain.sh @@ -0,0 +1,40 @@ +#!/usr/bin/env bash +# Detect C++ compiler toolchain information from ` --version` output. +# Used by Bazel genrule to generate toolchain_info.h. +# +# Usage: detect_toolchain.sh +# Output: Writes a C header to stdout with CODSPEED_CXX_* defines. + +set -e + +COMPILER="${1:?Usage: detect_toolchain.sh }" +BUILD_TYPE="${2:?Usage: detect_toolchain.sh }" + +FULL_VERSION=$("$COMPILER" --version 2>/dev/null | head -n1) || FULL_VERSION="unknown" + +COMPILER_ID="unknown" +COMPILER_VERSION="unknown" + +if echo "$FULL_VERSION" | grep -qi "clang"; then + COMPILER_ID="Clang" + COMPILER_VERSION=$(echo "$FULL_VERSION" | grep -oP '\d+\.\d+\.\d+' | head -n1) || COMPILER_VERSION="unknown" +elif echo "$FULL_VERSION" | grep -qi "gcc\|g++\|GNU"; then + COMPILER_ID="GNU" + COMPILER_VERSION=$(echo "$FULL_VERSION" | grep -oP '\d+\.\d+\.\d+' | head -n1) || COMPILER_VERSION="unknown" +elif echo "$FULL_VERSION" | grep -qi "MSVC\|Microsoft"; then + COMPILER_ID="MSVC" + COMPILER_VERSION=$(echo "$FULL_VERSION" | grep -oP '\d+\.\d+\.\d+' | head -n1) || COMPILER_VERSION="unknown" +fi + +cat << HEADER_EOF +// Auto-generated - do not edit +#ifndef CODSPEED_TOOLCHAIN_INFO_H +#define CODSPEED_TOOLCHAIN_INFO_H + +#define CODSPEED_CXX_COMPILER_ID "$COMPILER_ID" +#define CODSPEED_CXX_COMPILER_VERSION "$COMPILER_VERSION" +#define CODSPEED_CXX_COMPILER_FULL_VERSION "$FULL_VERSION" +#define CODSPEED_BUILD_TYPE "$BUILD_TYPE" + +#endif // CODSPEED_TOOLCHAIN_INFO_H +HEADER_EOF diff --git a/core/scripts/test_detect_toolchain.sh b/core/scripts/test_detect_toolchain.sh new file mode 100755 index 0000000..44b6c76 --- /dev/null +++ b/core/scripts/test_detect_toolchain.sh @@ -0,0 +1,101 @@ +#!/usr/bin/env bash +# Manual tests for detect_toolchain.sh +# Run: bash core/scripts/test_detect_toolchain.sh +# +# Uses mock compiler scripts to simulate different --version outputs. + +set -e + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +DETECT_SCRIPT="$SCRIPT_DIR/detect_toolchain.sh" +TMPDIR=$(mktemp -d) +trap 'rm -rf "$TMPDIR"' EXIT + +PASS=0 +FAIL=0 + +assert_contains() { + local label="$1" + local expected="$2" + local actual="$3" + if echo "$actual" | grep -qF "$expected"; then + PASS=$((PASS + 1)) + else + FAIL=$((FAIL + 1)) + echo "FAIL: $label" + echo " expected to contain: $expected" + echo " got: $actual" + fi +} + +# Create a mock compiler that outputs a given --version string +make_mock_compiler() { + local name="$1" + local version_output="$2" + local path="$TMPDIR/$name" + cat > "$path" << EOF +#!/usr/bin/env bash +echo "$version_output" +EOF + chmod +x "$path" + echo "$path" +} + +# --- Test cases --- + +echo "Running detect_toolchain.sh tests..." +echo + +# Test: GCC +mock=$(make_mock_compiler "gcc-mock" "gcc (GCC) 14.3.0") +output=$(bash "$DETECT_SCRIPT" "$mock" "Release") +assert_contains "GCC compiler_id" 'CODSPEED_CXX_COMPILER_ID "GNU"' "$output" +assert_contains "GCC version" 'CODSPEED_CXX_COMPILER_VERSION "14.3.0"' "$output" +assert_contains "GCC full_version" 'CODSPEED_CXX_COMPILER_FULL_VERSION "gcc (GCC) 14.3.0"' "$output" +assert_contains "GCC build_type" 'CODSPEED_BUILD_TYPE "Release"' "$output" + +# Test: g++ +mock=$(make_mock_compiler "gpp-mock" "g++ (GCC) 13.2.1 20230801") +output=$(bash "$DETECT_SCRIPT" "$mock" "Debug") +assert_contains "g++ compiler_id" 'CODSPEED_CXX_COMPILER_ID "GNU"' "$output" +assert_contains "g++ version" 'CODSPEED_CXX_COMPILER_VERSION "13.2.1"' "$output" +assert_contains "g++ build_type" 'CODSPEED_BUILD_TYPE "Debug"' "$output" + +# Test: Clang +mock=$(make_mock_compiler "clang-mock" "clang version 19.1.7 (https://github.com/llvm/llvm-project abc123)") +output=$(bash "$DETECT_SCRIPT" "$mock" "Release") +assert_contains "Clang compiler_id" 'CODSPEED_CXX_COMPILER_ID "Clang"' "$output" +assert_contains "Clang version" 'CODSPEED_CXX_COMPILER_VERSION "19.1.7"' "$output" + +# Test: Apple Clang +mock=$(make_mock_compiler "apple-clang-mock" "Apple clang version 15.0.0 (clang-1500.0.40.1)") +output=$(bash "$DETECT_SCRIPT" "$mock" "Release") +assert_contains "Apple Clang compiler_id" 'CODSPEED_CXX_COMPILER_ID "Clang"' "$output" +assert_contains "Apple Clang version" 'CODSPEED_CXX_COMPILER_VERSION "15.0.0"' "$output" + +# Test: Ubuntu GCC +mock=$(make_mock_compiler "ubuntu-gcc-mock" "gcc (Ubuntu 13.3.0-6ubuntu2~24.04) 13.3.0") +output=$(bash "$DETECT_SCRIPT" "$mock" "Release") +assert_contains "Ubuntu GCC compiler_id" 'CODSPEED_CXX_COMPILER_ID "GNU"' "$output" +assert_contains "Ubuntu GCC version" 'CODSPEED_CXX_COMPILER_VERSION "13.3.0"' "$output" + +# Test: Unknown compiler +mock=$(make_mock_compiler "unknown-mock" "some-compiler v2.0") +output=$(bash "$DETECT_SCRIPT" "$mock" "Release") +assert_contains "Unknown compiler_id" 'CODSPEED_CXX_COMPILER_ID "unknown"' "$output" +assert_contains "Unknown version" 'CODSPEED_CXX_COMPILER_VERSION "unknown"' "$output" + +# Test: Header guard present +assert_contains "Header guard" '#ifndef CODSPEED_TOOLCHAIN_INFO_H' "$output" +assert_contains "Header guard endif" '#endif' "$output" + +# --- Summary --- + +echo +TOTAL=$((PASS + FAIL)) +if [ "$FAIL" -eq 0 ]; then + echo "All $TOTAL tests passed." +else + echo "$FAIL/$TOTAL tests FAILED." + exit 1 +fi