Skip to content

Commit 04b36d5

Browse files
committed
Enable building abi3 shared objects
This depends on PyO3/pyo3#1125
1 parent 9fcd0e7 commit 04b36d5

File tree

6 files changed

+71
-12
lines changed

6 files changed

+71
-12
lines changed

.github/workflows/ci.yml

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,3 +67,47 @@ jobs:
6767
pip install --no-use-pep517 -e rust_with_cffi/
6868
pip install -r rust_with_cffi/requirements-dev.txt
6969
pytest rust_with_cffi/tests.py
70+
test-abi3:
71+
runs-on: ${{ matrix.os }}
72+
strategy:
73+
matrix:
74+
os: [ubuntu-latest, macos-latest, windows-latest]
75+
steps:
76+
- uses: actions/checkout@master
77+
- name: Setup python
78+
uses: actions/setup-python@v2
79+
with:
80+
python-version: 3.6
81+
82+
- uses: actions-rs/toolchain@v1
83+
with:
84+
profile: minimal
85+
toolchain: stable
86+
override: true
87+
88+
- name: Build package
89+
run: pip install -e .
90+
91+
- name: Build an abi3 wheel
92+
shell: bash
93+
run: |
94+
cd examples/rust_with_cffi/
95+
python --version
96+
python setup.py bdist_wheel --py-limited-api=cp35
97+
ls -la dist/
98+
99+
# Now we switch to a differnet Python version and ensure we can install
100+
# the wheel we just buitl.
101+
- name: Setup python
102+
uses: actions/setup-python@v2
103+
with:
104+
python-version: 3.8
105+
106+
- name: Install abi3 wheel and run tests
107+
shell: bash
108+
run: |
109+
cd examples/
110+
python --version
111+
pip install rust_with_cffi/dist/rust_with_cffi*.whl
112+
python -c "from rust_with_cffi import rust; assert rust.rust_func() == 14"
113+
python -c "from rust_with_cffi.cffi import lib; assert lib.cffi_func() == 15"

examples/rust_with_cffi/Cargo.lock

Lines changed: 6 additions & 9 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

examples/rust_with_cffi/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ authors = ["Alex Gaynor <[email protected]>"]
55
edition = "2018"
66

77
[dependencies]
8-
pyo3 = { version = "0.12.1", features = ["extension-module"] }
8+
pyo3 = { git = "https://github.com/alex/pyo3", branch="abi3-link-python3", features = ["extension-module", "abi3"] }
99

1010
[lib]
1111
name = "rust_with_cffi"

examples/rust_with_cffi/setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
"Operating System :: MacOS :: MacOS X",
2222
],
2323
packages=["rust_with_cffi"],
24-
rust_extensions=[RustExtension("rust_with_cffi.rust")],
24+
rust_extensions=[RustExtension("rust_with_cffi.rust", py_limited_api=True)],
2525
cffi_modules=["cffi_module.py:ffi"],
2626
install_requires=install_requires,
2727
setup_requires=setup_requires,

setuptools_rust/build.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -285,7 +285,16 @@ def build_extension(self, ext):
285285

286286
ext.install_script(ext_path)
287287
else:
288-
ext_path = build_ext.get_ext_fullpath(target_fname)
288+
# Technically it's supposed to contain a
289+
# `setuptools.Extension`, but in practice the only attribute it
290+
# checks is `ext.py_limited_api`.
291+
modpath = target_fname.split('.')[-1]
292+
assert modpath not in build_ext.ext_map
293+
build_ext.ext_map[modpath] = ext
294+
try:
295+
ext_path = build_ext.get_ext_fullpath(target_fname)
296+
finally:
297+
del build_ext.ext_map[modpath]
289298

290299
try:
291300
os.makedirs(os.path.dirname(ext_path))

setuptools_rust/extension.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,10 @@ class RustExtension:
4747
optional : bool
4848
if it is true, a build failure in the extension will not abort the
4949
build process, but instead simply not install the failing extension.
50+
py_limited_api : bool
51+
Same as `py_limited_api` on `setuptools.Extension`. Note that if you
52+
set this to True, your extension must pass the appropriate feature
53+
flags to pyo3 (ensuring that `abi3` feature is enabled).
5054
"""
5155

5256
def __init__(
@@ -64,6 +68,7 @@ def __init__(
6468
script=False,
6569
native=False,
6670
optional=False,
71+
py_limited_api=False,
6772
):
6873
if isinstance(target, dict):
6974
name = "; ".join("%s=%s" % (key, val) for key, val in target.items())
@@ -83,6 +88,10 @@ def __init__(
8388
self.script = script
8489
self.native = native
8590
self.optional = optional
91+
self.py_limited_api = py_limited_api
92+
# We pass this over to setuptools in one place, and it wants this
93+
# attribute to exist.
94+
self._links_to_dynamic = False
8695

8796
if features is None:
8897
features = []

0 commit comments

Comments
 (0)