diff --git a/.github/workflows/build_all.yml b/.github/workflows/build_all.yml index 8812fbd174..758e7d6c1c 100644 --- a/.github/workflows/build_all.yml +++ b/.github/workflows/build_all.yml @@ -55,7 +55,7 @@ jobs: if: ${{ !cancelled() && (github.event_name != 'schedule' || github.repository == 'OrcaSlicer/OrcaSlicer') }} uses: ./.github/workflows/build_check_cache.yml with: - os: ${{ vars.SELF_HOSTED && 'orca-lnx-server' || 'ubuntu-24.04' }} + os: ${{ vars.SELF_HOSTED && 'orca-lnx-server' || 'ubuntu-22.04' }} build-deps-only: ${{ inputs.build-deps-only || false }} secrets: inherit build_windows: @@ -95,7 +95,7 @@ jobs: secrets: inherit unit_tests: name: Unit Tests - runs-on: ${{ vars.SELF_HOSTED && 'orca-lnx-server' || 'ubuntu-24.04' }} + runs-on: ${{ vars.SELF_HOSTED && 'orca-lnx-server' || 'ubuntu-22.04' }} needs: build_linux if: ${{ !cancelled() && success() }} steps: diff --git a/.github/workflows/build_orca.yml b/.github/workflows/build_orca.yml index cb28b23311..797088c9ce 100644 --- a/.github/workflows/build_orca.yml +++ b/.github/workflows/build_orca.yml @@ -26,8 +26,8 @@ jobs: date: ver: ver_pure: - ubuntu-ver: '2404' - ubuntu-ver-str: '_Ubuntu2404' + ubuntu-ver: '2204' + ubuntu-ver-str: '_Ubuntu2204' ORCA_UPDATER_SIG_KEY: ${{ secrets.ORCA_UPDATER_SIG_KEY }} steps: @@ -382,6 +382,7 @@ jobs: shell: bash run: | ./build_linux.sh -istrlL + ./scripts/check_appimage_libs.sh ./build/package ./build/package/bin/orca-slicer mv -n ./build/OrcaSlicer_Linux_V${{ env.ver_pure }}.AppImage ./build/OrcaSlicer_Linux_AppImage${{ env.ubuntu-ver-str }}_${{ env.ver }}.AppImage chmod +x ./build/OrcaSlicer_Linux_AppImage${{ env.ubuntu-ver-str }}_${{ env.ver }}.AppImage tar -cvpf build_tests.tar build/tests diff --git a/deps/Boost/Boost.cmake b/deps/Boost/Boost.cmake index a374004f97..d20f6f97ad 100644 --- a/deps/Boost/Boost.cmake +++ b/deps/Boost/Boost.cmake @@ -18,6 +18,7 @@ orcaslicer_add_cmake_project(Boost -DBOOST_EXCLUDE_LIBRARIES:STRING=contract|fiber|numpy|stacktrace|wave|test -DBOOST_LOCALE_ENABLE_ICU:BOOL=OFF # do not link to libicu, breaks compatibility between distros -DBUILD_TESTING:BOOL=OFF + -DBOOST_IOSTREAMS_ENABLE_BZIP2:BOOL=OFF # avoid libbz2 soname differences in AppImage builds -DBOOST_IOSTREAMS_ENABLE_ZSTD:BOOL=OFF "${_context_abi_line}" "${_context_arch_line}" diff --git a/scripts/appimage_lib_policy.sh b/scripts/appimage_lib_policy.sh new file mode 100755 index 0000000000..972a9bf7b3 --- /dev/null +++ b/scripts/appimage_lib_policy.sh @@ -0,0 +1,52 @@ +#!/usr/bin/env bash + +# Libraries that are safer to resolve from the host than bundle into the AppImage. +# Keep this list focused on the glibc/runtime loader and host-specific graphics/audio stacks. +appimage_is_host_library() { + local lib_name + lib_name="$(basename "$1")" + + case "$lib_name" in + linux-vdso.so.*|linux-gate.so.*|ld-linux*.so*|ld64.so*|ld-musl-*.so*|libc.so*|libpthread.so*|libm.so*|libdl.so*|librt.so*|libresolv.so*|libutil.so*|libanl.so*|libnsl.so*|libBrokenLocale.so*|libcrypt.so*|libnss_*.so*|\ + libGL.so*|libOpenGL.so*|libGLX*.so*|libGLU.so*|libEGL.so*|libGLES*.so*|libGLdispatch.so*|libdrm.so*|libdrm_*.so*|libgbm.so*|libwayland-*.so*|libxcb*.so*|libX11.so*|libX11-xcb.so*|libXau.so*|libXdmcp.so*|libXext.so*|libXdamage.so*|libXfixes.so*|libXcomposite.so*|libXrender.so*|libXrandr.so*|libXcursor.so*|libXi.so*|libXinerama.so*|libxshmfence.so*|libxkbcommon.so*|libxkbcommon-x11.so*|libSM.so*|libICE.so*|libudev.so*|libasound.so*|libpulse.so*|libpulsecommon*.so*|libjack.so*|libpipewire-*.so*|libvulkan.so*|libva.so*|libva-*.so*|\ + libgtk-*.so*|libgdk-*.so*|libpango*.so*|libatk*.so*|libatk-bridge-*.so*|libatspi.so*|libcairo*.so*|libgdk_pixbuf-*.so*|libgio-2.0.so*|libgmodule-2.0.so*|libgobject-2.0.so*|libglib-2.0.so*|\ + libgstreamer-1.0.so*|libgst*.so*|libsoup-*.so*|libwebkit2gtk-*.so*|libjavascriptcoregtk-*.so*|libsecret-1.so*|libmanette-0.2.so*|libenchant-2.so*|libhyphen.so*|libtasn1.so*|\ + libfontconfig.so*|libfreetype.so*|libharfbuzz*.so*|libfribidi.so*|libgraphite2.so*|libthai.so*|libdatrie.so*|libepoxy.so*|libpixman-1.so*|\ + libstdc++.so*|libgcc_s.so*|libatomic.so*|libdbus-1.so*|libuuid.so*|libffi.so*|libselinux.so*|libmount.so*|libblkid.so*|libpcre2-*.so*|libsystemd.so*|libcap.so*|libseccomp.so*|\ + libexpat.so*|libz.so*|liblzma.so*|libdeflate.so*|libzstd.so*|libpng*.so*|libjpeg.so*|libtiff.so*|libwebp*.so*|libwoff2*.so*|libjbig.so*|libLerc.so*|liblcms2.so*|libjxl*.so*|libhwy.so*|libsharpyuv.so*|\ + libxml2.so*|libxslt.so*|libsqlite3.so*|libicu*.so*|libpsl.so*|libnghttp2.so*|libbrotli*.so*|libidn2.so*|libunistring.so*|libgcrypt.so*|libgpg-error.so*|\ + libgssapi_krb5.so*|libkrb5.so*|libkrb5support.so*|libk5crypto.so*|libcom_err.so*|libkeyutils.so*|liborc-0.4.so*|libgudev-1.0.so*) + return 0 + ;; + *) + return 1 + ;; + esac +} + +appimage_is_elf_file() { + file -b "$1" 2>/dev/null | grep -q '^ELF ' +} + +appimage_list_direct_dependencies() { + local target="$1" + local line dep + + while IFS= read -r line; do + if [[ "$line" == *"=> not found"* ]]; then + echo "MISSING:${line%% *}" + continue + fi + + dep="" + if [[ "$line" == *"=>"* ]]; then + dep="$(printf '%s\n' "$line" | sed -n 's/.*=> \(\/[^ ]*\).*/\1/p')" + elif [[ "$line" =~ ^[[:space:]]/ ]]; then + dep="$(printf '%s\n' "$line" | awk '{print $1}')" + fi + + if [[ -n "$dep" ]]; then + echo "$dep" + fi + done < <(ldd "$target" 2>/dev/null || true) +} diff --git a/scripts/check_appimage_libs.sh b/scripts/check_appimage_libs.sh new file mode 100755 index 0000000000..d6f22a73b3 --- /dev/null +++ b/scripts/check_appimage_libs.sh @@ -0,0 +1,99 @@ +#!/usr/bin/env bash + +set -euo pipefail + +SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)" +# shellcheck source=/dev/null +source "${SCRIPT_DIR}/appimage_lib_policy.sh" + +usage() { + echo "Usage: $0 [entrypoint]" +} + +if [[ $# -lt 1 || $# -gt 2 ]]; then + usage + exit 1 +fi + +APPDIR="$1" +ENTRYPOINT="${2:-}" + +if [[ ! -d "$APPDIR" ]]; then + echo "Error: AppDir does not exist: $APPDIR" + exit 1 +fi + +APPDIR="$(cd -- "$APPDIR" && pwd)" + +if [[ -n "$ENTRYPOINT" ]]; then + if [[ ! -e "$ENTRYPOINT" ]]; then + echo "Error: entrypoint does not exist: $ENTRYPOINT" + exit 1 + fi + ENTRYPOINT="$(cd -- "$(dirname -- "$ENTRYPOINT")" && pwd)/$(basename -- "$ENTRYPOINT")" +fi + +declare -a lib_paths=( + "$APPDIR/lib/orca-runtime" + "$APPDIR/lib" + "$APPDIR/bin" +) + +for candidate in \ + "$APPDIR/lib/gstreamer-1.0" \ + "$APPDIR/lib/gio/modules" \ + "$APPDIR/lib/gdk-pixbuf-2.0/2.10.0/loaders"; do + if [[ -d "$candidate" ]]; then + lib_paths+=("$candidate") + fi +done + +audit_ld_library_path="$(IFS=:; printf '%s' "${lib_paths[*]}")" + +declare -a targets=() +declare -A seen_unresolved=() +declare -A seen_host=() + +if [[ -n "$ENTRYPOINT" ]]; then + targets+=("$ENTRYPOINT") +fi + +while IFS= read -r -d '' file; do + if appimage_is_elf_file "$file"; then + targets+=("$file") + fi +done < <(find "$APPDIR" -type f -print0) + +for target in "${targets[@]}"; do + while IFS= read -r dep; do + if [[ "$dep" == MISSING:* ]]; then + seen_unresolved["$target -> ${dep#MISSING:}"]=1 + continue + fi + + dep="$(readlink -f "$dep" 2>/dev/null || printf '%s' "$dep")" + if [[ "$dep" == "$APPDIR"* ]]; then + continue + fi + + if appimage_is_host_library "$dep"; then + continue + fi + + seen_host["$target -> $dep"]=1 + done < <(LD_LIBRARY_PATH="$audit_ld_library_path${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}" appimage_list_direct_dependencies "$target") +done + +if (( ${#seen_unresolved[@]} > 0 )); then + echo "AppImage dependency audit failed: unresolved runtime libraries detected" + printf '%s\n' "${!seen_unresolved[@]}" | LC_ALL=C sort + exit 1 +fi + +if (( ${#seen_host[@]} > 0 )); then + echo "AppImage dependency audit failed: unexpected host libraries are still required" + printf '%s\n' "${!seen_host[@]}" | LC_ALL=C sort + exit 1 +fi + +echo "AppImage dependency audit passed: $APPDIR" diff --git a/src/dev-utils/platform/unix/build_appimage.sh.in b/src/dev-utils/platform/unix/build_appimage.sh.in index 56fe084cff..2384560bb8 100644 --- a/src/dev-utils/platform/unix/build_appimage.sh.in +++ b/src/dev-utils/platform/unix/build_appimage.sh.in @@ -1,4 +1,4 @@ -#!/bin/sh +#!/usr/bin/env bash APPIMAGETOOLURL="https://github.com/AppImage/appimagetool/releases/download/continuous/appimagetool-$(uname -m).AppImage" @@ -11,7 +11,6 @@ if [ -f /.dockerenv ] ; then # Only run if inside of a Docker Container sed '0,/AI\x02/{s|AI\x02|\x00\x00\x00|}' -i ../appimagetool.AppImage fi -sed -i -e 's#/usr#././#g' bin/@SLIC3R_APP_CMD@ mv @SLIC3R_APP_CMD@ AppRun chmod +x AppRun @@ -28,13 +27,29 @@ Categories=Utility; MimeType=model/stl;application/vnd.ms-3mfdocument;application/prs.wavefront-obj;application/x-amf; EOF +mkdir -p usr/share/metainfo +cat < usr/share/metainfo/@SLIC3R_APP_KEY@.appdata.xml + + + @SLIC3R_APP_KEY@.desktop + @SLIC3R_APP_KEY@ + Open-source 3D slicer for FFF and SLA printers + CC0-1.0 + AGPL-3.0-or-later + +

OrcaSlicer prepares 3D models for printing, including printer profile management, preview tooling, and network-connected device workflows.

+
+ @SLIC3R_APP_KEY@.desktop +
+EOF + export ARCH=$(uname -m) if [ -f /.dockerenv ] ; then # Only run if inside of a Docker Container - ../appimagetool.AppImage --appimage-extract-and-run . $([ ! -z "${container}" ] && echo '--appimage-extract-and-run') + ../appimagetool.AppImage --appimage-extract-and-run . $([ -n "${container}" ] && echo '--appimage-extract-and-run') else - ../appimagetool.AppImage . $([ ! -z "${container}" ] && echo '--appimage-extract-and-run') + ../appimagetool.AppImage . $([ -n "${container}" ] && echo '--appimage-extract-and-run') fi mv @SLIC3R_APP_KEY@-$(uname -m).AppImage ${APP_IMAGE} diff --git a/src/dev-utils/platform/unix/build_linux_image.sh.in b/src/dev-utils/platform/unix/build_linux_image.sh.in index 810701dccc..8b29ec3014 100755 --- a/src/dev-utils/platform/unix/build_linux_image.sh.in +++ b/src/dev-utils/platform/unix/build_linux_image.sh.in @@ -3,10 +3,25 @@ # Despite the script name, this doesn't necessarily create an "image"; # it sets up a compatibility script wrapper for the binary and arranges some resources. +set -e + export ROOT=$(echo $ROOT | grep . || pwd) -export NCORES=`nproc --all` +export NCORES=$(nproc --all) CONFIG=Release +SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)" +REPO_ROOT="$(cd -- "${SCRIPT_DIR}/../.." && pwd)" +POLICY_FILE="${REPO_ROOT}/scripts/appimage_lib_policy.sh" +CHECK_SCRIPT="${REPO_ROOT}/scripts/check_appimage_libs.sh" + +if [ ! -f "${POLICY_FILE}" ]; then + echo "Error: missing AppImage helper ${POLICY_FILE}" + exit 1 +fi + +# shellcheck source=/dev/null +source "${POLICY_FILE}" + while getopts ":ihR:" opt; do case ${opt} in i ) @@ -23,35 +38,324 @@ while getopts ":ihR:" opt; do esac done -echo -n "[9/9] Generating Linux app..." -#{ - # create directory and copy into it - if [ -d "package" ]; then - rm -rf package - fi - mkdir -p package/bin +copy_directory_if_present() { + local src_dir="$1" + local dst_dir="$2" + + if [ -n "$src_dir" ] && [ -d "$src_dir" ]; then + mkdir -p "$dst_dir" + cp -a "$src_dir"/. "$dst_dir"/ + fi +} + +find_pkg_config_dir() { + local variable="$1" + shift + + local module + for module in "$@"; do + if pkg-config --exists "$module" 2>/dev/null; then + pkg-config --variable="$variable" "$module" 2>/dev/null || true + return 0 + fi + done + + return 1 +} + +find_first_existing_file() { + local path + for path in "$@"; do + if [ -f "$path" ]; then + printf '%s\n' "$path" + return 0 + fi + done + + return 1 +} + +copy_shared_object_to_dir() { + local src="$1" + local dst_dir="$2" + local src_real dst_name soname + + src_real="$(readlink -f "$src")" + dst_name="$(basename "$src_real")" + mkdir -p "$dst_dir" + cp -fL "$src_real" "$dst_dir/$dst_name" + + if [ -L "$src" ]; then + ln -snf "$dst_name" "$dst_dir/$(basename "$src")" + fi + + soname="$(objdump -p "$src_real" 2>/dev/null | awk '$1 == "SONAME" { print $2; exit }')" + if [ -n "$soname" ] && [ "$soname" != "$dst_name" ]; then + ln -snf "$dst_name" "$dst_dir/$soname" + fi +} + +bundle_dependency_closure() { + local dst_dir="$1" + shift + + local -a queue=("$@") + local target dep dep_real copied_path + declare -A seen=() + + while [ ${#queue[@]} -gt 0 ]; do + target="${queue[0]}" + queue=("${queue[@]:1}") + + if [ ! -e "$target" ] || ! appimage_is_elf_file "$target"; then + continue + fi + + while IFS= read -r dep; do + if [[ "$dep" == MISSING:* ]]; then + echo "Error: missing runtime dependency ${dep#MISSING:} while bundling $target" + exit 1 + fi + + dep_real="$(readlink -f "$dep" 2>/dev/null || printf '%s' "$dep")" + if appimage_is_host_library "$dep_real"; then + continue + fi + + if [ -n "${seen[$dep_real]}" ]; then + continue + fi + + seen[$dep_real]=1 + copy_shared_object_to_dir "$dep" "$dst_dir" + copied_path="$dst_dir/$(basename "$dep_real")" + if [ -e "$copied_path" ]; then + queue+=("$copied_path") + fi + done < <(appimage_list_direct_dependencies "$target") + done +} + +echo -n "[9/9] Generating Linux app..." +# { + if [ -d "package" ]; then + rm -rf package + fi + + APPDIR="package" + BIN_DIR="$APPDIR/bin" + LIB_DIR="$APPDIR/lib" + PRIVATE_LIB_DIR="$LIB_DIR/orca-runtime" + SHARE_DIR="$APPDIR/share" + LIBEXEC_DIR="$APPDIR/libexec" + BUNDLE_DESKTOP_STACK="${ORCA_BUNDLE_DESKTOP_STACK:-0}" + GST_PLUGIN_DIR="$LIB_DIR/gstreamer-1.0" + GIO_MODULE_DIR="$LIB_DIR/gio/modules" + GDK_PIXBUF_DIR="$LIB_DIR/gdk-pixbuf-2.0/2.10.0/loaders" + + mkdir -p "$BIN_DIR" "$LIB_DIR" "$PRIVATE_LIB_DIR" "$SHARE_DIR" "$LIBEXEC_DIR" + if [ "$BUNDLE_DESKTOP_STACK" = "1" ]; then + mkdir -p "$GST_PLUGIN_DIR" "$GIO_MODULE_DIR" "$GDK_PIXBUF_DIR" + fi + + cp -Rf ../resources "$APPDIR/resources" - # Copy Resources - cp -Rf ../resources package/resources - - # Find and hard link the @SLIC3R_APP_CMD@ binary from Multi-Config build ORIGINAL_BINARY_LOCATION="" if [ -f "src/${CONFIG}/@SLIC3R_APP_CMD@" ]; then - ORIGINAL_BINARY_LOCATION="$(realpath "src/${CONFIG}/@SLIC3R_APP_CMD@")" + ORIGINAL_BINARY_LOCATION="$(realpath "src/${CONFIG}/@SLIC3R_APP_CMD@")" elif [ -f "src/@SLIC3R_APP_CMD@" ]; then - # Fallback for single-config builds ORIGINAL_BINARY_LOCATION="$(realpath "src/@SLIC3R_APP_CMD@")" else echo "Error: @SLIC3R_APP_CMD@ binary not found in any configuration directory" exit 1 fi - cp -fl "${ORIGINAL_BINARY_LOCATION}" package/bin/@SLIC3R_APP_CMD@ + cp -fl "${ORIGINAL_BINARY_LOCATION}" "$BIN_DIR/@SLIC3R_APP_CMD@" + + if [ "$BUNDLE_DESKTOP_STACK" = "1" ]; then + GSTREAMER_PLUGIN_SOURCE_DIR="$(find_pkg_config_dir pluginsdir gstreamer-1.0 || true)" + if [ -z "$GSTREAMER_PLUGIN_SOURCE_DIR" ]; then + GSTREAMER_PLUGIN_SOURCE_DIR="$(find /usr/lib /usr/lib64 -maxdepth 4 -type d -name gstreamer-1.0 2>/dev/null | head -n1)" + fi + copy_directory_if_present "$GSTREAMER_PLUGIN_SOURCE_DIR" "$GST_PLUGIN_DIR" + + GIO_MODULE_SOURCE_DIR="$(find_pkg_config_dir giomoduledir gio-2.0 || true)" + if [ -z "$GIO_MODULE_SOURCE_DIR" ]; then + GIO_MODULE_SOURCE_DIR="$(find /usr/lib /usr/lib64 -maxdepth 5 -type d -path '*/gio/modules' 2>/dev/null | head -n1)" + fi + copy_directory_if_present "$GIO_MODULE_SOURCE_DIR" "$GIO_MODULE_DIR" + + GDK_PIXBUF_SOURCE_DIR="$(find_pkg_config_dir gdk_pixbuf_moduledir gdk-pixbuf-2.0 || true)" + if [ -z "$GDK_PIXBUF_SOURCE_DIR" ]; then + GDK_PIXBUF_SOURCE_DIR="$(find /usr/lib /usr/lib64 -maxdepth 6 -type d -path '*/gdk-pixbuf-2.0/*/loaders' 2>/dev/null | head -n1)" + fi + copy_directory_if_present "$GDK_PIXBUF_SOURCE_DIR" "$GDK_PIXBUF_DIR" + + GLIB_SCHEMAS_SOURCE_DIR="$(find_pkg_config_dir schemasdir gio-2.0 || true)" + if [ -z "$GLIB_SCHEMAS_SOURCE_DIR" ]; then + GLIB_SCHEMAS_SOURCE_DIR="/usr/share/glib-2.0/schemas" + fi + copy_directory_if_present "$GLIB_SCHEMAS_SOURCE_DIR" "$SHARE_DIR/glib-2.0/schemas" + if [ -d "$SHARE_DIR/glib-2.0/schemas" ] && command -v glib-compile-schemas >/dev/null 2>&1; then + glib-compile-schemas "$SHARE_DIR/glib-2.0/schemas" + fi + + # Distros disagree on where helper executables live: pkg-config may point to libexec, + # Debian/Ubuntu often ship the scanner under a multiarch libdir, and RPM distros may use lib64. + GST_PLUGIN_SCANNER_SOURCE="$(find_first_existing_file \ + "$(find_pkg_config_dir pluginscannerdir gstreamer-1.0 || true)/gst-plugin-scanner" \ + /usr/libexec/gstreamer-1.0/gst-plugin-scanner \ + /usr/lib/gstreamer1.0/gstreamer-1.0/gst-plugin-scanner \ + /usr/lib/*/gstreamer1.0/gstreamer-1.0/gst-plugin-scanner \ + /usr/lib64/gstreamer1.0/gstreamer-1.0/gst-plugin-scanner)" || true + if [ -n "$GST_PLUGIN_SCANNER_SOURCE" ]; then + mkdir -p "$LIBEXEC_DIR/gstreamer-1.0" + cp -fL "$GST_PLUGIN_SCANNER_SOURCE" "$LIBEXEC_DIR/gstreamer-1.0/gst-plugin-scanner" + fi + + # Prefer the canonical pkg-config-reported helper path, but keep PATH-based fallbacks + # for distros exposing gdk-pixbuf-query-loaders or gdk-pixbuf-query-loaders-64 directly. + GDK_PIXBUF_QUERY_LOADERS_SOURCE="$(find_first_existing_file \ + "$(pkg-config --variable=gdk_pixbuf_query_loaders gdk-pixbuf-2.0 2>/dev/null || true)" \ + "$(command -v gdk-pixbuf-query-loaders 2>/dev/null || true)" \ + "$(command -v gdk-pixbuf-query-loaders-64 2>/dev/null || true)")" || true + if [ -n "$GDK_PIXBUF_QUERY_LOADERS_SOURCE" ]; then + cp -fL "$GDK_PIXBUF_QUERY_LOADERS_SOURCE" "$LIBEXEC_DIR/gdk-pixbuf-query-loaders" + fi + fi + + # WebKitGTK helper binaries are resolved from distro-specific absolute paths + # baked into libwebkit2gtk. Bundling Ubuntu's WebKitGTK inside an AppImage + # built with -g makes those helper paths unusable on Fedora and vice versa, + # so rely on the host WebKitGTK runtime instead of copying the helper stack. + + mapfile -d '' BUNDLE_TARGETS < <(find "$BIN_DIR" "$LIB_DIR" "$LIBEXEC_DIR" -type f -print0 2>/dev/null) + bundle_dependency_closure "$PRIVATE_LIB_DIR" "${BUNDLE_TARGETS[@]}" + +cat << EOF >"$LIBEXEC_DIR/@SLIC3R_APP_CMD@-env" +#!/bin/sh +set -e +SELF_DIR=\$(CDPATH= cd -- "\$(dirname -- "\$0")" && pwd) +APPDIR="\${APPDIR:-\$(CDPATH= cd -- "\$SELF_DIR/.." && pwd)}" +USE_BUNDLED_WEBKITGTK_STACK=0 +if [ -e "\$APPDIR/lib/libwebkit2gtk-4.1.so.0" ] || [ -e "\$APPDIR/lib/libwebkit2gtk-4.0.so.0" ]; then + USE_BUNDLED_WEBKITGTK_STACK=1 +fi + +export APPDIR +PRIVATE_LIB_DIR="\$APPDIR/lib/orca-runtime" +if [ -d "\$PRIVATE_LIB_DIR" ]; then + export LD_LIBRARY_PATH="\$PRIVATE_LIB_DIR:\$APPDIR/bin\${LD_LIBRARY_PATH:+:\$LD_LIBRARY_PATH}" +else + export LD_LIBRARY_PATH="\$APPDIR/bin\${LD_LIBRARY_PATH:+:\$LD_LIBRARY_PATH}" +fi + +has_host_runtime_library() { + local lib_name path + + if command -v ldconfig >/dev/null 2>&1; then + if ldconfig -p 2>/dev/null | grep -Fq " \$lib_name"; then + return 0 + fi + fi + + for path in \ + /lib /lib64 /usr/lib /usr/lib64 \ + /usr/lib/* /usr/lib64/* /lib/* /lib64/*; do + if [ -e "\$path/\$lib_name" ]; then + return 0 + fi + done + + return 1 +} + +target_missing_runtime_library() { + local target_bin="\$1" + local lib_name="\$2" + + if [ -z "\$target_bin" ] || [ ! -e "\$target_bin" ]; then + return 1 + fi + + if command -v ldd >/dev/null 2>&1; then + if ldd "\$target_bin" 2>/dev/null | grep -Fq "\$lib_name => not found"; then + return 0 + fi + fi + + return 1 +} + +TARGET_BIN="\$1" + +if target_missing_runtime_library "\$TARGET_BIN" "libOpenGL.so.0" || ! has_host_runtime_library "libOpenGL.so.0"; then + echo "Error: missing host OpenGL runtime library libOpenGL.so.0." >&2 + echo "On Ubuntu/Pop!_OS/Debian, install: libopengl0 and libglu1-mesa" >&2 + echo "On Arch/CachyOS, install: libglvnd" >&2 + exit 1 +fi + +if [ "\$USE_BUNDLED_WEBKITGTK_STACK" = "1" ]; then + export LD_LIBRARY_PATH="\$APPDIR/lib\${LD_LIBRARY_PATH:+:\$LD_LIBRARY_PATH}" + export GST_PLUGIN_SYSTEM_PATH="" + export GST_PLUGIN_PATH="\$APPDIR/lib/gstreamer-1.0\${GST_PLUGIN_PATH:+:\$GST_PLUGIN_PATH}" + export GIO_EXTRA_MODULES="\$APPDIR/lib/gio/modules\${GIO_EXTRA_MODULES:+:\$GIO_EXTRA_MODULES}" + export XDG_DATA_DIRS="\$APPDIR/share\${XDG_DATA_DIRS:+:\$XDG_DATA_DIRS}" + + if [ -d "\$APPDIR/share/glib-2.0/schemas" ]; then + export GSETTINGS_SCHEMA_DIR="\$APPDIR/share/glib-2.0/schemas" + fi + + if [ -x "\$APPDIR/libexec/gstreamer-1.0/gst-plugin-scanner" ]; then + export GST_PLUGIN_SCANNER="\$APPDIR/libexec/gstreamer-1.0/gst-plugin-scanner" + fi + + if [ -d "\$APPDIR/lib/gdk-pixbuf-2.0/2.10.0/loaders" ]; then + export GDK_PIXBUF_MODULEDIR="\$APPDIR/lib/gdk-pixbuf-2.0/2.10.0/loaders" + if [ -x "\$APPDIR/libexec/gdk-pixbuf-query-loaders" ]; then + PIXBUF_CACHE_DIR="\${XDG_CACHE_HOME:-\$HOME/.cache}/@SLIC3R_APP_KEY@" + PIXBUF_CACHE_FILE="\$PIXBUF_CACHE_DIR/gdk-pixbuf-loaders.cache" + mkdir -p "\$PIXBUF_CACHE_DIR" + if [ ! -s "\$PIXBUF_CACHE_FILE" ] || find "\$APPDIR/lib/gdk-pixbuf-2.0/2.10.0/loaders" -type f -newer "\$PIXBUF_CACHE_FILE" | grep -q .; then + "\$APPDIR/libexec/gdk-pixbuf-query-loaders" "\$APPDIR/lib/gdk-pixbuf-2.0/2.10.0/loaders"/*.so > "\$PIXBUF_CACHE_FILE" 2>/dev/null || true + fi + if [ -s "\$PIXBUF_CACHE_FILE" ]; then + export GDK_PIXBUF_MODULE_FILE="\$PIXBUF_CACHE_FILE" + fi + fi + fi + + if [ -d "\$APPDIR/lib/webkit2gtk-4.1" ]; then + export WEBKIT_EXEC_PATH="\$APPDIR/lib/webkit2gtk-4.1" + elif [ -d "\$APPDIR/lib/webkit2gtk-4.0" ]; then + export WEBKIT_EXEC_PATH="\$APPDIR/lib/webkit2gtk-4.0" + fi + + if [ -d "\$APPDIR/lib/webkit2gtk-4.1/injected-bundle" ]; then + export WEBKIT_INJECTED_BUNDLE_PATH="\$APPDIR/lib/webkit2gtk-4.1/injected-bundle" + elif [ -d "\$APPDIR/lib/webkit2gtk-4.0/injected-bundle" ]; then + export WEBKIT_INJECTED_BUNDLE_PATH="\$APPDIR/lib/webkit2gtk-4.0/injected-bundle" + fi +else + if target_missing_runtime_library "\$TARGET_BIN" "libwebkit2gtk-4.1.so.0" || \ + target_missing_runtime_library "\$TARGET_BIN" "libjavascriptcoregtk-4.1.so.0" || \ + ! has_host_runtime_library "libwebkit2gtk-4.1.so.0" || \ + ! has_host_runtime_library "libjavascriptcoregtk-4.1.so.0"; then + echo "Error: missing host WebKitGTK 4.1 runtime libraries." >&2 + echo "Install the distro package providing libwebkit2gtk-4.1.so.0 and libjavascriptcoregtk-4.1.so.0." >&2 + echo "On Arch/CachyOS, install: webkit2gtk-4.1" >&2 + exit 1 + fi +fi + +exec "\$@" +EOF + chmod ug+x "$LIBEXEC_DIR/@SLIC3R_APP_CMD@-env" - # create bin cat << EOF >@SLIC3R_APP_CMD@ #!/bin/bash -DIR=\$(readlink -f "\$0" | xargs dirname) -export LD_LIBRARY_PATH="\$DIR/bin:\$LD_LIBRARY_PATH" +DIR=\$(dirname "\$(readlink -f "\$0")") +export APPDIR="\${APPDIR:-\$DIR}" # FIXME: OrcaSlicer segfault workarounds # 1) OrcaSlicer will segfault on systems where locale info is not as expected (i.e. Holo-ISO arch-based distro) @@ -76,38 +380,33 @@ if [ "\$XDG_SESSION_TYPE" = "wayland" ] && [ "\$ZINK_DISABLE_OVERRIDE" != "1" ]; fi fi fi -exec "\$DIR/bin/@SLIC3R_APP_CMD@" "\$@" +exec "\$DIR/libexec/@SLIC3R_APP_CMD@-env" "\$DIR/bin/@SLIC3R_APP_CMD@" "\$@" EOF chmod ug+x @SLIC3R_APP_CMD@ - cp -fl @SLIC3R_APP_CMD@ package/@SLIC3R_APP_CMD@ - # Nothing uses this tar? Remove if nobody has complained and it's been a while since this comment added. - # Original commit was https://github.com/OrcaSlicer/OrcaSlicer/commit/f5a4862da52fc68f77b5201ddf330a9800d83228 - # and it doesn't appear to have been used there either. - #pushd package > /dev/null - #tar -cvf ../@SLIC3R_APP_KEY@.tar . &>/dev/null - #popd > /dev/null -#} &> $ROOT/Build.log # Capture all command output + cp -fl @SLIC3R_APP_CMD@ "$APPDIR/@SLIC3R_APP_CMD@" + + if [ -x "${CHECK_SCRIPT}" ] && [ -z "${ORCA_SKIP_APPIMAGE_AUDIT}" ]; then + "${CHECK_SCRIPT}" "$APPDIR" "$BIN_DIR/@SLIC3R_APP_CMD@" + fi +# } &> $ROOT/Build.log # Capture all command output echo "done" if [[ -n "$BUILD_IMAGE" ]] then echo -n "Creating Appimage for distribution..." -#{ - # AppImage script modifies files in place, so make a copy and clean up after. +# { rm -rf package_appimage cp -Rf package package_appimage pushd package_appimage > /dev/null chmod +x ../build_appimage.sh if ../build_appimage.sh; then - # Clean up on success. - popd > /dev/null - mv package_appimage/"@SLIC3R_APP_KEY@_Linux_V@SoftFever_VERSION@.AppImage" "@SLIC3R_APP_KEY@_Linux_V@SoftFever_VERSION@.AppImage" - rm -fR package_appimage + popd > /dev/null + mv package_appimage/"@SLIC3R_APP_KEY@_Linux_V@SoftFever_VERSION@.AppImage" "@SLIC3R_APP_KEY@_Linux_V@SoftFever_VERSION@.AppImage" + rm -fR package_appimage else - # Leave files on failure so you can debug. - popd > /dev/null + popd > /dev/null fi -#} &> $ROOT/Build.log # Capture all command output +# } &> $ROOT/Build.log # Capture all command output echo "done" fi