From 578a77ce1aa1faa88ae3a9396ebccad3189fa215 Mon Sep 17 00:00:00 2001 From: Ludovic Henry Date: Fri, 25 Sep 2026 15:13:35 +0000 Subject: [PATCH 1/2] pycolmap: Add version 4.1.1 Upstream builds its Linux wheels in manylinux_2_28 with vcpkg supplying Ceres, SuiteSparse, METIS, glog, OpenImageIO (with OpenColorIO) and GLEW, and builds COLMAP itself in cibuildwheel's before-all. vcpkg has no riscv64 binary cache and Rocky 10 packages none of those libraries, so a first job builds them from the versions upstream's vcpkg baseline pins (cached across runs) and COLMAP with upstream's CMake flags; the per-interpreter jobs build only the pybind11 bindings against that SDK. clang-format==22.1.1 is dropped from the build requirements: nothing in the wheel build runs it and it has no riscv64 wheel. --- .github/workflows/build-pycolmap.yml | 400 ++++++++++++++++++ docs/packages/pycolmap.yaml | 6 + ...nused-clang-format-build-requirement.patch | 30 ++ 3 files changed, 436 insertions(+) create mode 100644 .github/workflows/build-pycolmap.yml create mode 100644 docs/packages/pycolmap.yaml create mode 100644 patches/pycolmap/4.1.1/0001-build-drop-the-unused-clang-format-build-requirement.patch diff --git a/.github/workflows/build-pycolmap.yml b/.github/workflows/build-pycolmap.yml new file mode 100644 index 00000000000..83a7f029851 --- /dev/null +++ b/.github/workflows/build-pycolmap.yml @@ -0,0 +1,400 @@ +# SPDX-FileCopyrightText: 2026 The RISE Project +# SPDX-License-Identifier: MIT +--- +# This workflow is based on: https://github.com/colmap/colmap/blob/4.1.1/.github/workflows/build-pycolmap.yml +# Upstream installs COLMAP's dependencies with vcpkg and builds COLMAP itself in +# python/ci/install-colmap-almalinux.sh (cibuildwheel's before-all). vcpkg has no +# riscv64 binary cache, so the libraries Rocky 10 does not package are built here +# from the versions upstream's vcpkg baseline pins, COLMAP is built once with +# upstream's CMake flags, and the per-interpreter wheel jobs build only the bindings. +name: Build pycolmap wheels (riscv64) + +on: + workflow_dispatch: + inputs: + version: + description: 'Version glob to (re)build; empty builds every version of docs/packages/pycolmap.yaml not released yet' + required: false + default: '' + pull_request: + branches: [main] + paths: + - '.github/workflows/build-pycolmap.yml' + - 'docs/packages/pycolmap.yaml' + - 'patches/pycolmap/**' + push: + branches: [main] + paths: + - '.github/workflows/build-pycolmap.yml' + - 'docs/packages/pycolmap.yaml' + - 'patches/pycolmap/**' + +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} + cancel-in-progress: true + +permissions: + contents: read # to fetch code (actions/checkout) + +env: + MANYLINUX_RISCV64_IMAGE: quay.io/pypa/manylinux_2_39_riscv64 + DNF_PACKAGES: >- + ninja-build eigen3-devel boost-devel sqlite-devel openblas-devel + libcurl-devel openssl-devel mesa-libGL-devel libX11-devel + libtiff-devel libjpeg-turbo-devel libpng-devel openexr-devel imath-devel + expat-devel zlib-ng-compat-devel + GLOG_VERSION: 0.7.1 + METIS_VERSION: 5.1.0 + METIS_SHA256: 76faebe03f6c963127dbb73c13eab58c9a3faeae48779f049066a21c087c5db2 + GLEW_VERSION: 2.3.1 + GLEW_SHA256: b64790f94b926acd7e8f84c5d6000a86cb43967bd1e688b03089079799c9e889 + SUITESPARSE_VERSION: 7.12.2 + CERES_VERSION: 2.2.0 + OIIO_VERSION: 3.1.14.0 + +jobs: + setup: + uses: $/.github/workflows/_setup.yml + with: + package: pycolmap + version: ${{ inputs.version }} + + colmap: + needs: [setup] + if: needs.setup.outputs.versions != '[]' + name: Build COLMAP ${{ matrix.version }} manylinux_riscv64 + runs-on: ubuntu-24.04-riscv + timeout-minutes: 2880 + strategy: + fail-fast: false + matrix: + version: ${{ fromJSON(needs.setup.outputs.versions) }} + + env: + PYCOLMAP_VERSION: ${{ matrix.version }} + + steps: + - name: Checkout COLMAP ${{ env.PYCOLMAP_VERSION }} + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + repository: colmap/colmap + ref: ${{ env.PYCOLMAP_VERSION }} + path: colmap + persist-credentials: false + + - name: Restore the COLMAP dependencies + id: deps + uses: actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 + with: + path: sdk + key: pycolmap-deps-manylinux_riscv64-glog${{ env.GLOG_VERSION }}-metis${{ env.METIS_VERSION }}-glew${{ env.GLEW_VERSION }}-suitesparse${{ env.SUITESPARSE_VERSION }}-ceres${{ env.CERES_VERSION }}-oiio${{ env.OIIO_VERSION }} + + - name: Build the COLMAP dependencies + if: steps.deps.outputs.cache-hit != 'true' + run: | + mkdir -p sdk + docker run --rm -i --network=host \ + -v "${GITHUB_WORKSPACE}/sdk:/opt/colmap" \ + -e DNF_PACKAGES \ + -e GLOG_VERSION -e METIS_VERSION -e METIS_SHA256 -e GLEW_VERSION -e GLEW_SHA256 \ + -e SUITESPARSE_VERSION -e CERES_VERSION -e OIIO_VERSION \ + "${MANYLINUX_RISCV64_IMAGE}" \ + bash <<'SCRIPT' + set -eux + + dnf install -y --setopt=install_weak_deps=False ${DNF_PACKAGES} + + # METIS 5.1.0, GLEW and yaml-cpp declare a cmake_minimum_required CMake 4 rejects. + export CMAKE_POLICY_VERSION_MINIMUM=3.5 + common=(-GNinja -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/opt/colmap + -DCMAKE_INSTALL_LIBDIR=lib -DCMAKE_PREFIX_PATH=/opt/colmap -DBLA_VENDOR=OpenBLAS) + licenses=/opt/colmap/share/licenses + mkdir -p "${licenses}" + cd /tmp + + git clone --depth 1 --branch "v${GLOG_VERSION}" https://github.com/google/glog + cmake -S glog -B glog/build "${common[@]}" \ + -DBUILD_SHARED_LIBS=ON -DBUILD_TESTING=OFF -DWITH_GFLAGS=OFF -DWITH_GTEST=OFF + cmake --build glog/build --target install --parallel "$(nproc)" + cp glog/COPYING "${licenses}/glog-COPYING" + + curl -fsSLo metis.tar.gz "https://karypis.github.io/glaros/files/sw/metis/metis-${METIS_VERSION}.tar.gz" + echo "${METIS_SHA256} metis.tar.gz" | sha256sum -c - + tar xzf metis.tar.gz + make -C "metis-${METIS_VERSION}" config shared=1 prefix=/opt/colmap + make -C "metis-${METIS_VERSION}" install -j "$(nproc)" + cp "metis-${METIS_VERSION}/LICENSE.txt" "${licenses}/METIS-LICENSE.txt" + + # Only configure-time: COLMAP's FindDependencies requires GLEW even with the GUI off. + curl -fsSLo glew.tgz "https://github.com/nigels-com/glew/releases/download/glew-${GLEW_VERSION}/glew-${GLEW_VERSION}.tgz" + echo "${GLEW_SHA256} glew.tgz" | sha256sum -c - + tar xzf glew.tgz + cmake -S "glew-${GLEW_VERSION}/build/cmake" -B glew-build "${common[@]}" -DBUILD_UTILS=OFF + cmake --build glew-build --target install --parallel "$(nproc)" + + # upstream's vcpkg ceres[suitesparse] pulls CHOLMOD's GPL modules and SPQR in. + git clone --depth 1 --branch "v${SUITESPARSE_VERSION}" https://github.com/DrTimothyAldenDavis/SuiteSparse + cmake -S SuiteSparse -B SuiteSparse/build "${common[@]}" \ + -DSUITESPARSE_ENABLE_PROJECTS="suitesparse_config;amd;camd;colamd;ccolamd;cholmod;spqr" \ + -DBUILD_STATIC_LIBS=OFF -DBUILD_TESTING=OFF -DSUITESPARSE_DEMOS=OFF \ + -DSUITESPARSE_USE_FORTRAN=OFF -DSUITESPARSE_USE_CUDA=OFF -DSUITESPARSE_USE_OPENMP=OFF \ + -DSUITESPARSE_USE_STRICT=ON + cmake --build SuiteSparse/build --target install --parallel "$(nproc)" + cp SuiteSparse/LICENSE.txt "${licenses}/SuiteSparse-LICENSE.txt" + cp SuiteSparse/SPQR/Doc/gpl.txt "${licenses}/SuiteSparse-gpl.txt" + + git clone --depth 1 --branch "${CERES_VERSION}" https://github.com/ceres-solver/ceres-solver + cmake -S ceres-solver -B ceres-solver/build "${common[@]}" \ + -DBUILD_SHARED_LIBS=ON -DBUILD_TESTING=OFF -DBUILD_EXAMPLES=OFF -DBUILD_BENCHMARKS=OFF \ + -DGFLAGS=OFF -DUSE_CUDA=OFF -DSUITESPARSE=ON -DLAPACK=ON -DSCHUR_SPECIALIZATIONS=ON \ + -DPROVIDE_UNINSTALL_TARGET=OFF + cmake --build ceres-solver/build --target install --parallel "$(nproc)" + cp ceres-solver/LICENSE "${licenses}/ceres-solver-LICENSE" + + # Rocky 10 has no fmt, robin-map or OpenColorIO (nor OCIO's yaml-cpp, pystring, + # minizip-ng): let OpenImageIO build them itself, as its own PyPI wheels do. + git clone --depth 1 --branch "v${OIIO_VERSION}" https://github.com/AcademySoftwareFoundation/OpenImageIO + cmake -S OpenImageIO -B OpenImageIO/build "${common[@]}" \ + -DOpenImageIO_BUILD_MISSING_DEPS="fmt;Robinmap;OpenColorIO;pystring;yaml-cpp;minizip-ng" \ + -DBUILD_TESTING=OFF -DOIIO_BUILD_TESTS=OFF -DOIIO_BUILD_TOOLS=OFF -DBUILD_DOCS=OFF \ + -DINSTALL_DOCS=OFF -DSTOP_ON_WARNING=OFF -DLINKSTATIC=OFF -DENABLE_IV=OFF \ + -DUSE_PYTHON=OFF -DUSE_DCMTK=OFF -DUSE_FFMPEG=OFF -DUSE_FREETYPE=OFF -DUSE_GIF=OFF \ + -DUSE_JXL=OFF -DUSE_LIBHEIF=OFF -DUSE_LIBRAW=OFF -DUSE_NUKE=OFF -DUSE_OPENCV=OFF \ + -DUSE_OPENJPEG=OFF -DUSE_OpenVDB=OFF -DUSE_PTEX=OFF -DUSE_TBB=OFF -DUSE_WEBP=OFF + cmake --build OpenImageIO/build --target install --parallel "$(nproc)" + cp OpenImageIO/LICENSE.md "${licenses}/OpenImageIO-LICENSE.md" + cp OpenImageIO/THIRD-PARTY.md "${licenses}/OpenImageIO-THIRD-PARTY.md" + for dep in OpenColorIO fmt Robinmap pystring yaml-cpp minizip-ng; do + found=$(find "OpenImageIO/build/deps/${dep}" -maxdepth 1 -type f \( -iname 'LICENSE*' -o -iname 'COPYING*' \)) + test -n "${found}" + for file in ${found}; do cp "${file}" "${licenses}/${dep}-$(basename "${file}")"; done + done + ls "${licenses}" + SCRIPT + + - name: Save the COLMAP dependencies + if: steps.deps.outputs.cache-hit != 'true' + uses: actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 + with: + path: sdk + key: ${{ steps.deps.outputs.cache-primary-key }} + + - name: Build COLMAP + run: | + docker run --rm -i --network=host \ + -v "${GITHUB_WORKSPACE}/sdk:/opt/colmap" \ + -v "${GITHUB_WORKSPACE}/colmap:/colmap" \ + -e DNF_PACKAGES \ + "${MANYLINUX_RISCV64_IMAGE}" \ + bash <<'SCRIPT' + set -eux + + dnf install -y --setopt=install_weak_deps=False ${DNF_PACKAGES} + + cmake -S /colmap -B /tmp/build -GNinja \ + -DCUDA_ENABLED=OFF \ + -DONNX_ENABLED=OFF \ + -DGUI_ENABLED=OFF \ + -DCGAL_ENABLED=OFF \ + -DLSD_ENABLED=OFF \ + -DCMAKE_BUILD_TYPE=Release \ + -DCMAKE_EXE_LINKER_FLAGS_INIT="-ldl" \ + -DCMAKE_INSTALL_PREFIX=/opt/colmap \ + -DCMAKE_INSTALL_LIBDIR=lib \ + -DCMAKE_PREFIX_PATH=/opt/colmap \ + -DBLA_VENDOR=OpenBLAS + cmake --build /tmp/build --target install --parallel "$(nproc)" + + licenses=/opt/colmap/share/licenses + cp /tmp/build/_deps/faiss-src/LICENSE "${licenses}/faiss-LICENSE" + cp /tmp/build/_deps/poselib-src/LICENSE "${licenses}/PoseLib-LICENSE" + cp /colmap/src/thirdparty/VLFeat/LICENSE "${licenses}/VLFeat-LICENSE" + cp /colmap/src/thirdparty/PoissonRecon/LICENSE "${licenses}/PoissonRecon-LICENSE" + SCRIPT + + - name: Pack the COLMAP SDK + run: tar -C sdk -czf colmap-sdk.tar.gz . + + - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 + with: + name: pycolmap-${{ env.PYCOLMAP_VERSION }}-colmap-sdk + path: colmap-sdk.tar.gz + if-no-files-found: error + + build_wheels: + needs: [setup, colmap] + if: needs.setup.outputs.versions != '[]' + name: Build pycolmap ${{ matrix.version }} ${{ matrix.python }}-manylinux_riscv64 + runs-on: ubuntu-24.04-riscv + timeout-minutes: 1440 + strategy: + fail-fast: false + matrix: + version: ${{ fromJSON(needs.setup.outputs.versions) }} + # Upstream's build selector (cp3{10,11,12,13,14}) has no free-threaded interpreter. + python: ["cp312", "cp313", "cp314"] + + env: + PYCOLMAP_VERSION: ${{ matrix.version }} + + steps: + - name: Checkout COLMAP ${{ env.PYCOLMAP_VERSION }} + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + repository: colmap/colmap + ref: ${{ env.PYCOLMAP_VERSION }} + persist-credentials: false + + - name: Checkout python-wheels + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + path: python-wheels + persist-credentials: false + + - name: Patch COLMAP + run: git apply python-wheels/patches/pycolmap/${{ env.PYCOLMAP_VERSION }}/*.patch + + - name: Download the COLMAP SDK + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 + with: + name: pycolmap-${{ env.PYCOLMAP_VERSION }}-colmap-sdk + + # auditwheel vendors the from-source libraries of the SDK and the image libraries + # they pull in; ship the licence of each alongside COLMAP's own. + - name: Write the wheel repair script + run: | + cat > riscv64-repair-wheel.sh <<'EOF' + set -euxo pipefail + wheel="$1" + dest="$2" + work="$(mktemp -d)" + mkdir -p "${work}/core" "${work}/licenses" "${work}/repaired" + auditwheel repair -w "${work}/repaired" "${wheel}" + cp /opt/colmap/share/licenses/* "${work}/licenses/" + python3 -c 'import sys, zipfile; z = zipfile.ZipFile(sys.argv[1]); z.extractall(sys.argv[2], [n for n in z.namelist() if n.startswith("pycolmap/_core")])' "${wheel}" "${work}/core" + mapfile -t grafted < <(python3 -c 'import re, sys, zipfile; print("\n".join(re.sub(r"-[0-9a-f]{8}(\.so)", r"\1", n.split("/")[-1]) for n in zipfile.ZipFile(sys.argv[1]).namelist() if n.startswith("pycolmap.libs/") and n != "pycolmap.libs/"))' "${work}"/repaired/*.whl) + mapfile -t libs < <(ldd "${work}"/core/pycolmap/_core*.so | tr ' ' '\n' | grep '^/' | grep -v '^/opt/colmap/' | sort -u \ + | xargs readlink -f | while read -r lib; do if printf '%s\n' "${grafted[@]}" | grep -qxF "$(basename "${lib}")"; then echo "${lib}"; fi; done) + mapfile -t pkgs < <(rpm -qf --qf '%{NAME}\n' "${libs[@]}" 2>/dev/null | grep -E '^[A-Za-z0-9._+-]+$' | sort -u) + dnf reinstall -y --setopt=tsflags= "${pkgs[@]}" >/dev/null || true + for pkg in "${pkgs[@]}"; do + files=$(rpm -qL "${pkg}" | grep -v '^(contains no files)$' || true) + if [ -n "${files}" ]; then + for file in ${files}; do cp "${file}" "${work}/licenses/${pkg}-$(basename "${file}")"; done + else + rpm -q --qf '%{NAME} %{VERSION}: %{LICENSE}\n' "${pkg}" >> "${work}/licenses/third-party.txt" + fi + done + python3 - "${work}"/repaired/*.whl "${work}/licenses" "${dest}" <<'PY' + import base64, hashlib, os, sys, zipfile + + wheel, licenses, dest = sys.argv[1:] + with zipfile.ZipFile(wheel) as src: + entries = [(info, src.read(info)) for info in src.infolist()] + record_name = next(info.filename for info, _ in entries if info.filename.endswith(".dist-info/RECORD")) + dist_info = record_name.split("/")[0] + with zipfile.ZipFile(os.path.join(dest, os.path.basename(wheel)), "w", zipfile.ZIP_DEFLATED) as out: + for info, data in entries: + if info.filename == record_name: + record = data.decode() + else: + out.writestr(info, data) + record = record if record.endswith("\n") else record + "\n" + for name in sorted(os.listdir(licenses)): + path = f"{dist_info}/licenses/{name}" + with open(os.path.join(licenses, name), "rb") as f: + data = f.read() + out.writestr(path, data) + digest = base64.urlsafe_b64encode(hashlib.sha256(data).digest()).rstrip(b"=").decode() + record += f"{path},sha256={digest},{len(data)}\n" + out.writestr(record_name, record) + PY + EOF + + - name: Build wheels + uses: pypa/cibuildwheel@1828c10ab37f080699c7b81cea34097c684a7074 # v4.2.0 + with: + output-dir: wheelhouse/ + only: ${{ matrix.python }}-manylinux_riscv64 + env: + CIBW_MANYLINUX_RISCV64_IMAGE: ${{ env.MANYLINUX_RISCV64_IMAGE }} + CIBW_BEFORE_ALL_LINUX: >- + dnf install -y --setopt=install_weak_deps=False ${{ env.DNF_PACKAGES }} && + mkdir -p /opt/colmap && + tar -C /opt/colmap -xzf {project}/colmap-sdk.tar.gz + # Upstream's vcpkg build links every dependency statically, so only what the + # module uses ends up in it; --as-needed keeps the shared equivalents to that set. + # WERROR_ENABLED=ON from upstream's config settings is left out: the image's GCC 14 + # is newer than upstream's gcc-toolset-12. + CIBW_ENVIRONMENT: >- + PIP_EXTRA_INDEX_URL=https://pypi.riseproject.dev/simple/ + CMAKE_PREFIX_PATH=/opt/colmap + LD_LIBRARY_PATH=/opt/colmap/lib + LDFLAGS=-Wl,--as-needed + CIBW_REPAIR_WHEEL_COMMAND_LINUX: bash {project}/riscv64-repair-wheel.sh {wheel} {dest_dir} + + - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 + with: + name: pycolmap-${{ env.PYCOLMAP_VERSION }}-${{ matrix.python }}-manylinux_riscv64 + path: wheelhouse/*.whl + if-no-files-found: error + + gpl_sources: + needs: [setup] + if: needs.setup.outputs.versions != '[]' + strategy: + fail-fast: false + matrix: + version: ${{ fromJSON(needs.setup.outputs.versions) }} + name: Collect GPL sources for pycolmap ${{ matrix.version }} + runs-on: ubuntu-24.04-riscv + + env: + PYCOLMAP_VERSION: ${{ matrix.version }} + + steps: + - name: Checkout python-wheels + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false + + # libgomp/libgfortran, libtiff's jbigkit and libcurl's copyleft closure, all + # vendored out of the build image. + - uses: ./actions/collect-gpl-sources + with: + image: ${{ env.MANYLINUX_RISCV64_IMAGE }} + packages: gcc jbigkit-libs keyutils-libs libssh libidn2 libunistring libxcrypt systemd-libs libcap pcre2 + output: gpl-sources.tar + + # CHOLMOD's GPL modules and SPQR are built from source into the wheel. + - name: Add the SuiteSparse sources + run: | + curl -fsSLo "SuiteSparse-${SUITESPARSE_VERSION}.tar.gz" \ + "https://github.com/DrTimothyAldenDavis/SuiteSparse/archive/refs/tags/v${SUITESPARSE_VERSION}.tar.gz" + tar -rf gpl-sources.tar "SuiteSparse-${SUITESPARSE_VERSION}.tar.gz" + tar -tf gpl-sources.tar + + - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 + with: + name: pycolmap-${{ env.PYCOLMAP_VERSION }}-gpl-sources + path: gpl-sources.tar + if-no-files-found: error + + publish: + name: Publish pycolmap ${{ matrix.version }} + needs: [setup, build_wheels, gpl_sources] + if: needs.setup.outputs.versions != '[]' + strategy: + fail-fast: false + matrix: + version: ${{ fromJSON(needs.setup.outputs.versions) }} + permissions: + contents: write + pull-requests: write + uses: $/.github/workflows/_publish-wheel.yml + secrets: + app-private-key: ${{ secrets.RISEPROJECT_APP_PRIVATE_KEY }} + with: + artifact-pattern: pycolmap-${{ matrix.version }}-*-manylinux_riscv64 + gpl-sources-artifact: pycolmap-${{ matrix.version }}-gpl-sources + gpl-sources-description: gcc and the copyleft libraries bundled in the wheel diff --git a/docs/packages/pycolmap.yaml b/docs/packages/pycolmap.yaml new file mode 100644 index 00000000000..0b35ec471b1 --- /dev/null +++ b/docs/packages/pycolmap.yaml @@ -0,0 +1,6 @@ +package-name: pycolmap +source-code: https://github.com/colmap/colmap +license: BSD-3-Clause +versions: +- version: 4.1.1 + patched: true diff --git a/patches/pycolmap/4.1.1/0001-build-drop-the-unused-clang-format-build-requirement.patch b/patches/pycolmap/4.1.1/0001-build-drop-the-unused-clang-format-build-requirement.patch new file mode 100644 index 00000000000..f6dcce62d95 --- /dev/null +++ b/patches/pycolmap/4.1.1/0001-build-drop-the-unused-clang-format-build-requirement.patch @@ -0,0 +1,30 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Ludovic Henry +Date: Fri, 25 Sep 2026 15:00:00 +0000 +Subject: [PATCH] build: drop the unused clang-format build requirement + +Upstream-Status: Inappropriate [riscv64-only: clang-format 22.1.1 ships no riscv64 wheel, and the wheel build never runs it] + +clang-format is only used by scripts/format/c++.sh; neither +python/CMakeLists.txt nor python/generate_stubs.sh (which formats the +generated stubs with ruff) invokes it. With no riscv64 wheel for the +pinned 22.1.1, the isolated build environment would compile it from its +sdist, i.e. a slice of LLVM, once per interpreter. + +Signed-off-by: Ludovic Henry +--- + pyproject.toml | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/pyproject.toml b/pyproject.toml +index e46baa57..976dd4e0 100644 +--- a/pyproject.toml ++++ b/pyproject.toml +@@ -5,7 +5,6 @@ requires = [ + "pybind11_stubgen @ git+https://github.com/sarlinpe/pybind11-stubgen@sarlinpe/fix-2025-08-20", + "numpy", + "ruff==0.15.7", +- "clang-format==22.1.1", + ] + build-backend = "scikit_build_core.build" + From 6611d7caaacbdc939e58c101b4e0f1ddf254d8da Mon Sep 17 00:00:00 2001 From: Ludovic Henry Date: Fri, 25 Sep 2026 18:09:57 +0000 Subject: [PATCH 2/2] pycolmap: Fix the OpenImageIO dependency build Rocky 10's libjpeg-turbo-devel ships a CMake config whose libjpeg-turbo::turbojpeg target points at libturbojpeg.so, which lives in the separate CRB turbojpeg package; without it any find_package(libjpeg-turbo), OpenImageIO's included, fails. Install it. OpenImageIO 3.1.14.0 builds its missing pystring from master and checks it against a fixed commit, which master has since moved past. 3.1.14.1 changes only that, to the v1.2.0 tag vcpkg itself pins. --- .github/workflows/build-pycolmap.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build-pycolmap.yml b/.github/workflows/build-pycolmap.yml index 83a7f029851..2308cfeb100 100644 --- a/.github/workflows/build-pycolmap.yml +++ b/.github/workflows/build-pycolmap.yml @@ -41,7 +41,7 @@ env: DNF_PACKAGES: >- ninja-build eigen3-devel boost-devel sqlite-devel openblas-devel libcurl-devel openssl-devel mesa-libGL-devel libX11-devel - libtiff-devel libjpeg-turbo-devel libpng-devel openexr-devel imath-devel + libtiff-devel libjpeg-turbo-devel turbojpeg libpng-devel openexr-devel imath-devel expat-devel zlib-ng-compat-devel GLOG_VERSION: 0.7.1 METIS_VERSION: 5.1.0 @@ -50,7 +50,9 @@ env: GLEW_SHA256: b64790f94b926acd7e8f84c5d6000a86cb43967bd1e688b03089079799c9e889 SUITESPARSE_VERSION: 7.12.2 CERES_VERSION: 2.2.0 - OIIO_VERSION: 3.1.14.0 + # vcpkg pins 3.1.14.0, whose pystring build expects pystring's master at a commit master + # has since moved past; 3.1.14.1 only changes that to the v1.2.0 tag vcpkg itself pins. + OIIO_VERSION: 3.1.14.1 jobs: setup: