宣告元件

每個元件都有一個宣告,說明元件的屬性和 即便沒有技術背景,也能因這些工具的功能而受益對於在套件中發布的元件,宣告 是使用元件資訊清單檔案來表示,並透過 元件解析器

這張圖表顯示如何使用「元件資訊清單」宣告元件。
然後在裝置上解析
執行階段。

您可以使用元件資訊清單語言 (CML) 檔案宣告元件。建立期間 元件資訊清單編譯器 (cmc) 工具會驗證並編譯 將資訊清單來源轉換為二進位格式 (.cm),並儲存在元件的 套件。在執行階段,元件解析器會將二進位資訊清單載入 ComponentDecl FIDL 結構: 元件管理工具 ,直接在 Google Cloud 控制台實際操作。

元件資訊清單

CML 檔案是 JSON5 檔案,結尾為 .cml 副檔名。以下是適用於簡易元件的 CML 資訊清單檔案範例 執行會顯示「Hello, World」的 ELF 二進位檔訊息傳送至系統記錄:

{
    // 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 建構系統提供範本,就像匯入 GN 時 //build/components.gni:用於建構及套件軟體 轉換為 Fuchsia 元件以下是簡易用的 BUILD.gn 檔案範例 C++ 元件:


import("//build/components.gni")

executable("bin") {
  sources = [ "main.cc" ]
}

resource("my_file") {
  sources = [ "my_file.txt" ]
  outputs = [ "data/{{source_file_part}}" ]
}

fuchsia_component("hello-world-component") {
  component_name = "hello-world"
  deps = [
    ":bin",
    ":my_file",
  ]
  manifest = "meta/hello-world.cml"
}

fuchsia_package("hello-world") {
  package-name = "hello-world"
  deps = [
    ":hello-world-component",
  ]
}

這個檔案包含以下主要元素:

  • executable():將原始碼編譯為二進位檔。這個目標會有所不同 根據程式設計語言而定例如 executable 目標 可用於 C++、rustc_binary 適用於 Rust,go_binary 適用於 Golang。
  • resource():要複製為資源的資料檔案 (選用) 集合 導入其他 GN 目標使用者可以透過 元件的命名空間
  • fuchsia_component():收集二進位檔、元件資訊清單等 會將資源匯總成單一目標這個目標會編譯資訊清單 將原始碼轉換為元件宣告cmc
  • fuchsia_package():元件的分佈單位。允許一或多個網域 要在套件存放區中託管並納入目標的 裝置的套件組。這個目標會產生套件中繼資料和建構作業 Fuchsia Archive (.far) 檔案。

套件可包含多個元件,在deps fuchsia_package() 範本。您可以簡化套件的建構檔案 只包含一個元件,並使用 fuchsia_package_with_single_component() 範本。

下列簡化的 BUILD.gn 範例等同於上一個 範例:


import("//build/components.gni")

executable("bin") {
  sources = [ "main.cc" ]
}

resource("my_file") {
  sources = [ "my_file.txt" ]
  outputs = [ "data/{{source_file_part}}" ]
}

fuchsia_package_with_single_component("hello-world") {
  manifest = "meta/hello-world.cml"
  deps = [
    ":bin",
    ":my_file",
  ]
}

練習:建立新元件

在本練習中,您將建構並執行能讀取程式的基本元件 並回應系統記錄中的問候語。

首先,請為名為 echo-args 的新元件建立專案 Scaffold //vendor/fuchsia-codelab 目錄:

mkdir -p vendor/fuchsia-codelab/echo-args

在新的專案目錄中建立以下檔案和目錄結構:

荒漠油廠

//vendor/fuchsia-codelab/echo-args
                        |- BUILD.gn
                        |- meta
                        |   |- echo.cml
                        |
                        |- src
                            |- main.rs
  • BUILD.gn:可執行二進位檔、元件和元件的 GN 建構目標 套件。
  • meta/echo.cml:宣告元件的可執行檔和 所需能力
  • src/main.rs:Rust 可執行二進位檔和單元測試的原始碼。

C++

//vendor/fuchsia-codelab/echo-args
                        |- BUILD.gn
                        |- meta
                        |   |- echo.cml
                        |
                        |- echo_component.cc
                        |- echo_component.h
                        |- main.cc
  • BUILD.gn:可執行二進位檔、元件和元件的 GN 建構目標 套件。
  • meta/echo.cml:宣告元件的可執行檔和 所需能力
  • echo_component.cc:C++ 元件功能的原始碼。
  • main.cc:C++ 可執行二進位檔主要進入點的原始碼。

新增程式引數

元件資訊清單檔案會定義元件可執行檔的屬性 包括程式引數及元件的功能 在 meta/echo.cml 中新增下列內容:

荒漠油廠

echo-args/meta/echo.cml

{
    include: [
        // Enable logging on stdout
        "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-args",

        // Program arguments
        args: [
            "Alice",
            "Bob",
        ],

        // Program environment variables
        environ: [ "FAVORITE_ANIMAL=Spot" ],
    },
}

C++

echo-args/meta/echo.cml

{
    include: [
        // Enable logging.
        "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-args",

        // Program arguments
        args: [
            "Alice",
            "Bob",
        ],

        // Program environment variables
        environ: [ "FAVORITE_ANIMAL=Spot" ],
    },
}

記錄引數

開啟主要執行檔的來源檔案,並新增下列匯入陳述式:

荒漠油廠

echo-args/src/main.rs

use tracing::info;

C++

echo-args/main.cc

#include <lib/syslog/cpp/log_settings.h>
#include <lib/syslog/cpp/macros.h>

#include <cstdlib>
#include <iostream>

#include "vendor/fuchsia-codelab/echo-args/echo_component.h"

新增以下程式碼來實作 main() 函式:

荒漠油廠

echo-args/src/main.rs

#[fuchsia::main(logging = true)]
async fn main() -> Result<(), anyhow::Error> {
    // Read program arguments, and strip off binary name
    let mut args: Vec<String> = std::env::args().collect();
    args.remove(0);

    // Include environment variables
    let animal = std::env::var("FAVORITE_ANIMAL").unwrap();
    args.push(animal);

    // Print a greeting to syslog
    info!("Hello, {}!", greeting(&args));

    Ok(())
}

C++

echo-args/main.cc

int main(int argc, const char* argv[], char* envp[]) {
  fuchsia_logging::LogSettingsBuilder builder;
  builder.WithTags({"echo"}).BuildAndInitialize();
  // Read program arguments, and exclude the binary name in argv[0]
  std::vector<std::string> arguments;
  for (int i = 1; i < argc; i++) {
    arguments.push_back(argv[i]);
  }

  // Include environment variables
  const char* favorite_animal = std::getenv("FAVORITE_ANIMAL");
  arguments.push_back(favorite_animal);

  // Print a greeting to syslog
  FX_LOG_KV(INFO, "Hello", FX_KV("greeting", echo::greeting(arguments).c_str()));

  return 0;
}

此程式碼會讀取程式引數,並傳遞至呼叫的函式 greeting() 可產生系統記錄項目的回應。

新增以下程式碼來實作 greeting() 函式:

荒漠油廠

echo-args/src/main.rs

// Return a proper greeting for the list
fn greeting(names: &Vec<String>) -> String {
    // Join the list of names based on length
    match names.len() {
        0 => String::from("Nobody"),
        1 => names.join(""),
        2 => names.join(" and "),
        _ => names.join(", "),
    }
}

C++

echo-args/echo_component.h

#include <string>
#include <vector>

namespace echo {

std::string greeting(std::vector<std::string>& names);

}  // namespace echo

echo-args/echo_component.cc

#include "vendor/fuchsia-codelab/echo-args/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

此函式會根據提供的引數清單,建立簡易字串 會依照清單長度

新增至建構設定

更新 BUILD.gn 檔案中程式的依附元件:

荒漠油廠

echo-args/BUILD.gn

import("//build/components.gni")
import("//build/rust/rustc_binary.gni")


group("echo-args") {
  testonly = true
  deps = [
    ":package",
  ]
}

rustc_binary("bin") {
  output_name = "echo-args"
  edition = "2021"

  # Generates a GN target for unit-tests with the label `bin_test`,
  # and a binary named `echo_bin_test`.
  with_unit_tests = true

  deps = [
    "//src/lib/fuchsia",
    "//third_party/rust_crates:anyhow",
    "//third_party/rust_crates:tracing",
  ]

  sources = [ "src/main.rs" ]
}

fuchsia_component("component") {
  component_name = "echo-args"
  manifest = "meta/echo.cml"
  deps = [ ":bin" ]
}

fuchsia_package("package") {
  package_name = "echo-args"
  deps = [ ":component" ]
}

C++

echo-args/BUILD.gn

import("//build/components.gni")


group("echo-args") {
  testonly = true
  deps = [
    ":package",
  ]
}

executable("bin") {
  output_name = "echo-args"

  sources = [ "main.cc" ]

  deps = [
    ":cpp-lib",
    "//sdk/lib/async-default",
    "//sdk/lib/async-loop:async-loop-cpp",
    "//sdk/lib/async-loop:async-loop-default",
    "//sdk/lib/syslog/cpp",
  ]
}

source_set("cpp-lib") {
  sources = [
    "echo_component.cc",
    "echo_component.h",
  ]
}

fuchsia_component("component") {
  component_name = "echo-args"
  manifest = "meta/echo.cml"
  deps = [ ":bin" ]
}

fuchsia_package("package") {
  package_name = "echo-args"
  deps = [ ":component" ]
}

將新元件新增至建構設定:

fx set workstation_eng.x64 --with //vendor/fuchsia-codelab/echo-args

執行 fx build,並確認建構作業是否順利完成:

fx build

在下一節中,我們會將此元件整合至建構作業中,並測試 寫入系統記錄