Files
allwpilib/shared/bazel/rules/robotpy/pybind_rules.bzl
2026-04-13 21:51:36 -07:00

262 lines
8.5 KiB
Python

load("@aspect_bazel_lib//lib:copy_file.bzl", "copy_file")
load("@pybind11_bazel//:build_defs.bzl", "pybind_extension", "pybind_library")
load("@rules_pycross//pycross:defs.bzl", "pycross_wheel_library")
load("@rules_python//python:defs.bzl", "py_library")
load("@rules_python//python:packaging.bzl", "py_wheel")
load("//shared/bazel/rules/robotpy:compatibility_select.bzl", "robotpy_compatibility_select")
def create_pybind_library(
name,
extension_name,
install_path,
generated_srcs = [],
extra_hdrs = [],
extra_srcs = [],
deps = [],
dynamic_deps = [],
semiwrap_header = [],
includes = [],
local_defines = []):
"""
Function to create a pybind C++ extension library that has been defined by a semiwrap config
Outputs:
<name>_pybind_library - A pybind_library that functions like a header-only cc_library. It will include all
of the extra_hdrs, resolve the include paths, and add a dependency on the semiwrap headers
<install_path + extension_name> - A pybind_extension that wraps the pybind_library and compiles all the source files.
Params:
extension_name - The name of the pybind extension. Should be sourced from pyproject
install_path - The subpath where the library will be installed. Should be source from pyproject
generated_srcs - List of auto-generated sources to be compiled into the extension.
extra_hdrs - Any non-autogenerated headers
extra_srcs - Any non-autogenerated sources
deps - cc_library deps used to create the pybind_library
dynamic_deps - cc_shared_library deps used to filter objects from the pybind_extension
semiwrap_header - Auto-generated file used to initialize the extension
includes - see cc_library#includes. Used during the creating of the pybind_library
local_defines - see cc_library#local_defines. Used during the compilation of the extension
"""
pybind_library(
name = "{}_pybind_library".format(name),
hdrs = extra_hdrs,
target_compatible_with = robotpy_compatibility_select(),
deps = deps + [
"//shared/bazel/rules/robotpy:semiwrap_headers",
],
includes = includes,
visibility = ["//visibility:public"],
tags = ["robotpy"],
)
extension_name = extension_name or "_{}".format(name)
pybind_extension(
name = install_path + extension_name,
srcs = extra_srcs + generated_srcs,
deps = [":{}_pybind_library".format(name)] + semiwrap_header,
dynamic_deps = dynamic_deps,
copts = select({
"@bazel_tools//src/conditions:darwin": [
"-Wno-deprecated-declarations",
"-Wno-overloaded-virtual",
"-Wno-pessimizing-move",
"-Wno-unused-value",
],
"@bazel_tools//src/conditions:linux_x86_64": [
"-Wno-attributes",
"-Wno-unused-value",
"-Wno-deprecated",
"-Wno-deprecated-declarations",
"-Wno-unused-parameter",
"-Wno-redundant-move",
"-Wno-unused-but-set-variable",
"-Wno-unused-variable",
"-Wno-pessimizing-move",
"-Wno-overloaded-virtual",
],
"@bazel_tools//src/conditions:windows": [
],
}),
target_compatible_with = robotpy_compatibility_select(),
local_defines = local_defines,
tags = ["robotpy"],
)
def robotpy_library(
name,
deps = [],
data = [],
strip_path_prefixes = None,
summary = None,
project_urls = None,
author_email = None,
entry_points = None,
requires = None,
**kwargs):
"""
Defines a python library that is wrapping a series of pybind extensions.
Outputs:
<name> - The python library
<name>-wheel - A wheel for the library
"""
py_library(
name = name + "-lib",
data = data,
deps = deps,
tags = ["robotpy"],
**kwargs
)
py_wheel(
name = "{}-wheel".format(name),
distribution = name,
stamp = 1,
version = "$(ROBOTPY_VERSION)",
summary = summary,
requires = requires,
project_urls = project_urls,
author_email = author_email,
deps = data + [":{}-lib".format(name)],
strip_path_prefixes = strip_path_prefixes,
entry_points = entry_points,
license = "BSD-3-Clause",
tags = ["robotpy"],
)
pycross_wheel_library(
name = "{}".format(name),
wheel = "{}-wheel".format(name),
deps = deps,
visibility = ["//visibility:public"],
tags = ["manual"],
)
def copy_native_file(name, library, base_path):
"""
Copies a compiled shared library into a naming format that can be used by robotpy rules. The libraries are named
differently on OSX / Linux / Windows and this creates a handy alias to for easier use downstream
"""
copy_file(
name = name + ".win_copy_lib",
src = library,
out = "{}lib/{}.dll".format(base_path, name),
tags = ["manual"],
visibility = ["//visibility:public"],
)
copy_file(
name = name + ".osx_copy_lib",
src = library,
out = "{}lib/lib{}.dylib".format(base_path, name),
tags = ["manual"],
visibility = ["//visibility:public"],
)
copy_file(
name = name + ".linux_copy_lib",
src = library,
out = "{}lib/lib{}.so".format(base_path, name),
tags = ["manual"],
visibility = ["//visibility:public"],
)
native.alias(
name = "{}.copy_lib".format(name),
actual = select({
"@bazel_tools//src/conditions:darwin": name + ".osx_copy_lib",
"@bazel_tools//src/conditions:windows": name + ".win_copy_lib",
"//conditions:default": name + ".linux_copy_lib",
}),
visibility = ["//visibility:public"],
tags = ["robotpy"],
)
def _folder_prefix(name):
if "/" in name:
last_slash = name.rfind("/")
return (name[0:last_slash], name[last_slash + 1:])
else:
return ("", name)
def native_wrappery_library(
name,
pyproject_toml,
libinit_file,
pc_file,
pc_deps,
native_shared_library,
install_path,
headers,
strip_path_prefixes = [],
summary = None,
project_urls = None,
author_email = None,
entry_points = None,
requires = None,
deps = []):
"""
This function provides a sugar wrapper for defining a python library that wraps an allwpilib native library
"""
cmd = "$(locations //shared/bazel/rules/robotpy/hatchlib_native_port:generate_native_lib_files) "
cmd += " $(location " + pyproject_toml + ")"
cmd += " $(OUTS) "
for pc_dep in pc_deps:
cmd += " $(location " + pc_dep + ")"
native.genrule(
name = name + ".gen",
srcs = [pyproject_toml],
outs = [libinit_file, pc_file],
cmd = cmd,
tools = ["//shared/bazel/rules/robotpy/hatchlib_native_port:generate_native_lib_files"] + pc_deps,
visibility = ["//visibility:public"],
tags = ["robotpy"],
)
prefix, libname = _folder_prefix(native_shared_library)
copy_native_file(
name = libname,
library = native_shared_library,
base_path = install_path,
)
native.filegroup(
name = name + ".pc_wrapper",
srcs = [pc_file],
)
py_library(
name = name + "-lib",
srcs = [libinit_file],
data = [pc_file, ":{}.copy_lib".format(libname), headers],
deps = deps,
imports = ["."],
tags = ["robotpy"],
)
py_wheel(
name = "{}-wheel".format(name),
distribution = name,
stamp = 1,
version = "$(ROBOTPY_VERSION)",
summary = summary,
requires = requires,
project_urls = project_urls,
author_email = author_email,
deps = [name + "-lib", ":{}.copy_lib".format(libname), headers, name + ".pc_wrapper"],
strip_path_prefixes = strip_path_prefixes,
entry_points = entry_points,
tags = ["robotpy"],
license = "BSD-3-Clause",
)
pycross_wheel_library(
name = "{}".format(name),
wheel = "{}-wheel".format(name),
visibility = ["//visibility:public"],
tags = ["manual"],
deps = deps,
)