Skip to content

Modernize CMake build system with modular structure and toolchain files#48

Open
Copilot wants to merge 4 commits intomasterfrom
copilot/refactor-cmake-for-idiomatic-use
Open

Modernize CMake build system with modular structure and toolchain files#48
Copilot wants to merge 4 commits intomasterfrom
copilot/refactor-cmake-for-idiomatic-use

Conversation

Copy link
Copy Markdown

Copilot AI commented Jan 31, 2026

  • Analyze existing CMake build system structure
  • Create modular cmake/ directory with helper modules:
    • cmake/DCMACompilerOptions.cmake - compiler flags and settings
    • cmake/DCMADependencies.cmake - dependency finding with FetchContent fallback
    • cmake/DCMAPlatformChecks.cmake - platform/feature detection
    • cmake/DCMADefines.cmake - project-wide definitions
    • cmake/toolchains/ - toolchain files for cross-compilation
      • mxe-x86_64-w64-mingw32.cmake - Windows cross-compilation
      • macos-x86_64.cmake - macOS cross-compilation
      • linux-aarch64.cmake - ARM64 cross-compilation
      • linux-musl.cmake - musl libc static builds
  • Add CMakePresets.json for modern build configuration
  • Modernize root CMakeLists.txt:
    • Add DCMA_ prefixed options with backward compatibility
    • Include modular cmake components
    • Graceful dependency fallback (QUIET instead of REQUIRED)
    • Add dependency configuration summary
    • Improve comments referencing modular approach
  • Test CMake configuration with minimal dependencies - SUCCESS
  • Apply review feedback:
    • Move -pie from compile options to link options (MSan)
    • Use add_link_options(-static) in MXE toolchain
    • Use add_link_options(-static) in musl toolchain
    • Add dcma_check_cgal_compatibility() to umbrella function
    • Lower CMakePresets.json version to match project minimum (3.12)
    • Fix backward compatibility by removing _SET checks
    • Fix "dynamicly" typo to "dynamically"
    • Fix -U_FORTIFY_SOURCE to use compile_options instead of compile_definitions

Summary

This PR modernizes the DICOMautomaton CMake build system by:

  1. Creating modular cmake/ helper modules that encapsulate compiler options, dependency finding, platform checks, and feature definitions into reusable functions
  2. Adding FetchContent fallbacks in DCMADependencies.cmake for Eigen and NLopt when system packages are unavailable
  3. Creating cross-compilation toolchain files for Windows (MXE), macOS (osxcross), ARM64, and musl libc builds
  4. Adding CMakePresets.json for standardized build configurations (debug, release, minimal, full, sanitizers, cross-compile presets)
  5. Improving dependency handling by using QUIET instead of REQUIRED with graceful fallback, allowing builds to succeed with fewer dependencies
  6. Adding DCMA_ prefixed options with backward compatibility for existing build scripts using legacy option names
  7. Adding a dependency configuration summary at configure time for better build visibility

💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.

Copilot AI and others added 2 commits January 31, 2026 03:31
Co-authored-by: hdclark <934858+hdclark@users.noreply.github.com>
Co-authored-by: hdclark <934858+hdclark@users.noreply.github.com>
Copilot AI changed the title [WIP] Refactor CMakeLists.txt for modern idiomatic usage Modernize CMake build system with modular structure and toolchain files Jan 31, 2026
Copilot AI requested a review from hdclark January 31, 2026 03:36
@hdclark hdclark marked this pull request as ready for review January 31, 2026 03:53
Copilot AI review requested due to automatic review settings January 31, 2026 03:53
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR modernizes the CMake build system by introducing a modular structure with separate files for compiler options, dependencies, platform checks, and definitions. It adds comprehensive cross-compilation toolchain files for Windows (MXE), macOS (osxcross), Linux ARM64/ARMv7, and musl-based static builds, along with CMakePresets.json for common build configurations.

Changes:

  • Introduced modular CMake structure with cmake/DCMA*.cmake files providing reusable functions for compiler options, dependency finding (with FetchContent fallbacks), platform detection, and feature definitions
  • Added four cross-compilation toolchain files and CMakePresets.json with debug, release, minimal, full, sanitizer, and cross-compile configurations
  • Updated root CMakeLists.txt to use DCMA_-prefixed options with backward compatibility for legacy names, changed dependency finding from REQUIRED to QUIET with graceful fallback, and added a dependency configuration summary

