Сборка проекта Qt 6.9.2 на Ubuntu 24.04

Столкнулся с проблемой при сборке своего приложения для портабл версии. Написал скрипт для автоматизации сборки:

#!/bin/bash
set -e

# ==============================================
APP_NAME="flygenapp"
EXECUTABLE_PATH="/home/user/repos/flygenapp/flygenapp/build/Desktop_Qt_6_9_2-Release/flygenapp"
SOURCE_ROOT="/home/user/repos/flygenapp/flygenapp"
ICON_PATH="$SOURCE_ROOT/img/drone.png"
PACKAGE_DIR="portable_flygenapp"
OUTPUT_ARCHIVE="${APP_NAME}_portable_ubuntu.tar.gz"
QT_ROOT="/home/user/Qt/6.9.2/gcc_64"

if [ ! -f "$EXECUTABLE_PATH" ]; then
    echo "ERROR: bin not found: $EXECUTABLE_PATH"
    exit 1
fi

if ! command -v patchelf &> /dev/null; then
    echo "ERROR: patchelf not found!"
    exit 1
fi

# ==============================================
if [ -z "$QT_ROOT" ] || [ ! -d "$QT_ROOT/lib" ]; then
    QMAKE_PATH=$(which qmake6 2>/dev/null || which qmake 2>/dev/null)
    if [ -n "$QMAKE_PATH" ]; then
        QT_ROOT=$(dirname $(dirname $(readlink -f "$QMAKE_PATH")))
    fi
fi

if [ -z "$QT_ROOT" ] || [ ! -d "$QT_ROOT/lib" ]; then
    QT_PATH_FROM_BIN=$(strings "$EXECUTABLE_PATH" | grep -oE "/Qt/6\.9\.[0-9]+/gcc_64" | head -1)
    if [ -n "$QT_PATH_FROM_BIN" ] && [ -d "$QT_PATH_FROM_BIN/lib" ]; then
        QT_ROOT="$QT_PATH_FROM_BIN"
    fi
fi

if [ -z "$QT_ROOT" ] || [ ! -d "$QT_ROOT/lib" ]; then
    echo "ERROR: Qt 6.9.2 not found."
    exit 1
fi

echo "Using Qt: $QT_ROOT"

QT_PLUGINS_DIR="$QT_ROOT/plugins"
QT_QML_DIR="$QT_ROOT/qml"
QT_LIB_DIR="$QT_ROOT/lib"
QT_LIBEXEC_DIR="$QT_ROOT/libexec"
QT_RESOURCES_DIR="$QT_ROOT/resources"
QT_TRANSLATIONS_DIR="$QT_ROOT/translations"

if [ ! -f "$QT_PLUGINS_DIR/platforms/libqxcb.so" ]; then
    echo "ERROR: libqxcb.so not found in $QT_PLUGINS_DIR/platforms/"
    exit 1
fi

# ==============================================
GLX_PLUGIN_SRC="$QT_PLUGINS_DIR/platforms/libqxcb-glx-plugin.so"
if [ -f "$GLX_PLUGIN_SRC" ]; then
    cp "$GLX_PLUGIN_SRC" "$PACKAGE_DIR/plugins/platforms/"
    echo " + libqxcb-glx-plugin.so"
    USE_SOFTWARE_RENDERING=0
else
    echo "WARNING: software rendering"
    USE_SOFTWARE_RENDERING=1
fi

# ==============================================
QT_VERSION_IN_BINARY=$(strings "$EXECUTABLE_PATH" | grep -E "Qt_6\.9" | head -1 || echo "unknown")
echo "Version Qt in bin: $QT_VERSION_IN_BINARY"
if [[ "$QT_VERSION_IN_BINARY" != *"Qt_6.9"* ]]; then
    echo "ERROR: Waiting Qt 6.9, found: $QT_VERSION_IN_BINARY"
    exit 1
fi

# ==============================================
echo "Creating structure..."
rm -rf "$PACKAGE_DIR"
mkdir -p "$PACKAGE_DIR"/{bin,lib,libexec,resources,translations/qtwebengine_locales,plugins/{platforms,imageformats,styles},qml,share/icons/hicolor/256x256/apps,scripts}

cp "$EXECUTABLE_PATH" "$PACKAGE_DIR/bin/$APP_NAME"
chmod +x "$PACKAGE_DIR/bin/$APP_NAME"

