Support Intel macOS with the last upstream runtime.
Some checks failed
Tagged release / prepare-release (push) Successful in 3m0s
Tagged release / build-linux-x64 (push) Successful in 35m32s
Tagged release / build-macos (push) Failing after 38m56s
Tagged release / build-windows (push) Has been cancelled
Tagged release / publish-release (push) Has been cancelled
Tagged release / build-linux-arm64 (push) Has been cancelled

This commit is contained in:
Hermes Agent
2026-08-15 03:42:22 +00:00
parent 0c32f9fdee
commit d3bfc13e67
8 changed files with 264 additions and 70 deletions

View File

@@ -11,6 +11,9 @@ fn main() -> Result<(), Box<dyn Error>> {
[command, directory] if command == "macos-linker-alias" => {
packaging::prepare_macos_linker_alias(Path::new(directory))
}
[command, directory] if command == "macos-x64-runtime" => {
packaging::prepare_macos_x64_runtime(Path::new(directory))
}
[command, directory, sdk_libraries] if command == "windows-runtime" => {
packaging::prepare_windows_runtime(Path::new(directory), Path::new(sdk_libraries))
}
@@ -42,7 +45,7 @@ fn main() -> Result<(), Box<dyn Error>> {
gitea::upload(assets.iter().map(|path| path.as_path()))
}
_ => Err(
"usage: bds-release prepare|publish|macos-linker-alias <directory>|windows-runtime <directory> <sdk-libraries>|upload <asset>...|package <tag> <release-dir> <rust-lib-dir> <platform> <dist-dir> [--upload]"
"usage: bds-release prepare|publish|macos-linker-alias <directory>|macos-x64-runtime <directory>|windows-runtime <directory> <sdk-libraries>|upload <asset>...|package <tag> <release-dir> <rust-lib-dir> <platform> <dist-dir> [--upload]"
.into(),
),
}

View File

