Skip to content

Commit

Permalink
Move Wheel-related options to their own section
Browse files Browse the repository at this point in the history
  • Loading branch information
tttapa committed Jun 4, 2024
1 parent dc9df06 commit dc21bfe
Show file tree
Hide file tree
Showing 10 changed files with 139 additions and 48 deletions.
13 changes: 12 additions & 1 deletion docs/Config.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,14 @@ Defines how to build the project to package. If omitted, py-build-cmake will pro
| `install_args` | Extra arguments passed to the install step.<br/>For example: `install_args = ["--strip"]` | list+ | `[]` |
| `install_components` | List of components to install, the install step is executed once for each component, with the option `--component <?>`.<br/>Use an empty string to specify the default component. | list | `['']` |
| `env` | Environment variables to set when running CMake. Supports variable expansion using `${VAR}` (but not `$VAR`).<br/>For example: `env = { "CMAKE_PREFIX_PATH" = "${HOME}/.local" }` | dict | `{}` |
| `pure_python` | Indicate that this package contains no platform-specific binaries, only Python scripts and other platform-agnostic files. It causes the Wheel tags to be set to `py3-none-any`.<br/>For example: `pure_python = true` | bool | `false` |

## wheel
Defines how to create the Wheel package.

| Option | Description | Type | Default |
|--------|-------------|------|---------|
| `pure_python` | Indicate that this package contains no platform-specific binaries, only Python scripts and other platform-agnostic files. Setting this value to true causes the Wheel tags to be set to `py3-none-any`. If unset, the value depends on whether the `cmake` option is set.<br/>For example: `pure_python = true` | bool | `none` |
| `python_tag` | Override the default Python tag for the Wheel package.<br/>If your package contains any Python extension modules, you want to set this to `auto`.<br/>For details about platform compatibility tags, see the PyPA specification: https://packaging.python.org/en/latest/specifications/platform-compatibility-tags<br/>For example: `python_tag = 'py2.py3'` | string | `'auto'` |
| `python_abi` | Override the default ABI tag for the Wheel package.<br/>For packages with a Python extension module that make use of the full Python C API, this option should be set to `auto`.<br/>If your package does not contain Python extension modules (e.g. because it only includes executables to run as a subprocess, or only shared library files to be loaded using `ctypes`), you can set this to `none`.<br/>If your package only includes Python extension modules that use the CPython stable ABI, set this to `abi3` (see also `abi3_minimum_cpython_version` below).<br/>For details about platform compatibility tags, see the PyPA specification: https://packaging.python.org/en/latest/specifications/platform-compatibility-tags<br/>For example: `python_abi = 'none'` | `'auto'` \| `'none'` \| `'abi3'` | `'auto'` |
| `abi3_minimum_cpython_version` | If `python_abi` is set to `abi3`, only use the stable CPython API for CPython version that are newer than `abi3_minimum_version`. Useful for nanobind, which supports the stable ABI for CPython 12 and later.<br/>The Python version is encoded as a single integer, consisting of the major and minor version numbers, without a dot.<br/>For example: `abi3_minimum_cpython_version = 312` | int | `32` |

Expand All @@ -74,6 +81,7 @@ Override options for Linux.
| `editable` | Linux-specific editable options.<br/>Inherits from: `/pyproject.toml/tool/py-build-cmake/editable` | | `none` |
| `sdist` | Linux-specific sdist options.<br/>Inherits from: `/pyproject.toml/tool/py-build-cmake/sdist` | | `none` |
| `cmake` | Linux-specific CMake options.<br/>Inherits from: `/pyproject.toml/tool/py-build-cmake/cmake` | | `none` |
| `wheel` | Linux-specific Wheel options.<br/>Inherits from: `/pyproject.toml/tool/py-build-cmake/wheel` | | `none` |

