Skip to content

Commit

Permalink
Merge pull request #31 from KokaKiwi/gxx
Browse files Browse the repository at this point in the history
Add C++ library compilation support.
  • Loading branch information
alexcrichton committed Mar 30, 2015
2 parents 15ba0d1 + a09c6ca commit 2ef6d2d
Show file tree
Hide file tree
Showing 2 changed files with 75 additions and 8 deletions.
17 changes: 17 additions & 0 deletions README.md
Expand Up @@ -55,6 +55,23 @@ architecture corresponding to your installation of rustc.
Once gcc is installed, it also requires that the directory containing gcc is in
the PATH environment variable.

# C++ support

`gcc-rs` supports C++ libraries compilation by using the `cpp` method on `Config`:

```rust,no_run
extern crate gcc;
fn main() {
gcc::Config::new()
.cpp(true) // Switch to C++ library compilation.
.file("foo.cpp")
.compile("libfoo.a");
}
```

When using C++ library compilation switch, the `CXX` and `CXXFLAGS` env variables are used instead of `CC` and `CFLAGS` and the C++ standard library is linked to the crate target.

# License

`gcc-rs` is primarily distributed under the terms of both the MIT license and
Expand Down
66 changes: 58 additions & 8 deletions src/lib.rs
Expand Up @@ -59,6 +59,7 @@ pub struct Config {
objects: Vec<PathBuf>,
flags: Vec<String>,
files: Vec<PathBuf>,
cpp: bool,
}

fn getenv(v: &str) -> Option<String> {
Expand Down Expand Up @@ -106,6 +107,7 @@ impl Config {
objects: Vec::new(),
flags: Vec::new(),
files: Vec::new(),
cpp: false,
}
}

Expand Down Expand Up @@ -139,6 +141,12 @@ impl Config {
self
}

/// Set C++ support
pub fn cpp(&mut self, cpp: bool) -> &mut Config {
self.cpp = cpp;
self
}

/// Run the compiler, generating the file `output`
///
/// The name `output` must begin with `lib` and end with `.a`
Expand All @@ -151,11 +159,11 @@ impl Config {
let dst = PathBuf::from(getenv_unwrap("OUT_DIR"));
let mut objects = Vec::new();
for file in self.files.iter() {
let mut cmd = self.gcc();
let mut cmd = self.compile_cmd();
let obj = dst.join(file).with_extension("o");
fs::create_dir_all(&obj.parent().unwrap()).unwrap();
run(cmd.arg(&src.join(file)).arg("-o").arg(&obj),
&gcc(&target));
&self.compiler(&target));
objects.push(obj);
}

Expand All @@ -167,19 +175,41 @@ impl Config {
println!("cargo:rustc-link-search=native={}", dst.display());
println!("cargo:rustc-link-lib=static={}",
&output[3..output.len() - 2]);

// Add specific C++ libraries, if enabled.
if self.cpp {
println!("cargo:rustc-link-lib=stdc++");
}
}

fn compiler(&self, target: &str) -> String {
if self.cpp {
gxx(target)
} else {
gcc(target)
}
}

fn gcc(&self) -> Command {
fn compile_flags(&self) -> Vec<String> {
if self.cpp {
cxxflags()
} else {
cflags()
}
}

fn compile_cmd(&self) -> Command {
let target = getenv_unwrap("TARGET");
let opt_level = getenv_unwrap("OPT_LEVEL");
let profile = getenv_unwrap("PROFILE");
println!("{} {}", profile, opt_level);

let mut cmd = Command::new(&gcc(&target));
cmd.arg(&format!("-O{}", opt_level));
let mut cmd = Command::new(self.compiler(&target));

cmd.arg(format!("-O{}", opt_level));
cmd.arg("-c");
cmd.arg("-ffunction-sections").arg("-fdata-sections");
cmd.args(&cflags());
cmd.args(&self.compile_flags());

if target.contains("-ios") {
cmd.args(&ios_flags(&target));
Expand Down Expand Up @@ -261,6 +291,18 @@ fn gcc(target: &str) -> String {
})
}

fn gxx(target: &str) -> String {
let is_android = target.find("android").is_some();

get_var("CXX").unwrap_or(if cfg!(windows) {
"g++".to_string()
} else if is_android {
format!("{}-g++", target)
} else {
"c++".to_string()
})
}

fn ar(target: &str) -> String {
let is_android = target.find("android").is_some();

Expand All @@ -271,13 +313,21 @@ fn ar(target: &str) -> String {
})
}

fn cflags() -> Vec<String> {
get_var("CFLAGS").unwrap_or(String::new())
fn envflags(name: &str) -> Vec<String> {
get_var(name).unwrap_or(String::new())
.split(|c: char| c.is_whitespace()).filter(|s| !s.is_empty())
.map(|s| s.to_string())
.collect()
}

fn cflags() -> Vec<String> {
envflags("CFLAGS")
}

fn cxxflags() -> Vec<String> {
envflags("CXXFLAGS")
}

fn ios_flags(target: &str) -> Vec<String> {
enum ArchSpec {
Device(&'static str),
Expand Down

0 comments on commit 2ef6d2d

Please sign in to comment.