itsi-server 0.2.21 → 0.2.23

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. checksums.yaml +4 -4
  2. data/Cargo.lock +25 -38
  3. data/Cargo.toml +4 -0
  4. data/Rakefile +39 -7
  5. data/ext/itsi_scheduler/Cargo.toml +1 -1
  6. data/ext/itsi_server/Cargo.lock +2 -2
  7. data/ext/itsi_server/Cargo.toml +1 -1
  8. data/ext/itsi_server/src/server/middleware_stack/mod.rs +3 -9
  9. data/ext/itsi_server/src/server/signal.rs +7 -5
  10. data/ext/itsi_server/src/services/itsi_http_service.rs +5 -8
  11. data/lib/itsi/server/native_extension.rb +34 -0
  12. data/lib/itsi/server/version.rb +1 -1
  13. data/lib/itsi/server.rb +10 -2
  14. data/vendor/rb-sys-build/.cargo-ok +1 -0
  15. data/vendor/rb-sys-build/.cargo_vcs_info.json +6 -0
  16. data/vendor/rb-sys-build/Cargo.lock +294 -0
  17. data/vendor/rb-sys-build/Cargo.toml +71 -0
  18. data/vendor/rb-sys-build/Cargo.toml.orig +32 -0
  19. data/vendor/rb-sys-build/LICENSE-APACHE +190 -0
  20. data/vendor/rb-sys-build/LICENSE-MIT +21 -0
  21. data/vendor/rb-sys-build/src/bindings/sanitizer.rs +185 -0
  22. data/vendor/rb-sys-build/src/bindings/stable_api.rs +247 -0
  23. data/vendor/rb-sys-build/src/bindings/wrapper.h +71 -0
  24. data/vendor/rb-sys-build/src/bindings.rs +280 -0
  25. data/vendor/rb-sys-build/src/cc.rs +421 -0
  26. data/vendor/rb-sys-build/src/lib.rs +12 -0
  27. data/vendor/rb-sys-build/src/rb_config/flags.rs +101 -0
  28. data/vendor/rb-sys-build/src/rb_config/library.rs +132 -0
  29. data/vendor/rb-sys-build/src/rb_config/search_path.rs +57 -0
  30. data/vendor/rb-sys-build/src/rb_config.rs +906 -0
  31. data/vendor/rb-sys-build/src/utils.rs +53 -0
  32. metadata +25 -11
  33. data/ext/itsi_server/target/release/build/clang-sys-0dae18670e690c25/out/common.rs +0 -355
  34. data/ext/itsi_server/target/release/build/clang-sys-0dae18670e690c25/out/dynamic.rs +0 -276
  35. data/ext/itsi_server/target/release/build/clang-sys-0dae18670e690c25/out/macros.rs +0 -49
  36. data/ext/itsi_server/target/release/build/oid-registry-71b994a322b296ec/out/oid_db.rs +0 -537
  37. data/ext/itsi_server/target/release/build/rb-sys-9f9831ab50fb86db/out/bindings-0.9.124-mri-arm64-darwin24-2.7.8.rs +0 -6234
  38. data/ext/itsi_server/target/release/build/rb-sys-9f9831ab50fb86db/out/bindings-0.9.124-mri-arm64-darwin24-3.4.5.rs +0 -8936
  39. data/ext/itsi_server/target/release/build/rb-sys-9f9831ab50fb86db/out/bindings-0.9.124-mri-arm64-darwin24-4.0.1.rs +0 -9060
  40. data/ext/itsi_server/target/release/build/typenum-11265e44e46de3b7/out/tests.rs +0 -20563
