Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,15 @@ jobs:
include:
- os: ubuntu-latest
CMAKE_ARGS: ""
CMAKE_VERSION: '3.29.x'
- os: macos-latest
CMAKE_ARGS: -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_C_COMPILER=clang -DCMAKE_OSX_DEPLOYMENT_TARGET=14
CMAKE_VERSION: '3.29.x'
- os: windows-latest
CMAKE_ARGS: -G"Visual Studio 17 2022" -A"x64"
# windows-latest is Windows Server 2025 + Visual Studio 2026 (since June 2026).
# The "Visual Studio 18 2026" generator requires CMake >= 4.2 (see CMAKE_VERSION below).
CMAKE_ARGS: -G"Visual Studio 18 2026" -A"x64"
CMAKE_VERSION: '4.3.x'
- os: ubuntu-24.04-arm
CMAKE_ARGS: ""

Expand All @@ -47,7 +52,7 @@ jobs:
if: ${{ !endsWith(matrix.os, '-arm') }}
uses: jwlawson/actions-setup-cmake@v2
with:
cmake-version: '3.29.x'
cmake-version: ${{ matrix.CMAKE_VERSION }}

- name: Install CMake (Ubuntu arm64)
if: ${{ endsWith(matrix.os, '-arm') }}
Expand Down
16 changes: 15 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,17 @@ set(ARCHIVE_ZLIB_SHA256 "9a93b2b7dfdac77ceba5a558a580e74667dd6fede4585b91eefb60f
set(ARCHIVE_BOOST boost-1.87.0.tar.gz)
set(ARCHIVE_BOOST_TAR boost-1.87.0.tar)
set(ARCHIVE_BOOST_SHA256 "73af4e4716603abd741fe43d1ab10dea4692975ba868160883d55a1dfc3b7d17")
if(MSVC)
## Windows builds Boost via its native CMake "superproject" (see libraries.cmake/boost.cmake),
## which requires the MODULAR source layout (libs/*/include + a top-level CMakeLists.txt). The
## canonical boost.org tarball above only ships the unified boost/ header tree, so on MSVC we
## use boostorg's dedicated "-cmake" release archive (mirrored to OpenMS/contrib-sources). It
## extracts to the same boost-1.87.0/ directory, so BOOST_DIR (set above) is unchanged. Unix
## keeps the unified tarball + b2 build untouched.
set(ARCHIVE_BOOST boost-1.87.0-cmake.tar.gz)
set(ARCHIVE_BOOST_TAR boost-1.87.0-cmake.tar)
set(ARCHIVE_BOOST_SHA256 "78fbf579e3caf0f47517d3fb4d9301852c3154bfecdc5eeebd9b2b0292366f5b")
endif()

set(ARCHIVE_XERCES Xerces-C_3_2_0.tar.gz)
set(ARCHIVE_XERCES_TAR Xerces-C_3_2_0.tar)
Expand Down Expand Up @@ -335,11 +346,14 @@ if (MSVC)
elseif (CMAKE_GENERATOR MATCHES ".*Visual Studio 17.*") ## VS2022
set(TMP_VS_VERSION "17")
set(TMP_MSVC_TOOLSET_VERSION "14.3")
elseif (CMAKE_GENERATOR MATCHES ".*Visual Studio 18.*") ## VS2026
set(TMP_VS_VERSION "18")
set(TMP_MSVC_TOOLSET_VERSION "14.5") ## v145 (MSVC 14.5x); ABI-compatible with the v14x family
else()
if (OVERRIDE_GENERATOR)
message(FATAL_ERROR "Chosen to override the Generator check, proceed with caution.")
else()
message(FATAL_ERROR "Please use 'Visual Studio ??' (??={14, 15, 16, 17}) as Generator - identical to the MSVC toolchain you plan to use for OpenMS! Note that you must not use NMake or alike for the contrib (nor for OpenMS). There will be errors (mostly missing libraries). Under very special circumstances, you can override this with -DOVERRIDE_GENERATOR=On.")
message(FATAL_ERROR "Please use 'Visual Studio ??' (??={14, 15, 16, 17, 18}) as Generator - identical to the MSVC toolchain you plan to use for OpenMS! Note that you must not use NMake or alike for the contrib (nor for OpenMS). There will be errors (mostly missing libraries). Under very special circumstances, you can override this with -DOVERRIDE_GENERATOR=On.")
endif()
endif()
## For coinor to find the correct names of the VS solutions
Expand Down
226 changes: 155 additions & 71 deletions libraries.cmake/boost.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -25,81 +25,165 @@ MACRO( OPENMS_CONTRIB_BUILD_BOOST)
set(_BOOST_PARALLEL_JOBS 2)
endif()

if(MSVC) ## build boost library for windows

## omitting the version (i.e. 'toolset=msvc'), causes Boost to use the latest(!) VS it can find the system -- irrespective of the current env (and its cl.exe)
set(TOOLSET "toolset=msvc-${CONTRIB_MSVC_TOOLSET_VERSION}")

if (NOT QUICKBUILD)
## not a Visual Studio project .. just build by hand
message(STATUS "Bootstrapping Boost libraries (bootstrap.bat) ...")
execute_process(COMMAND bootstrap.bat
if(MSVC) ## build boost library for windows (Boost CMake superproject)

## ------------------------------------------------------------------------
## Boost is built via its native CMake "superproject" (the boost-1.87.0
## archive ships tools/cmake + per-library CMakeLists.txt since 1.82) instead
## of bootstrap.bat + b2/bjam. This removes the Boost.Build engine bootstrap
## entirely, which is what breaks on Visual Studio 2026 (b2's build.bat does
## not know the vc145 toolset and aborts with "Unknown toolset: vcunk").
##
## We re-invoke cmake with the SAME generator + the SAME architecture token
## (${ARCHITECTURE_OPTION_CMAKE}, i.e. "-A;x64" / "-A;Win32") that the sibling
## nested builds zlib.cmake/bzip2.cmake already use. The MSVC toolset is thus
## inherited from the parent contrib configure (no toolset= pinning, no silent
## fallback to a newer VS than the active cl.exe), and the platform handling is
## byte-for-byte identical to the zlib/bzip2 trees Boost depends on.
## NOTE: we deliberately do NOT use CMAKE_GENERATOR_PLATFORM here -- it is never
## set anywhere in the contrib and would be passed as an empty "-A" argument.
##
## CRT contract: OpenMS uses the dynamic CRT (Boost_USE_STATIC_RUNTIME OFF in
## build_system_macros.cmake). We pin /MD,/MDd explicitly via
## CMAKE_MSVC_RUNTIME_LIBRARY so Boost matches regardless of BOOST_RUNTIME_LINK
## defaults; this reproduces the old "runtime-link=shared".
## ------------------------------------------------------------------------

## fresh out-of-source build dir for the nested configure
set(BOOST_CMAKE_BUILD_DIR "${BOOST_DIR}/build-openms")
file(MAKE_DIRECTORY "${BOOST_CMAKE_BUILD_DIR}")

## static libs by default; shared only if the contrib was asked for shared libs.
## BUILD_SHARED_LIBS is ORTHOGONAL to the CRT: static .lib + dynamic CRT (/MD)
## is exactly the old link=static + runtime-link=shared.
set(BOOST_BUILD_SHARED OFF)
if (BUILD_SHARED_LIBRARIES)
set(BOOST_BUILD_SHARED ON)
endif()

## NOTE: we build the FULL Boost (no BOOST_INCLUDE_LIBRARIES restriction). Downstream
## contrib consumers (Arrow + its bundled Thrift) and OpenMS itself pull in many
## header-only Boost libraries (uuid, multiprecision, locale, scope_exit, ...), so the
## install must carry the COMPLETE header tree -- exactly what the old b2 "install"
## produced. Restricting to a handful of libs only installs their headers and breaks
## those consumers. Python/MPI stay off (boost-cmake superproject defaults).

## ------------------------------------------------------------------------
## Boost.Iostreams compression backends: ALL OFF.
## A single nested configure cannot supply per-config (Debug /MDd vs Release
## /MD) external zlib/bzip2 to a multi-config VS generator -- find_package(ZLIB)
## / find_package(BZip2) inside Boost.Iostreams runs ONCE and would freeze one
## .lib path, mixing a Release /MD libbz2.lib into the Debug /MDd Boost build
## (the exact mixed-CRT corruption cmake_findExternalLibs.cmake warns against).
## This is behavior-equivalent for OpenMS: OpenMS uses no iostreams compression
## filter (only filtering_ostream + null_sink in src/topp/FileInfo.cpp) and
## links ZLIB::ZLIB / BZip2::BZip2 directly. (Subsumes the old NO_LZMA/NO_ZSTD.)
## ------------------------------------------------------------------------

message(STATUS "Configuring Boost (CMake superproject) .. ")
execute_process(COMMAND ${CMAKE_COMMAND}
-G "${CMAKE_GENERATOR}"
${ARCHITECTURE_OPTION_CMAKE}
-S "${BOOST_DIR}"
-B "${BOOST_CMAKE_BUILD_DIR}"
"-DCMAKE_INSTALL_PREFIX=${PROJECT_BINARY_DIR}"
## let an even-newer CMake still configure Boost 1.87's
## cmake_minimum_required(3.5...) (harmless otherwise)
-D CMAKE_POLICY_VERSION_MINIMUM=3.5
## pin dynamic CRT (/MD,/MDd), matching Boost_USE_STATIC_RUNTIME OFF
"-DCMAKE_MSVC_RUNTIME_LIBRARY=MultiThreaded$<$<CONFIG:Debug>:Debug>DLL"
## static .lib archives unless contrib was asked for shared
-D BUILD_SHARED_LIBS=${BOOST_BUILD_SHARED}
## dynamic CRT == old runtime-link=shared (belt-and-suspenders
## with CMAKE_MSVC_RUNTIME_LIBRARY above)
-D BOOST_RUNTIME_LINK=shared
## tagged lib names (-mt/-gd/-x64, no vcXXX) + flat include/boost
## dir == old --layout=tagged (cosmetic under CONFIG-mode consumption)
-D BOOST_INSTALL_LAYOUT=tagged
## BoostConfig.cmake -> ${PROJECT_BINARY_DIR}/lib/cmake/Boost-1.87.0
-D BOOST_INSTALL_CMAKEDIR=lib/cmake
## regex without ICU (== old --disable-icu): keep the COMPILED
## Boost::regex target but make find_package(ICU) impossible
-D BOOST_REGEX_STANDALONE=OFF
-D BOOST_LOCALE_ENABLE_ICU=OFF
-D CMAKE_DISABLE_FIND_PACKAGE_ICU=ON
"-DICU_ROOT=${PROJECT_BINARY_DIR}/no-icu"
## iostreams: all compression backends OFF (see comment above)
-D BOOST_IOSTREAMS_ENABLE_ZLIB=OFF
-D BOOST_IOSTREAMS_ENABLE_BZIP2=OFF
-D BOOST_IOSTREAMS_ENABLE_LZMA=OFF
-D BOOST_IOSTREAMS_ENABLE_ZSTD=OFF
WORKING_DIRECTORY ${BOOST_DIR}
OUTPUT_VARIABLE BOOST_CMAKE_OUT
ERROR_VARIABLE BOOST_CMAKE_ERR
RESULT_VARIABLE BOOST_CMAKE_SUCCESS)

file(APPEND ${LOGFILE} "${BOOST_CMAKE_OUT}")
file(APPEND ${LOGFILE} "${BOOST_CMAKE_ERR}")

if (NOT BOOST_CMAKE_SUCCESS EQUAL 0)
message(STATUS "Configuring Boost (CMake superproject) .. failed")
message(FATAL_ERROR "Configuring Boost failed:\n${BOOST_CMAKE_OUT}\n${BOOST_CMAKE_ERR}")
else()
message(STATUS "Configuring Boost (CMake superproject) .. done")
endif()

## Build + install BOTH Debug and Release into the SAME prefix (multi-config VS
## generator). This reproduces b2 --build-type=complete: the two install passes
## MERGE, so each per-component *-config.cmake imported target carries both
## IMPORTED_LOCATION_DEBUG (the -gd libs) and IMPORTED_LOCATION_RELEASE, and
## config-mode find_package picks the right variant per consumer. Do NOT prune
## either config: dropping Debug breaks Debug OpenMS builds (missing -mt-gd libs).
foreach(_BOOST_CFG Debug Release)
message(STATUS "Building Boost library (${_BOOST_CFG}) .. ")
execute_process(COMMAND ${CMAKE_COMMAND} --build "${BOOST_CMAKE_BUILD_DIR}"
--config ${_BOOST_CFG}
-j ${_BOOST_PARALLEL_JOBS}
WORKING_DIRECTORY ${BOOST_DIR}
OUTPUT_VARIABLE BOOST_BOOTSTRAP_OUT
ERROR_VARIABLE BOOST_BOOTSTRAP_OUT # use same variable for stderr as stdout to merge streams
RESULT_VARIABLE BOOST_BOOTSTRAP_SUCCESS)

file(APPEND ${LOGFILE} ${BOOST_BOOTSTRAP_OUT})

## check for failed bootstrapping. Even if failing the return code can be 0 (indicating success), so we additionally check the output
if ((NOT BOOST_BOOTSTRAP_SUCCESS EQUAL 0) OR (BOOST_BOOTSTRAP_OUT MATCHES "[fF]ailed"))
message(STATUS "Bootstrapping Boost libraries (bootstrap.bat) ... failed\nOutput was:\n ${BOOST_BOOTSTRAP_OUT}\nEnd of output.\n")
message(STATUS "Renaming bootstrap.log to bootstrap_firstTry.log")
file(RENAME ${BOOST_DIR}/bootstrap.log ${BOOST_DIR}/bootstrap_firstTry.log)
### on some command lines bootstrapping fail (e.g. the toolset is too new) or will give:
# "Building Boost.Build engine. The input line is too long."
## ,thus we provide a backup bjam.exe(32bit), which hopefully works on all target systems.
## However this bjam results in a version mismatch and a warning (that you can ignore).
message(STATUS " ... trying fallback with backup bjam.exe ...")
configure_file("${PROJECT_SOURCE_DIR}/patches/boost/bjam.exe" "${BOOST_DIR}/bjam.exe" COPYONLY)
OUTPUT_VARIABLE BOOST_BUILD_OUT
ERROR_VARIABLE BOOST_BUILD_ERR
RESULT_VARIABLE BOOST_BUILD_SUCCESS)

file(APPEND ${LOGFILE} "${BOOST_BUILD_OUT}")
file(APPEND ${LOGFILE} "${BOOST_BUILD_ERR}")

if (NOT BOOST_BUILD_SUCCESS EQUAL 0)
message(STATUS "Building Boost library (${_BOOST_CFG}) .. failed")
message(FATAL_ERROR "Building Boost (${_BOOST_CFG}) failed:\n${BOOST_BUILD_OUT}\n${BOOST_BUILD_ERR}")
else()
message(STATUS "Bootstrapping Boost libraries (bootstrap.bat) ... done")
message(STATUS "Building Boost library (${_BOOST_CFG}) .. done")
endif()

set(BOOST_CMD_ARGS "${BOOST_ARG}"
"-j" "${_BOOST_PARALLEL_JOBS}"
"install"
"--prefix=${PROJECT_BINARY_DIR}"
"--layout=tagged" # create libnames without vcXXX in filename; include dir is /include/boost (as opposed to "versioned" where /include/boost-1.52/boost plus ...vc110.lib
"--with-filesystem"
"--with-math"
"--with-date_time"
"--with-iostreams"
"--with-regex"
"--with-system"
"--with-thread"
"--build-type=complete"
"--disable-icu"
"-s"
"NO_LZMA=1"
"-s"
"NO_ZSTD=1"
"runtime-link=shared"
"link=${BOOST_BUILD_TYPE}"
"${TOOLSET}")

## WARNING: boost call is not "space in path" save yet (the easy way of using \" does not work out of the box
message(STATUS "Building Boost library (bjam ${BOOST_CMD_ARGS}) .. ")
execute_process(COMMAND b2.exe ${BOOST_CMD_ARGS}
WORKING_DIRECTORY ${BOOST_DIR}
OUTPUT_VARIABLE BUILD_BOOST_OUT
ERROR_VARIABLE BUILD_BOOST_ERR
RESULT_VARIABLE BUILD_BOOST)

# output to logfile
file(APPEND ${LOGFILE} ${BUILD_BOOST_OUT})

if (NOT BUILD_BOOST EQUAL 0)
message(STATUS "Building Boost library (bjam ${BOOST_CMD_ARGS}) .. failed")
message(STATUS "BUILD_BOOST_OUT = ${BUILD_BOOST_OUT}")
message(STATUS "BUILD_BOOST_ERR = ${BUILD_BOOST_ERR}")
message(STATUS "BUILD_BOOST = ${BUILD_BOOST}")
message(FATAL_ERROR ${BUILD_BOOST_OUT})
else()
message(STATUS "Building Boost library (bjam ${BOOST_CMD_ARGS}) .. done")
endif()

endif() ## end quickbuild
message(STATUS "Installing Boost library (${_BOOST_CFG}) .. ")
execute_process(COMMAND ${CMAKE_COMMAND} --install "${BOOST_CMAKE_BUILD_DIR}"
--config ${_BOOST_CFG}
WORKING_DIRECTORY ${BOOST_DIR}
OUTPUT_VARIABLE BOOST_INSTALL_OUT
ERROR_VARIABLE BOOST_INSTALL_ERR
RESULT_VARIABLE BOOST_INSTALL_SUCCESS)

file(APPEND ${LOGFILE} "${BOOST_INSTALL_OUT}")
file(APPEND ${LOGFILE} "${BOOST_INSTALL_ERR}")

if (NOT BOOST_INSTALL_SUCCESS EQUAL 0)
message(STATUS "Installing Boost library (${_BOOST_CFG}) .. failed")
message(FATAL_ERROR "Installing Boost (${_BOOST_CFG}) failed:\n${BOOST_INSTALL_OUT}\n${BOOST_INSTALL_ERR}")
else()
message(STATUS "Installing Boost library (${_BOOST_CFG}) .. done")
endif()
endforeach()

## Fail LOUDLY at contrib-build time (not later at OpenMS configure) if the
## a core compiled component failed to install: assert each
## expected per-component config dir exists under the install prefix.
foreach(_BOOST_COMP date_time iostreams regex system thread)
file(GLOB _BOOST_COMP_CFG "${PROJECT_BINARY_DIR}/lib/cmake/boost_${_BOOST_COMP}-*")
if (NOT _BOOST_COMP_CFG)
message(FATAL_ERROR "Boost component '${_BOOST_COMP}' did not install a CMake config dir "
"under ${PROJECT_BINARY_DIR}/lib/cmake/boost_${_BOOST_COMP}-* -- "
"the Boost build is incomplete.")
endif()
endforeach()
Comment on lines +176 to +186

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Missing math component in post-install verification.

The verification loop checks only 5 of the 6 compiled components. math is listed in _BOOST_LIBS (line 69) but is missing from the verification foreach at line 182.

If Boost.Math fails to install its CMake config, this check won't catch it at contrib-build time, defeating the stated purpose of failing loudly here rather than later at OpenMS configure.

Proposed fix
-    foreach(_BOOST_COMP date_time iostreams regex system thread)
+    foreach(_BOOST_COMP math date_time iostreams regex system thread)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@libraries.cmake/boost.cmake` around lines 179 - 189, The verification loop
iterating over Boost components is missing the math component that is included
in the _BOOST_LIBS list. Add math to the foreach loop that iterates over the
components (date_time, iostreams, regex, system, thread) to ensure that if
Boost.Math fails to install its CMake config, the check will catch it at
contrib-build time as intended.


else() ## LINUX/MAC

Expand Down
17 changes: 16 additions & 1 deletion libraries.cmake/coinor.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,22 @@ MACRO( OPENMS_CONTRIB_BUILD_COINOR)
set(ENV{WindowsSDKVersion} "10.0.17763.0") # fallback, just to have a value. If this is incorrect, at least VS will tell you what to use
endif()

set(MSBUILD_ARGS_SLN "${COINOR_DIR}/CoinMP/MSVisualStudio/v${CONTRIB_VS_VERSION}/CoinMP.sln")
## The vendored CoinMP archive (CoinMP-1.8.3-vs22) ships MSBuild solution/project files only
## up to v17 (VS2022). Newer Visual Studio toolchains share the v14x ABI and are binary
## compatible, so for VS2026 (v18) and beyond we reuse the v17 solution and let MSBuild
## retarget the PlatformToolset to the toolchain actually installed (see CONTRIB_MSBUILD_PLATFORMTOOLSET
## below, which OPENMS_BUILDLIB passes to MSBuild as /p:PlatformToolset).
set(_COINMP_SLN_VERSION ${CONTRIB_VS_VERSION})
set(CONTRIB_MSBUILD_PLATFORMTOOLSET "")
if (CONTRIB_VS_VERSION GREATER 17)
set(_COINMP_SLN_VERSION 17)
## derive e.g. "14.5" -> "v145"
string(REPLACE "." "" _COINMP_TOOLSET_DIGITS "${CONTRIB_MSVC_TOOLSET_VERSION}")
set(CONTRIB_MSBUILD_PLATFORMTOOLSET "v${_COINMP_TOOLSET_DIGITS}")
message(STATUS "CoinMP: reusing the v17 (VS2022) solution and retargeting PlatformToolset to ${CONTRIB_MSBUILD_PLATFORMTOOLSET}")
endif()

set(MSBUILD_ARGS_SLN "${COINOR_DIR}/CoinMP/MSVisualStudio/v${_COINMP_SLN_VERSION}/CoinMP.sln")
set(MSBUILD_ARGS_TARGET "libCbc")
OPENMS_BUILDLIB("CoinOR-Cbc (Debug)" MSBUILD_ARGS_SLN MSBUILD_ARGS_TARGET "Debug" COINOR_DIR)
OPENMS_BUILDLIB("CoinOR-Cbc (Release)" MSBUILD_ARGS_SLN MSBUILD_ARGS_TARGET "Release" COINOR_DIR)
Expand Down
6 changes: 6 additions & 0 deletions macros.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,12 @@ MACRO ( OPENMS_BUILDLIB libname solutionfile_varname target_varname config worki
if(NOT CONTRIB_MSVC_VERSION STREQUAL "8")
list(APPEND MSBUILD_ARGS /maxcpucount)
endif()
## Retarget the solution's PlatformToolset when we reuse an older solution on a newer
## Visual Studio (e.g. the v17 CoinMP solution on VS2026). The command-line global property
## overrides the <PlatformToolset> pinned in every vcxproj of the solution.
if(DEFINED CONTRIB_MSBUILD_PLATFORMTOOLSET AND NOT CONTRIB_MSBUILD_PLATFORMTOOLSET STREQUAL "")
list(APPEND MSBUILD_ARGS /p:PlatformToolset=${CONTRIB_MSBUILD_PLATFORMTOOLSET})
endif()

execute_process(
COMMAND ${MSBUILD_EXECUTABLE} ${MSBUILD_ARGS}
Expand Down
Loading