## windows
Override options for Windows.
Expand All @@ -83,6 +91,7 @@ Override options for Windows.
| `editable` | Windows-specific editable options.<br/>Inherits from: `/pyproject.toml/tool/py-build-cmake/editable` | | `none` |
| `sdist` | Windows-specific sdist options.<br/>Inherits from: `/pyproject.toml/tool/py-build-cmake/sdist` | | `none` |
| `cmake` | Windows-specific CMake options.<br/>Inherits from: `/pyproject.toml/tool/py-build-cmake/cmake` | | `none` |
| `wheel` | Windows-specific Wheel options.<br/>Inherits from: `/pyproject.toml/tool/py-build-cmake/wheel` | | `none` |

## mac
Override options for Mac.
Expand All @@ -92,6 +101,7 @@ Override options for Mac.
| `editable` | Mac-specific editable options.<br/>Inherits from: `/pyproject.toml/tool/py-build-cmake/editable` | | `none` |
| `sdist` | Mac-specific sdist options.<br/>Inherits from: `/pyproject.toml/tool/py-build-cmake/sdist` | | `none` |
| `cmake` | Mac-specific CMake options.<br/>Inherits from: `/pyproject.toml/tool/py-build-cmake/cmake` | | `none` |
| `wheel` | Mac-specific Wheel options.<br/>Inherits from: `/pyproject.toml/tool/py-build-cmake/wheel` | | `none` |

## cross
Causes py-build-cmake to cross-compile the project. See https://tttapa.github.io/py-build-cmake/Cross-compilation.html for more information.
Expand All @@ -110,6 +120,7 @@ Causes py-build-cmake to cross-compile the project. See https://tttapa.github.io
| `editable` | Override editable options when cross-compiling.<br/>Inherits from: `/pyproject.toml/tool/py-build-cmake/editable` | | `none` |
| `sdist` | Override sdist options when cross-compiling.<br/>Inherits from: `/pyproject.toml/tool/py-build-cmake/sdist` | | `none` |
| `cmake` | Override CMake options when cross-compiling.<br/>Inherits from: `/pyproject.toml/tool/py-build-cmake/cmake` | | `none` |
| `wheel` | Override Wheel options when cross-compiling.<br/>Inherits from: `/pyproject.toml/tool/py-build-cmake/wheel` | | `none` |

# Local overrides

