Qt Remote Objects Compiler

REPC Überblick

Der Replica Compiler(repc) generiert QObject Header-Dateien auf der Grundlage einer API-Definitionsdatei. Die Datei (eine so genannte "rep"-Datei) verwendet eine spezifische (Text-)Syntax zur Beschreibung der API. Konventionell erhalten diese Dateien die Dateierweiterung .rep, kurz für Replica. Wenn diese Dateien von repc verarbeitet werden, erzeugt repc sowohl Source- als auch Replica-Header-Dateien.

Das Modul Qt Remote Objects enthält auch CMake-Funktionen und qmake-Variablen, die zu Ihrer Projektdatei hinzugefügt werden können, um repc automatisch auszuführen und die resultierenden Dateien zur Liste der Dateien hinzuzufügen, die vom Meta-Object Compiler während des Build-Prozesses verarbeitet werden, was die Verwendung von Qt Remote Objects in Ihren Projekten einfach macht.

Während Qt Remote Objects die gemeinsame Nutzung von QObject über das Netzwerk unterstützt (mit enableRemoting auf der Source-Seite und acquireDynamic auf der Replica-Seite), gibt es einige Vorteile, wenn Sie repc Ihre Objekte definieren lassen. Zunächst einmal ist DynamicReplicas zwar nützlich, aber auch umständlicher in der Handhabung. Die API ist nicht bekannt, bis das Objekt initialisiert ist, und die Verwendung der API von C++ aus erfordert String-Lookups durch die Methoden von QMetaObject. Zweitens ist die Schnittstelle bereits zur Kompilierzeit bekannt, so dass Probleme bei der Kompilierung und nicht erst zur Laufzeit auftreten. Drittens unterstützt das Replica-Format Standardwerte, was praktisch sein kann, wenn Sie nicht sicherstellen können, dass die Quelle verfügbar ist, wenn das Replica instanziert wird.

In der Dokumentation finden Sie Informationen zur Verwendung der generierten Dateien in Ihrem Code. Hier werden wir uns auf das repc-Format und die Optionen konzentrieren.

Das rep-Dateiformat

Das rep-Dateiformat ist eine einfache domänenspezifische Sprache (DSL) zur Beschreibung einer Schnittstelle, die über Qt Remote Objects (QtRO) unterstützt wird. Da QtRO ein objektbasiertes System ist, werden diese Schnittstellen durch APIs definiert, die über Objekte verfügbar sind, d.h. Klassen mit Eigenschaften, Signalen und Slots.

Der Klassentyp

Jede Klasse, die in einer Rep-Datei definiert ist, wird in den generierten Header-Dateien zu einer QObject, wobei die beschriebene API für Sie generiert wird.

Um eine Klasse zu definieren, verwenden Sie das Schlüsselwort class, gefolgt von dem Namen, den Sie für Ihren Typ verwenden möchten, und schließen Sie dann Ihre API in Klammern ein, wie folgt

class MyType
{
    //PROP/CLASS/MODEL/SIGNAL/SLOT/ENUM declarations to define your API
};

Wenn Sie die generierten Header-Dateien innerhalb einer Bibliothek verwenden, kann es erforderlich sein, Klassenattribute zu definieren, um die Sichtbarkeit von Symbolen festzulegen. Dies kann ähnlich wie in C++ geschehen, indem das Attribut nach dem Schlüsselwort class definiert wird. Im folgenden Beispiel wird das Makro MYSHAREDLIB_EXPORT verwendet, das in "mysharedlib_global.h" definiert ist. Weitere Informationen zur Funktionsweise finden Sie unter Erstellen gemeinsamer Bibliotheken.

#include "mysharedlib_global.h"
class MYSHAREDLIB_EXPORT MyType
{
    ...
};

PROP

Q_PROPERTY Elemente werden durch Verwendung des PROP-Schlüsselworts in der rep-Datei erstellt. Die Syntax ist das Schlüsselwort PROP, gefolgt von der in Klammern eingeschlossenen Definition, wobei die Definition aus dem Typ, dem Namen und (optional) einem Standardwert oder Attributen besteht.

