Воскресенье, 28.01.2024 18:11

Подготовка проекта на Qt 6.6.0 к публикации

Подготовка проекта на Qt 6.6.0 к публикации

В прошлой статье – Разрабатываем консольную утилиту с использованием Qt 6.6.0 в РЕДОС Linux мы приступили к созданию простой консольной утилиты, позволяющей создавать на рабочем столе ярлык для запуска программы.

Сегодня мы рассмотрим подготовку проекта, написанного на Qt6 к публикации и запуску на ПК с Linux, без установленных библиотек Qt 6.6.0.

Допустим, что несмотря на слабый функционал, руководство приказало готовить утилиту к установке на ПК как она есть. В данный момент она решает все поставленные задачи, а доработкой будем заниматься по ходу дела.

Это сразу ставит перед нами задачу - упаковать в архив с программой все библиотеки, необходимые для её запуска.

До этого мы пользовались версией Qt 6.6.0 собранной с использованием shared - общих, разделяемых или динамических библиотек. Существует так же версия со статической сборкой – static, но согласно лицензии эта версия является платной и мы не будем её рассматривать!

Что означает сборка с shared – динамическими библиотеками? Мы создаем программу, которая должна позволять использовать любую совместимую сборку библиотек! Теоретически, если мы соберем из исходников динамическую библиотеку и заменим её той, что поставляется разработчиком, программа этого не заметит. Но это же означает, что нам придется вместе с программой распространять несколько файлов с расширением .so.X – в Linux или .dll в Windows.

Проверка списка динамических библиотек используемых программой

Перейдем в папку с собранным проектом:

cd ~/Projects/build-addlink-Desktop-Debug

Запустим:

ldd ./addlink
        linux-vdso.so.1 (0x00007ffe4cf8d000)
        libQt6Core.so.6 => /usr/local/qt660/lib/libQt6Core.so.6 (0x00007f1d80c00000)
        libstdc++.so.6 => /lib64/libstdc++.so.6 (0x00007f1d80800000)
        libm.so.6 => /lib64/libm.so.6 (0x00007f1d81305000)
        libgcc_s.so.1 => /lib64/libgcc_s.so.1 (0x00007f1d812ea000)
        libpthread.so.0 => /lib64/libpthread.so.0 (0x00007f1d812c8000)
        libc.so.6 => /lib64/libc.so.6 (0x00007f1d80a3a000)
        libicui18n.so.56 => /usr/local/qt660/lib/libicui18n.so.56 (0x00007f1d80200000)
        libicuuc.so.56 => /usr/local/qt660/lib/libicuuc.so.56 (0x00007f1d7fe00000)
        libicudata.so.56 => /usr/local/qt660/lib/libicudata.so.56 (0x00007f1d7e400000)
        libdl.so.2 => /lib64/libdl.so.2 (0x00007f1d80a33000)
        libglib-2.0.so.0 => /lib64/libglib-2.0.so.0 (0x00007f1d7e000000)
        libz.so.1 => /lib64/libz.so.1 (0x00007f1d807e0000)
        libgthread-2.0.so.0 => /lib64/libgthread-2.0.so.0 (0x00007f1d7dc00000)
        librt.so.1 => /lib64/librt.so.1 (0x00007f1d80a28000)
        /lib64/ld-linux-x86-64.so.2 (0x00007f1d814a6000)
        libpcre.so.1 => /lib64/libpcre.so.1 (0x00007f1d7d800000)

Сократим вывод:

ldd ./addlink | grep qt660
        libQt6Core.so.6 => /usr/local/qt660/lib/libQt6Core.so.6 (0x00007f92cbc00000)
        libicui18n.so.56 => /usr/local/qt660/lib/libicui18n.so.56 (0x00007f92cb000000)
        libicuuc.so.56 => /usr/local/qt660/lib/libicuuc.so.56 (0x00007f92cac00000)
        libicudata.so.56 => /usr/local/qt660/lib/libicudata.so.56 (0x00007f92c9200000)

Для запуска программы нам понадобится как минимум 4 файла с библиотеками.

Давайте скопируем файл на ПК со свежеустановленным РЕДОС Linux и проверим, что произойдет.

На новом ПК проверим, установку Qt 6.6.0:

qmake6
bash: qmake6: команда не найдена

Фреймворк не установлен!

Проверим ip-адрес:

ip a | grep inet
    inet 127.0.0.1/8 scope host lo
    inet6 ::1/128 scope host
    inet 192.168.1.49/24 brd 192.168.1.255 scope global dynamic noprefixroute eth0
    inet6 fe80::215:5dff:fe01:280c/64 scope link noprefixroute

Ip-адрес:

