Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 21 additions & 6 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -94,19 +94,19 @@ jobs:
uses: actions/cache@v4
with:
path: |
~/.cargo/bin/cargo-tauri
~/.cargo/bin/cargo-tauri*
~/.cargo/registry
~/.cargo/git
key: ${{ runner.os }}-${{ matrix.target }}-cargo-tauri-v2-${{ hashFiles('src-tauri/Cargo.lock') }}

- name: Install Tauri CLI (cargo plugin)
if: steps.cache-tauri-cli.outputs.cache-hit != 'true'
run: cargo install tauri-cli --locked
shell: bash
run: cargo tauri --version || cargo install tauri-cli --locked

- name: Install dependencies (macOS)
if: matrix.platform == 'macos-latest'
run: |
brew install create-dmg
brew install apache-arrow create-dmg libomp

- name: Install dependencies (Linux)
if: matrix.platform == 'ubuntu-latest' || matrix.platform == 'ubuntu-24.04-arm'
Expand Down Expand Up @@ -171,6 +171,15 @@ jobs:
LBUG_TARGET_DIR: ${{ github.workspace }}/src-tauri/liblbug
run: bash scripts/download-liblbug.sh

- name: Download icebug
env:
ICEBUG_TARGET_DIR: ${{ github.workspace }}/src-tauri/icebug
run: bash scripts/download_icebug.sh

- name: Stage macOS dylibs
if: matrix.platform == 'macos-latest'
run: bash scripts/stage_macos_frameworks.sh

- name: Build Tauri app (Linux)
if: matrix.platform == 'ubuntu-latest' || matrix.platform == 'ubuntu-24.04-arm'
run: pnpm tauri build --target ${{ matrix.target }} --bundles ${{ matrix.bundles }} --verbose
Expand All @@ -181,8 +190,14 @@ jobs:
LD_LIBRARY_PATH: ${{ github.workspace }}/src-tauri/liblbug
NO_STRIP: "true" # https://github.com/tauri-apps/tauri/issues/14796

- name: Build Tauri app (macOS/Windows)
if: matrix.platform == 'macos-latest' || matrix.platform == 'windows-latest'
- name: Build Tauri app (macOS)
if: matrix.platform == 'macos-latest'
run: pnpm tauri build --target ${{ matrix.target }} --bundles ${{ matrix.bundles }} --features icebug-analytics --verbose
env:
CXXFLAGS: -I/opt/homebrew/opt/libomp/include

- name: Build Tauri app (Windows)
if: matrix.platform == 'windows-latest'
run: pnpm tauri build --target ${{ matrix.target }} --bundles ${{ matrix.bundles }} --verbose

- name: Upload artifacts
Expand Down
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,6 @@ pnpm-lock.yaml
# Tauri
src-tauri/target/
src-tauri/liblbug/
src-tauri/icebug/
src-tauri/macos-frameworks/
src-tauri/gen/
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"version": "0.15.1",
"type": "module",
"scripts": {
"setup": "bash scripts/download-liblbug.sh",
"setup": "bash scripts/download-liblbug.sh && bash scripts/download_icebug.sh && bash scripts/stage_macos_frameworks.sh",
"dev:frontend": "vite",
"build:frontend": "tsc -b && vite build",
"tauri": "cargo tauri",
Expand Down
89 changes: 89 additions & 0 deletions scripts/download_icebug.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
#!/usr/bin/env bash
# Download the platform-specific Icebug prebuilt into src-tauri/icebug.
set -euo pipefail

SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
PROJECT_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"

REPOSITORY="${ICEBUG_GITHUB_REPOSITORY:-Ladybug-Memory/icebug}"
TARGET_DIR="${ICEBUG_TARGET_DIR:-$PROJECT_DIR/src-tauri/icebug}"
VERSION="${ICEBUG_VERSION:-12.8}"

OS="$(uname -s)"
ARCH="$(uname -m)"

case "$OS" in
Darwin)
ASSET_OS="macos"
;;
Linux)
ASSET_OS="linux"
;;
MINGW*|MSYS*|CYGWIN*)
ASSET_OS="win"
;;
*)
echo "Unsupported OS: $OS" >&2
exit 1
;;
esac

case "$ARCH" in
arm64|aarch64)
ASSET_ARCH="arm64"
;;
x86_64)
if [ "$ASSET_OS" = "win" ]; then
ASSET_ARCH="amd64"
else
ASSET_ARCH="x86_64"
fi
;;
*)
echo "Unsupported architecture: $ARCH" >&2
exit 1
;;
esac

if [ "$ASSET_OS" = "win" ]; then
ARCHIVE="icebug-${ASSET_OS}-${ASSET_ARCH}.zip"
else
ARCHIVE="icebug-${ASSET_OS}-${ASSET_ARCH}.tar.gz"
fi

LIB_NAME="libnetworkit.so"
case "$ASSET_OS" in
macos)
LIB_NAME="libnetworkit.dylib"
;;
win)
LIB_NAME="networkit.lib"
;;
esac

