Sur cette page

Qt Remote Objects Compilateur

Présentation de REPC

Le compilateur Replica(repc) génère des fichiers d'en-tête « QObject » à partir d'un fichier de définition d'API. Ce fichier (appelé fichier « rep ») utilise une syntaxe (textuelle) spécifique pour décrire l’API. Par convention, ces fichiers portent l’extension .rep, abréviation de Replica. Lorsque ces fichiers sont traités par repc, celui-ci génère à la fois des fichiers d’en-tête Source et Replica.

Le module Qt Remote Objects comprend également des fonctions CMake et des variables qmake qui peuvent être ajoutées à votre fichier de projet pour exécuter automatiquement repc et ajouter les fichiers résultants à la liste des fichiers traités par le Meta-Object Compiler pendant le processus de compilation, ce qui simplifie l’utilisation d’ Qt Remote Objects dans vos projets.

Bien que l’ Qt Remote Objects prenne en charge le partage de n’importe quel objet « QObject » sur le réseau (à l’aide de `enableRemoting` côté Source et de `acquireDynamic` côté Replica), le fait de laisser repc définir vos objets présente plusieurs avantages. Tout d’abord, bien que les objets « DynamicReplicas » soient utiles, ils sont plus lourds à manipuler. L’API n’est pas connue tant que l’objet n’est pas initialisé, et l’utilisation de l’API depuis C++ nécessite des recherches de chaînes de caractères via les méthodes de QMetaObject. Deuxièmement, le fait de connaître l’interface au moment de la compilation permet de détecter d’éventuels problèmes lors de la compilation plutôt qu’au moment de l’exécution. Enfin, le format REP prend en charge les valeurs par défaut, ce qui peut s’avérer pratique si vous ne pouvez pas garantir que la source soit disponible lors de l’instanciation de la réplique.

Consultez la documentation ici pour plus d’informations sur l’utilisation des fichiers générés dans votre code. Nous nous concentrerons ici sur le format repc et ses options.

Le format de fichier rep

Le format de fichier rep est un langage spécifique au domaine (DSL) simple permettant de décrire une interface prise en charge par QtRO ( Qt Remote Objects ). QtRO étant un système orienté objet, ces interfaces sont définies par des API accessibles via des objets, c'est-à-dire des classes dotées de propriétés, de signaux et de slots.

Commentaires

Les commentaires sur une seule ligne au format C++ (// text ) ainsi que les commentaires sur plusieurs lignes au format C (/* text * / ) sont pris en charge.

Le type de classe

Chaque classe définie dans un fichier rep devient une QObject dans les fichiers d’en-tête générés, avec l’API décrite générée pour vous.

Pour définir une classe, utilisez le mot-clé « class », suivi du nom que vous souhaitez donner à votre type, puis placez votre API entre crochets comme ceci

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

Lorsque vous utilisez les fichiers d’en-tête générés au sein d’une bibliothèque, il peut s’avérer nécessaire de définir des attributs de classe pour définir la visibilité des symboles. Cela peut être effectué de manière similaire au C++ en définissant l’attribut après le mot-clé « class ». Dans l’exemple suivant, la macro « MYSHAREDLIB_EXPORT » est utilisée ; elle est définie dans "mysharedlib_global.h". Consultez la section Création de bibliothèques partagées pour plus d’informations sur son fonctionnement.

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

Les éléments

Q_PROPERTY sont créés à l’aide du mot-clé PROP dans le fichier rep. La syntaxe est la suivante : le mot-clé PROP suivi de la définition entre parenthèses, où la définition comprend le type, le nom et (facultativement) une valeur par défaut ou des attributs.

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)

Vous trouverez ici plus d’informations sur la création de types personnalisés.

Par défaut, les propriétés disposent de getters et d’un slot « push » défini, ainsi que d’un signal « notify » émis lorsque la valeur est modifiée. « Qt Remote Objects » nécessite que le signal « notify » de l’objet Source déclenche l’envoi de mises à jour aux répliques associées. Dans les versions antérieures de QtRO, les propriétés étaient par défaut en lecture/écriture, c’est-à-dire qu’elles disposaient de getters et de setters. Cependant, en raison de la nature asynchrone de QtRO, cela entraînait parfois un comportement peu intuitif. La définition de l’attribut READWRITE sur la propriété PROP permettra de retrouver l’ancien comportement (getter et setter).

// 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

S’il est nécessaire de bloquer l’exécution jusqu’à ce que la valeur soit modifiée, il faut utiliser un code similaire à celui-ci.

// 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 utilise désormais READPUSH par défaut, ce qui fournit un slot généré automatiquement pour demander une modification de propriété.

// 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)

Vous pouvez également utiliser les mots-clés CONSTANT, READONLY, PERSISTED, READWRITE, READPUSH ou SOURCEONLYSETTER dans la déclaration de la PROP, ce qui influe sur la manière dont la propriété est implémentée. READPUSH est la valeur par défaut si aucune valeur n’est spécifiée.

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

Veuillez noter qu’il existe ici certaines subtilités. Une propriété CONSTANT PROP dispose d’un emplacement « Q_PROPERTY » déclaré comme CONSTANT du côté SOURCE. Cependant, les répliques ne peuvent pas connaître la valeur correcte tant qu’elles ne sont pas initialisées, ce qui signifie que la valeur de la propriété doit pouvoir changer pendant l’initialisation. Pour READONLY, la source ne disposera ni d’un setter ni d’un slot push, et aucun slot push ne sera généré du côté des répliques. L’ajout du trait PERSISTED à une PROP permettra à celle-ci d’utiliser l’instance d’ QRemoteObjectAbstractPersistedStore définie sur un nœud (le cas échéant) pour enregistrer/restaurer les valeurs de la PROP.

Une autre valeur nuancée est SOURCEONLYSETTER, qui offre une autre façon de spécifier un comportement asymétrique : la source (plus précisément la classe d’aide SimpleSource) disposera d’un getter et d’un setter publics pour la propriété, mais celle-ci sera en lecture seule (avec un signal de notification) du côté de la réplique. Ainsi, la propriété peut être entièrement contrôlée du côté de la source, mais uniquement observée du côté de la réplique. SOURCEONLYSETTER est le mode utilisé par repc pour les instances MODEL et CLASS, ce qui signifie que la source peut modifier l’objet pointé, mais que la réplique ne peut pas fournir de nouvel objet, car aucune méthode set<Prop> ou push<Prop> n’est générée. Notez que cela n’a pas d’incidence sur le comportement des propriétés du type pointé, mais uniquement sur la possibilité de modifier le pointeur lui-même.

CLASS

Le mot-clé CLASS génère des éléments d’ Q_PROPERTY s spéciaux pour les objets dérivés de QObject. Ces propriétés ont la même sémantique que SOURCEONLYSETTER. La syntaxe est le mot-clé CLASS suivi du nom de la propriété, puis du type du sous-objet entre parenthèses.

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

class MainClass
{
    CLASS subObject(OtherClass)
}

MODEL

Le mot-clé MODEL génère des éléments d'Q_PROPERTY s spéciaux pour les objets dérivés de QAbstractItemModel. Ces propriétés ont la même sémantique que SOURCEONLYSETTER. La syntaxe est la suivante : le mot-clé MODEL suivi du nom de la propriété, puis de parenthèses renfermant les rôles (séparés par des virgules) qui doivent être exposés à la réplique.

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

SIGNAL

Les méthodesde signal sont créées à l’aide du mot-clé SIGNAL dans le fichier rep.

Pour les utiliser, il faut déclarer « SIGNAL » suivi de la signature souhaitée entre parenthèses. La valeur de retour « void » doit être omise.

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

Tout comme dans les « queued connections » de Qt XML, les paramètres des signaux qui sont des références seront copiés lorsqu’ils seront transmis aux répliques.

SLOT

Les méthodesde slot sont créées à l'aide du mot-clé SLOT dans le fichier rep.

Pour les utiliser, il suffit de déclarer ` SLOT ` suivi de la signature souhaitée entre parenthèses. La valeur de retour peut être incluse dans la déclaration. Si la valeur de retour est omise, `void` sera utilisé dans les fichiers générés.

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))

Tout comme dans les « queued connections » Qt XML et les « QtRO SIGNALS », les paramètres des slots qui sont des références seront copiés lorsqu’ils seront transmis aux répliques.

ENUM

Les énumérations (qui utilisent une combinaison de l’énumération C++ et des « Q_ENUM » de Qt dans QtRO) sont décrites à l’aide du mot-clé ENUM.

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}

Sujets connexes : Le type ENUM, le mot-clé USE_ENUM

Le type POD

« Plain Old Data » (POD) est un terme utilisé pour décrire un ensemble de données simple, à l’instar d’une structure C++. Par exemple, si vous disposez d’une API pour un annuaire téléphonique, vous pouvez souhaiter utiliser le concept d’« adresse » dans son interface (où l’adresse peut inclure la rue, la ville, la région, le pays et le code postal). Vous pouvez utiliser le mot-clé POD pour définir des objets de ce type, qui pourront ensuite être utilisés dans les définitions PROP/SIGNAL/SLOT de vos classes.

Pour l'utiliser, il faut déclarer « POD », suivi du nom du type généré, puis des paires type/nom séparées par des virgules, ces paires étant placées entre parenthèses.

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)

