Skip to content

Build Llama.cpp + ROCm #411

Build Llama.cpp + ROCm

Build Llama.cpp + ROCm #411

name: Build Llama.cpp + ROCm
on:
workflow_dispatch:
inputs:
operating_systems:
description: 'Operating systems to build for (comma-separated: windows,ubuntu)'
required: false
default: 'windows,ubuntu'
gfx_target:
description: 'AMD GPU targets (comma-separated)'
required: false
default: 'gfx1151,gfx1150,gfx120X,gfx110X,gfx103X'
rocm_version:
description: 'ROCm version to use (e.g., 7.13.0a20260318) or "latest" to auto-detect'
required: false
default: 'latest'
llamacpp_version:
description: 'Llama.cpp version (e.g., tag, branch, or commit hash) or "latest" for master branch'
required: false
default: 'latest'
create_release:
description: 'Create a GitHub release after successful build'
required: false
default: true
type: boolean
# Trigger on pushes to pull requests
pull_request:
types: [opened, synchronize, reopened]
# Trigger on a schedule to build nightly releases
schedule:
# Runs at 1:00 PM UTC, which is 5:00 AM PST (UTC-8)
# This is two hours after the ROCm nightly tarball is triggered
- cron: '0 13 * * *'
env:
OPERATING_SYSTEMS: ${{ github.event.inputs.operating_systems || 'windows,ubuntu' }}
GFX_TARGETS: ${{ github.event.inputs.gfx_target || 'gfx1151,gfx1150,gfx120X,gfx110X,gfx103X' }}
ROCM_VERSION: ${{ github.event.inputs.rocm_version || 'latest' }}
LLAMACPP_VERSION: ${{ github.event.inputs.llamacpp_version || 'latest' }}
jobs:
prepare-matrix:
runs-on: ubuntu-22.04
outputs:
windows_matrix: ${{ steps.set-matrix.outputs.windows_matrix }}
ubuntu_matrix: ${{ steps.set-matrix.outputs.ubuntu_matrix }}
should_build_windows: ${{ steps.set-matrix.outputs.should_build_windows }}
should_build_ubuntu: ${{ steps.set-matrix.outputs.should_build_ubuntu }}
steps:
- name: Set matrix
id: set-matrix
run: |
targets="${{ env.GFX_TARGETS }}"
operating_systems="${{ env.OPERATING_SYSTEMS }}"
echo "Input targets: $targets"
echo "Input operating systems: $operating_systems"
# Convert targets to JSON array
matrix_targets=$(echo "$targets" \
| tr ',' '\n' \
| sed 's/^ *//;s/ *$//' \
| sed 's/^"//;s/"$//' \
| jq -R . \
| jq -s '{gfx_target: .}' \
| jq -c)
# Check which operating systems to build
should_build_windows="false"
should_build_ubuntu="false"
if [[ "$operating_systems" == *"windows"* ]]; then
should_build_windows="true"
echo "windows_matrix=$matrix_targets" >> $GITHUB_OUTPUT
fi
if [[ "$operating_systems" == *"ubuntu"* ]]; then
should_build_ubuntu="true"
echo "ubuntu_matrix=$matrix_targets" >> $GITHUB_OUTPUT
fi
echo "should_build_windows=$should_build_windows" >> $GITHUB_OUTPUT
echo "should_build_ubuntu=$should_build_ubuntu" >> $GITHUB_OUTPUT
echo "Windows build: $should_build_windows"
echo "Ubuntu build: $should_build_ubuntu"
echo "Generated matrix: $matrix_targets"
build-windows:
runs-on: windows-latest
needs: prepare-matrix
if: needs.prepare-matrix.outputs.should_build_windows == 'true'
strategy:
matrix: ${{fromJson(needs.prepare-matrix.outputs.windows_matrix)}}
fail-fast: false
outputs:
rocm_version: ${{ steps.set-outputs.outputs.rocm_version }}
llamacpp_commit_hash: ${{ steps.set-outputs.outputs.llamacpp_commit_hash }}
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Clean up existing directories (safety precaution)
run: |
# Remove existing llama.cpp directory if it exists
if (Test-Path "llama.cpp") {
Write-Host "Removing existing llama.cpp directory..."
Remove-Item -Recurse -Force "llama.cpp"
}
# Remove existing C:\opt\rocm directory if it exists
if (Test-Path "C:\opt\rocm") {
Write-Host "Removing existing C:\opt\rocm directory..."
Remove-Item -Recurse -Force "C:\opt\rocm"
}
# Remove any existing ROCm tarball
if (Test-Path "rocm.tar.gz") {
Write-Host "Removing existing rocm.tar.gz..."
Remove-Item -Force "rocm.tar.gz"
}
Write-Host "Cleanup completed successfully"
- name: Install Visual Studio Build Tools
run: |
# Download and install Visual Studio Build Tools
$vsInstallerUrl = "https://aka.ms/vs/17/release/vs_buildtools.exe"
$vsInstallerPath = "$env:TEMP\vs_buildtools.exe"
Write-Host "Downloading Visual Studio Build Tools..."
Invoke-WebRequest -Uri $vsInstallerUrl -OutFile $vsInstallerPath
Write-Host "Installing Visual Studio Build Tools..."
Start-Process -FilePath $vsInstallerPath -ArgumentList "--quiet", "--wait", "--norestart", "--add", "Microsoft.VisualStudio.Component.VC.Tools.x86.x64", "--add", "Microsoft.VisualStudio.Component.VC.CMake.Project", "--add", "Microsoft.VisualStudio.Component.VC.ATL", "--add", "Microsoft.VisualStudio.Component.Windows11SDK.22621" -Wait
# Clean up installer
Remove-Item $vsInstallerPath -Force
- name: Install build dependencies
run: |
Write-Host "Installing build dependencies using manual methods..."
# Install Ninja
Write-Host "Installing Ninja..."
$ninjaUrl = "https://github.com/ninja-build/ninja/releases/download/v1.11.1/ninja-win.zip"
$ninjaPath = "$env:TEMP\ninja-win.zip"
$ninjaDir = "C:\ninja"
New-Item -ItemType Directory -Force -Path $ninjaDir
Invoke-WebRequest -Uri $ninjaUrl -OutFile $ninjaPath
Expand-Archive -Path $ninjaPath -DestinationPath $ninjaDir -Force
# Install Strawberry Perl
Write-Host "Installing Strawberry Perl..."
$perlUrl = "http://strawberryperl.com/download/5.32.1.1/strawberry-perl-5.32.1.1-64bit.msi"
$perlPath = "$env:TEMP\strawberry-perl-5.32.1.1-64bit.msi"
Invoke-WebRequest -Uri $perlUrl -OutFile $perlPath
Start-Process msiexec.exe -ArgumentList "/i $perlPath /quiet /norestart" -Wait
# Verify installations
$env:PATH = "C:\ninja;C:\Strawberry\perl\bin;$env:PATH"
Write-Host "Verifying installations..."
ninja --version
perl --version
Write-Host "Manual installation of build dependencies completed"
- name: Download ROCm nightly tarball
run: |
# Determine ROCm version to use
$rocmVersion = "${{ env.ROCM_VERSION }}"
$currentTarget = "${{ matrix.gfx_target }}"
# Add appropriate suffixes for different GPU targets
$s3Target = $currentTarget
if ($currentTarget -eq "gfx103X") {
$s3Target = "$currentTarget-dgpu"
Write-Host "Using S3 target with -dgpu suffix: $s3Target"
} elseif ($currentTarget -eq "gfx110X" -or $currentTarget -eq "gfx120X") {
$s3Target = "$currentTarget-all"
Write-Host "Using S3 target with -all suffix: $s3Target"
}
if ($rocmVersion -eq "latest") {
Write-Host "Auto-detecting latest ROCm version for target: $currentTarget"
$s3Response = (Invoke-WebRequest "https://therock-nightly-tarball.s3.amazonaws.com/?prefix=therock-dist-windows-$s3Target-7").Content
$files = $s3Response -split '<Key>' | Where-Object {$_ -match '</Key>'} | ForEach-Object { ($_ -split '</Key>')[0] }
# Extract versions and sort them properly using semantic versioning
$versionFiles = @()
foreach ($file in $files) {
if ($file -match "therock-dist-windows-$s3Target-.*?(\d+\.\d+\.\d+(?:a|rc)\d+)\.tar\.gz") {
$version = $matches[1]
$versionFiles += [PSCustomObject]@{
File = $file
Version = $version
Major = [int]($version -split '\.')[0]
Minor = [int]($version -split '\.')[1]
Patch = [int](($version -split '\.')[2] -replace '(?:a|rc).*', '')
RC = [int]($version -replace '.*(?:a|rc)', '')
IsAlpha = $version -match 'a'
}
}
}
# Sort by semantic version (major.minor.patch.rc, with alpha versions being newer than rc)
$latestFile = ($versionFiles | Sort-Object Major, Minor, Patch, @{Expression={if($_.IsAlpha){1}else{0}}}, RC | Select-Object -Last 1).File
Write-Host "Found latest file: $latestFile"
# Extract version from the filename for environment variable
if ($latestFile -match "therock-dist-windows-$s3Target-.*?(\d+\.\d+\.\d+(?:a|rc)\d+)\.tar\.gz") {
$rocmVersion = $matches[1]
Write-Host "Detected latest ROCm version: $rocmVersion"
} else {
Write-Error "Failed to extract ROCm version from latest file: $latestFile"
Write-Error "Expected pattern: therock-dist-windows-$s3Target-*<version>.tar.gz"
exit 1
}
# Use the exact filename from S3 instead of reconstructing
$rocmUrl = "https://therock-nightly-tarball.s3.amazonaws.com/$latestFile"
} else {
# For specific versions, construct the URL as before
$rocmUrl = "https://therock-nightly-tarball.s3.amazonaws.com/therock-dist-windows-$s3Target-$rocmVersion.tar.gz"
}
# Store the version for use in other steps
echo "DETECTED_ROCM_VERSION=$rocmVersion" >> $env:GITHUB_ENV
Write-Host "Downloading ROCm from: $rocmUrl"
Invoke-WebRequest -Uri $rocmUrl -OutFile "rocm.tar.gz"
- name: Extract ROCm to C:\opt\rocm
run: |
# Create directory if it doesn't exist
New-Item -ItemType Directory -Force -Path "C:\opt\rocm"
# Extract the tarball
tar -xzf rocm.tar.gz -C C:\opt\rocm --strip-components=1
- name: Clone llama.cpp
run: |
$llamacppVersion = "${{ env.LLAMACPP_VERSION }}"
if ($llamacppVersion -eq "latest") {
Write-Host "Cloning master branch (latest) with shallow clone"
git clone --depth 1 --single-branch --branch master https://github.com/ggerganov/llama.cpp.git
} else {
Write-Host "Cloning llama.cpp version: $llamacppVersion with shallow clone"
git clone --depth 1 --single-branch --branch $llamacppVersion https://github.com/ggerganov/llama.cpp.git
}
cd llama.cpp
# Get commit hash (5 digits) and store it as environment variable
$commitHash = git rev-parse --short=5 HEAD
echo "LLAMACPP_COMMIT_HASH=$commitHash" >> $env:GITHUB_ENV
Write-Host "llama.cpp commit hash (5 digits): $commitHash"
# Show current commit info
Write-Host "Current llama.cpp commit:"
git log --oneline -1
- name: Build Llama.cpp + ROCm
shell: cmd
run: |
REM Map GPU targets
set "current_target=${{ matrix.gfx_target }}"
echo Input target: %current_target%
if "%current_target%"=="gfx110X" (
set "mapped_target=gfx1100;gfx1101;gfx1102;gfx1103"
) else if "%current_target%"=="gfx103X" (
set "mapped_target=gfx1030;gfx1031;gfx1032;gfx1034"
) else if "%current_target%"=="gfx1151" (
set "mapped_target=gfx1151"
) else if "%current_target%"=="gfx1150" (
set "mapped_target=gfx1150"
) else if "%current_target%"=="gfx120X" (
set "mapped_target=gfx1200;gfx1201"
) else (
set "mapped_target=%current_target%"
)
echo Mapped target: %mapped_target%
REM Set up environment variables and PATH
set HIP_PATH=C:\opt\rocm
set HIP_PLATFORM=amd
set PATH=%HIP_PATH%\lib\llvm\bin;%HIP_PATH%\bin;%PATH%
REM Set up x64 Native Tools Command Prompt environment
call "C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe" -latest -products * -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 -property installationPath > vs_path.txt
set /p VS_PATH=<vs_path.txt
call "%VS_PATH%\VC\Auxiliary\Build\vcvars64.bat"
REM Create build directory
cd llama.cpp
mkdir build
cd build
REM Configure the project
cmake .. -G Ninja ^
-DCMAKE_C_COMPILER="C:\opt\rocm\lib\llvm\bin\clang.exe" ^
-DCMAKE_CXX_COMPILER="C:\opt\rocm\lib\llvm\bin\clang++.exe" ^
-DCMAKE_CXX_FLAGS="-IC:\opt\rocm\include" ^
-DCMAKE_CROSSCOMPILING=ON ^
-DCMAKE_BUILD_TYPE=Release ^
-DGPU_TARGETS="%mapped_target%" ^
-DBUILD_SHARED_LIBS=ON ^
-DLLAMA_BUILD_TESTS=OFF ^
-DGGML_HIP=ON ^
-DGGML_OPENMP=OFF ^
-DGGML_CUDA_FORCE_CUBLAS=OFF ^
-DGGML_RPC=ON ^
-DGGML_HIP_ROCWMMA_FATTN=OFF ^
-DLLAMA_BUILD_BORINGSSL=ON ^
-DGGML_NATIVE=OFF ^
-DGGML_STATIC=OFF ^
-DCMAKE_SYSTEM_NAME=Windows
REM Build the project
cmake --build . -j %NUMBER_OF_PROCESSORS%
- name: Copy ROCm core DLLs to build directory
run: |
$rocmVersion = if ($env:DETECTED_ROCM_VERSION) { $env:DETECTED_ROCM_VERSION } else { $env:ROCM_VERSION }
$buildBinPath = "llama.cpp\build\bin"
$rocmBinPath = "C:\opt\rocm\bin"
Write-Host "Copying ROCm core DLL files to build directory..."
Write-Host "Source: $rocmBinPath"
Write-Host "Destination: $buildBinPath"
if (Test-Path $rocmBinPath) {
# Copy files matching patterns and specific names
$filesToCopy = @(
"amdhip64_*.dll",
"rocm_kpack.dll",
"amd_comgr*.dll",
"libhipblas.dll",
"rocblas.dll",
"rocsolver.dll",
"hipblaslt.dll",
"libhipblaslt.dll",
"hipblas.dll"
)
foreach ($pattern in $filesToCopy) {
$matchingFiles = Get-ChildItem -Path $rocmBinPath -Name $pattern -ErrorAction SilentlyContinue
if ($matchingFiles) {
foreach ($file in $matchingFiles) {
$sourcePath = Join-Path $rocmBinPath $file
$destPath = Join-Path $buildBinPath $file
Copy-Item $sourcePath $destPath
Write-Host "Copied: $file"
}
} else {
Write-Host "Warning: No files found matching pattern: $pattern"
}
}
# Copy the rocblas\library folder and all its contents
$rocblasLibPath = Join-Path $rocmBinPath "rocblas\library"
if (Test-Path $rocblasLibPath) {
Write-Host "Copying rocblas\library folder and all contents..."
$destRocblasPath = Join-Path $buildBinPath "rocblas\library"
Copy-Item -Path $rocblasLibPath -Destination $destRocblasPath -Recurse -Force
Write-Host "Copied: rocblas\library folder with all contents"
# List the contents of the copied rocblas\library folder
Write-Host "Contents of rocblas\library:"
Get-ChildItem $destRocblasPath -Recurse | Select-Object FullName, Length | Format-Table -AutoSize
} else {
Write-Host "Warning: rocblas\library folder not found at: $rocblasLibPath"
}
# Copy the hipblaslt\library folder and all its contents
$hipblasltLibPath = Join-Path $rocmBinPath "hipblaslt\library"
if (Test-Path $hipblasltLibPath) {
Write-Host "Copying hipblaslt\library folder and all contents..."
$destHipblasltPath = Join-Path $buildBinPath "hipblaslt\library"
Copy-Item -Path $hipblasltLibPath -Destination $destHipblasltPath -Recurse -Force
Write-Host "Copied: hipblaslt\library folder with all contents"
# List the contents of the copied hipblaslt\library folder
Write-Host "Contents of hipblaslt\library:"
Get-ChildItem $destHipblasltPath -Recurse | Select-Object FullName, Length | Format-Table -AutoSize
} else {
Write-Host "Warning: rocblas\library folder not found at: $rocblasLibPath"
}
Write-Host "ROCm core files successfully copied to build directory"
} else {
Write-Error "ROCm bin directory not found: $rocmBinPath"
exit 1
}
- name: List build artifacts (including ROCm files)
run: |
cd llama.cpp\build\bin
Write-Host "Final build artifacts (including ROCm core files):"
Get-ChildItem -Recurse | Format-Table Name, Length, LastWriteTime
- name: Upload build artifacts
id: upload-artifacts
uses: actions/upload-artifact@v4
with:
name: llama-windows-rocm-${{ matrix.gfx_target }}-x64
path: llama.cpp/build/bin/
retention-days: 30
- name: Set job outputs
id: set-outputs
run: |
Write-Host "Setting job outputs..."
Write-Host "Current target: ${{ matrix.gfx_target }}"
Write-Host "DETECTED_ROCM_VERSION: $env:DETECTED_ROCM_VERSION"
Write-Host "ROCM_VERSION: $env:ROCM_VERSION"
Write-Host "LLAMACPP_COMMIT_HASH: $env:LLAMACPP_COMMIT_HASH"
$rocmVersion = if ($env:DETECTED_ROCM_VERSION) { $env:DETECTED_ROCM_VERSION } else { $env:ROCM_VERSION }
echo "rocm_version=$rocmVersion" >> $env:GITHUB_OUTPUT
echo "llamacpp_commit_hash=$env:LLAMACPP_COMMIT_HASH" >> $env:GITHUB_OUTPUT
Write-Host "Final rocm_version: $rocmVersion"
Write-Host "Final llamacpp_commit_hash: $env:LLAMACPP_COMMIT_HASH"
- name: Create release summary
run: |
$summary = @"
# Llama.cpp + ROCm Build Summary (Windows - ${{ matrix.gfx_target }})
## Build Configuration
- **GPU Target**: ${{ matrix.gfx_target }}
- **ROCm Version**: ${{ env.DETECTED_ROCM_VERSION || env.ROCM_VERSION }}
- **llama.cpp Commit Hash**: ${{ env.LLAMACPP_COMMIT_HASH }}
- **Build Type**: Release
- **Platform**: Windows
## Build Artifacts
The compiled binaries are available in the build artifacts.
"@
Set-Content -Path "build-summary-windows-${{ matrix.gfx_target }}.md" -Value $summary
- name: Upload build summary
id: upload-summary
uses: actions/upload-artifact@v4
with:
name: build-summary-windows-${{ matrix.gfx_target }}
path: build-summary-windows-${{ matrix.gfx_target }}.md
retention-days: 30
- name: Clean up build artifacts and temporary files
if: always()
run: |
Write-Host "Starting cleanup process..."
# Remove ROCm tarball
if (Test-Path "rocm.tar.gz") {
Write-Host "Removing rocm.tar.gz..."
Remove-Item -Force "rocm.tar.gz"
}
# Remove ROCm installation directory
if (Test-Path "C:\opt\rocm") {
Write-Host "Removing C:\opt\rocm directory..."
Remove-Item -Recurse -Force "C:\opt\rocm"
}
# Remove llama.cpp source directory (keeping only the build artifacts)
if (Test-Path "llama.cpp") {
Write-Host "Removing llama.cpp source directory..."
Remove-Item -Recurse -Force "llama.cpp"
}
# Clean up any temporary build files
if (Test-Path "build-summary-windows-${{ matrix.gfx_target }}.md") {
Write-Host "Removing build-summary-windows-${{ matrix.gfx_target }}.md..."
Remove-Item -Force "build-summary-windows-${{ matrix.gfx_target }}.md"
}
Write-Host "Cleanup completed successfully"
build-ubuntu:
runs-on: ubuntu-22.04
needs: prepare-matrix
if: needs.prepare-matrix.outputs.should_build_ubuntu == 'true'
strategy:
matrix: ${{fromJson(needs.prepare-matrix.outputs.ubuntu_matrix)}}
fail-fast: false
outputs:
rocm_version: ${{ steps.set-outputs.outputs.rocm_version }}
llamacpp_commit_hash: ${{ steps.set-outputs.outputs.llamacpp_commit_hash }}
steps:
- name: Free disk space
# Remove unused runner files to free up disk space
run: curl -fsSL https://raw.githubusercontent.com/kou/arrow/e49d8ae15583ceff03237571569099a6ad62be32/ci/scripts/util_free_space.sh | bash
- name: Checkout repository
uses: actions/checkout@v4
- name: Clean up existing directories (safety precaution)
run: |
# Remove existing llama.cpp directory if it exists
if [ -d "llama.cpp" ]; then
echo "Removing existing llama.cpp directory..."
rm -rf llama.cpp
fi
# Remove existing /opt/rocm directory if it exists
if [ -d "/opt/rocm" ]; then
echo "Removing existing /opt/rocm directory..."
sudo rm -rf /opt/rocm
fi
# Remove any existing ROCm tarball
if [ -f "rocm.tar.gz" ]; then
echo "Removing existing rocm.tar.gz..."
rm -f rocm.tar.gz
fi
echo "Cleanup completed successfully"
- name: Install build dependencies
run: |
echo "Installing build dependencies..."
sudo apt update
sudo apt install -y cmake ninja-build unzip curl
# Verify installations
echo "Verifying installations..."
cmake --version
ninja --version
echo "Build dependencies installation completed"
- name: Download and extract ROCm directly to /opt/rocm
run: |
# Determine ROCm version to use
rocm_version="${{ env.ROCM_VERSION }}"
current_target="${{ matrix.gfx_target }}"
# Add appropriate suffixes for different GPU targets
s3_target="$current_target"
if [ "$current_target" = "gfx103X" ]; then
s3_target="${current_target}-dgpu"
echo "Using S3 target with -dgpu suffix: $s3_target"
elif [[ "$current_target" = "gfx110X" || "$current_target" = "gfx120X" ]]; then
s3_target="${current_target}-all"
echo "Using S3 target with -all suffix: $s3_target"
fi
if [ "$rocm_version" = "latest" ]; then
echo "Auto-detecting latest ROCm version for target: $current_target"
s3_response=$(curl -s "https://therock-nightly-tarball.s3.amazonaws.com/?prefix=therock-dist-linux-${s3_target}-7")
# Extract all files and parse versions properly
files=$(echo "$s3_response" | grep -oP '(?<=<Key>)[^<]*' | grep "therock-dist-linux-${s3_target}-")
# Extract versions and sort them properly using semantic versioning
latest_file=""
latest_major=0
latest_minor=0
latest_patch=0
latest_rc=0
latest_is_alpha=false
while IFS= read -r file; do
if [[ "$file" =~ therock-dist-linux-${s3_target}-.*?([0-9]+\.[0-9]+\.[0-9]+(a|rc)[0-9]+)\.tar\.gz ]]; then
version="${BASH_REMATCH[1]}"
major=$(echo "$version" | cut -d. -f1)
minor=$(echo "$version" | cut -d. -f2)
patch=$(echo "$version" | cut -d. -f3 | sed 's/\(a\|rc\).*//')
rc=$(echo "$version" | sed 's/.*\(a\|rc\)//')
is_alpha=false
if [[ "$version" =~ a ]]; then
is_alpha=true
fi
# Compare versions (alpha versions are newer than rc versions)
is_newer=false
if [ "$major" -gt "$latest_major" ]; then
is_newer=true
elif [ "$major" -eq "$latest_major" ] && [ "$minor" -gt "$latest_minor" ]; then
is_newer=true
elif [ "$major" -eq "$latest_major" ] && [ "$minor" -eq "$latest_minor" ] && [ "$patch" -gt "$latest_patch" ]; then
is_newer=true
elif [ "$major" -eq "$latest_major" ] && [ "$minor" -eq "$latest_minor" ] && [ "$patch" -eq "$latest_patch" ]; then
# Same major.minor.patch, compare alpha vs rc
if [ "$is_alpha" = true ] && [ "$latest_is_alpha" = false ]; then
is_newer=true
elif [ "$is_alpha" = "$latest_is_alpha" ] && [ "$rc" -gt "$latest_rc" ]; then
is_newer=true
fi
fi
if [ "$is_newer" = true ]; then
latest_file="$file"
latest_major="$major"
latest_minor="$minor"
latest_patch="$patch"
latest_rc="$rc"
latest_is_alpha="$is_alpha"
fi
fi
done <<< "$files"
echo "Found latest file: $latest_file"
# Extract version from the filename for environment variable
if [[ "$latest_file" =~ therock-dist-linux-${s3_target}-.*?([0-9]+\.[0-9]+\.[0-9]+(a|rc)[0-9]+)\.tar\.gz ]]; then
rocm_version="${BASH_REMATCH[1]}"
echo "Detected latest ROCm version: $rocm_version"
else
echo "Failed to extract ROCm version from latest file: $latest_file"
echo "Expected pattern: therock-dist-linux-${s3_target}-*<version>.tar.gz"
exit 1
fi
# Use the exact filename from S3 instead of reconstructing
rocm_url="https://therock-nightly-tarball.s3.amazonaws.com/$latest_file"
else
# For specific versions, construct the URL as before
rocm_url="https://therock-nightly-tarball.s3.amazonaws.com/therock-dist-linux-${s3_target}-${rocm_version}.tar.gz"
fi
# Store the version for use in other steps
echo "DETECTED_ROCM_VERSION=$rocm_version" >> $GITHUB_ENV
echo "Streaming ROCm from: $rocm_url directly to extraction"
# Create directory if it doesn't exist
sudo mkdir -p /opt/rocm
# Stream download directly into tar extraction (no intermediate file)
curl -sL "$rocm_url" | sudo tar --use-compress-program=gzip -xf - -C /opt/rocm --strip-components=1
- name: Set ROCm environment variables
run: |
echo "Setting ROCm environment variables..."
# Set environment variables for this step and subsequent steps
echo "HIP_PATH=/opt/rocm" >> $GITHUB_ENV
echo "ROCM_PATH=/opt/rocm" >> $GITHUB_ENV
echo "HIP_PLATFORM=amd" >> $GITHUB_ENV
echo "HIP_CLANG_PATH=/opt/rocm/llvm/bin" >> $GITHUB_ENV
echo "HIP_INCLUDE_PATH=/opt/rocm/include" >> $GITHUB_ENV
echo "HIP_LIB_PATH=/opt/rocm/lib" >> $GITHUB_ENV
echo "HIP_DEVICE_LIB_PATH=/opt/rocm/lib/llvm/amdgcn/bitcode" >> $GITHUB_ENV
# Update PATH
echo "/opt/rocm/bin:/opt/rocm/llvm/bin:$PATH" >> $GITHUB_PATH
# Set library paths
echo "LD_LIBRARY_PATH=/opt/rocm/lib:/opt/rocm/lib64:/opt/rocm/llvm/lib:${LD_LIBRARY_PATH:-}" >> $GITHUB_ENV
echo "LIBRARY_PATH=/opt/rocm/lib:/opt/rocm/lib64:${LIBRARY_PATH:-}" >> $GITHUB_ENV
echo "CPATH=/opt/rocm/include:${CPATH:-}" >> $GITHUB_ENV
echo "PKG_CONFIG_PATH=/opt/rocm/lib/pkgconfig:${PKG_CONFIG_PATH:-}" >> $GITHUB_ENV
echo "ROCm environment variables set successfully"
- name: Clone llama.cpp
run: |
llamacpp_version="${{ env.LLAMACPP_VERSION }}"
if [ "$llamacpp_version" = "latest" ]; then
echo "Cloning master branch (latest) with shallow clone"
git clone --depth 1 --single-branch --branch master https://github.com/ggerganov/llama.cpp.git
else
echo "Cloning llama.cpp version: $llamacpp_version with shallow clone"
git clone --depth 1 --single-branch --branch "$llamacpp_version" https://github.com/ggerganov/llama.cpp.git
fi
cd llama.cpp
# Get commit hash (5 digits) and store it as environment variable
commit_hash=$(git rev-parse --short=5 HEAD)
echo "LLAMACPP_COMMIT_HASH=$commit_hash" >> $GITHUB_ENV
echo "llama.cpp commit hash (5 digits): $commit_hash"
# Show current commit info
echo "Current llama.cpp commit:"
git log --oneline -1
- name: Build Llama.cpp + ROCm
run: |
# Map GPU targets
current_target="${{ matrix.gfx_target }}"
echo "Input target: $current_target"
if [ "$current_target" = "gfx110X" ]; then
mapped_target="gfx1100;gfx1101;gfx1102;gfx1103"
elif [ "$current_target" = "gfx103X" ]; then
mapped_target="gfx1030;gfx1031;gfx1032;gfx1034"
elif [ "$current_target" = "gfx1151" ]; then
mapped_target="gfx1151"
elif [ "$current_target" = "gfx1150" ]; then
mapped_target="gfx1150"
elif [ "$current_target" = "gfx120X" ]; then
mapped_target="gfx1200;gfx1201"
else
mapped_target="$current_target"
fi
echo "Mapped target: $mapped_target"
# Create build directory
cd llama.cpp
mkdir build
cd build
# Configure the project
cmake .. -G Ninja \
-DCMAKE_C_COMPILER=/opt/rocm/llvm/bin/clang \
-DCMAKE_CXX_COMPILER=/opt/rocm/llvm/bin/clang++ \
-DCMAKE_CXX_FLAGS="-I/opt/rocm/include" \
-DCMAKE_CROSSCOMPILING=ON \
-DCMAKE_BUILD_TYPE=Release \
-DGPU_TARGETS="$mapped_target" \
-DBUILD_SHARED_LIBS=ON \
-DLLAMA_BUILD_TESTS=OFF \
-DGGML_HIP=ON \
-DGGML_OPENMP=OFF \
-DGGML_CUDA_FORCE_CUBLAS=OFF \
-DGGML_RPC=ON \
-DGGML_HIP_ROCWMMA_FATTN=OFF \
-DLLAMA_BUILD_BORINGSSL=ON \
-DGGML_NATIVE=OFF \
-DGGML_STATIC=OFF \
-DCMAKE_SYSTEM_NAME=Linux
# Build the project
cmake --build . -j $(nproc)
- name: Copy ROCm core libs to build directory
run: |
build_bin_path="llama.cpp/build/bin"
rocm_bin_path="/opt/rocm/bin"
# Copy the rocblas/library folder and all its contents
rocblas_lib_path="/opt/rocm/lib/rocblas/library"
if [ -d "$rocblas_lib_path" ]; then
echo "Copying rocblas/library folder and all contents..."
dest_rocblas_path="$build_bin_path/rocblas/library"
mkdir -p "$(dirname "$dest_rocblas_path")"
cp -r "$rocblas_lib_path" "$(dirname "$dest_rocblas_path")/"
echo "Copied: rocblas/library folder with all contents"
# List the contents of the copied rocblas/library folder
echo "Contents of rocblas/library:"
find "$dest_rocblas_path" -type f -exec ls -la {} \; | head -20
else
echo "Warning: rocblas/library folder not found at: $rocblas_lib_path"
fi
# Copy the hipblaslt/library folder and all its contents
hipblaslt_lib_path="/opt/rocm/lib/hipblaslt/library"
if [ -d "$hipblaslt_lib_path" ]; then
echo "Copying hipblaslt/library folder and all contents..."
dest_hipblaslt_path="$build_bin_path/hipblaslt/library"
mkdir -p "$(dirname "$dest_hipblaslt_path")"
cp -r "$hipblaslt_lib_path" "$(dirname "$dest_hipblaslt_path")/"
echo "Copied: hipblaslt/library folder with all contents"
# List the contents of the copied hipblaslt/library folder
echo "Contents of hipblaslt/library:"
find "$dest_hipblaslt_path" -type f -exec ls -la {} \; | head -20
else
echo "Warning: hipblaslt/library folder not found at: $hipblaslt_lib_path"
fi
# Copy required ROCm libraries to build directory
# If artifacts from ROCm or Llama.cpp change, you may need to update this list
# To get a new list of all libraries, run:
# gather_required_libs.py --rocm-dir /opt/rocm --dest-dir llama.cpp/build/bin
echo "Copying required ROCm libraries to build directory..."
cp -v /opt/rocm/lib/libhipblas.so* "$build_bin_path/" 2>/dev/null || echo "libhipblas.so* not found"
cp -v /opt/rocm/lib/librocblas.so* "$build_bin_path/" 2>/dev/null || echo "librocblas.so* not found"
cp -v /opt/rocm/lib/libamdhip64.so* "$build_bin_path/" 2>/dev/null || echo "libamdhip64.so* not found"
cp -v /opt/rocm/lib/librocsolver.so* "$build_bin_path/" 2>/dev/null || echo "librocsolver.so* not found"
cp -v /opt/rocm/lib/libroctx64.so* "$build_bin_path/" 2>/dev/null || echo "libroctx64.so* not found"
cp -v /opt/rocm/lib/libhipblaslt.so* "$build_bin_path/" 2>/dev/null || echo "libhipblaslt.so* not found"
cp -v /opt/rocm/lib/rocm_sysdeps/lib/librocm_sysdeps_liblzma.so* "$build_bin_path/" 2>/dev/null || echo "librocm_sysdeps_liblzma.so* not found"
cp -v /opt/rocm/lib/librocprofiler-register.so* "$build_bin_path/" 2>/dev/null || echo "librocprofiler-register.so* not found"
cp -v /opt/rocm/lib/libamd_comgr.so* "$build_bin_path/" 2>/dev/null || echo "libamd_comgr.so* not found"
cp -v /opt/rocm/lib/libamd_comgr_loader.so* "$build_bin_path/" 2>/dev/null || echo "libamd_comgr_loader.so* not found"
cp -v /opt/rocm/lib/libhsa-runtime64.so* "$build_bin_path/" 2>/dev/null || echo "libhsa-runtime64.so* not found"
cp -v /opt/rocm/lib/rocm_sysdeps/lib/librocm_sysdeps_numa.so* "$build_bin_path/" 2>/dev/null || echo "librocm_sysdeps_numa.so* not found"
cp -v /opt/rocm/lib/librocroller.so* "$build_bin_path/" 2>/dev/null || echo "librocroller.so* not found"
cp -v /opt/rocm/lib/librocm_kpack.so* "$build_bin_path/" 2>/dev/null || echo "librocm_kpack.so* not found"
cp -v /opt/rocm/lib/rocm_sysdeps/lib/librocm_sysdeps_z.so* "$build_bin_path/" 2>/dev/null || echo "librocm_sysdeps_z.so* not found"
cp -v /opt/rocm/lib/rocm_sysdeps/lib/librocm_sysdeps_zstd.so* "$build_bin_path/" 2>/dev/null || echo "librocm_sysdeps_zstd.so* not found"
cp -v /opt/rocm/lib/llvm/lib/libLLVM.so* "$build_bin_path/" 2>/dev/null || echo "libLLVM.so* not found"
cp -v /opt/rocm/lib/llvm/lib/libclang-cpp.so* "$build_bin_path/" 2>/dev/null || echo "libclang-cpp.so* not found"
cp -v /opt/rocm/lib/rocm_sysdeps/lib/librocm_sysdeps_elf.so* "$build_bin_path/" 2>/dev/null || echo "librocm_sysdeps_elf.so* not found"
cp -v /opt/rocm/lib/rocm_sysdeps/lib/librocm_sysdeps_drm.so* "$build_bin_path/" 2>/dev/null || echo "librocm_sysdeps_drm.so* not found"
cp -v /opt/rocm/lib/rocm_sysdeps/lib/librocm_sysdeps_drm_amdgpu.so* "$build_bin_path/" 2>/dev/null || echo "librocm_sysdeps_drm_amdgpu.so* not found"
cp -v /opt/rocm/lib/rocm_sysdeps/lib/librocm_sysdeps_bz2.so* "$build_bin_path/" 2>/dev/null || echo "librocm_sysdeps_bz2.so* not found"
echo "Finished copying required ROCm libraries"
- name: Set RPATH for portable distribution
run: |
sudo apt-get install -y patchelf
cd llama.cpp/build/bin
# Set RPATH to $ORIGIN so all libraries (including the comgr stub loader) find deps locally
for file in *.so* llama-*; do
[ -f "$file" ] && [ ! -L "$file" ] && patchelf --set-rpath '$ORIGIN' "$file" 2>/dev/null || true
done
- name: List build artifacts (including ROCm files)
run: |
cd llama.cpp/build/bin
echo "Final build artifacts (including ROCm library files):"
ls -la
- name: Upload build artifacts
id: upload-artifacts
uses: actions/upload-artifact@v4
with:
name: llama-ubuntu-rocm-${{ matrix.gfx_target }}-x64
path: llama.cpp/build/bin/
retention-days: 30
- name: Set job outputs
id: set-outputs
run: |
echo "Setting job outputs..."
echo "Current target: ${{ matrix.gfx_target }}"
echo "DETECTED_ROCM_VERSION: ${DETECTED_ROCM_VERSION}"
echo "ROCM_VERSION: ${{ env.ROCM_VERSION }}"
echo "LLAMACPP_COMMIT_HASH: ${LLAMACPP_COMMIT_HASH}"
rocm_version="${DETECTED_ROCM_VERSION:-${{ env.ROCM_VERSION }}}"
echo "rocm_version=$rocm_version" >> $GITHUB_OUTPUT
echo "llamacpp_commit_hash=${LLAMACPP_COMMIT_HASH}" >> $GITHUB_OUTPUT
echo "Final rocm_version: $rocm_version"
echo "Final llamacpp_commit_hash: ${LLAMACPP_COMMIT_HASH}"
- name: Create release summary
run: |
cat > "build-summary-ubuntu-${{ matrix.gfx_target }}.md" << 'EOF'
# Llama.cpp + ROCm Build Summary (Ubuntu - ${{ matrix.gfx_target }})
## Build Configuration
- **GPU Target**: ${{ matrix.gfx_target }}
- **ROCm Version**: ${{ env.DETECTED_ROCM_VERSION || env.ROCM_VERSION }}
- **llama.cpp Commit Hash**: ${{ env.LLAMACPP_COMMIT_HASH }}
- **Build Type**: Release
- **Platform**: Ubuntu
## Build Artifacts
The compiled binaries are available in the build artifacts.
EOF
- name: Upload build summary
id: upload-summary
uses: actions/upload-artifact@v4
with:
name: build-summary-ubuntu-${{ matrix.gfx_target }}
path: build-summary-ubuntu-${{ matrix.gfx_target }}.md
retention-days: 30
- name: Clean up build artifacts and temporary files
if: always()
run: |
echo "Starting cleanup process..."
# Remove ROCm tarball
if [ -f "rocm.tar.gz" ]; then
echo "Removing rocm.tar.gz..."
rm -f rocm.tar.gz
fi
# Remove ROCm installation directory
if [ -d "/opt/rocm" ]; then
echo "Removing /opt/rocm directory..."
sudo rm -rf /opt/rocm
fi
# Remove llama.cpp source directory (keeping only the build artifacts)
if [ -d "llama.cpp" ]; then
echo "Removing llama.cpp source directory..."
rm -rf llama.cpp
fi
# Clean up any temporary build files
if [ -f "build-summary-ubuntu-${{ matrix.gfx_target }}.md" ]; then
echo "Removing build-summary-ubuntu-${{ matrix.gfx_target }}.md..."
rm -f "build-summary-ubuntu-${{ matrix.gfx_target }}.md"
fi
echo "Cleanup completed successfully"
test-stx-halo:
runs-on: ${{ matrix.runner }}
needs: [prepare-matrix, build-windows, build-ubuntu]
if: |
(needs.build-windows.result == 'success' || needs.build-ubuntu.result == 'success') &&
contains(github.event.inputs.gfx_target || 'gfx1151,gfx1150,gfx120X,gfx110X', 'gfx1151')
strategy:
matrix:
include:
- os: Windows
gfx_target: gfx1151
artifact_prefix: windows
runner: ["stx-halo", "Windows"]
- os: Linux
gfx_target: gfx1151
artifact_prefix: ubuntu
runner: ["stx-halo", "Linux"]
fail-fast: false
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Test llama.cpp build
uses: ./.github/actions/test-llamacpp-build
with:
os_type: ${{ matrix.os }}
gfx_target: ${{ matrix.gfx_target }}
artifact_name: llama-${{ matrix.artifact_prefix }}-rocm-${{ matrix.gfx_target }}-x64
test-stx:
runs-on: ${{ matrix.runner }}
needs: [prepare-matrix, build-windows, build-ubuntu]
if: |
(needs.build-windows.result == 'success' || needs.build-ubuntu.result == 'success') &&
contains(github.event.inputs.gfx_target || 'gfx1151,gfx1150,gfx120X,gfx110X', 'gfx1150')
strategy:
matrix:
include:
- os: Windows
gfx_target: gfx1150
artifact_prefix: windows
runner: ["stx", "Windows"]
fail-fast: false
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Test llama.cpp build
uses: ./.github/actions/test-llamacpp-build
with:
os_type: ${{ matrix.os }}
gfx_target: ${{ matrix.gfx_target }}
artifact_name: llama-${{ matrix.artifact_prefix }}-rocm-${{ matrix.gfx_target }}-x64
create-release:
needs: [prepare-matrix, build-windows, build-ubuntu, test-stx-halo, test-stx]
runs-on: ubuntu-22.04
permissions:
contents: write
pull-requests: write
if: |
always() &&
(needs.build-windows.result == 'success' || needs.build-ubuntu.result == 'success') &&
(needs.test-stx-halo.result == 'success' || needs.test-stx-halo.result == 'skipped') &&
(needs.test-stx.result == 'success' || needs.test-stx.result == 'skipped') &&
github.event_name != 'pull_request' &&
(github.event_name == 'workflow_dispatch' &&
(github.event.inputs.create_release == 'true' || github.event.inputs.create_release == null) ||
github.event_name == 'schedule')
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Download all build artifacts
uses: actions/download-artifact@v4
with:
path: ./all-artifacts
- name: Generate release tag
id: generate-tag
env:
GITHUB_TOKEN: ${{ secrets.GH_TOKEN }}
run: |
# Get all existing release tags that match the pattern b####
existing_tags=$(gh release list --limit 1000 --json tagName --jq '.[].tagName' | grep -E '^b[0-9]{4}$' | sort -V || echo "")
if [ -z "$existing_tags" ]; then
# No existing sequential tags found, start with b1000
next_number=1000
echo "No existing sequential release tags found, starting with b1000"
else
# Find the highest existing number
highest_tag=$(echo "$existing_tags" | tail -n 1)
highest_number=$(echo "$highest_tag" | sed 's/^b//')
next_number=$((highest_number + 1))
echo "Highest existing tag: $highest_tag (number: $highest_number)"
echo "Next number will be: $next_number"
fi
# Format as b#### (4-digit number with leading zeros)
TAG=$(printf "b%04d" $next_number)
echo "tag=${TAG}" >> $GITHUB_OUTPUT
echo "Generated release tag: ${TAG}"
- name: Check if tag already exists
id: check-tag
run: |
TAG="${{ steps.generate-tag.outputs.tag }}"
# Check if the tag already exists
if git ls-remote --tags origin "$TAG" | grep -q "$TAG"; then
echo "Tag $TAG already exists, skipping release creation"
echo "tag_exists=true" >> $GITHUB_OUTPUT
else
echo "Tag $TAG does not exist, proceeding with release creation"
echo "tag_exists=false" >> $GITHUB_OUTPUT
fi
- name: Create archives for all target artifacts
if: steps.check-tag.outputs.tag_exists == 'false'
run: |
# Parse targets and operating systems from environment
targets="${{ env.GFX_TARGETS }}"
operating_systems="${{ env.OPERATING_SYSTEMS }}"
TAG="${{ steps.generate-tag.outputs.tag }}"
echo "Processing targets: $targets"
echo "Processing operating systems: $operating_systems"
echo "Using release tag: $TAG"
# Create individual archives for each target and OS combination
IFS=',' read -ra TARGET_ARRAY <<< "$targets"
IFS=',' read -ra OS_ARRAY <<< "$operating_systems"
for os in "${OS_ARRAY[@]}"; do
os=$(echo "$os" | xargs) # trim whitespace
for target in "${TARGET_ARRAY[@]}"; do
target=$(echo "$target" | xargs) # trim whitespace
echo "Processing OS: $os, target: $target"
# Use artifact name to find the directory
artifact_name="llama-${os}-rocm-${target}-x64"
artifact_dir="./all-artifacts/${artifact_name}"
# Create final archive with release tag
final_archive_name="llama-${TAG}-${os}-rocm-${target}-x64"
if [ -d "$artifact_dir" ]; then
echo "Creating archive: ${final_archive_name}.zip"
cd "$artifact_dir"
zip -r "../../${final_archive_name}.zip" *
cd ../../
else
echo "Warning: Artifact directory not found: $artifact_dir"
ls -la ./all-artifacts/
fi
done
done
echo "Created archives:"
ls -la *.zip
- name: Create Release
if: steps.check-tag.outputs.tag_exists == 'false'
env:
GITHUB_TOKEN: ${{ secrets.GH_TOKEN }}
run: |
TAG="${{ steps.generate-tag.outputs.tag }}"
# Get ROCm version from either Windows or Ubuntu build (whichever succeeded)
ROCM_VERSION="${{ needs.build-windows.outputs.rocm_version || needs.build-ubuntu.outputs.rocm_version }}"
# Get llama.cpp commit hash from either Windows or Ubuntu build (whichever succeeded)
LLAMACPP_COMMIT_HASH="${{ needs.build-windows.outputs.llamacpp_commit_hash || needs.build-ubuntu.outputs.llamacpp_commit_hash }}"
targets="${{ env.GFX_TARGETS }}"
operating_systems="${{ env.OPERATING_SYSTEMS }}"
echo "Creating release with tag: $TAG"
echo "GPU Targets: $targets"
echo "Operating Systems: $operating_systems"
echo "ROCm Version: $ROCM_VERSION"
echo "Llama.cpp Commit: $LLAMACPP_COMMIT_HASH"
# Verify archives exist
ls -la *.zip
# Prepare upload files list
upload_files=""
IFS=',' read -ra TARGET_ARRAY <<< "$targets"
IFS=',' read -ra OS_ARRAY <<< "$operating_systems"
for os in "${OS_ARRAY[@]}"; do
os=$(echo "$os" | xargs) # trim whitespace
for target in "${TARGET_ARRAY[@]}"; do
target=$(echo "$target" | xargs) # trim whitespace
final_archive_name="llama-${TAG}-${os}-rocm-${target}-x64"
if [ -f "${final_archive_name}.zip" ]; then
upload_files="${upload_files} ${final_archive_name}.zip"
fi
done
done
echo "Files to upload: $upload_files"
# Create release with GitHub CLI
gh release create "$TAG" \
--title "$TAG" \
--notes "**Build Number**: $TAG
**Operating System(s)**: $operating_systems
**GPU Target(s)**: $targets
**ROCm Version**: $ROCM_VERSION
**Llama.cpp Commit Hash**: $LLAMACPP_COMMIT_HASH
**Build Date**: $(date -u '+%Y-%m-%d %H:%M:%S UTC')
This release includes compiled llama.cpp binaries with ROCm support for multiple GPU targets and operating systems, with all essential ROCm runtime libraries included." \
$upload_files