外部工具

Cargo 的目标之一是与第三方工具(如 IDE 和其他构建系统)简单集成。为了使集成更容易,Cargo 提供了以下几个功能:

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

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

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

关于包结构的信息

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

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

如果您正在使用 Rust,可以使用 cargo_metadata crate 来解析输出。

JSON 消息

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

  • 编译器错误和警告,

  • 生成的工件,

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

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

注意:--message-format=json 仅控制 Cargo 和 Rustc 的输出。它不能控制其他工具的输出,例如 cargo run --message-format=json 或来自过程宏的任意输出。在这种情况下,一个可能的解决方法是仅当行以 { 开头时才将其解释为 JSON。

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

如果您正在使用 Rust,可以使用 cargo_metadata crate 来解析这些消息。

MSRV: package_id 必须为 Package ID 规范才能使用 1.77 版本。 在此之前,它是不可见的。

编译器消息

“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.
           For lib targets, dashes will be replaced with underscores.
        */
        "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 调用(形式为 cargo (?<command>[^ ]+) )转换为对外部工具 cargo-${command} 的调用来实现的。 外部工具必须位于用户的 $PATH 目录之一中。

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

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

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

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

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

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