Moved to entirely cmake workflow

Signed-off-by: Pratik Mankawde <3397372+pratikmankawde@users.noreply.github.com>
This commit is contained in:
Pratik Mankawde
2025-12-12 15:23:35 +00:00
parent 8d7398419a
commit a4f112d479
6 changed files with 180 additions and 149 deletions

View File

@@ -209,7 +209,6 @@ def generate_strategy_matrix(all: bool, config: Config) -> list:
):
continue
cxx_flags = ""
# Enable code coverage for Debian Bookworm using GCC 14 in Debug and no
# Unity on linux/amd64
if (
@@ -218,8 +217,7 @@ def generate_strategy_matrix(all: bool, config: Config) -> list:
and "-Dunity=OFF" in cmake_args
and architecture["platform"] == "linux/amd64"
):
cmake_args = f"-Dcoverage=ON -Dcoverage_format=xml -DCODE_COVERAGE_VERBOSE=ON -DCMAKE_C_FLAGS=-O0 {cmake_args}"
cxx_flags = f"-O0 {cxx_flags}"
cmake_args = f"-Dcoverage=ON -Dcoverage_format=xml -DCODE_COVERAGE_VERBOSE=ON -DCMAKE_C_FLAGS=-O0 -DCMAKE_CXX_FLAGS=-O0 {cmake_args}"
# Generate a unique name for the configuration, e.g. macos-arm64-debug
# or debian-bookworm-gcc-12-amd64-release-unity.
@@ -247,25 +245,26 @@ def generate_strategy_matrix(all: bool, config: Config) -> list:
"gcc-15",
"clang-20",
}:
configs = addSanitizerConfigs(architecture, os, cmake_args, cxx_flags)
if "asan_ubsan" in configs:
configurations.append(
{
"config_name": config_name + "-asan-ubsan",
"cmake_args": configs["asan_ubsan"],
"cmake_target": cmake_target,
"build_only": build_only,
"build_type": build_type,
"os": os,
"architecture": architecture,
"sanitizers": "Address,UndefinedBehavior",
}
)
if "tsan_ubsan" in configs:
# Add ASAN + UBSAN configuration.
configurations.append(
{
"config_name": config_name + "-asan-ubsan",
"cmake_args": cmake_args,
"cmake_target": cmake_target,
"build_only": build_only,
"build_type": build_type,
"os": os,
"architecture": architecture,
"sanitizers": "Address,UndefinedBehavior",
}
)
# TSAN is deactivated due to seg faults with latest compilers.
activateTSAN = False
if activateTSAN:
configurations.append(
{
"config_name": config_name + "-tsan-ubsan",
"cmake_args": configs["tsan_ubsan"],
"cmake_args": cmake_args,
"cmake_target": cmake_target,
"build_only": build_only,
"build_type": build_type,
@@ -290,102 +289,6 @@ def generate_strategy_matrix(all: bool, config: Config) -> list:
return configurations
def addSanitizerConfigs(
architecture: dict,
os: dict,
cmake_args: str,
cxx_flags: str,
) -> dict:
extra_warning_flags = ""
linker_relocation_flags = ""
linker_flags = ""
cxx_flags += " -fno-omit-frame-pointer"
# Use large code model to avoid relocation errors with large binaries
# Only for x86-64 (amd64) - ARM64 doesn't support -mcmodel=large
if architecture["platform"] == "linux/amd64" and os["compiler_name"] == "gcc":
# Add -mcmodel=large to both compiler AND linker flags
# This is needed because sanitizers create very large binaries and
# large model removes the 2GB limitation that medium model has
cxx_flags += " -mcmodel=large"
linker_relocation_flags += " -mcmodel=large"
# Create default sanitizer flags
sanitizers_flags = "undefined,float-divide-by-zero"
# There are some differences between GCC and Clang support for sanitizers.
# Hence we must use diff. falg combinations for each compiler.
# These combination of flags were tested to work with GCC 15 and Clang 20.
# If the versions are changed, the flags might need to be updated.
if os["compiler_name"] == "gcc":
# Suppress false positive warnings in GCC with stringop-overflow
extra_warning_flags += " -Wno-stringop-overflow"
# Disable mold, gold and lld linkers.
# Use default linker (bfd/ld) which is more lenient with mixed code models
cmake_args += " -Duse_mold=OFF -Duse_gold=OFF -Duse_lld=OFF"
# Add linker flags for Sanitizers
linker_flags += f" -DCMAKE_EXE_LINKER_FLAGS='{linker_relocation_flags} -fsanitize=address,{sanitizers_flags}'"
linker_flags += f" -DCMAKE_SHARED_LINKER_FLAGS='{linker_relocation_flags} -fsanitize=address,{sanitizers_flags}'"
elif os["compiler_name"] == "clang":
# Note: We use $GITHUB_WORKSPACE environment variable which will be expanded by the shell
# before CMake processes it. This ensures the compiler receives an absolute path.
# CMAKE_SOURCE_DIR won't work here because it's inside CMAKE_CXX_FLAGS string.
# GCC doesn't support ignorelist.
cxx_flags += " -fsanitize-ignorelist=${GITHUB_WORKSPACE}/sanitizers/suppressions/sanitizer-ignorelist.txt"
sanitizers_flags = f"{sanitizers_flags},unsigned-integer-overflow"
linker_flags += (
f" -DCMAKE_EXE_LINKER_FLAGS='-fsanitize=address,{sanitizers_flags}'"
)
linker_flags += (
f" -DCMAKE_SHARED_LINKER_FLAGS='-fsanitize=address,{sanitizers_flags}'"
)
# Sanitizers recommend minimum of -O1 for reasonable performance
cxx_flags += " -O1"
# First create config for asan
cmake_args_flags = f'{cmake_args} -DCMAKE_CXX_FLAGS="-fsanitize=address,{sanitizers_flags} {cxx_flags} {extra_warning_flags}" {linker_flags}'
# Add config with asan+ubsan
configs = {}
configs["asan_ubsan"] = cmake_args_flags
# Since TSAN runs are crashing with seg faults(could be compatibility issues with latest compilers)
# We deactivate it for now. But I would keep the code, since it took some effort to find the correct set of config needed to run this.
# This will be useful when we decide to activate it again in future.
activateTSAN = False
if activateTSAN:
linker_flags = ""
# Update configs for tsan
# gcc doesn't supports atomic_thread_fence with tsan. Suppress warnings.
# Also tsan doesn't work well with mcmode=large and bfd linker
if os["compiler_name"] == "gcc":
extra_warning_flags += " -Wno-tsan"
cxx_flags = cxx_flags.replace("-mcmodel=large", "-mcmodel=medium")
linker_relocation_flags = linker_relocation_flags.replace(
"-mcmodel=large", "-mcmodel=medium"
)
# Add linker flags for Sanitizers
linker_flags += f" -DCMAKE_EXE_LINKER_FLAGS='{linker_relocation_flags} -fsanitize=thread,{sanitizers_flags}'"
linker_flags += f" -DCMAKE_SHARED_LINKER_FLAGS='{linker_relocation_flags} -fsanitize=thread,{sanitizers_flags}'"
elif os["compiler_name"] == "clang":
linker_flags += (
f" -DCMAKE_EXE_LINKER_FLAGS='-fsanitize=thread,{sanitizers_flags}'"
)
linker_flags += (
f" -DCMAKE_SHARED_LINKER_FLAGS='-fsanitize=thread,{sanitizers_flags}'"
)
cmake_args_flags = f"{cmake_args} -DCMAKE_CXX_FLAGS='-fsanitize=thread,{sanitizers_flags} {cxx_flags} {extra_warning_flags}' {linker_flags}"
# Add config with tsan+ubsan
configs["tsan_ubsan"] = cmake_args_flags
return configs
def read_config(file: Path) -> Config:
config = json.loads(file.read_text())
if (

View File

@@ -51,7 +51,7 @@ on:
default: 2
sanitizers:
description: "The sanitizers to enable ('Address+UndefinedBehavior' or 'Thread+UndefinedBehavior')."
description: "The sanitizers to enable ('Address,UndefinedBehavior' or 'Thread,UndefinedBehavior')."
required: false
type: string
default: ""
@@ -74,7 +74,7 @@ jobs:
env:
ENABLED_VOIDSTAR: ${{ contains(inputs.cmake_args, '-Dvoidstar=ON') }}
ENABLED_COVERAGE: ${{ contains(inputs.cmake_args, '-Dcoverage=ON') }}
ENABLED_SANITIZERS: ${{ contains(inputs.cmake_args, '-fsanitize') }}
ENABLED_SANITIZERS: ${{ inputs.sanitizers != '' }}
steps:
- name: Cleanup workspace (macOS and Windows)
if: ${{ runner.os == 'macOS' || runner.os == 'Windows' }}
@@ -115,6 +115,7 @@ jobs:
working-directory: ${{ inputs.build_dir }}
env:
BUILD_TYPE: ${{ inputs.build_type }}
SANITIZER: ${{ inputs.sanitizers }}
run: |
cmake \
-G '${{ runner.os == 'Windows' && 'Visual Studio 17 2022' || 'Ninja' }}' \

View File

@@ -74,6 +74,7 @@ if (packages_only)
return ()
endif ()
include(XrplCompiler)
include(XrplSanitizers)
include(XrplInterface)
option(only_docs "Include only the docs target?" FALSE)

View File

@@ -1,5 +0,0 @@
# This file is included by Conan's toolchain file.
# We set the required CMake variable as a CACHE variable to ensure
# it takes effect during the configure step.
set(ABSL_ENABLE_CONSTANT_INIT_V2 "OFF" CACHE BOOL "Disable Abseil's V2 constant init logic to fix compiler errors.")

158
cmake/XrplSanitizers.cmake Normal file
View File

@@ -0,0 +1,158 @@
#[===================================================================[
Configure sanitizers based on environment variables.
This module reads the following environment variables:
- SANITIZER: The sanitizers to enable. Possible values:
- "Address"
- "Address,UndefinedBehavior"
- "Thread"
- "Thread,UndefinedBehavior"
The compiler type and platform are detected automatically by CMake.
The sanitizer compile options are applied to the 'common' interface library
which is linked to all targets in the project.
#]===================================================================]
# Read environment variable
set(SANITIZER $ENV{SANITIZER})
if(SANITIZER)
message(STATUS "Configuring sanitizers: ${SANITIZER}")
# Parse SANITIZER value to determine which sanitizers to enable
set(ENABLE_ASAN FALSE)
set(ENABLE_TSAN FALSE)
set(ENABLE_UBSAN FALSE)
if(SANITIZER MATCHES "Address")
set(ENABLE_ASAN TRUE)
endif()
if(SANITIZER MATCHES "Thread")
set(ENABLE_TSAN TRUE)
endif()
if(SANITIZER MATCHES "UndefinedBehavior")
set(ENABLE_UBSAN TRUE)
endif()
# Detect compiler type
set(IS_GCC FALSE)
set(IS_CLANG FALSE)
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
set(IS_GCC TRUE)
message(STATUS " Compiler: GCC ${CMAKE_CXX_COMPILER_VERSION}")
elseif(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
set(IS_CLANG TRUE)
message(STATUS " Compiler: Clang ${CMAKE_CXX_COMPILER_VERSION}")
endif()
# Detect platform (amd64/x86_64 vs arm64/aarch64)
set(IS_AMD64 FALSE)
if(CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64|AMD64")
set(IS_AMD64 TRUE)
message(STATUS " Platform: amd64")
else()
message(STATUS " Platform: ${CMAKE_SYSTEM_PROCESSOR}")
endif()
# Frame pointer is required for meaningful stack traces
set(SANITIZER_COMPILE_FLAGS "-fno-omit-frame-pointer")
# Sanitizers recommend minimum of -O1 for reasonable performance
set(SANITIZER_COMPILE_FLAGS "${SANITIZER_COMPILE_FLAGS} -O1")
# Build the sanitizer flags string
set(SANITIZER_FLAGS "")
if(ENABLE_ASAN)
set(SANITIZER_FLAGS "address")
elseif(ENABLE_TSAN)
set(SANITIZER_FLAGS "thread")
endif()
if(ENABLE_UBSAN)
# UB sanitizer flags
if(IS_CLANG)
# Clang supports additional UB checks
set(UBSAN_FLAGS "undefined,float-divide-by-zero,unsigned-integer-overflow")
else()
set(UBSAN_FLAGS "undefined,float-divide-by-zero")
endif()
if(SANITIZER_FLAGS)
set(SANITIZER_FLAGS "${SANITIZER_FLAGS},${UBSAN_FLAGS}")
else()
set(SANITIZER_FLAGS "${UBSAN_FLAGS}")
endif()
endif()
# Configure code model for GCC on amd64
# Use large code model for ASAN to avoid relocation errors
# Use medium code model for TSAN (large is not compatible with TSAN)
set(SANITIZER_RELOCATION_FLAGS "")
if(IS_GCC AND IS_AMD64)
if(ENABLE_ASAN)
message(STATUS " Using large code model (-mcmodel=large)")
set(SANITIZER_COMPILE_FLAGS "${SANITIZER_COMPILE_FLAGS} -mcmodel=large")
set(SANITIZER_RELOCATION_FLAGS "-mcmodel=large")
elseif(ENABLE_TSAN)
message(STATUS " Using medium code model (-mcmodel=medium)")
set(SANITIZER_COMPILE_FLAGS "${SANITIZER_COMPILE_FLAGS} -mcmodel=medium")
set(SANITIZER_RELOCATION_FLAGS "-mcmodel=medium")
endif()
endif()
# Compiler-specific configuration
if(IS_GCC)
# Disable mold, gold and lld linkers for GCC with sanitizers
# Use default linker (bfd/ld) which is more lenient with mixed code models
set(use_mold OFF CACHE BOOL "Use mold linker" FORCE)
set(use_gold OFF CACHE BOOL "Use gold linker" FORCE)
set(use_lld OFF CACHE BOOL "Use lld linker" FORCE)
message(STATUS " Disabled mold, gold, and lld linkers for GCC with sanitizers")
# Suppress false positive warnings in GCC with stringop-overflow
set(SANITIZER_COMPILE_FLAGS "${SANITIZER_COMPILE_FLAGS} -Wno-stringop-overflow")
if(ENABLE_TSAN)
# GCC doesn't support atomic_thread_fence with tsan. Suppress warnings.
set(SANITIZER_COMPILE_FLAGS "${SANITIZER_COMPILE_FLAGS} -Wno-tsan")
endif()
# Add sanitizer to compile and link flags
set(SANITIZER_COMPILE_FLAGS "${SANITIZER_COMPILE_FLAGS} -fsanitize=${SANITIZER_FLAGS}")
set(SANITIZER_LINK_FLAGS "${SANITIZER_RELOCATION_FLAGS} -fsanitize=${SANITIZER_FLAGS}")
elseif(IS_CLANG)
# Add ignorelist for Clang (GCC doesn't support this)
# Use CMAKE_SOURCE_DIR to get the path to the ignorelist
set(IGNORELIST_PATH "${CMAKE_SOURCE_DIR}/sanitizers/suppressions/sanitizer-ignorelist.txt")
if(EXISTS "${IGNORELIST_PATH}")
set(SANITIZER_COMPILE_FLAGS "${SANITIZER_COMPILE_FLAGS} -fsanitize-ignorelist=${IGNORELIST_PATH}")
message(STATUS " Using sanitizer ignorelist: ${IGNORELIST_PATH}")
else()
message(WARNING "Sanitizer ignorelist not found: ${IGNORELIST_PATH}")
endif()
# Add sanitizer to compile and link flags
set(SANITIZER_COMPILE_FLAGS "${SANITIZER_COMPILE_FLAGS} -fsanitize=${SANITIZER_FLAGS}")
set(SANITIZER_LINK_FLAGS "-fsanitize=${SANITIZER_FLAGS}")
endif()
message(STATUS " Compile flags: ${SANITIZER_COMPILE_FLAGS}")
message(STATUS " Link flags: ${SANITIZER_LINK_FLAGS}")
# Convert space-separated strings to lists for CMake
separate_arguments(SANITIZER_COMPILE_FLAGS_LIST NATIVE_COMMAND "${SANITIZER_COMPILE_FLAGS}")
separate_arguments(SANITIZER_LINK_FLAGS_LIST NATIVE_COMMAND "${SANITIZER_LINK_FLAGS}")
# Apply the sanitizer flags to the 'common' interface library
# This is the same library used by XrplCompiler.cmake
target_compile_options(common INTERFACE
$<$<COMPILE_LANGUAGE:CXX>:${SANITIZER_COMPILE_FLAGS_LIST}>
$<$<COMPILE_LANGUAGE:C>:${SANITIZER_COMPILE_FLAGS_LIST}>
)
# Apply linker flags
target_link_options(common INTERFACE ${SANITIZER_LINK_FLAGS_LIST})
endif()

View File

@@ -92,33 +92,6 @@ option(local_protobuf
option(local_grpc
"Force a local build of gRPC instead of looking for an installed version." OFF)
# this one is a string and therefore can't be an option
set(san "" CACHE STRING "On gcc & clang, add sanitizer instrumentation")
set_property(CACHE san PROPERTY STRINGS ";undefined;memory;address;thread")
if(san)
string(TOLOWER ${san} san)
set(SAN_FLAG "-fsanitize=${san}")
set(SAN_LIB "")
if(is_gcc)
if(san STREQUAL "address")
set(SAN_LIB "asan")
elseif(san STREQUAL "thread")
set(SAN_LIB "tsan")
elseif(san STREQUAL "memory")
set(SAN_LIB "msan")
elseif(san STREQUAL "undefined")
set(SAN_LIB "ubsan")
endif()
endif()
set(_saved_CRL ${CMAKE_REQUIRED_LIBRARIES})
set(CMAKE_REQUIRED_LIBRARIES "${SAN_FLAG};${SAN_LIB}")
check_cxx_compiler_flag(${SAN_FLAG} COMPILER_SUPPORTS_SAN)
set(CMAKE_REQUIRED_LIBRARIES ${_saved_CRL})
if(NOT COMPILER_SUPPORTS_SAN)
message(FATAL_ERROR "${san} sanitizer does not seem to be supported by your compiler")
endif()
endif()
# the remaining options are obscure and rarely used
option(beast_no_unit_test_inline
"Prevents unit test definitions from being inserted into global table"