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