PROP(bool simpleBool)                // boolean named simpleBool
PROP(bool defaultFalseBool=false)    // boolean named defaultFalseBool, with false
                                     // as the default value

PROP(int lifeUniverseEverything=42)  // int value that defaults to 42
PROP(QByteArray myBinaryInfo)        // Qt types are fine, may need #include
                                     // additional headers in your rep file

PROP(QString name CONSTANT)          // Property with the CONSTANT attribute
PROP(QString setable READWRITE)      // Property with the READWRITE attribute
                                     // note: Properties default to READPUSH
                                     // (see description below)

PROP(SomeOtherType myCustomType)     // Custom types work. Needs #include for the
                                     // appropriate header for your type, make
                                     // sure your type is known to the metabject
                                     // system, and make sure it supports Queued
                                     // Connections (see Q_DECLARE_METATYPE and
                                     // qRegisterMetaType)

Weitere Informationen zum Erstellen von benutzerdefinierten Typen finden Sie hier.

Standardmäßig sind für Eigenschaften Getter und ein "Push"-Slot definiert, sowie ein Notify-Signal, das ausgegeben wird, wenn der Wert geändert wird. Qt Remote Objects benötigt das Notify-Signal auf dem Source-Objekt, um das Senden von Updates an die angeschlossenen Replicas auszulösen. In früheren Versionen von QtRO waren Eigenschaften standardmäßig lesbar/schreibbar, d.h. sie hatten Getter und Setter. Aufgrund der asynchronen Natur von QtRO führte dies jedoch manchmal zu unintuitivem Verhalten. Durch das Setzen des READWRITE-Attributs auf das PROP wird das alte Verhalten (Getter und Setter) wiederhergestellt.

// In .rep file, old (setter) behavior
PROP(int myVal READWRITE)             // Old behavior with setMyVal(int myVal) method

// In code...  Assume myVal is initially set to 0 in Source
int originalValue = rep->myVal();     // Will be 0
rep->setMyVal(10);                    // Call setter, expecting a blocking/
                                      // non-asynchronous return

if (rep->myVal() == 10) ...           // Test will usually fail

Wenn es notwendig ist, zu blockieren, bis der Wert geändert wird, ist etwas wie das Folgende notwendig.

// In .rep file, old (setter) behavior
PROP(int myVal READWRITE)             // Old behavior with setMyVal(int myVal) method

// In code...  Assume myVal is initially set to 0 in Source
bool originalValue = rep->myVal();    // Will be 0

// We can wait for the change using \l QSignalSpy
QSignalSpy spy(rep, SIGNAL(myValChanged(int)));

rep->setMyVal(10);                    // Call setter, expecting a blocking/
                                      // non-asynchronous return

spy.wait();                           // spy.wait() blocks until changed signal
                                      // is received
if (rep->myVal() == 10) ...           // Test will succeed assuming
                                      // 1. Source object is connected
                                      // 2. Nobody else (Source or other Replica)
                                      //    sets the myVal to something else (race
                                      //    condition)
// Rather than use QSignalSpy, the event-driven practice would be to connect the
// myValChanged notify signal to a slot that responds to the changes.

QtRO setzt nun standardmäßig READPUSH ein, was einen automatisch generierten Slot für die Anforderung einer Eigenschaftsänderung bereitstellt.

// In .rep file, defaults to READPUSH
PROP(bool myVal)                      // No setMyVal(int myVal) on Replica, has
                                      // pushMyVal(int myVal) instead

// In code...  Assume myVal is initially set to 0 in Source
bool originalValue = rep->myVal();    // Will be 0

// We can wait for the change using \l QSignalSpy
QSignalSpy spy(rep, SIGNAL(myValChanged(int)));

rep->pushMyVal(10);                   // Call push method, no expectation that change
                                      // is applied upon method completion.

// Some way of waiting for change to be received by the Replica is still necessary,
// but hopefully not a surprise with the new pushMyVal() Slot.
spy.wait();                           // spy.wait() blocks until changed signal
                                      // is received
if (rep->myVal() == 10) ...           // Test will succeed assuming
                                      // 1. Source object is connected
                                      // 2. Nobody else (Source or other Replica)
                                      //    set the myVal to something else (race
                                      //    condition)