# ==============================================
echo "Copying system files .so..."
ldd "$PACKAGE_DIR/bin/$APP_NAME" | grep "=>" | awk '{print $3}' | while read lib; do
    if [[ -f "$lib" && "$lib" != *"$QT_LIB_DIR"* && "$lib" != *"/lib/"*ld-linux* ]]; then
        cp -L "$lib" "$PACKAGE_DIR/lib/" 2>/dev/null || true
    fi
done

# ==============================================
echo "Copying Qt Libraries..."
cp "$QT_LIB_DIR"/libQt6*.so.6 "$PACKAGE_DIR/lib/" 2>/dev/null || true

echo "Copying libQt6XcbQpa.so.6"
if [ -f "$QT_LIB_DIR/libQt6XcbQpa.so.6" ]; then
    cp "$QT_LIB_DIR/libQt6XcbQpa.so.6" "$PACKAGE_DIR/lib/"
    echo " + libQt6XcbQpa.so.6"
else
    echo "ERROR: libQt6XcbQpa.so.6 not found! GUI will not start."
    exit 1
fi

cp "$QT_LIB_DIR/libQt6DBus.so.6" "$PACKAGE_DIR/lib/" 2>/dev/null || true


# ==============================================
echo "Copying ICU..."

ICU_REAL_LIBS=(
    "$QT_LIB_DIR/libicudata.so.73.2"
    "$QT_LIB_DIR/libicuuc.so.73.2"
    "$QT_LIB_DIR/libicui18n.so.73.2"
)

for real_lib in "${ICU_REAL_LIBS[@]}"; do
    if [ ! -f "$real_lib" ]; then
        echo "ERROR: $real_lib not found!"
        exit 1
    fi
    cp -a "$real_lib" "$PACKAGE_DIR/lib/"
    echo " + $(basename "$real_lib")"
done

ln -sf libicudata.so.73.2   "$PACKAGE_DIR/lib/libicudata.so.73"
ln -sf libicudata.so.73.2   "$PACKAGE_DIR/lib/libicudata.so"
ln -sf libicuuc.so.73.2     "$PACKAGE_DIR/lib/libicuuc.so.73"
ln -sf libicuuc.so.73.2     "$PACKAGE_DIR/lib/libicuuc.so"
ln -sf libicui18n.so.73.2   "$PACKAGE_DIR/lib/libicui18n.so.73"
ln -sf libicui18n.so.73.2   "$PACKAGE_DIR/lib/libicui18n.so"

# ==============================================
echo "Copying platform plugins..."
mkdir -p "$PACKAGE_DIR/plugins/platforms" "$PACKAGE_DIR/plugins/imageformats" "$PACKAGE_DIR/plugins/styles"

cp "$QT_PLUGINS_DIR/platforms/libqxcb.so" "$PACKAGE_DIR/plugins/platforms/"
cp "$QT_PLUGINS_DIR/platforms/libqminimal.so" "$PACKAGE_DIR/plugins/platforms/" 2>/dev/null || true
cp "$QT_PLUGINS_DIR/platforms/libqoffscreen.so" "$PACKAGE_DIR/plugins/platforms/" 2>/dev/null || true

GLX_PLUGIN="$QT_PLUGINS_DIR/platforms/libqxcb-glx-plugin.so"
cp "$GLX_PLUGIN" "$PACKAGE_DIR/plugins/platforms/"
echo " + libqxcb-glx-plugin.so"

cp "$QT_PLUGINS_DIR/imageformats/"*.so "$PACKAGE_DIR/plugins/imageformats/" 2>/dev/null || true
cp "$QT_PLUGINS_DIR/styles/"*.so "$PACKAGE_DIR/plugins/styles/" 2>/dev/null || true

# ==============================================
echo "Copying OpenGL libraries..."
GL_LIBS=(
    "/usr/lib/x86_64-linux-gnu/libGLX_mesa.so.0"
    "/usr/lib/x86_64-linux-gnu/libEGL_mesa.so.0"
    "/usr/lib/x86_64-linux-gnu/libGLX.so.0"
    "/usr/lib/x86_64-linux-gnu/libEGL.so.1"
    "/usr/lib/x86_64-linux-gnu/libGLdispatch.so.0"
)

for lib in "${GL_LIBS[@]}"; do
    if [ -f "$lib" ]; then
        cp -L "$lib" "$PACKAGE_DIR/lib/" 2>/dev/null && echo " + $(basename "$lib")"
    else
        echo " WARNING: $lib not found"
    fi
