load("@aspect_bazel_lib//lib:copy_file.bzl", "copy_file") load("@pybind11_bazel//:build_defs.bzl", "pybind_extension", "pybind_library") load("@rules_python//python:defs.bzl", "py_library") 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, data = [], **kwargs): """ Defines a python library that is wrapping a series of pybind extensions. Outputs: - The python library """ py_library( name = name, data = data, tags = ["robotpy"], **kwargs ) 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, 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, srcs = [libinit_file], data = [pc_file, ":{}.copy_lib".format(libname), headers], deps = deps, imports = ["."], visibility = ["//visibility:public"], tags = ["robotpy"], )