@@ -129,35 +129,189 @@ jobs:
129129 mkdir dist
130130 Move-Item ${{ matrix.artifact }} dist\${{ matrix.artifact }}
131131
132- - name : Package (Linux)
132+ - name : Package (Linux) - AppImage
133133 if : matrix.os == 'ubuntu-latest'
134134 shell : bash
135135 run : |
136- mkdir -p krview/assets/fonts
137- mkdir -p krview/assets/screenshots
136+ set -euo pipefail
137+ APPDIR=AppDir
138+ ARTIFACT_NAME=${{ matrix.artifact }}
138139
139- cp zig-out/bin/krview krview/
140- cp assets/fonts/Terminus.ttf krview/assets/fonts/
141- cp assets/fonts/OFL.TXT krview/assets/fonts/
140+ sudo apt-get update
141+ sudo apt-get install -y patchelf wget
142+
143+ rm -rf "$APPDIR"
144+ mkdir -p "$APPDIR"/usr/bin
145+ mkdir -p "$APPDIR"/usr/lib
146+ mkdir -p "$APPDIR"/usr/share/krview/assets/fonts
147+ mkdir -p "$APPDIR"/usr/share/krview/assets/screenshots
148+ mkdir -p "$APPDIR"/usr/share/applications
149+ mkdir -p "$APPDIR"/usr/share/icons/hicolor/256x256/apps
150+
151+ # Copy binary + assets
152+ cp zig-out/bin/krview "$APPDIR"/usr/bin/
153+ chmod +x "$APPDIR"/usr/bin/krview
154+ cp assets/fonts/Terminus.ttf "$APPDIR"/usr/share/krview/assets/fonts/
155+ cp assets/fonts/OFL.TXT "$APPDIR"/usr/share/krview/assets/fonts/
156+
157+ # Collect shared libs used by the binary (exclude core glibc/ld and linux-vdso)
158+ # Use sed to reliably extract the absolute path after the "=>"
159+ ldd zig-out/bin/krview \
160+ | sed -n 's/.*=> \(\/[^ ]*\).*/\1/p' \
161+ | sort -u \
162+ | grep -vE 'libc.so.6|ld-linux|linux-vdso' \
163+ | while read -r lib; do
164+ echo "Copying $lib"
165+ cp -v "$lib" "$APPDIR"/usr/lib/ || true
166+ done
167+
168+ # Optionally: also copy any symlink targets (sometimes ldd gives symlinks)
169+ # and ensure they resolve correctly. The above cp usually copies the file the symlink points to.
170+
171+ # Ensure rpath is relative to AppImage's lib folder (patchelf accepts $ORIGIN literal)
172+ patchelf --set-rpath '$ORIGIN/../lib' "$APPDIR"/usr/bin/krview
173+
174+ # AppRun that sets LD_LIBRARY_PATH and runs the binary
175+ cat > "$APPDIR"/AppRun <<'EOF'
176+ # !/bin/sh
177+ HERE="$(dirname "$(readlink -f "${0}")")"
178+ export LD_LIBRARY_PATH="$HERE/usr/lib:${LD_LIBRARY_PATH-}"
179+ exec "$HERE/usr/bin/krview" "$@"
180+ EOF
181+ chmod +x "$APPDIR"/AppRun
182+
183+ # Minimal desktop entry
184+ cat > "$APPDIR"/usr/share/applications/krview.desktop <<'EOF'
185+ [Desktop Entry]
186+ Type=Application
187+ Name=krview
188+ Exec=krview
189+ Icon=krview
190+ Categories=Utility;
191+ EOF
192+
193+ # Copy icon (make sure assets/pictures/icon.png exists)
194+ cp assets/pictures/icon.png "$APPDIR"/usr/share/icons/hicolor/256x256/apps/krview.png || true
195+
196+ # Download appimagetool (stable or continuous — choose what you prefer)
197+ wget -q -O appimagetool-x86_64.AppImage \
198+ https://github.com/AppImage/AppImageKit/releases/download/continuous/appimagetool-x86_64.AppImage
199+ chmod +x appimagetool-x86_64.AppImage
142200
143- tar -czf ${{ matrix.artifact }} krview
201+ ./appimagetool-x86_64.AppImage "$APPDIR"
202+
203+ # Move produced AppImage into dist with predictable name
144204 mkdir -p dist
145- mv ${{ matrix.artifact }} dist/${{ matrix.artifact }}
205+ mv -v *.AppImage "dist/${ARTIFACT_NAME}"
206+
146207
147- - name : Package (macOS)
208+ - name : Package (macOS) - .app bundle
148209 if : matrix.os == 'macos-latest'
149210 shell : bash
150211 run : |
151- mkdir -p krview/assets/fonts
152- mkdir -p krview/assets/screenshots
212+ set -euo pipefail
213+ APP_NAME=krview
214+ APP_BUNDLE="${APP_NAME}.app"
215+ CONTENTS="$APP_BUNDLE/Contents"
216+ MACOS_DIR="$CONTENTS/MacOS"
217+ RESOURCES_DIR="$CONTENTS/Resources"
218+ FRAMEWORKS_DIR="$CONTENTS/Frameworks"
219+ ARTIFACT=${{ matrix.artifact }}
220+
221+ # Prepare bundle layout
222+ rm -rf "$APP_BUNDLE"
223+ mkdir -p "$MACOS_DIR" "$RESOURCES_DIR/assets/fonts" "$RESOURCES_DIR/assets/screenshots" "$FRAMEWORKS_DIR"
224+
225+ # Copy binary and assets
226+ cp zig-out/bin/krview "$MACOS_DIR/$APP_NAME"
227+ chmod +x "$MACOS_DIR/$APP_NAME"
228+ cp -v assets/fonts/Terminus.ttf "$RESOURCES_DIR/assets/fonts/" || true
229+ cp -v assets/fonts/OFL.TXT "$RESOURCES_DIR/assets/fonts/" || true
230+ cp -v assets/pictures/icon.png "$RESOURCES_DIR/icon.png" || true
231+
232+ # Minimal Info.plist
233+ cat > "$CONTENTS/Info.plist" <<'EOF'
234+ <?xml version="1.0" encoding="UTF-8"?>
235+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
236+ <plist version="1.0">
237+ <dict>
238+ <key>CFBundleName</key><string>krview</string>
239+ <key>CFBundleDisplayName</key><string>krview</string>
240+ <key>CFBundleIdentifier</key><string>com.example.krview</string>
241+ <key>CFBundleExecutable</key><string>krview</string>
242+ <key>CFBundleVersion</key><string>1.0</string>
243+ <key>CFBundlePackageType</key><string>APPL</string>
244+ <key>LSMinimumSystemVersion</key><string>10.13</string>
245+ </dict>
246+ </plist>
247+ EOF
248+
249+ # Find non-system dylib/framework dependencies and copy them into Contents/Frameworks
250+ # Exclude /usr/lib and /System libraries (these are system-provided).
251+ otool -L zig-out/bin/krview | sed '1d' | awk '{print $1}' | sort -u | while read -r dep; do
252+ # skip empty or system libs
253+ if [ -z "$dep" ]; then continue; fi
254+ case "$dep" in
255+ /usr/lib/*|/System/*)
256+ # system lib, skip
257+ continue
258+ ;;
259+ esac
260+
261+ # If dependency is inside a .framework path, copy whole framework
262+ if echo "$dep" | grep -qE '\.framework/'; then
263+ # extract framework root (e.g. /opt/homebrew/Cellar/sdl2/2.0.16/Frameworks/SDL2.framework)
264+ FROOT=$(echo "$dep" | sed -E 's@(.*/[^/]+\.framework)/.*@\1@')
265+ FN=$(basename "$FROOT")
266+ if [ ! -d "$FRAMEWORKS_DIR/$FN" ]; then
267+ echo "Copying framework $FROOT -> $FRAMEWORKS_DIR/$FN"
268+ cp -R "$FROOT" "$FRAMEWORKS_DIR/$FN"
269+ fi
270+ # change binary's reference to point to bundled framework
271+ install_name_tool -change "$dep" "@executable_path/../Frameworks/$FN/$(basename "$dep")" "$MACOS_DIR/$APP_NAME" || true
272+ else
273+ # normal dylib: copy into Frameworks and rewrite binary reference
274+ LIBNAME=$(basename "$dep")
275+ if [ ! -f "$FRAMEWORKS_DIR/$LIBNAME" ]; then
276+ echo "Copying dylib $dep -> $FRAMEWORKS_DIR/$LIBNAME"
277+ cp -v "$dep" "$FRAMEWORKS_DIR/$LIBNAME" || true
278+ fi
279+ install_name_tool -change "$dep" "@executable_path/../Frameworks/$LIBNAME" "$MACOS_DIR/$APP_NAME" || true
280+ fi
281+ done
282+
283+ # Ensure binary will look into our Frameworks folder at runtime
284+ install_name_tool -add_rpath "@executable_path/../Frameworks" "$MACOS_DIR/$APP_NAME" || true
285+
286+ # For copied dylibs: set their id to @rpath/<name> and fix internal references to each other
287+ find "$FRAMEWORKS_DIR" -type f \( -name "*.dylib" -o -name "*.so" \) -print0 | while IFS= read -r -d '' LIB; do
288+ BASENAME=$(basename "$LIB")
289+ echo "Setting id for $LIB -> @rpath/$BASENAME"
290+ install_name_tool -id "@rpath/$BASENAME" "$LIB" || true
291+
292+ # fix dependencies inside the dylib to point to @rpath if they are in our Frameworks folder
293+ otool -L "$LIB" | sed '1d' | awk '{print $1}' | while read -r sub; do
294+ case "$sub" in
295+ /usr/lib/*|/System/*)
296+ continue
297+ ;;
298+ *)
299+ SUBNAME=$(basename "$sub")
300+ if [ -f "$FRAMEWORKS_DIR/$SUBNAME" ]; then
301+ install_name_tool -change "$sub" "@rpath/$SUBNAME" "$LIB" || true
302+ fi
303+ ;;
304+ esac
305+ done
306+ done
153307
154- cp zig-out/bin/krview krview/
155- cp assets/fonts/Terminus.ttf krview/assets/fonts/
156- cp assets/fonts/OFL.TXT krview/assets/fonts/
308+ # For copied frameworks: adjust binary references were handled above; some frameworks may contain inner dylibs
309+ # (best-effort; for complex frameworks further corrections might be necessary)
157310
158- tar -czf ${{ matrix. artifact }} krview
311+ # Create the tarball artifact containing the .app bundle
159312 mkdir -p dist
160- mv ${{ matrix.artifact }} dist/${{ matrix.artifact }}
313+ tar -czf "$ARTIFACT" "$APP_BUNDLE"
314+ mv -v "$ARTIFACT" dist/"$ARTIFACT"
161315
162316
163317 - name : Upload artifact
0 commit comments