192.168.1.49

Скопируем файл, вернемся к основному ПК и введем:

scp ./addlink user@192.168.1.49:/home/user
The authenticity of host '192.168.1.49 (192.168.1.49)' can't be established.
ED25519 key fingerprint is SHA256:PTWKdP71XmEb7OGtpGRaw9eaano5zNSXpkeZdyTRmPg.
This key is not known by any other names
Are you sure you want to continue connecting (yes/no/[fingerprint])?

Введем

yes

Нажмем Enter

Warning: Permanently added '192.168.1.49' (ED25519) to the list of known hosts.
user@192.168.1.49's password:

Введем пароль user от второго ПК

addlink                                                                       100%  902KB 208.5MB/s   00:00

Файл будет скопирован.

Перейдем ко второму ПК и введем

~/addlink
/home/user/addlink: error while loading shared libraries: libQt6Core.so.6: cannot open shared object file: No such file or directory

Нам не хватает библиотек, в данном случае:

libQt6Core.so.6

Проверим

ldd ./addlink
        linux-vdso.so.1 (0x00007fffed782000)
        libQt6Core.so.6 => not found
        libstdc++.so.6 => /lib64/libstdc++.so.6 (0x00007f360f600000)
        libm.so.6 => /lib64/libm.so.6 (0x00007f360f47c000)
        libgcc_s.so.1 => /lib64/libgcc_s.so.1 (0x00007f360f200000)
        libpthread.so.0 => /lib64/libpthread.so.0 (0x00007f360faea000)
        libc.so.6 => /lib64/libc.so.6 (0x00007f360f03a000)
        /lib64/ld-linux-x86-64.so.2 (0x00007f360fb27000)

Сократим:

ldd ./addlink | grep not
        libQt6Core.so.6 => not found

Теперь у нас не хватает уже одной библиотеки. Это происходит потому, что сама библиотека связана с еще тремя. Мы сможем узнать прочие зависимости только после очередного запуска программы!

Скопируем файл libQt6Core.so.6:

scp /usr/local/qt660/lib/libQt6Core.so.6 user@192.168.1.49:/home/user
user@192.168.1.49's password:
libQt6Core.so.6                                                               100% 6900KB  64.8MB/s   00:00

Проверим на другом ПК, запускается ли программа:

./addlink
./addlink: error while loading shared libraries: libicui18n.so.56: cannot open shared object file: No such file or directory

Проверим:

ldd ./addlink | grep not
        libicui18n.so.56 => not found
        libicuuc.so.56 => not found
        libicudata.so.56 => not found

Теперь нам не хватает еще трех файлов!

На самом деле так можно продолжать довольно долго и со временем скопировать все необходимые программы, но для автоматизации этого процесса уже создана программа:

linuxdeployqt

Установка linuxdeployqt в РЕДОС linux

linuxdeployqt автоматически определяет и копирует в отдельную папку все необходимые для запуска библиотеки! В результате мы получаем программу, которую можно запускать на ПК без установленных библиотек Qt6!

Лучшим способом установки программы в РЕДОС Linux – установка из официального репозитория или сборка из исходного кода.

linuxdeployqt не предоставляет rpm-файлов, так что мы соберем её из исходного кода!

Перейдем в папку:

cd ~

Клонируем репозиторий:

git clone https://github.com/probonopd/linuxdeployqt.git

Установим требуемые пакеты:

su
dnf install git mesa-libGL-devel patchelf
exit

Запустим конфигурирование:

cd linuxdeployqt
mkdir build
cd build
cmake ../

Здесь мы можем получить ошибку:

-- The C compiler identification is GNU 11.4.1
-- The CXX compiler identification is GNU 11.4.1
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: /usr/bin/cc - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: /usr/bin/c++ - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Performing Test CMAKE_HAVE_LIBC_PTHREAD
-- Performing Test CMAKE_HAVE_LIBC_PTHREAD - Failed
-- Check if compiler accepts -pthread
-- Check if compiler accepts -pthread - yes
-- Found Threads: TRUE
-- Updating excludelist...
-- Configuring done
CMake Error: AUTOMOC for target linuxdeployqt: Could not find moc executable target Qt6::moc
CMake Generate step failed.  Build files cannot be regenerated correctly.

К сожалению, проект еще не портирован на Qt6, так что собирать нам его придется с использованием qmake6.

Попробуем еще раз, перейдем в папку:

cd ~/
rm -drf ~/linuxdeployqt
git clone https://github.com/probonopd/linuxdeployqt.git
cd ~/linuxdeployqt
mkdir build
cd build
qmake6 ../tools/
make

Строки

