mirror of https://github.com/bazelbuild/rules_cc
prototype cc_shared_library with example
This commit is contained in:
parent
236c6eb75c
commit
8214dc026f
|
@ -0,0 +1,80 @@
|
|||
load("//:cc_shared_library.bzl", "cc_bin", "cc_shared_library")
|
||||
|
||||
sh_binary(
|
||||
name = "symbol_grabber",
|
||||
srcs = ["symbol_grabber.sh"],
|
||||
)
|
||||
|
||||
cc_bin(
|
||||
name = "main",
|
||||
srcs = ["main.cc"],
|
||||
dynamic_deps = [":libA_shared.so"],
|
||||
)
|
||||
|
||||
# FIX: add cc_binary to test
|
||||
cc_shared_library(
|
||||
name = "libA_shared.so",
|
||||
of = "A",
|
||||
dynamic_deps = [":libB_shared.so"],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "A",
|
||||
srcs = ["a.cc"],
|
||||
hdrs = ["a.h"],
|
||||
deps = [
|
||||
"C",
|
||||
"D",
|
||||
],
|
||||
)
|
||||
|
||||
cc_shared_library(
|
||||
name = "libB_shared.so",
|
||||
of = "B",
|
||||
#dynamic_deps = [":libE_shared.so"],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "B",
|
||||
srcs = ["b.cc"],
|
||||
hdrs = ["b.h"],
|
||||
deps = [
|
||||
"E",
|
||||
"F",
|
||||
],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "C",
|
||||
srcs = ["c.cc"],
|
||||
hdrs = ["c.h"],
|
||||
deps = [
|
||||
"E",
|
||||
],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "D",
|
||||
srcs = ["d.cc"],
|
||||
hdrs = ["d.h"],
|
||||
deps = [
|
||||
"B",
|
||||
],
|
||||
)
|
||||
|
||||
cc_shared_library(
|
||||
name = "libE_shared.so",
|
||||
of = "E",
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "E",
|
||||
srcs = ["e.cc"],
|
||||
hdrs = ["e.h"],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "F",
|
||||
srcs = ["f.cc"],
|
||||
hdrs = ["f.h"],
|
||||
)
|
|
@ -0,0 +1,8 @@
|
|||
#include "a.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "c.h"
|
||||
#include "d.h"
|
||||
|
||||
std::string a() { return "-a" + c() + d(); }
|
|
@ -0,0 +1,8 @@
|
|||
#ifndef LIBRARY_A
|
||||
#define LIBRARY_A
|
||||
|
||||
#include <string>
|
||||
|
||||
std::string a();
|
||||
|
||||
#endif
|
|
@ -0,0 +1,8 @@
|
|||
#include "b.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "e.h"
|
||||
#include "f.h"
|
||||
|
||||
std::string b() { return "-b" + e() + f(); }
|
|
@ -0,0 +1,8 @@
|
|||
#ifndef LIBRARY_B
|
||||
#define LIBRARY_B
|
||||
|
||||
#include <string>
|
||||
|
||||
std::string b();
|
||||
|
||||
#endif
|
|
@ -0,0 +1 @@
|
|||
/usr/local/google/home/plf/.cache/bazel/_bazel_plf/e28f6f4251177f0cba97bce09eefc316/execroot/__main__/bazel-out/k8-fastbuild/bin
|
|
@ -0,0 +1 @@
|
|||
/usr/local/google/home/plf/.cache/bazel/_bazel_plf/e28f6f4251177f0cba97bce09eefc316/execroot/__main__/bazel-out/k8-fastbuild/bin
|
|
@ -0,0 +1 @@
|
|||
/usr/local/google/home/plf/.cache/bazel/_bazel_plf/e28f6f4251177f0cba97bce09eefc316/execroot/__main__/bazel-out
|
|
@ -0,0 +1 @@
|
|||
/usr/local/google/home/plf/.cache/bazel/_bazel_plf/e28f6f4251177f0cba97bce09eefc316/execroot/__main__
|
|
@ -0,0 +1 @@
|
|||
/usr/local/google/home/plf/.cache/bazel/_bazel_plf/e28f6f4251177f0cba97bce09eefc316/execroot/__main__/bazel-out/k8-fastbuild/testlogs
|
|
@ -0,0 +1,7 @@
|
|||
#include "c.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "e.h"
|
||||
|
||||
std::string c() { return "-c" + e(); }
|
|
@ -0,0 +1,8 @@
|
|||
#ifndef LIBRARY_C
|
||||
#define LIBRARY_C
|
||||
|
||||
#include <string>
|
||||
|
||||
std::string c();
|
||||
|
||||
#endif
|
|
@ -0,0 +1,270 @@
|
|||
load("@bazel_tools//tools/cpp:toolchain_utils.bzl", "find_cpp_toolchain")
|
||||
|
||||
CcSharedLibraryInfo = provider()
|
||||
|
||||
def _get_all_labels(direct_children):
|
||||
node = None
|
||||
all_children = list(direct_children)
|
||||
all_labels = {}
|
||||
for i in range(1, 2147483647):
|
||||
if len(all_children) == 0:
|
||||
break
|
||||
node = all_children.pop(0)
|
||||
|
||||
all_labels[node.label] = True
|
||||
|
||||
all_children.extend(node.children)
|
||||
return all_labels
|
||||
|
||||
def _get_dynamic_libraries(ctx, all_labels):
|
||||
direct_cc_shared_library_infos = []
|
||||
for direct_dynamic_dep in ctx.attr.dynamic_deps:
|
||||
cc_shared_library_info = direct_dynamic_dep[CcSharedLibraryInfo]
|
||||
direct_cc_shared_library_infos.append(cc_shared_library_info)
|
||||
|
||||
dynamic_labels = {}
|
||||
cc_shared_library_infos = list(direct_cc_shared_library_infos)
|
||||
dynamic_libraries = []
|
||||
for i in range(1, 2147483647):
|
||||
if len(cc_shared_library_infos) == 0:
|
||||
break
|
||||
cc_shared_library_info = cc_shared_library_infos.pop(0)
|
||||
dynamic_labels[cc_shared_library_info.of] = True
|
||||
dynamic_libraries.append(cc_shared_library_info.transitive_library)
|
||||
for direct_cc_shared_library_info in cc_shared_library_info.direct_cc_shared_library_infos:
|
||||
if direct_cc_shared_library_info.of in all_labels:
|
||||
cc_shared_library_infos.append(direct_cc_shared_library_info)
|
||||
|
||||
return (direct_cc_shared_library_infos, dynamic_labels, dynamic_libraries)
|
||||
|
||||
def _get_whitelisted_labels(direct_children, dynamic_labels):
|
||||
whitelisted_labels = {}
|
||||
whitelisted_children = list(direct_children)
|
||||
for i in range(1, 2147483647):
|
||||
if len(whitelisted_children) == 0:
|
||||
break
|
||||
node = whitelisted_children.pop(0)
|
||||
|
||||
whitelisted_labels[node.label] = True
|
||||
|
||||
for child in node.children:
|
||||
if child.label not in dynamic_labels:
|
||||
whitelisted_children.append(child)
|
||||
|
||||
return whitelisted_labels
|
||||
|
||||
def _get_new_linking_context(cc_info, dynamic_libraries, whitelisted_labels):
|
||||
libraries_to_link = []
|
||||
for library_to_link in cc_info.linking_context.libraries_to_link.to_list():
|
||||
if library_to_link.label in whitelisted_labels:
|
||||
libraries_to_link.append(library_to_link)
|
||||
|
||||
libraries_to_link.extend(dynamic_libraries)
|
||||
|
||||
return cc_common.create_linking_context(
|
||||
libraries_to_link = libraries_to_link,
|
||||
user_link_flags = cc_info.linking_context.user_link_flags,
|
||||
additional_inputs = cc_info.linking_context.additional_inputs.to_list(),
|
||||
)
|
||||
|
||||
def _get_version_script(ctx, new_linking_context, export_labels):
|
||||
libraries_to_link = new_linking_context.libraries_to_link
|
||||
objects = []
|
||||
exports = {}
|
||||
for export_label in export_labels:
|
||||
exports[export_label.label] = True
|
||||
|
||||
for library_to_link in libraries_to_link.to_list():
|
||||
if library_to_link.label in exports:
|
||||
if library_to_link.objects != None:
|
||||
objects.extend(library_to_link.objects)
|
||||
elif library_to_link.pic_objects != None:
|
||||
objects.extend(library_to_link.pic_objects)
|
||||
|
||||
symbols_file = ctx.actions.declare_file(ctx.label.name + "_symbols.txt")
|
||||
arguments = [symbols_file.path]
|
||||
for object_file in objects:
|
||||
arguments.append(object_file.path)
|
||||
|
||||
ctx.actions.run(
|
||||
outputs = [symbols_file],
|
||||
inputs = objects,
|
||||
executable = ctx.executable._symbol_grabber,
|
||||
arguments = arguments,
|
||||
)
|
||||
|
||||
return symbols_file
|
||||
|
||||
GraphNodeInfo = provider()
|
||||
|
||||
def _graph_structure_aspect_impl(target, ctx):
|
||||
children = []
|
||||
|
||||
# TODO: We should actually check every attribute, not just deps or of, with the
|
||||
# exception of those which don't have CcInfo.
|
||||
if hasattr(ctx.rule.attr, "deps"):
|
||||
for dep in ctx.rule.attr.deps:
|
||||
if GraphNodeInfo in dep:
|
||||
children.append(dep[GraphNodeInfo])
|
||||
if hasattr(ctx.rule.attr, "of"):
|
||||
children.append(ctx.rule.attr.of[GraphNodeInfo])
|
||||
|
||||
return [GraphNodeInfo(label = ctx.label, children = children)]
|
||||
|
||||
graph_structure_aspect = aspect(
|
||||
attr_aspects = ["*"],
|
||||
implementation = _graph_structure_aspect_impl,
|
||||
)
|
||||
|
||||
def _cc_shared_library_impl(ctx):
|
||||
of_graph_node_info = ctx.attr.of[GraphNodeInfo]
|
||||
all_labels = _get_all_labels([of_graph_node_info])
|
||||
|
||||
(direct_cc_shared_library_infos, dynamic_labels, dynamic_libraries) = _get_dynamic_libraries(ctx, all_labels)
|
||||
|
||||
whitelisted_labels = _get_whitelisted_labels([of_graph_node_info], dynamic_labels)
|
||||
|
||||
new_linking_context = _get_new_linking_context(ctx.attr.of[CcInfo], dynamic_libraries, whitelisted_labels)
|
||||
|
||||
cc_toolchain = find_cpp_toolchain(ctx)
|
||||
feature_configuration = cc_common.configure_features(
|
||||
ctx = ctx,
|
||||
cc_toolchain = cc_toolchain,
|
||||
requested_features = ctx.features,
|
||||
unsupported_features = ctx.disabled_features,
|
||||
)
|
||||
symbols = _get_version_script(ctx, new_linking_context, [ctx.attr.of])
|
||||
|
||||
linking_outputs = cc_common.link(
|
||||
actions = ctx.actions,
|
||||
feature_configuration = feature_configuration,
|
||||
cc_toolchain = cc_toolchain,
|
||||
linking_contexts = [new_linking_context],
|
||||
user_link_flags = ["-Wl,--version-script=" + symbols.path],
|
||||
additional_inputs = [symbols],
|
||||
name = ctx.label.name,
|
||||
output_type = "dynamic_library",
|
||||
)
|
||||
transitive_library = linking_outputs.library_to_link
|
||||
|
||||
return [
|
||||
DefaultInfo(files = depset([transitive_library.resolved_symlink_dynamic_library, symbols])),
|
||||
CcSharedLibraryInfo(
|
||||
of = ctx.attr.of[GraphNodeInfo].label,
|
||||
compilation_context = ctx.attr.of[CcInfo].compilation_context,
|
||||
transitive_library = transitive_library,
|
||||
direct_cc_shared_library_infos = direct_cc_shared_library_infos,
|
||||
),
|
||||
]
|
||||
|
||||
cc_shared_library = rule(
|
||||
implementation = _cc_shared_library_impl,
|
||||
attrs = {
|
||||
"of": attr.label(aspects = [graph_structure_aspect]),
|
||||
"dynamic_deps": attr.label_list(providers = [CcSharedLibraryInfo]),
|
||||
"preloaded_deps": attr.label_list(providers = [CcInfo]),
|
||||
"export_all": attr.bool(),
|
||||
"export_wrapped_library": attr.bool(),
|
||||
"additional_symbols_to_export": attr.label(allow_single_file = True),
|
||||
"_cc_toolchain": attr.label(default = "@bazel_tools//tools/cpp:current_cc_toolchain"),
|
||||
"_symbol_grabber": attr.label(default = ":symbol_grabber", executable = True, cfg = "host"),
|
||||
},
|
||||
fragments = ["google_cpp", "cpp"],
|
||||
)
|
||||
|
||||
def _cc_bin_impl(ctx):
|
||||
cc_toolchain = find_cpp_toolchain(ctx)
|
||||
feature_configuration = cc_common.configure_features(
|
||||
ctx = ctx,
|
||||
cc_toolchain = cc_toolchain,
|
||||
requested_features = ctx.features,
|
||||
unsupported_features = ctx.disabled_features,
|
||||
)
|
||||
|
||||
direct_children = []
|
||||
cc_infos = []
|
||||
compilation_contexts = []
|
||||
for dep in ctx.attr.deps:
|
||||
if GraphNodeInfo in dep:
|
||||
direct_children.append(dep[GraphNodeInfo])
|
||||
if CcInfo in dep:
|
||||
compilation_contexts.append(dep[CcInfo].compilation_context)
|
||||
cc_infos.append(dep[CcInfo])
|
||||
|
||||
for dep in ctx.attr.dynamic_deps:
|
||||
if GraphNodeInfo in dep:
|
||||
direct_children.append(dep[GraphNodeInfo])
|
||||
if CcInfo in dep:
|
||||
compilation_contexts.append(dep[CcInfo].compilation_context)
|
||||
cc_infos.append(dep[CcInfo])
|
||||
|
||||
all_labels = _get_all_labels(direct_children)
|
||||
|
||||
(direct_cc_shared_library_infos, dynamic_labels, dynamic_libraries) = _get_dynamic_libraries(ctx, all_labels)
|
||||
|
||||
for direct_cc_shared_library_info in direct_cc_shared_library_infos:
|
||||
compilation_contexts.append(direct_cc_shared_library_info.compilation_context)
|
||||
|
||||
merged_cc_info = cc_common.merge_cc_infos(cc_infos = cc_infos)
|
||||
|
||||
(_compilation_context, compilation_outputs) = cc_common.compile(
|
||||
name = ctx.label.name,
|
||||
actions = ctx.actions,
|
||||
feature_configuration = feature_configuration,
|
||||
cc_toolchain = cc_toolchain,
|
||||
srcs = ctx.files.srcs,
|
||||
compilation_contexts = compilation_contexts,
|
||||
)
|
||||
|
||||
whitelisted_children = []
|
||||
for child in direct_children:
|
||||
if child.label in dynamic_labels:
|
||||
fail("From cc_binary, do not depend on the same library statically and dynamically")
|
||||
whitelisted_children.append(child)
|
||||
|
||||
whitelisted_labels = _get_whitelisted_labels(whitelisted_children, dynamic_labels)
|
||||
|
||||
new_linking_context = _get_new_linking_context(merged_cc_info, dynamic_libraries, whitelisted_labels)
|
||||
|
||||
linking_outputs = cc_common.link(
|
||||
name = ctx.label.name,
|
||||
actions = ctx.actions,
|
||||
feature_configuration = feature_configuration,
|
||||
cc_toolchain = cc_toolchain,
|
||||
compilation_outputs = compilation_outputs,
|
||||
linking_contexts = [new_linking_context],
|
||||
link_deps_statically = ctx.attr.linkstatic,
|
||||
)
|
||||
files = [linking_outputs.executable]
|
||||
runfiles = []
|
||||
for library in dynamic_libraries:
|
||||
runfiles.append(library.dynamic_library)
|
||||
|
||||
return [
|
||||
DefaultInfo(
|
||||
files = depset(files),
|
||||
runfiles = ctx.runfiles(files = runfiles),
|
||||
),
|
||||
]
|
||||
|
||||
cc_bin = rule(
|
||||
implementation = _cc_bin_impl,
|
||||
attrs = {
|
||||
"srcs": attr.label_list(allow_files = [".cc"]),
|
||||
"deps": attr.label_list(
|
||||
allow_empty = True,
|
||||
providers = [CcInfo],
|
||||
),
|
||||
"data": attr.label_list(
|
||||
default = [],
|
||||
allow_files = True,
|
||||
),
|
||||
"dynamic_deps": attr.label_list(
|
||||
providers = [CcSharedLibraryInfo],
|
||||
aspects = [graph_structure_aspect],
|
||||
),
|
||||
"linkstatic": attr.bool(default = True),
|
||||
"_cc_toolchain": attr.label(default = "@bazel_tools//tools/cpp:current_cc_toolchain"),
|
||||
},
|
||||
fragments = ["google_cpp", "cpp"],
|
||||
)
|
|
@ -0,0 +1,7 @@
|
|||
#include "d.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "b.h"
|
||||
|
||||
std::string d() { return "-d" + b(); }
|
|
@ -0,0 +1,8 @@
|
|||
#ifndef LIBRARY_D
|
||||
#define LIBRARY_D
|
||||
|
||||
#include <string>
|
||||
|
||||
std::string d();
|
||||
|
||||
#endif
|
|
@ -0,0 +1,5 @@
|
|||
#include "e.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
std::string e() { return "-e"; }
|
|
@ -0,0 +1,8 @@
|
|||
#ifndef LIBRARY_E
|
||||
#define LIBRARY_E
|
||||
|
||||
#include <string>
|
||||
|
||||
std::string e();
|
||||
|
||||
#endif
|
|
@ -0,0 +1,5 @@
|
|||
#include "f.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
std::string f() { return "-f"; }
|
|
@ -0,0 +1,8 @@
|
|||
#ifndef LIBRARY_F
|
||||
#define LIBRARY_F
|
||||
|
||||
#include <string>
|
||||
|
||||
std::string f();
|
||||
|
||||
#endif
|
|
@ -0,0 +1,8 @@
|
|||
#include <iostream>
|
||||
|
||||
#include "a.h"
|
||||
|
||||
int main() {
|
||||
std::cout << "Hello " + a() << std::endl;
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
#!/bin/bash
|
||||
|
||||
output_file=$1
|
||||
touch $output_file.symbols
|
||||
shift
|
||||
for object_file in "$@" ; do
|
||||
nm $object_file | grep " T " | rev | cut -f1 -d" " | rev >> $output_file.symbols
|
||||
done
|
||||
|
||||
sort -u $output_file.symbols > "$output_file".symbols.tmp
|
||||
sed 's/$/\;/' $output_file.symbols.tmp > "$output_file".symbols
|
||||
rm "$output_file".symbols.tmp
|
||||
|
||||
echo "VERS_1.1 {" > "$output_file"
|
||||
echo "global:" >> "$output_file"
|
||||
cat "$output_file".symbols >> "$output_file"
|
||||
echo "local:" >> "$output_file"
|
||||
echo "*;" >> "$output_file"
|
||||
echo "};" >> "$output_file"
|
||||
|
Loading…
Reference in New Issue