外部工具

Cargo 的目标之一是与第三方工具(如 IDE 和其他构建系统)简单集成。为了简化集成,Cargo 提供了几种工具

  • cargo metadata 命令,以 JSON 格式输出包结构和依赖项信息,

  • --message-format 标志,输出有关特定构建的信息,以及

  • 对自定义子命令的支持。

有关包结构的信息

您可以使用 cargo metadata 命令获取有关包结构和依赖项的信息。有关输出格式的详细信息,请参阅 cargo metadata 文档。

该格式是稳定的并进行版本控制。调用 cargo metadata 时,您应该显式传递 --format-version 标志,以避免向前不兼容的风险。

如果您使用的是 Rust,则可以使用 cargo_metadata 包来解析输出。

JSON 消息

传递 --message-format=json 时,Cargo 将在构建期间输出以下信息

  • 编译器错误和警告,

  • 生成的工件,

  • 构建脚本的结果(例如,原生依赖项)。

输出以每行一个 JSON 对象的格式发送到标准输出。reason 字段区分不同类型的消息。package_id 字段是用于引用包的唯一标识符,并且作为许多命令的 --package 参数。语法规则可以在 包 ID 规范 章节中找到。

--message-format 选项还可以采用其他格式值,这些值会改变 JSON 消息的计算和呈现方式。有关更多详细信息,请参阅 构建命令文档 中对 --message-format 选项的描述。

如果您使用的是 Rust,则可以使用 cargo_metadata 包来解析这些消息。

编译器消息

“compiler-message”消息包含来自编译器的输出,例如警告和错误。有关 rustc 消息格式的详细信息,请参阅 rustc JSON 章节,该格式嵌入在以下结构中

{
    /* The "reason" indicates the kind of message. */
    "reason": "compiler-message",
    /* The Package ID, a unique identifier for referring to the package. */
    "package_id": "file:///path/to/my-package#0.1.0",
    /* Absolute path to the package manifest. */
    "manifest_path": "/path/to/my-package/Cargo.toml",
    /* The Cargo target (lib, bin, example, etc.) that generated the message. */
    "target": {
        /* Array of target kinds.
           - lib targets list the `crate-type` values from the
             manifest such as "lib", "rlib", "dylib",
             "proc-macro", etc. (default ["lib"])
           - binary is ["bin"]
           - example is ["example"]
           - integration test is ["test"]
           - benchmark is ["bench"]
           - build script is ["custom-build"]
        */
        "kind": [
            "lib"
        ],
        /* Array of crate types.
           - lib and example libraries list the `crate-type` values
             from the manifest such as "lib", "rlib", "dylib",
             "proc-macro", etc. (default ["lib"])
           - all other target kinds are ["bin"]
        */
        "crate_types": [
            "lib"
        ],
        /* The name of the target. */
        "name": "my-package",
        /* Absolute path to the root source file of the target. */
        "src_path": "/path/to/my-package/src/lib.rs",
        /* The Rust edition of the target.
           Defaults to the package edition.
        */
        "edition": "2018",
        /* Array of required features.
           This property is not included if no required features are set.
        */
        "required-features": ["feat1"],
        /* Whether the target should be documented by `cargo doc`. */
        "doc": true,
        /* Whether or not this target has doc tests enabled, and
           the target is compatible with doc testing.
        */
        "doctest": true
        /* Whether or not this target should be built and run with `--test`
        */
        "test": true
    },
    /* The message emitted by the compiler.

    See https://doc.rust-lang.net.cn/rustc/json.html for details.
    */
    "message": {
        /* ... */
    }
}

工件消息

对于每个编译步骤,都会发出带有以下结构的“compiler-artifact”消息

{
    /* The "reason" indicates the kind of message. */
    "reason": "compiler-artifact",
    /* The Package ID, a unique identifier for referring to the package. */
    "package_id": "file:///path/to/my-package#0.1.0",
    /* Absolute path to the package manifest. */
    "manifest_path": "/path/to/my-package/Cargo.toml",
    /* The Cargo target (lib, bin, example, etc.) that generated the artifacts.
       See the definition above for `compiler-message` for details.
    */
    "target": {
        "kind": [
            "lib"
        ],
        "crate_types": [
            "lib"
        ],
        "name": "my-package",
        "src_path": "/path/to/my-package/src/lib.rs",
        "edition": "2018",
        "doc": true,
        "doctest": true,
        "test": true
    },
    /* The profile indicates which compiler settings were used. */
    "profile": {
        /* The optimization level. */
        "opt_level": "0",
        /* The debug level, an integer of 0, 1, or 2, or a string
           "line-directives-only" or "line-tables-only". If `null`, it implies
           rustc's default of 0.
        */
        "debuginfo": 2,
        /* Whether or not debug assertions are enabled. */
        "debug_assertions": true,
        /* Whether or not overflow checks are enabled. */
        "overflow_checks": true,
        /* Whether or not the `--test` flag is used. */
        "test": false
    },
    /* Array of features enabled. */
    "features": ["feat1", "feat2"],
    /* Array of files generated by this step. */
    "filenames": [
        "/path/to/my-package/target/debug/libmy_package.rlib",
        "/path/to/my-package/target/debug/deps/libmy_package-be9f3faac0a26ef0.rmeta"
    ],
    /* A string of the path to the executable that was created, or null if
       this step did not generate an executable.
    */
    "executable": null,
    /* Whether or not this step was actually executed.
       When `true`, this means that the pre-existing artifacts were
       up-to-date, and `rustc` was not executed. When `false`, this means that
       `rustc` was run to generate the artifacts.
    */
    "fresh": true
}

