Сборка библиотек на примере bluez-qt
Руководство описывает процесс сборки и подключения к проекту приложения библиотеки bluez-qt, а также сложности и пути их решения на разных этапах.
Для работы использовалась bluez-qt версии 6.1.0.
Содержание:
- Сборка библиотеки
- Шаги по сборке
- Проблемы в процессе генерации Makefile
- Проблемы в процессе сборки бинарных артефактов
- Неопределённый тип qsizetype
- Некорректное объявление указателя d_ptr
- Неподдерживаемая инициализация QSharedPointer
- Отсутствие включения заголовочного файла functional
- Отсутствие включения заголовочного файла memory
- Отсутствие включения заголовочного файла chrono
- Некорректное использование вызова std::chrono::seconds(1) для установки интервала QTimer
- Ошибки линковки
- Использование недоступного API QString
- Использование SkipEmptyParts из пространства имён Qt
- Отсутствие включения заголовочного файла QtQml
- Некорректная установка соединений между сигналом и слотом
- Использование неподдерживаемого вызова QTest::qCompare
- Формирование патча по адаптации библиотеки под Qt 5.6.3
- Подключение бинарных файлов библиотеки к проекту приложения
Сборка библиотеки
Сборка бинарных артефактов библиотеки под ОС Аврора может выполняться с использованием двух разных инструментов:
- С помощью Аврора Build Engine, входящего в состав Аврора SDK (MB2).
- С помощью Аврора Platform SDK.
Шаги по сборке
Предварительная настройка:
-
Перейти в сборочное окружение.
Для Аврора Build Engine требуется перейти в виртуальную машину "Build Engine" по SSH. Для этого достаточно выполнить следующую команду:
~/AuroraOS/bin/sfdk engine exec
Команда выше предполагает, что Аврора SDK был ранее установлен по пути
~/AuroraOS/
. Если Аврора SDK располагается по иному пути, то потребуется заменить~/AuroraOS/
на нужный путь.Примечание: команду
sfdk
удобнее выполнять непосредственно в корне проекта, чтобы оказаться в нём после перехода в Build Engine для последующей сборки.Для Аврора Platform SDK требуется выполнить следующую команду:
~/AuroraPlatformSDK-5.1.3.85/sdks/aurora_psdk/sdk-chroot
Команда выше предполагает, что Аврора Platform SDK был ранее установлен по пути
~/AuroraPlatformSDK-5.1.3.85/
. Если Аврора Platform SDK располагается по иному пути, то потребуется заменить~/AuroraPlatformSDK-5.1.3.85/
на нужный путь.Примечание: команду удобнее выполнять непосредственно в корне проекта, чтобы оказаться в нём после перехода в окружение Platform SDK для последующей сборки.
Следующие шаги индентичны для всех сборочных интрументов.
-
Перейти в окружение ScratchBox2.
sb2 -t AuroraOS-5.1.3.85-MB2-armv7hl -R
- Параметр
-t
задаёт цель для сборочного окружения. Список доступных целей можно получить с помощью командыsdk-manage target list
. - Параметр
-R
запускает сборочное окружение с правами суперпользователя.
- Параметр
-
Установить переменные окружения, отвечающие за сборку. При обычном запуске окружения ScratchBox2 их настройка не происходит. Для их установки необходимо выполнить следующую команду:
eval $(rpm --eval '%set_build_flags')
- Субкоманда
rpm --eval '%set_build_flags'
выводит команды для настройки переменных окружения. - Субкоманда
eval $(...)
передаёт вывод первой субкоманды на вход встроенной в Bash командыeval
, которая исполняет команды в рамках текущей сессии интерпретатора.
В результате выполнения данной команды будут установлены значения переменных окружения для сборки:
CFLAGS
,CXXFLAGS
,FFLAGS
,FCFlAGS
,LDFLAGS
. Обязательно следует учитывать их наличие и их значения. Затирание значений данных переменных может привести к проблемам сборки бинарных артефактов.
Следует обратить внимание, что при завершении работы окружения ScratchBox2 установленные переменные окружения будут сброшены. - Субкоманда
-
Выполнить установку пути для поиска динамических библиотек
rpath
. Это делается путём изменения флагов компоновщика следующим образом:LDFLAGS="$LDFLAGS -Wl,-rpath=%{_datadir}/%{name}/lib"
С помощью комбинации макросов
%{_datadir}
и%{name}
указывается стандартное для ОС Аврора расположение разделяемых библиотек, поставляемых вместе с приложением.
Сборка библиотеки bluez-qt выполняется с помощью утилиты cmake
.
Сборка выполняется в два этапа:
- Генерация
Makefile
-файлов. - Сборка бинарных артефактов.
Для генерации Makefile
-файлов необходимо вызвать следующую команду:
cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX:PATH=$(pwd)/out/install -S . -B out/build
- Параметр
-DCMAKE_BUILD_TYPE
задаёт тип сборки (Release). - Параметр
-DCMAKE_INSTALL_PREFIX:PATH
задаёт базовый путь для установки проекта после его сборки. После выполнения командыmake install
илиcmake --install
все файлы проекта будут установлены в подкаталоги указанногоCMAKE_INSTALL_PREFIX
. В данном случае это каталогout/install
в текущем каталоге, т.е. в корне проекта. - Параметр
-S
задаёт путь до каталога с исходными файлами проекта. В данном случае.
означает, что исходные файлы располагаются в текущем каталоге (корне проекта). - Параметр
-B
задаёт путь до сборочного каталога. В данном случае это каталогout/build
в текущем каталоге, т.е. в корне проекта.
После выполнения этой команды в каталоге out/build
появятся сгенерированные Makefile
-файлы,
а также дополнительные сборочные файлы.
Для библиотеки bluez-qt
генерация Makefile
-файлов не прошла безошибочно.
О проблемах и том, как они решались, подробнее описано в следующем разделе.
Сборка бинарных файлов библиотеки выполняется с помощью команды:
cmake --build out/build --target install --config Release --parallel $(nproc)
- Параметр
--build
задаёт путь до сборочного каталога. Он был создан на предыдущем шаге в текущем каталога (корне проекта). - Параметр
--target
определяет цель сборки. В данном случае цельinstall
позволит не только собрать проект, но и установить бинарные артефакты в каталог, указанный в качестве значения для параметра-DCMAKE_INSTALL_PREFIX:PATH
на предыдущем шаге. - Параметр
--config
задаёт тип сборки (Release). - Параметр
--parallel
позволяет распараллелить сборку на несколько потоков для уменьшения её длительности. Количество потоков определяется субкомандой$(nproc)
, возвращающей количество процессоров на текущей машине.
После выполнения этой команды собранные бинарные артефакты библиотеки будут
располагаться в каталоге out/install
.
Для библиотеки bluez-qt
сборка бинарных артефактов не прошла безошибочно.
О проблемах и том, как они решались, подробнее описано в следующем разделе.
Итоговая последовательность команд для сборки бинарных артефактов библиотеки в сборочном окружении ScratchBox2:
eval $(rpm --eval '%set_build_flags')
LDFLAGS="$LDFLAGS -Wl,-rpath=%{_datadir}/%{name}/lib"
cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX:PATH=$(pwd)/out/install -S . -B out/build
cmake --build out/build --target install --config Release --parallel $(nproc)
Проблемы в процессе генерации Makefile
Данный раздел описывает проблемы, возникшие на этапе генерации Makefile
с помощью команды:
cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX:PATH=$(pwd)/out/install -S . -B out/build
Далее будут приведены сообщения об ошибках и способы их решения.
Отсутствие зависимости extra-cmake-modules
-- Could NOT find ECM (missing: ECM_DIR)
--
* ECM (required version >= 6.1.0), Extra CMake Modules., <https://commits.kde.org/extra-cmake-modules>
CMake Error at /usr/share/cmake/Modules/FeatureSummary.cmake:457 (message):
feature_summary() Error: REQUIRED package(s) are missing, aborting CMake
run.
Call Stack (most recent call first):
CMakeLists.txt:9 (feature_summary)
Сообщение об ошибке прямо говорит об отсутствии "Extra CMake Modules" (ECM) в сборочном окружении, а также о том, что для сборки требуется версия 6.1.0.
Данные модули пришлось установить "вручную" с помощью утилиты zypper
:
zypper install extra-cmake-modules
После успешной установки пакета можно заметить, что по умолчанию поставляется ECM версии 5.112.0,
а сборка bluez-qt требует версии 6.1.0.
Для возможности использования более ранней версии ECM потребовалось внести изменение в файл
CMakeLists.txt
в корне проекта bluez-qt и снизить значение требуемой версии.
- find_package(ECM 6.1.0 NO_MODULE)
+ find_package(ECM 5.112.0 NO_MODULE)
Использование Qt версии 6
CMake Error at CMakeLists.txt:46 (find_package):
Could not find a package configuration file provided by "Qt6" (requested
version 6.5.0) with any of the following names:
Qt6Config.cmake
qt6-config.cmake
Add the installation prefix of "Qt6" to CMAKE_PREFIX_PATH or set "Qt6_DIR"
to a directory containing one of the above files. If "Qt6" provides a
separate development package or SDK, be sure it has been installed.
Сообщение об ошибке говорит о том, что проект bluez-qt настроен на использование библиотеки Qt 6-й версии для сборки, но в Аврора SDK поддерживается Qt версии 5.6.3. Решением такой проблемы стала попытка уменьшить требование к версии Qt во всём проекте bluez-qt до 5.6.3, которая в итоге увенчалась успехом.
Полный список изменений в данном руководстве приводиться не будет, но отметим типовые из них.
-
Настройка значения
REQUIRED_QT_VERSION
в файлеCMakeLists.txt
в корне проекта:- set(REQUIRED_QT_VERSION 6.5.0) + set(REQUIRED_QT_VERSION 5.6.3)
-
Настройка значения
ecm_set_disabled_deprecation_versions
в файлеCMakeLists.txt
в корне проекта:ecm_set_disabled_deprecation_versions( - QT 6.5 + QT 5.6 )
-
Замена всех упоминаний
Qt6
наQt5
во всех файлахCMakeLists.txt
в проекте, а также в файлеKF6BluezQtConfig.cmake.in
. Например,Qt6::Core
->Qt5::Core
,Qt6Qml
->Qt5Qml
и т.д.
Отсутствие зависимостей qt5-qttest-devel и qt5-qtdeclarative-qtquicktest-devel
fatal: HEAD does not point to a branch
-- Could NOT find Qt5Test (missing: Qt5Test_DIR)
-- Could NOT find Qt5QuickTest (missing: Qt5QuickTest_DIR)
Сообщение об ошибке говорит об отсутствии библиотек Qt5Test
и Qt5QuickTest
в сборочном
окружении.
Для решения проблемы необходимо установить пакеты с библиотеками:
zypper install qt5-qttest-devel qt5-qtdeclarative-qtquicktest-devel
Использование cmake-функции qt_add_dbus_interface
CMake Error at src/CMakeLists.txt:78 (qt_add_dbus_interface):
Unknown CMake command "qt_add_dbus_interface".
Сообщение говорит об использовании в CMake-файлах функции qt_add_dbus_interface
, которая стала
доступна только в Qt 5.15.
В версии Qt 5.6.3, поставляющейся в рамках Аврора SDK, используется функция
qt5_add_dbus_interface
.
Соответственно, для решения проблемы требуется заменить использование
qt_add_dbus_interface
на qt5_add_dbus_interface
во всём проекте.
Использование cmake-модуля ECMFeatureSummary и функции ecm_feature_summary
CMake Error at CMakeLists.txt:115 (include):
include could not find load file:
ECMFeatureSummary
CMake Error at CMakeLists.txt:116 (ecm_feature_summary):
Unknown CMake command "ecm_feature_summary".
Сообщение говорит об отсутствии cmake-модуля ECMFeatureSummary
и его функции
ecm_feature_summary
, использующихся в файле CMakeLists.txt
в корне проекта bluez-qt.
Модуль ECMFeatureSummary
был добавлен в ECM версии 5.248.0, но Аврора SDK позволяет установить
лишь версию 5.112.0.
Путём сравнения файла CMakeLists.txt
версии bluez-qt 6.1.0 с аналогичным файлом в версии
bluez-qt 5.248.0 (последней версией, где ещё не использовался модуль ECMFeatureSummary
)
было определено, что вместо модуля ECMFeatureSummary
и его функции ecm_feature_summary
можно использовать функцию feature_summary
:
- include(ECMFeatureSummary)
- ecm_feature_summary(WHAT ALL FATAL_ON_MISSING_REQUIRED_PACKAGES)
+ feature_summary(WHAT ALL FATAL_ON_MISSING_REQUIRED_PACKAGES)
После исправления пяти описанных выше проблем удалось успешно сгенерировать Makefile
.
Далее можно приступать к сборке бинарных артефактов библиотеки bluez-qt.
Проблемы в процессе сборки бинарных артефактов
Данный раздел описывает проблемы, возникшие при сборке бинарных артефактов библиотеки bluez-qt с помощью команды:
cmake --build out/build --target install --config Release --parallel $(nproc)
Далее будут приведены сообщения об ошибках и способы их решения.
Неопределённый тип qsizetype
bluez-qt/tools/bluezapi2qt/Comment.cpp:19:5: error: 'qsizetype' was not declared in this scope; did you mean 'size_type'?
19 | qsizetype indents = 255;
| ^~~~~~~~~
| size_type
Сообщение говорит о том, что тип qsizetype
не определён.
Действительно, данный тип доступен с версии Qt 5.10, и в 5.6.3 он недоступен.
Тип qsizetype
является псевдонимом для QIntegerForSizeof<std::size_t>::Signed
.
Чтобы продолжить сборку проекта, было решено заменить все использования qsizetype
на int
.
Некорректное объявление указателя d_ptr
bluez-qt/src/job.h:227:5: required from here
/usr/include/qt5/QtCore/qglobal.h:1019:112: error: 'const class std::unique_ptr<BluezQt::JobPrivate>'
has no member named 'data'
1019 | template <typename Wrapper> static inline
typename Wrapper::pointer qGetPtrHelper(const Wrapper &p) { return p.data(); }
|
Сообщение об ошибке ссылается на объявление std::unique_ptr
в классе JobPrivate
проекта
bluez-qt:
private:
std::unique_ptr<JobPrivate> const d_ptr;
Q_DECLARE_PRIVATE(Job)
Путём многочисленных опытов и чтения исходного кода макроса Q_DECLARE_PRIVATE
было выяснено,
что реализация макроса в Qt 5-й версии не поддерживает использование std:unique_ptr
для объявления указателя d_ptr
, который неявно используется макросом.
В связи с этим объявление указателя было отредактировано:
private:
- std::unique_ptr<JobPrivate> const d_ptr;
+ JobPrivate *const d_ptr;
Q_DECLARE_PRIVATE(Job)
Неподдерживаемая инициализация QSharedPointer
bluez-qt/src/device_p.cpp:213:40: error: conversion from 'std::nullptr_t'
to non-scalar type 'BluezQt::GattServiceRemotePtr' {aka 'QSharedPointer<BluezQt::GattServiceRemote>'} requested
213 | GattServiceRemotePtr gattService = nullptr;
| ^~~~~~~
Сообщение об ошибке говорит о невозможности проинициализировать переменную типа
GattServiceRemotePtr
значением nullptr
.
Тип GattServiceRemotePtr
является псевдонимом для QSharedPointer<BluezQt::GattServiceRemote>
.
Т.е. получается, что объект QSharedPointer
невозможно инициализировать значением nullptr
.
Документация на данный класс версии Qt 5.6 действительно не содержит информации о том,
что QSharedPointer
содержит переопределение оператора =
с возможностью приведения одного типа
указателя (например, BluezQt::GattServiceRemote
) к другому типу (например, nullptr
).
В таком случае решением будет передача значения в конструктор класса:
- GattServiceRemotePtr gattService = nullptr;
+ GattServiceRemotePtr gattService(nullptr);
Стоит отметить, что подобное изменение необходимо внести не только в файле device_p.cpp
,
но оно потребуется и в других, где QSharedPointer
инициализируется с помощью nullptr
:
gattcharacteristicremote_p.cpp
и gattserviceremote_p.cpp
.
Отсутствие включения заголовочного файла functional
bluez-qt/src/gattcharacteristic.h:66:31: error: 'function' in namespace 'std'
does not name a template type
66 | using ReadCallback = std::function<QByteArray()>;
|
Сообщение об ошибке говорит о том, что объявление типа std::function
недоступно.
Для решения необходимо в соответствующий файл с исходным кодом добавить включение заголовочного
файла <functional>
:
#include <functional>
Отсутствие включения заголовочного файла memory
bluez-qt/src/gattserviceremote.h:167:16: error: 'unique_ptr' in namespace 'std'
does not name a template type
167 | const std::unique_ptr<class GattServiceRemotePrivate> d;
| ^~~~~~~~~~
bluez-qt/src/gattserviceremote.h:18:1: note: 'std::unique_ptr' is defined in header '<memory>';
did you forget to '#include <memory>'?
17 | #include "bluezqt_export.h"
+++ |+#include <memory>
18 |
Сообщение об ошибке говорит о том, что объявление типа std::unique_ptr
недоступно.
Для решения необходимо в соответствующий файл с исходным кодом добавить включение заголовочного
файла <memory>
:
#include <memory>
Стоит отметить, что включение данного заголовочного файла нужно добавить не только в файл
gattserviceremote.h
, но также в gattdescriptorremote.h
и в gattcharacteristicremote.h
.
Отсутствие включения заголовочного файла chrono
bluez-qt/tests/leserver.cpp:58:49: error: 'std::chrono' has not been declared
58 | m_characteristicWriteTimer.setInterval(std::chrono::seconds(1));
|
Сообщение об ошибке говорит о том, что объявление типа std::chrono
недоступно.
Для решения необходимо в соответствующий файл с исходным кодом добавить включение заголовочного
файла <chrono>
:
#include <chrono>
Некорректное использование вызова std::chrono::seconds(1) для установки интервала QTimer
bluez-qt/tests/leserver.cpp:59:57: error: cannot convert 'std::chrono::seconds'
{aka 'std::chrono::duration<long long int>'} to 'int'
59 | m_characteristicWriteTimer.setInterval(std::chrono::seconds(1));
| ^~~~~~~~~~
| |
|
Сообщение говорит о том, что вызов std::chrono::seconds(1)
возвращает значение типа
std::chrono::duration<long long int>
, в то время как вызов QTimer::setInterval()
ожидает на вход значение типа int
.
Для решения необходимо вызвать метод std::chrono::duration<>::count()
, возвращающий целочисленное
значение:
- m_characteristicWriteTimer.setInterval(std::chrono::seconds(1));
+ m_characteristicWriteTimer.setInterval(std::chrono::seconds(1).count());
Ошибки линковки
/srv/mer/toolings/AuroraOS-5.1.3.51-MB2/opt/cross/bin/armv7hl-meego-linux-gnueabi-ld:
CMakeFiles/KF6BluezQt.dir/obexobjectpush1.cpp.o:(.data.rel.ro+0x38): multiple definition of
`OrgBluezObexObjectPush1Interface::staticMetaObject'; CMakeFiles/KF6BluezQt.dir/KF6BluezQt_autogen
mocs_compilation.cpp.o:(.data.rel.ro+0x1e0): first defined here
collect2: error: ld returned 1 exit status
После множества экспериментов и изучения предыдущих версий bluez-qt удалось выяснить, что подобные
ошибки линковки связаны с разницей реализации cmake-функции qt_add_dbus_interface
для версии
CMake 3.16 (используется в bluez-qt 6.1.0) и CMake 3.5 (используется по умолчанию в проектах
под ОС Аврора).
Функция qt_add_dbus_interface
служит для генерации классов DBus-интерфейсов на языке C++ по их
описаниям в виде XML-файлов в процессе выполнения сборки.
Для решения проблемы необходимо заменить использующуюся минимальную версию CMake в файле
CMakeLists.txt
в корне проекта:
-cmake_minimum_required(VERSION 3.16)
+cmake_minimum_required(VERSION 3.5)
Использование недоступного API QString
bluez-qt/tools/bluezapi2qt/CppGenerator.cpp:194:22: error: 'class QString' has no member named 'back'
194 | while (className.back() > QLatin1Char('0') && className.back() <= QLatin1Char('9')) {
| ^~~~
bluez-qt/tools/bluezapi2qt/CppGenerator.cpp:194:61: error: 'class QString' has no member named 'back'
194 | while (className.back() > QLatin1Char('0') && className.back() <= QLatin1Char('9')) {
|
Сообщение об ошибке указывает на то, что в коде проекта используется метод back()
класса
QString
, однако он недоступен в Qt 5.6.
Данный метод появился в Qt версии 5.10.
Метод back()
выполняет возврат последнего символа в строке в виде объекта QChar
.
В качестве решения необходимо заменить использование метода back()
на получение последнего
символа в строке доступным в Qt 5.6 способом:
- while (className.back() > QLatin1Char('0') && className.back() <= QLatin1Char('9')) {
+ while (className.at(className.size() - 1) > QLatin1Char('0') && className.at(className.size() - 1) <= QLatin1Char('9')) {
Использование SkipEmptyParts из пространства имён Qt
bluez-qt/tools/bluezapi2qt/Methods.cpp:40:110: error: 'SkipEmptyParts' is not a member of 'Qt'
40 | m_currentMethod->m_outParameterStrings = match.captured(1).toLower().split(QStringLiteral(", "),
| Qt::SkipEmptyParts);
|
Сообщение об ошибке говорит о том, что в пространстве имён Qt
нет перечисления SkipEmptyParts
.
В Qt 5.6 данное перечисление находится в пространстве имён QString
.
Для решения проблемы необходимо во всём проекте заменить упоминания
Qt::SkipEmptyParts
на QString::SkipEmptyParts
.
Отсутствие включения заголовочного файла QtQml
bluez-qt/autotests/qmltests.cpp:88:5: error: 'qmlRegisterSingletonType' was not declared in this scope
88 | qmlRegisterSingletonType<FakeBluezObject>("org.kde.bluezqt.fakebluez", 1, 0, "FakeBluez",
| fakebluez_singleton);
|
Сообщение об ошибке говорит о том, функция qmlRegisterSingletonType
не объявлена в данном файле
исходного кода.
Для решения необходимо включить заголовочный файл <QtQML>
:
#include <QtQml>
Аналогичное изменение потребуется и в файле bluezqtextensionplugin.cpp
.
Некорректная установка соединений между сигналом и слотом
bluez-qt/autotests/autotests.cpp:63:12: error: no matching function for call to
'StartJob::connect(QProcess*&, <unresolved overloaded function type>, StartJob*, void (StartJob::*)(int, QProcess::ExitStatus))'
63 | connect(FakeBluez::s_process, &QProcess::finished, this, &StartJob::processFinished);
|
Сообщение об ошибке говорит о некорректном для Qt 5.6 способе установки соединения
между сигналом и слотом.
В данном случае потребуется использовать макросы SIGNAL
и SLOT
:
- connect(FakeBluez::s_process, &QProcess::errorOccurred, this, &StartJob::processError);
- connect(FakeBluez::s_process, &QProcess::finished, this, &StartJob::processFinished);
+ connect(FakeBluez::s_process, SIGNAL(error(QProcess::ProcessError)), this, SLOT(processError(QProcess::ProcessError)));
+ connect(FakeBluez::s_process, SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(processFinished(int, QProcess::ExitStatus)));
Использование неподдерживаемого вызова QTest::qCompare
/srv/mer/toolings/AuroraOS-5.1.3.51-MB2/opt/cross/bin/armv7hl-meego-linux-gnueabi-ld:
CMakeFiles/gattserviceremotetest.dir/gattserviceremotetest.cpp.o: in function
`GattServiceRemoteTest::setHandleTest()':
gattserviceremotetest.cpp:(.text+0x422): undefined reference to
`bool QTest::qCompare<unsigned int, unsigned short>(unsigned int const&, unsigned short const&, char const*,
char const*, char const*, int)'
collect2: error: ld returned 1 exit status
Сообщение об ошибке указывает на проблемы в линковке.
Точного сообщения о проблеме нет, однако в ходе экспериментов и чтения
документации о QTest::qCompare()
было выяснено, что данный метод в версии Qt 5.6 не может
принимать на вход значения типа unsigned int
.
В связи с этим было решено привести такие значения к QString
:
- QCOMPARE(arguments.at(0).toUInt(), value);
+ QCOMPARE(QTest::toString(arguments.at(0).toUInt()), QTest::toString(value));
Стоит отметить, что подобное изменение необходимо внести не только в код метода
GattServiceRemoteTest::setHandleTest()
, но и в GattDescriptorRemoteTest::setHandleTest()
,
GattCharacteristicRemoteTest::setHandleTest()
,
AdapterTest::discoveryFilterTest()
и BatteryTest::getPropertiesTest()
.
После внесения всех описанных выше правок бинарные артефакты библиотеки bluez-qt версии 6.1.0
будут успешно собраны и готовы к включению их в проект приложения под ОС Аврора.
Располагаться бинарные артефакты после сборки будут в каталоге out/install
в корне проекта.
Формирование патча по адаптации библиотеки под Qt 5.6.3
Описанные выше правки позволили собрать библиотеку bluez-qt под Аврора SDK с Qt 5.6.3. Все изменения можно объединить в один общий патч, который впоследствии можно будет наложить на исходный код bluez-qt и выполнить сборку, избежав множества отдельных итераций правок исходного кода.
Чтобы сформировать патч, в первый раз всё же придётся выполнить все правки, что описаны выше. После этого в корне репозитория bluez-qt необходимо выполнить команду:
git diff > 01-backport-to-qt-5.6.3.patch
Данная команда запишет вывод git diff
в патч-файл 01-backport-to-qt-5.6.3.patch
.
Имя патч-файла может быть произвольным.
Для того, чтобы впоследствии наложить готовый патч на исходный код библиотеки, необходимо в корне
проекта воспользоваться утилитой patch
:
patch -p1 < 01-backport-to-qt-5.6.3.patch
После этого все изменения, описанные в патч-файле, будут применены к файлам и каталогам репозитория, в корне которого выполнялась команда.
Примечание: данный патч будет соответствовать только тому срезу репозитория, с которого он формировался. В данном случае это версия bluez-qt 6.1.0. Соответствующий тег в репозитории: v6.1.0. Применение патча на любых других срезах репозитория может привести как к ошибкам его применения, так и к некорректному слиянию изменений.
Подключение бинарных файлов библиотеки к проекту приложения
Для подключения библиотеки к проекту приложения сперва нужно её собрать. Процесс сборки bluez-qt был описан выше. Структура каталогов собранных артефактов bluez-qt:
bluez-qt/
├─ include/
├─ lib/
├─ share/
- В каталоге
include/
располагаются заголовочные файлы библиотеки. - В каталоге
lib/
располагаются бинарные файлы библиотеки (*.so
). - В каталоге
share/
располагаются дополнительные файлы с описанием категории логирования Qt.
После сборки библиотеки под все три архитектуры (aarch64, armv7hl и x86_64) можно сформировать
каталог bluez-qt
со следующим деревом каталогов:
bluez-qt/
├─ aarch64/
├─ include/
├─ lib/
├─ share/
├─ armv7l/
├─ include/
├─ lib/
├─ share/
├─ x86_64/
├─ include/
├─ lib/
├─ share/
Для подключения библиотеки к проекту приложения необходимо:
- Положить каталог с собранными файлами библиотеки (
bluez-qt/
) в корень проекта. - Описать пути к .so-файлам библиотек и к заголовочным файлам в pro-файле (или в файле CMakeLists.txt, если используется сборка с помощью CMake).
- Описать исключение для so-файлов библиотек, чтобы генератор зависимостей не сканировал их как зависимости проекта.
Конфигурация проекта на базе qmake
Для проектов на базе qmake, чтобы иметь возможность использовать библиотеку, необходимо в pro-файле проекта описать следующее.
-
Получить информацию о текущей архитектуре для сборки.
GCC_INFO = $$system($$QMAKE_CXX -dumpmachine) contains(GCC_INFO, .*aarch64.*) { ARCH = aarch64 } else { contains(GCC_INFO, .*x86_64.*) { ARCH = x86_64 } else { contains(GCC_INFO, .*armv7hl.*) { ARCH = armv7hl } } }
Переменная
ARCH
потребуется далее для указания путей к файлам библиотеки. -
Настроить переменные
LIBS
иINCLUDEPATH
:LIBS += -L$$PWD/bluez-qt/$$ARCH/lib -lKF6BluezQt INCLUDEPATH += $$PWD/bluez-qt/$$ARCH/include/KF5/BluezQt/
Указываемые пути и флаги можно найти в pkgconfig-файле, который генерируется во время сборки библиотеки bluez-qt и располагается по пути
bluez-qt/$$ARCH/lib/pkgconfig/KF6BluezQt.pc
. -
Указать цель для установки файлов библиотеки в итоговый RPM-пакет приложения:
bluez_install.path = /usr/share/$$TARGET/lib/ bluez_install.files += $$PWD/bluez-qt/$$ARCH/lib/* bluez_install.CONFIG = no_check_exist INSTALLS += bluez_install
Для приложений ОС Аврора библиотеки должны поставляться в каталог
/usr/share/$$TARGET/lib/
, где$$TARGET
содержит название пакета приложения, состоящее из названия организации и названия приложения. Например,ru.auroraos.BluetoothChat
.
Конфигурация проекта на базе cmake
Для проектов на базе cmake идея добавления библиотеки к проекту та же, что и для qmake,
отличия лишь в синтаксисе.
Изменения, которые необходимо внести в файл CMakeLists.txt
:
add_library(bluez-qt SHARED IMPORTED)
set_target_properties(bluez-qt PROPERTIES IMPORTED_LOCATION
${CMAKE_SOURCE_DIR}/bluez-qt-bins/${CMAKE_SYSTEM_PROCESSOR}/lib/libKF6BluezQt.so)
target_include_directories(${PROJECT_NAME} PRIVATE
$<BUILD_INTERFACE:
${AURORA_INCLUDE_DIRS}
bluez-qt/${CMAKE_SYSTEM_PROCESSOR}/include/KF5/BluezQt/
>)
target_link_libraries(${PROJECT_NAME} PRIVATE
Qt5::Quick
${AURORA_LDFLAGS}
bluez-qt
)
install(DIRECTORY bluez-qt/${CMAKE_SYSTEM_PROCESSOR}/
DESTINATION share/${PROJECT_NAME}
)
- Переменная
CMAKE_SOURCE_DIR
содержит путь до текущего файлаCMakeLists.txt
. - Переменная
CMAKE_SYSTEM_PROCESSOR
содержит информацию о текущей архитектуре для сборки проекта (aarch64, armv7hl или x86_64). - Переменная
PROJECT_NAME
аналогична переменнойTARGET
, описанной выше для pro-файлов.
Поскольку RPM-пакет приложения будет поставлять в своём составе библиотеку, то необходимо
определить в spec-файле макросы __provides_exclude_from
и __requires_exclude
, чтобы генератор
зависимостей не сканировал определённые файлы или каталоги на предмет зависимостей.
Это делается для того, чтобы данный проект не предоставлял собственные библиотеки для других
RPM-архивов.
%define __provides_exclude_from ^%{_datadir}/%{name}/lib/.*$
%define __requires_exclude ^libKF6BluezQt.*$
После внесения описанных выше изменений:
- проект будет собираться с использованием заголовочных файлов и so-файлов библиотеки;
- все файлы собранной библиотеки будут упаковываться в итоговый RPM-пакет приложения во время его сборки.