Voici un exemple complet :

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

Le code généré par repc crée une classe d’ Q_GADGET s pour chaque POD, avec des membres d’ Q_PROPERTY correspondants pour chaque type défini pour le POD.

Lors de l’utilisation des fichiers d’en-tête générés au sein d’une bibliothèque, il peut s’avérer nécessaire de définir des attributs de classe afin de définir la visibilité des symboles. Cela peut être effectué en définissant l’attribut après le mot-clé ` POD `. Dans l’exemple suivant, la macro ` MYSHAREDLIB_EXPORT ` est utilisée ; celle-ci est définie dans ` "mysharedlib_global.h"`. Consultez la section « Création de bibliothèques partagées » pour plus d’informations sur son fonctionnement.

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

Le type ENUM

Il est souvent plus simple et plus clair de définir un ENUM à l’intérieur d’une classe (voir ENUM), mais si vous avez besoin d’un type ENUM autonome, l’utilisation du mot-clé ENUM en dehors d’une définition de classe peut s’avérer utile. Cela générera une nouvelle classe dans vos fichiers d’en-tête qui gère le marshalling, etc. La syntaxe est identique à celle d’ENUM, à l’exception du fait que, dans ce cas, la déclaration n’est pas contenue dans une déclaration de type « class ».

Sujets connexes : ENUM, mot-clé USE_ENUM

Mot-clé USE_ENUM

Le mot-clé USE_ENUM a été implémenté avant l’ajout de la génération automatique via le mot-clé ENUM. Il est conservé pour des raisons de compatibilité ascendante.

Sujets connexes : ENUM, le type ENUM

Directives

Le fichier rep définit une interface, mais les interfaces nécessitent souvent des éléments externes. Pour prendre cela en charge, repc inclura toutes les directives (sur une seule ligne) en haut des fichiers générés. Cela vous permet, par exemple, d’utiliser des directives #include ou #define qui prennent en charge la logique ou les types de données nécessaires.

L'outil repc ignore actuellement tout ce qui se trouve entre le symbole « # » et la fin de ligne, et ajoute cette partie aux fichiers générés. Les instructions #if/#else/#endif sur plusieurs lignes ainsi que les macros sur plusieurs lignes ne sont donc pas prises en charge.

Il existe deux directives spéciales : #HEADER et #FOOTER. Ces directives peuvent être utilisées pour définir du contenu qui doit être inséré tel quel dans le code généré, soit avant (HEADER), soit après (FOOTER) la déclaration des interfaces. Les tokens #HEADER et #FOOTER en début de ligne, suivis d’un espace, sont supprimés.

Dans l’exemple suivant, les classes repc générées sont placées dans un espace de noms.

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

Fonctions CMake

Les fonctions CMake permettant de générer des types source et réplica sont répertoriées ci-dessous.

qt_add_repc_merged

Crée des fichiers d’en-tête C++ pour les types source et réplica à partir des fichiers .rep de Qt Remote Objects.

qt_add_repc_replicas

Crée des fichiers d'en-tête C++ pour les types de réplique à partir des fichiers .rep de Qt Remote Objects.

qt_add_repc_sources

Crée des fichiers d'en-tête C++ pour les types source à partir des fichiers .rep de Qt Remote Objects.

qt_reps_from_headers

Crée des fichiers .rep à partir des fichiers d'en-tête QObject.

Variables qmake

REPC_REPLICA

Spécifie les noms de tous les fichiers .rep du projet qui doivent être utilisés pour générer des fichiers d'en-tête de réplique.

Par exemple :

REPC_REPLICA = media.rep \
               location.rep

Le ou les fichiers générés auront la forme suivante : rep_<replica file base>_replica.h.

REPC_SOURCE

Spécifie les noms de tous les fichiers rep du projet qui doivent être utilisés pour générer les fichiers d'en-tête source.

Par exemple :

REPC_SOURCE = media.rep \
              location.rep

Le ou les fichiers générés auront la forme rep_<replica file base>_source.h.

REPC_MERGED

Spécifie les noms de tous les fichiers « rep » du projet qui doivent être utilisés pour générer des fichiers d'en-tête combinés (source et réplique).

Par exemple :

REPC_MERGED = media.rep \
              location.rep

Le ou les fichiers générés auront la forme rep_<replica file base>_merged.h.

Remarque : en général , les sources et les répliques se trouvent dans des processus ou des périphériques distincts ; cette variable n'est donc pas couramment utilisée.

QOBJECT_REP

Spécifie les noms des fichiers d'en-tête QObject existants qui doivent être utilisés pour générer les fichiers .rep correspondants.

Voir également QRemoteObjectAbstractPersistedStore.

© 2026 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.