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: _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 headrs - 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: - The python library -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, )