From fbae71964a4d5c7c6aebc9d49b0d638efb6976b0 Mon Sep 17 00:00:00 2001 From: Peter Feerick Date: Tue, 1 Sep 2026 15:59:02 +1000 Subject: [PATCH] chore(cpn): guard the macOS bundle's minimum system version (#7740) Co-authored-by: Claude Opus 5 --- CMakeLists.txt | 2 + cmake/Macros.cmake | 5 ++- cmake/wasm/CMakeLists.txt | 1 + .../targets/mac/MacOSXBundleInfo.plist.in | 2 + companion/targets/mac/bundle_verify.cmake.in | 42 ++++++++++++++++++- tools/build-companion.sh | 3 +- 6 files changed, 52 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 0655d8c0d..3b5fbf706 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -61,6 +61,7 @@ if(EdgeTX_SUPERBUILD) ExternalProject_Add(native SOURCE_DIR ${CMAKE_SOURCE_DIR} BINARY_DIR ${CMAKE_BINARY_DIR}/native + LIST_SEPARATOR | CMAKE_ARGS ${CMAKE_ARGS} -Wno-dev -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} CMAKE_CACHE_ARGS -DCMAKE_TOOLCHAIN_FILE:FILEPATH=${CMAKE_SOURCE_DIR}/cmake/toolchain/native.cmake @@ -75,6 +76,7 @@ if(EdgeTX_SUPERBUILD) ExternalProject_Add(arm-none-eabi SOURCE_DIR ${CMAKE_SOURCE_DIR} BINARY_DIR ${CMAKE_BINARY_DIR}/arm-none-eabi + LIST_SEPARATOR | CMAKE_ARGS ${CMAKE_ARGS} -Wno-dev -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} CMAKE_CACHE_ARGS -DCMAKE_TOOLCHAIN_FILE:FILEPATH=${CMAKE_SOURCE_DIR}/cmake/toolchain/arm-none-eabi.cmake diff --git a/cmake/Macros.cmake b/cmake/Macros.cmake index 6f6d2978e..b5228f362 100644 --- a/cmake/Macros.cmake +++ b/cmake/Macros.cmake @@ -171,7 +171,10 @@ function(CollectCommandLineArgs out_var) else() set(_type :${_type}) endif() - list(APPEND _args "-D${_var}${_type}=${${_var}}") + # Escape CMake's ';' so a multi-path value (CMAKE_PREFIX_PATH) stays one argument + # instead of splitting; callers pair this with LIST_SEPARATOR | to restore it. + string(REPLACE ";" "|" _value "${${_var}}") + list(APPEND _args "-D${_var}${_type}=${_value}") endif() endforeach() set(${out_var} ${_args} PARENT_SCOPE) diff --git a/cmake/wasm/CMakeLists.txt b/cmake/wasm/CMakeLists.txt index 1562abe25..18b6ff6c5 100644 --- a/cmake/wasm/CMakeLists.txt +++ b/cmake/wasm/CMakeLists.txt @@ -25,6 +25,7 @@ include(ExternalProject) ExternalProject_Add(wasm SOURCE_DIR ${EDGETX_SOURCE_DIR} BINARY_DIR ${CMAKE_BINARY_DIR}/wasm-build + LIST_SEPARATOR | CMAKE_ARGS ${_forwarded_args} -Wno-dev diff --git a/companion/targets/mac/MacOSXBundleInfo.plist.in b/companion/targets/mac/MacOSXBundleInfo.plist.in index 820532155..94fa7dfe2 100644 --- a/companion/targets/mac/MacOSXBundleInfo.plist.in +++ b/companion/targets/mac/MacOSXBundleInfo.plist.in @@ -34,6 +34,8 @@ + LSMinimumSystemVersion + ${CMAKE_OSX_DEPLOYMENT_TARGET} NSPrincipalClass NSApplication NSHighResolutionCapable diff --git a/companion/targets/mac/bundle_verify.cmake.in b/companion/targets/mac/bundle_verify.cmake.in index 8b0102937..63825f37e 100644 --- a/companion/targets/mac/bundle_verify.cmake.in +++ b/companion/targets/mac/bundle_verify.cmake.in @@ -27,7 +27,10 @@ endif() file(GLOB_RECURSE _candidates "${_app}/Contents/*") set(_offenders "") +set(_toonew "") set(_checked 0) +set(_max_minos "0.0") +set(_target_minos "@CMAKE_OSX_DEPLOYMENT_TARGET@") foreach(_file IN LISTS _candidates) if(IS_SYMLINK "${_file}" OR IS_DIRECTORY "${_file}") continue() @@ -45,6 +48,30 @@ foreach(_file IN LISTS _candidates) endif() math(EXPR _checked "${_checked} + 1") + # macOS refuses to launch an app stamped above the running system - that is how 2.12.3 + # became "requires macOS 15.0 or later" (issue #7732). + execute_process( + COMMAND otool -l "${_file}" + OUTPUT_VARIABLE _otool_l_out + ERROR_QUIET + RESULT_VARIABLE _otool_l_res + ) + # MATCHALL, not MATCHES: a universal binary reports one minos per slice and any of them + # can be the one that is wrong. + if(_otool_l_res EQUAL 0) + string(REGEX MATCHALL "minos [0-9]+(\.[0-9]+)+" _minos_all "${_otool_l_out}") + foreach(_entry IN LISTS _minos_all) + string(REPLACE "minos " "" _minos "${_entry}") + if(_minos VERSION_GREATER _max_minos) + set(_max_minos "${_minos}") + endif() + if(_target_minos AND _minos VERSION_GREATER _target_minos) + file(RELATIVE_PATH _rel "${_app}" "${_file}") + list(APPEND _toonew "${_rel}: minos ${_minos}") + endif() + endforeach() + endif() + string(REPLACE "\n" ";" _lines "${_otool_out}") foreach(_line IN LISTS _lines) string(REGEX MATCH "^\t([^ ]+)" _matched "${_line}") @@ -77,7 +104,20 @@ if(_offenders) "Re-run with -DCOMPANION_VERIFY_BUNDLE=OFF to package anyway.") endif() -message(STATUS "Bundle verification: ${_checked} Mach-O files, no external references") +if(_toonew) + list(REMOVE_DUPLICATES _toonew) + string(REPLACE ";" "\n " _report "${_toonew}") + message(FATAL_ERROR + "Bundle contains Mach-O files built for a newer macOS than the deployment target " + "(${_target_minos}) - macOS refuses to launch an app stamped above the running " + "system:\n ${_report}\n" + "Re-run with -DCOMPANION_VERIFY_BUNDLE=OFF to package anyway.") +endif() + +# CPack discards message(STATUS) from install scripts, so echo via a subprocess - otherwise +# the bundle's real macOS floor never reaches the packaging log. +execute_process(COMMAND ${CMAKE_COMMAND} -E echo + "-- Bundle verification: ${_checked} Mach-O files, no external references, minimum macOS ${_max_minos}") # The bundle seal is a separate concern from the per-Mach-O signatures: dyld does not consult # CodeResources when loading, so a stale seal does not stop the app launching. It would matter diff --git a/tools/build-companion.sh b/tools/build-companion.sh index eda29d309..1bd5485d3 100755 --- a/tools/build-companion.sh +++ b/tools/build-companion.sh @@ -30,8 +30,9 @@ else fi COMMON_OPTIONS="${COMMON_OPTIONS} -DCMAKE_BUILD_TYPE=Release -DCMAKE_MESSAGE_LOG_LEVEL=WARNING -Wno-dev" +# Qt 6.9's frameworks are macOS 12, so the bundle cannot start below that anyway. if [ "$(uname)" = "Darwin" ]; then - COMMON_OPTIONS="${COMMON_OPTIONS} -DCMAKE_OSX_DEPLOYMENT_TARGET='11.0'" + COMMON_OPTIONS="${COMMON_OPTIONS} -DCMAKE_OSX_DEPLOYMENT_TARGET='12.0'" fi # find_package(... CONFIG) skips the lib/cmake/ search pattern for prefixes that only