g++ -Wl,-O1 -Wl,-rpath,/usr/local/qt660/lib -o linuxdeployqt  main.o shared.o   /usr/local/qt660/lib/libQt6Core.so -lpthread
make[1]: выход из каталога «/home/user/linuxdeployqt/build/linuxdeployqt»

Означают что сборка прошла успешно!

Проверим

cd linuxdeployqt
./linuxdeployqt
linuxdeployqt 10 (commit 2b38449), build <local dev build> built on 2024-01-27 09:29:31 UTC

Usage: linuxdeployqt <app-binary|desktop file> [options]

Options:
   -always-overwrite        : Copy files even if the target file exists.
   -appimage                : Create an AppImage (implies -bundle-non-qt-libs).
   -bundle-non-qt-libs      : Also bundle non-core, non-Qt libraries.
   -exclude-libs=<list>     : List of libraries which should be excluded,
                              separated by comma.
   -ignore-glob=<glob>      : Glob pattern relative to appdir to ignore when
                              searching for libraries.
   -executable=<path>       : Let the given executable use the deployed libraries
                              too
   -executable-dir=<path>   : Let all the executables in the folder (recursive) use
                              the deployed libraries too
   -extra-plugins=<list>    : List of extra plugins which should be deployed,
                              separated by comma.
   -no-copy-copyright-files : Skip deployment of copyright files.
   -no-plugins              : Skip plugin deployment.
   -no-strip                : Don't run 'strip' on the binaries.
   -no-translations         : Skip deployment of translations.
   -qmake=<path>            : The qmake executable to use.
   -qmldir=<path>           : Scan for QML imports in the given path.
   -qmlimport=<path>        : Add the given path to QML module search locations.
   -show-exclude-libs       : Print exclude libraries list.
   -verbose=<0-3>           : 0 = no output, 1 = error/warning (default),
                              2 = normal, 3 = debug.
   -updateinformation=<update string>        : Embed update information STRING; if zsyncmake is installed, generate zsync file
   -qtlibinfix=<infix>      : Adapt the .so search if your Qt distribution has infix.
   -version                 : Print version statement and exit.

linuxdeployqt takes an application as input and makes it
self-contained by copying in the Qt libraries and plugins that
the application uses.

By default it deploys the Qt instance that qmake on the $PATH points to.
The '-qmake' option can be used to point to the qmake executable
to be used instead.

Plugins related to a Qt library are copied in with the library.

See the "Deploying Applications on Linux" topic in the
documentation for more information about deployment on Linux.

Скопируем в папку /usr/local/bin

su
cp ./linuxdeployqt /usr/local/bin
exit

Проверим:

cd ~
linuxdeployqt -version
linuxdeployqt 10 (commit 2b38449), build <local dev build> built on 2024-01-27 09:29:31 UTC

Программа собрана и готова к работе!

Собираем все библиотеки для программы на Qt 6.6.0

Запустим:

cd ~/Projects/build-addlink-Desktop-Debug
linuxdeployqt addlink -no-translations -always-overwrite -verbose=2
linuxdeployqt 10 (commit 2b38449), build <local dev build> built on 2024-01-27 09:29:31 UTC
Not using FHS-like mode
app-binary: "/home/user/Projects/build-addlink-Desktop-Debug/addlink"
appDirPath: "/home/user/Projects/build-addlink-Desktop-Debug"
relativeBinPath: "addlink"
qmakePath 3= ""
Log: Using qmake:  "/usr/local/qt660/bin/qmake"
Log: Deploying the following libraries: QList("/home/user/Projects/build-addlink-Desktop-Debug/addlink")
Log: Setting deploymentInfo.qtPath to: "/usr/local/qt660/lib/"
Log:  copied: "/usr/local/qt660/lib/libQt6Core.so.6"
Log:  to "/home/user/Projects/build-addlink-Desktop-Debug/lib//libQt6Core.so.6"
Log: dpkg not found, hence not deploying copyright files
Log: Checking rpath in "/home/user/Projects/build-addlink-Desktop-Debug/lib/libQt6Core.so.6"
Log: Changing rpath in "/home/user/Projects/build-addlink-Desktop-Debug/lib/libQt6Core.so.6" to "$ORIGIN"
Log:  copied: "/usr/local/qt660/lib/libicui18n.so.56"
Log:  to "/home/user/Projects/build-addlink-Desktop-Debug/lib//libicui18n.so.56"
Log: dpkg not found, hence not deploying copyright files
Log: Checking rpath in "/home/user/Projects/build-addlink-Desktop-Debug/lib/libicui18n.so.56"
Log: Changing rpath in "/home/user/Projects/build-addlink-Desktop-Debug/lib/libicui18n.so.56" to "$ORIGIN"
Log:  copied: "/usr/local/qt660/lib/libicuuc.so.56"
Log:  to "/home/user/Projects/build-addlink-Desktop-Debug/lib//libicuuc.so.56"
Log: dpkg not found, hence not deploying copyright files
Log: Checking rpath in "/home/user/Projects/build-addlink-Desktop-Debug/lib/libicuuc.so.56"
Log: Changing rpath in "/home/user/Projects/build-addlink-Desktop-Debug/lib/libicuuc.so.56" to "$ORIGIN"
Log:  copied: "/usr/local/qt660/lib/libicudata.so.56"
Log:  to "/home/user/Projects/build-addlink-Desktop-Debug/lib//libicudata.so.56"
Log: dpkg not found, hence not deploying copyright files
Log: Checking rpath in "/home/user/Projects/build-addlink-Desktop-Debug/lib/libicudata.so.56"
Log: Changing rpath in "/home/user/Projects/build-addlink-Desktop-Debug/lib/libicudata.so.56" to "$ORIGIN"
Log: Checking rpath in "/home/user/Projects/build-addlink-Desktop-Debug/addlink"
Log: Removing absolute rpath of  "/usr/local/qt660/lib"  in  "/home/user/Projects/build-addlink-Desktop-Debug/addlink"
Log: Changing rpath in "/home/user/Projects/build-addlink-Desktop-Debug/addlink" to "$ORIGIN/lib"
Log: Deploying plugins from "/usr/local/qt660/plugins"
Log: pluginList after having detected hopefully all required plugins: QList()
Log: Created configuration file: "/home/user/Projects/build-addlink-Desktop-Debug/qt.conf"

