|
| 1 | +// Copyright 2015-2016 Brian Smith. |
| 2 | +// |
| 3 | +// Permission to use, copy, modify, and/or distribute this software for any |
| 4 | +// purpose with or without fee is hereby granted, provided that the above |
| 5 | +// copyright notice and this permission notice appear in all copies. |
| 6 | +// |
| 7 | +// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
| 8 | +// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
| 9 | +// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY |
| 10 | +// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
| 11 | +// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION |
| 12 | +// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN |
| 13 | +// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
| 14 | + |
| 15 | +//! Cargo-specific build logic that isn't specific to this project. |
| 16 | +
|
| 17 | +use super::{Profile, Target, target::Endian}; |
| 18 | +// Avoid `std::env` here; use `self::env` instead. |
| 19 | +use std::{ |
| 20 | + fs::{self}, |
| 21 | + path::{Path, PathBuf}, |
| 22 | +}; |
| 23 | + |
| 24 | +pub mod env { |
| 25 | + use std::ffi::OsString; |
| 26 | + |
| 27 | + macro_rules! define_env { |
| 28 | + { $vis:vis $NAME:ident : $ty:ident } => { |
| 29 | + $vis const $NAME: EnvVar = EnvVar { |
| 30 | + name: stringify!($NAME), |
| 31 | + ty: EnvVarTy::$ty, |
| 32 | + }; |
| 33 | + }; |
| 34 | + } |
| 35 | + |
| 36 | + enum EnvVarTy { |
| 37 | + RerunIfChanged, |
| 38 | + SetByCargo, |
| 39 | + } |
| 40 | + |
| 41 | + pub struct EnvVar { |
| 42 | + pub name: &'static str, |
| 43 | + ty: EnvVarTy, |
| 44 | + } |
| 45 | + |
| 46 | + /// Read an environment variable and optionally tell Cargo that we depend on it. |
| 47 | + /// |
| 48 | + /// The env var is static since we intend to only read a static set of environment |
| 49 | + /// variables. |
| 50 | + pub fn var_os(env_var: &'static EnvVar) -> Option<OsString> { |
| 51 | + match env_var.ty { |
| 52 | + EnvVarTy::RerunIfChanged => { |
| 53 | + println!("cargo:rerun-if-env-changed={}", env_var.name); |
| 54 | + } |
| 55 | + EnvVarTy::SetByCargo => {} |
| 56 | + } |
| 57 | + std::env::var_os(env_var.name) |
| 58 | + } |
| 59 | + |
| 60 | + pub fn var(env_var: &'static EnvVar) -> Option<String> { |
| 61 | + var_os(env_var).and_then(|value| value.into_string().ok()) |
| 62 | + } |
| 63 | + |
| 64 | + // In alphabetical order |
| 65 | + define_env! { pub(super) CARGO_CFG_TARGET_ARCH: SetByCargo } |
| 66 | + define_env! { pub(super) CARGO_CFG_TARGET_ENDIAN: SetByCargo } |
| 67 | + define_env! { pub(super) CARGO_CFG_TARGET_ENV: SetByCargo } |
| 68 | + define_env! { pub(super) CARGO_CFG_TARGET_OS: SetByCargo } |
| 69 | + define_env! { pub(super) CARGO_MANIFEST_DIR: SetByCargo } |
| 70 | + define_env! { pub(super) CARGO_MANIFEST_LINKS: SetByCargo } |
| 71 | + define_env! { pub(super) CARGO_PKG_NAME: SetByCargo } |
| 72 | + define_env! { pub(super) CARGO_PKG_VERSION_MAJOR: SetByCargo } |
| 73 | + define_env! { pub(super) CARGO_PKG_VERSION_MINOR: SetByCargo } |
| 74 | + define_env! { pub(super) CARGO_PKG_VERSION_PATCH: SetByCargo } |
| 75 | + define_env! { pub(super) CARGO_PKG_VERSION_PRE: SetByCargo } |
| 76 | + define_env! { pub(super) DEBUG: SetByCargo } |
| 77 | + define_env! { pub(super) OUT_DIR: SetByCargo } |
| 78 | + |
| 79 | + // XXX: These don't belong here. |
| 80 | + define_env! { pub PERL_EXECUTABLE: RerunIfChanged } |
| 81 | + define_env! { pub RING_PREGENERATE_ASM: RerunIfChanged } |
| 82 | +} |
| 83 | + |
| 84 | +pub fn root_dir() -> PathBuf { |
| 85 | + // Avoid assuming the working directory is the same is the $CARGO_MANIFEST_DIR so that toolchains |
| 86 | + // which may assume other working directories can still build this code. |
| 87 | + PathBuf::from( |
| 88 | + env::var_os(&env::CARGO_MANIFEST_DIR).expect("CARGO_MANIFEST_DIR should always be set"), |
| 89 | + ) |
| 90 | +} |
| 91 | + |
| 92 | +pub fn extern_c_prefix(component: &str) -> String { |
| 93 | + // Keep in sync with `core_name_and_version!` in prefixed.rs. |
| 94 | + let core_name_and_version = [ |
| 95 | + &env::var(&env::CARGO_PKG_NAME).unwrap(), |
| 96 | + component, |
| 97 | + &env::var(&env::CARGO_PKG_VERSION_MAJOR).unwrap(), |
| 98 | + &env::var(&env::CARGO_PKG_VERSION_MINOR).unwrap(), |
| 99 | + &env::var(&env::CARGO_PKG_VERSION_PATCH).unwrap(), |
| 100 | + &env::var(&env::CARGO_PKG_VERSION_PRE).unwrap(), // Often empty |
| 101 | + ] |
| 102 | + .join("_"); |
| 103 | + // Ensure `links` in Cargo.toml is consistent with the version. |
| 104 | + assert_eq!( |
| 105 | + &env::var(&env::CARGO_MANIFEST_LINKS).unwrap(), |
| 106 | + &core_name_and_version |
| 107 | + ); |
| 108 | + core_name_and_version |
| 109 | +} |
| 110 | + |
| 111 | +impl Target { |
| 112 | + pub fn new_from_env() -> Self { |
| 113 | + let arch = env::var(&env::CARGO_CFG_TARGET_ARCH).unwrap(); |
| 114 | + let os = env::var(&env::CARGO_CFG_TARGET_OS).unwrap(); |
| 115 | + let env = env::var(&env::CARGO_CFG_TARGET_ENV).unwrap(); |
| 116 | + let endian = env::var(&env::CARGO_CFG_TARGET_ENDIAN).unwrap(); |
| 117 | + let endian = if endian == "little" { |
| 118 | + Endian::Little |
| 119 | + } else { |
| 120 | + Endian::Other |
| 121 | + }; |
| 122 | + |
| 123 | + let out_dir = PathBuf::from(env::var_os(&env::OUT_DIR).unwrap()); |
| 124 | + |
| 125 | + Self { |
| 126 | + arch, |
| 127 | + os, |
| 128 | + env, |
| 129 | + endian, |
| 130 | + out_dir, |
| 131 | + } |
| 132 | + } |
| 133 | +} |
| 134 | + |
| 135 | +impl Profile { |
| 136 | + pub fn new_from_env(root_dir: &Path) -> Self { |
| 137 | + let is_git = fs::metadata(root_dir.join(".git")).is_ok(); |
| 138 | + |
| 139 | + // Published builds are always built in release mode. |
| 140 | + let is_debug = is_git && env::var(&env::DEBUG).unwrap() != "false"; |
| 141 | + |
| 142 | + // During local development, force warnings in non-Rust code to be treated |
| 143 | + // as errors. Since warnings are highly compiler-dependent and compilers |
| 144 | + // don't maintain backward compatibility w.r.t. which warnings they issue, |
| 145 | + // don't do this for packaged builds. |
| 146 | + let force_warnings_into_errors = is_git; |
| 147 | + |
| 148 | + Self { |
| 149 | + is_git, |
| 150 | + is_debug, |
| 151 | + force_warnings_into_errors, |
| 152 | + } |
| 153 | + } |
| 154 | +} |
| 155 | + |
| 156 | +// TODO: We should emit `cargo:rerun-if-changed-env` for the various |
| 157 | +// environment variables that affect the build. |
| 158 | +pub fn emit_rerun_if_changed<'a>(paths: impl Iterator<Item = &'a Path>) { |
| 159 | + paths.for_each(|path| { |
| 160 | + println!("cargo:rerun-if-changed={}", path.to_str().unwrap()); |
| 161 | + }) |
| 162 | +} |
0 commit comments