Sie können auch die Schlüsselwörter CONSTANT, READONLY, PERSISTED, READWRITE, READPUSH oder SOURCEONLYSETTER in der PROP-Deklaration verwenden, was die Implementierung der Eigenschaft beeinflusst. READPUSH ist der Standardwert, wenn kein Wert verwendet wird.

PROP(int lifeUniverseEverything=42 CONSTANT)
PROP(QString name READONLY)

Bitte beachten Sie, dass es hier einige Feinheiten gibt. Ein CONSTANT PROP hat eine Q_PROPERTY, die auf der SOURCE-Seite als CONSTANT deklariert ist. Die Replikate können den korrekten Wert jedoch erst kennen, wenn sie initialisiert werden, d. h. der Eigenschaftswert muss sich während der Initialisierung ändern dürfen. Für READONLY hat die Quelle weder einen Setter noch einen Push-Slot, und auf der Replikat-Seite wird kein Push-Slot erzeugt. Das Hinzufügen der PERSISTED-Eigenschaft zu einem PROP bewirkt, dass das PROP die QRemoteObjectAbstractPersistedStore -Instanz verwendet, die auf einem Knoten (falls vorhanden) eingestellt ist, um PROP-Werte zu speichern/wiederherzustellen.

Ein weiterer nuancierter Wert ist SOURCEONLYSETTER, der eine weitere Möglichkeit bietet, asymmetrisches Verhalten zu spezifizieren, wobei die Quelle (insbesondere die Hilfsklasse SimpleSource) einen öffentlichen Getter und Setter für die Eigenschaft hat, diese aber auf der Replica-Seite ReadOnly (mit einem Notify-Signal) ist. Somit kann die Eigenschaft von der Quellseite aus vollständig kontrolliert, von der Replikaseite aus aber nur beobachtet werden. SOURCEONLYSETTER ist der Modus, der von repc für MODEL und CLASS Instanzen verwendet wird, d.h. die Quelle kann das Objekt, auf das gezeigt wird, ändern, aber das Replikat kann kein neues Objekt bereitstellen, da keine set<Prop> oder push<Prop> Methode erzeugt wird. Beachten Sie, dass dies keinen Einfluss auf das Verhalten der Eigenschaften des Typs hat, auf den gezeigt wird, sondern nur auf die Möglichkeit, den Zeiger selbst zu ändern.

CLASS

Das Schlüsselwort CLASS erzeugt spezielle Q_PROPERTY Elemente für von QObject abgeleitete Objekte. Diese Eigenschaften haben die gleiche Semantik wie SOURCEONLYSETTER. Die Syntax ist das Schlüsselwort CLASS, gefolgt von dem Eigenschaftsnamen und dem Typ des Unterobjekts in Klammern.

// In .rep file
class OtherClass
{
    PROP(int value)
}

class MainClass
{
    CLASS subObject(OtherClass)
}

MODEL

Das Schlüsselwort MODEL erzeugt spezielle Q_PROPERTY Elemente für von QAbstractItemModel abgeleitete Objekte. Diese Eigenschaften haben die gleiche Semantik wie SOURCEONLYSETTER. Die Syntax besteht aus dem Schlüsselwort MODEL, gefolgt vom Eigenschaftsnamen und den in Klammern eingeschlossenen (durch Komma getrennten) Rollen, die der Nachbildung zugänglich gemacht werden sollen.

// In .rep file
class CdClass
{
    PROP(QString title READONLY)
    MODEL tracks(title, artist, length)
}

SIGNAL

Signalmethoden werden mit dem Schlüsselwort SIGNAL in der Replikationsdatei erstellt.

Die Verwendung besteht darin, SIGNAL zu deklarieren, gefolgt von der gewünschten Signatur, die in Klammern gesetzt wird. Der void-Rückgabewert sollte übersprungen werden.

SIGNAL(test())
SIGNAL(test(QString foo, int bar))
SIGNAL(test(QMap<QString,int> foo))
SIGNAL(test(const QString &foo))
SIGNAL(test(QString &foo))

Genau wie in Qt queued connections werden Parameter in Signalen, die Referenzen sind, kopiert, wenn sie an Replikate übergeben werden.

