Bundle native inference runtimes in releases.
Some checks failed
Tagged release / prepare-release (push) Successful in 2m53s
Tagged release / build-linux-x64 (push) Failing after 6s
Tagged release / build-macos (push) Has been skipped
Tagged release / build-linux-arm64 (push) Has been skipped
Tagged release / build-windows (push) Has been skipped
Tagged release / publish-release (push) Has been skipped
Some checks failed
Tagged release / prepare-release (push) Successful in 2m53s
Tagged release / build-linux-x64 (push) Failing after 6s
Tagged release / build-macos (push) Has been skipped
Tagged release / build-linux-arm64 (push) Has been skipped
Tagged release / build-windows (push) Has been skipped
Tagged release / publish-release (push) Has been skipped
This commit is contained in:
@@ -43,7 +43,7 @@ jobs:
|
|||||||
run: cargo +${RUST_TOOLCHAIN} run --locked --package bds-release -- prepare
|
run: cargo +${RUST_TOOLCHAIN} run --locked --package bds-release -- prepare
|
||||||
|
|
||||||
build-macos:
|
build-macos:
|
||||||
needs: prepare-release
|
needs: [prepare-release, build-linux-x64]
|
||||||
runs-on: linux-arm64
|
runs-on: linux-arm64
|
||||||
container: ghcr.io/rust-cross/cargo-zigbuild@sha256:82af75c41958c2af2787e8bedd912da7678a9438937e223e9d83d006d747b38b
|
container: ghcr.io/rust-cross/cargo-zigbuild@sha256:82af75c41958c2af2787e8bedd912da7678a9438937e223e9d83d006d747b38b
|
||||||
env:
|
env:
|
||||||
@@ -96,7 +96,7 @@ jobs:
|
|||||||
done
|
done
|
||||||
|
|
||||||
build-linux-arm64:
|
build-linux-arm64:
|
||||||
needs: prepare-release
|
needs: [prepare-release, build-linux-x64]
|
||||||
runs-on: linux-arm64
|
runs-on: linux-arm64
|
||||||
env:
|
env:
|
||||||
CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_RUSTFLAGS: -C link-arg=-Wl,-rpath,$ORIGIN
|
CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_RUSTFLAGS: -C link-arg=-Wl,-rpath,$ORIGIN
|
||||||
@@ -174,11 +174,11 @@ jobs:
|
|||||||
"$GITEA_REF_NAME" "target/$target/release" "$rust_lib_dir" linux-x64 dist --upload
|
"$GITEA_REF_NAME" "target/$target/release" "$rust_lib_dir" linux-x64 dist --upload
|
||||||
|
|
||||||
build-windows:
|
build-windows:
|
||||||
needs: prepare-release
|
needs: [prepare-release, build-linux-x64]
|
||||||
runs-on: linux-arm64
|
runs-on: linux-arm64
|
||||||
container: messense/cargo-xwin@sha256:4696dd4e79edf8569fa99c4b06bd99273e0501c7adc983aa61d57945f795bef0
|
container: messense/cargo-xwin@sha256:4696dd4e79edf8569fa99c4b06bd99273e0501c7adc983aa61d57945f795bef0
|
||||||
env:
|
env:
|
||||||
CARGO_TARGET_X86_64_PC_WINDOWS_MSVC_RUSTFLAGS: -C target-feature=+crt-static
|
CARGO_TARGET_X86_64_PC_WINDOWS_MSVC_RUSTFLAGS: -Lnative=target/x86_64-pc-windows-msvc/release
|
||||||
steps:
|
steps:
|
||||||
- name: Check out the tag
|
- name: Check out the tag
|
||||||
env:
|
env:
|
||||||
@@ -211,6 +211,10 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
set -eu
|
set -eu
|
||||||
target=x86_64-pc-windows-msvc
|
target=x86_64-pc-windows-msvc
|
||||||
|
cargo +${RUST_TOOLCHAIN} xwin cache xwin
|
||||||
|
cargo +${RUST_TOOLCHAIN} run --locked --package bds-release -- \
|
||||||
|
windows-runtime "target/$target/release" \
|
||||||
|
/root/.cache/cargo-xwin/xwin/sdk/lib/um/x86_64
|
||||||
cargo +${RUST_TOOLCHAIN} xwin build --release --locked --target "$target" \
|
cargo +${RUST_TOOLCHAIN} xwin build --release --locked --target "$target" \
|
||||||
--package bds-ui --package bds-cli --package bds-mcp
|
--package bds-ui --package bds-cli --package bds-mcp
|
||||||
rust_lib_dir=$(rustc +${RUST_TOOLCHAIN} --target "$target" --print target-libdir)
|
rust_lib_dir=$(rustc +${RUST_TOOLCHAIN} --target "$target" --print target-libdir)
|
||||||
|
|||||||
2
BUILD.md
2
BUILD.md
@@ -24,7 +24,7 @@ Windows packaging requires the MSVC Rust toolchain, Visual Studio Build Tools wi
|
|||||||
|
|
||||||
Pushing a tag runs `.gitea/workflows/release.yml` on Linux arm64. The workflow builds Linux arm64 natively, cross-links Linux x64 with Ubuntu's amd64 development libraries and GNU cross-toolchain, uses Cargo Zigbuild for macOS, Cargo Xwin for Windows x64, and `bds-release` for every packaging and Gitea API operation. It does not require host installations of Python, `curl`, `tar`, `hdiutil`, or NSIS.
|
Pushing a tag runs `.gitea/workflows/release.yml` on Linux arm64. The workflow builds Linux arm64 natively, cross-links Linux x64 with Ubuntu's amd64 development libraries and GNU cross-toolchain, uses Cargo Zigbuild for macOS, Cargo Xwin for Windows x64, and `bds-release` for every packaging and Gitea API operation. It does not require host installations of Python, `curl`, `tar`, `hdiutil`, or NSIS.
|
||||||
|
|
||||||
The workflow publishes CLI/MCP and desktop artifacts for Linux and macOS on arm64 and x64, plus Windows x64. Linux desktop binaries dynamically use the target system's GTK 3, WebKitGTK 4.1, and libxdo runtime packages. macOS desktop artifacts are ad-hoc-signed `.dmg` files, Unix artifacts are `.tar.gz`, and Windows artifacts are `.zip` files containing the native `.exe` application and its runtime DLLs. The Gitea release remains a draft unless every build and upload succeeds.
|
The workflow publishes CLI/MCP and desktop artifacts for Linux and macOS on arm64 and x64, plus Windows x64. Linux desktop binaries dynamically use the target system's GTK 3, WebKitGTK 4.1, and libxdo runtime packages. Every archive includes its downloaded ONNX Runtime shared library; Windows archives also include the checksum-pinned Microsoft DirectML redistributable and license. macOS desktop artifacts are ad-hoc-signed `.dmg` files, Unix artifacts are `.tar.gz`, and Windows artifacts are `.zip` files containing the native `.exe` application and its runtime DLLs. The Gitea release remains a draft unless every build and upload succeeds.
|
||||||
|
|
||||||
## macOS system requirements
|
## macOS system requirements
|
||||||
|
|
||||||
|
|||||||
1
Cargo.lock
generated
1
Cargo.lock
generated
@@ -1213,6 +1213,7 @@ dependencies = [
|
|||||||
"reqwest",
|
"reqwest",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
|
"sha2 0.10.9",
|
||||||
"simple-file-manifest",
|
"simple-file-manifest",
|
||||||
"tar",
|
"tar",
|
||||||
"tempfile",
|
"tempfile",
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ mlua = { version = "0.12", features = ["lua54", "vendored", "serialize"] }
|
|||||||
url = "2.5"
|
url = "2.5"
|
||||||
fastembed = { version = "5.17.3", default-features = false, features = ["hf-hub-rustls-tls", "ort-download-binaries-rustls-tls"] }
|
fastembed = { version = "5.17.3", default-features = false, features = ["hf-hub-rustls-tls", "ort-download-binaries-rustls-tls"] }
|
||||||
usearch = { version = "2.26", default-features = false }
|
usearch = { version = "2.26", default-features = false }
|
||||||
ort = { version = "=2.0.0-rc.12", default-features = false, features = ["std", "api-24", "coreml", "directml"] }
|
ort = { version = "=2.0.0-rc.12", default-features = false, features = ["std", "api-24", "copy-dylibs"] }
|
||||||
russh = "0.62.5"
|
russh = "0.62.5"
|
||||||
ratatui = "0.30.2"
|
ratatui = "0.30.2"
|
||||||
ratatui-image = { version = "11.0.6", default-features = false, features = ["crossterm", "image-defaults"] }
|
ratatui-image = { version = "11.0.6", default-features = false, features = ["crossterm", "image-defaults"] }
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ RuDS uses no JavaScript application runtime and loads no CSS or JavaScript from
|
|||||||
|
|
||||||
The packaged Apple Silicon application requires macOS 26 or newer.
|
The packaged Apple Silicon application requires macOS 26 or newer.
|
||||||
|
|
||||||
Packaged executables share native `bds-core` and `bds-server` dynamic libraries. ONNX Runtime is statically contained in `bds-core`; the package does not ship or download a separate ONNX library. The **Install CLI** action replaces `~/.local/bin/bds-cli` with a symbolic link to the packaged CLI, so the command executes beside the same runtime libraries and always follows the package selected by the latest installation.
|
Packaged executables share native `bds-core` and `bds-server` dynamic libraries. Release archives also carry the matching ONNX Runtime library; Windows archives include Microsoft's DirectML redistributable and its license for GPU-accelerated local embeddings. The **Install CLI** action replaces `~/.local/bin/bds-cli` with a symbolic link to the packaged CLI, so the command executes beside the same runtime libraries and always follows the package selected by the latest installation.
|
||||||
|
|
||||||
Local macOS packages are ad-hoc signed without hardened runtime. A Developer ID and notarization remain optional release-channel steps for downloads that should pass Gatekeeper without a user override.
|
Local macOS packages are ad-hoc signed without hardened runtime. A Developer ID and notarization remain optional release-channel steps for downloads that should pass Gatekeeper without a user override.
|
||||||
|
|
||||||
|
|||||||
@@ -48,12 +48,14 @@ fastembed = { workspace = true }
|
|||||||
ort = { workspace = true }
|
ort = { workspace = true }
|
||||||
|
|
||||||
[target.'cfg(target_os = "macos")'.dependencies]
|
[target.'cfg(target_os = "macos")'.dependencies]
|
||||||
|
ort = { workspace = true, features = ["coreml"] }
|
||||||
usearch = { workspace = true }
|
usearch = { workspace = true }
|
||||||
|
|
||||||
[target.'cfg(target_os = "windows")'.dependencies]
|
[target.'cfg(target_os = "windows")'.dependencies]
|
||||||
# libwebp's MSVC autodetection enables SSE 4.1 sources, so clang-cl must
|
# libwebp's MSVC autodetection enables SSE 4.1 sources, so clang-cl must
|
||||||
# compile them with the matching target feature during cargo-xwin builds.
|
# compile them with the matching target feature during cargo-xwin builds.
|
||||||
libwebp-sys = { workspace = true, features = ["sse41"] }
|
libwebp-sys = { workspace = true, features = ["sse41"] }
|
||||||
|
ort = { workspace = true, features = ["directml"] }
|
||||||
|
|
||||||
[target.'cfg(not(target_os = "macos"))'.dependencies]
|
[target.'cfg(not(target_os = "macos"))'.dependencies]
|
||||||
usearch = { workspace = true, features = ["numkong"] }
|
usearch = { workspace = true, features = ["numkong"] }
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ plist.workspace = true
|
|||||||
reqwest.workspace = true
|
reqwest.workspace = true
|
||||||
serde.workspace = true
|
serde.workspace = true
|
||||||
serde_json.workspace = true
|
serde_json.workspace = true
|
||||||
|
sha2.workspace = true
|
||||||
simple-file-manifest.workspace = true
|
simple-file-manifest.workspace = true
|
||||||
tar.workspace = true
|
tar.workspace = true
|
||||||
zip.workspace = true
|
zip.workspace = true
|
||||||
|
|||||||
@@ -11,6 +11,9 @@ fn main() -> Result<(), Box<dyn Error>> {
|
|||||||
[command, directory] if command == "macos-linker-alias" => {
|
[command, directory] if command == "macos-linker-alias" => {
|
||||||
packaging::prepare_macos_linker_alias(Path::new(directory))
|
packaging::prepare_macos_linker_alias(Path::new(directory))
|
||||||
}
|
}
|
||||||
|
[command, directory, sdk_libraries] if command == "windows-runtime" => {
|
||||||
|
packaging::prepare_windows_runtime(Path::new(directory), Path::new(sdk_libraries))
|
||||||
|
}
|
||||||
[command, paths @ ..] if command == "upload" && !paths.is_empty() => {
|
[command, paths @ ..] if command == "upload" && !paths.is_empty() => {
|
||||||
gitea::upload(paths.iter().map(Path::new))
|
gitea::upload(paths.iter().map(Path::new))
|
||||||
}
|
}
|
||||||
@@ -39,7 +42,7 @@ fn main() -> Result<(), Box<dyn Error>> {
|
|||||||
gitea::upload(assets.iter().map(|path| path.as_path()))
|
gitea::upload(assets.iter().map(|path| path.as_path()))
|
||||||
}
|
}
|
||||||
_ => Err(
|
_ => Err(
|
||||||
"usage: bds-release prepare|publish|macos-linker-alias <directory>|upload <asset>...|package <tag> <release-dir> <rust-lib-dir> <platform> <dist-dir> [--upload]"
|
"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]"
|
||||||
.into(),
|
.into(),
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,12 +3,13 @@ use apple_codesign::{SigningSettings, UnifiedSigner};
|
|||||||
use flate2::{Compression, write::GzEncoder};
|
use flate2::{Compression, write::GzEncoder};
|
||||||
use icns::{IconFamily, Image};
|
use icns::{IconFamily, Image};
|
||||||
use plist::{Dictionary, Value};
|
use plist::{Dictionary, Value};
|
||||||
|
use sha2::{Digest, Sha256};
|
||||||
use simple_file_manifest::FileEntry;
|
use simple_file_manifest::FileEntry;
|
||||||
use std::{
|
use std::{
|
||||||
error::Error,
|
error::Error,
|
||||||
ffi::OsStr,
|
ffi::OsStr,
|
||||||
fs::{self, File},
|
fs::{self, File},
|
||||||
io::{self, BufReader},
|
io::{self, BufReader, Read, Seek},
|
||||||
path::{Path, PathBuf},
|
path::{Path, PathBuf},
|
||||||
};
|
};
|
||||||
use zip::{CompressionMethod, ZipWriter, write::SimpleFileOptions};
|
use zip::{CompressionMethod, ZipWriter, write::SimpleFileOptions};
|
||||||
@@ -23,6 +24,8 @@ const LC_LOAD_WEAK_DYLIB: u32 = 0x8000_0018;
|
|||||||
const LC_REEXPORT_DYLIB: u32 = 0x8000_001f;
|
const LC_REEXPORT_DYLIB: u32 = 0x8000_001f;
|
||||||
const LC_LAZY_LOAD_DYLIB: u32 = 0x20;
|
const LC_LAZY_LOAD_DYLIB: u32 = 0x20;
|
||||||
const LC_LOAD_UPWARD_DYLIB: u32 = 0x8000_0023;
|
const LC_LOAD_UPWARD_DYLIB: u32 = 0x8000_0023;
|
||||||
|
const DIRECTML_VERSION: &str = "1.15.4";
|
||||||
|
const DIRECTML_SHA256: &str = "4e7cb7ddce8cf837a7a75dc029209b520ca0101470fcdf275c1f49736a3615b9";
|
||||||
|
|
||||||
pub(crate) fn prepare_macos_linker_alias(directory: &Path) -> Result<(), Box<dyn Error>> {
|
pub(crate) fn prepare_macos_linker_alias(directory: &Path) -> Result<(), Box<dyn Error>> {
|
||||||
fs::create_dir_all(directory)?;
|
fs::create_dir_all(directory)?;
|
||||||
@@ -30,6 +33,84 @@ pub(crate) fn prepare_macos_linker_alias(directory: &Path) -> Result<(), Box<dyn
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn prepare_windows_runtime(
|
||||||
|
directory: &Path,
|
||||||
|
sdk_libraries: &Path,
|
||||||
|
) -> Result<(), Box<dyn Error>> {
|
||||||
|
fs::create_dir_all(directory)?;
|
||||||
|
let package_path = directory.join(format!("microsoft.ai.directml.{DIRECTML_VERSION}.nupkg"));
|
||||||
|
let result = (|| {
|
||||||
|
let url = format!(
|
||||||
|
"https://api.nuget.org/v3-flatcontainer/microsoft.ai.directml/{DIRECTML_VERSION}/microsoft.ai.directml.{DIRECTML_VERSION}.nupkg"
|
||||||
|
);
|
||||||
|
let mut response = reqwest::blocking::get(url)?.error_for_status()?;
|
||||||
|
let mut package = File::create(&package_path)?;
|
||||||
|
io::copy(&mut response, &mut package)?;
|
||||||
|
drop(package);
|
||||||
|
|
||||||
|
let mut package = BufReader::new(File::open(&package_path)?);
|
||||||
|
let mut digest = Sha256::new();
|
||||||
|
let mut buffer = [0_u8; 64 * 1024];
|
||||||
|
loop {
|
||||||
|
let read = package.read(&mut buffer)?;
|
||||||
|
if read == 0 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
digest.update(&buffer[..read]);
|
||||||
|
}
|
||||||
|
let digest = digest.finalize();
|
||||||
|
if format!("{digest:x}") != DIRECTML_SHA256 {
|
||||||
|
return Err("DirectML package checksum mismatch".into());
|
||||||
|
}
|
||||||
|
prepare_windows_runtime_from_archive(File::open(&package_path)?, directory)?;
|
||||||
|
prepare_windows_sdk_linker_aliases(sdk_libraries, directory)
|
||||||
|
})();
|
||||||
|
if package_path.try_exists()? {
|
||||||
|
fs::remove_file(package_path)?;
|
||||||
|
}
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
|
fn prepare_windows_sdk_linker_aliases(
|
||||||
|
sdk_libraries: &Path,
|
||||||
|
directory: &Path,
|
||||||
|
) -> Result<(), Box<dyn Error>> {
|
||||||
|
let source = fs::read_dir(sdk_libraries)?
|
||||||
|
.filter_map(Result::ok)
|
||||||
|
.find(|entry| {
|
||||||
|
entry
|
||||||
|
.file_name()
|
||||||
|
.to_str()
|
||||||
|
.is_some_and(|name| name.eq_ignore_ascii_case("pathcch.lib"))
|
||||||
|
})
|
||||||
|
.ok_or_else(|| {
|
||||||
|
format!(
|
||||||
|
"PathCch.lib is missing from Windows SDK directory: {}",
|
||||||
|
sdk_libraries.display()
|
||||||
|
)
|
||||||
|
})?
|
||||||
|
.path();
|
||||||
|
fs::copy(source, directory.join("PathCch.lib"))?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn prepare_windows_runtime_from_archive(
|
||||||
|
archive: impl Read + Seek,
|
||||||
|
directory: &Path,
|
||||||
|
) -> Result<(), Box<dyn Error>> {
|
||||||
|
fs::create_dir_all(directory)?;
|
||||||
|
let mut archive = zip::ZipArchive::new(archive)?;
|
||||||
|
for (source, destination) in [
|
||||||
|
("bin/x64-win/DirectML.lib", "DirectML.lib"),
|
||||||
|
("bin/x64-win/DirectML.dll", "DirectML.dll"),
|
||||||
|
("LICENSE.txt", "DirectML-LICENSE.txt"),
|
||||||
|
] {
|
||||||
|
let mut source = archive.by_name(source)?;
|
||||||
|
io::copy(&mut source, &mut File::create(directory.join(destination))?)?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||||
enum Platform {
|
enum Platform {
|
||||||
MacOs,
|
MacOs,
|
||||||
@@ -177,6 +258,37 @@ fn runtime_files(
|
|||||||
.to_owned();
|
.to_owned();
|
||||||
files.push((path, name));
|
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::Linux => 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.so"))
|
||||||
|
.collect::<Vec<_>>(),
|
||||||
|
Platform::Windows => ["onnxruntime.dll", "DirectML.dll", "DirectML-LICENSE.txt"]
|
||||||
|
.into_iter()
|
||||||
|
.map(str::to_owned)
|
||||||
|
.collect(),
|
||||||
|
};
|
||||||
|
external_names.sort();
|
||||||
|
if external_names.is_empty() {
|
||||||
|
return Err(format!(
|
||||||
|
"ONNX Runtime is missing from release directory: {}",
|
||||||
|
release_dir.display()
|
||||||
|
)
|
||||||
|
.into());
|
||||||
|
}
|
||||||
|
for name in external_names {
|
||||||
|
let path = release_dir.join(&name);
|
||||||
|
require_file(&path)?;
|
||||||
|
files.push((path, name));
|
||||||
|
}
|
||||||
Ok(files)
|
Ok(files)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -443,7 +555,7 @@ fn dmg_sectors(bundle_bytes: u64) -> Result<u32, Box<dyn Error>> {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use std::io::Read;
|
use std::io::{Read, Write};
|
||||||
use tempfile::tempdir;
|
use tempfile::tempdir;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -477,6 +589,50 @@ mod tests {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn windows_runtime_extracts_only_redistributable_files() {
|
||||||
|
let temp = tempdir().unwrap();
|
||||||
|
let sdk = temp.path().join("sdk");
|
||||||
|
let runtime = temp.path().join("runtime");
|
||||||
|
fs::create_dir(&sdk).unwrap();
|
||||||
|
fs::create_dir(&runtime).unwrap();
|
||||||
|
fs::write(sdk.join("pathcch.lib"), b"sdk-import-library").unwrap();
|
||||||
|
let archive = std::io::Cursor::new(Vec::new());
|
||||||
|
let mut archive = ZipWriter::new(archive);
|
||||||
|
let options = SimpleFileOptions::default();
|
||||||
|
for (name, contents) in [
|
||||||
|
("bin/x64-win/DirectML.lib", b"import-library".as_slice()),
|
||||||
|
("bin/x64-win/DirectML.dll", b"runtime".as_slice()),
|
||||||
|
("LICENSE.txt", b"license".as_slice()),
|
||||||
|
(
|
||||||
|
"bin/arm64-win/DirectML.dll",
|
||||||
|
b"wrong-architecture".as_slice(),
|
||||||
|
),
|
||||||
|
] {
|
||||||
|
archive.start_file(name, options).unwrap();
|
||||||
|
archive.write_all(contents).unwrap();
|
||||||
|
}
|
||||||
|
let archive = archive.finish().unwrap();
|
||||||
|
|
||||||
|
prepare_windows_runtime_from_archive(archive, &runtime).unwrap();
|
||||||
|
prepare_windows_sdk_linker_aliases(&sdk, &runtime).unwrap();
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
fs::read(runtime.join("DirectML.lib")).unwrap(),
|
||||||
|
b"import-library"
|
||||||
|
);
|
||||||
|
assert_eq!(fs::read(runtime.join("DirectML.dll")).unwrap(), b"runtime");
|
||||||
|
assert_eq!(
|
||||||
|
fs::read(runtime.join("DirectML-LICENSE.txt")).unwrap(),
|
||||||
|
b"license"
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
fs::read(runtime.join("PathCch.lib")).unwrap(),
|
||||||
|
b"sdk-import-library"
|
||||||
|
);
|
||||||
|
assert_eq!(fs::read_dir(runtime).unwrap().count(), 4);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn windows_package_contains_the_app_without_dynamic_std() {
|
fn windows_package_contains_the_app_without_dynamic_std() {
|
||||||
let temp = tempdir().unwrap();
|
let temp = tempdir().unwrap();
|
||||||
@@ -491,6 +647,9 @@ mod tests {
|
|||||||
"bds-mcp.exe",
|
"bds-mcp.exe",
|
||||||
"bds_core.dll",
|
"bds_core.dll",
|
||||||
"bds_server.dll",
|
"bds_server.dll",
|
||||||
|
"onnxruntime.dll",
|
||||||
|
"DirectML.dll",
|
||||||
|
"DirectML-LICENSE.txt",
|
||||||
] {
|
] {
|
||||||
fs::write(release.join(file), format!("MZ-{file}")).unwrap();
|
fs::write(release.join(file), format!("MZ-{file}")).unwrap();
|
||||||
}
|
}
|
||||||
@@ -511,6 +670,14 @@ mod tests {
|
|||||||
.by_name("bds-desktop-v1.2.3-windows-x64/bds_core.dll")
|
.by_name("bds-desktop-v1.2.3-windows-x64/bds_core.dll")
|
||||||
.is_ok()
|
.is_ok()
|
||||||
);
|
);
|
||||||
|
for runtime in ["onnxruntime.dll", "DirectML.dll", "DirectML-LICENSE.txt"] {
|
||||||
|
assert!(
|
||||||
|
archive
|
||||||
|
.by_name(&format!("bds-desktop-v1.2.3-windows-x64/{runtime}"))
|
||||||
|
.is_ok(),
|
||||||
|
"missing {runtime}"
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -527,6 +694,7 @@ mod tests {
|
|||||||
"bds-mcp",
|
"bds-mcp",
|
||||||
"libbds_core.so",
|
"libbds_core.so",
|
||||||
"libbds_server.so",
|
"libbds_server.so",
|
||||||
|
"libonnxruntime.so.1",
|
||||||
] {
|
] {
|
||||||
fs::write(release.join(file), file).unwrap();
|
fs::write(release.join(file), file).unwrap();
|
||||||
}
|
}
|
||||||
@@ -549,6 +717,11 @@ mod tests {
|
|||||||
.unwrap()
|
.unwrap()
|
||||||
.map(|entry| entry.unwrap().path().unwrap().into_owned())
|
.map(|entry| entry.unwrap().path().unwrap().into_owned())
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
assert!(
|
||||||
|
names
|
||||||
|
.iter()
|
||||||
|
.any(|name| name.ends_with("libonnxruntime.so.1"))
|
||||||
|
);
|
||||||
assert!(names.iter().any(|name| name.ends_with("bds-ui")));
|
assert!(names.iter().any(|name| name.ends_with("bds-ui")));
|
||||||
assert!(names.iter().any(|name| name.ends_with("libbds_core.so")));
|
assert!(names.iter().any(|name| name.ends_with("libbds_core.so")));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -60,6 +60,7 @@ fn desktop_packages_have_native_icons_and_cargo_commands() {
|
|||||||
assert!(workspace_manifest.contains("Georg Bauer <gb@rfc1437.de>"));
|
assert!(workspace_manifest.contains("Georg Bauer <gb@rfc1437.de>"));
|
||||||
assert!(workspace_manifest.contains("strip = \"symbols\""));
|
assert!(workspace_manifest.contains("strip = \"symbols\""));
|
||||||
assert!(workspace_manifest.contains("ort-download-binaries-rustls-tls"));
|
assert!(workspace_manifest.contains("ort-download-binaries-rustls-tls"));
|
||||||
|
assert!(workspace_manifest.contains("\"copy-dylibs\""));
|
||||||
assert!(workspace_manifest.contains("\"sync-secret-service\", \"vendored\""));
|
assert!(workspace_manifest.contains("\"sync-secret-service\", \"vendored\""));
|
||||||
assert!(
|
assert!(
|
||||||
workspace_manifest
|
workspace_manifest
|
||||||
@@ -134,6 +135,10 @@ fn tagged_releases_are_built_and_packaged_with_rust_tools() {
|
|||||||
"aarch64-unknown-linux-gnu",
|
"aarch64-unknown-linux-gnu",
|
||||||
"x86_64-unknown-linux-gnu",
|
"x86_64-unknown-linux-gnu",
|
||||||
"cargo-xwin",
|
"cargo-xwin",
|
||||||
|
"windows-runtime",
|
||||||
|
"cargo +${RUST_TOOLCHAIN} xwin cache xwin",
|
||||||
|
"/root/.cache/cargo-xwin/xwin/sdk/lib/um/x86_64",
|
||||||
|
"-Lnative=target/x86_64-pc-windows-msvc/release",
|
||||||
"apt-get install --no-install-recommends --yes nasm",
|
"apt-get install --no-install-recommends --yes nasm",
|
||||||
"x86_64-pc-windows-msvc",
|
"x86_64-pc-windows-msvc",
|
||||||
"bds-release",
|
"bds-release",
|
||||||
@@ -155,6 +160,10 @@ fn tagged_releases_are_built_and_packaged_with_rust_tools() {
|
|||||||
"release workflow must not use host tool {forbidden}"
|
"release workflow must not use host tool {forbidden}"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
assert!(
|
||||||
|
!workflow.contains("target-feature=+crt-static"),
|
||||||
|
"Windows and downloaded ONNX Runtime must use the same dynamic CRT"
|
||||||
|
);
|
||||||
assert!(
|
assert!(
|
||||||
!workflow.contains("run --release --locked --package bds-release"),
|
!workflow.contains("run --release --locked --package bds-release"),
|
||||||
"the release helper itself must stay unoptimized so cold runner jobs remain practical"
|
"the release helper itself must stay unoptimized so cold runner jobs remain practical"
|
||||||
@@ -166,6 +175,13 @@ fn tagged_releases_are_built_and_packaged_with_rust_tools() {
|
|||||||
4,
|
4,
|
||||||
"every release job using the Ubuntu runner image must bootstrap Rust"
|
"every release job using the Ubuntu runner image must bootstrap Rust"
|
||||||
);
|
);
|
||||||
|
assert_eq!(
|
||||||
|
workflow
|
||||||
|
.matches("needs: [prepare-release, build-linux-x64]")
|
||||||
|
.count(),
|
||||||
|
3,
|
||||||
|
"the expensive platform builds must wait for the Linux x64 cross-build smoke test"
|
||||||
|
);
|
||||||
|
|
||||||
let linux_dependencies =
|
let linux_dependencies =
|
||||||
fs::read_to_string(workspace.join(".gitea/scripts/install-linux-build-dependencies.sh"))
|
fs::read_to_string(workspace.join(".gitea/scripts/install-linux-build-dependencies.sh"))
|
||||||
|
|||||||
Reference in New Issue
Block a user