Сборка проекта 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 шт):
Есть рабочий метод: воспользоваться готовым решением, например CQtDeployer. Сборка релиза выполнятся в одну команду, и получается красивый установочник, а главное рабочий.
Документация: https://wiki.qt.io/CQtDeployer