@@ -26,6 +26,9 @@ const LC_LAZY_LOAD_DYLIB: u32 = 0x20;
const LC_LOAD_UPWARD_DYLIB: u32 = 0x8000_0023;
const DIRECTML_VERSION: &str = "1.15.4";
const DIRECTML_SHA256: &str = "4e7cb7ddce8cf837a7a75dc029209b520ca0101470fcdf275c1f49736a3615b9";
const MACOS_X64_ORT_VERSION: &str = "1.23.2";
const MACOS_X64_ORT_SHA256: &str =
"d10359e16347b57d9959f7e80a225a5b4a66ed7d7e007274a15cae86836485a6";
pub(crate) fn prepare_macos_linker_alias(directory: &Path) -> Result<(), Box<dyn Error>> {
fs::create_dir_all(directory)?;
@@ -33,6 +36,72 @@ pub(crate) fn prepare_macos_linker_alias(directory: &Path) -> Result<(), Box<dyn
Ok(())
}
pub(crate) fn prepare_macos_x64_runtime(directory: &Path) -> Result<(), Box<dyn Error>> {
fs::create_dir_all(directory)?;
let archive_path = directory.join(format!(
"onnxruntime-osx-x86_64-{MACOS_X64_ORT_VERSION}.tgz"
));
let result = (|| {
let url = format!(
"https://github.com/microsoft/onnxruntime/releases/download/v{MACOS_X64_ORT_VERSION}/onnxruntime-osx-x86_64-{MACOS_X64_ORT_VERSION}.tgz"
);
let mut response = reqwest::blocking::get(url)?.error_for_status()?;
let mut archive = File::create(&archive_path)?;
io::copy(&mut response, &mut archive)?;
drop(archive);
let mut archive = BufReader::new(File::open(&archive_path)?);
let mut digest = Sha256::new();
let mut buffer = [0_u8; 64 * 1024];
loop {
let read = archive.read(&mut buffer)?;
if read == 0 {
break;
}
digest.update(&buffer[..read]);
}
if format!("{:x}", digest.finalize()) != MACOS_X64_ORT_SHA256 {
return Err("macOS x64 ONNX Runtime archive checksum mismatch".into());
}
prepare_macos_x64_runtime_from_archive(File::open(&archive_path)?, directory)
})();
if archive_path.try_exists()? {
fs::remove_file(archive_path)?;
}
result
}
fn prepare_macos_x64_runtime_from_archive(
archive: impl Read,
directory: &Path,
) -> Result<(), Box<dyn Error>> {
fs::create_dir_all(directory)?;
let decoder = flate2::read::GzDecoder::new(archive);
let mut archive = tar::Archive::new(decoder);
for entry in archive.entries()? {
let mut entry = entry?;
let path = entry.path()?;
let destination = if path.ends_with(format!(
"lib/libonnxruntime.{MACOS_X64_ORT_VERSION}.dylib"
)) {
Some(format!("libonnxruntime.{MACOS_X64_ORT_VERSION}.dylib"))
} else if path.ends_with("LICENSE") {
Some("ONNXRuntime-LICENSE.txt".to_owned())
} else {
None
};
if let Some(destination) = destination {
io::copy(&mut entry, &mut File::create(directory.join(destination))?)?;
}
}
let versioned = directory.join(format!("libonnxruntime.{MACOS_X64_ORT_VERSION}.dylib"));
require_file(&versioned)?;
require_file(&directory.join("ONNXRuntime-LICENSE.txt"))?;
fs::copy(versioned, directory.join("libonnxruntime.dylib"))?;
Ok(())
}
pub(crate) fn prepare_windows_runtime(
directory: &Path,
sdk_libraries: &Path,
@@ -259,12 +328,24 @@ fn runtime_files(
files.push((path, name));
}
let mut external_names = match platform {
Platform::MacOs => fs::read_dir(release_dir)?
.filter_map(Result::ok)
.map(|entry| entry.file_name())
.filter_map(|name| name.into_string().ok())
.filter(|name| name.starts_with("libonnxruntime") && name.contains(".dylib"))
.collect::<Vec<_>>(),
Platform::MacOs => {
let mut names = fs::read_dir(release_dir)?
.filter_map(Result::ok)
.map(|entry| entry.file_name())
.filter_map(|name| name.into_string().ok())
.filter(|name| name.starts_with("libonnxruntime") && name.contains(".dylib"))
.collect::<Vec<_>>();
let has_versioned = names
.iter()
.any(|name| name != "libonnxruntime.dylib");
if has_versioned {
names.retain(|name| name != "libonnxruntime.dylib");
}
if release_dir.join("ONNXRuntime-LICENSE.txt").is_file() {
names.push("ONNXRuntime-LICENSE.txt".to_owned());
}
names
}
Platform::Linux => fs::read_dir(release_dir)?
.filter_map(Result::ok)
.map(|entry| entry.file_name())
@@ -362,7 +443,7 @@ fn macos_dmg<'a>(
for (source, name) in &files {
let entry = FileEntry::new_from_path(source, true);
if name.ends_with(".dylib") {
if is_macos_bundle_resource(name) {
bundle.add_file_resources(name, entry)?;
} else {
bundle.add_file_macos(name, entry)?;
@@ -375,12 +456,14 @@ fn macos_dmg<'a>(
.map(|(_, name)| name.clone())
.collect::<Vec<_>>();
for (_, name) in &files {
let staged = if name.ends_with(".dylib") {
let staged = if is_macos_bundle_resource(name) {
materialized.join("Contents/Resources").join(name)
} else {
materialized.join("Contents/MacOS").join(name)
};
rewrite_macho_rpaths(&staged, &runtime_names)?;
if is_macos_macho(name) {
rewrite_macho_rpaths(&staged, &runtime_names)?;
}
}
let signer = UnifiedSigner::new(SigningSettings::default());
signer.sign_path_in_place(&materialized)?;
@@ -395,6 +478,14 @@ fn macos_dmg<'a>(
Ok(())
}
fn is_macos_bundle_resource(name: &str) -> bool {
name.ends_with(".dylib") || name.ends_with(".txt")
}
fn is_macos_macho(name: &str) -> bool {
!name.ends_with(".txt")
}
fn rewrite_macho_rpaths(path: &Path, runtime_names: &[String]) -> Result<(), Box<dyn Error>> {
let mut bytes = fs::read(path)?;
if read_u32(&bytes, 0)? != 0xfeed_facf {
@@ -582,6 +673,88 @@ mod tests {
);
}
#[test]
fn macos_x64_runtime_extracts_the_versioned_library_and_license() {
let temp = tempdir().unwrap();
let runtime = temp.path().join("runtime");
let archive = Vec::new();
let encoder = GzEncoder::new(archive, Compression::default());
let mut archive = tar::Builder::new(encoder);
for (name, contents) in [
(
"onnxruntime-osx-x86_64-1.23.2/lib/libonnxruntime.1.23.2.dylib",
b"runtime".as_slice(),
),
(
"onnxruntime-osx-x86_64-1.23.2/LICENSE",
b"license".as_slice(),
),
(
"onnxruntime-osx-x86_64-1.23.2/include/onnxruntime.h",
b"header".as_slice(),
),
] {
let mut header = tar::Header::new_gnu();
header.set_size(contents.len() as u64);
header.set_mode(0o644);
header.set_cksum();
archive.append_data(&mut header, name, contents).unwrap();
}
let encoder = archive.into_inner().unwrap();
let archive = std::io::Cursor::new(encoder.finish().unwrap());
prepare_macos_x64_runtime_from_archive(archive, &runtime).unwrap();
assert_eq!(
fs::read(runtime.join("libonnxruntime.1.23.2.dylib")).unwrap(),
b"runtime"
);
assert_eq!(
fs::read(runtime.join("libonnxruntime.dylib")).unwrap(),
b"runtime"
);
assert_eq!(
fs::read(runtime.join("ONNXRuntime-LICENSE.txt")).unwrap(),
b"license"
);
assert_eq!(fs::read_dir(runtime).unwrap().count(), 3);
}
#[test]
fn macos_runtime_files_package_one_versioned_ort_library_and_its_license() {
let temp = tempdir().unwrap();
let release = temp.path().join("release");
let rust_libs = temp.path().join("rust-libs");
fs::create_dir(&release).unwrap();
fs::create_dir(&rust_libs).unwrap();
for file in [
"libbds_core.dylib",
"libbds_server.dylib",
"libonnxruntime.dylib",
"libonnxruntime.1.23.2.dylib",
"ONNXRuntime-LICENSE.txt",
] {
fs::write(release.join(file), file).unwrap();
}
let files = runtime_files(Platform::MacOs, &release, &rust_libs).unwrap();
let names = files.into_iter().map(|(_, name)| name).collect::<Vec<_>>();
assert!(names.contains(&"libonnxruntime.1.23.2.dylib".to_owned()));
assert!(names.contains(&"ONNXRuntime-LICENSE.txt".to_owned()));
assert!(!names.contains(&"libonnxruntime.dylib".to_owned()));
}
#[test]
fn macos_license_is_a_non_macho_bundle_resource() {
assert!(is_macos_bundle_resource("ONNXRuntime-LICENSE.txt"));
assert!(!is_macos_macho("ONNXRuntime-LICENSE.txt"));
assert!(is_macos_bundle_resource("libonnxruntime.1.23.2.dylib"));
assert!(is_macos_macho("libonnxruntime.1.23.2.dylib"));
assert!(!is_macos_bundle_resource("bds-ui"));
assert!(is_macos_macho("bds-ui"));
}
#[test]
fn windows_runtime_extracts_only_redistributable_files() {
let temp = tempdir().unwrap();