@@ -149,12 +149,32 @@ jobs:
149149 python-version : ' 3.11'
150150
151151 - name : Install Python dependencies
152- run : python -m pip install huggingface_hub mlx-lm
152+ run : |
153+ python -m pip install --upgrade pip
154+ python -m pip install huggingface_hub mlx mlx-lm
153155
154156 - name : Download test model from HuggingFace
157+ env :
158+ HF_TOKEN : ${{ secrets.HF_TOKEN }}
155159 run : |
156160 mkdir -p models
157- huggingface-cli download mlx-community/Qwen1.5-0.5B-Chat-4bit --local-dir models/Qwen1.5-0.5B-Chat-4bit
161+ python - <<'PY'
162+ import os
163+ from pathlib import Path
164+
165+ from huggingface_hub import snapshot_download
166+
167+ target_dir = Path("models/Qwen1.5-0.5B-Chat-4bit")
168+ target_dir.mkdir(parents=True, exist_ok=True)
169+
170+ snapshot_download(
171+ repo_id="mlx-community/Qwen1.5-0.5B-Chat-4bit",
172+ local_dir=str(target_dir),
173+ local_dir_use_symlinks=False,
174+ token=os.environ.get("HF_TOKEN") or None,
175+ resume_download=True,
176+ )
177+ PY
158178 echo "Model files:"
159179 ls -la models/Qwen1.5-0.5B-Chat-4bit/
160180
@@ -170,6 +190,168 @@ jobs:
170190 name : native-linux-x64
171191 path : artifacts/native/linux-x64
172192
193+ - name : Ensure macOS metallib is available
194+ run : |
195+ set -euo pipefail
196+
197+ metallib_path="artifacts/native/osx-arm64/mlx.metallib"
198+ if [ -f "${metallib_path}" ]; then
199+ echo "Found mlx.metallib in downloaded native artifact."
200+ exit 0
201+ fi
202+
203+ echo "::warning::mlx.metallib missing from native artifact; attempting to source from installed mlx package"
204+ python - <<'PY'
205+ import importlib.util
206+ from importlib import resources
207+ import pathlib
208+ import shutil
209+ import sys
210+ from typing import Iterable, Optional
211+
212+ try:
213+ import mlx # type: ignore
214+ except ImportError:
215+ print("::error::The 'mlx' Python package is not installed; cannot locate mlx.metallib.")
216+ sys.exit(1)
217+
218+ search_dirs: list[pathlib.Path] = []
219+ package_dir: Optional[pathlib.Path] = None
220+ package_paths: list[pathlib.Path] = []
221+
222+ package_file = getattr(mlx, "__file__", None)
223+ if package_file:
224+ try:
225+ package_paths.append(pathlib.Path(package_file).resolve().parent)
226+ except (TypeError, OSError):
227+ pass
228+
229+ package_path_attr = getattr(mlx, "__path__", None)
230+ if package_path_attr:
231+ for entry in package_path_attr:
232+ try:
233+ package_paths.append(pathlib.Path(entry).resolve())
234+ except (TypeError, OSError):
235+ continue
236+
237+ try:
238+ spec = importlib.util.find_spec("mlx.backend.metal.kernels")
239+ except ModuleNotFoundError:
240+ spec = None
241+
242+ if spec and spec.origin:
243+ candidate = pathlib.Path(spec.origin).resolve().parent
244+ if candidate.exists():
245+ search_dirs.append(candidate)
246+ package_paths.append(candidate)
247+
248+ def append_resource_directory(module: str, *subpath: str) -> None:
249+ try:
250+ traversable = resources.files(module)
251+ except (ModuleNotFoundError, AttributeError):
252+ return
253+
254+ for segment in subpath:
255+ traversable = traversable / segment
256+
257+ try:
258+ with resources.as_file(traversable) as extracted:
259+ if extracted:
260+ extracted_path = pathlib.Path(extracted).resolve()
261+ if extracted_path.exists():
262+ search_dirs.append(extracted_path)
263+ package_paths.append(extracted_path)
264+ except (FileNotFoundError, RuntimeError):
265+ pass
266+
267+ append_resource_directory("mlx.backend.metal", "kernels")
268+ append_resource_directory("mlx")
269+
270+ existing_package_paths: list[pathlib.Path] = []
271+ seen_package_paths: set[pathlib.Path] = set()
272+ for path in package_paths:
273+ if not path:
274+ continue
275+ try:
276+ resolved = path.resolve()
277+ except (OSError, RuntimeError):
278+ continue
279+ if not resolved.exists():
280+ continue
281+ if resolved in seen_package_paths:
282+ continue
283+ seen_package_paths.add(resolved)
284+ existing_package_paths.append(resolved)
285+
286+ if existing_package_paths:
287+ package_dir = existing_package_paths[0]
288+ for root in existing_package_paths:
289+ search_dirs.extend(
290+ [
291+ root / "backend" / "metal" / "kernels",
292+ root / "backend" / "metal",
293+ root,
294+ ]
295+ )
296+
297+ ordered_dirs: list[pathlib.Path] = []
298+ seen: set[pathlib.Path] = set()
299+ for candidate in search_dirs:
300+ if not candidate:
301+ continue
302+ candidate = candidate.resolve()
303+ if candidate in seen:
304+ continue
305+ seen.add(candidate)
306+ ordered_dirs.append(candidate)
307+
308+ def iter_metallibs(dirs: Iterable[pathlib.Path]):
309+ for directory in dirs:
310+ if not directory.exists():
311+ continue
312+ preferred = directory / "mlx.metallib"
313+ if preferred.exists():
314+ yield preferred
315+ continue
316+ for alternative in sorted(directory.glob("*.metallib")):
317+ yield alternative
318+
319+ src = next(iter_metallibs(ordered_dirs), None)
320+
321+ package_roots = existing_package_paths if existing_package_paths else ([] if not package_dir else [package_dir])
322+
323+ if src is None:
324+ for root in package_roots:
325+ for candidate in root.rglob("mlx.metallib"):
326+ src = candidate
327+ print(f"::warning::Resolved metallib via recursive search under {root}")
328+ break
329+ if src is not None:
330+ break
331+
332+ if src is None:
333+ for root in package_roots:
334+ for candidate in sorted(root.rglob("*.metallib")):
335+ src = candidate
336+ print(f"::warning::Using metallib {candidate.name} discovered via package-wide search in {root}")
337+ break
338+ if src is not None:
339+ break
340+
341+ if src is None:
342+ print("::error::Could not locate any mlx.metallib artifacts within the installed mlx package.")
343+ sys.exit(1)
344+
345+ if src.name != "mlx.metallib":
346+ print(f"::warning::Using metallib {src.name} from {src.parent}")
347+
348+ dest = pathlib.Path("artifacts/native/osx-arm64/mlx.metallib").resolve()
349+ dest.parent.mkdir(parents=True, exist_ok=True)
350+
351+ shutil.copy2(src, dest)
352+ print(f"Copied mlx.metallib from {src} to {dest}")
353+ PY
354+
173355 - name : Stage native libraries in project
174356 run : |
175357 mkdir -p src/MLXSharp/runtimes/osx-arm64/native
0 commit comments