From 7bf4ca76472386be314a7142f59aeaca4e09e067 Mon Sep 17 00:00:00 2001 From: HPDell Date: Mon, 17 Aug 2026 11:14:57 +0800 Subject: [PATCH 01/42] add: workflow configure by ai --- .github/workflows/ci.yml | 249 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 249 insertions(+) create mode 100644 .github/workflows/ci.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..d736891 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,249 @@ +# GitHub Actions CI for GWmodelS (QGIS 3.28 LTR secondary development) +# +# Targets: +# - Windows (x64) +# - macOS (Intel, x86_64) +# - macOS (Apple Silicon, arm64) +# +# Pipeline: +# 1. Install the libgwmodel kernel (https://github.com/GWmodel-Lab/libgwmodel.git) +# 2. Create a conda environment: qgis==3.28, armadillo, catch2, openblas, nomkl +# 3. Patch the missing qgswebframe.h header from the QGIS source tree +# 4. Configure + build GWmodelS +# 5. Package with CPack (packaging scripts are provided on pack/* branches) +# - macOS: sign the .app with a self-signed certificate before packaging +# +# NOTE: draft only, not yet pushed/validated. + +name: CI + +on: + push: + branches: [master, 'feat/**', 'enhance/**'] + tags: ['v*'] + pull_request: + workflow_dispatch: + inputs: + pack_branch: + description: 'CPack packaging scripts branch (pack/*)' + required: false + default: 'pack/20260511' + +env: + CONDA_ENV: gwmodels + QGIS_VER: '3.28' + # CPack packaging scripts live on a branch starting with "pack/" + PACK_BRANCH: ${{ github.event.inputs.pack_branch || 'pack/20260511' }} + # qgswebframe.h is fetched from the QGIS 3.28 LTR source tree + QGIS_HEADER_REF: final-3_28_16 + +jobs: + # --------------------------------------------------------------------------- + # Windows + # --------------------------------------------------------------------------- + build-windows: + name: Windows (x64) + runs-on: windows-latest + + steps: + - name: Checkout source + uses: actions/checkout@v4 + + - name: Set up Miniconda + uses: conda-incubator/setup-miniconda@v3 + with: + auto-update-conda: true + python-version: '3.10' + channels: conda-forge, defaults + channel-priority: flexible + activate-environment: ${{ env.CONDA_ENV }} + + # qgis/armadillo/catch2/openblas come from conda-forge; nomkl (no MKL) + # is only available in the 'defaults' channel. + - name: Install conda dependencies + shell: bash -l {0} + run: | + conda install -n "$CONDA_ENV" -y \ + -c conda-forge qgis==$QGIS_VER armadillo catch2 openblas \ + -c defaults nomkl + conda list -n "$CONDA_ENV" + + # libgwmodel is the spatial-statistics kernel required by GWmodelS. + # Build first (the conda deps above are already in place). + - name: Install libgwmodel kernel + shell: bash -l {0} + run: | + git clone --depth 1 https://github.com/GWmodel-Lab/libgwmodel.git + cmake -S libgwmodel -B libgwmodel/build \ + -G "Visual Studio 17 2022" -A x64 \ + -DCMAKE_INSTALL_PREFIX="$CONDA_PREFIX/Library" \ + -DCMAKE_PREFIX_PATH="$CONDA_PREFIX/Library" \ + -DBUILD_TESTING=OFF + cmake --build libgwmodel/build --config Release --parallel + cmake --install libgwmodel/build + + # The conda QGIS package is missing qgswebframe.h; download it from the + # QGIS 3.28 LTR source tree and drop it into the include directory. + - name: Patch missing qgswebframe.h + shell: bash -l {0} + run: | + QGIS_INC="$CONDA_PREFIX/Library/include/qgis" + curl -fsSL -o "$QGIS_INC/qgswebframe.h" \ + "https://raw.githubusercontent.com/qgis/QGIS/$QGIS_HEADER_REF/src/gui/qgswebframe.h" + + - name: Enable MSVC toolchain + uses: ilammy/msvc-dev-cmd@v1 + with: + arch: x64 + + - name: Configure (cmake) + shell: pwsh + run: | + $env:LIB_DIR = "$env:CONDA_PREFIX\Library" + $env:INCLUDE = "$env:CONDA_PREFIX\Library\include;$env:INCLUDE" + cmake -S . -B build -G "Visual Studio 17 2022" -A x64 ` + -DCMAKE_PREFIX_PATH="$env:CONDA_PREFIX\Library" ` + -DCMAKE_BUILD_TYPE=Release ` + -DBLAS_LIBRARIES="$env:CONDA_PREFIX\Library\lib\libopenblas.lib" ` + -DLAPACK_LIBRARIES="$env:CONDA_PREFIX\Library\lib\libopenblas.lib" + + - name: Build GWmodelS + shell: pwsh + run: | + cmake --build build --config Release --target GWmodelS --parallel + + # Pull the CPack configuration from the pack/* branch, reconfigure to + # regenerate CPackConfig.cmake, then produce the installer/package. + - name: Package with CPack + shell: pwsh + run: | + git fetch origin "$env:PACK_BRANCH" + git checkout "origin/$env:PACK_BRANCH" -- CMakeLists.txt src/CMakeLists.txt cmake + $env:LIB_DIR = "$env:CONDA_PREFIX\Library" + $env:INCLUDE = "$env:CONDA_PREFIX\Library\include;$env:INCLUDE" + cmake -S . -B build -G "Visual Studio 17 2022" -A x64 ` + -DCMAKE_PREFIX_PATH="$env:CONDA_PREFIX\Library" ` + -DCMAKE_BUILD_TYPE=Release ` + -DBLAS_LIBRARIES="$env:CONDA_PREFIX\Library\lib\libopenblas.lib" ` + -DLAPACK_LIBRARIES="$env:CONDA_PREFIX\Library\lib\libopenblas.lib" + cmake --build build --config Release --target GWmodelS --parallel + cpack --config build/CPackConfig.cmake -G ZIP + + - name: Upload package + uses: actions/upload-artifact@v4 + with: + name: GWmodelS-Windows-x64 + path: build/*.zip + if-no-files-found: error + + # --------------------------------------------------------------------------- + # macOS (Intel + Apple Silicon) + # --------------------------------------------------------------------------- + build-macos: + name: macOS (${{ matrix.arch }}) + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + include: + - os: macos-13 # Intel + arch: x86_64 + - os: macos-14 # Apple Silicon + arch: arm64 + + steps: + - name: Checkout source + uses: actions/checkout@v4 + + - name: Set up Miniconda + uses: conda-incubator/setup-miniconda@v3 + with: + auto-update-conda: true + python-version: '3.10' + channels: conda-forge, defaults + channel-priority: flexible + activate-environment: ${{ env.CONDA_ENV }} + + - name: Install conda dependencies + shell: bash -l {0} + run: | + conda install -n "$CONDA_ENV" -y \ + -c conda-forge qgis==$QGIS_VER armadillo catch2 openblas llvm-openmp \ + -c defaults nomkl + conda list -n "$CONDA_ENV" + + - name: Install libgwmodel kernel + shell: bash -l {0} + run: | + git clone --depth 1 https://github.com/GWmodel-Lab/libgwmodel.git + cmake -S libgwmodel -B libgwmodel/build \ + -DCMAKE_BUILD_TYPE=Release \ + -DCMAKE_INSTALL_PREFIX="$CONDA_PREFIX" \ + -DCMAKE_PREFIX_PATH="$CONDA_PREFIX" \ + -DBUILD_TESTING=OFF + cmake --build libgwmodel/build --config Release --parallel + cmake --install libgwmodel/build + + # qgswebframe.h is missing from the conda QGIS package; fetch it from the + # QGIS 3.28 LTR source tree into the conda include directory. + - name: Patch missing qgswebframe.h + shell: bash -l {0} + run: | + QGIS_INC="$CONDA_PREFIX/include/qgis" + curl -fsSL -o "$QGIS_INC/qgswebframe.h" \ + "https://raw.githubusercontent.com/qgis/QGIS/$QGIS_HEADER_REF/src/gui/qgswebframe.h" + + - name: Configure (cmake) + shell: bash -l {0} + run: | + cmake -S . -B build \ + -DCMAKE_BUILD_TYPE=Release \ + -DCMAKE_PREFIX_PATH="$CONDA_PREFIX" \ + -DQGIS_PREFIX_PATH="$CONDA_PREFIX" + + - name: Build GWmodelS + shell: bash -l {0} + run: | + cmake --build build --config Release --target GWmodelS --parallel + + # Create a self-signed code-signing identity and sign the .app bundle so + # CPack (DMG) produces a package that macOS accepts. + - name: Sign GWmodelS.app (self-signed certificate) + shell: bash + run: | + KEYCHAIN="$RUNNER_TEMP/build.keychain" + security create-keychain -p build "$KEYCHAIN" + security default-keychain -s "$KEYCHAIN" + security unlock-keychain -p build "$KEYCHAIN" + security set-keychain-settings -t 3600 -u "$KEYCHAIN" + + openssl req -x509 -newkey rsa:2048 -keyout /tmp/dev.key -out /tmp/dev.crt \ + -days 365 -nodes -subj "/CN=GWmodelS CI" + openssl pkcs12 -export -out /tmp/dev.p12 \ + -inkey /tmp/dev.key -in /tmp/dev.crt -passout pass:build + security import /tmp/dev.p12 -k "$KEYCHAIN" -P build -T /usr/bin/codesign + + IDENTITY=$(security find-identity -v -p codesigning "$KEYCHAIN" \ + | awk -F'[()]' '/GWmodelS/{print $2; exit}') + codesign --force --deep --sign "$IDENTITY" --keychain "$KEYCHAIN" build/GWmodelS.app + + # Pull the CPack configuration from the pack/* branch, reconfigure to + # regenerate CPackConfig.cmake, then produce the DMG. + - name: Package with CPack + shell: bash -l {0} + run: | + git fetch origin "$PACK_BRANCH" + git checkout "origin/$PACK_BRANCH" -- CMakeLists.txt src/CMakeLists.txt cmake macOS + cmake -S . -B build \ + -DCMAKE_BUILD_TYPE=Release \ + -DCMAKE_PREFIX_PATH="$CONDA_PREFIX" \ + -DQGIS_PREFIX_PATH="$CONDA_PREFIX" + cmake --build build --config Release --target GWmodelS --parallel + cpack --config build/CPackConfig.cmake -G DragNDrop + + - name: Upload package + uses: actions/upload-artifact@v4 + with: + name: GWmodelS-macOS-${{ matrix.arch }} + path: build/*.dmg + if-no-files-found: error From 4145adc44607e6f204581d9d647fc22ea07ee76e Mon Sep 17 00:00:00 2001 From: HPDell Date: Mon, 17 Aug 2026 11:19:22 +0800 Subject: [PATCH 02/42] add: cpack configure --- .github/workflows/ci.yml | 36 +++++++++++++------------- src/CMakeLists.txt | 55 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 73 insertions(+), 18 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d736891..ce663cc 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -10,7 +10,7 @@ # 2. Create a conda environment: qgis==3.28, armadillo, catch2, openblas, nomkl # 3. Patch the missing qgswebframe.h header from the QGIS source tree # 4. Configure + build GWmodelS -# 5. Package with CPack (packaging scripts are provided on pack/* branches) +# 5. Package with CPack (INSTALL/CPack rules live in src/CMakeLists.txt) # - macOS: sign the .app with a self-signed certificate before packaging # # NOTE: draft only, not yet pushed/validated. @@ -23,17 +23,10 @@ on: tags: ['v*'] pull_request: workflow_dispatch: - inputs: - pack_branch: - description: 'CPack packaging scripts branch (pack/*)' - required: false - default: 'pack/20260511' env: CONDA_ENV: gwmodels QGIS_VER: '3.28' - # CPack packaging scripts live on a branch starting with "pack/" - PACK_BRANCH: ${{ github.event.inputs.pack_branch || 'pack/20260511' }} # qgswebframe.h is fetched from the QGIS 3.28 LTR source tree QGIS_HEADER_REF: final-3_28_16 @@ -104,6 +97,8 @@ jobs: cmake -S . -B build -G "Visual Studio 17 2022" -A x64 ` -DCMAKE_PREFIX_PATH="$env:CONDA_PREFIX\Library" ` -DCMAKE_BUILD_TYPE=Release ` + -DCMAKE_INSTALL_PREFIX="$env:CONDA_PREFIX\Library" ` + -DDATADIR="share" ` -DBLAS_LIBRARIES="$env:CONDA_PREFIX\Library\lib\libopenblas.lib" ` -DLAPACK_LIBRARIES="$env:CONDA_PREFIX\Library\lib\libopenblas.lib" @@ -112,21 +107,21 @@ jobs: run: | cmake --build build --config Release --target GWmodelS --parallel - # Pull the CPack configuration from the pack/* branch, reconfigure to - # regenerate CPackConfig.cmake, then produce the installer/package. + # CPack configuration is provided by the INSTALL/CPack section in + # src/CMakeLists.txt; reconfigure is a no-op and regenerates the + # CPackConfig.cmake before producing the ZIP package. - name: Package with CPack shell: pwsh run: | - git fetch origin "$env:PACK_BRANCH" - git checkout "origin/$env:PACK_BRANCH" -- CMakeLists.txt src/CMakeLists.txt cmake $env:LIB_DIR = "$env:CONDA_PREFIX\Library" $env:INCLUDE = "$env:CONDA_PREFIX\Library\include;$env:INCLUDE" cmake -S . -B build -G "Visual Studio 17 2022" -A x64 ` -DCMAKE_PREFIX_PATH="$env:CONDA_PREFIX\Library" ` -DCMAKE_BUILD_TYPE=Release ` + -DCMAKE_INSTALL_PREFIX="$env:CONDA_PREFIX\Library" ` + -DDATADIR="share" ` -DBLAS_LIBRARIES="$env:CONDA_PREFIX\Library\lib\libopenblas.lib" ` -DLAPACK_LIBRARIES="$env:CONDA_PREFIX\Library\lib\libopenblas.lib" - cmake --build build --config Release --target GWmodelS --parallel cpack --config build/CPackConfig.cmake -G ZIP - name: Upload package @@ -208,6 +203,13 @@ jobs: # Create a self-signed code-signing identity and sign the .app bundle so # CPack (DMG) produces a package that macOS accepts. + # + # NOTE: the INSTALL rule for APPLE in src/CMakeLists.txt runs fixup_bundle + # during `cpack`/`cmake --install`, which rewrites dylib install names and + # invalidates this signature. A robust approach is to re-sign the .app + # inside the CPack staging tree (build/_CPack_Packages/*/DragNDrop/) after + # cpack and before DMG creation; for this draft the sign-before-pack keeps + # the flow simple and easy to iterate on. - name: Sign GWmodelS.app (self-signed certificate) shell: bash run: | @@ -227,18 +229,16 @@ jobs: | awk -F'[()]' '/GWmodelS/{print $2; exit}') codesign --force --deep --sign "$IDENTITY" --keychain "$KEYCHAIN" build/GWmodelS.app - # Pull the CPack configuration from the pack/* branch, reconfigure to - # regenerate CPackConfig.cmake, then produce the DMG. + # CPack configuration is provided by the INSTALL/CPack section in + # src/CMakeLists.txt; reconfigure is a no-op and regenerates the + # CPackConfig.cmake before producing the DMG. - name: Package with CPack shell: bash -l {0} run: | - git fetch origin "$PACK_BRANCH" - git checkout "origin/$PACK_BRANCH" -- CMakeLists.txt src/CMakeLists.txt cmake macOS cmake -S . -B build \ -DCMAKE_BUILD_TYPE=Release \ -DCMAKE_PREFIX_PATH="$CONDA_PREFIX" \ -DQGIS_PREFIX_PATH="$CONDA_PREFIX" - cmake --build build --config Release --target GWmodelS --parallel cpack --config build/CPackConfig.cmake -G DragNDrop - name: Upload package diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index c3439a3..5f2fb45 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -285,3 +285,58 @@ target_link_libraries(GWmodelS ${GWMODELCUDA_LIBRARIES} ) endif(ENABLE_CUDA) + +# INSTALL + +if (WIN32) +get_filename_component(qgis_dir ${QGIS_INCLUDE_DIR} DIRECTORY) +install(TARGETS GWmodelS + COMPONENT Runtime + RUNTIME_DEPENDENCIES DIRECTORIES "${qgis_dir}/bin" POST_EXCLUDE_REGEXES ".*system32.*" POST_INCLUDE_REGEXES "libomp140.x86_64.dll" + DESTINATION . +) +get_target_property(uic_location Qt5::uic IMPORTED_LOCATION) +get_filename_component( _dir ${uic_location} DIRECTORY) +set(deployqt "${_dir}/windeployqt.exe") +install(CODE "set(deployqt \"${deployqt}\")" COMPONENT Runtime) +install(CODE [===[ +execute_process(COMMAND "${deployqt}" "${CMAKE_INSTALL_PREFIX}/GWmodelS.exe") +]===] COMPONENT Runtime) +install(DIRECTORY "${qgis_dir}/resources" DESTINATION .) +install(DIRECTORY "${qgis_dir}/share/proj" DESTINATION "./${DATADIR}") +elseif(APPLE) +install(TARGETS GWmodelS + # RUNTIME_DEPENDENCY_SET _dep_mac + DESTINATION . + BUNDLE DESTINATION . + RESOURCE DESTINATION "./${CMAKE_PROJECT_NAME}.app/Contents/Resources" +) +get_filename_component(qgis_dir ${QGIS_UI_INCLUDE_DIR} DIRECTORY) +get_filename_component(qgis_dir ${qgis_dir} DIRECTORY) +install(DIRECTORY "${qgis_dir}/share/proj" DESTINATION "./${CMAKE_PROJECT_NAME}.app/Contents/Resources") +install(DIRECTORY "${qgis_dir}/share/qgis/resources" DESTINATION "./${CMAKE_PROJECT_NAME}.app/Contents/Resources") +install(CODE "set(APPS ${CMAKE_INSTALL_PREFIX}/${PROJECT_NAME}.app)" COMPONENT Runtime) +install(CODE "set(DIRS ${QGIS_PREFIX_PATH}/lib)" COMPONENT Runtime) +install(CODE [===[ + include(BundleUtilities) + fixup_bundle("${APPS}" "" "") +]===] COMPONENT Runtime) +# install(RUNTIME_DEPENDENCY_SET _dep_mac DESTINATION "./${CMAKE_PROJECT_NAME}.app/Contents/Frameworks" POST_EXCLUDE_REGEXES ".*homebrew.*") +# get_target_property(uic_location Qt5::uic IMPORTED_LOCATION) +# get_filename_component( _dir ${uic_location} DIRECTORY) +# set(deployqt "${_dir}/macdeployqt") +# install(CODE "set(deployqt \"${deployqt}\")" COMPONENT Runtime) +# install(CODE [===[ +# execute_process(COMMAND "${deployqt}" "${CMAKE_INSTALL_PREFIX}/GWmodelS.app") +# ]===] COMPONENT Runtime) +endif() + +# CPack +set(CPACK_PACKAGE_NAME ${CMAKE_PROJECT_NAME}) +set(CPACK_PACKAGE_VENDOR "GWmodel Lab") +set(CPACK_PACKAGE_VERSION ${CMAKE_PROJECT_VERSION}) +set(CPACK_NSIS_MUI_ICON "${CMAKE_SOURCE_DIR}/icons/GWmodelS.ico") +set(CPACK_PACKAGE_INSTALL_DIRECTORY ${CMAKE_PROJECT_NAME}) +set(CPACK_PACKAGE_EXECUTABLES "GWmodelS;GWmodelS") +set(CPACK_NSIS_EXECUTABLES_DIRECTORY ".") +include(CPack) From dfcfe337678882907e3129460a396dec5371bb67 Mon Sep 17 00:00:00 2001 From: HPDell Date: Tue, 18 Aug 2026 11:34:56 +0800 Subject: [PATCH 03/42] edit: nomkl as a package --- .github/workflows/ci.yml | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ce663cc..9f93773 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -57,8 +57,7 @@ jobs: shell: bash -l {0} run: | conda install -n "$CONDA_ENV" -y \ - -c conda-forge qgis==$QGIS_VER armadillo catch2 openblas \ - -c defaults nomkl + -c conda-forge qgis==$QGIS_VER armadillo catch2 openblas nomkl conda list -n "$CONDA_ENV" # libgwmodel is the spatial-statistics kernel required by GWmodelS. @@ -163,8 +162,7 @@ jobs: shell: bash -l {0} run: | conda install -n "$CONDA_ENV" -y \ - -c conda-forge qgis==$QGIS_VER armadillo catch2 openblas llvm-openmp \ - -c defaults nomkl + -c conda-forge qgis==$QGIS_VER armadillo catch2 openblas llvm-openmp nomkl conda list -n "$CONDA_ENV" - name: Install libgwmodel kernel From e89c993bf61259803548de727654d90aafbd0e98 Mon Sep 17 00:00:00 2001 From: HPDell Date: Tue, 18 Aug 2026 12:33:01 +0800 Subject: [PATCH 04/42] edit: qgis version match --- .github/workflows/ci.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9f93773..2a303f2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -7,7 +7,7 @@ # # Pipeline: # 1. Install the libgwmodel kernel (https://github.com/GWmodel-Lab/libgwmodel.git) -# 2. Create a conda environment: qgis==3.28, armadillo, catch2, openblas, nomkl +# 2. Create a conda environment: qgis=3.28, armadillo, catch2, openblas, nomkl # 3. Patch the missing qgswebframe.h header from the QGIS source tree # 4. Configure + build GWmodelS # 5. Package with CPack (INSTALL/CPack rules live in src/CMakeLists.txt) @@ -57,7 +57,7 @@ jobs: shell: bash -l {0} run: | conda install -n "$CONDA_ENV" -y \ - -c conda-forge qgis==$QGIS_VER armadillo catch2 openblas nomkl + -c conda-forge qgis=$QGIS_VER armadillo catch2 openblas nomkl conda list -n "$CONDA_ENV" # libgwmodel is the spatial-statistics kernel required by GWmodelS. @@ -162,7 +162,7 @@ jobs: shell: bash -l {0} run: | conda install -n "$CONDA_ENV" -y \ - -c conda-forge qgis==$QGIS_VER armadillo catch2 openblas llvm-openmp nomkl + -c conda-forge qgis=$QGIS_VER armadillo catch2 openblas llvm-openmp nomkl conda list -n "$CONDA_ENV" - name: Install libgwmodel kernel From e778450c987ce90fcc3e230412cf845a723562f2 Mon Sep 17 00:00:00 2001 From: HPDell Date: Tue, 18 Aug 2026 12:36:22 +0800 Subject: [PATCH 05/42] edit: install gsl via conda --- .github/workflows/ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2a303f2..05dace8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -57,7 +57,7 @@ jobs: shell: bash -l {0} run: | conda install -n "$CONDA_ENV" -y \ - -c conda-forge qgis=$QGIS_VER armadillo catch2 openblas nomkl + -c conda-forge qgis=$QGIS_VER armadillo catch2 openblas gsl nomkl conda list -n "$CONDA_ENV" # libgwmodel is the spatial-statistics kernel required by GWmodelS. @@ -162,7 +162,7 @@ jobs: shell: bash -l {0} run: | conda install -n "$CONDA_ENV" -y \ - -c conda-forge qgis=$QGIS_VER armadillo catch2 openblas llvm-openmp nomkl + -c conda-forge qgis=$QGIS_VER armadillo catch2 openblas gsl llvm-openmp nomkl conda list -n "$CONDA_ENV" - name: Install libgwmodel kernel From 1ab9de0d08a46c0f4b09d4ab05f69033f8c9ebd4 Mon Sep 17 00:00:00 2001 From: HPDell Date: Tue, 18 Aug 2026 13:10:04 +0800 Subject: [PATCH 06/42] edit: cmake problems --- .github/workflows/ci.yml | 72 ++++++++++++++++++++++++++++++++-------- 1 file changed, 58 insertions(+), 14 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 05dace8..fe8c403 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -51,14 +51,36 @@ jobs: channel-priority: flexible activate-environment: ${{ env.CONDA_ENV }} - # qgis/armadillo/catch2/openblas come from conda-forge; nomkl (no MKL) - # is only available in the 'defaults' channel. + # qgis/armadillo/catch2/openblas/gsl come from conda-forge; nomkl (no + # MKL) is only available in the 'defaults' channel. + # + # NOTE: the conda-forge gsl package ships no CMake config files, so + # libgwmodel's `find_package(GSL)` relies on CMake's built-in FindGSL, + # which only provides the GSL::gsl/GSL::gslcblas targets since CMake 3.27. + # Install a recent cmake from conda-forge to guarantee that. - name: Install conda dependencies shell: bash -l {0} run: | - conda install -n "$CONDA_ENV" -y \ - -c conda-forge qgis=$QGIS_VER armadillo catch2 openblas gsl nomkl - conda list -n "$CONDA_ENV" + conda install -n "$CONDA_ENV" -q -y \ + -c conda-forge qgis=$QGIS_VER armadillo catch2 openblas gsl cmake nomkl + conda list -n "$CONDA_ENV" -q + + # GitHub-hosted runners may have an old system cmake that cannot detect + # the installed VS instance; point CMake at the exact VS install found by + # vswhere (the CMAKE_GENERATOR_INSTANCE env var is honored by CMake). + - name: Locate Visual Studio instance + shell: pwsh + run: | + $vswhere = "${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\vswhere.exe" + $vs = & $vswhere -latest -products * ` + -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 ` + -property installationPath + if ($vs) { + "CMAKE_GENERATOR_INSTANCE=$vs" | Out-File -FilePath $env:GITHUB_ENV -Append + Write-Host "Found VS at: $vs" + } else { + Write-Error "No Visual Studio with C++ tools found by vswhere" + } # libgwmodel is the spatial-statistics kernel required by GWmodelS. # Build first (the conda deps above are already in place). @@ -91,6 +113,7 @@ jobs: - name: Configure (cmake) shell: pwsh run: | + $env:PATH = "$env:CONDA_PREFIX\Library\bin;$env:PATH" $env:LIB_DIR = "$env:CONDA_PREFIX\Library" $env:INCLUDE = "$env:CONDA_PREFIX\Library\include;$env:INCLUDE" cmake -S . -B build -G "Visual Studio 17 2022" -A x64 ` @@ -104,6 +127,7 @@ jobs: - name: Build GWmodelS shell: pwsh run: | + $env:PATH = "$env:CONDA_PREFIX\Library\bin;$env:PATH" cmake --build build --config Release --target GWmodelS --parallel # CPack configuration is provided by the INSTALL/CPack section in @@ -112,6 +136,7 @@ jobs: - name: Package with CPack shell: pwsh run: | + $env:PATH = "$env:CONDA_PREFIX\Library\bin;$env:PATH" $env:LIB_DIR = "$env:CONDA_PREFIX\Library" $env:INCLUDE = "$env:CONDA_PREFIX\Library\include;$env:INCLUDE" cmake -S . -B build -G "Visual Studio 17 2022" -A x64 ` @@ -158,12 +183,25 @@ jobs: channel-priority: flexible activate-environment: ${{ env.CONDA_ENV }} - - name: Install conda dependencies + # QGIS itself is installed via conda-forge; all other (non-QGIS) build + # dependencies are provided by Homebrew instead, to keep the QGIS + # toolchain self-contained inside the conda environment. + - name: Install conda dependencies (QGIS) shell: bash -l {0} run: | - conda install -n "$CONDA_ENV" -y \ - -c conda-forge qgis=$QGIS_VER armadillo catch2 openblas gsl llvm-openmp nomkl - conda list -n "$CONDA_ENV" + conda install -n "$CONDA_ENV" -q -y \ + -c conda-forge qgis=$QGIS_VER nomkl + conda list -n "$CONDA_ENV" -q + + # Non-QGIS build deps via Homebrew. Note: the brew formula for + # llvm-openmp is called 'libomp'. A recent cmake is required because the + # brew gsl formula ships no CMake config files, so libgwmodel's + # `find_package(GSL)` relies on CMake's built-in FindGSL (>= 3.27, which + # provides the GSL::gsl/GSL::gslcblas targets). + - name: Install brew dependencies + shell: bash + run: | + brew install --quiet armadillo openblas gsl catch2 libomp cmake - name: Install libgwmodel kernel shell: bash -l {0} @@ -172,7 +210,9 @@ jobs: cmake -S libgwmodel -B libgwmodel/build \ -DCMAKE_BUILD_TYPE=Release \ -DCMAKE_INSTALL_PREFIX="$CONDA_PREFIX" \ - -DCMAKE_PREFIX_PATH="$CONDA_PREFIX" \ + -DCMAKE_PREFIX_PATH="$(brew --prefix);$CONDA_PREFIX" \ + -DBLAS_LIBRARIES="$(brew --prefix)/lib/libopenblas.dylib" \ + -DLAPACK_LIBRARIES="$(brew --prefix)/lib/libopenblas.dylib" \ -DBUILD_TESTING=OFF cmake --build libgwmodel/build --config Release --parallel cmake --install libgwmodel/build @@ -191,8 +231,10 @@ jobs: run: | cmake -S . -B build \ -DCMAKE_BUILD_TYPE=Release \ - -DCMAKE_PREFIX_PATH="$CONDA_PREFIX" \ - -DQGIS_PREFIX_PATH="$CONDA_PREFIX" + -DCMAKE_PREFIX_PATH="$(brew --prefix);$CONDA_PREFIX" \ + -DQGIS_PREFIX_PATH="$CONDA_PREFIX" \ + -DBLAS_LIBRARIES="$(brew --prefix)/lib/libopenblas.dylib" \ + -DLAPACK_LIBRARIES="$(brew --prefix)/lib/libopenblas.dylib" - name: Build GWmodelS shell: bash -l {0} @@ -235,8 +277,10 @@ jobs: run: | cmake -S . -B build \ -DCMAKE_BUILD_TYPE=Release \ - -DCMAKE_PREFIX_PATH="$CONDA_PREFIX" \ - -DQGIS_PREFIX_PATH="$CONDA_PREFIX" + -DCMAKE_PREFIX_PATH="$(brew --prefix);$CONDA_PREFIX" \ + -DQGIS_PREFIX_PATH="$CONDA_PREFIX" \ + -DBLAS_LIBRARIES="$(brew --prefix)/lib/libopenblas.dylib" \ + -DLAPACK_LIBRARIES="$(brew --prefix)/lib/libopenblas.dylib" cpack --config build/CPackConfig.cmake -G DragNDrop - name: Upload package From 7dff84a59d9c4931ad5bc80904d478c3e9390574 Mon Sep 17 00:00:00 2001 From: HPDell Date: Tue, 18 Aug 2026 13:25:27 +0800 Subject: [PATCH 07/42] edit: activate conda env in build steps --- .github/workflows/ci.yml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index fe8c403..ba7a594 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -87,6 +87,7 @@ jobs: - name: Install libgwmodel kernel shell: bash -l {0} run: | + conda activate "$CONDA_ENV" git clone --depth 1 https://github.com/GWmodel-Lab/libgwmodel.git cmake -S libgwmodel -B libgwmodel/build \ -G "Visual Studio 17 2022" -A x64 \ @@ -113,6 +114,7 @@ jobs: - name: Configure (cmake) shell: pwsh run: | + conda activate $env:CONDA_ENV $env:PATH = "$env:CONDA_PREFIX\Library\bin;$env:PATH" $env:LIB_DIR = "$env:CONDA_PREFIX\Library" $env:INCLUDE = "$env:CONDA_PREFIX\Library\include;$env:INCLUDE" @@ -127,6 +129,7 @@ jobs: - name: Build GWmodelS shell: pwsh run: | + conda activate $env:CONDA_ENV $env:PATH = "$env:CONDA_PREFIX\Library\bin;$env:PATH" cmake --build build --config Release --target GWmodelS --parallel @@ -136,6 +139,7 @@ jobs: - name: Package with CPack shell: pwsh run: | + conda activate $env:CONDA_ENV $env:PATH = "$env:CONDA_PREFIX\Library\bin;$env:PATH" $env:LIB_DIR = "$env:CONDA_PREFIX\Library" $env:INCLUDE = "$env:CONDA_PREFIX\Library\include;$env:INCLUDE" @@ -206,6 +210,7 @@ jobs: - name: Install libgwmodel kernel shell: bash -l {0} run: | + conda activate "$CONDA_ENV" git clone --depth 1 https://github.com/GWmodel-Lab/libgwmodel.git cmake -S libgwmodel -B libgwmodel/build \ -DCMAKE_BUILD_TYPE=Release \ @@ -229,6 +234,7 @@ jobs: - name: Configure (cmake) shell: bash -l {0} run: | + conda activate "$CONDA_ENV" cmake -S . -B build \ -DCMAKE_BUILD_TYPE=Release \ -DCMAKE_PREFIX_PATH="$(brew --prefix);$CONDA_PREFIX" \ @@ -239,6 +245,7 @@ jobs: - name: Build GWmodelS shell: bash -l {0} run: | + conda activate "$CONDA_ENV" cmake --build build --config Release --target GWmodelS --parallel # Create a self-signed code-signing identity and sign the .app bundle so @@ -275,6 +282,7 @@ jobs: - name: Package with CPack shell: bash -l {0} run: | + conda activate "$CONDA_ENV" cmake -S . -B build \ -DCMAKE_BUILD_TYPE=Release \ -DCMAKE_PREFIX_PATH="$(brew --prefix);$CONDA_PREFIX" \ From f672604cca1fb5ef4c51a4435ea38ca52f913e8e Mon Sep 17 00:00:00 2001 From: HPDell Date: Tue, 18 Aug 2026 13:32:39 +0800 Subject: [PATCH 08/42] edit: install gsl via conda and pass GSL_ROOT_DIR --- .github/workflows/ci.yml | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ba7a594..ac64774 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -190,22 +190,25 @@ jobs: # QGIS itself is installed via conda-forge; all other (non-QGIS) build # dependencies are provided by Homebrew instead, to keep the QGIS # toolchain self-contained inside the conda environment. + # + # gsl is still installed via conda (its location is passed explicitly to + # CMake via GSL_ROOT_DIR, see the configure steps below). - name: Install conda dependencies (QGIS) shell: bash -l {0} run: | conda install -n "$CONDA_ENV" -q -y \ - -c conda-forge qgis=$QGIS_VER nomkl + -c conda-forge qgis=$QGIS_VER gsl nomkl conda list -n "$CONDA_ENV" -q # Non-QGIS build deps via Homebrew. Note: the brew formula for # llvm-openmp is called 'libomp'. A recent cmake is required because the - # brew gsl formula ships no CMake config files, so libgwmodel's + # conda-forge gsl package ships no CMake config files, so libgwmodel's # `find_package(GSL)` relies on CMake's built-in FindGSL (>= 3.27, which # provides the GSL::gsl/GSL::gslcblas targets). - name: Install brew dependencies shell: bash run: | - brew install --quiet armadillo openblas gsl catch2 libomp cmake + brew install --quiet armadillo openblas catch2 libomp cmake - name: Install libgwmodel kernel shell: bash -l {0} @@ -216,6 +219,7 @@ jobs: -DCMAKE_BUILD_TYPE=Release \ -DCMAKE_INSTALL_PREFIX="$CONDA_PREFIX" \ -DCMAKE_PREFIX_PATH="$(brew --prefix);$CONDA_PREFIX" \ + -DGSL_ROOT_DIR="$CONDA_PREFIX" \ -DBLAS_LIBRARIES="$(brew --prefix)/lib/libopenblas.dylib" \ -DLAPACK_LIBRARIES="$(brew --prefix)/lib/libopenblas.dylib" \ -DBUILD_TESTING=OFF @@ -239,6 +243,7 @@ jobs: -DCMAKE_BUILD_TYPE=Release \ -DCMAKE_PREFIX_PATH="$(brew --prefix);$CONDA_PREFIX" \ -DQGIS_PREFIX_PATH="$CONDA_PREFIX" \ + -DGSL_ROOT_DIR="$CONDA_PREFIX" \ -DBLAS_LIBRARIES="$(brew --prefix)/lib/libopenblas.dylib" \ -DLAPACK_LIBRARIES="$(brew --prefix)/lib/libopenblas.dylib" @@ -287,6 +292,7 @@ jobs: -DCMAKE_BUILD_TYPE=Release \ -DCMAKE_PREFIX_PATH="$(brew --prefix);$CONDA_PREFIX" \ -DQGIS_PREFIX_PATH="$CONDA_PREFIX" \ + -DGSL_ROOT_DIR="$CONDA_PREFIX" \ -DBLAS_LIBRARIES="$(brew --prefix)/lib/libopenblas.dylib" \ -DLAPACK_LIBRARIES="$(brew --prefix)/lib/libopenblas.dylib" cpack --config build/CPackConfig.cmake -G DragNDrop From 38b5605c18f81bf881c4a619ace5f32023d04e91 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 18 Aug 2026 05:36:28 +0000 Subject: [PATCH 09/42] Initial plan From b9a1b573b81d6525f9684862348b1af6d77fda78 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 18 Aug 2026 05:42:51 +0000 Subject: [PATCH 10/42] ci: fix macOS arm64 GSL resolution in workflow Co-authored-by: HPDell <17842185+HPDell@users.noreply.github.com> --- .github/workflows/ci.yml | 303 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 303 insertions(+) create mode 100644 .github/workflows/ci.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..3c7af59 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,303 @@ +# GitHub Actions CI for GWmodelS (QGIS 3.28 LTR secondary development) +# +# Targets: +# - Windows (x64) +# - macOS (Intel, x86_64) +# - macOS (Apple Silicon, arm64) +# +# Pipeline: +# 1. Install the libgwmodel kernel (https://github.com/GWmodel-Lab/libgwmodel.git) +# 2. Create a conda environment: qgis=3.28, armadillo, catch2, openblas, nomkl +# 3. Patch the missing qgswebframe.h header from the QGIS source tree +# 4. Configure + build GWmodelS +# 5. Package with CPack (INSTALL/CPack rules live in src/CMakeLists.txt) +# - macOS: sign the .app with a self-signed certificate before packaging +# +# NOTE: draft only, not yet pushed/validated. + +name: CI + +on: + push: + branches: [master, 'feat/**', 'enhance/**'] + tags: ['v*'] + pull_request: + workflow_dispatch: + +env: + CONDA_ENV: gwmodels + QGIS_VER: '3.28' + # qgswebframe.h is fetched from the QGIS 3.28 LTR source tree + QGIS_HEADER_REF: final-3_28_16 + +jobs: + # --------------------------------------------------------------------------- + # Windows + # --------------------------------------------------------------------------- + build-windows: + name: Windows (x64) + runs-on: windows-latest + + steps: + - name: Checkout source + uses: actions/checkout@v4 + + - name: Set up Miniconda + uses: conda-incubator/setup-miniconda@v3 + with: + auto-update-conda: true + python-version: '3.10' + channels: conda-forge, defaults + channel-priority: flexible + activate-environment: ${{ env.CONDA_ENV }} + + # qgis/armadillo/catch2/openblas/gsl come from conda-forge; nomkl (no + # MKL) is only available in the 'defaults' channel. + # + # NOTE: the conda-forge gsl package ships no CMake config files, so + # libgwmodel's `find_package(GSL)` relies on CMake's built-in FindGSL, + # which only provides the GSL::gsl/GSL::gslcblas targets since CMake 3.27. + # Install a recent cmake from conda-forge to guarantee that. + - name: Install conda dependencies + shell: bash -l {0} + run: | + conda install -n "$CONDA_ENV" -q -y \ + -c conda-forge qgis=$QGIS_VER armadillo catch2 openblas gsl cmake nomkl + conda list -n "$CONDA_ENV" -q + + # GitHub-hosted runners may have an old system cmake that cannot detect + # the installed VS instance; point CMake at the exact VS install found by + # vswhere (the CMAKE_GENERATOR_INSTANCE env var is honored by CMake). + - name: Locate Visual Studio instance + shell: pwsh + run: | + $vswhere = "${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\vswhere.exe" + $vs = & $vswhere -latest -products * ` + -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 ` + -property installationPath + if ($vs) { + "CMAKE_GENERATOR_INSTANCE=$vs" | Out-File -FilePath $env:GITHUB_ENV -Append + Write-Host "Found VS at: $vs" + } else { + Write-Error "No Visual Studio with C++ tools found by vswhere" + } + + # libgwmodel is the spatial-statistics kernel required by GWmodelS. + # Build first (the conda deps above are already in place). + - name: Install libgwmodel kernel + shell: bash -l {0} + run: | + conda activate "$CONDA_ENV" + git clone --depth 1 https://github.com/GWmodel-Lab/libgwmodel.git + cmake -S libgwmodel -B libgwmodel/build \ + -G "Visual Studio 17 2022" -A x64 \ + -DCMAKE_INSTALL_PREFIX="$CONDA_PREFIX/Library" \ + -DCMAKE_PREFIX_PATH="$CONDA_PREFIX/Library" \ + -DBUILD_TESTING=OFF + cmake --build libgwmodel/build --config Release --parallel + cmake --install libgwmodel/build + + # The conda QGIS package is missing qgswebframe.h; download it from the + # QGIS 3.28 LTR source tree and drop it into the include directory. + - name: Patch missing qgswebframe.h + shell: bash -l {0} + run: | + QGIS_INC="$CONDA_PREFIX/Library/include/qgis" + curl -fsSL -o "$QGIS_INC/qgswebframe.h" \ + "https://raw.githubusercontent.com/qgis/QGIS/$QGIS_HEADER_REF/src/gui/qgswebframe.h" + + - name: Enable MSVC toolchain + uses: ilammy/msvc-dev-cmd@v1 + with: + arch: x64 + + - name: Configure (cmake) + shell: pwsh + run: | + conda activate $env:CONDA_ENV + $env:PATH = "$env:CONDA_PREFIX\Library\bin;$env:PATH" + $env:LIB_DIR = "$env:CONDA_PREFIX\Library" + $env:INCLUDE = "$env:CONDA_PREFIX\Library\include;$env:INCLUDE" + cmake -S . -B build -G "Visual Studio 17 2022" -A x64 ` + -DCMAKE_PREFIX_PATH="$env:CONDA_PREFIX\Library" ` + -DCMAKE_BUILD_TYPE=Release ` + -DCMAKE_INSTALL_PREFIX="$env:CONDA_PREFIX\Library" ` + -DDATADIR="share" ` + -DBLAS_LIBRARIES="$env:CONDA_PREFIX\Library\lib\libopenblas.lib" ` + -DLAPACK_LIBRARIES="$env:CONDA_PREFIX\Library\lib\libopenblas.lib" + + - name: Build GWmodelS + shell: pwsh + run: | + conda activate $env:CONDA_ENV + $env:PATH = "$env:CONDA_PREFIX\Library\bin;$env:PATH" + cmake --build build --config Release --target GWmodelS --parallel + + # CPack configuration is provided by the INSTALL/CPack section in + # src/CMakeLists.txt; reconfigure is a no-op and regenerates the + # CPackConfig.cmake before producing the ZIP package. + - name: Package with CPack + shell: pwsh + run: | + conda activate $env:CONDA_ENV + $env:PATH = "$env:CONDA_PREFIX\Library\bin;$env:PATH" + $env:LIB_DIR = "$env:CONDA_PREFIX\Library" + $env:INCLUDE = "$env:CONDA_PREFIX\Library\include;$env:INCLUDE" + cmake -S . -B build -G "Visual Studio 17 2022" -A x64 ` + -DCMAKE_PREFIX_PATH="$env:CONDA_PREFIX\Library" ` + -DCMAKE_BUILD_TYPE=Release ` + -DCMAKE_INSTALL_PREFIX="$env:CONDA_PREFIX\Library" ` + -DDATADIR="share" ` + -DBLAS_LIBRARIES="$env:CONDA_PREFIX\Library\lib\libopenblas.lib" ` + -DLAPACK_LIBRARIES="$env:CONDA_PREFIX\Library\lib\libopenblas.lib" + cpack --config build/CPackConfig.cmake -G ZIP + + - name: Upload package + uses: actions/upload-artifact@v4 + with: + name: GWmodelS-Windows-x64 + path: build/*.zip + if-no-files-found: error + + # --------------------------------------------------------------------------- + # macOS (Intel + Apple Silicon) + # --------------------------------------------------------------------------- + build-macos: + name: macOS (${{ matrix.arch }}) + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + include: + - os: macos-13 # Intel + arch: x86_64 + - os: macos-14 # Apple Silicon + arch: arm64 + + steps: + - name: Checkout source + uses: actions/checkout@v4 + + - name: Set up Miniconda + uses: conda-incubator/setup-miniconda@v3 + with: + auto-update-conda: true + python-version: '3.10' + channels: conda-forge, defaults + channel-priority: flexible + activate-environment: ${{ env.CONDA_ENV }} + + # QGIS itself is installed via conda-forge; all other (non-QGIS) build + # dependencies are provided by Homebrew instead, to keep the QGIS + # toolchain self-contained inside the conda environment. + # + # gsl is installed via Homebrew because libgwmodel uses + # `find_package(GSL)` and requires a GSL CMake package config. + - name: Install conda dependencies (QGIS) + shell: bash -l {0} + run: | + conda install -n "$CONDA_ENV" -q -y \ + -c conda-forge qgis=$QGIS_VER nomkl + conda list -n "$CONDA_ENV" -q + + # Non-QGIS build deps via Homebrew. Note: the brew formula for + # llvm-openmp is called 'libomp'. Homebrew's gsl formula ships + # GSLConfig.cmake, which satisfies libgwmodel's `find_package(GSL)`. + - name: Install brew dependencies + shell: bash + run: | + brew install --quiet armadillo openblas catch2 libomp gsl cmake + + - name: Install libgwmodel kernel + shell: bash -l {0} + run: | + conda activate "$CONDA_ENV" + git clone --depth 1 https://github.com/GWmodel-Lab/libgwmodel.git + cmake -S libgwmodel -B libgwmodel/build \ + -DCMAKE_BUILD_TYPE=Release \ + -DCMAKE_INSTALL_PREFIX="$CONDA_PREFIX" \ + -DCMAKE_PREFIX_PATH="$(brew --prefix);$CONDA_PREFIX" \ + -DGSL_DIR="$(brew --prefix)/opt/gsl/lib/cmake/gsl" \ + -DBLAS_LIBRARIES="$(brew --prefix)/lib/libopenblas.dylib" \ + -DLAPACK_LIBRARIES="$(brew --prefix)/lib/libopenblas.dylib" \ + -DBUILD_TESTING=OFF + cmake --build libgwmodel/build --config Release --parallel + cmake --install libgwmodel/build + + # qgswebframe.h is missing from the conda QGIS package; fetch it from the + # QGIS 3.28 LTR source tree into the conda include directory. + - name: Patch missing qgswebframe.h + shell: bash -l {0} + run: | + QGIS_INC="$CONDA_PREFIX/include/qgis" + curl -fsSL -o "$QGIS_INC/qgswebframe.h" \ + "https://raw.githubusercontent.com/qgis/QGIS/$QGIS_HEADER_REF/src/gui/qgswebframe.h" + + - name: Configure (cmake) + shell: bash -l {0} + run: | + conda activate "$CONDA_ENV" + cmake -S . -B build \ + -DCMAKE_BUILD_TYPE=Release \ + -DCMAKE_PREFIX_PATH="$(brew --prefix);$CONDA_PREFIX" \ + -DQGIS_PREFIX_PATH="$CONDA_PREFIX" \ + -DGSL_DIR="$(brew --prefix)/opt/gsl/lib/cmake/gsl" \ + -DBLAS_LIBRARIES="$(brew --prefix)/lib/libopenblas.dylib" \ + -DLAPACK_LIBRARIES="$(brew --prefix)/lib/libopenblas.dylib" + + - name: Build GWmodelS + shell: bash -l {0} + run: | + conda activate "$CONDA_ENV" + cmake --build build --config Release --target GWmodelS --parallel + + # Create a self-signed code-signing identity and sign the .app bundle so + # CPack (DMG) produces a package that macOS accepts. + # + # NOTE: the INSTALL rule for APPLE in src/CMakeLists.txt runs fixup_bundle + # during `cpack`/`cmake --install`, which rewrites dylib install names and + # invalidates this signature. A robust approach is to re-sign the .app + # inside the CPack staging tree (build/_CPack_Packages/*/DragNDrop/) after + # cpack and before DMG creation; for this draft the sign-before-pack keeps + # the flow simple and easy to iterate on. + - name: Sign GWmodelS.app (self-signed certificate) + shell: bash + run: | + KEYCHAIN="$RUNNER_TEMP/build.keychain" + security create-keychain -p build "$KEYCHAIN" + security default-keychain -s "$KEYCHAIN" + security unlock-keychain -p build "$KEYCHAIN" + security set-keychain-settings -t 3600 -u "$KEYCHAIN" + + openssl req -x509 -newkey rsa:2048 -keyout /tmp/dev.key -out /tmp/dev.crt \ + -days 365 -nodes -subj "/CN=GWmodelS CI" + openssl pkcs12 -export -out /tmp/dev.p12 \ + -inkey /tmp/dev.key -in /tmp/dev.crt -passout pass:build + security import /tmp/dev.p12 -k "$KEYCHAIN" -P build -T /usr/bin/codesign + + IDENTITY=$(security find-identity -v -p codesigning "$KEYCHAIN" \ + | awk -F'[()]' '/GWmodelS/{print $2; exit}') + codesign --force --deep --sign "$IDENTITY" --keychain "$KEYCHAIN" build/GWmodelS.app + + # CPack configuration is provided by the INSTALL/CPack section in + # src/CMakeLists.txt; reconfigure is a no-op and regenerates the + # CPackConfig.cmake before producing the DMG. + - name: Package with CPack + shell: bash -l {0} + run: | + conda activate "$CONDA_ENV" + cmake -S . -B build \ + -DCMAKE_BUILD_TYPE=Release \ + -DCMAKE_PREFIX_PATH="$(brew --prefix);$CONDA_PREFIX" \ + -DQGIS_PREFIX_PATH="$CONDA_PREFIX" \ + -DGSL_DIR="$(brew --prefix)/opt/gsl/lib/cmake/gsl" \ + -DBLAS_LIBRARIES="$(brew --prefix)/lib/libopenblas.dylib" \ + -DLAPACK_LIBRARIES="$(brew --prefix)/lib/libopenblas.dylib" + cpack --config build/CPackConfig.cmake -G DragNDrop + + - name: Upload package + uses: actions/upload-artifact@v4 + with: + name: GWmodelS-macOS-${{ matrix.arch }} + path: build/*.dmg + if-no-files-found: error From bb4896cbcad454e7eb15a8e92b26646c214ffe3c Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 18 Aug 2026 05:44:22 +0000 Subject: [PATCH 11/42] ci: use brew gsl and set workflow permissions Co-authored-by: HPDell <17842185+HPDell@users.noreply.github.com> --- .github/workflows/ci.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3c7af59..ed4fa1b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -24,6 +24,9 @@ on: pull_request: workflow_dispatch: +permissions: + contents: read + env: CONDA_ENV: gwmodels QGIS_VER: '3.28' From 30662142c9f8357ad3986cf5178bcdf088c6c27f Mon Sep 17 00:00:00 2001 From: HPDell Date: Tue, 18 Aug 2026 14:20:54 +0800 Subject: [PATCH 12/42] edit: ci configs --- .github/workflows/ci.yml | 91 ++++++++++++++++++++-------------------- 1 file changed, 46 insertions(+), 45 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ed4fa1b..926c8a4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -45,6 +45,23 @@ jobs: - name: Checkout source uses: actions/checkout@v4 + # GitHub-hosted runners may have an old system cmake that cannot detect + # the installed VS instance; point CMake at the exact VS install found by + # vswhere (the CMAKE_GENERATOR_INSTANCE env var is honored by CMake). + - name: Locate Visual Studio instance + shell: pwsh + run: | + $vswhere = "${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\vswhere.exe" + $vs = & $vswhere -latest -products * ` + -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 ` + -property installationPath + if ($vs) { + "CMAKE_GENERATOR_INSTANCE=$vs" | Out-File -FilePath $env:GITHUB_ENV -Append + Write-Host "Found VS at: $vs" + } else { + Write-Error "No Visual Studio with C++ tools found by vswhere" + } + - name: Set up Miniconda uses: conda-incubator/setup-miniconda@v3 with: @@ -68,23 +85,6 @@ jobs: -c conda-forge qgis=$QGIS_VER armadillo catch2 openblas gsl cmake nomkl conda list -n "$CONDA_ENV" -q - # GitHub-hosted runners may have an old system cmake that cannot detect - # the installed VS instance; point CMake at the exact VS install found by - # vswhere (the CMAKE_GENERATOR_INSTANCE env var is honored by CMake). - - name: Locate Visual Studio instance - shell: pwsh - run: | - $vswhere = "${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\vswhere.exe" - $vs = & $vswhere -latest -products * ` - -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 ` - -property installationPath - if ($vs) { - "CMAKE_GENERATOR_INSTANCE=$vs" | Out-File -FilePath $env:GITHUB_ENV -Append - Write-Host "Found VS at: $vs" - } else { - Write-Error "No Visual Studio with C++ tools found by vswhere" - } - # libgwmodel is the spatial-statistics kernel required by GWmodelS. # Build first (the conda deps above are already in place). - name: Install libgwmodel kernel @@ -92,13 +92,14 @@ jobs: run: | conda activate "$CONDA_ENV" git clone --depth 1 https://github.com/GWmodel-Lab/libgwmodel.git - cmake -S libgwmodel -B libgwmodel/build \ - -G "Visual Studio 17 2022" -A x64 \ + cmake -S . -B libgwmodel/build \ + -A x64 \ -DCMAKE_INSTALL_PREFIX="$CONDA_PREFIX/Library" \ -DCMAKE_PREFIX_PATH="$CONDA_PREFIX/Library" \ -DBUILD_TESTING=OFF - cmake --build libgwmodel/build --config Release --parallel - cmake --install libgwmodel/build + cmake --build build --config Release --parallel + cmake --install build + working-directory: ${{ github.workspace }}/libgwmodel # The conda QGIS package is missing qgswebframe.h; download it from the # QGIS 3.28 LTR source tree and drop it into the include directory. @@ -181,6 +182,30 @@ jobs: - name: Checkout source uses: actions/checkout@v4 + # Non-QGIS build deps via Homebrew. Note: the brew formula for + # llvm-openmp is called 'libomp'. Homebrew's gsl formula ships + # GSLConfig.cmake, which satisfies libgwmodel's `find_package(GSL)`. + - name: Install brew dependencies + shell: bash + run: | + brew install --quiet armadillo openblas catch2 libomp gsl cmake + + - name: Install libgwmodel kernel + shell: bash -l {0} + run: | + conda activate "$CONDA_ENV" + git clone --depth 1 https://github.com/GWmodel-Lab/libgwmodel.git + cmake -S . -B build \ + -DCMAKE_BUILD_TYPE=Release \ + -DCMAKE_PREFIX_PATH="$(brew --prefix);$CONDA_PREFIX" \ + -DGSL_DIR="$(brew --prefix)/opt/gsl/lib/cmake/gsl" \ + -DBLAS_LIBRARIES="$(brew --prefix)/lib/libopenblas.dylib" \ + -DLAPACK_LIBRARIES="$(brew --prefix)/lib/libopenblas.dylib" \ + -DBUILD_TESTING=OFF + cmake --build build --config Release --parallel + cmake --install build + working-directory: ${{ github.workspace }}/libgwmodel + - name: Set up Miniconda uses: conda-incubator/setup-miniconda@v3 with: @@ -203,30 +228,6 @@ jobs: -c conda-forge qgis=$QGIS_VER nomkl conda list -n "$CONDA_ENV" -q - # Non-QGIS build deps via Homebrew. Note: the brew formula for - # llvm-openmp is called 'libomp'. Homebrew's gsl formula ships - # GSLConfig.cmake, which satisfies libgwmodel's `find_package(GSL)`. - - name: Install brew dependencies - shell: bash - run: | - brew install --quiet armadillo openblas catch2 libomp gsl cmake - - - name: Install libgwmodel kernel - shell: bash -l {0} - run: | - conda activate "$CONDA_ENV" - git clone --depth 1 https://github.com/GWmodel-Lab/libgwmodel.git - cmake -S libgwmodel -B libgwmodel/build \ - -DCMAKE_BUILD_TYPE=Release \ - -DCMAKE_INSTALL_PREFIX="$CONDA_PREFIX" \ - -DCMAKE_PREFIX_PATH="$(brew --prefix);$CONDA_PREFIX" \ - -DGSL_DIR="$(brew --prefix)/opt/gsl/lib/cmake/gsl" \ - -DBLAS_LIBRARIES="$(brew --prefix)/lib/libopenblas.dylib" \ - -DLAPACK_LIBRARIES="$(brew --prefix)/lib/libopenblas.dylib" \ - -DBUILD_TESTING=OFF - cmake --build libgwmodel/build --config Release --parallel - cmake --install libgwmodel/build - # qgswebframe.h is missing from the conda QGIS package; fetch it from the # QGIS 3.28 LTR source tree into the conda include directory. - name: Patch missing qgswebframe.h From c0d87b928cb074145a66c253fe7838c99e501f9d Mon Sep 17 00:00:00 2001 From: HPDell Date: Tue, 18 Aug 2026 14:22:36 +0800 Subject: [PATCH 13/42] edit(macos): does not active conda when installing libgwmodel --- .github/workflows/ci.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 926c8a4..7c73566 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -193,7 +193,6 @@ jobs: - name: Install libgwmodel kernel shell: bash -l {0} run: | - conda activate "$CONDA_ENV" git clone --depth 1 https://github.com/GWmodel-Lab/libgwmodel.git cmake -S . -B build \ -DCMAKE_BUILD_TYPE=Release \ From 14ecf1ce43438a7a285e1997282563bf031bef66 Mon Sep 17 00:00:00 2001 From: HPDell Date: Tue, 18 Aug 2026 14:24:59 +0800 Subject: [PATCH 14/42] edti: separate clone and install libgwmodel --- .github/workflows/ci.yml | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7c73566..7492105 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -84,6 +84,10 @@ jobs: conda install -n "$CONDA_ENV" -q -y \ -c conda-forge qgis=$QGIS_VER armadillo catch2 openblas gsl cmake nomkl conda list -n "$CONDA_ENV" -q + + - name: Clone libgwmodel + run: | + git clone --depth 1 https://github.com/GWmodel-Lab/libgwmodel.git # libgwmodel is the spatial-statistics kernel required by GWmodelS. # Build first (the conda deps above are already in place). @@ -91,7 +95,6 @@ jobs: shell: bash -l {0} run: | conda activate "$CONDA_ENV" - git clone --depth 1 https://github.com/GWmodel-Lab/libgwmodel.git cmake -S . -B libgwmodel/build \ -A x64 \ -DCMAKE_INSTALL_PREFIX="$CONDA_PREFIX/Library" \ @@ -189,11 +192,14 @@ jobs: shell: bash run: | brew install --quiet armadillo openblas catch2 libomp gsl cmake + + - name: Clone libgwmodel + run: | + git clone --depth 1 https://github.com/GWmodel-Lab/libgwmodel.git - name: Install libgwmodel kernel shell: bash -l {0} run: | - git clone --depth 1 https://github.com/GWmodel-Lab/libgwmodel.git cmake -S . -B build \ -DCMAKE_BUILD_TYPE=Release \ -DCMAKE_PREFIX_PATH="$(brew --prefix);$CONDA_PREFIX" \ From bf45a976c1566672f3c1379dbc2f325856096a4e Mon Sep 17 00:00:00 2001 From: HPDell Date: Tue, 18 Aug 2026 14:31:01 +0800 Subject: [PATCH 15/42] edit: disable libgwmodel tests --- .github/workflows/ci.yml | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7492105..35aba63 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -99,7 +99,7 @@ jobs: -A x64 \ -DCMAKE_INSTALL_PREFIX="$CONDA_PREFIX/Library" \ -DCMAKE_PREFIX_PATH="$CONDA_PREFIX/Library" \ - -DBUILD_TESTING=OFF + -DWITH_TESTS=OFF cmake --build build --config Release --parallel cmake --install build working-directory: ${{ github.workspace }}/libgwmodel @@ -202,11 +202,7 @@ jobs: run: | cmake -S . -B build \ -DCMAKE_BUILD_TYPE=Release \ - -DCMAKE_PREFIX_PATH="$(brew --prefix);$CONDA_PREFIX" \ - -DGSL_DIR="$(brew --prefix)/opt/gsl/lib/cmake/gsl" \ - -DBLAS_LIBRARIES="$(brew --prefix)/lib/libopenblas.dylib" \ - -DLAPACK_LIBRARIES="$(brew --prefix)/lib/libopenblas.dylib" \ - -DBUILD_TESTING=OFF + -DWITH_TESTS=OFF cmake --build build --config Release --parallel cmake --install build working-directory: ${{ github.workspace }}/libgwmodel From 50e8b756935230e97cf24966085f576d6716a05b Mon Sep 17 00:00:00 2001 From: HPDell Date: Tue, 18 Aug 2026 14:35:30 +0800 Subject: [PATCH 16/42] edit: install libgwmodel to conda env --- .github/workflows/ci.yml | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 35aba63..a08c4a6 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -192,20 +192,6 @@ jobs: shell: bash run: | brew install --quiet armadillo openblas catch2 libomp gsl cmake - - - name: Clone libgwmodel - run: | - git clone --depth 1 https://github.com/GWmodel-Lab/libgwmodel.git - - - name: Install libgwmodel kernel - shell: bash -l {0} - run: | - cmake -S . -B build \ - -DCMAKE_BUILD_TYPE=Release \ - -DWITH_TESTS=OFF - cmake --build build --config Release --parallel - cmake --install build - working-directory: ${{ github.workspace }}/libgwmodel - name: Set up Miniconda uses: conda-incubator/setup-miniconda@v3 @@ -228,6 +214,21 @@ jobs: conda install -n "$CONDA_ENV" -q -y \ -c conda-forge qgis=$QGIS_VER nomkl conda list -n "$CONDA_ENV" -q + + - name: Clone libgwmodel + run: | + git clone --depth 1 https://github.com/GWmodel-Lab/libgwmodel.git + + - name: Install libgwmodel kernel + shell: bash -l {0} + run: | + cmake -S . -B build \ + -DCMAKE_BUILD_TYPE=Release \ + -DCMAKE_INSTALL_PREFIX="$CONDA_PREFIX" \ + -DWITH_TESTS=OFF + cmake --build build --config Release --parallel + cmake --install build + working-directory: ${{ github.workspace }}/libgwmodel # qgswebframe.h is missing from the conda QGIS package; fetch it from the # QGIS 3.28 LTR source tree into the conda include directory. From 6faa9d9005100c7d4f55b4bf6a93b09e59e5db5c Mon Sep 17 00:00:00 2001 From: HPDell Date: Tue, 18 Aug 2026 14:45:04 +0800 Subject: [PATCH 17/42] fix: qgswebframe path --- .github/workflows/ci.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a08c4a6..f81968b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -31,7 +31,7 @@ env: CONDA_ENV: gwmodels QGIS_VER: '3.28' # qgswebframe.h is fetched from the QGIS 3.28 LTR source tree - QGIS_HEADER_REF: final-3_28_16 + QGIS_HEADER_REF: final-3_28_1 jobs: # --------------------------------------------------------------------------- @@ -111,7 +111,7 @@ jobs: run: | QGIS_INC="$CONDA_PREFIX/Library/include/qgis" curl -fsSL -o "$QGIS_INC/qgswebframe.h" \ - "https://raw.githubusercontent.com/qgis/QGIS/$QGIS_HEADER_REF/src/gui/qgswebframe.h" + "https://raw.githubusercontent.com/qgis/QGIS/$QGIS_HEADER_REF/src/core/qgswebframe.h" - name: Enable MSVC toolchain uses: ilammy/msvc-dev-cmd@v1 @@ -237,7 +237,7 @@ jobs: run: | QGIS_INC="$CONDA_PREFIX/include/qgis" curl -fsSL -o "$QGIS_INC/qgswebframe.h" \ - "https://raw.githubusercontent.com/qgis/QGIS/$QGIS_HEADER_REF/src/gui/qgswebframe.h" + "https://raw.githubusercontent.com/qgis/QGIS/$QGIS_HEADER_REF/src/core/qgswebframe.h" - name: Configure (cmake) shell: bash -l {0} From 7e4159ee6f5b008925980875a28a501bf71e9c3f Mon Sep 17 00:00:00 2001 From: HPDell Date: Tue, 18 Aug 2026 14:48:02 +0800 Subject: [PATCH 18/42] edit: macos os specification --- .github/workflows/ci.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f81968b..1c5efa4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -176,9 +176,9 @@ jobs: fail-fast: false matrix: include: - - os: macos-13 # Intel - arch: x86_64 - - os: macos-14 # Apple Silicon + - os: macos-15-intel # Intel + arch: x64 + - os: macos-15 # Apple Silicon arch: arm64 steps: From 235f0e79cc3d4cc9992045bd41fb4651a9472e9d Mon Sep 17 00:00:00 2001 From: HPDell Date: Tue, 18 Aug 2026 14:51:57 +0800 Subject: [PATCH 19/42] edit: GWmodel cmake configure --- .github/workflows/ci.yml | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1c5efa4..29739f5 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -245,11 +245,7 @@ jobs: conda activate "$CONDA_ENV" cmake -S . -B build \ -DCMAKE_BUILD_TYPE=Release \ - -DCMAKE_PREFIX_PATH="$(brew --prefix);$CONDA_PREFIX" \ - -DQGIS_PREFIX_PATH="$CONDA_PREFIX" \ - -DGSL_DIR="$(brew --prefix)/opt/gsl/lib/cmake/gsl" \ - -DBLAS_LIBRARIES="$(brew --prefix)/lib/libopenblas.dylib" \ - -DLAPACK_LIBRARIES="$(brew --prefix)/lib/libopenblas.dylib" + -DQGIS_PREFIX_PATH="$CONDA_PREFIX" - name: Build GWmodelS shell: bash -l {0} From ae7ee663c9834f5c8a61e1a966858f6f8b1c79d1 Mon Sep 17 00:00:00 2001 From: HPDell Date: Tue, 18 Aug 2026 15:03:52 +0800 Subject: [PATCH 20/42] fix: windows build path for libgwmodel --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 29739f5..6c96240 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -95,7 +95,7 @@ jobs: shell: bash -l {0} run: | conda activate "$CONDA_ENV" - cmake -S . -B libgwmodel/build \ + cmake -S . -B build \ -A x64 \ -DCMAKE_INSTALL_PREFIX="$CONDA_PREFIX/Library" \ -DCMAKE_PREFIX_PATH="$CONDA_PREFIX/Library" \ From 2be429112748666e00dbfa073cebf73b590ba773 Mon Sep 17 00:00:00 2001 From: HPDell Date: Tue, 18 Aug 2026 15:04:01 +0800 Subject: [PATCH 21/42] fix: GWmodelS cmake prefix path --- .github/workflows/ci.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6c96240..b78dec3 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -245,6 +245,7 @@ jobs: conda activate "$CONDA_ENV" cmake -S . -B build \ -DCMAKE_BUILD_TYPE=Release \ + -DCMAKE_PREFIX_PATH="$CONDA_PREFIX" \ -DQGIS_PREFIX_PATH="$CONDA_PREFIX" - name: Build GWmodelS From ee0be7c3b16c8d1a43ccc750e2ec17865ee704b3 Mon Sep 17 00:00:00 2001 From: HPDell Date: Tue, 18 Aug 2026 15:18:34 +0800 Subject: [PATCH 22/42] fix: use pwsh on windows --- .github/workflows/ci.yml | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b78dec3..8bc30de 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -79,26 +79,28 @@ jobs: # which only provides the GSL::gsl/GSL::gslcblas targets since CMake 3.27. # Install a recent cmake from conda-forge to guarantee that. - name: Install conda dependencies - shell: bash -l {0} + shell: pwsh run: | - conda install -n "$CONDA_ENV" -q -y \ - -c conda-forge qgis=$QGIS_VER armadillo catch2 openblas gsl cmake nomkl - conda list -n "$CONDA_ENV" -q + conda activate $env:CONDA_ENV + conda install -n $env:CONDA_ENV -q -y ` + -c conda-forge qgis=$env:QGIS_VER armadillo catch2 openblas gsl cmake nomkl + conda list -n $env:CONDA_ENV -q - name: Clone libgwmodel + shell: pwsh run: | git clone --depth 1 https://github.com/GWmodel-Lab/libgwmodel.git # libgwmodel is the spatial-statistics kernel required by GWmodelS. # Build first (the conda deps above are already in place). - name: Install libgwmodel kernel - shell: bash -l {0} + shell: pwsh run: | - conda activate "$CONDA_ENV" - cmake -S . -B build \ - -A x64 \ - -DCMAKE_INSTALL_PREFIX="$CONDA_PREFIX/Library" \ - -DCMAKE_PREFIX_PATH="$CONDA_PREFIX/Library" \ + conda activate $env:CONDA_ENV + cmake -S . -B build ` + -A x64 ` + -DCMAKE_INSTALL_PREFIX="$env:CONDA_PREFIX\Library" ` + -DCMAKE_PREFIX_PATH="$env:CONDA_PREFIX\Library" ` -DWITH_TESTS=OFF cmake --build build --config Release --parallel cmake --install build @@ -107,11 +109,11 @@ jobs: # The conda QGIS package is missing qgswebframe.h; download it from the # QGIS 3.28 LTR source tree and drop it into the include directory. - name: Patch missing qgswebframe.h - shell: bash -l {0} + shell: pwsh run: | - QGIS_INC="$CONDA_PREFIX/Library/include/qgis" - curl -fsSL -o "$QGIS_INC/qgswebframe.h" \ - "https://raw.githubusercontent.com/qgis/QGIS/$QGIS_HEADER_REF/src/core/qgswebframe.h" + $QGIS_INC = "$env:CONDA_PREFIX\Library\include\qgis" + curl.exe -fsSL -o "$QGIS_INC\qgswebframe.h" ` + "https://raw.githubusercontent.com/qgis/QGIS/$env:QGIS_HEADER_REF/src/core/qgswebframe.h" - name: Enable MSVC toolchain uses: ilammy/msvc-dev-cmd@v1 From 19d90fde9af21e624075870aa2cb3ed36f194a48 Mon Sep 17 00:00:00 2001 From: HPDell Date: Tue, 18 Aug 2026 18:00:41 +0800 Subject: [PATCH 23/42] fix: make packages --- .github/workflows/ci.yml | 141 ++++++++++++++++++--------------------- src/CMakeLists.txt | 21 ++++++ 2 files changed, 87 insertions(+), 75 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8bc30de..2cf4615 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -45,23 +45,6 @@ jobs: - name: Checkout source uses: actions/checkout@v4 - # GitHub-hosted runners may have an old system cmake that cannot detect - # the installed VS instance; point CMake at the exact VS install found by - # vswhere (the CMAKE_GENERATOR_INSTANCE env var is honored by CMake). - - name: Locate Visual Studio instance - shell: pwsh - run: | - $vswhere = "${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\vswhere.exe" - $vs = & $vswhere -latest -products * ` - -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 ` - -property installationPath - if ($vs) { - "CMAKE_GENERATOR_INSTANCE=$vs" | Out-File -FilePath $env:GITHUB_ENV -Append - Write-Host "Found VS at: $vs" - } else { - Write-Error "No Visual Studio with C++ tools found by vswhere" - } - - name: Set up Miniconda uses: conda-incubator/setup-miniconda@v3 with: @@ -81,7 +64,6 @@ jobs: - name: Install conda dependencies shell: pwsh run: | - conda activate $env:CONDA_ENV conda install -n $env:CONDA_ENV -q -y ` -c conda-forge qgis=$env:QGIS_VER armadillo catch2 openblas gsl cmake nomkl conda list -n $env:CONDA_ENV -q @@ -96,14 +78,13 @@ jobs: - name: Install libgwmodel kernel shell: pwsh run: | - conda activate $env:CONDA_ENV cmake -S . -B build ` -A x64 ` -DCMAKE_INSTALL_PREFIX="$env:CONDA_PREFIX\Library" ` -DCMAKE_PREFIX_PATH="$env:CONDA_PREFIX\Library" ` -DWITH_TESTS=OFF cmake --build build --config Release --parallel - cmake --install build + cmake --install build --config Release working-directory: ${{ github.workspace }}/libgwmodel # The conda QGIS package is missing qgswebframe.h; download it from the @@ -111,9 +92,9 @@ jobs: - name: Patch missing qgswebframe.h shell: pwsh run: | - $QGIS_INC = "$env:CONDA_PREFIX\Library\include\qgis" - curl.exe -fsSL -o "$QGIS_INC\qgswebframe.h" ` - "https://raw.githubusercontent.com/qgis/QGIS/$env:QGIS_HEADER_REF/src/core/qgswebframe.h" + $QGIS_INC = "$env:CONDA_PREFIX\Library\include" + Invoke-WebRequest -Uri "https://raw.githubusercontent.com/qgis/QGIS/$env:QGIS_HEADER_REF/src/core/qgswebframe.h" ` + -OutFile "$QGIS_INC\qgswebframe.h" - name: Enable MSVC toolchain uses: ilammy/msvc-dev-cmd@v1 @@ -123,49 +104,38 @@ jobs: - name: Configure (cmake) shell: pwsh run: | - conda activate $env:CONDA_ENV $env:PATH = "$env:CONDA_PREFIX\Library\bin;$env:PATH" $env:LIB_DIR = "$env:CONDA_PREFIX\Library" $env:INCLUDE = "$env:CONDA_PREFIX\Library\include;$env:INCLUDE" cmake -S . -B build -G "Visual Studio 17 2022" -A x64 ` -DCMAKE_PREFIX_PATH="$env:CONDA_PREFIX\Library" ` -DCMAKE_BUILD_TYPE=Release ` - -DCMAKE_INSTALL_PREFIX="$env:CONDA_PREFIX\Library" ` - -DDATADIR="share" ` - -DBLAS_LIBRARIES="$env:CONDA_PREFIX\Library\lib\libopenblas.lib" ` - -DLAPACK_LIBRARIES="$env:CONDA_PREFIX\Library\lib\libopenblas.lib" + -DCMAKE_INSTALL_PREFIX="build\staged" ` + -DDATADIR="share" - name: Build GWmodelS shell: pwsh run: | - conda activate $env:CONDA_ENV $env:PATH = "$env:CONDA_PREFIX\Library\bin;$env:PATH" cmake --build build --config Release --target GWmodelS --parallel # CPack configuration is provided by the INSTALL/CPack section in # src/CMakeLists.txt; reconfigure is a no-op and regenerates the - # CPackConfig.cmake before producing the ZIP package. + # CPackConfig.cmake before producing the NSIS64 installer. - name: Package with CPack shell: pwsh run: | - conda activate $env:CONDA_ENV $env:PATH = "$env:CONDA_PREFIX\Library\bin;$env:PATH" $env:LIB_DIR = "$env:CONDA_PREFIX\Library" $env:INCLUDE = "$env:CONDA_PREFIX\Library\include;$env:INCLUDE" - cmake -S . -B build -G "Visual Studio 17 2022" -A x64 ` - -DCMAKE_PREFIX_PATH="$env:CONDA_PREFIX\Library" ` - -DCMAKE_BUILD_TYPE=Release ` - -DCMAKE_INSTALL_PREFIX="$env:CONDA_PREFIX\Library" ` - -DDATADIR="share" ` - -DBLAS_LIBRARIES="$env:CONDA_PREFIX\Library\lib\libopenblas.lib" ` - -DLAPACK_LIBRARIES="$env:CONDA_PREFIX\Library\lib\libopenblas.lib" - cpack --config build/CPackConfig.cmake -G ZIP + cpack -G NSIS64 -C Release + working-directory: ${{ github.workspace }}/build - name: Upload package uses: actions/upload-artifact@v4 with: name: GWmodelS-Windows-x64 - path: build/*.zip + path: build/*.exe if-no-files-found: error # --------------------------------------------------------------------------- @@ -193,7 +163,7 @@ jobs: - name: Install brew dependencies shell: bash run: | - brew install --quiet armadillo openblas catch2 libomp gsl cmake + brew install --quiet armadillo openblas catch2 libomp gsl cmake create-dmg - name: Set up Miniconda uses: conda-incubator/setup-miniconda@v3 @@ -214,7 +184,7 @@ jobs: shell: bash -l {0} run: | conda install -n "$CONDA_ENV" -q -y \ - -c conda-forge qgis=$QGIS_VER nomkl + -c conda-forge qgis=$QGIS_VER qtkeychain=0.14.1 nomkl conda list -n "$CONDA_ENV" -q - name: Clone libgwmodel @@ -227,6 +197,7 @@ jobs: cmake -S . -B build \ -DCMAKE_BUILD_TYPE=Release \ -DCMAKE_INSTALL_PREFIX="$CONDA_PREFIX" \ + -DENABLE_OpenMP=OFF \ -DWITH_TESTS=OFF cmake --build build --config Release --parallel cmake --install build @@ -241,31 +212,10 @@ jobs: curl -fsSL -o "$QGIS_INC/qgswebframe.h" \ "https://raw.githubusercontent.com/qgis/QGIS/$QGIS_HEADER_REF/src/core/qgswebframe.h" - - name: Configure (cmake) - shell: bash -l {0} - run: | - conda activate "$CONDA_ENV" - cmake -S . -B build \ - -DCMAKE_BUILD_TYPE=Release \ - -DCMAKE_PREFIX_PATH="$CONDA_PREFIX" \ - -DQGIS_PREFIX_PATH="$CONDA_PREFIX" - - - name: Build GWmodelS - shell: bash -l {0} - run: | - conda activate "$CONDA_ENV" - cmake --build build --config Release --target GWmodelS --parallel - - # Create a self-signed code-signing identity and sign the .app bundle so - # CPack (DMG) produces a package that macOS accepts. - # - # NOTE: the INSTALL rule for APPLE in src/CMakeLists.txt runs fixup_bundle - # during `cpack`/`cmake --install`, which rewrites dylib install names and - # invalidates this signature. A robust approach is to re-sign the .app - # inside the CPack staging tree (build/_CPack_Packages/*/DragNDrop/) after - # cpack and before DMG creation; for this draft the sign-before-pack keeps - # the flow simple and easy to iterate on. - - name: Sign GWmodelS.app (self-signed certificate) + # Create a self-signed code-signing identity. It is used by the manual + # `codesign` step that runs after Qt deployment and install_name_tool + # patches (both of which invalidate any prior signature). + - name: Create self-signed certificate shell: bash run: | KEYCHAIN="$RUNNER_TEMP/build.keychain" @@ -281,24 +231,65 @@ jobs: security import /tmp/dev.p12 -k "$KEYCHAIN" -P build -T /usr/bin/codesign IDENTITY=$(security find-identity -v -p codesigning "$KEYCHAIN" \ - | awk -F'[()]' '/GWmodelS/{print $2; exit}') - codesign --force --deep --sign "$IDENTITY" --keychain "$KEYCHAIN" build/GWmodelS.app + | awk -F'"' '/GWmodelS/{print $2; exit}') + echo "CODESIGN_IDENTITY=$IDENTITY" >> "$GITHUB_ENV" + echo "CODESIGN_KEYCHAIN=$KEYCHAIN" >> "$GITHUB_ENV" - # CPack configuration is provided by the INSTALL/CPack section in - # src/CMakeLists.txt; reconfigure is a no-op and regenerates the - # CPackConfig.cmake before producing the DMG. - - name: Package with CPack + - name: Configure (cmake) shell: bash -l {0} run: | - conda activate "$CONDA_ENV" + QGIS_INC="$CONDA_PREFIX/include/qgis" cmake -S . -B build \ + -DENABLE_OpenMP=OFF \ -DCMAKE_BUILD_TYPE=Release \ -DCMAKE_PREFIX_PATH="$(brew --prefix);$CONDA_PREFIX" \ + -DCMAKE_INSTALL_PREFIX="build/staged" \ -DQGIS_PREFIX_PATH="$CONDA_PREFIX" \ + -DQGIS_GUI_INCLUDE_DIR="$QGIS_INC" \ + -DQGIS_ANALYSIS_INCLUDE_DIR="$QGIS_INC" \ -DGSL_DIR="$(brew --prefix)/opt/gsl/lib/cmake/gsl" \ -DBLAS_LIBRARIES="$(brew --prefix)/lib/libopenblas.dylib" \ -DLAPACK_LIBRARIES="$(brew --prefix)/lib/libopenblas.dylib" - cpack --config build/CPackConfig.cmake -G DragNDrop + + - name: Build GWmodelS + shell: bash -l {0} + run: | + cmake --build build --config Release --target GWmodelS --parallel + cmake --install build --config Release + + # Fix libpdalcpp's dependency on libpdal_util: rewrite its install name + # and set the id on the patched libpdal_util.15.dylib we copied earlier. + - name: Fix libpdalcpp install names + shell: bash + run: | + APP="build/staged/GWmodelS.app" + FW="$APP/Contents/Frameworks" + install_name_tool -change @rpath/libpdal_util.15.dylib @executable_path/../Frameworks/libpdal_util.15.dylib "$FW/libpdalcpp.15.dylib" + install_name_tool -id @executable_path/../libpdal_util.15.dylib "$FW/libpdal_util.15.dylib" + + # Deploy Qt runtime into the bundle (macdeployqt ships with the conda Qt). + - name: Deploy Qt + shell: bash -l {0} + run: | + conda activate "$CONDA_ENV" + macdeployqt "build/staged/GWmodelS.app" + + # Sign the fully-assembled bundle. + - name: Sign GWmodelS.app (self-signed certificate) + shell: bash + run: | + codesign --force --deep --sign "$CODESIGN_IDENTITY" --keychain "$CODESIGN_KEYCHAIN" "build/staged/GWmodelS.app" + + # Package into a DMG with create-dmg (no longer via CPack). + - name: Package with create-dmg + shell: bash + run: | + cd build/staged + create-dmg --volname "GWmodelS" \ + --window-pos 200 120 --window-size 800 400 \ + --icon-size 100 --icon GWmodelS.app 200 190 \ + --hide-extension GWmodelS.app --app-drop-link 600 185 \ + GWmodelS.dmg GWmodelS.app - name: Upload package uses: actions/upload-artifact@v4 diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 5f2fb45..e1fa509 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -320,6 +320,27 @@ install(CODE "set(DIRS ${QGIS_PREFIX_PATH}/lib)" COMPONENT Runtime) install(CODE [===[ include(BundleUtilities) fixup_bundle("${APPS}" "" "") + # Patch: conda ships libpdal_util as a symlink/hardlink, so fixup_bundle may + # not bundle the real library. Copy the actual libpdal_util.15.*.*.dylib + # (a regular, non-hardlinked file) into the bundle as libpdal_util.15.dylib. + if(DEFINED ENV{CONDA_PREFIX}) + file(GLOB _pdal_candidates "$ENV{CONDA_PREFIX}/lib/libpdal_util.15.*.*.dylib") + set(_pdal_real "") + foreach(_c IN LISTS _pdal_candidates) + execute_process(COMMAND stat -f %l "${_c}" OUTPUT_VARIABLE _pdal_links OUTPUT_STRIP_TRAILING_WHITESPACE) + if(_pdal_links STREQUAL "1") + set(_pdal_real "${_c}") + break() + endif() + endforeach() + if(NOT _pdal_real AND _pdal_candidates) + list(GET _pdal_candidates 0 _pdal_real) + endif() + if(_pdal_real) + file(MAKE_DIRECTORY "${APPS}/Contents/Frameworks") + file(COPY_FILE "${_pdal_real}" "${APPS}/Contents/Frameworks/libpdal_util.15.dylib") + endif() + endif() ]===] COMPONENT Runtime) # install(RUNTIME_DEPENDENCY_SET _dep_mac DESTINATION "./${CMAKE_PROJECT_NAME}.app/Contents/Frameworks" POST_EXCLUDE_REGEXES ".*homebrew.*") # get_target_property(uic_location Qt5::uic IMPORTED_LOCATION) From 90c359a19b6935cf87fc169fad41183bd28ae6a2 Mon Sep 17 00:00:00 2001 From: HPDell Date: Tue, 18 Aug 2026 18:05:18 +0800 Subject: [PATCH 24/42] fix: macos icon resource --- src/CMakeLists.txt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index e1fa509..e35729c 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -242,7 +242,11 @@ endif(WIN32) if(UNIX AND NOT CYGWIN) if(APPLE) add_executable(GWmodelS MACOSX_BUNDLE ${SOURCES} ${HEADERS} ${FORMS_H} ${app_MACICON} ${GWMODEL_ICONS}) - set_target_properties(GWmodelS PROPERTIES FRAMEWORK TRUE MACOSX_BUNDLE_INFO_PLIST ${CMAKE_SOURCE_DIR}/macOS/Info.plist.in) + set_target_properties(GWmodelS PROPERTIES + MACOSX_BUNDLE TRUE + MACOSX_BUNDLE_INFO_PLIST ${CMAKE_SOURCE_DIR}/macOS/Info.plist.in + RESOURCE "${app_MACICON}" + ) else(APPLE) set(CMAKE_CXX_LINK_FLAGS "${CMAKE_CXX_LINK_FLAGS} -no-pie") add_executable(GWmodelS ${SOURCES} ${HEADERS} ${FORMS_H} ${app_WINRC} ${GWMODEL_ICONS}) From 751c5754fcaf1a66d05b66945a51e332194a23a1 Mon Sep 17 00:00:00 2001 From: HPDell Date: Tue, 18 Aug 2026 18:23:07 +0800 Subject: [PATCH 25/42] fix: dont specify vs version on windows and disable parallel compile --- .github/workflows/ci.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2cf4615..955f3a7 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -83,7 +83,7 @@ jobs: -DCMAKE_INSTALL_PREFIX="$env:CONDA_PREFIX\Library" ` -DCMAKE_PREFIX_PATH="$env:CONDA_PREFIX\Library" ` -DWITH_TESTS=OFF - cmake --build build --config Release --parallel + cmake --build build --config Release cmake --install build --config Release working-directory: ${{ github.workspace }}/libgwmodel @@ -107,7 +107,7 @@ jobs: $env:PATH = "$env:CONDA_PREFIX\Library\bin;$env:PATH" $env:LIB_DIR = "$env:CONDA_PREFIX\Library" $env:INCLUDE = "$env:CONDA_PREFIX\Library\include;$env:INCLUDE" - cmake -S . -B build -G "Visual Studio 17 2022" -A x64 ` + cmake -S . -B build ` -DCMAKE_PREFIX_PATH="$env:CONDA_PREFIX\Library" ` -DCMAKE_BUILD_TYPE=Release ` -DCMAKE_INSTALL_PREFIX="build\staged" ` @@ -117,7 +117,7 @@ jobs: shell: pwsh run: | $env:PATH = "$env:CONDA_PREFIX\Library\bin;$env:PATH" - cmake --build build --config Release --target GWmodelS --parallel + cmake --build build --config Release --target GWmodelS # CPack configuration is provided by the INSTALL/CPack section in # src/CMakeLists.txt; reconfigure is a no-op and regenerates the @@ -199,7 +199,7 @@ jobs: -DCMAKE_INSTALL_PREFIX="$CONDA_PREFIX" \ -DENABLE_OpenMP=OFF \ -DWITH_TESTS=OFF - cmake --build build --config Release --parallel + cmake --build build --config Release cmake --install build working-directory: ${{ github.workspace }}/libgwmodel @@ -254,7 +254,7 @@ jobs: - name: Build GWmodelS shell: bash -l {0} run: | - cmake --build build --config Release --target GWmodelS --parallel + cmake --build build --config Release --target GWmodelS cmake --install build --config Release # Fix libpdalcpp's dependency on libpdal_util: rewrite its install name From b2b44a0dacc41ff82828352c6c82a33bca28a3dd Mon Sep 17 00:00:00 2001 From: HPDell Date: Tue, 18 Aug 2026 18:49:18 +0800 Subject: [PATCH 26/42] fix: macos GWmodel cmake prefix --- .github/workflows/ci.yml | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 955f3a7..d776135 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -242,14 +242,11 @@ jobs: cmake -S . -B build \ -DENABLE_OpenMP=OFF \ -DCMAKE_BUILD_TYPE=Release \ - -DCMAKE_PREFIX_PATH="$(brew --prefix);$CONDA_PREFIX" \ + -DCMAKE_PREFIX_PATH="$CONDA_PREFIX:$(brew --prefix)" \ -DCMAKE_INSTALL_PREFIX="build/staged" \ -DQGIS_PREFIX_PATH="$CONDA_PREFIX" \ -DQGIS_GUI_INCLUDE_DIR="$QGIS_INC" \ - -DQGIS_ANALYSIS_INCLUDE_DIR="$QGIS_INC" \ - -DGSL_DIR="$(brew --prefix)/opt/gsl/lib/cmake/gsl" \ - -DBLAS_LIBRARIES="$(brew --prefix)/lib/libopenblas.dylib" \ - -DLAPACK_LIBRARIES="$(brew --prefix)/lib/libopenblas.dylib" + -DQGIS_ANALYSIS_INCLUDE_DIR="$QGIS_INC" - name: Build GWmodelS shell: bash -l {0} From 088d822fd93dab2b5301da7e585a27813228e637 Mon Sep 17 00:00:00 2001 From: HPDell Date: Tue, 18 Aug 2026 18:58:18 +0800 Subject: [PATCH 27/42] fix: cmake prefix path on macos --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d776135..1d6e2a2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -242,7 +242,7 @@ jobs: cmake -S . -B build \ -DENABLE_OpenMP=OFF \ -DCMAKE_BUILD_TYPE=Release \ - -DCMAKE_PREFIX_PATH="$CONDA_PREFIX:$(brew --prefix)" \ + -DCMAKE_PREFIX_PATH="$CONDA_PREFIX;$(brew --prefix)" \ -DCMAKE_INSTALL_PREFIX="build/staged" \ -DQGIS_PREFIX_PATH="$CONDA_PREFIX" \ -DQGIS_GUI_INCLUDE_DIR="$QGIS_INC" \ From 7541f65ade86f397e07fc73b6db49163f879e8fb Mon Sep 17 00:00:00 2001 From: HPDell Date: Tue, 18 Aug 2026 19:02:36 +0800 Subject: [PATCH 28/42] fix: libgwmodel cmake prefix path on macos --- .github/workflows/ci.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1d6e2a2..8fe3720 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -196,7 +196,6 @@ jobs: run: | cmake -S . -B build \ -DCMAKE_BUILD_TYPE=Release \ - -DCMAKE_INSTALL_PREFIX="$CONDA_PREFIX" \ -DENABLE_OpenMP=OFF \ -DWITH_TESTS=OFF cmake --build build --config Release From 1fe98d7d817d288b7d74ed09b8720bccc98f5607 Mon Sep 17 00:00:00 2001 From: HPDell Date: Tue, 18 Aug 2026 19:13:07 +0800 Subject: [PATCH 29/42] Revert "fix: libgwmodel cmake prefix path on macos" This reverts commit 7541f65ade86f397e07fc73b6db49163f879e8fb. --- .github/workflows/ci.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8fe3720..1d6e2a2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -196,6 +196,7 @@ jobs: run: | cmake -S . -B build \ -DCMAKE_BUILD_TYPE=Release \ + -DCMAKE_INSTALL_PREFIX="$CONDA_PREFIX" \ -DENABLE_OpenMP=OFF \ -DWITH_TESTS=OFF cmake --build build --config Release From d194d69b39bc40ffa187493fb2cd91ae5ce1e63a Mon Sep 17 00:00:00 2001 From: HPDell Date: Thu, 20 Aug 2026 10:12:35 +0800 Subject: [PATCH 30/42] edit: windows use 2022 --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1d6e2a2..356b5bb 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -39,7 +39,7 @@ jobs: # --------------------------------------------------------------------------- build-windows: name: Windows (x64) - runs-on: windows-latest + runs-on: windows-2022 steps: - name: Checkout source From b8d3f88694379df7357cc8d92904e681fbabda74 Mon Sep 17 00:00:00 2001 From: HPDell Date: Thu, 20 Aug 2026 11:16:42 +0800 Subject: [PATCH 31/42] fix: macos codesign --- .github/workflows/ci.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 356b5bb..5a26965 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -231,9 +231,10 @@ jobs: security import /tmp/dev.p12 -k "$KEYCHAIN" -P build -T /usr/bin/codesign IDENTITY=$(security find-identity -v -p codesigning "$KEYCHAIN" \ - | awk -F'"' '/GWmodelS/{print $2; exit}') + | awk '/GWmodelS/{print $2; exit}') echo "CODESIGN_IDENTITY=$IDENTITY" >> "$GITHUB_ENV" echo "CODESIGN_KEYCHAIN=$KEYCHAIN" >> "$GITHUB_ENV" + echo "CODESIGN_KEYCHAIN_PASSWORD=build" >> "$GITHUB_ENV" - name: Configure (cmake) shell: bash -l {0} @@ -275,6 +276,8 @@ jobs: - name: Sign GWmodelS.app (self-signed certificate) shell: bash run: | + security unlock-keychain -p "$CODESIGN_KEYCHAIN_PASSWORD" "$CODESIGN_KEYCHAIN" + security set-keychain-settings -t 3600 -u "$CODESIGN_KEYCHAIN" codesign --force --deep --sign "$CODESIGN_IDENTITY" --keychain "$CODESIGN_KEYCHAIN" "build/staged/GWmodelS.app" # Package into a DMG with create-dmg (no longer via CPack). From 8560b2be5622e30fc85d91f709ee376a43f37220 Mon Sep 17 00:00:00 2001 From: HPDell Date: Thu, 20 Aug 2026 11:34:01 +0800 Subject: [PATCH 32/42] edit: merge create self-signed certificate and codesign --- .github/workflows/ci.yml | 42 +++++++++++++++++----------------------- 1 file changed, 18 insertions(+), 24 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5a26965..592cadf 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -212,30 +212,6 @@ jobs: curl -fsSL -o "$QGIS_INC/qgswebframe.h" \ "https://raw.githubusercontent.com/qgis/QGIS/$QGIS_HEADER_REF/src/core/qgswebframe.h" - # Create a self-signed code-signing identity. It is used by the manual - # `codesign` step that runs after Qt deployment and install_name_tool - # patches (both of which invalidate any prior signature). - - name: Create self-signed certificate - shell: bash - run: | - KEYCHAIN="$RUNNER_TEMP/build.keychain" - security create-keychain -p build "$KEYCHAIN" - security default-keychain -s "$KEYCHAIN" - security unlock-keychain -p build "$KEYCHAIN" - security set-keychain-settings -t 3600 -u "$KEYCHAIN" - - openssl req -x509 -newkey rsa:2048 -keyout /tmp/dev.key -out /tmp/dev.crt \ - -days 365 -nodes -subj "/CN=GWmodelS CI" - openssl pkcs12 -export -out /tmp/dev.p12 \ - -inkey /tmp/dev.key -in /tmp/dev.crt -passout pass:build - security import /tmp/dev.p12 -k "$KEYCHAIN" -P build -T /usr/bin/codesign - - IDENTITY=$(security find-identity -v -p codesigning "$KEYCHAIN" \ - | awk '/GWmodelS/{print $2; exit}') - echo "CODESIGN_IDENTITY=$IDENTITY" >> "$GITHUB_ENV" - echo "CODESIGN_KEYCHAIN=$KEYCHAIN" >> "$GITHUB_ENV" - echo "CODESIGN_KEYCHAIN_PASSWORD=build" >> "$GITHUB_ENV" - - name: Configure (cmake) shell: bash -l {0} run: | @@ -276,6 +252,24 @@ jobs: - name: Sign GWmodelS.app (self-signed certificate) shell: bash run: | + KEYCHAIN="$RUNNER_TEMP/build.keychain" + security create-keychain -p build "$KEYCHAIN" + security default-keychain -s "$KEYCHAIN" + security unlock-keychain -p build "$KEYCHAIN" + security set-keychain-settings -t 3600 -u "$KEYCHAIN" + + openssl req -x509 -newkey rsa:2048 -keyout /tmp/dev.key -out /tmp/dev.crt \ + -days 365 -nodes -subj "/CN=GWmodelS CI" + openssl pkcs12 -export -out /tmp/dev.p12 \ + -inkey /tmp/dev.key -in /tmp/dev.crt -passout pass:build + security import /tmp/dev.p12 -k "$KEYCHAIN" -P build -T /usr/bin/codesign + + IDENTITY=$(security find-identity -v -p codesigning "$KEYCHAIN" \ + | awk '/GWmodelS/{print $2; exit}') + echo "CODESIGN_IDENTITY=$IDENTITY" >> "$GITHUB_ENV" + echo "CODESIGN_KEYCHAIN=$KEYCHAIN" >> "$GITHUB_ENV" + echo "CODESIGN_KEYCHAIN_PASSWORD=build" >> "$GITHUB_ENV" + security unlock-keychain -p "$CODESIGN_KEYCHAIN_PASSWORD" "$CODESIGN_KEYCHAIN" security set-keychain-settings -t 3600 -u "$CODESIGN_KEYCHAIN" codesign --force --deep --sign "$CODESIGN_IDENTITY" --keychain "$CODESIGN_KEYCHAIN" "build/staged/GWmodelS.app" From 434b5c5b9772dc54411c7983ee84a94e940c0551 Mon Sep 17 00:00:00 2001 From: HPDell Date: Thu, 20 Aug 2026 12:01:49 +0800 Subject: [PATCH 33/42] edit: remove certificate export --- .github/workflows/ci.yml | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 592cadf..d434e78 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -266,13 +266,7 @@ jobs: IDENTITY=$(security find-identity -v -p codesigning "$KEYCHAIN" \ | awk '/GWmodelS/{print $2; exit}') - echo "CODESIGN_IDENTITY=$IDENTITY" >> "$GITHUB_ENV" - echo "CODESIGN_KEYCHAIN=$KEYCHAIN" >> "$GITHUB_ENV" - echo "CODESIGN_KEYCHAIN_PASSWORD=build" >> "$GITHUB_ENV" - - security unlock-keychain -p "$CODESIGN_KEYCHAIN_PASSWORD" "$CODESIGN_KEYCHAIN" - security set-keychain-settings -t 3600 -u "$CODESIGN_KEYCHAIN" - codesign --force --deep --sign "$CODESIGN_IDENTITY" --keychain "$CODESIGN_KEYCHAIN" "build/staged/GWmodelS.app" + codesign --force --deep --sign "$IDENTITY" --keychain "$KEYCHAIN" "build/staged/GWmodelS.app" # Package into a DMG with create-dmg (no longer via CPack). - name: Package with create-dmg From e5f68706fc696fd20dc9b1095bed00980d21260b Mon Sep 17 00:00:00 2001 From: HPDell Date: Sun, 23 Aug 2026 16:28:34 +0800 Subject: [PATCH 34/42] edit: apple keychain set-key-partition-list --- .github/workflows/ci.yml | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d434e78..08634cf 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -264,8 +264,21 @@ jobs: -inkey /tmp/dev.key -in /tmp/dev.crt -passout pass:build security import /tmp/dev.p12 -k "$KEYCHAIN" -P build -T /usr/bin/codesign + # Authorize Apple tooling to access the imported private key; without + # this, codesign reports "The specified item could not be found in + # the keychain" because the key partition list blocks access. + security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k build "$KEYCHAIN" + security list-keychains -s "$KEYCHAIN" + security default-keychain -s "$KEYCHAIN" + IDENTITY=$(security find-identity -v -p codesigning "$KEYCHAIN" \ | awk '/GWmodelS/{print $2; exit}') + if [ -z "$IDENTITY" ]; then + echo "No codesigning identity found; dumping find-identity output:" >&2 + security find-identity -v -p codesigning "$KEYCHAIN" >&2 + exit 1 + fi + echo "Signing with identity: $IDENTITY" codesign --force --deep --sign "$IDENTITY" --keychain "$KEYCHAIN" "build/staged/GWmodelS.app" # Package into a DMG with create-dmg (no longer via CPack). From 5b381b2d800795bf4b07363e453f7aaa51a6c4f3 Mon Sep 17 00:00:00 2001 From: HPDell Date: Sun, 23 Aug 2026 16:49:44 +0800 Subject: [PATCH 35/42] fix: add code-signing EKU to self-signed certificate --- .github/workflows/ci.yml | 31 ++++++++++++++++++------------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 08634cf..99021f3 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -253,23 +253,28 @@ jobs: shell: bash run: | KEYCHAIN="$RUNNER_TEMP/build.keychain" - security create-keychain -p build "$KEYCHAIN" + KEYCHAIN_PW="build" + + security create-keychain -p "$KEYCHAIN_PW" "$KEYCHAIN" security default-keychain -s "$KEYCHAIN" - security unlock-keychain -p build "$KEYCHAIN" + security unlock-keychain -p "$KEYCHAIN_PW" "$KEYCHAIN" security set-keychain-settings -t 3600 -u "$KEYCHAIN" - openssl req -x509 -newkey rsa:2048 -keyout /tmp/dev.key -out /tmp/dev.crt \ - -days 365 -nodes -subj "/CN=GWmodelS CI" + # Generate a self-signed certificate with the code-signing extended + # key usage. Without it, `find-identity -p codesigning` reports + # "0 valid identities found" and codesign cannot locate the identity. + openssl req -x509 -nodes -newkey rsa:2048 \ + -keyout /tmp/dev.key -out /tmp/dev.crt \ + -days 365 -subj "/CN=GWmodelS CI" \ + -addext "keyUsage=digitalSignature" \ + -addext "extendedKeyUsage=codeSigning" openssl pkcs12 -export -out /tmp/dev.p12 \ - -inkey /tmp/dev.key -in /tmp/dev.crt -passout pass:build - security import /tmp/dev.p12 -k "$KEYCHAIN" -P build -T /usr/bin/codesign - - # Authorize Apple tooling to access the imported private key; without - # this, codesign reports "The specified item could not be found in - # the keychain" because the key partition list blocks access. - security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k build "$KEYCHAIN" - security list-keychains -s "$KEYCHAIN" - security default-keychain -s "$KEYCHAIN" + -inkey /tmp/dev.key -in /tmp/dev.crt -passout pass:"$KEYCHAIN_PW" + + security import /tmp/dev.p12 -k "$KEYCHAIN" -P "$KEYCHAIN_PW" -A + + # Authorize Apple tooling to access the imported private key. + security set-key-partition-list -S apple-tool:,apple: -s -k "$KEYCHAIN_PW" "$KEYCHAIN" IDENTITY=$(security find-identity -v -p codesigning "$KEYCHAIN" \ | awk '/GWmodelS/{print $2; exit}') From ff66e00d53fe8d93f713c56972f4ffce69bb3423 Mon Sep 17 00:00:00 2001 From: HPDell Date: Sun, 23 Aug 2026 17:18:34 +0800 Subject: [PATCH 36/42] edit: macos ci use ad-hoc sign --- .github/workflows/ci.yml | 39 ++++----------------------------------- 1 file changed, 4 insertions(+), 35 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 99021f3..16e5e1f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -11,7 +11,7 @@ # 3. Patch the missing qgswebframe.h header from the QGIS source tree # 4. Configure + build GWmodelS # 5. Package with CPack (INSTALL/CPack rules live in src/CMakeLists.txt) -# - macOS: sign the .app with a self-signed certificate before packaging +# - macOS: ad-hoc sign the .app before packaging # # NOTE: draft only, not yet pushed/validated. @@ -249,42 +249,11 @@ jobs: macdeployqt "build/staged/GWmodelS.app" # Sign the fully-assembled bundle. - - name: Sign GWmodelS.app (self-signed certificate) + - name: Sign GWmodelS.app (ad-hoc) shell: bash run: | - KEYCHAIN="$RUNNER_TEMP/build.keychain" - KEYCHAIN_PW="build" - - security create-keychain -p "$KEYCHAIN_PW" "$KEYCHAIN" - security default-keychain -s "$KEYCHAIN" - security unlock-keychain -p "$KEYCHAIN_PW" "$KEYCHAIN" - security set-keychain-settings -t 3600 -u "$KEYCHAIN" - - # Generate a self-signed certificate with the code-signing extended - # key usage. Without it, `find-identity -p codesigning` reports - # "0 valid identities found" and codesign cannot locate the identity. - openssl req -x509 -nodes -newkey rsa:2048 \ - -keyout /tmp/dev.key -out /tmp/dev.crt \ - -days 365 -subj "/CN=GWmodelS CI" \ - -addext "keyUsage=digitalSignature" \ - -addext "extendedKeyUsage=codeSigning" - openssl pkcs12 -export -out /tmp/dev.p12 \ - -inkey /tmp/dev.key -in /tmp/dev.crt -passout pass:"$KEYCHAIN_PW" - - security import /tmp/dev.p12 -k "$KEYCHAIN" -P "$KEYCHAIN_PW" -A - - # Authorize Apple tooling to access the imported private key. - security set-key-partition-list -S apple-tool:,apple: -s -k "$KEYCHAIN_PW" "$KEYCHAIN" - - IDENTITY=$(security find-identity -v -p codesigning "$KEYCHAIN" \ - | awk '/GWmodelS/{print $2; exit}') - if [ -z "$IDENTITY" ]; then - echo "No codesigning identity found; dumping find-identity output:" >&2 - security find-identity -v -p codesigning "$KEYCHAIN" >&2 - exit 1 - fi - echo "Signing with identity: $IDENTITY" - codesign --force --deep --sign "$IDENTITY" --keychain "$KEYCHAIN" "build/staged/GWmodelS.app" + codesign --force --deep --sign - "build/staged/GWmodelS.app" + codesign --verify --deep --strict --verbose=2 "build/staged/GWmodelS.app" # Package into a DMG with create-dmg (no longer via CPack). - name: Package with create-dmg From 693ae9beae9c541737ad37d40090a993926554e8 Mon Sep 17 00:00:00 2001 From: HPDell Date: Sun, 23 Aug 2026 18:10:56 +0800 Subject: [PATCH 37/42] edit: remove unnecessary conda activate --- .github/workflows/ci.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 16e5e1f..05d892c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -245,7 +245,6 @@ jobs: - name: Deploy Qt shell: bash -l {0} run: | - conda activate "$CONDA_ENV" macdeployqt "build/staged/GWmodelS.app" # Sign the fully-assembled bundle. From 3b1fdf88cd23a7a78a7a4803bb7785f444c44b80 Mon Sep 17 00:00:00 2001 From: HPDell Date: Sun, 23 Aug 2026 18:12:13 +0800 Subject: [PATCH 38/42] fix: macos package dir --- .github/workflows/ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 05d892c..5066413 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -258,16 +258,16 @@ jobs: - name: Package with create-dmg shell: bash run: | - cd build/staged create-dmg --volname "GWmodelS" \ --window-pos 200 120 --window-size 800 400 \ --icon-size 100 --icon GWmodelS.app 200 190 \ --hide-extension GWmodelS.app --app-drop-link 600 185 \ GWmodelS.dmg GWmodelS.app + working-directory: ${{ github.workspace }}/build/staged - name: Upload package uses: actions/upload-artifact@v4 with: name: GWmodelS-macOS-${{ matrix.arch }} - path: build/*.dmg + path: build/staged/*.dmg if-no-files-found: error From baaaa6ef77761a08b8dba33d71e4fdc2857e6884 Mon Sep 17 00:00:00 2001 From: HPDell Date: Sun, 23 Aug 2026 19:05:58 +0800 Subject: [PATCH 39/42] edit: use cpack to handle dependencies and codesign --- .github/workflows/ci.yml | 42 ++++--------------- src/CMakeLists.txt | 88 ++++++++++++++++++++++++++-------------- 2 files changed, 64 insertions(+), 66 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5066413..75afb12 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -163,7 +163,7 @@ jobs: - name: Install brew dependencies shell: bash run: | - brew install --quiet armadillo openblas catch2 libomp gsl cmake create-dmg + brew install --quiet armadillo openblas catch2 libomp gsl cmake - name: Set up Miniconda uses: conda-incubator/setup-miniconda@v3 @@ -220,7 +220,6 @@ jobs: -DENABLE_OpenMP=OFF \ -DCMAKE_BUILD_TYPE=Release \ -DCMAKE_PREFIX_PATH="$CONDA_PREFIX;$(brew --prefix)" \ - -DCMAKE_INSTALL_PREFIX="build/staged" \ -DQGIS_PREFIX_PATH="$CONDA_PREFIX" \ -DQGIS_GUI_INCLUDE_DIR="$QGIS_INC" \ -DQGIS_ANALYSIS_INCLUDE_DIR="$QGIS_INC" @@ -229,45 +228,18 @@ jobs: shell: bash -l {0} run: | cmake --build build --config Release --target GWmodelS - cmake --install build --config Release - - # Fix libpdalcpp's dependency on libpdal_util: rewrite its install name - # and set the id on the patched libpdal_util.15.dylib we copied earlier. - - name: Fix libpdalcpp install names - shell: bash - run: | - APP="build/staged/GWmodelS.app" - FW="$APP/Contents/Frameworks" - install_name_tool -change @rpath/libpdal_util.15.dylib @executable_path/../Frameworks/libpdal_util.15.dylib "$FW/libpdalcpp.15.dylib" - install_name_tool -id @executable_path/../libpdal_util.15.dylib "$FW/libpdal_util.15.dylib" - # Deploy Qt runtime into the bundle (macdeployqt ships with the conda Qt). - - name: Deploy Qt + # CPack runs the complete install pipeline: deploy Qt, collect and fix + # runtime dependencies, ad-hoc sign the app, then create the DMG. + - name: Package with CPack shell: bash -l {0} run: | - macdeployqt "build/staged/GWmodelS.app" - - # Sign the fully-assembled bundle. - - name: Sign GWmodelS.app (ad-hoc) - shell: bash - run: | - codesign --force --deep --sign - "build/staged/GWmodelS.app" - codesign --verify --deep --strict --verbose=2 "build/staged/GWmodelS.app" - - # Package into a DMG with create-dmg (no longer via CPack). - - name: Package with create-dmg - shell: bash - run: | - create-dmg --volname "GWmodelS" \ - --window-pos 200 120 --window-size 800 400 \ - --icon-size 100 --icon GWmodelS.app 200 190 \ - --hide-extension GWmodelS.app --app-drop-link 600 185 \ - GWmodelS.dmg GWmodelS.app - working-directory: ${{ github.workspace }}/build/staged + cpack --config CPackConfig.cmake -C Release -G DragNDrop + working-directory: ${{ github.workspace }}/build - name: Upload package uses: actions/upload-artifact@v4 with: name: GWmodelS-macOS-${{ matrix.arch }} - path: build/staged/*.dmg + path: build/*.dmg if-no-files-found: error diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index e35729c..1f3e215 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -310,7 +310,6 @@ install(DIRECTORY "${qgis_dir}/resources" DESTINATION .) install(DIRECTORY "${qgis_dir}/share/proj" DESTINATION "./${DATADIR}") elseif(APPLE) install(TARGETS GWmodelS - # RUNTIME_DEPENDENCY_SET _dep_mac DESTINATION . BUNDLE DESTINATION . RESOURCE DESTINATION "./${CMAKE_PROJECT_NAME}.app/Contents/Resources" @@ -319,41 +318,62 @@ get_filename_component(qgis_dir ${QGIS_UI_INCLUDE_DIR} DIRECTORY) get_filename_component(qgis_dir ${qgis_dir} DIRECTORY) install(DIRECTORY "${qgis_dir}/share/proj" DESTINATION "./${CMAKE_PROJECT_NAME}.app/Contents/Resources") install(DIRECTORY "${qgis_dir}/share/qgis/resources" DESTINATION "./${CMAKE_PROJECT_NAME}.app/Contents/Resources") -install(CODE "set(APPS ${CMAKE_INSTALL_PREFIX}/${PROJECT_NAME}.app)" COMPONENT Runtime) -install(CODE "set(DIRS ${QGIS_PREFIX_PATH}/lib)" COMPONENT Runtime) + +# Locate the deployment tool from the same Qt installation used to build the +# application. The complete bundle is assembled by the install step, so both +# `cmake --install` and CPack follow exactly the same deployment path. +get_target_property(qmake_location Qt5::qmake IMPORTED_LOCATION) +get_filename_component(qt_bin_dir "${qmake_location}" DIRECTORY) +find_program(MACDEPLOYQT_EXECUTABLE + NAMES macdeployqt + HINTS "${qt_bin_dir}" "${QGIS_PREFIX_PATH}/bin" + NO_DEFAULT_PATH +) +if(NOT MACDEPLOYQT_EXECUTABLE) + message(FATAL_ERROR "macdeployqt was not found next to the Qt installation") +endif() + +install(CODE "set(APP_BUNDLE \"\${CMAKE_INSTALL_PREFIX}/${PROJECT_NAME}.app\")" COMPONENT Runtime) +install(CODE "set(MACDEPLOYQT_EXECUTABLE \"${MACDEPLOYQT_EXECUTABLE}\")" COMPONENT Runtime) +install(CODE "set(QGIS_LIBRARY_DIR \"${QGIS_PREFIX_PATH}/lib\")" COMPONENT Runtime) install(CODE [===[ + execute_process( + COMMAND "${MACDEPLOYQT_EXECUTABLE}" "${APP_BUNDLE}" -always-overwrite + RESULT_VARIABLE _macdeployqt_result + ) + if(NOT _macdeployqt_result EQUAL 0) + message(FATAL_ERROR "macdeployqt failed with exit code ${_macdeployqt_result}") + endif() + include(BundleUtilities) - fixup_bundle("${APPS}" "" "") - # Patch: conda ships libpdal_util as a symlink/hardlink, so fixup_bundle may - # not bundle the real library. Copy the actual libpdal_util.15.*.*.dylib - # (a regular, non-hardlinked file) into the bundle as libpdal_util.15.dylib. + + # In particular, this search path lets BundleUtilities resolve conda + # libraries referenced through @rpath, including PDAL's libpdal_util. + set(_bundle_search_dirs "${QGIS_LIBRARY_DIR}") if(DEFINED ENV{CONDA_PREFIX}) - file(GLOB _pdal_candidates "$ENV{CONDA_PREFIX}/lib/libpdal_util.15.*.*.dylib") - set(_pdal_real "") - foreach(_c IN LISTS _pdal_candidates) - execute_process(COMMAND stat -f %l "${_c}" OUTPUT_VARIABLE _pdal_links OUTPUT_STRIP_TRAILING_WHITESPACE) - if(_pdal_links STREQUAL "1") - set(_pdal_real "${_c}") - break() - endif() - endforeach() - if(NOT _pdal_real AND _pdal_candidates) - list(GET _pdal_candidates 0 _pdal_real) - endif() - if(_pdal_real) - file(MAKE_DIRECTORY "${APPS}/Contents/Frameworks") - file(COPY_FILE "${_pdal_real}" "${APPS}/Contents/Frameworks/libpdal_util.15.dylib") - endif() + list(APPEND _bundle_search_dirs "$ENV{CONDA_PREFIX}/lib") + endif() + + fixup_bundle("${APP_BUNDLE}" "" "${_bundle_search_dirs}") + + # BundleUtilities and macdeployqt modify Mach-O files, so signing must be + # the final operation performed on the assembled application. + execute_process( + COMMAND codesign --force --deep --sign - "${APP_BUNDLE}" + RESULT_VARIABLE _codesign_result + ) + if(NOT _codesign_result EQUAL 0) + message(FATAL_ERROR "ad-hoc codesign failed with exit code ${_codesign_result}") + endif() + + execute_process( + COMMAND codesign --verify --deep --strict --verbose=2 "${APP_BUNDLE}" + RESULT_VARIABLE _codesign_verify_result + ) + if(NOT _codesign_verify_result EQUAL 0) + message(FATAL_ERROR "codesign verification failed with exit code ${_codesign_verify_result}") endif() ]===] COMPONENT Runtime) -# install(RUNTIME_DEPENDENCY_SET _dep_mac DESTINATION "./${CMAKE_PROJECT_NAME}.app/Contents/Frameworks" POST_EXCLUDE_REGEXES ".*homebrew.*") -# get_target_property(uic_location Qt5::uic IMPORTED_LOCATION) -# get_filename_component( _dir ${uic_location} DIRECTORY) -# set(deployqt "${_dir}/macdeployqt") -# install(CODE "set(deployqt \"${deployqt}\")" COMPONENT Runtime) -# install(CODE [===[ -# execute_process(COMMAND "${deployqt}" "${CMAKE_INSTALL_PREFIX}/GWmodelS.app") -# ]===] COMPONENT Runtime) endif() # CPack @@ -364,4 +384,10 @@ set(CPACK_NSIS_MUI_ICON "${CMAKE_SOURCE_DIR}/icons/GWmodelS.ico") set(CPACK_PACKAGE_INSTALL_DIRECTORY ${CMAKE_PROJECT_NAME}) set(CPACK_PACKAGE_EXECUTABLES "GWmodelS;GWmodelS") set(CPACK_NSIS_EXECUTABLES_DIRECTORY ".") +if(APPLE) + set(CPACK_GENERATOR "DragNDrop") + set(CPACK_DMG_VOLUME_NAME "GWmodelS") + set(CPACK_DMG_FORMAT "UDZO") + set(CPACK_PACKAGE_FILE_NAME "${CMAKE_PROJECT_NAME}-${CMAKE_PROJECT_VERSION}-macOS") +endif() include(CPack) From bf791ce79de99519ed7f0a1eb474264d525751eb Mon Sep 17 00:00:00 2001 From: HPDell Date: Sun, 23 Aug 2026 19:18:32 +0800 Subject: [PATCH 40/42] fix: include macOS bundle in CPack runtime component --- src/CMakeLists.txt | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 1f3e215..3ea3202 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -310,14 +310,19 @@ install(DIRECTORY "${qgis_dir}/resources" DESTINATION .) install(DIRECTORY "${qgis_dir}/share/proj" DESTINATION "./${DATADIR}") elseif(APPLE) install(TARGETS GWmodelS - DESTINATION . - BUNDLE DESTINATION . - RESOURCE DESTINATION "./${CMAKE_PROJECT_NAME}.app/Contents/Resources" + BUNDLE DESTINATION . COMPONENT Runtime + RESOURCE DESTINATION "./${CMAKE_PROJECT_NAME}.app/Contents/Resources" COMPONENT Runtime ) get_filename_component(qgis_dir ${QGIS_UI_INCLUDE_DIR} DIRECTORY) get_filename_component(qgis_dir ${qgis_dir} DIRECTORY) -install(DIRECTORY "${qgis_dir}/share/proj" DESTINATION "./${CMAKE_PROJECT_NAME}.app/Contents/Resources") -install(DIRECTORY "${qgis_dir}/share/qgis/resources" DESTINATION "./${CMAKE_PROJECT_NAME}.app/Contents/Resources") +install(DIRECTORY "${qgis_dir}/share/proj" + DESTINATION "./${CMAKE_PROJECT_NAME}.app/Contents/Resources" + COMPONENT Runtime +) +install(DIRECTORY "${qgis_dir}/share/qgis/resources" + DESTINATION "./${CMAKE_PROJECT_NAME}.app/Contents/Resources" + COMPONENT Runtime +) # Locate the deployment tool from the same Qt installation used to build the # application. The complete bundle is assembled by the install step, so both From c5eaa2b6e484d91d5a9920fa6933105cbc37a485 Mon Sep 17 00:00:00 2001 From: HPDell Date: Mon, 24 Aug 2026 09:54:31 +0800 Subject: [PATCH 41/42] add: release process --- .github/workflows/ci.yml | 103 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 98 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 75afb12..4c92a8f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -13,16 +13,18 @@ # 5. Package with CPack (INSTALL/CPack rules live in src/CMakeLists.txt) # - macOS: ad-hoc sign the .app before packaging # -# NOTE: draft only, not yet pushed/validated. - name: CI on: push: - branches: [master, 'feat/**', 'enhance/**'] - tags: ['v*'] + branches: + - master + - 'ci/*' + tags: + - '**' pull_request: - workflow_dispatch: + branches: + - master permissions: contents: read @@ -237,9 +239,100 @@ jobs: cpack --config CPackConfig.cmake -C Release -G DragNDrop working-directory: ${{ github.workspace }}/build + # Both matrix jobs produce the same CPack base name. Add the architecture + # so both DMGs can coexist as assets on the same GitHub Release. + - name: Add architecture to package filename + shell: bash + run: | + for package in build/*.dmg; do + mv "$package" "${package%.dmg}-${{ matrix.arch }}.dmg" + done + - name: Upload package uses: actions/upload-artifact@v4 with: name: GWmodelS-macOS-${{ matrix.arch }} path: build/*.dmg if-no-files-found: error + + # --------------------------------------------------------------------------- + # GitHub Release (tag pushes only) + # --------------------------------------------------------------------------- + release: + name: Publish GitHub Release + if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/') + needs: + - build-windows + - build-macos + runs-on: ubuntu-latest + permissions: + contents: write + + steps: + - name: Download installation packages + uses: actions/download-artifact@v4 + with: + pattern: GWmodelS-* + path: release-assets + merge-multiple: true + + - name: Locate installation packages + id: packages + shell: bash + run: | + windows_path=$(find release-assets -maxdepth 1 -type f -name '*.exe' -print -quit) + macos_x64_path=$(find release-assets -maxdepth 1 -type f -name '*-x64.dmg' -print -quit) + macos_arm64_path=$(find release-assets -maxdepth 1 -type f -name '*-arm64.dmg' -print -quit) + + test -n "$windows_path" + test -n "$macos_x64_path" + test -n "$macos_arm64_path" + + echo "windows_path=$windows_path" >> "$GITHUB_OUTPUT" + echo "windows_name=$(basename "$windows_path")" >> "$GITHUB_OUTPUT" + echo "macos_x64_path=$macos_x64_path" >> "$GITHUB_OUTPUT" + echo "macos_x64_name=$(basename "$macos_x64_path")" >> "$GITHUB_OUTPUT" + echo "macos_arm64_path=$macos_arm64_path" >> "$GITHUB_OUTPUT" + echo "macos_arm64_name=$(basename "$macos_arm64_path")" >> "$GITHUB_OUTPUT" + + - name: Create GitHub Release + id: create_release + uses: actions/create-release@v1 + env: + GITHUB_TOKEN: ${{ github.token }} + with: + tag_name: ${{ github.ref_name }} + release_name: GWmodelS ${{ github.ref_name }} + body: Automated installation packages for GWmodelS ${{ github.ref_name }}. + draft: false + prerelease: false + + - name: Upload Windows x64 package + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ github.token }} + with: + upload_url: ${{ steps.create_release.outputs.upload_url }} + asset_path: ${{ steps.packages.outputs.windows_path }} + asset_name: ${{ steps.packages.outputs.windows_name }} + asset_content_type: application/vnd.microsoft.portable-executable + + - name: Upload macOS x64 package + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ github.token }} + with: + upload_url: ${{ steps.create_release.outputs.upload_url }} + asset_path: ${{ steps.packages.outputs.macos_x64_path }} + asset_name: ${{ steps.packages.outputs.macos_x64_name }} + asset_content_type: application/x-apple-diskimage + + - name: Upload macOS arm64 package + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ github.token }} + with: + upload_url: ${{ steps.create_release.outputs.upload_url }} + asset_path: ${{ steps.packages.outputs.macos_arm64_path }} + asset_name: ${{ steps.packages.outputs.macos_arm64_name }} + asset_content_type: application/x-apple-diskimage From bf712e07670a7264f317e4c02ec6f174bbeeecc1 Mon Sep 17 00:00:00 2001 From: HPDell Date: Mon, 24 Aug 2026 09:57:29 +0800 Subject: [PATCH 42/42] edit: trigger on feat/ci --- .github/workflows/ci.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4c92a8f..d1dc8f3 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -19,6 +19,7 @@ on: push: branches: - master + - feat/ci - 'ci/*' tags: - '**'