@@ -0,0 +1,280 @@
1
+ mod sanitizer;
2
+ mod stable_api;
3
+
4
+ use crate::cc::Build;
5
+ use crate::utils::is_msvc;
6
+ use crate::{debug_log, RbConfig};
7
+ use quote::ToTokens;
8
+ use stable_api::{categorize_bindings, opaqueify_bindings};
9
+ use std::fs::File;
10
+ use std::io::Write;
11
+ use std::path::{Path, PathBuf};
12
+ use std::{env, error::Error};
13
+ use syn::{Expr, ExprLit, ItemConst, Lit};
14
+
15
+ const WRAPPER_H_CONTENT: &str = include_str!("bindings/wrapper.h");
16
+
17
+ /// Generate bindings for the Ruby using bindgen.
18
+ pub fn generate(
19
+ rbconfig: &RbConfig,
20
+ static_ruby: bool,
21
+ cfg_out: &mut File,
22
+ ) -> Result<PathBuf, Box<dyn Error>> {
23
+ let out_dir = PathBuf::from(env::var("OUT_DIR")?);
24
+
25
+ let mut clang_args = vec![];
26
+ if let Some(ruby_include_dir) = rbconfig.get("rubyhdrdir") {
27
+ clang_args.push(format!("-I{}", ruby_include_dir));
28
+ }
29
+ if let Some(ruby_arch_include_dir) = rbconfig.get("rubyarchhdrdir") {
30
+ clang_args.push(format!("-I{}", ruby_arch_include_dir));
31
+ }
32
+
33
+ clang_args.extend(Build::default_cflags());
34
+ clang_args.extend(rbconfig.cflags.clone());
35
+ clang_args.extend(rbconfig.cppflags());
36
+
37
+ // On Windows x86_64, we need to handle AVX512 FP16 compatibility issues
38
+ // Clang 20+ includes types like __m512h that aren't compatible with bindgen
39
+ if cfg!(target_os = "windows") && cfg!(target_arch = "x86_64") {
40
+ // For MinGW toolchain, disable SSE/AVX only for bindgen
41
+ // This prevents intrinsics headers from loading but doesn't affect the final binary
42
+ if !is_msvc() {
43
+ clang_args.push("-mno-sse".to_string());
44
+ clang_args.push("-mno-avx".to_string());
45
+ }
46
+ }
47
+
48
+ debug_log!("INFO: using bindgen with clang args: {:?}", clang_args);
49
+
50
+ let mut wrapper_h = WRAPPER_H_CONTENT.to_string();
51
+
52
+ if !is_msvc() {
53
+ wrapper_h.push_str("#ifdef HAVE_RUBY_ATOMIC_H\n");
54
+ wrapper_h.push_str("#include \"ruby/atomic.h\"\n");
55
+ wrapper_h.push_str("#endif\n");
56
+ }
57
+
58
+ if rbconfig.have_ruby_header("ruby/io/buffer.h") {
59
+ clang_args.push("-DHAVE_RUBY_IO_BUFFER_H".to_string());
60
+ }
61
+
62
+ let bindings = default_bindgen(clang_args, rbconfig)
63
+ .allowlist_file(".*ruby.*")
64
+ .blocklist_item("ruby_abi_version")
65
+ .blocklist_function("rb_tr_abi_version")
66
+ .blocklist_function("^__.*")
67
+ .blocklist_item("RData")
68
+ .blocklist_function("rb_tr_rdata")
69
+ .blocklist_function("rb_tr_rtypeddata")
70
+ .parse_callbacks(Box::new(bindgen::CargoCallbacks::new()));
71
+
72
+ let bindings = if cfg!(feature = "bindgen-rbimpls") {
73
+ bindings
74
+ } else {
75
+ bindings
76
+ .blocklist_item("^rbimpl_.*")
77
+ .blocklist_item("^RBIMPL_.*")
78
+ };
79
+
80
+ let bindings = if cfg!(feature = "bindgen-deprecated-types") {
81
+ bindings
82
+ } else {
83
+ bindings.blocklist_item("^_bindgen_ty_9.*")
84
+ };
85
+
86
+ let bindings = opaqueify_bindings(rbconfig, bindings, &mut wrapper_h);
87
+
88
+ let mut tokens = {
89
+ write!(std::io::stderr(), "{}", wrapper_h)?;
90
+ let bindings = bindings.header_contents("wrapper.h", &wrapper_h);
91
+ let code_string = bindings.generate()?.to_string();
92
+ syn::parse_file(&code_string)?
93
+ };
94
+
95
+ let slug = rbconfig.ruby_version_slug();
96
+ let crate_version = env!("CARGO_PKG_VERSION");
97
+ let out_path = out_dir.join(format!("bindings-{}-{}.rs", crate_version, slug));
98
+
99
+ let code = {
100
+ sanitizer::ensure_backwards_compatible_encoding_pointers(&mut tokens);
101
+ clean_docs(rbconfig, &mut tokens);
102
+
103
+ if is_msvc() {
104
+ qualify_symbols_for_msvc(&mut tokens, static_ruby, rbconfig);
105
+ }
106
+
107
+ push_cargo_cfg_from_bindings(&tokens, cfg_out)?;
108
+ categorize_bindings(&mut tokens);
109
+ tokens.into_token_stream().to_string()
110
+ };
111
+
112
+ let mut out_file = File::create(&out_path)?;
113
+ std::io::Write::write_all(&mut out_file, code.as_bytes())?;
114
+ run_rustfmt(&out_path);
115
+
116
+ Ok(out_path)
117
+ }
118
+
119
+ fn run_rustfmt(path: &Path) {
120
+ let mut cmd = std::process::Command::new("rustfmt");
121
+ cmd.stderr(std::process::Stdio::inherit());
122
+ cmd.stdout(std::process::Stdio::inherit());
123
+
124
+ cmd.arg(path);
125
+
126
+ if let Err(e) = cmd.status() {
127
+ debug_log!("WARN: failed to run rustfmt: {}", e);
128
+ }
129
+ }
130
+
131
+ fn clean_docs(rbconfig: &RbConfig, syntax: &mut syn::File) {
132
+ if rbconfig.is_cross_compiling() {
133
+ return;
134
+ }
135
+
136
+ let ver = rbconfig.ruby_version_slug();
137
+
138
+ sanitizer::cleanup_docs(syntax, &ver).unwrap_or_else(|e| {
139
+ debug_log!("WARN: failed to clean up docs, skipping: {}", e);
140
+ })
141
+ }
142
+
143
+ fn default_bindgen(clang_args: Vec<String>, _rbconfig: &RbConfig) -> bindgen::Builder {
144
+ // Disable layout tests and Debug impl on Windows MinGW due to packed struct layout incompatibilities
145
+ let is_windows_mingw = cfg!(target_os = "windows") && !is_msvc();
146
+
147
+ let enable_layout_tests = !is_windows_mingw && cfg!(feature = "bindgen-layout-tests");
148
+ let impl_debug = !is_windows_mingw && cfg!(feature = "bindgen-impl-debug");
149
+
150
+ let mut bindings = bindgen::Builder::default()
151
+ .rustified_enum(".*")
152
+ .no_copy("rb_data_type_struct")
153
+ .derive_eq(true)
154
+ .derive_debug(true)
155
+ .clang_args(clang_args)
156
+ .layout_tests(enable_layout_tests)
157
+ .blocklist_item("^__darwin_pthread.*")
158
+ .blocklist_item("^_opaque_pthread.*")
159
+ .blocklist_item("^__pthread_.*")
160
+ .blocklist_item("^pthread_.*")
161
+ .blocklist_item("^rb_native.*")
162
+ .blocklist_type("INET_PORT_RESERVATION_INSTANCE")
163
+ .blocklist_type("PINET_PORT_RESERVATION_INSTANCE")
164
+ .opaque_type("^__sFILE$")
165
+ .merge_extern_blocks(true)
166
+ .generate_comments(true)
167
+ .size_t_is_usize(env::var("CARGO_FEATURE_BINDGEN_SIZE_T_IS_USIZE").is_ok())
168
+ .impl_debug(impl_debug)
169
+ .parse_callbacks(Box::new(bindgen::CargoCallbacks::new()));
170
+
171
+ // Make __mingw_ldbl_type_t opaque on Windows MinGW to avoid conflicting packed/align representation
172
+ if cfg!(target_os = "windows") && !is_msvc() {
173
+ bindings = bindings.opaque_type("__mingw_ldbl_type_t");
174
+ }
175
+
176
+ if env::var("CARGO_FEATURE_BINDGEN_ENABLE_FUNCTION_ATTRIBUTE_DETECTION").is_ok() {
177
+ bindings.enable_function_attribute_detection()
178
+ } else {
179
+ bindings
180
+ }
181
+ }
182
+
183
+ // This is needed because bindgen doesn't support the `__declspec(dllimport)` on
184
+ // global variables. Without it, symbols are not found.
185
+ // See https://stackoverflow.com/a/66182704/2057700
186
+ fn qualify_symbols_for_msvc(tokens: &mut syn::File, is_static: bool, rbconfig: &RbConfig) {
187
+ let kind = if is_static { "static" } else { "dylib" };
188
+
189
+ let name = if is_static {
190
+ rbconfig.libruby_static_name()
191
+ } else {
192
+ rbconfig.libruby_so_name()
193
+ };
194
+
195
+ sanitizer::add_link_ruby_directives(tokens, &name, kind).unwrap_or_else(|e| {
196
+ debug_log!("WARN: failed to add link directives: {}", e);
197
+ });
198
+ }
199
+
200
+ // Add things like `#[cfg(ruby_use_transient_heap = "true")]` to the bindings config
201
+ fn push_cargo_cfg_from_bindings(
202
+ syntax: &syn::File,
203
+ cfg_out: &mut File,
204
+ ) -> Result<(), Box<dyn Error>> {
205
+ fn is_defines(line: &str) -> bool {
206
+ line.starts_with("HAVE_RUBY")
207
+ || line.starts_with("HAVE_RB")
208
+ || line.starts_with("USE")
209
+ || line.starts_with("RUBY_DEBUG")
210
+ || line.starts_with("RUBY_NDEBUG")
211
+ }
212
+
213
+ for item in syntax.items.iter() {
214
+ if let syn::Item::Const(item) = item {
215
+ let conf = ConfValue::new(item);
216
+ let conf_name = conf.name();
217
+
218
+ if is_defines(&conf_name) {
219
+ let name = conf_name.to_lowercase();
220
+ let val = conf.value_bool().to_string();
221
+ println!(
222
+ r#"cargo:rustc-check-cfg=cfg(ruby_{}, values("true", "false"))"#,
223
+ name
224
+ );
225
+ println!("cargo:rustc-cfg=ruby_{}=\"{}\"", name, val);
226
+ println!("cargo:defines_{}={}", name, val);
227
+ writeln!(cfg_out, "cargo:defines_{}={}", name, val)?;
228
+ }
229
+
230
+ if conf_name.starts_with("RUBY_ABI_VERSION") {
231
+ println!("cargo:ruby_abi_version={}", conf.value_string());
232
+ writeln!(cfg_out, "cargo:ruby_abi_version={}", conf.value_string())?;
233
+ }
234
+ }
235
+ }
236
+
237
+ Ok(())
238
+ }
239
+
240
+ /// An autoconf constant in the bindings
241
+ struct ConfValue<'a> {
242
+ item: &'a syn::ItemConst,
243
+ }
244
+
245
+ impl<'a> ConfValue<'a> {
246
+ pub fn new(item: &'a ItemConst) -> Self {
247
+ Self { item }
248
+ }
249
+
250
+ pub fn name(&self) -> String {
251
+ self.item.ident.to_string()
252
+ }
253
+
254
+ pub fn value_string(&self) -> String {
255
+ match &*self.item.expr {
256
+ Expr::Lit(ExprLit { lit, .. }) => lit.to_token_stream().to_string(),
257
+ _ => panic!(
258
+ "Could not convert HAVE_* constant to string: {:#?}",
259
+ self.item
260
+ ),
261
+ }
262
+ }
263
+
264
+ pub fn value_bool(&self) -> bool {
265
+ match &*self.item.expr {
266
+ Expr::Lit(ExprLit {
267
+ lit: Lit::Int(ref lit),
268
+ ..
269
+ }) => lit.base10_parse::<u8>().unwrap_or(1) != 0,
270
+ Expr::Lit(ExprLit {
271
+ lit: Lit::Bool(ref lit),
272
+ ..
273
+ }) => lit.value,
274
+ _ => panic!(
275
+ "Could not convert HAVE_* constant to bool: {:#?}",
276
+ self.item
277
+ ),
278
+ }
279
+ }
280
+ }
@@ -0,0 +1,421 @@
1
+ use crate::{
2
+ debug_log, rb_config,
3
+ utils::{is_msvc, shellsplit},
4
+ };
5
+ use std::{
6
+ collections::{hash_map::DefaultHasher, HashSet},
7
+ env,
8
+ ffi::{OsStr, OsString},
9
+ fs,
10
+ hash::Hasher,
11
+ path::{Path, PathBuf},
12
+ process::{Command, ExitStatus, Stdio},
13
+ };
14
+
15
+ type Result<T> = std::result::Result<T, Box<dyn std::error::Error>>;
16
+
17
+ const WELL_KNOWN_WRAPPERS: &[&str] = &["sccache", "cachepot"];
18
+
19
+ #[derive(Default, Debug)]
20
+ pub struct Build {
21
+ files: Vec<PathBuf>,
22
+ flags: Vec<String>,
23
+ }
24
+
25
+ impl Build {
26
+ pub fn new() -> Self {
27
+ Self::default()
28
+ }
29
+
30
+ pub fn default_cflags() -> Vec<String> {
31
+ let mut cflags = vec![];
32
+
33
+ if cfg!(target_os = "openbsd") {
34
+ cflags.push("-fdeclspec".into());
35
+ } else {
36
+ cflags.push("-fms-extensions".into());
37
+ };
38
+
39
+ cflags
40
+ }
41
+
42
+ pub fn file(&mut self, file: PathBuf) {
43
+ println!("cargo:rerun-if-changed={}", file.display());
44
+ self.files.push(file);
45
+ }
46
+
47
+ pub fn try_compile(self, name: &str) -> Result<()> {
48
+ let compiler = get_compiler();
49
+ let archiver = get_archiver();
50
+ let out_dir = PathBuf::from(env::var("OUT_DIR")?).join("cc");
51
+ fs::create_dir_all(&out_dir)?;
52
+ let rb = rb_config();
53
+
54
+ let object_files = self.compile_each_file(compiler, &rb, &out_dir)?;
55
+ debug_log!("INFO: compiled object files: {:?}", object_files);
56
+ let (lib_path, lib_name) =
57
+ self.archive_object_files(archiver.copied(), name, &out_dir, object_files)?;
58
+ if let Err(e) = self.strip_archived_objects(archiver, &lib_path) {
59
+ debug_log!("WARN: failed to strip archived objects: {:?}", e);
60
+ }
61
+
62
+ println!("cargo:rustc-link-search=native={}", out_dir.display());
63
+ println!("cargo:rustc-link-lib=static={}", lib_name);
64
+
65
+ Ok(())
66
+ }
67
+
68
+ fn compile_each_file(
69
+ &self,
70
+ compiler: Command,
71
+ rb: &rb_config::RbConfig,
72
+ out_dir: &Path,
73
+ ) -> Result<HashSet<PathBuf>> {
74
+ self.files
75
+ .iter()
76
+ .map(|f| self.compile_file(f, compiler.copied(), rb, out_dir))
77
+ .collect()
78
+ }
79
+
80
+ fn compile_file(
81
+ &self,
82
+ f: &Path,
83
+ compiler: Command,
84
+ rb: &rb_config::RbConfig,
85
+ out_dir: &Path,
86
+ ) -> Result<PathBuf> {
87
+ let mut hasher = DefaultHasher::new();
88
+ hasher.write(fs::read(f)?.as_slice());
89
+
90
+ let object_file = out_dir
91
+ .join(hasher.finish().to_string())
92
+ .with_extension("o");
93
+
94
+ let mut cmd = compiler;
95
+ cmd.args(get_include_args(rb))
96
+ .arg("-c")
97
+ .arg(f)
98
+ .args(&rb.cflags)
99
+ .args(get_common_args())
100
+ .args(&self.flags)
101
+ .args(get_output_file_flag(&object_file));
102
+
103
+ run_command(cmd)?;
104
+
105
+ Ok(object_file)
106
+ }
107
+
108
+ fn archive_object_files(
109
+ &self,
110
+ archiver: Command,
111
+ name: &str,
112
+ out_dir: &Path,
113
+ object_files: HashSet<PathBuf>,
114
+ ) -> Result<(PathBuf, String)> {
115
+ let mut cmd = archiver;
116
+ let mut hasher = DefaultHasher::new();
117
+ object_files
118
+ .iter()
119
+ .for_each(|f| hasher.write(f.to_str().expect("non-utf8 filename").as_bytes()));
120
+ let lib_name = format!("{}-{}", name, hasher.finish());
121
+ let lib_filename = format!("lib{}.a", lib_name);
122
+ let dst = out_dir.join(lib_filename);
123
+
124
+ // The argument structure differs for MSVC and GCC.
125
+ if is_msvc() {
126
+ cmd.arg(format!("/OUT:{}", dst.display()));
127
+ cmd.args(&object_files);
128
+ } else {
129
+ cmd.env("ZERO_AR_DATE", "1").arg("crs").arg(&dst);
130
+ cmd.args(&object_files);
131
+ }
132
+
133
+ run_command(cmd)?;
134
+
135
+ // The Rust compiler will look for libfoo.a and foo.lib, but the
136
+ // MSVC linker will also be passed foo.lib, so be sure that both
137
+ // exist for now.
138
+ if is_msvc() {
139
+ let lib_dst = dst.with_file_name(format!("{}.lib", lib_name));
140
+ let _ = fs::remove_file(&lib_dst);
141
+ match fs::hard_link(&dst, &lib_dst).or_else(|_| {
142
+ // if hard-link fails, just copy (ignoring the number of bytes written)
143
+ fs::copy(&dst, &lib_dst).map(|_| ())
144
+ }) {
145
+ Ok(_) => (),
146
+ Err(_) => {
147
+ return Err(
148
+ "Could not copy or create a hard-link to the generated lib file.".into(),
149
+ );
150
+ }
151
+ };
152
+ }
153
+
154
+ Ok((dst, lib_name))
155
+ }
156
+
157
+ fn strip_archived_objects(&self, archiver: Command, libpath: &Path) -> Result<()> {
158
+ let mut cmd = archiver;
159
+
160
+ if is_msvc() {
161
+ cmd.arg("/LTCG").arg(libpath);
162
+ } else {
163
+ cmd.arg("s").arg(libpath);
164
+ }
165
+
166
+ run_command(cmd)?;
167
+
168
+ Ok(())
169
+ }
170
+ }
171
+
172
+ fn get_include_args(rb: &rb_config::RbConfig) -> Vec<String> {
173
+ let mut args = vec![];
174
+ if let Some(include_dir) = rb.get("rubyhdrdir") {
175
+ args.push(format!("-I{}", include_dir));
176
+ }
177
+ if let Some(arch_include_dir) = rb.get("rubyarchhdrdir") {
178
+ args.push(format!("-I{}", arch_include_dir));
179
+ }
180
+ if let Some(internal_include_dir) = rb.get("rubyhdrdir") {
181
+ args.push(format!("-I{}/include/internal", internal_include_dir));
182
+ }
183
+ if let Some(impl_include_dir) = rb.get("rubyhdrdir") {
184
+ args.push(format!("-I{}/include/impl", impl_include_dir));
185
+ }
186
+
187
+ args
188
+ }
189
+
190
+ fn get_common_args() -> Vec<String> {
191
+ fn add_debug_flags(flags: &mut Vec<String>) {
192
+ match env::var("DEBUG") {
193
+ Ok(val) if val == "true" => {
194
+ if is_msvc() {
195
+ flags.push("-Z7".into());
196
+ } else if cfg!(target_os = "linux") {
197
+ flags.push("-gdwarf-4".into());
198
+ } else {
199
+ flags.push("-gdwarf-2".into());
200
+ }
201
+ }
202
+ _ => {}
203
+ }
204
+ }
205
+
206
+ fn add_opt_level(flags: &mut Vec<String>) {
207
+ if let Ok(val) = env::var("OPT_LEVEL") {
208
+ match val.as_str() {
209
+ // Msvc uses /O1 to enable all optimizations that minimize code size.
210
+ "z" | "s" | "1" if is_msvc() => flags.push("-O1".into()),
211
+ // -O3 is a valid value for gcc and clang compilers, but not msvc. Cap to /O2.
212
+ "2" | "3" if is_msvc() => flags.push("-O2".into()),
213
+ lvl => flags.push(format!("-O{}", lvl)),
214
+ }
215
+ }
216
+ }
217
+
218
+ fn add_compiler_flags(flags: &mut Vec<String>) {
219
+ if !is_msvc() {
220
+ flags.push("-ffunction-sections".into());
221
+ flags.push("-fdata-sections".into());
222
+ flags.push("-fPIC".into());
223
+ flags.push("-fno-omit-frame-pointer".into());
224
+ }
225
+
226
+ flags.extend(Build::default_cflags());
227
+ }
228
+
229
+ let mut items = vec![];
230
+
231
+ add_debug_flags(&mut items);
232
+ add_compiler_flags(&mut items);
233
+ add_opt_level(&mut items);
234
+
235
+ items
236
+ }
237
+
238
+ fn get_compiler() -> Command {
239
+ let cmd = get_tool("CC", "cc");
240
+ let cmd_program = cmd.get_program().to_str().unwrap_or_default();
241
+ let already_wrapped = WELL_KNOWN_WRAPPERS.iter().any(|w| cmd_program.contains(w));
242
+
243
+ match get_tool_from_rb_config_or_env("CC_WRAPPER") {
244
+ Some(wrapper) if !wrapper.is_empty() && !already_wrapped => {
245
+ debug_log!("INFO: using CC_WRAPPER ({:?})", wrapper);
246
+ cmd.wrapped(wrapper)
247
+ }
248
+ _ => match rustc_wrapper_fallback() {
249
+ Some(wrapper) if !already_wrapped => cmd.wrapped(wrapper),
250
+ _ => cmd,
251
+ },
252
+ }
253
+ }
254
+
255
+ pub fn rustc_wrapper_fallback() -> Option<String> {
256
+ let rustc_wrapper = std::env::var("RUSTC_WRAPPER").ok()?;
257
+ rustc_wrapper_fallback_detect(rustc_wrapper)
258
+ }
259
+
260
+ pub fn rustc_wrapper_fallback_detect(rustc_wrapper: String) -> Option<String> {
261
+ let wrapper_path = Path::new(&rustc_wrapper);
262
+ let wrapper_stem = wrapper_path.file_stem()?;
263
+
264
+ if WELL_KNOWN_WRAPPERS.contains(&wrapper_stem.to_str()?) {
265
+ debug_log!("INFO: using RUSTC_WRAPPER ({:?})", rustc_wrapper);
266
+ Some(rustc_wrapper)
267
+ } else {
268
+ None
269
+ }
270
+ }
271
+
272
+ fn get_archiver() -> Command {
273
+ let cmd = get_tool("AR", "ar");
274
+
275
+ if cmd.get_program() == "libtool" {
276
+ new_command("ar")
277
+ } else {
278
+ cmd
279
+ }
280
+ }
281
+
282
+ fn get_tool(env_var: &str, default: &str) -> Command {
283
+ let tool_args = get_tool_from_rb_config_or_env(env_var)
284
+ .unwrap_or_else(|| panic!("no {} tool found", env_var));
285
+
286
+ let mut tool_args = shellsplit(tool_args).into_iter();
287
+ let tool = tool_args.next().unwrap_or_else(|| default.to_string());
288
+
289
+ fn tool_exists(tool_name: &str) -> std::io::Result<bool> {
290
+ let path = PathBuf::from(tool_name);
291
+
292
+ if path.is_file() {
293
+ return Ok(true);
294
+ }
295
+
296
+ match Command::new(tool_name).spawn() {
297
+ Ok(_) => Ok(true),
298
+ Err(e) => {
299
+ if e.kind() == std::io::ErrorKind::NotFound {
300
+ Ok(false)
301
+ } else {
302
+ Err(e)
303
+ }
304
+ }
305
+ }
306
+ }
307
+
308
+ let mut cmd = if tool_exists(&tool).unwrap_or(false) {
309
+ debug_log!("[INFO] using {tool} for {env_var}");
310
+ new_command(&tool)
311
+ } else {
312
+ debug_log!("[WARN] {tool} tool not found, falling back to {default}");
313
+ new_command(default)
314
+ };
315
+
316
+ cmd.args(tool_args.clone());
317
+
318
+ debug_log!("INFO: found {:?} tool ({:?})", env_var, &cmd);
319
+
320
+ cmd
321
+ }
322
+
323
+ fn get_tool_from_rb_config_or_env(env_var: &str) -> Option<String> {
324
+ let rb = rb_config();
325
+
326
+ get_tool_from_env(env_var)
327
+ .filter(|s| !s.is_empty())
328
+ .or_else(|| rb.get(env_var))
329
+ }
330
+
331
+ fn get_tool_from_env(env_var: &str) -> Option<String> {
332
+ let target_slug = env::var("TARGET").ok()?.replace('-', "_");
333
+ let env_var_with_target = format!("{}_{}", env_var, target_slug);
334
+
335
+ println!("cargo:rerun-if-env-changed={}", env_var);
336
+ println!("cargo:rerun-if-env-changed={}", env_var_with_target);
337
+
338
+ env::var(env_var)
339
+ .or_else(|_| env::var(env_var_with_target))
340
+ .ok()
341
+ }
342
+
343
+ fn run_command(mut cmd: Command) -> Result<ExitStatus> {
344
+ debug_log!("INFO: running command ({:?})", cmd);
345
+ let status = cmd.status()?;
346
+
347
+ if !status.success() {
348
+ Err(format!("Command '{:?}' failed with status: {}", cmd, status).into())
349
+ } else {
350
+ Ok(status)
351
+ }
352
+ }
353
+
354
+ fn new_command(name: &str) -> Command {
355
+ let mut cmd = Command::new(name);
356
+ cmd.stderr(Stdio::inherit()).stdout(Stdio::inherit());
357
+ cmd
358
+ }
359
+
360
+ fn get_output_file_flag(file: &Path) -> Vec<OsString> {
361
+ if is_msvc() {
362
+ vec![format!("-Fo{}", file.display()).into()]
363
+ } else {
364
+ vec!["-o".into(), file.into()]
365
+ }
366
+ }
367
+
368
+ pub trait CommandExt {
369
+ fn copied(&self) -> Command;
370
+ fn wrapped<W: AsRef<OsStr>>(&self, wrapper: W) -> Command;
371
+ }
372
+
373
+ impl CommandExt for Command {
374
+ fn copied(&self) -> Command {
375
+ let mut cmd = Command::new(self.get_program());
376
+ cmd.args(self.get_args());
377
+
378
+ for (k, v) in self.get_envs() {
379
+ if let Some(v) = v {
380
+ cmd.env(k, v);
381
+ } else {
382
+ cmd.env_remove(k);
383
+ }
384
+ }
385
+ cmd
386
+ }
387
+
388
+ fn wrapped<W: AsRef<OsStr>>(&self, wrapper: W) -> Command {
389
+ let mut new_cmd = Command::new(wrapper);
390
+
391
+ new_cmd.arg(self.get_program());
392
+
393
+ for arg in self.get_args() {
394
+ new_cmd.arg(arg);
395
+ }
396
+
397
+ for (k, v) in self.get_envs() {
398
+ if let Some(v) = v {
399
+ new_cmd.env(k, v);
400
+ } else {
401
+ new_cmd.env_remove(k);
402
+ }
403
+ }
404
+
405
+ new_cmd
406
+ }
407
+ }
408
+
409
+ #[cfg(test)]
410
+ mod tests {
411
+ use super::*;
412
+
413
+ #[test]
414
+ fn rustc_wrapper_detect() {
415
+ let wrapper = "/usr/local/bin/sccache";
416
+ assert_eq!(
417
+ rustc_wrapper_fallback_detect(wrapper.to_owned()),
418
+ Some(wrapper.to_owned())
419
+ );
420
+ }
421
+ }
@@ -0,0 +1,12 @@
1
+ pub mod bindings;
2
+ pub mod cc;
3
+ pub mod utils;
4
+
5
+ mod rb_config;
6
+
7
+ pub use rb_config::*;
8
+
9
+ /// The current RbConfig.
10
+ pub fn rb_config() -> RbConfig {
11
+ RbConfig::current()
12
+ }