Skip to content

Commit 6826193

Browse files
committed
Build release runners with platform accelerators
1 parent 55d069b commit 6826193

5 files changed

Lines changed: 145 additions & 11 deletions

File tree

.github/scripts/patch-koharu-diffusion.py

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,60 @@ def koharu_enums_path() -> Path:
2929
return Path(matches[0]["manifest_path"]).parent / "src" / "enums.rs"
3030

3131

32+
def koharu_libtorch_path() -> Path:
33+
metadata = subprocess.run(
34+
["cargo", "metadata", "--locked", "--format-version", "1"],
35+
check=True,
36+
stdout=subprocess.PIPE,
37+
text=True,
38+
encoding="utf-8",
39+
)
40+
packages = json.loads(metadata.stdout)["packages"]
41+
matches = [
42+
package
43+
for package in packages
44+
if package["name"] == "koharu-runtime"
45+
and package["source"].startswith("git+")
46+
]
47+
if len(matches) != 1:
48+
raise RuntimeError(
49+
f"expected one Git koharu-runtime package, found {len(matches)}"
50+
)
51+
return Path(matches[0]["manifest_path"]).parent / "src" / "package" / "libtorch.rs"
52+
53+
54+
def patch_libtorch_selection() -> None:
55+
libtorch_path = koharu_libtorch_path()
56+
libtorch_source = libtorch_path.read_text(encoding="utf-8")
57+
libtorch_marker = "// Patched by Flint: allow release CI to select a LibTorch device."
58+
if libtorch_marker in libtorch_source:
59+
print(f"already patched {libtorch_path}")
60+
return
61+
62+
libtorch_old = " pub fn for_current_target() -> Result<Self> {\n"
63+
libtorch_new = libtorch_old + f""" {libtorch_marker}
64+
if let Some(device) = std::env::var_os("FLINT_LIBTORCH_DEVICE") {{
65+
match device.to_str() {{
66+
Some("cpu") => return Ok(Self::Cpu),
67+
Some("cu126") => return Ok(Self::Cuda126),
68+
Some("cu129") => return Ok(Self::Cuda129),
69+
Some("cu130") => return Ok(Self::Cuda130),
70+
Some(device) => bail!("unsupported FLINT_LIBTORCH_DEVICE '{{device}}'"),
71+
None => bail!("FLINT_LIBTORCH_DEVICE is not valid UTF-8"),
72+
}}
73+
}}
74+
"""
75+
if libtorch_source.count(libtorch_old) != 1:
76+
raise RuntimeError("could not locate Koharu LibTorch target selection")
77+
libtorch_path.write_text(
78+
libtorch_source.replace(libtorch_old, libtorch_new), encoding="utf-8"
79+
)
80+
print(f"patched {libtorch_path}")
81+
82+
83+
patch_libtorch_selection()
84+
85+
3286
path = koharu_enums_path()
3387
source = path.read_text(encoding="utf-8")
3488

.github/workflows/release.yml

Lines changed: 79 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ concurrency:
2121
env:
2222
CARGO_TERM_COLOR: always
2323
CARGO_TARGET_DIR: target
24+
LIBTORCH_VERSION: "2.12.1"
2425

2526
jobs:
2627
build-runner:
@@ -33,12 +34,15 @@ jobs:
3334
- os: ubuntu-latest
3435
platform: linux-x86_64
3536
exe_suffix: ""
37+
libtorch_device: cpu
3638
- os: windows-latest
3739
platform: windows-x86_64
3840
exe_suffix: ".exe"
41+
libtorch_device: cu130
3942
- os: macos-14
4043
platform: macos-arm64
4144
exe_suffix: ""
45+
libtorch_device: cpu
4246

4347
steps:
4448
- name: Checkout Flint
@@ -55,12 +59,11 @@ jobs:
5559
- name: Install Rust toolchain
5660
uses: dtolnay/rust-toolchain@stable
5761

58-
- name: Patch Koharu C enum ABI compatibility
62+
- name: Patch Koharu release dependencies
5963
working-directory: flint
6064
run: python .github/scripts/patch-koharu-diffusion.py
6165

