ollama source for Momentry Core verification
This commit is contained in:
2
scripts/.this-is-the-create-dmg-repo
Normal file
2
scripts/.this-is-the-create-dmg-repo
Normal file
@@ -0,0 +1,2 @@
|
||||
This is just a dummy file so create-dmg can tell whether it's being run from
|
||||
inside the Git repo or from an installed location.
|
||||
354
scripts/build_darwin.sh
Executable file
354
scripts/build_darwin.sh
Executable file
@@ -0,0 +1,354 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Note:
|
||||
# While testing, if you double-click on the Ollama.app
|
||||
# some state is left on MacOS and subsequent attempts
|
||||
# to build again will fail with:
|
||||
#
|
||||
# hdiutil: create failed - Operation not permitted
|
||||
#
|
||||
# To work around, specify another volume name with:
|
||||
#
|
||||
# VOL_NAME="$(date)" ./scripts/build_darwin.sh
|
||||
#
|
||||
VOL_NAME=${VOL_NAME:-"Ollama"}
|
||||
export VERSION=${VERSION:-$(git describe --tags --first-parent --abbrev=7 --long --dirty --always | sed -e "s/^v//g")}
|
||||
export GOFLAGS="'-ldflags=-w -s \"-X=github.com/ollama/ollama/version.Version=${VERSION#v}\" \"-X=github.com/ollama/ollama/server.mode=release\"'"
|
||||
export CGO_CFLAGS="-O3 -mmacosx-version-min=14.0"
|
||||
export CGO_CXXFLAGS="-O3 -mmacosx-version-min=14.0"
|
||||
export CGO_LDFLAGS="-mmacosx-version-min=14.0"
|
||||
|
||||
set -e
|
||||
|
||||
status() { echo >&2 ">>> $@"; }
|
||||
usage() {
|
||||
echo "usage: $(basename $0) [build app [sign]]"
|
||||
exit 1
|
||||
}
|
||||
|
||||
mkdir -p dist
|
||||
|
||||
# Work around MLX's v3 metallib link leaking the macOS 26 deployment target.
|
||||
_relink_mlx_metallib() {
|
||||
BUILD_DIR="$1"
|
||||
KERNEL_DIR="$BUILD_DIR/_deps/mlx-build/mlx/backend/metal/kernels"
|
||||
AIR_LIST="$BUILD_DIR/mlx-air-files.txt"
|
||||
METALLIB="$KERNEL_DIR/mlx.metallib"
|
||||
|
||||
find "$KERNEL_DIR" -type f -name '*.air' | sort > "$AIR_LIST"
|
||||
if [ ! -s "$AIR_LIST" ]; then
|
||||
echo "error: could not find MLX AIR files in $KERNEL_DIR" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
status "Relinking MLX metallib"
|
||||
rm -f "$METALLIB"
|
||||
xargs xcrun -sdk macosx metallib -o "$METALLIB" < "$AIR_LIST"
|
||||
}
|
||||
|
||||
|
||||
ARCHS="arm64 amd64"
|
||||
while getopts "a:h" OPTION; do
|
||||
case $OPTION in
|
||||
a) ARCHS=$OPTARG ;;
|
||||
h) usage ;;
|
||||
esac
|
||||
done
|
||||
|
||||
shift $(( $OPTIND - 1 ))
|
||||
|
||||
_build_darwin() {
|
||||
for ARCH in $ARCHS; do
|
||||
status "Building darwin $ARCH"
|
||||
INSTALL_PREFIX=dist/darwin-$ARCH/
|
||||
|
||||
if [ "$ARCH" = "amd64" ]; then
|
||||
status "Building darwin $ARCH dynamic backends"
|
||||
BUILD_DIR=build/darwin-$ARCH
|
||||
cmake -B $BUILD_DIR \
|
||||
-DCMAKE_OSX_ARCHITECTURES=x86_64 \
|
||||
-DCMAKE_OSX_DEPLOYMENT_TARGET=14.0 \
|
||||
-DCMAKE_INSTALL_PREFIX=$INSTALL_PREFIX \
|
||||
-DMLX_ENGINE=ON \
|
||||
-DMLX_ENABLE_X64_MAC=ON \
|
||||
-DOLLAMA_RUNNER_DIR=./
|
||||
cmake --build $BUILD_DIR --target ggml-cpu -j
|
||||
cmake --build $BUILD_DIR --target mlx mlxc -j
|
||||
cmake --install $BUILD_DIR --component CPU
|
||||
cmake --install $BUILD_DIR --component MLX
|
||||
cmake --install $BUILD_DIR --component MLX_VENDOR
|
||||
# Override CGO flags to point to the amd64 build directory
|
||||
MLX_CGO_CFLAGS="-O3 -mmacosx-version-min=14.0"
|
||||
MLX_CGO_LDFLAGS="-ldl -lc++ -framework Accelerate -mmacosx-version-min=14.0"
|
||||
else
|
||||
# CPU backend (ggml-cpu, installed flat to lib/ollama/)
|
||||
BUILD_DIR_CPU=build/arm64-cpu
|
||||
status "Building arm64 CPU backend"
|
||||
cmake -S . -B $BUILD_DIR_CPU \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
-DCMAKE_OSX_DEPLOYMENT_TARGET=14.0 \
|
||||
-DCMAKE_INSTALL_PREFIX=$INSTALL_PREFIX
|
||||
cmake --build $BUILD_DIR_CPU --target ggml-cpu --parallel
|
||||
cmake --install $BUILD_DIR_CPU --component CPU
|
||||
|
||||
# Build MLX twice for arm64
|
||||
# Metal 3.x build (backward compatible, macOS 14+)
|
||||
BUILD_DIR=build/metal-v3
|
||||
status "Building MLX Metal v3 (macOS 14+)"
|
||||
cmake -S . -B $BUILD_DIR \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
-DMLX_ENGINE=ON \
|
||||
-DOLLAMA_RUNNER_DIR=mlx_metal_v3 \
|
||||
-DCMAKE_OSX_DEPLOYMENT_TARGET=14.0 \
|
||||
-DCMAKE_INSTALL_PREFIX=$INSTALL_PREFIX
|
||||
cmake --build $BUILD_DIR --target mlx mlxc --parallel
|
||||
_relink_mlx_metallib $BUILD_DIR
|
||||
cmake --install $BUILD_DIR --component MLX
|
||||
cmake --install $BUILD_DIR --component MLX_VENDOR
|
||||
|
||||
# Metal 4.x build (NAX-enabled, macOS 26+)
|
||||
# Only possible with Xcode 26+ SDK; skip on older toolchains.
|
||||
SDK_MAJOR=$(xcrun --show-sdk-version 2>/dev/null | cut -d. -f1)
|
||||
if [ "${SDK_MAJOR:-0}" -ge 26 ]; then
|
||||
V3_DEPS=$BUILD_DIR/_deps
|
||||
BUILD_DIR_V4=build/metal-v4
|
||||
status "Building MLX Metal v4 (macOS 26+, NAX)"
|
||||
cmake -S . -B $BUILD_DIR_V4 \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
-DMLX_ENGINE=ON \
|
||||
-DOLLAMA_RUNNER_DIR=mlx_metal_v4 \
|
||||
-DCMAKE_OSX_DEPLOYMENT_TARGET=26.0 \
|
||||
-DCMAKE_INSTALL_PREFIX=$INSTALL_PREFIX \
|
||||
-DFETCHCONTENT_SOURCE_DIR_MLX=$V3_DEPS/mlx-src \
|
||||
-DFETCHCONTENT_SOURCE_DIR_MLX-C=$V3_DEPS/mlx-c-src \
|
||||
-DFETCHCONTENT_SOURCE_DIR_JSON=$V3_DEPS/json-src \
|
||||
-DFETCHCONTENT_SOURCE_DIR_FMT=$V3_DEPS/fmt-src \
|
||||
-DFETCHCONTENT_SOURCE_DIR_METAL_CPP=$V3_DEPS/metal_cpp-src
|
||||
cmake --build $BUILD_DIR_V4 --target mlx mlxc --parallel
|
||||
cmake --install $BUILD_DIR_V4 --component MLX
|
||||
cmake --install $BUILD_DIR_V4 --component MLX_VENDOR
|
||||
else
|
||||
status "Skipping MLX Metal v4 (SDK $SDK_MAJOR < 26, need Xcode 26+)"
|
||||
fi
|
||||
|
||||
# Use the v3 build for CGO linking (compatible with both)
|
||||
MLX_CGO_CFLAGS="-O3 -mmacosx-version-min=14.0"
|
||||
MLX_CGO_LDFLAGS="-lc++ -framework Metal -framework Foundation -framework Accelerate -mmacosx-version-min=14.0"
|
||||
fi
|
||||
GOOS=darwin GOARCH=$ARCH CGO_ENABLED=1 CGO_CFLAGS="$MLX_CGO_CFLAGS" CGO_LDFLAGS="$MLX_CGO_LDFLAGS" go build -o $INSTALL_PREFIX .
|
||||
# MLX libraries stay in lib/ollama/ (flat or variant subdirs).
|
||||
# The runtime discovery in dynamic.go searches lib/ollama/ relative
|
||||
# to the executable, including mlx_* subdirectories.
|
||||
done
|
||||
}
|
||||
|
||||
_sign_darwin() {
|
||||
status "Creating universal binary..."
|
||||
mkdir -p dist/darwin
|
||||
lipo -create -output dist/darwin/ollama dist/darwin-*/ollama
|
||||
chmod +x dist/darwin/ollama
|
||||
|
||||
if [ -n "$APPLE_IDENTITY" ]; then
|
||||
for F in dist/darwin/ollama dist/darwin-*/lib/ollama/* dist/darwin-*/lib/ollama/mlx_metal_v*/*; do
|
||||
[ -f "$F" ] && [ ! -L "$F" ] || continue
|
||||
codesign -f --timestamp -s "$APPLE_IDENTITY" --identifier ai.ollama.ollama --options=runtime "$F"
|
||||
done
|
||||
|
||||
# create a temporary zip for notarization
|
||||
TEMP=$(mktemp -u).zip
|
||||
ditto -c -k --keepParent dist/darwin/ollama "$TEMP"
|
||||
xcrun notarytool submit "$TEMP" --wait --timeout 20m --apple-id $APPLE_ID --password $APPLE_PASSWORD --team-id $APPLE_TEAM_ID
|
||||
rm -f "$TEMP"
|
||||
fi
|
||||
|
||||
status "Creating universal tarball..."
|
||||
tar -cf dist/ollama-darwin.tar --strip-components 2 dist/darwin/ollama
|
||||
tar -rf dist/ollama-darwin.tar --strip-components 4 dist/darwin-amd64/lib/
|
||||
tar -rf dist/ollama-darwin.tar --strip-components 4 dist/darwin-arm64/lib/
|
||||
gzip -9vc <dist/ollama-darwin.tar >dist/ollama-darwin.tgz
|
||||
}
|
||||
|
||||
_build_macapp() {
|
||||
if ! command -v npm &> /dev/null; then
|
||||
echo "npm is not installed. Please install Node.js and npm first:"
|
||||
echo " Visit: https://nodejs.org/"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! command -v tsc &> /dev/null; then
|
||||
echo "Installing TypeScript compiler..."
|
||||
npm install -g typescript
|
||||
fi
|
||||
|
||||
echo "Installing required Go tools..."
|
||||
|
||||
cd app/ui/app
|
||||
npm install
|
||||
npm run build
|
||||
cd ../../..
|
||||
|
||||
# Build the Ollama.app bundle
|
||||
rm -rf dist/Ollama.app
|
||||
cp -a ./app/darwin/Ollama.app dist/Ollama.app
|
||||
|
||||
# update the modified date of the app bundle to now
|
||||
touch dist/Ollama.app
|
||||
|
||||
go clean -cache
|
||||
GOARCH=amd64 CGO_ENABLED=1 GOOS=darwin go build -o dist/darwin-app-amd64 -ldflags="-s -w -X=github.com/ollama/ollama/app/version.Version=${VERSION}" ./app/cmd/app
|
||||
GOARCH=arm64 CGO_ENABLED=1 GOOS=darwin go build -o dist/darwin-app-arm64 -ldflags="-s -w -X=github.com/ollama/ollama/app/version.Version=${VERSION}" ./app/cmd/app
|
||||
mkdir -p dist/Ollama.app/Contents/MacOS
|
||||
lipo -create -output dist/Ollama.app/Contents/MacOS/Ollama dist/darwin-app-amd64 dist/darwin-app-arm64
|
||||
rm -f dist/darwin-app-amd64 dist/darwin-app-arm64
|
||||
|
||||
# Create a mock Squirrel.framework bundle
|
||||
mkdir -p dist/Ollama.app/Contents/Frameworks/Squirrel.framework/Versions/A/Resources/
|
||||
cp -a dist/Ollama.app/Contents/MacOS/Ollama dist/Ollama.app/Contents/Frameworks/Squirrel.framework/Versions/A/Squirrel
|
||||
ln -s ../Squirrel dist/Ollama.app/Contents/Frameworks/Squirrel.framework/Versions/A/Resources/ShipIt
|
||||
cp -a ./app/cmd/squirrel/Info.plist dist/Ollama.app/Contents/Frameworks/Squirrel.framework/Versions/A/Resources/Info.plist
|
||||
ln -s A dist/Ollama.app/Contents/Frameworks/Squirrel.framework/Versions/Current
|
||||
ln -s Versions/Current/Resources dist/Ollama.app/Contents/Frameworks/Squirrel.framework/Resources
|
||||
ln -s Versions/Current/Squirrel dist/Ollama.app/Contents/Frameworks/Squirrel.framework/Squirrel
|
||||
|
||||
# Update the version in the Info.plist
|
||||
plutil -replace CFBundleShortVersionString -string "$VERSION" dist/Ollama.app/Contents/Info.plist
|
||||
plutil -replace CFBundleVersion -string "$VERSION" dist/Ollama.app/Contents/Info.plist
|
||||
|
||||
# Setup the ollama binaries
|
||||
mkdir -p dist/Ollama.app/Contents/Resources
|
||||
if [ -d dist/darwin-amd64 ]; then
|
||||
lipo -create -output dist/Ollama.app/Contents/Resources/ollama dist/darwin-amd64/ollama dist/darwin-arm64/ollama
|
||||
|
||||
# Copy .so files from both architectures (names don't collide: arm64=libggml-cpu.so, amd64=libggml-cpu-*.so)
|
||||
cp dist/darwin-arm64/lib/ollama/*.so dist/Ollama.app/Contents/Resources/ 2>/dev/null || true
|
||||
cp dist/darwin-amd64/lib/ollama/*.so dist/Ollama.app/Contents/Resources/ 2>/dev/null || true
|
||||
# Lipo common dylibs into universal binaries, copy amd64-only ones as-is.
|
||||
# Skip MLX dylibs (libmlx*.dylib) — on arm64 these live in variant
|
||||
# subdirs (mlx_metal_v3/) and are lipo'd there below. Copying the
|
||||
# amd64 flat copy here would produce an x86_64-only dylib in
|
||||
# Resources/ that shadows the variant subdirs.
|
||||
for F in dist/darwin-amd64/lib/ollama/*.dylib; do
|
||||
[ -f "$F" ] && [ ! -L "$F" ] || continue
|
||||
BASE=$(basename "$F")
|
||||
case "$BASE" in libmlx*) continue ;; esac
|
||||
if [ -f "dist/darwin-arm64/lib/ollama/$BASE" ]; then
|
||||
lipo -create -output "dist/Ollama.app/Contents/Resources/$BASE" "$F" "dist/darwin-arm64/lib/ollama/$BASE"
|
||||
else
|
||||
cp "$F" dist/Ollama.app/Contents/Resources/
|
||||
fi
|
||||
done
|
||||
# Recreate ggml-base symlinks
|
||||
(cd dist/Ollama.app/Contents/Resources && ln -sf libggml-base.0.0.0.dylib libggml-base.0.dylib && ln -sf libggml-base.0.dylib libggml-base.dylib) 2>/dev/null || true
|
||||
|
||||
# MLX Metal variant subdirs from arm64
|
||||
for VARIANT in dist/darwin-arm64/lib/ollama/mlx_metal_v*/; do
|
||||
[ -d "$VARIANT" ] || continue
|
||||
VNAME=$(basename "$VARIANT")
|
||||
DEST=dist/Ollama.app/Contents/Resources/$VNAME
|
||||
mkdir -p "$DEST"
|
||||
if [ "$VNAME" = "mlx_metal_v3" ]; then
|
||||
# v3: lipo amd64 flat + arm64 v3 into universal dylibs
|
||||
for LIB in libmlx.dylib libmlxc.dylib; do
|
||||
if [ -f "dist/darwin-amd64/lib/ollama/$LIB" ] && [ -f "$VARIANT$LIB" ]; then
|
||||
lipo -create -output "$DEST/$LIB" "dist/darwin-amd64/lib/ollama/$LIB" "$VARIANT$LIB"
|
||||
elif [ -f "$VARIANT$LIB" ]; then
|
||||
cp "$VARIANT$LIB" "$DEST/"
|
||||
fi
|
||||
done
|
||||
# Copy remaining files (metallib and auxiliary runtime dylibs)
|
||||
# from arm64 v3. libmlx/libmlxc are handled above so v3 can
|
||||
# be universal when an x86_64 build is available.
|
||||
for F in "$VARIANT"*; do
|
||||
case "$(basename "$F")" in libmlx.dylib|libmlxc.dylib) continue ;; esac
|
||||
[ -f "$F" ] && [ ! -L "$F" ] || continue
|
||||
cp "$F" "$DEST/"
|
||||
done
|
||||
else
|
||||
# v4+: arm64-only, copy all non-symlink files
|
||||
for F in "$VARIANT"*; do
|
||||
[ -f "$F" ] && [ ! -L "$F" ] || continue
|
||||
cp "$F" "$DEST/"
|
||||
done
|
||||
fi
|
||||
done
|
||||
else
|
||||
cp -a dist/darwin/ollama dist/Ollama.app/Contents/Resources/ollama
|
||||
# arm64-only build: copy variant subdirs directly
|
||||
for VARIANT in dist/darwin-arm64/lib/ollama/mlx_metal_v*/; do
|
||||
[ -d "$VARIANT" ] || continue
|
||||
VNAME=$(basename "$VARIANT")
|
||||
mkdir -p dist/Ollama.app/Contents/Resources/$VNAME
|
||||
cp "$VARIANT"* dist/Ollama.app/Contents/Resources/$VNAME/ 2>/dev/null || true
|
||||
done
|
||||
# CPU backend libs (ggml-base, ggml-cpu) are flat in lib/ollama/
|
||||
cp dist/darwin-arm64/lib/ollama/*.so dist/Ollama.app/Contents/Resources/ 2>/dev/null || true
|
||||
for F in dist/darwin-arm64/lib/ollama/*.dylib; do
|
||||
[ -f "$F" ] && [ ! -L "$F" ] || continue
|
||||
cp "$F" dist/Ollama.app/Contents/Resources/
|
||||
done
|
||||
(cd dist/Ollama.app/Contents/Resources && ln -sf libggml-base.0.0.0.dylib libggml-base.0.dylib && ln -sf libggml-base.0.dylib libggml-base.dylib) 2>/dev/null || true
|
||||
fi
|
||||
chmod a+x dist/Ollama.app/Contents/Resources/ollama
|
||||
|
||||
# Sign
|
||||
if [ -n "$APPLE_IDENTITY" ]; then
|
||||
codesign -f --timestamp -s "$APPLE_IDENTITY" --identifier ai.ollama.ollama --options=runtime dist/Ollama.app/Contents/Resources/ollama
|
||||
for lib in dist/Ollama.app/Contents/Resources/*.so dist/Ollama.app/Contents/Resources/*.dylib dist/Ollama.app/Contents/Resources/*.metallib dist/Ollama.app/Contents/Resources/mlx_metal_v*/*.dylib dist/Ollama.app/Contents/Resources/mlx_metal_v*/*.metallib dist/Ollama.app/Contents/Resources/mlx_metal_v*/*.so; do
|
||||
[ -f "$lib" ] || continue
|
||||
codesign -f --timestamp -s "$APPLE_IDENTITY" --identifier ai.ollama.ollama --options=runtime "$lib"
|
||||
done
|
||||
codesign -f --timestamp -s "$APPLE_IDENTITY" --identifier com.electron.ollama --deep --options=runtime dist/Ollama.app
|
||||
fi
|
||||
|
||||
rm -f dist/Ollama-darwin.zip
|
||||
ditto -c -k --norsrc --keepParent dist/Ollama.app dist/Ollama-darwin.zip
|
||||
(cd dist/Ollama.app/Contents/Resources/; tar -cf - ollama *.so *.dylib *.metallib mlx_metal_v*/ 2>/dev/null) | gzip -9vc > dist/ollama-darwin.tgz
|
||||
|
||||
# Notarize and Staple
|
||||
if [ -n "$APPLE_IDENTITY" ]; then
|
||||
$(xcrun -f notarytool) submit dist/Ollama-darwin.zip --wait --timeout 20m --apple-id "$APPLE_ID" --password "$APPLE_PASSWORD" --team-id "$APPLE_TEAM_ID"
|
||||
rm -f dist/Ollama-darwin.zip
|
||||
$(xcrun -f stapler) staple dist/Ollama.app
|
||||
ditto -c -k --norsrc --keepParent dist/Ollama.app dist/Ollama-darwin.zip
|
||||
|
||||
rm -f dist/Ollama.dmg
|
||||
|
||||
(cd dist && ../scripts/create-dmg.sh \
|
||||
--volname "${VOL_NAME}" \
|
||||
--volicon ../app/darwin/Ollama.app/Contents/Resources/icon.icns \
|
||||
--background ../app/assets/background.png \
|
||||
--window-pos 200 120 \
|
||||
--window-size 800 400 \
|
||||
--icon-size 128 \
|
||||
--icon "Ollama.app" 200 190 \
|
||||
--hide-extension "Ollama.app" \
|
||||
--app-drop-link 600 190 \
|
||||
--text-size 12 \
|
||||
"Ollama.dmg" \
|
||||
"Ollama.app" \
|
||||
; )
|
||||
rm -f dist/rw*.dmg
|
||||
|
||||
codesign -f --timestamp -s "$APPLE_IDENTITY" --identifier ai.ollama.ollama --options=runtime dist/Ollama.dmg
|
||||
$(xcrun -f notarytool) submit dist/Ollama.dmg --wait --timeout 20m --apple-id "$APPLE_ID" --password "$APPLE_PASSWORD" --team-id "$APPLE_TEAM_ID"
|
||||
$(xcrun -f stapler) staple dist/Ollama.dmg
|
||||
else
|
||||
echo "WARNING: Code signing disabled, this bundle will not work for upgrade testing"
|
||||
fi
|
||||
}
|
||||
|
||||
if [ "$#" -eq 0 ]; then
|
||||
_build_darwin
|
||||
_sign_darwin
|
||||
_build_macapp
|
||||
exit 0
|
||||
fi
|
||||
|
||||
for CMD in "$@"; do
|
||||
case $CMD in
|
||||
build) _build_darwin ;;
|
||||
sign) _sign_darwin ;;
|
||||
app) _build_macapp ;;
|
||||
*) usage ;;
|
||||
esac
|
||||
done
|
||||
35
scripts/build_docker.sh
Executable file
35
scripts/build_docker.sh
Executable file
@@ -0,0 +1,35 @@
|
||||
#!/bin/sh
|
||||
|
||||
set -eu
|
||||
|
||||
. $(dirname $0)/env.sh
|
||||
|
||||
# Set PUSH to a non-empty string to trigger push instead of load
|
||||
PUSH=${PUSH:-""}
|
||||
|
||||
if [ -z "${PUSH}" ] ; then
|
||||
echo "Building ${FINAL_IMAGE_REPO}:$VERSION locally. set PUSH=1 to push"
|
||||
LOAD_OR_PUSH="--load"
|
||||
else
|
||||
echo "Will be pushing ${FINAL_IMAGE_REPO}:$VERSION"
|
||||
LOAD_OR_PUSH="--push"
|
||||
fi
|
||||
|
||||
docker buildx build \
|
||||
${LOAD_OR_PUSH} \
|
||||
--platform=${PLATFORM} \
|
||||
${OLLAMA_COMMON_BUILD_ARGS} \
|
||||
-f Dockerfile \
|
||||
-t ${FINAL_IMAGE_REPO}:$VERSION \
|
||||
.
|
||||
|
||||
if echo $PLATFORM | grep "amd64" > /dev/null; then
|
||||
docker buildx build \
|
||||
${LOAD_OR_PUSH} \
|
||||
--platform=linux/amd64 \
|
||||
${OLLAMA_COMMON_BUILD_ARGS} \
|
||||
--build-arg FLAVOR=rocm \
|
||||
-f Dockerfile \
|
||||
-t ${FINAL_IMAGE_REPO}:$VERSION-rocm \
|
||||
.
|
||||
fi
|
||||
91
scripts/build_linux.sh
Executable file
91
scripts/build_linux.sh
Executable file
@@ -0,0 +1,91 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# Mac ARM users, rosetta can be flaky, so to use a remote x86 builder.
|
||||
# Use the docker-container driver with the bundled buildkit GC config
|
||||
# for improved cache behavior
|
||||
#
|
||||
# docker context create amd64 --docker host=ssh://mybuildhost
|
||||
# docker buildx create --name mybuilder \
|
||||
# --driver docker-container \
|
||||
# --config ./buildkitd.toml.example \
|
||||
# --bootstrap amd64 --platform linux/amd64
|
||||
# docker buildx create --name mybuilder --append desktop-linux --platform linux/arm64
|
||||
# docker buildx use mybuilder
|
||||
|
||||
|
||||
set -eu
|
||||
|
||||
. $(dirname $0)/env.sh
|
||||
|
||||
# Check for required tools
|
||||
if ! command -v zstd >/dev/null 2>&1; then
|
||||
echo "ERROR: zstd is required but not installed." >&2
|
||||
echo "Please install zstd:" >&2
|
||||
echo " - macOS: brew install zstd" >&2
|
||||
echo " - Debian/Ubuntu: sudo apt-get install zstd" >&2
|
||||
echo " - RHEL/CentOS/Fedora: sudo dnf install zstd" >&2
|
||||
echo " - Arch: sudo pacman -S zstd" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
mkdir -p dist
|
||||
|
||||
docker buildx build \
|
||||
--output type=local,dest=./dist/ \
|
||||
--platform=${PLATFORM} \
|
||||
${OLLAMA_COMMON_BUILD_ARGS} \
|
||||
--target archive \
|
||||
-f Dockerfile \
|
||||
.
|
||||
|
||||
if echo $PLATFORM | grep "amd64" > /dev/null; then
|
||||
outDir="./dist"
|
||||
if echo $PLATFORM | grep "," > /dev/null ; then
|
||||
outDir="./dist/linux_amd64"
|
||||
fi
|
||||
docker buildx build \
|
||||
--output type=local,dest=${outDir} \
|
||||
--platform=linux/amd64 \
|
||||
${OLLAMA_COMMON_BUILD_ARGS} \
|
||||
--build-arg FLAVOR=rocm \
|
||||
--target archive \
|
||||
-f Dockerfile \
|
||||
.
|
||||
fi
|
||||
|
||||
# Run deduplication for each platform output directory
|
||||
if echo $PLATFORM | grep "," > /dev/null ; then
|
||||
$(dirname $0)/deduplicate_cuda_libs.sh "./dist/linux_amd64"
|
||||
$(dirname $0)/deduplicate_cuda_libs.sh "./dist/linux_arm64"
|
||||
elif echo $PLATFORM | grep "amd64\|arm64" > /dev/null ; then
|
||||
$(dirname $0)/deduplicate_cuda_libs.sh "./dist"
|
||||
fi
|
||||
|
||||
# buildx behavior changes for single vs. multiplatform
|
||||
echo "Compressing linux tar bundles..."
|
||||
if echo $PLATFORM | grep "," > /dev/null ; then
|
||||
tar c -C ./dist/linux_arm64 --exclude cuda_jetpack5 --exclude cuda_jetpack6 . | zstd -9 -T0 >./dist/ollama-linux-arm64.tar.zst
|
||||
tar c -C ./dist/linux_arm64 ./lib/ollama/cuda_jetpack5 | zstd -9 -T0 >./dist/ollama-linux-arm64-jetpack5.tar.zst
|
||||
tar c -C ./dist/linux_arm64 ./lib/ollama/cuda_jetpack6 | zstd -9 -T0 >./dist/ollama-linux-arm64-jetpack6.tar.zst
|
||||
tar c -C ./dist/linux_amd64 --exclude rocm --exclude 'mlx*' . | zstd -9 -T0 >./dist/ollama-linux-amd64.tar.zst
|
||||
tar c -C ./dist/linux_amd64 ./lib/ollama/rocm | zstd -9 -T0 >./dist/ollama-linux-amd64-rocm.tar.zst
|
||||
( cd ./dist/linux_amd64 && tar c lib/ollama/mlx* ) | zstd -9 -T0 >./dist/ollama-linux-amd64-mlx.tar.zst
|
||||
elif echo $PLATFORM | grep "arm64" > /dev/null ; then
|
||||
tar c -C ./dist/ --exclude cuda_jetpack5 --exclude cuda_jetpack6 bin lib | zstd -9 -T0 >./dist/ollama-linux-arm64.tar.zst
|
||||
tar c -C ./dist/ ./lib/ollama/cuda_jetpack5 | zstd -9 -T0 >./dist/ollama-linux-arm64-jetpack5.tar.zst
|
||||
tar c -C ./dist/ ./lib/ollama/cuda_jetpack6 | zstd -9 -T0 >./dist/ollama-linux-arm64-jetpack6.tar.zst
|
||||
elif echo $PLATFORM | grep "amd64" > /dev/null ; then
|
||||
tar c -C ./dist/ --exclude rocm --exclude 'mlx*' bin lib | zstd -9 -T0 >./dist/ollama-linux-amd64.tar.zst
|
||||
tar c -C ./dist/ ./lib/ollama/rocm | zstd -9 -T0 >./dist/ollama-linux-amd64-rocm.tar.zst
|
||||
( cd ./dist/ && tar c lib/ollama/mlx* ) | zstd -9 -T0 >./dist/ollama-linux-amd64-mlx.tar.zst
|
||||
fi
|
||||
|
||||
# Warn if any compressed tarball exceeds GitHub's 2 GiB release-asset limit
|
||||
LIMIT=2147483648
|
||||
for f in ./dist/ollama-linux-*.tar.zst; do
|
||||
[ -f "$f" ] || continue
|
||||
size=$(stat -f%z "$f" 2>/dev/null || stat -c%s "$f")
|
||||
if [ "$size" -gt "$LIMIT" ]; then
|
||||
echo "WARNING: $f is $size bytes ($((size - LIMIT)) over the 2 GiB GitHub release-asset limit)" >&2
|
||||
fi
|
||||
done
|
||||
552
scripts/build_windows.ps1
Normal file
552
scripts/build_windows.ps1
Normal file
@@ -0,0 +1,552 @@
|
||||
#!powershell
|
||||
#
|
||||
# powershell -ExecutionPolicy Bypass -File .\scripts\build_windows.ps1
|
||||
#
|
||||
# gcloud auth application-default login
|
||||
|
||||
# Use "Continue" so that stderr output from native commands (e.g. CGo warnings)
|
||||
# is not promoted to a terminating exception by the try/catch block.
|
||||
# All native commands already check $LASTEXITCODE explicitly.
|
||||
$ErrorActionPreference = "Continue"
|
||||
|
||||
mkdir -Force -path .\dist | Out-Null
|
||||
|
||||
function checkEnv {
|
||||
if ($null -ne $env:ARCH ) {
|
||||
$script:ARCH = $env:ARCH
|
||||
} else {
|
||||
$arch=([System.Runtime.InteropServices.RuntimeInformation]::OSArchitecture)
|
||||
if ($null -ne $arch) {
|
||||
$script:ARCH = ($arch.ToString().ToLower()).Replace("x64", "amd64")
|
||||
} else {
|
||||
Write-Output "WARNING: old powershell detected, assuming amd64 architecture - set `$env:ARCH to override"
|
||||
$script:ARCH="amd64"
|
||||
}
|
||||
}
|
||||
$script:TARGET_ARCH=$script:ARCH
|
||||
Write-host "Building for ${script:TARGET_ARCH}"
|
||||
Write-Output "Locating required tools and paths"
|
||||
$script:SRC_DIR=$PWD
|
||||
|
||||
# Locate CUDA versions
|
||||
$cudaList=(get-item "C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v*\bin\" -ea 'silentlycontinue')
|
||||
if ($cudaList.length -eq 0) {
|
||||
$d=(get-command -ea 'silentlycontinue' nvcc).path
|
||||
if ($null -ne $d) {
|
||||
$script:CUDA_DIRS=@($d| split-path -parent)
|
||||
}
|
||||
} else {
|
||||
# Favor newer patch versions if available
|
||||
$script:CUDA_DIRS=($cudaList | sort-object -Descending)
|
||||
}
|
||||
if ($script:CUDA_DIRS.length -gt 0) {
|
||||
Write-Output "Available CUDA Versions: $script:CUDA_DIRS"
|
||||
} else {
|
||||
Write-Output "No CUDA versions detected"
|
||||
}
|
||||
|
||||
# Locate ROCm v6
|
||||
$rocmDir=(get-item "C:\Program Files\AMD\ROCm\6.*" -ea 'silentlycontinue' | sort-object -Descending | select-object -First 1)
|
||||
if ($null -ne $rocmDir) {
|
||||
$script:HIP_PATH=$rocmDir.FullName
|
||||
} elseif ($null -ne $env:HIP_PATH -and $env:HIP_PATH -match '[/\\]6\.') {
|
||||
$script:HIP_PATH=$env:HIP_PATH
|
||||
}
|
||||
|
||||
$inoSetup=(get-item "C:\Program Files*\Inno Setup*\")
|
||||
if ($inoSetup.length -gt 0) {
|
||||
$script:INNO_SETUP_DIR=$inoSetup[0]
|
||||
}
|
||||
|
||||
$script:DIST_DIR="${script:SRC_DIR}\dist\windows-${script:TARGET_ARCH}"
|
||||
$env:CGO_ENABLED="1"
|
||||
if (-not $env:CGO_CFLAGS) {
|
||||
$env:CGO_CFLAGS = "-O3"
|
||||
}
|
||||
if (-not $env:CGO_CXXFLAGS) {
|
||||
$env:CGO_CXXFLAGS = "-O3"
|
||||
}
|
||||
Write-Output "Checking version"
|
||||
if (!$env:VERSION) {
|
||||
$data=(git describe --tags --first-parent --abbrev=7 --long --dirty --always)
|
||||
$pattern="v(.+)"
|
||||
if ($data -match $pattern) {
|
||||
$script:VERSION=$matches[1]
|
||||
}
|
||||
} else {
|
||||
$script:VERSION=$env:VERSION
|
||||
}
|
||||
$pattern = "(\d+[.]\d+[.]\d+).*"
|
||||
if ($script:VERSION -match $pattern) {
|
||||
$script:PKG_VERSION=$matches[1]
|
||||
} else {
|
||||
$script:PKG_VERSION="0.0.0"
|
||||
}
|
||||
Write-Output "Building Ollama $script:VERSION with package version $script:PKG_VERSION"
|
||||
|
||||
# Note: Windows Kits 10 signtool crashes with GCP's plugin
|
||||
if ($null -eq $env:SIGN_TOOL) {
|
||||
${script:SignTool}="C:\Program Files (x86)\Windows Kits\8.1\bin\x64\signtool.exe"
|
||||
} else {
|
||||
${script:SignTool}=${env:SIGN_TOOL}
|
||||
}
|
||||
if ("${env:KEY_CONTAINER}") {
|
||||
if (Test-Path "${script:SRC_DIR}\ollama_inc.crt") {
|
||||
${script:OLLAMA_CERT}=$(resolve-path "${script:SRC_DIR}\ollama_inc.crt")
|
||||
Write-host "Code signing enabled"
|
||||
} else {
|
||||
Write-Output "WARNING: KEY_CONTAINER is set but ollama_inc.crt not found at ${script:SRC_DIR}\ollama_inc.crt - code signing disabled"
|
||||
}
|
||||
} else {
|
||||
Write-Output "Code signing disabled - please set KEY_CONTAINERS to sign and copy ollama_inc.crt to the top of the source tree"
|
||||
}
|
||||
if ($env:OLLAMA_BUILD_PARALLEL) {
|
||||
$script:JOBS=[int]$env:OLLAMA_BUILD_PARALLEL
|
||||
} else {
|
||||
# Use physical core count rather than logical processors (hyperthreads)
|
||||
# to avoid saturating the system during builds
|
||||
try {
|
||||
$cores = (Get-CimInstance Win32_Processor | Measure-Object -Property NumberOfCores -Sum).Sum
|
||||
} catch {
|
||||
$cores = 0
|
||||
}
|
||||
if ($cores -gt 0) {
|
||||
$script:JOBS = $cores
|
||||
} else {
|
||||
$script:JOBS = [Environment]::ProcessorCount
|
||||
}
|
||||
}
|
||||
Write-Output "Build parallelism: $script:JOBS (set OLLAMA_BUILD_PARALLEL to override)"
|
||||
}
|
||||
|
||||
|
||||
function cpu {
|
||||
mkdir -Force -path "${script:DIST_DIR}\" | Out-Null
|
||||
if ($script:ARCH -ne "arm64") {
|
||||
Remove-Item -ea 0 -recurse -force -path "${script:SRC_DIR}\dist\windows-${script:ARCH}"
|
||||
New-Item "${script:SRC_DIR}\dist\windows-${script:ARCH}\lib\ollama\" -ItemType Directory -ea 0
|
||||
|
||||
& cmake -B build\cpu --preset CPU --install-prefix $script:DIST_DIR
|
||||
if ($LASTEXITCODE -ne 0) { exit($LASTEXITCODE)}
|
||||
& cmake --build build\cpu --target ggml-cpu --config Release --parallel $script:JOBS
|
||||
if ($LASTEXITCODE -ne 0) { exit($LASTEXITCODE)}
|
||||
& cmake --install build\cpu --component CPU --strip
|
||||
if ($LASTEXITCODE -ne 0) { exit($LASTEXITCODE)}
|
||||
}
|
||||
}
|
||||
|
||||
function cuda11 {
|
||||
# CUDA v11 claims to be compatible with MSVC 2022, but the latest updates are no longer compatible
|
||||
# 19.40 is the last compiler version that works, but recent udpates are 19.43
|
||||
# So this pins to MSVC 2019 for best compatibility
|
||||
mkdir -Force -path "${script:DIST_DIR}\" | Out-Null
|
||||
$cudaMajorVer="11"
|
||||
if ($script:ARCH -ne "arm64") {
|
||||
if ("$script:CUDA_DIRS".Contains("v$cudaMajorVer")) {
|
||||
foreach ($d in $Script:CUDA_DIRS){
|
||||
if ($d.FullName.Contains("v$cudaMajorVer")) {
|
||||
if (test-path -literalpath (join-path -path $d -childpath "nvcc.exe" ) ) {
|
||||
$cuda=($d.FullName|split-path -parent)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
Write-Output "Building CUDA v$cudaMajorVer backend libraries $cuda"
|
||||
$env:CUDAToolkit_ROOT=$cuda
|
||||
& cmake -B build\cuda_v$cudaMajorVer --preset "CUDA $cudaMajorVer" -T cuda="$cuda" -DCMAKE_CUDA_COMPILER="$cuda\bin\nvcc.exe" -G "Visual Studio 16 2019" --install-prefix "$script:DIST_DIR"
|
||||
if ($LASTEXITCODE -ne 0) { exit($LASTEXITCODE)}
|
||||
& cmake --build build\cuda_v$cudaMajorVer --target ggml-cuda --config Release --parallel $script:JOBS
|
||||
if ($LASTEXITCODE -ne 0) { exit($LASTEXITCODE)}
|
||||
& cmake --install build\cuda_v$cudaMajorVer --component "CUDA" --strip
|
||||
if ($LASTEXITCODE -ne 0) { exit($LASTEXITCODE)}
|
||||
} else {
|
||||
Write-Output "CUDA v$cudaMajorVer not detected, skipping"
|
||||
}
|
||||
} else {
|
||||
Write-Output "not arch we wanted"
|
||||
}
|
||||
Write-Output "done"
|
||||
}
|
||||
|
||||
function cudaCommon {
|
||||
param (
|
||||
[string]$cudaMajorVer
|
||||
)
|
||||
mkdir -Force -path "${script:DIST_DIR}\" | Out-Null
|
||||
if ($script:ARCH -ne "arm64") {
|
||||
if ("$script:CUDA_DIRS".Contains("v$cudaMajorVer")) {
|
||||
foreach ($d in $Script:CUDA_DIRS){
|
||||
if ($d.FullName.Contains("v$cudaMajorVer")) {
|
||||
if (test-path -literalpath (join-path -path $d -childpath "nvcc.exe" ) ) {
|
||||
$cuda=($d.FullName|split-path -parent)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
Write-Output "Building CUDA v$cudaMajorVer backend libraries $cuda"
|
||||
$env:CUDAToolkit_ROOT=$cuda
|
||||
& cmake -B build\cuda_v$cudaMajorVer --preset "CUDA $cudaMajorVer" -T cuda="$cuda" --install-prefix "$script:DIST_DIR"
|
||||
if ($LASTEXITCODE -ne 0) { exit($LASTEXITCODE)}
|
||||
& cmake --build build\cuda_v$cudaMajorVer --target ggml-cuda --config Release --parallel $script:JOBS
|
||||
if ($LASTEXITCODE -ne 0) { exit($LASTEXITCODE)}
|
||||
& cmake --install build\cuda_v$cudaMajorVer --component "CUDA" --strip
|
||||
if ($LASTEXITCODE -ne 0) { exit($LASTEXITCODE)}
|
||||
} else {
|
||||
Write-Output "CUDA v$cudaMajorVer not detected, skipping"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function cuda12 {
|
||||
cudaCommon("12")
|
||||
}
|
||||
|
||||
function cuda13 {
|
||||
cudaCommon("13")
|
||||
}
|
||||
|
||||
function rocm6 {
|
||||
mkdir -Force -path "${script:DIST_DIR}\" | Out-Null
|
||||
if ($script:ARCH -ne "arm64") {
|
||||
if ($script:HIP_PATH) {
|
||||
Write-Output "Building ROCm backend libraries $script:HIP_PATH"
|
||||
if (-Not (get-command -ErrorAction silent ninja)) {
|
||||
$NINJA_DIR=(gci -path (Get-CimInstance MSFT_VSInstance -Namespace root/cimv2/vs)[0].InstallLocation -r -fi ninja.exe).Directory.FullName
|
||||
$env:PATH="$NINJA_DIR;$env:PATH"
|
||||
}
|
||||
$env:HIPCXX="${script:HIP_PATH}\bin\clang++.exe"
|
||||
$env:HIP_PLATFORM="amd"
|
||||
$env:CMAKE_PREFIX_PATH="${script:HIP_PATH}"
|
||||
# Set CC/CXX via environment instead of -D flags to avoid triggering
|
||||
# spurious compiler-change reconfigures that reset CMAKE_INSTALL_PREFIX
|
||||
$env:CC="${script:HIP_PATH}\bin\clang.exe"
|
||||
$env:CXX="${script:HIP_PATH}\bin\clang++.exe"
|
||||
& cmake -B build\rocm --preset "ROCm 6" -G Ninja `
|
||||
-DCMAKE_C_FLAGS="-parallel-jobs=4 -Wno-ignored-attributes -Wno-deprecated-pragma" `
|
||||
-DCMAKE_CXX_FLAGS="-parallel-jobs=4 -Wno-ignored-attributes -Wno-deprecated-pragma" `
|
||||
--install-prefix $script:DIST_DIR
|
||||
if ($LASTEXITCODE -ne 0) { exit($LASTEXITCODE)}
|
||||
$env:HIPCXX=""
|
||||
$env:HIP_PLATFORM=""
|
||||
$env:CMAKE_PREFIX_PATH=""
|
||||
$env:CC=""
|
||||
$env:CXX=""
|
||||
& cmake --build build\rocm --target ggml-hip --config Release --parallel $script:JOBS
|
||||
if ($LASTEXITCODE -ne 0) { exit($LASTEXITCODE)}
|
||||
& cmake --install build\rocm --component "HIP" --strip
|
||||
if ($LASTEXITCODE -ne 0) { exit($LASTEXITCODE)}
|
||||
Remove-Item -Path $script:DIST_DIR\lib\ollama\rocm\rocblas\library\*gfx906* -ErrorAction SilentlyContinue
|
||||
} else {
|
||||
Write-Output "ROCm not detected, skipping"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function vulkan {
|
||||
if ($env:VULKAN_SDK) {
|
||||
Write-Output "Building Vulkan backend libraries"
|
||||
& cmake -B build\vulkan --preset Vulkan --install-prefix $script:DIST_DIR
|
||||
if ($LASTEXITCODE -ne 0) { exit($LASTEXITCODE)}
|
||||
& cmake --build build\vulkan --target ggml-vulkan --config Release --parallel $script:JOBS
|
||||
if ($LASTEXITCODE -ne 0) { exit($LASTEXITCODE)}
|
||||
& cmake --install build\vulkan --component Vulkan --strip
|
||||
if ($LASTEXITCODE -ne 0) { exit($LASTEXITCODE)}
|
||||
} else {
|
||||
Write-Output "Vulkan not detected, skipping"
|
||||
}
|
||||
}
|
||||
|
||||
function mlxCuda13 {
|
||||
mkdir -Force -path "${script:DIST_DIR}\" | Out-Null
|
||||
$cudaMajorVer="13"
|
||||
if ($script:ARCH -ne "arm64") {
|
||||
if ("$script:CUDA_DIRS".Contains("v$cudaMajorVer")) {
|
||||
foreach ($d in $Script:CUDA_DIRS){
|
||||
if ($d.FullName.Contains("v$cudaMajorVer")) {
|
||||
if (test-path -literalpath (join-path -path $d -childpath "nvcc.exe" ) ) {
|
||||
$cuda=($d.FullName|split-path -parent)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Check for cuDNN - required for MLX CUDA backend
|
||||
# Supports two layouts:
|
||||
# 1. CI/zip extract: CUDNN\include\cudnn.h, lib\x64\, bin\x64\
|
||||
# 2. Official installer: CUDNN\v*\include\{cuda-ver}\cudnn.h, lib\{cuda-ver}\x64\, bin\{cuda-ver}\
|
||||
if ($env:CUDNN_INCLUDE_PATH -and $env:CUDNN_LIBRARY_PATH) {
|
||||
Write-Output "Using cuDNN from environment: $env:CUDNN_INCLUDE_PATH"
|
||||
} elseif (Test-Path "C:\Program Files\NVIDIA\CUDNN\include\cudnn.h") {
|
||||
# CI/zip layout (flat)
|
||||
$cudnnRoot = "C:\Program Files\NVIDIA\CUDNN"
|
||||
$env:CUDNN_ROOT_DIR = $cudnnRoot
|
||||
$env:CUDNN_INCLUDE_PATH = "$cudnnRoot\include"
|
||||
$env:CUDNN_LIBRARY_PATH = "$cudnnRoot\lib\x64"
|
||||
Write-Output "Found cuDNN at $cudnnRoot (flat layout)"
|
||||
} else {
|
||||
# Official installer layout (versioned)
|
||||
$cudnnRoot = $null
|
||||
$resolved = Resolve-Path -Path "C:\Program Files\NVIDIA\CUDNN\v*" -ErrorAction SilentlyContinue | Sort-Object -Descending | Select-Object -First 1
|
||||
if ($resolved -and (Test-Path "$($resolved.Path)\include\$cudaMajorVer.0\cudnn.h")) {
|
||||
$cudnnRoot = $resolved.Path
|
||||
$env:CUDNN_ROOT_DIR = $cudnnRoot
|
||||
$env:CUDNN_INCLUDE_PATH = "$cudnnRoot\include\$cudaMajorVer.0"
|
||||
$env:CUDNN_LIBRARY_PATH = "$cudnnRoot\lib\$cudaMajorVer.0\x64"
|
||||
Write-Output "Found cuDNN at $cudnnRoot (official installer, CUDA $cudaMajorVer.0)"
|
||||
} else {
|
||||
Write-Output "cuDNN not found - set CUDNN_INCLUDE_PATH and CUDNN_LIBRARY_PATH environment variables"
|
||||
Write-Output "Skipping MLX build"
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
Write-Output "Building MLX CUDA v$cudaMajorVer backend libraries $cuda"
|
||||
$env:CUDAToolkit_ROOT=$cuda
|
||||
& cmake -B build\mlx_cuda_v$cudaMajorVer --preset "MLX CUDA $cudaMajorVer" -T cuda="$cuda" --install-prefix "$script:DIST_DIR"
|
||||
if ($LASTEXITCODE -ne 0) { exit($LASTEXITCODE)}
|
||||
& cmake --build build\mlx_cuda_v$cudaMajorVer --target mlx --target mlxc --config Release --parallel $script:JOBS -- /nodeReuse:false
|
||||
if ($LASTEXITCODE -ne 0) { exit($LASTEXITCODE)}
|
||||
& cmake --install build\mlx_cuda_v$cudaMajorVer --component "MLX" --strip
|
||||
if ($LASTEXITCODE -ne 0) { exit($LASTEXITCODE)}
|
||||
& cmake --install build\mlx_cuda_v$cudaMajorVer --component "MLX_VENDOR"
|
||||
if ($LASTEXITCODE -ne 0) { exit($LASTEXITCODE)}
|
||||
} else {
|
||||
Write-Output "CUDA v$cudaMajorVer not detected, skipping MLX build"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function ollama {
|
||||
mkdir -Force -path "${script:DIST_DIR}\" | Out-Null
|
||||
Write-Output "Building ollama CLI"
|
||||
& go build -trimpath -ldflags "-s -w -X=github.com/ollama/ollama/version.Version=$script:VERSION -X=github.com/ollama/ollama/server.mode=release" .
|
||||
if ($LASTEXITCODE -ne 0) { exit($LASTEXITCODE)}
|
||||
cp .\ollama.exe "${script:DIST_DIR}\"
|
||||
}
|
||||
|
||||
function app {
|
||||
Write-Output "Building Ollama App $script:VERSION with package version $script:PKG_VERSION"
|
||||
|
||||
if (!(Get-Command npm -ErrorAction SilentlyContinue)) {
|
||||
Write-Output "npm is not installed. Please install Node.js and npm first:"
|
||||
Write-Output " Visit: https://nodejs.org/"
|
||||
exit 1
|
||||
}
|
||||
|
||||
if (!(Get-Command tsc -ErrorAction SilentlyContinue)) {
|
||||
Write-Output "Installing TypeScript compiler..."
|
||||
npm install -g typescript
|
||||
}
|
||||
if (!(Get-Command tscriptify -ErrorAction SilentlyContinue)) {
|
||||
Write-Output "Installing tscriptify..."
|
||||
go install github.com/tkrajina/typescriptify-golang-structs/tscriptify@latest
|
||||
}
|
||||
if (!(Get-Command tscriptify -ErrorAction SilentlyContinue)) {
|
||||
$env:PATH="$env:PATH;$(go env GOPATH)\bin"
|
||||
}
|
||||
|
||||
Push-Location app/ui/app
|
||||
npm install
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
Write-Output "ERROR: npm install failed with exit code $LASTEXITCODE"
|
||||
exit $LASTEXITCODE
|
||||
}
|
||||
|
||||
Write-Output "Building React application..."
|
||||
npm run build
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
Write-Output "ERROR: npm run build failed with exit code $LASTEXITCODE"
|
||||
exit $LASTEXITCODE
|
||||
}
|
||||
|
||||
# Check if dist directory exists and has content
|
||||
if (!(Test-Path "dist")) {
|
||||
Write-Output "ERROR: dist directory was not created by npm run build"
|
||||
exit 1
|
||||
}
|
||||
|
||||
$distFiles = Get-ChildItem "dist" -Recurse
|
||||
if ($distFiles.Count -eq 0) {
|
||||
Write-Output "ERROR: dist directory is empty after npm run build"
|
||||
exit 1
|
||||
}
|
||||
|
||||
Pop-Location
|
||||
|
||||
Write-Output "Running go generate"
|
||||
& go generate ./...
|
||||
if ($LASTEXITCODE -ne 0) { exit($LASTEXITCODE)}
|
||||
& go build -trimpath -ldflags "-s -w -H windowsgui -X=github.com/ollama/ollama/app/version.Version=$script:VERSION" -o .\dist\windows-ollama-app-${script:ARCH}.exe ./app/cmd/app/
|
||||
if ($LASTEXITCODE -ne 0) { exit($LASTEXITCODE)}
|
||||
}
|
||||
|
||||
function deps {
|
||||
Write-Output "Download MSVC Redistributables"
|
||||
mkdir -Force -path "${script:SRC_DIR}\dist\\windows-arm64" | Out-Null
|
||||
mkdir -Force -path "${script:SRC_DIR}\dist\\windows-amd64" | Out-Null
|
||||
invoke-webrequest -Uri "https://aka.ms/vs/17/release/vc_redist.arm64.exe" -OutFile "${script:SRC_DIR}\dist\windows-arm64\vc_redist.arm64.exe" -ErrorAction Stop
|
||||
invoke-webrequest -Uri "https://aka.ms/vs/17/release/vc_redist.x64.exe" -OutFile "${script:SRC_DIR}\dist\windows-amd64\vc_redist.x64.exe" -ErrorAction Stop
|
||||
Write-Output "Done."
|
||||
}
|
||||
|
||||
function sign {
|
||||
# Copy install.ps1 to dist for release packaging
|
||||
Write-Output "Copying install.ps1 to dist"
|
||||
Copy-Item -Path "${script:SRC_DIR}\scripts\install.ps1" -Destination "${script:SRC_DIR}\dist\install.ps1" -ErrorAction Stop
|
||||
|
||||
if ("${env:KEY_CONTAINER}") {
|
||||
Write-Output "Signing Ollama executables, scripts and libraries"
|
||||
& "${script:SignTool}" sign /v /fd sha256 /t http://timestamp.digicert.com /f "${script:OLLAMA_CERT}" `
|
||||
/csp "Google Cloud KMS Provider" /kc ${env:KEY_CONTAINER} `
|
||||
$(get-childitem -path "${script:SRC_DIR}\dist\windows-*" -r -include @('*.exe', '*.dll'))
|
||||
if ($LASTEXITCODE -ne 0) { exit($LASTEXITCODE)}
|
||||
|
||||
Write-Output "Signing install.ps1"
|
||||
& "${script:SignTool}" sign /v /fd sha256 /t http://timestamp.digicert.com /f "${script:OLLAMA_CERT}" `
|
||||
/csp "Google Cloud KMS Provider" /kc ${env:KEY_CONTAINER} `
|
||||
"${script:SRC_DIR}\dist\install.ps1"
|
||||
if ($LASTEXITCODE -ne 0) { exit($LASTEXITCODE)}
|
||||
} else {
|
||||
Write-Output "Signing not enabled"
|
||||
}
|
||||
}
|
||||
|
||||
function installer {
|
||||
if ($null -eq ${script:INNO_SETUP_DIR}) {
|
||||
Write-Output "ERROR: missing Inno Setup installation directory - install from https://jrsoftware.org/isdl.php"
|
||||
exit 1
|
||||
}
|
||||
Write-Output "Building Ollama Installer"
|
||||
cd "${script:SRC_DIR}\app"
|
||||
$env:PKG_VERSION=$script:PKG_VERSION
|
||||
if ("${env:KEY_CONTAINER}") {
|
||||
& "${script:INNO_SETUP_DIR}\ISCC.exe" /DARCH=$script:TARGET_ARCH /SMySignTool="${script:SignTool} sign /fd sha256 /t http://timestamp.digicert.com /f ${script:OLLAMA_CERT} /csp `$qGoogle Cloud KMS Provider`$q /kc ${env:KEY_CONTAINER} `$f" .\ollama.iss
|
||||
} else {
|
||||
& "${script:INNO_SETUP_DIR}\ISCC.exe" /DARCH=$script:TARGET_ARCH .\ollama.iss
|
||||
}
|
||||
if ($LASTEXITCODE -ne 0) { exit($LASTEXITCODE)}
|
||||
}
|
||||
|
||||
function newZipJob($sourceDir, $destZip) {
|
||||
$use7z = [bool](Get-Command 7z -ErrorAction SilentlyContinue)
|
||||
Start-Job -ScriptBlock {
|
||||
param($src, $dst, $use7z)
|
||||
if ($use7z) {
|
||||
& 7z a -tzip -mx=7 -mmt=on $dst "${src}\*"
|
||||
if ($LASTEXITCODE -ne 0) { throw "7z failed with exit code $LASTEXITCODE" }
|
||||
} else {
|
||||
Compress-Archive -CompressionLevel Optimal -Path "${src}\*" -DestinationPath $dst -Force
|
||||
}
|
||||
} -ArgumentList $sourceDir, $destZip, $use7z
|
||||
}
|
||||
|
||||
function stageComponents($mainDir, $stagingDir, $pattern, $readmePrefix) {
|
||||
$components = Get-ChildItem -Path "${mainDir}\lib\ollama" -Directory -Filter $pattern -ErrorAction SilentlyContinue
|
||||
if ($components) {
|
||||
Remove-Item -ea 0 -r $stagingDir
|
||||
mkdir -Force -path "${stagingDir}\lib\ollama" | Out-Null
|
||||
Write-Output "Extract this ${readmePrefix} zip file to the same location where you extracted ollama-windows-amd64.zip" > "${stagingDir}\README_${readmePrefix}.txt"
|
||||
foreach ($dir in $components) {
|
||||
Write-Output " Staging $($dir.Name)"
|
||||
Move-Item -path $dir.FullName -destination "${stagingDir}\lib\ollama\$($dir.Name)"
|
||||
}
|
||||
return $true
|
||||
}
|
||||
return $false
|
||||
}
|
||||
|
||||
function restoreComponents($mainDir, $stagingDir) {
|
||||
if (Test-Path -Path "${stagingDir}\lib\ollama") {
|
||||
foreach ($dir in (Get-ChildItem -Path "${stagingDir}\lib\ollama" -Directory)) {
|
||||
Move-Item -path $dir.FullName -destination "${mainDir}\lib\ollama\$($dir.Name)"
|
||||
}
|
||||
}
|
||||
Remove-Item -ea 0 -r $stagingDir
|
||||
}
|
||||
|
||||
function zip {
|
||||
$jobs = @()
|
||||
$distDir = "${script:SRC_DIR}\dist"
|
||||
$amd64Dir = "${distDir}\windows-amd64"
|
||||
|
||||
# Remove any stale zip files before starting
|
||||
Remove-Item -ea 0 "${distDir}\ollama-windows-*.zip"
|
||||
|
||||
try {
|
||||
if (Test-Path -Path $amd64Dir) {
|
||||
# Stage ROCm into its own directory for independent compression
|
||||
if (stageComponents $amd64Dir "${distDir}\windows-amd64-rocm" "rocm*" "ROCm") {
|
||||
Write-Output "Generating ${distDir}\ollama-windows-amd64-rocm.zip"
|
||||
$jobs += newZipJob "${distDir}\windows-amd64-rocm" "${distDir}\ollama-windows-amd64-rocm.zip"
|
||||
}
|
||||
|
||||
# Stage MLX into its own directory for independent compression
|
||||
if (stageComponents $amd64Dir "${distDir}\windows-amd64-mlx" "mlx_*" "MLX") {
|
||||
Write-Output "Generating ${distDir}\ollama-windows-amd64-mlx.zip"
|
||||
$jobs += newZipJob "${distDir}\windows-amd64-mlx" "${distDir}\ollama-windows-amd64-mlx.zip"
|
||||
}
|
||||
|
||||
# Compress the main amd64 zip (without rocm/mlx)
|
||||
Write-Output "Generating ${distDir}\ollama-windows-amd64.zip"
|
||||
$jobs += newZipJob $amd64Dir "${distDir}\ollama-windows-amd64.zip"
|
||||
}
|
||||
|
||||
if (Test-Path -Path "${distDir}\windows-arm64") {
|
||||
Write-Output "Generating ${distDir}\ollama-windows-arm64.zip"
|
||||
$jobs += newZipJob "${distDir}\windows-arm64" "${distDir}\ollama-windows-arm64.zip"
|
||||
}
|
||||
|
||||
if ($jobs.Count -gt 0) {
|
||||
Write-Output "Waiting for $($jobs.Count) parallel zip jobs..."
|
||||
$jobs | Wait-Job | Out-Null
|
||||
$failed = $false
|
||||
foreach ($job in $jobs) {
|
||||
if ($job.State -eq 'Failed') {
|
||||
Write-Error "Zip job failed: $($job.ChildJobs[0].JobStateInfo.Reason)"
|
||||
$failed = $true
|
||||
}
|
||||
Receive-Job $job
|
||||
Remove-Job $job
|
||||
}
|
||||
if ($failed) { throw "One or more zip jobs failed" }
|
||||
}
|
||||
} finally {
|
||||
# Always restore staged components back into the main tree
|
||||
restoreComponents $amd64Dir "${distDir}\windows-amd64-rocm"
|
||||
restoreComponents $amd64Dir "${distDir}\windows-amd64-mlx"
|
||||
}
|
||||
}
|
||||
|
||||
function clean {
|
||||
Remove-Item -ea 0 -r "${script:SRC_DIR}\dist\"
|
||||
Remove-Item -ea 0 -r "${script:SRC_DIR}\build\"
|
||||
}
|
||||
|
||||
checkEnv
|
||||
try {
|
||||
if ($($args.count) -eq 0) {
|
||||
cpu
|
||||
cuda12
|
||||
cuda13
|
||||
rocm6
|
||||
vulkan
|
||||
mlxCuda13
|
||||
ollama
|
||||
app
|
||||
deps
|
||||
sign
|
||||
installer
|
||||
zip
|
||||
} else {
|
||||
for ( $i = 0; $i -lt $args.count; $i++ ) {
|
||||
Write-Output "running build step $($args[$i])"
|
||||
& $($args[$i])
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
Write-Error "Build Failed: $($_.Exception.Message)"
|
||||
Write-Error "$($_.ScriptStackTrace)"
|
||||
} finally {
|
||||
set-location $script:SRC_DIR
|
||||
$env:PKG_VERSION=""
|
||||
}
|
||||
21
scripts/buildkitd.toml.example
Normal file
21
scripts/buildkitd.toml.example
Normal file
@@ -0,0 +1,21 @@
|
||||
# Suggested BuildKit GC config for ollama local development.
|
||||
#
|
||||
[worker.oci]
|
||||
gc = true
|
||||
gckeepstorage = "150GB"
|
||||
|
||||
[[worker.oci.gcpolicy]]
|
||||
filters = ["type==source.local", "type==source.git.checkout"]
|
||||
keepDuration = "48h"
|
||||
maxUsedSpace = "5GB"
|
||||
|
||||
[[worker.oci.gcpolicy]]
|
||||
filters = ["type==exec.cachemount"]
|
||||
keepDuration = "168h" # 7 days
|
||||
maxUsedSpace = "20GB"
|
||||
|
||||
[[worker.oci.gcpolicy]]
|
||||
keepDuration = "720h" # 30 days
|
||||
reservedSpace = "20GB"
|
||||
maxUsedSpace = "150GB"
|
||||
minFreeSpace = "50GB"
|
||||
636
scripts/create-dmg.sh
Executable file
636
scripts/create-dmg.sh
Executable file
@@ -0,0 +1,636 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Vendored from https://github.com/create-dmg/create-dmg so our build can be self-contained
|
||||
|
||||
# Create a read-only disk image of the contents of a folder
|
||||
|
||||
# Bail out on any unhandled errors
|
||||
set -e;
|
||||
# Any command that exits with non-zero code will cause the pipeline to fail
|
||||
set -o pipefail;
|
||||
|
||||
CDMG_VERSION='1.2.1'
|
||||
|
||||
# The full path to the "support/" directory this script is using
|
||||
# (This will be set up by code later in the script.)
|
||||
CDMG_SUPPORT_DIR=""
|
||||
|
||||
OS_FULL_VERSION="$(sw_vers | sed -n 2p | cut -d : -f 2 | tr -d '[:space:]' | cut -c1-)"
|
||||
OS_MAJOR_VERSION="$(echo $OS_FULL_VERSION | cut -d . -f 1)"
|
||||
OS_MINOR_VERSION="$(echo $OS_FULL_VERSION | cut -d . -f 2)"
|
||||
WINX=10
|
||||
WINY=60
|
||||
WINW=500
|
||||
WINH=350
|
||||
ICON_SIZE=128
|
||||
TEXT_SIZE=16
|
||||
FORMAT="UDZO"
|
||||
FILESYSTEM="HFS+"
|
||||
ADD_FILE_SOURCES=()
|
||||
ADD_FILE_TARGETS=()
|
||||
IMAGEKEY=""
|
||||
HDIUTIL_VERBOSITY=""
|
||||
SANDBOX_SAFE=0
|
||||
BLESS=0
|
||||
SKIP_JENKINS=0
|
||||
MAXIMUM_UNMOUNTING_ATTEMPTS=3
|
||||
SIGNATURE=""
|
||||
NOTARIZE=""
|
||||
|
||||
function pure_version() {
|
||||
echo "$CDMG_VERSION"
|
||||
}
|
||||
|
||||
function hdiutil_detach_retry() {
|
||||
# Unmount
|
||||
unmounting_attempts=0
|
||||
until
|
||||
echo "Unmounting disk image..."
|
||||
(( unmounting_attempts++ ))
|
||||
hdiutil detach "$1"
|
||||
exit_code=$?
|
||||
(( exit_code == 0 )) && break # nothing goes wrong
|
||||
(( exit_code != 16 )) && exit $exit_code # exit with the original exit code
|
||||
# The above statement returns 1 if test failed (exit_code == 16).
|
||||
# It can make the code in the {do... done} block to be executed
|
||||
do
|
||||
(( unmounting_attempts == MAXIMUM_UNMOUNTING_ATTEMPTS )) && exit 16 # patience exhausted, exit with code EBUSY
|
||||
echo "Wait a moment..."
|
||||
sleep $(( 1 * (2 ** unmounting_attempts) ))
|
||||
done
|
||||
unset unmounting_attempts
|
||||
}
|
||||
|
||||
function version() {
|
||||
echo "create-dmg $(pure_version)"
|
||||
}
|
||||
|
||||
function usage() {
|
||||
version
|
||||
cat <<EOHELP
|
||||
|
||||
Creates a fancy DMG file.
|
||||
|
||||
Usage: $(basename $0) [options] <output_name.dmg> <source_folder>
|
||||
|
||||
All contents of <source_folder> will be copied into the disk image.
|
||||
|
||||
Options:
|
||||
--volname <name>
|
||||
set volume name (displayed in the Finder sidebar and window title)
|
||||
--volicon <icon.icns>
|
||||
set volume icon
|
||||
--background <pic.png>
|
||||
set folder background image (provide png, gif, or jpg)
|
||||
--window-pos <x> <y>
|
||||
set position the folder window
|
||||
--window-size <width> <height>
|
||||
set size of the folder window
|
||||
--text-size <text_size>
|
||||
set window text size (10-16)
|
||||
--icon-size <icon_size>
|
||||
set window icons size (up to 128)
|
||||
--icon file_name <x> <y>
|
||||
set position of the file's icon
|
||||
--hide-extension <file_name>
|
||||
hide the extension of file
|
||||
--app-drop-link <x> <y>
|
||||
make a drop link to Applications, at location x,y
|
||||
--ql-drop-link <x> <y>
|
||||
make a drop link to user QuickLook install dir, at location x,y
|
||||
--eula <eula_file>
|
||||
attach a license file to the dmg (plain text or RTF)
|
||||
--no-internet-enable
|
||||
disable automatic mount & copy
|
||||
--format <format>
|
||||
specify the final disk image format (UDZO|UDBZ|ULFO|ULMO) (default is UDZO)
|
||||
--filesystem <filesystem>
|
||||
specify the disk image filesystem (HFS+|APFS) (default is HFS+, APFS supports macOS 10.13 or newer)
|
||||
--encrypt
|
||||
enable encryption for the resulting disk image (AES-256 - you will be prompted for password)
|
||||
--encrypt-aes128
|
||||
enable encryption for the resulting disk image (AES-128 - you will be prompted for password)
|
||||
--add-file <target_name> <file>|<folder> <x> <y>
|
||||
add additional file or folder (can be used multiple times)
|
||||
--disk-image-size <x>
|
||||
set the disk image size manually to x MB
|
||||
--hdiutil-verbose
|
||||
execute hdiutil in verbose mode
|
||||
--hdiutil-quiet
|
||||
execute hdiutil in quiet mode
|
||||
--bless
|
||||
bless the mount folder (deprecated, needs macOS 12.2.1 or older)
|
||||
--codesign <signature>
|
||||
codesign the disk image with the specified signature
|
||||
--notarize <credentials>
|
||||
notarize the disk image (waits and staples) with the keychain stored credentials
|
||||
--sandbox-safe
|
||||
execute hdiutil with sandbox compatibility and do not bless (not supported for APFS disk images)
|
||||
--skip-jenkins
|
||||
skip Finder-prettifying AppleScript, useful in Sandbox and non-GUI environments
|
||||
--version
|
||||
show create-dmg version number
|
||||
-h, --help
|
||||
display this help screen
|
||||
|
||||
EOHELP
|
||||
exit 0
|
||||
}
|
||||
|
||||
# factors can cause interstitial disk images to contain more than a single
|
||||
# partition - expand the hunt for the temporary disk image by checking for
|
||||
# the path of the volume, versus assuming its the first result (as in pr/152).
|
||||
function find_mount_dir() {
|
||||
local dev_name="${1}"
|
||||
|
||||
>&2 echo "Searching for mounted interstitial disk image using ${dev_name}... "
|
||||
# enumerate up to 9 partitions
|
||||
for i in {1..9}; do
|
||||
# attempt to find the partition
|
||||
local found_dir
|
||||
found_dir=$(hdiutil info | grep -E --color=never "${dev_name}" | head -${i} | awk '{print $3}' | xargs)
|
||||
if [[ -n "${found_dir}" ]]; then
|
||||
echo "${found_dir}"
|
||||
return 0
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
# Argument parsing
|
||||
|
||||
while [[ "${1:0:1}" = "-" ]]; do
|
||||
case $1 in
|
||||
--volname)
|
||||
VOLUME_NAME="$2"
|
||||
shift; shift;;
|
||||
--volicon)
|
||||
VOLUME_ICON_FILE="$2"
|
||||
shift; shift;;
|
||||
--background)
|
||||
BACKGROUND_FILE="$2"
|
||||
BACKGROUND_FILE_NAME="$(basename "$BACKGROUND_FILE")"
|
||||
BACKGROUND_CLAUSE="set background picture of opts to file \".background:$BACKGROUND_FILE_NAME\""
|
||||
REPOSITION_HIDDEN_FILES_CLAUSE="set position of every item to {theBottomRightX + 100, 100}"
|
||||
shift; shift;;
|
||||
--icon-size)
|
||||
ICON_SIZE="$2"
|
||||
shift; shift;;
|
||||
--text-size)
|
||||
TEXT_SIZE="$2"
|
||||
shift; shift;;
|
||||
--window-pos)
|
||||
WINX=$2; WINY=$3
|
||||
shift; shift; shift;;
|
||||
--window-size)
|
||||
WINW=$2; WINH=$3
|
||||
shift; shift; shift;;
|
||||
--icon)
|
||||
POSITION_CLAUSE="${POSITION_CLAUSE}set position of item \"$2\" to {$3, $4}
|
||||
"
|
||||
shift; shift; shift; shift;;
|
||||
--hide-extension)
|
||||
HIDING_CLAUSE="${HIDING_CLAUSE}set the extension hidden of item \"$2\" to true
|
||||
"
|
||||
shift; shift;;
|
||||
-h | --help)
|
||||
usage;;
|
||||
--version)
|
||||
version; exit 0;;
|
||||
--pure-version)
|
||||
pure_version; exit 0;;
|
||||
--ql-drop-link)
|
||||
QL_LINK=$2
|
||||
QL_CLAUSE="set position of item \"QuickLook\" to {$2, $3}
|
||||
"
|
||||
shift; shift; shift;;
|
||||
--app-drop-link)
|
||||
APPLICATION_LINK=$2
|
||||
APPLICATION_CLAUSE="set position of item \"Applications\" to {$2, $3}
|
||||
"
|
||||
shift; shift; shift;;
|
||||
--eula)
|
||||
EULA_RSRC=$2
|
||||
shift; shift;;
|
||||
--no-internet-enable)
|
||||
NOINTERNET=1
|
||||
shift;;
|
||||
--format)
|
||||
FORMAT="$2"
|
||||
shift; shift;;
|
||||
--filesystem)
|
||||
FILESYSTEM="$2"
|
||||
shift; shift;;
|
||||
--encrypt)
|
||||
ENABLE_ENCRYPTION=1
|
||||
AESBITS=256
|
||||
shift;;
|
||||
--encrypt-aes128)
|
||||
ENABLE_ENCRYPTION=1
|
||||
AESBITS=128
|
||||
shift;;
|
||||
--add-file | --add-folder)
|
||||
ADD_FILE_TARGETS+=("$2")
|
||||
ADD_FILE_SOURCES+=("$3")
|
||||
POSITION_CLAUSE="${POSITION_CLAUSE}
|
||||
set position of item \"$2\" to {$4, $5}
|
||||
"
|
||||
shift; shift; shift; shift; shift;;
|
||||
--disk-image-size)
|
||||
DISK_IMAGE_SIZE="$2"
|
||||
shift; shift;;
|
||||
--hdiutil-verbose)
|
||||
HDIUTIL_VERBOSITY='-verbose'
|
||||
shift;;
|
||||
--hdiutil-quiet)
|
||||
HDIUTIL_VERBOSITY='-quiet'
|
||||
shift;;
|
||||
--codesign)
|
||||
SIGNATURE="$2"
|
||||
shift; shift;;
|
||||
--notarize)
|
||||
NOTARIZE="$2"
|
||||
shift; shift;;
|
||||
--sandbox-safe)
|
||||
SANDBOX_SAFE=1
|
||||
shift;;
|
||||
--bless)
|
||||
BLESS=1
|
||||
shift;;
|
||||
--rez)
|
||||
echo "REZ is no more directly used. You can remove the --rez argument."
|
||||
shift; shift;;
|
||||
--skip-jenkins)
|
||||
SKIP_JENKINS=1
|
||||
shift;;
|
||||
-*)
|
||||
echo "Unknown option: $1. Run 'create-dmg --help' for help."
|
||||
exit 1;;
|
||||
esac
|
||||
case $FORMAT in
|
||||
UDZO)
|
||||
IMAGEKEY="-imagekey zlib-level=9";;
|
||||
UDBZ)
|
||||
IMAGEKEY="-imagekey bzip2-level=9";;
|
||||
ULFO)
|
||||
;;
|
||||
ULMO)
|
||||
;;
|
||||
*)
|
||||
echo >&2 "Unknown disk image format: $FORMAT"
|
||||
exit 1;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [[ -z "$2" ]]; then
|
||||
echo "Not enough arguments. Run 'create-dmg --help' for help."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
DMG_PATH="$1"
|
||||
SRC_FOLDER="$(cd "$2" > /dev/null; pwd)"
|
||||
|
||||
# Argument validation checks
|
||||
|
||||
if [[ "${DMG_PATH: -4}" != ".dmg" ]]; then
|
||||
echo "Output file name must end with a .dmg extension. Run 'create-dmg --help' for help."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ "${FILESYSTEM}" != "HFS+" ]] && [[ "${FILESYSTEM}" != "APFS" ]]; then
|
||||
echo "Unknown disk image filesystem: ${FILESYSTEM}. Run 'create-dmg --help' for help."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ "${FILESYSTEM}" == "APFS" ]] && [[ ${SANDBOX_SAFE} -eq 1 ]]; then
|
||||
echo "Creating an APFS disk image that is sandbox safe is not supported."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Main script logic
|
||||
|
||||
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
|
||||
DMG_DIRNAME="$(dirname "$DMG_PATH")"
|
||||
DMG_DIR="$(cd "$DMG_DIRNAME" > /dev/null; pwd)"
|
||||
DMG_NAME="$(basename "$DMG_PATH")"
|
||||
DMG_TEMP_NAME="$DMG_DIR/rw.$$.${DMG_NAME}"
|
||||
|
||||
# Detect where we're running from
|
||||
|
||||
sentinel_file="$SCRIPT_DIR/.this-is-the-create-dmg-repo"
|
||||
if [[ -f "$sentinel_file" ]]; then
|
||||
# We're running from inside a repo
|
||||
CDMG_SUPPORT_DIR="$SCRIPT_DIR/support"
|
||||
else
|
||||
# We're running inside an installed location
|
||||
bin_dir="$SCRIPT_DIR"
|
||||
prefix_dir=$(dirname "$bin_dir")
|
||||
CDMG_SUPPORT_DIR="$prefix_dir/share/create-dmg/support"
|
||||
fi
|
||||
|
||||
if [[ -z "$VOLUME_NAME" ]]; then
|
||||
VOLUME_NAME="$(basename "$DMG_PATH" .dmg)"
|
||||
fi
|
||||
|
||||
if [[ ! -d "$CDMG_SUPPORT_DIR" ]]; then
|
||||
echo >&2 "Cannot find support/ directory: expected at: $CDMG_SUPPORT_DIR"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ -f "$SRC_FOLDER/.DS_Store" ]]; then
|
||||
echo "Deleting .DS_Store found in source folder"
|
||||
rm "$SRC_FOLDER/.DS_Store"
|
||||
fi
|
||||
|
||||
# Create the image
|
||||
echo "Creating disk image..."
|
||||
if [[ -f "${DMG_TEMP_NAME}" ]]; then
|
||||
rm -f "${DMG_TEMP_NAME}"
|
||||
fi
|
||||
|
||||
# Use Megabytes since hdiutil fails with very large byte numbers
|
||||
function blocks_to_megabytes() {
|
||||
# Add 1 extra MB, since there's no decimal retention here
|
||||
MB_SIZE=$((($1 * 512 / 1000 / 1000) + 1))
|
||||
echo $MB_SIZE
|
||||
}
|
||||
|
||||
function get_size() {
|
||||
# Get block size in disk
|
||||
if [[ $OS_MAJOR_VERSION -ge 12 ]]; then
|
||||
bytes_size=$(du -B 512 -s "$1")
|
||||
else
|
||||
bytes_size=$(du -s "$1")
|
||||
fi
|
||||
bytes_size=$(echo $bytes_size | sed -e 's/ .*//g')
|
||||
echo $(blocks_to_megabytes $bytes_size)
|
||||
}
|
||||
|
||||
# Create the DMG with the specified size or the hdiutil estimation
|
||||
CUSTOM_SIZE=''
|
||||
if [[ -n "$DISK_IMAGE_SIZE" ]]; then
|
||||
CUSTOM_SIZE="-size ${DISK_IMAGE_SIZE}m"
|
||||
fi
|
||||
|
||||
if [[ $SANDBOX_SAFE -eq 0 ]]; then
|
||||
if [[ "$FILESYSTEM" == "APFS" ]]; then
|
||||
FILESYSTEM_ARGUMENTS=""
|
||||
else
|
||||
FILESYSTEM_ARGUMENTS="-c c=64,a=16,e=16"
|
||||
fi
|
||||
hdiutil create ${HDIUTIL_VERBOSITY} -srcfolder "$SRC_FOLDER" -volname "${VOLUME_NAME}" \
|
||||
-fs "${FILESYSTEM}" -fsargs "${FILESYSTEM_ARGUMENTS}" -format UDRW ${CUSTOM_SIZE} "${DMG_TEMP_NAME}"
|
||||
else
|
||||
hdiutil makehybrid ${HDIUTIL_VERBOSITY} -default-volume-name "${VOLUME_NAME}" -hfs -o "${DMG_TEMP_NAME}" "$SRC_FOLDER"
|
||||
hdiutil convert -format UDRW -ov -o "${DMG_TEMP_NAME}" "${DMG_TEMP_NAME}"
|
||||
DISK_IMAGE_SIZE_CUSTOM=$DISK_IMAGE_SIZE
|
||||
fi
|
||||
|
||||
# Get the created DMG actual size
|
||||
DISK_IMAGE_SIZE=$(get_size "${DMG_TEMP_NAME}")
|
||||
|
||||
# Use the custom size if bigger
|
||||
if [[ $SANDBOX_SAFE -eq 1 ]] && [[ ! -z "$DISK_IMAGE_SIZE_CUSTOM" ]] && [[ $DISK_IMAGE_SIZE_CUSTOM -gt $DISK_IMAGE_SIZE ]]; then
|
||||
DISK_IMAGE_SIZE=$DISK_IMAGE_SIZE_CUSTOM
|
||||
fi
|
||||
|
||||
# Estimate the additional sources size
|
||||
if [[ -n "$ADD_FILE_SOURCES" ]]; then
|
||||
for i in "${!ADD_FILE_SOURCES[@]}"; do
|
||||
SOURCE_SIZE=$(get_size "${ADD_FILE_SOURCES[$i]}")
|
||||
DISK_IMAGE_SIZE=$(expr $DISK_IMAGE_SIZE + $SOURCE_SIZE)
|
||||
done
|
||||
fi
|
||||
|
||||
# Add extra space for additional resources
|
||||
DISK_IMAGE_SIZE=$(expr $DISK_IMAGE_SIZE + 20)
|
||||
|
||||
# Make sure target image size is within limits
|
||||
MIN_DISK_IMAGE_SIZE=$(hdiutil resize -limits "${DMG_TEMP_NAME}" | awk 'NR=1{print int($1/2048+1)}')
|
||||
if [ $MIN_DISK_IMAGE_SIZE -gt $DISK_IMAGE_SIZE ]; then
|
||||
DISK_IMAGE_SIZE=$MIN_DISK_IMAGE_SIZE
|
||||
fi
|
||||
|
||||
# Resize the image for the extra stuff
|
||||
hdiutil resize ${HDIUTIL_VERBOSITY} -size ${DISK_IMAGE_SIZE}m "${DMG_TEMP_NAME}"
|
||||
|
||||
# Mount the new DMG
|
||||
|
||||
echo "Mounting disk image..."
|
||||
|
||||
MOUNT_RANDOM_PATH="/Volumes"
|
||||
if [[ $SANDBOX_SAFE -eq 1 ]]; then
|
||||
MOUNT_RANDOM_PATH="/tmp"
|
||||
fi
|
||||
if [[ "$FILESYSTEM" == "APFS" ]]; then
|
||||
HDIUTIL_FILTER="tail -n 1"
|
||||
else
|
||||
HDIUTIL_FILTER="sed 1q"
|
||||
fi
|
||||
DEV_NAME=$(hdiutil attach -mountrandom ${MOUNT_RANDOM_PATH} -readwrite -noverify -noautoopen -nobrowse "${DMG_TEMP_NAME}" | grep -E --color=never '^/dev/' | ${HDIUTIL_FILTER} | awk '{print $1}')
|
||||
echo "Device name: $DEV_NAME"
|
||||
if [[ "$FILESYSTEM" == "APFS" ]]; then
|
||||
MOUNT_DIR=$(find_mount_dir "${DEV_NAME}")
|
||||
else
|
||||
MOUNT_DIR=$(find_mount_dir "${DEV_NAME}s")
|
||||
fi
|
||||
if [[ -z "${MOUNT_DIR}" ]]; then
|
||||
>&2 echo "ERROR: unable to proceed with final disk image creation because the interstitial disk image was not found."
|
||||
>&2 echo "The interstitial disk image will likely be mounted and will need to be cleaned up manually."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Mount dir: $MOUNT_DIR"
|
||||
|
||||
if [[ -n "$BACKGROUND_FILE" ]]; then
|
||||
echo "Copying background file '$BACKGROUND_FILE'..."
|
||||
[[ -d "$MOUNT_DIR/.background" ]] || mkdir "$MOUNT_DIR/.background"
|
||||
cp "$BACKGROUND_FILE" "$MOUNT_DIR/.background/$BACKGROUND_FILE_NAME"
|
||||
fi
|
||||
|
||||
if [[ -n "$APPLICATION_LINK" ]]; then
|
||||
echo "Making link to Applications dir..."
|
||||
echo $MOUNT_DIR
|
||||
ln -s /Applications "$MOUNT_DIR/Applications"
|
||||
fi
|
||||
|
||||
if [[ -n "$QL_LINK" ]]; then
|
||||
echo "Making link to QuickLook install dir..."
|
||||
echo $MOUNT_DIR
|
||||
ln -s "/Library/QuickLook" "$MOUNT_DIR/QuickLook"
|
||||
fi
|
||||
|
||||
if [[ -n "$VOLUME_ICON_FILE" ]]; then
|
||||
echo "Copying volume icon file '$VOLUME_ICON_FILE'..."
|
||||
cp "$VOLUME_ICON_FILE" "$MOUNT_DIR/.VolumeIcon.icns"
|
||||
SetFile -c icnC "$MOUNT_DIR/.VolumeIcon.icns"
|
||||
fi
|
||||
|
||||
if [[ -n "$ADD_FILE_SOURCES" ]]; then
|
||||
echo "Copying custom files..."
|
||||
for i in "${!ADD_FILE_SOURCES[@]}"; do
|
||||
echo "${ADD_FILE_SOURCES[$i]}"
|
||||
cp -a "${ADD_FILE_SOURCES[$i]}" "$MOUNT_DIR/${ADD_FILE_TARGETS[$i]}"
|
||||
done
|
||||
fi
|
||||
|
||||
VOLUME_NAME=$(basename $MOUNT_DIR)
|
||||
|
||||
# Run AppleScript to do all the Finder cosmetic stuff
|
||||
APPLESCRIPT_FILE=$(mktemp -t createdmg.tmp.XXXXXXXXXX)
|
||||
if [[ $SANDBOX_SAFE -eq 1 ]]; then
|
||||
echo "Skipping Finder-prettifying AppleScript because we are in Sandbox..."
|
||||
else
|
||||
if [[ $SKIP_JENKINS -eq 0 ]]; then
|
||||
cat "$CDMG_SUPPORT_DIR/template.applescript" \
|
||||
| sed -e "s/WINX/$WINX/g" -e "s/WINY/$WINY/g" -e "s/WINW/$WINW/g" \
|
||||
-e "s/WINH/$WINH/g" -e "s/BACKGROUND_CLAUSE/$BACKGROUND_CLAUSE/g" \
|
||||
-e "s/REPOSITION_HIDDEN_FILES_CLAUSE/$REPOSITION_HIDDEN_FILES_CLAUSE/g" \
|
||||
-e "s/ICON_SIZE/$ICON_SIZE/g" -e "s/TEXT_SIZE/$TEXT_SIZE/g" \
|
||||
| perl -pe "s/POSITION_CLAUSE/$POSITION_CLAUSE/g" \
|
||||
| perl -pe "s/QL_CLAUSE/$QL_CLAUSE/g" \
|
||||
| perl -pe "s/APPLICATION_CLAUSE/$APPLICATION_CLAUSE/g" \
|
||||
| perl -pe "s/HIDING_CLAUSE/$HIDING_CLAUSE/" \
|
||||
> "$APPLESCRIPT_FILE"
|
||||
|
||||
# pause to workaround occasional "Can’t get disk" (-1728) issues
|
||||
ERROR_1728_WORKAROUND_SLEEP_INTERVAL=2
|
||||
echo "Will sleep for $ERROR_1728_WORKAROUND_SLEEP_INTERVAL seconds to workaround occasions \"Can't get disk (-1728)\" issues..."
|
||||
sleep $ERROR_1728_WORKAROUND_SLEEP_INTERVAL
|
||||
|
||||
echo "Running AppleScript to make Finder stuff pretty: /usr/bin/osascript \"${APPLESCRIPT_FILE}\" \"${VOLUME_NAME}\""
|
||||
if /usr/bin/osascript "${APPLESCRIPT_FILE}" "${VOLUME_NAME}"; then
|
||||
# Okay, we're cool
|
||||
true
|
||||
else
|
||||
echo >&2 "Failed running AppleScript"
|
||||
hdiutil_detach_retry "${DEV_NAME}"
|
||||
exit 64
|
||||
fi
|
||||
echo "Done running the AppleScript..."
|
||||
sleep 4
|
||||
rm "$APPLESCRIPT_FILE"
|
||||
else
|
||||
echo ''
|
||||
echo "Will skip running AppleScript to configure DMG aesthetics because of --skip-jenkins option."
|
||||
echo "This will result in a DMG without any custom background or icons positioning."
|
||||
echo "More info at https://github.com/create-dmg/create-dmg/issues/72"
|
||||
echo ''
|
||||
fi
|
||||
fi
|
||||
|
||||
# Make sure it's not world writeable
|
||||
echo "Fixing permissions..."
|
||||
chmod -Rf go-w "${MOUNT_DIR}" &> /dev/null || true
|
||||
echo "Done fixing permissions"
|
||||
|
||||
# Make the top window open itself on mount:
|
||||
if [[ $BLESS -eq 1 && $SANDBOX_SAFE -eq 0 ]]; then
|
||||
echo "Blessing started"
|
||||
if [ $(uname -m) == "arm64" ]; then
|
||||
bless --folder "${MOUNT_DIR}"
|
||||
else
|
||||
bless --folder "${MOUNT_DIR}" --openfolder "${MOUNT_DIR}"
|
||||
fi
|
||||
echo "Blessing finished"
|
||||
else
|
||||
echo "Skipping blessing on sandbox"
|
||||
fi
|
||||
|
||||
if [[ -n "$VOLUME_ICON_FILE" ]]; then
|
||||
# Tell the volume that it has a special file attribute
|
||||
SetFile -a C "$MOUNT_DIR"
|
||||
fi
|
||||
|
||||
# Delete unnecessary file system events log if possible
|
||||
echo "Deleting .fseventsd"
|
||||
rm -rf "${MOUNT_DIR}/.fseventsd" || true
|
||||
|
||||
hdiutil_detach_retry "${DEV_NAME}"
|
||||
|
||||
# Compress image and optionally encrypt
|
||||
if [[ $ENABLE_ENCRYPTION -eq 0 ]]; then
|
||||
echo "Compressing disk image..."
|
||||
hdiutil convert ${HDIUTIL_VERBOSITY} "${DMG_TEMP_NAME}" -format ${FORMAT} ${IMAGEKEY} -o "${DMG_DIR}/${DMG_NAME}"
|
||||
else
|
||||
echo "Compressing and encrypting disk image..."
|
||||
echo "NOTE: hdiutil will only prompt a single time for a password - ensure entry is correct."
|
||||
hdiutil convert ${HDIUTIL_VERBOSITY} "${DMG_TEMP_NAME}" -format ${FORMAT} ${IMAGEKEY} -encryption AES-${AESBITS} -stdinpass -o "${DMG_DIR}/${DMG_NAME}"
|
||||
fi
|
||||
rm -f "${DMG_TEMP_NAME}"
|
||||
|
||||
# Adding EULA resources
|
||||
if [[ -n "${EULA_RSRC}" && "${EULA_RSRC}" != "-null-" ]]; then
|
||||
echo "Adding EULA resources..."
|
||||
#
|
||||
# Use udifrez instead flatten/rez/unflatten
|
||||
# https://github.com/create-dmg/create-dmg/issues/109
|
||||
#
|
||||
# Based on a thread from dawn2dusk & peterguy
|
||||
# https://developer.apple.com/forums/thread/668084
|
||||
#
|
||||
EULA_RESOURCES_FILE=$(mktemp -t createdmg.tmp.XXXXXXXXXX)
|
||||
EULA_FORMAT=$(file -b ${EULA_RSRC})
|
||||
if [[ ${EULA_FORMAT} == 'Rich Text Format data'* ]] ; then
|
||||
EULA_FORMAT='RTF '
|
||||
else
|
||||
EULA_FORMAT='TEXT'
|
||||
fi
|
||||
# Encode the EULA to base64
|
||||
# Replace 'openssl base64' with 'base64' if Mac OS X 10.6 support is no more needed
|
||||
# EULA_DATA="$(base64 -b 52 "${EULA_RSRC}" | sed s$'/^\(.*\)$/\t\t\t\\1/')"
|
||||
EULA_DATA="$(openssl base64 -in "${EULA_RSRC}" | tr -d '\n' | awk '{gsub(/.{52}/,"&\n")}1' | sed s$'/^\(.*\)$/\t\t\t\\1/')"
|
||||
# Fill the template with the custom EULA contents
|
||||
eval "cat > \"${EULA_RESOURCES_FILE}\" <<EOF
|
||||
$(<${CDMG_SUPPORT_DIR}/eula-resources-template.xml)
|
||||
EOF
|
||||
"
|
||||
# Apply the resources
|
||||
hdiutil udifrez -xml "${EULA_RESOURCES_FILE}" '' -quiet "${DMG_DIR}/${DMG_NAME}" || {
|
||||
echo "Failed to add the EULA license"
|
||||
exit 1
|
||||
}
|
||||
echo "Successfully added the EULA license"
|
||||
fi
|
||||
|
||||
# Enable "internet", whatever that is
|
||||
if [[ ! -z "${NOINTERNET}" && "${NOINTERNET}" == 1 ]]; then
|
||||
echo "Not setting 'internet-enable' on the dmg, per caller request"
|
||||
else
|
||||
# Check if hdiutil supports internet-enable
|
||||
# Support was removed in macOS 10.15. See https://github.com/andreyvit/create-dmg/issues/76
|
||||
if hdiutil internet-enable -help >/dev/null 2>/dev/null; then
|
||||
hdiutil internet-enable -yes "${DMG_DIR}/${DMG_NAME}"
|
||||
else
|
||||
echo "hdiutil does not support internet-enable. Note it was removed in macOS 10.15."
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ -n "${SIGNATURE}" && "${SIGNATURE}" != "-null-" ]]; then
|
||||
echo "Codesign started"
|
||||
codesign -s "${SIGNATURE}" "${DMG_DIR}/${DMG_NAME}"
|
||||
dmgsignaturecheck="$(codesign --verify --deep --verbose=2 --strict "${DMG_DIR}/${DMG_NAME}" 2>&1 >/dev/null)"
|
||||
if [ $? -eq 0 ]; then
|
||||
echo "The disk image is now codesigned"
|
||||
else
|
||||
echo "The signature seems invalid${NC}"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ -n "${NOTARIZE}" && "${NOTARIZE}" != "-null-" ]]; then
|
||||
echo "Notarization started"
|
||||
xcrun notarytool submit "${DMG_DIR}/${DMG_NAME}" --keychain-profile "${NOTARIZE}" --wait
|
||||
echo "Stapling the notarization ticket"
|
||||
staple="$(xcrun stapler staple "${DMG_DIR}/${DMG_NAME}")"
|
||||
if [ $? -eq 0 ]; then
|
||||
echo "The disk image is now notarized"
|
||||
else
|
||||
echo "$staple"
|
||||
echo "The notarization failed with error $?"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
# All done!
|
||||
echo "Disk image done"
|
||||
exit 0
|
||||
60
scripts/deduplicate_cuda_libs.sh
Executable file
60
scripts/deduplicate_cuda_libs.sh
Executable file
@@ -0,0 +1,60 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# Deduplicate CUDA libraries across mlx_* and cuda_* directories
|
||||
# This script finds identical .so* files in mlx_cuda_* directories that exist
|
||||
# in corresponding cuda_* directories and replaces them with symlinks.
|
||||
#
|
||||
|
||||
set -eu
|
||||
|
||||
if [ $# -eq 0 ]; then
|
||||
echo "ERROR: No directory specified" >&2
|
||||
echo "Usage: $0 <base_directory>" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
base_dir="$1"
|
||||
|
||||
if [ ! -d "${base_dir}" ]; then
|
||||
echo "ERROR: Directory ${base_dir} does not exist" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Deduplicating CUDA libraries in ${base_dir}..."
|
||||
|
||||
# Find all mlx_cuda_* directories
|
||||
for mlx_dir in "${base_dir}"/lib/ollama/mlx_cuda_*; do
|
||||
[ -d "${mlx_dir}" ] || continue
|
||||
|
||||
# Extract CUDA version (e.g., v12, v13)
|
||||
cuda_version=$(basename "${mlx_dir}" | sed 's/mlx_cuda_//')
|
||||
cuda_dir="${base_dir}/lib/ollama/cuda_${cuda_version}"
|
||||
|
||||
# Skip if corresponding cuda_* directory doesn't exist
|
||||
[ -d "${cuda_dir}" ] || continue
|
||||
|
||||
echo " Checking ${mlx_dir} against ${cuda_dir}..."
|
||||
|
||||
# Find all .so* files in mlx directory
|
||||
find "${mlx_dir}" -type f -name "*.so*" | while read mlx_file; do
|
||||
filename=$(basename "${mlx_file}")
|
||||
cuda_file="${cuda_dir}/${filename}"
|
||||
|
||||
# Skip if file doesn't exist in cuda directory
|
||||
[ -f "${cuda_file}" ] || continue
|
||||
|
||||
# Compare checksums
|
||||
mlx_sum=$(sha256sum "${mlx_file}" | awk '{print $1}')
|
||||
cuda_sum=$(sha256sum "${cuda_file}" | awk '{print $1}')
|
||||
|
||||
if [ "${mlx_sum}" = "${cuda_sum}" ]; then
|
||||
echo " Deduplicating ${filename}"
|
||||
# Calculate relative path from mlx_dir to cuda_dir
|
||||
rel_path="../cuda_${cuda_version}/${filename}"
|
||||
rm -f "${mlx_file}"
|
||||
ln -s "${rel_path}" "${mlx_file}"
|
||||
fi
|
||||
done
|
||||
done
|
||||
|
||||
echo "Deduplication complete"
|
||||
31
scripts/env.sh
Normal file
31
scripts/env.sh
Normal file
@@ -0,0 +1,31 @@
|
||||
# Common environment setup across build*.sh scripts
|
||||
|
||||
export VERSION=${VERSION:-$(git describe --tags --first-parent --abbrev=7 --long --dirty --always | sed -e "s/^v//g")}
|
||||
export GOFLAGS="'-ldflags=-w -s \"-X=github.com/ollama/ollama/version.Version=$VERSION\" \"-X=github.com/ollama/ollama/server.mode=release\"'"
|
||||
# TODO - consider `docker buildx ls --format=json` to autodiscover platform capability
|
||||
PLATFORM=${PLATFORM:-"linux/arm64,linux/amd64"}
|
||||
DOCKER_ORG=${DOCKER_ORG:-"ollama"}
|
||||
FINAL_IMAGE_REPO=${FINAL_IMAGE_REPO:-"${DOCKER_ORG}/ollama"}
|
||||
OLLAMA_COMMON_BUILD_ARGS="--build-arg=VERSION \
|
||||
--build-arg=GOFLAGS \
|
||||
--build-arg=OLLAMA_CUSTOM_CPU_DEFS \
|
||||
--build-arg=OLLAMA_SKIP_CUDA_GENERATE \
|
||||
--build-arg=OLLAMA_SKIP_CUDA_12_GENERATE \
|
||||
--build-arg=CUDA_V12_ARCHITECTURES \
|
||||
--build-arg=OLLAMA_SKIP_ROCM_GENERATE \
|
||||
--build-arg=OLLAMA_FAST_BUILD \
|
||||
--build-arg=CUSTOM_CPU_FLAGS \
|
||||
--build-arg=GPU_RUNNER_CPU_FLAGS \
|
||||
--build-arg=AMDGPU_TARGETS"
|
||||
|
||||
# Forward local MLX source overrides as Docker build contexts
|
||||
if [ -n "${OLLAMA_MLX_SOURCE:-}" ]; then
|
||||
OLLAMA_COMMON_BUILD_ARGS="$OLLAMA_COMMON_BUILD_ARGS --build-context local-mlx=$(cd "$OLLAMA_MLX_SOURCE" && pwd)"
|
||||
fi
|
||||
if [ -n "${OLLAMA_MLX_C_SOURCE:-}" ]; then
|
||||
OLLAMA_COMMON_BUILD_ARGS="$OLLAMA_COMMON_BUILD_ARGS --build-context local-mlx-c=$(cd "$OLLAMA_MLX_C_SOURCE" && pwd)"
|
||||
fi
|
||||
|
||||
echo "Building Ollama"
|
||||
echo "VERSION=$VERSION"
|
||||
echo "PLATFORM=$PLATFORM"
|
||||
323
scripts/install.ps1
Normal file
323
scripts/install.ps1
Normal file
@@ -0,0 +1,323 @@
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Install, upgrade, or uninstall Ollama on Windows.
|
||||
|
||||
.DESCRIPTION
|
||||
Downloads and installs Ollama.
|
||||
|
||||
Quick install:
|
||||
|
||||
irm https://ollama.com/install.ps1 | iex
|
||||
|
||||
Specific version:
|
||||
|
||||
$env:OLLAMA_VERSION="0.5.7"; irm https://ollama.com/install.ps1 | iex
|
||||
|
||||
Custom install directory:
|
||||
|
||||
$env:OLLAMA_INSTALL_DIR="D:\Ollama"; irm https://ollama.com/install.ps1 | iex
|
||||
|
||||
Uninstall:
|
||||
|
||||
$env:OLLAMA_UNINSTALL=1; irm https://ollama.com/install.ps1 | iex
|
||||
|
||||
Environment variables:
|
||||
|
||||
OLLAMA_VERSION Target version (default: latest stable)
|
||||
OLLAMA_INSTALL_DIR Custom install directory
|
||||
OLLAMA_UNINSTALL Set to 1 to uninstall Ollama
|
||||
OLLAMA_DEBUG Enable verbose output
|
||||
|
||||
.EXAMPLE
|
||||
irm https://ollama.com/install.ps1 | iex
|
||||
|
||||
.EXAMPLE
|
||||
$env:OLLAMA_VERSION = "0.5.7"; irm https://ollama.com/install.ps1 | iex
|
||||
|
||||
.LINK
|
||||
https://ollama.com
|
||||
#>
|
||||
|
||||
$ErrorActionPreference = "Stop"
|
||||
$ProgressPreference = "SilentlyContinue"
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
# Configuration from environment variables
|
||||
# --------------------------------------------------------------------------
|
||||
|
||||
$Version = if ($env:OLLAMA_VERSION) { $env:OLLAMA_VERSION } else { "" }
|
||||
$InstallDir = if ($env:OLLAMA_INSTALL_DIR) { $env:OLLAMA_INSTALL_DIR } else { "" }
|
||||
$Uninstall = $env:OLLAMA_UNINSTALL -eq "1"
|
||||
$DebugInstall = [bool]$env:OLLAMA_DEBUG
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
# Constants
|
||||
# --------------------------------------------------------------------------
|
||||
|
||||
# OLLAMA_DOWNLOAD_URL for developer testing only
|
||||
$DownloadBaseURL = if ($env:OLLAMA_DOWNLOAD_URL) { $env:OLLAMA_DOWNLOAD_URL.TrimEnd('/') } else { "https://ollama.com/download" }
|
||||
$InnoSetupUninstallGuid = "{44E83376-CE68-45EB-8FC1-393500EB558C}_is1"
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
# Helpers
|
||||
# --------------------------------------------------------------------------
|
||||
|
||||
function Write-Status {
|
||||
param([string]$Message)
|
||||
if ($DebugInstall) { Write-Host $Message }
|
||||
}
|
||||
|
||||
function Write-Step {
|
||||
param([string]$Message)
|
||||
if ($DebugInstall) { Write-Host ">>> $Message" -ForegroundColor Cyan }
|
||||
}
|
||||
|
||||
function Test-Signature {
|
||||
param([string]$FilePath)
|
||||
|
||||
$sig = Get-AuthenticodeSignature -FilePath $FilePath
|
||||
if ($sig.Status -ne "Valid") {
|
||||
Write-Status " Signature status: $($sig.Status)"
|
||||
return $false
|
||||
}
|
||||
|
||||
# Verify it's signed by Ollama Inc. (check exact organization name)
|
||||
# Anchor with comma/boundary to prevent "O=Not Ollama Inc." from matching
|
||||
$subject = $sig.SignerCertificate.Subject
|
||||
if ($subject -notmatch "(^|, )O=Ollama Inc\.(,|$)") {
|
||||
Write-Status " Unexpected signer: $subject"
|
||||
return $false
|
||||
}
|
||||
|
||||
Write-Status " Signature valid: $subject"
|
||||
return $true
|
||||
}
|
||||
|
||||
function Find-InnoSetupInstall {
|
||||
# Check both HKCU (per-user) and HKLM (per-machine) locations
|
||||
$possibleKeys = @(
|
||||
"HKCU:\Software\Microsoft\Windows\CurrentVersion\Uninstall\$InnoSetupUninstallGuid",
|
||||
"HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\$InnoSetupUninstallGuid",
|
||||
"HKLM:\Software\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\$InnoSetupUninstallGuid"
|
||||
)
|
||||
|
||||
foreach ($key in $possibleKeys) {
|
||||
if (Test-Path $key) {
|
||||
Write-Status " Found install at: $key"
|
||||
return $key
|
||||
}
|
||||
}
|
||||
return $null
|
||||
}
|
||||
|
||||
function Update-SessionPath {
|
||||
# Update PATH in current session so 'ollama' works immediately
|
||||
if ($InstallDir) {
|
||||
$ollamaDir = $InstallDir
|
||||
} else {
|
||||
$ollamaDir = Join-Path $env:LOCALAPPDATA "Programs\Ollama"
|
||||
}
|
||||
|
||||
# Add to PATH if not already present
|
||||
if (Test-Path $ollamaDir) {
|
||||
$currentPath = $env:PATH -split ';'
|
||||
if ($ollamaDir -notin $currentPath) {
|
||||
$env:PATH = "$ollamaDir;$env:PATH"
|
||||
Write-Status " Added $ollamaDir to session PATH"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function Invoke-Download {
|
||||
param(
|
||||
[string]$Url,
|
||||
[string]$OutFile
|
||||
)
|
||||
|
||||
Write-Status " Downloading: $Url"
|
||||
try {
|
||||
$request = [System.Net.HttpWebRequest]::Create($Url)
|
||||
$request.AllowAutoRedirect = $true
|
||||
$response = $request.GetResponse()
|
||||
$totalBytes = $response.ContentLength
|
||||
$stream = $response.GetResponseStream()
|
||||
$fileStream = [System.IO.FileStream]::new($OutFile, [System.IO.FileMode]::Create)
|
||||
$buffer = [byte[]]::new(65536)
|
||||
$totalRead = 0
|
||||
$lastUpdate = [DateTime]::MinValue
|
||||
$barWidth = 40
|
||||
|
||||
try {
|
||||
while (($read = $stream.Read($buffer, 0, $buffer.Length)) -gt 0) {
|
||||
$fileStream.Write($buffer, 0, $read)
|
||||
$totalRead += $read
|
||||
|
||||
$now = [DateTime]::UtcNow
|
||||
if (($now - $lastUpdate).TotalMilliseconds -ge 250) {
|
||||
if ($totalBytes -gt 0) {
|
||||
$pct = [math]::Min(100.0, ($totalRead / $totalBytes) * 100)
|
||||
$filled = [math]::Floor($barWidth * $pct / 100)
|
||||
$empty = $barWidth - $filled
|
||||
$bar = ('#' * $filled) + (' ' * $empty)
|
||||
$pctFmt = $pct.ToString("0.0")
|
||||
Write-Host -NoNewline "`r$bar ${pctFmt}%"
|
||||
} else {
|
||||
$sizeMB = [math]::Round($totalRead / 1MB, 1)
|
||||
Write-Host -NoNewline "`r${sizeMB} MB downloaded..."
|
||||
}
|
||||
$lastUpdate = $now
|
||||
}
|
||||
}
|
||||
|
||||
# Final progress update
|
||||
if ($totalBytes -gt 0) {
|
||||
$bar = '#' * $barWidth
|
||||
Write-Host "`r$bar 100.0%"
|
||||
} else {
|
||||
$sizeMB = [math]::Round($totalRead / 1MB, 1)
|
||||
Write-Host "`r${sizeMB} MB downloaded. "
|
||||
}
|
||||
} finally {
|
||||
$fileStream.Close()
|
||||
$stream.Close()
|
||||
$response.Close()
|
||||
}
|
||||
} catch {
|
||||
if ($_.Exception -is [System.Net.WebException]) {
|
||||
$webEx = [System.Net.WebException]$_.Exception
|
||||
if ($webEx.Response -and ([System.Net.HttpWebResponse]$webEx.Response).StatusCode -eq [System.Net.HttpStatusCode]::NotFound) {
|
||||
throw "Download failed: not found at $Url"
|
||||
}
|
||||
}
|
||||
if ($_.Exception.InnerException -is [System.Net.WebException]) {
|
||||
$webEx = [System.Net.WebException]$_.Exception.InnerException
|
||||
if ($webEx.Response -and ([System.Net.HttpWebResponse]$webEx.Response).StatusCode -eq [System.Net.HttpStatusCode]::NotFound) {
|
||||
throw "Download failed: not found at $Url"
|
||||
}
|
||||
}
|
||||
throw "Download failed for ${Url}: $($_.Exception.Message)"
|
||||
}
|
||||
}
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
# Uninstall
|
||||
# --------------------------------------------------------------------------
|
||||
|
||||
function Invoke-Uninstall {
|
||||
Write-Step "Uninstalling Ollama"
|
||||
|
||||
$regKey = Find-InnoSetupInstall
|
||||
if (-not $regKey) {
|
||||
Write-Host ">>> Ollama is not installed."
|
||||
return
|
||||
}
|
||||
|
||||
$uninstallString = (Get-ItemProperty -Path $regKey).UninstallString
|
||||
if (-not $uninstallString) {
|
||||
Write-Warning "No uninstall string found in registry"
|
||||
return
|
||||
}
|
||||
|
||||
# Strip quotes if present
|
||||
$uninstallExe = $uninstallString -replace '"', ''
|
||||
Write-Status " Uninstaller: $uninstallExe"
|
||||
|
||||
if (-not (Test-Path $uninstallExe)) {
|
||||
Write-Warning "Uninstaller not found at: $uninstallExe"
|
||||
return
|
||||
}
|
||||
|
||||
Write-Host ">>> Launching uninstaller..."
|
||||
# Run with GUI so user can choose whether to keep models
|
||||
Start-Process -FilePath $uninstallExe -Wait
|
||||
|
||||
# Verify removal
|
||||
if (Find-InnoSetupInstall) {
|
||||
Write-Warning "Uninstall may not have completed"
|
||||
} else {
|
||||
Write-Host ">>> Ollama has been uninstalled."
|
||||
}
|
||||
}
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
# Install
|
||||
# --------------------------------------------------------------------------
|
||||
|
||||
function Invoke-Install {
|
||||
# Determine installer URL
|
||||
if ($Version) {
|
||||
$installerUrl = "$DownloadBaseURL/OllamaSetup.exe?version=$Version"
|
||||
} else {
|
||||
$installerUrl = "$DownloadBaseURL/OllamaSetup.exe"
|
||||
}
|
||||
|
||||
# Download installer
|
||||
Write-Step "Downloading Ollama"
|
||||
if (-not $DebugInstall) {
|
||||
Write-Host ">>> Downloading Ollama for Windows..."
|
||||
}
|
||||
|
||||
$tempInstaller = Join-Path $env:TEMP "OllamaSetup.exe"
|
||||
Invoke-Download -Url $installerUrl -OutFile $tempInstaller
|
||||
|
||||
# Verify signature
|
||||
Write-Step "Verifying signature"
|
||||
if (-not (Test-Signature -FilePath $tempInstaller)) {
|
||||
Remove-Item $tempInstaller -Force -ErrorAction SilentlyContinue
|
||||
throw "Installer signature verification failed"
|
||||
}
|
||||
|
||||
# Build installer arguments
|
||||
$installerArgs = "/VERYSILENT /NORESTART /SUPPRESSMSGBOXES"
|
||||
if ($InstallDir) {
|
||||
$installerArgs += " /DIR=`"$InstallDir`""
|
||||
}
|
||||
Write-Status " Installer args: $installerArgs"
|
||||
|
||||
# Run installer
|
||||
Write-Step "Installing Ollama"
|
||||
if (-not $DebugInstall) {
|
||||
Write-Host ">>> Installing Ollama..."
|
||||
}
|
||||
|
||||
# Create upgrade marker so the app starts hidden
|
||||
# The app checks for this file on startup and removes it after
|
||||
$markerDir = Join-Path $env:LOCALAPPDATA "Ollama"
|
||||
$markerFile = Join-Path $markerDir "upgraded"
|
||||
if (-not (Test-Path $markerDir)) {
|
||||
New-Item -ItemType Directory -Path $markerDir -Force | Out-Null
|
||||
}
|
||||
New-Item -ItemType File -Path $markerFile -Force | Out-Null
|
||||
Write-Status " Created upgrade marker: $markerFile"
|
||||
|
||||
# Start installer and wait for just the installer process (not children)
|
||||
# Using -Wait would wait for Ollama to exit too, which we don't want
|
||||
$proc = Start-Process -FilePath $tempInstaller `
|
||||
-ArgumentList $installerArgs `
|
||||
-PassThru
|
||||
$proc.WaitForExit()
|
||||
|
||||
if ($proc.ExitCode -ne 0) {
|
||||
Remove-Item $tempInstaller -Force -ErrorAction SilentlyContinue
|
||||
throw "Installation failed with exit code $($proc.ExitCode)"
|
||||
}
|
||||
|
||||
# Cleanup
|
||||
Remove-Item $tempInstaller -Force -ErrorAction SilentlyContinue
|
||||
|
||||
# Update PATH in current session so 'ollama' works immediately
|
||||
Write-Step "Updating session PATH"
|
||||
Update-SessionPath
|
||||
|
||||
Write-Host ">>> Install complete. Run 'ollama' from the command line."
|
||||
}
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
# Main
|
||||
# --------------------------------------------------------------------------
|
||||
|
||||
if ($Uninstall) {
|
||||
Invoke-Uninstall
|
||||
} else {
|
||||
Invoke-Install
|
||||
}
|
||||
455
scripts/install.sh
Executable file
455
scripts/install.sh
Executable file
@@ -0,0 +1,455 @@
|
||||
#!/bin/sh
|
||||
# This script installs Ollama on Linux and macOS.
|
||||
# It detects the current operating system architecture and installs the appropriate version of Ollama.
|
||||
|
||||
# Wrap script in main function so that a truncated partial download doesn't end
|
||||
# up executing half a script.
|
||||
main() {
|
||||
|
||||
set -eu
|
||||
|
||||
red="$( (/usr/bin/tput bold || :; /usr/bin/tput setaf 1 || :) 2>&-)"
|
||||
plain="$( (/usr/bin/tput sgr0 || :) 2>&-)"
|
||||
|
||||
status() { echo ">>> $*" >&2; }
|
||||
error() { echo "${red}ERROR:${plain} $*"; exit 1; }
|
||||
warning() { echo "${red}WARNING:${plain} $*"; }
|
||||
|
||||
TEMP_DIR=$(mktemp -d)
|
||||
cleanup() { rm -rf $TEMP_DIR; }
|
||||
trap cleanup EXIT
|
||||
|
||||
available() { command -v $1 >/dev/null; }
|
||||
require() {
|
||||
local MISSING=''
|
||||
for TOOL in $*; do
|
||||
if ! available $TOOL; then
|
||||
MISSING="$MISSING $TOOL"
|
||||
fi
|
||||
done
|
||||
|
||||
echo $MISSING
|
||||
}
|
||||
|
||||
OS="$(uname -s)"
|
||||
ARCH=$(uname -m)
|
||||
case "$ARCH" in
|
||||
x86_64) ARCH="amd64" ;;
|
||||
aarch64|arm64) ARCH="arm64" ;;
|
||||
*) error "Unsupported architecture: $ARCH" ;;
|
||||
esac
|
||||
|
||||
VER_PARAM="${OLLAMA_VERSION:+?version=$OLLAMA_VERSION}"
|
||||
|
||||
###########################################
|
||||
# macOS
|
||||
###########################################
|
||||
|
||||
if [ "$OS" = "Darwin" ]; then
|
||||
NEEDS=$(require curl unzip)
|
||||
if [ -n "$NEEDS" ]; then
|
||||
status "ERROR: The following tools are required but missing:"
|
||||
for NEED in $NEEDS; do
|
||||
echo " - $NEED"
|
||||
done
|
||||
exit 1
|
||||
fi
|
||||
|
||||
DOWNLOAD_URL="https://ollama.com/download/Ollama-darwin.zip${VER_PARAM}"
|
||||
|
||||
if pgrep -x Ollama >/dev/null 2>&1; then
|
||||
status "Stopping running Ollama instance..."
|
||||
pkill -x Ollama 2>/dev/null || true
|
||||
sleep 2
|
||||
fi
|
||||
|
||||
if [ -d "/Applications/Ollama.app" ]; then
|
||||
status "Removing existing Ollama installation..."
|
||||
rm -rf "/Applications/Ollama.app"
|
||||
fi
|
||||
|
||||
status "Downloading Ollama for macOS..."
|
||||
curl --fail --show-error --location --progress-bar \
|
||||
-o "$TEMP_DIR/Ollama-darwin.zip" "$DOWNLOAD_URL"
|
||||
|
||||
status "Installing Ollama to /Applications..."
|
||||
unzip -q "$TEMP_DIR/Ollama-darwin.zip" -d "$TEMP_DIR"
|
||||
mv "$TEMP_DIR/Ollama.app" "/Applications/"
|
||||
|
||||
if [ ! -L "/usr/local/bin/ollama" ] || [ "$(readlink "/usr/local/bin/ollama")" != "/Applications/Ollama.app/Contents/Resources/ollama" ]; then
|
||||
status "Adding 'ollama' command to PATH (may require password)..."
|
||||
mkdir -p "/usr/local/bin" 2>/dev/null || sudo mkdir -p "/usr/local/bin"
|
||||
ln -sf "/Applications/Ollama.app/Contents/Resources/ollama" "/usr/local/bin/ollama" 2>/dev/null || \
|
||||
sudo ln -sf "/Applications/Ollama.app/Contents/Resources/ollama" "/usr/local/bin/ollama"
|
||||
fi
|
||||
|
||||
if [ -z "${OLLAMA_NO_START:-}" ]; then
|
||||
status "Starting Ollama..."
|
||||
open -a Ollama --args hidden
|
||||
fi
|
||||
|
||||
status "Install complete. You can now run 'ollama'."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
###########################################
|
||||
# Linux
|
||||
###########################################
|
||||
|
||||
[ "$OS" = "Linux" ] || error 'This script is intended to run on Linux and macOS only.'
|
||||
|
||||
IS_WSL2=false
|
||||
|
||||
KERN=$(uname -r)
|
||||
case "$KERN" in
|
||||
*icrosoft*WSL2 | *icrosoft*wsl2) IS_WSL2=true;;
|
||||
*icrosoft) error "Microsoft WSL1 is not currently supported. Please use WSL2 with 'wsl --set-version <distro> 2'" ;;
|
||||
*) ;;
|
||||
esac
|
||||
|
||||
SUDO=
|
||||
if [ "$(id -u)" -ne 0 ]; then
|
||||
# Running as root, no need for sudo
|
||||
if ! available sudo; then
|
||||
error "This script requires superuser permissions. Please re-run as root."
|
||||
fi
|
||||
|
||||
SUDO="sudo"
|
||||
fi
|
||||
|
||||
NEEDS=$(require curl awk grep sed tee xargs)
|
||||
if [ -n "$NEEDS" ]; then
|
||||
status "ERROR: The following tools are required but missing:"
|
||||
for NEED in $NEEDS; do
|
||||
echo " - $NEED"
|
||||
done
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Function to download and extract with fallback from zst to tgz
|
||||
download_and_extract() {
|
||||
local url_base="$1"
|
||||
local dest_dir="$2"
|
||||
local filename="$3"
|
||||
|
||||
# Check if .tar.zst is available
|
||||
if curl --fail --silent --head --location "${url_base}/${filename}.tar.zst${VER_PARAM}" >/dev/null 2>&1; then
|
||||
# zst file exists - check if we have zstd tool
|
||||
if ! available zstd; then
|
||||
error "This version requires zstd for extraction. Please install zstd and try again:
|
||||
- Debian/Ubuntu: sudo apt-get install zstd
|
||||
- RHEL/CentOS/Fedora: sudo dnf install zstd
|
||||
- Arch: sudo pacman -S zstd"
|
||||
fi
|
||||
|
||||
status "Downloading ${filename}.tar.zst"
|
||||
curl --fail --show-error --location --progress-bar \
|
||||
"${url_base}/${filename}.tar.zst${VER_PARAM}" | \
|
||||
zstd -d | $SUDO tar -xf - -C "${dest_dir}"
|
||||
return 0
|
||||
fi
|
||||
|
||||
# Fall back to .tgz for older versions
|
||||
status "Downloading ${filename}.tgz"
|
||||
curl --fail --show-error --location --progress-bar \
|
||||
"${url_base}/${filename}.tgz${VER_PARAM}" | \
|
||||
$SUDO tar -xzf - -C "${dest_dir}"
|
||||
}
|
||||
|
||||
for BINDIR in /usr/local/bin /usr/bin /bin; do
|
||||
echo $PATH | grep -q $BINDIR && break || continue
|
||||
done
|
||||
OLLAMA_INSTALL_DIR=$(dirname ${BINDIR})
|
||||
|
||||
if [ -d "$OLLAMA_INSTALL_DIR/lib/ollama" ] ; then
|
||||
status "Cleaning up old version at $OLLAMA_INSTALL_DIR/lib/ollama"
|
||||
$SUDO rm -rf "$OLLAMA_INSTALL_DIR/lib/ollama"
|
||||
fi
|
||||
status "Installing ollama to $OLLAMA_INSTALL_DIR"
|
||||
$SUDO install -o0 -g0 -m755 -d $BINDIR
|
||||
$SUDO install -o0 -g0 -m755 -d "$OLLAMA_INSTALL_DIR/lib/ollama"
|
||||
download_and_extract "https://ollama.com/download" "$OLLAMA_INSTALL_DIR" "ollama-linux-${ARCH}"
|
||||
|
||||
if [ "$OLLAMA_INSTALL_DIR/bin/ollama" != "$BINDIR/ollama" ] ; then
|
||||
status "Making ollama accessible in the PATH in $BINDIR"
|
||||
$SUDO ln -sf "$OLLAMA_INSTALL_DIR/ollama" "$BINDIR/ollama"
|
||||
fi
|
||||
|
||||
# Check for NVIDIA JetPack systems with additional downloads
|
||||
if [ -f /etc/nv_tegra_release ] ; then
|
||||
if grep R36 /etc/nv_tegra_release > /dev/null ; then
|
||||
download_and_extract "https://ollama.com/download" "$OLLAMA_INSTALL_DIR" "ollama-linux-${ARCH}-jetpack6"
|
||||
elif grep R35 /etc/nv_tegra_release > /dev/null ; then
|
||||
download_and_extract "https://ollama.com/download" "$OLLAMA_INSTALL_DIR" "ollama-linux-${ARCH}-jetpack5"
|
||||
else
|
||||
warning "Unsupported JetPack version detected. GPU may not be supported"
|
||||
fi
|
||||
fi
|
||||
|
||||
install_success() {
|
||||
status 'The Ollama API is now available at 127.0.0.1:11434.'
|
||||
status 'Install complete. Run "ollama" from the command line.'
|
||||
}
|
||||
trap install_success EXIT
|
||||
|
||||
# Everything from this point onwards is optional.
|
||||
|
||||
configure_systemd() {
|
||||
if ! id ollama >/dev/null 2>&1; then
|
||||
status "Creating ollama user..."
|
||||
$SUDO useradd -r -s /bin/false -U -m -d /usr/share/ollama ollama
|
||||
fi
|
||||
if getent group render >/dev/null 2>&1; then
|
||||
status "Adding ollama user to render group..."
|
||||
$SUDO usermod -a -G render ollama
|
||||
fi
|
||||
if getent group video >/dev/null 2>&1; then
|
||||
status "Adding ollama user to video group..."
|
||||
$SUDO usermod -a -G video ollama
|
||||
fi
|
||||
|
||||
status "Adding current user to ollama group..."
|
||||
$SUDO usermod -a -G ollama $(whoami)
|
||||
|
||||
status "Creating ollama systemd service..."
|
||||
cat <<EOF | $SUDO tee /etc/systemd/system/ollama.service >/dev/null
|
||||
[Unit]
|
||||
Description=Ollama Service
|
||||
After=network-online.target
|
||||
|
||||
[Service]
|
||||
ExecStart=$BINDIR/ollama serve
|
||||
User=ollama
|
||||
Group=ollama
|
||||
Restart=always
|
||||
RestartSec=3
|
||||
Environment="PATH=$PATH"
|
||||
|
||||
[Install]
|
||||
WantedBy=default.target
|
||||
EOF
|
||||
SYSTEMCTL_RUNNING="$(systemctl is-system-running || true)"
|
||||
case $SYSTEMCTL_RUNNING in
|
||||
running|degraded)
|
||||
status "Enabling and starting ollama service..."
|
||||
$SUDO systemctl daemon-reload
|
||||
$SUDO systemctl enable ollama
|
||||
|
||||
start_service() { $SUDO systemctl restart ollama; }
|
||||
trap start_service EXIT
|
||||
;;
|
||||
*)
|
||||
warning "systemd is not running"
|
||||
if [ "$IS_WSL2" = true ]; then
|
||||
warning "see https://learn.microsoft.com/en-us/windows/wsl/systemd#how-to-enable-systemd to enable it"
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
if available systemctl; then
|
||||
configure_systemd
|
||||
fi
|
||||
|
||||
# WSL2 only supports GPUs via nvidia passthrough
|
||||
# so check for nvidia-smi to determine if GPU is available
|
||||
if [ "$IS_WSL2" = true ]; then
|
||||
if available nvidia-smi && [ -n "$(nvidia-smi | grep -o "CUDA Version: [0-9]*\.[0-9]*")" ]; then
|
||||
status "Nvidia GPU detected."
|
||||
fi
|
||||
install_success
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Don't attempt to install drivers on Jetson systems
|
||||
if [ -f /etc/nv_tegra_release ] ; then
|
||||
status "NVIDIA JetPack ready."
|
||||
install_success
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Install GPU dependencies on Linux
|
||||
if ! available lspci && ! available lshw; then
|
||||
warning "Unable to detect NVIDIA/AMD GPU. Install lspci or lshw to automatically detect and install GPU dependencies."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
check_gpu() {
|
||||
# Look for devices based on vendor ID for NVIDIA and AMD
|
||||
case $1 in
|
||||
lspci)
|
||||
case $2 in
|
||||
nvidia) available lspci && lspci -d '10de:' | grep -q 'NVIDIA' || return 1 ;;
|
||||
amdgpu) available lspci && lspci -d '1002:' | grep -q 'AMD' || return 1 ;;
|
||||
esac ;;
|
||||
lshw)
|
||||
case $2 in
|
||||
nvidia) available lshw && $SUDO lshw -c display -numeric -disable network | grep -q 'vendor: .* \[10DE\]' || return 1 ;;
|
||||
amdgpu) available lshw && $SUDO lshw -c display -numeric -disable network | grep -q 'vendor: .* \[1002\]' || return 1 ;;
|
||||
esac ;;
|
||||
nvidia-smi) available nvidia-smi || return 1 ;;
|
||||
esac
|
||||
}
|
||||
|
||||
if check_gpu nvidia-smi; then
|
||||
status "NVIDIA GPU installed."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if ! check_gpu lspci nvidia && ! check_gpu lshw nvidia && ! check_gpu lspci amdgpu && ! check_gpu lshw amdgpu; then
|
||||
install_success
|
||||
warning "No NVIDIA/AMD GPU detected. Ollama will run in CPU-only mode."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if check_gpu lspci amdgpu || check_gpu lshw amdgpu; then
|
||||
download_and_extract "https://ollama.com/download" "$OLLAMA_INSTALL_DIR" "ollama-linux-${ARCH}-rocm"
|
||||
|
||||
install_success
|
||||
status "AMD GPU ready."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
CUDA_REPO_ERR_MSG="NVIDIA GPU detected, but your OS and Architecture are not supported by NVIDIA. Please install the CUDA driver manually https://docs.nvidia.com/cuda/cuda-installation-guide-linux/"
|
||||
# ref: https://docs.nvidia.com/cuda/cuda-installation-guide-linux/index.html#rhel-7-centos-7
|
||||
# ref: https://docs.nvidia.com/cuda/cuda-installation-guide-linux/index.html#rhel-8-rocky-8
|
||||
# ref: https://docs.nvidia.com/cuda/cuda-installation-guide-linux/index.html#rhel-9-rocky-9
|
||||
# ref: https://docs.nvidia.com/cuda/cuda-installation-guide-linux/index.html#fedora
|
||||
install_cuda_driver_yum() {
|
||||
status 'Installing NVIDIA repository...'
|
||||
|
||||
case $PACKAGE_MANAGER in
|
||||
yum)
|
||||
$SUDO $PACKAGE_MANAGER -y install yum-utils
|
||||
if curl -I --silent --fail --location "https://developer.download.nvidia.com/compute/cuda/repos/$1$2/$(uname -m | sed -e 's/aarch64/sbsa/')/cuda-$1$2.repo" >/dev/null ; then
|
||||
$SUDO $PACKAGE_MANAGER-config-manager --add-repo https://developer.download.nvidia.com/compute/cuda/repos/$1$2/$(uname -m | sed -e 's/aarch64/sbsa/')/cuda-$1$2.repo
|
||||
else
|
||||
error $CUDA_REPO_ERR_MSG
|
||||
fi
|
||||
;;
|
||||
dnf)
|
||||
if curl -I --silent --fail --location "https://developer.download.nvidia.com/compute/cuda/repos/$1$2/$(uname -m | sed -e 's/aarch64/sbsa/')/cuda-$1$2.repo" >/dev/null ; then
|
||||
$SUDO $PACKAGE_MANAGER config-manager --add-repo https://developer.download.nvidia.com/compute/cuda/repos/$1$2/$(uname -m | sed -e 's/aarch64/sbsa/')/cuda-$1$2.repo
|
||||
else
|
||||
error $CUDA_REPO_ERR_MSG
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
|
||||
case $1 in
|
||||
rhel)
|
||||
status 'Installing EPEL repository...'
|
||||
# EPEL is required for third-party dependencies such as dkms and libvdpau
|
||||
$SUDO $PACKAGE_MANAGER -y install https://dl.fedoraproject.org/pub/epel/epel-release-latest-$2.noarch.rpm || true
|
||||
;;
|
||||
esac
|
||||
|
||||
status 'Installing CUDA driver...'
|
||||
|
||||
if [ "$1" = 'centos' ] || [ "$1$2" = 'rhel7' ]; then
|
||||
$SUDO $PACKAGE_MANAGER -y install nvidia-driver-latest-dkms
|
||||
fi
|
||||
|
||||
$SUDO $PACKAGE_MANAGER -y install cuda-drivers
|
||||
}
|
||||
|
||||
# ref: https://docs.nvidia.com/cuda/cuda-installation-guide-linux/index.html#ubuntu
|
||||
# ref: https://docs.nvidia.com/cuda/cuda-installation-guide-linux/index.html#debian
|
||||
install_cuda_driver_apt() {
|
||||
status 'Installing NVIDIA repository...'
|
||||
if curl -I --silent --fail --location "https://developer.download.nvidia.com/compute/cuda/repos/$1$2/$(uname -m | sed -e 's/aarch64/sbsa/')/cuda-keyring_1.1-1_all.deb" >/dev/null ; then
|
||||
curl -fsSL -o $TEMP_DIR/cuda-keyring.deb https://developer.download.nvidia.com/compute/cuda/repos/$1$2/$(uname -m | sed -e 's/aarch64/sbsa/')/cuda-keyring_1.1-1_all.deb
|
||||
else
|
||||
error $CUDA_REPO_ERR_MSG
|
||||
fi
|
||||
|
||||
case $1 in
|
||||
debian)
|
||||
status 'Enabling contrib sources...'
|
||||
$SUDO sed 's/main/contrib/' < /etc/apt/sources.list | $SUDO tee /etc/apt/sources.list.d/contrib.list > /dev/null
|
||||
if [ -f "/etc/apt/sources.list.d/debian.sources" ]; then
|
||||
$SUDO sed 's/main/contrib/' < /etc/apt/sources.list.d/debian.sources | $SUDO tee /etc/apt/sources.list.d/contrib.sources > /dev/null
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
|
||||
status 'Installing CUDA driver...'
|
||||
$SUDO dpkg -i $TEMP_DIR/cuda-keyring.deb
|
||||
$SUDO apt-get update
|
||||
|
||||
[ -n "$SUDO" ] && SUDO_E="$SUDO -E" || SUDO_E=
|
||||
DEBIAN_FRONTEND=noninteractive $SUDO_E apt-get -y install cuda-drivers -q
|
||||
}
|
||||
|
||||
if [ ! -f "/etc/os-release" ]; then
|
||||
error "Unknown distribution. Skipping CUDA installation."
|
||||
fi
|
||||
|
||||
. /etc/os-release
|
||||
|
||||
OS_NAME=$ID
|
||||
OS_VERSION=$VERSION_ID
|
||||
|
||||
PACKAGE_MANAGER=
|
||||
for PACKAGE_MANAGER in dnf yum apt-get; do
|
||||
if available $PACKAGE_MANAGER; then
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
if [ -z "$PACKAGE_MANAGER" ]; then
|
||||
error "Unknown package manager. Skipping CUDA installation."
|
||||
fi
|
||||
|
||||
if ! check_gpu nvidia-smi || [ -z "$(nvidia-smi | grep -o "CUDA Version: [0-9]*\.[0-9]*")" ]; then
|
||||
case $OS_NAME in
|
||||
centos|rhel) install_cuda_driver_yum 'rhel' $(echo $OS_VERSION | cut -d '.' -f 1) ;;
|
||||
rocky) install_cuda_driver_yum 'rhel' $(echo $OS_VERSION | cut -c1) ;;
|
||||
fedora) [ $OS_VERSION -lt '39' ] && install_cuda_driver_yum $OS_NAME $OS_VERSION || install_cuda_driver_yum $OS_NAME '39';;
|
||||
amzn) install_cuda_driver_yum 'fedora' '37' ;;
|
||||
debian) install_cuda_driver_apt $OS_NAME $OS_VERSION ;;
|
||||
ubuntu) install_cuda_driver_apt $OS_NAME $(echo $OS_VERSION | sed 's/\.//') ;;
|
||||
*) exit ;;
|
||||
esac
|
||||
fi
|
||||
|
||||
if ! lsmod | grep -q nvidia || ! lsmod | grep -q nvidia_uvm; then
|
||||
KERNEL_RELEASE="$(uname -r)"
|
||||
case $OS_NAME in
|
||||
rocky) $SUDO $PACKAGE_MANAGER -y install kernel-devel kernel-headers ;;
|
||||
centos|rhel|amzn) $SUDO $PACKAGE_MANAGER -y install kernel-devel-$KERNEL_RELEASE kernel-headers-$KERNEL_RELEASE ;;
|
||||
fedora) $SUDO $PACKAGE_MANAGER -y install kernel-devel-$KERNEL_RELEASE ;;
|
||||
debian|ubuntu) $SUDO apt-get -y install linux-headers-$KERNEL_RELEASE ;;
|
||||
*) exit ;;
|
||||
esac
|
||||
|
||||
NVIDIA_CUDA_VERSION=$($SUDO dkms status | awk -F: '/added/ { print $1 }')
|
||||
if [ -n "$NVIDIA_CUDA_VERSION" ]; then
|
||||
$SUDO dkms install $NVIDIA_CUDA_VERSION
|
||||
fi
|
||||
|
||||
if lsmod | grep -q nouveau; then
|
||||
status 'Reboot to complete NVIDIA CUDA driver install.'
|
||||
exit 0
|
||||
fi
|
||||
|
||||
$SUDO modprobe nvidia
|
||||
$SUDO modprobe nvidia_uvm
|
||||
fi
|
||||
|
||||
# make sure the NVIDIA modules are loaded on boot with nvidia-persistenced
|
||||
if available nvidia-persistenced; then
|
||||
$SUDO touch /etc/modules-load.d/nvidia.conf
|
||||
MODULES="nvidia nvidia-uvm"
|
||||
for MODULE in $MODULES; do
|
||||
if ! grep -qxF "$MODULE" /etc/modules-load.d/nvidia.conf; then
|
||||
echo "$MODULE" | $SUDO tee -a /etc/modules-load.d/nvidia.conf > /dev/null
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
status "NVIDIA GPU ready."
|
||||
install_success
|
||||
}
|
||||
|
||||
main
|
||||
15
scripts/push_docker.sh
Executable file
15
scripts/push_docker.sh
Executable file
@@ -0,0 +1,15 @@
|
||||
#!/bin/sh
|
||||
|
||||
set -eu
|
||||
|
||||
export VERSION=${VERSION:-0.0.0}
|
||||
export GOFLAGS="'-ldflags=-w -s \"-X=github.com/ollama/ollama/version.Version=$VERSION\" \"-X=github.com/ollama/ollama/server.mode=release\"'"
|
||||
|
||||
docker build \
|
||||
--push \
|
||||
--platform=linux/arm64,linux/amd64 \
|
||||
--build-arg=VERSION \
|
||||
--build-arg=GOFLAGS \
|
||||
-f Dockerfile \
|
||||
-t ollama/ollama -t ollama/ollama:$VERSION \
|
||||
.
|
||||
105
scripts/support/eula-resources-template.xml
Normal file
105
scripts/support/eula-resources-template.xml
Normal file
@@ -0,0 +1,105 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>LPic</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>Attributes</key>
|
||||
<string>0x0000</string>
|
||||
<key>Data</key>
|
||||
<data>
|
||||
AAAAAgAAAAAAAAAAAAQAAA==
|
||||
</data>
|
||||
<key>ID</key>
|
||||
<string>5000</string>
|
||||
<key>Name</key>
|
||||
<string></string>
|
||||
</dict>
|
||||
</array>
|
||||
<key>STR#</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>Attributes</key>
|
||||
<string>0x0000</string>
|
||||
<key>Data</key>
|
||||
<data>
|
||||
AAYNRW5nbGlzaCB0ZXN0MQVBZ3JlZQhEaXNhZ3JlZQVQcmludAdT
|
||||
YXZlLi4ueklmIHlvdSBhZ3JlZSB3aXRoIHRoZSB0ZXJtcyBvZiB0
|
||||
aGlzIGxpY2Vuc2UsIGNsaWNrICJBZ3JlZSIgdG8gYWNjZXNzIHRo
|
||||
ZSBzb2Z0d2FyZS4gSWYgeW91IGRvIG5vdCBhZ3JlZSwgY2xpY2sg
|
||||
IkRpc2FncmVlIi4=
|
||||
</data>
|
||||
<key>ID</key>
|
||||
<string>5000</string>
|
||||
<key>Name</key>
|
||||
<string>English buttons</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>Attributes</key>
|
||||
<string>0x0000</string>
|
||||
<key>Data</key>
|
||||
<data>
|
||||
AAYHRW5nbGlzaAVBZ3JlZQhEaXNhZ3JlZQVQcmludAdTYXZlLi4u
|
||||
e0lmIHlvdSBhZ3JlZSB3aXRoIHRoZSB0ZXJtcyBvZiB0aGlzIGxp
|
||||
Y2Vuc2UsIHByZXNzICJBZ3JlZSIgdG8gaW5zdGFsbCB0aGUgc29m
|
||||
dHdhcmUuIElmIHlvdSBkbyBub3QgYWdyZWUsIGNsaWNrICJEaXNh
|
||||
Z3JlZSIu
|
||||
</data>
|
||||
<key>ID</key>
|
||||
<string>5002</string>
|
||||
<key>Name</key>
|
||||
<string>English</string>
|
||||
</dict>
|
||||
</array>
|
||||
<key>${EULA_FORMAT}</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>Attributes</key>
|
||||
<string>0x0000</string>
|
||||
<key>Data</key>
|
||||
<data>
|
||||
${EULA_DATA}
|
||||
</data>
|
||||
<key>ID</key>
|
||||
<string>5000</string>
|
||||
<key>Name</key>
|
||||
<string>English</string>
|
||||
</dict>
|
||||
</array>
|
||||
<key>TMPL</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>Attributes</key>
|
||||
<string>0x0000</string>
|
||||
<key>Data</key>
|
||||
<data>
|
||||
E0RlZmF1bHQgTGFuZ3VhZ2UgSUREV1JEBUNvdW50T0NOVAQqKioq
|
||||
TFNUQwtzeXMgbGFuZyBJRERXUkQebG9jYWwgcmVzIElEIChvZmZz
|
||||
ZXQgZnJvbSA1MDAwRFdSRBAyLWJ5dGUgbGFuZ3VhZ2U/RFdSRAQq
|
||||
KioqTFNURQ==
|
||||
</data>
|
||||
<key>ID</key>
|
||||
<string>128</string>
|
||||
<key>Name</key>
|
||||
<string>LPic</string>
|
||||
</dict>
|
||||
</array>
|
||||
<key>styl</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>Attributes</key>
|
||||
<string>0x0000</string>
|
||||
<key>Data</key>
|
||||
<data>
|
||||
AAMAAAAAAAwACQAUAAAAAAAAAAAAAAAAACcADAAJABQBAAAAAAAA
|
||||
AAAAAAAAKgAMAAkAFAAAAAAAAAAAAAA=
|
||||
</data>
|
||||
<key>ID</key>
|
||||
<string>5000</string>
|
||||
<key>Name</key>
|
||||
<string>English</string>
|
||||
</dict>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
||||
74
scripts/support/template.applescript
Normal file
74
scripts/support/template.applescript
Normal file
@@ -0,0 +1,74 @@
|
||||
on run (volumeName)
|
||||
tell application "Finder"
|
||||
tell disk (volumeName as string)
|
||||
open
|
||||
|
||||
set theXOrigin to WINX
|
||||
set theYOrigin to WINY
|
||||
set theWidth to WINW
|
||||
set theHeight to WINH
|
||||
|
||||
set theBottomRightX to (theXOrigin + theWidth)
|
||||
set theBottomRightY to (theYOrigin + theHeight)
|
||||
set dsStore to "\"" & "/Volumes/" & volumeName & "/" & ".DS_STORE\""
|
||||
|
||||
tell container window
|
||||
set current view to icon view
|
||||
set toolbar visible to false
|
||||
set statusbar visible to false
|
||||
set the bounds to {theXOrigin, theYOrigin, theBottomRightX, theBottomRightY}
|
||||
set statusbar visible to false
|
||||
REPOSITION_HIDDEN_FILES_CLAUSE
|
||||
end tell
|
||||
|
||||
set opts to the icon view options of container window
|
||||
tell opts
|
||||
set icon size to ICON_SIZE
|
||||
set text size to TEXT_SIZE
|
||||
set arrangement to not arranged
|
||||
end tell
|
||||
BACKGROUND_CLAUSE
|
||||
|
||||
-- Positioning
|
||||
POSITION_CLAUSE
|
||||
|
||||
-- Hiding
|
||||
HIDING_CLAUSE
|
||||
|
||||
-- Application and QL Link Clauses
|
||||
APPLICATION_CLAUSE
|
||||
QL_CLAUSE
|
||||
close
|
||||
open
|
||||
-- Force saving of the size
|
||||
delay 1
|
||||
|
||||
tell container window
|
||||
set statusbar visible to false
|
||||
set the bounds to {theXOrigin, theYOrigin, theBottomRightX - 10, theBottomRightY - 10}
|
||||
end tell
|
||||
end tell
|
||||
|
||||
delay 1
|
||||
|
||||
tell disk (volumeName as string)
|
||||
tell container window
|
||||
set statusbar visible to false
|
||||
set the bounds to {theXOrigin, theYOrigin, theBottomRightX, theBottomRightY}
|
||||
end tell
|
||||
end tell
|
||||
|
||||
--give the finder some time to write the .DS_Store file
|
||||
delay 3
|
||||
|
||||
set waitTime to 0
|
||||
set ejectMe to false
|
||||
repeat while ejectMe is false
|
||||
delay 1
|
||||
set waitTime to waitTime + 1
|
||||
|
||||
if (do shell script "[ -f " & dsStore & " ]; echo $?") = "0" then set ejectMe to true
|
||||
end repeat
|
||||
log "waited " & waitTime & " seconds for .DS_STORE to be created."
|
||||
end tell
|
||||
end run
|
||||
13
scripts/tag_latest.sh
Executable file
13
scripts/tag_latest.sh
Executable file
@@ -0,0 +1,13 @@
|
||||
#!/bin/sh
|
||||
|
||||
set -eu
|
||||
|
||||
# For developers, you can override the DOCKER_ORG to generate multiarch manifests
|
||||
# DOCKER_ORG=jdoe VERSION=0.1.30 ./scripts/tag_latest.sh
|
||||
DOCKER_ORG=${DOCKER_ORG:-"ollama"}
|
||||
FINAL_IMAGE_REPO=${FINAL_IMAGE_REPO:-"${DOCKER_ORG}/ollama"}
|
||||
|
||||
echo "Updating ${FINAL_IMAGE_REPO}:latest -> ${FINAL_IMAGE_REPO}:${VERSION}"
|
||||
docker buildx imagetools create -t ${FINAL_IMAGE_REPO}:latest ${FINAL_IMAGE_REPO}:${VERSION}
|
||||
echo "Updating ${FINAL_IMAGE_REPO}:rocm -> ${FINAL_IMAGE_REPO}:${VERSION}-rocm"
|
||||
docker buildx imagetools create -t ${FINAL_IMAGE_REPO}:rocm ${FINAL_IMAGE_REPO}:${VERSION}-rocm
|
||||
Reference in New Issue
Block a user