Skip to content

Commit 6f320b9

Browse files
committed
split Tool and ToolFamily to a new tool module
1 parent 6320cf3 commit 6f320b9

File tree

2 files changed

+377
-365
lines changed

2 files changed

+377
-365
lines changed

src/lib.rs

Lines changed: 3 additions & 365 deletions
Original file line numberDiff line numberDiff line change
@@ -184,97 +184,9 @@ impl Display for Error {
184184

185185
impl std::error::Error for Error {}
186186

187-
/// Configuration used to represent an invocation of a C compiler.
188-
///
189-
/// This can be used to figure out what compiler is in use, what the arguments
190-
/// to it are, and what the environment variables look like for the compiler.
191-
/// This can be used to further configure other build systems (e.g. forward
192-
/// along CC and/or CFLAGS) or the `to_command` method can be used to run the
193-
/// compiler itself.
194-
#[derive(Clone, Debug)]
195-
pub struct Tool {
196-
path: PathBuf,
197-
cc_wrapper_path: Option<PathBuf>,
198-
cc_wrapper_args: Vec<OsString>,
199-
args: Vec<OsString>,
200-
env: Vec<(OsString, OsString)>,
201-
family: ToolFamily,
202-
cuda: bool,
203-
removed_args: Vec<OsString>,
204-
has_internal_target_arg: bool,
205-
}
206-
207-
/// Represents the family of tools this tool belongs to.
208-
///
209-
/// Each family of tools differs in how and what arguments they accept.
210-
///
211-
/// Detection of a family is done on best-effort basis and may not accurately reflect the tool.
212-
#[derive(Copy, Clone, Debug, PartialEq)]
213-
enum ToolFamily {
214-
/// Tool is GNU Compiler Collection-like.
215-
Gnu,
216-
/// Tool is Clang-like. It differs from the GCC in a sense that it accepts superset of flags
217-
/// and its cross-compilation approach is different.
218-
Clang,
219-
/// Tool is the MSVC cl.exe.
220-
Msvc { clang_cl: bool },
221-
}
222-
223-
impl ToolFamily {
224-
/// What the flag to request debug info for this family of tools look like
225-
fn add_debug_flags(&self, cmd: &mut Tool, dwarf_version: Option<u32>) {
226-
match *self {
227-
ToolFamily::Msvc { .. } => {
228-
cmd.push_cc_arg("-Z7".into());
229-
}
230-
ToolFamily::Gnu | ToolFamily::Clang => {
231-
cmd.push_cc_arg(
232-
dwarf_version
233-
.map_or_else(|| "-g".into(), |v| format!("-gdwarf-{}", v))
234-
.into(),
235-
);
236-
}
237-
}
238-
}
239-
240-
/// What the flag to force frame pointers.
241-
fn add_force_frame_pointer(&self, cmd: &mut Tool) {
242-
match *self {
243-
ToolFamily::Gnu | ToolFamily::Clang => {
244-
cmd.push_cc_arg("-fno-omit-frame-pointer".into());
245-
}
246-
_ => (),
247-
}
248-
}
249-
250-
/// What the flags to enable all warnings
251-
fn warnings_flags(&self) -> &'static str {
252-
match *self {
253-
ToolFamily::Msvc { .. } => "-W4",
254-
ToolFamily::Gnu | ToolFamily::Clang => "-Wall",
255-
}
256-
}
257-
258-
/// What the flags to enable extra warnings
259-
fn extra_warnings_flags(&self) -> Option<&'static str> {
260-
match *self {
261-
ToolFamily::Msvc { .. } => None,
262-
ToolFamily::Gnu | ToolFamily::Clang => Some("-Wextra"),
263-
}
264-
}
265-
266-
/// What the flag to turn warning into errors
267-
fn warnings_to_errors_flag(&self) -> &'static str {
268-
match *self {
269-
ToolFamily::Msvc { .. } => "-WX",
270-
ToolFamily::Gnu | ToolFamily::Clang => "-Werror",
271-
}
272-
}
273-
274-
fn verbose_stderr(&self) -> bool {
275-
*self == ToolFamily::Clang
276-
}
277-
}
187+
mod tool;
188+
pub use tool::Tool;
189+
use tool::ToolFamily;
278190

279191
/// Represents an object.
280192
///
@@ -3549,280 +3461,6 @@ impl Default for Build {
35493461
}
35503462
}
35513463

