llama_cpp_bindings_build/
lib.rs1mod android_ndk;
4mod bindgen_config;
5mod cmake_config;
6mod cpp_wrapper;
7mod cpp_wrapper_mtmd;
8mod glob_paths;
9mod library_asset_extraction;
10mod library_linking;
11mod library_name_extraction;
12mod rebuild_tracking;
13mod shared_libs;
14mod stable_cmake_build_dir;
15mod target_os;
16
17use std::env;
18use std::path::{Path, PathBuf};
19
20use android_ndk::AndroidNdk;
21use stable_cmake_build_dir::stable_cmake_build_dir;
22use target_os::TargetOs;
23
24#[macro_export]
25macro_rules! debug_log {
26 ($($arg:tt)*) => {
27 if std::env::var("BUILD_DEBUG").is_ok() {
28 println!("cargo:warning=[DEBUG] {}", format!($($arg)*));
29 }
30 };
31}
32
33#[derive(Debug)]
35pub struct BuildContext {
36 pub out_dir: PathBuf,
37 pub target_dir: PathBuf,
38 pub cmake_dir: PathBuf,
39 pub llama_src: PathBuf,
40 pub target_os: TargetOs,
41 pub target_triple: String,
42 pub build_shared_libs: bool,
43 pub profile: String,
44 pub static_crt: bool,
45 pub android_ndk: Option<AndroidNdk>,
46}
47
48impl BuildContext {
49 fn detect() -> Self {
50 let target_triple =
51 env::var("TARGET").expect("TARGET env var is required in build scripts");
52 let target_os = TargetOs::from_target_triple(&target_triple)
53 .unwrap_or_else(|error| panic!("Failed to parse target OS: {error}"));
54 let out_dir = PathBuf::from(
55 env::var("OUT_DIR").expect("OUT_DIR env var is required in build scripts"),
56 );
57 let target_dir = cargo_target_dir(&out_dir);
58 let manifest_dir = env::var("CARGO_MANIFEST_DIR")
59 .expect("CARGO_MANIFEST_DIR env var is required in build scripts");
60 let llama_src = Path::new(&manifest_dir).join("llama.cpp");
61
62 let build_shared_libs = env::var("LLAMA_BUILD_SHARED_LIBS")
63 .map_or_else(|_| cfg!(feature = "dynamic-link"), |value| value == "1");
64
65 let profile = env::var("LLAMA_LIB_PROFILE").unwrap_or_else(|_| "Release".to_string());
66
67 let static_crt = env::var("LLAMA_STATIC_CRT")
68 .map(|value| value == "1")
69 .unwrap_or(false);
70
71 let android_ndk = if target_os.is_android() {
72 Some(
73 AndroidNdk::detect(&target_triple)
74 .unwrap_or_else(|error| panic!("Android NDK detection failed: {error}")),
75 )
76 } else {
77 None
78 };
79
80 let cmake_dir = stable_cmake_build_dir(
81 &target_dir,
82 &target_triple,
83 &profile,
84 static_crt,
85 build_shared_libs,
86 );
87
88 debug_log!("TARGET: {}", target_triple);
89 debug_log!("CARGO_MANIFEST_DIR: {}", manifest_dir);
90 debug_log!("TARGET_DIR: {}", target_dir.display());
91 debug_log!("OUT_DIR: {}", out_dir.display());
92 debug_log!("CMAKE_DIR: {}", cmake_dir.display());
93 debug_log!("BUILD_SHARED: {}", build_shared_libs);
94
95 Self {
96 out_dir,
97 target_dir,
98 cmake_dir,
99 llama_src,
100 target_os,
101 target_triple,
102 build_shared_libs,
103 profile,
104 static_crt,
105 android_ndk,
106 }
107 }
108}
109
110fn cargo_target_dir(out_dir: &Path) -> PathBuf {
111 out_dir
112 .ancestors()
113 .nth(3)
114 .expect("OUT_DIR is not deep enough to determine target directory")
115 .to_path_buf()
116}
117
118fn set_cmake_parallelism() {
119 if let Ok(parallelism) = std::thread::available_parallelism() {
120 unsafe {
122 env::set_var("CMAKE_BUILD_PARALLEL_LEVEL", parallelism.get().to_string());
123 }
124 }
125}
126
127pub fn build() {
131 let context = BuildContext::detect();
132
133 rebuild_tracking::register_rebuild_triggers(&context.llama_src);
134
135 set_cmake_parallelism();
136
137 bindgen_config::generate_bindings(
138 &context.llama_src,
139 &context.out_dir,
140 &context.target_os,
141 &context.target_triple,
142 context.android_ndk.as_ref(),
143 );
144
145 cpp_wrapper::compile_cpp_wrappers(&context.llama_src, &context.target_os);
146
147 let build_dir = cmake_config::configure_and_build(&context);
148
149 cpp_wrapper_mtmd::compile_mtmd(&context.llama_src, &context.target_os);
150
151 library_linking::link_libraries(
152 &context.cmake_dir,
153 &build_dir,
154 &context.target_os,
155 &context.target_triple,
156 context.build_shared_libs,
157 &context.profile,
158 );
159
160 if context.build_shared_libs {
161 shared_libs::copy_shared_libraries(&context.cmake_dir, &context.target_dir);
162 }
163}