diff --git a/.github/workflows/build-openmm.yml b/.github/workflows/build-openmm.yml new file mode 100644 index 00000000000..0ab8c6faed6 --- /dev/null +++ b/.github/workflows/build-openmm.yml @@ -0,0 +1,215 @@ +# SPDX-FileCopyrightText: 2026 The RISE Project +# SPDX-License-Identifier: MIT +--- +# This workflow is based on: https://github.com/openmm/openmm-build-wheels/blob/db996361bca08a147c00f79dd4de8793d721fe34/.github/workflows/BuildWheels.yml +name: Build openmm wheels (riscv64) + +on: + workflow_dispatch: + inputs: + version: + description: 'Version glob to (re)build; empty builds every version of docs/packages/openmm.yaml not released yet' + required: false + default: '' + pull_request: + branches: [main] + paths: + - '.github/workflows/build-openmm.yml' + - 'docs/packages/openmm.yaml' + - 'patches/openmm/**' + push: + branches: [main] + paths: + - '.github/workflows/build-openmm.yml' + - 'docs/packages/openmm.yaml' + - 'patches/openmm/**' + +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} + cancel-in-progress: true + +permissions: + contents: read + +env: + OPENMM_BUILD_WHEELS_REF: db996361bca08a147c00f79dd4de8793d721fe34 + +jobs: + setup: + uses: $/.github/workflows/_setup.yml + with: + package: openmm + version: ${{ inputs.version }} + + build_wheels: + name: Build openmm ${{ matrix.version }} manylinux_riscv64 + needs: [setup] + if: needs.setup.outputs.versions != '[]' + strategy: + fail-fast: false + matrix: + version: ${{ fromJSON(needs.setup.outputs.versions) }} + env: + OPENMM_VERSION: ${{ matrix.version }} + PYTHON_TAGS: cp312 cp313 cp314 + runs-on: ubuntu-24.04-riscv + timeout-minutes: 720 + container: + image: quay.io/pypa/manylinux_2_39_riscv64 + + steps: + - name: Checkout openmm ${{ env.OPENMM_VERSION }} + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + repository: openmm/openmm + ref: ${{ env.OPENMM_VERSION }} + path: openmm + persist-credentials: false + + - name: Checkout openmm-build-wheels + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + repository: openmm/openmm-build-wheels + ref: ${{ env.OPENMM_BUILD_WHEELS_REF }} + path: openmm-build-wheels + persist-credentials: false + + - name: Checkout python-wheels + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + path: python-wheels + persist-credentials: false + + - name: Install dependencies with dnf + run: dnf -y install doxygen zip opencl-headers ocl-icd + + - name: Patch openmm source + working-directory: openmm + run: | + git apply "$GITHUB_WORKSPACE"/python-wheels/patches/openmm/"$OPENMM_VERSION"/*.patch + git apply "$GITHUB_WORKSPACE"/openmm-build-wheels/devtools/patches/library_path.patch + git apply "$GITHUB_WORKSPACE"/openmm-build-wheels/devtools/patches/cxx11_abi.patch + git apply "$GITHUB_WORKSPACE"/openmm-build-wheels/devtools/patches/link_args.patch + + - name: Configure build with CMake + run: | + set -euxo pipefail + /opt/python/cp312-cp312/bin/python -m pip install --extra-index-url https://pypi.riseproject.dev/simple/ --only-binary=numpy \ + swig cython numpy setuptools wheel delocate + export PATH="/opt/python/cp312-cp312/bin:$PATH" + # BUILD_TESTING=OFF: upstream's wheel job compiles the ctest suite but never runs it. + cmake -S openmm -B openmm/build \ + -DCMAKE_INSTALL_PREFIX="${HOME}/openmm-install" \ + -DCMAKE_CXX_FLAGS='-D_GLIBCXX_USE_CXX11_ABI=1' \ + -DOPENMM_BUILD_OPENCL_LIB=ON \ + -DOPENCL_INCLUDE_DIR=/usr/include/CL \ + -DOPENCL_LIBRARY=/usr/lib64/libOpenCL.so.1 \ + -DCMAKE_POLICY_VERSION_MINIMUM=3.5 \ + -DBUILD_TESTING=OFF \ + -DPYTHON_EXECUTABLE=/opt/python/cp312-cp312/bin/python + + - name: Build OpenMM + working-directory: openmm/build + run: | + export PATH="/opt/python/cp312-cp312/bin:$PATH" + make -j"$(nproc)" install + + - name: Build wheels + run: | + set -euxo pipefail + export PATH="/opt/python/cp312-cp312/bin:$PATH" + export LD_LIBRARY_PATH="${HOME}/openmm-install/lib" + mkdir -p wheelhouse + for tag in $PYTHON_TAGS; do + py="/opt/python/${tag}-${tag}/bin/python" + "$py" -m pip install --extra-index-url https://pypi.riseproject.dev/simple/ --only-binary=numpy \ + cython numpy setuptools wheel delocate + cmake -S openmm -B openmm/build -DPYTHON_EXECUTABLE="$py" + rm -rf openmm/build/python/dist + make -C openmm/build PythonBdistWheel + ( + cd openmm/build/python/dist + ls ./*.whl + "$py" "$GITHUB_WORKSPACE"/openmm-build-wheels/devtools/scripts/add_plugins_and_headers.py "${HOME}/openmm-install" "!CUDA" "!HIP" + ) + auditwheel repair -w wheelhouse -L ".libs/lib" --plat manylinux_2_39_riscv64 openmm/build/python/dist/*.whl \ + --exclude libOpenMM.so \ + --exclude libOpenMMOpenCL.so \ + --exclude libOpenMMDrude.so \ + --exclude libOpenMMAmoeba.so \ + --exclude libOpenMMRPMD.so \ + --exclude libOpenCL.so.1 + "$py" -m zipfile -l wheelhouse/openmm-*-"${tag}"-*.whl | grep -F licenses/Licenses.txt + done + ls -la wheelhouse + + - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 + with: + name: openmm-${{ env.OPENMM_VERSION }}-wheels-manylinux_riscv64 + path: wheelhouse/*.whl + if-no-files-found: error + + test_wheels: + name: Test openmm ${{ matrix.version }} ${{ matrix.python }}-manylinux_riscv64 + needs: [setup, build_wheels] + if: needs.setup.outputs.versions != '[]' + strategy: + fail-fast: false + matrix: + version: ${{ fromJSON(needs.setup.outputs.versions) }} + python: ["cp312", "cp313", "cp314"] + env: + OPENMM_VERSION: ${{ matrix.version }} + runs-on: ubuntu-24.04-riscv + timeout-minutes: 360 + container: + image: quay.io/pypa/manylinux_2_39_riscv64 + + steps: + - name: Checkout openmm ${{ env.OPENMM_VERSION }} + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + repository: openmm/openmm + ref: ${{ env.OPENMM_VERSION }} + sparse-checkout: wrappers/python/tests + persist-credentials: false + + - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 + with: + name: openmm-${{ env.OPENMM_VERSION }}-wheels-manylinux_riscv64 + path: wheelhouse + + - name: Install dependencies with dnf + run: dnf -y install ocl-icd + + - name: Test the wheel + run: | + set -euxo pipefail + "/opt/python/${{ matrix.python }}-${{ matrix.python }}/bin/python" -m venv "${RUNNER_TEMP}/test_env" + source "${RUNNER_TEMP}/test_env/bin/activate" + pip install --extra-index-url https://pypi.riseproject.dev/simple/ --only-binary=numpy \ + wheelhouse/openmm-*-${{ matrix.python }}-*.whl pytest pytest-xdist + python -m openmm.testInstallation + python -c "import openmm as mm; print(mm.version.openmm_library_path)" + python -c "import openmm as mm; print('---Loaded---', *mm.pluginLoadedLibNames, '---Failed---', *mm.Platform.getPluginLoadFailures(), sep='\n')" + python -c "import openmm as mm; mm.Platform.getPlatformByName('CPU')" + cp -r wrappers/python/tests "${RUNNER_TEMP}/tests" + cd "${RUNNER_TEMP}/tests" + python -m pytest -v -n auto + + publish: + name: Publish openmm ${{ matrix.version }} + needs: [setup, test_wheels] + 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: openmm-${{ matrix.version }}-*-manylinux_riscv64 diff --git a/docs/packages/openmm.yaml b/docs/packages/openmm.yaml new file mode 100644 index 00000000000..5afd2401cc9 --- /dev/null +++ b/docs/packages/openmm.yaml @@ -0,0 +1,6 @@ +package-name: openmm +source-code: https://github.com/openmm/openmm +license: MIT AND LGPL-3.0-or-later +versions: +- version: 8.6.0 + patched: true diff --git a/patches/openmm/8.6.0/0001-python-ship-the-licence-texts-in-the-wheel.patch b/patches/openmm/8.6.0/0001-python-ship-the-licence-texts-in-the-wheel.patch new file mode 100644 index 00000000000..67076104d45 --- /dev/null +++ b/patches/openmm/8.6.0/0001-python-ship-the-licence-texts-in-the-wheel.patch @@ -0,0 +1,51 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Ludovic Henry +Date: Fri, 2 Oct 2026 23:49:48 +0000 +Subject: [PATCH] python: ship the licence texts in the wheel + +The Python wheel carries no licence file at all: dist-info has only +METADATA/WHEEL/RECORD/top_level.txt, and OpenMM.libs/ holds the core +libraries and plugins without any notice. The MIT licence covering the +API, Reference and CPU platforms requires the notice to accompany +copies, the OpenCL plugins in the wheel are LGPL, and the bundled +SFMT, Hilbert, irrXML, L-BFGS and VkFFT code carry their own notices -- +all of which upstream already collects in docs-source/licenses/. + +Stage that directory next to setup.py and list it in license_files, so +Licenses.txt, LGPL.txt and GPL.txt land in dist-info/licenses. + +Upstream's own PyPI wheels have the same gap on every platform. + +Upstream-Status: To upstream [not submitted from this automated port run; needs a pull request against openmm/openmm] +--- + wrappers/python/CMakeLists.txt | 1 + + wrappers/python/setup.py | 1 + + 2 files changed, 2 insertions(+) + +diff --git a/wrappers/python/CMakeLists.txt b/wrappers/python/CMakeLists.txt +index b7400fa..93d72bf 100644 +--- a/wrappers/python/CMakeLists.txt ++++ b/wrappers/python/CMakeLists.txt +@@ -13,6 +13,7 @@ file(MAKE_DIRECTORY ${OPENMM_PYTHON_STAGING_DIR}/simtk/openmm) + file(MAKE_DIRECTORY ${OPENMM_PYTHON_STAGING_DIR}/simtk/unit) + file(MAKE_DIRECTORY ${OPENMM_PYTHON_STAGING_DIR}/src/swig_doxygen/swig_lib/python) + file(MAKE_DIRECTORY ${OPENMM_PYTHON_STAGING_DIR}/tests) ++file(COPY "${CMAKE_SOURCE_DIR}/docs-source/licenses/" DESTINATION "${OPENMM_PYTHON_STAGING_DIR}/licenses") + + ############################################################################## + ### Identify files that need to be copied from source area to staging area ### +diff --git a/wrappers/python/setup.py b/wrappers/python/setup.py +index 356e6de..f008244 100644 +--- a/wrappers/python/setup.py ++++ b/wrappers/python/setup.py +@@ -135,6 +135,7 @@ def buildKeywordDictionary(major_version_num=MAJOR_VERSION_NUM, + setupKeywords["author"] = "Peter Eastman" + setupKeywords["license"] = \ + "Python Software Foundation License (BSD-like)" ++ setupKeywords["license_files"] = ["licenses/*.txt"] + setupKeywords["url"] = "https://openmm.org" + setupKeywords["download_url"] = "https://openmm.org" + setupKeywords["packages"] = [ +-- +2.43.0 +