SLOT

Slot-Methoden werden mit dem SLOT-Schlüsselwort in der rep-Datei erstellt.

Die Verwendung besteht darin, SLOT zu deklarieren, gefolgt von der gewünschten Signatur, die in Klammern gesetzt wird. Der Rückgabewert kann in die Deklaration aufgenommen werden. Wenn der Rückgabewert weggelassen wird, wird in den generierten Dateien void verwendet.

SLOT(test())
SLOT(void test(QString foo, int bar))
SLOT(test(QMap<QString,int> foo))
SLOT(test(QMap<QString,int> foo, QMap<QString,int> bar))
SLOT(test(QMap<QList<QString>,int> foo))
SLOT(test(const QString &foo))
SLOT(test(QString &foo))
SLOT(test(const QMap<QList<QString>,int> &foo))
SLOT(test(const QString &foo, int bar))

Genau wie in Qt queued connections und QtRO SIGNALS werden Parameter in Slots, die Referenzen sind, kopiert, wenn sie an Replicas übergeben werden.

ENUM

Aufzählungen (die eine Kombination aus C++ enum und Qt's Q_ENUM in QtRO verwenden) werden mit dem ENUM Schlüsselwort beschrieben.

ENUM MyEnum {Foo}
ENUM MyEnum {Foo, Bar}
ENUM MyEnum {Foo, Bar = -1}
ENUM MyEnum {Foo=-1, Bar}
ENUM MyEnum {Foo=0xf, Bar}
ENUM MyEnum {Foo=1, Bar=3, Bas=5}

Verwandte Themen: Der ENUM-Typ, USE_ENUM-Schlüsselwort

Der POD-Typ

Plain Old Data (POD) ist ein Begriff zur Beschreibung einer einfachen Datensammlung, ähnlich wie eine C++-Struktur. Wenn Sie z. B. eine API für ein Telefonbuch haben, möchten Sie vielleicht das Konzept einer "Adresse" in der Schnittstelle verwenden (wobei die Adresse Straße, Stadt, Bundesland, Land und Postleitzahl enthalten kann). Sie können das Schlüsselwort POD verwenden, um solche Objekte zu definieren, die dann in PROP/SIGNAL/SLOT-Definitionen in Ihren Klassendefinitionen verwendet werden können.

Die Verwendung besteht darin, POD zu deklarieren, gefolgt vom Namen des generierten Typs, gefolgt von Typ- und Namenspaaren, die durch Kommata getrennt sind, wobei die Typ/Namenspaare in Klammern eingeschlossen sind.

POD Foo(int bar)
POD Foo(int bar, double bas)
POD Foo(QMap<QString,int> bar)
POD Foo(QList<QString> bar)
POD Foo(QMap<QString,int> bar, QMap<double,int> bas)

Ein vollständiges Beispiel würde wie folgt aussehen

POD Foo(QList<QString> bar)
class MyType
{
    SIGNAL(sendCustom(Foo foo));
};

Der von repc generierte Code erstellt für jeden POD eine Klasse Q_GADGET mit entsprechenden Q_PROPERTY Mitgliedern für jeden für den POD definierten Typ.

Bei der Verwendung der generierten Header-Dateien innerhalb einer Bibliothek kann es erforderlich sein, Klassenattribute zu definieren, um die Sichtbarkeit von Symbolen festzulegen. Dies kann durch die Definition des Attributs nach dem Schlüsselwort POD erfolgen. Im folgenden Beispiel wird das Makro MYSHAREDLIB_EXPORT verwendet, das in "mysharedlib_global.h" definiert ist. Weitere Informationen zur Funktionsweise finden Sie unter Gemeinsame Bibliotheken erstellen.

#include "mysharedlib_global.h"
POD MYSHAREDLIB_EXPORT Foo(int bar)

Der ENUM-Typ

Oft ist es einfacher und sauberer, ein ENUM innerhalb einer Klasse zu definieren (siehe ENUM), aber wenn Sie einen eigenständigen Enum-Typ benötigen, kann die Verwendung des ENUM-Schlüsselworts außerhalb einer Klassendefinition hilfreich sein. Dadurch wird eine neue Klasse in Ihren Header-Dateien erzeugt, die das Marshalling usw. übernimmt. Die Syntax ist identisch mit ENUM, mit der Ausnahme, dass die Deklaration in diesem Fall nicht in einer class Deklaration enthalten ist.

Verwandte Themen: ENUM, USE_ENUM-Schlüsselwort

USE_ENUM-Schlüsselwort

Das USE_ENUM-Schlüsselwort wurde implementiert, bevor die automatische Generierung über das ENUM-Schlüsselwort eingeführt wurde. Es wird aus Gründen der Abwärtskompatibilität beibehalten.

Verwandte Themen: ENUM, Der ENUM-Typ

Direktiven

Die rep-Datei definiert eine Schnittstelle, aber Schnittstellen erfordern oft externe Elemente. Um dies zu unterstützen, fügt repc beliebige (einzeilige) Direktiven an den Anfang der erzeugten Dateien. So können Sie zum Beispiel #include- oder #define-Direktiven verwenden, die die benötigte Logik oder Datentypen unterstützen.

Das repc-Tool ignoriert derzeit alles vom "#"-Symbol bis zum Zeilenende und fügt es den generierten Dateien hinzu. Mehrzeilige #if/#else/#endif-Anweisungen und mehrzeilige Makros werden also nicht unterstützt.

Es gibt zwei spezielle Direktiven, #HEADER und #FOOTER. Diese Direktiven können verwendet werden, um Inhalte zu definieren, die im generierten Code entweder vor (HEADER) oder nach (FOOTER) der Schnittstellendeklaration eingefügt werden sollen. Die führenden Zeichen #HEADER und #FOOTER sowie ein Leerzeichen werden entfernt.

Im folgenden Beispiel werden die generierten repc-Klassen in einen Namespace eingefügt.

#HEADER namespace MyNamespace {
class MyType
{
    ...
};
#FOOTER } // namespace MyNamespace

CMake-Funktionen

Die CMake-Funktionen zur Erzeugung von Quell- und Replikat-Typen sind im Folgenden aufgeführt.

qt_add_repc_merged

Erzeugt C++-Header-Dateien für Quell- und Replikat-Typen aus den Qt Remote Objects.rep-Dateien.

qt_add_repc_replicas

Erzeugt C++-Header-Dateien für Replikat-Typen aus den Qt Remote Objects.rep-Dateien.

qt_add_repc_sources

Erzeugt C++-Header-Dateien für Quelltypen aus den Qt Remote Objects.rep-Dateien.

qt_reps_from_headers

Erzeugt .rep-Dateien aus den QObject-Header-Dateien.

qmake-Variablen

REPC_REPLICA

Gibt die Namen aller Rep-Dateien im Projekt an, die zur Erzeugung von Replica-Header-Dateien verwendet werden sollen.

Zum Beispiel:

REPC_REPLICA = media.rep \
               location.rep

Die erzeugte(n) Datei(en) haben die Form rep_<replica file base>_replica.h.

REPC_SOURCE

Gibt die Namen aller Replikationsdateien im Projekt an, die zur Erzeugung von Quelltext-Header-Dateien verwendet werden sollen.

Zum Beispiel:

REPC_SOURCE = media.rep \
              location.rep

Die generierte(n) Datei(en) haben die Form rep_<replica file base>_source.h.

REPC_MERGED

Gibt die Namen aller Replikationsdateien im Projekt an, die verwendet werden sollen, um kombinierte (Quell- und Replikations-) Header-Dateien zu erzeugen.

Zum Beispiel:

REPC_MERGED = media.rep \
              location.rep

Die generierte(n) Datei(en) haben die Form rep_<replica file base>_merged.h.

Hinweis: Normalerweise befinden sich Quellen und Replikate in getrennten Prozessen oder Geräten, daher wird diese Variable normalerweise nicht verwendet.

QOBJECT_REP

Gibt die Namen bestehender QObject Header-Dateien an, die verwendet werden sollen, um entsprechende .rep-Dateien zu erzeugen.

Siehe auch QRemoteObjectAbstractPersistedStore.

© 2025 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.