-
Notifications
You must be signed in to change notification settings - Fork 16
320 lines (269 loc) · 12 KB
/
Copy pathpython.yml
File metadata and controls
320 lines (269 loc) · 12 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
name: 🐍 Bindings
on:
release:
types:
- published
push:
branches:
- master
pull_request:
workflow_dispatch:
inputs:
publish:
type: boolean
description: Publish on PyPi
jobs:
test-bindings:
strategy:
fail-fast: false
matrix:
include:
- os: ubuntu-latest
container: ghcr.io/viennatools/vienna-builder:cuda-suite-python-nocuda
- os: windows-latest
- os: macos-15-intel
- os: macos-latest
runs-on: ${{ matrix.os }}
container: ${{ matrix.container }}
env:
VCPKG_COMMIT: 72d876b20f06129a1b1e0db80c7075fe3e419d7c
VCPKG_DEFAULT_BINARY_CACHE: ${{ github.workspace }}/.vcpkg-bincache
name: "🐍 Test Bindings on ${{ matrix.os }}"
steps:
- name: 📥 Checkout
uses: actions/checkout@v6
- name: 🖥️ Setup Environment
uses: ./.github/actions/setup
with:
os: ${{ matrix.os }}
- name: 🖥️ Setup vcpkg (Windows)
shell: pwsh
if: ${{ matrix.os == 'windows-latest' }}
run: |
Remove-Item Env:VCPKG_ROOT -ErrorAction SilentlyContinue
git clone https://github.com/microsoft/vcpkg.git
git -C vcpkg checkout $env:VCPKG_COMMIT
& .\vcpkg\bootstrap-vcpkg.bat
"VCPKG_ROOT=$($env:GITHUB_WORKSPACE)\vcpkg" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append
New-Item -ItemType Directory -Force -Path "${{ env.VCPKG_DEFAULT_BINARY_CACHE }}"
- name: 📋 Install MacOS Dependencies
if: ${{ startsWith(matrix.os, 'macos-') }}
run: brew install vtk
- name: 🦥 Cache vcpkg installed
if: ${{ matrix.os == 'windows-latest' }}
id: vcpkg-installed-cache
uses: actions/cache@v5
with:
path: ${{ github.workspace }}/vcpkg_installed
key: vcpkg-installed-${{ matrix.os }}-${{ env.VCPKG_COMMIT }}-${{ hashFiles('vcpkg.json') }}
- name: 🛠️ Build VTK (Windows)
if: ${{ matrix.os == 'windows-latest' && steps.vcpkg-installed-cache.outputs.cache-hit != 'true' }}
shell: pwsh
run: |
./vcpkg/vcpkg install --triplet x64-windows
- name: 🐍 Build and check Python Module (Windows)
if: ${{ matrix.os == 'windows-latest' }}
shell: pwsh
run: |
python -m venv venv
$toolchain = "${{ github.workspace }}/vcpkg/scripts/buildsystems/vcpkg.cmake".Replace('\', '/')
.\venv\Scripts\python -m pip install --upgrade pip
$vcpkgInstalled = "${{ github.workspace }}/vcpkg_installed".Replace('\', '/')
.\venv\Scripts\python -m pip install . `
--config-settings=cmake.define.CMAKE_TOOLCHAIN_FILE="$toolchain" `
--config-settings=cmake.define.VCPKG_TARGET_TRIPLET="x64-windows" `
--config-settings=cmake.define.VCPKG_INSTALLED_DIR="$vcpkgInstalled" `
--config-settings=cmake.define.VCPKG_MANIFEST_INSTALL=OFF
.\venv\Scripts\python -c "import viennals; print(viennals.__doc__)"
- name: 🐍 Build and check Python Module (Other)
if: ${{ matrix.os != 'windows-latest' }}
run: |
python -m venv venv
CMAKE_ARGS=-DCMAKE_INTERPROCEDURAL_OPTIMIZATION=OFF ./venv/bin/pip install .
./venv/bin/python -c "import viennals; print(viennals.__doc__)"
- name: 📦 Upload Artifact
uses: actions/upload-artifact@v7
with:
name: Pre-Built (${{ matrix.os }})
path: venv
package:
strategy:
fail-fast: false
matrix:
include:
- os: ubuntu-latest
skip: "cp38-* cp39-* *-manylinux_i686 *-musllinux_*"
- os: windows-latest
skip: "cp38-* cp39-*"
- os: macos-15-intel
archs: x86_64
skip: "cp38-* cp39-* cp310-*"
- os: macos-15
archs: arm64
skip: "cp38-* cp39-* cp310-*"
runs-on: ${{ matrix.os }}
name: "🐍 Package Bindings on ${{ matrix.os }}"
env:
VCPKG_COMMIT: 72d876b20f06129a1b1e0db80c7075fe3e419d7c
VCPKG_DEFAULT_BINARY_CACHE: ${{ github.workspace }}/.vcpkg-bincache
steps:
- name: 📥 Checkout
uses: actions/checkout@v6
- name: 🖥️ Setup Environment
uses: ./.github/actions/setup
with:
os: ${{ matrix.os }}
- name: 🛞 CIBuildWheel
run: pip install cibuildwheel==3.4.0 --break-system-packages
- name: 🏗️ Build Wheels (Linux)
if: ${{ matrix.os == 'ubuntu-latest' }}
run: python -m cibuildwheel --output-dir wheelhouse
env:
CIBW_SKIP: ${{ matrix.skip }}
CIBW_MANYLINUX_X86_64_IMAGE: ghcr.io/viennatools/vienna-builder:cuda-python
# The CUDA libraries are far too large to vendor (libcusparse alone is
# >160 MB, over the PyPI file limit), so they are left unbundled.
# That is safe here only because _core.so does not link them: they are
# needed solely by libViennaLS_GPU.so, which ViennaLS dlopen()s on
# demand and does without when it cannot be loaded. Keep it that way —
# linking CUDA into _core.so is what broke the 5.8.3 wheel.
CIBW_REPAIR_WHEEL_COMMAND_LINUX: >-
auditwheel repair
--exclude libcuda.so.1
--exclude libcudart.so.12
--exclude libcusparse.so.12
--exclude libnvJitLink.so.12
-w {dest_dir} {wheel}
CIBW_TEST_COMMAND: >-
python -c "import viennals;
print(viennals.__file__);
print(viennals.d2);
print(viennals.d3)"
CIBW_CONFIG_SETTINGS: >-
cmake.define.VIENNALS_PACKAGE_PYTHON=ON
cmake.define.VIENNALS_IS_CI=ON
cmake.define.VIENNALS_VTK_RENDERING=ON
cmake.define.VIENNALS_USE_GPU=ON
cmake.define.VIENNACORE_LINK_CUDA_DRIVER=OFF
cmake.define.USE_IPO=OFF
- name: 🏗️ Build Wheels (Other)
if: ${{ matrix.os != 'ubuntu-latest' }}
run: python -m cibuildwheel --output-dir wheelhouse
env:
CIBW_SKIP: ${{ matrix.skip }}
CIBW_ARCHS_WINDOWS: auto64
CIBW_ARCHS_MACOS: ${{ matrix.archs }}
CIBW_TEST_COMMAND: >-
python -c "import viennals;
print(viennals.__file__);
print(viennals.d2);
print(viennals.d3)"
CIBW_CONFIG_SETTINGS: >-
cmake.define.VIENNALS_PACKAGE_PYTHON=ON
cmake.define.VIENNALS_IS_CI=ON
cmake.define.VIENNALS_VTK_RENDERING=ON
- name: 🔎 Inspect wheel contents
shell: bash
run: |
python - <<'PY'
import glob
import re
import subprocess
import sys
import tempfile
import zipfile
missing = []
# Matched by prefix so a CUDA major-version bump cannot slip past.
CUDA_RE = re.compile(r"^lib(cuda|cudart|cusparse|cublas|nvJitLink|nvrtc)", re.I)
def dt_needed(path):
out = subprocess.run(["readelf", "-d", path], capture_output=True, text=True).stdout
return re.findall(r"\(NEEDED\).*?\[([^\]]+)\]", out)
for wheel in glob.glob("wheelhouse/*.whl"):
print("\n" + wheel)
with zipfile.ZipFile(wheel) as zf:
entries = sorted(zf.infolist(), key=lambda item: item.file_size, reverse=True)
for entry in entries[:40]:
size_mb = entry.file_size / 1024 / 1024
print(f"{size_mb:8.2f} MB {entry.filename}")
names = [entry.filename for entry in entries]
if "win_amd64" in wheel:
libs = [name for name in names if name.startswith("viennals.libs/")]
openmp = [
name
for name in libs
if name.lower() == "viennals.libs/libomp140.x86_64.dll"
]
core = next(name for name in names if name.startswith("viennals/_core") and name.endswith(".pyd"))
core_bytes = zf.read(core)
print("\nWindows runtime libraries:")
for name in libs:
print(f" {name}")
if not libs:
missing.append(f"{wheel}: missing viennals.libs/")
if not openmp:
missing.append(f"{wheel}: missing viennals.libs/libomp140.x86_64.dll")
if b"omp_set_nested" in core_bytes:
missing.append(f"{wheel}: _core.pyd still references deprecated omp_set_nested")
if "manylinux" in wheel:
# The GPU solver lives in a separate library that ViennaLS
# dlopen()s on demand. Two things must hold, and CI cannot
# detect either by importing: CIBW_TEST_COMMAND runs inside
# the CUDA build image, where a CUDA-linked wheel imports
# happily. That is exactly how 5.8.3 shipped broken.
core = next(n for n in names if n.startswith("viennals/_core") and n.endswith(".so"))
gpu = [n for n in names if n.endswith("libViennaLS_GPU.so")]
with tempfile.TemporaryDirectory() as tmp:
# 1. _core must not hard-link CUDA, or the wheel fails
# to import on any machine without a CUDA runtime.
cuda = [x for x in dt_needed(zf.extract(core, tmp)) if CUDA_RE.match(x)]
print(f"\n{core} CUDA dependencies: {cuda or 'none'}")
if cuda:
missing.append(
f"{wheel}: _core links CUDA directly ({', '.join(cuda)}); "
"it will not import without a CUDA runtime")
# 2. If GPU support was built, the library has to
# survive auditwheel, else GPU users silently lose it.
# Linux wheels are built with VIENNALS_USE_GPU=ON, so
# absence means it was dropped, not never built. If
# GPU is ever turned off here, this must be updated
# rather than left to pass silently.
if not gpu:
missing.append(
f"{wheel}: libViennaLS_GPU.so is missing; GPU support "
"was built but did not survive into the wheel")
else:
gpu_cuda = [x for x in dt_needed(zf.extract(gpu[0], tmp)) if CUDA_RE.match(x)]
print(f"{gpu[0]} CUDA dependencies: {gpu_cuda or 'none'}")
if not gpu_cuda:
missing.append(
f"{wheel}: {gpu[0]} has no CUDA dependencies; "
"auditwheel may have rewritten it")
if missing:
print("\nWheel runtime checks failed:", file=sys.stderr)
for item in missing:
print(f" {item}", file=sys.stderr)
raise SystemExit(1)
PY
- name: 📦 Upload Artifact
uses: actions/upload-artifact@v7
with:
name: wheels-${{ matrix.os }}
path: ./wheelhouse/*.whl
deploy:
if: ${{ github.event_name == 'release' || github.event.inputs.publish == 'true' }}
needs: [package]
permissions:
id-token: write
runs-on: ubuntu-latest
name: "🐍 Publish Bindings"
steps:
- name: 📦 Download Wheels
uses: actions/download-artifact@v8
with:
pattern: wheels-*
path: dist
merge-multiple: true
- name: 🚀 Publish Wheels
uses: pypa/gh-action-pypi-publish@release/v1
with:
skip-existing: true