From 0ba241498e4ceccf052ffa91883d53b7cdfb3a85 Mon Sep 17 00:00:00 2001 From: Jordan Rose Date: Thu, 22 Oct 2020 13:34:48 -0700 Subject: [PATCH] Allow controlling the Cargo profile used for macro expansion If there's already a release build, it's better for cbindgen to reuse the build artifacts from that to expand macros rather than starting from scratch with a debug build. Controlled with --profile (debug|release) as well as parse.expand.profile in cbindgen.toml, though hardcoding a profile in a config file seems unlikely. --- Cargo.lock | 83 ++++++++++++++++++++++++++ Cargo.toml | 3 + src/bindgen/builder.rs | 8 ++- src/bindgen/cargo/cargo.rs | 3 + src/bindgen/cargo/cargo_expand.rs | 15 +++++ src/bindgen/config.rs | 25 ++++++++ src/bindgen/mod.rs | 1 + src/bindgen/parser.rs | 7 ++- src/main.rs | 23 ++++++- tests/profile.rs | 99 +++++++++++++++++++++++++++++++ 10 files changed, 264 insertions(+), 3 deletions(-) create mode 100644 tests/profile.rs diff --git a/Cargo.lock b/Cargo.lock index 6fc4ac0..49c6bd9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -44,6 +44,7 @@ dependencies = [ "quote", "serde", "serde_json", + "serial_test", "syn", "tempfile", "toml", @@ -70,6 +71,15 @@ dependencies = [ "vec_map", ] +[[package]] +name = "cloudabi" +version = "0.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" +dependencies = [ + "bitflags", +] + [[package]] name = "getrandom" version = "0.1.15" @@ -121,12 +131,27 @@ version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc6f3ad7b9d11a0c00842ff8de1b60ee58661048eb8049ed33c73594f359d7e6" +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + [[package]] name = "libc" version = "0.2.77" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f2f96b10ec2560088a8e76961b00d47107b3a625fecb76dedb29ee7ccbf98235" +[[package]] +name = "lock_api" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4da24a77a3d8a6d4862d95f72e6fdb9c09a643ecdb402d754004a557f2bec75" +dependencies = [ + "scopeguard", +] + [[package]] name = "log" version = "0.4.11" @@ -136,6 +161,30 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "parking_lot" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3a704eb390aafdc107b0e392f56a82b668e3a71366993b5340f5833fd62505e" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d58c7c768d4ba344e3e8d72518ac13e259d7c7ade24167003b8488e10b6740a3" +dependencies = [ + "cfg-if", + "cloudabi", + "libc", + "redox_syscall", + "smallvec", + "winapi", +] + [[package]] name = "ppv-lite86" version = "0.2.9" @@ -222,6 +271,12 @@ version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + [[package]] name = "serde" version = "1.0.116" @@ -253,6 +308,34 @@ dependencies = [ "serde", ] +[[package]] +name = "serial_test" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b15f74add9a9d4a3eb2bf739c9a427d266d3895b53d992c3a7c234fec2ff1f1" +dependencies = [ + "lazy_static", + "parking_lot", + "serial_test_derive", +] + +[[package]] +name = "serial_test_derive" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65f59259be9fc1bf677d06cc1456e97756004a1a5a577480f71430bd7c17ba33" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "smallvec" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbee7696b84bbf3d89a1c2eccff0850e3047ed46bfcd2e92c29a2d074d57e252" + [[package]] name = "strsim" version = "0.8.0" diff --git a/Cargo.toml b/Cargo.toml index ec1815b..3b2dc71 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -31,6 +31,9 @@ version = "1.0.3" default-features = false features = ["clone-impls", "extra-traits", "full", "parsing", "printing"] +[dev-dependencies] +serial_test = "0.5.0" + [features] default = ["clap"] diff --git a/src/bindgen/builder.rs b/src/bindgen/builder.rs index 3bacfaf..5f984ec 100644 --- a/src/bindgen/builder.rs +++ b/src/bindgen/builder.rs @@ -6,7 +6,7 @@ use std::path; use crate::bindgen::bindings::Bindings; use crate::bindgen::cargo::Cargo; -use crate::bindgen::config::{Braces, Config, Language, Style}; +use crate::bindgen::config::{Braces, Config, Language, Profile, Style}; use crate::bindgen::error::Error; use crate::bindgen::library::Library; use crate::bindgen::parser::{self, Parse}; @@ -225,6 +225,12 @@ impl Builder { self } + #[allow(unused)] + pub fn with_parse_expand_profile(mut self, profile: Profile) -> Builder { + self.config.parse.expand.profile = profile; + self + } + #[allow(unused)] pub fn with_documentation(mut self, documentation: bool) -> Builder { self.config.documentation = documentation; diff --git a/src/bindgen/cargo/cargo.rs b/src/bindgen/cargo/cargo.rs index 0c85cc2..4bfb5de 100644 --- a/src/bindgen/cargo/cargo.rs +++ b/src/bindgen/cargo/cargo.rs @@ -11,6 +11,7 @@ use crate::bindgen::cargo::cargo_metadata::{self, Metadata}; use crate::bindgen::cargo::cargo_toml; use crate::bindgen::error::Error; use crate::bindgen::ir::Cfg; +pub(crate) use cargo_expand::Profile; /// Parse a dependency string used in Cargo.lock fn parse_dep_string(dep_string: &str) -> (&str, Option<&str>) { @@ -233,6 +234,7 @@ impl Cargo { expand_all_features: bool, expand_default_features: bool, expand_features: &Option>, + profile: Profile, ) -> Result { cargo_expand::expand( &self.manifest_path, @@ -242,6 +244,7 @@ impl Cargo { expand_all_features, expand_default_features, expand_features, + profile, ) } } diff --git a/src/bindgen/cargo/cargo_expand.rs b/src/bindgen/cargo/cargo_expand.rs index 0fcf3bd..df2dc54 100644 --- a/src/bindgen/cargo/cargo_expand.rs +++ b/src/bindgen/cargo/cargo_expand.rs @@ -24,6 +24,14 @@ pub enum Error { Compile(String), } +/// Which Cargo profile (group) to use when expanding macros. +pub enum Profile { + /// Do not pass `--release` when expanding macros + Debug, + /// Pass `--release` when expanding macros + Release, +} + impl From for Error { fn from(err: io::Error) -> Self { Error::Io(err) @@ -65,6 +73,7 @@ pub fn expand( expand_all_features: bool, expand_default_features: bool, expand_features: &Option>, + profile: Profile, ) -> Result { let cargo = env::var("CARGO").unwrap_or_else(|_| String::from("cargo")); let mut cmd = Command::new(cargo); @@ -108,6 +117,12 @@ pub fn expand( if !expand_default_features { cmd.arg("--no-default-features"); } + match profile { + Profile::Debug => {} + Profile::Release => { + cmd.arg("--release"); + } + } cmd.arg("-p"); let mut package = crate_name.to_owned(); if let Some(version) = version { diff --git a/src/bindgen/config.rs b/src/bindgen/config.rs index 5ef3f4c..011ef5f 100644 --- a/src/bindgen/config.rs +++ b/src/bindgen/config.rs @@ -668,6 +668,27 @@ pub struct MacroExpansionConfig { pub bitflags: bool, } +/// Controls which Cargo profile is used for macro expansion. +#[derive(Debug, Copy, Clone, PartialEq)] +pub enum Profile { + Debug, + Release, +} + +impl FromStr for Profile { + type Err = String; + + fn from_str(s: &str) -> Result { + match s { + "debug" | "Debug" => Ok(Profile::Debug), + "release" | "Release" => Ok(Profile::Release), + _ => Err(format!("Unrecognized Profile: '{}'.", s)), + } + } +} + +deserialize_enum_str!(Profile); + /// Settings to apply when running `rustc --pretty=expanded` #[derive(Debug, Clone, Deserialize)] #[serde(rename_all = "snake_case")] @@ -683,6 +704,8 @@ pub struct ParseExpandConfig { /// List of features to use when expanding. Combines with `default_features` like in /// `Cargo.toml`. pub features: Option>, + /// Controls whether or not to pass `--release` when expanding. + pub profile: Profile, } impl Default for ParseExpandConfig { @@ -692,6 +715,7 @@ impl Default for ParseExpandConfig { all_features: false, default_features: true, features: None, + profile: Profile::Debug, } } } @@ -723,6 +747,7 @@ fn retrocomp_parse_expand_config_deserialize<'de, D: Deserializer<'de>>( all_features: true, default_features: true, features: None, + profile: Profile::Debug, }) } diff --git a/src/bindgen/mod.rs b/src/bindgen/mod.rs index 85b3f22..d0789da 100644 --- a/src/bindgen/mod.rs +++ b/src/bindgen/mod.rs @@ -60,5 +60,6 @@ pub(crate) use self::cargo::*; pub use self::bindings::Bindings; pub use self::builder::Builder; +pub use self::config::Profile; // disambiguate with cargo::Profile pub use self::config::*; pub use self::error::Error; diff --git a/src/bindgen/parser.rs b/src/bindgen/parser.rs index 8c985b0..138fb27 100644 --- a/src/bindgen/parser.rs +++ b/src/bindgen/parser.rs @@ -9,8 +9,9 @@ use std::io::Read; use std::path::{Path as FilePath, PathBuf as FilePathBuf}; use crate::bindgen::bitflags; +use crate::bindgen::cargo; use crate::bindgen::cargo::{Cargo, PackageRef}; -use crate::bindgen::config::{Config, ParseConfig}; +use crate::bindgen::config::{Config, ParseConfig, Profile}; use crate::bindgen::error::Error; use crate::bindgen::ir::{ AnnotationSet, Cfg, Constant, Documentation, Enum, Function, GenericParams, ItemMap, @@ -191,6 +192,10 @@ impl<'a> Parser<'a> { self.config.parse.expand.all_features, self.config.parse.expand.default_features, &self.config.parse.expand.features, + match self.config.parse.expand.profile { + Profile::Debug => cargo::Profile::Debug, + Profile::Release => cargo::Profile::Release, + }, ) .map_err(|x| Error::CargoExpand(pkg.name.clone(), x))?; let i = syn::parse_file(&s).map_err(|x| Error::ParseSyntaxError { diff --git a/src/main.rs b/src/main.rs index 69c1ebd..3cf1ef2 100644 --- a/src/main.rs +++ b/src/main.rs @@ -5,6 +5,7 @@ use std::env; use std::io; use std::path::{Path, PathBuf}; +use std::str::FromStr; extern crate clap; #[macro_use] @@ -24,7 +25,7 @@ use clap::{App, Arg, ArgMatches}; mod bindgen; mod logging; -use crate::bindgen::{Bindings, Builder, Cargo, Config, Error, Language, Style}; +use crate::bindgen::{Bindings, Builder, Cargo, Config, Error, Language, Profile, Style}; fn apply_config_overrides<'a>(config: &mut Config, matches: &ArgMatches<'a>) { // We allow specifying a language to override the config default. This is @@ -61,6 +62,16 @@ fn apply_config_overrides<'a>(config: &mut Config, matches: &ArgMatches<'a>) { } } + if let Some(profile) = matches.value_of("profile") { + config.parse.expand.profile = match Profile::from_str(profile) { + Ok(p) => p, + Err(e) => { + error!("{}", e); + return; + } + } + } + if matches.is_present("d") { config.parse.parse_deps = true; } @@ -226,6 +237,16 @@ fn main() { ) .required(false), ) + .arg( + Arg::with_name("profile") + .long("profile") + .value_name("PROFILE") + .help( + "Specify the profile to use when expanding macros. \ + Has no effect otherwise." + ) + .possible_values(&["Debug", "debug", "Release", "release"]), + ) .arg( Arg::with_name("quiet") .short("q") diff --git a/tests/profile.rs b/tests/profile.rs new file mode 100644 index 0000000..08330fe --- /dev/null +++ b/tests/profile.rs @@ -0,0 +1,99 @@ +use cbindgen::*; + +use serial_test::serial; +use std::path::{Path, PathBuf}; +use std::process::Command; + +fn build_using_lib(config: fn(Builder) -> Builder) -> tempfile::TempDir { + let expand_dep_test_dir = { + let mut this_file = PathBuf::from(file!()); + this_file.pop(); + this_file.extend(&["rust", "expand_dep"]); + this_file + }; + + let tmp_dir = tempfile::Builder::new() + .prefix("cbindgen-test-output-") + .tempdir() + .expect("Creating tmp dir failed"); + + std::env::set_var("CARGO_EXPAND_TARGET_DIR", tmp_dir.path()); + let builder = Builder::new() + .with_config(Config::from_file(expand_dep_test_dir.join("cbindgen.toml")).unwrap()) + .with_crate(expand_dep_test_dir); + let builder = config(builder); + builder.generate().expect("build should succeed"); + + tmp_dir +} + +fn build_using_bin(extra_args: &[&str]) -> tempfile::TempDir { + let expand_dep_test_dir = { + let mut this_file = PathBuf::from(file!()); + this_file.pop(); + this_file.extend(&["rust", "expand_dep"]); + this_file + }; + + let tmp_dir = tempfile::Builder::new() + .prefix("cbindgen-test-output-") + .tempdir() + .expect("Creating tmp dir failed"); + + let cbindgen_path = env!("CARGO_BIN_EXE_cbindgen"); + Command::new(cbindgen_path) + .current_dir(expand_dep_test_dir) + .env("CARGO_EXPAND_TARGET_DIR", tmp_dir.path()) + .args(extra_args) + .output() + .expect("build should succed"); + + tmp_dir +} + +fn get_contents_of_dir(path: &Path) -> Vec { + path.read_dir() + .unwrap() + .map(|f| f.unwrap().file_name().to_str().unwrap().to_string()) + .filter(|name| !name.starts_with(".")) + .collect() +} + +#[test] +#[serial] +fn lib_default_uses_debug_build() { + let target_dir = build_using_lib(|b| b); + assert_eq!(get_contents_of_dir(target_dir.path()), &["debug"]); +} + +#[test] +#[serial] +fn lib_explicit_debug_build() { + let target_dir = build_using_lib(|b| b.with_parse_expand_profile(Profile::Debug)); + assert_eq!(get_contents_of_dir(target_dir.path()), &["debug"]); +} + +#[test] +#[serial] +fn lib_explicit_release_build() { + let target_dir = build_using_lib(|b| b.with_parse_expand_profile(Profile::Release)); + assert_eq!(get_contents_of_dir(target_dir.path()), &["release"]); +} + +#[test] +fn bin_default_uses_debug_build() { + let target_dir = build_using_bin(&[]); + assert_eq!(get_contents_of_dir(target_dir.path()), &["debug"]); +} + +#[test] +fn bin_explicit_debug_build() { + let target_dir = build_using_bin(&["--profile", "debug"]); + assert_eq!(get_contents_of_dir(target_dir.path()), &["debug"]); +} + +#[test] +fn bin_explicit_release_build() { + let target_dir = build_using_bin(&["--profile", "release"]); + assert_eq!(get_contents_of_dir(target_dir.path()), &["release"]); +}