每個元件都有描述元件屬性和功能的宣告。若是以套件形式發布的元件,系統會使用元件資訊清單檔案表示宣告,並在元件解析器的協助下載入。
您可以使用元件資訊清單語言 (CML) 檔案宣告元件。在建構期間,元件資訊清單編譯器 (cmc
) 工具會驗證資訊清單來源並編譯為二進位格式 (.cm
),然後將其儲存在元件套件中。
ComponentDecl
元件資訊清單
CML 檔案是 JSON5 檔案,結尾為 .cml
副檔名。以下是執行 ELF 二進位檔的簡單元件 CML 資訊清單檔案範例,該元件會在系統記錄中顯示「Hello, World」訊息:
{
// Information about the program to run.
program: {
// Use the built-in ELF runner.
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" },
],
}
這個檔案宣告元件的兩個主要資訊部分:
program
:說明可執行資訊,例如二進位檔案、程式引數,以及相關聯的執行階段。在這個範例中,二進位檔會編譯為 ELF 執行檔,並使用內建的 ELF 執行器。use
:宣告這個元件需要執行的功能。在此範例中,fuchsia.logger.LogSink
通訊協定可讓元件將訊息寫入系統記錄 (syslog
)。
資訊清單資料分割
功能集合代表系統中許多元件通用的用途需求,例如記錄。為了簡化在元件中加入這些功能,架構會將這些功能抽象化至可納入 CML 來源檔案中的資訊清單資料分割。
下方是與先前範例相等的 CML。在這種情況下,系統會透過加入 diagnostics/syslog/client.shard.cml
提供必要的記錄功能,而不是明確宣告 fuchsia.logger.LogSink
:
{
include: [ "syslog/client.shard.cml" ],
// Information about the program to run.
program: {
// Use the built-in ELF runner.
runner: "elf",
// The binary to run for this component.
binary: "bin/hello-world",
// Program arguments
args: [
"Hello",
"World!",
],
},
}
建築元件
Fuchsia SDK 系統提供 Bazel 規則,可建構軟體並將軟體套件至 Fuchsia 元件中。Fuchsia SDK 環境會在 Bazel 工作區目錄中提供這些規則。
在 Bazel 工作區中,您可以透過 BUILD.bazel
檔案所述,在 Bazel 套件中將 Fuchsia 套件和元件宣告為 Bazel 目標。
以下是簡易 C++ 元件的 BUILD.bazel
檔案範例:
# Build rules provided by the Fuchsia SDK
load(
"fuchsia_cc_binary",
"fuchsia_component",
"fuchsia_component_manifest",
"fuchsia_package",
)
fuchsia_cc_binary(
name = "hello_world",
srcs = [
"hello_world.cc",
],
)
fuchsia_component_manifest(
name = "manifest",
src = "meta/hello_world.cml",
)
fuchsia_component(
name = "component",
manifest = ":manifest",
deps = [":hello_world"],
)
fuchsia_package(
name = "pkg",
package_name = "hello_world",
visibility = ["//visibility:public"],
deps = [
":component",
],
)
此檔案包含下列主要元素:
fuchsia_cc_binary()
:將 C++ 原始碼編譯為二進位檔,包括任何必要的程式庫依附元件。fuchsia_component_manifest()
:使用cmc
將元件資訊清單檔案來源檔案 (.cml
) 編譯為二進位元件宣告。fuchsia_component()
:將二進位檔、元件資訊清單和其他資源一併收集至單一目標。fuchsia_package()
:元件的分佈單位。允許將一或多個元件託管於套件存放區,並納入目標裝置的套件集。這個目標會產生套件中繼資料,並建構 Fuchsia 封存 (.far
) 檔案。
運動:建立新元件
在本練習中,您將建構並執行基本元件,用於讀取程式引數,並回應問候語的問候語。
首先,請在 Bazel 工作區中為名為 echo
的新元件建立新的專案目錄:
mkdir -p fuchsia-codelab/echo
完成這個部分後,專案應具有以下目錄結構:
//fuchsia-codelab/echo
|- BUILD.bazel
|- meta
| |- echo.cml
|
|- echo_component.cc
|- echo_component.h
|- main.cc
BUILD.bazel
:適用於可執行二進位檔、元件和套件的 Bazel 建構目標。meta/echo.cml
:資訊清單會宣告元件的執行檔和必要功能。echo_component.cc
:C++ 元件功能的原始碼。main.cc
:C++ 可執行二進位檔主要進入點的原始碼。
新增程式引數
元件資訊清單檔案定義了元件執行檔的屬性,包括程式引數和元件的功能。
建立 echo/meta/echo.cml
並新增下列內容:
echo/meta/echo.cml
:
{
include: [
"syslog/client.shard.cml",
],
// 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",
// Program arguments
args: [
"Alice",
"Bob",
],
// Program environment variables
environ: [ "FAVORITE_ANIMAL=Spot" ],
},
// ...
}
記錄引數
為主要執行檔建立 echo/main.cc
來源檔案,並新增下列匯入陳述式:
echo/main.cc
:
#include <lib/syslog/global.h>
#include <cstdlib>
#include <iostream>
#include <string>
#include "echo_component.h"
為 main()
函式新增下列程式碼:
echo/main.cc
:
int main(int argc, const char* argv[], char* envp[]) {
// Read program arguments, and exclude the binary name in argv[0]
std::vector<std::string> arguments;
arguments.resize(0);
for (int i = 1; i < argc; i++) {
arguments.push_back(argv[i]);
}
// Include environment variables
const char* favorite_animal = std::getenv("FAVORITE_ANIMAL");
if (favorite_animal != NULL) {
arguments.push_back(favorite_animal);
}
// Print a greeting to syslog
FX_LOGF(INFO, "echo", "Hello, %s!", echo::greeting(arguments).c_str());
return 0;
}
此程式碼會讀取程式引數,並傳遞至名為 greeting()
的函式,以產生系統記錄項目的回應。
建立 echo/echo_component.h
和 echo/echo_component.cc
,包括下列程式碼實作 greeting()
函式:
echo/echo_component.h
:
#include <string>
#include <vector>
namespace echo {
std::string greeting(std::vector<std::string>& names);
} // namespace echo
echo/echo_component.cc
:
#include "echo_component.h"
#include <numeric>
namespace echo {
static std::string join(std::vector<std::string>& input_list,
const std::string& separator) {
return std::accumulate(
std::begin(input_list), std::end(input_list), std::string(""),
[&separator](std::string current, std::string& next) {
return current.empty() ? next : (std::move(current) + separator + next);
});
}
// Return a proper greeting for the list
std::string greeting(std::vector<std::string>& names) {
// Join the list of names based on length
auto number_of_names = names.size();
switch (number_of_names) {
case 0:
return "Nobody!";
case 1:
return join(names, "");
case 2:
return join(names, " and ");
default:
return join(names, ", ");
}
}
} // namespace echo
這個函式會根據清單長度,從提供的引數清單中建立簡單字串。
新增至建構設定
建立 echo/BUILD.bazel
檔案並新增下列建構規則,將新元件納入建構設定:
echo/BUILD.bazel
:
load(
"@rules_fuchsia//fuchsia:defs.bzl",
"fuchsia_cc_binary",
"fuchsia_component",
"fuchsia_component_manifest",
"fuchsia_package",
)
fuchsia_cc_binary(
name = "echo_example",
srcs = [
"echo_component.cc",
"echo_component.h",
"main.cc",
],
deps = [
"@fuchsia_sdk//pkg/fdio",
"@fuchsia_sdk//pkg/syslog",
],
)
fuchsia_component_manifest(
name = "manifest",
src = "meta/echo.cml",
component_name = "echo",
includes = [
"@fuchsia_sdk//pkg/syslog:client",
],
)
fuchsia_component(
name = "component",
component_name = "echo",
manifest = ":manifest",
visibility = ["//visibility:public"],
deps = [":echo_example"],
)
fuchsia_package(
name = "pkg",
package_name = "echo-example",
visibility = ["//visibility:public"],
components = [
":component",
],
)
執行 bazel build
,並確認建構作業已成功完成:
bazel build //fuchsia-codelab/echo:pkg
在下一節中,您會將這個元件整合至建構作業,並在系統記錄中測試輸出內容。