Подготовка проекта на 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 собрали готовый к переносу проект и скопировали его другой ПК;
Успешно запустили нашу программу на чистом ПК и проверили работоспособность!
Добавить комментарий