Conversation
awscrt (aws-crt-python) builds its C extension against the AWS Common Runtime C libraries, AWS-LC and s2n-tls, all vendored as submodules and compiled from source by setup.py's build_ext. AWS-LC recognises riscv64 in its CMakeLists.txt and falls back to portable C there, so no architecture work is needed beyond building in the manylinux_riscv64 image. setup.py chooses the wheel tag from the interpreter it runs on, so the matrix is over build interpreters rather than output tags: cp312 emits cp311-abi3, cp313 emits cp313-abi3 (3.13 dropped PyWeakref_GetObject, so upstream cuts a second stable-ABI wheel there) and cp314t emits cp314-cp314t (free-threaded builds cannot use the limited API). That is the same set upstream's continuous-delivery/build-wheels-manylinux2014-*.sh builds, minus cp39/cp310 which predate our floor. Tests are upstream's `python -m unittest discover`, run with AWS_TEST_LOCALHOST=1 the way its .builder action does. The h2 mock-server tests load a helper and TLS material from the aws-c-http submodule via test/../crt/aws-c-http/tests/, so those two directories are staged alongside test/ in CIBW_TEST_SOURCES; staging test/ on its own also keeps the checkout's awscrt/ package from shadowing the installed wheel. Verified against the released 0.36.2 wheel on macOS: 499 tests, 250 skipped, no failures.
Two fixes from the first CI run.
The wheels came out named awscrt-1.0.0.dev0: setup.py reads
awscrt/__init__.py's __version__, which carries a 1.0.0.dev0 placeholder
in git. Upstream's continuous-delivery/build-wheels-manylinux2014-*.sh
runs continuous-delivery/update-version.py as its very first step to
rewrite it from `git describe --tags`; do the same, and assert the
result matches the requested tag so a bad describe fails in seconds
rather than after the build.
The two abi3 jobs then failed cibuildwheel's default audit,
`abi3audit --strict --report {abi3_wheel}`, with "17 ABI violations".
Those 17 are awscrt's own helpers declared in source/module.h
(PyErr_AwsLastError, PyObject_GetAttrAsBool, PyUnicode_FromAwsString,
...): they are Py-prefixed but are not CPython API, and abi3audit
matches on the name. They are defined in _awscrt.abi3.so (st_shndx
points at a real section, not UND), not imported from libpython, and
abi3audit reports is_abi3_baseline_compatible=true / baseline 3.11 in
the same breath. Upstream's released
awscrt-0.36.2-cp311-abi3-manylinux2014_aarch64 wheel fails the same
check with the same 17 symbols, with and without --strict, so there is
nothing riscv64-specific to fix and no exit code to relax. Disable the
audit step; auditwheel repair still runs.
cp314t was unaffected (not an abi3 wheel, so the {abi3_wheel} command is
skipped) and went green: 499 tests, 248 skipped, 14 minutes end to end.
awscrt's source/module.h defines PY_SSIZE_T_CLEAN and the extension parses "s#"/"z#" in ~40 places, which is exactly the shape that makes an abi3 wheel's build interpreter load-bearing: the wheel is tagged from setup.py's py_limited_api regardless of which headers compiled it, so building the cp311-abi3 wheel on cp312 mislabels it for every 3.11 consumer. Build each abi3 wheel on the oldest interpreter its tag claims and let cibuildwheel's find_compatible_wheel re-test it on the next one, which is also what upstream's release script does (it builds cp311 and cp313, not cp312 and cp313). Splitting the two abi3 tags across separate jobs is what keeps find_compatible_wheel from collapsing them: cp313 would otherwise reuse the cp311-abi3 wheel and no cp313-abi3 wheel would be produced at all. The two abi3 jobs now run the suite twice each, so this also doubles interpreter coverage of the tests.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds
.github/workflows/build-awscrt.yml, building riscv64 wheels for awscrt (aws-crt-python) 0.36.2.Shape
Build-from-checkout with cibuildwheel. awscrt vendors the whole AWS Common Runtime C stack as submodules (
crt/aws-c-*,crt/aws-checksums,crt/aws-lc,crt/s2n) andsetup.py'sbuild_extruns CMake overcrt/before compiling_awscrt, so the only riscv64-specific setting isCIBW_MANYLINUX_RISCV64_IMAGE. AWS-LC enumerates riscv64 in itsCMakeLists.txt(elseif(CMAKE_SYSTEM_PROCESSOR_LOWER STREQUAL "riscv64") set(ARCH "riscv64")) and defines noCRYPTO_ARCH_SOURCESfor it, so it falls back to portable C — the only two files in the tree that mentionOPENSSL_RISCV64areinclude/openssl/target.handcrypto/rand_extra/getrandom_fillin.h.crt/CMakeLists.txtalready passes-DDISABLE_GO=ON -DDISABLE_PERL=ON -DBUILD_TESTING=OFFto AWS-LC, so none of the usual manylinux host-tooling gaps apply.Upstream's release script (
continuous-delivery/build-wheels-manylinux2014-aarch64.sh) stamps the version first:awscrt/__init__.pycarries a1.0.0.dev0placeholder in git andsetup.py's_load_version()reads it, so withoutcontinuous-delivery/update-version.pyevery wheel is namedawscrt-1.0.0.dev0. The workflow runs that same script and greps the result against the requested tag, so a badgit describefails in seconds instead of after the build.Matrix
setup.pypicks the wheel tag from the interpreter it runs on (abdist_wheelsubclass pluspy_limited_apicomputed inawscrt_ext()), so the matrix is over build interpreters and the tag is what falls out. Each abi3 wheel is built on the oldest interpreter its tag claims and only re-tested on the next one viafind_compatible_wheel— awscrt definesPY_SSIZE_T_CLEANand parses"s#"/"z#"in about forty places, which is precisely the shape that makes the build interpreter load-bearing for an abi3 wheel, so cp311 is in the matrix despite our cp312 floor. That is also exactly what upstream builds (cp311 and cp313, not cp312 and cp313); cp39/cp310 are dropped as below our floor.CIBW_BUILDcp311-… cp312-…cp311-abi3cp313-… cp314-…cp313-abi3PyWeakref_GetObject(), so upstream cuts a second stable-ABI wheelcp314t-…cp314-cp314tThe two abi3 tags have to live in separate jobs: put cp313 in job 1 and
find_compatible_wheelreuses thecp311-abi3wheel for it, and nocp313-abi3wheel is ever produced.Tests
Upstream's
.builder/actions/aws_crt_python.pyrunspython -m unittest discover --verbosewithAWS_TEST_LOCALHOST=1, so that is whatCIBW_TEST_COMMAND/CIBW_TEST_ENVIRONMENTdo here. Test requirements are the two testing entries from upstream'sdevextra (websockets>=13.1,h2==4.1.0); the rest of that extra is Sphinx/autopep8/build tooling. websockets publishes riscv64 wheels on PyPI for cp311 through cp314t and h2 is pure Python, so nothing has to compile from sdist.CIBW_TEST_SOURCESstagestest crt/aws-c-http/tests/mock_server crt/aws-c-http/tests/resources. The h2 mock-server tests intest_http_client.py/test_aiohttp_client.pyspawntest/../crt/aws-c-http/tests/mock_server/h2tls_mock_server.py, which in turn loads../resources/unittests.crt|key, andtest-sourcespreserves each staged path relative to the project root so those__file__-relative lookups keep resolving. Stagingtest/on its own is also what stops the checkout'sawscrt/package at the repo root from shadowing the installed wheel — note the sdist prunescrt/aws-c-http/tests, so this only works because we build from a checkout with submodules.Dry-ran the test phase against the released 0.36.2 PyPI wheel on macOS/arm64 the way
test-sourcesstages it: 499 tests, 250 skipped, no failures. Without the mock-server directories staged, 10 tests error insetUpwithAttributeError: 'NoneType' object has no attribute 'decode'(the server never starts and_wait_for_server_readymishandles the missing pipes) — that is how the staged path list was arrived at. The 250 skips are the tests gated on AWS credentials and IoT/proxy endpoints (AWS_TEST_S3,AWS_TEST_MQTT311_*,AWS_TEST_HTTP_PROXY_*, …), which upstream also only runs with its CI role assumed.CIBW_AUDIT_COMMAND: ''cibuildwheel's default audit,
abi3audit --strict --report {abi3_wheel}, fails both abi3 wheels with "17 ABI violations". The 17 are awscrt's own helpers declared insource/module.h—PyErr_AwsLastError,PyObject_GetAttrAsBool,PyUnicode_FromAwsString,PyObject_GetAsOptionalUint64, … — which arePy-prefixed but are not CPython API; abi3audit matches on the name. They are defined in_awscrt.abi3.so(st_shndxpoints at a real section, notUND), not imported from libpython, and abi3audit reportsis_abi3_baseline_compatible: true/baseline: 3.11in the same breath. Running abi3audit on upstream's releasedawscrt-0.36.2-cp311-abi3-manylinux2014_aarch64.whlgives the identical 17 symbols and exits 1 both with and without--strict, so there is nothing riscv64-specific here and no exit code to relax.auditwheel repairstill runs.Licensing
The wheel ships
LICENSEandNOTICEindist-info/licenses/already. Nothing else was needed: AWS-LC, s2n-tls and everyaws-c-*library are Amazon-owned and Apache-2.0 (AWS-LC additionally ISC, for its BoringSSL/OpenSSL heritage, reproduced in full incrt/aws-lc/LICENSE), and awscrt's ownNOTICEalready carries the one non-Amazon attribution that is compiled in (xxHash, BSD-2-Clause).Validation
python -c "import yaml; yaml.safe_load(...)"andactionlintclean apart from the usuallabel "ubuntu-24.04-riscv" is unknown.crt/aws-lcunder--platform linux/riscv64inquay.io/pypa/manylinux_2_39_riscv64: configure and generate both succeed with the image's CMake 4.4.2 (well past everycmake_minimum_requiredin the vendored tree) and GCC 14.3.1, and arch detection lands onriscv64.cp314twent green on the real runner with 499 tests, 248 skipped, no failures, 14 minutes end to end including the full AWS-LC/s2n/aws-c-*compile — so the C stack itself needed nothing. The two abi3 jobs failed only on the abi3audit and version issues described above.CI (run 33036859139)
All three jobs green, and every wheel is exercised on both interpreters its tag covers — 499 tests, 248 skipped, no failures, five times over:
awscrt-0.36.2-cp311-abi3-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whlFound previously built wheel …, that's compatible with cp312-manylinux_riscv64)awscrt-0.36.2-cp313-abi3-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whlawscrt-0.36.2-cp314-cp314t-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whlEach wheel carries a real
_awscrtextension (9.7–10.0 MB.so, statically linked against-laws-c-s3 -laws-c-mqtt -laws-c-auth -laws-c-http -laws-c-event-stream -laws-c-compression -laws-checksums -laws-c-io -laws-c-cal -laws-c-sdkutils -laws-c-common -ls2n -lcrypto), asserted by theCheck wheel contains the compiled extensionstep. The publish job dry-ran cleanly:Dry run (not on main branch — no upload will happen)/Would upload 3 file(s).