Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add rb-sys-env to ease integration pains #99

Merged
merged 8 commits into from
Nov 12, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,6 @@ members = [
"crates/rb-sys",
"crates/rb-sys-tests",
"crates/rb-sys-build",
"crates/rb-sys-env",
]
exclude = ["examples/rust_reverse/ext/rust_reverse"]
exclude = ["examples/rust_reverse/ext/rust_reverse"]
7 changes: 5 additions & 2 deletions crates/rb-sys-build/src/bindings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,15 @@ use std::path::PathBuf;

/// Generate bindings for the Ruby using bindgen.
pub fn generate(rbconfig: &RbConfig, static_ruby: bool) {
let clang_args = vec![
let mut clang_args = vec![
format!("-I{}", rbconfig.get("rubyhdrdir")),
format!("-I{}", rbconfig.get("rubyarchhdrdir")),
"-fms-extensions".to_string(),
];

clang_args.extend(rbconfig.cflags.clone());
clang_args.extend(rbconfig.cppflags());

eprintln!("Using bindgen with clang args: {:?}", clang_args);

let mut src_wrapper_h = File::open("wrapper.h").unwrap();
Expand Down Expand Up @@ -161,7 +164,7 @@ fn push_cargo_cfg_from_bindings() -> Result<(), Box<dyn std::error::Error>> {
let name = val.name().to_lowercase();
let val = val.as_bool();
println!("cargo:rustc-cfg=ruby_{}=\"{}\"", name, val);
println!("cargo:defines_{}=\"{}\"", name, val);
println!("cargo:defines_{}={}", name, val);
}
}

Expand Down
23 changes: 20 additions & 3 deletions crates/rb-sys-build/src/rb_config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use library::*;
use search_path::*;
use std::ffi::OsString;

use crate::utils::{is_msvc, shellsplit};
use crate::utils::{is_msvc, is_mswin_or_mingw, shellsplit};

use self::flags::Flags;

Expand Down Expand Up @@ -155,6 +155,16 @@ impl RbConfig {
self.get("ruby_version")
}

/// Get the CPPFLAGS from the RbConfig, making sure to subsitute variables.
pub fn cppflags(&self) -> Vec<String> {
if let Some(cppflags) = self.get_optional("CPPFLAGS") {
let flags = self.subst_shell_variables(&cppflags);
shellsplit(&flags)
} else {
vec![]
}
}

/// Returns the value of the given key from the either the matching
/// `RBCONFIG_{key}` environment variable or `RbConfig::CONFIG[{key}]` hash.
pub fn get(&self, key: &str) -> String {
Expand Down Expand Up @@ -237,9 +247,16 @@ impl RbConfig {

/// Print to rb_config output for cargo
pub fn print_cargo_args(&self) {
for arg in self.cargo_args() {
let cargo_args = self.cargo_args();

for arg in &cargo_args {
println!("{}", arg);
}

let encoded_cargo_args = cargo_args.join("\x1E");
let encoded_cargo_args = encoded_cargo_args.replace('\n', "\x1F");

println!("cargo:encoded_cargo_args={}", encoded_cargo_args);
}

/// Adds items to the rb_config based on a string from LDFLAGS/DLDFLAGS
Expand Down Expand Up @@ -378,7 +395,7 @@ fn capture_name(regex: &Regex, arg: &str) -> Option<String> {
// Needed because Rust 1.51 does not support link-arg, and thus rpath
// See <https://doc.rust-lang.org/cargo/reference/environment-variables.html#dynamic-library-paths
fn append_ld_library_path(search_paths: Vec<&str>) {
let env_var_name = if cfg!(windows) {
let env_var_name = if is_mswin_or_mingw() {
"PATH"
} else if cfg!(target_os = "macos") {
"DYLD_FALLBACK_LIBRARY_PATH"
Expand Down
9 changes: 9 additions & 0 deletions crates/rb-sys-build/src/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,15 @@ pub fn is_msvc() -> bool {
}
}

/// Check if current platform is mswin or mingw.
pub fn is_mswin_or_mingw() -> bool {
if let Ok(target) = std::env::var("TARGET") {
target.contains("msvc") || target.contains("pc-windows-gnu")
} else {
false
}
}

/// Splits shell words.
pub fn shellsplit(s: &str) -> Vec<String> {
match shell_words::split(s) {
Expand Down
13 changes: 13 additions & 0 deletions crates/rb-sys-env/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
[package]
name = "rb-sys-env"
version = "0.1.0"
edition = "2018"
description = "Integrates rb-sys into high level frameworks"
homepage = "https://github.com/oxidize-rb/rb-sys"
license = "MIT OR Apache-2.0"
repository = "https://github.com/oxidize-rb/rb-sys"
readme = "readme.md"

[lib]
bench = false
doctest = false
119 changes: 119 additions & 0 deletions crates/rb-sys-env/readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
# `rb-sys-env`

Helpers to integrate `rb-sys` into your high-level Ruby bindings library.

## Features

- Provides the neccesary Cargo configuration to ensure that Rust crates compile properly across all platforms
- Sets useful rustc-cfg flags that you can use from your crate
- Exposes all `RbConfig::CONFIG` values from rb-sys

## Usage

Add this to your `Cargo.toml`:

```toml
[build-dependencies]
rb-sys-env = "0.1"
```

Then, in your crate's `build.rs`:

```rust
pub fn main() -> Result<(), Box<dyn std::error::Error>> {
let _rb_env = rb_sys_env::activate()?;

Ok(())
}
```

## Available `rustc-cfg`

Here is an example of the `rustc-cfg` flags that are set by this crate:

- `#[cfg(ruby_have_ruby_re_h)]`
- `#[cfg(ruby_use_rgengc)]`
- `#[cfg(ruby_use_symbol_as_method_name)]`
- `#[cfg(ruby_have_ruby_util_h)]`
- `#[cfg(ruby_have_ruby_oniguruma_h)]`
- `#[cfg(ruby_have_ruby_defines_h)]`
- `#[cfg(ruby_use_flonum)]`
- `#[cfg(ruby_have_ruby_onigmo_h)]`
- `#[cfg(ruby_use_unaligned_member_access)]`
- `#[cfg(ruby_use_transient_heap)]`
- `#[cfg(ruby_have_ruby_atomic_h)]`
- `#[cfg(ruby_have_rb_scan_args_optional_hash)]`
- `#[cfg(ruby_have_rb_data_type_t_parent)]`
- `#[cfg(ruby_have_ruby_debug_h)]`
- `#[cfg(ruby_have_ruby_encoding_h)]`
- `#[cfg(ruby_have_ruby_ruby_h)]`
- `#[cfg(ruby_have_ruby_intern_h)]`
- `#[cfg(ruby_use_mjit)]`
- `#[cfg(ruby_have_rb_data_type_t_function)]`
- `#[cfg(ruby_have_rb_fd_init)]`
- `#[cfg(ruby_have_rb_reg_new_str)]`
- `#[cfg(ruby_have_rb_io_t)]`
- `#[cfg(ruby_have_ruby_memory_view_h)]`
- `#[cfg(ruby_have_ruby_version_h)]`
- `#[cfg(ruby_have_ruby_st_h)]`
- `#[cfg(ruby_have_ruby_thread_native_h)]`
- `#[cfg(ruby_have_ruby_random_h)]`
- `#[cfg(ruby_have_ruby_regex_h)]`
- `#[cfg(ruby_have_rb_define_alloc_func)]`
- `#[cfg(ruby_have_ruby_fiber_scheduler_h)]`
- `#[cfg(ruby_have_ruby_missing_h)]`
- `#[cfg(ruby_have_rb_ext_ractor_safe)]`
- `#[cfg(ruby_have_ruby_thread_h)]`
- `#[cfg(ruby_have_ruby_vm_h)]`
- `#[cfg(ruby_use_rincgc)]`
- `#[cfg(ruby_have_ruby_ractor_h)]`
- `#[cfg(ruby_have_ruby_io_h)]`
- `#[cfg(ruby_3)]`
- `#[cfg(ruby_3_1)]`
- `#[cfg(ruby_3_1_2)]`
- `#[cfg(ruby_gte_2_2)]`
- `#[cfg(ruby_gt_2_2)]`
- `#[cfg(ruby_gte_2_3)]`
- `#[cfg(ruby_gt_2_3)]`
- `#[cfg(ruby_gte_2_4)]`
- `#[cfg(ruby_gt_2_4)]`
- `#[cfg(ruby_gte_2_5)]`
- `#[cfg(ruby_gt_2_5)]`
- `#[cfg(ruby_gte_2_6)]`
- `#[cfg(ruby_gt_2_6)]`
- `#[cfg(ruby_gte_2_7)]`
- `#[cfg(ruby_gt_2_7)]`
- `#[cfg(ruby_gte_3_0)]`
- `#[cfg(ruby_gt_3_0)]`
- `#[cfg(ruby_lte_3_1)]`
- `#[cfg(ruby_3_1)]`
- `#[cfg(ruby_eq_3_1)]`
- `#[cfg(ruby_gte_3_1)]`
- `#[cfg(ruby_lt_3_2)]`
- `#[cfg(ruby_lte_3_2)]`
- `#[cfg(ruby_lt_3_3)]`
- `#[cfg(ruby_lte_3_3)]`
- `#[cfg(ruby_gte_1)]`
- `#[cfg(ruby_gt_1)]`
- `#[cfg(ruby_gte_2)]`
- `#[cfg(ruby_gt_2)]`
- `#[cfg(ruby_lte_3)]`
- `#[cfg(ruby_3)]`
- `#[cfg(ruby_eq_3)]`
- `#[cfg(ruby_gte_3)]`
- `#[cfg(ruby_lt_4)]`
- `#[cfg(ruby_lte_4)]`

## License

Licensed under either of

- Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0)
- MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)

at your option.

### Contribution

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as
defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.
37 changes: 37 additions & 0 deletions crates/rb-sys-env/src/defines.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
use std::{collections::HashMap, rc::Rc};

/// The DEFINES variables from libruby.
#[derive(Debug, Clone)]
pub struct Defines {
raw_environment: Rc<HashMap<String, String>>,
}

impl Defines {
pub(crate) fn from_raw_environment(raw_environment: Rc<HashMap<String, String>>) -> Self {
Self { raw_environment }
}

/// Determines the given key is true.
pub fn is_value_true(&self, key: &str) -> bool {
self.raw_environment
.get(format!("DEFINES_{}", key).as_str())
.map(|v| v == "1" || v == "true")
.unwrap_or(false)
}

/// Fetches the raw value for the given key.
pub fn get_raw_value(&self, key: &str) -> Option<&str> {
self.raw_environment
.get(format!("DEFINES_{}", key).as_str())
.map(|v| v.as_str())
}

pub(crate) fn print_cargo_rustc_cfg(&self) {
for (key, val) in self.raw_environment.iter() {
if key.starts_with("DEFINES_") && val == "true" {
let key = key.trim_start_matches("DEFINES_");
rustc_cfg!("ruby_{}", key.to_lowercase());
}
}
}
}
Loading