1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173
|
# Copyright 2022 The Chromium Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import("//build/config/clang/clang.gni")
import("//build/config/rust.gni")
import("//build/config/sysroot.gni")
set_defaults("rust_cxx") {
native_header_deps = []
}
# Template to build Rust/C++ bindings using the tooling
# described at https://cxx.rs.
#
# (Specifically, this builds the C++ side of the bindings.
# The Rust side of the bindings are not 'built' as such, but
# automatically expanded by the Rust compiler by virtue of a
# proc macro which is a simple dependency relationship on the
# Rust target).
#
# This template expands to a source_set containing the
# C++ side of the bindings. Simply treat it as a dependency.
#
# If you're using this, consider whether you should be using
# rust_static_library.gni or mixed_static_library.gni which have
# facilities to do the same code generation in an easier
# way.
#
# Parameters:
#
# sources:
# The .rs files containing a #[cxx::bridge] section.
#
# deps (optional)
# C++ targets on which the headers depend in order to build
# successfully.
#
# export_symbols
# Whether the C++ side of the bindings should be exported
# from any shared objects in which it finds itself.
# This is not necessary if the Rust and C++ side of the
# bindings will always find themselves within the same binary,
# which is usually the case in a non-component build.
# Even in a component build, the Rust and C++ code will
# often find itself within the same binary and no exporting
# is required. However, there may be other binaries - most
# commonly Rust unit test executables - which contain the
# Rust side of the bindings but not the C++ side. In such
# a case, it's important that the C++ side symbols are
# exported such that the Rust unit tests can link against
# them. This does the equivalent of adding BASE_EXPORT
# or similar.
# Example:
# Non-component build:
# group of libfoo.a, foo.rlib # contain
# # C++ and Rust side bindings, always both linked
# # into final targets
# foo_rs_unittests # contains Rust side bindings,
# # and any C++ dependencies which will include
# # all of the libfoo code.
# Component build:
# libfoo.so # contains C++ and Rust side bindings
# foo_rs_unittests # contains Rust side test code,
# # but links against libfoo.so to get the C++
# # side bindings. So libfoo.so must make those
# # symbols visible.
template("rust_cxx") {
assert(defined(invoker.sources),
"Must specify the Rust file to use as input.")
_target_name = target_name
_testonly = false
if (defined(invoker.testonly)) {
_testonly = invoker.testonly
}
if (defined(invoker.visibility)) {
_visibility = invoker.visibility
}
action_foreach("${_target_name}_gen") {
testonly = _testonly
visibility = [ ":${_target_name}" ]
if (defined(_visibility)) {
visibility += _visibility
}
sources = invoker.sources
output_h = "{{source_gen_dir}}/{{source_file_part}}.h"
output_cc = "{{source_gen_dir}}/{{source_file_part}}.cc"
# Below we use $rust_macro_toolchain rather than $host_toolchain since we
# are building a standalone Rust target that is not part of the Chromium
# production build, and this unblocks it from building while the Chromium
# stdlib is still compiling, further freeing up other Rust proc-macro
# targets (if they used cxxbridge for some reason).
cxxbridge_target =
"//third_party/rust/cxxbridge_cmd/v1:cxxbridge($rust_macro_toolchain)"
cxxbridge_out_dir = get_label_info(cxxbridge_target, "root_out_dir")
cxxbridge_executable = "${cxxbridge_out_dir}/cxxbridge"
# The executable is always built with the `rust_macro_toolchain` which
# targets the `host_os`. The rule here is on the `target_toolchain` which
# can be different (e.g. compiling on Linux, targeting Windows).
if (host_os == "win") {
cxxbridge_executable = "${cxxbridge_executable}.exe"
}
script = "//third_party/rust/cxx/chromium_integration/run_cxxbridge.py"
inputs = [
cxxbridge_executable,
script,
]
outputs = [
output_h,
output_cc,
]
deps = [ cxxbridge_target ]
args = [
"--exe",
rebase_path(cxxbridge_executable, root_build_dir),
"--header",
output_h,
"--cc",
output_cc,
"{{source}}",
"--",
]
if (invoker.export_symbols) {
# See explanation of 'export_symbols' above for what this does.
# Implementation note: we could have required users of this template to
# specify a preprocessor symbol, e.g. BASE_EXPORT, which would vary
# per-component. However, since we're building only the definition of the
# bindings, not any header files, the export specifications are
# predictable and we don't need to foist that complexity on users of this
# template. The default behavior here should be correct. If this proves to
# be insufficient in future, this template should be modified to accept a
# parameter where users can specify 'BASE_EXPORT' or the equivalent for
# their component. cxxbridge --cxx-impl-annotations adds this annotation
# to each exported C++ function.
args += [ "--cxx-impl-annotations" ]
if (is_win) {
args += [ "__declspec(dllexport)" ]
} else {
args += [ "__attribute__((visibility(\"default\")))" ]
}
}
}
static_library(target_name) {
forward_variables_from(invoker, [ "deps" ])
testonly = _testonly
if (defined(invoker.visibility)) {
visibility = invoker.visibility
}
sources = get_target_outputs(":${target_name}_gen")
if (!defined(deps)) {
deps = []
}
deps += [
":${target_name}_gen",
"//build/rust:cxx_cppdeps",
]
if (defined(invoker.configs)) {
configs = []
configs = invoker.configs
}
}
}
|