宣告元件

每個元件都有宣告,可說明元件的屬性和功能。對於在套件中發布的元件,宣告會使用元件資訊清單檔案表示,並透過元件解析器載入。

圖表說明如何使用「元件資訊清單」宣告元件。資訊清單會由開發人員工具編譯,並在執行階段解析至裝置。

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

元件資訊清單

CML 檔案是結尾為 .cml 副檔名的 JSON5 檔案。以下是簡易元件 CML 資訊清單檔案的範例,該元件會執行 ELF 二進位檔,並將「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 工作區中,您可以將 Fuchsia 套件和元件宣告為 Bazel 套件中的 Bazel 目標,並由 BUILD.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():編譯元件資訊清單檔案來源檔案 (.cml) 轉換為二進位元件宣告,使用 cmc
  • fuchsia_component():將二進位檔、元件資訊清單和其他資源收集到單一目標中。
  • fuchsia_package():元件的分佈單位。允許一或多個元件託管在套件存放區中,並納入目標裝置的套件組合。這個目標會產生套件中繼資料和建構作業 Fuchsia Archive (.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.hecho/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(
    "@fuchsia_sdk//fuchsia:defs.bzl",
    "fuchsia_cc_binary",
    "fuchsia_component",
    "fuchsia_component_manifest",
    "fuchsia_package",
    "fuchsia_select",
    "fuchsia_unittest_package",
)

fuchsia_cc_binary(
    name = "echo_example",
    srcs = [
        "echo_component.cc",
        "echo_component.h",
        "main.cc",
    ],
    deps = [] + fuchsia_select({
        "@platforms//os:fuchsia": [
            "@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

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