本文档演示了如何构建和测试组件,重点介绍了 定义软件包、组件及其测试的最佳做法。
概念
在构建组件之前,您应该了解以下概念:
<ph type="x-smartling-placeholder"></ph>
软件包
是 Google Cloud 上的软件分发单元,
紫红色。Packages 是一系列文件集合,其关联路径可用于
相对于文件包底板的高度例如,一个软件包可能包含
路径 bin/hello_world
下的 ELF 二进制文件,路径下的 JSON 文件
data/config.json
。必须将文件分组到文件包中才能推送
将这些文件上传到设备上
<ph type="x-smartling-placeholder"></ph> 组件 是 Google Cloud 上软件执行的 紫红色。Fuchsia 上的所有软件(内核映像和用户模式除外) 引导加载程序被定义为组件。
组件由 <ph type="x-smartling-placeholder"></ph> 组件清单 。通常使用的组件 添加额外的文件,例如在 Google Cloud 控制台中 运行时。
开发者必须根据软件包和组件来定义其软件 无论是构建生产软件还是编写测试。
在运行时,
组件实例
请参阅
其软件包的内容以只读文件形式保存在路径 /pkg
下。定义两个
同一软件包中的一个或多个组件不会向每个组件
彼此的功能不过,它能保证一个组件
其他可用。因此,如果组件试图启动
其他组件(例如在集成测试中),
将这两个组件打包在一起
组件可通过几种方式进行实例化,所有这些方式都以某种方式指定其
网址
,了解所有最新动态。通常,您可以通过指定
其软件包名称及其在软件包中的组件清单的路径,使用
fuchsia-pkg://
架构
,了解所有最新动态。
组件清单
组件清单是对组件声明进行编码的文件, 作为软件包的一部分分发二进制格式是持久性 FIDL 文件 其中包含组件声明该清单声明了 组件的程序二进制文件和所需功能。
以下是一个简单的“Hello, World”的清单文件示例组件:
{
// Information about the program to run.
program: {
// Use the built-in ELF runner to run platform-specific binaries.
runner: "elf",
// The binary to run for this component.
binary: "bin/hello",
// Program arguments
args: [
"Hello",
"World!",
],
},
// Capabilities used by this component.
use: [
{ protocol: "fuchsia.logger.LogSink" },
],
}
清单分片
一些功能集合代表了常见的使用场景要求
系统中的许多组件,例如日志记录。为了简化包含这些
功能,则组件框架支持
将它们转换为可包含在主清单文件中的清单分片中。
它在概念上与 C 编程中的 #include
指令类似。
语言。
下面是与上一示例等效的清单,其中包含
功能替换为清单分片 include
:
{
// Include capabilities for the syslog library
include: [ "syslog/client.shard.cml" ],
// Information about the program to run.
program: {
// Use the built-in ELF runner to run platform-specific binaries.
runner: "elf",
// The binary to run for this component.
binary: "bin/hello-world",
// Program arguments
args: [
"Hello",
"World!",
],
},
}
相对路径
以 "//"
开头的包含路径相对于源代码树的根目录
所用的工具对于不以 "//"
开头的包含路径,
构建系统会尝试通过 Fuchsia SDK 解决它们。
分片间依赖项
如果一个清单分片向该清单添加一个子项,而向另一个清单分片添加 添加第二个子级,该子级依赖于第一个子级,然后来自 如果存在以下情况,则从第一个子项到第二个子项将导致清单验证错误 第二个分片会包含在没有第一个分片的清单中,因为 优惠将提及不存在的孩子。
// echo_server.shard.cml
{
children: [ {
name: "echo_server",
url: "fuchsia-pkg://fuchsia.com/echo_server#meta/echo_server.cm",
} ],
}
// echo_client.shard.cml
{
children: [
{
name: "echo_client",
url: "fuchsia-pkg://fuchsia.com/echo_client#meta/echo_client.cm",
}
],
offer: [ {
// This offer will cause manifest validation to fail if
// `echo_client.shard.cml` is included in a manifest without
// `echo_server.shard.cml`.
protocol: "fuchsia.examples.Echo",
from: "echo_server",
to: "echo_client",
} ],
}
为解决此问题,可以将优惠的 source_availability
字段设置为
告知清单编译可以接受优惠来源
缺失。如果设置为 unknown
,优惠将会出现以下情况
声明:
- 如果
from
来源存在:可用性设置为required
。 - 如果
from
来源不存在:库存状况设置为optional
,并且 优惠的来源被重写为void
。
// echo_client.shard.cml
{
children: [
{
name: "echo_client",
url: "fuchsia-pkg://fuchsia.com/echo_client#meta/echo_client.cm",
}
],
offer: [
{
// If `echo_server.shard.cml` is included in this manifest, then
// `echo_client` can access the `fuchsia.examples.Echo` protocol from
// it.
//
// If `echo_server.shard.cml` is not included in this manifest, then
// `echo_client` will be offered the protocol with a source of
// `void` and `availability == optional`. `echo_client` must consume
// the capability optionally to not fail route validation.
protocol: "fuchsia.examples.Echo",
from: "echo_server",
to: "echo_client",
source_availability: "unknown",
}
],
}
如需详细了解 availability
的工作原理,请参阅可用性。
客户端库包括
如上所示,组件清单支持“include”语法, 引用一个或多个清单分片作为其他清单内容的来源。 库等某些依赖项会假定依赖组件 在运行时可用的某些功能例如, C++ Syslog 库做出了这样的假设。
如果要构建客户端库,可以声明这些必需的依赖项
在 BUILD.gn
文件中使用 expect_includes
。例如,您可以考虑使用
下面的假设文件 //sdk/lib/fonts/BUILD.gn
:
import("//tools/cmc/build/expect_includes.gni")
# Client library for components that want to use fonts
source_set("font_provider_client") {
sources = [
"font_provider_client.cc",
...
]
deps = [
":font_provider_client_includes",
...
]
}
expect_includes("font_provider_client_includes") {
includes = [
"client.shard.cml",
]
}
这会为从属清单设置构建时间要求,使其包含 预期的清单分片数:
{
include: [
"//sdk/lib/fonts/client.shard.cml",
]
...
}
包含路径相对于源根目录进行解析。 允许使用传递包含(包括包含)。 不允许循环。
为分片命名时,相对于完整路径,不要重复。
在上面的示例中,为分片命名是重复性的
fonts.shard.cml
,因为完整路径将为
sdk/lib/fonts/fonts.shard.cml
(重复)。而是
名为 client.shard.cml
,以表明将由
适用于字体的 SDK 库。
组件包 GN 模板
GN 是 Fuchsia 使用的元构建系统。Fuchsia 扩展了 GN 来生成模型。模板提供了一种添加到 GN 内置目标的方法 。
Fuchsia 定义了以下 GN 模板来定义软件包和组件:
下面是一个假设的软件包,其中包含一个运行 C++ 组件的组件 计划:
import("//build/components.gni")
executable("my_program") {
sources = [ "my_program.cc" ]
}
fuchsia_component("my_component") {
manifest = "meta/my_program.cml"
deps = [ ":my_program" ]
}
fuchsia_package("my_package") {
deps = [ ":my_component" ]
}
请注意以下详细信息:
- 导入
"//build/components.gni"
即可访问与以下内容相关的所有模板: 软件包、组件和测试 fuchsia_component()
模板会声明组件。这取决于 程序二进制文件(本例中为executable()
),并且需要manifest
指向组件清单文件组件和包的名称都是从其目标名称派生而来。 在上例中,这些名称一起构成了 启动组件:
fuchsia-pkg://fuchsia.com/my_package#meta/my_component.cm
。
特定语言的组件示例
以下是定义包含单个组件的软件包的基本示例 以各种常用语言启动程序的功能。引用的 指定源文件和组件清单, 路径。
C++
import("//build/components.gni")
executable("bin") {
output_name = "my_program"
sources = [ "main.cc" ]
}
fuchsia_component("my_component") {
manifest = "meta/my_component.cml"
deps = [ ":bin" ]
}
fuchsia_package("my_package") {
deps = [ ":my_component" ]
}
Rust
import("//build/rust/rustc_binary.gni")
import("//build/components.gni")
rustc_binary("bin") {
output_name = "my_program"
sources = [ "src/main.rs" ]
}
fuchsia_component("my_component") {
manifest = "meta/my_component.cml"
deps = [ ":bin" ]
}
fuchsia_package("my_package") {
deps = [ ":my_component" ]
}
Go
import("//build/go/go_binary.gni")
import("//build/components.gni")
go_binary("bin") {
output_name = "my_program"
sources = [ "main.go" ]
}
fuchsia_component("my_component") {
manifest = "meta/my_component.cml"
deps = [ ":bin" ]
}
fuchsia_package("my_package") {
deps = [ ":my_component" ]
}
包含单个组件的软件包
软件包是分发的单位。最好定义多个 多个组件 组件始终共存,或者如果您希望能够更新 (通过更新单个软件包)。
此模式也常用于创建封闭集成测试。 例如,两个组件之间的集成测试,其中一个组件是客户端 另一个组件中实现的服务的两个不同部分 和服务器组件
不过,您经常可能会定义只需要一个组件的软件包。
在这种情况下,您可以使用 fuchsia_package_with_single_component()
模板。此模板将 fuchsia_package()
和
fuchsia_component()
。
C++
import("//build/components.gni")
executable("rot13_encoder_decoder") {
sources = [ "rot13_encoder_decoder.cc" ]
}
fuchsia_package_with_single_component("rot13") {
manifest = "meta/rot13.cml"
deps = [ ":rot13_encoder_decoder" ]
}
Rust
import("//build/rust/rustc_binary.gni")
import("//build/components.gni")
rustc_binary("rot13_encoder_decoder") {
sources = [ "src/rot13_encoder_decoder.rs" ]
}
fuchsia_package_with_single_component("rot13") {
manifest = "meta/rot13.cml"
deps = [ ":rot13_encoder_decoder" ]
}
Go
import("//build/go/go_binary.gni")
import("//build/components.gni")
go_binary("rot13_encoder_decoder") {
sources = [ "rot13_encoder_decoder.go" ]
}
fuchsia_package_with_single_component("rot13") {
manifest = "meta/rot13.cml"
deps = [ ":rot13_encoder_decoder" ]
}
测试软件包 GN 模板
测试软件包是指至少包含一个
作为测试启动测试软件包是使用
fuchsia_test_package.gni
。这个
可以用来定义各种测试,不过它最适用于
集成测试 - 用于测试除测试本身以外的其他组件
参与测试。请参阅单元测试,了解
专门从事单元测试
import("//build/components.gni")
executable("my_test") {
sources = [ "my_test.cc" ]
testonly = true
deps = [
"//src/lib/fxl/test:gtest_main",
"//third_party/googletest:gtest",
]
}
fuchsia_component("my_test_component") {
testonly = true
manifest = "meta/my_test.cml"
deps = [ ":my_test" ]
}
executable("my_program_under_test") {
sources = [ "my_program_under_test.cc" ]
}
fuchsia_component("my_other_component_under_test") {
manifest = "meta/my_component_under_test.cml"
deps = [ ":my_program_under_test" ]
}
fuchsia_test_package("my_integration_test") {
test_components = [ ":my_test_component" ]
deps = [ ":my_other_component_under_test" ]
test_specs = {
environments = [ vim3_env ]
}
}
group("tests") {
deps = [ ":my_integration_test" ]
testonly = true
}
请注意以下详细信息:
- 此示例定义了
"my_test_component"
,假定实现 使用一些常见测试框架(如 C++ Googletest、 Rust Cargo 测试等。 - 测试与依赖组件打包在一起
"my_other_component_under_test"
。这可能是模拟服务提供商 测试组件所需的资源或测试需要调用的其他组件所需的资源。 将这些组件打包在一起可以保证依赖组件 可以在测试运行时启动 测试版本。 - 借助
environments
参数,fuchsia_test_package()
可以选择性地 采用test_spec.gni
参数并替换 默认测试行为在此示例中,此测试配置为 在 VIM3 设备上运行。 - 最后,此示例定义了一个
group()
以包含所有测试( 只能有 1 项)。这是推荐做法 以便在整个源代码树中组织目标
由于 GN 中的限制,任何 test_component
目标
必须在与 fuchsia_test_package()
相同的 BUILD.gn
文件中定义
测试软件包目标。您可以通过间接
至 fuchsia_test()
。
在一个 BUILD.gn
文件中,定义以下内容:
# Let this be //foo/BUILD.gn
import("//build/components.gni")
executable("my_test") {
sources = [ "my_test.cc" ]
testonly = true
deps = [
"//src/lib/fxl/test:gtest_main",
"//third_party/googletest:gtest",
]
}
fuchsia_component("my_test_component") {
testonly = true
manifest = "meta/my_test.cml"
deps = [ ":my_test" ]
}
fuchsia_test("my_test_component_test") {
package = "//bar:my_test_package"
component = ":my_test_component"
}
group("tests") {
testonly = true
deps = [ ":my_test_component_test" ]
}
然后在其他位置将 fuchsia_component()
目标添加到deps
fuchsia_package()
目标。
# Let this be //bar/BUILD.gn
import("//build/components.gni")
fuchsia_package("my_test_package") {
testonly = true
deps = [ "//foo:my_test_component" ]
}
单元测试
由于单元测试很常见,构建系统提供了两种简化的 GN 模板:
fuchsia_unittest_component.gni
定义了要作为测试运行的组件,可以选择 生成基本的组件清单,该清单随后必须包含在软件包中。fuchsia_unittest_package.gni
定义了一个软件包,其中包含要作为测试运行的单个组件,它是 单个fuchsia_unittest_component()
目标与fuchsia_test_package()
。
使用清单的单元测试
以下示例演示了如何构建测试可执行文件以及如何定义 用于测试的软件包和组件
C++
import("//build/components.gni")
executable("my_test") {
sources = [ "test.cc" ]
deps = [
"//src/lib/fxl/test:gtest_main",
"//third_party/googletest:gtest",
]
testonly = true
}
fuchsia_unittest_package("my_test") {
manifest = "meta/my_test.cml"
deps = [ ":my_test" ]
}
Rust
import("//build/rust/rustc_test.gni")
import("//build/components.gni")
rustc_test("my_test") {
sources = [ "test.rs" ]
testonly = true
}
fuchsia_unittest_package("my_test") {
manifest = "meta/my_test.cml"
deps = [ ":my_test" ]
}
Go
import("//build/go/go_test.gni")
import("//build/components.gni")
go_test("my_test") {
sources = [ "test.go" ]
testonly = true
}
fuchsia_unittest_package("my_test") {
manifest = "meta/my_test.cml"
deps = [ ":my_test" ]
}
使用 fx test
和 GN 目标名称启动测试组件
或完整的组件网址:
GN 目标
fx test my_test
组件网址
fx test fuchsia-pkg://fuchsia.com/my_test#meta/my_test.cm
使用生成的清单进行单元测试
上面的示例为测试指定了清单。不过, 不要求任何特定功能。
下面是一个执行 ROT13 加密和解密的测试示例。 被测算法是可在完整环境中测试的纯逻辑 隔离。如果我们要为这些测试编写一个清单, 包含要执行的测试二进制文件。在这种情况下,我们只需指定 测试可执行文件路径,而模板会生成简单的清单, 。
C++
import("//build/components.gni")
executable("rot13_test") {
sources = [ "rot13_test.cc" ]
deps = [
"//src/lib/fxl/test:gtest_main",
"//third_party/googletest:gtest",
]
testonly = true
}
fuchsia_unittest_package("rot13_test") {
deps = [ ":rot13_test" ]
}
Rust
import("//build/rust/rustc_test.gni")
import("//build/components.gni")
rustc_test("rot13_test") {
sources = [ "rot13_test.rs" ]
testonly = true
}
fuchsia_unittest_package("rot13_test") {
deps = [ ":rot13_test" ]
}
Go
import("//build/go/go_test.gni")
import("//build/components.gni")
go_test("rot13_test") {
sources = [ "rot13_test.go" ]
testonly = true
}
fuchsia_unittest_package("rot13_test") {
deps = [ ":rot13_test" ]
}
您可以使用以下命令找到生成的组件清单文件:
fx gn outputs $(fx get-build-dir) //some/path/to/build/file:unittest target_component_generated_manifest
如需直接输出,请执行以下操作:
fx build && cat $(fx get-build-dir)/$(fx gn outputs $(fx get-build-dir) //some/path/to/build/file:unittest target_component_generated_manifest)
使用 fx test
和 GN 目标名称启动测试组件
或完整的组件网址:
GN 目标
fx test rot13_test
组件网址
fx test fuchsia-pkg://fuchsia.com/rot13_test#meta/rot13_test.cm
单个软件包中的多个单元测试
要将多个单元测试组件打包在一起,请使用
fuchsia_unittest_component()
规则(而非 fuchsia_unittest_package()
),
将它们放在 fuchsia_test_package()
中。这样,您就可以
使用 fx test <package_name>
将所有测试组件置于一个软件包中,而不是
而不是逐个执行
以下示例会创建一个测试软件包 rot13_tests
,其中包含两个
单独的测试组件 rot13_decoder_test
和 rot13_encoder_test
。
C++
import("//build/components.gni")
executable("rot13_decoder_bin_test") {}
executable("rot13_encoder_bin_test") {}
fuchsia_unittest_component("rot13_decoder_test") {
deps = [ ":rot13_decoder_bin_test" ]
}
fuchsia_unittest_component("rot13_encoder_test") {
deps = [ ":rot13_encoder_bin_test" ]
}
fuchsia_test_package("rot13_tests") {
test_components = [
":rot13_decoder_test",
":rot13_encoder_test",
]
}
Rust
import("//build/rust/rustc_test.gni")
import("//build/components.gni")
rustc_test("rot13_decoder_bin_test") {}
rustc_test("rot13_encoder_bin_test") {}
fuchsia_unittest_component("rot13_decoder_test") {
deps = [ ":rot13_decoder_bin_test" ]
}
fuchsia_unittest_component("rot13_encoder_test") {
deps = [ ":rot13_encoder_bin_test" ]
}
fuchsia_test_package("rot13_tests") {
test_components = [
":rot13_decoder_test",
":rot13_encoder_test",
]
}
Go
import("//build/go/go_test.gni")
import("//build/components.gni")
go_test("rot13_decoder_test") {}
go_test("rot13_encoder_test") {}
fuchsia_unittest_component("rot13_decoder_test") {
deps = [ ":rot13_decoder_bin_test" ]
}
fuchsia_unittest_component("rot13_encoder_test") {
deps = [ ":rot13_encoder_bin_test" ]
}
fuchsia_test_package("rot13_tests") {
test_components = [
":rot13_decoder_test",
":rot13_encoder_test",
]
}
使用 fx test
启动软件包内的所有测试组件,只需使用
GN 目标名称:
fx test rot13_tests
测试驱动型开发
fx smoke-test
命令会自动检测已知
会受检出更改的影响。请尝试以下操作:
fx -i smoke-test --verbose
在上面的命令中,--verbose
会输出 fx smoke-test
认为的哪些测试
都会受到您更改的影响,-i
会自动重复此命令
每次保存更改。对于测试驱动型开发,请尝试启动
在单独的 shell 中运行此命令,并观察您的代码如何重新构建和重新测试,
正在处理中。
fx smoke-test
最适合与封闭测试软件包搭配使用。测试包是
如果软件包包含其中任何测试的所有依赖项,则封闭。
也就是说,任何会影响此测试结果的代码更改都应
也需要重新构建该测试的软件包。
其他打包资源
在上面的示例中,我们演示了从软件包到deps
目标,可确保该可执行文件包含在
该软件包。
有时需要添加其他文件。下面,我们将介绍
使用两个 resource.gni
模板,
resource()
、resource_group()
和 resource_tree()
。
示例:字体
import("//build/components.gni")
resource("roboto_family") {
sources = [
"Roboto-Black.ttf",
"Roboto-Bold.ttf",
"Roboto-Light.ttf",
"Roboto-Medium.ttf",
"Roboto-Regular.ttf",
"Roboto-Thin.ttf",
]
outputs = [ "data/fonts/{{source_file_part}}" ]
}
fuchsia_component("text_viewer") {
...
deps = [
":roboto_family",
...
]
}
在上面的示例中,提供了六个文件打包到 data/fonts/
下,
生成路径 data/fonts/Roboto-Black.ttf
,
data/fonts/Roboto-Bold.ttf
等。destination
的格式接受 GN
来源扩展占位符。
然后,定义文本查看器组件依赖于字体。在本课中,
例如,文本查看器实现会使用 Roboto 字体渲染文本。通过
组件可以读取其沙盒中位于路径下的指定字体
/pkg/data/fonts/...
。
示例:使用黄金数据进行集成测试
在此示例中,我们定义了一项用于缩减 JSON 文件的假设服务。通过 服务接收包含 JSON 文本的缓冲区,并返回缓冲区。 包含相同的 JSON 数据但空白较少。我们展示了一个 在集成测试中,测试组件充当缩减器的客户端 组件,并比较要缩减的给定 JSON 文件的结果 一个已知良好的结果(或“黄金文件”)。
import("//build/components.gni")
fuchsia_component("minifier_component") {
...
}
fuchsia_package("minifier_package") {
...
}
resource("testdata") {
sources = [
"testdata/input.json",
"testdata/input_minified.json",
]
outputs = [ "data/{{source_file_part}}" ]
}
fuchsia_component("minifier_test_client") {
testonly = true
deps = [
":testdata",
...
]
...
}
fuchsia_test_package("minifier_integration_test") {
test_components = [ ":minifier_test_client" ]
deps = [ ":minifier_component" ]
}
请注意,我们将 resource()
依赖项放在测试组件上。在
从构建系统的角度来看,资源依赖项可能处于
测试软件包,并且 build 会产生相同的结果。
不过,更好的做法是将依赖项置于需要
。这样,我们就可以在不同的
test 软件包(例如,针对不同的压缩工具组件进行测试);以及
测试组件的运作方式与之相同
示例:使用 resource_group()
在上面的示例中,所有路径都符合某个结构, 我们可以为多个文件指定单一输出模式, GN 源代码扩展占位符。在接下来的 例如,我们需要将不同的文件重命名为 打包路径
import("//build/components.gni")
resource_group("favorite_recipes") {
files = [
{
source = "//recipes/spaghetti_bolognese.txt"
dest = "data/pasta/spaghetti_bolognese.txt"
},
{
source = "//recipes/creamy_carbonara.txt"
dest = "data/pasta/carbonara.txt"
},
{
source = "//recipes/creme_brulee.txt"
dest = "data/dessert/creme_brulee.txt"
},
...
]
}
我们的源代码都位于同一个目录中,但会打包到不同的
有些甚至以不同的名称命名为了表达这种关系
我们可能需要与文件一样多的 resource()
目标。这类情形
此调用改为使用 resource_group()
,如上所示。
示例:使用 resource_tree()
使用 resource_group()
将每个源文件映射到目标文件路径的操作如下:
会很麻烦resource_tree()
提供了一种在地图上
源文件目录树,到目标位置下相同层次结构
目录中。以下示例会将子目录
将 default_repo_files/
复制到软件包目录 repo/
(使用 sources
列表)
以确保只包含明确列出的文件)。
import("//build/components.gni")
resource_tree("default-repo") {
sources_root = "default_repo_files"
sources = [
"keys/root.json",
"keys/snapshot.json",
"keys/targets.json",
"keys/timestamp.json",
"repository/1.root.json",
"repository/1.snapshot.json",
"repository/1.targets.json",
"repository/root.json",
"repository/snapshot.json",
"repository/targets.json",
"repository/timestamp.json",
]
dest_dir = "repo"
}
resource()
、resource_group()
和
resource_tree()
完全相同。您可以自由选择自己喜欢的设置。
受限的功能
积极开发新的组件清单功能,或
面向小范围的受众群体,因此组件框架团队可能希望
限制哪些人可以使用此功能CML 编译器 (cmc
) 控制对
您可以通过组件 build 中的选择启用属性将这些受限功能
规则。
如需使用受限功能,请添加 restricted_features
属性:
fuchsia_component("my-component") {
manifest = "meta/my-component.cml"
# This component opts-in to the restricted "allow_long_names" feature.
restricted_features = [ "allow_long_names" ]
deps = [ ... ]
}
只能在许可名单内使用受限功能。
您必须将您的组件添加到以下项目的许可名单中:
//tools/cmc/build/restricted_features/BUILD.gn
。
问题排查
本部分包含您在构建组件时可能会遇到的常见问题。
缺少分片包含
在以下情况下,check_includes
操作会使构建失败并显示以下错误:
组件清单
缺少 include
必需的清单分片:
Error at ../../examples/components/echo_server/meta/echo_server.cml:
"../../examples/components/echo_server/meta/echo_server.cml" must include "../../sdk/lib/inspect/client.shard.cml".
当组件依赖项链中的某个库具有
expect_includes
要求和必需的
在您的组件清单中找不到“include
”。请参考以下示例
使用 Inspect:
C++
您的组件依赖于
//sdk/lib/inspect/component/cpp
:executable("bin") { output_name = "echo_server_cpp" sources = [ "main.cc" ] deps = [ "//examples/components/routing/fidl:echo", "//sdk/lib/sys/cpp", # This library requires "inspect/client.shard.cml" "//sdk/lib/inspect/component/cpp", "//sdk/lib/async-loop:async-loop-cpp", "//sdk/lib/async-loop:async-loop-default", ] }
//sdk/lib/inspect/component/cpp
依赖//sdk/lib/inspect:client_includes
,expect_includes()
规则。
Rust
您的组件依赖于
//src/lib/diagnostics/inspect/runtime/rust
:rustc_binary("echo_server") { edition = "2021" deps = [ "//examples/components/routing/fidl:echo_rust", # This library requires "inspect/client.shard.cml" "//src/lib/diagnostics/inspect/runtime/rust", "//src/lib/diagnostics/inspect/rust", "//src/lib/fuchsia", "//src/lib/fuchsia-component", "//third_party/rust_crates:anyhow", "//third_party/rust_crates:futures", ] sources = [ "src/main.rs" ] }
//src/lib/diagnostics/inspect/runtime/rust
依赖//sdk/lib/inspect:client_includes
,expect_includes()
规则。
若要解决此问题,请在组件清单中添加缺少的 include
。例如:
{
include: [
// Add this required include
"inspect/client.shard.cml",
// Enable logging
"syslog/client.shard.cml",
],
// ...
}
如需详细了解所需包含内容的来源,您可以使用 gn path
命令来查看依赖项路径:
fx gn path $(fx get-build-dir) my-component expect_includes target --with-data
该命令会输出类似于以下内容的输出,显示 要求包括:
C++
$ fx gn path $(fx get-build-dir) //examples/components/routing/cpp/echo_server //sdk/lib/inspect:client_includes --with-data
//examples/components/echo_server:bin --[private]-->
//sdk/lib/inspect/component/cpp --[data]-->
//sdk/lib/inspect:client_includes
Rust
$ fx gn path $(fx get-build-dir) //examples/components/routing/rust/echo_server //sdk/lib/inspect:client_includes --with-data
//examples/components/routing/rust/echo_server:bin --[public]-->
//examples/components/routing/rust/echo_server:bin.actual --[private]-->
//src/lib/diagnostics/inspect/runtime/rust:rust --[public]-->
//src/lib/diagnostics/inspect/runtime/rust:lib --[public]-->
//src/lib/diagnostics/inspect/runtime/rust:lib.actual --[private]-->
//sdk/lib/inspect:client_includes
未能验证清单
在以下情况下,cmc_validate_references
操作会使构建失败并显示以下错误:
组件清单
其中包含对
组件包中找不到:
Error found in: //examples/components/echo/rust:rust-component_cmc_validate_references(//build/toolchain/fuchsia:x64)
Failed to validate manifest: "obj/examples/components/echo/rust/cml/rust-component_manifest_compile/echo_rust.cm"
program.binary=bin/echo_example_oops but bin/echo_example_oops is not provided by deps!
Did you mean bin/echo_example?
Try any of the following:
...
当组件清单 program
块中的 binary
字段时,就会发生这种情况
引用的 fuchsia_package()
中不存在的文件路径。
如需解决此问题,请验证以下内容:
正确输入了组件清单中的引用路径。
{ // ... // Information about the program to run. program: { // Use the built-in ELF runner. runner: "elf", // The binary to run for this component. binary: "bin/echo_example_oops", }, }
组件可执行目标是
deps
连接至fuchsia_package()
:C++
executable("bin") { output_name = "echo_example" sources = [ "main.cc" ] deps = [ ... ] } # Neither the component or package depend on ":bin" fuchsia_component("component") { manifest = "meta/echo_example.cml" deps = [] } fuchsia_package("package") { package_name = "echo_example" deps = [ ":component" ] }
Rust
rustc_binary("echo_example") { edition = "2021" sources = [ "src/main.rs" ] deps = [ ... ] } # Neither the component or package depend on ":echo_example" fuchsia_component("component") { manifest = "meta/echo_example.cml" deps = [] } fuchsia_package("package") { package_name = "echo_example" deps = [ ":component" ] }
静态功能分析器
如果 Scrutiny 静态分析器无法执行构建,它会使构建失败,并显示以下错误 验证每个 功能路由 在 组件拓扑 :
Static Capability Flow Analysis Error:
The route verifier failed to verify all capability routes in this build.
...
Verification Errors:
[
{
"capability_type": "directory",
"results": { ... }
},
{
"capability_type": "protocol",
"results": { ... }
},
]
当分析无法从来源成功跟踪功能路由时,就会发生这种情况
传递给通过有效的 expose
链请求功能的组件
和 offer
组件清单声明。
在以下示例中,由于组件 /core/echo
请求
use
使用 fuchsia.logger.LogSink
协议,但没有针对该功能的相应 offer
:
"errors": [
{
"using_node": "/core/echo",
"capability": "fuchsia.logger.LogSink",
"error": {
"error": {
"analyzer_model_error": {
"routing_error": {
"use_from_parent_not_found": {
"moniker": {
"path": [
{
"name": "core",
"collection": null,
"rep": "core"
},
{
"name": "echo",
"collection": null,
"rep": "echo"
}
]
},
"capability_id": "fuchsia.logger.LogSink"
}
}
}
},
"message": "A `use from parent` declaration was found at `/core/echo` for `fuchsia.logger.LogSink`, but no matching `offer` declaration was found in the parent"
}
}
]
如需解决此问题,请浏览构建失败中提供的错误详情,以发现
然后添加或更正路由链中的无效声明。
在前面的错误示例中,应在父组件的清单中添加一个 offer
:
{
// ...
children: [
// ...
{
name: "echo",
url: "echo#meta/default.cm",
},
],
offer: [
// ...
{
protocol: "fuchsia.logger.LogSink",
from: "parent",
to: "#echo",
},
],
}
如需详细了解如何构建功能路由,请参阅连接组件。