ctranslate2_src_build_support/
lib.rs

1use std::{
2    env,
3    fs::File,
4    path::{Path, PathBuf},
5};
6
7use flate2::Compression;
8use tar::Builder;
9use walkdir::WalkDir;
10
11mod a;
12pub mod dnnl;
13pub mod download;
14pub mod file_changes;
15pub mod native;
16pub mod submodules;
17pub mod windows_crt_patch;
18pub use a::main;
19
20#[derive(Debug, Eq, PartialEq, Copy, Clone)]
21pub enum Os {
22    Win,
23    Mac,
24    Linux,
25    Unknown,
26}
27
28pub fn export(lib_path: &Path, modules: &[PathBuf], modules2: &[PathBuf]) {
29    let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap());
30    let out_dir = out_dir
31        .parent()
32        .unwrap()
33        .parent()
34        .unwrap()
35        .parent()
36        .unwrap();
37
38    let tar_gz = File::create(out_dir.join("vendored.tar.gz")).unwrap();
39    let enc = flate2::write::GzEncoder::new(tar_gz, Compression::default());
40    let mut tar = Builder::new(enc);
41
42    tar.append_dir_all("include", lib_path.join("../include"))
43        .unwrap();
44
45    for module in modules {
46        let mut file = File::open(&module).unwrap();
47        let name = module.file_name().unwrap().to_str().unwrap();
48        tar.append_file(format!("lib/{}", name), &mut file).unwrap();
49    }
50    for module in modules2 {
51        let mut file = File::open(&module).unwrap();
52        let name = module.file_name().unwrap().to_str().unwrap();
53        tar.append_file(format!("dyn/{}", name), &mut file).unwrap();
54    }
55
56    tar.finish().unwrap();
57}
58
59pub fn link_libraries<T: AsRef<Path>>(root: T) -> Vec<PathBuf> {
60    let mut current_dir = None;
61    let mut libs = Vec::new();
62    for entry in WalkDir::new(root).into_iter().filter_map(Result::ok) {
63        let path = entry.path();
64        if path.is_file() {
65            if let Some(file_name) = path
66                .file_name()
67                .and_then(|name| name.to_str())
68                .filter(|name| is_library(name))
69            {
70                let parent = path.parent().unwrap();
71                if Some(parent) != current_dir.as_deref() {
72                    println!("cargo:rustc-link-search={}", parent.display());
73                    current_dir = Some(parent.to_path_buf());
74                }
75                libs.push(path.to_path_buf());
76
77                let lib_name = library_name(file_name);
78                println!("cargo:rustc-link-lib=static={}", lib_name);
79            }
80        }
81    }
82    libs
83}
84
85#[cfg(not(target_os = "windows"))]
86fn is_library(name: &&str) -> bool {
87    name.starts_with("lib") && name.ends_with(".a")
88}
89
90#[cfg(not(target_os = "windows"))]
91fn library_name(name: &str) -> &str {
92    &name[3..name.len() - 2]
93}
94
95#[cfg(target_os = "windows")]
96fn is_library(name: &&str) -> bool {
97    name.ends_with(".lib") && !name.starts_with(".")
98}
99
100#[cfg(target_os = "windows")]
101fn library_name(name: &str) -> &str {
102    &name[0..name.len() - 4]
103}
104
105pub fn link_dynamic_libraries<T: AsRef<Path>>(root: T) -> Vec<PathBuf> {
106    let mut current_dir = None;
107    let mut libs = Vec::new();
108
109    for entry in WalkDir::new(root).into_iter().filter_map(Result::ok) {
110        let path = entry.path();
111        if path.is_file() {
112            if let Some(file_name) = path
113                .file_name()
114                .and_then(|name| name.to_str())
115                .filter(|name| is_dynamic_library(name))
116            {
117                let parent = path.parent().unwrap();
118                if Some(parent) != current_dir.as_deref() {
119                    println!("cargo:rustc-link-search={}", parent.display());
120                    current_dir = Some(parent.to_path_buf());
121                }
122                libs.push(path.to_path_buf());
123
124                let lib_name = dynamic_library_name(file_name);
125                println!("cargo:rustc-link-lib=dylib={}", lib_name);
126            }
127        }
128    }
129
130    libs
131}
132
133#[cfg(target_os = "linux")]
134fn is_dynamic_library(name: &str) -> bool {
135    name.starts_with("lib") && name.ends_with(".so")
136}
137
138#[cfg(target_os = "linux")]
139fn dynamic_library_name(name: &str) -> &str {
140    &name[3..name.len() - 3] // remove "lib" prefix and ".so" suffix
141}
142
143#[cfg(target_os = "macos")]
144fn is_dynamic_library(name: &str) -> bool {
145    name.starts_with("lib") && name.ends_with(".dylib")
146}
147
148#[cfg(target_os = "macos")]
149fn dynamic_library_name(name: &str) -> &str {
150    &name[3..name.len() - 6] // remove "lib" prefix and ".dylib" suffix
151}
152
153#[cfg(target_os = "windows")]
154fn is_dynamic_library(name: &str) -> bool {
155    // On Windows, Cargo links to the .lib import library, but you can also detect .dll
156    name.ends_with(".lib") && !name.starts_with(".")
157}
158
159#[cfg(target_os = "windows")]
160fn dynamic_library_name(name: &str) -> &str {
161    &name[0..name.len() - 4] // remove ".lib"
162}