blob: 799c36b10499921d3c23f0648f1136bf9b2ac7cf [file] [log] [blame]
use std::env;
use std::path::Path;
use std::process::Command;
use crate::{bin_name, cygpath_windows, handle_failed_output, is_msvc, is_windows, tmp_dir, uname};
/// Construct a new platform-specific C compiler invocation.
///
/// WARNING: This means that what flags are accepted by the underlying C compiler is
/// platform- AND compiler-specific. Consult the relevant docs for `gcc`, `clang` and `mvsc`.
pub fn cc() -> Cc {
Cc::new()
}
/// A platform-specific C compiler invocation builder. The specific C compiler used is
/// passed down from compiletest.
#[derive(Debug)]
pub struct Cc {
cmd: Command,
}
crate::impl_common_helpers!(Cc);
impl Cc {
/// Construct a new platform-specific C compiler invocation.
///
/// WARNING: This means that what flags are accepted by the underlying C compile is
/// platform- AND compiler-specific. Consult the relevant docs for `gcc`, `clang` and `mvsc`.
pub fn new() -> Self {
let compiler = env::var("CC").unwrap();
let mut cmd = Command::new(compiler);
let default_cflags = env::var("CC_DEFAULT_FLAGS").unwrap();
for flag in default_cflags.split(char::is_whitespace) {
cmd.arg(flag);
}
Self { cmd }
}
/// Specify path of the input file.
pub fn input<P: AsRef<Path>>(&mut self, path: P) -> &mut Self {
self.cmd.arg(path.as_ref());
self
}
/// Adds directories to the list that the linker searches for libraries.
/// Equivalent to `-L`.
pub fn library_search_path<P: AsRef<Path>>(&mut self, path: P) -> &mut Self {
self.cmd.arg("-L");
self.cmd.arg(path.as_ref());
self
}
/// Specify `-o` or `-Fe`/`-Fo` depending on platform/compiler. This assumes that the executable
/// is under `$TMPDIR`.
pub fn out_exe(&mut self, name: &str) -> &mut Self {
// Ref: tools.mk (irrelevant lines omitted):
//
// ```makefile
// ifdef IS_MSVC
// OUT_EXE=-Fe:`cygpath -w $(TMPDIR)/$(call BIN,$(1))` \
// -Fo:`cygpath -w $(TMPDIR)/$(1).obj`
// else
// OUT_EXE=-o $(TMPDIR)/$(1)
// endif
// ```
if is_msvc() {
let fe_path = cygpath_windows(tmp_dir().join(bin_name(name)));
let fo_path = cygpath_windows(tmp_dir().join(format!("{name}.obj")));
self.cmd.arg(format!("-Fe:{fe_path}"));
self.cmd.arg(format!("-Fo:{fo_path}"));
} else {
self.cmd.arg("-o");
self.cmd.arg(tmp_dir().join(name));
}
self
}
/// Get the [`Output`][::std::process::Output] of the finished process.
pub fn command_output(&mut self) -> ::std::process::Output {
self.cmd.output().expect("failed to get output of finished process")
}
}
/// `EXTRACFLAGS`
pub fn extra_c_flags() -> Vec<&'static str> {
// Adapted from tools.mk (trimmed):
//
// ```makefile
// ifdef IS_WINDOWS
// ifdef IS_MSVC
// EXTRACFLAGS := ws2_32.lib userenv.lib advapi32.lib bcrypt.lib ntdll.lib synchronization.lib
// else
// EXTRACFLAGS := -lws2_32 -luserenv -lbcrypt -lntdll -lsynchronization
// endif
// else
// ifeq ($(UNAME),Darwin)
// EXTRACFLAGS := -lresolv
// else
// ifeq ($(UNAME),FreeBSD)
// EXTRACFLAGS := -lm -lpthread -lgcc_s
// else
// ifeq ($(UNAME),SunOS)
// EXTRACFLAGS := -lm -lpthread -lposix4 -lsocket -lresolv
// else
// ifeq ($(UNAME),OpenBSD)
// EXTRACFLAGS := -lm -lpthread -lc++abi
// else
// EXTRACFLAGS := -lm -lrt -ldl -lpthread
// endif
// endif
// endif
// endif
// endif
// ```
if is_windows() {
if is_msvc() {
vec![
"ws2_32.lib",
"userenv.lib",
"advapi32.lib",
"bcrypt.lib",
"ntdll.lib",
"synchronization.lib",
]
} else {
vec!["-lws2_32", "-luserenv", "-lbcrypt", "-lntdll", "-lsynchronization"]
}
} else {
match uname() {
n if n.contains("Darwin") => vec!["-lresolv"],
n if n.contains("FreeBSD") => vec!["-lm", "-lpthread", "-lgcc_s"],
n if n.contains("SunOS") => {
vec!["-lm", "-lpthread", "-lposix4", "-lsocket", "-lresolv"]
}
n if n.contains("OpenBSD") => vec!["-lm", "-lpthread", "-lc++abi"],
_ => vec!["-lm", "-lrt", "-ldl", "-lpthread"],
}
}
}
/// `EXTRACXXFLAGS`
pub fn extra_cxx_flags() -> Vec<&'static str> {
// Adapted from tools.mk (trimmed):
//
// ```makefile
// ifdef IS_WINDOWS
// ifdef IS_MSVC
// else
// EXTRACXXFLAGS := -lstdc++
// endif
// else
// ifeq ($(UNAME),Darwin)
// EXTRACXXFLAGS := -lc++
// else
// ifeq ($(UNAME),FreeBSD)
// else
// ifeq ($(UNAME),SunOS)
// else
// ifeq ($(UNAME),OpenBSD)
// else
// EXTRACXXFLAGS := -lstdc++
// endif
// endif
// endif
// endif
// endif
// ```
if is_windows() {
if is_msvc() { vec![] } else { vec!["-lstdc++"] }
} else {
match &uname()[..] {
"Darwin" => vec!["-lc++"],
"FreeBSD" | "SunOS" | "OpenBSD" => vec![],
_ => vec!["-lstdc++"],
}
}
}