I am trying to force a Python3 non-universal wheel I'm building to be a platform wheel, despite not having any native build steps that happen during the distribution-packaging process.
The wheel will include an OS-specific shared library, but that library is built and copied into my package directory by a larger build system that my package knows nothing about. By the time my Python3 package is ready to be built into a wheel, my build system has already built the native shared library and copied it into the package directory.
This SO post details a solution that works for the now-deprecated setup.py
approach, but I'm unsure how to accomplish the same result using the new and now-standard build
/ pyproject.toml
system:
mypackage/
mypackage.py # Uses platform.system and importlib to load the local OS-specific library
pyproject.toml
mysharedlib.so # Or .dylib on macOS, or .dll on Windows
Based on the host OS performing the build, I would like the resulting wheel to be manylinux
, macos
, or windows
.
I build with python3 -m build --wheel
, and that always emits mypackage-0.1-py3-none-any.whl
.
What do I have to change to force the build to emit a platform wheel?
Update 2 Sept 2023:
-C=--build-option=--plat {your-platform-tag}
no longer works, so I added my preferred replacement to the end of the list.
==========
OK, after some research and reading of code, I can present a bit of information and a few solutions that might meet other people's needs, summarized here:
Firstly, pyproject.toml
is not mutually exclusive from setup.py
. setuptools
will complain about deprecation if you create a distribution package via python3 setup.py ...
and no pyproject.toml
file is present.
However, setup.py
is still around and available, but it's a mistake to duplicate project configuration values (name
, version
, etc). So, put as much as your package will allow inside your pyproject.toml
file, and use setup.py
for things like overriding the Distribution
class, or overriding the bdist_wheel
module, etc.
As far as creating platform wheels, there are a few approaches that work, with pros and cons:
bdist_wheel
command class in setup.py
as described here and set self.root_is_pure
to False in the finalize_options
override. This forces the python tag (e.g. cp39
) to be set, along with the platform tag.Distribution
class in setup.py
as described here and override has_ext_modules()
to simply return True. This also forces the python and platform tags to be set.-C=--build-option=--plat {your-platform-tag}
to the build invocation (for my case that's python -m build -w -n
, for example). This leaves the Python tag untouched but you have to supply your own tag; there's no way to say "use whatever the native platform is". You can discover the exact platform tag with the command wheel.bdist_wheel.get_platform(pathlib.Path('.'))
after importing the pathlib
and wheel.bdist_wheel
packages, but that can be cumbersome because wheel
isn't a standard library package.mypkg-py3-none-any.whl
to mypkg-py3-none-macosx_13_0_x86_64.whl
- it appears that the platform tag is only encoded into the filename, and not any of the package metadata that's generated during the distribution-package process.wheel
package utility to update the tags, to turn the pure wheel into a platform wheel. python -m wheel tags --platform-tag macosx_13_0_x86_64 mypkg-py3-none-any.whl
will emit a new platform wheel with the tags you want.In the end I chose the final options because it required the least amount of work- no setup.py
files need to be introduced solely to accomplish this, and the build logs make it clear that a platform wheel (not a pure wheel) is being created.