Expand Down
2 changes: 1 addition & 1 deletion examples/minimal-program/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ should be in `${PY_BUILD_CMAKE_PACKAGE_NAME}-${PY_BUILD_CMAKE_PACKAGE_VERSION}.d
as per [PEP 427](https://peps.python.org/pep-0427/). Pip will then automatically
install it to a folder that's in the `PATH`.
Since there are no Python extension modules with specific ABI requirements for
the Python interpreter, `tool.py-build-cmake.cmake.python_abi` is set
the Python interpreter, `tool.py-build-cmake.wheel.python_abi` is set
to `'none'`.

For more information about the file structure and the configuration files,
Expand Down
1 change: 1 addition & 0 deletions examples/minimal-program/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ build_args = ["-j"]
install_components = ["python_binaries"]
find_python = false
find_python3 = false
[tool.py-build-cmake.wheel]
python_abi = "none"

[tool.pytest.ini_options]
Expand Down
1 change: 1 addition & 0 deletions examples/nanobind-project/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ build_tool_args = []
install_args = ["--verbose"]
install_components = ["python_modules"]
env = {}
[tool.py-build-cmake.wheel]
python_abi = 'abi3'
abi3_minimum_cpython_version = 312

Expand Down
14 changes: 11 additions & 3 deletions src/py_build_cmake/build.py
Original file line number Diff line number Diff line change
Expand Up @@ -327,7 +327,8 @@ def create_wheel(
whl = Wheel()
whl.name = package_info.norm_name
whl.version = package_info.version
pure = is_pure(cmake_cfg)
wheel_cfg = _BuildBackend.get_wheel_config(cfg)
pure = is_pure(wheel_cfg, cmake_cfg)
libdir = "purelib" if pure else "platlib"
staging_dir = paths.pkg_staging_dir
whl_paths = {"prefix": str(staging_dir), libdir: str(staging_dir)}
Expand All @@ -336,10 +337,10 @@ def create_wheel(
tags = {"pyver": ["py3"]}
elif cfg.cross:
tags = get_cross_tags(cfg.cross)
tags = convert_wheel_tags(tags, cmake_cfg)
tags = convert_wheel_tags(tags, wheel_cfg, cmake_cfg)
else:
tags = get_native_tags()
tags = convert_wheel_tags(tags, cmake_cfg)
tags = convert_wheel_tags(tags, wheel_cfg, cmake_cfg)
wheel_path = whl.build(whl_paths, tags=tags, wheel_version=(1, 0))
logger.debug("Built Wheel: %s", wheel_path)
return str(Path(wheel_path).relative_to(paths.wheel_dir))
Expand All @@ -353,6 +354,13 @@ def get_cmake_config(cfg: Config):
else:
return cfg.cmake["cross"]

@staticmethod
def get_wheel_config(cfg: Config):
if cfg.cross is None:
return cfg.wheel[util.get_os_name()]
else:
return cfg.wheel["cross"]

# --- Building sdists -----------------------------------------------------

def do_build_sdist(self, sdist_directory, config_settings):
Expand Down
1 change: 1 addition & 0 deletions src/py_build_cmake/common/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ class Config:
editable: dict[str, dict[str, Any]] = field(default_factory=dict)
sdist: dict[str, dict[str, Any]] = field(default_factory=dict)
cmake: dict[str, dict[str, Any]] | None = field(default=None)
wheel: dict[str, dict[str, Any]] = field(default_factory=dict)
stubgen: dict[str, Any] | None = field(default=None)
cross: dict[str, Any] | None = field(default=None)

Expand Down
9 changes: 8 additions & 1 deletion src/py_build_cmake/config/load.py
Original file line number Diff line number Diff line change
Expand Up @@ -292,6 +292,13 @@ def get_sdist_cludes(v: ValueReference) -> dict[str, Any]:
}
cfg.cmake = cfg.cmake or None

# Store the Wheel configuration
cfg.wheel = {
os: cast(Dict[str, Any], pbc_value_ref.get_value(ConfPath((os, "wheel"))))
for os in ("linux", "windows", "mac", "cross")
if pbc_value_ref.is_value_set(ConfPath((os, "wheel")))
}

# Store stubgen configuration
s = "stubgen"
if pbc_value_ref.is_value_set(s):
Expand All @@ -302,7 +309,7 @@ def get_sdist_cludes(v: ValueReference) -> dict[str, Any]:
if pbc_value_ref.is_value_set(s):
cfg.cross = copy(cast(Optional[Dict[str, Any]], pbc_value_ref.get_value(s)))
if cfg.cross is not None:
for k in ("cmake", "sdist", "editable"):
for k in ("cmake", "wheel", "sdist", "editable"):
cfg.cross.pop(k, None)

# Check for incompatible options
Expand Down
38 changes: 34 additions & 4 deletions src/py_build_cmake/config/options/pyproject_options.py
Original file line number Diff line number Diff line change
Expand Up @@ -234,13 +234,35 @@ def get_options(project_path: Path | PurePosixPath, *, test: bool = False):
"env = { \"CMAKE_PREFIX_PATH\" "
"= \"${HOME}/.local\" }",
default=DefaultValueValue({})),
]) # fmt: skip

# [tool.py-build-cmake.wheel]
wheel = pbc.insert(
ConfigOption("wheel",
"Defines how to create the Wheel package.",
default=DefaultValueValue({}),
)) # fmt: skip
wheel_pth = ConfPath.from_string("pyproject.toml/tool/py-build-cmake/wheel")
wheel.insert_multiple([
BoolConfigOption("pure_python",
"Indicate that this package contains no platform-"
"specific binaries, only Python scripts and other "
"platform-agnostic files. It causes the Wheel tags "
"to be set to `py3-none-any`.",
"pure_python = true",
default=DefaultValueValue(False)),
"platform-agnostic files. Setting this value to true "
"causes the Wheel tags to be set to `py3-none-any`. "
"If unset, the value depends on whether the `cmake` "
"option is set.",
"pure_python = true"),
StringConfigOption("python_tag",
"Override the default Python tag for the Wheel "
"package.\n"
"If your package contains any Python extension "
"modules, you want to set this to `auto`.\n"
"For details about platform compatibility tags, "
"see the PyPA specification: "
"https://packaging.python.org/en/latest/"
"specifications/platform-compatibility-tags",
"python_tag = 'py2.py3'",
default=DefaultValueValue("auto")),
EnumConfigOption("python_abi",
"Override the default ABI tag for the Wheel package.\n"
"For packages with a Python extension module that "
Expand Down Expand Up @@ -318,6 +340,10 @@ def get_options(project_path: Path | PurePosixPath, *, test: bool = False):
f"{system}-specific CMake options.",
inherit_from=cmake_pth,
create_if_inheritance_target_exists=True),
ConfigOption("wheel",
f"{system}-specific Wheel options.",
inherit_from=wheel_pth,
create_if_inheritance_target_exists=True),
]) # fmt: skip

# [tool.py-build-cmake.cross]
Expand Down Expand Up @@ -413,6 +439,10 @@ def get_options(project_path: Path | PurePosixPath, *, test: bool = False):
"Override CMake options when cross-compiling.",
inherit_from=cmake_pth,
create_if_inheritance_target_exists=True),
ConfigOption("wheel",
"Override Wheel options when cross-compiling.",
inherit_from=wheel_pth,
create_if_inheritance_target_exists=True),
]) # fmt: skip

return root
Expand Down
28 changes: 16 additions & 12 deletions src/py_build_cmake/export/tags.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,39 +19,43 @@ def get_cross_tags(crosscfg: dict[str, Any]) -> WheelTags:
return tags


def convert_abi_tag(abi_tag: str, cmake_cfg: dict | None) -> str:
def convert_abi_tag(abi_tag: str, wheel_cfg: dict, cmake_cfg: dict | None) -> str:
"""Set the ABI tag to 'none' or 'abi3', depending on the config options
specified by the user."""
if not cmake_cfg:
return "none"
elif cmake_cfg["python_abi"] == "auto":
elif wheel_cfg["python_abi"] == "auto":
return abi_tag
elif cmake_cfg["python_abi"] == "none":
elif wheel_cfg["python_abi"] == "none":
return "none"
elif cmake_cfg["python_abi"] == "abi3":
elif wheel_cfg["python_abi"] == "abi3":
# Only use abi3 if we're actually building for CPython
m = re.match(r"^cp(\d+).*$", abi_tag)
if m and int(m[1]) >= cmake_cfg["abi3_minimum_cpython_version"]:
if m and int(m[1]) >= wheel_cfg["abi3_minimum_cpython_version"]:
return "abi3"
return abi_tag
else:
msg = "Unsupported python_abi"
raise AssertionError(msg)


def convert_wheel_tags(tags: dict[str, list[str]], cmake_cfg: dict | None) -> WheelTags:
def convert_wheel_tags(
tags: dict[str, list[str]], wheel_cfg: dict, cmake_cfg: dict | None
) -> WheelTags:
"""Apply convert_abi_tag to each of the abi tags."""
tags = copy(tags)
cvt_abi = lambda tag: convert_abi_tag(tag, cmake_cfg)
cvt_abi = lambda tag: convert_abi_tag(tag, wheel_cfg, cmake_cfg)
tags["abi"] = list(map(cvt_abi, tags["abi"]))
if "none" in tags["abi"]:
if wheel_cfg["python_tag"] != "auto":
tags["pyver"] = wheel_cfg["python_tag"]
elif "none" in tags["abi"]:
tags["pyver"] = ["py3"]
return tags


def is_pure(cmake_cfg: dict | None) -> bool:
def is_pure(wheel_cfg: dict, cmake_cfg: dict | None) -> bool:
"""Check if the package is a pure-Python package without platform-
specific binaries."""
if not cmake_cfg:
return True
return cmake_cfg["pure_python"]
if "pure_python" in wheel_cfg:
return wheel_cfg["pure_python"]
return not cmake_cfg
Loading

0 comments on commit dc21bfe

Please sign in to comment.