Skip to content

Commit

Permalink
Pure refactor - cleanup build script
Browse files Browse the repository at this point in the history
The OS detection code was bothering me as it wasn't properly doing cross
compilation (some places were and some weren't). Additionally, the OS
detection was a bit haphazard. This is a pure cleanup that parses the
information in TARGET up-front into an enum that is then checked instead
of working with strings.
  • Loading branch information
vlovich committed Feb 13, 2025
1 parent 04e9e31 commit 251b97e
Showing 1 changed file with 97 additions and 51 deletions.
148 changes: 97 additions & 51 deletions llama-cpp-sys-2/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,23 @@ use std::path::{Path, PathBuf};
use std::process::Command;
use walkdir::DirEntry;

enum WindowsVariant {
Msvc,
Other,
}

enum AppleVariant {
MacOS,
Other,
}

enum TargetOs {
Windows(WindowsVariant),
Apple(AppleVariant),
Linux,
Android,
}

macro_rules! debug_log {
($($arg:tt)*) => {
if std::env::var("BUILD_DEBUG").is_ok() {
Expand All @@ -13,6 +30,30 @@ macro_rules! debug_log {
};
}

fn parse_target_os() -> Result<(TargetOs, String), String> {
let target = env::var("TARGET").unwrap();

if target.contains("windows") {
if target.ends_with("-windows-msvc") {
Ok((TargetOs::Windows(WindowsVariant::Msvc), target))
} else {
Ok((TargetOs::Windows(WindowsVariant::Other), target))
}
} else if target.contains("linux") {
Ok((TargetOs::Linux, target))
} else if target.contains("apple") {
if target.ends_with("-apple-darwin") {
Ok((TargetOs::Apple(AppleVariant::MacOS), target))
} else {
Ok((TargetOs::Apple(AppleVariant::Other), target))
}
} else if target.contains("android") {
Ok((TargetOs::Android, target))
} else {
Err(target)
}
}

fn get_cargo_target_dir() -> Result<PathBuf, Box<dyn std::error::Error>> {
let out_dir = env::var("OUT_DIR")?;
let path = PathBuf::from(out_dir);
Expand Down Expand Up @@ -132,7 +173,8 @@ fn is_hidden(e: &DirEntry) -> bool {
fn main() {
println!("cargo:rerun-if-changed=build.rs");

let target = env::var("TARGET").unwrap();
let (target_os, target_triple) =
parse_target_os().unwrap_or_else(|t| panic!("Failed to parse target os {t}"));
let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap());

let target_dir = get_cargo_target_dir().unwrap();
Expand All @@ -152,7 +194,7 @@ fn main() {
println!("cargo:rerun-if-env-changed=LLAMA_BUILD_SHARED_LIBS");
println!("cargo:rerun-if-env-changed=LLAMA_STATIC_CRT");

debug_log!("TARGET: {}", target);
debug_log!("TARGET: {}", target_triple);
debug_log!("CARGO_MANIFEST_DIR: {}", manifest_dir);
debug_log!("TARGET_DIR: {}", target_dir.display());
debug_log!("OUT_DIR: {}", out_dir.display());
Expand Down Expand Up @@ -232,15 +274,13 @@ fn main() {
if build_shared_libs { "ON" } else { "OFF" },
);

if cfg!(target_os = "macos") {
if matches!(target_os, TargetOs::Apple(_)) {
config.define("GGML_BLAS", "OFF");
}

if cfg!(windows) {
config.static_crt(static_crt);
}
config.static_crt(static_crt);

if target.contains("android") {
if matches!(target_os, TargetOs::Android) {
// build flags for android taken from this doc
// https://github.com/ggerganov/llama.cpp/blob/master/docs/android.md
let android_ndk = env::var("ANDROID_NDK")
Expand All @@ -257,21 +297,21 @@ fn main() {
} else {
config.define("ANDROID_PLATFORM", "android-28");
}
if target.contains("aarch64") {
if target_triple.contains("aarch64") {
config.cflag("-march=armv8.7a");
config.cxxflag("-march=armv8.7a");
} else if target.contains("armv7") {
} else if target_triple.contains("armv7") {
config.cflag("-march=armv8.7a");
config.cxxflag("-march=armv8.7a");
} else if target.contains("x86_64") {
} else if target_triple.contains("x86_64") {
config.cflag("-march=x86-64");
config.cxxflag("-march=x86-64");
} else if target.contains("i686") {
} else if target_triple.contains("i686") {
config.cflag("-march=i686");
config.cxxflag("-march=i686");
} else {
// Rather than guessing just fail.
panic!("Unsupported Android target {target}");
panic!("Unsupported Android target {target_triple}");
}
config.define("GGML_LLAMAFILE", "OFF");
if cfg!(feature = "shared-stdcxx") {
Expand All @@ -282,16 +322,19 @@ fn main() {

if cfg!(feature = "vulkan") {
config.define("GGML_VULKAN", "ON");
if cfg!(windows) {
let vulkan_path = env::var("VULKAN_SDK")
.expect("Please install Vulkan SDK and ensure that VULKAN_SDK env variable is set");
let vulkan_lib_path = Path::new(&vulkan_path).join("Lib");
println!("cargo:rustc-link-search={}", vulkan_lib_path.display());
println!("cargo:rustc-link-lib=vulkan-1");
}

if cfg!(target_os = "linux") {
println!("cargo:rustc-link-lib=vulkan");
match target_os {
TargetOs::Windows(_) => {
let vulkan_path = env::var("VULKAN_SDK").expect(
"Please install Vulkan SDK and ensure that VULKAN_SDK env variable is set",
);
let vulkan_lib_path = Path::new(&vulkan_path).join("Lib");
println!("cargo:rustc-link-search={}", vulkan_lib_path.display());
println!("cargo:rustc-link-lib=vulkan-1");
}
TargetOs::Linux => {
println!("cargo:rustc-link-lib=vulkan");
}
_ => (),
}
}

Expand All @@ -302,7 +345,7 @@ fn main() {
// Android doesn't have OpenMP support AFAICT and openmp is a default feature. Do this here
// rather than modifying the defaults in Cargo.toml just in case someone enables the OpenMP feature
// and tries to build for Android anyway.
if cfg!(feature = "openmp") && !target.contains("android") {
if cfg!(feature = "openmp") && !matches!(target_os, TargetOs::Android) {
config.define("GGML_OPENMP", "ON");
} else {
config.define("GGML_OPENMP", "OFF");
Expand Down Expand Up @@ -341,38 +384,41 @@ fn main() {
}

// OpenMP
if cfg!(feature = "openmp") && target.contains("gnu") {
if cfg!(feature = "openmp") && target_triple.contains("gnu") {
println!("cargo:rustc-link-lib=gomp");
}

// Windows debug
if cfg!(all(debug_assertions, windows)) {
println!("cargo:rustc-link-lib=dylib=msvcrtd");
}

// // macOS
if cfg!(target_os = "macos") {
println!("cargo:rustc-link-lib=framework=Foundation");
println!("cargo:rustc-link-lib=framework=Metal");
println!("cargo:rustc-link-lib=framework=MetalKit");
println!("cargo:rustc-link-lib=framework=Accelerate");
println!("cargo:rustc-link-lib=c++");
}

// Linux
if cfg!(target_os = "linux") {
println!("cargo:rustc-link-lib=dylib=stdc++");
}

if target.contains("apple") {
// On (older) OSX we need to link against the clang runtime,
// which is hidden in some non-default path.
//
// More details at https://github.com/alexcrichton/curl-rust/issues/279.
if let Some(path) = macos_link_search_path() {
println!("cargo:rustc-link-lib=clang_rt.osx");
println!("cargo:rustc-link-search={}", path);
match target_os {
TargetOs::Windows(WindowsVariant::Msvc) => {
if cfg!(debug_assertions) {
println!("cargo:rustc-link-lib=dylib=msvcrtd");
}
}
TargetOs::Linux => {
println!("cargo:rustc-link-lib=dylib=stdc++");
}
TargetOs::Apple(variant) => {
println!("cargo:rustc-link-lib=framework=Foundation");
println!("cargo:rustc-link-lib=framework=Metal");
println!("cargo:rustc-link-lib=framework=MetalKit");
println!("cargo:rustc-link-lib=framework=Accelerate");
println!("cargo:rustc-link-lib=c++");

match variant {
AppleVariant::MacOS => {
// On (older) OSX we need to link against the clang runtime,
// which is hidden in some non-default path.
//
// More details at https://github.com/alexcrichton/curl-rust/issues/279.
if let Some(path) = macos_link_search_path() {
println!("cargo:rustc-link-lib=clang_rt.osx");
println!("cargo:rustc-link-search={}", path);
}
}
AppleVariant::Other => (),
}
}
_ => (),
}

// copy DLLs to target
Expand Down

0 comments on commit 251b97e

Please sign in to comment.