Browse Source

Add C++ library compilation support.

add-rc-path
KokaKiwi 10 years ago
parent
commit
52f21016dd
  1. 17
      README.md
  2. 60
      src/lib.rs

17
README.md

@ -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 Once gcc is installed, it also requires that the directory containing gcc is in
the PATH environment variable. 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 # License
`gcc-rs` is primarily distributed under the terms of both the MIT license and `gcc-rs` is primarily distributed under the terms of both the MIT license and

60
src/lib.rs

@ -59,6 +59,7 @@ pub struct Config {
objects: Vec<PathBuf>, objects: Vec<PathBuf>,
flags: Vec<String>, flags: Vec<String>,
files: Vec<PathBuf>, files: Vec<PathBuf>,
cpp: bool,
} }
fn getenv(v: &str) -> Option<String> { fn getenv(v: &str) -> Option<String> {
@ -106,6 +107,7 @@ impl Config {
objects: Vec::new(), objects: Vec::new(),
flags: Vec::new(), flags: Vec::new(),
files: Vec::new(), files: Vec::new(),
cpp: false,
} }
} }
@ -139,6 +141,12 @@ impl Config {
self self
} }
/// Set C++ support
pub fn cpp(&mut self, cpp: bool) -> &mut Config {
self.cpp = cpp;
self
}
/// Run the compiler, generating the file `output` /// Run the compiler, generating the file `output`
/// ///
/// The name `output` must begin with `lib` and end with `.a` /// The name `output` must begin with `lib` and end with `.a`
@ -151,11 +159,11 @@ impl Config {
let dst = PathBuf::from(getenv_unwrap("OUT_DIR")); let dst = PathBuf::from(getenv_unwrap("OUT_DIR"));
let mut objects = Vec::new(); let mut objects = Vec::new();
for file in self.files.iter() { 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"); let obj = dst.join(file).with_extension("o");
fs::create_dir_all(&obj.parent().unwrap()).unwrap(); fs::create_dir_all(&obj.parent().unwrap()).unwrap();
run(cmd.arg(&src.join(file)).arg("-o").arg(&obj), run(cmd.arg(&src.join(file)).arg("-o").arg(&obj),
&gcc(&target)); &self.compiler(&target));
objects.push(obj); objects.push(obj);
} }
@ -167,19 +175,35 @@ impl Config {
println!("cargo:rustc-link-search=native={}", dst.display()); println!("cargo:rustc-link-search=native={}", dst.display());
println!("cargo:rustc-link-lib=static={}", println!("cargo:rustc-link-lib=static={}",
&output[3..output.len() - 2]); &output[3..output.len() - 2]);
// Add specific C++ libraries, if enabled.
if self.cpp {
println!("cargo:rustc-link-lib=static=stdc++");
}
}
fn compiler(&self, target: &str) -> String {
let compiler_fn: fn(&str) -> String = if self.cpp { gxx } else { gcc };
compiler_fn(target)
}
fn compile_flags(&self) -> Vec<String> {
let flags_fn: fn() -> Vec<String> = if self.cpp { cxxflags } else { cflags };
flags_fn()
} }
fn gcc(&self) -> Command { fn compile_cmd(&self) -> Command {
let target = getenv_unwrap("TARGET"); let target = getenv_unwrap("TARGET");
let opt_level = getenv_unwrap("OPT_LEVEL"); let opt_level = getenv_unwrap("OPT_LEVEL");
let profile = getenv_unwrap("PROFILE"); let profile = getenv_unwrap("PROFILE");
println!("{} {}", profile, opt_level); println!("{} {}", profile, opt_level);
let mut cmd = Command::new(&gcc(&target)); let mut cmd = Command::new(self.compiler(&target));
cmd.arg(&format!("-O{}", opt_level));
cmd.arg(format!("-O{}", opt_level));
cmd.arg("-c"); cmd.arg("-c");
cmd.arg("-ffunction-sections").arg("-fdata-sections"); cmd.arg("-ffunction-sections").arg("-fdata-sections");
cmd.args(&cflags()); cmd.args(&self.compile_flags());
if target.contains("-ios") { if target.contains("-ios") {
cmd.args(&ios_flags(&target)); cmd.args(&ios_flags(&target));
@ -261,6 +285,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 { fn ar(target: &str) -> String {
let is_android = target.find("android").is_some(); let is_android = target.find("android").is_some();
@ -271,13 +307,21 @@ fn ar(target: &str) -> String {
}) })
} }
fn cflags() -> Vec<String> { fn envflags(name: &str) -> Vec<String> {
get_var("CFLAGS").unwrap_or(String::new()) get_var(name).unwrap_or(String::new())
.split(|c: char| c.is_whitespace()).filter(|s| !s.is_empty()) .split(|c: char| c.is_whitespace()).filter(|s| !s.is_empty())
.map(|s| s.to_string()) .map(|s| s.to_string())
.collect() .collect()
} }
fn cflags() -> Vec<String> {
envflags("CFLAGS")
}
fn cxxflags() -> Vec<String> {
envflags("CXXFLAGS")
}
fn ios_flags(target: &str) -> Vec<String> { fn ios_flags(target: &str) -> Vec<String> {
enum ArchSpec { enum ArchSpec {
Device(&'static str), Device(&'static str),

Loading…
Cancel
Save