2017-05-03 1 views
6

Ich hostet ein Rust-Projekt in Git-Repository und ich möchte es die Version auf einen Befehl drucken. Wie kann ich die Version in das Programm aufnehmen? Ich dachte, dass die Build-Skript Umgebungsvariablen könnte, die verwendet werden können, während das Projekt selbst kompilieren, aber es funktioniert nicht:Include git commit Hash als String in Rust-Programm

build.rs:

use std::env; 

fn get_git_hash() -> Option<String> { 
    use std::process::Command; 

    let branch = Command::new("git") 
         .arg("rev-parse") 
         .arg("--abbrev-ref") 
         .arg("HEAD") 
         .output(); 
    if let Ok(branch_output) = branch { 
     let branch_string = String::from_utf8_lossy(&branch_output.stdout); 
     let commit = Command::new("git") 
          .arg("rev-parse") 
          .arg("--verify") 
          .arg("HEAD") 
          .output(); 
     if let Ok(commit_output) = commit { 
      let commit_string = String::from_utf8_lossy(&commit_output.stdout); 

      return Some(format!("{}, {}", 
         branch_string.lines().next().unwrap_or(""), 
         commit_string.lines().next().unwrap_or(""))) 
     } else { 
      panic!("Can not get git commit: {}", commit_output.unwrap_err()); 
     } 
    } else { 
     panic!("Can not get git branch: {}", branch.unwrap_err()); 
    } 
    None 
} 

fn main() { 
    if let Some(git) = get_git_hash() { 
     env::set_var("GIT_HASH", git); 
    } 
} 

src/main.rs:

pub const GIT_HASH: &'static str = env!("GIT_HASH"); 

fm main() { 
    println!("Git hash: {}", GIT_HASH); 
} 

Die Fehlermeldung:

error: environment variable `GIT_HASH` not defined 
    --> src/main.rs:10:25 
    | 
10 | pub const GIT_HASH: &'static str = env!("GIT_HASH"); 
    | 
             ^^^^^^^^^^^^^^^^ 

Gibt es eine Möglichkeit, solche Daten zur Kompilierzeit zu übergeben? Wie kann ich zwischen dem Build-Skript und dem Quellcode kommunizieren, wenn nicht mit Umgebungsvariablen? Ich kann nur darüber nachdenken, Daten in eine Datei zu schreiben, aber ich denke, das ist für diesen Fall übertrieben.

Antwort

6

Ich kann nur darüber nachdenken, Daten in eine Datei zu schreiben, aber ich denke, das ist für diesen Fall übertrieben.

Das ist bedauerlich, weil die ist der einzige Weg, es zu tun. Umgebungsvariablen können nicht funktionieren, weil Änderungen an der Umgebung nicht in andere, nicht untergeordnete Prozesse "ausgeleert" werden können.

Für einfachere Dinge können Sie können Cargo anweisen, bedingte Kompilierungsflags zu definieren, aber diese sind nicht stark genug, um eine Zeichenfolge [1] zu kommunizieren.

Die Details zum Generieren von Code aus einem Buildskript finden Sie in der code generation section of the Cargo documentation.


[1]: Ich meine, wenn Sie den Hash in 160 Config-Flags das Gefühl, zu brechen und sie dann in der Quelle wieder zusammenbauen kompiliert wird, aber das ist auch mehr trieben.

+0

Ich würde gerne ein Beispiel der Config-Flag-Version sehen. Ein Git-Hash muss jedoch nur 40 Zeichen lang sein. – Shepmaster

+1

** in andere, Nicht-Kind-Prozesse ** Ich denke, das ist der Schlüssel, um hier zu realisieren. Das Build-Skript wird * vor * der Kompilierung der Bibliothek ausgeführt, nicht * um * es herum. – Shepmaster

+2

@Shempmaster: Eine Flagge gibt Ihnen jedoch nur ein Bit. Sie haben etwas wie '# [cfg (bit_0)] const BIT_0: u8 = 1; # [cfg (nicht (bit_0))] const BIT_0: u8 = 0; 160 mal. Ich * habe * etwas ähnliches in der Vergangenheit nicht ratsam gemacht ... \ ** pfeift * \ * –

6

Es gibt bereits eine existierende Kiste vergen, die das Git-Commit im Build-Skript berechnen kann. Wie @DK's answer beschrieben, kann das Buildskript die Umgebungsvariable nicht vor Rust 1.19 ändern, also funktioniert vergen immer noch, indem das Ergebnis in OUT_DIR geschrieben wird (d. H. vergen löst die Frage von OP immer noch nicht, sollte aber einfacher zu verwenden sein).


Verbrauch:

# Cargo.toml 
... 
[build-dependencies] 
vergen = "0.1" 
// build.rs 
extern crate vergen; 
use vergen::*; 
fn main() { 
    vergen(SHORT_SHA | COMMIT_DATE).unwrap(); 
} 
mod version { 
    include!(concat!(env!("OUT_DIR"), "/version.rs")); 
} 
fn main() { 
    println!("commit: {} {}", version::commit_date(), version::short_sha()); 
    // output something like: 
    //  commit: 2017-05-03 a29c7e5 
} 
8

Seit Rust 1,19 (Ladung 0,20.

println!("cargo:rustc-env=KEY=value"); 

So OP Programm kann wie folgt geschrieben werden:: 0), dank https://github.com/rust-lang/cargo/pull/3929, können Sie jetzt ein Compiler-Umgebungsvariable (env!(…)) für rustc und rustdoc über definieren

// build.rs 
use std::process::Command; 
fn main() { 
    // note: add error checking yourself. 
    let output = Command::new("git").args(&["rev-parse", "HEAD"]).output().unwrap(); 
    let git_hash = String::from_utf8(output.stdout).unwrap(); 
    println!("cargo:rustc-env=GIT_HASH={}", git_hash); 
} 
// main.rs 
fn main() { 
    println!("{}", env!("GIT_HASH")); 
    // output something like: 
    // 7480b50f3c75eeed88323ec6a718d7baac76290d 
} 

Beachten Sie, dass Sie dies immer noch nicht verwenden können, wenn Sie immer noch 1.18 oder weniger unterstützen möchten.