From 373eedc77b6ae7d5c96125165aa37d136e4df7ef Mon Sep 17 00:00:00 2001 From: Austin Schuh Date: Sat, 26 Jul 2025 14:47:12 -0700 Subject: [PATCH] [bazel] Generate a filtered .def file for windows for wpimath (#8113) wpimath otherwise quickly gets too many symbols. Instead, gradle exports only some of the symbols from protobuf files automatically, and then manually exports the math operations. Do that here too. Signed-off-by: Austin Schuh --- shared/bazel/rules/cc_rules.bzl | 121 ++++++++++++++++++++++++++++++++ wpimath/BUILD.bazel | 14 +++- 2 files changed, 134 insertions(+), 1 deletion(-) diff --git a/shared/bazel/rules/cc_rules.bzl b/shared/bazel/rules/cc_rules.bzl index c7225efd49..c364744593 100644 --- a/shared/bazel/rules/cc_rules.bzl +++ b/shared/bazel/rules/cc_rules.bzl @@ -7,6 +7,31 @@ load("@rules_cc//cc/common:cc_common.bzl", "cc_common") load("@rules_pkg//:mappings.bzl", "pkg_files") load("@rules_pkg//:pkg.bzl", "pkg_zip") +# Copied from bazel since it isn't exposed publicly that I can find. +# https://github.com/bazelbuild/bazel/blob/cc4e3b25a89cd8294406d9489ece706cfcc019bd/src/main/starlark/builtins_bzl/common/cc/cc_helper.bzl#L272 +def generate_def_file(ctx, def_parser, object_files, dll_name): + def_file = ctx.actions.declare_file(ctx.label.name + ".gen.def") + + args = ctx.actions.args() + args.add(def_file) + args.add(dll_name) + argv = ctx.actions.args() + argv.use_param_file("@%s", use_always = True) + argv.set_param_file_format("shell") + for object_file in object_files: + argv.add(object_file.path) + + ctx.actions.run( + mnemonic = "DefParser", + executable = def_parser, + toolchain = None, + arguments = [args, argv], + inputs = object_files, + outputs = [def_file], + use_default_shell_env = True, + ) + return def_file + def _folder_prefix(name): if "/" in name: last_slash = name.rfind("/") @@ -154,15 +179,23 @@ def wpilib_cc_library( def wpilib_cc_shared_library( name, auto_export_windows_symbols = True, + win_def_file = None, **kwargs): folder, lib = _folder_prefix(name) features = [] if auto_export_windows_symbols: features.append("windows_export_all_symbols") + cc_shared_library( name = name, features = features, + # Only include a .def file on windows. This makes it so we can mark + # the .def file as only compatible with windows. + win_def_file = select({ + "@platforms//os:windows": win_def_file, + "//conditions:default": None, + }), **kwargs ) @@ -388,3 +421,91 @@ def wpilib_cc_static_library( static_lib_name = static_lib_name, **kwargs ) + +def _generate_def_windows_impl(ctx): + deps = ctx.attr.deps + + cc_toolchain = find_cpp_toolchain(ctx) + + feature_configuration = cc_common.configure_features( + ctx = ctx, + cc_toolchain = cc_toolchain, + requested_features = ctx.features + ["force_no_whole_archive"], + unsupported_features = ctx.disabled_features, + ) + + def_parser = ctx.file._def_parser + win_def_file = [] + + if cc_common.is_enabled(feature_configuration = feature_configuration, feature_name = "targets_windows"): + object_files = [] + + # Now, hunt down all the linker inputs directly specified. + for dep in deps: + linker_input = dep[CcInfo].linking_context.linker_inputs + + for l in linker_input.to_list(): + # Find the linker stanza owned directly by the dependency, not transitively + if l.owner != dep.label: + continue + + # Grab all the .o's out of it. + for library in l.libraries: + if library.pic_static_library != None: + if library.pic_objects != None: + object_files.extend(library.pic_objects) + elif library.static_library != None: + if library.objects != None: + object_files.extend(library.objects) + + # Filter the list so we only generate def files for the provided dependencies. + filtered_object_files = [] + for o in object_files: + for f in ctx.attr.filters: + if f in o.path: + filtered_object_files.append(o) + break + + if def_parser != None: + generated_def_file = generate_def_file(ctx, def_parser, filtered_object_files, ctx.label.name) + + win_def_file = [generated_def_file] + + files = depset(direct = win_def_file) + return [ + DefaultInfo(files = files), + OutputGroupInfo(default = files), + ] + +_generate_def_windows = rule( + implementation = _generate_def_windows_impl, + attrs = { + "deps": attr.label_list( + providers = [CcInfo], + doc = """ +List of all static libraries to not duplicate .o files from. +""", + ), + "filters": attr.string_list(), + "_def_parser": attr.label(default = "@bazel_tools//tools/def_parser:def_parser", allow_single_file = True, cfg = "exec"), + } | CC_TOOLCHAIN_ATTRS, + toolchains = use_cc_toolchain(), + fragments = ["cpp"], +) + +def generate_def_windows(name, deps = None, **kwargs): + """Generates a .def file for linking a windows .dll for the provided cc_library and filters + + Args: + deps: A list of cc_libraries to export symbols from. + filters: All object files in the provided cc_libraries (but not their + dependencies) are checked against this list. If a string in + this list appears inside the name of the object file, it is + added to the export list. + """ + _generate_def_windows( + name = name, + deps = deps, + target_compatible_with = ["@platforms//os:windows"], + **kwargs + ) diff --git a/wpimath/BUILD.bazel b/wpimath/BUILD.bazel index 95ae371530..a4f3b22e34 100644 --- a/wpimath/BUILD.bazel +++ b/wpimath/BUILD.bazel @@ -4,7 +4,7 @@ load("@rules_cc//cc:defs.bzl", "cc_binary", "cc_library", "cc_test") load("@rules_java//java:defs.bzl", "java_binary") load("@rules_pkg//:mappings.bzl", "pkg_files") load("@rules_python//python:defs.bzl", "py_binary") -load("//shared/bazel/rules:cc_rules.bzl", "third_party_cc_lib_helper", "wpilib_cc_library", "wpilib_cc_shared_library", "wpilib_cc_static_library") +load("//shared/bazel/rules:cc_rules.bzl", "generate_def_windows", "third_party_cc_lib_helper", "wpilib_cc_library", "wpilib_cc_shared_library", "wpilib_cc_static_library") load("//shared/bazel/rules:java_rules.bzl", "wpilib_java_junit5_test") load("//shared/bazel/rules:jni_rules.bzl", "wpilib_jni_cc_library", "wpilib_jni_java_library") load("//shared/bazel/rules:packaging.bzl", "package_minimal_jni_project") @@ -154,6 +154,17 @@ wpilib_cc_library( ], ) +generate_def_windows( + name = "wpimath_def", + filters = [ + ".pb.obj", + ".npb.obj", + ], + deps = [ + ":wpimath", + ], +) + wpilib_cc_shared_library( name = "shared/wpimath", auto_export_windows_symbols = False, @@ -161,6 +172,7 @@ wpilib_cc_shared_library( "//wpiutil:shared/wpiutil", ], visibility = ["//visibility:public"], + win_def_file = ":wpimath_def", deps = [ ":wpimath", ],