Skip to content

Commit fa8e533

Browse files
authored
Build workflow (#96)
* Improve dependency handling * Propagate test results to make * Start build wheels actions prototype * Add linux before-build script * Add toml cibuild linux section * Add cibw corrections * small correction to wheel build process * small correction to wheel build process * Remove unnecessary data from TOML file * Testing cibw workflow * New attempt to build * New attempt cibuild * Add dummy extension to fix ciwb problems * Correct project toml * Force wheels to be set as not pure * Add support for musllinux * Fix ibw_before_build_linux.sh * Relax hci test to pass with aarch architecture * Exclude musllinux aarch64 as there is not scipy for it * Exclude python 3.13t as there is not scipy for it * Add test to built wheels * Add fix to test to built wheels * Add option to include pyci package data * Fix option to include pyci package data * Fix option to include pyci package data * Try fix on option to include pyci package data * Test pyci wheels * Add actions to publish package
1 parent f0e9749 commit fa8e533

File tree

7 files changed

+365
-18
lines changed

7 files changed

+365
-18
lines changed

.github/workflows/build_wheels.yml

Lines changed: 271 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,271 @@
1+
# Workflow to build and test wheels.
2+
name: Wheel builder
3+
4+
on:
5+
push:
6+
tags:
7+
# Trigger on version tags (e.g., v1.0.0)
8+
- "v[0-9].[0-9].[0-9]*"
9+
- "[0-9].[0-9].[0-9]*"
10+
# Trigger on pre-release tags (e.g., v1.0.0-alpha.1)
11+
- "v[0-9].[0-9].[0-9]*-*"
12+
- "[0-9].[0-9].[0-9]*-*"
13+
env:
14+
# The name of the package to be published to PyPI and TestPyPI.
15+
PYPI_NAME: qc-PyCI
16+
17+
permissions:
18+
contents: read # to fetch code (actions/checkout)
19+
20+
# ensure that only one wheel builder runs at a time
21+
concurrency:
22+
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
23+
cancel-in-progress: true
24+
25+
jobs:
26+
build_wheels:
27+
name: Wheel, ${{ matrix.python[0] }}-${{ matrix.buildplat[1] }}
28+
${{ matrix.buildplat[2] }} ${{ matrix.buildplat[3] }}
29+
${{ matrix.buildplat[4] }}
30+
runs-on: ${{ matrix.buildplat[0] }}
31+
32+
strategy:
33+
# Ensure that a wheel builder finishes even if another fails
34+
fail-fast: false
35+
matrix:
36+
# If need to exclude several configurations see:
37+
# https://github.com/github/feedback/discussions/7835#discussioncomment-1769026
38+
buildplat:
39+
# Different architectures are in different jobs because the need of different compiler configurations
40+
- [ubuntu-22.04, manylinux, x86_64, "", ""]
41+
- [ubuntu-22.04, musllinux, x86_64, "", ""]
42+
- [ubuntu-24.04-arm, manylinux, aarch64, "", ""]
43+
# - [ubuntu-24.04-arm, musllinux, aarch64, "", ""]
44+
# - [macos-13, macosx, x86_64, openblas, "10.13"]
45+
# - [macos-13, macosx, x86_64, accelerate, "14.0"]
46+
# - [macos-14, macosx, arm64, openblas, "12.3"]
47+
# - [macos-14, macosx, arm64, accelerate, "14.0"]
48+
# - [windows-2019, win, AMD64, "", ""]
49+
# python[0] is the python version of the wheel and python[1] is the python version of the configuration
50+
python: [["cp39", "3.9"],["cp310", "3.10"], ["cp311", "3.11"], ["cp312", "3.12"], ["cp313", "3.13"]]
51+
52+
env:
53+
# set 32-bit flag accessable in the build script
54+
IS_32_BIT: ${{ matrix.buildplat[2] == 'x86' }}
55+
56+
steps:
57+
- name: Checkout pyci
58+
uses: actions/checkout@v4
59+
with:
60+
fetch-depth: 0
61+
62+
- name: win_amd64 - mingw-w64
63+
# TODO: finish the windows build actions
64+
run: |
65+
# mingw-w64
66+
if [[ ${{ matrix.buildplat[0] }} == 'windows-2019' && ${{ matrix.buildplat[2] }} == 'AMD64' ]]; then
67+
choco install -y mingw
68+
export PATH="/c/Program Files/mingw-w64/x86_64-8.1.0-posix-seh-rt_v6-rev0/mingw64/bin:$PATH"
69+
echo "PATH=$PATH" >> $GITHUB_ENV
70+
fi
71+
72+
- name: windows - set PKG_CONFIG_PATH
73+
if: ${{ runner.os == 'Windows' }}
74+
run: |
75+
$env:CIBW = "${{ github.workspace }}"
76+
# It seems somewhere in the env passing, `\` is not
77+
# passed through, so convert it to '/'
78+
$env:CIBW=$env:CIBW.replace("\","/")
79+
echo "CIBW_ENVIRONMENT=PKG_CONFIG_PATH=$env:CIBW" >> $env:GITHUB_ENV
80+
81+
- name: Setup macOS
82+
if: startsWith( matrix.buildplat[0], 'macos-' )
83+
run: |
84+
if [[ ${{ matrix.buildplat[3] }} == 'accelerate' ]]; then
85+
echo CIBW_CONFIG_SETTINGS=\"setup-args=-Dblas=accelerate\" >> "$GITHUB_ENV"
86+
# Always use preinstalled gfortran for Accelerate builds
87+
ln -s $(which gfortran-13) gfortran
88+
export PATH=$PWD:$PATH
89+
echo "PATH=$PATH" >> "$GITHUB_ENV"
90+
LIB_PATH=$(dirname $(gfortran --print-file-name libgfortran.dylib))
91+
fi
92+
if [[ ${{ matrix.buildplat[4] }} == '10.13' ]]; then
93+
# 20241017 macos-13 images span Xcode 14.1-->15.2
94+
XCODE_VER='14.1'
95+
else
96+
XCODE_VER='15.2'
97+
fi
98+
CIBW="sudo xcode-select -s /Applications/Xcode_${XCODE_VER}.app"
99+
echo "CIBW_BEFORE_ALL=$CIBW" >> $GITHUB_ENV
100+
# setting SDKROOT necessary when using the gfortran compiler
101+
# installed in cibw_before_build_macos.sh
102+
sudo xcode-select -s /Applications/Xcode_${XCODE_VER}.app
103+
CIBW="MACOSX_DEPLOYMENT_TARGET=${{ matrix.buildplat[4] }}\
104+
SDKROOT=$(xcrun --sdk macosx --show-sdk-path)\
105+
PKG_CONFIG_PATH=${{ github.workspace }}"
106+
echo "CIBW_ENVIRONMENT=$CIBW" >> "$GITHUB_ENV"
107+
108+
echo "REPAIR_PATH=$LIB_PATH" >> "$GITHUB_ENV"
109+
110+
PREFIX=DYLD_LIBRARY_PATH="\$(dirname \$(gfortran --print-file-name libgfortran.dylib))"
111+
# remove libgfortran from location used for linking (if any), to
112+
# check wheel has bundled things correctly and all tests pass without
113+
# needing installed gfortran
114+
POSTFIX=" sudo rm -rf /opt/gfortran-darwin-x86_64-native &&\
115+
sudo rm -rf /usr/local/gfortran/lib"
116+
CIBW="$PREFIX delocate-listdeps -d {wheel} && echo "-----------" &&\
117+
$PREFIX delocate-wheel -v $EXCLUDE --require-archs \
118+
{delocate_archs} -w {dest_dir} {wheel} && echo "-----------" &&\
119+
delocate-listdeps -d {dest_dir}/*.whl && echo "-----------" &&\
120+
$POSTFIX"
121+
122+
# Rename x86 Accelerate wheel to test on macOS 13 runner
123+
if [[ ${{ matrix.buildplat[0] }} == 'macos-13' && ${{ matrix.buildplat[4] }} == '14.0' ]]; then
124+
CIBW+=" && mv {dest_dir}/\$(basename {wheel}) \
125+
{dest_dir}/\$(echo \$(basename {wheel}) | sed 's/14_0/13_0/')"
126+
fi
127+
128+
# macos-arm64-openblas wheels that target macos-12 need a
129+
# MACOS_DEPLOYMENT_TARGET of 12.3 otherwise delocate complains.
130+
# Unclear of cause, possibly build tool related.
131+
# This results in wheels that have 12_3 in their name. Since Python
132+
# has no concept of minor OS versions in packaging land rename the
133+
# wheel back to 12.
134+
if [[ ${{ matrix.buildplat[0] }} == 'macos-14' && ${{ matrix.buildplat[4] }} == '12.3' ]]; then
135+
CIBW+=" && echo \$(ls {dest_dir}) && \
136+
mv {dest_dir}/*.whl \$(find {dest_dir} -type f -name '*.whl' | sed 's/12_3/12_0/')"
137+
fi
138+
echo "CIBW_REPAIR_WHEEL_COMMAND_MACOS=$CIBW" >> "$GITHUB_ENV"
139+
140+
- name: Build wheels
141+
uses: pypa/cibuildwheel@7940a4c0e76eb2030e473a5f864f291f63ee879b # v2.21.3
142+
env:
143+
CIBW_BUILD: ${{ matrix.python[0] }}-${{ matrix.buildplat[1] }}*
144+
CIBW_ARCHS: ${{ matrix.buildplat[2] }}
145+
CIBW_PRERELEASE_PYTHONS: True
146+
CIBW_FREE_THREADED_SUPPORT: True
147+
CIBW_OUTPUT_DIR: ./wheelhouse
148+
CIBW_BUILD_VERBOSITY: 2
149+
CIBW_ENVIRONMENT: CFLAGS="-I/project/pyci/include" LDFLAGS="-L/project/pyci"
150+
151+
- name: Rename macOS wheels
152+
if: startsWith( matrix.buildplat[0], 'macos-' )
153+
run: |
154+
# macos-x86_64-accelerate wheels targeting macos-14 were renamed to 13
155+
# so they could be tested. Shift wheel name back to targeting 14.
156+
if [[ ${{ matrix.buildplat[0] }} == 'macos-13' && ${{ matrix.buildplat[4] }} == '14.0' ]]; then
157+
mv ./wheelhouse/*.whl $(find ./wheelhouse -type f -name '*.whl' | sed 's/13_0/14_0/')
158+
fi
159+
160+
# - name: Test the build wheels
161+
# run: |
162+
# # Install the built wheels
163+
# pip install pytest
164+
# pip install ./wheelhouse/*.whl
165+
# # Test the installed wheels
166+
# pytest project/pyci
167+
168+
- uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4.4.3
169+
with:
170+
path: ./wheelhouse/*.whl
171+
name: ${{ matrix.python[0] }}-${{ matrix.buildplat[1] }}
172+
${{ matrix.buildplat[2] }} ${{ matrix.buildplat[3] }}
173+
${{ matrix.buildplat[4] }}
174+
175+
176+
177+
# TODO: Test the build wheels
178+
# - name: Test the build wheels
179+
180+
# TODO: Upload the build wheels to the release
181+
182+
publish-to-pypi:
183+
name: Publish Python distribution to PyPI
184+
# only publish to PyPI on tag pushes
185+
if: startsWith(github.ref, 'refs/tags/')
186+
needs:
187+
- build_wheels
188+
runs-on: ubuntu-latest
189+
environment:
190+
name: PyPI-Release
191+
url: https://pypi.org/project/${{ env.PYPI_NAME }}
192+
permissions:
193+
id-token: write
194+
195+
steps:
196+
- name: Download all the dists
197+
uses: actions/download-artifact@v4
198+
with:
199+
name: python-package-distributions
200+
path: ./wheelhouse/*.whl
201+
- name: Publish distribution to PyPI
202+
uses: pypa/gh-action-pypi-publish@release/v1
203+
env:
204+
TWINE_USERNAME: "__token__"
205+
TWINE_PASSWORD: ${{ secrets.PYPI_TOKEN }}
206+
207+
github-release:
208+
name: Sign the Python distribution with Sigstore and upload them to GitHub Release
209+
needs:
210+
- publish-to-pypi
211+
runs-on: ubuntu-latest
212+
213+
permissions:
214+
contents: write
215+
id-token: write
216+
217+
steps:
218+
- name: Download all the dists
219+
uses: actions/download-artifact@v4
220+
with:
221+
name: python-package-distributions
222+
path: ./wheelhouse
223+
- name: Sign the dists with Sigstore
224+
uses: sigstore/[email protected]
225+
with:
226+
inputs: >-
227+
./wheelhouse/*.whl
228+
229+
- name: Create GitHub Release
230+
env:
231+
GITHUB_TOKEN: ${{ github.token }}
232+
run: >-
233+
gh release create
234+
"${{ github.ref_name }}"
235+
--repo "${{ github.repository }}"
236+
--notes ""
237+
- name: Upload artifact signatures to GitHub Release
238+
env:
239+
GITHUB_TOKEN: ${{ github.token }}
240+
run: >-
241+
gh release upload
242+
"${{ github.ref_name }}" wheelhouse/**
243+
--repo "${{ github.repository }}"
244+
245+
publish-to-testpypi:
246+
name: Publish Python distribution to TestPyPI
247+
# if: ${{ github.ref == "refs/heads/master" && github.repository_owner == "theochem" }}
248+
needs:
249+
- build_wheels
250+
runs-on: ubuntu-latest
251+
252+
environment:
253+
name: TestPyPI
254+
url: https://test.pypi.org/project/${{ env.PYPI_NAME }}
255+
256+
permissions:
257+
id-token: write
258+
259+
steps:
260+
- name: Download all the dists
261+
uses: actions/download-artifact@v4
262+
with:
263+
name: python-package-distributions
264+
path: wheelhouse/
265+
- name: Publish distribution to TestPyPI
266+
uses: pypa/gh-action-pypi-publish@release/v1
267+
with:
268+
repository-url: https://test.pypi.org/legacy/
269+
env:
270+
TWINE_USERNAME: "__token__"
271+
TWINE_PASSWORD: ${{ secrets.TEST_PYPI_TOKEN }}

Makefile

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ all: pyci/_pyci.so.$(PYCI_VERSION) pyci/_pyci.so.$(VERSION_MAJOR) pyci/_pyci.so
7474

7575
.PHONY: test
7676
test:
77-
$(PYTHON) -m pytest -sv ./pyci
77+
@set -e; $(PYTHON) -m pytest -sv ./pyci
7878

7979
.PHONY: clean
8080
clean:
@@ -104,13 +104,13 @@ pyci/_pyci.so: pyci/_pyci.so.$(PYCI_VERSION)
104104
ln -sf $(notdir $(<)) $(@)
105105

106106
deps/eigen:
107-
@git clone https://gitlab.com/libeigen/eigen.git $(@)
107+
[ -d $@ ] || git clone https://gitlab.com/libeigen/eigen.git $@
108108

109109
deps/spectra:
110-
@git clone https://github.com/yixuan/spectra.git $(@)
110+
[ -d $@ ] || git clone https://github.com/yixuan/spectra.git $@
111111

112112
deps/parallel-hashmap:
113-
@git clone https://github.com/greg7mdp/parallel-hashmap.git $(@)
113+
[ -d $@ ] || git clone https://github.com/greg7mdp/parallel-hashmap.git $@
114114

115115
deps/pybind11:
116-
@git clone https://github.com/pybind/pybind11.git $(@)
116+
[ -d $@ ] || git clone https://github.com/pybind/pybind11.git $@

pyci/test/test_routines.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -307,7 +307,7 @@ def test_run_hci(filename, wfn_type, occs, energy):
307307
assert len(wfn) == np.prod([comb(wfn.nbasis, occ, exact=True) for occ in occs])
308308
else:
309309
assert len(wfn) == comb(wfn.nbasis, occs[0], exact=True)
310-
npt.assert_allclose(es[0], energy, rtol=0.0, atol=1.0e-9)
310+
npt.assert_allclose(es[0], energy, rtol=0.0, atol=2.0e-9)
311311

312312

313313
@pytest.mark.parametrize(

pyproject.toml

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,10 @@
22
[build-system]
33
# Required packages for building the project
44
requires = [
5-
# "scikit-build-core >= 0.9.10",
65
"setuptools_scm>=8", # For version management
76
"setuptools>=61.0.0", # For building the package
87
"pytest>=8.0.0", # For running tests
98
]
10-
# build-backend = "scikit_build_core.build"
11-
build-backend = "setuptools.build_meta"
129

1310
[project]
1411
# Basic project metadata
@@ -76,13 +73,14 @@ packages = [
7673
"pyci",
7774
"pyci.fanci",
7875
"pyci.test",
79-
"pyci.fanci.test"
76+
"pyci.fanci.test",
8077
]
8178

8279
[tool.setuptools.package-data]
8380
# Non-Python files to include in the package
8481
"pyci" = [
8582
"_pyci.so", # Compiled C++ extension
83+
"_pyci.so.0.6.1", # Compiled C++ extension
8684
"include/*.h", # C++ header files
8785
"src/*.cpp" # C++ source files
8886
]
@@ -91,15 +89,19 @@ packages = [
9189
"data/*.npy", # NumPy data files
9290
"data/*.npz" # Compressed NumPy data files
9391
]
94-
95-
# Build configuration
96-
[tool.scikit-build]
97-
sdist.exclude = [
98-
".github",
99-
"tests/data/*.fchk",
100-
"examples/*.fchk"
92+
"pyci.fanci.test" = [
93+
"data/*.fcidump", # Test input files
94+
"data/*.npy", # NumPy data files
95+
"data/*.npz" # Compressed NumPy data files
10196
]
102-
metadata.version.provider = "scikit_build_core.metadata.setuptools_scm"
97+
98+
[tool.cibuildwheel]
99+
# Switch to using build
100+
build-frontend = "build"
101+
102+
[tool.cibuildwheel.linux]
103+
before-build = "bash {project}/tools/wheels/cibw_before_build_linux.sh"
104+
103105

104106
# Version management configuration
105107
[tool.setuptools_scm]

setup.cfg

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,6 @@ add_ignore=D100,D101,D102,D103,D104,D105,D302,D401,D413
44
[pycodestyle]
55
max-line-length=100
66
ignore=E127,E201,E203,E231,E241,E402,E741
7+
8+
[options.package_data]
9+
pyci = _pyci.so

0 commit comments

Comments
 (0)