Skip to content

Commit c2feda9

Browse files
committed
Cleanup
1 parent 19e96ef commit c2feda9

File tree

2 files changed

+264
-228
lines changed

2 files changed

+264
-228
lines changed

build/generator.rs

Lines changed: 45 additions & 228 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,17 @@
1-
use std::ffi::OsStr;
2-
use std::fs::{File, OpenOptions};
3-
use std::io::{BufRead, BufReader, BufWriter, Write};
41
use std::ops::Deref;
52
use std::path::{Path, PathBuf};
63
use std::process::Command;
74
use std::time::Instant;
8-
use std::{env, fs, io, thread};
5+
use std::{env, fs, thread};
96

7+
use collector::Collector;
108
use opencv_binding_generator::{Generator, IteratorExt};
119

1210
use super::docs::transfer_bindings_to_docs;
13-
use super::{files_with_extension, files_with_predicate, Library, Result, MODULES, OUT_DIR, SRC_CPP_DIR, SRC_DIR};
11+
use super::{files_with_predicate, Library, Result, MODULES, OUT_DIR, SRC_CPP_DIR, SRC_DIR};
12+
13+
#[path = "generator/collector.rs"]
14+
mod collector;
1415

1516
pub struct BindingGenerator {
1617
build_script_path: PathBuf,
@@ -47,7 +48,8 @@ impl BindingGenerator {
4748

4849
self.run(modules, opencv_header_dir, opencv)?;
4950

50-
collect_generated_bindings(modules, &target_module_dir, &manual_dir)?;
51+
let collector = Collector::new(modules, &target_module_dir, &manual_dir, &OUT_DIR);
52+
collector.collect_bindings()?;
5153

5254
if let Some(target_docs_dir) = target_docs_dir {
5355
if !target_docs_dir.exists() {
@@ -82,7 +84,7 @@ impl BindingGenerator {
8284
.into_iter()
8385
.map(|p| p.to_str().expect("Can't convert additional include dir to UTF-8 string"))
8486
.join(",");
85-
let job_server = build_job_server()?;
87+
let job_server = Jobserver::build()?;
8688
let start = Instant::now();
8789
eprintln!("=== Generating {} modules", modules.len());
8890
thread::scope(|scope| {
@@ -123,233 +125,48 @@ impl BindingGenerator {
123125
}
124126
}
125127

126-
fn is_type_file(path: &Path, module: &str) -> bool {
127-
path.file_stem().and_then(OsStr::to_str).map_or(false, |stem| {
128-
let mut stem_chars = stem.chars();
129-
(&mut stem_chars).take(3).all(|c| c.is_ascii_digit()) && // first 3 chars are digits
130-
matches!(stem_chars.next(), Some('-')) && // dash
131-
module.chars().zip(&mut stem_chars).all(|(m, s)| m == s) && // module name
132-
matches!(stem_chars.next(), Some('-')) && // dash
133-
stem.ends_with(".type") // ends with ".type"
134-
})
135-
}
136-
137-
fn is_type_externs_file(path: &Path, module: &str) -> bool {
138-
path.file_stem().and_then(OsStr::to_str).map_or(false, |stem| {
139-
let mut stem_chars = stem.chars();
140-
(&mut stem_chars).take(3).all(|c| c.is_ascii_digit()) && // first 3 chars are digits
141-
matches!(stem_chars.next(), Some('-')) && // dash
142-
module.chars().zip(&mut stem_chars).all(|(m, s)| m == s) && // module name
143-
matches!(stem_chars.next(), Some('-')) && // dash
144-
stem.ends_with(".type.externs") // ends with ".type"
145-
})
146-
}
147-
148-
fn copy_indent(mut read: impl BufRead, mut write: impl Write, indent: &str) -> Result<()> {
149-
let mut line = Vec::with_capacity(100);
150-
while read.read_until(b'\n', &mut line)? != 0 {
151-
write.write_all(indent.as_bytes())?;
152-
write.write_all(&line)?;
153-
line.clear();
154-
}
155-
Ok(())
128+
pub struct Jobserver {
129+
client: jobserver::Client,
130+
reacquire_token_on_drop: bool,
156131
}
157132

158-
fn collect_generated_bindings(modules: &[String], target_module_dir: &Path, manual_dir: &Path) -> Result<()> {
159-
if !target_module_dir.exists() {
160-
fs::create_dir(target_module_dir)?;
161-
}
162-
for path in files_with_extension(target_module_dir, "rs")? {
163-
let _ = fs::remove_file(path);
164-
}
165-
166-
fn write_has_module(mut write: impl Write, module: &str) -> Result<()> {
167-
Ok(writeln!(write, "#[cfg(ocvrs_has_module_{module})]")?)
168-
}
169-
170-
fn write_module_include(write: &mut BufWriter<File>, module: &str) -> Result<()> {
171-
// Use include instead of #[path] attribute because rust-analyzer doesn't handle #[path] inside other include! too well:
172-
// https://github.com/twistedfall/opencv-rust/issues/418
173-
// https://github.com/rust-lang/rust-analyzer/issues/11682
174-
Ok(writeln!(
175-
write,
176-
r#"include!(concat!(env!("OUT_DIR"), "/opencv/{module}.rs"));"#
177-
)?)
178-
}
179-
180-
let add_manual = |file: &mut BufWriter<File>, module: &str| -> Result<bool> {
181-
if manual_dir.join(format!("{module}.rs")).exists() {
182-
writeln!(file, "pub use crate::manual::{module}::*;")?;
183-
Ok(true)
184-
} else {
185-
Ok(false)
186-
}
187-
};
188-
189-
let start = Instant::now();
190-
let mut hub_rs = BufWriter::new(File::create(target_module_dir.join("hub.rs"))?);
191-
192-
let mut types_rs = BufWriter::new(File::create(target_module_dir.join("types.rs"))?);
193-
writeln!(types_rs)?;
194-
195-
let mut sys_rs = BufWriter::new(File::create(target_module_dir.join("sys.rs"))?);
196-
writeln!(sys_rs, "use crate::{{mod_prelude_sys::*, core}};")?;
197-
writeln!(sys_rs)?;
198-
199-
for module in modules {
200-
// merge multiple *-type.cpp files into a single module_types.hpp
201-
let module_cpp = OUT_DIR.join(format!("{module}.cpp"));
202-
if module_cpp.is_file() {
203-
let module_types_cpp = OUT_DIR.join(format!("{module}_types.hpp"));
204-
let mut module_types_file = BufWriter::new(
205-
OpenOptions::new()
206-
.create(true)
207-
.truncate(true)
208-
.write(true)
209-
.open(module_types_cpp)?,
210-
);
211-
let mut type_files = files_with_extension(&OUT_DIR, "cpp")?
212-
.filter(|f| is_type_file(f, module))
213-
.collect::<Vec<_>>();
214-
type_files.sort_unstable();
215-
for entry in type_files {
216-
io::copy(&mut BufReader::new(File::open(&entry)?), &mut module_types_file)?;
217-
let _ = fs::remove_file(entry);
218-
}
219-
}
220-
221-
// add module entry to hub.rs and move the module file into opencv/
222-
write_has_module(&mut hub_rs, module)?;
223-
write_module_include(&mut hub_rs, module)?;
224-
let module_filename = format!("{module}.rs");
225-
let module_src_file = OUT_DIR.join(&module_filename);
226-
let mut module_rs = BufWriter::new(File::create(target_module_dir.join(&module_filename))?);
227-
// Need to wrap modules inside `mod { }` because they have top-level comments (//!) and those don't play well when
228-
// module file is include!d (as opposed to connecting the module with `mod` from the parent module).
229-
// The same doesn't apply to `sys` and `types` below because they don't contain top-level comments.
230-
writeln!(module_rs, "pub mod {module} {{")?;
231-
copy_indent(BufReader::new(File::open(&module_src_file)?), &mut module_rs, "\t")?;
232-
add_manual(&mut module_rs, module)?;
233-
writeln!(module_rs, "}}")?;
234-
let _ = fs::remove_file(module_src_file);
235-
236-
// merge multiple *-.type.rs files into a single types.rs
237-
let mut header_written = false;
238-
let mut type_files = files_with_extension(&OUT_DIR, "rs")?
239-
.filter(|f| is_type_file(f, module))
240-
.collect::<Vec<_>>();
241-
type_files.sort_unstable();
242-
for entry in type_files {
243-
if entry.metadata().map(|meta| meta.len()).unwrap_or(0) > 0 {
244-
if !header_written {
245-
write_has_module(&mut types_rs, module)?;
246-
writeln!(types_rs, "mod {module}_types {{")?;
247-
writeln!(types_rs, "\tuse crate::{{mod_prelude::*, core, types, sys}};")?;
248-
writeln!(types_rs)?;
249-
header_written = true;
133+
impl Jobserver {
134+
pub fn build() -> Result<Self> {
135+
unsafe { jobserver::Client::from_env() }
136+
.and_then(|client| {
137+
let own_token_released = client.release_raw().is_ok();
138+
let available_jobs = client.available().unwrap_or(0);
139+
if available_jobs > 0 {
140+
eprintln!("=== Using environment job server with the the amount of available jobs: {available_jobs}");
141+
Some(Jobserver {
142+
client,
143+
reacquire_token_on_drop: own_token_released,
144+
})
145+
} else {
146+
if own_token_released {
147+
client.acquire_raw().expect("Can't reacquire build script thread token");
148+
}
149+
eprintln!(
150+
"=== Available jobs from the environment created jobserver is: {available_jobs} or there is an error reading that value"
151+
);
152+
None
250153
}
251-
copy_indent(BufReader::new(File::open(&entry)?), &mut types_rs, "\t")?;
252-
}
253-
let _ = fs::remove_file(entry);
254-
}
255-
if header_written {
256-
writeln!(types_rs, "}}")?;
257-
write_has_module(&mut types_rs, module)?;
258-
writeln!(types_rs, "pub use {module}_types::*;")?;
259-
writeln!(types_rs)?;
260-
}
261-
262-
// merge module-specific *.externs.rs and generated type-specific *.type.externs.rs into a single sys.rs
263-
let externs_rs = OUT_DIR.join(format!("{module}.externs.rs"));
264-
write_has_module(&mut sys_rs, module)?;
265-
writeln!(sys_rs, "mod {module}_sys {{")?;
266-
writeln!(sys_rs, "\tuse super::*;")?;
267-
writeln!(sys_rs)?;
268-
writeln!(sys_rs, "\textern \"C\" {{")?;
269-
copy_indent(BufReader::new(File::open(&externs_rs)?), &mut sys_rs, "\t\t")?;
270-
let _ = fs::remove_file(externs_rs);
271-
let mut type_extern_files = files_with_extension(&OUT_DIR, "rs")?
272-
.filter(|f| is_type_externs_file(f, module))
273-
.collect::<Vec<_>>();
274-
type_extern_files.sort_unstable();
275-
for entry in type_extern_files {
276-
if entry.metadata().map(|meta| meta.len()).unwrap_or(0) > 0 {
277-
copy_indent(BufReader::new(File::open(&entry)?), &mut sys_rs, "\t\t")?;
278-
}
279-
let _ = fs::remove_file(entry);
280-
}
281-
writeln!(sys_rs, "\t}}")?;
282-
writeln!(sys_rs, "}}")?;
283-
write_has_module(&mut sys_rs, module)?;
284-
writeln!(sys_rs, "pub use {module}_sys::*;")?;
285-
writeln!(sys_rs)?;
286-
}
287-
writeln!(hub_rs, "pub mod types {{")?;
288-
write!(hub_rs, "\t")?;
289-
write_module_include(&mut hub_rs, "types")?;
290-
writeln!(hub_rs, "}}")?;
291-
writeln!(hub_rs, "#[doc(hidden)]")?;
292-
writeln!(hub_rs, "pub mod sys {{")?;
293-
write!(hub_rs, "\t")?;
294-
write_module_include(&mut hub_rs, "sys")?;
295-
writeln!(hub_rs, "}}")?;
296-
297-
add_manual(&mut types_rs, "types")?;
298-
299-
add_manual(&mut sys_rs, "sys")?;
300-
301-
// write hub_prelude that imports all module-specific preludes
302-
writeln!(hub_rs, "pub mod hub_prelude {{")?;
303-
for module in modules {
304-
write!(hub_rs, "\t")?;
305-
write_has_module(&mut hub_rs, module)?;
306-
writeln!(hub_rs, "\tpub use super::{module}::prelude::*;")?;
307-
}
308-
writeln!(hub_rs, "}}")?;
309-
eprintln!("=== Total binding collection time: {:?}", start.elapsed());
310-
Ok(())
311-
}
312-
313-
fn build_job_server() -> Result<Jobserver> {
314-
unsafe { jobserver::Client::from_env() }
315-
.and_then(|client| {
316-
let own_token_released = client.release_raw().is_ok();
317-
let available_jobs = client.available().unwrap_or(0);
318-
if available_jobs > 0 {
319-
eprintln!("=== Using environment job server with the the amount of available jobs: {available_jobs}");
320-
Some(Jobserver {
154+
})
155+
.or_else(|| {
156+
let num_jobs = env::var("NUM_JOBS")
157+
.ok()
158+
.and_then(|jobs| jobs.parse().ok())
159+
.or_else(|| thread::available_parallelism().map(|p| p.get()).ok())
160+
.unwrap_or(2)
161+
.max(1);
162+
eprintln!("=== Creating a new job server with num_jobs: {num_jobs}");
163+
jobserver::Client::new(num_jobs).ok().map(|client| Jobserver {
321164
client,
322-
reacquire_token_on_drop: own_token_released,
165+
reacquire_token_on_drop: false,
323166
})
324-
} else {
325-
if own_token_released {
326-
client.acquire_raw().expect("Can't reacquire build script thread token");
327-
}
328-
eprintln!(
329-
"=== Available jobs from the environment created jobserver is: {available_jobs} or there is an error reading that value"
330-
);
331-
None
332-
}
333-
})
334-
.or_else(|| {
335-
let num_jobs = env::var("NUM_JOBS")
336-
.ok()
337-
.and_then(|jobs| jobs.parse().ok())
338-
.or_else(|| thread::available_parallelism().map(|p| p.get()).ok())
339-
.unwrap_or(2)
340-
.max(1);
341-
eprintln!("=== Creating a new job server with num_jobs: {num_jobs}");
342-
jobserver::Client::new(num_jobs).ok().map(|client| Jobserver {
343-
client,
344-
reacquire_token_on_drop: false,
345167
})
346-
})
347-
.ok_or_else(|| "Can't create job server".into())
348-
}
349-
350-
pub struct Jobserver {
351-
client: jobserver::Client,
352-
reacquire_token_on_drop: bool,
168+
.ok_or_else(|| "Can't create job server".into())
169+
}
353170
}
354171

355172
impl Drop for Jobserver {

0 commit comments

Comments
 (0)