if [ -f "$TARGET_DIR/lib/$LIB_NAME" ] && [ -d "$TARGET_DIR/include/networkit" ]; then
echo "icebug already exists in $TARGET_DIR"
exit 0
fi

mkdir -p "$TARGET_DIR"
TMPDIR="$(mktemp -d)"
trap 'rm -rf "$TMPDIR"' EXIT

DOWNLOAD_URL="https://github.com/${REPOSITORY}/releases/download/${VERSION}/${ARCHIVE}"
echo "Downloading $DOWNLOAD_URL ..."
curl -fSL "$DOWNLOAD_URL" -o "$TMPDIR/$ARCHIVE"

rm -rf "$TARGET_DIR/include" "$TARGET_DIR/lib" "$TARGET_DIR/extlibs"
if [[ "$ARCHIVE" == *.zip ]]; then
unzip -q "$TMPDIR/$ARCHIVE" -d "$TARGET_DIR"
else
tar xzf "$TMPDIR/$ARCHIVE" -C "$TARGET_DIR"
fi

if [ ! -f "$TARGET_DIR/lib/$LIB_NAME" ]; then
echo "Expected Icebug library not found at $TARGET_DIR/lib/$LIB_NAME" >&2
exit 1
fi

echo "Installed $ARCHIVE to $TARGET_DIR"
96 changes: 96 additions & 0 deletions scripts/patch_macos_bundle_dylibs.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
#!/usr/bin/env bash
# Rewrite macOS release binaries to load bundled dylibs from Contents/Frameworks.
set -euo pipefail

if [ "$(uname -s)" != "Darwin" ]; then
echo "Skipping macOS dylib patching on $(uname -s)"
exit 0
fi

SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
PROJECT_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
TAURI_DIR="$PROJECT_DIR/src-tauri"

find_frameworks_dirs() {
find "$TAURI_DIR/target" -type d -name Frameworks -print 2>/dev/null
}

change_if_present() {
local binary="$1"
local old="$2"
local new="$3"

if otool -L "$binary" | awk '{ print $1 }' | grep -Fxq "$old"; then
install_name_tool -change "$old" "$new" "$binary"
fi
}

patch_binary() {
local binary="$1"

while IFS= read -r dep; do
case "$dep" in
*libarrow*.dylib)
change_if_present "$binary" "$dep" "@rpath/libarrow.icebug.dylib"
;;
*libomp.dylib)
change_if_present "$binary" "$dep" "@rpath/libomp.dylib"
;;
*libnetworkit.dylib)
change_if_present "$binary" "$dep" "@rpath/libnetworkit.dylib"
;;
*liblbug*.dylib)
change_if_present "$binary" "$dep" "@rpath/liblbug.0.dylib"
;;
esac
done < <(otool -L "$binary" | awk 'NR > 1 { print $1 }')
}

patched_any=0
while IFS= read -r binary; do
chmod u+w "$binary"
patch_binary "$binary"
patched_any=1
echo "Patched load commands in $binary"
done < <(find "$TAURI_DIR/target" -path '*/release/bugscope' -type f -perm -111 -print 2>/dev/null)

if [ "$patched_any" -eq 0 ]; then
echo "Could not find a release bugscope binary under $TAURI_DIR/target" >&2
exit 1
fi

while IFS= read -r frameworks_dir; do
[ -d "$frameworks_dir" ] || continue

