在“货物构建”期间获取活动依赖项及其版本的列表

时间:2017-01-12 16:37:28

标签: build dependencies rust rust-cargo

有些crates提供了pub const &str - 版本字符串,有些则没有。要获得一般解决方案,我需要编译期间cargo build已知和使用的所有依赖项及其版本的列表,以便我可以构建自己的const &str 这是我自己的版本,我使用 -Debug输出编译的所有版本。

是否可以在build.rs中获取所有依赖项及其版本的列表?

Cargo.lock似乎是一个很好的来源。在Cargo.lock中解析build.rs实际上是否合理?是否保证已更新为Cargo实际使用并写入磁盘的内容?

1 个答案:

答案 0 :(得分:1)

我自己的答案,通过解析Cargo.lock解决。下面给出了依赖关系的依赖关系和依赖关系的列表 - 最终以某种方式得到链接的每个包(除此之外)。

Cargo.toml

[package]
name = "mycrate"
version = "0.1.0"
authors = ["John Doe"]
build = "build.rs"

[build-dependencies]
toml = "0.2"

build.rs

extern crate toml;

use std::env;
use std::fs;
use std::path;
use std::io::{Read, Write};

fn main() {
    // Read Cargo.lock and de-toml it
    let mut lock_buf = String::new();
    fs::File::open("Cargo.lock").unwrap().read_to_string(&mut lock_buf).unwrap();
    let lock_toml = toml::Parser::new(&lock_buf).parse().unwrap();

    // Get the table of [[package]]s. This is the deep list of dependencies and dependencies of
    // dependencies.
    let mut packages = Vec::new();
    for package in lock_toml.get("package").unwrap().as_slice().unwrap() {
        let package = package.as_table().unwrap();
        packages.push((package.get("name").unwrap().as_str().unwrap(),
                       package.get("version").unwrap().as_str().unwrap()));
    }
    packages.sort();

    // Write out the file to be included in the module stub
    let out_dir = env::var("OUT_DIR").unwrap();
    let mut versions_file = fs::File::create(&path::Path::new(&out_dir).join("versions.include")).unwrap();
    versions_file.write(format!("pub const BUILD_DEPS: [(&'static str, &'static str); {}] = [", packages.len()).as_ref()).unwrap();
    for package in packages {
        versions_file.write(format!("(\"{}\", \"{}\"),\n", package.0, package.1).as_ref()).unwrap();
    }
    versions_file.write("];".as_ref()).unwrap();
}

src/versions.rs

//! Information about the build-environment

// More info from env!() and friends go here

include!(concat!(env!("OUT_DIR"), "/versions.include"));

src/main.rs或需要的地方:

mod versions;

fn main() {
    println!("I was built using {}", versions::BUILD_DEPS.iter().map(|&(ref pkg, ref ver)| format!("{} {}", pkg, ver)).collect::<Vec<_>>().join(", "));
}

输出就像

  

我使用android_glue 0.2.1,bitflags 0.3.3,bitflags 0.4.0构建,   bitflags 0.6.0,bitflags 0.7.0,block 0.1.6,byteorder 0.5.3,bytes   0.3.0,cfg-if 0.1.0,cgl 0.1.5,cgmath 0.7.0,clippy 0.0.104 ......

当然,我们可以在编译时构建一个类似字符串的表示,但是它整齐地分开,提供了在运行时解析这些信息的机会。 据我所知,如果Cargo.lock不存在,这种情况有效:货物总是在build.rs运行之前生成它。