插件

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对象格式化输出。 reason 字段区分不同种类的信息。

可以用 --message-format 选项带有额外的格式化值,改变JSON信息的计算和显示方式。 更多细节参阅 build command documentation 中对 --message-format 选项的描述。

如果你使用的是Rust,可以使用 cargo_metadata crate来解析这些信息。

编译消息

"compiler-message" 消息包括来自编译器的输出,如警告和错误。关于 rustc 的消息格式,请参阅 rustc JSON 章节,其信息包含到以下结构中:

{
    /* "reason" 表示信息的种类。*/
    "reason": "compiler-message",
    /* 包的ID,是指代包的唯一标识。 */
    "package_id": "my-package 0.1.0 (path+file:///path/to/my-package)",
    /* 包配置清单的绝对路径。 */
    "manifest_path": "/path/to/my-package/Cargo.toml",
    /* 产生该消息的Cargo目标 (lib、bin、example等)。 */
    "target": {
        /* 目标种类数组。
           - lib目标列出配置清单中的 `cate-type` 值,如 "lib"、"rlib"、"dylib"、"proc-macro" 等(默认["lib"])。
           - 二进制是 ["bin"]
           - 实例是 ["example"]
           - 集成测试是 ["test"]
           - 性能测试是 ["bench"]
           - 构建脚本是 ["custom-build"]
        */
        "kind": [
            "lib"
        ],
        /* crate类型数组。
           - lib和示例库列出配置清单中的 `crate-type` 值,如 "lib"、"rlib"、"dylib"、"proc-macro" 等(默认为["lib"])。
           - 所有其他目标类型是 ["bin"]
        */
        "crate_types": [
            "lib"
        ],
        /* 目标名称。 */
        "name": "my-package",
        /* 目标的根源文件的绝对路径。 */
        "src_path": "/path/to/my-package/src/lib.rs",
        /* 目标的Rust版本。默认为包版本。 */
        "edition": "2018",
        /* 所需特性的数组。如果没有设置必要的特性,则不包含此属性。 */
        "required-features": ["feat1"],
        /* 该目标是否启用了文档测试,以及该目标是否与文档测试兼容。 */
        "doctest": true
    },
    /* 由编译器发出的信息。 参阅 https://doc.rust-lang.org/rustc/json.html 。 */
    "message": {
        /* ... */
    }
}

制品消息

对于每一个编译步骤,都会发出 "compiler-artifact" 消息,其结构如下:

{
    /* "reason" 表示信息的种类。 */
    "reason": "compiler-artifact",
    /* 包的ID,是指代包的唯一标识。 */
    "package_id": "my-package 0.1.0 (path+file:///path/to/my-package)",
    /* 包配置清单的绝对路径。 */
    "manifest_path": "/path/to/my-package/Cargo.toml",
    /* 产生制品的Cargo目标(lib、bin、example等等)。详见上面 `compiler-message` 的定义。 */
    "target": {
        "kind": [
            "lib"
        ],
        "crate_types": [
            "lib"
        ],
        "name": "my-package",
        "src_path": "/path/to/my-package/src/lib.rs",
        "edition": "2018",
        "doctest": true,
        "test": true
    },
    /* 该简介表明使用了哪些编译器设置。 */
    "profile": {
        /* 优化级别。 */
        "opt_level": "0",
        /* 调试级别,是0、1或2的整数。如果 "null",它意味着rustc的默认值为0。 */
        "debuginfo": 2,
        /* 是否启用了调试断言。 */
        "debug_assertions": true,
        /* 是否启用了溢出检查。 */
        "overflow_checks": true,
        /* 是否使用 `--test` 标志。*/
        "test": false
    },
    /* 启用特性数组。 */
    "features": ["feat1", "feat2"],
    /* 该步骤产生的文件的数组。*/
    "filenames": [
        "/path/to/my-package/target/debug/libmy_package.rlib",
        "/path/to/my-package/target/debug/deps/libmy_package-be9f3faac0a26ef0.rmeta"
    ],
    /* 创建的可执行文件的路径的字符串,如果该步骤没有生成可执行文件,则为空。 */
    "executable": null,
    /* 这个步骤是否被实际执行。当 `true` 时,这意味着预先存在的制品是最新的,并且 `rustc` 没有被执行。当 `false` 时,这意味着运行 `rustc` 以生成制品。 */
    "fresh": true
}

构建脚本输出

"build-script-executed" 消息包括构建脚本的解析输出。注意,即使构建脚本没有运行,也会发出这个消息; 它将显示之前缓存的值。关于构建脚本输出的更多细节可以在 构建脚本章节 中找到。

{
    /* "reason" 表示信息的种类。 */
    "reason": "build-script-executed",
    /* 包的ID,是指代包的唯一标识。 */
    "package_id": "my-package 0.1.0 (path+file:///path/to/my-package)",
    /* 要链接的库的数组,如 `cargo:rustc-link-lib` 指令所指示。注意,这可能包括字符串中的 "KIND=" 前缀,其中KIND是库的种类。 */
    "linked_libs": ["foo", "static=bar"],
    /* 包含在库搜索路径中的路径数组,如 `cargo:rustc-link-search` 指令所指示。注意,这可能包括字符串中的 "KIND=" 前缀,其中KIND是库的种类。 */
    "linked_paths": ["/some/path", "native=/another/path"],
    /* 要启用的cfg值数组,如 `cargo:rustc-cfg` 指令所示。 */
    "cfgs": ["cfg1", "cfg2=\"string\""],
    /* 要设置的环境变量的 [KEY, VALUE] 数组,如 `cargo:rustc-env` 指令所示。 */
    "env": [
        ["SOME_KEY", "some value"],
        ["ANOTHER_KEY", "another value"]
    ],
    /* 一个绝对路径,在编译当前包时作为 `OUT_DIR` 环境变量的值。 */
    "out_dir": "/some/path/in/target/dir"
}

构建完成

构建结束后会发出 "build-finished" 消息。

{
    /* "reason" 表示信息的种类。 */
    "reason": "build-finished",
    /* 构建是否成功完成。 */
    "success": true,
}

这条信息对工具来说很有帮助,可以知道何时停止读取JSON信息。 诸如 cargo testcargo run 之类的命令在构建完成后可能会产生额外的输出。 这条消息让工具知道Cargo不会产生额外的JSON消息,但之后可能会有额外的输出(比如 cargo run 执行的程序产生的输出)。

注意: 对测试的JSON输出有实验性的每日支持,所以如果启用了该功能,额外的测试专用JSON消息可能会在 "build-finished" 消息之后。

自定义子命令

Cargo被设计成可以扩展新的子命令,而不需要修改Cargo本身。 这是通过将 cargo (?<command>[^ ]+) 形式的调用转换成插件 cargo-${command} 的调用来实现的。 该插件必须存在于用户的 $PATH 目录中。

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

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

自定义子命令可以使用 CARGO 环境变量来回调Cargo。 另外,它也可以作为一个库链接到 cargo crate ,但这种方法有缺点。

  • 作为一个库,Cargo是不稳定的:API可能会改变而未淘汰。
  • 链接的Cargo库的版本可能与Cargo二进制文件不同。

相反,我们鼓励使用CLI接口来驱动Cargo。 cargo metadata 命令可以用来获取当前项目的信息( cargo_metadata crate为该命令提供了Rust接口)。