diff --git a/.github/workflows/build_release.yml b/.github/workflows/build_release.yml index 0ecc1c5fbb..dcd45558b6 100644 --- a/.github/workflows/build_release.yml +++ b/.github/workflows/build_release.yml @@ -95,8 +95,9 @@ jobs: include: - { target: linux-64, os: ubuntu-22.04 } - { target: linux-arm64, os: ubuntu-22.04-arm } - - { target: osx-64, os: macos-15-intel } - - { target: osx-arm64, os: macos-latest } + - { target: osx-64, os: macos-15-intel, deploy_target: "10.13" } + - { target: osx-arm64, os: macos-latest, deploy_target: "11.0" } + - { target: osx-arm64, os: macos-latest, deploy_target: "15.0" } - { target: win-64, os: windows-latest } fail-fast: false @@ -196,6 +197,9 @@ jobs: UPLOAD_RELEASE: "true" BUILD_TAG: ${{ needs.upload_src.outputs.build_tag }} run: | + if [[ "${{ runner.os }}" == "macOS" ]]; then + export MACOS_DEPLOYMENT_TARGET="${{ matrix.deploy_target }}" + fi python3 package/scripts/write_version_info.py ../freecad_version.txt cd package/rattler-build pixi install diff --git a/package/rattler-build/build.sh b/package/rattler-build/build.sh index d90976bc00..7367530ff9 100644 --- a/package/rattler-build/build.sh +++ b/package/rattler-build/build.sh @@ -8,7 +8,9 @@ if [[ ${HOST} =~ .*darwin.* ]]; then # add hacks for osx here! echo "adding hacks for osx" - # install space-mouse + # Install 3DConnexion (SpaceMouse) driver + # Note: For local builds, comment out the following lines if you encounter issues + # installing the driver or don't need SpaceMouse support /usr/bin/curl -o /tmp/3dFW.dmg -L 'https://download.3dconnexion.com/drivers/mac/10-7-0_B564CC6A-6E81-42b0-82EC-418EA823B81A/3DxWareMac_v10-7-0_r3411.dmg' hdiutil attach -readonly /tmp/3dFW.dmg sudo installer -package /Volumes/3Dconnexion\ Software/Install\ 3Dconnexion\ software.pkg -target / @@ -17,6 +19,31 @@ if [[ ${HOST} =~ .*darwin.* ]]; then CMAKE_PLATFORM_FLAGS+=(-D3DCONNEXIONCLIENT_FRAMEWORK:FILEPATH="/Library/Frameworks/3DconnexionClient.framework") CXXFLAGS="${CXXFLAGS} -D_LIBCPP_DISABLE_AVAILABILITY" + + # Use MACOS_DEPLOYMENT_TARGET from environment, default to 11.0 for backwards compat. + # Note that CI sets this per target: 10.13 (Intel), 11.0 (ARM legacy), 15.0 (ARM modern) + # - macOS 10.13+ Intel: legacy QuickLook generator (.qlgenerator) + # - macOS 11-14 ARM: legacy QuickLook generator (.qlgenerator) + # - macOS 15+ ARM: modern QuickLook App Extensions (.appex) + DEPLOY_TARGET="${MACOS_DEPLOYMENT_TARGET:-11.0}" + CMAKE_PLATFORM_FLAGS+=(-DCMAKE_OSX_DEPLOYMENT_TARGET=${DEPLOY_TARGET}) + + # Patch Qt6's FindWrapOpenGL.cmake to not link AGL on macOS 10.15+ + # AGL framework was removed in macOS 10.15 Catalina and Qt6's cmake + # unconditionally tries to link it on Apple platforms, causing build failures. + # Only apply this patch for deployment targets >= 10.15. + # See: https://github.com/conda-forge/qt-main-feedstock/issues/240 + DEPLOY_MAJOR=$(echo "$DEPLOY_TARGET" | cut -d. -f1) + DEPLOY_MINOR=$(echo "$DEPLOY_TARGET" | cut -d. -f2) + if [[ "$DEPLOY_MAJOR" -gt 10 ]] || [[ "$DEPLOY_MAJOR" -eq 10 && "$DEPLOY_MINOR" -ge 15 ]]; then + FIND_WRAP_OPENGL="$PREFIX/lib/cmake/Qt6/FindWrapOpenGL.cmake" + if [[ -f "$FIND_WRAP_OPENGL" ]]; then + echo "Patching Qt6 FindWrapOpenGL.cmake to remove AGL linkage (not available on macOS 10.15+)..." + sed -i.bak \ + -e '/find_library(WrapOpenGL_AGL/,/target_link_libraries.*__opengl_agl_fw_path/d' \ + "$FIND_WRAP_OPENGL" + fi + fi fi unset CMAKE_GENERATOR @@ -24,6 +51,7 @@ unset CMAKE_GENERATOR_PLATFORM cmake \ ${CMAKE_ARGS} \ + ${CMAKE_PLATFORM_FLAGS[@]} \ --preset ${CMAKE_PRESET} \ -D CMAKE_IGNORE_PREFIX_PATH="/opt/homebrew;/usr/local/homebrew" \ -D CMAKE_INCLUDE_PATH:FILEPATH="$PREFIX/include" \ diff --git a/package/rattler-build/osx/create_bundle.sh b/package/rattler-build/osx/create_bundle.sh index 7872126c24..54d7739d7e 100644 --- a/package/rattler-build/osx/create_bundle.sh +++ b/package/rattler-build/osx/create_bundle.sh @@ -48,7 +48,11 @@ mkdir -p FreeCAD.app/Contents/MacOS cp build/FreeCAD FreeCAD.app/Contents/MacOS/FreeCAD python_version=$(${conda_env}/bin/python -c 'import platform; print("py" + platform.python_version_tuple()[0] + platform.python_version_tuple()[1])') -version_name="FreeCAD_${BUILD_TAG}-macOS-$(uname -m)-${python_version}" + +# Add deployment target suffix to artifact name (e.g., "-macOS11" or "-macOS15") +deploy_target="${MACOS_DEPLOYMENT_TARGET:-11.0}" +deploy_suffix="-macOS${deploy_target%%.*}" +version_name="FreeCAD_${BUILD_TAG}-macOS-$(uname -m)${deploy_suffix}-${python_version}" application_menu_name="FreeCAD_${BUILD_TAG}" echo -e "\################" @@ -62,14 +66,37 @@ sed -i "s/APPLICATION_MENU_NAME/${application_menu_name}/" ${conda_env}/../Info. pixi list -e default > FreeCAD.app/Contents/packages.txt sed -i '1s/.*/\nLIST OF PACKAGES:/' FreeCAD.app/Contents/packages.txt -# copy the plugin into its final location -cp -a ${conda_env}/Library ${conda_env}/.. -rm -rf ${conda_env}/Library +# move plugins into their final location (Library only exists for macOS < 15.0 builds) +if [ -d "${conda_env}/Library" ]; then + mv ${conda_env}/Library ${conda_env}/.. +fi + +# move App Extensions (PlugIns) to the correct location for macOS registration +if [ -d "${conda_env}/PlugIns" ]; then + mv ${conda_env}/PlugIns ${conda_env}/.. +fi if [[ "${SIGN_RELEASE}" == "true" ]]; then # create the signed dmg ../../scripts/macos_sign_and_notarize.zsh -p "FreeCAD" -k ${SIGNING_KEY_ID} -o "${version_name}.dmg" else + # Ad-hoc sign for local builds (required for QuickLook extensions to register) + if [ -d "FreeCAD.app/Contents/PlugIns" ]; then + echo "Ad-hoc signing App Extensions with entitlements..." + codesign --force --sign - \ + --entitlements ../../../src/MacAppBundle/QuickLook/modern/ThumbnailExtension.entitlements \ + FreeCAD.app/Contents/PlugIns/FreeCADThumbnailExtension.appex + codesign --force --sign - \ + --entitlements ../../../src/MacAppBundle/QuickLook/modern/PreviewExtension.entitlements \ + FreeCAD.app/Contents/PlugIns/FreeCADPreviewExtension.appex + fi + echo "Ad-hoc signing app bundle..." + codesign --force --sign - FreeCAD.app/Contents/packages.txt + if [ -f "FreeCAD.app/Contents/Library/QuickLook/QuicklookFCStd.qlgenerator/Contents/MacOS/QuicklookFCStd" ]; then + codesign --force --sign - FreeCAD.app/Contents/Library/QuickLook/QuicklookFCStd.qlgenerator/Contents/MacOS/QuicklookFCStd + fi + codesign --force --sign - FreeCAD.app + # create the dmg dmgbuild -s dmg_settings.py "FreeCAD" "${version_name}.dmg" fi diff --git a/package/rattler-build/osx/launcher/CMakeLists.txt b/package/rattler-build/osx/launcher/CMakeLists.txt index 222fd17559..bba802978b 100644 --- a/package/rattler-build/osx/launcher/CMakeLists.txt +++ b/package/rattler-build/osx/launcher/CMakeLists.txt @@ -1,7 +1,12 @@ cmake_minimum_required(VERSION 3.20) project(freecad-launcher LANGUAGES CXX) -set(CMAKE_OSX_DEPLOYMENT_TARGET "10.13" CACHE STRING "Minimum OS X deployment version" FORCE) +# Use MACOS_DEPLOYMENT_TARGET from environment if set, otherwise keep original default +if(DEFINED ENV{MACOS_DEPLOYMENT_TARGET}) + set(CMAKE_OSX_DEPLOYMENT_TARGET "$ENV{MACOS_DEPLOYMENT_TARGET}" CACHE STRING "Minimum OS X deployment version" FORCE) +else() + set(CMAKE_OSX_DEPLOYMENT_TARGET "10.13" CACHE STRING "Minimum OS X deployment version" FORCE) +endif() set(CMAKE_CXX_STANDARD 17) add_executable(FreeCAD FreeCAD.cpp) diff --git a/package/scripts/macos_sign_and_notarize.zsh b/package/scripts/macos_sign_and_notarize.zsh index e1e2deeaa0..a5da837d10 100755 --- a/package/scripts/macos_sign_and_notarize.zsh +++ b/package/scripts/macos_sign_and_notarize.zsh @@ -123,7 +123,11 @@ done # Two additional files that must be signed that aren't caught by the above searches: run_codesign "${CONTAINING_FOLDER}/${APP_NAME}/Contents/packages.txt" -run_codesign "${CONTAINING_FOLDER}/${APP_NAME}/Contents/Library/QuickLook/QuicklookFCStd.qlgenerator/Contents/MacOS/QuicklookFCStd" + +# Sign legacy QuickLook generator if present (not built for macOS 15.0+) +if [ -f "${CONTAINING_FOLDER}/${APP_NAME}/Contents/Library/QuickLook/QuicklookFCStd.qlgenerator/Contents/MacOS/QuicklookFCStd" ]; then + run_codesign "${CONTAINING_FOLDER}/${APP_NAME}/Contents/Library/QuickLook/QuicklookFCStd.qlgenerator/Contents/MacOS/QuicklookFCStd" +fi # Sign new Swift QuickLook extensions (macOS 15.0+) with their specific entitlements # These must be signed before the app itself to avoid overriding the extension signatures diff --git a/src/MacAppBundle/QuickLook/CMakeLists.txt b/src/MacAppBundle/QuickLook/CMakeLists.txt index 3b15d0a35f..e616474f48 100644 --- a/src/MacAppBundle/QuickLook/CMakeLists.txt +++ b/src/MacAppBundle/QuickLook/CMakeLists.txt @@ -49,8 +49,12 @@ if(FREECAD_QUICKLOOK_MODERN_SUPPORT) endif() if(FREECAD_QUICKLOOK_LEGACY_SUPPORT) - set(BUILD_LEGACY_GENERATOR ON) - message(STATUS "Building legacy .qlgenerator QuickLook support") + if(CMAKE_OSX_DEPLOYMENT_TARGET VERSION_LESS "15.0") + set(BUILD_LEGACY_GENERATOR ON) + message(STATUS "Building legacy .qlgenerator QuickLook support") + else() + message(STATUS "Skipping legacy .qlgenerator (not needed for macOS 15.0+)") + endif() endif() if(NOT BUILD_MODERN_EXTENSIONS AND NOT BUILD_LEGACY_GENERATOR) diff --git a/src/MacAppBundle/QuickLook/legacy/CMakeLists.txt b/src/MacAppBundle/QuickLook/legacy/CMakeLists.txt index c083af31c0..c2697ba086 100644 --- a/src/MacAppBundle/QuickLook/legacy/CMakeLists.txt +++ b/src/MacAppBundle/QuickLook/legacy/CMakeLists.txt @@ -10,10 +10,10 @@ cmake_minimum_required(VERSION 3.22) set(TARGET_APP_BUNDLE "${CMAKE_BINARY_DIR}/src/MacAppBundle/FreeCAD.app") set(LEGACY_QUICKLOOK_DIR "${TARGET_APP_BUNDLE}/Contents/Library/QuickLook") -# Build legacy QuickLook generator using traditional CMake approach +# Build legacy QuickLook generator as a proper macOS plugin bundle add_library( QuicklookFCStd - SHARED + MODULE GeneratePreviewForURL.m GenerateThumbnailForURL.m main.c @@ -22,8 +22,9 @@ add_library( set_target_properties( QuicklookFCStd PROPERTIES - FRAMEWORK TRUE - MACOSX_FRAMEWORK_INFO_PLIST "${CMAKE_CURRENT_SOURCE_DIR}/QuicklookFCStd.qlgenerator/Contents/Info.plist" + BUNDLE TRUE + BUNDLE_EXTENSION "qlgenerator" + MACOSX_BUNDLE_INFO_PLIST "${CMAKE_CURRENT_SOURCE_DIR}/QuicklookFCStd.qlgenerator/Contents/Info.plist" ) target_link_libraries(