use crate::cli::Args;
use crate::color;
use crate::config::{Arch, HostPlatform, TargetConfig};
use crate::download::download_and_extract;
use crate::env::CrossEnv;
use crate::error::{CrossError, Result};
use crate::platform::{setup_cmake, setup_generic_cmake_toolchain};
use crate::runner;
pub async fn setup(
target_config: &TargetConfig,
args: &Args,
host: &HostPlatform,
) -> Result<CrossEnv> {
let arch = target_config.arch;
let rust_target = target_config.target;
if host.is_darwin() {
setup_native(arch, rust_target, args, host).await
} else if host.is_linux() {
setup_osxcross(arch, rust_target, args, host).await
} else {
Err(CrossError::CrossCompilationNotSupported {
target_os: "darwin".to_string(),
host_os: host.os.to_string(),
})
}
}
async fn setup_native(
arch: Arch,
rust_target: &str,
args: &Args,
host: &HostPlatform,
) -> Result<CrossEnv> {
let mut env = CrossEnv::new();
if args.command.needs_runner() {
runner::setup_rosetta_runner(&mut env, arch, rust_target, host);
}
let sdk_path = if let Some(ref path) = args.macos_sdk_path {
if !path.exists() {
return Err(CrossError::SdkPathNotExist { path: path.clone() });
}
Some(path.clone())
} else {
super::find_apple_sdk(super::AppleSdkType::MacOS, &args.macos_sdk_version).await
};
if let Some(ref sdk) = sdk_path {
env.set_sdkroot(sdk);
env.add_rustflag(format!("-C link-arg=--sysroot={}", sdk.display()));
color::log_success(&format!(
"Using macOS SDK at {}",
color::cyan(&sdk.display().to_string())
));
}
setup_cmake(&mut env, args.cmake_generator.as_deref(), host.is_windows());
setup_generic_cmake_toolchain(&mut env);
color::log_success(&format!(
"Using native macOS toolchain for {}",
color::yellow(rust_target)
));
Ok(env)
}
async fn setup_osxcross(
arch: Arch,
rust_target: &str,
args: &Args,
host: &HostPlatform,
) -> Result<CrossEnv> {
let host_arch_name = match host.arch {
"x86_64" | "amd64" => "amd64",
"aarch64" | "arm64" => "aarch64",
_ => {
return Err(CrossError::CrossCompilationNotSupported {
target_os: "darwin".to_string(),
host_os: format!("{}/{}", host.os, host.arch),
});
}
};
let osxcross_version = "v0.2.6";
let macos_sdk_suffix = args.macos_sdk_version.replace('.', "-");
let osxcross_dir = args.cross_compiler_dir.join(format!(
"osxcross-{macos_sdk_suffix}-{host_arch_name}-{osxcross_version}"
));
if !osxcross_dir.join("bin").exists() {
let ubuntu_version = super::get_ubuntu_version()
.await
.unwrap_or_else(|| "20.04".to_string());
let url_arch = if host_arch_name == "amd64" {
"x86_64"
} else {
host_arch_name
};
let download_url = format!(
"https://github.com/zijiren233/osxcross/releases/download/{osxcross_version}/osxcross-{macos_sdk_suffix}-linux-{url_arch}-gnu-ubuntu-{ubuntu_version}.tar.gz"
);
download_and_extract(
&download_url,
&osxcross_dir,
None,
args.github_proxy.as_deref(),
)
.await?;
}
let mut env = CrossEnv::new();
super::setup_darwin_linker_library_path(&mut env, &osxcross_dir);
env.set_env("OSXCROSS_MP_INC", "1");
env.set_env("MACOSX_DEPLOYMENT_TARGET", "10.12");
if args.verbose_level > 0 {
env.set_env("OCDEBUG", "1");
}
let clang_pattern = format!("{}-apple-darwin*-clang", arch.as_str());
let clang_path = super::find_file_by_pattern(&osxcross_dir.join("bin"), &clang_pattern)
.await
.ok_or_else(|| CrossError::CompilerNotFound {
path: osxcross_dir.join("bin"),
})?;
let tool_prefix = clang_path
.file_name()
.and_then(|n| n.to_str())
.and_then(|n| n.strip_suffix("-clang"))
.ok_or_else(|| CrossError::CompilerNotFound {
path: clang_path.clone(),
})?
.to_string();
env.set_cc(format!("{tool_prefix}-clang"));
env.set_cxx(format!("{tool_prefix}-clang++"));
env.set_ar(format!("{tool_prefix}-ar"));
env.set_linker(format!("{tool_prefix}-clang"));
env.add_path(osxcross_dir.join("bin"));
env.add_path(osxcross_dir.join("clang/bin"));
env.set_env(
"COMPILER_PATH",
osxcross_dir.join("bin").display().to_string(),
);
let linker_path = osxcross_dir.join("bin").join(format!("{tool_prefix}-ld"));
env.add_ldflag(format!("-fuse-ld={}", linker_path.display()));
env.add_rustflag(format!("-C link-arg=-fuse-ld={}", linker_path.display()));
let sdk_dir = osxcross_dir.join("SDK");
if sdk_dir.exists() {
if let Ok(mut entries) = tokio::fs::read_dir(&sdk_dir).await {
while let Ok(Some(entry)) = entries.next_entry().await {
let name = entry.file_name();
if name.to_string_lossy().starts_with("MacOSX") {
let sdk_path = entry.path();
env.set_sdkroot(&sdk_path);
env.add_rustflag(format!("-C link-arg=--sysroot={}", sdk_path.display()));
break;
}
}
}
}
setup_cmake(&mut env, args.cmake_generator.as_deref(), host.is_windows());
setup_generic_cmake_toolchain(&mut env);
color::log_success(&format!(
"Configured osxcross toolchain (SDK {}) for {}",
color::cyan(&args.macos_sdk_version),
color::yellow(rust_target)
));
Ok(env)
}