3552-
impl Tool {
3553-
fn new(path: PathBuf, cargo_output: &CargoOutput) -> Self {
3554-
Tool::with_features(path, None, false, cargo_output)
3555-
}
3556-
3557-
fn with_clang_driver(
3558-
path: PathBuf,
3559-
clang_driver: Option<&str>,
3560-
cargo_output: &CargoOutput,
3561-
) -> Self {
3562-
Self::with_features(path, clang_driver, false, cargo_output)
3563-
}
3564-
3565-
#[cfg(windows)]
3566-
/// Explicitly set the `ToolFamily`, skipping name-based detection.
3567-
fn with_family(path: PathBuf, family: ToolFamily) -> Self {
3568-
Self {
3569-
path,
3570-
cc_wrapper_path: None,
3571-
cc_wrapper_args: Vec::new(),
3572-
args: Vec::new(),
3573-
env: Vec::new(),
3574-
family,
3575-
cuda: false,
3576-
removed_args: Vec::new(),
3577-
has_internal_target_arg: false,
3578-
}
3579-
}
3580-
3581-
fn with_features(
3582-
path: PathBuf,
3583-
clang_driver: Option<&str>,
3584-
cuda: bool,
3585-
cargo_output: &CargoOutput,
3586-
) -> Self {
3587-
fn detect_family(path: &Path, cargo_output: &CargoOutput) -> ToolFamily {
3588-
let mut cmd = Command::new(path);
3589-
cmd.arg("--version");
3590-
3591-
let stdout = match run_output(
3592-
&mut cmd,
3593-
&path.to_string_lossy(),
3594-
// tool detection issues should always be shown as warnings
3595-
cargo_output,
3596-
)
3597-
.ok()
3598-
.and_then(|o| String::from_utf8(o).ok())
3599-
{
3600-
Some(s) => s,
3601-
None => {
3602-
// --version failed. fallback to gnu
3603-
cargo_output.print_warning(&format_args!("Failed to run: {:?}", cmd));
3604-
return ToolFamily::Gnu;
3605-
}
3606-
};
3607-
if stdout.contains("clang") {
3608-
ToolFamily::Clang
3609-
} else if stdout.contains("GCC") {
3610-
ToolFamily::Gnu
3611-
} else {
3612-
// --version doesn't include clang for GCC
3613-
cargo_output.print_warning(&format_args!(
3614-
"Compiler version doesn't include clang or GCC: {:?}",
3615-
cmd
3616-
));
3617-
ToolFamily::Gnu
3618-
}
3619-
}
3620-
3621-
// Try to detect family of the tool from its name, falling back to Gnu.
3622-
let family = if let Some(fname) = path.file_name().and_then(|p| p.to_str()) {
3623-
if fname.contains("clang-cl") {
3624-
ToolFamily::Msvc { clang_cl: true }
3625-
} else if fname.ends_with("cl") || fname == "cl.exe" {
3626-
ToolFamily::Msvc { clang_cl: false }
3627-
} else if fname.contains("clang") {
3628-
match clang_driver {
3629-
Some("cl") => ToolFamily::Msvc { clang_cl: true },
3630-
_ => ToolFamily::Clang,
3631-
}
3632-
} else {
3633-
detect_family(&path, cargo_output)
3634-
}
3635-
} else {
3636-
detect_family(&path, cargo_output)
3637-
};
3638-
3639-
Tool {
3640-
path,
3641-
cc_wrapper_path: None,
3642-
cc_wrapper_args: Vec::new(),
3643-
args: Vec::new(),
3644-
env: Vec::new(),
3645-
family,
3646-
cuda,
3647-
removed_args: Vec::new(),
3648-
has_internal_target_arg: false,
3649-
}
3650-
}
3651-
3652-
/// Add an argument to be stripped from the final command arguments.
3653-
fn remove_arg(&mut self, flag: OsString) {
3654-
self.removed_args.push(flag);
3655-
}
3656-
3657-
/// Push an "exotic" flag to the end of the compiler's arguments list.
3658-
///
3659-
/// Nvidia compiler accepts only the most common compiler flags like `-D`,
3660-
/// `-I`, `-c`, etc. Options meant specifically for the underlying
3661-
/// host C++ compiler have to be prefixed with `-Xcompiler`.
3662-
/// [Another possible future application for this function is passing
3663-
/// clang-specific flags to clang-cl, which otherwise accepts only
3664-
/// MSVC-specific options.]
3665-
fn push_cc_arg(&mut self, flag: OsString) {
3666-
if self.cuda {
3667-
self.args.push("-Xcompiler".into());
3668-
}
3669-
self.args.push(flag);
3670-
}
3671-
3672-
/// Checks if an argument or flag has already been specified or conflicts.
3673-
///
3674-
/// Currently only checks optimization flags.
3675-
fn is_duplicate_opt_arg(&self, flag: &OsString) -> bool {
3676-
let flag = flag.to_str().unwrap();
3677-
let mut chars = flag.chars();
3678-
3679-
// Only duplicate check compiler flags
3680-
if self.is_like_msvc() {
3681-
if chars.next() != Some('/') {
3682-
return false;
3683-
}
3684-
} else if self.is_like_gnu() || self.is_like_clang() {
3685-
if chars.next() != Some('-') {
3686-
return false;
3687-
}
3688-
}
3689-
3690-
// Check for existing optimization flags (-O, /O)
3691-
if chars.next() == Some('O') {
3692-
return self
3693-
.args()
3694-
.iter()
3695-
.any(|a| a.to_str().unwrap_or("").chars().nth(1) == Some('O'));
3696-
}
3697-
3698-
// TODO Check for existing -m..., -m...=..., /arch:... flags
3699-
false
3700-
}
3701-
3702-
/// Don't push optimization arg if it conflicts with existing args.
3703-
fn push_opt_unless_duplicate(&mut self, flag: OsString) {
3704-
if self.is_duplicate_opt_arg(&flag) {
3705-
println!("Info: Ignoring duplicate arg {:?}", &flag);
3706-
} else {
3707-
self.push_cc_arg(flag);
3708-
}
3709-
}
3710-
3711-
/// Converts this compiler into a `Command` that's ready to be run.
3712-
///
3713-
/// This is useful for when the compiler needs to be executed and the
3714-
/// command returned will already have the initial arguments and environment
3715-
/// variables configured.
3716-
pub fn to_command(&self) -> Command {
3717-
let mut cmd = match self.cc_wrapper_path {
3718-
Some(ref cc_wrapper_path) => {
3719-
let mut cmd = Command::new(cc_wrapper_path);
3720-
cmd.arg(&self.path);
3721-
cmd
3722-
}
3723-
None => Command::new(&self.path),
3724-
};
3725-
cmd.args(&self.cc_wrapper_args);
3726-
3727-
let value = self
3728-
.args
3729-
.iter()
3730-
.filter(|a| !self.removed_args.contains(a))
3731-
.collect::<Vec<_>>();
3732-
cmd.args(&value);
3733-
3734-
for (k, v) in self.env.iter() {
3735-
cmd.env(k, v);
3736-
}
3737-
cmd
3738-
}
3739-
3740-
/// Returns the path for this compiler.
3741-
///
3742-
/// Note that this may not be a path to a file on the filesystem, e.g. "cc",
3743-
/// but rather something which will be resolved when a process is spawned.
3744-
pub fn path(&self) -> &Path {
3745-
&self.path
3746-
}
3747-
3748-
/// Returns the default set of arguments to the compiler needed to produce
3749-
/// executables for the target this compiler generates.
3750-
pub fn args(&self) -> &[OsString] {
3751-
&self.args
3752-
}
3753-
3754-
/// Returns the set of environment variables needed for this compiler to
3755-
/// operate.
3756-
///
3757-
/// This is typically only used for MSVC compilers currently.
3758-
pub fn env(&self) -> &[(OsString, OsString)] {
3759-
&self.env
3760-
}
3761-
3762-
/// Returns the compiler command in format of CC environment variable.
3763-
/// Or empty string if CC env was not present
3764-
///
3765-
/// This is typically used by configure script
3766-
pub fn cc_env(&self) -> OsString {
3767-
match self.cc_wrapper_path {
3768-
Some(ref cc_wrapper_path) => {
3769-
let mut cc_env = cc_wrapper_path.as_os_str().to_owned();
3770-
cc_env.push(" ");
3771-
cc_env.push(self.path.to_path_buf().into_os_string());
3772-
for arg in self.cc_wrapper_args.iter() {
3773-
cc_env.push(" ");
3774-
cc_env.push(arg);
3775-
}
3776-
cc_env
3777-
}
3778-
None => OsString::from(""),
3779-
}
3780-
}
3781-
3782-
/// Returns the compiler flags in format of CFLAGS environment variable.
3783-
/// Important here - this will not be CFLAGS from env, its internal gcc's flags to use as CFLAGS
3784-
/// This is typically used by configure script
3785-
pub fn cflags_env(&self) -> OsString {
3786-
let mut flags = OsString::new();
3787-
for (i, arg) in self.args.iter().enumerate() {
3788-
if i > 0 {
3789-
flags.push(" ");
3790-
}
3791-
flags.push(arg);
3792-
}
3793-
flags
3794-
}
3795-
3796-
/// Whether the tool is GNU Compiler Collection-like.
3797-
pub fn is_like_gnu(&self) -> bool {
3798-
self.family == ToolFamily::Gnu
3799-
}
3800-
3801-
/// Whether the tool is Clang-like.
3802-
pub fn is_like_clang(&self) -> bool {
3803-
self.family == ToolFamily::Clang
3804-
}
3805-
3806-
/// Whether the tool is AppleClang under .xctoolchain
3807-
#[cfg(target_vendor = "apple")]
3808-
fn is_xctoolchain_clang(&self) -> bool {
3809-
let path = self.path.to_string_lossy();
3810-
path.contains(".xctoolchain/")
3811-
}
3812-
#[cfg(not(target_vendor = "apple"))]
3813-
fn is_xctoolchain_clang(&self) -> bool {
3814-
false
3815-
}
3816-
3817-
/// Whether the tool is MSVC-like.
3818-
pub fn is_like_msvc(&self) -> bool {
3819-
match self.family {
3820-
ToolFamily::Msvc { .. } => true,
3821-
_ => false,
3822-
}
3823-
}
3824-
}
3825-
38263464
fn wait_on_child(cmd: &Command, program: &str, child: &mut Child) -> Result<(), Error> {
38273465
let status = match child.wait() {
38283466
Ok(s) => s,

0 commit comments

Comments
 (0)