构建脚本输出

“build-script-executed”消息包含构建脚本的解析输出。请注意,即使未运行构建脚本,也会发出此消息;它将显示先前缓存的值。有关构建脚本输出的更多详细信息,请参见 关于构建脚本的章节

{
    /* The "reason" indicates the kind of message. */
    "reason": "build-script-executed",
    /* The Package ID, a unique identifier for referring to the package. */
    "package_id": "file:///path/to/my-package#0.1.0",
    /* Array of libraries to link, as indicated by the `cargo::rustc-link-lib`
       instruction. Note that this may include a "KIND=" prefix in the string
       where KIND is the library kind.
    */
    "linked_libs": ["foo", "static=bar"],
    /* Array of paths to include in the library search path, as indicated by
       the `cargo::rustc-link-search` instruction. Note that this may include a
       "KIND=" prefix in the string where KIND is the library kind.
    */
    "linked_paths": ["/some/path", "native=/another/path"],
    /* Array of cfg values to enable, as indicated by the `cargo::rustc-cfg`
       instruction.
    */
    "cfgs": ["cfg1", "cfg2=\"string\""],
    /* Array of [KEY, VALUE] arrays of environment variables to set, as
       indicated by the `cargo::rustc-env` instruction.
    */
    "env": [
        ["SOME_KEY", "some value"],
        ["ANOTHER_KEY", "another value"]
    ],
    /* An absolute path which is used as a value of `OUT_DIR` environmental
       variable when compiling current package.
    */
    "out_dir": "/some/path/in/target/dir"
}

构建完成

“build-finished”消息在构建结束时发出。

{
    /* The "reason" indicates the kind of message. */
    "reason": "build-finished",
    /* Whether or not the build finished successfully. */
    "success": true,
}

此消息有助于工具了解何时停止读取 JSON 消息。诸如 cargo testcargo run 之类的命令可以在构建完成后产生额外的输出。此消息让工具知道 Cargo 将不会产生额外的 JSON 消息,但之后可能会生成其他输出(例如由 cargo run 执行的程序生成的输出)。

注意:对于测试,实验性的仅限 nightly 版本的 JSON 输出支持,因此如果启用了该功能,则在“build-finished”消息之后可能会开始接收其他特定于测试的 JSON 消息。

自定义子命令

Cargo 旨在通过新的子命令进行扩展,而无需修改 Cargo 本身。这是通过将形式为 cargo (?<command>[^ ]+) 的 cargo 调用转换为对外部工具 cargo-${command} 的调用来实现的。外部工具必须存在于用户的 $PATH 目录之一中。

**注意**:默认情况下,Cargo 优先考虑 $CARGO_HOME/bin 中的外部工具,而不是 $PATH。用户可以通过将 $CARGO_HOME/bin 添加到 $PATH 来覆盖此优先级。

当 Cargo 调用自定义子命令时,子命令的第一个参数将像往常一样是自定义子命令的文件名。第二个参数将是子命令名称本身。例如,调用 cargo-${command} 时,第二个参数将是 ${command}。命令行上的任何其他参数都将不加更改地转发。

Cargo 还可以使用 cargo help ${command} 显示自定义子命令的帮助输出。如果子命令的第三个参数是 --help,Cargo 假定该子命令将打印帮助消息。因此,cargo help ${command} 将调用 cargo-${command} ${command} --help

自定义子命令可以使用 CARGO 环境变量回调 Cargo。或者,它可以链接到 cargo 包作为库,但是这种方法有缺点

  • Cargo 作为库是不稳定的:API 可能会在没有弃用警告的情况下更改
  • 链接的 Cargo 库的版本可能与 Cargo 二进制文件不同

相反,鼓励使用 CLI 接口来驱动 Cargo。cargo metadata 命令可用于获取有关当前项目的信息(cargo_metadata 包为此命令提供了 Rust 接口)。