mirror of
https://github.com/scp-fs2open/fs2open.github.com.git
synced 2026-11-07 08:15:59 -10:00
* ci: run clang-tidy on macOS and Linux clang builds Install a version-matched clang-tidy on macOS and make the shared runner portable across both CI environments. * ci: keep valgrind compatible with clang debug builds Emit DWARF4 debug information and suppress SDL's one-time initialization allocation so memcheck can report actionable failures. * ci: suppress SDL3/libX11 video backend leaks under valgrind Now that the `[ "$CONFIGURATION" = "Debug" ]` typo is fixed, valgrind actually runs on the Linux Debug legs again, and memcheck fails the build on six "definitely lost" contexts (480 bytes) that all originate inside SDL3's X11 backend at X11_CreateDevice, reached from SDL_VideoInit. These aren't ours to fix: both call sites (os_init's SDL_Init and the temporary video init in resolution_default(), reached via gr_init) already pair their init with a matching quit, and the allocations are made and kept by SDL/libX11 across SDL_VideoQuit. Collapsing the repeated init/quit cycles would only reduce the block count, not the number of leak contexts, so the build would still fail. The suppression is truncated at X11_CreateDevice on purpose: it stays caller-agnostic (covering both the os_init and gr_init paths) and avoids matching on SDL_InitSubSystem_REAL.part.0, whose .part.0 suffix is a partial-inlining artifact of how SDL3 happened to be built. Co-Authored-By: Claude Opus 5 <[email protected]> * ci: suppress glibc dlopen loader leaks under valgrind The Linux clang-16 Debug leg fails memcheck on a single zero-byte block lost in glibc's `_dl_find_object_update()`, reached from `dlopen()` while SDL probes its video backends. It is loader bookkeeping that glibc keeps by design, and it only shows up on some legs because it depends on how many objects the loader has mapped by that point. The file already carried three suppressions for this class, but each pinned a full, exact glibc stack, so every new loader code path costs another CI round. Replace them with a single block matching on `_dl_open`: nothing of ours runs below that frame, only loader internals and the static constructors of shared libraries the loader brings in, so this gives up no coverage we care about while retiring the whole class. All three removed blocks contain `_dl_open` themselves and are therefore subsumed by it. Both new suppressions match `definite,possible` rather than `definite` alone, since `--errors-for-leak-kinds` defaults to `definite,possible` and the same allocations would otherwise fail the build if valgrind ever reported them as possibly lost instead. Co-Authored-By: Claude Opus 5 <[email protected]> --------- Co-authored-by: Claude Opus 5 <[email protected]>
187 lines
6.2 KiB
CMake
187 lines
6.2 KiB
CMake
# Clang
|
|
include(EnableExtraCompilerWarnings)
|
|
include(CheckCXXCompilerFlag)
|
|
|
|
MESSAGE(STATUS "Doing configuration specific to clang...")
|
|
|
|
option(CLANG_ENABLE_LEAK_CHECK "Enable -fsanitize=leak" OFF)
|
|
option(CLANG_ENABLE_ADDRESS_SANITIZER "Enable -fsanitize=address" OFF)
|
|
|
|
option(CLANG_USE_LIBCXX "Use libc++" OFF)
|
|
|
|
# These are the default values
|
|
set(C_BASE_FLAGS "-pipe")
|
|
set(CXX_BASE_FLAGS "-pipe")
|
|
|
|
if(IS_X86)
|
|
if(FORCED_NATIVE_SIMD_INSTRUCTIONS)
|
|
set(CLANG_EXTENSIONS "-march=native")
|
|
elseif (FSO_INSTRUCTION_SET STREQUAL "")
|
|
set(CLANG_EXTENSIONS "-march=x86-64")
|
|
elseif (FSO_INSTRUCTION_SET STREQUAL "SSE")
|
|
set(CLANG_EXTENSIONS "-march=x86-64 -msse -mfpmath=sse")
|
|
elseif (FSO_INSTRUCTION_SET STREQUAL "SSE2")
|
|
set(CLANG_EXTENSIONS "-march=x86-64 -msse -msse2 -mfpmath=sse")
|
|
elseif (FSO_INSTRUCTION_SET STREQUAL "AVX")
|
|
set(CLANG_EXTENSIONS "-march=x86-64-v2 -msse -msse2 -mavx -mfpmath=sse")
|
|
elseif (FSO_INSTRUCTION_SET STREQUAL "AVX2")
|
|
set(CLANG_EXTENSIONS "-march=x86-64-v3 -msse -msse2 -mavx -mavx2 -mfpmath=sse")
|
|
else ()
|
|
message( FATAL_ERROR "Unknown instruction set encountered for clang. Update toolchain-clang.cmake!" )
|
|
endif()
|
|
|
|
set(C_BASE_FLAGS "${C_BASE_FLAGS} ${CLANG_EXTENSIONS}")
|
|
set(CXX_BASE_FLAGS "${CXX_BASE_FLAGS} ${CLANG_EXTENSIONS}")
|
|
elseif(IS_ARM)
|
|
if(FORCED_NATIVE_SIMD_INSTRUCTIONS)
|
|
set(C_BASE_FLAGS "${C_BASE_FLAGS} -march=native")
|
|
set(CXX_BASE_FLAGS "${CXX_BASE_FLAGS} -march=native")
|
|
endif ()
|
|
elseif(IS_RISCV)
|
|
# Default C/CXX_BASE_FLAGS are fine for RISC-V
|
|
endif()
|
|
|
|
if (USE_STATIC_LIBCXX)
|
|
set(CXX_BASE_FLAGS "${CXX_BASE_FLAGS} -static-libstdc++ -Qunused-arguments")
|
|
endif()
|
|
|
|
# For C and C++, the values can be overwritten independently
|
|
if(DEFINED ENV{CXXFLAGS})
|
|
set(CXX_BASE_FLAGS $ENV{CXXFLAGS})
|
|
endif()
|
|
if(DEFINED ENV{CFLAGS})
|
|
set(C_BASE_FLAGS $ENV{CFLAGS})
|
|
endif()
|
|
|
|
if (CLANG_USE_LIBCXX)
|
|
set(CXX_BASE_FLAGS "${CXX_BASE_FLAGS} -stdlib=libc++")
|
|
target_link_libraries(compiler INTERFACE "c++" "c++abi")
|
|
endif()
|
|
|
|
# Initialize with an empty string to make sure we always get a clean start
|
|
set(COMPILER_FLAGS "")
|
|
|
|
# This is a slight hack since our flag setup is a bit more complicated
|
|
_enable_extra_compiler_warnings_flags()
|
|
set(COMPILER_FLAGS "${COMPILER_FLAGS} ${_flags}")
|
|
|
|
set(COMPILER_FLAGS "${COMPILER_FLAGS} -fsigned-char -Wno-unknown-pragmas")
|
|
|
|
|
|
if ("${CMAKE_GENERATOR}" STREQUAL "Ninja")
|
|
# Force color diagnostics for Ninja generator
|
|
set(COMPILER_FLAGS "${COMPILER_FLAGS} -fdiagnostics-color")
|
|
endif()
|
|
|
|
# Start with an empty list
|
|
set(SANITIZE_FLAGS)
|
|
|
|
if(CLANG_ENABLE_ADDRESS_SANITIZER)
|
|
set(CMAKE_REQUIRED_FLAGS "-fsanitize=address")
|
|
CHECK_C_COMPILER_FLAG("-fsanitize=address" SUPPORTS_SANITIZE_ADDRESS)
|
|
|
|
if (SUPPORTS_SANITIZE_ADDRESS)
|
|
set(SANITIZE_FLAGS ${SANITIZE_FLAGS} "address")
|
|
endif()
|
|
endif()
|
|
if (CLANG_ENABLE_LEAK_CHECK)
|
|
check_linker_flag("-fsanitize=leak" SUPPORTS_FSANITIZE_LEAK)
|
|
|
|
if (SUPPORTS_FSANITIZE_LEAK)
|
|
set(SANITIZE_FLAGS ${SANITIZE_FLAGS} "leak")
|
|
endif()
|
|
endif()
|
|
|
|
string(REPLACE ";" "," SANITIZE_FLAGS "${SANITIZE_FLAGS}")
|
|
if (NOT "${SANITIZE_FLAGS}" STREQUAL "")
|
|
set(SANITIZE_FLAGS "-fsanitize=${SANITIZE_FLAGS}")
|
|
endif()
|
|
|
|
set(COMPILER_FLAGS "${COMPILER_FLAGS} ${SANITIZE_FLAGS}")
|
|
|
|
set(COMPILER_FLAGS "${COMPILER_FLAGS} -Wformat-security")
|
|
|
|
# Dear Clang, please tell us if a function does not return a value since that part of the standard is stupid!
|
|
set(COMPILER_FLAGS "${COMPILER_FLAGS} -Wreturn-type")
|
|
|
|
set(COMPILER_FLAGS "${COMPILER_FLAGS} -Wno-char-subscripts")
|
|
|
|
check_cxx_compiler_flag(-Wshift-negative-value SUPPORTS_SHIFT_NEGATIVE_VALUE)
|
|
if(SUPPORTS_SHIFT_NEGATIVE_VALUE)
|
|
set(COMPILER_FLAGS "${COMPILER_FLAGS} -Wno-shift-negative-value")
|
|
endif()
|
|
|
|
# Check if there is a user-set optimisation flag
|
|
string(REGEX MATCH "-O[a-zA-Z|0-9]+" CXX_OPT_FLAG ${CXX_BASE_FLAGS})
|
|
string(REGEX MATCH "-O[a-zA-Z|0-9]+" C_OPT_FLAG ${C_BASE_FLAGS})
|
|
|
|
# If no user-set opt flag, set -O3 and -Og
|
|
if ("${CXX_OPT_FLAG}" STREQUAL "")
|
|
set(CXX_OPT_FLAG_RELEASE "-O3")
|
|
set(CXX_OPT_FLAG_DEBUG "-O0")
|
|
else()
|
|
set(CXX_OPT_FLAG_RELEASE "${CXX_OPT_FLAG}")
|
|
set(CXX_OPT_FLAG_DEBUG "${CXX_OPT_FLAG}")
|
|
endif()
|
|
if ("${C_OPT_FLAG}" STREQUAL "")
|
|
set(C_OPT_FLAG_RELEASE "-O3")
|
|
set(C_OPT_FLAG_DEBUG "-O0")
|
|
else()
|
|
set(C_OPT_FLAG_RELEASE "${C_OPT_FLAG}")
|
|
set(C_OPT_FLAG_DEBUG "${C_OPT_FLAG}")
|
|
endif()
|
|
|
|
set(CXX_FLAGS_RELEASE "${CXX_OPT_FLAG_RELEASE} -Wno-unused-variable -Wno-unused-parameter")
|
|
set(C_FLAGS_RELEASE "${C_OPT_FLAG_RELEASE} -Wno-unused-variable -Wno-unused-parameter")
|
|
|
|
# Valgrind (as used by CI) does not understand the DWARF5 debug info that clang
|
|
# emits by default, so force DWARF4 to keep memcheck able to symbolize the binary.
|
|
set(CXX_FLAGS_DEBUG "${CXX_OPT_FLAG_DEBUG} -g -gdwarf-4 -Wshadow")
|
|
set(C_FLAGS_DEBUG "${C_OPT_FLAG_DEBUG} -g -gdwarf-4 -Wshadow")
|
|
|
|
# Always use the base flags and add our compiler flags at the back
|
|
set(CMAKE_CXX_FLAGS "${CXX_BASE_FLAGS} ${COMPILER_FLAGS}")
|
|
set(CMAKE_C_FLAGS "${C_BASE_FLAGS} ${COMPILER_FLAGS}")
|
|
|
|
set(CMAKE_CXX_FLAGS_RELEASE ${CXX_FLAGS_RELEASE})
|
|
set(CMAKE_C_FLAGS_RELEASE ${C_FLAGS_RELEASE})
|
|
|
|
set(CMAKE_CXX_FLAGS_DEBUG ${CXX_FLAGS_DEBUG})
|
|
set(CMAKE_C_FLAGS_DEBUG ${C_FLAGS_DEBUG})
|
|
|
|
set(CMAKE_EXE_LINKER_FLAGS "")
|
|
|
|
if(DEFINED ENV{LDFLAGS})
|
|
set(CMAKE_EXE_LINKER_FLAGS $ENV{LDFLAGS})
|
|
endif()
|
|
|
|
if (CLANG_USE_LIBCXX)
|
|
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -lc++abi")
|
|
endif()
|
|
|
|
if (SANITIZE_FLAGS)
|
|
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${SANITIZE_FLAGS}")
|
|
endif()
|
|
|
|
set(CMAKE_EXE_LINKER_FLAGS_RELEASE "")
|
|
set(CMAKE_EXE_LINKER_FLAGS_DEBUG "-g -rdynamic")
|
|
|
|
if (FSO_FATAL_WARNINGS)
|
|
# Make warnings fatal if the right variable is set
|
|
target_compile_options(compiler INTERFACE "-Werror")
|
|
endif()
|
|
|
|
# Always define this to make sure that the fixed-width format macros are available
|
|
target_compile_definitions(compiler INTERFACE __STDC_FORMAT_MACROS)
|
|
|
|
if(CMAKE_SYSTEM_NAME STREQUAL "Linux" OR MINGW)
|
|
# GNU ar: Create thin archive files.
|
|
# Requires binutils-2.19 or later.
|
|
set(CMAKE_C_ARCHIVE_CREATE "<CMAKE_AR> qcTP <TARGET> <LINK_FLAGS> <OBJECTS>")
|
|
set(CMAKE_C_ARCHIVE_APPEND "<CMAKE_AR> qTP <TARGET> <LINK_FLAGS> <OBJECTS>")
|
|
set(CMAKE_CXX_ARCHIVE_CREATE "<CMAKE_AR> qcTP <TARGET> <LINK_FLAGS> <OBJECTS>")
|
|
set(CMAKE_CXX_ARCHIVE_APPEND "<CMAKE_AR> qTP <TARGET> <LINK_FLAGS> <OBJECTS>")
|
|
endif()
|
|
|
|
target_link_libraries(compiler INTERFACE m)
|