Yocto – SQL-Datenbanken in Qt einbinden

Eine häufige Anforderung bei Embedded-Applikationen ist der Zugriff auf Datenbanken – sei es zum Lesen von Sensordaten oder zum Speichern von Benutzerkonfigurationen.

Qt bringt mit seinem QtSQL-Modul eine solide Grundlage dafür mit. Allerdings ist die Einbindung von SQL-Treibern unter Yocto nicht ganz trivial, da diese nicht standardmäßig mitgebaut werden – meist aufgrund lizenzrechtlicher Einschränkungen.

In diesem Beitrag zeige ich, wie man mit Yocto ein Image erstellt, das SQL-Treiber für MySQL/MariaDB und ODBC enthält – inklusive einer Demo-Anwendung, die auch Zugriff auf einen Microsoft SQL Server via FreeTDS demonstriert.

SQL-Unterstützung im QtSQL-Modul aktivieren

Im Layer meta-qt6, konkret in qtbase_git.bb, findet sich eine Konfigurationsmöglichkeit für optionale SQL-Treiber:

Um beispielsweise MySQL und ODBC zu aktivieren, erweitern wir die Variable PACKAGECONFIG entsprechend.

Für eine bessere Übersicht erstelle ich im Layer meta-raspilab folgende Struktur:

In diesem Datei erstelle ich nun die Datei qtbase_git.bbappend mit folgendem Inhalt.

Damit werden automatisch unixodbc, libmysqlclient (bzw. mariadb) sowie die benötigten Qt-Treiber mit ins Image aufgenommen.

Microsoft SQL Server per ODBC/FreeTDS

ODBC ist eine standardisierte Schnittstelle zum Zugriff auf Datenbanken verschiedenster Hersteller.
Microsoft stellt zwar einen eigenen ODBC-Treiber für Linux zur Verfügung, dieser liegt jedoch nur als Binary-Paket vor und ist weder quelloffen noch für ARM-Architekturen verfügbar – und somit für Yocto nicht nutzbar.

Die Lösung: FreeTDS – ein Open-Source-Treiber für das TDS-Protokoll (Tabular Data Stream), das u. a. von Microsoft SQL Server und Sybase verwendet wird.

Da das Rezept aus meta-parallel-php teils veraltete oder problematische Konfigurationen verwendet, stelle ich ein eigenes Rezept in meta-raspilab in folgender Verzeichnisstrutur bereit.

Treiber-Registrierung

ODBC benötigt zwei zentrale Konfigurationsdateien, die für den Betrieb unerlässlich sind, odbcinst.ini und odbc.ini. Das Rezept bringt den Teil zur Registrierung des Treibers in der /etc/odbcinst.ini direkt mit

Die Datei odbcinst.ini enthält die Definitionen der verfügbaren ODBC-Treiber auf dem System.
Jeder Treiber (z. B. FreeTDS, PostgreSQL, SQLite) wird hier mit Name und Pfad zur .so-Datei registriert.

Bereitstellung unter Yocto

Da unixodbc bereits beim Paketbau die datei /etc/odbcinst.ini anlegt, dürfen wir sie nicht direkt überschreiben. Stattdessen wird eine Datei odbcinst.ini.append erstellt, die im Recipe freetds enthalten ist. Diese Datei wird bei erster Ausführung auf dem Zielsystem per pkg_postinst_ontarget an /etc/odbcinst.ini angehängt, ohne bestehende Inhalte zu löschen.

Warum nicht direkt /etc/odbc*.ini ersetzen?

Yocto erlaubt es nicht, systemeigene Dateien anderer Pakete direkt zu überschreiben. Würde man das tun, käme es zu QA-Fehlern im Buildprozess (installed-vs-shipped). Durch die Nutzung von *.append-Dateien und Laufzeit-Erweiterung bleibt das System paketkonform und wartbar.

Qt-Demoanwendung für SQL-Datenbanken

Zur Verifikation verwende ich eine kleine Qt6-Anwendung, die sich via ODBC mit einem MS SQL Server verbindet. Für die Demoanwendung erstelle ich unter recipes-applications ein Verzeichnis sqldemo in dem sich alle Dateien zum erstellen der Anwendung befinden.

DSN-Konfiguration

Die Datei /etc/odbc.ini beschreibt die Datenquellen (DSNs), mit denen Programme über ODBC kommunizieren können.

Bereitstellung unter Yocto

Auch hier wird die Datei nicht direkt ersetzt. In der Demo-Anwendung (sqldemo) liegt eine Datei odbc.ini.append. Diese wird zur Laufzeit beim ersten Systemstart (ebenfalls via pkg_postinst_ontarget) an /etc/odbc.ini angehängt.

Die wichtigsten Informationen sind die DSN (WinSRV02), die IP-Adresse und die zu verwendende Datenbank. Benutzername und Passwort gebe ich hier nicht an, die Daten kann ich später in der Anwendung angeben.

Die Quelltexte der Anwendung hänge ich gleich nach dem Screenshot an diesen Beitrag, sie können aber auch auf meinem Github-Repository gefunden werden.