Skip to content

Commit 03bdbb0

Browse files
fix: consistent macOS deployment target for Metal compatibility
Ensure cmake, the C++ compiler, and the Rust linker all use the same macOS deployment target. Mismatch between these components causes ___isPlatformVersionAtLeast linking errors. Resolution priority: 1. MACOSX_DEPLOYMENT_TARGET env var (user override) 2. Current system macOS version (via sw_vers) 3. MLX minimum (14.0) as final fallback Enforces a floor of macOS 14.0 (MLX's minimum requirement) with a cargo warning if a lower target is requested. Fixes: ml-explore/mlx#1602
1 parent fc41a8f commit 03bdbb0

File tree

1 file changed

+78
-0
lines changed

1 file changed

+78
-0
lines changed

mlx-sys/build.rs

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,65 @@ extern crate cmake;
33
use cmake::Config;
44
use std::{env, path::PathBuf, process::Command};
55

6+
/// MLX requires macOS >= 14.0 (Sonoma).
7+
#[cfg(target_os = "macos")]
8+
const MLX_MIN_MACOS_VERSION: &str = "14.0";
9+
10+
/// Query the current macOS version via `sw_vers -productVersion`.
11+
#[cfg(target_os = "macos")]
12+
fn detect_macos_version() -> Option<String> {
13+
let output = Command::new("sw_vers")
14+
.args(["-productVersion"])
15+
.output()
16+
.ok()?;
17+
if !output.status.success() {
18+
return None;
19+
}
20+
let version = String::from_utf8_lossy(&output.stdout).trim().to_string();
21+
if version.is_empty() {
22+
None
23+
} else {
24+
Some(version)
25+
}
26+
}
27+
28+
/// Resolve the macOS deployment target.
29+
///
30+
/// Priority:
31+
/// 1. `MACOSX_DEPLOYMENT_TARGET` env var (user override)
32+
/// 2. Current system macOS version (via `sw_vers`)
33+
/// 3. MLX minimum (14.0) as final fallback
34+
///
35+
/// Ensures the resolved target is at least [`MLX_MIN_MACOS_VERSION`].
36+
#[cfg(target_os = "macos")]
37+
fn resolve_deployment_target() -> String {
38+
let target = env::var("MACOSX_DEPLOYMENT_TARGET")
39+
.ok()
40+
.or_else(detect_macos_version)
41+
.unwrap_or_else(|| MLX_MIN_MACOS_VERSION.to_string());
42+
43+
// Parse major version to enforce minimum
44+
let major: u32 = target
45+
.split('.')
46+
.next()
47+
.and_then(|s| s.parse().ok())
48+
.unwrap_or(14);
49+
let min_major: u32 = MLX_MIN_MACOS_VERSION
50+
.split('.')
51+
.next()
52+
.and_then(|s| s.parse().ok())
53+
.unwrap_or(14);
54+
55+
if major < min_major {
56+
eprintln!(
57+
"cargo:warning=MACOSX_DEPLOYMENT_TARGET={target} is below MLX minimum ({MLX_MIN_MACOS_VERSION}), using {MLX_MIN_MACOS_VERSION}"
58+
);
59+
MLX_MIN_MACOS_VERSION.to_string()
60+
} else {
61+
target
62+
}
63+
}
64+
665
/// Find the clang runtime library path dynamically using xcrun
766
fn find_clang_rt_path() -> Option<String> {
867
// Use xcrun to find the active toolchain path
@@ -53,6 +112,18 @@ fn build_and_link_mlx_c() {
53112
config.define("CMAKE_C_COMPILER", "/usr/bin/cc");
54113
config.define("CMAKE_CXX_COMPILER", "/usr/bin/c++");
55114

115+
// Ensure consistent macOS deployment target across cmake, C++ compiler, and Rust linker.
116+
// Mismatch causes ___isPlatformVersionAtLeast linking errors.
117+
// See: https://github.com/ml-explore/mlx/issues/1602
118+
#[cfg(target_os = "macos")]
119+
let deployment_target = {
120+
let target = resolve_deployment_target();
121+
config.define("CMAKE_OSX_DEPLOYMENT_TARGET", &target);
122+
env::set_var("MACOSX_DEPLOYMENT_TARGET", &target);
123+
println!("cargo:rerun-if-env-changed=MACOSX_DEPLOYMENT_TARGET");
124+
target
125+
};
126+
56127
#[cfg(debug_assertions)]
57128
{
58129
config.define("CMAKE_BUILD_TYPE", "Debug");
@@ -97,6 +168,13 @@ fn build_and_link_mlx_c() {
97168
println!("cargo:rustc-link-lib=framework=Accelerate");
98169
}
99170

171+
// Pass matching deployment target to the Rust linker so all components agree.
172+
#[cfg(target_os = "macos")]
173+
println!(
174+
"cargo:rustc-link-arg=-mmacosx-version-min={}",
175+
deployment_target
176+
);
177+
100178
// Link against Xcode's clang runtime for ___isPlatformVersionAtLeast symbol
101179
// This is needed on macOS 26+ where the bundled LLVM runtime may be outdated
102180
// See: https://github.com/conda-forge/llvmdev-feedstock/issues/244

0 commit comments

Comments
 (0)