From 52f21016dd9c00b38b2e790c01fb2141b805cc73 Mon Sep 17 00:00:00 2001 From: KokaKiwi Date: Thu, 26 Mar 2015 21:52:38 +0100 Subject: [PATCH] Add C++ library compilation support. --- README.md | 17 ++++++++++++++++ src/lib.rs | 60 ++++++++++++++++++++++++++++++++++++++++++++++-------- 2 files changed, 69 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 42fb496..f4ad104 100644 --- a/README.md +++ b/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 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 diff --git a/src/lib.rs b/src/lib.rs index 460ca98..5eef212 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -59,6 +59,7 @@ pub struct Config { objects: Vec, flags: Vec, files: Vec, + cpp: bool, } fn getenv(v: &str) -> Option { @@ -106,6 +107,7 @@ impl Config { objects: Vec::new(), flags: Vec::new(), files: Vec::new(), + cpp: false, } } @@ -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` @@ -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); } @@ -167,19 +175,35 @@ 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=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 { + let flags_fn: fn() -> Vec = if self.cpp { cxxflags } else { cflags }; + flags_fn() } - fn gcc(&self) -> Command { + 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)); @@ -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 { let is_android = target.find("android").is_some(); @@ -271,13 +307,21 @@ fn ar(target: &str) -> String { }) } -fn cflags() -> Vec { - get_var("CFLAGS").unwrap_or(String::new()) +fn envflags(name: &str) -> Vec { + 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 { + envflags("CFLAGS") +} + +fn cxxflags() -> Vec { + envflags("CXXFLAGS") +} + fn ios_flags(target: &str) -> Vec { enum ArchSpec { Device(&'static str),