1 | //! A Rust library for build scripts to automatically configure code based on |
---|---|
2 | //! compiler support. Code snippets are dynamically tested to see if the `rustc` |
3 | //! will accept them, rather than hard-coding specific version support. |
4 | //! |
5 | //! |
6 | //! ## Usage |
7 | //! |
8 | //! Add this to your `Cargo.toml`: |
9 | //! |
10 | //! ```toml |
11 | //! [build-dependencies] |
12 | //! autocfg = "1" |
13 | //! ``` |
14 | //! |
15 | //! Then use it in your `build.rs` script to detect compiler features. For |
16 | //! example, to test for 128-bit integer support, it might look like: |
17 | //! |
18 | //! ```rust |
19 | //! extern crate autocfg; |
20 | //! |
21 | //! fn main() { |
22 | //! # // Normally, cargo will set `OUT_DIR` for build scripts. |
23 | //! # let exe = std::env::current_exe().unwrap(); |
24 | //! # std::env::set_var("OUT_DIR", exe.parent().unwrap()); |
25 | //! let ac = autocfg::new(); |
26 | //! ac.emit_has_type("i128"); |
27 | //! |
28 | //! // (optional) We don't need to rerun for anything external. |
29 | //! autocfg::rerun_path("build.rs"); |
30 | //! } |
31 | //! ``` |
32 | //! |
33 | //! If the type test succeeds, this will write a `cargo:rustc-cfg=has_i128` line |
34 | //! for Cargo, which translates to Rust arguments `--cfg has_i128`. Then in the |
35 | //! rest of your Rust code, you can add `#[cfg(has_i128)]` conditions on code that |
36 | //! should only be used when the compiler supports it. |
37 | //! |
38 | //! ## Caution |
39 | //! |
40 | //! Many of the probing methods of `AutoCfg` document the particular template they |
41 | //! use, **subject to change**. The inputs are not validated to make sure they are |
42 | //! semantically correct for their expected use, so it's _possible_ to escape and |
43 | //! inject something unintended. However, such abuse is unsupported and will not |
44 | //! be considered when making changes to the templates. |
45 | |
46 | #![deny(missing_debug_implementations)] |
47 | #![deny(missing_docs)] |
48 | // allow future warnings that can't be fixed while keeping 1.0 compatibility |
49 | #![allow(unknown_lints)] |
50 | #![allow(bare_trait_objects)] |
51 | #![allow(ellipsis_inclusive_range_patterns)] |
52 | |
53 | /// Local macro to avoid `std::try!`, deprecated in Rust 1.39. |
54 | macro_rules! try { |
55 | ($result:expr) => { |
56 | match $result { |
57 | Ok(value) => value, |
58 | Err(error) => return Err(error), |
59 | } |
60 | }; |
61 | } |
62 | |
63 | use std::env; |
64 | use std::ffi::OsString; |
65 | use std::fmt::Arguments; |
66 | use std::fs; |
67 | use std::io::{stderr, Write}; |
68 | use std::path::{Path, PathBuf}; |
69 | use std::process::Stdio; |
70 | #[allow(deprecated)] |
71 | use std::sync::atomic::ATOMIC_USIZE_INIT; |
72 | use std::sync::atomic::{AtomicUsize, Ordering}; |
73 | |
74 | mod error; |
75 | pub use error::Error; |
76 | |
77 | mod rustc; |
78 | use rustc::Rustc; |
79 | |
80 | mod version; |
81 | use version::Version; |
82 | |
83 | #[cfg(test)] |
84 | mod tests; |
85 | |
86 | /// Helper to detect compiler features for `cfg` output in build scripts. |
87 | #[derive(Clone, Debug)] |
88 | pub struct AutoCfg { |
89 | out_dir: PathBuf, |
90 | rustc: Rustc, |
91 | rustc_version: Version, |
92 | target: Option<OsString>, |
93 | no_std: bool, |
94 | rustflags: Vec<String>, |
95 | uuid: u64, |
96 | } |
97 | |
98 | /// Writes a config flag for rustc on standard out. |
99 | /// |
100 | /// This looks like: `cargo:rustc-cfg=CFG` |
101 | /// |
102 | /// Cargo will use this in arguments to rustc, like `--cfg CFG`. |
103 | /// |
104 | /// This does not automatically call [`emit_possibility`] |
105 | /// so the compiler my generate an [`unexpected_cfgs` warning][check-cfg-flags]. |
106 | /// However, all the builtin emit methods on [`AutoCfg`] call [`emit_possibility`] automatically. |
107 | /// |
108 | /// [check-cfg-flags]: https://blog.rust-lang.org/2024/05/06/check-cfg.html |
109 | pub fn emit(cfg: &str) { |
110 | println!("cargo:rustc-cfg={} ", cfg); |
111 | } |
112 | |
113 | /// Writes a line telling Cargo to rerun the build script if `path` changes. |
114 | /// |
115 | /// This looks like: `cargo:rerun-if-changed=PATH` |
116 | /// |
117 | /// This requires at least cargo 0.7.0, corresponding to rustc 1.6.0. Earlier |
118 | /// versions of cargo will simply ignore the directive. |
119 | pub fn rerun_path(path: &str) { |
120 | println!("cargo:rerun-if-changed={} ", path); |
121 | } |
122 | |
123 | /// Writes a line telling Cargo to rerun the build script if the environment |
124 | /// variable `var` changes. |
125 | /// |
126 | /// This looks like: `cargo:rerun-if-env-changed=VAR` |
127 | /// |
128 | /// This requires at least cargo 0.21.0, corresponding to rustc 1.20.0. Earlier |
129 | /// versions of cargo will simply ignore the directive. |
130 | pub fn rerun_env(var: &str) { |
131 | println!("cargo:rerun-if-env-changed={} ", var); |
132 | } |
133 | |
134 | /// Indicates to rustc that a config flag should not generate an [`unexpected_cfgs` warning][check-cfg-flags] |
135 | /// |
136 | /// This looks like `cargo:rustc-check-cfg=cfg(VAR)` |
137 | /// |
138 | /// As of rust 1.80, the compiler does [automatic checking of cfgs at compile time][check-cfg-flags]. |
139 | /// All custom configuration flags must be known to rustc, or they will generate a warning. |
140 | /// This is done automatically when calling the builtin emit methods on [`AutoCfg`], |
141 | /// but not when calling [`autocfg::emit`](crate::emit) directly. |
142 | /// |
143 | /// Versions before rust 1.80 will simply ignore this directive. |
144 | /// |
145 | /// This function indicates to the compiler that the config flag never has a value. |
146 | /// If this is not desired, see [the blog post][check-cfg]. |
147 | /// |
148 | /// [check-cfg-flags]: https://blog.rust-lang.org/2024/05/06/check-cfg.html |
149 | pub fn emit_possibility(cfg: &str) { |
150 | println!("cargo:rustc-check-cfg=cfg({} )", cfg); |
151 | } |
152 | |
153 | /// Creates a new `AutoCfg` instance. |
154 | /// |
155 | /// # Panics |
156 | /// |
157 | /// Panics if `AutoCfg::new()` returns an error. |
158 | pub fn new() -> AutoCfg { |
159 | AutoCfg::new().unwrap() |
160 | } |
161 | |
162 | impl AutoCfg { |
163 | /// Creates a new `AutoCfg` instance. |
164 | /// |
165 | /// # Common errors |
166 | /// |
167 | /// - `rustc` can't be executed, from `RUSTC` or in the `PATH`. |
168 | /// - The version output from `rustc` can't be parsed. |
169 | /// - `OUT_DIR` is not set in the environment, or is not a writable directory. |
170 | /// |
171 | pub fn new() -> Result<Self, Error> { |
172 | match env::var_os("OUT_DIR") { |
173 | Some(d) => Self::with_dir(d), |
174 | None => Err(error::from_str("no OUT_DIR specified!")), |
175 | } |
176 | } |
177 | |
178 | /// Creates a new `AutoCfg` instance with the specified output directory. |
179 | /// |
180 | /// # Common errors |
181 | /// |
182 | /// - `rustc` can't be executed, from `RUSTC` or in the `PATH`. |
183 | /// - The version output from `rustc` can't be parsed. |
184 | /// - `dir` is not a writable directory. |
185 | /// |
186 | pub fn with_dir<T: Into<PathBuf>>(dir: T) -> Result<Self, Error> { |
187 | let rustc = Rustc::new(); |
188 | let rustc_version = try!(rustc.version()); |
189 | |
190 | let target = env::var_os("TARGET"); |
191 | |
192 | // Sanity check the output directory |
193 | let dir = dir.into(); |
194 | let meta = try!(fs::metadata(&dir).map_err(error::from_io)); |
195 | if !meta.is_dir() || meta.permissions().readonly() { |
196 | return Err(error::from_str("output path is not a writable directory")); |
197 | } |
198 | |
199 | let mut ac = AutoCfg { |
200 | rustflags: rustflags(&target, &dir), |
201 | out_dir: dir, |
202 | rustc: rustc, |
203 | rustc_version: rustc_version, |
204 | target: target, |
205 | no_std: false, |
206 | uuid: new_uuid(), |
207 | }; |
208 | |
209 | // Sanity check with and without `std`. |
210 | if !ac.probe_raw("").is_ok() { |
211 | if ac.probe_raw("#![no_std]").is_ok() { |
212 | ac.no_std = true; |
213 | } else { |
214 | // Neither worked, so assume nothing... |
215 | let warning = b"warning: autocfg could not probe for `std`\n "; |
216 | stderr().write_all(warning).ok(); |
217 | } |
218 | } |
219 | Ok(ac) |
220 | } |
221 | |
222 | /// Returns whether `AutoCfg` is using `#![no_std]` in its probes. |
223 | /// |
224 | /// This is automatically detected during construction -- if an empty probe |
225 | /// fails while one with `#![no_std]` succeeds, then the attribute will be |
226 | /// used for all further probes. This is usually only necessary when the |
227 | /// `TARGET` lacks `std` altogether. If neither succeeds, `no_std` is not |
228 | /// set, but that `AutoCfg` will probably only work for version checks. |
229 | /// |
230 | /// This attribute changes the implicit [prelude] from `std` to `core`, |
231 | /// which may affect the paths you need to use in other probes. It also |
232 | /// restricts some types that otherwise get additional methods in `std`, |
233 | /// like floating-point trigonometry and slice sorting. |
234 | /// |
235 | /// See also [`set_no_std`](#method.set_no_std). |
236 | /// |
237 | /// [prelude]: https://doc.rust-lang.org/reference/names/preludes.html#the-no_std-attribute |
238 | pub fn no_std(&self) -> bool { |
239 | self.no_std |
240 | } |
241 | |
242 | /// Sets whether `AutoCfg` should use `#![no_std]` in its probes. |
243 | /// |
244 | /// See also [`no_std`](#method.no_std). |
245 | pub fn set_no_std(&mut self, no_std: bool) { |
246 | self.no_std = no_std; |
247 | } |
248 | |
249 | /// Tests whether the current `rustc` reports a version greater than |
250 | /// or equal to "`major`.`minor`". |
251 | pub fn probe_rustc_version(&self, major: usize, minor: usize) -> bool { |
252 | self.rustc_version >= Version::new(major, minor, 0) |
253 | } |
254 | |
255 | /// Sets a `cfg` value of the form `rustc_major_minor`, like `rustc_1_29`, |
256 | /// if the current `rustc` is at least that version. |
257 | pub fn emit_rustc_version(&self, major: usize, minor: usize) { |
258 | let cfg_flag = format!("rustc_{} _{} ", major, minor); |
259 | emit_possibility(&cfg_flag); |
260 | if self.probe_rustc_version(major, minor) { |
261 | emit(&cfg_flag); |
262 | } |
263 | } |
264 | |
265 | /// Returns a new (hopefully unique) crate name for probes. |
266 | fn new_crate_name(&self) -> String { |
267 | #[allow(deprecated)] |
268 | static ID: AtomicUsize = ATOMIC_USIZE_INIT; |
269 | |
270 | let id = ID.fetch_add(1, Ordering::Relaxed); |
271 | format!("autocfg_{:016x} _{} ", self.uuid, id) |
272 | } |
273 | |
274 | fn probe_fmt<'a>(&self, source: Arguments<'a>) -> Result<(), Error> { |
275 | let mut command = self.rustc.command(); |
276 | command |
277 | .arg("--crate-name") |
278 | .arg(self.new_crate_name()) |
279 | .arg("--crate-type=lib") |
280 | .arg("--out-dir") |
281 | .arg(&self.out_dir) |
282 | .arg("--emit=llvm-ir"); |
283 | |
284 | if let Some(target) = self.target.as_ref() { |
285 | command.arg("--target").arg(target); |
286 | } |
287 | |
288 | command.args(&self.rustflags); |
289 | |
290 | command.arg("-").stdin(Stdio::piped()); |
291 | let mut child = try!(command.spawn().map_err(error::from_io)); |
292 | let mut stdin = child.stdin.take().expect("rustc stdin"); |
293 | |
294 | try!(stdin.write_fmt(source).map_err(error::from_io)); |
295 | drop(stdin); |
296 | |
297 | match child.wait() { |
298 | Ok(status) if status.success() => Ok(()), |
299 | Ok(status) => Err(error::from_exit(status)), |
300 | Err(error) => Err(error::from_io(error)), |
301 | } |
302 | } |
303 | |
304 | fn probe<'a>(&self, code: Arguments<'a>) -> bool { |
305 | let result = if self.no_std { |
306 | self.probe_fmt(format_args!("#![no_std]\n{} ", code)) |
307 | } else { |
308 | self.probe_fmt(code) |
309 | }; |
310 | result.is_ok() |
311 | } |
312 | |
313 | /// Tests whether the given code can be compiled as a Rust library. |
314 | /// |
315 | /// This will only return `Ok` if the compiler ran and exited successfully, |
316 | /// per `ExitStatus::success()`. |
317 | /// The code is passed to the compiler exactly as-is, notably not even |
318 | /// adding the [`#![no_std]`][Self::no_std] attribute like other probes. |
319 | /// |
320 | /// Raw probes are useful for testing functionality that's not yet covered |
321 | /// by the rest of the `AutoCfg` API. For example, the following attribute |
322 | /// **must** be used at the crate level, so it wouldn't work within the code |
323 | /// templates used by other `probe_*` methods. |
324 | /// |
325 | /// ``` |
326 | /// # extern crate autocfg; |
327 | /// # // Normally, cargo will set `OUT_DIR` for build scripts. |
328 | /// # let exe = std::env::current_exe().unwrap(); |
329 | /// # std::env::set_var("OUT_DIR", exe.parent().unwrap()); |
330 | /// let ac = autocfg::new(); |
331 | /// assert!(ac.probe_raw("#![no_builtins]").is_ok()); |
332 | /// ``` |
333 | /// |
334 | /// Rust nightly features could be tested as well -- ideally including a |
335 | /// code sample to ensure the unstable feature still works as expected. |
336 | /// For example, `slice::group_by` was renamed to `chunk_by` when it was |
337 | /// stabilized, even though the feature name was unchanged, so testing the |
338 | /// `#![feature(..)]` alone wouldn't reveal that. For larger snippets, |
339 | /// [`include_str!`] may be useful to load them from separate files. |
340 | /// |
341 | /// ``` |
342 | /// # extern crate autocfg; |
343 | /// # // Normally, cargo will set `OUT_DIR` for build scripts. |
344 | /// # let exe = std::env::current_exe().unwrap(); |
345 | /// # std::env::set_var("OUT_DIR", exe.parent().unwrap()); |
346 | /// let ac = autocfg::new(); |
347 | /// let code = r#" |
348 | /// #![feature(slice_group_by)] |
349 | /// pub fn probe(slice: &[i32]) -> impl Iterator<Item = &[i32]> { |
350 | /// slice.group_by(|a, b| a == b) |
351 | /// } |
352 | /// "#; |
353 | /// if ac.probe_raw(code).is_ok() { |
354 | /// autocfg::emit("has_slice_group_by"); |
355 | /// } |
356 | /// ``` |
357 | pub fn probe_raw(&self, code: &str) -> Result<(), Error> { |
358 | self.probe_fmt(format_args!("{} ", code)) |
359 | } |
360 | |
361 | /// Tests whether the given sysroot crate can be used. |
362 | /// |
363 | /// The test code is subject to change, but currently looks like: |
364 | /// |
365 | /// ```ignore |
366 | /// extern crate CRATE as probe; |
367 | /// ``` |
368 | pub fn probe_sysroot_crate(&self, name: &str) -> bool { |
369 | // Note: `as _` wasn't stabilized until Rust 1.33 |
370 | self.probe(format_args!("extern crate{} as probe;", name)) |
371 | } |
372 | |
373 | /// Emits a config value `has_CRATE` if `probe_sysroot_crate` returns true. |
374 | pub fn emit_sysroot_crate(&self, name: &str) { |
375 | let cfg_flag = format!("has_{} ", mangle(name)); |
376 | emit_possibility(&cfg_flag); |
377 | if self.probe_sysroot_crate(name) { |
378 | emit(&cfg_flag); |
379 | } |
380 | } |
381 | |
382 | /// Tests whether the given path can be used. |
383 | /// |
384 | /// The test code is subject to change, but currently looks like: |
385 | /// |
386 | /// ```ignore |
387 | /// pub use PATH; |
388 | /// ``` |
389 | pub fn probe_path(&self, path: &str) -> bool { |
390 | self.probe(format_args!("pub use{} ;", path)) |
391 | } |
392 | |
393 | /// Emits a config value `has_PATH` if `probe_path` returns true. |
394 | /// |
395 | /// Any non-identifier characters in the `path` will be replaced with |
396 | /// `_` in the generated config value. |
397 | pub fn emit_has_path(&self, path: &str) { |
398 | self.emit_path_cfg(path, &format!("has_{} ", mangle(path))); |
399 | } |
400 | |
401 | /// Emits the given `cfg` value if `probe_path` returns true. |
402 | pub fn emit_path_cfg(&self, path: &str, cfg: &str) { |
403 | emit_possibility(cfg); |
404 | if self.probe_path(path) { |
405 | emit(cfg); |
406 | } |
407 | } |
408 | |
409 | /// Tests whether the given trait can be used. |
410 | /// |
411 | /// The test code is subject to change, but currently looks like: |
412 | /// |
413 | /// ```ignore |
414 | /// pub trait Probe: TRAIT + Sized {} |
415 | /// ``` |
416 | pub fn probe_trait(&self, name: &str) -> bool { |
417 | self.probe(format_args!("pub trait Probe:{} + Sized{{}} ", name)) |
418 | } |
419 | |
420 | /// Emits a config value `has_TRAIT` if `probe_trait` returns true. |
421 | /// |
422 | /// Any non-identifier characters in the trait `name` will be replaced with |
423 | /// `_` in the generated config value. |
424 | pub fn emit_has_trait(&self, name: &str) { |
425 | self.emit_trait_cfg(name, &format!("has_{} ", mangle(name))); |
426 | } |
427 | |
428 | /// Emits the given `cfg` value if `probe_trait` returns true. |
429 | pub fn emit_trait_cfg(&self, name: &str, cfg: &str) { |
430 | emit_possibility(cfg); |
431 | if self.probe_trait(name) { |
432 | emit(cfg); |
433 | } |
434 | } |
435 | |
436 | /// Tests whether the given type can be used. |
437 | /// |
438 | /// The test code is subject to change, but currently looks like: |
439 | /// |
440 | /// ```ignore |
441 | /// pub type Probe = TYPE; |
442 | /// ``` |
443 | pub fn probe_type(&self, name: &str) -> bool { |
444 | self.probe(format_args!("pub type Probe ={} ;", name)) |
445 | } |
446 | |
447 | /// Emits a config value `has_TYPE` if `probe_type` returns true. |
448 | /// |
449 | /// Any non-identifier characters in the type `name` will be replaced with |
450 | /// `_` in the generated config value. |
451 | pub fn emit_has_type(&self, name: &str) { |
452 | self.emit_type_cfg(name, &format!("has_{} ", mangle(name))); |
453 | } |
454 | |
455 | /// Emits the given `cfg` value if `probe_type` returns true. |
456 | pub fn emit_type_cfg(&self, name: &str, cfg: &str) { |
457 | emit_possibility(cfg); |
458 | if self.probe_type(name) { |
459 | emit(cfg); |
460 | } |
461 | } |
462 | |
463 | /// Tests whether the given expression can be used. |
464 | /// |
465 | /// The test code is subject to change, but currently looks like: |
466 | /// |
467 | /// ```ignore |
468 | /// pub fn probe() { let _ = EXPR; } |
469 | /// ``` |
470 | pub fn probe_expression(&self, expr: &str) -> bool { |
471 | self.probe(format_args!("pub fn probe(){{ let _ ={} ;}} ", expr)) |
472 | } |
473 | |
474 | /// Emits the given `cfg` value if `probe_expression` returns true. |
475 | pub fn emit_expression_cfg(&self, expr: &str, cfg: &str) { |
476 | emit_possibility(cfg); |
477 | if self.probe_expression(expr) { |
478 | emit(cfg); |
479 | } |
480 | } |
481 | |
482 | /// Tests whether the given constant expression can be used. |
483 | /// |
484 | /// The test code is subject to change, but currently looks like: |
485 | /// |
486 | /// ```ignore |
487 | /// pub const PROBE: () = ((), EXPR).0; |
488 | /// ``` |
489 | pub fn probe_constant(&self, expr: &str) -> bool { |
490 | self.probe(format_args!("pub const PROBE: () = ((),{} ).0;", expr)) |
491 | } |
492 | |
493 | /// Emits the given `cfg` value if `probe_constant` returns true. |
494 | pub fn emit_constant_cfg(&self, expr: &str, cfg: &str) { |
495 | emit_possibility(cfg); |
496 | if self.probe_constant(expr) { |
497 | emit(cfg); |
498 | } |
499 | } |
500 | } |
501 | |
502 | fn mangle(s: &str) -> String { |
503 | simpl Iterator |
504 | .map(|c: char| match c { |
505 | 'A'... 'Z'| 'a'... 'z'| '0'... '9'=> c, |
506 | _ => '_', |
507 | }) |
508 | .collect() |
509 | } |
510 | |
511 | fn dir_contains_target( |
512 | target: &Option<OsString>, |
513 | dir: &Path, |
514 | cargo_target_dir: Option<OsString>, |
515 | ) -> bool { |
516 | target |
517 | .as_ref() |
518 | .and_then(|target| { |
519 | dir.to_str().and_then(|dir| { |
520 | let mut cargo_target_dir = cargo_target_dir |
521 | .map(PathBuf::from) |
522 | .unwrap_or_else(|| PathBuf::from("target")); |
523 | cargo_target_dir.push(target); |
524 | |
525 | cargo_target_dir |
526 | .to_str() |
527 | .map(|cargo_target_dir| dir.contains(cargo_target_dir)) |
528 | }) |
529 | }) |
530 | .unwrap_or(default:false) |
531 | } |
532 | |
533 | fn rustflags(target: &Option<OsString>, dir: &Path) -> Vec<String> { |
534 | // Starting with rust-lang/cargo#9601, shipped in Rust 1.55, Cargo always sets |
535 | // CARGO_ENCODED_RUSTFLAGS for any host/target build script invocation. This |
536 | // includes any source of flags, whether from the environment, toml config, or |
537 | // whatever may come in the future. The value is either an empty string, or a |
538 | // list of arguments separated by the ASCII unit separator (US), 0x1f. |
539 | if let Ok(a) = env::var("CARGO_ENCODED_RUSTFLAGS") { |
540 | return if a.is_empty() { |
541 | Vec::new() |
542 | } else { |
543 | a.split('\x1f ').map(str::to_string).collect() |
544 | }; |
545 | } |
546 | |
547 | // Otherwise, we have to take a more heuristic approach, and we don't |
548 | // support values from toml config at all. |
549 | // |
550 | // Cargo only applies RUSTFLAGS for building TARGET artifact in |
551 | // cross-compilation environment. Sadly, we don't have a way to detect |
552 | // when we're building HOST artifact in a cross-compilation environment, |
553 | // so for now we only apply RUSTFLAGS when cross-compiling an artifact. |
554 | // |
555 | // See https://github.com/cuviper/autocfg/pull/10#issuecomment-527575030. |
556 | if *target != env::var_os("HOST") |
557 | || dir_contains_target(target, dir, env::var_os("CARGO_TARGET_DIR")) |
558 | { |
559 | if let Ok(rustflags) = env::var("RUSTFLAGS") { |
560 | // This is meant to match how cargo handles the RUSTFLAGS environment variable. |
561 | // See https://github.com/rust-lang/cargo/blob/69aea5b6f69add7c51cca939a79644080c0b0ba0/src/cargo/core/compiler/build_context/target_info.rs#L434-L441 |
562 | return rustflags |
563 | .split(' ') |
564 | .map(str::trim) |
565 | .filter(|s| !s.is_empty()) |
566 | .map(str::to_string) |
567 | .collect(); |
568 | } |
569 | } |
570 | |
571 | Vec::new() |
572 | } |
573 | |
574 | /// Generates a numeric ID to use in probe crate names. |
575 | /// |
576 | /// This attempts to be random, within the constraints of Rust 1.0 and no dependencies. |
577 | fn new_uuid() -> u64 { |
578 | const FNV_OFFSET_BASIS: u64 = 0xcbf2_9ce4_8422_2325; |
579 | const FNV_PRIME: u64 = 0x100_0000_01b3; |
580 | |
581 | // This set should have an actual random hasher. |
582 | let set: std::collections::HashSet<u64> = (0..256).collect(); |
583 | |
584 | // Feed the `HashSet`-shuffled order into FNV-1a. |
585 | let mut hash: u64 = FNV_OFFSET_BASIS; |
586 | for x: u64 in set { |
587 | hash = (hash ^ x).wrapping_mul(FNV_PRIME); |
588 | } |
589 | hash |
590 | } |
591 |
Definitions
- try
- AutoCfg
- out_dir
- rustc
- rustc_version
- target
- no_std
- rustflags
- uuid
- emit
- rerun_path
- rerun_env
- emit_possibility
- new
- new
- with_dir
- no_std
- set_no_std
- probe_rustc_version
- emit_rustc_version
- new_crate_name
- probe_fmt
- probe
- probe_raw
- probe_sysroot_crate
- emit_sysroot_crate
- probe_path
- emit_has_path
- emit_path_cfg
- probe_trait
- emit_has_trait
- emit_trait_cfg
- probe_type
- emit_has_type
- emit_type_cfg
- probe_expression
- emit_expression_cfg
- probe_constant
- emit_constant_cfg
- mangle
- dir_contains_target
- rustflags
Learn Rust with the experts
Find out more