mirror of
https://github.com/wpilibsuite/allwpilib
synced 2026-06-19 00:41:43 +00:00
[bazel] Create better static libraries and add basic publishing (#8029)
This commit is contained in:
@@ -0,0 +1,21 @@
|
||||
load("@bazel_skylib//rules:write_file.bzl", "write_file")
|
||||
load("@rules_pkg//:mappings.bzl", "pkg_files")
|
||||
|
||||
# Generate this because otherwise the linter wants to change the format.
|
||||
write_file(
|
||||
name = "manifest_write",
|
||||
out = "MANIFEST.MF",
|
||||
content = [
|
||||
"Manifest-Version: 1.0",
|
||||
"",
|
||||
],
|
||||
)
|
||||
|
||||
pkg_files(
|
||||
name = "src_jar_dummy_manifest",
|
||||
srcs = [
|
||||
"MANIFEST.MF",
|
||||
],
|
||||
prefix = "META-INF",
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
|
||||
@@ -1,4 +1,16 @@
|
||||
load("@rules_cc//cc:defs.bzl", "cc_library")
|
||||
load("@rules_cc//cc:action_names.bzl", "CPP_LINK_STATIC_LIBRARY_ACTION_NAME")
|
||||
load("@rules_cc//cc:defs.bzl", "CcInfo", "cc_library")
|
||||
load("@rules_cc//cc:find_cc_toolchain.bzl", "CC_TOOLCHAIN_ATTRS", "find_cpp_toolchain", "use_cc_toolchain")
|
||||
load("@rules_cc//cc/common:cc_common.bzl", "cc_common")
|
||||
load("@rules_pkg//:mappings.bzl", "pkg_files")
|
||||
load("@rules_pkg//:pkg.bzl", "pkg_zip")
|
||||
|
||||
def _folder_prefix(name):
|
||||
if "/" in name:
|
||||
last_slash = name.rfind("/")
|
||||
return (name[0:last_slash], name[last_slash + 1:])
|
||||
else:
|
||||
return ("", name)
|
||||
|
||||
def third_party_cc_lib_helper(
|
||||
name,
|
||||
@@ -13,7 +25,8 @@ def third_party_cc_lib_helper(
|
||||
to make a header shim to deal with the include path, and a filegroup of the sources. This pattern is extermely
|
||||
common for the thirdparty libraries that live beneath certain libraries.
|
||||
|
||||
This will produce a library shim with the include path stripped, and a filegroup of sources.
|
||||
This will produce a library shim with the include path stripped, a filegroup of sources, and packages that can be
|
||||
used to downstream to zip headers / sources with their "parent" library.
|
||||
|
||||
Params
|
||||
include_root: The package relative path to the header files. This will be used to glob the files and strip the include prefix
|
||||
@@ -31,6 +44,12 @@ def third_party_cc_lib_helper(
|
||||
visibility = visibility,
|
||||
)
|
||||
|
||||
pkg_files(
|
||||
name = name + "-hdrs-pkg",
|
||||
srcs = native.glob([include_root + "/**"]),
|
||||
strip_prefix = include_root,
|
||||
)
|
||||
|
||||
if src_root:
|
||||
native.filegroup(
|
||||
name = name + "-srcs",
|
||||
@@ -38,23 +57,294 @@ def third_party_cc_lib_helper(
|
||||
visibility = visibility,
|
||||
)
|
||||
|
||||
pkg_files(
|
||||
name = name + "-srcs-pkg",
|
||||
srcs = native.glob([src_root + "/**"]),
|
||||
strip_prefix = src_root,
|
||||
)
|
||||
|
||||
def wpilib_cc_library(
|
||||
name,
|
||||
srcs = [],
|
||||
hdrs = [],
|
||||
deps = [],
|
||||
copts = [],
|
||||
third_party_libraries = [],
|
||||
third_party_header_only_libraries = [],
|
||||
extra_src_pkg_files = [],
|
||||
extra_hdr_pkg_files = [],
|
||||
include_license_files = False,
|
||||
srcs_pkg_root = "src/main/native/cpp",
|
||||
hdrs_pkg_root = "src/main/native/include",
|
||||
strip_include_prefix = None,
|
||||
linkopts = None,
|
||||
**kwargs):
|
||||
"""
|
||||
This function is used to ease the creation of a cc_library with helpers for handling thirdparty libraries in the standard allwpilib format.
|
||||
This function is used to ease the creation of a cc_library with publishing given the standard allwpilib directory structure.
|
||||
|
||||
This will create a cc_library as well as automatically create header, source, and library artifacts that can be used for publishing. This
|
||||
also provides some syntactic sugar for third party library shims declared by third_party_cc_lib_helper.
|
||||
|
||||
Important outputs:
|
||||
":name" - The cc_library
|
||||
name + "-srcs-zip" - A zip file containing all the exported sources
|
||||
name + "-hdrs-zip" - A zip file containing all the exported headers
|
||||
name + "-zip" - A zip file that contains the compiled library
|
||||
|
||||
Params:
|
||||
srcs: The sources used to compile the library. Note: This may be platform dependent and not include all the sources of the library for packaging
|
||||
hdrs: The headers used to compile the library. Note: This may be platform dependent and not include all the sources of the library for packaging
|
||||
third_party_libraries: These are helper dependencies, created by third_party_cc_lib_helper. Header shims will be added as deps and src filegroups will be added to srcs
|
||||
third_party_header_only_libraries: Similar to third_party_libraries, but for shims that contain no sources
|
||||
extra_src_pkg_files: Extra pkg_files to add to the source bundle. This is useful in the event that a library is complicated and requires
|
||||
extra, customized sources to be added to the published zip file
|
||||
extra_hdr_pkg_files: Extra pkg_files to add to the headers bundle. This is useful in the event that a library is complicated and requires
|
||||
extra, customized headers to be added to the published zip file
|
||||
include_license_files: If the header / source / library zip files should automatically includes the license files. This is used to maintain
|
||||
consistency with the gradle publishing, as not all of them export the license files.
|
||||
"""
|
||||
maybe_license_pkg = ["//:license_pkg_files"] if include_license_files else []
|
||||
|
||||
cc_library(
|
||||
name = name,
|
||||
srcs = srcs + [lib + "-srcs" for lib in third_party_libraries],
|
||||
deps = deps + [lib + "-headers" for lib in third_party_libraries + third_party_header_only_libraries],
|
||||
name = name + "-headers",
|
||||
hdrs = hdrs,
|
||||
deps = [lib + "-headers" for lib in third_party_libraries + third_party_header_only_libraries],
|
||||
strip_include_prefix = strip_include_prefix,
|
||||
**kwargs
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = name,
|
||||
hdrs = hdrs,
|
||||
copts = copts,
|
||||
srcs = srcs + [lib + "-srcs" for lib in third_party_libraries],
|
||||
deps = deps + [lib + "-headers" for lib in third_party_libraries + third_party_header_only_libraries],
|
||||
strip_include_prefix = strip_include_prefix,
|
||||
**kwargs
|
||||
)
|
||||
|
||||
if srcs_pkg_root:
|
||||
pkg_files(
|
||||
name = name + "-srcs-pkg",
|
||||
srcs = native.glob([srcs_pkg_root + "/**"]),
|
||||
strip_prefix = srcs_pkg_root,
|
||||
)
|
||||
|
||||
pkg_zip(
|
||||
name = name + "-srcs-zip",
|
||||
srcs = maybe_license_pkg + extra_src_pkg_files + [name + "-srcs-pkg"] + [lib + "-srcs-pkg" for lib in third_party_libraries],
|
||||
tags = ["no-remote"],
|
||||
)
|
||||
|
||||
if hdrs_pkg_root:
|
||||
pkg_files(
|
||||
name = name + "-hdrs-pkg",
|
||||
srcs = native.glob([hdrs_pkg_root + "/**"]),
|
||||
strip_prefix = hdrs_pkg_root,
|
||||
)
|
||||
|
||||
pkg_zip(
|
||||
name = name + "-hdrs-zip",
|
||||
srcs = extra_hdr_pkg_files + maybe_license_pkg + [name + "-hdrs-pkg"] + [lib + "-hdrs-pkg" for lib in third_party_libraries + third_party_header_only_libraries],
|
||||
tags = ["no-remote"],
|
||||
)
|
||||
|
||||
CcStaticLibraryInfo = provider(
|
||||
"Information about a cc static library.",
|
||||
fields = {
|
||||
"linker_input": "the resulting linker input artifact for the static library",
|
||||
"used_objects": "the object files already accounted for",
|
||||
},
|
||||
)
|
||||
|
||||
def _accumulate_used_objects(ctx):
|
||||
transitive_used_objects = []
|
||||
for dep in ctx.attr.static_deps:
|
||||
transitive_used_objects.append(dep[CcStaticLibraryInfo].used_objects)
|
||||
|
||||
return transitive_used_objects
|
||||
|
||||
def _filter_inputs(
|
||||
ctx,
|
||||
feature_configuration,
|
||||
cc_toolchain,
|
||||
deps,
|
||||
used_objects):
|
||||
dependency_linker_inputs_sets = []
|
||||
for dep in deps:
|
||||
dependency_linker_inputs_sets.append(dep[CcInfo].linking_context.linker_inputs)
|
||||
|
||||
dependency_linker_inputs = depset(transitive = dependency_linker_inputs_sets, order = "topological").to_list()
|
||||
|
||||
used_objects_depset = depset(transitive = used_objects, order = "topological").to_list()
|
||||
|
||||
linker_inputs = []
|
||||
for linker_input in dependency_linker_inputs:
|
||||
for lib in linker_input.libraries:
|
||||
if lib.pic_objects:
|
||||
for o in lib.pic_objects:
|
||||
if o not in used_objects_depset:
|
||||
linker_inputs.append(o)
|
||||
elif lib.objects:
|
||||
for o in lib.objects:
|
||||
if o not in used_objects_depset:
|
||||
linker_inputs.append(o)
|
||||
|
||||
return sorted(linker_inputs)
|
||||
|
||||
def _cc_static_library_impl(ctx):
|
||||
"""
|
||||
This is a modified version of built in cc_static_library implementation
|
||||
https://github.com/bazelbuild/bazel/blob/8.2.1/src/main/starlark/builtins_bzl/common/cc/experimental_cc_static_library.bzl
|
||||
|
||||
The built in version amalgamates all of the transative dependency objects into a single shared library. However, we do not want our
|
||||
static libraries to only have the symbols related to the objects for this library, and not anything transative. In order to do this,
|
||||
we add the option to specify transative static_libraries. The rule then filters out the objects that are defines in the other static
|
||||
libraries.
|
||||
"""
|
||||
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,
|
||||
)
|
||||
|
||||
# Find all the objects which are already in another static library.
|
||||
used_objects = _accumulate_used_objects(ctx)
|
||||
|
||||
# Now, find the ones we depend on which aren't.
|
||||
libs = _filter_inputs(
|
||||
ctx,
|
||||
feature_configuration,
|
||||
cc_toolchain,
|
||||
deps,
|
||||
used_objects,
|
||||
)
|
||||
|
||||
used_objects_depset = depset(direct = libs, transitive = used_objects, order = "topological")
|
||||
|
||||
# Generate the output library name if one isn't provided.
|
||||
output_file = ctx.actions.declare_file(ctx.attr.static_lib_name)
|
||||
|
||||
# And, now do it.
|
||||
linker_input = cc_common.create_linker_input(
|
||||
owner = ctx.label,
|
||||
libraries = depset(direct = [
|
||||
cc_common.create_library_to_link(
|
||||
actions = ctx.actions,
|
||||
feature_configuration = feature_configuration,
|
||||
cc_toolchain = cc_toolchain,
|
||||
static_library = output_file,
|
||||
),
|
||||
]),
|
||||
)
|
||||
compilation_context = cc_common.create_compilation_context()
|
||||
linking_context = cc_common.create_linking_context(linker_inputs = depset(direct = [linker_input], order = "topological"))
|
||||
|
||||
archiver_path = cc_common.get_tool_for_action(
|
||||
feature_configuration = feature_configuration,
|
||||
action_name = CPP_LINK_STATIC_LIBRARY_ACTION_NAME,
|
||||
)
|
||||
archiver_variables = cc_common.create_link_variables(
|
||||
feature_configuration = feature_configuration,
|
||||
cc_toolchain = cc_toolchain,
|
||||
output_file = output_file.path,
|
||||
is_using_linker = False,
|
||||
)
|
||||
command_line = cc_common.get_memory_inefficient_command_line(
|
||||
feature_configuration = feature_configuration,
|
||||
action_name = CPP_LINK_STATIC_LIBRARY_ACTION_NAME,
|
||||
variables = archiver_variables,
|
||||
)
|
||||
|
||||
args = ctx.actions.args()
|
||||
args.add_all(command_line)
|
||||
args.add_all(libs)
|
||||
|
||||
if cc_common.is_enabled(
|
||||
feature_configuration = feature_configuration,
|
||||
feature_name = "archive_param_file",
|
||||
):
|
||||
# TODO: The flag file arg should come from the toolchain instead.
|
||||
args.use_param_file("@%s", use_always = True)
|
||||
|
||||
env = cc_common.get_environment_variables(
|
||||
feature_configuration = feature_configuration,
|
||||
action_name = CPP_LINK_STATIC_LIBRARY_ACTION_NAME,
|
||||
variables = archiver_variables,
|
||||
)
|
||||
|
||||
ctx.actions.run(
|
||||
executable = archiver_path,
|
||||
arguments = [args],
|
||||
env = env,
|
||||
inputs = depset(
|
||||
direct = libs,
|
||||
transitive = [
|
||||
cc_toolchain.all_files,
|
||||
],
|
||||
),
|
||||
outputs = [output_file],
|
||||
)
|
||||
|
||||
cc_info = cc_common.merge_cc_infos(cc_infos = [
|
||||
CcInfo(compilation_context = compilation_context, linking_context = linking_context),
|
||||
] + [dep[CcInfo] for dep in ctx.attr.deps])
|
||||
|
||||
# TODO(austin): Do we want this to be able to link into a binary? Probably... Need to figure out what the right result needs to be for that.
|
||||
|
||||
return [
|
||||
cc_info,
|
||||
DefaultInfo(
|
||||
files = depset([output_file]),
|
||||
),
|
||||
CcStaticLibraryInfo(
|
||||
used_objects = used_objects_depset,
|
||||
linker_input = linker_input,
|
||||
),
|
||||
]
|
||||
|
||||
_wpilib_cc_static_library = rule(
|
||||
implementation = _cc_static_library_impl,
|
||||
attrs = {
|
||||
"deps": attr.label_list(
|
||||
providers = [CcInfo],
|
||||
doc = """
|
||||
List of all the dependencies to accumulate objects from to link into this static library.
|
||||
""",
|
||||
),
|
||||
"static_deps": attr.label_list(
|
||||
providers = [CcStaticLibraryInfo],
|
||||
doc = """
|
||||
List of all static libraries to not duplicate .o files from.
|
||||
""",
|
||||
),
|
||||
"static_lib_name": attr.string(doc = """
|
||||
By default cc_static_library will use a name for the static library output file based on
|
||||
the target's name and the platform. This includes an extension and sometimes a prefix.
|
||||
Sometimes you may not want the default name, in which case you can use this
|
||||
attribute to choose a custom name."""),
|
||||
} | CC_TOOLCHAIN_ATTRS,
|
||||
toolchains = use_cc_toolchain(),
|
||||
fragments = ["cpp"],
|
||||
)
|
||||
|
||||
def wpilib_cc_static_library(
|
||||
name,
|
||||
static_lib_name = None,
|
||||
**kwargs):
|
||||
if not static_lib_name:
|
||||
folder, lib = _folder_prefix(name)
|
||||
static_lib_name = select({
|
||||
"@bazel_tools//src/conditions:windows": folder + "/" + lib + ".lib",
|
||||
"//conditions:default": folder + "/lib" + lib + ".a",
|
||||
})
|
||||
|
||||
_wpilib_cc_static_library(
|
||||
name = name,
|
||||
static_lib_name = static_lib_name,
|
||||
**kwargs
|
||||
)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
load("@bazel_tools//tools/cpp:toolchain_utils.bzl", "find_cpp_toolchain")
|
||||
load("@rules_cc//cc:defs.bzl", "cc_library")
|
||||
load("@rules_java//java:defs.bzl", "java_library")
|
||||
load("@rules_pkg//:mappings.bzl", "filter_directory")
|
||||
|
||||
def _jni_headers_impl(ctx):
|
||||
include_dir = ctx.actions.declare_directory(ctx.attr.name + ".h")
|
||||
@@ -75,6 +76,7 @@ def wpilib_jni_java_library(
|
||||
name = name,
|
||||
visibility = visibility,
|
||||
testonly = testonly,
|
||||
tags = tags,
|
||||
**java_library_args
|
||||
)
|
||||
|
||||
@@ -87,14 +89,26 @@ def wpilib_jni_java_library(
|
||||
visibility = visibility,
|
||||
)
|
||||
|
||||
# Expose a pkg_files with the JNI generated header in it.
|
||||
filter_directory(
|
||||
name = name + "-jni-hdrs-pkg",
|
||||
src = headers_name,
|
||||
excludes = ["MANIFEST.MF"],
|
||||
outdir_name = "jni/",
|
||||
)
|
||||
|
||||
def wpilib_jni_cc_library(
|
||||
name,
|
||||
deps = [],
|
||||
java_dep = None,
|
||||
**kwargs):
|
||||
jni = "@rules_bzlmodrio_toolchains//jni"
|
||||
|
||||
if java_dep[0] != ":":
|
||||
fail("java_dep", java_dep, "should start with a :")
|
||||
|
||||
cc_library(
|
||||
name = name + ".static",
|
||||
name = name,
|
||||
deps = [jni, java_dep + ".hdrs"] + deps,
|
||||
**kwargs
|
||||
)
|
||||
|
||||
30
shared/bazel/rules/packaging.bzl
Normal file
30
shared/bazel/rules/packaging.bzl
Normal file
@@ -0,0 +1,30 @@
|
||||
load("@rules_pkg//:mappings.bzl", "pkg_filegroup", "pkg_files")
|
||||
|
||||
def pkg_java_files(name):
|
||||
pkg_files(
|
||||
name = name + "-java-srcs",
|
||||
srcs = native.glob(["src/main/java/**"]),
|
||||
strip_prefix = "src/main/java",
|
||||
)
|
||||
|
||||
pkg_files(
|
||||
name = name + "-generated-java-srcs",
|
||||
srcs = native.glob(["src/generated/main/java/**/*.java"], allow_empty = True),
|
||||
strip_prefix = "src/generated/main/java",
|
||||
)
|
||||
|
||||
pkg_files(
|
||||
name = name + "-proto-srcs",
|
||||
srcs = native.glob(["src/main/proto/**"], allow_empty = True),
|
||||
strip_prefix = "src/main/proto",
|
||||
)
|
||||
|
||||
pkg_filegroup(
|
||||
name = name,
|
||||
srcs = [
|
||||
name + "-java-srcs",
|
||||
name + "-proto-srcs",
|
||||
name + "-generated-java-srcs",
|
||||
"//shared/bazel/rules:src_jar_dummy_manifest",
|
||||
],
|
||||
)
|
||||
Reference in New Issue
Block a user