for dylib in "$frameworks_dir"/*.dylib; do
[ -f "$dylib" ] || continue
chmod u+w "$dylib"
done

if [ -f "$frameworks_dir/libarrow.icebug.dylib" ]; then
install_name_tool -id "@rpath/libarrow.icebug.dylib" "$frameworks_dir/libarrow.icebug.dylib"
patch_binary "$frameworks_dir/libarrow.icebug.dylib"
fi

if [ -f "$frameworks_dir/libnetworkit.dylib" ]; then
install_name_tool -id "@rpath/libnetworkit.dylib" "$frameworks_dir/libnetworkit.dylib"
patch_binary "$frameworks_dir/libnetworkit.dylib"
fi

if [ -f "$frameworks_dir/liblbug.0.dylib" ]; then
install_name_tool -id "@rpath/liblbug.0.dylib" "$frameworks_dir/liblbug.0.dylib"
patch_binary "$frameworks_dir/liblbug.0.dylib"
fi

if [ -f "$frameworks_dir/liblbug.dylib" ]; then
install_name_tool -id "@rpath/liblbug.dylib" "$frameworks_dir/liblbug.dylib"
patch_binary "$frameworks_dir/liblbug.dylib"
fi

if [ -f "$frameworks_dir/libomp.dylib" ]; then
install_name_tool -id "@rpath/libomp.dylib" "$frameworks_dir/libomp.dylib"
patch_binary "$frameworks_dir/libomp.dylib"
fi

echo "Patched bundled dylibs in $frameworks_dir"
done < <(find_frameworks_dirs)
110 changes: 110 additions & 0 deletions scripts/stage_macos_frameworks.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
#!/usr/bin/env bash
# Stage dylibs that Tauri should copy into Contents/Frameworks on macOS.
set -euo pipefail

if [ "$(uname -s)" != "Darwin" ]; then
echo "Skipping macOS framework staging on $(uname -s)"
exit 0
fi

SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
PROJECT_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
TAURI_DIR="$PROJECT_DIR/src-tauri"
ICEBUG_DIR="${ICEBUG_DIR:-$TAURI_DIR/icebug}"
FRAMEWORKS_DIR="$TAURI_DIR/macos-frameworks"

NETWORKIT_SRC="$ICEBUG_DIR/lib/libnetworkit.dylib"
LBUG_SRC="$TAURI_DIR/liblbug/liblbug.0.dylib"

if [ ! -f "$NETWORKIT_SRC" ]; then
echo "Missing $NETWORKIT_SRC. Run scripts/download_icebug.sh first." >&2
exit 1
fi

if [ ! -f "$LBUG_SRC" ]; then
echo "Missing $LBUG_SRC. Run scripts/download-liblbug.sh first." >&2
exit 1
fi

dep_path() {
local lib="$1"
local pattern="$2"
otool -L "$lib" | awk -v pattern="$pattern" '$1 ~ pattern { print $1; exit }'
}

resolve_dep() {
local dep="$1"
local loader_dir="$2"

case "$dep" in
@loader_path/*)
echo "$loader_dir/${dep#@loader_path/}"
;;
@rpath/*)
local name="${dep#@rpath/}"
if [ -f "$ICEBUG_DIR/lib/$name" ]; then
echo "$ICEBUG_DIR/lib/$name"
elif [ -f "/opt/homebrew/opt/apache-arrow/lib/$name" ]; then
echo "/opt/homebrew/opt/apache-arrow/lib/$name"
elif [ -f "/usr/local/opt/apache-arrow/lib/$name" ]; then
echo "/usr/local/opt/apache-arrow/lib/$name"
elif [ -f "/opt/homebrew/opt/libomp/lib/$name" ]; then
echo "/opt/homebrew/opt/libomp/lib/$name"
elif [ -f "/usr/local/opt/libomp/lib/$name" ]; then
echo "/usr/local/opt/libomp/lib/$name"
else
echo "$dep"
fi
;;
*)
echo "$dep"
;;
esac
}

NETWORKIT_DIR="$(cd "$(dirname "$NETWORKIT_SRC")" && pwd)"
ARROW_DEP="$(dep_path "$NETWORKIT_SRC" 'libarrow[.].*[.]dylib')"
OMP_DEP="$(dep_path "$NETWORKIT_SRC" 'libomp[.]dylib')"

if [ -z "$ARROW_DEP" ]; then
echo "Could not find libarrow dependency in $NETWORKIT_SRC" >&2
exit 1
fi

ARROW_SRC="$(resolve_dep "$ARROW_DEP" "$NETWORKIT_DIR")"
if [ ! -f "$ARROW_SRC" ]; then
echo "Icebug requires $ARROW_DEP, but it was not found at $ARROW_SRC" >&2
echo "Install the matching Apache Arrow C++ package before building." >&2
exit 1
fi

if [ -n "$OMP_DEP" ]; then
OMP_SRC="$(resolve_dep "$OMP_DEP" "$NETWORKIT_DIR")"
if [ ! -f "$OMP_SRC" ]; then
echo "Icebug requires $OMP_DEP, but it was not found at $OMP_SRC" >&2
echo "Install libomp before building." >&2
exit 1
fi
else
OMP_SRC=""
fi

mkdir -p "$FRAMEWORKS_DIR"
cp -f "$NETWORKIT_SRC" "$FRAMEWORKS_DIR/libnetworkit.dylib"
cp -f "$ARROW_SRC" "$FRAMEWORKS_DIR/libarrow.icebug.dylib"
cp -f "$LBUG_SRC" "$FRAMEWORKS_DIR/liblbug.0.dylib"
cp -f "$LBUG_SRC" "$FRAMEWORKS_DIR/liblbug.dylib"

if [ -n "$OMP_SRC" ]; then
cp -f "$OMP_SRC" "$FRAMEWORKS_DIR/libomp.dylib"
fi

chmod u+w "$FRAMEWORKS_DIR"/*.dylib

echo "Staged macOS frameworks in $FRAMEWORKS_DIR"
echo " libnetworkit.dylib <= $NETWORKIT_SRC"
echo " libarrow.icebug.dylib <= $ARROW_SRC (from $ARROW_DEP)"
echo " liblbug.0.dylib <= $LBUG_SRC"
if [ -n "$OMP_SRC" ]; then
echo " libomp.dylib <= $OMP_SRC"
fi
1 change: 1 addition & 0 deletions src-tauri/.cargo/config.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
LBUG_LIBRARY_DIR = { value = "liblbug", relative = true }
LBUG_INCLUDE_DIR = { value = "liblbug", relative = true }
LBUG_SHARED = "1"
ICEBUG_DIR = { value = "icebug", relative = true }

# Embed rpath so the binary can find liblbug.dylib at runtime.
# First rpath: for production .app bundles (Contents/Frameworks/)
Expand Down
Loading
Loading