done

# ==============================================
echo "Copying QtWebEngineProcess..."
WEBENGINE_PROCESS_SRC="$QT_LIBEXEC_DIR/QtWebEngineProcess"
if [ -f "$WEBENGINE_PROCESS_SRC" ]; then
    mkdir -p "$PACKAGE_DIR/libexec"
    cp "$WEBENGINE_PROCESS_SRC" "$PACKAGE_DIR/libexec/QtWebEngineProcess"
    chmod +x "$PACKAGE_DIR/libexec/QtWebEngineProcess"
    echo " + QtWebEngineProcess"
else
    echo "ERROR: QtWebEngineProcess not found"
    exit 1
fi

# ==============================================
echo "Copying WebEngine Resources..."
if [ -d "$QT_RESOURCES_DIR" ]; then
    mkdir -p "$PACKAGE_DIR/resources"
    cp -r "$QT_RESOURCES_DIR/"* "$PACKAGE_DIR/resources/" 2>/dev/null || true
    echo " + WebEngine Resources"
else
    echo "ERROR: Resourses not found"
    exit 1
fi

# ==============================================
echo "Copying WebEngine Locales..."
if [ -d "$QT_TRANSLATIONS_DIR/qtwebengine_locales" ]; then
    mkdir -p "$PACKAGE_DIR/translations/qtwebengine_locales"
    cp "$QT_TRANSLATIONS_DIR/qtwebengine_locales/"*.pak "$PACKAGE_DIR/translations/qtwebengine_locales/" 2>/dev/null || true
    echo " + WebEngine Locales"
fi

# ==============================================
echo "Copying QML modules..."
QML_MODULES=(
    "QtQuick" "QtQuick.2" "QtQml" "QtLocation" "QtPositioning"
    "QtQuick/Controls" "QtQuick/Layouts" "QtQuick/Dialogs" "QtQuick/Window"
    "QtQuick/Templates" "QtQuick/Particles" "Qt5Compat" "Qt5Compat/GraphicalEffects"
    "QtWebEngine" "QtWebChannel"
    "QtQuick/Controls/Basic"
)

for mod in "${QML_MODULES[@]}"; do
    src="$QT_QML_DIR/$mod"
    dst="$PACKAGE_DIR/qml/$mod"
    if [ -d "$src" ]; then
        mkdir -p "$dst"
        cp "$src/qmldir" "$dst/" 2>/dev/null || true
        cp "$src/"*.so "$dst/" 2>/dev/null || true
        cp "$src/"*.qml "$dst/" 2>/dev/null || true
        cp "$src/"*.js "$dst/" 2>/dev/null || true
        echo " + QML: $mod"
    else
        echo " WARNING: QML modules not found: $mod"
    fi
done

# ==============================================
echo "Installing RPATH in bin..."
patchelf --set-rpath '$ORIGIN/../lib' "$PACKAGE_DIR/bin/$APP_NAME"

# ==============================================
echo "RPATH patching in plugins and libexec..."
find "$PACKAGE_DIR/plugins" -name "*.so" -exec patchelf --set-rpath '$ORIGIN/../../lib' {} \; 2>/dev/null || true
patchelf --set-rpath '$ORIGIN/../../lib' "$PACKAGE_DIR/libexec/QtWebEngineProcess" 2>/dev/null || true

find "$PACKAGE_DIR/lib" -name "*.so*" -exec patchelf --set-rpath '$ORIGIN' {} \; 2>/dev/null || true


# ==============================================
if [ -f "$ICON_PATH" ]; then
    mkdir -p "$PACKAGE_DIR/share/icons/hicolor/256x256/apps"
    cp "$ICON_PATH" "$PACKAGE_DIR/share/icons/hicolor/256x256/apps/flygenapp.png"
    echo "Icon is copied."
else
    echo "WARNING: Icon not foud: $ICON_PATH"
fi

# ==============================================

# run.sh
cat > "$PACKAGE_DIR/scripts/run.sh" << 'EOF'
#!/bin/bash
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
APP_DIR="$(dirname "$SCRIPT_DIR")"

