run_make_support/external_deps/c_cxx_compiler/
cc.rs

1use std::path::Path;
2
3use crate::command::Command;
4use crate::{env_var, is_msvc};
5
6/// Construct a new platform-specific C compiler invocation.
7///
8/// WARNING: This means that what flags are accepted by the underlying C compiler is
9/// platform- AND compiler-specific. Consult the relevant docs for `gcc`, `clang` and `mvsc`.
10#[track_caller]
11pub fn cc() -> Cc {
12    Cc::new()
13}
14
15/// Construct a new platform-specific CXX compiler invocation.
16/// CXX_DEFAULT_FLAGS is passed from compiletest.
17#[track_caller]
18pub fn cxx() -> Cc {
19    Cc::new_cxx()
20}
21
22/// A platform-specific C compiler invocation builder. The specific C compiler used is
23/// passed down from compiletest.
24#[derive(Debug)]
25#[must_use]
26pub struct Cc {
27    cmd: Command,
28}
29
30crate::macros::impl_common_helpers!(Cc);
31
32impl Cc {
33    /// Construct a new platform-specific C compiler invocation.
34    ///
35    /// WARNING: This means that what flags are accepted by the underlying C compile is
36    /// platform- AND compiler-specific. Consult the relevant docs for `gcc`, `clang` and `mvsc`.
37    #[track_caller]
38    pub fn new() -> Self {
39        let compiler = env_var("CC");
40
41        let mut cmd = Command::new(compiler);
42
43        let default_cflags = env_var("CC_DEFAULT_FLAGS");
44        for flag in default_cflags.split(char::is_whitespace) {
45            cmd.arg(flag);
46        }
47
48        Self { cmd }
49    }
50
51    /// Construct a new platform-specific CXX compiler invocation.
52    /// CXX_DEFAULT_FLAGS is passed from compiletest.
53    #[track_caller]
54    pub fn new_cxx() -> Self {
55        let compiler = env_var("CXX");
56
57        let mut cmd = Command::new(compiler);
58
59        let default_cflags = env_var("CXX_DEFAULT_FLAGS");
60        for flag in default_cflags.split(char::is_whitespace) {
61            cmd.arg(flag);
62        }
63
64        Self { cmd }
65    }
66
67    /// Specify path of the input file.
68    pub fn input<P: AsRef<Path>>(&mut self, path: P) -> &mut Self {
69        self.cmd.arg(path.as_ref());
70        self
71    }
72
73    /// Adds directories to the list that the linker searches for libraries.
74    /// Equivalent to `-L`.
75    pub fn library_search_path<P: AsRef<Path>>(&mut self, path: P) -> &mut Self {
76        self.cmd.arg("-L");
77        self.cmd.arg(path.as_ref());
78        self
79    }
80
81    /// Specify `-o` or `-Fe`/`-Fo` depending on platform/compiler.
82    pub fn out_exe(&mut self, name: &str) -> &mut Self {
83        // Ref: tools.mk (irrelevant lines omitted):
84        //
85        // ```makefile
86        // ifdef IS_MSVC
87        //     OUT_EXE=-Fe:`cygpath -w $(TMPDIR)/$(call BIN,$(1))` \
88        //         -Fo:`cygpath -w $(TMPDIR)/$(1).obj`
89        // else
90        //     OUT_EXE=-o $(TMPDIR)/$(1)
91        // endif
92        // ```
93
94        let mut path = std::path::PathBuf::from(name);
95
96        if is_msvc() {
97            path.set_extension("exe");
98            let fe_path = path.clone();
99            path.set_extension("");
100            path.set_extension("obj");
101            let fo_path = path;
102            self.cmd.arg(format!("-Fe:{}", fe_path.to_str().unwrap()));
103            self.cmd.arg(format!("-Fo:{}", fo_path.to_str().unwrap()));
104        } else {
105            self.cmd.arg("-o");
106            self.cmd.arg(name);
107        }
108
109        self
110    }
111
112    /// Specify path of the output binary.
113    pub fn output<P: AsRef<Path>>(&mut self, path: P) -> &mut Self {
114        self.cmd.arg("-o");
115        self.cmd.arg(path.as_ref());
116        self
117    }
118
119    /// Optimize the output.
120    /// Equivalent to `-O3` for GNU-compatible linkers or `-O2` for MSVC linkers.
121    pub fn optimize(&mut self) -> &mut Self {
122        if is_msvc() {
123            self.cmd.arg("-O2");
124        } else {
125            self.cmd.arg("-O3");
126        }
127        self
128    }
129}