Проверим содержимое папки:

ls ~/Projects/build-addlink-Desktop-Debug
addlink          CMakeCache.txt       cmake_install.cmake  qt.conf            test.txt
addlink_autogen  CMakeCache.txt.prev  lib                  qtcsettings.cmake
AppRun           CMakeFiles           Makefile             Testing

Как видите, здесь слишком много ненужных файлов, поэтому давайте напишем скрипт для сборки всего нужного в отдельную папку:

cd ~/Projects/

Создадим файл:

mcedit ~/Projects/pack_addlink.sh

С содержимым:

mkdir addlink_release
cp ~/Projects/build-addlink-Desktop-Debug/addlink ~/Projects/addlink_release
cd ~/Projects/addlink_release
linuxdeployqt addlink -no-translations -always-overwrite

Запустим:

chmod +x ~/Projects/pack_addlink.sh
~/Projects/pack_addlink.sh

Получим папку

addlink_release

Скопируем на тестовый ПК:

scp -r ~/Projects/addlink_release/* user@192.168.1.49:/home/user/addlinks/
user@192.168.1.49's password:
addlink                                                                       100%  902KB 122.1MB/s   00:00
AppRun                                                                        100%  902KB 332.2MB/s   00:00
libQt6Core.so.6                                                               100% 6900KB 404.0MB/s   00:00
libicui18n.so.56                                                              100% 3289KB 411.2MB/s   00:00
libicuuc.so.56                                                                100% 2021KB 392.6MB/s   00:00
libicudata.so.56                                                              100%   24MB 443.9MB/s   00:00
qt.conf                                                                       100%  145   479.7KB/s   00:00

Перейдем на тестовый ПК и запустим:

cd addlinks
./addlink
Не найден обязательный параметр!
Первый параметр должен задавать полный путь до запускаемой программы!

Программа запускается.

Добавим ярлык на калькулятор:

./addlink /usr/bin/mate-calc

Проверим:

ls ~/"Рабочий стол"
mate-calc.desktop

Ярлык создан, программа запускается!

Заключение

Сегодня мы рассмотрели подготовку программы, написанной на Qt6, к публикации и запуска на других ПК:

Рассмотрели чем статические библиотеки отличаются динамических;

Проверили какие библиотеки необходимы для запуска нашей тестовой программы;

Скопировали тестовую программу на другой ПК и определили возникающие ошибки;

Попробовали вручную скопировать недостающую библиотеку;

Собрали из исходного кода программу linuxdeployqt;

С помощью linuxdeployqt собрали готовый к переносу проект и скопировали его другой ПК;

Успешно запустили нашу программу на чистом ПК и проверили работоспособность!

Категория Qt6
Теги Qt6 РЕДОС

Добавить комментарий

Простой текст

  • HTML-теги не обрабатываются и показываются как обычный текст
  • Строки и абзацы переносятся автоматически.
  • Адреса веб-страниц и email-адреса преобразовываются в ссылки автоматически.
Просмотров: 424