Документация
ОС Аврора 5.1.4

Сборка библиотек на примере bluez-qt

Руководство описывает процесс сборки и подключения к проекту приложения библиотеки bluez-qt, а также сложности и пути их решения на разных этапах.

Для работы использовалась bluez-qt версии 6.1.0.

Содержание:

Сборка библиотеки

Сборка бинарных артефактов библиотеки под ОС Аврора может выполняться с использованием двух разных инструментов:

  1. С помощью Аврора Build Engine, входящего в состав Аврора SDK (MB2).
  2. С помощью Аврора Platform SDK.

Шаги по сборке

Предварительная настройка:

  1. Перейти в сборочное окружение.

    Для Аврора 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 для последующей сборки.

    Следующие шаги индентичны для всех сборочных интрументов.

  2. Перейти в окружение ScratchBox2.

    sb2 -t AuroraOS-5.1.3.85-MB2-armv7hl -R
    
    • Параметр -t задаёт цель для сборочного окружения. Список доступных целей можно получить с помощью команды sdk-manage target list.
    • Параметр -R запускает сборочное окружение с правами суперпользователя.
  3. Установить переменные окружения, отвечающие за сборку. При обычном запуске окружения ScratchBox2 их настройка не происходит. Для их установки необходимо выполнить следующую команду:

    eval $(rpm --eval '%set_build_flags')
    
    • Субкоманда rpm --eval '%set_build_flags' выводит команды для настройки переменных окружения.
    • Субкоманда eval $(...) передаёт вывод первой субкоманды на вход встроенной в Bash команды eval, которая исполняет команды в рамках текущей сессии интерпретатора.

    В результате выполнения данной команды будут установлены значения переменных окружения для сборки: CFLAGS, CXXFLAGS, FFLAGS, FCFlAGS, LDFLAGS. Обязательно следует учитывать их наличие и их значения. Затирание значений данных переменных может привести к проблемам сборки бинарных артефактов.
    Следует обратить внимание, что при завершении работы окружения ScratchBox2 установленные переменные окружения будут сброшены.

  4. Выполнить установку пути для поиска динамических библиотек rpath. Это делается путём изменения флагов компоновщика следующим образом:

    LDFLAGS="$LDFLAGS -Wl,-rpath=%{_datadir}/%{name}/lib"
    

    С помощью комбинации макросов %{_datadir} и %{name} указывается стандартное для ОС Аврора расположение разделяемых библиотек, поставляемых вместе с приложением.

Сборка библиотеки bluez-qt выполняется с помощью утилиты cmake. Сборка выполняется в два этапа:

  1. Генерация Makefile-файлов.
  2. Сборка бинарных артефактов.

Для генерации 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, которая в итоге увенчалась успехом.

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

  1. Настройка значения REQUIRED_QT_VERSION в файле CMakeLists.txt в корне проекта:

    - set(REQUIRED_QT_VERSION 6.5.0)
    + set(REQUIRED_QT_VERSION 5.6.3)
    
  2. Настройка значения ecm_set_disabled_deprecation_versions в файле CMakeLists.txt в корне проекта:

     ecm_set_disabled_deprecation_versions(
    -    QT 6.5
    +    QT 5.6
     )
    
  3. Замена всех упоминаний 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/

Для подключения библиотеки к проекту приложения необходимо:

  1. Положить каталог с собранными файлами библиотеки (bluez-qt/) в корень проекта.
  2. Описать пути к .so-файлам библиотек и к заголовочным файлам в pro-файле (или в файле CMakeLists.txt, если используется сборка с помощью CMake).
  3. Описать исключение для so-файлов библиотек, чтобы генератор зависимостей не сканировал их как зависимости проекта.

Конфигурация проекта на базе qmake

Для проектов на базе qmake, чтобы иметь возможность использовать библиотеку, необходимо в pro-файле проекта описать следующее.

  1. Получить информацию о текущей архитектуре для сборки.

    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 потребуется далее для указания путей к файлам библиотеки.

  2. Настроить переменные 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.

  3. Указать цель для установки файлов библиотеки в итоговый 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-пакет приложения во время его сборки.

Мы используем cookies для персонализации сайта и его более удобного использования. Вы можете запретить cookies в настройках браузера.

Пожалуйста ознакомьтесь с политикой использования cookies.