]> git.proxmox.com Git - rustc.git/blob - src/bootstrap/util.rs
New upstream version 1.12.0+dfsg1
[rustc.git] / src / bootstrap / util.rs
1 // Copyright 2015 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 //! Various utility functions used throughout rustbuild.
12 //!
13 //! Simple things like testing the various filesystem operations here and there,
14 //! not a lot of interesting happenings here unfortunately.
15
16 use std::env;
17 use std::ffi::OsString;
18 use std::fs;
19 use std::path::{Path, PathBuf};
20 use std::process::Command;
21
22 use filetime::FileTime;
23
24 /// Returns the `name` as the filename of a static library for `target`.
25 pub fn staticlib(name: &str, target: &str) -> String {
26 if target.contains("windows-msvc") {
27 format!("{}.lib", name)
28 } else {
29 format!("lib{}.a", name)
30 }
31 }
32
33 /// Returns the last-modified time for `path`, or zero if it doesn't exist.
34 pub fn mtime(path: &Path) -> FileTime {
35 fs::metadata(path).map(|f| {
36 FileTime::from_last_modification_time(&f)
37 }).unwrap_or(FileTime::zero())
38 }
39
40 /// Copies a file from `src` to `dst`, attempting to use hard links and then
41 /// falling back to an actually filesystem copy if necessary.
42 pub fn copy(src: &Path, dst: &Path) {
43 let res = fs::hard_link(src, dst);
44 let res = res.or_else(|_| fs::copy(src, dst).map(|_| ()));
45 if let Err(e) = res {
46 panic!("failed to copy `{}` to `{}`: {}", src.display(),
47 dst.display(), e)
48 }
49 }
50
51 /// Copies the `src` directory recursively to `dst`. Both are assumed to exist
52 /// when this function is called.
53 pub fn cp_r(src: &Path, dst: &Path) {
54 for f in t!(fs::read_dir(src)) {
55 let f = t!(f);
56 let path = f.path();
57 let name = path.file_name().unwrap();
58 let dst = dst.join(name);
59 if t!(f.file_type()).is_dir() {
60 let _ = fs::remove_dir_all(&dst);
61 t!(fs::create_dir(&dst));
62 cp_r(&path, &dst);
63 } else {
64 let _ = fs::remove_file(&dst);
65 copy(&path, &dst);
66 }
67 }
68 }
69
70 /// Copies the `src` directory recursively to `dst`. Both are assumed to exist
71 /// when this function is called. Unwanted files or directories can be skipped
72 /// by returning `false` from the filter function.
73 pub fn cp_filtered<F: Fn(&Path) -> bool>(src: &Path, dst: &Path, filter: &F) {
74 // Inner function does the actual work
75 fn recurse<F: Fn(&Path) -> bool>(src: &Path, dst: &Path, relative: &Path, filter: &F) {
76 for f in t!(fs::read_dir(src)) {
77 let f = t!(f);
78 let path = f.path();
79 let name = path.file_name().unwrap();
80 let dst = dst.join(name);
81 let relative = relative.join(name);
82 // Only copy file or directory if the filter function returns true
83 if filter(&relative) {
84 if t!(f.file_type()).is_dir() {
85 let _ = fs::remove_dir_all(&dst);
86 t!(fs::create_dir(&dst));
87 recurse(&path, &dst, &relative, filter);
88 } else {
89 let _ = fs::remove_file(&dst);
90 copy(&path, &dst);
91 }
92 }
93 }
94 }
95 // Immediately recurse with an empty relative path
96 recurse(src, dst, Path::new(""), filter)
97 }
98
99 /// Given an executable called `name`, return the filename for the
100 /// executable for a particular target.
101 pub fn exe(name: &str, target: &str) -> String {
102 if target.contains("windows") {
103 format!("{}.exe", name)
104 } else {
105 name.to_string()
106 }
107 }
108
109 /// Returns whether the file name given looks like a dynamic library.
110 pub fn is_dylib(name: &str) -> bool {
111 name.ends_with(".dylib") || name.ends_with(".so") || name.ends_with(".dll")
112 }
113
114 /// Returns the corresponding relative library directory that the compiler's
115 /// dylibs will be found in.
116 pub fn libdir(target: &str) -> &'static str {
117 if target.contains("windows") {"bin"} else {"lib"}
118 }
119
120 /// Adds a list of lookup paths to `cmd`'s dynamic library lookup path.
121 pub fn add_lib_path(path: Vec<PathBuf>, cmd: &mut Command) {
122 let mut list = dylib_path();
123 for path in path {
124 list.insert(0, path);
125 }
126 cmd.env(dylib_path_var(), t!(env::join_paths(list)));
127 }
128
129 /// Returns whether `dst` is up to date given that the file or files in `src`
130 /// are used to generate it.
131 ///
132 /// Uses last-modified time checks to verify this.
133 pub fn up_to_date(src: &Path, dst: &Path) -> bool {
134 let threshold = mtime(dst);
135 let meta = match fs::metadata(src) {
136 Ok(meta) => meta,
137 Err(e) => panic!("source {:?} failed to get metadata: {}", src, e),
138 };
139 if meta.is_dir() {
140 dir_up_to_date(src, &threshold)
141 } else {
142 FileTime::from_last_modification_time(&meta) <= threshold
143 }
144 }
145
146 fn dir_up_to_date(src: &Path, threshold: &FileTime) -> bool {
147 t!(fs::read_dir(src)).map(|e| t!(e)).all(|e| {
148 let meta = t!(e.metadata());
149 if meta.is_dir() {
150 dir_up_to_date(&e.path(), threshold)
151 } else {
152 FileTime::from_last_modification_time(&meta) < *threshold
153 }
154 })
155 }
156
157 /// Returns the environment variable which the dynamic library lookup path
158 /// resides in for this platform.
159 pub fn dylib_path_var() -> &'static str {
160 if cfg!(target_os = "windows") {
161 "PATH"
162 } else if cfg!(target_os = "macos") {
163 "DYLD_LIBRARY_PATH"
164 } else {
165 "LD_LIBRARY_PATH"
166 }
167 }
168
169 /// Parses the `dylib_path_var()` environment variable, returning a list of
170 /// paths that are members of this lookup path.
171 pub fn dylib_path() -> Vec<PathBuf> {
172 env::split_paths(&env::var_os(dylib_path_var()).unwrap_or(OsString::new()))
173 .collect()
174 }