Move rules_pkg targets into //pkg, and add experimental C++ library rules (#9823)
This change moves the `pkg_*` rules into the `//pkg` package, which cleans up the root package. It also adds an experimental `cc_dist_library` rule, which is similar to Bazel's `cc_import` rule. The goal of `cc_dist_library` is to produce output libraries from several targets. For example, splitting `//:protobuf` into multiple targets means that `bazel-bin/libprotobuf.a` won't contain all of the objects. The `cc_dist_library` creates a single library from several different `cc_library` targets. This may be useful for future packaging targets.pull/9833/head
parent
f7b9886f9d
commit
46710cabc4
3 changed files with 366 additions and 78 deletions
@ -0,0 +1,117 @@ |
|||||||
|
load("@rules_pkg//:pkg.bzl", "pkg_zip") |
||||||
|
load("@rules_pkg//:mappings.bzl", "pkg_attributes", "pkg_files") |
||||||
|
load("//:protobuf_release.bzl", "package_naming") |
||||||
|
load(":cc_dist_library.bzl", "cc_dist_library") |
||||||
|
|
||||||
|
pkg_files( |
||||||
|
name = "wkt_protos_files", |
||||||
|
srcs = [ |
||||||
|
"//:any_proto", |
||||||
|
"//:api_proto", |
||||||
|
"//:duration_proto", |
||||||
|
"//:empty_proto", |
||||||
|
"//:field_mask_proto", |
||||||
|
"//:source_context_proto", |
||||||
|
"//:struct_proto", |
||||||
|
"//:timestamp_proto", |
||||||
|
"//:type_proto", |
||||||
|
"//:wrappers_proto", |
||||||
|
], |
||||||
|
prefix = "include/google/protobuf", |
||||||
|
visibility = ["//visibility:private"], |
||||||
|
) |
||||||
|
|
||||||
|
pkg_files( |
||||||
|
name = "descriptor_protos_files", |
||||||
|
srcs = [ |
||||||
|
"//:descriptor_proto", |
||||||
|
], |
||||||
|
prefix = "include/google/protobuf", |
||||||
|
visibility = ["//visibility:private"], |
||||||
|
) |
||||||
|
|
||||||
|
pkg_files( |
||||||
|
name = "compiler_plugin_protos_files", |
||||||
|
srcs = ["//:compiler_plugin_proto"], |
||||||
|
prefix = "include/google/protobuf/compiler", |
||||||
|
visibility = ["//visibility:private"], |
||||||
|
) |
||||||
|
|
||||||
|
################################################################################ |
||||||
|
# Generates protoc release artifacts. |
||||||
|
################################################################################ |
||||||
|
|
||||||
|
genrule( |
||||||
|
name = "protoc_readme", |
||||||
|
outs = ["readme.txt"], |
||||||
|
cmd = """ |
||||||
|
echo "Protocol Buffers - Google's data interchange format |
||||||
|
Copyright 2008 Google Inc. |
||||||
|
https://developers.google.com/protocol-buffers/ |
||||||
|
This package contains a precompiled binary version of the protocol buffer |
||||||
|
compiler (protoc). This binary is intended for users who want to use Protocol |
||||||
|
Buffers in languages other than C++ but do not want to compile protoc |
||||||
|
themselves. To install, simply place this binary somewhere in your PATH. |
||||||
|
If you intend to use the included well known types then don't forget to |
||||||
|
copy the contents of the 'include' directory somewhere as well, for example |
||||||
|
into '/usr/local/include/'. |
||||||
|
Please refer to our official github site for more installation instructions: |
||||||
|
https://github.com/protocolbuffers/protobuf" > $@ |
||||||
|
""", |
||||||
|
visibility = ["//visibility:private"], |
||||||
|
) |
||||||
|
|
||||||
|
pkg_files( |
||||||
|
name = "protoc_files", |
||||||
|
srcs = ["//:protoc"], |
||||||
|
attributes = pkg_attributes(mode = "0555"), |
||||||
|
prefix = "bin/", |
||||||
|
visibility = ["//visibility:private"], |
||||||
|
) |
||||||
|
|
||||||
|
package_naming( |
||||||
|
name = "protoc_pkg_naming", |
||||||
|
) |
||||||
|
|
||||||
|
pkg_zip( |
||||||
|
name = "protoc_release", |
||||||
|
srcs = [ |
||||||
|
":compiler_plugin_protos_files", |
||||||
|
":descriptor_protos_files", |
||||||
|
":protoc_files", |
||||||
|
":protoc_readme", |
||||||
|
":wkt_protos_files", |
||||||
|
], |
||||||
|
package_file_name = "protoc-{version}-{platform}.zip", |
||||||
|
package_variables = ":protoc_pkg_naming", |
||||||
|
) |
||||||
|
|
||||||
|
################################################################################ |
||||||
|
# Protobuf runtime libraries. |
||||||
|
################################################################################ |
||||||
|
|
||||||
|
cc_dist_library( |
||||||
|
name = "protobuf_lite", |
||||||
|
linkopts = select({ |
||||||
|
"//:msvc": [], |
||||||
|
"//conditions:default": ["-lpthread"], |
||||||
|
}), |
||||||
|
deps = [ |
||||||
|
"//:protobuf_lite", |
||||||
|
], |
||||||
|
) |
||||||
|
|
||||||
|
cc_dist_library( |
||||||
|
name = "protobuf", |
||||||
|
linkopts = select({ |
||||||
|
"//:msvc": [], |
||||||
|
"//conditions:default": [ |
||||||
|
"-lz", |
||||||
|
"-lpthread", |
||||||
|
], |
||||||
|
}), |
||||||
|
deps = [ |
||||||
|
"//:protobuf", |
||||||
|
"//:protobuf_lite", |
||||||
|
], |
||||||
|
) |
@ -0,0 +1,232 @@ |
|||||||
|
# Rules for distributable C++ libraries |
||||||
|
|
||||||
|
load("@rules_cc//cc:action_names.bzl", cc_action_names = "ACTION_NAMES") |
||||||
|
load("@rules_cc//cc:find_cc_toolchain.bzl", "find_cc_toolchain") |
||||||
|
|
||||||
|
# Creates an action to build the `output_file` static library (archive) |
||||||
|
# using `object_files`. |
||||||
|
def _create_archive_action( |
||||||
|
ctx, |
||||||
|
feature_configuration, |
||||||
|
cc_toolchain, |
||||||
|
output_file, |
||||||
|
object_files): |
||||||
|
# Based on Bazel's src/main/starlark/builtins_bzl/common/cc/cc_import.bzl: |
||||||
|
|
||||||
|
# Build the command line and add args for all of the input files: |
||||||
|
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 = cc_action_names.cpp_link_static_library, |
||||||
|
variables = archiver_variables, |
||||||
|
) |
||||||
|
args = ctx.actions.args() |
||||||
|
args.add_all(command_line) |
||||||
|
args.add_all(object_files) |
||||||
|
args.use_param_file("@%s", use_always = True) |
||||||
|
|
||||||
|
archiver_path = cc_common.get_tool_for_action( |
||||||
|
feature_configuration = feature_configuration, |
||||||
|
action_name = cc_action_names.cpp_link_static_library, |
||||||
|
) |
||||||
|
|
||||||
|
env = cc_common.get_environment_variables( |
||||||
|
feature_configuration = feature_configuration, |
||||||
|
action_name = cc_action_names.cpp_link_static_library, |
||||||
|
variables = archiver_variables, |
||||||
|
) |
||||||
|
|
||||||
|
ctx.actions.run( |
||||||
|
executable = archiver_path, |
||||||
|
arguments = [args], |
||||||
|
env = env, |
||||||
|
inputs = depset( |
||||||
|
direct = object_files, |
||||||
|
transitive = [ |
||||||
|
cc_toolchain.all_files, |
||||||
|
], |
||||||
|
), |
||||||
|
use_default_shell_env = True, |
||||||
|
outputs = [output_file], |
||||||
|
mnemonic = "CppArchiveDist", |
||||||
|
) |
||||||
|
|
||||||
|
# Implementation for cc_dist_library rule. |
||||||
|
def _cc_dist_library_impl(ctx): |
||||||
|
cc_toolchain_info = find_cc_toolchain(ctx) |
||||||
|
if cc_toolchain_info.ar_executable == None: |
||||||
|
return [] |
||||||
|
|
||||||
|
feature_configuration = cc_common.configure_features( |
||||||
|
ctx = ctx, |
||||||
|
cc_toolchain = cc_toolchain_info, |
||||||
|
) |
||||||
|
|
||||||
|
# Collect the set of object files from the immediate deps. |
||||||
|
|
||||||
|
objs = [] |
||||||
|
pic_objs = [] |
||||||
|
for dep in ctx.attr.deps: |
||||||
|
if CcInfo not in dep: |
||||||
|
continue |
||||||
|
|
||||||
|
link_ctx = dep[CcInfo].linking_context |
||||||
|
if link_ctx == None: |
||||||
|
continue |
||||||
|
|
||||||
|
linker_inputs = link_ctx.linker_inputs.to_list() |
||||||
|
for link_input in linker_inputs: |
||||||
|
if link_input.owner != dep.label: |
||||||
|
# This is a transitive dep: skip it. |
||||||
|
continue |
||||||
|
|
||||||
|
for lib in link_input.libraries: |
||||||
|
objs.extend(lib.objects or []) |
||||||
|
pic_objs.extend(lib.pic_objects or []) |
||||||
|
|
||||||
|
# For static libraries, build separately with and without pic. |
||||||
|
|
||||||
|
stemname = "lib" + ctx.label.name |
||||||
|
outputs = [] |
||||||
|
|
||||||
|
if len(objs) > 0: |
||||||
|
archive_out = ctx.actions.declare_file(stemname + ".a") |
||||||
|
_create_archive_action( |
||||||
|
ctx, |
||||||
|
feature_configuration, |
||||||
|
cc_toolchain_info, |
||||||
|
archive_out, |
||||||
|
objs, |
||||||
|
) |
||||||
|
outputs.append(archive_out) |
||||||
|
|
||||||
|
if len(pic_objs) > 0: |
||||||
|
pic_archive_out = ctx.actions.declare_file(stemname + ".pic.a") |
||||||
|
_create_archive_action( |
||||||
|
ctx, |
||||||
|
feature_configuration, |
||||||
|
cc_toolchain_info, |
||||||
|
pic_archive_out, |
||||||
|
pic_objs, |
||||||
|
) |
||||||
|
outputs.append(pic_archive_out) |
||||||
|
|
||||||
|
# For dynamic libraries, use the `cc_common.link` command to ensure |
||||||
|
# everything gets built correctly according to toolchain definitions. |
||||||
|
|
||||||
|
compilation_outputs = cc_common.create_compilation_outputs( |
||||||
|
objects = depset(objs), |
||||||
|
pic_objects = depset(pic_objs), |
||||||
|
) |
||||||
|
link_output = cc_common.link( |
||||||
|
actions = ctx.actions, |
||||||
|
feature_configuration = feature_configuration, |
||||||
|
cc_toolchain = cc_toolchain_info, |
||||||
|
compilation_outputs = compilation_outputs, |
||||||
|
name = ctx.label.name, |
||||||
|
output_type = "dynamic_library", |
||||||
|
user_link_flags = ctx.attr.linkopts, |
||||||
|
) |
||||||
|
library_to_link = link_output.library_to_link |
||||||
|
|
||||||
|
# Note: library_to_link.dynamic_library and interface_library are often |
||||||
|
# symlinks in the solib directory. For DefaultInfo, prefer reporting |
||||||
|
# the resolved artifact paths. |
||||||
|
if library_to_link.resolved_symlink_dynamic_library != None: |
||||||
|
outputs.append(library_to_link.resolved_symlink_dynamic_library) |
||||||
|
elif library_to_link.dynamic_library != None: |
||||||
|
outputs.append(library_to_link.dynamic_library) |
||||||
|
|
||||||
|
if library_to_link.resolved_symlink_interface_library != None: |
||||||
|
outputs.append(library_to_link.resolved_symlink_interface_library) |
||||||
|
elif library_to_link.interface_library != None: |
||||||
|
outputs.append(library_to_link.interface_library) |
||||||
|
|
||||||
|
# We could expose the libraries for use from cc rules: |
||||||
|
# |
||||||
|
# linking_context = cc_common.create_linking_context( |
||||||
|
# linker_inputs = depset([ |
||||||
|
# cc_common.create_linker_input( |
||||||
|
# owner = ctx.label, |
||||||
|
# libraries = depset([library_to_link]), |
||||||
|
# ), |
||||||
|
# ]), |
||||||
|
# ) |
||||||
|
# cc_info = CcInfo(linking_context = linking_context) # and return this |
||||||
|
# |
||||||
|
# However, if the goal is to force a protobuf dependency to use the |
||||||
|
# DSO, then `cc_import` is a better-supported way to do so. |
||||||
|
# |
||||||
|
# If we wanted to expose CcInfo from this rule (and make it usable as a |
||||||
|
# C++ dependency), then we would probably want to include the static |
||||||
|
# archive and headers as well. exposing headers would probably require |
||||||
|
# an additional aspect to extract CcInfos with just the deps' headers. |
||||||
|
|
||||||
|
return [ |
||||||
|
DefaultInfo(files = depset(outputs)), |
||||||
|
] |
||||||
|
|
||||||
|
cc_dist_library = rule( |
||||||
|
implementation = _cc_dist_library_impl, |
||||||
|
doc = """ |
||||||
|
Create libraries suitable for distribution. |
||||||
|
|
||||||
|
This rule creates static and dynamic libraries from the libraries listed in |
||||||
|
'deps'. The resulting libraries are suitable for distributing all of 'deps' |
||||||
|
in a single logical library, for example, in an installable binary package. |
||||||
|
Only the targets listed in 'deps' are included in the result (i.e., the |
||||||
|
output does not include transitive dependencies), allowing precise control |
||||||
|
over the library boundary. |
||||||
|
|
||||||
|
The outputs of this rule are a dynamic library and a static library. (If |
||||||
|
the build produces both PIC and non-PIC object files, then there is also a |
||||||
|
second static library.) The example below illustrates additional details. |
||||||
|
|
||||||
|
This rule is different from Bazel's experimental `shared_cc_library` in |
||||||
|
several ways. First, this rule ignores transitive dependencies, which means |
||||||
|
that dynamic library dependencies generally need to be specified via |
||||||
|
'linkopts'. Second, this rule produces a static archive library in addition |
||||||
|
to the dynamic shared library. Third, this rule is not directly usable as a |
||||||
|
C++ dependency (although the outputs could be used, e.g., by `cc_import`). |
||||||
|
|
||||||
|
Example: |
||||||
|
|
||||||
|
cc_library(name = "a", srcs = ["a.cc"], hdrs = ["a.h"]) |
||||||
|
cc_library(name = "b", srcs = ["b.cc"], hdrs = ["b.h"], deps = [":a"]) |
||||||
|
cc_library(name = "c", srcs = ["c.cc"], hdrs = ["c.h"], deps = [":b"]) |
||||||
|
|
||||||
|
# Creates libdist.so and (typically) libdist.pic.a: |
||||||
|
# (This may also produce libdist.a if the build produces non-PIC objects.) |
||||||
|
cc_dist_library( |
||||||
|
name = "dist", |
||||||
|
linkopts = ["-la"], # libdist.so dynamically links against liba.so. |
||||||
|
deps = [":b", ":c"], # Output contains b.o and c.o, but not a.o. |
||||||
|
) |
||||||
|
""", |
||||||
|
attrs = { |
||||||
|
"deps": attr.label_list( |
||||||
|
doc = ("The list of libraries to be included in the outputs. " + |
||||||
|
"Only these targets' compilation outputs will be " + |
||||||
|
"included (i.e., the transitive dependencies are not " + |
||||||
|
"included in the output)."), |
||||||
|
), |
||||||
|
"linkopts": attr.string_list( |
||||||
|
doc = ("Add these flags to the C++ linker command when creating " + |
||||||
|
"the dynamic library."), |
||||||
|
), |
||||||
|
# C++ toolchain before https://github.com/bazelbuild/bazel/issues/7260: |
||||||
|
"_cc_toolchain": attr.label( |
||||||
|
default = Label("@rules_cc//cc:current_cc_toolchain"), |
||||||
|
), |
||||||
|
}, |
||||||
|
toolchains = [ |
||||||
|
# C++ toolchain after https://github.com/bazelbuild/bazel/issues/7260: |
||||||
|
"@bazel_tools//tools/cpp:toolchain_type", |
||||||
|
], |
||||||
|
fragments = ["cpp"], |
||||||
|
) |
Loading…
Reference in new issue