外部工具
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 会在构建过程中输出以下信息:
-
编译器错误和警告,
-
生成的 artifacts,
-
构建脚本的结果(例如,原生依赖项)。
输出会以每行一个 JSON 对象 的格式发送到 stdout。reason 字段区分不同类型的消息。package_id 字段是引用包的唯一标识符,也是许多命令的 --package 参数。语法规范可以在 包 ID 规范 章找到。
注意:
--message-format=json只控制 Cargo 和 Rustc 的输出。它无法控制其他工具的输出,例如cargo run --message-format=json,或 procedural macros 的任意输出。在这种情况下,一个可能的解决方法是只有当一行以{开头时,才将其解释为 JSON。
--message-format 选项还可以接受额外的格式化值,这些值会改变 JSON 消息的计算和渲染方式。有关详细信息,请参阅 build command 文档 中关于 --message-format 选项的描述。
如果你正在使用 Rust,可以使用 cargo_metadata crate 来解析这些消息。
MSRV: 要使
package_id成为包 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": {
/* ... */
}
}
Artifact 消息
对于每个编译步骤,都会发出一个“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 test 或 cargo 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} 显示自定义子命令的帮助输出。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 接口)。