1use crate::{Defines, RubyVersion};
2use std::{collections::HashMap, rc::Rc};
3
4const ENV_PREFIX: &str = "DEP_RB_";
5const RBCONFIG_PREFIX: &str = "RBCONFIG_";
6const CARGO_FEATURE_PREFIX: &str = "CARGO_FEATURE_";
7
8#[derive(Debug, Clone)]
10pub struct RbEnv {
11 defines: Defines,
12 vars: Rc<HashMap<String, String>>,
13}
14
15impl RbEnv {
16 pub fn ruby_version(&self) -> RubyVersion {
18 RubyVersion::from_raw_environment(&self.vars)
19 }
20
21 pub fn ruby_major_minor(&self) -> (u8, u8) {
23 self.ruby_version().major_minor()
24 }
25
26 pub fn get_rbconfig_value(&self, key: &str) -> Option<&str> {
28 self.vars
29 .get(&format!("{}{}", RBCONFIG_PREFIX, key))
30 .map(|v| v.as_str())
31 }
32
33 pub fn cargo_features(&self) -> Vec<String> {
35 let keys = self.vars.keys();
36 let keys = keys.filter(|k| k.starts_with(CARGO_FEATURE_PREFIX));
37 let keys = keys.map(|k| k.trim_start_matches(CARGO_FEATURE_PREFIX));
38
39 keys.map(|k| k.replace('_', "-").to_lowercase()).collect()
40 }
41
42 pub fn force_link_ruby(self) -> Self {
44 let libdir = self.vars.get("LIBDIR").expect("DEP_RB_LIBDIR is not set");
45 let lib = self.vars.get("LIB").expect("DEP_RB_LIB is not set");
46
47 println!("cargo:rustc-link-search=native={}", libdir);
48 println!("cargo:rustc-link-lib={}", lib);
49
50 self
51 }
52
53 pub fn encoded_cargo_args(&self) -> Vec<String> {
55 if let Some(raw_args) = self.vars.get("ENCODED_CARGO_ARGS") {
56 let lines = raw_args.split('\x1E');
57 let unescaped = lines.map(|line| line.replace('\x1F', "\n"));
58 unescaped.collect()
59 } else {
60 vec![]
61 }
62 }
63
64 pub fn is_ruby_static(&self) -> bool {
66 self.vars
67 .get("RUBY_STATIC")
68 .map(|v| v == "true")
69 .unwrap_or(false)
70 }
71
72 pub fn print_cargo_rustc_cfg(&self) {
74 self.defines.print_cargo_rustc_cfg();
75 self.ruby_version().print_cargo_rustc_cfg();
76 }
77
78 pub fn print_encoded_cargo_args(&self) {
80 for line in self.encoded_cargo_args() {
81 println!("{}", line);
82 }
83 }
84
85 pub fn print_cargo_rerun_if_changed(&self) {
87 for key in self.vars.keys() {
88 println!("cargo:rerun-if-env-changed={}{}", ENV_PREFIX, key);
89 }
90
91 println!("cargo:rerun-if-changed=build.rs");
92 println!("cargo:rerun-if-env-changed=RB_SYS_ENV_DEBUG");
93 println!("cargo:rerun-if-env-changed=RUBY");
94 println!("cargo:rerun-if-env-changed=RUBY_ROOT");
95 println!("cargo:rerun-if-env-changed=RUBY_VERSION");
96 }
97}
98
99impl Default for RbEnv {
100 fn default() -> Self {
101 let vars = std::env::vars();
102 let vars = vars.filter(|(key, _)| key.starts_with(ENV_PREFIX));
103 let vars = vars.map(|(key, value)| (key.trim_start_matches(ENV_PREFIX).to_string(), value));
104 let vars: HashMap<String, String> = vars.collect();
105 let vars = Rc::new(vars);
106 let defines = Defines::from_raw_environment(vars.clone());
107
108 Self { defines, vars }
109 }
110}