Reviewed changes

Copilot reviewed 10 out of 10 changed files in this pull request and generated 8 comments.

Show a summary per file
File Description
CMakePresets.json Adds preset configurations for debug, release, minimal, full, sanitizers, static, and cross-compilation builds
cmake/DCMACompilerOptions.cmake Provides target-based compiler flag functions with GCC/Clang support and sanitizer configurations
cmake/DCMADependencies.cmake Implements dependency finding with FetchContent fallbacks for Eigen and NLopt
cmake/DCMAPlatformChecks.cmake Handles ARM detection, stdlib feature checks, CGAL compatibility, and Windows configuration
cmake/DCMADefines.cmake Manages feature compile definitions and version extraction
cmake/toolchains/mxe-x86_64-w64-mingw32.cmake Windows cross-compilation via MXE toolchain
cmake/toolchains/macos-x86_64.cmake macOS cross-compilation via osxcross
cmake/toolchains/linux-musl.cmake musl libc static build configuration
cmake/toolchains/linux-aarch64.cmake ARM64/ARMv7 cross-compilation setup
CMakeLists.txt Adds DCMA_-prefixed options, backward compatibility mapping, graceful dependency fallback, and configuration summary

Comment on lines +110 to +113
-pie
-fsanitize-memory-track-origins
)
target_link_options(${target} PRIVATE -fsanitize=memory)
Copy link

Copilot AI Jan 31, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The -pie flag in line 110 is a linker flag, not a compiler flag. It should be passed via target_link_options instead of target_compile_options. The -fPIE flag is correct for compile options, but -pie should be moved to the link options in line 113 along with -fsanitize=memory.

Suggested change
-pie
-fsanitize-memory-track-origins
)
target_link_options(${target} PRIVATE -fsanitize=memory)
-fsanitize-memory-track-origins
)
target_link_options(${target} PRIVATE
-fsanitize=memory
-pie
)

Copilot uses AI. Check for mistakes.
Comment on lines +48 to +49
set(CMAKE_EXE_LINKER_FLAGS "-static")
set(BUILD_SHARED_LIBS OFF CACHE BOOL "Build shared libraries" FORCE)
Copy link

Copilot AI Jan 31, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The linker flag -static is being set globally in CMAKE_EXE_LINKER_FLAGS on line 48, but this may not propagate correctly to all targets. Consider using add_link_options(-static) instead or documenting that users may need to set additional link options for libraries. Additionally, the CACHE FORCE approach on line 49 prevents users from overriding this setting.

Suggested change
set(CMAKE_EXE_LINKER_FLAGS "-static")
set(BUILD_SHARED_LIBS OFF CACHE BOOL "Build shared libraries" FORCE)
# Prefer static linking for executables built with this static MXE toolchain;
# use add_link_options so that the flag propagates correctly to targets.
add_link_options(-static)
# Default to building static libraries, but allow users to override
# BUILD_SHARED_LIBS from the command line or presets.
if(NOT DEFINED BUILD_SHARED_LIBS)
set(BUILD_SHARED_LIBS OFF CACHE BOOL "Build shared libraries")
endif()

Copilot uses AI. Check for mistakes.
# Flags for musl compatibility
set(CMAKE_C_FLAGS_INIT "-static")
set(CMAKE_CXX_FLAGS_INIT "-static")
set(CMAKE_EXE_LINKER_FLAGS_INIT "-static")
Copy link

Copilot AI Jan 31, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The static linking flags are set via CMAKE_*_FLAGS_INIT variables (lines 67-69), which are initialization flags. While this is a valid approach, these flags may not apply to all link scenarios (e.g., shared libraries if BUILD_SHARED_LIBS is later changed). Consider using add_link_options(-static) or document that this toolchain is strictly for static executables only.

Suggested change
set(CMAKE_EXE_LINKER_FLAGS_INIT "-static")
add_link_options(-static)

