summaryrefslogtreecommitdiff
path: root/cc
diff options
context:
space:
mode:
Diffstat (limited to 'cc')
-rw-r--r--cc/.github/workflows/main.yml124
-rw-r--r--cc/Cargo.toml10
-rw-r--r--cc/README.md8
-rw-r--r--cc/azure-pipelines.yml105
-rw-r--r--cc/cc-test/Cargo.toml1
-rw-r--r--cc/cc-test/build.rs2
-rw-r--r--cc/cc-test/tests/all.rs2
-rw-r--r--cc/ci/azure-install-rust.yml38
-rw-r--r--cc/ci/azure-steps.yml28
-rw-r--r--cc/src/com.rs14
-rw-r--r--cc/src/lib.rs302
-rw-r--r--cc/src/setup_config.rs24
-rw-r--r--cc/src/windows_registry.rs125
-rw-r--r--cc/tests/cc_env.rs5
-rw-r--r--cc/tests/cflags.rs5
-rw-r--r--cc/tests/cxxflags.rs5
-rw-r--r--cc/tests/support/mod.rs4
-rw-r--r--cc/tests/test.rs37
18 files changed, 514 insertions, 325 deletions
diff --git a/cc/.github/workflows/main.yml b/cc/.github/workflows/main.yml
new file mode 100644
index 0000000..9c35a41
--- /dev/null
+++ b/cc/.github/workflows/main.yml
@@ -0,0 +1,124 @@
+name: CI
+on: [push, pull_request]
+
+jobs:
+ test:
+ name: Test
+ runs-on: ${{ matrix.os }}
+ strategy:
+ matrix:
+ build: [stable, beta, nightly, linux32, macos, aarch64-ios, win32, win64, mingw32, mingw64, windows-2016]
+ include:
+ - build: stable
+ os: ubuntu-latest
+ rust: stable
+ target: x86_64-unknown-linux-gnu
+ - build: beta
+ os: ubuntu-latest
+ rust: beta
+ target: x86_64-unknown-linux-gnu
+ - build: nightly
+ os: ubuntu-latest
+ rust: nightly
+ target: x86_64-unknown-linux-gnu
+ - build: linux32
+ os: ubuntu-latest
+ rust: stable
+ target: i686-unknown-linux-gnu
+ - build: macos
+ os: macos-latest
+ rust: stable
+ target: x86_64-apple-darwin
+ - build: aarch64-ios
+ os: macos-latest
+ rust: stable
+ target: aarch64-apple-ios
+ no_run: --no-run
+ - build: win32
+ os: windows-2016
+ rust: stable-i686-msvc
+ target: i686-pc-windows-msvc
+ - build: win64
+ os: windows-latest
+ rust: stable
+ target: x86_64-pc-windows-msvc
+ - build: mingw32
+ os: windows-latest
+ rust: stable-i686-gnu
+ target: i686-pc-windows-gnu
+ - build: mingw64
+ os: windows-latest
+ rust: stable-x86_64-gnu
+ target: x86_64-pc-windows-gnu
+ - build: windows-2016
+ os: windows-2016
+ rust: stable-x86_64
+ target: x86_64-pc-windows-msvc
+ steps:
+ - uses: actions/checkout@master
+ - name: Install Rust (rustup)
+ run: rustup update ${{ matrix.rust }} --no-self-update && rustup default ${{ matrix.rust }}
+ if: matrix.os != 'macos-latest'
+ shell: bash
+ - name: Install Rust (macos)
+ run: |
+ curl https://sh.rustup.rs | sh -s -- -y
+ echo "##[add-path]$HOME/.cargo/bin"
+ if: matrix.os == 'macos-latest'
+ - run: rustup target add ${{ matrix.target }}
+ - name: Install g++-multilib
+ run: |
+ set -e
+ # Remove the ubuntu-toolchain-r/test PPA, which is added by default.
+ # Some packages were removed, and this is causing the g++multilib
+ # install to fail. Similar issue:
+ # https://github.com/scikit-learn/scikit-learn/issues/13928.
+ sudo add-apt-repository --remove ppa:ubuntu-toolchain-r/test
+ sudo apt-get install g++-multilib
+ if: matrix.build == 'linux32'
+ - run: cargo build
+ - run: cargo test ${{ matrix.no_run }}
+ - run: cargo test ${{ matrix.no_run }} --features parallel
+ - run: cargo test ${{ matrix.no_run }} --manifest-path cc-test/Cargo.toml --target ${{ matrix.target }}
+ - run: cargo test ${{ matrix.no_run }} --manifest-path cc-test/Cargo.toml --target ${{ matrix.target }} --features parallel
+ - run: cargo test ${{ matrix.no_run }} --manifest-path cc-test/Cargo.toml --target ${{ matrix.target }} --release
+
+ msrv:
+ name: MSRV
+ runs-on: ${{ matrix.os }}
+ strategy:
+ matrix:
+ os: [ubuntu-latest, windows-latest]
+ steps:
+ - uses: actions/checkout@master
+ - name: Install Rust
+ run: rustup update 1.31.0 --no-self-update && rustup default 1.31.0
+ shell: bash
+ - run: cargo build
+
+ rustfmt:
+ name: Rustfmt
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@master
+ - name: Install Rust
+ run: rustup update stable && rustup default stable && rustup component add rustfmt
+ - run: cargo fmt -- --check
+
+ publish_docs:
+ name: Publish Documentation
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@master
+ - name: Install Rust
+ run: rustup update stable && rustup default stable
+ - name: Build documentation
+ run: cargo doc --no-deps --all-features
+ - name: Publish documentation
+ run: |
+ cd target/doc
+ git init
+ git add .
+ git -c user.name='ci' -c user.email='ci' commit -m init
+ git push -f -q https://git:${{ secrets.github_token }}@github.com/${{ github.repository }} HEAD:gh-pages
+ if: github.event_name == 'push' && github.event.ref == 'refs/heads/master'
diff --git a/cc/Cargo.toml b/cc/Cargo.toml
index 52e18ce..88f44eb 100644
--- a/cc/Cargo.toml
+++ b/cc/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "cc"
-version = "1.0.40"
+version = "1.0.48"
authors = ["Alex Crichton <alex@alexcrichton.com>"]
license = "MIT/Apache-2.0"
repository = "https://github.com/alexcrichton/cc-rs"
@@ -15,12 +15,14 @@ keywords = ["build-dependencies"]
readme = "README.md"
categories = ["development-tools::build-utils"]
exclude = ["/.travis.yml", "/appveyor.yml"]
+edition = "2018"
[dependencies]
-rayon = { version = "1.0", optional = true }
+num_cpus = { version = "1.10", optional = true }
+jobserver = { version = "0.1.16", optional = true }
[features]
-parallel = ["rayon"]
+parallel = ["num_cpus", "jobserver"]
[dev-dependencies]
-tempdir = "0.3"
+tempfile = "3"
diff --git a/cc/README.md b/cc/README.md
index e3c6ad0..68448ac 100644
--- a/cc/README.md
+++ b/cc/README.md
@@ -2,8 +2,6 @@
A library to compile C/C++/assembly into a Rust library/application.
-[![Build Status](https://dev.azure.com/alexcrichton/cc-rs/_apis/build/status/alexcrichton.cc-rs?branchName=master)](https://dev.azure.com/alexcrichton/cc-rs/_build/latest?definitionId=5&branchName=master)
-
[Documentation](https://docs.rs/cc)
A simple library meant to be used as a build dependency with Cargo packages in
@@ -28,8 +26,6 @@ Next up, you'll want to write a build script like so:
```rust,no_run
// build.rs
-extern crate cc;
-
fn main() {
cc::Build::new()
.file("foo.c")
@@ -143,8 +139,6 @@ required varies per platform, but there are three broad categories:
`Build`:
```rust,no_run
-extern crate cc;
-
fn main() {
cc::Build::new()
.cpp(true) // Switch to C++ library compilation.
@@ -163,8 +157,6 @@ linked to the crate target.
on `Build` (currently for GNU/Clang toolchains only):
```rust,no_run
-extern crate cc;
-
fn main() {
cc::Build::new()
// Switch to CUDA C++ library compilation using NVCC.
diff --git a/cc/azure-pipelines.yml b/cc/azure-pipelines.yml
deleted file mode 100644
index e925da1..0000000
--- a/cc/azure-pipelines.yml
+++ /dev/null
@@ -1,105 +0,0 @@
-# Note for forks: Azure Pipelines is triggered only by commits to the branches
-# matching the patterns below.
-# See https://docs.microsoft.com/en-us/azure/devops/pipelines/build/triggers
-trigger:
- - master
- - ci-*
-
-jobs:
- - job: min_linux
- pool:
- vmImage: ubuntu-16.04
- displayName: Minimum Rust (Linux)
- variables:
- TOOLCHAIN: 1.16.0
- steps:
- - template: ci/azure-install-rust.yml
- - script: cargo build
-
- - job: min_Windows
- pool:
- vmImage: vs2017-win2016
- displayName: Minimum Rust (Windows)
- variables:
- TOOLCHAIN: 1.16.0
- steps:
- - template: ci/azure-install-rust.yml
- - script: cargo build
-
- - job: Linux
- pool:
- vmImage: ubuntu-16.04
- steps:
- - template: ci/azure-steps.yml
- strategy:
- matrix:
- x86_64:
- TARGET: x86_64-unknown-linux-gnu
- i686:
- TARGET: i686-unknown-linux-gnu
- x86_64-beta:
- TARGET: x86_64-unknown-linux-gnu
- TOOLCHAIN: beta
- x86_64-nightly:
- TARGET: x86_64-unknown-linux-gnu
- TOOLCHAIN: nightly
-
- - job: macOS
- pool:
- vmImage: macos-10.13
- steps:
- - template: ci/azure-steps.yml
- strategy:
- matrix:
- x86_64:
- TARGET: x86_64-apple-darwin
- aarch64-ios:
- TARGET: aarch64-apple-ios
- NO_RUN: --no-run
-
- - job: Windows_vs2019
- pool:
- vmImage: windows-2019
- steps:
- - template: ci/azure-steps.yml
- strategy:
- matrix:
- x86_64-msvc:
- TARGET: x86_64-pc-windows-msvc
-
- - job: Windows_vs2017
- pool:
- vmImage: vs2017-win2016
- steps:
- - template: ci/azure-steps.yml
- strategy:
- matrix:
- x86_64-msvc:
- TARGET: x86_64-pc-windows-msvc
- i686-msvc:
- TARGET: i686-pc-windows-msvc
- x86_64-gnu:
- TARGET: x86_64-pc-windows-gnu
- i686-gnu:
- TARGET: i686-pc-windows-gnu
-
- - job: Windows_vs2015
- pool:
- vmImage: vs2015-win2012r2
- steps:
- - template: ci/azure-steps.yml
- strategy:
- matrix:
- x86_64-msvc:
- TARGET: x86_64-pc-windows-msvc
- i686-msvc:
- TARGET: i686-pc-windows-msvc
-
- - job: docs
- steps:
- - template: ci/azure-install-rust.yml
- - script: cargo doc --no-deps --all-features
- - script: curl -LsSf https://git.io/fhJ8n | rustc - && (cd target/doc && ../../rust_out)
- condition: and(succeeded(), eq(variables['Build.SourceBranch'], 'refs/heads/master'))
- env:
- GITHUB_DEPLOY_KEY: $(GITHUB_DEPLOY_KEY)
diff --git a/cc/cc-test/Cargo.toml b/cc/cc-test/Cargo.toml
index e83416a..c25854c 100644
--- a/cc/cc-test/Cargo.toml
+++ b/cc/cc-test/Cargo.toml
@@ -2,6 +2,7 @@
name = "cc-test"
version = "0.1.0"
authors = ["Alex Crichton <alex@alexcrichton.com>"]
+edition = "2018"
[lib]
name = "cc_test"
diff --git a/cc/cc-test/build.rs b/cc/cc-test/build.rs
index 677161e..3065861 100644
--- a/cc/cc-test/build.rs
+++ b/cc/cc-test/build.rs
@@ -1,5 +1,3 @@
-extern crate cc;
-
use std::env;
use std::fs;
use std::path::PathBuf;
diff --git a/cc/cc-test/tests/all.rs b/cc/cc-test/tests/all.rs
index 59cb8e4..a457c72 100644
--- a/cc/cc-test/tests/all.rs
+++ b/cc/cc-test/tests/all.rs
@@ -1,5 +1,3 @@
-extern crate cc_test;
-
use cc_test::*;
#[link(name = "OptLinkage", kind = "static")]
diff --git a/cc/ci/azure-install-rust.yml b/cc/ci/azure-install-rust.yml
deleted file mode 100644
index 9c1bae8..0000000
--- a/cc/ci/azure-install-rust.yml
+++ /dev/null
@@ -1,38 +0,0 @@
-steps:
- - bash: |
- set -e
- toolchain=$TOOLCHAIN
- if [ "$toolchain" = "" ]; then
- toolchain=stable
- fi
- if command -v rustup; then
- rustup update $toolchain
- rustup default $toolchain
- else
- curl https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain $toolchain
- echo "##vso[task.prependpath]$HOME/.cargo/bin"
- fi
- displayName: Install rust (unix)
- condition: ne( variables['Agent.OS'], 'Windows_NT' )
-
- - bash: |
- set -e
- toolchain=$TOOLCHAIN
- if [ "$toolchain" = "" ]; then
- toolchain=stable-$TARGET
- fi
- if command -v rustup; then
- rustup update --no-self-update $toolchain
- rustup default $toolchain
- else
- curl.exe -sSf -o rustup-init.exe https://win.rustup.rs
- ./rustup-init.exe -y --default-toolchain $toolchain
- echo "##vso[task.prependpath]$USERPROFILE/.cargo/bin"
- fi
- displayName: Install rust (windows)
- condition: eq( variables['Agent.OS'], 'Windows_NT' )
-
- - script: |
- rustc -Vv
- cargo -V
- displayName: Query rust and cargo versions
diff --git a/cc/ci/azure-steps.yml b/cc/ci/azure-steps.yml
deleted file mode 100644
index bbf8ec6..0000000
--- a/cc/ci/azure-steps.yml
+++ /dev/null
@@ -1,28 +0,0 @@
-steps:
- - template: azure-install-rust.yml
- - bash: rustup target add $TARGET
- displayName: Install Rust target
-
- # Remove the ubuntu-toolchain-r/test PPA, which is added by default. Some
- # packages were removed, and this is causing the g++multilib install to fail.
- # Similar issue: https://github.com/scikit-learn/scikit-learn/issues/13928
- - bash: sudo add-apt-repository --remove ppa:ubuntu-toolchain-r/test
- condition: eq( variables['Agent.OS'], 'Linux' )
- displayName: Remove ppa:ubuntu-toolchain-r/test
-
- - bash: sudo apt-get install g++-multilib
- condition: eq( variables['Agent.OS'], 'Linux' )
- displayName: Install g++-multilib
-
- - script: cargo build
- displayName: "Normal build"
- - bash: cargo test $NO_RUN
- displayName: "Crate tests"
- - bash: cargo test $NO_RUN --features parallel
- displayName: "Crate tests (parallel)"
- - bash: cargo test $NO_RUN --manifest-path cc-test/Cargo.toml --target $TARGET
- displayName: "cc-test tests"
- - bash: cargo test $NO_RUN --manifest-path cc-test/Cargo.toml --target $TARGET --features parallel
- displayName: "cc-test tests (parallel)"
- - bash: cargo test $NO_RUN --manifest-path cc-test/Cargo.toml --target $TARGET --release
- displayName: "cc-test tests (release)"
diff --git a/cc/src/com.rs b/cc/src/com.rs
index 9b75d47..a5f2afe 100644
--- a/cc/src/com.rs
+++ b/cc/src/com.rs
@@ -7,19 +7,19 @@
#![allow(unused)]
+use crate::winapi::CoInitializeEx;
+use crate::winapi::IUnknown;
+use crate::winapi::Interface;
+use crate::winapi::BSTR;
+use crate::winapi::COINIT_MULTITHREADED;
+use crate::winapi::{SysFreeString, SysStringLen};
+use crate::winapi::{HRESULT, S_FALSE, S_OK};
use std::ffi::{OsStr, OsString};
use std::mem::forget;
use std::ops::Deref;
use std::os::windows::ffi::{OsStrExt, OsStringExt};
use std::ptr::null_mut;
use std::slice::from_raw_parts;
-use winapi::CoInitializeEx;
-use winapi::IUnknown;
-use winapi::Interface;
-use winapi::BSTR;
-use winapi::COINIT_MULTITHREADED;
-use winapi::{SysFreeString, SysStringLen};
-use winapi::{HRESULT, S_FALSE, S_OK};
pub fn initialize() -> Result<(), HRESULT> {
let err = unsafe { CoInitializeEx(null_mut(), COINIT_MULTITHREADED) };
diff --git a/cc/src/lib.rs b/cc/src/lib.rs
index 2d918b8..d795e5a 100644
--- a/cc/src/lib.rs
+++ b/cc/src/lib.rs
@@ -35,15 +35,13 @@
//! Cargo will also set this environment variable when executed with the `-jN` flag.
//!
//! If `NUM_JOBS` is not set, the `RAYON_NUM_THREADS` environment variable can
-//! also specify the build paralellism.
+//! also specify the build parallelism.
//!
//! # Examples
//!
//! Use the `Build` struct to compile `src/foo.c`:
//!
//! ```no_run
-//! extern crate cc;
-//!
//! fn main() {
//! cc::Build::new()
//! .file("src/foo.c")
@@ -58,9 +56,6 @@
#![allow(deprecated)]
#![deny(missing_docs)]
-#[cfg(feature = "parallel")]
-extern crate rayon;
-
use std::collections::HashMap;
use std::env;
use std::ffi::{OsStr, OsString};
@@ -99,6 +94,8 @@ pub struct Build {
flags: Vec<String>,
flags_supported: Vec<String>,
known_flag_support_status: Arc<Mutex<HashMap<String, bool>>>,
+ ar_flags: Vec<String>,
+ no_default_flags: bool,
files: Vec<PathBuf>,
cpp: bool,
cpp_link_stdlib: Option<Option<String>>,
@@ -109,6 +106,7 @@ pub struct Build {
out_dir: Option<PathBuf>,
opt_level: Option<String>,
debug: Option<bool>,
+ force_frame_pointer: Option<bool>,
env: Vec<(OsString, OsString)>,
compiler: Option<PathBuf>,
archiver: Option<PathBuf>,
@@ -213,8 +211,17 @@ impl ToolFamily {
}
ToolFamily::Gnu | ToolFamily::Clang => {
cmd.push_cc_arg("-g".into());
+ }
+ }
+ }
+
+ /// What the flag to force frame pointers.
+ fn add_force_frame_pointer(&self, cmd: &mut Tool) {
+ match *self {
+ ToolFamily::Gnu | ToolFamily::Clang => {
cmd.push_cc_arg("-fno-omit-frame-pointer".into());
}
+ _ => (),
}
}
@@ -277,6 +284,8 @@ impl Build {
flags: Vec::new(),
flags_supported: Vec::new(),
known_flag_support_status: Arc::new(Mutex::new(HashMap::new())),
+ ar_flags: Vec::new(),
+ no_default_flags: false,
files: Vec::new(),
shared_flag: None,
static_flag: None,
@@ -289,6 +298,7 @@ impl Build {
out_dir: None,
opt_level: None,
debug: None,
+ force_frame_pointer: None,
env: Vec::new(),
compiler: None,
archiver: None,
@@ -361,6 +371,23 @@ impl Build {
self
}
+ /// Add an arbitrary flag to the invocation of the compiler
+ ///
+ /// # Example
+ ///
+ /// ```no_run
+ /// cc::Build::new()
+ /// .file("src/foo.c")
+ /// .file("src/bar.c")
+ /// .ar_flag("/NODEFAULTLIB:libc.dll")
+ /// .compile("foo");
+ /// ```
+
+ pub fn ar_flag(&mut self, flag: &str) -> &mut Build {
+ self.ar_flags.push(flag.to_string());
+ self
+ }
+
fn ensure_check_file(&self) -> Result<PathBuf, Error> {
let out_dir = self.get_out_dir()?;
let src = if self.cuda {
@@ -497,6 +524,17 @@ impl Build {
self
}
+ /// Disables the generation of default compiler flags. The default compiler
+ /// flags may cause conflicts in some cross compiling scenarios.
+ ///
+ /// Setting the `CRATE_CC_NO_DEFAULTS` environment variable has the same
+ /// effect as setting this to `true`. The presence of the environment
+ /// variable and the value of `no_default_flags` will be OR'd together.
+ pub fn no_default_flags(&mut self, no_default_flags: bool) -> &mut Build {
+ self.no_default_flags = no_default_flags;
+ self
+ }
+
/// Add a file which will be compiled
pub fn file<P: AsRef<Path>>(&mut self, p: P) -> &mut Build {
self.files.push(p.as_ref().to_path_buf());
@@ -750,6 +788,17 @@ impl Build {
self
}
+ /// Configures whether the compiler will emit instructions to store
+ /// frame pointers during codegen.
+ ///
+ /// This option is automatically enabled when debug information is emitted.
+ /// Otherwise the target platform compiler's default will be used.
+ /// You can use this option to force a specific setting.
+ pub fn force_frame_pointer(&mut self, force: bool) -> &mut Build {
+ self.force_frame_pointer = Some(force);
+ self
+ }
+
/// Configures the output directory where all object files and static
/// libraries will be located.
///
@@ -931,22 +980,150 @@ impl Build {
}
#[cfg(feature = "parallel")]
- fn compile_objects(&self, objs: &[Object]) -> Result<(), Error> {
- use self::rayon::prelude::*;
+ fn compile_objects<'me>(&'me self, objs: &[Object]) -> Result<(), Error> {
+ use std::sync::atomic::{AtomicBool, Ordering::SeqCst};
+ use std::sync::Once;
+
+ // Limit our parallelism globally with a jobserver. Start off by
+ // releasing our own token for this process so we can have a bit of an
+ // easier to write loop below. If this fails, though, then we're likely
+ // on Windows with the main implicit token, so we just have a bit extra
+ // parallelism for a bit and don't reacquire later.
+ let server = jobserver();
+ let reacquire = server.release_raw().is_ok();
+
+ // When compiling objects in parallel we do a few dirty tricks to speed
+ // things up:
+ //
+ // * First is that we use the `jobserver` crate to limit the parallelism
+ // of this build script. The `jobserver` crate will use a jobserver
+ // configured by Cargo for build scripts to ensure that parallelism is
+ // coordinated across C compilations and Rust compilations. Before we
+ // compile anything we make sure to wait until we acquire a token.
+ //
+ // Note that this jobserver is cached globally so we only used one per
+ // process and only worry about creating it once.
+ //
+ // * Next we use a raw `thread::spawn` per thread to actually compile
+ // objects in parallel. We only actually spawn a thread after we've
+ // acquired a token to perform some work
+ //
+ // * Finally though we want to keep the dependencies of this crate
+ // pretty light, so we avoid using a safe abstraction like `rayon` and
+ // instead rely on some bits of `unsafe` code. We know that this stack
+ // frame persists while everything is compiling so we use all the
+ // stack-allocated objects without cloning/reallocating. We use a
+ // transmute to `State` with a `'static` lifetime to persist
+ // everything we need across the boundary, and the join-on-drop
+ // semantics of `JoinOnDrop` should ensure that our stack frame is
+ // alive while threads are alive.
+ //
+ // With all that in mind we compile all objects in a loop here, after we
+ // acquire the appropriate tokens, Once all objects have been compiled
+ // we join on all the threads and propagate the results of compilation.
+ //
+ // Note that as a slight optimization we try to break out as soon as
+ // possible as soon as any compilation fails to ensure that errors get
+ // out to the user as fast as possible.
+ let error = AtomicBool::new(false);
+ let mut threads = Vec::new();
+ for obj in objs {
+ if error.load(SeqCst) {
+ break;
+ }
+ let token = server.acquire()?;
+ let state = State {
+ build: self,
+ obj,
+ error: &error,
+ };
+ let state = unsafe { std::mem::transmute::<State, State<'static>>(state) };
+ let thread = thread::spawn(|| {
+ let state: State<'me> = state; // erase the `'static` lifetime
+ let result = state.build.compile_object(state.obj);
+ if result.is_err() {
+ state.error.store(true, SeqCst);
+ }
+ drop(token); // make sure our jobserver token is released after the compile
+ return result;
+ });
+ threads.push(JoinOnDrop(Some(thread)));
+ }
- if let Some(amt) = self.getenv("NUM_JOBS") {
- if let Ok(amt) = amt.parse() {
- let _ = rayon::ThreadPoolBuilder::new()
- .num_threads(amt)
- .build_global();
+ for mut thread in threads {
+ if let Some(thread) = thread.0.take() {
+ thread.join().expect("thread should not panic")?;
}
}
- // Check for any errors and return the first one found.
- objs.par_iter()
- .with_max_len(1)
- .map(|obj| self.compile_object(obj))
- .collect()
+ // Reacquire our process's token before we proceed, which we released
+ // before entering the loop above.
+ if reacquire {
+ server.acquire_raw()?;
+ }
+
+ return Ok(());
+
+ /// Shared state from the parent thread to the child thread. This
+ /// package of pointers is temporarily transmuted to a `'static`
+ /// lifetime to cross the thread boundary and then once the thread is
+ /// running we erase the `'static` to go back to an anonymous lifetime.
+ struct State<'a> {
+ build: &'a Build,
+ obj: &'a Object,
+ error: &'a AtomicBool,
+ }
+
+ /// Returns a suitable `jobserver::Client` used to coordinate
+ /// parallelism between build scripts.
+ fn jobserver() -> &'static jobserver::Client {
+ static INIT: Once = Once::new();
+ static mut JOBSERVER: Option<jobserver::Client> = None;
+
+ fn _assert_sync<T: Sync>() {}
+ _assert_sync::<jobserver::Client>();
+
+ unsafe {
+ INIT.call_once(|| {
+ let server = default_jobserver();
+ JOBSERVER = Some(server);
+ });
+ JOBSERVER.as_ref().unwrap()
+ }
+ }
+
+ unsafe fn default_jobserver() -> jobserver::Client {
+ // Try to use the environmental jobserver which Cargo typically
+ // initializes for us...
+ if let Some(client) = jobserver::Client::from_env() {
+ return client;
+ }
+
+ // ... but if that fails for whatever reason fall back to the number
+ // of cpus on the system or the `NUM_JOBS` env var.
+ let mut parallelism = num_cpus::get();
+ if let Ok(amt) = env::var("NUM_JOBS") {
+ if let Ok(amt) = amt.parse() {
+ parallelism = amt;
+ }
+ }
+
+ // If we create our own jobserver then be sure to reserve one token
+ // for ourselves.
+ let client = jobserver::Client::new(parallelism).expect("failed to create jobserver");
+ client.acquire_raw().expect("failed to acquire initial");
+ return client;
+ }
+
+ struct JoinOnDrop(Option<thread::JoinHandle<Result<(), Error>>>);
+
+ impl Drop for JoinOnDrop {
+ fn drop(&mut self) {
+ if let Some(thread) = self.0.take() {
+ drop(thread.join());
+ }
+ }
+ }
}
#[cfg(not(feature = "parallel"))]
@@ -1073,11 +1250,10 @@ impl Build {
let mut cmd = self.get_base_compiler()?;
let envflags = self.envflags(if self.cpp { "CXXFLAGS" } else { "CFLAGS" });
- // Disable default flag generation via environment variable or when
- // certain cross compiling arguments are set
- let use_defaults = self.getenv("CRATE_CC_NO_DEFAULTS").is_none();
+ // Disable default flag generation via `no_default_flags` or environment variable
+ let no_defaults = self.no_default_flags || self.getenv("CRATE_CC_NO_DEFAULTS").is_some();
- if use_defaults {
+ if !no_defaults {
self.add_default_flags(&mut cmd, &target, &opt_level)?;
} else {
println!("Info: default compiler flags are disabled");
@@ -1213,12 +1389,22 @@ impl Build {
family.add_debug_flags(cmd);
}
+ if self.get_force_frame_pointer() {
+ let family = cmd.family;
+ family.add_force_frame_pointer(cmd);
+ }
+
// Target flags
match cmd.family {
ToolFamily::Clang => {
cmd.args.push(format!("--target={}", target).into());
}
ToolFamily::Msvc { clang_cl } => {
+ // This is an undocumented flag from MSVC but helps with making
+ // builds more reproducible by avoiding putting timestamps into
+ // files.
+ cmd.args.push("-Brepro".into());
+
if clang_cl {
if target.contains("x86_64") {
cmd.args.push("-m64".into());
@@ -1402,9 +1588,11 @@ impl Build {
if let Some(arch) = parts.next() {
let arch = &arch[5..];
cmd.args.push(("-march=rv".to_owned() + arch).into());
- // ABI is always soft-float right now, update this when this is no longer the
- // case:
- if arch.starts_with("64") {
+ if target.contains("linux") && arch.starts_with("64") {
+ cmd.args.push("-mabi=lp64d".into());
+ } else if target.contains("linux") && arch.starts_with("32") {
+ cmd.args.push("-mabi=ilp32d".into());
+ } else if arch.starts_with("64") {
cmd.args.push("-mabi=lp64".into());
} else {
cmd.args.push("-mabi=ilp32".into());
@@ -1501,6 +1689,9 @@ impl Build {
let mut out = OsString::from("-out:");
out.push(dst);
cmd.arg(out).arg("-nologo");
+ for flag in self.ar_flags.iter() {
+ cmd.arg(flag);
+ }
// Similar to https://github.com/rust-lang/rust/pull/47507
// and https://github.com/rust-lang/rust/pull/48548
@@ -1563,6 +1754,33 @@ impl Build {
};
} else {
let (mut ar, cmd) = self.get_ar()?;
+
+ // Set an environment variable to tell the OSX archiver to ensure
+ // that all dates listed in the archive are zero, improving
+ // determinism of builds. AFAIK there's not really official
+ // documentation of this but there's a lot of references to it if
+ // you search google.
+ //
+ // You can reproduce this locally on a mac with:
+ //
+ // $ touch foo.c
+ // $ cc -c foo.c -o foo.o
+ //
+ // # Notice that these two checksums are different
+ // $ ar crus libfoo1.a foo.o && sleep 2 && ar crus libfoo2.a foo.o
+ // $ md5sum libfoo*.a
+ //
+ // # Notice that these two checksums are the same
+ // $ export ZERO_AR_DATE=1
+ // $ ar crus libfoo1.a foo.o && sleep 2 && touch foo.o && ar crus libfoo2.a foo.o
+ // $ md5sum libfoo*.a
+ //
+ // In any case if this doesn't end up getting read, it shouldn't
+ // cause that many issues!
+ ar.env("ZERO_AR_DATE", "1");
+ for flag in self.ar_flags.iter() {
+ ar.arg(flag);
+ }
run(
ar.arg("crs").arg(dst).args(&objects).args(&self.objects),
&cmd,
@@ -1687,13 +1905,19 @@ impl Build {
let tool_opt: Option<Tool> = self
.env_tool(env)
- .map(|(tool, cc, args)| {
+ .map(|(tool, wrapper, args)| {
+ // find the driver mode, if any
+ const DRIVER_MODE: &str = "--driver-mode=";
+ let driver_mode = args
+ .iter()
+ .find(|a| a.starts_with(DRIVER_MODE))
+ .map(|a| &a[DRIVER_MODE.len()..]);
// chop off leading/trailing whitespace to work around
// semi-buggy build scripts which are shared in
// makefiles/configure scripts (where spaces are far more
// lenient)
- let mut t = Tool::new(PathBuf::from(tool.trim()));
- if let Some(cc) = cc {
+ let mut t = Tool::with_clang_driver(PathBuf::from(tool.trim()), driver_mode);
+ if let Some(cc) = wrapper {
t.cc_wrapper_path = Some(PathBuf::from(cc));
}
for arg in args {
@@ -1846,7 +2070,7 @@ impl Build {
Err(_) => "nvcc".into(),
Ok(nvcc) => nvcc,
};
- let mut nvcc_tool = Tool::with_features(PathBuf::from(nvcc), self.cuda);
+ let mut nvcc_tool = Tool::with_features(PathBuf::from(nvcc), None, self.cuda);
nvcc_tool
.args
.push(format!("-ccbin={}", tool.path.display()).into());
@@ -2062,6 +2286,10 @@ impl Build {
})
}
+ fn get_force_frame_pointer(&self) -> bool {
+ self.force_frame_pointer.unwrap_or_else(|| self.get_debug())
+ }
+
fn get_out_dir(&self) -> Result<PathBuf, Error> {
match self.out_dir.clone() {
Some(p) => Ok(p),
@@ -2109,11 +2337,15 @@ impl Default for Build {
}
impl Tool {
- fn new(path: PathBuf) -> Tool {
- Tool::with_features(path, false)
+ fn new(path: PathBuf) -> Self {
+ Tool::with_features(path, None, false)
}
- fn with_features(path: PathBuf, cuda: bool) -> Tool {
+ fn with_clang_driver(path: PathBuf, clang_driver: Option<&str>) -> Self {
+ Self::with_features(path, clang_driver, false)
+ }
+
+ fn with_features(path: PathBuf, clang_driver: Option<&str>, cuda: bool) -> Self {
// Try to detect family of the tool from its name, falling back to Gnu.
let family = if let Some(fname) = path.file_name().and_then(|p| p.to_str()) {
if fname.contains("clang-cl") {
@@ -2125,13 +2357,17 @@ impl Tool {
{
ToolFamily::Msvc { clang_cl: false }
} else if fname.contains("clang") {
- ToolFamily::Clang
+ match clang_driver {
+ Some("cl") => ToolFamily::Msvc { clang_cl: true },
+ _ => ToolFamily::Clang,
+ }
} else {
ToolFamily::Gnu
}
} else {
ToolFamily::Gnu
};
+
Tool {
path: path,
cc_wrapper_path: None,
diff --git a/cc/src/setup_config.rs b/cc/src/setup_config.rs
index 56fe114..bc2b1c2 100644
--- a/cc/src/setup_config.rs
+++ b/cc/src/setup_config.rs
@@ -8,19 +8,19 @@
#![allow(bad_style)]
#![allow(unused)]
+use crate::winapi::Interface;
+use crate::winapi::BSTR;
+use crate::winapi::LPCOLESTR;
+use crate::winapi::LPSAFEARRAY;
+use crate::winapi::S_FALSE;
+use crate::winapi::{CoCreateInstance, CLSCTX_ALL};
+use crate::winapi::{IUnknown, IUnknownVtbl};
+use crate::winapi::{HRESULT, LCID, LPCWSTR, PULONGLONG};
+use crate::winapi::{LPFILETIME, ULONG};
use std::ffi::OsString;
use std::ptr::null_mut;
-use winapi::Interface;
-use winapi::BSTR;
-use winapi::LPCOLESTR;
-use winapi::LPSAFEARRAY;
-use winapi::S_FALSE;
-use winapi::{CoCreateInstance, CLSCTX_ALL};
-use winapi::{IUnknown, IUnknownVtbl};
-use winapi::{HRESULT, LCID, LPCWSTR, PULONGLONG};
-use winapi::{LPFILETIME, ULONG};
-use com::{BStr, ComPtr};
+use crate::com::{BStr, ComPtr};
// Bindings to the Setup.Configuration stuff
pub type InstanceState = u32;
@@ -196,7 +196,7 @@ impl SetupConfiguration {
}
pub fn enum_all_instances(&self) -> Result<EnumSetupInstances, i32> {
let mut obj = null_mut();
- let this = try!(self.0.cast::<ISetupConfiguration2>());
+ let this = self.0.cast::<ISetupConfiguration2>()?;
let err = unsafe { this.EnumAllInstances(&mut obj) };
if err < 0 {
return Err(err);
@@ -249,7 +249,7 @@ impl SetupInstance {
}
pub fn product_path(&self) -> Result<OsString, i32> {
let mut s = null_mut();
- let this = try!(self.0.cast::<ISetupInstance2>());
+ let this = self.0.cast::<ISetupInstance2>()?;
let err = unsafe { this.GetProductPath(&mut s) };
let bstr = unsafe { BStr::from_raw(s) };
if err < 0 {
diff --git a/cc/src/windows_registry.rs b/cc/src/windows_registry.rs
index ee39339..5af3ff7 100644
--- a/cc/src/windows_registry.rs
+++ b/cc/src/windows_registry.rs
@@ -13,17 +13,7 @@
use std::process::Command;
-use Tool;
-
-#[cfg(windows)]
-macro_rules! otry {
- ($expr:expr) => {
- match $expr {
- Some(val) => val,
- None => return None,
- }
- };
-}
+use crate::Tool;
/// Attempts to find a tool within an MSVC installation using the Windows
/// registry as a point to search from.
@@ -173,9 +163,9 @@ pub fn find_vs_version() -> Result<VsVers, String> {
#[cfg(windows)]
mod impl_ {
- use com;
- use registry::{RegistryKey, LOCAL_MACHINE};
- use setup_config::{EnumSetupInstances, SetupConfiguration, SetupInstance};
+ use crate::com;
+ use crate::registry::{RegistryKey, LOCAL_MACHINE};
+ use crate::setup_config::{EnumSetupInstances, SetupConfiguration, SetupInstance};
use std::env;
use std::ffi::OsString;
use std::fs::File;
@@ -184,7 +174,7 @@ mod impl_ {
use std::mem;
use std::path::{Path, PathBuf};
- use Tool;
+ use crate::Tool;
struct MsvcTool {
tool: PathBuf,
@@ -218,6 +208,7 @@ mod impl_ {
}
}
+ #[allow(bare_trait_objects)]
fn vs16_instances() -> Box<Iterator<Item = PathBuf>> {
let instances = if let Some(instances) = vs15_instances() {
instances
@@ -225,10 +216,10 @@ mod impl_ {
return Box::new(iter::empty());
};
Box::new(instances.filter_map(|instance| {
- let instance = otry!(instance.ok());
- let installation_name = otry!(instance.installation_name().ok());
- if otry!(installation_name.to_str()).starts_with("VisualStudio/16.") {
- Some(PathBuf::from(otry!(instance.installation_path().ok())))
+ let instance = instance.ok()?;
+ let installation_name = instance.installation_name().ok()?;
+ if installation_name.to_str()?.starts_with("VisualStudio/16.") {
+ Some(PathBuf::from(instance.installation_path().ok()?))
} else {
None
}
@@ -263,16 +254,16 @@ mod impl_ {
//
// [online]: https://blogs.msdn.microsoft.com/vcblog/2017/03/06/finding-the-visual-c-compiler-tools-in-visual-studio-2017/
fn vs15_instances() -> Option<EnumSetupInstances> {
- otry!(com::initialize().ok());
+ com::initialize().ok()?;
- let config = otry!(SetupConfiguration::new().ok());
+ let config = SetupConfiguration::new().ok()?;
config.enum_all_instances().ok()
}
pub fn find_msvc_15(tool: &str, target: &str) -> Option<Tool> {
- let iter = otry!(vs15_instances());
+ let iter = vs15_instances()?;
for instance in iter {
- let instance = otry!(instance.ok());
+ let instance = instance.ok()?;
let tool = tool_from_vs15_instance(tool, target, &instance);
if tool.is_some() {
return tool;
@@ -322,8 +313,7 @@ mod impl_ {
}
fn tool_from_vs15_instance(tool: &str, target: &str, instance: &SetupInstance) -> Option<Tool> {
- let (bin_path, host_dylib_path, lib_path, include_path) =
- otry!(vs15_vc_paths(target, instance));
+ let (bin_path, host_dylib_path, lib_path, include_path) = vs15_vc_paths(target, instance)?;
let tool_path = bin_path.join(tool);
if !tool_path.exists() {
return None;
@@ -339,7 +329,7 @@ mod impl_ {
tool.include.push(atl_include_path);
}
- otry!(add_sdks(&mut tool, target));
+ add_sdks(&mut tool, target)?;
Some(tool.into_tool())
}
@@ -348,19 +338,19 @@ mod impl_ {
target: &str,
instance: &SetupInstance,
) -> Option<(PathBuf, PathBuf, PathBuf, PathBuf)> {
- let instance_path: PathBuf = otry!(instance.installation_path().ok()).into();
+ let instance_path: PathBuf = instance.installation_path().ok()?.into();
let version_path =
instance_path.join(r"VC\Auxiliary\Build\Microsoft.VCToolsVersion.default.txt");
- let mut version_file = otry!(File::open(version_path).ok());
+ let mut version_file = File::open(version_path).ok()?;
let mut version = String::new();
- otry!(version_file.read_to_string(&mut version).ok());
+ version_file.read_to_string(&mut version).ok()?;
let version = version.trim();
let host = match host_arch() {
X86 => "X86",
X86_64 => "X64",
_ => return None,
};
- let target = otry!(lib_subdir(target));
+ let target = lib_subdir(target)?;
// The directory layout here is MSVC/bin/Host$host/$target/
let path = instance_path.join(r"VC\Tools\MSVC").join(version);
// This is the path to the toolchain for a particular target, running
@@ -383,7 +373,7 @@ mod impl_ {
fn atl_paths(target: &str, path: &Path) -> Option<(PathBuf, PathBuf)> {
let atl_path = path.join("atlfmc");
- let sub = otry!(lib_subdir(target));
+ let sub = lib_subdir(target)?;
if atl_path.exists() {
Some((atl_path.join("lib").join(sub), atl_path.join("include")))
} else {
@@ -394,15 +384,15 @@ mod impl_ {
// For MSVC 14 we need to find the Universal CRT as well as either
// the Windows 10 SDK or Windows 8.1 SDK.
pub fn find_msvc_14(tool: &str, target: &str) -> Option<Tool> {
- let vcdir = otry!(get_vc_dir("14.0"));
- let mut tool = otry!(get_tool(tool, &vcdir, target));
- otry!(add_sdks(&mut tool, target));
+ let vcdir = get_vc_dir("14.0")?;
+ let mut tool = get_tool(tool, &vcdir, target)?;
+ add_sdks(&mut tool, target)?;
Some(tool.into_tool())
}
fn add_sdks(tool: &mut MsvcTool, target: &str) -> Option<()> {
- let sub = otry!(lib_subdir(target));
- let (ucrt, ucrt_version) = otry!(get_ucrt_dir());
+ let sub = lib_subdir(target)?;
+ let (ucrt, ucrt_version) = get_ucrt_dir()?;
tool.path
.push(ucrt.join("bin").join(&ucrt_version).join(sub));
@@ -437,10 +427,10 @@ mod impl_ {
// For MSVC 12 we need to find the Windows 8.1 SDK.
pub fn find_msvc_12(tool: &str, target: &str) -> Option<Tool> {
- let vcdir = otry!(get_vc_dir("12.0"));
- let mut tool = otry!(get_tool(tool, &vcdir, target));
- let sub = otry!(lib_subdir(target));
- let sdk81 = otry!(get_sdk81_dir());
+ let vcdir = get_vc_dir("12.0")?;
+ let mut tool = get_tool(tool, &vcdir, target)?;
+ let sub = lib_subdir(target)?;
+ let sdk81 = get_sdk81_dir()?;
tool.path.push(sdk81.join("bin").join(sub));
let sdk_lib = sdk81.join("lib").join("winv6.3");
tool.libs.push(sdk_lib.join("um").join(sub));
@@ -453,10 +443,10 @@ mod impl_ {
// For MSVC 11 we need to find the Windows 8 SDK.
pub fn find_msvc_11(tool: &str, target: &str) -> Option<Tool> {
- let vcdir = otry!(get_vc_dir("11.0"));
- let mut tool = otry!(get_tool(tool, &vcdir, target));
- let sub = otry!(lib_subdir(target));
- let sdk8 = otry!(get_sdk8_dir());
+ let vcdir = get_vc_dir("11.0")?;
+ let mut tool = get_tool(tool, &vcdir, target)?;
+ let sub = lib_subdir(target)?;
+ let sdk8 = get_sdk8_dir()?;
tool.path.push(sdk8.join("bin").join(sub));
let sdk_lib = sdk8.join("lib").join("win8");
tool.libs.push(sdk_lib.join("um").join(sub));
@@ -493,7 +483,7 @@ mod impl_ {
tool
})
.filter_map(|mut tool| {
- let sub = otry!(vc_lib_subdir(target));
+ let sub = vc_lib_subdir(target)?;
tool.libs.push(path.join("lib").join(sub));
tool.include.push(path.join("include"));
let atlmfc_path = path.join("atlmfc");
@@ -510,8 +500,8 @@ mod impl_ {
// trying to find.
fn get_vc_dir(ver: &str) -> Option<PathBuf> {
let key = r"SOFTWARE\Microsoft\VisualStudio\SxS\VC7";
- let key = otry!(LOCAL_MACHINE.open(key.as_ref()).ok());
- let path = otry!(key.query_str(ver).ok());
+ let key = LOCAL_MACHINE.open(key.as_ref()).ok()?;
+ let path = key.query_str(ver).ok()?;
Some(path.into())
}
@@ -523,19 +513,20 @@ mod impl_ {
// Returns a pair of (root, version) for the ucrt dir if found
fn get_ucrt_dir() -> Option<(PathBuf, String)> {
let key = r"SOFTWARE\Microsoft\Windows Kits\Installed Roots";
- let key = otry!(LOCAL_MACHINE.open(key.as_ref()).ok());
- let root = otry!(key.query_str("KitsRoot10").ok());
- let readdir = otry!(Path::new(&root).join("lib").read_dir().ok());
- let max_libdir = otry!(readdir
+ let key = LOCAL_MACHINE.open(key.as_ref()).ok()?;
+ let root = key.query_str("KitsRoot10").ok()?;
+ let readdir = Path::new(&root).join("lib").read_dir().ok()?;
+ let max_libdir = readdir
.filter_map(|dir| dir.ok())
.map(|dir| dir.path())
- .filter(|dir| dir
- .components()
- .last()
- .and_then(|c| c.as_os_str().to_str())
- .map(|c| c.starts_with("10.") && dir.join("ucrt").is_dir())
- .unwrap_or(false))
- .max());
+ .filter(|dir| {
+ dir.components()
+ .last()
+ .and_then(|c| c.as_os_str().to_str())
+ .map(|c| c.starts_with("10.") && dir.join("ucrt").is_dir())
+ .unwrap_or(false)
+ })
+ .max()?;
let version = max_libdir.components().last().unwrap();
let version = version.as_os_str().to_str().unwrap().to_string();
Some((root.into(), version))
@@ -551,19 +542,19 @@ mod impl_ {
// asciibetically to find the newest one as that is what vcvars does.
fn get_sdk10_dir() -> Option<(PathBuf, String)> {
let key = r"SOFTWARE\Microsoft\Microsoft SDKs\Windows\v10.0";
- let key = otry!(LOCAL_MACHINE.open(key.as_ref()).ok());
- let root = otry!(key.query_str("InstallationFolder").ok());
- let readdir = otry!(Path::new(&root).join("lib").read_dir().ok());
+ let key = LOCAL_MACHINE.open(key.as_ref()).ok()?;
+ let root = key.query_str("InstallationFolder").ok()?;
+ let readdir = Path::new(&root).join("lib").read_dir().ok()?;
let mut dirs = readdir
.filter_map(|dir| dir.ok())
.map(|dir| dir.path())
.collect::<Vec<_>>();
dirs.sort();
- let dir = otry!(dirs
+ let dir = dirs
.into_iter()
.rev()
.filter(|dir| dir.join("um").join("x64").join("kernel32.lib").is_file())
- .next());
+ .next()?;
let version = dir.components().last().unwrap();
let version = version.as_os_str().to_str().unwrap().to_string();
Some((root.into(), version))
@@ -575,15 +566,15 @@ mod impl_ {
// instead of user mode applications, we would care.
fn get_sdk81_dir() -> Option<PathBuf> {
let key = r"SOFTWARE\Microsoft\Microsoft SDKs\Windows\v8.1";
- let key = otry!(LOCAL_MACHINE.open(key.as_ref()).ok());
- let root = otry!(key.query_str("InstallationFolder").ok());
+ let key = LOCAL_MACHINE.open(key.as_ref()).ok()?;
+ let root = key.query_str("InstallationFolder").ok()?;
Some(root.into())
}
fn get_sdk8_dir() -> Option<PathBuf> {
let key = r"SOFTWARE\Microsoft\Microsoft SDKs\Windows\v8.0";
- let key = otry!(LOCAL_MACHINE.open(key.as_ref()).ok());
- let root = otry!(key.query_str("InstallationFolder").ok());
+ let key = LOCAL_MACHINE.open(key.as_ref()).ok()?;
+ let root = key.query_str("InstallationFolder").ok()?;
Some(root.into())
}
diff --git a/cc/tests/cc_env.rs b/cc/tests/cc_env.rs
index e862fea..43eb689 100644
--- a/cc/tests/cc_env.rs
+++ b/cc/tests/cc_env.rs
@@ -1,12 +1,9 @@
-extern crate cc;
-extern crate tempdir;
-
use std::env;
use std::ffi::OsString;
use std::path::Path;
mod support;
-use support::Test;
+use crate::support::Test;
#[test]
fn main() {
diff --git a/cc/tests/cflags.rs b/cc/tests/cflags.rs
index df6b0a7..caec6ea 100644
--- a/cc/tests/cflags.rs
+++ b/cc/tests/cflags.rs
@@ -1,10 +1,7 @@
-extern crate cc;
-extern crate tempdir;
-
mod support;
+use crate::support::Test;
use std::env;
-use support::Test;
/// This test is in its own module because it modifies the environment and would affect other tests
/// when run in parallel with them.
diff --git a/cc/tests/cxxflags.rs b/cc/tests/cxxflags.rs
index 26426af..c524c7d 100644
--- a/cc/tests/cxxflags.rs
+++ b/cc/tests/cxxflags.rs
@@ -1,10 +1,7 @@
-extern crate cc;
-extern crate tempdir;
-
mod support;
+use crate::support::Test;
use std::env;
-use support::Test;
/// This test is in its own module because it modifies the environment and would affect other tests
/// when run in parallel with them.
diff --git a/cc/tests/support/mod.rs b/cc/tests/support/mod.rs
index 7d74719..fe8acde 100644
--- a/cc/tests/support/mod.rs
+++ b/cc/tests/support/mod.rs
@@ -8,7 +8,7 @@ use std::io::prelude::*;
use std::path::{Path, PathBuf};
use cc;
-use tempdir::TempDir;
+use tempfile::{Builder, TempDir};
pub struct Test {
pub td: TempDir,
@@ -27,7 +27,7 @@ impl Test {
if gcc.ends_with("deps") {
gcc.pop();
}
- let td = TempDir::new_in(&gcc, "gcc-test").unwrap();
+ let td = Builder::new().prefix("gcc-test").tempdir_in(&gcc).unwrap();
gcc.push(format!("gcc-shim{}", env::consts::EXE_SUFFIX));
Test {
td: td,
diff --git a/cc/tests/test.rs b/cc/tests/test.rs
index 74eca1e..def11f0 100644
--- a/cc/tests/test.rs
+++ b/cc/tests/test.rs
@@ -1,7 +1,4 @@
-extern crate cc;
-extern crate tempdir;
-
-use support::Test;
+use crate::support::Test;
mod support;
@@ -42,10 +39,40 @@ fn gnu_opt_level_s() {
}
#[test]
-fn gnu_debug() {
+fn gnu_debug_fp_auto() {
let test = Test::gnu();
test.gcc().debug(true).file("foo.c").compile("foo");
test.cmd(0).must_have("-g");
+ test.cmd(0).must_have("-fno-omit-frame-pointer");
+}
+
+#[test]
+fn gnu_debug_fp() {
+ let test = Test::gnu();
+ test.gcc().debug(true).file("foo.c").compile("foo");
+ test.cmd(0).must_have("-g");
+ test.cmd(0).must_have("-fno-omit-frame-pointer");
+}
+
+#[test]
+fn gnu_debug_nofp() {
+ let test = Test::gnu();
+ test.gcc()
+ .debug(true)
+ .force_frame_pointer(false)
+ .file("foo.c")
+ .compile("foo");
+ test.cmd(0).must_have("-g");
+ test.cmd(0).must_not_have("-fno-omit-frame-pointer");
+
+ let test = Test::gnu();
+ test.gcc()
+ .force_frame_pointer(false)
+ .debug(true)
+ .file("foo.c")
+ .compile("foo");
+ test.cmd(0).must_have("-g");
+ test.cmd(0).must_not_have("-fno-omit-frame-pointer");
}
#[test]