export LD_LIBRARY_PATH="$APP_DIR/lib:$LD_LIBRARY_PATH"
export QT_PLUGIN_PATH="$APP_DIR/plugins"
export QML2_IMPORT_PATH="$APP_DIR/qml"
export QTWEBENGINEPROCESS_PATH="$APP_DIR/libexec/QtWebEngineProcess"
export QTWEBENGINE_RESOURCES_PATH="$APP_DIR/resources"
export QTWEBENGINE_LOCALES_PATH="$APP_DIR/translations/qtwebengine_locales"
export QTWEBENGINE_DISABLE_SANDBOX=1
export QTWEBENGINE_CHROMIUM_FLAGS="--no-sandbox --disable-gpu-compositing"

export QT_QPA_PLATFORM=xcb
export QT_XCB_GL_INTEGRATION=xcb_glx
export QT_OPENGL=desktop
export LIBGL_ALWAYS_SOFTWARE=0

echo "Starting FlyGenApp (XCB + GLX)..."
exec "$APP_DIR/bin/flygenapp" "$@"
EOF
chmod +x "$PACKAGE_DIR/scripts/run.sh"

# install.sh
cat > "$PACKAGE_DIR/scripts/install.sh" << 'EOF'
#!/bin/bash
set -e
APP_NAME="flygenapp"
INSTALL_DIR="/opt/$APP_NAME"
DESKTOP_FILE="/usr/share/applications/$APP_NAME.desktop"
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
APP_ROOT="$(dirname "$SCRIPT_DIR)"

echo "Install $APP_NAME to $INSTALL_DIR..."
sudo mkdir -p "$INSTALL_DIR"
sudo cp -r "$APP_ROOT/"* "$INSTALL_DIR/"

sudo tee "$DESKTOP_FILE" > /dev/null << DESKTOP
[Desktop Entry]
Name=FlyGen App
Comment=Ground control station for drones
Exec=$INSTALL_DIR/scripts/run.sh
Icon=$INSTALL_DIR/share/icons/hicolor/256x256/apps/flygenapp.png
Terminal=false
Type=Application
Categories=Utility;Qt;
DESKTOP

sudo chmod +x "$INSTALL_DIR/scripts/run.sh"
sudo ln -sf "$INSTALL_DIR/scripts/run.sh" /usr/local/bin/$APP_NAME
echo "Installation is complete! Launch: $APP_NAME"
EOF
chmod +x "$PACKAGE_DIR/scripts/install.sh"

# uninstall.sh
cat > "$PACKAGE_DIR/scripts/uninstall.sh" << 'EOF'
#!/bin/bash
APP_NAME="flygenapp"
INSTALL_DIR="/opt/$APP_NAME"
DESKTOP_FILE="/usr/share/applications/$APP_NAME.desktop"
echo "Removal $APP_NAME..."
sudo rm -rf "$INSTALL_DIR"
sudo rm -f "$DESKTOP_FILE"
sudo rm -f /usr/local/bin/$APP_NAME
echo "Deleted."
EOF
chmod +x "$PACKAGE_DIR/scripts/uninstall.sh"

# ==============================================
echo "Archive packaging..."
tar -czf "$OUTPUT_ARCHIVE" "$PACKAGE_DIR"

echo ""
echo "DONE!"
echo "Archive: $OUTPUT_ARCHIVE"

Этот скрипт создает папку перенося туда все либы и зависимости и потом создает архив, вот структура:

portable_flygenapp
│   ├── bin
│   ├── lib
│   ├── libexec
│   ├── plugins
│   │   ├── imageformats
│   │   ├── platforms
│   │   └── styles
│   ├── qml
│   ├── resources
│   ├── scripts
│   ├── share
│   │   └── icons
│   └── translations

Сама проблема в том что при запуске портабл версии приложение запускается но с черным экраном и появляются такие ошибки:

QXcbIntegration: Cannot create platform OpenGL context, neither GLX nor EGL are enabled
QRhiGles2: Failed to create temporary context
QXcbIntegration: Cannot create platform offscreen surface, neither GLX nor EGL are enabled
QXcbIntegration: Cannot create platform OpenGL context, neither GLX nor EGL are enabled
QRhiGles2: Failed to create context
Failed to create QRhi for QBackingStoreRhiSupport

При этом дебажные логи идут и приложение работает, если я переключаюсь на X11, то картинки все равно нет и ошибки те же. Уже не знаю что делать.


Ответы (1 шт):

Автор решения: cxz

Есть рабочий метод: воспользоваться готовым решением, например CQtDeployer. Сборка релиза выполнятся в одну команду, и получается красивый установочник, а главное рабочий.

Документация: https://wiki.qt.io/CQtDeployer

→ Ссылка