mirror of
https://github.com/google/sandboxed-api.git
synced 2024-03-22 13:11:30 +08:00
4e20e0702a
Since the interface generator is invoked via a Bazel macro, it will be expanded in the embedding context of the project using SAPI, so package access needs to go through the full workspace root @com_google_sandboxed_api. This change also modifies the CMakeLists.txt accordingly, as the "external" subdirectory is no longer needed/wanted. PiperOrigin-RevId: 255918784 Change-Id: I052c687509f65fef7f011a9d1a074a171595330f
261 lines
8.6 KiB
Python
261 lines
8.6 KiB
Python
# Copyright 2019 Google LLC. All Rights Reserved.
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
# you may not use this file except in compliance with the License.
|
|
# You may obtain a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
# See the License for the specific language governing permissions and
|
|
# limitations under the License.
|
|
|
|
"""Macros that simplifies header and library generation for Sandboxed API."""
|
|
|
|
load("//sandboxed_api/bazel:embed_data.bzl", "sapi_cc_embed_data")
|
|
|
|
# Helper functions
|
|
def append_arg(arguments, name, value):
|
|
if value:
|
|
arguments.append("{}".format(name))
|
|
arguments.append(value)
|
|
|
|
def append_all(arguments, name, values):
|
|
if values:
|
|
for v in values:
|
|
append_arg(arguments, name, v)
|
|
|
|
def get_embed_dir():
|
|
return native.package_name()
|
|
|
|
def sort_deps(deps):
|
|
colon_deps = [x for x in deps if x.startswith(":")]
|
|
other_deps = [x for x in deps if not x.startswith(":")]
|
|
return sorted(colon_deps) + sorted(other_deps)
|
|
|
|
def sapi_interface_impl(ctx):
|
|
"""Implementation of build rule that generates SAPI interface."""
|
|
|
|
# TODO(szwl): warn if input_files is not set and we didn't find anything
|
|
input_files_paths = []
|
|
input_files = []
|
|
|
|
args = []
|
|
append_arg(args, "--sapi_name", ctx.attr.lib_name)
|
|
append_arg(args, "--sapi_out", ctx.outputs.out.path)
|
|
append_arg(args, "--sapi_embed_dir", ctx.attr.embed_dir)
|
|
append_arg(args, "--sapi_embed_name", ctx.attr.embed_name)
|
|
append_arg(args, "--sapi_functions", ",".join(ctx.attr.functions))
|
|
append_arg(args, "--sapi_ns", ctx.attr.namespace)
|
|
if ctx.attr.isystem:
|
|
isystem = ctx.attr.isystem.files.to_list()[0]
|
|
append_arg(args, "--sapi_isystem", isystem.path)
|
|
input_files += [isystem]
|
|
|
|
# Parse provided files.
|
|
|
|
# The parser doesn't need the entire set of transitive headers
|
|
# here, just the top-level cc_library headers. It would be nice
|
|
# if Skylark or Bazel provided this, but it is surprisingly hard
|
|
# to get.
|
|
#
|
|
# Allow all headers through that contain the dependency's
|
|
# package path. Including extra headers is harmless except that
|
|
# we may hit Bazel's file-count limit, so be conservative and
|
|
# pass a lot through that we don't strictly need.
|
|
|
|
extra_flags = []
|
|
if ctx.attr.lib[CcInfo]:
|
|
cc_ctx = ctx.attr.lib[CcInfo].compilation_context
|
|
|
|
# Append system headers as dependencies
|
|
input_files += cc_ctx.headers.to_list()
|
|
append_all(extra_flags, "-D", cc_ctx.defines.to_list())
|
|
append_all(extra_flags, "-isystem", cc_ctx.system_includes.to_list())
|
|
append_all(extra_flags, "-iquote", cc_ctx.quote_includes.to_list())
|
|
|
|
if ctx.attr.input_files:
|
|
for h in cc_ctx.headers.to_list():
|
|
# Collect all headers as dependency in case libclang needs them.
|
|
if h.extension == "h" and "/PROTECTED/" not in h.path:
|
|
input_files.append(h)
|
|
for target in ctx.attr.input_files:
|
|
if target.files:
|
|
for f in target.files.to_list():
|
|
input_files_paths.append(f.path)
|
|
input_files.append(f)
|
|
|
|
# Try to find files automatically.
|
|
else:
|
|
for h in cc_ctx.headers.to_list():
|
|
# Collect all headers as dependency in case clang needs them.
|
|
if h.extension == "h" and "/PROTECTED/" not in h.path:
|
|
input_files.append(h)
|
|
|
|
# Include only headers coming from the target
|
|
# not ones that it depends on by comparing the label packages.
|
|
if (h.owner.package == ctx.attr.lib.label.package):
|
|
input_files_paths.append(h.path)
|
|
|
|
append_arg(args, "--sapi_in", ",".join(input_files_paths))
|
|
args += ["--"] + extra_flags
|
|
else:
|
|
# TODO(szwl): Error out if the lib has no cc.
|
|
pass
|
|
|
|
progress_msg = ("Generating {} from {} header files." +
|
|
"").format(ctx.outputs.out.short_path, len(input_files_paths))
|
|
ctx.actions.run(
|
|
inputs = input_files,
|
|
outputs = [ctx.outputs.out],
|
|
arguments = args,
|
|
progress_message = progress_msg,
|
|
executable = ctx.executable._sapi_generator,
|
|
)
|
|
|
|
# Build rule that generates SAPI interface.
|
|
sapi_interface = rule(
|
|
implementation = sapi_interface_impl,
|
|
attrs = {
|
|
"out": attr.output(mandatory = True),
|
|
"embed_dir": attr.string(),
|
|
"embed_name": attr.string(),
|
|
"functions": attr.string_list(allow_empty = True, default = []),
|
|
"include_prefix": attr.string(),
|
|
"input_files": attr.label_list(allow_files = True),
|
|
"lib": attr.label(mandatory = True),
|
|
"lib_name": attr.string(mandatory = True),
|
|
"namespace": attr.string(),
|
|
"isystem": attr.label(),
|
|
"_sapi_generator": attr.label(
|
|
executable = True,
|
|
cfg = "host",
|
|
allow_files = True,
|
|
default = Label("@com_google_sandboxed_api//sandboxed_api/" +
|
|
"tools/generator2:sapi_generator"),
|
|
),
|
|
},
|
|
output_to_genfiles = True,
|
|
)
|
|
|
|
def sapi_library(
|
|
name,
|
|
lib,
|
|
lib_name,
|
|
namespace = "",
|
|
embed = False,
|
|
add_default_deps = True,
|
|
srcs = [],
|
|
hdrs = [],
|
|
functions = [],
|
|
header = "",
|
|
input_files = [],
|
|
deps = [],
|
|
tags = [],
|
|
visibility = None):
|
|
"""BUILD rule providing implementation of a Sandboxed API library."""
|
|
|
|
common = {
|
|
"tags": tags,
|
|
}
|
|
if visibility:
|
|
common["visibility"] = visibility
|
|
|
|
generated_header = name + ".sapi.h"
|
|
|
|
# Reference (pull into the archive) required functions only. If the functions'
|
|
# array is empty, pull in the whole archive (may not compile with MSAN).
|
|
exported_funcs = ["-Wl,--export-dynamic-symbol," + s for s in functions]
|
|
if (not exported_funcs):
|
|
exported_funcs = [
|
|
"-Wl,--whole-archive",
|
|
"-Wl,--allow-multiple-definition",
|
|
]
|
|
|
|
lib_hdrs = hdrs or []
|
|
if header:
|
|
lib_hdrs += [header]
|
|
else:
|
|
lib_hdrs += [generated_header]
|
|
|
|
default_deps = ["@com_google_sandboxed_api//sandboxed_api/sandbox2"]
|
|
|
|
# Library that contains generated interface and sandboxed binary as a data
|
|
# dependency. Add this as a dependency instead of original library.
|
|
native.cc_library(
|
|
name = name,
|
|
srcs = srcs,
|
|
hdrs = lib_hdrs,
|
|
data = [":" + name + ".bin"],
|
|
deps = sort_deps(
|
|
[
|
|
"@com_google_sandboxed_api//sandboxed_api:sapi",
|
|
"@com_google_sandboxed_api//sandboxed_api:vars",
|
|
] + deps +
|
|
([":" + name + "_embed"] if embed else []) +
|
|
(default_deps if add_default_deps else []),
|
|
),
|
|
**common
|
|
)
|
|
|
|
native.cc_binary(
|
|
name = name + ".bin",
|
|
linkopts = [
|
|
# The sandboxing client must have access to all
|
|
"-Wl,-E", # symbols used in the sandboxed library, so these
|
|
] + exported_funcs, # must be both referenced, and exported
|
|
deps = [
|
|
":" + name + ".lib",
|
|
"@com_google_sandboxed_api//sandboxed_api:client",
|
|
],
|
|
**common
|
|
)
|
|
|
|
native.cc_library(
|
|
name = name + ".lib",
|
|
deps = [
|
|
lib,
|
|
],
|
|
alwayslink = 1, # All functions are linked into depending binaries
|
|
**common
|
|
)
|
|
|
|
embed_name = ""
|
|
embed_dir = ""
|
|
if embed:
|
|
embed_name = name
|
|
|
|
sapi_cc_embed_data(
|
|
srcs = [name + ".bin"],
|
|
name = name + "_embed",
|
|
namespace = namespace,
|
|
**common
|
|
)
|
|
embed_dir = get_embed_dir()
|
|
|
|
sapi_interface(
|
|
name = name + ".interface",
|
|
lib_name = lib_name,
|
|
lib = lib,
|
|
functions = functions,
|
|
input_files = input_files,
|
|
out = generated_header,
|
|
embed_name = embed_name,
|
|
embed_dir = embed_dir,
|
|
namespace = namespace,
|
|
isystem = ":" + name + ".isystem",
|
|
**common
|
|
)
|
|
|
|
native.genrule(
|
|
name = name + ".isystem",
|
|
outs = [name + ".isystem.list"],
|
|
cmd = """echo |
|
|
$(CC) -E -x c++ - -v 2>&1 |
|
|
awk '/> search starts here:/{flag=1;next}/End of search/{flag=0}flag' > $@
|
|
""",
|
|
toolchains = ["@bazel_tools//tools/cpp:current_cc_toolchain"],
|
|
)
|