62-
- name: Preload Unix LibTorch
63-
if: runner.os != 'Windows'
66+
- name: Prefetch platform LibTorch
6467
working-directory: flint
6568
shell: python
6669
env:
@@ -73,19 +76,55 @@ jobs:
7376
import urllib.request
7477
import zipfile
7578
76-
version = "2.12.1"
79+
version = os.environ["LIBTORCH_VERSION"]
7780
runner_os = os.environ["RUNNER_OS"]
7881
if runner_os == "Linux":
82+
device = "cpu"
7983
archive_name = f"libtorch-shared-with-deps-{version}%2Bcpu.zip"
80-
required = ("libc10.so", "libtorch_cpu.so", "libtorch.so")
84+
required = (
85+
"libgomp.so.1",
86+
"libc10.so",
87+
"libshm.so",
88+
"libtorch_global_deps.so",
89+
"libtorch_cpu.so",
90+
"libtorch.so",
91+
)
8192
elif runner_os == "macOS":
93+
# Apple Silicon LibTorch includes the MPS backend implemented on Metal.
94+
device = "cpu"
8295
archive_name = f"libtorch-macos-arm64-{version}.zip"
83-
required = ("libomp.dylib", "libc10.dylib", "libtorch_cpu.dylib", "libtorch.dylib")
96+
required = (
97+
"libomp.dylib",
98+
"libc10.dylib",
99+
"libshm.dylib",
100+
"libtorch_global_deps.dylib",
101+
"libtorch_cpu.dylib",
102+
"libtorch.dylib",
103+
)
104+
elif runner_os == "Windows":
105+
# GitHub's Windows runner has no CUDA driver. Prefetch CUDA LibTorch
106+
# explicitly so the released archive can use CUDA on a user's machine.
107+
device = "cu130"
108+
archive_name = f"libtorch-win-shared-with-deps-{version}%2B{device}.zip"
109+
required = (
110+
"libiomp5md.dll",
111+
"libiompstubs5md.dll",
112+
"zlibwapi.dll",
113+
"uv.dll",
114+
"c10.dll",
115+
"c10_cuda.dll",
116+
"caffe2_nvrtc.dll",
117+
"torch_global_deps.dll",
118+
"torch_cpu.dll",
119+
"torch_cuda.dll",
120+
"shm.dll",
121+
"torch.dll",
122+
)
84123
else:
85124
raise RuntimeError(f"unsupported runner OS: {runner_os}")
86-
url = f"https://download.pytorch.org/libtorch/cpu/{archive_name}"
125+
url = f"https://download.pytorch.org/libtorch/{device}/{archive_name}"
87126
target_dir = pathlib.Path(os.environ.get("CARGO_TARGET_DIR", "target"))
88-
package_dir = target_dir / "store" / "libtorch" / version / "cpu"
127+
package_dir = target_dir / "store" / "libtorch" / version / device
89128
lib_dir = package_dir / "libtorch" / "lib"
90129
91130
if all((lib_dir / name).is_file() for name in required):
@@ -128,6 +167,8 @@ jobs:
128167
129168
- name: Build release runner
130169
working-directory: flint
170+
env:
171+
FLINT_LIBTORCH_DEVICE: ${{ matrix.libtorch_device }}
131172
run: cargo build --release --locked --bin flint
132173

133174
- name: Package runner
@@ -136,6 +177,8 @@ jobs:
136177
env:
137178
PLATFORM: ${{ matrix.platform }}
138179
EXE_SUFFIX: ${{ matrix.exe_suffix }}
180+
RUNNER_OS: ${{ runner.os }}
181+
LIBTORCH_VERSION: ${{ env.LIBTORCH_VERSION }}
139182
run: |
140183
import os
141184
import pathlib
@@ -161,13 +204,40 @@ jobs:
161204
raise FileNotFoundError(f"missing built runner binary: {binary}")
162205
shutil.copy2(binary, package_dir / binary.name)
163206
207+
native_library_patterns = {
208+
"Windows": "koharu*.dll",
209+
"macOS": "libkoharu*.dylib",
210+
"Linux": "libkoharu*.so",
211+
}
212+
pattern = native_library_patterns[os.environ["RUNNER_OS"]]
213+
for source in release_dir.glob(pattern):
214+
shutil.copy2(source, package_dir / source.name)
215+
164216
for extra in ("README.md", "LICENSE"):
165217
source = root / extra
166218
if source.exists():
167219
shutil.copy2(source, package_dir / extra)
168220
221+
platform = os.environ["PLATFORM"]
222+
if platform == "windows-x86_64":
223+
required = (
224+
"flint.exe",
225+
"koharu-torch.dll",
226+
)
227+
elif platform == "macos-arm64":
228+
required = (
229+
"flint",
230+
"libkoharu-torch.dylib",
231+
)
232+
else:
233+
required = ("flint", "libkoharu-torch.so")
234+
missing = [name for name in required if not (package_dir / name).is_file()]
235+
if missing:
236+
raise RuntimeError(f"release package is missing: {', '.join(missing)}")
237+
238+
all_files = sorted(path for path in package_dir.rglob("*") if path.is_file())
169239
with zipfile.ZipFile(archive, "w", compression=zipfile.ZIP_DEFLATED) as zf:
170-
for path in package_dir.rglob("*"):
240+
for path in all_files:
171241
zf.write(path, path.relative_to(package_dir.parent))
172242
173243
with open(os.environ["GITHUB_OUTPUT"], "a", encoding="utf-8") as output:

Cargo.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "rs-flint"
3-
version = "0.1.0"
3+
version = "0.1.8"
44
edition = "2024"
55
license = "Apache-2.0"
66
description = "RustScript-native AI inference with Torch, llama.cpp, and stable-diffusion.cpp"

README.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,16 @@ imported as `flint_ai`.
5151
repository checkout so the referenced files under `scripts/` are available;
5252
`--script` also accepts an absolute path to an RSS program.
5353

54+
## Release Archives
55+
56+
Release assets are zip archives containing the runner and its native Koharu
57+
shims. LibTorch, llama.cpp, and stable-diffusion.cpp are fetched by
58+
`koharu-runtime` on first use and stored next to the executable under `store`.
59+
The `macos-arm64` runner uses Apple Silicon LibTorch with its MPS backend,
60+
which uses Metal; run Torch scripts with `--device mps`. The `windows-x86_64`
61+
runner is built against CUDA 13 LibTorch; with a compatible NVIDIA driver,
62+
Torch scripts can use `--device cuda` or `--device cuda:N`.
63+
5464
## CLI
5565

5666
The `flint` binary has explicit modes:

0 commit comments

Comments
 (0)