From 7adb69581e410a77a5fcd3ff2c421187495415ea Mon Sep 17 00:00:00 2001 From: Roland Tannous <115670425+rolandtannous@users.noreply.github.com> Date: Wed, 25 Feb 2026 03:30:54 +0400 Subject: [PATCH] Fix GGUF export cwd confusion: remove os.chdir, use absolute paths Remove os.chdir(save_directory) from export.py which was causing all of unsloth-zoo's relative-path internals (check_llama_cpp, use_local_gguf, _download_convert_hf_to_gguf) to resolve against the export directory instead of the repo root. This caused llama.cpp to be cloned inside each export dir and destroyed the repo root's llama-server build on cleanup. Now passes absolute paths to save_pretrained_gguf so unsloth resolves llama.cpp from the repo root where setup.sh already built it. Also builds llama-quantize in setup.sh (needed by unsloth-zoo's export pipeline) and symlinks it to llama.cpp root for check_llama_cpp(). --- setup.sh | 20 +++++++-- studio/backend/core/export/export.py | 62 ++++++++++------------------ 2 files changed, 38 insertions(+), 44 deletions(-) diff --git a/setup.sh b/setup.sh index 36165dac65..0d8821d50a 100755 --- a/setup.sh +++ b/setup.sh @@ -206,10 +206,11 @@ else fi fi -# ── 8. Build llama-server for GGUF inference ── +# ── 8. Build llama.cpp binaries for GGUF inference + export ── # Builds in-tree at $REPO/llama.cpp/. This directory is shared with -# unsloth-zoo's GGUF export pipeline — if converter/quantize are missing, -# unsloth-zoo will rebuild them on first export. We only build llama-server here. +# unsloth-zoo's GGUF export pipeline. We build: +# - llama-server: for GGUF model inference +# - llama-quantize: for GGUF export quantization (symlinked to root for check_llama_cpp()) LLAMA_SERVER_BIN="$SCRIPT_DIR/llama.cpp/build/bin/llama-server" if [ -f "$LLAMA_SERVER_BIN" ]; then echo "" @@ -272,12 +273,25 @@ else run_quiet "build llama-server" cmake --build "$LLAMA_CPP_DIR/build" --config Release --target llama-server -j"$NCPU" || BUILD_OK=false fi + # Also build llama-quantize (needed by unsloth-zoo's GGUF export pipeline) + if [ "$BUILD_OK" = true ]; then + run_quiet "build llama-quantize" cmake --build "$LLAMA_CPP_DIR/build" --config Release --target llama-quantize -j"$NCPU" || true + # Symlink to llama.cpp root — check_llama_cpp() looks for the binary there + QUANTIZE_BIN="$LLAMA_CPP_DIR/build/bin/llama-quantize" + if [ -f "$QUANTIZE_BIN" ]; then + ln -sf build/bin/llama-quantize "$LLAMA_CPP_DIR/llama-quantize" + fi + fi + if [ "$BUILD_OK" = true ]; then if [ -f "$LLAMA_SERVER_BIN" ]; then echo "✅ llama-server built at $LLAMA_SERVER_BIN" else echo "⚠️ llama-server binary not found after build — GGUF inference won't be available" fi + if [ -f "$LLAMA_CPP_DIR/llama-quantize" ]; then + echo "✅ llama-quantize available for GGUF export" + fi else echo "⚠️ llama-server build failed — GGUF inference won't be available, but everything else works" fi diff --git a/studio/backend/core/export/export.py b/studio/backend/core/export/export.py index da5b11c60d..865900cb65 100644 --- a/studio/backend/core/export/export.py +++ b/studio/backend/core/export/export.py @@ -378,53 +378,33 @@ class ExportBackend: # Save locally if requested if save_directory: - logger.info(f"Saving GGUF model locally to: {save_directory}") + # Resolve to absolute path so unsloth's relative-path internals + # (check_llama_cpp, use_local_gguf, _download_convert_hf_to_gguf) + # all resolve against the repo root cwd, NOT the export directory. + abs_save_dir = os.path.abspath(save_directory) + logger.info(f"Saving GGUF model locally to: {abs_save_dir}") # Create the directory if it doesn't exist - os.makedirs(save_directory, exist_ok=True) + os.makedirs(abs_save_dir, exist_ok=True) - # Get the base filename for the GGUF file - import shutil - original_dir = os.getcwd() + # On WSL, patch out sudo check before llama.cpp build + _apply_wsl_sudo_patch() - try: - # Change to target directory - os.chdir(save_directory) - logger.info(f"Changed directory to: {save_directory}") + # Enable verbose logging so subprocess errors are printed + os.environ["UNSLOTH_ENABLE_LOGGING"] = "1" - # On WSL, patch out sudo check before llama.cpp build - _apply_wsl_sudo_patch() + # Pass absolute path — no os.chdir needed. + # unsloth saves model files into this directory, while + # check_llama_cpp("llama.cpp") resolves against cwd (repo root) + # where setup.sh already built llama.cpp with quantizer. + model_save_path = os.path.join(abs_save_dir, "model") + self.current_model.save_pretrained_gguf( + model_save_path, + self.current_tokenizer, + quantization_method=quant_method + ) - # Now save (will save in current directory) - self.current_model.save_pretrained_gguf( - "model", # Base filename - self.current_tokenizer, - quantization_method=quant_method - ) - - logger.info(f"GGUF model saved successfully in {save_directory}") - - # Check if llama.cpp directory was created here - llama_cpp_in_target = os.path.join(save_directory, "llama.cpp") - llama_cpp_in_original = os.path.join(original_dir, "llama.cpp") - - if os.path.exists(llama_cpp_in_target): - logger.info(f"Found llama.cpp directory in {save_directory}") - - # Remove llama.cpp from original directory if it exists - if os.path.exists(llama_cpp_in_original): - logger.info(f"Removing existing llama.cpp in {original_dir}") - shutil.rmtree(llama_cpp_in_original) - - # Move llama.cpp back to original directory - logger.info(f"Moving llama.cpp to {original_dir}") - shutil.move(llama_cpp_in_target, llama_cpp_in_original) - logger.info(f"Successfully moved llama.cpp back to original directory") - - finally: - # Always change back to original directory - os.chdir(original_dir) - logger.info(f"Changed back to original directory: {original_dir}") + logger.info(f"GGUF model saved successfully in {abs_save_dir}") # Push to hub if requested if push_to_hub: