diff --git a/.github/actions/get-workflow-artifact-ids/action.yml b/.github/actions/get-workflow-artifact-ids/action.yml new file mode 100644 index 000000000000..56af5f67b209 --- /dev/null +++ b/.github/actions/get-workflow-artifact-ids/action.yml @@ -0,0 +1,34 @@ +name: 'Get Workflow Artifact IDs' +description: 'Generates consistent artifact IDs and names based on workflow trigger' + +outputs: + filename: + description: 'Filename to use for artifacts (e.g. pr123)' + value: ${{ steps.generate-ids.outputs.filename }} + display-name: + description: 'Human readable name (e.g. PR123)' + value: ${{ steps.generate-ids.outputs.display_name }} + +runs: + using: "composite" + steps: + - id: generate-ids + shell: bash + run: | + if [ "${{ github.event_name }}" = "pull_request" ]; then + ID="pr${{ github.event.pull_request.number }}" + DISPLAY_ID="PR${{ github.event.pull_request.number }}" + elif [[ "${{ github.ref }}" == refs/tags/* ]]; then + TAG=${GITHUB_REF#refs/tags/} + ID="$TAG" + DISPLAY_ID="$TAG" + else + SHORT_SHA=$(echo ${{ github.sha }} | cut -c1-7) + BRANCH_NAME=${GITHUB_REF#refs/heads/} + ID="$BRANCH_NAME-$SHORT_SHA" + DISPLAY_ID="$BRANCH_NAME build $SHORT_SHA" + fi + + # Set outputs + echo "filename=$ID" >> $GITHUB_OUTPUT + echo "display_name=$DISPLAY_ID" >> $GITHUB_OUTPUT diff --git a/.github/workflows/build-macos-qt6.yml b/.github/workflows/build-macos-qt6.yml index 4edf1d8280ec..d6fa2bc0e8e9 100644 --- a/.github/workflows/build-macos-qt6.yml +++ b/.github/workflows/build-macos-qt6.yml @@ -1,12 +1,13 @@ --- name: 🍎 Build - MacOS Qt6 on: - # push: - # branches: - # - main - # pull_request: - # release: - # types: ['published'] + push: + branches: + - master + - release-* + pull_request: + release: + types: ['published'] workflow_dispatch: concurrency: @@ -18,9 +19,9 @@ jobs: strategy: matrix: include: -# - os: macos-13 -# triplet: x64-osx -# deployment-target: "10.15" + - os: macos-13 + triplet: x64-osx-dynamic-release + deployment-target: "10.15" - os: macos-14 triplet: arm64-osx-dynamic-release deployment-target: "11.0" @@ -42,9 +43,13 @@ jobs: id: setup-vcpkg uses: ./.github/actions/setup-vcpkg + - name: 🎲 Get artifact ids + id: workflow-artifact-ids + uses: ./.github/actions/get-workflow-artifact-ids + - name: πŸ”¨ Prepare build env run: | - brew install automake bison flex gnu-sed create-dmg autoconf-archive nasm libtool fdupes + brew install automake bison flex gnu-sed autoconf-archive nasm libtool fdupes echo $(brew --prefix bison)/bin >> $GITHUB_PATH echo $(brew --prefix flex)/bin >> $GITHUB_PATH echo $(brew --prefix libtool)/bin >> $GITHUB_PATH @@ -58,6 +63,19 @@ jobs: with: xcode-version: latest-stable + - name: πŸ›οΈ Setup ccache + uses: hendrikmuhs/ccache-action@v1.2 + with: + max-size: 500M + key: build-ccache-win64-qt6-${{Β github.event.pull_request.base.ref || github.ref_name }} +# save: ${{ github.event_name == 'push' }} + + - name: πŸ›οΈ Tune ccache configuration + shell: bash + run: | + # To make ccache work properly with precompiled headers + ccache --set-config sloppiness=pch_defines,time_macros,include_file_mtime,include_file_ctime + - name: 🌱 Install dependencies and generate project files run: | echo "VCPKG_ROOT: ${VCPKG_ROOT}" @@ -67,18 +85,20 @@ jobs: cmake -S . \ -G Ninja \ -B build \ + -D QGIS_APP_NAME="QGIS-${{steps.workflow-artifact-ids.outputs.display-name}}" \ -D WITH_VCPKG=ON \ -D BUILD_WITH_QT6=ON \ -D WITH_QTWEBKIT=OFF \ -D WITH_BINDINGS=ON \ - -D QGIS_MACAPP_FRAMEWORK=OFF \ -D VCPKG_TARGET_TRIPLET="${{ matrix.triplet }}" \ -D VCPKG_HOST_TRIPLET="${{ matrix.triplet }}" \ -D VCPKG_INSTALL_OPTIONS="--only-binarycaching" \ + -D ENABLE_UNITY_BUILDS=ON \ -D NUGET_USERNAME=${{ github.actor }} \ + -D NUGET_SOURCE="https://nuget.pkg.github.com/${{ github.repository_owner }}/index.json" \ -D NUGET_TOKEN=${{ secrets.GITHUB_TOKEN }} || true - fdupes -r -1 build/vcpkg_installed/arm64-osx-dynamic/lib | grep libQt | while read line; do master=""; for file in ${line[*]}; do if [[ "x${master}" == "x" ]]; then master=$file; else rm "${file}"; ln -s $(basename "${master}") "${file}"; fi; done; done + fdupes -q -r -1 build/vcpkg_installed/${{ matrix.triplet }}/lib | grep libQt | while read line; do master=""; for file in ${line[*]}; do if [[ "x${master}" == "x" ]]; then master=$file; else rm "${file}"; ln -s $(basename "${master}") "${file}"; fi; done; done cmake -D VCPKG_INSTALL_OPTIONS="" build @@ -99,10 +119,100 @@ jobs: if: github.event_name == 'workflow_dispatch' || github.event_name == 'release' uses: actions/upload-artifact@v4 with: - name: kadas-albireo2-sdk-${{ matrix.triplet }} + name: qgis-sdk-${{ matrix.triplet }} path: | sdk/vcpkg-export-*.zip - name: πŸŒ‹ Build run: | + # We make sure the target "all" is built before bundling + # Ideally, we would specify each target that is required to be installed, but this workaround is sufficient for now cmake --build build + cmake --build build --target bundle + + - name: Archive app + run: | + gtar -cpvzf qgis-app-${{steps.workflow-artifact-ids.outputs.display-name}}-${{ matrix.triplet }}.tar.gz ./build/_CPack_Packages/Darwin/External/*/*.app + + - name: πŸ“€ Upload app + uses: actions/upload-artifact@v4 + with: + name: qgis-app-${{steps.workflow-artifact-ids.outputs.display-name}}-${{ matrix.triplet }} + path: | + qgis-app-${{steps.workflow-artifact-ids.outputs.display-name}}-${{ matrix.triplet }}.tar.gz + + schedule_download_comment: + name: Create dmg + runs-on: macos-latest + needs: build + steps: + - name: 🐣 Checkout + uses: actions/checkout@v4 + + - name: πŸ”¨ Prepare build env + run: | + brew install create-dmg + + + - name: 🎲 Get artifact ids + id: workflow-artifact-ids + uses: ./.github/actions/get-workflow-artifact-ids + + - name: πŸ“€ Download app + uses: actions/download-artifact@v4 + with: + pattern: qgis-app-${{steps.workflow-artifact-ids.outputs.display-name}}-* + path: | + artifacts + + - name: Create universal app + run: | + mkdir -p x64 + gtar --strip-components=5 -zxf ./artifacts/qgis-app-${{steps.workflow-artifact-ids.outputs.display-name}}-x64-osx-dynamic-release/qgis-app-${{steps.workflow-artifact-ids.outputs.display-name}}-x64-osx-dynamic-release.tar.gz -C x64 + mkdir -p arm64 + gtar --strip-components=5 -zxf ./artifacts/qgis-app-${{steps.workflow-artifact-ids.outputs.display-name}}-arm64-osx-dynamic-release/qgis-app-${{steps.workflow-artifact-ids.outputs.display-name}}-arm64-osx-dynamic-release.tar.gz -C arm64 + + wget https://raw.githubusercontent.com/m-kuhn/lipo-dir-merge/refs/heads/main/lipo-dir-merge.py + python lipo-dir-merge.py x64 arm64 universal + + - name: Create dmg + run: | + QGIS_APP_NAME=QGIS-"${{steps.workflow-artifact-ids.outputs.display-name}}" + create-dmg --volname "${QGIS_APP_NAME} Installer" \ + --hide-extension ${QGIS_APP_NAME}.app \ + --volicon "$(pwd)/images/icons/mac/qgis.icns" \ + --background "$(pwd)/platform/macos/installer_background.png" \ + --window-pos 200 120 \ + --window-size 512 320 \ + --icon-size 100 \ + --icon "${QGIS_APP_NAME}.app" 130 160 \ + --app-drop-link 400 155 \ + ${QGIS_APP_NAME}-Installer.dmg \ + universal/*/*.app + + - name: πŸ“€ Upload app + uses: actions/upload-artifact@v4 + id: artifact-mac-qt6 + with: + name: qgis-${{steps.workflow-artifact-ids.outputs.display-name}}-dmg + path: | + *.dmg + + - name: Upload release assets + uses: AButler/upload-release-assets@v3.0 + if: ${{ github.event_name == 'release' }} + with: + files: '*.dmg' + repo-token: ${{ secrets.GITHUB_TOKEN }} + + - name: Schedule download comment + uses: ./.github/actions/post_sticky_comment + if: github.event_name == 'pull_request' + with: + marker: macos-qt6 + body: | + ### 🍎 MacOS Qt6 builds + Download [MacOS Qt6 builds of this PR for testing](${{ steps.artifact-mac-qt6.outputs.artifact-url }}). + _This installer is not signed, `control`+click > `open` the app to avoid the warning_ + *(Built from commit ${{ github.event.pull_request.head.sha }})* + pr: ${{ github.event.number }} diff --git a/.github/workflows/macos-build.yml b/.github/workflows/macos-build.yml deleted file mode 100644 index 9395c1c73676..000000000000 --- a/.github/workflows/macos-build.yml +++ /dev/null @@ -1,140 +0,0 @@ -name: 🍏 Mac OS build - -concurrency: - group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} - cancel-in-progress: true - -on: - push: - branches: - - master - - release-** - - queued_ltr_backports - paths: - pull_request: - branches: - - master - - release-** - - queued_ltr_backports - paths: - -permissions: - contents: read - -env: - QT_VERSION: 5.15.2 - QGIS_DEPS_VERSION: 0.9 - QGIS_DEPS_PATCH_VERSION: 0 - CCACHE_DIR: /Users/runner/work/ccache - BUILD_DIR: /Users/runner/work/QGIS/build-QGIS - # apparently we cannot cache /opt directory as it fails to restore - # so we copy the deps in the home directory - DEPS_CACHE_DIR: /Users/runner/work/deps-cache - -jobs: - mac_os_build: - if: github.repository == 'qgis/QGIS' - runs-on: macos-13 - steps: - - uses: actions/checkout@v4 - - - name: Restore build cache - uses: actions/cache/restore@v4 - with: - path: ${{ env.CCACHE_DIR }} - key: build-ccache-mac-${{Β github.event.pull_request.base.ref || github.ref_name }} - restore-keys: | - build-ccache-mac-master - - - name: Cache Qt - id: cache-qt - uses: actions/cache@v4 - with: - path: ${{ env.DEPS_CACHE_DIR }}/Qt/${{ env.QT_VERSION }} - key: mac-qt-${{ env.QT_VERSION }} - - - name: Restore Qt - if: steps.cache-qt.outputs.cache-hit == 'true' - run: | - sudo mkdir -p /opt - sudo mkdir -p /opt/Qt - sudo cp -r ${DEPS_CACHE_DIR}/Qt/${QT_VERSION} /opt/Qt/${QT_VERSION} - - - name: Download Qt - if: steps.cache-qt.outputs.cache-hit != 'true' - run: | - wget https://qgis.org/downloads/macos/deps/qt-${QT_VERSION}.tar.gz - mkdir -p ${DEPS_CACHE_DIR} - mkdir -p ${DEPS_CACHE_DIR}/Qt - - - # QGIS-deps caching - - name: Cache qgis-deps - id: cache-deps - uses: actions/cache@v4 - with: - path: ${{ env.DEPS_CACHE_DIR }}/QGIS/qgis-deps-${{ env.QGIS_DEPS_VERSION }}.${{ env.QGIS_DEPS_PATCH_VERSION }} - key: mac-qgis-deps-${{ env.QGIS_DEPS_VERSION }}.${{ env.QGIS_DEPS_PATCH_VERSION }} - - - name: Restore qgis-deps - if: steps.cache-deps.outputs.cache-hit == 'true' - run: | - sudo mkdir -p /opt - sudo mkdir -p /opt/QGIS - sudo cp -r ${DEPS_CACHE_DIR}/QGIS/qgis-deps-${QGIS_DEPS_VERSION}.${QGIS_DEPS_PATCH_VERSION} /opt/QGIS/qgis-deps-${QGIS_DEPS_VERSION} - - - name: Download qgis-deps - if: steps.cache-deps.outputs.cache-hit != 'true' - run: | - wget https://qgis.org/downloads/macos/deps/qgis-deps-${QGIS_DEPS_VERSION}.${QGIS_DEPS_PATCH_VERSION}.tar.gz - mkdir -p ${DEPS_CACHE_DIR} - mkdir -p ${DEPS_CACHE_DIR}/QGIS - - - name: Install Qt and deps - env: - QT_ALREADY_CACHED: ${{ steps.cache-qt.outputs.cache-hit }} - QGIS_DEPS_ALREADY_CACHED: ${{ steps.cache-deps.outputs.cache-hit }} - run: | - wget https://qgis.org/downloads/macos/deps/install_qgis_deps-${QGIS_DEPS_VERSION}.${QGIS_DEPS_PATCH_VERSION}.bash - chmod +x ./install_qgis_deps-${QGIS_DEPS_VERSION}.${QGIS_DEPS_PATCH_VERSION}.bash - echo ::group::Install deps - sudo ./install_qgis_deps-${QGIS_DEPS_VERSION}.${QGIS_DEPS_PATCH_VERSION}.bash - echo ::endgroup:: - [[ ${QT_ALREADY_CACHED} != "true" ]] && cp -r /opt/Qt/${QT_VERSION} ${DEPS_CACHE_DIR}/Qt/${QT_VERSION} || true - [[ ${QGIS_DEPS_ALREADY_CACHED} != "true" ]] && cp -r /opt/QGIS/qgis-deps-${QGIS_DEPS_VERSION} ${DEPS_CACHE_DIR}/QGIS/qgis-deps-${QGIS_DEPS_VERSION}.${QGIS_DEPS_PATCH_VERSION} || true - - - name: Install ccache - run: | - mkdir -p ${CCACHE_DIR} - brew install ccache - ccache --set-config=max_size=2.0G - # To make ccache work properly with precompiled headers - ccache --set-config sloppiness=pch_defines,time_macros,include_file_mtime,include_file_ctime - ccache -s - - - name: Run cmake - run: | - mkdir -p ${BUILD_DIR} - cd ${BUILD_DIR} - - PATH=/opt/QGIS/qgis-deps-${QGIS_DEPS_VERSION}/stage/bin:$PATH \ - cmake -DQGIS_MAC_DEPS_DIR=/opt/QGIS/qgis-deps-${QGIS_DEPS_VERSION}/stage \ - -DCMAKE_PREFIX_PATH=/opt/Qt/${QT_VERSION}/clang_64 \ - -DWITH_BINDINGS=TRUE \ - -DWITH_3D=TRUE \ - -DWITH_DRACO=FALSE \ - -DWITH_PDAL=TRUE \ - -DWITH_EPT=TRUE \ - ../QGIS - - - name: Build QGIS - run: | - cd ${BUILD_DIR} - make -j $(sysctl -n hw.ncpu) - - - name: Save build cache for push only - uses: actions/cache/save@v4 - if: ${{ github.event_name == 'push' }} - with: - path: ${{ env.CCACHE_DIR }} - key: build-ccache-mac-${{ github.ref_name }}-${{ github.run_id }} diff --git a/CMakeLists.txt b/CMakeLists.txt index e283e40d65c1..a605d7818ce1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -43,10 +43,11 @@ else() endif() if(WITH_VCPKG) + set(TARGET_SYSROOT "${VCPKG_INSTALL_PREFIX}/${VCPKG_TARGET_TRIPLET}") if(WIN32) - list(APPEND CMAKE_PROGRAM_PATH "${VCPKG_INSTALL_PREFIX}/${VCPKG_TARGET_TRIPLET}/tools/python3/Scripts/") + list(APPEND CMAKE_PROGRAM_PATH "${TARGET_SYSROOT}/tools/python3/Scripts/") else() - list(APPEND CMAKE_PROGRAM_PATH "${VCPKG_INSTALL_PREFIX}/${VCPKG_TARGET_TRIPLET}/bin") + list(APPEND CMAKE_PROGRAM_PATH "${TARGET_SYSROOT}/bin") endif() set(PREFER_INTERNAL_LIBS FALSE) else() @@ -63,7 +64,7 @@ set(RELEASE_NAME "Master") project(qgis VERSION ${COMPLETE_VERSION}) if (APPLE) - set(QGIS_APP_NAME "QGIS") + set(QGIS_APP_NAME "QGIS" CACHE STRING "The main app name and bundle name") else() set(QGIS_APP_NAME "qgis") endif() @@ -74,21 +75,6 @@ message(STATUS "QGIS version: ${COMPLETE_VERSION} ${RELEASE_NAME} (${QGIS_VERSIO set (ENABLE_LOCAL_BUILD_SHORTCUTS FALSE CACHE BOOL "Disables some build steps which are only relevant for releases to speed up compilation time for development") -############################################################# -if (APPLE) - # QGIS custom dependencies package from qgis/QGIS-Mac-Packager - # they can be downloaded from https://download.qgis.org/downloads/macos/deps/ - # and extracted to /opt/QGIS/qgis-deps-/stage - set (QGIS_MAC_DEPS_DIR "" CACHE PATH "Path to QGIS Mac custom dependencies directory") - - # Setup LIB_DIR and CMAKE_PREFIX_PATH to help CMake's - # find_packages to look for these libraries instead of system libraries - if ( QGIS_MAC_DEPS_DIR ) - set(ENV{LIB_DIR} ${QGIS_MAC_DEPS_DIR}) - list(APPEND CMAKE_PREFIX_PATH ${QGIS_MAC_DEPS_DIR}) - endif() -endif() - ############################################################# # Configure OpenCL if available set(HAVE_OPENCL FALSE) @@ -899,6 +885,27 @@ if( "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" OR "${CMAKE_CXX_COMPILER_ID}" ST include("cmake/modules/linker.cmake") endif() +set(MIN_PYTHON_VERSION "3.9") +set(Python_FIND_FRAMEWORK "LAST") + +if (WITH_BINDINGS) + find_package(Python ${MIN_PYTHON_VERSION} REQUIRED COMPONENTS Interpreter Development) +else() + find_package(Python ${MIN_PYTHON_VERSION} REQUIRED COMPONENTS Interpreter) +endif() + +# Fix python site-packages for Fedora +# See https://github.com/qgis/QGIS/issues/54348#issuecomment-1694216152 +if(CMAKE_SYSTEM_NAME STREQUAL "Linux") + if(EXISTS "/etc/fedora-release") + EXECUTE_PROCESS(COMMAND ${Python_EXECUTABLE} -c "import sysconfig;print(sysconfig.get_path(\"platlib\", \"rpm_prefix\"), end=\"\")" OUTPUT_VARIABLE Python_SITEARCH) + endif() +endif() + +message("-- Found Python executable: ${Python_EXECUTABLE} (version ${Python_VERSION})") +message("-- Python library: ${Python_LIBRARIES}") +message("-- Python site-packages: ${Python_SITEARCH}") + ############################################################# # platform specific stuff if (WITH_CORE) @@ -936,64 +943,29 @@ if (WITH_CORE) else() if(APPLE) - set(QGIS_MACAPP_FRAMEWORK TRUE CACHE BOOL "Build as a framework on OSX") + set(QGIS_MAC_BUNDLE TRUE CACHE BOOL "Install into a mac bundle") endif() - if (APPLE AND QGIS_MACAPP_FRAMEWORK) - if (POLICY CMP0042) # in CMake 3.0.0+ - set (CMAKE_MACOSX_RPATH OFF) # otherwise ON by default - endif() - if (POLICY CMP0068) # in CMake 3.9.0+ - cmake_policy(SET CMP0068 NEW) - endif() - # for Mac OS X, everything is put inside an application bundle - # save the root install prefix for the app later - set (QGIS_INSTALL_PREFIX ${CMAKE_INSTALL_PREFIX}) - set (QGIS_MACAPP_PREFIX ${CMAKE_INSTALL_PREFIX}/${QGIS_APP_NAME}.app/Contents) - # common prefix for components, let cmake handle it - set (CMAKE_INSTALL_PREFIX ${QGIS_MACAPP_PREFIX}/MacOS) - # 5 bundling levels, each includes previous - # -1 nothing - # 0 fixup the library paths for all QGIS libraries with @loader_path - # 1 Qt frameworks - # 2 non-system libraries, "standard" - # 3 non-system frameworks, "standalone" - set (QGIS_MACAPP_BUNDLE 1 CACHE STRING "What to bundle into app package") - set (QGIS_MACAPP_BUNDLE_USER "" CACHE STRING "Path to user bundling script") - set (QGIS_MACAPP_INSTALL_DEV FALSE CACHE BOOL "Install developer frameworks") - set (QGIS_MACAPP_DEV_PREFIX "/Library/Frameworks" CACHE STRING "Path to install developer frameworks") - - set (DEFAULT_BIN_SUBDIR bin) - set (QGIS_BIN_SUBDIR_REV ..) - set (DEFAULT_CGIBIN_SUBDIR fcgi-bin) - set (QGIS_CGIBIN_SUBDIR_REV ..) - set (DEFAULT_LIB_SUBDIR lib) - set (QGIS_LIB_SUBDIR_REV ..) - set (QGIS_FW_SUBDIR ../Frameworks) - set (QGIS_FW_SUBDIR_REV ../MacOS) - set (DEFAULT_DATA_SUBDIR ../Resources) - set (QGIS_DATA_SUBDIR_REV ../MacOS) - set (DEFAULT_LIBEXEC_SUBDIR lib/qgis) - set (QGIS_LIBEXEC_SUBDIR_REV ../..) - set (DEFAULT_PLUGIN_SUBDIR ../PlugIns/qgis) - set (QGIS_PLUGIN_SUBDIR_REV ../../MacOS) - set (DEFAULT_INCLUDE_SUBDIR include/qgis) - set (DEFAULT_QML_SUBDIR qml) - - # Set server moodules path to DEFAULT_LIBEXEC_SUBDIR+'/server' - set (DEFAULT_SERVER_MODULE_SUBDIR ${DEFAULT_LIBEXEC_SUBDIR}/server) - - # path for framework references when running from build directory - # changed later to reference in-app resources upon install - set (CMAKE_INSTALL_NAME_DIR ${CMAKE_BINARY_DIR}/output/lib) - # recent cmakes force SDKs, recent SDKs don't have user symlinks - # need to find non-system frameworks - # cmake bug #0007250 - CMAKE_SHARED_LINKER_FLAGS ignored when creating - # a framework, so these need to be manually handled with LINK_FLAGS options - set (CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -F/Library/Frameworks") - set (CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} -F/Library/Frameworks") - set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -F/Library/Frameworks") - + if (APPLE AND QGIS_MAC_BUNDLE) + set(CMAKE_MACOSX_RPATH ON) # If this is off, the path will be stripped (completely) at install time, we want to preserve the `@rpath` prefix + set(CMAKE_SKIP_INSTALL_RPATH TRUE) + + set(APP_CONTENTS_DIR "Contents") + set(APP_MACOS_DIR "${APP_CONTENTS_DIR}/MacOS") + set(APP_FRAMEWORKS_DIR "${APP_CONTENTS_DIR}/Frameworks") + set(APP_RESOURCES_DIR "${APP_CONTENTS_DIR}/Resources") + set(APP_PLUGINS_DIR "${APP_CONTENTS_DIR}/PlugIns") + + cmake_path(RELATIVE_PATH Python_SITEARCH BASE_DIRECTORY "${TARGET_SYSROOT}" OUTPUT_VARIABLE _RELATIVE_SITEARCH) + + set(DEFAULT_BIN_SUBDIR ${APP_MACOS_DIR}) + set(DEFAULT_LIB_SUBDIR ${APP_FRAMEWORKS_DIR}) + set(DEFAULT_DATA_SUBDIR ${APP_RESOURCES_DIR}/qgis) + set(DEFAULT_LIBEXEC_SUBDIR ${APP_MACOS_DIR}) + set(DEFAULT_PLUGIN_SUBDIR ${APP_PLUGINS_DIR}/qgis) + set(DEFAULT_INCLUDE_SUBDIR include/qgis) + set(DEFAULT_QML_SUBDIR ${APP_RESOURCES_DIR}/qgis/qml) + set(DEFAULT_PYTHON_SUBDIR ${APP_FRAMEWORKS_DIR}/${_RELATIVE_SITEARCH}) else() # UNIX set (DEFAULT_BIN_SUBDIR bin) @@ -1006,13 +978,6 @@ if (WITH_CORE) set (DEFAULT_QML_SUBDIR qml) set (DEFAULT_SERVER_MODULE_SUBDIR ${DEFAULT_LIBEXEC_SUBDIR}/server) - - # QGIS_MACAPP_FRAMEWORK=FALSE - if(APPLE) - set (QGIS_MACAPP_BUNDLE -1) - set (CMAKE_FRAMEWORK FALSE) - set (QGIS_INSTALL_PREFIX ${CMAKE_INSTALL_PREFIX}) - endif() endif() endif() @@ -1112,28 +1077,6 @@ option(ENABLE_UNITY_BUILDS "Enable Unity builds, that is compiling several .cpp ############################################################# # Python -set(MIN_PYTHON_VERSION "3.9") -set(Python_FIND_FRAMEWORK "LAST") - - -if (WITH_BINDINGS) - find_package(Python ${MIN_PYTHON_VERSION} REQUIRED COMPONENTS Interpreter Development) -else() - find_package(Python ${MIN_PYTHON_VERSION} REQUIRED COMPONENTS Interpreter) -endif() - -# Fix python site-packages for Fedora -# See https://github.com/qgis/QGIS/issues/54348#issuecomment-1694216152 -if(CMAKE_SYSTEM_NAME STREQUAL "Linux") - if(EXISTS "/etc/fedora-release") - EXECUTE_PROCESS(COMMAND ${Python_EXECUTABLE} -c "import sysconfig;print(sysconfig.get_path(\"platlib\", \"rpm_prefix\"), end=\"\")" OUTPUT_VARIABLE Python_SITEARCH) - endif() -endif() - -message("-- Found Python executable: ${Python_EXECUTABLE} (version ${Python_VERSION})") -message("-- Python library: ${Python_LIBRARIES}") -message("-- Python site-packages: ${Python_SITEARCH}") - if (WITH_CORE AND WITH_BINDINGS) set(PYTHON_OUTPUT_DIRECTORY ${QGIS_OUTPUT_DIRECTORY}/python) set (QGIS_PYTHON_OUTPUT_DIRECTORY ${PYTHON_OUTPUT_DIRECTORY}/qgis) @@ -1166,8 +1109,12 @@ if (WITH_CORE AND WITH_BINDINGS) set(SIP_INCLUDES ${PYQT_SIP_DIR} ${CMAKE_SOURCE_DIR}/python) set(SIP_CONCAT_PARTS 25) - if (NOT BINDINGS_GLOBAL_INSTALL) - set(Python_SITEARCH ${QGIS_DATA_DIR}/python) + if(BINDINGS_GLOBAL_INSTALL) + set(QGIS_PYTHON_INSTALL_DIR ${Python_SITEARCH}) + elseif(DEFINED DEFAULT_PYTHON_SUBDIR) + set(QGIS_PYTHON_INSTALL_DIR ${DEFAULT_PYTHON_SUBDIR}) + else() + set(QGIS_PYTHON_INSTALL_DIR ${QGIS_DATA_DIR}/python) endif() if (WITH_CUSTOM_WIDGETS) @@ -1225,22 +1172,6 @@ if (WITH_CORE) add_subdirectory(python) endif() - if (APPLE) - # must be last for install, so install_name_tool can do its work - add_subdirectory(mac) - - # allow QGIS to be run directly from build directory and to run unit tests - execute_process(COMMAND /bin/mkdir -p "${QGIS_OUTPUT_DIRECTORY}/lib") - execute_process( - COMMAND /bin/ln -fs ../../Plugins/qgis/qgisgrass6.framework lib/ - WORKING_DIRECTORY "${QGIS_OUTPUT_DIRECTORY}" - ) - execute_process( - COMMAND /bin/ln -fs ../../Plugins/qgis/qgisgrass7.framework lib/ - WORKING_DIRECTORY "${QGIS_OUTPUT_DIRECTORY}" - ) - endif() - # manual page - makes sense only on unix systems if (UNIX AND NOT APPLE) install (FILES qgis.1 DESTINATION ${QGIS_MANUAL_DIR}/man1) @@ -1280,8 +1211,8 @@ endif() ############################################################# # Enable packaging if (WITH_CORE) - include(Bundle) include(VcpkgInstallDeps) + include(Bundle) endif() if (UNIX AND NOT APPLE) diff --git a/INSTALL.md b/INSTALL.md index 6ab00d7f4a25..16fbe5fc98ee 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -1048,10 +1048,8 @@ cmake -S . \ -D BUILD_WITH_QT6=ON \ -D WITH_QTWEBKIT=OFF \ -D WITH_BINDINGS=ON \ - -D QGIS_MACAPP_FRAMEWORK=OFF \ -D VCPKG_TARGET_TRIPLET="$TRIPLET" \ - -D VCPKG_HOST_TRIPLET="$TRIPLET" \ - -D CREATE_MACOSX_BUNDLE=OFF + -D VCPKG_HOST_TRIPLET="$TRIPLET" ``` Build (switch the target to `Release` if you do not want to debug) diff --git a/cmake/Bundle.cmake b/cmake/Bundle.cmake index a1ffffd26f4e..5790917ba7e4 100644 --- a/cmake/Bundle.cmake +++ b/cmake/Bundle.cmake @@ -2,9 +2,9 @@ set(CPACK_GENERATOR) set(CPACK_OUTPUT_CONFIG_FILE "${CMAKE_BINARY_DIR}/BundleConfig.cmake") add_custom_target(bundle - COMMAND ${CMAKE_CPACK_COMMAND} "--config" "${CMAKE_BINARY_DIR}/BundleConfig.cmake" + COMMAND ${CMAKE_CPACK_COMMAND} "--config" "${CMAKE_BINARY_DIR}/BundleConfig.cmake" "--verbose" COMMENT "Running CPACK. Please wait..." - DEPENDS qgis) + DEPENDS "${QGIS_APP_NAME}") if(WIN32 AND NOT UNIX) set (CREATE_NSIS FALSE CACHE BOOL "Create an installer using NSIS") @@ -22,7 +22,6 @@ endif() set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "QGIS") set(CPACK_PACKAGE_VENDOR "Open Source Geospatial Foundation") -set(CPACK_PACKAGE_DESCRIPTION_FILE "${CMAKE_CURRENT_SOURCE_DIR}/README") set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/COPYING") set(CPACK_PACKAGE_INSTALL_DIRECTORY "QGIS ${COMPLETE_VERSION}") set(CPACK_PACKAGE_EXECUTABLES "qgis" "QGIS") @@ -44,4 +43,22 @@ if(CREATE_ZIP) list(APPEND CPACK_GENERATOR "ZIP") endif() + +if(CMAKE_SYSTEM_NAME STREQUAL "Darwin" AND QGIS_MAC_BUNDLE) + set(CREATE_DMG FALSE CACHE BOOL "Create a dmg bundle") + set(PYMACDEPLOYQT_EXECUTABLE "${CMAKE_SOURCE_DIR}/platform/macos/pymacdeployqt.py") + + configure_file("${CMAKE_SOURCE_DIR}/platform/macos/Info.plist.in" "${CMAKE_BINARY_DIR}/platform//macos/Info.plist" @ONLY) + install(FILES "${CMAKE_BINARY_DIR}/platform/macos/Info.plist" DESTINATION "${APP_CONTENTS_DIR}") + + set(CPACK_DMG_VOLUME_NAME "${PROJECT_NAME}") + set(CPACK_DMG_FORMAT "UDBZ") + list(APPEND CPACK_GENERATOR "External") + message(STATUS " + macdeployqt/DMG YES ") + configure_file(${CMAKE_SOURCE_DIR}/platform/macos/CPackMacDeployQt.cmake.in "${CMAKE_BINARY_DIR}/CPackExternal.cmake" @ONLY) + set(CPACK_EXTERNAL_PACKAGE_SCRIPT "${CMAKE_BINARY_DIR}/CPackExternal.cmake") + set(CPACK_EXTERNAL_ENABLE_STAGING ON) + set(CPACK_PACKAGING_INSTALL_PREFIX "/${QGIS_APP_NAME}.app") +endif() + include(CPack) diff --git a/cmake/MacBundleMacros.cmake b/cmake/MacBundleMacros.cmake deleted file mode 100644 index f724d11e71ee..000000000000 --- a/cmake/MacBundleMacros.cmake +++ /dev/null @@ -1,222 +0,0 @@ -# QGIS Mac Bundle Macros - -# BundleUtilities has functions to bundle and fixup libraries into an -# application package, but it's all-or-nothing and is missing some features: -# -# - @loader_path -# - helper functions can't get install_name, just dependencies - -# the following cmakecache vars must be set, redefine them -# with config-file substitutions in install-run scripts: -# -# CPACK_PACKAGE_VERSION_MAJOR, CPACK_PACKAGE_VERSION_MINOR -# CMAKE_INSTALL_PREFIX, CMAKE_VERBOSE_MAKEFILE, CMAKE_BUILD_TYPE -# CMAKE_OSX_ARCHITECTURES -# QGIS_APP_NAME -# QGIS_MACAPP_PREFIX -# QGIS_*_SUBDIR, QGIS_*_SUBDIR_REV -# WITH_* - -# this file must only be included after target installation is complete - -# message only if verbose makefiles - -FUNCTION (MYMESSAGE MSG) - IF (${CMAKE_VERBOSE_MAKEFILE}) - MESSAGE (STATUS "${MSG}") - ENDIF (${CMAKE_VERBOSE_MAKEFILE}) -ENDFUNCTION (MYMESSAGE) - -# get the install_name of a library or framework -# regex stuff taken from GetPrerequisites - -FUNCTION (GET_INSTALL_NAME LIBFILE LIBNAME OUTVAR) - IF (EXISTS "${LIBFILE}") - EXECUTE_PROCESS (COMMAND otool -L "${LIBFILE}" OUTPUT_VARIABLE iname_out) - # remove 1st line, it's just path to lib file - STRING (REGEX REPLACE ".*:\n" "" iname "${iname_out}") - IF (iname) - # find libname - STRING (REGEX MATCH "[^\n\t ]*${LIBNAME}[^\n]*" iname "${iname}") - STRING (REGEX REPLACE " \\(compatibility version .*, current version .*\\)" "" iname "${iname}") - ENDIF (iname) - SET (${OUTVAR} ${iname} PARENT_SCOPE) - ELSE () - SET (${OUTVAR} "" PARENT_SCOPE) - ENDIF () -ENDFUNCTION (GET_INSTALL_NAME) - -# install_name_tool -change CHANGE CHANGETO CHANGEBIN - -FUNCTION (INSTALLNAMETOOL_CHANGE CHANGE CHANGETO CHANGEBIN) - IF (EXISTS "${CHANGEBIN}" AND CHANGE AND CHANGETO) - # ensure CHANGEBIN is writable by user, e.g. Homebrew binaries are installed non-writable - EXECUTE_PROCESS (COMMAND chmod u+w "${CHANGEBIN}") - EXECUTE_PROCESS (COMMAND install_name_tool -change ${CHANGE} ${CHANGETO} "${CHANGEBIN}") - # if that didn't work, try a symlink-resolved id - # (some package systems, like Homebrew, heavily use symlinks; and, inter-package builds, like plugins, - # may point to the resolved location instead of the 'public' symlink installed to prefixes like /usr/local) - get_filename_component(_chgreal ${CHANGE} REALPATH) - EXECUTE_PROCESS (COMMAND install_name_tool -change ${_chgreal} ${CHANGETO} "${CHANGEBIN}") - ENDIF () -ENDFUNCTION (INSTALLNAMETOOL_CHANGE) - -# copy a framework, only specified archs, current version, debug dep on CMAKE_BUILD_TYPE - -FUNCTION (COPY_FRAMEWORK FWPREFIX FWNAME FWDEST) - # reconstruct framework to avoid excessive copying, then deleting - # especially when debug variants are present - # find current version - # use python because pwd not working with WORKING_DIRECTORY param - EXECUTE_PROCESS ( - COMMAND python -c "import os.path\nprint(os.path.realpath(\"${FWPREFIX}/${FWNAME}.framework/Versions/Current\"))" - OUTPUT_VARIABLE FWDIRPHYS - ) - STRING (STRIP "${FWDIRPHYS}" FWDIRPHYS) - IF (IS_DIRECTORY "${FWDIRPHYS}") - STRING (REGEX MATCH "[^/\n]+$" FWVER "${FWDIRPHYS}") - EXECUTE_PROCESS (COMMAND mkdir -p "${FWDEST}/${FWNAME}.framework/Versions/${FWVER}") - EXECUTE_PROCESS (COMMAND ln -sfn ${FWVER} "${FWDEST}/${FWNAME}.framework/Versions/Current") - EXECUTE_PROCESS (COMMAND ditto ${QARCHS} "${FWPREFIX}/${FWNAME}.framework/Versions/${FWVER}/${FWNAME}" "${FWDEST}/${FWNAME}.framework/Versions/${FWVER}/${FWNAME}") - EXECUTE_PROCESS (COMMAND ln -sf Versions/Current/${FWNAME} "${FWDEST}/${FWNAME}.framework/${FWNAME}") - IF (IS_DIRECTORY "${FWPREFIX}/${FWNAME}.framework/Versions/${FWVER}/Resources") - EXECUTE_PROCESS (COMMAND cp -Rfp "${FWPREFIX}/${FWNAME}.framework/Versions/${FWVER}/Resources" "${FWDEST}/${FWNAME}.framework/Versions/${FWVER}") - EXECUTE_PROCESS (COMMAND ln -sfn Versions/Current/Resources "${FWDEST}/${FWNAME}.framework/Resources") - ENDIF (IS_DIRECTORY "${FWPREFIX}/${FWNAME}.framework/Versions/${FWVER}/Resources") - # ensure writable by user, e.g. Homebrew frameworks are installed non-writable - EXECUTE_PROCESS (COMMAND chmod -R u+w "${FWDEST}/${FWNAME}.framework") - EXECUTE_PROCESS (COMMAND install_name_tool -id "${ATEXECUTABLE}/${QGIS_FW_SUBDIR}/${FWNAME}" "${FWDEST}/${FWNAME}.framework/${FWNAME}") - # debug variants - SET (FWD "${FWNAME}_debug") - IF ("${FWDEBUG}" STREQUAL "Debug" AND EXISTS "${FWPREFIX}/${FWNAME}.framework/Versions/${FWVER}/${FWD}") - EXECUTE_PROCESS (COMMAND ditto ${QARCHS} "${FWPREFIX}/${FWNAME}.framework/Versions/${FWVER}/${FWD}" "${FWDEST}/${FWNAME}.framework/Versions/${FWVER}/${FWD}") - EXECUTE_PROCESS (COMMAND ln -sf Versions/Current/${FWD} "${FWDEST}/${FWNAME}.framework/${FWD}") - IF (IS_DIRECTORY "${FWPREFIX}/${FWNAME}.framework/${FWD}.dSYM") - EXECUTE_PROCESS (COMMAND ditto -X ${QARCHS} "${FWPREFIX}/${FWNAME}.framework/${FWD}.dSYM" "${FWDEST}/${FWNAME}.framework") - ENDIF () - ENDIF () - ENDIF () -ENDFUNCTION (COPY_FRAMEWORK) - -# update a library path in all QGIS binary files -# if dylib, change LIBFROM to LIBTO as is -# else assumes it's a framework, change LIBFROM to LIBTO.framework/LIBTO - -FUNCTION (UPDATEQGISPATHS LIBFROM LIBTO) - IF (LIBFROM) - STRING (REGEX MATCH "\\.(dylib|so)$" ISLIB "${LIBTO}") - IF (ISLIB) - SET (LIBPOST "${LIBTO}") - SET (LIBMID "${QGIS_LIB_SUBDIR}") - ElSE () - SET (LIBPOST "${LIBTO}.framework/${LIBTO}") - SET (LIBMID "${QGIS_FW_SUBDIR}") - ENDIF () - SET (LIB_CHG_TO "${ATEXECUTABLE}/${LIBMID}/${LIBPOST}") - # app - always @executable_path - INSTALLNAMETOOL_CHANGE ("${LIBFROM}" "${LIB_CHG_TO}" "${QAPPDIR}/${QGIS_APP_NAME}") - # qgis helper apps - don't link anything else than Qt/Qgis - FOREACH (QA ${QGAPPLIST}) - INSTALLNAMETOOL_CHANGE ("${LIBFROM}" "${LIB_CHG_TO}" "${QBINDIR}/${QA}.app/Contents/MacOS/${QA}") - ENDFOREACH (QA) - # qgis-mapserver - IF (${WITH_SERVER}) - SET (LIB_CHG_TO "${ATEXECUTABLE}/${QGIS_CGIBIN_SUBDIR_REV}/${LIBMID}/${LIBPOST}") - INSTALLNAMETOOL_CHANGE ("${LIBFROM}" "${LIB_CHG_TO}" "${QCGIDIR}/qgis_mapserv.fcgi") - ENDIF () - # libs - # bundled frameworks can use short relative path - IF (ISLIB) - SET (LIB_CHG_TO "${ATLOADER}/../../../${QGIS_FW_SUBDIR_REV}/${LIBMID}/${LIBPOST}") - ElSE () - SET (LIB_CHG_TO "${ATLOADER}/../../../${LIBPOST}") - ENDIF () - FOREACH (QL ${QGFWLIST}) - INSTALLNAMETOOL_CHANGE ("${LIBFROM}" "${LIB_CHG_TO}" "${QFWDIR}/${QL}.framework/${QL}") - ENDFOREACH (QL) - # non-framework qgis libs - SET (LIB_CHG_TO "${ATLOADER}/${QGIS_LIB_SUBDIR_REV}/${LIBMID}/${LIBPOST}") - FOREACH (QL ${QGLIBLIST}) - INSTALLNAMETOOL_CHANGE ("${LIBFROM}" "${LIB_CHG_TO}" "${QLIBDIR}/${QL}") - ENDFOREACH (QL) - # crssync - SET (LIB_CHG_TO "${ATEXECUTABLE}/${QGIS_LIBEXEC_SUBDIR_REV}/${LIBMID}/${LIBPOST}") - INSTALLNAMETOOL_CHANGE ("${LIBFROM}" "${LIB_CHG_TO}" "${QLIBXDIR}/crssync") - # GRASS libexec stuff - FOREACH (QG ${QGRASSEXECLIST}) - IF (EXISTS "${QLIBXDIR}/grass/${QG}") - SET (LIB_CHG_TO "${ATLOADER}/../../${QGIS_LIBEXEC_SUBDIR_REV}/${LIBMID}/${LIBPOST}") - INSTALLNAMETOOL_CHANGE ("${LIBFROM}" "${LIB_CHG_TO}" "${QLIBXDIR}/grass/${QG}") - ENDIF () - ENDFOREACH (QG) - # plugins - SET (LIB_CHG_TO "${ATLOADER}/${QGIS_PLUGIN_SUBDIR_REV}/${LIBMID}/${LIBPOST}") - FOREACH (QP ${QGPLUGLIST}) - INSTALLNAMETOOL_CHANGE ("${LIBFROM}" "${LIB_CHG_TO}" "${QP}") - ENDFOREACH (QP) - # quick plugin - SET (LIB_CHG_TO "${ATLOADER}/../../${LIBMID}/${LIBPOST}") - INSTALLNAMETOOL_CHANGE ("${LIBFROM}" "${LIB_CHG_TO}" "${QAPPDIR}/qml/QgsQuick/libqgis_quick_plugin.dylib") - # qgis python - SET (LIB_CHG_TO "${ATLOADER}/../../${QGIS_DATA_SUBDIR_REV}/${LIBMID}/${LIBPOST}") - FOREACH (PG ${QGPYLIST}) - INSTALLNAMETOOL_CHANGE ("${LIBFROM}" "${LIB_CHG_TO}" "${PG}") - ENDFOREACH (PG) - # bin - nothing yet - # SET (LIB_CHG_TO "${ATLOADER}/${QGIS_BIN_SUBDIR_REV}/${LIBMID}/${LIBPOST}") - #FOREACH (PB ...) - # INSTALLNAMETOOL_CHANGE ("${LIBFROM}" "${LIB_CHG_TO}" "${QBINDIR}/${PB}") - #ENDFOREACH (PB) - ENDIF (LIBFROM) -ENDFUNCTION (UPDATEQGISPATHS) - - -# Find directory path for a known Python module (or package) directory or file name -# see: PYTHON_MODULE_PATHS in 0vars.cmake.in -FUNCTION (PYTHONMODULEDIR MOD_NAME OUTVAR) - FOREACH (MOD_PATH ${PYTHON_MODULE_PATHS}) - IF (EXISTS "${MOD_PATH}/${MOD_NAME}") - SET (${OUTVAR} "${MOD_PATH}" PARENT_SCOPE) - RETURN() - ENDIF() - ENDFOREACH (MOD_PATH) - SET (${OUTVAR} "" PARENT_SCOPE) -ENDFUNCTION (PYTHONMODULEDIR) - - -SET (ATEXECUTABLE "@executable_path") -SET (ATLOADER "@loader_path") -SET (Q_FWVER ${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}) - -# install destinations -SET (QAPPDIRC "$ENV{DESTDIR}${QGIS_MACAPP_PREFIX}") -SET (QAPPDIR "$ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}") -SET (QFWDIR "${QAPPDIR}/${QGIS_FW_SUBDIR}") -SET (QBINDIR "${QAPPDIR}/${QGIS_BIN_SUBDIR}") -SET (QCGIDIR "${QAPPDIR}/${QGIS_CGIBIN_SUBDIR}") -SET (QLIBDIR "${QAPPDIR}/${QGIS_LIB_SUBDIR}") -SET (QLIBXDIR "${QAPPDIR}/${QGIS_LIBEXEC_SUBDIR}") -SET (QDATADIR "${QAPPDIR}/${QGIS_DATA_SUBDIR}") -SET (QPLUGDIR "${QAPPDIR}/${QGIS_PLUGIN_SUBDIR}") -SET (QGISPYDIR "${QAPPDIR}/${QGIS_DATA_SUBDIR}/python") - -# build arches -SET (QARCHS "") -FOREACH (QARCH ${CMAKE_OSX_ARCHITECTURES}) - SET (QARCHS ${QARCHS} "--arch" "${QARCH}") -ENDFOREACH (QARCH) - -# common file lists -FILE (GLOB QGFWLIST RELATIVE "${QFWDIR}" "${QFWDIR}/qgis*.framework") -# for some reason, REPLACE is stripping list seps -STRING(REPLACE ".framework" ";" QGFWLIST ${QGFWLIST}) -# don't collect any library symlinks, limit to versioned libs -SET (Q_LIBVER ${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}) -FILE (GLOB QGLIBLIST RELATIVE "${QLIBDIR}" "${QLIBDIR}/libqgis*.dylib" "${QLIBDIR}/qgis/server/lib*.so") -FILE (GLOB QGPLUGLIST "${QPLUGDIR}/*.so") -FILE (GLOB QGPYLIST "${QGISPYDIR}/qgis/*.so") -FILE (GLOB QGAPPLIST RELATIVE "${QBINDIR}" "${QBINDIR}/q*.app") -FILE (GLOB QGRASSEXECLIST RELATIVE "${QLIBXDIR}/grass" "${QLIBXDIR}/grass/*/*") -IF (QGAPPLIST) - STRING(REPLACE ".app" ";" QGAPPLIST ${QGAPPLIST}) -ENDIF (QGAPPLIST) diff --git a/cmake/SIPMacros.cmake b/cmake/SIPMacros.cmake index e69e208b6a10..1870a64bd74b 100644 --- a/cmake/SIPMacros.cmake +++ b/cmake/SIPMacros.cmake @@ -204,5 +204,5 @@ MACRO(BUILD_SIP_PYTHON_MODULE MODULE_NAME SIP_FILES EXTRA_OBJECTS) ) ENDIF(WIN32) - INSTALL(TARGETS ${_logical_name} DESTINATION "${Python_SITEARCH}/${_parent_module_path}") + INSTALL(TARGETS ${_logical_name} DESTINATION "${QGIS_PYTHON_INSTALL_DIR}/${_parent_module_path}") ENDMACRO(BUILD_SIP_PYTHON_MODULE MODULE_NAME SIP_FILES EXTRA_OBJECTS) diff --git a/cmake/VcpkgInstallDeps.cmake b/cmake/VcpkgInstallDeps.cmake index 2ff892010750..6e15d476d42d 100644 --- a/cmake/VcpkgInstallDeps.cmake +++ b/cmake/VcpkgInstallDeps.cmake @@ -5,12 +5,15 @@ endif() set(VCPKG_BASE_DIR "${_VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET}") if(MSVC) - # At least python3.dll, qgis_analysis.dll and gsl.dll are missing - # Copy everything file(GLOB ALL_LIBS "${VCPKG_BASE_DIR}/bin/*.dll" ) install(FILES ${ALL_LIBS} DESTINATION "bin") +elseif(CMAKE_SYSTEM_NAME STREQUAL "Darwin") + file(GLOB ALL_LIBS + "${VCPKG_BASE_DIR}/lib/*.dylib" + ) + install(FILES ${ALL_LIBS} DESTINATION "${QGIS_LIB_SUBDIR}") endif() set(PROJ_DATA_PATH "${VCPKG_BASE_DIR}/share/proj") @@ -19,12 +22,67 @@ if(NOT EXISTS "${PROJ_DATA_PATH}/proj.db") message(FATAL_ERROR "proj.db not found at ${PROJ_DATA_PATH}/proj.db") endif() -install(DIRECTORY "${PROJ_DATA_PATH}/" DESTINATION "${CMAKE_INSTALL_DATADIR}/proj") -install(DIRECTORY "${VCPKG_BASE_DIR}/share/gdal/" DESTINATION "${CMAKE_INSTALL_DATADIR}/gdal") -install(DIRECTORY "${VCPKG_BASE_DIR}/bin/Qca/" DESTINATION "bin/Qca") # QCA plugins -install(DIRECTORY "${VCPKG_BASE_DIR}/Qt6/" DESTINATION "bin/Qt6") # qt plugins (qml and others) +install(DIRECTORY "${PROJ_DATA_PATH}/" DESTINATION "${QGIS_DATA_SUBDIR}/proj") +install(DIRECTORY "${VCPKG_BASE_DIR}/share/gdal/" DESTINATION "${QGIS_DATA_SUBDIR}/gdal") +if(MSVC) + install(DIRECTORY "${VCPKG_BASE_DIR}/bin/Qca/crypto/" DESTINATION "${QGIS_LIB_SUBDIR}/Qt6/plugins/crypto") # QCA plugins +else() + install(DIRECTORY "${VCPKG_BASE_DIR}/bin/Qca/crypto/" DESTINATION "${APP_PLUGINS_DIR}/crypto") # QCA plugins +endif() + +if(MSVC) + install(DIRECTORY "${VCPKG_BASE_DIR}/Qt6/" DESTINATION "${QGIS_LIB_SUBDIR}/Qt6") # qt plugins (qml and others) +else() + install(DIRECTORY "${VCPKG_BASE_DIR}/Qt6/plugins/" DESTINATION "${APP_PLUGINS_DIR}/") # qt plugins (qml and others) +endif() + if(WITH_BINDINGS) - install(DIRECTORY "${VCPKG_BASE_DIR}/tools/python3/" - DESTINATION "bin" + if(MSVC) + set(_SOURCE_PYTHON_DIR "${VCPKG_BASE_DIR}/tools/python3/") + set(_TARGET_PYTHON_DIR "bin") + elseif(CMAKE_SYSTEM_NAME STREQUAL "Darwin") + cmake_path(GET Python_SITEARCH PARENT_PATH _SOURCE_PYTHON_DIR) + set(_TARGET_PYTHON_DIR "${APP_FRAMEWORKS_DIR}/lib") + endif() + + install(DIRECTORY "${_SOURCE_PYTHON_DIR}" + DESTINATION "${_TARGET_PYTHON_DIR}" PATTERN "*.sip" EXCLUDE) endif() + +set(BUNDLED_EXECUTABLES + "tools/gdal/gdal_contour" + "tools/gdal/gdal_create" + "tools/gdal/gdal_footprint" + "tools/gdal/gdal_grid" + "tools/gdal/gdal_rasterize" + "tools/gdal/gdal_translate" + "tools/gdal/gdal_viewshed" + "tools/gdal/gdaladdo" + "tools/gdal/gdalbuildvrt" + "tools/gdal/gdaldem" + "tools/gdal/gdalenhance" + "tools/gdal/gdalinfo" + "tools/gdal/gdallocationinfo" + "tools/gdal/gdalmanage" + "tools/gdal/gdalmdiminfo" + "tools/gdal/gdalmdimtranslate" + "tools/gdal/gdalsrsinfo" + "tools/gdal/gdaltindex" + "tools/gdal/gdaltransform" + "tools/gdal/gdalwarp" + "tools/gdal/gnmanalyse" + "tools/gdal/gnmmanage" + "tools/gdal/nearblack" + "tools/gdal/ogr2ogr" + "tools/gdal/ogrinfo" + "tools/gdal/ogrlineref" + "tools/gdal/ogrtindex" + "tools/gdal/sozip" +) +if(NOT MSVC) + list(TRANSFORM BUNDLED_EXECUTABLES PREPEND "${VCPKG_BASE_DIR}/") + install(PROGRAMS ${BUNDLED_EXECUTABLES} + DESTINATION "${QGIS_BIN_SUBDIR}") +endif() + diff --git a/cmake_templates/qgsconfig.h.in b/cmake_templates/qgsconfig.h.in index b8f0949c9850..ab9ac0d682e5 100644 --- a/cmake_templates/qgsconfig.h.in +++ b/cmake_templates/qgsconfig.h.in @@ -37,11 +37,6 @@ #define QSCINTILLA_VERSION_STR "${QSCINTILLA_VERSION_STR}" #endif -#if defined( __APPLE__ ) -//used by Mac to find system or bundle resources relative to amount of bundling -#define QGIS_MACAPP_BUNDLE ${QGIS_MACAPP_BUNDLE} -#endif - #define PYTHON_VERSION "${Python_VERSION}" #define PYTHON_VERSION_MAJOR "${Python_VERSION_MAJOR}" #define PYTHON_VERSION_MINOR "${Python_VERSION_MINOR}" @@ -51,6 +46,8 @@ #define PROJ_VERSION_MINOR ${PROJ_VERSION_MINOR} #define PROJ_VERSION_PATCH ${PROJ_VERSION_PATCH} +#cmakedefine QGIS_MAC_BUNDLE + #cmakedefine USING_NMAKE #cmakedefine USING_NINJA diff --git a/images/icons/mac/CMakeLists.txt b/images/icons/mac/CMakeLists.txt index b2f9c905f209..89b80eab5851 100644 --- a/images/icons/mac/CMakeLists.txt +++ b/images/icons/mac/CMakeLists.txt @@ -2,5 +2,5 @@ if (WITH_DESKTOP) file (GLOB ICONS *.icns) install (FILES ${ICONS} - DESTINATION ${CMAKE_INSTALL_PREFIX}/../Resources) + DESTINATION ${APP_RESOURCES_DIR}) endif() diff --git a/images/icons/mac/qgis-dark.icns b/images/icons/mac/qgis-dark.icns new file mode 100644 index 000000000000..f98c0921b945 Binary files /dev/null and b/images/icons/mac/qgis-dark.icns differ diff --git a/images/icons/mac/qgis.icns b/images/icons/mac/qgis.icns index 8988161c2453..e317234f0d60 100644 Binary files a/images/icons/mac/qgis.icns and b/images/icons/mac/qgis.icns differ diff --git a/images/icons/mac/qgs.icns b/images/icons/mac/qgs.icns deleted file mode 100644 index 9b3c97465f77..000000000000 Binary files a/images/icons/mac/qgs.icns and /dev/null differ diff --git a/mac/CMakeLists.txt b/mac/CMakeLists.txt deleted file mode 100644 index 9b7a9f8cde2d..000000000000 --- a/mac/CMakeLists.txt +++ /dev/null @@ -1,31 +0,0 @@ -# mac bundling must happen at end, so all binaries installed -# and install_names can be adjusted -if (APPLE AND QGIS_MACAPP_BUNDLE GREATER -1) - # for included scripts that set policies (ie OS X bundling) - install (CODE "cmake_policy(SET CMP0011 NEW)") - configure_file (cmake/0vars.cmake.in 0vars.cmake @ONLY) - configure_file (cmake/0qgis.cmake.in 0qgis.cmake @ONLY) - install (SCRIPT ${CMAKE_BINARY_DIR}/mac/0qgis.cmake) - if (QGIS_MACAPP_BUNDLE GREATER 0) - # start with Qt - configure_file (cmake/1qt.cmake.in 1qt.cmake @ONLY) - install (SCRIPT ${CMAKE_BINARY_DIR}/mac/1qt.cmake) - if (QGIS_MACAPP_BUNDLE GREATER 1) - # next - libs - configure_file (cmake/2lib.cmake.in 2lib.cmake @ONLY) - install (SCRIPT ${CMAKE_BINARY_DIR}/mac/2lib.cmake) - if (QGIS_MACAPP_BUNDLE GREATER 2) - # last - frameworks - configure_file (cmake/3fw.cmake.in 3fw.cmake @ONLY) - install (SCRIPT ${CMAKE_BINARY_DIR}/mac/3fw.cmake) - endif() - endif() - endif() - # user bundling - if (QGIS_MACAPP_BUNDLE_USER) - configure_file (${QGIS_MACAPP_BUNDLE_USER} 4user.cmake @ONLY) - install (SCRIPT ${CMAKE_BINARY_DIR}/mac/4user.cmake) - endif() - # tickle app bundle - install (CODE "execute_process(COMMAND touch \"$ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}/../../.\")") -endif() diff --git a/mac/cmake/0qgis.cmake.in b/mac/cmake/0qgis.cmake.in deleted file mode 100644 index 9be19f7ab5be..000000000000 --- a/mac/cmake/0qgis.cmake.in +++ /dev/null @@ -1,31 +0,0 @@ -# 0qgis - fixup install_names for @loader_path -# ! cmakecache vars not available to external scripts -# so we configure it first to do substitutions -# make sure to use @varname@ - -# kill boolean warnings -CMAKE_POLICY (SET CMP0012 NEW) - -INCLUDE ("@CMAKE_BINARY_DIR@/mac/0vars.cmake") -INCLUDE ("@CMAKE_SOURCE_DIR@/cmake/MacBundleMacros.cmake") - -# assume all install_names start with CMAKE_INSTALL_NAME_DIR -# so we don't have to extract it from binaries -# leave main qgis executable and qgis_help with executable_paths - -MESSAGE (STATUS "Updating QGIS library paths...") -# inter-library links - do all combos, many will be noops -FOREACH (QL ${QGFWLIST}) - GET_INSTALL_NAME ("${QFWDIR}/${QL}.framework/${QL}" ${QL}.framework QQ) - SET (QFW_CHG "${QQ}") - UPDATEQGISPATHS ("${QFW_CHG}" ${QL}) - # change id of the framework - IF (NOT @QGIS_MACAPP_INSTALL_DEV@) - EXECUTE_PROCESS(COMMAND install_name_tool -id "${ATEXECUTABLE}/${QGIS_FW_SUBDIR}/${QL}.framework/${QL}" "${QFWDIR}/${QL}.framework/${QL}") - ENDIF () -ENDFOREACH (QL) -FOREACH (QLIB ${QGLIBLIST}) - GET_INSTALL_NAME ("${QLIBDIR}/${QLIB}" ${QLIB} QQ) - SET (QLIB_CHG "${QQ}") - UPDATEQGISPATHS ("${QLIB_CHG}" ${QLIB}) -ENDFOREACH (QLIB) diff --git a/mac/cmake/0vars.cmake.in b/mac/cmake/0vars.cmake.in deleted file mode 100644 index f1ff5eb39122..000000000000 --- a/mac/cmake/0vars.cmake.in +++ /dev/null @@ -1,70 +0,0 @@ -# 0vars - redefine cmakecache vars, needed by all other bundling scripts -# ! cmakecache vars not available to external scripts -# so we configure it first to do substitutions -# make sure to use @varname@ - -# kill boolean warnings -CMAKE_POLICY (SET CMP0012 NEW) - -# cmake -SET (CPACK_PACKAGE_VERSION_MAJOR @CPACK_PACKAGE_VERSION_MAJOR@) -SET (CPACK_PACKAGE_VERSION_MINOR @CPACK_PACKAGE_VERSION_MINOR@) -SET (CMAKE_VERBOSE_MAKEFILE "@CMAKE_VERBOSE_MAKEFILE@") -SET (CMAKE_INSTALL_PREFIX "@CMAKE_INSTALL_PREFIX@") -SET (CMAKE_BUILD_TYPE "@CMAKE_BUILD_TYPE@") - -# Qt5 cmake does not create overall qt prefix var, only individual lib prefixes. -# For simplicity, assume core prefix same as all others -SET (QT_LIBRARY_DIR "@_qt5Core_install_prefix@/lib") - -# OS X options -SET (CMAKE_OSX_ARCHITECTURES "@CMAKE_OSX_ARCHITECTURES@") - -# QGIS -SET (QGIS_APP_NAME "@QGIS_APP_NAME@") -SET (QGIS_MACAPP_PREFIX "@QGIS_MACAPP_PREFIX@") -SET (QGIS_FW_SUBDIR "@QGIS_FW_SUBDIR@") -SET (QGIS_FW_SUBDIR_REV "@QGIS_FW_SUBDIR_REV@") -SET (QGIS_BIN_SUBDIR "@QGIS_BIN_SUBDIR@") -SET (QGIS_BIN_SUBDIR_REV "@QGIS_BIN_SUBDIR_REV@") -SET (QGIS_CGIBIN_SUBDIR "@QGIS_CGIBIN_SUBDIR@") -SET (QGIS_CGIBIN_SUBDIR_REV "@QGIS_CGIBIN_SUBDIR_REV@") -SET (QGIS_LIB_SUBDIR "@QGIS_LIB_SUBDIR@") -SET (QGIS_LIB_SUBDIR_REV "@QGIS_LIB_SUBDIR_REV@") -SET (QGIS_LIBEXEC_SUBDIR "@QGIS_LIBEXEC_SUBDIR@") -SET (QGIS_LIBEXEC_SUBDIR_REV "@QGIS_LIBEXEC_SUBDIR_REV@") -SET (QGIS_PLUGIN_SUBDIR "@QGIS_PLUGIN_SUBDIR@") -SET (QGIS_PLUGIN_SUBDIR_REV "@QGIS_PLUGIN_SUBDIR_REV@") -SET (QGIS_DATA_SUBDIR "@QGIS_DATA_SUBDIR@") -SET (QGIS_DATA_SUBDIR_REV "@QGIS_DATA_SUBDIR_REV@") -SET (QGIS_SERVER_MODULE_SUBDIR "@QGIS_SERVER_MODULE_SUBDIR@") - -# optional components -SET (WITH_GRASS "@WITH_GRASS@") -SET (WITH_SERVER "@WITH_SERVER@") -SET (WITH_POSTGRESQL "@WITH_POSTGRESQL@") -SET (WITH_QSPATIALITE "@WITH_QSPATIALITE@") - -# tests -SET (ENABLE_TESTS "@ENABLE_TESTS@") - -# Python module search paths -# Allows overriding build variables with PYTHONPATH -# Handles case where resolved symlinked modules may not be where other resolved modules exist, e.g. -# a site-packages directory where all packages/modules are symlinked in (like Homebrew), -# and their respective install prefixes are completely different -# This also handles migration to next-gen sip/PyQt setup where sipconfig and pyqtconfig don't exist -# and the sys.paths used to import the modules dictates how the modules are found -# see: https://github.com/qgis/QGIS/pull/1508 -SET (PYTHON_MODULE_PATHS) -STRING(REPLACE ":" ";" _pythonpath "$ENV{PYTHONPATH}") -LIST(APPEND PYTHON_MODULE_PATHS ${_pythonpath}) -IF (EXISTS "@PYQT5_MOD_DIR@") - LIST(APPEND PYTHON_MODULE_PATHS "@PYQT5_MOD_DIR@") -ENDIF () -IF (EXISTS "@SIP_MODULE_DIR@") - LIST(APPEND PYTHON_MODULE_PATHS "@SIP_MODULE_DIR@") -ENDIF () -IF (EXISTS "@PYTHON_SITE_PACKAGES_SYS@") - LIST(APPEND PYTHON_MODULE_PATHS "@PYTHON_SITE_PACKAGES_SYS@") -ENDIF () diff --git a/mac/cmake/1qt.cmake.in b/mac/cmake/1qt.cmake.in deleted file mode 100644 index 25385f98e610..000000000000 --- a/mac/cmake/1qt.cmake.in +++ /dev/null @@ -1,509 +0,0 @@ -# 1qt - bundle Qt frameworks and PyQt -# ! cmakecache vars not available to external scripts -# so we configure it first to do substitutions -# make sure to use @varname@ - -# kill boolean warnings -CMAKE_POLICY (SET CMP0012 NEW) - -INCLUDE ("@CMAKE_BINARY_DIR@/mac/0vars.cmake") -INCLUDE ("@CMAKE_SOURCE_DIR@/cmake/MacBundleMacros.cmake") -INCLUDE ("@CMAKE_SOURCE_DIR@/cmake/QCAMacros.cmake") - -# Qt framework version is major version -SET (QT_FWVER "5") - -# build list of Qt frameworks to bundle - -# core list, includes dependencies and used by extra plugins -SET (QTLISTQG QtCore QtGui QtWidgets QtNetwork QtXml QtSvg QtConcurrent QtPrintSupport QtSerialPort QtPositioning QtTest QtSql QtDBus) -SET (PYQTLIST Qt QtCore QtGui QtWidgets QtNetwork QtXml QtSvg QtPrintSupport QtPositioning QtSerialPort QtTest QtSql QtDBus) - -# QtQuickWidgets appears to be implied direct dep, it needs Quick and Qml, -# whether or not WITH_QUICK specified -SET (QTLISTQG ${QTLISTQG} QtQuickWidgets QtQuick QtQml) -SET (PYQTLIST ${PYQTLIST} QtQuickWidgets QtQuick QtQml) - -IF(@WITH_QTWEBKIT@) - SET (QTLISTQG ${QTLISTQG} QtWebKit QtWebKitWidgets QtSensors QtWebChannel QtMultimedia QtMultimediaWidgets QtOpenGL) - SET (PYQTLIST ${PYQTLIST} QtWebKit QtWebKitWidgets QtSensors QtWebChannel QtMultimedia QtMultimediaWidgets QtOpenGL) -ENDIF () - -IF(@WITH_3D@) - SET (QTLISTQG ${QTLISTQG} Qt3DCore Qt3DRender Qt3DInput Qt3DLogic Qt3DExtras QtGamepad) - SET (PYQTLIST ${PYQTLIST} Qt3DCore Qt3DRender Qt3DInput Qt3DLogic Qt3DExtras QtGamepad) -ENDIF () - -# add Qsci.so, if available -IF (@QSCI_FOUND@) - SET (PYQTLIST ${PYQTLIST} Qsci) -ENDIF (@QSCI_FOUND@) - -MYMESSAGE ("Qt list: ${QTLISTQG}") - -# symlinks when only @executable_path used - -EXECUTE_PROCESS (COMMAND ln -sfn ../Frameworks "${QAPPDIR}/") -IF (IS_DIRECTORY "${QLIBDIR}/grass/bin") - EXECUTE_PROCESS (COMMAND ln -sfn ../@QGIS_LIBEXEC_SUBDIR_REV@/@QGIS_FW_SUBDIR@ "${QLIBDIR}/grass/Frameworks") -ENDIF () -EXECUTE_PROCESS (COMMAND ln -sfn @QGIS_CGIBIN_SUBDIR_REV@/@QGIS_LIB_SUBDIR@ "${QCGIDIR}/lib") - -### copy files & strip qt rpath - -# Qt frameworks -# Qt5 cmake does not create overall qt prefix var, only individual lib prefixes. -# For simplicity, assume core prefix same as all others. - -MESSAGE (STATUS "Copying Qt frameworks...") -EXECUTE_PROCESS (COMMAND mkdir -p "${QFWDIR}") -FOREACH (QFW ${QTLISTQG}) - IF (NOT IS_DIRECTORY "${QFWDIR}/${QFW}.framework") - COPY_FRAMEWORK("${QT_LIBRARY_DIR}" ${QFW} "${QFWDIR}") - EXECUTE_PROCESS (COMMAND install_name_tool -delete_rpath "@QT_LIBRARY_DIR@" "${QFWDIR}/${QFW}.framework/${QFW}") - ENDIF () -ENDFOREACH (QFW) - -# Qt plugins - -EXECUTE_PROCESS (COMMAND mkdir -p "${QPLUGDIR}/../imageformats") -FOREACH (QI qgif;qico;qjpeg;qsvg;qtiff) - IF (NOT EXISTS "${QPLUGDIR}/../imageformats/lib${QI}.dylib") - EXECUTE_PROCESS (COMMAND ditto ${QARCHS} "@QT_PLUGINS_DIR@/imageformats/lib${QI}.dylib" "${QPLUGDIR}/../imageformats/lib${QI}.dylib") - EXECUTE_PROCESS (COMMAND install_name_tool -delete_rpath "@QT_LIBRARY_DIR@" "${QPLUGDIR}/../imageformats/lib${QI}.dylib") - ENDIF () -ENDFOREACH (QI) -EXECUTE_PROCESS (COMMAND mkdir -p "${QPLUGDIR}/../platforms") -FOREACH (QTP cocoa;minimal;offscreen) - IF (NOT EXISTS "${QPLUGDIR}/../platforms/libq${QTP}.dylib") - EXECUTE_PROCESS (COMMAND ditto ${QARCHS} "@QT_PLUGINS_DIR@/platforms/libq${QTP}.dylib" "${QPLUGDIR}/../platforms/libq${QTP}.dylib") - EXECUTE_PROCESS (COMMAND install_name_tool -delete_rpath "@QT_LIBRARY_DIR@" "${QPLUGDIR}/../platforms/libq${QTP}.dylib") - ENDIF () -ENDFOREACH (QTP) -EXECUTE_PROCESS (COMMAND mkdir -p "${QPLUGDIR}/../sqldrivers") -SET (QTLISTSQL ite odbc psql mysql) -# qspatialite driver plugin is part of QGIS build -IF (@WITH_QSPATIALITE@) - LIST(APPEND QTLISTSQL spatialite) - IF (EXISTS "${QPLUGDIR}/../sqldrivers/libqsqlspatialite.dylib") - EXECUTE_PROCESS (COMMAND ${CMAKE_COMMAND} -E remove "${QPLUGDIR}/../sqldrivers/libqsqlspatialite.dylib") - EXECUTE_PROCESS (COMMAND install_name_tool -delete_rpath "@QT_LIBRARY_DIR@" "${QPLUGDIR}/../sqldrivers/libqsqlspatialite.dylib") - ENDIF () -ENDIF () -FOREACH (QSL ${QTLISTSQL}) - IF (NOT EXISTS "${QPLUGDIR}/../sqldrivers/libqsql${QSL}.dylib" AND EXISTS "@QT_PLUGINS_DIR@/sqldrivers/libqsql${QSL}.dylib") - EXECUTE_PROCESS (COMMAND ditto ${QARCHS} "@QT_PLUGINS_DIR@/sqldrivers/libqsql${QSL}.dylib" "${QPLUGDIR}/../sqldrivers/libqsql${QSL}.dylib") - EXECUTE_PROCESS (COMMAND install_name_tool -delete_rpath "@QT_LIBRARY_DIR@" "${QPLUGDIR}/../sqldrivers/libqsql${QSL}.dylib") - ENDIF () -ENDFOREACH (QSL) -IF (NOT @WITH_QSPATIALITE@ AND EXISTS "${QPLUGDIR}/../sqldrivers/libqsqlspatialite.dylib") - EXECUTE_PROCESS (COMMAND ${CMAKE_COMMAND} -E remove "${QPLUGDIR}/../sqldrivers/libqsqlspatialite.dylib") -ENDIF () -EXECUTE_PROCESS (COMMAND mkdir -p "${QPLUGDIR}/../iconengines") -IF (NOT EXISTS "${QPLUGDIR}/../iconengines/libqsvgicon.dylib") - EXECUTE_PROCESS (COMMAND ditto ${QARCHS} "@QT_PLUGINS_DIR@/iconengines/libqsvgicon.dylib" "${QPLUGDIR}/../iconengines/libqsvgicon.dylib") - EXECUTE_PROCESS (COMMAND install_name_tool -delete_rpath "@QT_LIBRARY_DIR@" "${QPLUGDIR}/../iconengines/libqsvgicon.dylib") -ENDIF () -EXECUTE_PROCESS (COMMAND mkdir -p "${QPLUGDIR}/../styles") -IF (NOT EXISTS "${QPLUGDIR}/../styles/libqmacstyle.dylib") - EXECUTE_PROCESS (COMMAND ditto ${QARCHS} "@QT_PLUGINS_DIR@/styles/libqmacstyle.dylib" "${QPLUGDIR}/../styles/libqmacstyle.dylib") - EXECUTE_PROCESS (COMMAND install_name_tool -delete_rpath "@QT_LIBRARY_DIR@" "${QPLUGDIR}/../styles/libqmacstyle.dylib") -ENDIF () - -# Qwt - -STRING (REGEX MATCH "\\.dylib$" QWT_ISLIB "@QWT_LIBRARY@") -STRING (REGEX MATCH "qwt.framework" QWT_ISFW "@QWT_LIBRARY@") -IF (QWT_ISLIB) - # shared libraries - MESSAGE (STATUS "Copying Qwt and updating library paths...") - IF (NOT EXISTS "${QLIBDIR}/libqwt.dylib") - EXECUTE_PROCESS (COMMAND ditto ${QARCHS} "@QWT_LIBRARY@" "${QLIBDIR}/libqwt.dylib") - EXECUTE_PROCESS (COMMAND install_name_tool -delete_rpath "@QT_LIBRARY_DIR@" "${QLIBDIR}/libqwt.dylib") - ENDIF () - GET_INSTALL_NAME ("@QWT_LIBRARY@" "libqwt" QWT_CHG) - IF (QWT_CHG) - UPDATEQGISPATHS (${QWT_CHG} libqwt.dylib) - ENDIF (QWT_CHG) -ELSEIF (QWT_ISFW AND EXISTS "@QWT_LIBRARY@") - # framework - MESSAGE (STATUS "Copying Qwt framework and updating library paths...") - STRING(REGEX REPLACE "/qwt.framework.*" "" QWT_PARENT "@QWT_LIBRARY@") - IF (NOT IS_DIRECTORY "${QFWDIR}/qwt.framework") - COPY_FRAMEWORK("${QWT_PARENT}" "qwt" "${QFWDIR}") - EXECUTE_PROCESS (COMMAND install_name_tool -delete_rpath "@QT_LIBRARY_DIR@" "${QFWDIR}/qwt.framework/qwt") - ENDIF () - GET_INSTALL_NAME ("${QWT_PARENT}/qwt.framework/qwt" "qwt.framework" QWT_CHG) - IF (QWT_CHG) - UPDATEQGISPATHS (${QWT_CHG} qwt) - ENDIF (QWT_CHG) -ENDIF (QWT_ISLIB) - - -# QwtPolar - -IF (@WITH_DESKTOP@) - IF (@WITH_QWTPOLAR@ AND NOT @WITH_INTERNAL_QWTPOLAR@) - STRING (REGEX MATCH "\\.dylib$" ISLIB "@QWTPOLAR_LIBRARY@") - STRING (REGEX MATCH "qwtpolar.framework" ISFW "@QWTPOLAR_LIBRARY@") - IF (ISLIB) - # shared libraries - MESSAGE (STATUS "Copying QwtPolar and updating library paths...") - IF (NOT EXISTS "${QLIBDIR}/libqwtpolar.dylib") - EXECUTE_PROCESS (COMMAND ditto ${QARCHS} "@QWT_LIBRARY@" "${QLIBDIR}/libqwtpolar.dylib") - EXECUTE_PROCESS (COMMAND install_name_tool -delete_rpath "@QT_LIBRARY_DIR@" "${QLIBDIR}/libqwtpolar.dylib") - ENDIF () - GET_INSTALL_NAME ("@QWTPOLAR_LIBRARY@" "libqwtpolar" QWTP_CHG) - IF (QWTP_CHG) - UPDATEQGISPATHS (${QWTP_CHG} libqwtpolar.dylib) - ENDIF (QWTP_CHG) - # update qwt lib in qwtpolar - IF (QWT_CHG) - IF (QWT_ISLIB) - SET (QWT_CHG_TO "${ATLOADER}/libqwt.dylib") - ElSE () - SET (QWT_CHG_TO "${ATLOADER}/${QGIS_LIB_SUBDIR_REV}/${QGIS_FW_SUBDIR}/qwt.framework/qwt") - ENDIF () - INSTALLNAMETOOL_CHANGE ("${QWT_CHG}" "${QWT_CHG_TO}" "${QLIBDIR}/libqwtpolar.dylib") - ENDIF (QWT_CHG) - ELSEIF (ISFW AND EXISTS "@QWTPOLAR_LIBRARY@") - # framework - MESSAGE (STATUS "Copying QwtPolar framework and updating library paths...") - STRING(REGEX REPLACE "/qwtpolar.framework.*" "" QWTP_PARENT "@QWTPOLAR_LIBRARY@") - IF (NOT IS_DIRECTORY "${QFWDIR}/qwtpolar.framework") - COPY_FRAMEWORK("${QWTP_PARENT}" "qwtpolar" "${QFWDIR}") - EXECUTE_PROCESS (COMMAND install_name_tool -delete_rpath "@QT_LIBRARY_DIR@" "${QFWDIR}/qwtpolar.framework/qwtpolar") - ENDIF () - GET_INSTALL_NAME ("${QWTP_PARENT}/qwtpolar.framework/qwtpolar" "qwtpolar.framework" QWTP_CHG) - IF (QWTP_CHG) - UPDATEQGISPATHS (${QWTP_CHG} qwtpolar) - ENDIF (QWTP_CHG) - # update qwt lib in qwtpolar - IF (QWT_CHG) - IF (QWT_ISLIB) - SET (QWT_CHG_TO "${ATLOADER}/../../../${QGIS_FW_SUBDIR_REV}/${QGIS_LIB_SUBDIR}/libqwt.dylib") - ElSE () - SET (QWT_CHG_TO "${ATLOADER}/../../../qwt.framework/qwt") - ENDIF () - INSTALLNAMETOOL_CHANGE ("${QWT_CHG}" "${QWT_CHG_TO}" "${QFWDIR}/qwtpolar.framework/qwtpolar") - ENDIF (QWT_CHG) - ENDIF (ISLIB) - ENDIF (@WITH_QWTPOLAR@ AND NOT @WITH_INTERNAL_QWTPOLAR@) -ENDIF (@WITH_DESKTOP@) - -# QCA - -STRING (REGEX MATCH "\\.dylib$" ISLIB "@QCA_LIBRARY@") -STRING (REGEX MATCH "qca.*.framework" ISFW "@QCA_LIBRARY@") -IF (ISLIB) - # shared libraries - MESSAGE (STATUS "Copying QCA and updating library paths...") - SET (QCA_CHG_TO "${ATLOADER}/@QGIS_PLUGIN_SUBDIR_REV@/${QGIS_LIB_SUBDIR}/libqca.dylib") - IF (NOT EXISTS "${QLIBDIR}/libqca.dylib") - EXECUTE_PROCESS (COMMAND ditto ${QARCHS} "@QCA_LIBRARY@" "${QLIBDIR}/libqca.dylib") - EXECUTE_PROCESS (COMMAND install_name_tool -delete_rpath "@QT_LIBRARY_DIR@" "${QLIBDIR}/libqca.dylib") - ENDIF () - GET_INSTALL_NAME ("@QCA_LIBRARY@" "libqca" QCA_CHG) - IF (QCA_CHG) - UPDATEQGISPATHS (${QCA_CHG} libqca.dylib) - ENDIF () -ELSEIF (ISFW AND EXISTS "@QCA_LIBRARY@") - # framework - MESSAGE (STATUS "Copying QCA framework and updating library paths...") - SET (QCA_LIBRARY "@QCA_LIBRARY@") - STRING (REGEX MATCH "qca-qt5" _has_long_name "${QCA_LIBRARY}") - IF (_has_long_name) - SET (_qca_libname "qca-qt5") - ELSE () - SET (_qca_libname "qca") - ENDIF () - STRING (REGEX MATCH "${_qca_libname}.framework/${_qca_libname}" _has_bin "${QCA_LIBRARY}") - IF (NOT _has_bin) - SET (QCA_LIBRARY "${QCA_LIBRARY}/${_qca_libname}") - ENDIF () - SET (QCA_CHG_TO "${ATLOADER}/@QGIS_PLUGIN_SUBDIR_REV@/${QGIS_FW_SUBDIR}/${_qca_libname}.framework/${_qca_libname}") - IF (NOT IS_DIRECTORY "${QFWDIR}/${_qca_libname}.framework") - STRING(REGEX REPLACE "/${_qca_libname}.framework.*" "" QCA_PARENT "@QCA_LIBRARY@") - COPY_FRAMEWORK("${QCA_PARENT}" "${_qca_libname}" "${QFWDIR}") - EXECUTE_PROCESS (COMMAND install_name_tool -delete_rpath "@QT_LIBRARY_DIR@" "${QFWDIR}/${_qca_libname}.framework/${_qca_libname}") - ENDIF () - GET_INSTALL_NAME ("${QCA_LIBRARY}" "${_qca_libname}" QCA_CHG) - IF (QCA_CHG) - UPDATEQGISPATHS (${QCA_CHG} ${_qca_libname}) - ENDIF () -ENDIF () -# copy and relink the plugins -EXECUTE_PROCESS (COMMAND mkdir -p "${QPLUGDIR}/../crypto") -FIND_QCA_PLUGIN_DIR (1) -MESSAGE (STATUS "Updating QCA plugins with QCA library path in ${QCA_PLUGIN_DIR} ...") -# don't copy over any unneeded plugins -SET(QCA_PLUGINS logger ossl softstore) -FOREACH (qca_plugin ${QCA_PLUGINS}) - EXECUTE_PROCESS (COMMAND ditto ${QARCHS} "${QCA_PLUGIN_DIR}/crypto/libqca-${qca_plugin}.dylib" "${QPLUGDIR}/../crypto/") - EXECUTE_PROCESS (COMMAND install_name_tool -delete_rpath "@QT_LIBRARY_DIR@" "${QCA_PLUGIN_DIR}/crypto/libqca-${qca_plugin}.dylib") - IF (QCA_CHG) - INSTALLNAMETOOL_CHANGE ("${QCA_CHG}" "${QCA_CHG_TO}" "${QPLUGDIR}/../crypto/libqca-${qca_plugin}.dylib") - ENDIF () -ENDFOREACH () - -# QSpatialite Qt plugin -# linked to qca and qgis_core frameworks (see also 2lib.cmake.in) -IF (@WITH_QSPATIALITE@ AND EXISTS "${QPLUGDIR}/../sqldrivers/libqsqlspatialite.dylib") - # qca.framework - EXECUTE_PROCESS (COMMAND install_name_tool -delete_rpath "@QT_LIBRARY_DIR@" "${QPLUGDIR}/../sqldrivers/libqsqlspatialite.dylib") - INSTALLNAMETOOL_CHANGE ("${QCA_CHG}" "${QCA_CHG_TO}" "${QPLUGDIR}/../sqldrivers/libqsqlspatialite.dylib") - # qgis_core.framework - GET_INSTALL_NAME ("@QGIS_OUTPUT_DIRECTORY@/lib/qgis_core.framework/qgis_core" qgis_core.framework QGCORE) - SET (QGCORE_CHG_TO "${ATLOADER}/@QGIS_PLUGIN_SUBDIR_REV@/${QGIS_FW_SUBDIR}/qgis_core.framework/qgis_core") - INSTALLNAMETOOL_CHANGE ("${QGCORE}" "${QGCORE_CHG_TO}" "${QPLUGDIR}/../sqldrivers/libqsqlspatialite.dylib") -ENDIF () - -# QScintilla2 - -IF (@QSCINTILLA_LIBRARY@ MATCHES ".*libqscintilla2_qt5.*dylib") - SET (QSCI_LIB "libqscintilla2_qt5") -ELSEIF (@QSCINTILLA_LIBRARY@ MATCHES ".*libqscintilla2.*dylib") - SET (QSCI_LIB "libqscintilla2") -ENDIF () -IF (QSCI_LIB) - MESSAGE (STATUS "Copying QScintilla2 library and updating library paths...") - EXECUTE_PROCESS (COMMAND ditto ${QARCHS} "@QSCINTILLA_LIBRARY@" "${QLIBDIR}/${QSCI_LIB}.dylib") - EXECUTE_PROCESS (COMMAND install_name_tool -delete_rpath "@QT_LIBRARY_DIR@" "${QLIBDIR}/${QSCI_LIB}.dylib") - GET_INSTALL_NAME ("@QSCINTILLA_LIBRARY@" "${QSCI_LIB}" QSCI_CHG) - IF (QSCI_CHG) - UPDATEQGISPATHS (${QSCI_CHG} ${QSCI_LIB}.dylib) - ENDIF (QSCI_CHG) -ENDIF () - -# QtKeychain - -IF (@QTKEYCHAIN_LIBRARY@ MATCHES ".*libqt5keychain.dylib") - MESSAGE (STATUS "Copying QtKeychain library and updating library paths...") - EXECUTE_PROCESS (COMMAND ditto ${QARCHS} "@QTKEYCHAIN_LIBRARY@" "${QLIBDIR}/libqt5keychain.dylib") - EXECUTE_PROCESS (COMMAND install_name_tool -delete_rpath "@QT_LIBRARY_DIR@" "${QLIBDIR}/libqt5keychain.dylib") - GET_INSTALL_NAME ("@QTKEYCHAIN_LIBRARY@" "libqt5keychain" QTKEY_CHG) - IF (QTKEY_CHG) - UPDATEQGISPATHS (${QTKEY_CHG} libqt5keychain.dylib) - ENDIF (QTKEY_CHG) -ENDIF () - -# Tell user what Python paths are being searched for modules and packages -# see: PYTHON_MODULE_PATHS in 0vars.cmake.in for why not all PyQt-related modules -# can be assumed to exist in symlinked-resolved PyQt or sip module directories -MESSAGE (STATUS "PYTHON_MODULE_PATHS to be searched:") -FOREACH (PYPATH ${PYTHON_MODULE_PATHS}) - MESSAGE (STATUS " ${PYPATH}") -ENDFOREACH (PYPATH) - -# sip and PyQt - -MESSAGE (STATUS "Copying sip...") -PYTHONMODULEDIR("sip.so" SIPMODDIR) -IF (SIPMODDIR) - IF (NOT EXISTS "${QGISPYDIR}/sip.so" AND NOT EXISTS "${QGISPYDIR}/PyQt5/sip.so") - # MYMESSAGE ("ditto ${QARCHS} \"${SIPMODDIR}/sip.so\" \"${QGISPYDIR}/\"") - IF (${SIPMODDIR} MATCHES ".*PyQt5.*") - EXECUTE_PROCESS (COMMAND ditto ${QARCHS} "${SIPMODDIR}/sip.so" "${QGISPYDIR}/PyQt5/") - EXECUTE_PROCESS (COMMAND install_name_tool -delete_rpath "@QT_LIBRARY_DIR@" "${QGISPYDIR}/PyQt5/sip.so") - ELSE () - EXECUTE_PROCESS (COMMAND ditto ${QARCHS} "${SIPMODDIR}/sip.so" "${QGISPYDIR}/") - EXECUTE_PROCESS (COMMAND install_name_tool -delete_rpath "@QT_LIBRARY_DIR@" "${QGISPYDIR}/sip.so") - ENDIF () - EXECUTE_PROCESS (COMMAND cp -fp "${SIPMODDIR}/sipconfig.py" "${QGISPYDIR}/") - ENDIF () -ELSE () - MESSAGE (STATUS " sip module not found") -ENDIF () - -MESSAGE (STATUS "Copying PyQt...") -EXECUTE_PROCESS (COMMAND mkdir -p "${QGISPYDIR}/PyQt${QT_FWVER}") -FOREACH (PQ ${PYQTLIST}) - SET (MODNAME "${PQ}.so") - SET (MODPYI "PyQt${QT_FWVER}/${PQ}.pyi") - SET (MODSUBPATH "PyQt${QT_FWVER}/${MODNAME}") - # search for each module separately, instead of only in first found PyQt directory, since PyQt may - # be installed to its a specific prefix, like with Homebrew, then symlinked into common 'site-packages' - PYTHONMODULEDIR("${MODSUBPATH}" MODDIR) - IF (MODDIR) - IF (NOT EXISTS "${QGISPYDIR}/${MODSUBPATH}") - # MESSAGE (STATUS "ditto ${QARCHS} \"${PYQT5MOD}\" \"${QGISPYDIR}/${MODSUBPATH}\"") - EXECUTE_PROCESS (COMMAND ditto ${QARCHS} "${MODDIR}/${MODSUBPATH}" "${QGISPYDIR}/${MODSUBPATH}") - EXECUTE_PROCESS (COMMAND install_name_tool -delete_rpath "@QT_LIBRARY_DIR@" "${QGISPYDIR}/${MODSUBPATH}") - IF (EXISTS "${MODDIR}/${MODPYI}") - EXECUTE_PROCESS (COMMAND ditto "${MODDIR}/${MODPYI}" "${QGISPYDIR}/${MODPYI}") - ENDIF () - ENDIF () - ELSE (MODDIR) - MESSAGE (STATUS " PyQt5 module ${MODNAME} not found") - ENDIF (MODDIR) - UNSET(PYQT5MOD) -ENDFOREACH (PQ) -PYTHONMODULEDIR("PyQt${QT_FWVER}" PYQTMODDIR) -FILE (GLOB PQPYLIST "${PYQTMODDIR}/PyQt${QT_FWVER}/*.py*") -FOREACH (PQPY ${PQPYLIST}) - EXECUTE_PROCESS (COMMAND cp -fp "${PQPY}" "${QGISPYDIR}/PyQt${QT_FWVER}/") -ENDFOREACH (PQPY) -EXECUTE_PROCESS (COMMAND cp -RfpL "${PYQTMODDIR}/PyQt${QT_FWVER}/uic" "${QGISPYDIR}/PyQt${QT_FWVER}") - -# PyQt utilities - -FOREACH (PU pylupdate5;pyrcc5) - IF (NOT EXISTS "${QBINDIR}/${PU}") - EXECUTE_PROCESS (COMMAND ditto ${QARCHS} "@PYQT5_BIN_DIR@/${PU}" "${QBINDIR}/") - ENDIF () -ENDFOREACH (PU) -IF (NOT EXISTS "${QBINDIR}/pyuic5") - EXECUTE_PROCESS (COMMAND sed -E "s, /.*/PyQt5/uic/pyuic.py, \"\$(/usr/bin/dirname \"\$0\")/../../Resources/python/PyQt5/uic/pyuic.py\"," "@PYQT5_BIN_DIR@/pyuic5" - OUTPUT_VARIABLE PYUIC_CONTENTS) - FILE (WRITE "${QBINDIR}/pyuic4" "${PYUIC_CONTENTS}") - EXECUTE_PROCESS (COMMAND chmod +x "${QBINDIR}/pyuic4") -ENDIF () - -# PyQwt -# only if it's available, not compatible with newer PyQt -PYTHONMODULEDIR("Qwt5/_iqt.so" QWT4MODDIR) -IF (QWT4MODDIR) - MESSAGE (STATUS "Copying PyQwt and updating library paths...") - EXECUTE_PROCESS (COMMAND mkdir -p "${QGISPYDIR}/PyQt${QT_FWVER}/Qwt5") - IF (NOT EXISTS "${QGISPYDIR}/PyQt${QT_FWVER}/Qwt5/_iqt.so") - EXECUTE_PROCESS (COMMAND ditto ${QARCHS} "${QWT4MODDIR}/Qwt5/_iqt.so" "${QGISPYDIR}/PyQt${QT_FWVER}/Qwt5/") - ENDIF () - IF (NOT EXISTS "${QGISPYDIR}/PyQt${QT_FWVER}/Qwt5/Qwt.so") - EXECUTE_PROCESS (COMMAND ditto ${QARCHS} "${QWT4MODDIR}/Qwt5/Qwt.so" "${QGISPYDIR}/PyQt${QT_FWVER}/Qwt5/") - ENDIF () - FILE (GLOB PQWPYLIST "${QWT4MODDIR}/Qwt5/*.py") - FOREACH (PQWPY ${PQWPYLIST}) - EXECUTE_PROCESS (COMMAND cp -fp "${PQWPY}" "${QGISPYDIR}/PyQt${QT_FWVER}/Qwt5/") - ENDFOREACH (PQWPY) - IF (QWT_CHG) - SET (QWT_CHG_TO "${ATLOADER}/../../../@QGIS_DATA_SUBDIR_REV@/@QGIS_LIB_SUBDIR@/libqwt.dylib") - FOREACH (PW _iqt;Qwt) - INSTALLNAMETOOL_CHANGE ("${QWT_CHG}" "${QWT_CHG_TO}" "${QGISPYDIR}/PyQt${QT_FWVER}/Qwt5/${PW}.so") - ENDFOREACH (PW) - ENDIF (QWT_CHG) -ENDIF () - -# QScintilla Python module -# should have already been copied with PyQt modules - -IF (EXISTS "${QGISPYDIR}/PyQt${QT_FWVER}/Qsci.so") - MESSAGE (STATUS "Updating QScintilla2 Python module library paths...") - GET_INSTALL_NAME ("${QGISPYDIR}/PyQt${QT_FWVER}/Qsci.so" "${QSCI_LIB}" QSCI_CHG) - IF (QSCI_CHG) - SET (QSCI_CHG_TO "${ATEXECUTABLE}/@QGIS_LIB_SUBDIR@/${QSCI_LIB}.dylib") - SET (QSCI_CHG_TO "${ATLOADER}/../../@QGIS_DATA_SUBDIR_REV@/@QGIS_LIB_SUBDIR@/${QSCI_LIB}.dylib") - INSTALLNAMETOOL_CHANGE ("${QSCI_CHG}" "${QSCI_CHG_TO}" "${QGISPYDIR}/PyQt${QT_FWVER}/Qsci.so") - ENDIF (QSCI_CHG) -ENDIF () - -# don't load plugins from system-installed Qt -FILE (WRITE "${QAPPDIRC}/Resources/qt.conf" "") -FOREACH (QA ${QGAPPLIST}) - FILE (WRITE "${QBINDIR}/${QA}.app/Contents/Resources/qt.conf" "") -ENDFOREACH (QA) - -### update lib paths - -MESSAGE (STATUS "Updating Qt library paths...") - -FOREACH (QFW ${QTLISTQG}) - # get install names from installed in case bundled copy already changed - # from a previous install attempt - GET_INSTALL_NAME ("${QT_LIBRARY_DIR}/${QFW}.framework/${QFW}" ${QFW}.framework QQ) - SET (QFW_CHG "${QQ}") - # qgis stuff - UPDATEQGISPATHS ("${QFW_CHG}" ${QFW}) - - SET (LIBPOST "${QFW}.framework/${QFW}") - # Qwt - STRING (REGEX MATCH "\\.dylib$" ISLIB "@QWT_LIBRARY@") - STRING (REGEX MATCH "qwt.framework" ISFW "@QWT_LIBRARY@") - IF (ISLIB) - SET (QFW_CHG_TO "${ATLOADER}/${QGIS_LIB_SUBDIR_REV}/${QGIS_FW_SUBDIR}/${LIBPOST}") - INSTALLNAMETOOL_CHANGE ("${QFW_CHG}" "${QFW_CHG_TO}" "${QLIBDIR}/libqwt.dylib") - ELSEIF (ISFW AND EXISTS "${QFWDIR}/qwt.framework/qwt") - SET (QFW_CHG_TO "${ATLOADER}/../../../${LIBPOST}") - INSTALLNAMETOOL_CHANGE ("${QFW_CHG}" "${QFW_CHG_TO}" "${QFWDIR}/qwt.framework/qwt") - ENDIF (ISLIB) - # qtkeychain - STRING (REGEX MATCH "\\.dylib$" ISLIB "@QTKEYCHAIN_LIBRARY@") - STRING (REGEX MATCH "qt5keychain.framework" ISFW "@QTKEYCHAIN_LIBRARY@") - IF (ISLIB) - SET (QFW_CHG_TO "${ATLOADER}/${QGIS_LIB_SUBDIR_REV}/${QGIS_FW_SUBDIR}/${LIBPOST}") - INSTALLNAMETOOL_CHANGE ("${QFW_CHG}" "${QFW_CHG_TO}" "${QLIBDIR}/libqt5keychain.dylib") - ELSEIF (ISFW AND EXISTS "${QFWDIR}/qt5keychain.framework/qt5keychain") - SET (QFW_CHG_TO "${ATLOADER}/../../../${LIBPOST}") - INSTALLNAMETOOL_CHANGE ("${QFW_CHG}" "${QFW_CHG_TO}" "${QFWDIR}/qt5keychain.framework/qt5keychain") - ENDIF (ISLIB) - # QwtPolar - STRING (REGEX MATCH "\\.dylib$" ISLIB "@QWTPOLAR_LIBRARY@") - STRING (REGEX MATCH "qwtpolar.framework" ISFW "@QWTPOLAR_LIBRARY@") - IF (ISLIB) - SET (QFW_CHG_TO "${ATLOADER}/${QGIS_LIB_SUBDIR_REV}/${QGIS_FW_SUBDIR}/${LIBPOST}") - INSTALLNAMETOOL_CHANGE ("${QFW_CHG}" "${QFW_CHG_TO}" "${QLIBDIR}/libqwtpolar.dylib") - ELSEIF (ISFW AND EXISTS "${QFWDIR}/qwtpolar.framework/qwtpolar") - SET (QFW_CHG_TO "${ATLOADER}/../../../${LIBPOST}") - INSTALLNAMETOOL_CHANGE ("${QFW_CHG}" "${QFW_CHG_TO}" "${QFWDIR}/qwtpolar.framework/qwtpolar") - ENDIF (ISLIB) - # QCA - STRING (REGEX MATCH "\\.dylib$" ISLIB "@QCA_LIBRARY@") - STRING (REGEX MATCH "${_qca_libname}.framework" ISFW "@QCA_LIBRARY@") - IF (ISLIB) - SET (QFW_CHG_TO "${ATLOADER}/${QGIS_LIB_SUBDIR_REV}/${QGIS_FW_SUBDIR}/${LIBPOST}") - INSTALLNAMETOOL_CHANGE ("${QFW_CHG}" "${QFW_CHG_TO}" "${QLIBDIR}/libqca.dylib") - ELSEIF (ISFW AND EXISTS "${QFWDIR}/${_qca_libname}.framework/${_qca_libname}") - SET (QFW_CHG_TO "${ATLOADER}/../../../${LIBPOST}") - INSTALLNAMETOOL_CHANGE ("${QFW_CHG}" "${QFW_CHG_TO}" "${QFWDIR}/${_qca_libname}.framework/${_qca_libname}") - ENDIF (ISLIB) - # QScintilla2 - SET (QFW_CHG_TO "${ATLOADER}/${QGIS_LIB_SUBDIR_REV}/${QGIS_FW_SUBDIR}/${LIBPOST}") - INSTALLNAMETOOL_CHANGE ("${QFW_CHG}" "${QFW_CHG_TO}" "${QLIBDIR}/${QSCI_LIB}.dylib") - # qt plugs - SET (QFW_CHG_TO "${ATLOADER}/@QGIS_PLUGIN_SUBDIR_REV@/${QGIS_FW_SUBDIR}/${LIBPOST}") - # qca plugins - FOREACH (qca_plugin ${QCA_PLUGINS}) - INSTALLNAMETOOL_CHANGE ("${QFW_CHG}" "${QFW_CHG_TO}" "${QPLUGDIR}/../crypto/libqca-${qca_plugin}.dylib") - ENDFOREACH () - FOREACH (QI qgif;qico;qjpeg;qsvg;qtiff) - INSTALLNAMETOOL_CHANGE ("${QFW_CHG}" "${QFW_CHG_TO}" "${QPLUGDIR}/../imageformats/lib${QI}.dylib") - ENDFOREACH (QI) - FOREACH (QP cocoa;minimal;offscreen) - INSTALLNAMETOOL_CHANGE ("${QFW_CHG}" "${QFW_CHG_TO}" "${QPLUGDIR}/../platforms/libq${QP}.dylib") - ENDFOREACH (QP) - FOREACH (QSL ${QTLISTSQL}) - IF (EXISTS "${QPLUGDIR}/../sqldrivers/libqsql${QSL}.dylib") - INSTALLNAMETOOL_CHANGE ("${QFW_CHG}" "${QFW_CHG_TO}" "${QPLUGDIR}/../sqldrivers/libqsql${QSL}.dylib") - ENDIF () - ENDFOREACH (QSL) - IF (@WITH_QSPATIALITE@ AND EXISTS "${QPLUGDIR}/../sqldrivers/libqsqlspatialite.dylib") - EXECUTE_PROCESS (COMMAND install_name_tool -id "libqsqlspatialite.dylib" "${QPLUGDIR}/../sqldrivers/libqsqlspatialite.dylib") - ENDIF () - INSTALLNAMETOOL_CHANGE ("${QFW_CHG}" "${QFW_CHG_TO}" "${QPLUGDIR}/../iconengines/libqsvgicon.dylib") - INSTALLNAMETOOL_CHANGE ("${QFW_CHG}" "${QFW_CHG_TO}" "${QPLUGDIR}/../phonon_backend/libphonon_qt7.dylib") - INSTALLNAMETOOL_CHANGE ("${QFW_CHG}" "${QFW_CHG_TO}" "${QPLUGDIR}/../styles/libqmacstyle.dylib") - # quick plugin - SET (QFW_CHG_TO "${ATLOADER}/../../../${LIBPOST}") - INSTALLNAMETOOL_CHANGE ("${QFW_CHG}" "${QFW_CHG_TO}" "${QAPPDIR}/qml/QgsQuick/libqgis_quick_plugin.dylib") - # qt fw - SET (QFW_CHG_TO "${ATLOADER}/../../../${LIBPOST}") - FOREACH (QF ${QTLISTQG}) - INSTALLNAMETOOL_CHANGE ("${QFW_CHG}" "${QFW_CHG_TO}" "${QFWDIR}/${QF}.framework/${QF}") - ENDFOREACH (QF) - # PyQt (includes QScintilla2 module) - SET (QFW_CHG_TO "${ATLOADER}/../../@QGIS_DATA_SUBDIR_REV@/${QGIS_FW_SUBDIR}/${LIBPOST}") - FOREACH (PQ ${PYQTLIST}) - INSTALLNAMETOOL_CHANGE ("${QFW_CHG}" "${QFW_CHG_TO}" "${QGISPYDIR}/PyQt${QT_FWVER}/${PQ}.so") - ENDFOREACH (PQ) - # PyQwt - SET (QFW_CHG_TO "${ATLOADER}/../../../@QGIS_DATA_SUBDIR_REV@/${QGIS_FW_SUBDIR}/${LIBPOST}") - FOREACH (PW _iqt;Qwt) - IF (EXISTS "${QGISPYDIR}/PyQt${QT_FWVER}/Qwt5/${PW}.so") - INSTALLNAMETOOL_CHANGE ("${QFW_CHG}" "${QFW_CHG_TO}" "${QGISPYDIR}/PyQt${QT_FWVER}/Qwt5/${PW}.so") - ENDIF () - ENDFOREACH (PW) - # bin - PyQt utils - SET (QFW_CHG_TO "${ATEXECUTABLE}/@QGIS_BIN_SUBDIR_REV@/${QGIS_FW_SUBDIR}/${LIBPOST}") - FOREACH (PB pylupdate4;pyrcc4) - INSTALLNAMETOOL_CHANGE ("${QFW_CHG}" "${QFW_CHG_TO}" "${QBINDIR}/${PB}") - ENDFOREACH (PB) -ENDFOREACH (QFW) diff --git a/mac/cmake/2lib.cmake.in b/mac/cmake/2lib.cmake.in deleted file mode 100644 index fc99ffea9c60..000000000000 --- a/mac/cmake/2lib.cmake.in +++ /dev/null @@ -1,57 +0,0 @@ -# 2lib - bundle shared libraries (but not standard frameworks) -# ! cmakecache vars not available to external scripts -# so we configure it first to do substitutions -# make sure to use @varname@ - -# for now, just libs not available as frameworks -# libpq -# libfcgi (non-system) - -# kill boolean warnings -CMAKE_POLICY (SET CMP0012 NEW) - -INCLUDE ("@CMAKE_BINARY_DIR@/mac/0vars.cmake") -INCLUDE ("@CMAKE_SOURCE_DIR@/cmake/MacBundleMacros.cmake") - -# Postgres - -IF ("@POSTGRES_LIBRARY@" MATCHES ".*libpq.dylib") - MESSAGE (STATUS "Copying libpq and updating library paths...") - EXECUTE_PROCESS (COMMAND ditto ${QARCHS} "@POSTGRES_LIBRARY@" "${QLIBDIR}/libpq.dylib") - GET_INSTALL_NAME ("@POSTGRES_LIBRARY@" "libpq" PQLIB) - UPDATEQGISPATHS (${PQLIB} libpq.dylib) - # may have been built with libintl - GET_INSTALL_NAME ("@POSTGRES_LIBRARY@" "libintl" INTLLIB) - IF (INTLLIB) - EXECUTE_PROCESS (COMMAND ditto ${QARCHS} "${INTLLIB}" "${QLIBDIR}/libintl.dylib") - SET (LIB_CHG_TO "${ATEXECUTABLE}/@QGIS_LIB_SUBDIR@/libintl.dylib") - SET (LIB_CHG_TO "${ATLOADER}/libintl.dylib") - INSTALLNAMETOOL_CHANGE ("${INTLLIB}" "${LIB_CHG_TO}" "${QLIBDIR}/libpq.dylib") - ENDIF (INTLLIB) - IF (EXISTS "${QPLUGDIR}/../sqldrivers/libqsqlpsql.dylib") - FILE (RELATIVE_PATH _relpath "${QPLUGDIR}/../sqldrivers" "${QLIBDIR}/libpq.dylib") - INSTALLNAMETOOL_CHANGE ("${PQLIB}" "${ATLOADER}/${_relpath}" "${QPLUGDIR}/../sqldrivers/libqsqlpsql.dylib") - ENDIF () -ENDIF () - -# libspatialindex - -IF ("@SPATIALINDEX_LIBRARY@" MATCHES ".*libspatialindex.dylib") - MESSAGE (STATUS "Copying libspatialindex and updating library paths...") - EXECUTE_PROCESS (COMMAND ditto ${QARCHS} "@SPATIALINDEX_LIBRARY@" "${QLIBDIR}/libspatialindex.dylib") - GET_INSTALL_NAME ("@SPATIALINDEX_LIBRARY@" "libspatialindex" SPILIB) - UPDATEQGISPATHS (${SPILIB} libspatialindex.dylib) - IF (@WITH_QSPATIALITE@ AND EXISTS "${QPLUGDIR}/../sqldrivers/libqsqlspatialite.dylib") - FILE (RELATIVE_PATH _relpath "${QPLUGDIR}/../sqldrivers" "${QLIBDIR}/libspatialindex.dylib") - INSTALLNAMETOOL_CHANGE ("${SPILIB}" "${ATLOADER}/${_relpath}" "${QPLUGDIR}/../sqldrivers/libqsqlspatialite.dylib") - ENDIF () -ENDIF () - -# libfcgi (non-system) - -IF ("@FCGI_LIBRARY@" MATCHES ".*libfcgi.dylib" AND NOT "@FCGI_LIBRARY@" MATCHES "/usr/lib/.*") - MESSAGE (STATUS "Copying libfcgi and updating library paths...") - EXECUTE_PROCESS (COMMAND ditto ${QARCHS} "@FCGI_LIBRARY@" "${QLIBDIR}/libfcgi.dylib") - GET_INSTALL_NAME ("@FCGI_LIBRARY@" "libfcgi" FCGILIB) - UPDATEQGISPATHS (${FCGILIB} libfcgi.dylib) -ENDIF () diff --git a/mac/cmake/3fw.cmake.in b/mac/cmake/3fw.cmake.in deleted file mode 100644 index bf91c46d9cf1..000000000000 --- a/mac/cmake/3fw.cmake.in +++ /dev/null @@ -1,15 +0,0 @@ -# 3fw - bundle standard frameworks -# ! cmakecache vars not available to external scripts -# so we configure it first to do substitutions -# make sure to use @varname@ - -MESSAGE (STATUS "Bundling other frameworks is not functional yet, skipping...") - -# kill boolean warnings -CMAKE_POLICY (SET CMP0012 NEW) - -INCLUDE ("@CMAKE_BINARY_DIR@/mac/0vars.cmake") -INCLUDE ("@CMAKE_SOURCE_DIR@/cmake/MacBundleMacros.cmake") - -# - diff --git a/mac/framework.info.plist.in b/mac/framework.info.plist.in deleted file mode 100644 index 435458b4f9fa..000000000000 --- a/mac/framework.info.plist.in +++ /dev/null @@ -1,26 +0,0 @@ - - - - - CFBundleDevelopmentRegion - English - CFBundleExecutable - ${MACOSX_FRAMEWORK_NAME} - CFBundleGetInfoString - ${MACOSX_FRAMEWORK_NAME} ${COMPLETE_VERSION} - CFBundleIdentifier - ${MACOSX_FRAMEWORK_IDENTIFIER} - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - ${MACOSX_FRAMEWORK_NAME} - CFBundlePackageType - FMWK - CFBundleShortVersionString - ${MACOSX_FRAMEWORK_SHORT_VERSION_STRING} - CFBundleSignature - ???? - CFBundleVersion - ${MACOSX_FRAMEWORK_NAME} ${COMPLETE_VERSION} - - diff --git a/mac/readme.txt b/mac/readme.txt deleted file mode 100644 index 136309e5ed60..000000000000 --- a/mac/readme.txt +++ /dev/null @@ -1,21 +0,0 @@ -Mac Notes -********* - -The 'cmake' folder scripts handle bundling dependent libraries in the QGIS -application package and fixing up the library paths. It is automatic during -installation. There are 2 levels currently, specified with the cmake config -option QGIS_MACAPP_BUNDLE, and one that always occurs: - --1 = do not run bundle install scrips -0 = (default) fixup the library paths for all QGIS libraries if @loader_path - is available in the system (OS X 10.5+) -1 = bundle Qt, PyQt, PyQwt and OSG/osgEarth -2 = additionally, bundle libraries, but not frameworks - -A third level that is not finished will additionally bundle frameworks. -This would create the "standalone" QGIS. - -There is also a configure option to set a user bundle script, -QGIS_MACAPP_BUNDLE_USER. This specifies the path to a cmake bundle script -similar to the built-in bundle scripts for the defined levels. This script is -always run independent of and after the QGIS_MACAPP_BUNDLE level specified. diff --git a/platform/macos/CPackMacDeployQt.cmake.in b/platform/macos/CPackMacDeployQt.cmake.in new file mode 100644 index 000000000000..44d3dd77b989 --- /dev/null +++ b/platform/macos/CPackMacDeployQt.cmake.in @@ -0,0 +1,31 @@ +if(NOT "$ENV{MACOS_CODE_SIGN_IDENTITY}" STREQUAL "") + # -appstore-compliant will strip away odbc, psql and webengine plugins + execute_process(COMMAND "@PYMACDEPLOYQT_EXECUTABLE@" @QGIS_APP_NAME@.app -codesign=${MACOS_CODE_SIGN_IDENTITY} -sign-for-notarization=${MACOS_CODE_SIGN_IDENTITY} + WORKING_DIRECTORY ${CPACK_TEMPORARY_DIRECTORY} + COMMAND_ERROR_IS_FATAL ANY + ) + + if (@CREATE_DMG@) + execute_process(COMMAND create-dmg --volname "@QGIS_APP_NAME@ Installer" --hide-extension @QGIS_APP_NAME@.app --volicon "@CMAKE_SOURCE_DIR@/images/icons/mac/qgis.icns" --background "@CMAKE_SOURCE_DIR@/platform/macos/installer_background.png" --window-pos 200 120 --window-size 512 384 --icon-size 100 --icon "@QGIS_APP_NAME@.app" 130 160 --app-drop-link 400 155 --codesign "${MACOS_CODE_SIGN_IDENTITY}" @CMAKE_BINARY_DIR@/@QGIS_APP_NAME@-Installer.dmg ${CPACK_TEMPORARY_DIRECTORY}/@QGIS_APP_NAME@.app + RESULT_VARIABLE CREATE_DMG_FAILURE) + + if(CREATE_DMG_FAILURE) + message(STATUS "Creating dmg failed.") + endif() + endif() +else() + # -appstore-compliant will strip away odbc, psql and webengine plugins + execute_process(COMMAND "@PYMACDEPLOYQT_EXECUTABLE@" "@QGIS_APP_NAME@.app" + WORKING_DIRECTORY ${CPACK_TEMPORARY_DIRECTORY} + COMMAND_ERROR_IS_FATAL ANY + ) + + if (@CREATE_DMG@) + execute_process(COMMAND create-dmg --volname "@QGIS_APP_NAME@ Installer" --hide-extension @QGIS_APP_NAME@.app --volicon "@CMAKE_SOURCE_DIR@/images/icons/mac/qgis.icns" --background "@CMAKE_SOURCE_DIR@/platform/macos/installer_background.png" --window-pos 200 120 --window-size 512 384 --icon-size 100 --icon "@QGIS_APP_NAME@.app" 130 160 --app-drop-link 400 155 @CMAKE_BINARY_DIR@/@QGIS_APP_NAME@-Installer.dmg ${CPACK_TEMPORARY_DIRECTORY}/@QGIS_APP_NAME@.app + RESULT_VARIABLE CREATE_DMG_FAILURE) + + if(CREATE_DMG_FAILURE) + message(STATUS "Creating dmg failed.") + endif() + endif() +endif() diff --git a/mac/app.info.plist.in b/platform/macos/Info.plist.in similarity index 90% rename from mac/app.info.plist.in rename to platform/macos/Info.plist.in index 10153c514ebe..3a5fef6cd4c0 100644 --- a/mac/app.info.plist.in +++ b/platform/macos/Info.plist.in @@ -9,19 +9,39 @@ CFBundleIdentifier org.qgis.qgis3 CFBundleExecutable - ${QGIS_APP_NAME} + @QGIS_APP_NAME@ CFBundlePackageType APPL CFBundleSignature QGIS CFBundleGetInfoString - ${QGIS_APP_NAME} ${COMPLETE_VERSION}-${RELEASE_NAME} (${SHA}), Β© 2002-2019 QGIS Development Team + @QGIS_APP_NAME@ @COMPLETE_VERSION@-@RELEASE_NAME@ (@SHA@), Β© 2002-2019 QGIS Development Team CFBundleShortVersionString - ${COMPLETE_VERSION} + @COMPLETE_VERSION@ CFBundleVersion - ${COMPLETE_VERSION} (${SHA}) + @COMPLETE_VERSION@ (@SHA@) CFBundleIconFile qgis.icns + CFBundleIcons + + CFBundlePrimaryIcon + + CFBundleIconFiles + + qgis.icns + + + CFBundleAlternateIcons + + DarkModeIcon + + CFBundleIconFiles + + qgis-dark.icns + + + + CFBundleInfoDictionaryVersion 6.0 CSResourcesFileMapped @@ -34,7 +54,7 @@ CFBundleTypeRole Editor CFBundleTypeIconFile - qgs.icns + qgis.icns CFBundleTypeExtensions qgs diff --git a/platform/macos/installer_background.png b/platform/macos/installer_background.png new file mode 100644 index 000000000000..4badd146ff93 Binary files /dev/null and b/platform/macos/installer_background.png differ diff --git a/platform/macos/pymacdeployqt.py b/platform/macos/pymacdeployqt.py new file mode 100755 index 000000000000..65e3cb81f3ca --- /dev/null +++ b/platform/macos/pymacdeployqt.py @@ -0,0 +1,389 @@ +#!/usr/bin/env python3 + +import argparse +import os +import shutil +import subprocess + +from dataclasses import dataclass +from functools import lru_cache +from pathlib import Path +from typing import Dict, List, Set, Tuple + +# System paths that should be excluded from copying +SYSTEM_PATHS = [ + "/usr/lib", + "/System/Library", + "/Library/Frameworks", +] + + +@dataclass +class Library: + path: str + install_name: str + dependencies: list[str] + rpaths: list[str] + + +@lru_cache(maxsize=None) +def get_macho_info(path: str) -> bytes: + """Run otool -l and cache the output.""" + result = subprocess.run(["otool", "-l", path], capture_output=True, check=True) + return result.stdout + + +def parse_macho_info(path: str) -> Library: + """Parse otool -l output to extract all needed information.""" + output = get_macho_info(path).decode("utf-8").split("\n") + + install_name = path + rpaths = [] + dependencies = [] + + i = 0 + while i < len(output): + line = output[i].strip() + + # Look for load command type + if "cmd LC_" not in line: + i += 1 + continue + + cmd_type = line.split()[-1] + + if cmd_type == "LC_ID_DYLIB": + # Next line is cmdsize, name is in the line after + if i + 2 < len(output): + name_line = output[i + 2].strip() + if name_line.startswith("name"): + install_name = name_line.split()[1] + + elif cmd_type == "LC_LOAD_DYLIB" or cmd_type == "LC_LOAD_WEAK_DYLIB": + # Next line is cmdsize, name is in the line after + if i + 2 < len(output): + name_line = output[i + 2].strip() + if name_line.startswith("name"): + dep_path = name_line.split()[1] + if dep_path != install_name: + dependencies.append(dep_path) + + elif cmd_type == "LC_RPATH": + # Next line is cmdsize, path is in the line after + if i + 2 < len(output): + path_line = output[i + 2].strip() + if path_line.startswith("path"): + rpaths.append(path_line.split()[1]) + + i += 1 + + return Library(path, install_name, dependencies, rpaths) + + +def is_system_path(path: str) -> bool: + """Check if the path is a system path that should be excluded.""" + return any(path.startswith(sys_path) for sys_path in SYSTEM_PATHS) + + +def find_library(lib_name: str, search_paths: list[str]) -> str: + """Find library in search paths.""" + for path in search_paths: + full_path = os.path.join(path, lib_name) + if os.path.exists(full_path): + return full_path + return "" + + +def resolve_at_path(dep_path: str, binary_path: str, rpaths: list[str]) -> str: + """ + Resolve a path that starts with @rpath, @executable_path, or @loader_path + Returns resolved absolute path or empty string if not found + """ + if dep_path.startswith("@rpath/"): + lib_name = dep_path[len("@rpath/") :] + # Try all rpaths + for rpath in rpaths: + # Handle nested @ paths in rpaths + if rpath.startswith("@"): + rpath = resolve_at_path(rpath, binary_path, []) + if not rpath: + continue + full_path = os.path.join(rpath, lib_name) + if os.path.exists(full_path): + return full_path + elif dep_path.startswith("@executable_path/"): + lib_name = dep_path[len("@executable_path/") :] + exe_dir = os.path.dirname(binary_path) + full_path = os.path.join(exe_dir, lib_name) + if os.path.exists(full_path): + return full_path + elif dep_path.startswith("@loader_path/"): + lib_name = dep_path[len("@loader_path/") :] + loader_dir = os.path.dirname(binary_path) + full_path = os.path.join(loader_dir, lib_name) + if os.path.exists(full_path): + return full_path + return "" + + +def collect_dependencies( + binary_path: str, lib_dirs: list[str], processed: set[str] +) -> dict[str, Library]: + """Recursively collect all dependencies for a binary.""" + result = {} + search_paths = lib_dirs.copy() + + def process_binary(path: str) -> None: + if path in processed: + return + + processed.add(path) + real_path, _ = resolve_symlink(path) + lib_info = parse_macho_info(real_path) + result[path] = lib_info + + # Add library's directory to search paths if it's not a system path + lib_dir = os.path.dirname(real_path) + if lib_dir not in search_paths and not is_system_path(lib_dir): + search_paths.append(lib_dir) + + # Process dependencies + for dep in lib_info.dependencies: + if dep.startswith("@"): + # If we couldn't resolve it earlier, try again with updated search paths + resolved_path = resolve_at_path(dep, path, lib_info.rpaths) + if resolved_path: + dep = resolved_path + + if not os.path.isabs(dep): + dep = find_library(os.path.basename(dep), search_paths) + + if dep and os.path.exists(dep): + process_binary(dep) + + process_binary(binary_path) + return result + + +def resolve_symlink(path: str) -> tuple[str, list[str]]: + """ + Resolve a symlink chain to its final destination and return the real file path + along with the chain of symlinks that led to it. + """ + symlink_chain = [] + current_path = path + + while os.path.islink(current_path): + symlink_chain.append(os.path.basename(current_path)) + current_path = os.path.realpath(current_path) + + return current_path, symlink_chain + + +def is_macho(filepath: str) -> bool: + """ + Checks if a file is a Mach-O binary by reading the first 4 bytes. + + Args: + filepath: Path to the file to check + + Returns: + True if it is a Mach-O file + """ + # Mach-O magic numbers + MAGIC_64 = 0xCFFAEDFE # 64-bit mach-o + MAGIC_32 = 0xCEFAEDFE # 32-bit mach-o + + try: + # Open file in binary mode and read first 4 bytes + with open(filepath, "rb") as f: + magic = int.from_bytes(f.read(4), byteorder="big") + + if magic in (MAGIC_64, MAGIC_32): + return True + else: + return False + + except OSError: + return False + + +def handle_resources_binaries(app_bundle: str) -> None: + """ + Move Mach-O files from Contents/Resources to Contents/PlugIns/_Resources + and replace them with symlinks. + """ + resources_dir = os.path.join(app_bundle, "Contents", "Resources") + plugins_resources_dir = os.path.join( + app_bundle, "Contents", "PlugIns", "_Resources" + ) + + if not os.path.exists(resources_dir): + return + + # Find all Mach-O files in Resources + for root, _, files in os.walk(resources_dir): + for file in files: + path = os.path.join(root, file) + try: + if is_macho(file): + # Calculate relative path from Resources root + rel_path = os.path.relpath(path, resources_dir) + new_path = os.path.join(plugins_resources_dir, rel_path) + + # Create directory structure in PlugIns/_Resources + os.makedirs(os.path.dirname(new_path), exist_ok=True) + + # Move the file and create symlink + shutil.move(path, new_path) + relative_target = os.path.relpath(new_path, os.path.dirname(path)) + os.symlink(relative_target, path) + except subprocess.CalledProcessError: + continue + + +def deploy_libraries(app_bundle: str, lib_dirs: list[str]) -> None: + """Deploy all libraries to the app bundle.""" + frameworks_dir = os.path.join(app_bundle, "Contents", "Frameworks") + os.makedirs(frameworks_dir, exist_ok=True) + + print("Handle resources binaries") + # Handle Resources binaries first + handle_resources_binaries(app_bundle) + + print("Handle main binaries") + # Find all binaries in the app bundle + binaries = [] + for root, _, files in os.walk(app_bundle): + for file in files: + path = os.path.join(root, file) + try: + if not os.path.islink(path) and is_macho(path): + binaries.append(path) + except subprocess.CalledProcessError: + continue + + processed_libs = set() + all_dependencies = {} + + # Collect all dependencies + for binary in binaries: + print(f"Analyzing {binary}") + deps = collect_dependencies(binary, lib_dirs, processed_libs) + all_dependencies.update(deps) + # Copy libraries and prepare install_name_tool commands + commands = {} # path -> list of changes + lib_mapping = {} # old_install_name -> new_install_name + + # First pass: copy libraries and record their new install names + for lib_path, lib_info in all_dependencies.items(): + if lib_path.startswith(app_bundle): + continue + + # Skip system libraries + if is_system_path(lib_path): + continue + + # Resolve symlinks to get real file + real_lib_path, symlink_chain = resolve_symlink(lib_path) + + # Skip if the real file is in a system path + if is_system_path(real_lib_path): + continue + + lib_name = os.path.basename(real_lib_path) + new_path = os.path.join(frameworks_dir, lib_name) + new_install_name = f"@rpath/{lib_name}" + + # Record the mapping from old install name to new install name + lib_mapping[lib_info.install_name] = new_install_name + + # Copy the real file if not already present + if not os.path.exists(new_path): + shutil.copy2(real_lib_path, new_path) + + # Recreate symlink chain + current_name = lib_name + for link_name in reversed(symlink_chain): + link_path = os.path.join(frameworks_dir, link_name) + if not os.path.exists(link_path): + os.symlink(current_name, link_path) + current_name = link_name + + # Prepare commands for the library itself + if new_path not in commands: + commands[new_path] = [] + + # Set its own install name + commands[new_path].append(("-id", new_install_name)) + + # Second pass: update each binary's direct dependencies + for binary_path, lib_info in all_dependencies.items(): + if binary_path not in commands: + commands[binary_path] = [] + + # Update only the direct dependencies of this binary + for dep in lib_info.dependencies: + if dep in lib_mapping: + commands[binary_path].append(("-change", dep, lib_mapping[dep])) + + frameworks_dir = os.path.join(app_bundle, "Contents", "Frameworks") + + def calculate_relative_frameworks_path(binary_path: str) -> str: + """Calculate relative path from binary to Frameworks directory.""" + binary_dir = os.path.dirname(binary_path) + rel_path = os.path.relpath(frameworks_dir, binary_dir) + return rel_path + + # Set @loader_path/../Frameworks as the only rpath for all binaries + for binary in binaries: + if binary not in commands: + commands[binary] = [] + + # Get existing rpaths + lib_info = parse_macho_info(binary) + # Delete absolute rpaths + for rpath in lib_info.rpaths: + if rpath.startswith("/"): + commands[binary].append(("-delete_rpath", rpath)) + + # Add proper search path for all executables + rel_frameworks_path = calculate_relative_frameworks_path(binary) + new_path = f"@loader_path/{rel_frameworks_path}" + if ( + binary.startswith(f"{app_bundle}/Contents/MacOS") + and new_path not in lib_info.rpaths + ): + commands[binary].append(("-add_rpath", new_path)) + + # Execute install_name_tool commands + for path, changes in commands.items(): + print(f"Changing {path}") + cmd = ["install_name_tool"] + if not changes: + continue + print(f" {changes}") + for command_tuple in changes: + cmd.extend(command_tuple) + print(f"Executing {cmd} {path}") + subprocess.run(cmd + [path], check=True) + + +def main(): + parser = argparse.ArgumentParser(description="Enhanced macdeployqt implementation") + parser.add_argument("app_bundle", help="Path to the app bundle") + parser.add_argument( + "--libdir", + action="append", + default=[], + help="Additional library search directories", + ) + + args = parser.parse_args() + + lib_dirs = args.libdir + [os.path.join(args.app_bundle, "Contents", "Frameworks")] + deploy_libraries(args.app_bundle, lib_dirs) + + +if __name__ == "__main__": + main() diff --git a/python/CMakeLists.txt b/python/CMakeLists.txt index cf04c20710c2..d84286985b77 100644 --- a/python/CMakeLists.txt +++ b/python/CMakeLists.txt @@ -91,7 +91,7 @@ ELSE() SET(BINDING_FILES_ROOT_DIR ${CMAKE_CURRENT_SOURCE_DIR}) ENDIF() -set(QGIS_PYTHON_DIR ${Python_SITEARCH}/qgis) +set(QGIS_PYTHON_DIR ${QGIS_PYTHON_INSTALL_DIR}/qgis) # core module file(GLOB_RECURSE sip_files_core ${BINDING_FILES_ROOT_DIR}/core/*.sip ${BINDING_FILES_ROOT_DIR}/core/*.sip.in) diff --git a/python/PyQt/CMakeLists.txt b/python/PyQt/CMakeLists.txt index 8b062819d1a5..099958ac3d7c 100644 --- a/python/PyQt/CMakeLists.txt +++ b/python/PyQt/CMakeLists.txt @@ -1,4 +1,4 @@ -set (QGIS_PYQT_DIR ${Python_SITEARCH}/qgis/PyQt) +set (QGIS_PYQT_DIR ${QGIS_PYTHON_INSTALL_DIR}/qgis/PyQt) set(PYQT_COMPAT_FILES __init__.py diff --git a/python/plugins/processing/algs/gdal/GdalUtils.py b/python/plugins/processing/algs/gdal/GdalUtils.py index dde752aef547..4c9cf3b43c7d 100644 --- a/python/plugins/processing/algs/gdal/GdalUtils.py +++ b/python/plugins/processing/algs/gdal/GdalUtils.py @@ -113,14 +113,13 @@ def runGdal(commands, feedback=None): except OSError: # https://travis-ci.org/m-kuhn/QGIS#L1493-L1526 pass if isDarwin and os.path.isfile( - os.path.join(QgsApplication.prefixPath(), "bin", "gdalinfo") + os.path.join(QgsApplication.prefixPath(), "Contents", "MacOS", "gdalinfo") ): # Looks like there's a bundled gdal. Let's use it. os.environ["PATH"] = "{}{}{}".format( - os.path.join(QgsApplication.prefixPath(), "bin"), os.pathsep, envval - ) - os.environ["DYLD_LIBRARY_PATH"] = os.path.join( - QgsApplication.prefixPath(), "lib" + os.path.join(QgsApplication.prefixPath(), "Contents", "MacOS"), + os.pathsep, + envval, ) else: # Other platforms should use default gdal finder codepath diff --git a/python/processing/CMakeLists.txt b/python/processing/CMakeLists.txt index 81cd0be4a942..4ac96104ba84 100644 --- a/python/processing/CMakeLists.txt +++ b/python/processing/CMakeLists.txt @@ -1,6 +1,6 @@ # See ../CMakeLists.txt for info on staged-plugins* and clean-staged-plugins targets -set(QGIS_PYTHON_DIR ${Python_SITEARCH}/qgis) +set(QGIS_PYTHON_DIR ${QGIS_PYTHON_INSTALL_DIR}/qgis) set(PY_FILES __init__.py diff --git a/python/testing/CMakeLists.txt b/python/testing/CMakeLists.txt index c428e5e93594..38b9f7a89b8d 100644 --- a/python/testing/CMakeLists.txt +++ b/python/testing/CMakeLists.txt @@ -1,6 +1,6 @@ # See ../CMakeLists.txt for info on staged-plugins* and clean-staged-plugins targets -set(QGIS_PYTHON_DIR ${Python_SITEARCH}/qgis) +set(QGIS_PYTHON_DIR ${QGIS_PYTHON_INSTALL_DIR}/qgis) set(PY_FILES __init__.py diff --git a/scripts/spell_check/.agignore b/scripts/spell_check/.agignore index 36dad1553d41..d4176f228bac 100644 --- a/scripts/spell_check/.agignore +++ b/scripts/spell_check/.agignore @@ -58,6 +58,7 @@ resources/cpt-city-qgis-min/selections/reds.xml resources/cpt-city-qgis-min/wkp/schwarzwald/COPYING.xml resources/data/world_map_generalize.model3 scripts/spell_check/spelling.dat +platform/macos/pymacdeployqt.py scripts/spell_check/test.sh src/server/qgis_wms.xmi src/plugins/grass/modules/v.generalize.qgm diff --git a/src/3d/CMakeLists.txt b/src/3d/CMakeLists.txt index f8a0583f4a38..7337da9ccb25 100644 --- a/src/3d/CMakeLists.txt +++ b/src/3d/CMakeLists.txt @@ -304,30 +304,7 @@ GENERATE_EXPORT_HEADER( set(QGIS_3D_HDRS ${QGIS_3D_HDRS} ${CMAKE_CURRENT_BINARY_DIR}/qgis_3d.h) -if(NOT APPLE OR NOT QGIS_MACAPP_FRAMEWORK) - install(FILES ${QGIS_3D_HDRS} DESTINATION ${QGIS_INCLUDE_DIR}) -else() - set_target_properties(qgis_3d PROPERTIES - # no moc headers, messes up PROPERTIES syntax - CLEAN_DIRECT_OUTPUT 1 - FRAMEWORK 1 - FRAMEWORK_VERSION "${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}" - MACOSX_FRAMEWORK_INFO_PLIST "${CMAKE_SOURCE_DIR}/mac/framework.info.plist.in" - MACOSX_FRAMEWORK_SHORT_VERSION_STRING ${COMPLETE_VERSION} - MACOSX_FRAMEWORK_IDENTIFIER org.qgis.qgis3_3d - BUILD_WITH_INSTALL_RPATH TRUE - PUBLIC_HEADER "${QGIS_3D_HDRS}" - LINK_FLAGS "${CMAKE_SHARED_LINKER_FLAGS}" - ) - # generated export header does not get copied with PUBLIC_HEADER files - add_custom_command(TARGET qgis_3d - POST_BUILD - COMMAND ${CMAKE_COMMAND} -E copy qgis_3d.h - "${QGIS_OUTPUT_DIRECTORY}/${QGIS_LIB_SUBDIR}/qgis_3d.framework/Headers" - WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} - DEPENDS qgis_3d.h - ) -endif() +install(FILES ${QGIS_3D_HDRS} DESTINATION ${QGIS_INCLUDE_DIR}) #generate unversioned libs for android if (NOT ANDROID) @@ -353,13 +330,4 @@ install(TARGETS qgis_3d RUNTIME DESTINATION ${QGIS_BIN_DIR} LIBRARY DESTINATION ${QGIS_LIB_DIR} ARCHIVE DESTINATION ${QGIS_LIB_DIR} - FRAMEWORK DESTINATION ${QGIS_FW_SUBDIR} - PUBLIC_HEADER DESTINATION ${QGIS_INCLUDE_DIR}) - -# Mac dev frameworks - -if (APPLE AND QGIS_MACAPP_INSTALL_DEV) - install(TARGETS qgis_3d FRAMEWORK DESTINATION ${QGIS_MACAPP_DEV_PREFIX}) - install(CODE "execute_process(COMMAND install_name_tool -id \"${QGIS_MACAPP_DEV_PREFIX}/qgis_3d.framework/Versions/${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}/qgis_3d\" \"$ENV{DESTDIR}${QGIS_MACAPP_DEV_PREFIX}/qgis_3d.framework/qgis_3d\")") - install(CODE "execute_process(COMMAND install_name_tool -change \"${CMAKE_INSTALL_NAME_DIR}/qgis_core.framework/Versions/${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}/qgis_core\" \"${QGIS_MACAPP_DEV_PREFIX}/qgis_core.framework/Versions/${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}/qgis_core\" \"$ENV{DESTDIR}${QGIS_MACAPP_DEV_PREFIX}/qgis_3d.framework/qgis_3d\")") -endif() + PUBLIC_HEADER DESTINATION ${QGIS_INCLUDE_DIR}) \ No newline at end of file diff --git a/src/analysis/CMakeLists.txt b/src/analysis/CMakeLists.txt index c633fcd974af..7c482c2c3a96 100644 --- a/src/analysis/CMakeLists.txt +++ b/src/analysis/CMakeLists.txt @@ -565,30 +565,7 @@ GENERATE_EXPORT_HEADER( set(QGIS_ANALYSIS_HDRS ${QGIS_ANALYSIS_HDRS} ${CMAKE_CURRENT_BINARY_DIR}/qgis_analysis.h) -if(NOT APPLE OR NOT QGIS_MACAPP_FRAMEWORK) - install(FILES ${QGIS_ANALYSIS_HDRS} DESTINATION ${QGIS_INCLUDE_DIR}) -else() - set_target_properties(qgis_analysis PROPERTIES - # no moc headers, messes up PROPERTIES syntax - CLEAN_DIRECT_OUTPUT 1 - FRAMEWORK 1 - FRAMEWORK_VERSION "${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}" - MACOSX_FRAMEWORK_INFO_PLIST "${CMAKE_SOURCE_DIR}/mac/framework.info.plist.in" - MACOSX_FRAMEWORK_SHORT_VERSION_STRING ${COMPLETE_VERSION} - MACOSX_FRAMEWORK_IDENTIFIER org.qgis.qgis3_analysis - BUILD_WITH_INSTALL_RPATH TRUE - PUBLIC_HEADER "${QGIS_ANALYSIS_HDRS}" - LINK_FLAGS "${CMAKE_SHARED_LINKER_FLAGS}" - ) - # generated export header does not get copied with PUBLIC_HEADER files - add_custom_command(TARGET qgis_analysis - POST_BUILD - COMMAND ${CMAKE_COMMAND} -E copy qgis_analysis.h - "${QGIS_OUTPUT_DIRECTORY}/${QGIS_LIB_SUBDIR}/qgis_analysis.framework/Headers" - WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} - DEPENDS qgis_analysis.h - ) -endif() +install(FILES ${QGIS_ANALYSIS_HDRS} DESTINATION ${QGIS_INCLUDE_DIR}) #generate unversioned libs for android if (NOT ANDROID) @@ -631,13 +608,4 @@ install(TARGETS qgis_analysis RUNTIME DESTINATION ${QGIS_BIN_DIR} LIBRARY DESTINATION ${QGIS_LIB_DIR} ARCHIVE DESTINATION ${QGIS_LIB_DIR} - FRAMEWORK DESTINATION ${QGIS_FW_SUBDIR} PUBLIC_HEADER DESTINATION ${QGIS_INCLUDE_DIR}) - -# Mac dev frameworks - -if (APPLE AND QGIS_MACAPP_INSTALL_DEV) - install(TARGETS qgis_analysis FRAMEWORK DESTINATION ${QGIS_MACAPP_DEV_PREFIX}) - install(CODE "execute_process(COMMAND install_name_tool -id \"${QGIS_MACAPP_DEV_PREFIX}/qgis_analysis.framework/Versions/${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}/qgis_analysis\" \"$ENV{DESTDIR}${QGIS_MACAPP_DEV_PREFIX}/qgis_analysis.framework/qgis_analysis\")") - install(CODE "execute_process(COMMAND install_name_tool -change \"${CMAKE_INSTALL_NAME_DIR}/qgis_core.framework/Versions/${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}/qgis_core\" \"${QGIS_MACAPP_DEV_PREFIX}/qgis_core.framework/Versions/${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}/qgis_core\" \"$ENV{DESTDIR}${QGIS_MACAPP_DEV_PREFIX}/qgis_analysis.framework/qgis_analysis\")") -endif() diff --git a/src/app/CMakeLists.txt b/src/app/CMakeLists.txt index 9f642ca0dfb1..9c3e1e6f7a5b 100644 --- a/src/app/CMakeLists.txt +++ b/src/app/CMakeLists.txt @@ -514,13 +514,7 @@ if (ANDROID) # require c++17 target_compile_features(${QGIS_APP_NAME} PRIVATE cxx_std_17) else() - if(APPLE) - set (CREATE_MACOSX_BUNDLE TRUE CACHE BOOL "Create macosx bundle during build. Disable for development to avoid copying libraries and ease debugging.") - if(CREATE_MACOSX_BUNDLE) - set(MACOSX_BUNDLE "MACOSX_BUNDLE") - endif() - endif() - add_executable(${QGIS_APP_NAME} ${MACOSX_BUNDLE} WIN32 ${QGIS_APPMAIN_SRCS}) + add_executable(${QGIS_APP_NAME} WIN32 ${QGIS_APPMAIN_SRCS}) if(WIN32 AND BUILD_WITH_QT6) qt_disable_unicode_defines(${QGIS_APP_NAME}) @@ -540,7 +534,7 @@ target_compile_features(qgis_app PRIVATE cxx_std_17) target_compile_definitions(qgis_app PRIVATE "QT_PLUGINS_DIR=\"${QT_PLUGINS_DIR}\"") if (POSTGRES_FOUND) - target_compile_definitions(qgis_app PRIVATE -DPOSTGRESQL_VERSION=${PostgreSQL_VERSION_STRING}) + target_compile_definitions(qgis_app PRIVATE -DPOSTGRESQL_VERSION=\"${PostgreSQL_VERSION_STRING}\") endif() target_include_directories(qgis_app PUBLIC @@ -673,13 +667,6 @@ if (NOT WIN32) target_link_libraries(${QGIS_APP_NAME} QTSignal) endif() -if (APPLE) - set_target_properties(${QGIS_APP_NAME} PROPERTIES - INSTALL_RPATH ${CMAKE_INSTALL_PREFIX}/${QGIS_LIB_DIR} - INSTALL_RPATH_USE_LINK_PATH true - MACOSX_BUNDLE_INFO_PLIST "${CMAKE_SOURCE_DIR}/mac/app.info.plist.in") -endif() - if (CMAKE_SYSTEM_NAME STREQUAL "FreeBSD") find_library(EXECINFO_LIBRARY NAMES execinfo) target_link_libraries(${QGIS_APP_NAME} ${EXECINFO_LIBRARY}) @@ -697,7 +684,6 @@ install(TARGETS qgis_app RUNTIME DESTINATION ${QGIS_BIN_DIR} LIBRARY DESTINATION ${QGIS_LIB_DIR} ARCHIVE DESTINATION ${QGIS_LIB_DIR} - FRAMEWORK DESTINATION ${QGIS_FW_SUBDIR} PUBLIC_HEADER DESTINATION ${QGIS_INCLUDE_DIR}) install(TARGETS ${QGIS_APP_NAME} @@ -705,9 +691,4 @@ install(TARGETS ${QGIS_APP_NAME} RUNTIME DESTINATION ${QGIS_BIN_DIR} LIBRARY DESTINATION ${QGIS_LIB_DIR} ARCHIVE DESTINATION ${QGIS_LIB_DIR} - FRAMEWORK DESTINATION ${QGIS_FW_SUBDIR} PUBLIC_HEADER DESTINATION ${QGIS_INCLUDE_DIR}) - -if (APPLE) - install(CODE "execute_process(COMMAND /bin/echo -n \"APPLQGIS\" OUTPUT_FILE \"$ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}/../PkgInfo\")") -endif() diff --git a/src/app/qgisapp.cpp b/src/app/qgisapp.cpp index 0d2bfecfc44a..0f741a67b2b4 100644 --- a/src/app/qgisapp.cpp +++ b/src/app/qgisapp.cpp @@ -537,19 +537,6 @@ // Editor widgets #include "qgseditorwidgetregistry.h" -// -// Conditional Includes -// -#ifdef HAVE_PGCONFIG -#undef PACKAGE_BUGREPORT -#undef PACKAGE_NAME -#undef PACKAGE_STRING -#undef PACKAGE_TARNAME -#undef PACKAGE_VERSION -#include -#else -#define PG_VERSION "unknown" -#endif #include @@ -5554,7 +5541,7 @@ QString QgisApp::getVersionString() // postgres versionString += QStringLiteral( "%1" ).arg( tr( "PostgreSQL client version" ) ); #ifdef HAVE_POSTGRESQL - versionString += QStringLiteral( PG_VERSION ); + versionString += QStringLiteral( POSTGRESQL_VERSION ); #else versionString += tr( "No support" ); #endif diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index ba1a6cc0c920..8842d144c028 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -2202,8 +2202,6 @@ if (NOT MSVC) endif() # install headers -# install qgsconfig.h and plugin.h here so they can get into -# the OS X framework target if (HAVE_OPENCL) set(QGIS_CORE_SRCS ${QGIS_CORE_SRCS} @@ -2479,33 +2477,10 @@ if(HAVE_OPENCL) endif() -if(NOT APPLE OR NOT QGIS_MACAPP_FRAMEWORK) - install(FILES ${QGIS_CORE_HDRS} DESTINATION ${QGIS_INCLUDE_DIR}) +install(FILES ${QGIS_CORE_HDRS} DESTINATION ${QGIS_INCLUDE_DIR}) - if(WITH_INTERNAL_NLOHMANN_JSON) - install(FILES ${CMAKE_SOURCE_DIR}/external/nlohmann/json_fwd.hpp DESTINATION ${QGIS_INCLUDE_DIR}/nlohmann) - endif() -else() - - set_target_properties(qgis_core PROPERTIES - CLEAN_DIRECT_OUTPUT 1 - FRAMEWORK 1 - FRAMEWORK_VERSION "${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}" - MACOSX_FRAMEWORK_INFO_PLIST "${CMAKE_SOURCE_DIR}/mac/framework.info.plist.in" - MACOSX_FRAMEWORK_SHORT_VERSION_STRING ${COMPLETE_VERSION} - MACOSX_FRAMEWORK_IDENTIFIER org.qgis.qgis3_core - BUILD_WITH_INSTALL_RPATH TRUE - PUBLIC_HEADER "${QGIS_CORE_HDRS}" - LINK_FLAGS "${CMAKE_SHARED_LINKER_FLAGS}" - ) - # generated export header does not get copied with PUBLIC_HEADER files - add_custom_command(TARGET qgis_core - POST_BUILD - COMMAND ${CMAKE_COMMAND} -E copy qgis_core.h - "${QGIS_OUTPUT_DIRECTORY}/${QGIS_LIB_SUBDIR}/qgis_core.framework/Headers" - WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} - DEPENDS qgis_core.h - ) +if(WITH_INTERNAL_NLOHMANN_JSON) + install(FILES ${CMAKE_SOURCE_DIR}/external/nlohmann/json_fwd.hpp DESTINATION ${QGIS_INCLUDE_DIR}/nlohmann) endif() #generate unversioned libs for android @@ -2671,12 +2646,4 @@ install(TARGETS qgis_core RUNTIME DESTINATION ${QGIS_BIN_DIR} LIBRARY DESTINATION ${QGIS_LIB_DIR} ARCHIVE DESTINATION ${QGIS_LIB_DIR} - FRAMEWORK DESTINATION ${QGIS_FW_SUBDIR} PUBLIC_HEADER DESTINATION ${QGIS_INCLUDE_DIR}) - -# Mac dev frameworks - -if (APPLE AND QGIS_MACAPP_INSTALL_DEV) - install(TARGETS qgis_core FRAMEWORK DESTINATION ${QGIS_MACAPP_DEV_PREFIX}) - install(CODE "execute_process(COMMAND install_name_tool -id \"${QGIS_MACAPP_DEV_PREFIX}/qgis_core.framework/Versions/${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}/qgis_core\" \"$ENV{DESTDIR}${QGIS_MACAPP_DEV_PREFIX}/qgis_core.framework/qgis_core\")") -endif() diff --git a/src/core/qgsapplication.cpp b/src/core/qgsapplication.cpp index 24158abb69da..73e73587ebf7 100644 --- a/src/core/qgsapplication.cpp +++ b/src/core/qgsapplication.cpp @@ -351,8 +351,11 @@ void QgsApplication::init( QString profileFolder ) { if ( sPrefixPath()->isNull() ) { -#if defined(Q_OS_MACOS) || defined(Q_OS_WIN) +#if defined(Q_OS_WIN) || defined(Q_OS_MACOS) && !defined(QGIS_MAC_BUNDLE) setPrefixPath( applicationDirPath(), true ); +#elif defined(QGIS_MAC_BUNDLE) + QDir myDir( applicationDirPath() + QLatin1String( "/../.." ) ); + setPrefixPath( myDir.absolutePath(), true ); #elif defined(ANDROID) // this is "/data/data/org.qgis.qgis" in android QDir myDir( QDir::homePath() ); diff --git a/src/gui/CMakeLists.txt b/src/gui/CMakeLists.txt index 6e3b283a034d..d137771d750c 100644 --- a/src/gui/CMakeLists.txt +++ b/src/gui/CMakeLists.txt @@ -1760,37 +1760,14 @@ GENERATE_EXPORT_HEADER( set(QGIS_GUI_HDRS ${QGIS_GUI_HDRS} ${CMAKE_CURRENT_BINARY_DIR}/qgis_gui.h) -if(NOT APPLE OR NOT QGIS_MACAPP_FRAMEWORK) - if (WIN32) - include_directories(${CMAKE_SOURCE_DIR}/src/native/win) - elseif (APPLE) - include_directories(${CMAKE_SOURCE_DIR}/src/native/mac) - elseif (UNIX) - include_directories(${CMAKE_SOURCE_DIR}/src/native/linux) - endif() - install(FILES ${QGIS_GUI_HDRS} DESTINATION ${QGIS_INCLUDE_DIR}) -else() +if (WIN32) + include_directories(${CMAKE_SOURCE_DIR}/src/native/win) +elseif (APPLE) include_directories(${CMAKE_SOURCE_DIR}/src/native/mac) - set_target_properties(qgis_gui PROPERTIES - CLEAN_DIRECT_OUTPUT 1 - FRAMEWORK 1 - FRAMEWORK_VERSION "${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}" - MACOSX_FRAMEWORK_INFO_PLIST "${CMAKE_SOURCE_DIR}/mac/framework.info.plist.in" - MACOSX_FRAMEWORK_SHORT_VERSION_STRING ${COMPLETE_VERSION} - MACOSX_FRAMEWORK_IDENTIFIER org.qgis.qgis3_gui - BUILD_WITH_INSTALL_RPATH TRUE - PUBLIC_HEADER "${QGIS_GUI_HDRS}" - LINK_FLAGS "${CMAKE_SHARED_LINKER_FLAGS}" - ) - # generated export header does not get copied with PUBLIC_HEADER files - add_custom_command(TARGET qgis_gui - POST_BUILD - COMMAND ${CMAKE_COMMAND} -E copy qgis_gui.h - "${QGIS_OUTPUT_DIRECTORY}/${QGIS_LIB_SUBDIR}/qgis_gui.framework/Headers" - WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} - DEPENDS qgis_gui.h - ) +elseif (UNIX) + include_directories(${CMAKE_SOURCE_DIR}/src/native/linux) endif() +install(FILES ${QGIS_GUI_HDRS} DESTINATION ${QGIS_INCLUDE_DIR}) #generate unversioned libs for android if (NOT ANDROID) @@ -1883,21 +1860,7 @@ install(TARGETS qgis_gui RUNTIME DESTINATION ${QGIS_BIN_DIR} LIBRARY DESTINATION ${QGIS_LIB_DIR} ARCHIVE DESTINATION ${QGIS_LIB_DIR} - FRAMEWORK DESTINATION ${QGIS_FW_SUBDIR} PUBLIC_HEADER DESTINATION ${QGIS_INCLUDE_DIR}) # ui headers to install, don't exist at target definition time, install manually -if (APPLE AND QGIS_MACAPP_FRAMEWORK) - install(FILES ${QGIS_GUI_UI_HDRS} DESTINATION ${QGIS_FW_SUBDIR}/qgis_gui.framework/Headers) -else() - install(FILES ${QGIS_GUI_UI_HDRS} DESTINATION ${QGIS_INCLUDE_DIR}) -endif() - -# Mac dev frameworks - -if (APPLE AND QGIS_MACAPP_INSTALL_DEV) - install(TARGETS qgis_gui FRAMEWORK DESTINATION ${QGIS_MACAPP_DEV_PREFIX}) - install(FILES ${QGIS_GUI_UI_HDRS} DESTINATION ${QGIS_MACAPP_DEV_PREFIX}/qgis_gui.framework/Headers) - install(CODE "execute_process(COMMAND install_name_tool -id \"${QGIS_MACAPP_DEV_PREFIX}/qgis_gui.framework/Versions/${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}/qgis_gui\" \"$ENV{DESTDIR}${QGIS_MACAPP_DEV_PREFIX}/qgis_gui.framework/qgis_gui\")") - install(CODE "execute_process(COMMAND install_name_tool -change \"${CMAKE_INSTALL_NAME_DIR}/qgis_core.framework/Versions/${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}/qgis_core\" \"${QGIS_MACAPP_DEV_PREFIX}/qgis_core.framework/Versions/${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}/qgis_core\" \"$ENV{DESTDIR}${QGIS_MACAPP_DEV_PREFIX}/qgis_gui.framework/qgis_gui\")") -endif() +install(FILES ${QGIS_GUI_UI_HDRS} DESTINATION ${QGIS_INCLUDE_DIR}) diff --git a/src/native/CMakeLists.txt b/src/native/CMakeLists.txt index 73edb952b1ad..f288ff37b0c8 100644 --- a/src/native/CMakeLists.txt +++ b/src/native/CMakeLists.txt @@ -7,34 +7,10 @@ if (IOS) endif() -set(NATIVE_LINK_LIBS) - if(UNIX AND NOT APPLE AND NOT ANDROID) find_package(${QT_VERSION_BASE} COMPONENTS DBus REQUIRED) endif() -if(APPLE) - set(APPLE_LIB_LIST ApplicationServices CoreFoundation IOKit AppKit) - foreach(_lib ${APPLE_LIB_LIST}) - string(TOUPPER ${_lib} _lib_var) - # prefer /System/Library/Frameworks, in case CMAKE_FIND_FRAMEWORK=LAST, etc. - find_library(APPLE_${_lib_var}_LIBRARY - NAMES ${_lib} - PATHS /System/Library/Frameworks - NO_DEFAULT_PATH - ) - # if not found, drop back to standard find paths - find_library(APPLE_${_lib_var}_LIBRARY ${_lib}) - - if(NOT APPLE_${_lib_var}_LIBRARY) - message(FATAL_ERROR "Couldn't find Apple's '${_lib}' framework or library") - endif() - - list(APPEND NATIVE_LINK_LIBS "-weak_framework ${_lib}") - endforeach(_lib ${APPLE_LIB_LIST}) -endif() - - ############################################################# # sources @@ -110,21 +86,7 @@ GENERATE_EXPORT_HEADER( set(QGIS_NATIVE_HDRS ${QGIS_NATIVE_HDRS} ${CMAKE_CURRENT_BINARY_DIR}/qgis_native.h) -if(NOT APPLE OR NOT QGIS_MACAPP_FRAMEWORK) - install(FILES ${QGIS_NATIVE_HDRS} DESTINATION ${QGIS_INCLUDE_DIR}) -else() - set_target_properties(qgis_native PROPERTIES - CLEAN_DIRECT_OUTPUT 1 - FRAMEWORK 1 - FRAMEWORK_VERSION "${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}" - MACOSX_FRAMEWORK_INFO_PLIST "${CMAKE_SOURCE_DIR}/mac/framework.info.plist.in" - MACOSX_FRAMEWORK_SHORT_VERSION_STRING ${COMPLETE_VERSION} - MACOSX_FRAMEWORK_IDENTIFIER org.qgis.qgis3_native - BUILD_WITH_INSTALL_RPATH TRUE - PUBLIC_HEADER "${QGIS_NATIVE_HDRS}" - LINK_FLAGS "${CMAKE_SHARED_LINKER_FLAGS}" - ) -endif() +install(FILES ${QGIS_NATIVE_HDRS} DESTINATION ${QGIS_INCLUDE_DIR}) #generate unversioned libs for android if(NOT ANDROID) @@ -134,11 +96,7 @@ if(NOT ANDROID) ) endif() -if (BUILD_WITH_QT6) - target_link_libraries(qgis_native ${Qt6Core_LIBRARIES} ${Qt6Gui_LIBRARIES} "${NATIVE_LINK_LIBS}") -else() - target_link_libraries(qgis_native ${Qt5Core_LIBRARIES} ${Qt5Gui_LIBRARIES} "${NATIVE_LINK_LIBS}") -endif() +target_link_libraries(qgis_native ${QT_VERSION_BASE}::Core ${QT_VERSION_BASE}::Gui) if (UNIX AND NOT APPLE AND NOT ANDROID) target_link_libraries(qgis_native ${QT_VERSION_BASE}::DBus) @@ -158,13 +116,5 @@ install(TARGETS qgis_native RUNTIME DESTINATION ${QGIS_BIN_DIR} LIBRARY DESTINATION ${QGIS_LIB_DIR} ARCHIVE DESTINATION ${QGIS_LIB_DIR} - FRAMEWORK DESTINATION ${QGIS_FW_SUBDIR} PUBLIC_HEADER DESTINATION ${QGIS_INCLUDE_DIR} ) - -# Mac dev frameworks - -if (APPLE AND QGIS_MACAPP_INSTALL_DEV) - install(TARGETS qgis_native FRAMEWORK DESTINATION ${QGIS_MACAPP_DEV_PREFIX}) - install(CODE "execute_process(COMMAND install_name_tool -id \"${QGIS_MACAPP_DEV_PREFIX}/qgis_native.framework/Versions/${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}/qgis_native\" \"$ENV{DESTDIR}${QGIS_MACAPP_DEV_PREFIX}/qgis_native.framework/qgis_native\")") -endif() diff --git a/src/process/CMakeLists.txt b/src/process/CMakeLists.txt index ab5a50a093ac..7f60cfdb42e4 100644 --- a/src/process/CMakeLists.txt +++ b/src/process/CMakeLists.txt @@ -15,7 +15,7 @@ endif() ######################################################## # Build -add_executable (qgis_process MACOSX_BUNDLE ${QGIS_PROCESS_SRCS}) +add_executable (qgis_process ${QGIS_PROCESS_SRCS}) # require c++17 target_compile_features(qgis_process PRIVATE cxx_std_17) diff --git a/src/providers/grass/CMakeLists.txt b/src/providers/grass/CMakeLists.txt index 53da1efe2837..f74c0666f4e4 100644 --- a/src/providers/grass/CMakeLists.txt +++ b/src/providers/grass/CMakeLists.txt @@ -7,9 +7,6 @@ include_directories( ${CMAKE_BINARY_DIR}/src/providers/grass ${CMAKE_CURRENT_BINARY_DIR} ) -include_directories (SYSTEM - ${POSTGRES_INCLUDE_DIR} -) # # GRASS library @@ -75,29 +72,9 @@ macro(ADD_GRASSLIB GRASS_BUILD_VERSION) set(GRASS_OFF_T_SIZE_DEF "") endif() - if(QGIS_MACAPP_FRAMEWORK) - set_target_properties(qgisgrass${GRASS_BUILD_VERSION} PROPERTIES - CLEAN_DIRECT_OUTPUT 1 - FRAMEWORK 1 - FRAMEWORK_VERSION "${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}" - MACOSX_FRAMEWORK_INFO_PLIST "${CMAKE_SOURCE_DIR}/mac/framework.info.plist.in" - MACOSX_FRAMEWORK_SHORT_VERSION_STRING ${COMPLETE_VERSION} - MACOSX_FRAMEWORK_IDENTIFIER org.qgis.qgis3_grass - COMPILE_FLAGS "-DGRASS_BASE=\\\"${GRASS_PREFIX}\\\" ${GRASS_OFF_T_SIZE_DEF}" - ) - else() - set_target_properties(qgisgrass${GRASS_BUILD_VERSION} PROPERTIES - CLEAN_DIRECT_OUTPUT 1 - FRAMEWORK 0 - COMPILE_FLAGS "-DGRASS_BASE=\\\"${GRASS_PREFIX}\\\" ${GRASS_OFF_T_SIZE_DEF}" - ) - endif() - - if (APPLE) - set_target_properties(qgisgrass${GRASS_BUILD_VERSION} PROPERTIES - LINK_FLAGS "${CMAKE_SHARED_LINKER_FLAGS}" - ) - endif() + set_target_properties(qgisgrass${GRASS_BUILD_VERSION} PROPERTIES + COMPILE_FLAGS "-DGRASS_BASE=\\\"${GRASS_PREFIX}\\\" ${GRASS_OFF_T_SIZE_DEF}" + ) #generate unversioned libs for android if (NOT ANDROID) @@ -140,10 +117,6 @@ macro(ADD_GRASSLIB GRASS_BUILD_VERSION) ) endif() - if (APPLE) - set_target_properties(qgisgrass${GRASS_BUILD_VERSION} PROPERTIES BUILD_WITH_INSTALL_RPATH TRUE) - endif() - GENERATE_EXPORT_HEADER( qgisgrass${GRASS_BUILD_VERSION} BASE_NAME GRASS_LIB @@ -288,8 +261,7 @@ macro(ADD_GRASSLIB GRASS_BUILD_VERSION) install(TARGETS qgisgrass${GRASS_BUILD_VERSION} RUNTIME DESTINATION ${QGIS_BIN_DIR} - LIBRARY DESTINATION ${QGIS_LIB_DIR} - FRAMEWORK DESTINATION ${QGIS_FW_SUBDIR}) + LIBRARY DESTINATION ${QGIS_LIB_DIR}) install(TARGETS provider_grass${GRASS_BUILD_VERSION} RUNTIME DESTINATION ${QGIS_PLUGIN_DIR} diff --git a/src/python/CMakeLists.txt b/src/python/CMakeLists.txt index 3323d3985f17..e6398e70f993 100644 --- a/src/python/CMakeLists.txt +++ b/src/python/CMakeLists.txt @@ -30,10 +30,6 @@ GENERATE_EXPORT_HEADER( EXPORT_FILE_NAME qgis_python.h ) -if (APPLE) - set_target_properties(qgispython PROPERTIES BUILD_WITH_INSTALL_RPATH TRUE) -endif() - install(TARGETS qgispython RUNTIME DESTINATION ${QGIS_BIN_DIR} LIBRARY DESTINATION ${QGIS_LIB_DIR} diff --git a/src/python/qgspythonutilsimpl.cpp b/src/python/qgspythonutilsimpl.cpp index 14facb8ea425..e59099bf70e8 100644 --- a/src/python/qgspythonutilsimpl.cpp +++ b/src/python/qgspythonutilsimpl.cpp @@ -218,8 +218,27 @@ void QgsPythonUtilsImpl::init() } #endif - // initialize python - Py_Initialize(); + PyConfig config; + PyConfig_InitPythonConfig( &config ); + +#ifdef QGIS_MAC_BUNDLE + // If we package QGIS as a mac app, we deploy Qt plugins into [app]/Contents/PlugIns + if ( qgetenv( "PYTHONHOME" ).isNull() ) + { + status = PyConfig_SetString( &config, &config.home, QgsApplication::libraryPath().toStdWString().c_str() ); + if ( PyStatus_Exception( status ) ) + { + qWarning() << "Failed to set python home"; + } + } +#endif + + status = Py_InitializeFromConfig( &config ); + if ( PyStatus_Exception( status ) ) + { + qWarning() << "Failed to initialize from config"; + } + PyConfig_Clear( &config ); mPythonEnabled = true; diff --git a/src/quickgui/CMakeLists.txt b/src/quickgui/CMakeLists.txt index a1f70a30e492..3841ed9c5f02 100644 --- a/src/quickgui/CMakeLists.txt +++ b/src/quickgui/CMakeLists.txt @@ -69,35 +69,12 @@ GENERATE_EXPORT_HEADER( ) # Installation -if(NOT APPLE OR NOT QGIS_MACAPP_FRAMEWORK) - install(FILES ${CMAKE_CURRENT_BINARY_DIR}/qgis_quick.h ${QGIS_QUICK_GUI_HDRS} ${QGIS_QUICK_GUI_MOC_HDRS} DESTINATION ${QGIS_INCLUDE_DIR}) -else() - set_target_properties(qgis_quick PROPERTIES - CLEAN_DIRECT_OUTPUT 1 - FRAMEWORK 1 - FRAMEWORK_VERSION "${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}" - MACOSX_FRAMEWORK_INFO_PLIST "${CMAKE_SOURCE_DIR}/mac/framework.info.plist.in" - MACOSX_FRAMEWORK_SHORT_VERSION_STRING ${COMPLETE_VERSION} - MACOSX_FRAMEWORK_IDENTIFIER org.qgis.qgis3_quick - BUILD_WITH_INSTALL_RPATH TRUE - PUBLIC_HEADER "${QGIS_QUICK_GUI_HDRS};${QGIS_QUICK_GUI_MOC_HDRS}" - LINK_FLAGS "${CMAKE_SHARED_LINKER_FLAGS}" - ) - # generated export header does not get copied with PUBLIC_HEADER files - add_custom_command(TARGET qgis_quick - POST_BUILD - COMMAND ${CMAKE_COMMAND} -E copy qgis_quick.h - "${QGIS_OUTPUT_DIRECTORY}/${QGIS_LIB_SUBDIR}/qgis_quick.framework/Headers" - WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} - DEPENDS qgis_quick.h - ) -endif() +install(FILES ${CMAKE_CURRENT_BINARY_DIR}/qgis_quick.h ${QGIS_QUICK_GUI_HDRS} ${QGIS_QUICK_GUI_MOC_HDRS} DESTINATION ${QGIS_INCLUDE_DIR}) install(TARGETS qgis_quick RUNTIME DESTINATION ${QGIS_BIN_DIR} LIBRARY DESTINATION ${QGIS_LIB_DIR} ARCHIVE DESTINATION ${QGIS_LIB_DIR} - FRAMEWORK DESTINATION ${QGIS_FW_SUBDIR} PUBLIC_HEADER DESTINATION ${QGIS_INCLUDE_DIR}) ############################################################ diff --git a/tests/bench/CMakeLists.txt b/tests/bench/CMakeLists.txt index 481e449d9d7f..216a90067b01 100644 --- a/tests/bench/CMakeLists.txt +++ b/tests/bench/CMakeLists.txt @@ -9,7 +9,7 @@ set (BENCH_SRCS ######################################################## # Build -add_executable (qgis_bench MACOSX_BUNDLE WIN32 ${BENCH_SRCS} ) +add_executable (qgis_bench WIN32 ${BENCH_SRCS} ) # require c++17 target_compile_features(qgis_bench PRIVATE cxx_std_17) @@ -46,13 +46,3 @@ install (TARGETS qgis_bench BUNDLE DESTINATION ${QGIS_BIN_DIR} RUNTIME DESTINATION ${QGIS_BIN_DIR} ) -if (APPLE) - install (CODE "execute_process(COMMAND ln -sfn ../../../${QGIS_FW_SUBDIR} \"$ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}/${QGIS_BIN_DIR}/qgis_bench.app/Contents/Frameworks\")") - install (CODE "execute_process(COMMAND ln -sfn ../../../../${QGIS_LIB_SUBDIR} \"$ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}/${QGIS_BIN_DIR}/qgis_bench.app/Contents/MacOS/lib\")") - install (CODE "execute_process(COMMAND ln -sfn ../../../${QGIS_PLUGIN_SUBDIR}/.. \"$ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}/${QGIS_BIN_DIR}/qgis_bench.app/Contents/Plugins\")") - install (CODE "execute_process(COMMAND ln -sfn ../../../${QGIS_DATA_SUBDIR} \"$ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}/${QGIS_BIN_DIR}/qgis_bench.app/Contents/Resources\")") - # may not exist, unless BundleUtilities are used - install (CODE "execute_process(COMMAND ln -sfn ../../../../share \"$ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}/${QGIS_BIN_DIR}/qgis_bench.app/Contents/MacOS/share\")") - -endif() - diff --git a/vcpkg/ports/qca/0001-fix-path-for-vcpkg.patch b/vcpkg/ports/qca/0001-fix-path-for-vcpkg.patch new file mode 100644 index 000000000000..744fce107d51 --- /dev/null +++ b/vcpkg/ports/qca/0001-fix-path-for-vcpkg.patch @@ -0,0 +1,72 @@ +diff --git "a/CMakeLists.txt" "b/CMakeLists.txt" +index 1f84c2c9e..f72ee9d8d 100644 +--- "a/CMakeLists.txt" ++++ "b/CMakeLists.txt" +@@ -58,6 +58,7 @@ set(QCA_SUFFIX "qt5") + if(NOT BUILD_SHARED_LIBS OR QT_IS_STATIC) + set(STATIC_PLUGINS ON) + add_definitions(-DQT_STATICPLUGIN) ++ add_definitions(-DQCA_STATIC) + set(PLUGIN_TYPE "STATIC") + else() + set(PLUGIN_TYPE "MODULE") +@@ -266,10 +267,17 @@ if(DEVELOPER_MODE) + add_definitions(-DDEVELOPER_MODE) + + # To prefer plugins from build tree when run qca from build tree +- file(WRITE ${CMAKE_BINARY_DIR}/bin/qt.conf +-"[Paths] +-Plugins=${CMAKE_BINARY_DIR}/lib/${QCA_LIB_NAME} +-") ++ if(NOT BUILD_SHARED_LIBS OR QT_IS_STATIC) ++ file(WRITE ${CMAKE_BINARY_DIR}/bin/qt.conf ++ "[Paths] ++ Plugins=${CMAKE_BINARY_DIR}/lib/${QCA_LIB_NAME} ++ ") ++ else() ++ file(WRITE ${CMAKE_BINARY_DIR}/bin/qt.conf ++ "[Paths] ++ Plugins=${CMAKE_BINARY_DIR}/bin/${QCA_LIB_NAME} ++ ") ++ endif() + endif() + + if (APPLE) +@@ -309,7 +317,7 @@ else() + set( qca_CERTSTORE "${CMAKE_CURRENT_SOURCE_DIR}/certs/rootcerts.pem") + # note that INSTALL_FILES targets are relative to the current installation prefix... + if(NOT DEVELOPER_MODE) +- install(FILES "${qca_CERTSTORE}" DESTINATION "${QCA_PREFIX_INSTALL_DIR}/certs") ++ install(FILES "${qca_CERTSTORE}" DESTINATION "${QCA_PREFIX_INSTALL_DIR}/share/qca/certs") + endif() + endif() + message(STATUS "certstore path: " ${qca_CERTSTORE}) +@@ -390,10 +398,10 @@ endif() + include(CMakePackageConfigHelpers) + configure_package_config_file( + "${CMAKE_CURRENT_SOURCE_DIR}/QcaConfig.cmake.in" +- "${CMAKE_CURRENT_BINARY_DIR}/lib/cmake/${QCA_CONFIG_NAME_BASE}/${QCA_CONFIG_NAME_BASE}Config.cmake" +- INSTALL_DESTINATION ${QCA_LIBRARY_INSTALL_DIR}/cmake/${QCA_CONFIG_NAME_BASE} ++ "${CMAKE_BINARY_DIR}/share/qca/cmake/${QCA_CONFIG_NAME_BASE}Config.cmake" ++ INSTALL_DESTINATION ${CMAKE_BINARY_DIR}/share/qca/cmake + ) +-write_basic_config_version_file("${CMAKE_CURRENT_BINARY_DIR}/lib/cmake/${QCA_CONFIG_NAME_BASE}/${QCA_CONFIG_NAME_BASE}ConfigVersion.cmake" VERSION ${QCA_LIB_VERSION_STRING} COMPATIBILITY AnyNewerVersion) ++write_basic_config_version_file("${CMAKE_BINARY_DIR}/share/qca/cmake/${QCA_CONFIG_NAME_BASE}ConfigVersion.cmake" VERSION ${QCA_LIB_VERSION_STRING} COMPATIBILITY AnyNewerVersion) + + if(NOT DEVELOPER_MODE) + +@@ -461,10 +469,10 @@ if(NOT DEVELOPER_MODE) + endif() + endif() + +- install(EXPORT ${QCA_CONFIG_NAME_BASE}Targets DESTINATION ${QCA_LIBRARY_INSTALL_DIR}/cmake/${QCA_CONFIG_NAME_BASE} FILE ${QCA_CONFIG_NAME_BASE}Targets.cmake) ++ install(EXPORT ${QCA_CONFIG_NAME_BASE}Targets DESTINATION ${QCA_PREFIX_INSTALL_DIR}/share/qca/cmake FILE ${QCA_CONFIG_NAME_BASE}Targets.cmake) + install(FILES +- "${CMAKE_CURRENT_BINARY_DIR}/lib/cmake/${QCA_CONFIG_NAME_BASE}/${QCA_CONFIG_NAME_BASE}Config.cmake" +- "${CMAKE_CURRENT_BINARY_DIR}/lib/cmake/${QCA_CONFIG_NAME_BASE}/${QCA_CONFIG_NAME_BASE}ConfigVersion.cmake" +- DESTINATION ${QCA_LIBRARY_INSTALL_DIR}/cmake/${QCA_CONFIG_NAME_BASE} ++ "${CMAKE_BINARY_DIR}/share/qca/cmake/${QCA_CONFIG_NAME_BASE}Config.cmake" ++ "${CMAKE_BINARY_DIR}/share/qca/cmake/${QCA_CONFIG_NAME_BASE}ConfigVersion.cmake" ++ DESTINATION ${QCA_PREFIX_INSTALL_DIR}/share/qca/cmake + ) + endif() diff --git a/vcpkg/ports/qca/0002-fix-build-error.patch b/vcpkg/ports/qca/0002-fix-build-error.patch new file mode 100644 index 000000000000..5515d21f738a --- /dev/null +++ b/vcpkg/ports/qca/0002-fix-build-error.patch @@ -0,0 +1,26 @@ +From 8d67288a3dde7e535ff747715f96f98282a3bf67 Mon Sep 17 00:00:00 2001 +From: Matthias Kuhn +Date: Fri, 3 Dec 2021 15:17:25 +0100 +Subject: [PATCH] Ifdef codecs + +--- + cmake/modules/QcaMacro.cmake | 9 --------- + plugins/qca-ossl/qca-ossl.cpp | 6 ++++++ + 2 files changed, 6 insertions(+), 9 deletions(-) + +diff --git a/cmake/modules/QcaMacro.cmake b/cmake/modules/QcaMacro.cmake +index 80af6e84..ba86310d 100644 +--- a/cmake/modules/QcaMacro.cmake ++++ b/cmake/modules/QcaMacro.cmake +@@ -65,10 +65,6 @@ macro(add_qca_test TARGET DESCRIPTION) + endmacro(add_qca_test) + + macro(install_pdb TARGET INSTALL_PATH) +- if(MSVC) +- install(FILES $ DESTINATION ${INSTALL_PATH} CONFIGURATIONS Debug) +- install(FILES $ DESTINATION ${INSTALL_PATH} CONFIGURATIONS RelWithDebInfo) +- endif() + endmacro(install_pdb) + + macro(normalize_path PATH) + diff --git a/vcpkg/ports/qca/0003-Define-NOMINMAX-for-botan-plugin-with-MSVC.patch b/vcpkg/ports/qca/0003-Define-NOMINMAX-for-botan-plugin-with-MSVC.patch new file mode 100644 index 000000000000..d894000d617d --- /dev/null +++ b/vcpkg/ports/qca/0003-Define-NOMINMAX-for-botan-plugin-with-MSVC.patch @@ -0,0 +1,28 @@ +From f32f5ae8b8b49653bfff87f2f882862bcaa8c3f1 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?=D9=85=D9=87=D8=AF=D9=8A=20=D8=B4=D9=8A=D9=86=D9=88=D9=86?= + =?UTF-8?q?=20=28Mehdi=20Chinoune=29?= +Date: Mon, 20 Mar 2023 16:21:18 +0100 +Subject: [PATCH] Define NOMINMAX to fix building qca-botan plugin with MSVC + +--- + plugins/qca-botan/CMakeLists.txt | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/plugins/qca-botan/CMakeLists.txt b/plugins/qca-botan/CMakeLists.txt +index 11c0d20..9b8b978 100644 +--- a/plugins/qca-botan/CMakeLists.txt ++++ b/plugins/qca-botan/CMakeLists.txt +@@ -11,6 +11,10 @@ if(BOTAN_FOUND) + set(QCA_BOTAN_SOURCES qca-botan.cpp) + add_library(qca-botan ${PLUGIN_TYPE} ${QCA_BOTAN_SOURCES}) + ++ if(MSVC) ++ target_compile_definitions(qca-botan PRIVATE NOMINMAX) ++ endif() ++ + if(APPLE AND ${PLUGIN_TYPE} STREQUAL "MODULE") + set_property(TARGET qca-botan PROPERTY SUFFIX ".dylib") + endif() +-- +2.40.0.windows.1 + diff --git a/vcpkg/ports/qca/mk-ca-bundle.pl b/vcpkg/ports/qca/mk-ca-bundle.pl new file mode 100644 index 000000000000..9574f1dbf95b --- /dev/null +++ b/vcpkg/ports/qca/mk-ca-bundle.pl @@ -0,0 +1,554 @@ +#!/usr/bin/perl -w +# *************************************************************************** +# * _ _ ____ _ +# * Project ___| | | | _ \| | +# * / __| | | | |_) | | +# * | (__| |_| | _ <| |___ +# * \___|\___/|_| \_\_____| +# * +# * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. +# * +# * This software is licensed as described in the file COPYING, which +# * you should have received as part of this distribution. The terms +# * are also available at https://curl.haxx.se/docs/copyright.html. +# * +# * You may opt to use, copy, modify, merge, publish, distribute and/or sell +# * copies of the Software, and permit persons to whom the Software is +# * furnished to do so, under the terms of the COPYING file. +# * +# * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +# * KIND, either express or implied. +# * +# *************************************************************************** +# This Perl script creates a fresh ca-bundle.crt file for use with libcurl. +# It downloads certdata.txt from Mozilla's source tree (see URL below), +# then parses certdata.txt and extracts CA Root Certificates into PEM format. +# These are then processed with the OpenSSL commandline tool to produce the +# final ca-bundle.crt file. +# The script is based on the parse-certs script written by Roland Krikava. +# This Perl script works on almost any platform since its only external +# dependency is the OpenSSL commandline tool for optional text listing. +# Hacked by Guenter Knauf. +# +use Encode; +use Getopt::Std; +use MIME::Base64; +use strict; +use vars qw($opt_b $opt_d $opt_f $opt_h $opt_i $opt_k $opt_l $opt_m $opt_n $opt_p $opt_q $opt_s $opt_t $opt_u $opt_v $opt_w); +use List::Util; +use Text::Wrap; +my $MOD_SHA = "Digest::SHA"; +eval "require $MOD_SHA"; +if ($@) { + $MOD_SHA = "Digest::SHA::PurePerl"; + eval "require $MOD_SHA"; +} +eval "require LWP::UserAgent"; + +my %urls = ( + 'nss' => + 'https://hg.mozilla.org/projects/nss/raw-file/tip/lib/ckfw/builtins/certdata.txt', + 'central' => + 'https://hg.mozilla.org/mozilla-central/raw-file/default/security/nss/lib/ckfw/builtins/certdata.txt', + 'aurora' => + 'https://hg.mozilla.org/releases/mozilla-aurora/raw-file/default/security/nss/lib/ckfw/builtins/certdata.txt', + 'beta' => + 'https://hg.mozilla.org/releases/mozilla-beta/raw-file/default/security/nss/lib/ckfw/builtins/certdata.txt', + 'release' => + 'https://hg.mozilla.org/releases/mozilla-release/raw-file/default/security/nss/lib/ckfw/builtins/certdata.txt', +); + +$opt_d = 'release'; + +# If the OpenSSL commandline is not in search path you can configure it here! +my $openssl = 'openssl'; + +my $version = '1.27'; + +$opt_w = 76; # default base64 encoded lines length + +# default cert types to include in the output (default is to include CAs which may issue SSL server certs) +my $default_mozilla_trust_purposes = "SERVER_AUTH"; +my $default_mozilla_trust_levels = "TRUSTED_DELEGATOR"; +$opt_p = $default_mozilla_trust_purposes . ":" . $default_mozilla_trust_levels; + +my @valid_mozilla_trust_purposes = ( + "DIGITAL_SIGNATURE", + "NON_REPUDIATION", + "KEY_ENCIPHERMENT", + "DATA_ENCIPHERMENT", + "KEY_AGREEMENT", + "KEY_CERT_SIGN", + "CRL_SIGN", + "SERVER_AUTH", + "CLIENT_AUTH", + "CODE_SIGNING", + "EMAIL_PROTECTION", + "IPSEC_END_SYSTEM", + "IPSEC_TUNNEL", + "IPSEC_USER", + "TIME_STAMPING", + "STEP_UP_APPROVED" +); + +my @valid_mozilla_trust_levels = ( + "TRUSTED_DELEGATOR", # CAs + "NOT_TRUSTED", # Don't trust these certs. + "MUST_VERIFY_TRUST", # This explicitly tells us that it ISN'T a CA but is otherwise ok. In other words, this should tell the app to ignore any other sources that claim this is a CA. + "TRUSTED" # This cert is trusted, but only for itself and not for delegates (i.e. it is not a CA). +); + +my $default_signature_algorithms = $opt_s = "MD5"; + +my @valid_signature_algorithms = ( + "MD5", + "SHA1", + "SHA256", + "SHA384", + "SHA512" +); + +$0 =~ s@.*(/|\\)@@; +$Getopt::Std::STANDARD_HELP_VERSION = 1; +getopts('bd:fhiklmnp:qs:tuvw:'); + +if(!defined($opt_d)) { + # to make plain "-d" use not cause warnings, and actually still work + $opt_d = 'release'; +} + +# Use predefined URL or else custom URL specified on command line. +my $url; +if(defined($urls{$opt_d})) { + $url = $urls{$opt_d}; + if(!$opt_k && $url !~ /^https:\/\//i) { + die "The URL for '$opt_d' is not HTTPS. Use -k to override (insecure).\n"; + } +} +else { + $url = $opt_d; +} + +my $curl = `curl -V`; + +if ($opt_i) { + print ("=" x 78 . "\n"); + print "Script Version : $version\n"; + print "Perl Version : $]\n"; + print "Operating System Name : $^O\n"; + print "Getopt::Std.pm Version : ${Getopt::Std::VERSION}\n"; + print "MIME::Base64.pm Version : ${MIME::Base64::VERSION}\n"; + print "LWP::UserAgent.pm Version : ${LWP::UserAgent::VERSION}\n" if($LWP::UserAgent::VERSION); + print "LWP.pm Version : ${LWP::VERSION}\n" if($LWP::VERSION); + print "Digest::SHA.pm Version : ${Digest::SHA::VERSION}\n" if ($Digest::SHA::VERSION); + print "Digest::SHA::PurePerl.pm Version : ${Digest::SHA::PurePerl::VERSION}\n" if ($Digest::SHA::PurePerl::VERSION); + print ("=" x 78 . "\n"); +} + +sub warning_message() { + if ( $opt_d =~ m/^risk$/i ) { # Long Form Warning and Exit + print "Warning: Use of this script may pose some risk:\n"; + print "\n"; + print " 1) If you use HTTP URLs they are subject to a man in the middle attack\n"; + print " 2) Default to 'release', but more recent updates may be found in other trees\n"; + print " 3) certdata.txt file format may change, lag time to update this script\n"; + print " 4) Generally unwise to blindly trust CAs without manual review & verification\n"; + print " 5) Mozilla apps use additional security checks aren't represented in certdata\n"; + print " 6) Use of this script will make a security engineer grind his teeth and\n"; + print " swear at you. ;)\n"; + exit; + } else { # Short Form Warning + print "Warning: Use of this script may pose some risk, -d risk for more details.\n"; + } +} + +sub HELP_MESSAGE() { + print "Usage:\t${0} [-b] [-d] [-f] [-i] [-k] [-l] [-n] [-p] [-q] [-s] [-t] [-u] [-v] [-w] []\n"; + print "\t-b\tbackup an existing version of ca-bundle.crt\n"; + print "\t-d\tspecify Mozilla tree to pull certdata.txt or custom URL\n"; + print "\t\t Valid names are:\n"; + print "\t\t ", join( ", ", map { ( $_ =~ m/$opt_d/ ) ? "$_ (default)" : "$_" } sort keys %urls ), "\n"; + print "\t-f\tforce rebuild even if certdata.txt is current\n"; + print "\t-i\tprint version info about used modules\n"; + print "\t-k\tallow URLs other than HTTPS, enable HTTP fallback (insecure)\n"; + print "\t-l\tprint license info about certdata.txt\n"; + print "\t-m\tinclude meta data in output\n"; + print "\t-n\tno download of certdata.txt (to use existing)\n"; + print wrap("\t","\t\t", "-p\tlist of Mozilla trust purposes and levels for certificates to include in output. Takes the form of a comma separated list of purposes, a colon, and a comma separated list of levels. (default: $default_mozilla_trust_purposes:$default_mozilla_trust_levels)"), "\n"; + print "\t\t Valid purposes are:\n"; + print wrap("\t\t ","\t\t ", join( ", ", "ALL", @valid_mozilla_trust_purposes ) ), "\n"; + print "\t\t Valid levels are:\n"; + print wrap("\t\t ","\t\t ", join( ", ", "ALL", @valid_mozilla_trust_levels ) ), "\n"; + print "\t-q\tbe really quiet (no progress output at all)\n"; + print wrap("\t","\t\t", "-s\tcomma separated list of certificate signatures/hashes to output in plain text mode. (default: $default_signature_algorithms)\n"); + print "\t\t Valid signature algorithms are:\n"; + print wrap("\t\t ","\t\t ", join( ", ", "ALL", @valid_signature_algorithms ) ), "\n"; + print "\t-t\tinclude plain text listing of certificates\n"; + print "\t-u\tunlink (remove) certdata.txt after processing\n"; + print "\t-v\tbe verbose and print out processed CAs\n"; + print "\t-w \twrap base64 output lines after chars (default: ${opt_w})\n"; + exit; +} + +sub VERSION_MESSAGE() { + print "${0} version ${version} running Perl ${]} on ${^O}\n"; +} + +warning_message() unless ($opt_q || $url =~ m/^(ht|f)tps:/i ); +HELP_MESSAGE() if ($opt_h); + +sub report($@) { + my $output = shift; + + print STDERR $output . "\n" unless $opt_q; +} + +sub is_in_list($@) { + my $target = shift; + + return defined(List::Util::first { $target eq $_ } @_); +} + +# Parses $param_string as a case insensitive comma separated list with optional whitespace +# validates that only allowed parameters are supplied +sub parse_csv_param($$@) { + my $description = shift; + my $param_string = shift; + my @valid_values = @_; + + my @values = map { + s/^\s+//; # strip leading spaces + s/\s+$//; # strip trailing spaces + uc $_ # return the modified string as upper case + } split( ',', $param_string ); + + # Find all values which are not in the list of valid values or "ALL" + my @invalid = grep { !is_in_list($_,"ALL",@valid_values) } @values; + + if ( scalar(@invalid) > 0 ) { + # Tell the user which parameters were invalid and print the standard help message which will exit + print "Error: Invalid ", $description, scalar(@invalid) == 1 ? ": " : "s: ", join( ", ", map { "\"$_\"" } @invalid ), "\n"; + HELP_MESSAGE(); + } + + @values = @valid_values if ( is_in_list("ALL",@values) ); + + return @values; +} + +sub sha256 { + my $result; + if ($Digest::SHA::VERSION || $Digest::SHA::PurePerl::VERSION) { + open(FILE, $_[0]) or die "Can't open '$_[0]': $!"; + binmode(FILE); + $result = $MOD_SHA->new(256)->addfile(*FILE)->hexdigest; + close(FILE); + } else { + # Use OpenSSL command if Perl Digest::SHA modules not available + $result = `"$openssl" dgst -r -sha256 "$_[0]"`; + $result =~ s/^([0-9a-f]{64}) .+/$1/is; + } + return $result; +} + + +sub oldhash { + my $hash = ""; + open(C, "<$_[0]") || return 0; + while() { + chomp; + if($_ =~ /^\#\# SHA256: (.*)/) { + $hash = $1; + last; + } + } + close(C); + return $hash; +} + +if ( $opt_p !~ m/:/ ) { + print "Error: Mozilla trust identifier list must include both purposes and levels\n"; + HELP_MESSAGE(); +} + +(my $included_mozilla_trust_purposes_string, my $included_mozilla_trust_levels_string) = split( ':', $opt_p ); +my @included_mozilla_trust_purposes = parse_csv_param( "trust purpose", $included_mozilla_trust_purposes_string, @valid_mozilla_trust_purposes ); +my @included_mozilla_trust_levels = parse_csv_param( "trust level", $included_mozilla_trust_levels_string, @valid_mozilla_trust_levels ); + +my @included_signature_algorithms = parse_csv_param( "signature algorithm", $opt_s, @valid_signature_algorithms ); + +sub should_output_cert(%) { + my %trust_purposes_by_level = @_; + + foreach my $level (@included_mozilla_trust_levels) { + # for each level we want to output, see if any of our desired purposes are included + return 1 if ( defined( List::Util::first { is_in_list( $_, @included_mozilla_trust_purposes ) } @{$trust_purposes_by_level{$level}} ) ); + } + + return 0; +} + +my $crt = $ARGV[0] || 'ca-bundle.crt'; +(my $txt = $url) =~ s@(.*/|\?.*)@@g; + +my $stdout = $crt eq '-'; +my $resp; +my $fetched; + +my $oldhash = oldhash($crt); + +report "SHA256 of old file: $oldhash"; + +if(!$opt_n) { + report "Downloading $txt ..."; + + # If we have an HTTPS URL then use curl + if($url =~ /^https:\/\//i) { + if($curl) { + if($curl =~ /^Protocols:.* https( |$)/m) { + report "Get certdata with curl!"; + my $proto = !$opt_k ? "--proto =https" : ""; + my $quiet = $opt_q ? "-s" : ""; + my @out = `curl -w %{response_code} $proto $quiet -o "$txt" "$url"`; + if(@out && $out[0] == 200) { + $fetched = 1; + report "Downloaded $txt"; + } + else { + report "Failed downloading via HTTPS with curl"; + if(-e $txt && !unlink($txt)) { + report "Failed to remove '$txt': $!"; + } + } + } + else { + report "curl lacks https support"; + } + } + else { + report "curl not found"; + } + } + + # If nothing was fetched then use LWP + if(!$fetched) { + if($url =~ /^https:\/\//i) { + report "Falling back to HTTP"; + $url =~ s/^https:\/\//http:\/\//i; + } + if(!$opt_k) { + report "URLs other than HTTPS are disabled by default, to enable use -k"; + exit 1; + } + report "Get certdata with LWP!"; + if(!defined(${LWP::UserAgent::VERSION})) { + report "LWP is not available (LWP::UserAgent not found)"; + exit 1; + } + my $ua = new LWP::UserAgent(agent => "$0/$version"); + $ua->env_proxy(); + $resp = $ua->mirror($url, $txt); + if($resp && $resp->code eq '304') { + report "Not modified"; + exit 0 if -e $crt && !$opt_f; + } + else { + $fetched = 1; + report "Downloaded $txt"; + } + if(!$resp || $resp->code !~ /^(?:200|304)$/) { + report "Unable to download latest data: " + . ($resp? $resp->code . ' - ' . $resp->message : "LWP failed"); + exit 1 if -e $crt || ! -r $txt; + } + } +} + +my $filedate = $resp ? $resp->last_modified : (stat($txt))[9]; +my $datesrc = "as of"; +if(!$filedate) { + # mxr.mozilla.org gave us a time, hg.mozilla.org does not! + $filedate = time(); + $datesrc="downloaded on"; +} + +# get the hash from the download file +my $newhash= sha256($txt); + +if(!$opt_f && $oldhash eq $newhash) { + report "Downloaded file identical to previous run\'s source file. Exiting"; + exit; +} + +report "SHA256 of new file: $newhash"; + +my $currentdate = scalar gmtime($filedate); + +my $format = $opt_t ? "plain text and " : ""; +if( $stdout ) { + open(CRT, '> -') or die "Couldn't open STDOUT: $!\n"; +} else { + open(CRT,">$crt.~") or die "Couldn't open $crt.~: $!\n"; +} +print CRT <) { + if (/\*\*\*\*\* BEGIN LICENSE BLOCK \*\*\*\*\*/) { + print CRT; + print if ($opt_l); + while () { + print CRT; + print if ($opt_l); + last if (/\*\*\*\*\* END LICENSE BLOCK \*\*\*\*\*/); + } + } + elsif(/^# (Issuer|Serial Number|Subject|Not Valid Before|Not Valid After |Fingerprint \(MD5\)|Fingerprint \(SHA1\)):/) { + push @precert, $_; + next; + } + elsif(/^#|^\s*$/) { + undef @precert; + next; + } + chomp; + + # this is a match for the start of a certificate + if (/^CKA_CLASS CK_OBJECT_CLASS CKO_CERTIFICATE/) { + $start_of_cert = 1 + } + if ($start_of_cert && /^CKA_LABEL UTF8 \"(.*)\"/) { + $caname = $1; + } + my %trust_purposes_by_level; + if ($start_of_cert && /^CKA_VALUE MULTILINE_OCTAL/) { + my $data; + while () { + last if (/^END/); + chomp; + my @octets = split(/\\/); + shift @octets; + for (@octets) { + $data .= chr(oct); + } + } + # scan forwards until the trust part + while () { + last if (/^CKA_CLASS CK_OBJECT_CLASS CKO_NSS_TRUST/); + chomp; + } + # now scan the trust part to determine how we should trust this cert + while () { + last if (/^#/); + if (/^CKA_TRUST_([A-Z_]+)\s+CK_TRUST\s+CKT_NSS_([A-Z_]+)\s*$/) { + if ( !is_in_list($1,@valid_mozilla_trust_purposes) ) { + report "Warning: Unrecognized trust purpose for cert: $caname. Trust purpose: $1. Trust Level: $2"; + } elsif ( !is_in_list($2,@valid_mozilla_trust_levels) ) { + report "Warning: Unrecognized trust level for cert: $caname. Trust purpose: $1. Trust Level: $2"; + } else { + push @{$trust_purposes_by_level{$2}}, $1; + } + } + } + + if ( !should_output_cert(%trust_purposes_by_level) ) { + $skipnum ++; + } else { + my $encoded = MIME::Base64::encode_base64($data, ''); + $encoded =~ s/(.{1,${opt_w}})/$1\n/g; + my $pem = "-----BEGIN CERTIFICATE-----\n" + . $encoded + . "-----END CERTIFICATE-----\n"; + print CRT "\n$caname\n"; + print CRT @precert if($opt_m); + my $maxStringLength = length(decode('UTF-8', $caname, Encode::FB_CROAK)); + if ($opt_t) { + foreach my $key (keys %trust_purposes_by_level) { + my $string = $key . ": " . join(", ", @{$trust_purposes_by_level{$key}}); + $maxStringLength = List::Util::max( length($string), $maxStringLength ); + print CRT $string . "\n"; + } + } + print CRT ("=" x $maxStringLength . "\n"); + if (!$opt_t) { + print CRT $pem; + } else { + my $pipe = ""; + foreach my $hash (@included_signature_algorithms) { + $pipe = "|$openssl x509 -" . $hash . " -fingerprint -noout -inform PEM"; + if (!$stdout) { + $pipe .= " >> $crt.~"; + close(CRT) or die "Couldn't close $crt.~: $!"; + } + open(TMP, $pipe) or die "Couldn't open openssl pipe: $!"; + print TMP $pem; + close(TMP) or die "Couldn't close openssl pipe: $!"; + if (!$stdout) { + open(CRT, ">>$crt.~") or die "Couldn't open $crt.~: $!"; + } + } + $pipe = "|$openssl x509 -text -inform PEM"; + if (!$stdout) { + $pipe .= " >> $crt.~"; + close(CRT) or die "Couldn't close $crt.~: $!"; + } + open(TMP, $pipe) or die "Couldn't open openssl pipe: $!"; + print TMP $pem; + close(TMP) or die "Couldn't close openssl pipe: $!"; + if (!$stdout) { + open(CRT, ">>$crt.~") or die "Couldn't open $crt.~: $!"; + } + } + report "Parsing: $caname" if ($opt_v); + $certnum ++; + $start_of_cert = 0; + } + undef @precert; + } + +} +close(TXT) or die "Couldn't close $txt: $!\n"; +close(CRT) or die "Couldn't close $crt.~: $!\n"; +unless( $stdout ) { + if ($opt_b && -e $crt) { + my $bk = 1; + while (-e "$crt.~${bk}~") { + $bk++; + } + rename $crt, "$crt.~${bk}~" or die "Failed to create backup $crt.~$bk}~: $!\n"; + } elsif( -e $crt ) { + unlink( $crt ) or die "Failed to remove $crt: $!\n"; + } + rename "$crt.~", $crt or die "Failed to rename $crt.~ to $crt: $!\n"; +} +if($opt_u && -e $txt && !unlink($txt)) { + report "Failed to remove $txt: $!\n"; +} +report "Done ($certnum CA certs processed, $skipnum skipped)."; diff --git a/vcpkg/ports/qca/portfile.cmake b/vcpkg/ports/qca/portfile.cmake new file mode 100644 index 000000000000..cffcbb18b38a --- /dev/null +++ b/vcpkg/ports/qca/portfile.cmake @@ -0,0 +1,101 @@ +# This portfile adds the Qt Cryptographic Arcitecture +# Changes to the original build: +# No -qt5 suffix, which is recommended just for Linux +# Output directories according to vcpkg +# Updated certstore. See certstore.pem in the output dirs +# +vcpkg_find_acquire_program(PERL) +get_filename_component(PERL_EXE_PATH ${PERL} DIRECTORY) +vcpkg_add_to_path("${PERL_EXE_PATH}") + +vcpkg_from_github( + OUT_SOURCE_PATH SOURCE_PATH + REPO KDE/qca + REF "v${VERSION}" + SHA512 de06173aaea32aac19a24510b5dbb4bb79681217eb1e4256de36db9f7158ad485fa450ffba5e13c12a0425866923b54f9b4d6164d0eaf659fdf40e458f5ee017 + PATCHES + 0001-fix-path-for-vcpkg.patch + 0002-fix-build-error.patch + 0003-Define-NOMINMAX-for-botan-plugin-with-MSVC.patch +) + +vcpkg_find_acquire_program(PKGCONFIG) + +if(VCPKG_LIBRARY_LINKAGE STREQUAL "dynamic") + set(QCA_PLUGIN_INSTALL_DIR_DEBUG ${CURRENT_PACKAGES_DIR}/debug/bin/Qca) + set(QCA_PLUGIN_INSTALL_DIR_RELEASE ${CURRENT_PACKAGES_DIR}/bin/Qca) +else() + set(QCA_PLUGIN_INSTALL_DIR_DEBUG ${CURRENT_PACKAGES_DIR}/debug/lib/Qca) + set(QCA_PLUGIN_INSTALL_DIR_RELEASE ${CURRENT_PACKAGES_DIR}/lib/Qca) +endif() + +# According to: +# https://www.openssl.org/docs/faq.html#USER16 +# it is up to developers or admins to maintain CAs. +# So we do it here: +message(STATUS "Importing certstore") +file(REMOVE "${SOURCE_PATH}/certs/rootcerts.pem") +# Using file(DOWNLOAD) to use https +file(DOWNLOAD https://raw.githubusercontent.com/mozilla/gecko-dev/master/security/nss/lib/ckfw/builtins/certdata.txt + "${CURRENT_BUILDTREES_DIR}/cert/certdata.txt" + TLS_VERIFY ON +) +vcpkg_execute_required_process( + COMMAND "${PERL}" "${CMAKE_CURRENT_LIST_DIR}/mk-ca-bundle.pl" -n "${SOURCE_PATH}/certs/rootcerts.pem" + WORKING_DIRECTORY "${CURRENT_BUILDTREES_DIR}/cert" + LOGNAME ca-bundle +) +message(STATUS "Importing certstore done") + +set(PLUGINS gnupg logger wincrypto) +if("botan" IN_LIST FEATURES) + list(APPEND PLUGINS botan) +endif() +if ("ossl" IN_LIST FEATURES) + list(APPEND PLUGINS ossl) +endif() +if ("softstore" IN_LIST FEATURES) + list(APPEND PLUGINS softstore) +endif() + +# Configure and build +vcpkg_cmake_configure( + SOURCE_PATH "${SOURCE_PATH}" + OPTIONS + -DUSE_RELATIVE_PATHS=ON + "-DBUILD_PLUGINS=${PLUGINS}" + -DBUILD_TESTS=OFF + -DBUILD_TOOLS=OFF + -DBUILD_WITH_QT6=ON + -DQCA_SUFFIX=OFF + -DQCA_FEATURE_INSTALL_DIR=${CURRENT_PACKAGES_DIR}/share/qca/mkspecs/features + -DOSX_FRAMEWORK=OFF + "-DPKG_CONFIG_EXECUTABLE=${PKGCONFIG}" + OPTIONS_DEBUG + -DQCA_PLUGINS_INSTALL_DIR=${QCA_PLUGIN_INSTALL_DIR_DEBUG} + OPTIONS_RELEASE + -DQCA_PLUGINS_INSTALL_DIR=${QCA_PLUGIN_INSTALL_DIR_RELEASE} +) + +vcpkg_cmake_install() + +vcpkg_cmake_config_fixup(CONFIG_PATH share/qca/cmake) +file(READ "${CURRENT_PACKAGES_DIR}/share/${PORT}/QcaConfig.cmake" QCA_CONFIG_FILE) +string(REGEX REPLACE "PACKAGE_PREFIX_DIR \"(.*)\" ABSOLUTE" + [[PACKAGE_PREFIX_DIR "${CMAKE_CURRENT_LIST_DIR}/../../" ABSOLUTE]] + QCA_CONFIG_FILE "${QCA_CONFIG_FILE}" +) +file(WRITE "${CURRENT_PACKAGES_DIR}/share/${PORT}/QcaConfig.cmake" "${QCA_CONFIG_FILE}") + +# Remove unneeded dirs +file(REMOVE_RECURSE + "${CURRENT_BUILDTREES_DIR}/share/man" + "${CURRENT_PACKAGES_DIR}/share/man" + "${CURRENT_PACKAGES_DIR}/debug/include" + "${CURRENT_PACKAGES_DIR}/debug/share" +) + +vcpkg_fixup_pkgconfig() + +# Handle copyright +vcpkg_install_copyright(FILE_LIST "${SOURCE_PATH}/COPYING") diff --git a/vcpkg/ports/qca/vcpkg.json b/vcpkg/ports/qca/vcpkg.json new file mode 100644 index 000000000000..f292cfea23a3 --- /dev/null +++ b/vcpkg/ports/qca/vcpkg.json @@ -0,0 +1,45 @@ +{ + "name": "qca", + "version": "2.3.7", + "port-version": 2, + "description": "Qt Cryptographic Architecture (QCA).", + "homepage": "https://userbase.kde.org/QCA", + "dependencies": [ + { + "name": "qt5compat", + "default-features": false + }, + { + "name": "qtbase", + "default-features": false + }, + { + "name": "vcpkg-cmake", + "host": true + }, + { + "name": "vcpkg-cmake-config", + "host": true + } + ], + "default-features": [ + "botan" + ], + "features": { + "botan": { + "description": "Build with botan", + "dependencies": [ + "botan" + ] + }, + "ossl": { + "description": "Build with openssl", + "dependencies": [ + "openssl" + ] + }, + "softstore": { + "description": "Build with softstore" + } + } +} diff --git a/vcpkg/vcpkg.json b/vcpkg/vcpkg.json index c652f75faa90..4231a10b16e4 100644 --- a/vcpkg/vcpkg.json +++ b/vcpkg/vcpkg.json @@ -8,7 +8,7 @@ "registries": [ { "kind": "git", - "baseline": "a4bdac4fe806307844ddc5c663620ea919ffdf4c", + "baseline": "e494c9c25f3b0139c6274ece17f5c15374f9241f", "repository": "https://github.com/open-vcpkg/python-registry", "packages": [ "python3", @@ -44,7 +44,8 @@ "name": "gdal", "default-features": false, "features": [ - "poppler" + "poppler", + "tools" ] }, "geos", @@ -73,8 +74,10 @@ ] }, "qtbase", + "qtdeclarative", "qtkeychain-qt6", "qtlocation", + "qtquickcontrols2", "qtsvg", "qttools", "zlib" @@ -105,7 +108,15 @@ "py-owslib", "py-pip", "py-psycopg2", - "py-pyqt6", + { + "name": "py-pyqt6", + "features": [ + "qt3d", + "qt5compat", + "qtcharts", + "qtdeclarative" + ] + }, "py-pytz", "py-pyyaml", "py-qscintilla", @@ -128,13 +139,6 @@ "opencl" ] }, - "quick": { - "description": "Build the QGIS quick components for mobile interfaces", - "dependencies": [ - "qtdeclarative", - "qtquickcontrols2" - ] - }, "server": { "description": "Determines whether QGIS server should be built", "dependencies": [