Copilot uses AI. Check for mistakes.
function(dcma_run_all_platform_checks)
dcma_detect_arm_architecture()
dcma_check_cppstdlib_features()
dcma_check_system_features()
Copy link

Copilot AI Jan 31, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The function dcma_check_cgal_compatibility() is defined but not called in dcma_run_all_platform_checks() on line 126. If this function is intended to be part of the platform checks workflow, it should be added to the function. If it's intended to be called separately, consider documenting this or renaming the umbrella function to clarify its scope.

Suggested change
dcma_check_system_features()
dcma_check_system_features()
dcma_check_cgal_compatibility()

Copilot uses AI. Check for mistakes.
"version": 6,
"cmakeMinimumRequired": {
"major": 3,
"minor": 21,
Copy link

Copilot AI Jan 31, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The CMakePresets.json file specifies cmakeMinimumRequired as 3.21.0, but the root CMakeLists.txt file requires CMake 3.12.0. This creates an inconsistency where presets require a newer CMake version than the project itself. Consider updating CMakeLists.txt to require CMake 3.21 if presets are intended to be the primary configuration method, or lower the preset requirement to match the project minimum.

Suggested change
"minor": 21,
"minor": 12,

Copilot uses AI. Check for mistakes.
CMakeLists.txt Outdated
Comment on lines +65 to +86
if(DEFINED WITH_SFML AND NOT DEFINED DCMA_WITH_SFML_SET)
set(DCMA_WITH_SFML ${WITH_SFML})
endif()
if(DEFINED WITH_SDL AND NOT DEFINED DCMA_WITH_SDL_SET)
set(DCMA_WITH_SDL ${WITH_SDL})
endif()
if(DEFINED WITH_WT AND NOT DEFINED DCMA_WITH_WT_SET)
set(DCMA_WITH_WT ${WITH_WT})
endif()
if(DEFINED WITH_GNU_GSL AND NOT DEFINED DCMA_WITH_GNU_GSL_SET)
set(DCMA_WITH_GNU_GSL ${WITH_GNU_GSL})
endif()
if(DEFINED WITH_POSTGRES AND NOT DEFINED DCMA_WITH_POSTGRES_SET)
set(DCMA_WITH_POSTGRES ${WITH_POSTGRES})
endif()
if(DEFINED WITH_JANSSON AND NOT DEFINED DCMA_WITH_JANSSON_SET)
set(DCMA_WITH_JANSSON ${WITH_JANSSON})
endif()
if(DEFINED WITH_THRIFT AND NOT DEFINED DCMA_WITH_THRIFT_SET)
set(DCMA_WITH_THRIFT ${WITH_THRIFT})
endif()
if(DEFINED WITH_LTO AND NOT DEFINED DCMA_WITH_LTO_SET)
Copy link

Copilot AI Jan 31, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The backward compatibility mechanism is incomplete. The code checks for variables like DCMA_MEMORY_CONSTRAINED_BUILD_SET, DCMA_WITH_IWYU_SET, etc., but these variables are never set anywhere in the code. This means that if a user provides both the legacy option (e.g., WITH_EIGEN) and the new option (e.g., DCMA_WITH_EIGEN), the legacy option will always override the new one, which is likely not the intended behavior. The condition should either remove the _SET check, or the code should set these sentinel variables when the DCMA_ prefixed options are explicitly provided.

Suggested change
if(DEFINED WITH_SFML AND NOT DEFINED DCMA_WITH_SFML_SET)
set(DCMA_WITH_SFML ${WITH_SFML})
endif()
if(DEFINED WITH_SDL AND NOT DEFINED DCMA_WITH_SDL_SET)
set(DCMA_WITH_SDL ${WITH_SDL})
endif()
if(DEFINED WITH_WT AND NOT DEFINED DCMA_WITH_WT_SET)
set(DCMA_WITH_WT ${WITH_WT})
endif()
if(DEFINED WITH_GNU_GSL AND NOT DEFINED DCMA_WITH_GNU_GSL_SET)
set(DCMA_WITH_GNU_GSL ${WITH_GNU_GSL})
endif()
if(DEFINED WITH_POSTGRES AND NOT DEFINED DCMA_WITH_POSTGRES_SET)
set(DCMA_WITH_POSTGRES ${WITH_POSTGRES})
endif()
if(DEFINED WITH_JANSSON AND NOT DEFINED DCMA_WITH_JANSSON_SET)
set(DCMA_WITH_JANSSON ${WITH_JANSSON})
endif()
if(DEFINED WITH_THRIFT AND NOT DEFINED DCMA_WITH_THRIFT_SET)
set(DCMA_WITH_THRIFT ${WITH_THRIFT})
endif()
if(DEFINED WITH_LTO AND NOT DEFINED DCMA_WITH_LTO_SET)
if(DEFINED WITH_SFML)
set(DCMA_WITH_SFML ${WITH_SFML})
endif()
if(DEFINED WITH_SDL)
set(DCMA_WITH_SDL ${WITH_SDL})
endif()
if(DEFINED WITH_WT)
set(DCMA_WITH_WT ${WITH_WT})
endif()
if(DEFINED WITH_GNU_GSL)
set(DCMA_WITH_GNU_GSL ${WITH_GNU_GSL})
endif()
if(DEFINED WITH_POSTGRES)
set(DCMA_WITH_POSTGRES ${WITH_POSTGRES})
endif()
if(DEFINED WITH_JANSSON)
set(DCMA_WITH_JANSSON ${WITH_JANSSON})
endif()
if(DEFINED WITH_THRIFT)
set(DCMA_WITH_THRIFT ${WITH_THRIFT})
endif()
if(DEFINED WITH_LTO)

Copilot uses AI. Check for mistakes.
CMakeLists.txt Outdated
option(WITH_LTO "Use link-time optimization when available." OFF)
option(DCMA_WITH_LTO "Use link-time optimization when available." OFF)

option(BUILD_SHARED_LIBS "Build shared-object/dynamicly-loaded binaries." ON)
Copy link

Copilot AI Jan 31, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The word "dynamicly" is misspelled and should be "dynamically".

Suggested change
option(BUILD_SHARED_LIBS "Build shared-object/dynamicly-loaded binaries." ON)
option(BUILD_SHARED_LIBS "Build shared-object/dynamically-loaded binaries." ON)

Copilot uses AI. Check for mistakes.
target_link_libraries(${target} PRIVATE gcov)
endif()

target_compile_definitions(${target} PRIVATE -U_FORTIFY_SOURCE)
Copy link

Copilot AI Jan 31, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The -U_FORTIFY_SOURCE flag is being passed to target_compile_definitions but this is a compiler flag, not a definition. It should be passed to target_compile_options instead. The correct approach would be to use target_compile_options(${target} PRIVATE -U_FORTIFY_SOURCE) or target_compile_definitions(${target} PRIVATE _FORTIFY_SOURCE=0) depending on the intent.

Suggested change
target_compile_definitions(${target} PRIVATE -U_FORTIFY_SOURCE)
target_compile_options(${target} PRIVATE -U_FORTIFY_SOURCE)

Copilot uses AI. Check for mistakes.
@hdclark
Copy link
Copy Markdown
Owner

hdclark commented Jan 31, 2026

@copilot apply changes based on the comments in this thread

…d version consistency

Co-authored-by: hdclark <934858+hdclark@users.noreply.github.com>
Copy link
Copy Markdown
Author

Copilot AI commented Jan 31, 2026

@copilot apply changes based on the comments in this thread

Applied all 8 review comments in commit ae95c39:

  1. Moved -pie from compile options to link options for MSan
  2. Changed MXE toolchain to use add_link_options(-static) and removed CACHE FORCE for BUILD_SHARED_LIBS
  3. Changed musl toolchain to use add_link_options(-static) for proper propagation
  4. Added dcma_check_cgal_compatibility() to dcma_run_all_platform_checks()
  5. Lowered CMakePresets.json CMake version requirement from 3.21 to 3.12 to match project minimum
  6. Fixed backward compatibility by removing unused _SET suffix checks
  7. Fixed "dynamicly" typo to "dynamically"
  8. Changed -U_FORTIFY_SOURCE to use target_compile_options instead of target_compile_definitions

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants