itsi-server 0.2.21 → 0.2.22
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.
- checksums.yaml +4 -4
- data/Cargo.lock +25 -38
- data/Cargo.toml +4 -0
- data/Rakefile +39 -7
- data/ext/itsi_scheduler/Cargo.toml +1 -1
- data/ext/itsi_server/Cargo.toml +1 -1
- data/ext/itsi_server/src/server/signal.rs +7 -5
- data/lib/itsi/server/native_extension.rb +34 -0
- data/lib/itsi/server/version.rb +1 -1
- data/lib/itsi/server.rb +10 -2
- data/vendor/rb-sys-build/.cargo-ok +1 -0
- data/vendor/rb-sys-build/.cargo_vcs_info.json +6 -0
- data/vendor/rb-sys-build/Cargo.lock +294 -0
- data/vendor/rb-sys-build/Cargo.toml +71 -0
- data/vendor/rb-sys-build/Cargo.toml.orig +32 -0
- data/vendor/rb-sys-build/LICENSE-APACHE +190 -0
- data/vendor/rb-sys-build/LICENSE-MIT +21 -0
- data/vendor/rb-sys-build/src/bindings/sanitizer.rs +185 -0
- data/vendor/rb-sys-build/src/bindings/stable_api.rs +247 -0
- data/vendor/rb-sys-build/src/bindings/wrapper.h +71 -0
- data/vendor/rb-sys-build/src/bindings.rs +280 -0
- data/vendor/rb-sys-build/src/cc.rs +421 -0
- data/vendor/rb-sys-build/src/lib.rs +12 -0
- data/vendor/rb-sys-build/src/rb_config/flags.rs +101 -0
- data/vendor/rb-sys-build/src/rb_config/library.rs +132 -0
- data/vendor/rb-sys-build/src/rb_config/search_path.rs +57 -0
- data/vendor/rb-sys-build/src/rb_config.rs +906 -0
- data/vendor/rb-sys-build/src/utils.rs +53 -0
- metadata +25 -11
- data/ext/itsi_server/target/release/build/clang-sys-0dae18670e690c25/out/common.rs +0 -355
- data/ext/itsi_server/target/release/build/clang-sys-0dae18670e690c25/out/dynamic.rs +0 -276
- data/ext/itsi_server/target/release/build/clang-sys-0dae18670e690c25/out/macros.rs +0 -49
- data/ext/itsi_server/target/release/build/oid-registry-71b994a322b296ec/out/oid_db.rs +0 -537
- data/ext/itsi_server/target/release/build/rb-sys-9f9831ab50fb86db/out/bindings-0.9.124-mri-arm64-darwin24-2.7.8.rs +0 -6234
- data/ext/itsi_server/target/release/build/rb-sys-9f9831ab50fb86db/out/bindings-0.9.124-mri-arm64-darwin24-3.4.5.rs +0 -8936
- data/ext/itsi_server/target/release/build/rb-sys-9f9831ab50fb86db/out/bindings-0.9.124-mri-arm64-darwin24-4.0.1.rs +0 -9060
- data/ext/itsi_server/target/release/build/typenum-11265e44e46de3b7/out/tests.rs +0 -20563
|
@@ -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,101 @@
|
|
|
1
|
+
/// Some helper functionality around shell flags
|
|
2
|
+
pub struct Flags<'a> {
|
|
3
|
+
inner: &'a str,
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
impl<'a> Flags<'a> {
|
|
7
|
+
/// Creates a new `Flags` instance
|
|
8
|
+
pub fn new(inner: &'a str) -> Self {
|
|
9
|
+
Self { inner }
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/// Iterates over a string of flags
|
|
14
|
+
impl<'a> Iterator for Flags<'a> {
|
|
15
|
+
type Item = &'a str;
|
|
16
|
+
|
|
17
|
+
fn next(&mut self) -> Option<Self::Item> {
|
|
18
|
+
let mut last_was_space = false;
|
|
19
|
+
|
|
20
|
+
let last_idx = self
|
|
21
|
+
.inner
|
|
22
|
+
.chars()
|
|
23
|
+
.by_ref()
|
|
24
|
+
.take_while(|c| match c {
|
|
25
|
+
'-' => {
|
|
26
|
+
if last_was_space {
|
|
27
|
+
false
|
|
28
|
+
} else {
|
|
29
|
+
last_was_space = false;
|
|
30
|
+
true
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
' ' => {
|
|
34
|
+
last_was_space = true;
|
|
35
|
+
|
|
36
|
+
true
|
|
37
|
+
}
|
|
38
|
+
_ => {
|
|
39
|
+
last_was_space = false;
|
|
40
|
+
true
|
|
41
|
+
}
|
|
42
|
+
})
|
|
43
|
+
.count();
|
|
44
|
+
|
|
45
|
+
let buf = &self.inner[..last_idx].trim();
|
|
46
|
+
|
|
47
|
+
if buf.is_empty() {
|
|
48
|
+
None
|
|
49
|
+
} else {
|
|
50
|
+
self.inner = self.inner[last_idx..].trim();
|
|
51
|
+
Some(buf)
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
#[cfg(test)]
|
|
57
|
+
mod tests {
|
|
58
|
+
use super::*;
|
|
59
|
+
|
|
60
|
+
#[test]
|
|
61
|
+
fn test_basic_flags() {
|
|
62
|
+
let mut flags = Flags::new("--foo --bar -baz");
|
|
63
|
+
|
|
64
|
+
assert_eq!(flags.next(), Some("--foo"));
|
|
65
|
+
assert_eq!(flags.next(), Some("--bar"));
|
|
66
|
+
assert_eq!(flags.next(), Some("-baz"));
|
|
67
|
+
assert_eq!(flags.next(), None);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
#[test]
|
|
71
|
+
fn test_flag_variations() {
|
|
72
|
+
let mut flags = Flags::new("-ltest --library test");
|
|
73
|
+
|
|
74
|
+
assert_eq!(flags.next(), Some("-ltest"));
|
|
75
|
+
assert_eq!(flags.next(), Some("--library test"));
|
|
76
|
+
assert_eq!(flags.next(), None);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
#[test]
|
|
80
|
+
fn test_real_ldflags() {
|
|
81
|
+
let mut flags = Flags::new("-L. -L/Users/ianks/.asdf/installs/ruby/3.1.1/lib -L/opt/homebrew/opt/openssl@1.1/lib -fstack-protector-strong");
|
|
82
|
+
|
|
83
|
+
assert_eq!(flags.next(), Some("-L."));
|
|
84
|
+
assert_eq!(
|
|
85
|
+
flags.next(),
|
|
86
|
+
Some("-L/Users/ianks/.asdf/installs/ruby/3.1.1/lib")
|
|
87
|
+
);
|
|
88
|
+
assert_eq!(flags.next(), Some("-L/opt/homebrew/opt/openssl@1.1/lib"));
|
|
89
|
+
assert_eq!(flags.next(), Some("-fstack-protector-strong"));
|
|
90
|
+
assert_eq!(flags.next(), None);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
#[test]
|
|
94
|
+
fn test_dashed_flag_with_dashed_val() {
|
|
95
|
+
let mut flags = Flags::new("-ltest -fsomething-foo bar-val");
|
|
96
|
+
|
|
97
|
+
assert_eq!(flags.next(), Some("-ltest"));
|
|
98
|
+
assert_eq!(flags.next(), Some("-fsomething-foo bar-val"));
|
|
99
|
+
assert_eq!(flags.next(), None);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
/// Represents the kind of library.
|
|
2
|
+
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
|
3
|
+
pub enum LibraryKind {
|
|
4
|
+
Framework,
|
|
5
|
+
Dylib,
|
|
6
|
+
Static,
|
|
7
|
+
None,
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
/// Represents a search path that can be linked with Cargo.
|
|
11
|
+
#[derive(Debug, PartialEq, Eq)]
|
|
12
|
+
pub struct Library {
|
|
13
|
+
pub kind: LibraryKind,
|
|
14
|
+
pub name: String,
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
impl Library {
|
|
18
|
+
pub fn is_static(&self) -> bool {
|
|
19
|
+
self.kind == LibraryKind::Static
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
impl From<&str> for LibraryKind {
|
|
24
|
+
fn from(s: &str) -> Self {
|
|
25
|
+
match s {
|
|
26
|
+
"framework" => LibraryKind::Framework,
|
|
27
|
+
"dylib" => LibraryKind::Dylib,
|
|
28
|
+
"static" => LibraryKind::Static,
|
|
29
|
+
_ => LibraryKind::None,
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
impl From<&str> for Library {
|
|
35
|
+
fn from(s: &str) -> Self {
|
|
36
|
+
let parts: Vec<_> = s.splitn(2, '=').collect();
|
|
37
|
+
|
|
38
|
+
match parts.len() {
|
|
39
|
+
1 => (LibraryKind::None, parts[0]).into(),
|
|
40
|
+
2 => (parts[0], parts[1]).into(),
|
|
41
|
+
_ => panic!("Invalid library specification: {}", s),
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
impl From<String> for Library {
|
|
47
|
+
fn from(s: String) -> Self {
|
|
48
|
+
s.as_str().into()
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
fn sanitize_library_name(name: &str) -> &str {
|
|
53
|
+
name.trim_end_matches(".lib").trim_start_matches("-l")
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
impl<K, L> From<(K, L)> for Library
|
|
57
|
+
where
|
|
58
|
+
K: Into<LibraryKind>,
|
|
59
|
+
L: Into<String>,
|
|
60
|
+
{
|
|
61
|
+
fn from((kind, name): (K, L)) -> Self {
|
|
62
|
+
Self {
|
|
63
|
+
kind: kind.into(),
|
|
64
|
+
name: sanitize_library_name(&name.into()).into(),
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
impl std::fmt::Display for Library {
|
|
70
|
+
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
|
71
|
+
match self.kind {
|
|
72
|
+
LibraryKind::Framework => write!(f, "framework={}", self.name),
|
|
73
|
+
LibraryKind::Dylib => write!(f, "dylib={}", self.name),
|
|
74
|
+
LibraryKind::Static => write!(f, "static={}", self.name),
|
|
75
|
+
LibraryKind::None => write!(f, "{}", self.name),
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
#[cfg(test)]
|
|
81
|
+
mod tests {
|
|
82
|
+
use super::*;
|
|
83
|
+
|
|
84
|
+
#[test]
|
|
85
|
+
fn test_trim_leading_link_flag() {
|
|
86
|
+
let result: Library = "-lfoo".to_string().into();
|
|
87
|
+
|
|
88
|
+
assert_eq!(result.name, "foo");
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
#[test]
|
|
92
|
+
fn test_trim_trailing_lib_extension() {
|
|
93
|
+
let result: Library = "foo.lib".to_string().into();
|
|
94
|
+
|
|
95
|
+
assert_eq!(result.name, "foo");
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
#[test]
|
|
99
|
+
fn test_trim_leading_link_flag_and_trailing_lib_extension() {
|
|
100
|
+
let result: Library = "-lfoo.lib".to_string().into();
|
|
101
|
+
|
|
102
|
+
assert_eq!(result.name, "foo");
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
#[test]
|
|
106
|
+
fn test_display_framework() {
|
|
107
|
+
let result: Library = "framework=foo".to_string().into();
|
|
108
|
+
|
|
109
|
+
assert_eq!(result.to_string(), "framework=foo");
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
#[test]
|
|
113
|
+
fn test_display_dylib() {
|
|
114
|
+
let result: Library = "dylib=foo".to_string().into();
|
|
115
|
+
|
|
116
|
+
assert_eq!(result.to_string(), "dylib=foo");
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
#[test]
|
|
120
|
+
fn test_display_static() {
|
|
121
|
+
let result: Library = "static=-lfoo".to_string().into();
|
|
122
|
+
|
|
123
|
+
assert_eq!(result.to_string(), "static=foo");
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
#[test]
|
|
127
|
+
fn test_display_none() {
|
|
128
|
+
let result: Library = "foo".to_string().into();
|
|
129
|
+
|
|
130
|
+
assert_eq!(result.to_string(), "foo");
|
|
131
|
+
}
|
|
132
|
+
}
|