forked from rust-lang/cargo
-
Notifications
You must be signed in to change notification settings - Fork 1
/
build.rs
153 lines (135 loc) · 5.23 KB
/
build.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
use flate2::{Compression, GzBuilder};
use std::ffi::OsStr;
use std::fs;
use std::path::Path;
use std::process::Command;
fn main() {
commit_info();
compress_man();
windows_manifest();
// ALLOWED: Accessing environment during build time shouldn't be prohibited.
#[allow(clippy::disallowed_methods)]
let target = std::env::var("TARGET").unwrap();
println!("cargo:rustc-env=RUST_HOST_TARGET={target}");
}
fn compress_man() {
// ALLOWED: Accessing environment during build time shouldn't be prohibited.
#[allow(clippy::disallowed_methods)]
let out_path = Path::new(&std::env::var("OUT_DIR").unwrap()).join("man.tgz");
let dst = fs::File::create(out_path).unwrap();
let encoder = GzBuilder::new()
.filename("man.tar")
.write(dst, Compression::best());
let mut ar = tar::Builder::new(encoder);
ar.mode(tar::HeaderMode::Deterministic);
let mut add_files = |dir, extension| {
let mut files = fs::read_dir(dir)
.unwrap()
.map(|e| e.unwrap().path())
.collect::<Vec<_>>();
files.sort();
for path in files {
if path.extension() != Some(extension) {
continue;
}
println!("cargo:rerun-if-changed={}", path.display());
ar.append_path_with_name(&path, path.file_name().unwrap())
.unwrap();
}
};
add_files(Path::new("src/etc/man"), OsStr::new("1"));
add_files(Path::new("src/doc/man/generated_txt"), OsStr::new("txt"));
let encoder = ar.into_inner().unwrap();
encoder.finish().unwrap();
}
struct CommitInfo {
hash: String,
short_hash: String,
date: String,
}
fn commit_info_from_git() -> Option<CommitInfo> {
if !Path::new(".git").exists() {
return None;
}
let output = match Command::new("git")
.arg("log")
.arg("-1")
.arg("--date=short")
.arg("--format=%H %h %cd")
.arg("--abbrev=9")
.output()
{
Ok(output) if output.status.success() => output,
_ => return None,
};
let stdout = String::from_utf8(output.stdout).unwrap();
let mut parts = stdout.split_whitespace().map(|s| s.to_string());
Some(CommitInfo {
hash: parts.next()?,
short_hash: parts.next()?,
date: parts.next()?,
})
}
// The rustc source tarball is meant to contain all the source code to build an exact copy of the
// toolchain, but it doesn't include the git repository itself. It wouldn't thus be possible to
// populate the version information with the commit hash and the commit date.
//
// To work around this, the rustc build process obtains the git information when creating the
// source tarball and writes it to the `git-commit-info` file. The build process actually creates
// at least *two* of those files, one for Rust as a whole (in the root of the tarball) and one
// specifically for Cargo (in src/tools/cargo). This function loads that file.
//
// The file is a newline-separated list of full commit hash, short commit hash, and commit date.
fn commit_info_from_rustc_source_tarball() -> Option<CommitInfo> {
let path = Path::new("git-commit-info");
if !path.exists() {
return None;
}
// Dependency tracking is a nice to have for this (git doesn't do it), so if the path is not
// valid UTF-8 just avoid doing it rather than erroring out.
if let Some(utf8) = path.to_str() {
println!("cargo:rerun-if-changed={utf8}");
}
let content = std::fs::read_to_string(&path).ok()?;
let mut parts = content.split('\n').map(|s| s.to_string());
Some(CommitInfo {
hash: parts.next()?,
short_hash: parts.next()?,
date: parts.next()?,
})
}
fn commit_info() {
// Var set by bootstrap whenever omit-git-hash is enabled in rust-lang/rust's config.toml.
println!("cargo:rerun-if-env-changed=CFG_OMIT_GIT_HASH");
// ALLOWED: Accessing environment during build time shouldn't be prohibited.
#[allow(clippy::disallowed_methods)]
if std::env::var_os("CFG_OMIT_GIT_HASH").is_some() {
return;
}
let Some(git) = commit_info_from_git().or_else(commit_info_from_rustc_source_tarball) else {
return;
};
println!("cargo:rustc-env=CARGO_COMMIT_HASH={}", git.hash);
println!("cargo:rustc-env=CARGO_COMMIT_SHORT_HASH={}", git.short_hash);
println!("cargo:rustc-env=CARGO_COMMIT_DATE={}", git.date);
}
#[allow(clippy::disallowed_methods)]
fn windows_manifest() {
use std::env;
let target_os = env::var("CARGO_CFG_TARGET_OS");
let target_env = env::var("CARGO_CFG_TARGET_ENV");
if Ok("windows") == target_os.as_deref() && Ok("msvc") == target_env.as_deref() {
static WINDOWS_MANIFEST_FILE: &str = "windows.manifest.xml";
let mut manifest = env::current_dir().unwrap();
manifest.push(WINDOWS_MANIFEST_FILE);
println!("cargo:rerun-if-changed={WINDOWS_MANIFEST_FILE}");
// Embed the Windows application manifest file.
println!("cargo:rustc-link-arg-bin=cargo=/MANIFEST:EMBED");
println!(
"cargo:rustc-link-arg-bin=cargo=/MANIFESTINPUT:{}",
manifest.to_str().unwrap()
);
// Turn linker warnings into errors.
println!("cargo:rustc-link-arg-bin=cargo=/WX");
}
}