blob: 3efaab71f8109cc57198d4a3b4288957079c9231 [file] [edit]
# Copyright 2026 The Fuchsia Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import("//build/config/python_interpreter.gni")
import("//build/python/python_action.gni")
# Defines a Python wheel.
#
# Parameters
#
# deps (required)
# List of python_library or python_c_extension targets to include in the wheel.
#
# pyproject_toml (required)
# Path to the pyproject.toml file for the wheel. Note that the packaging
# script generates a setuptools-based setup.py, so the pyproject.toml must
# configure setuptools.build_meta as its build backend.
#
# version (optional)
# Version of the wheel. Defaults to "0.0.1".
#
# package_name (optional)
# Name of the package. Defaults to target_name.
#
# packages (optional)
# List of packages (directories) to include in the wheel.
#
# wheel_tags (optional)
# Compatibility tags for the wheel adhering to PEP 427
# ({python tag}-{abi tag}-{platform tag}). Defaults to "py3-none-any" for
# pure Python wheels. For wheels containing C extensions or native shared
# libraries, specify the target platform tags (e.g.,
# "cp311-cp311-linux_x86_64").
#
# output_name (optional)
# Name of the output wheel file. Defaults to
# "${_normalized_package_name}-${_normalized_version}-${_wheel_tags}.whl" to
# conform to the PEP 427 wheel filename specification.
#
# wheel_name (optional)
# Alias for output_name.
#
# output_dir (optional)
# Directory where the wheel will be placed. Defaults to
# ${target_out_dir}/${target_name}.
#
# testonly
# visibility
template("python_wheel") {
assert(defined(invoker.deps), "deps is required")
assert(defined(invoker.pyproject_toml), "pyproject_toml is required")
_version = "0.0.1"
if (defined(invoker.version)) {
_version = invoker.version
}
_package_name = target_name
if (defined(invoker.package_name)) {
_package_name = invoker.package_name
}
# PEP 427 specifies distribution name normalization rules where runs of
# non-alphanumeric characters (like hyphens) are replaced with a single
# underscore. Ensure package_name does not contain whitespace.
assert(string_replace(_package_name, " ", "") == _package_name,
"package_name must not contain whitespace: '${_package_name}'")
_wheel_tags = "py3-none-any"
if (defined(invoker.wheel_tags)) {
_wheel_tags = invoker.wheel_tags
}
# PEP 427 specifies distribution name normalization rules where runs of
# non-alphanumeric characters (like hyphens, dots) are replaced with a single
# underscore. GN lacks regex support, so we chain string_replace.
_normalized_package_name = string_replace(_package_name, "-", "_")
_normalized_package_name = string_replace(_normalized_package_name, ".", "_")
_normalized_package_name =
string_replace(_normalized_package_name, "___", "_")
_normalized_package_name = string_replace(_normalized_package_name, "__", "_")
# Per PEP 427 / PEP 440, version numbers retain periods and only replace
# hyphens with underscores.
_normalized_version = string_replace(_version, "-", "_")
_wheel_name =
"${_normalized_package_name}-${_normalized_version}-${_wheel_tags}.whl"
if (defined(invoker.wheel_name)) {
_wheel_name = invoker.wheel_name
} else if (defined(invoker.output_name)) {
_wheel_name = invoker.output_name
}
_output_dir = "${target_out_dir}/${target_name}"
if (defined(invoker.output_dir)) {
_output_dir = invoker.output_dir
}
_wheel_file = "${_output_dir}/${_wheel_name}"
_library_infos_target = "${target_name}.library_infos"
_library_infos_json = "${target_gen_dir}/${target_name}.library_infos.json"
generated_file(_library_infos_target) {
forward_variables_from(invoker, [ "testonly" ])
visibility = [ ":*" ]
public_deps = invoker.deps
outputs = [ _library_infos_json ]
output_conversion = "json"
data_keys = [ "library_info" ]
walk_keys = [ "library_info_barrier" ]
}
python_action(target_name) {
forward_variables_from(invoker,
[
"testonly",
"visibility",
])
binary_label = "//build/python:package_python_wheel"
depfile = "${target_out_dir}/${target_name}.d"
# Explicitly declare the stamp file and predictable wheel filename in
# outputs so they are tracked and downloaded by remote execution/caching
# systems (e.g., Siso).
_stamp_file = "${target_gen_dir}/${target_name}.wheel.stamp"
outputs = [
_stamp_file,
_wheel_file,
]
inputs = [
_library_infos_json,
invoker.pyproject_toml,
]
deps = [ ":${_library_infos_target}" ] + invoker.deps
args = [
"--target_name",
target_name,
"--python_interpreter",
rebase_path(python_exe_src, root_build_dir),
"--gen_dir",
rebase_path(target_gen_dir, root_build_dir),
"--wheel_file",
rebase_path(_wheel_file, root_build_dir),
"--stamp_file",
rebase_path(_stamp_file, root_build_dir),
"--library_infos",
rebase_path(_library_infos_json, root_build_dir),
"--pyproject_toml",
rebase_path(invoker.pyproject_toml, root_build_dir),
"--depfile",
rebase_path(depfile, root_build_dir),
"--version",
_version,
"--package_name",
_package_name,
]
if (defined(invoker.packages)) {
args += [ "--packages" ] + invoker.packages
}
}
}