Qt Remote Objects 컴파일러
REPC 개요
레플리카 컴파일러(repc)는 API 정의 파일을 기반으로 QObject 헤더 파일을 생성합니다. 이 파일("rep" 파일이라고 함)은 특정 (텍스트) 구문을 사용하여 API를 설명합니다. 관례에 따라 이러한 파일에는 Replica의 약자인 .rep 파일 확장자가 지정됩니다. 이러한 파일이 repc에 의해 처리되면 repc는 소스 및 복제 헤더 파일을 모두 생성합니다.
Qt Remote Objects 모듈에는 프로젝트 파일에 추가하여 repc를 자동으로 실행하고 결과 파일을 빌드 프로세스 중에 Meta-Object Compiler가 처리한 파일 목록에 추가할 수 있는 CMake 함수와 qmake 변수도 포함되어 있어 프로젝트에서 Qt Remote Objects 을 간편하게 사용할 수 있습니다.
Qt Remote Objects 는 네트워크를 통한 QObject 공유를 지원하지만(소스 쪽에서는 enableRemoting, 리플리카 쪽에서는 acquireDynamic 사용), repc가 오브젝트를 정의하도록 하면 몇 가지 장점이 있습니다. 우선, DynamicReplicas 은 유용하지만 작업하기가 더 번거롭습니다. 개체가 초기화될 때까지 API를 알 수 없으며, C++에서 API를 사용하려면 QMetaObject 의 메서드를 통해 문자열을 조회해야 합니다. 둘째, 컴파일 시점에 인터페이스를 알면 컴파일 시와 런타임 시점에 문제를 발견할 수 있습니다. 셋째, 레플리카가 인스턴스화될 때 소스를 사용할 수 있는지 확인할 수 없는 경우 유용하게 사용할 수 있는 기본값을 지원합니다.
코드에서 생성된 파일을 사용하는 방법에 대한 자세한 내용은 여기 문서를 참조하세요. 여기서는 repc 형식과 옵션에 중점을 두겠습니다.
rep 파일 형식
rep 파일 형식은 Qt Remote Objects (QtRO)를 통해 지원되는 인터페이스를 설명하기 위한 간단한 도메인별 언어(DSL) 입니다. QtRO는 객체 기반 시스템이므로 이러한 인터페이스는 객체, 즉 속성, 신호 및 슬롯이 있는 클래스를 통해 사용할 수 있는 API로 정의됩니다.
클래스 유형
렙 파일에 정의된 각 클래스는 생성된 헤더 파일에서 QObject 이 되며, 설명된 API가 생성됩니다.
클래스를 정의하려면 class
키워드 다음에 원하는 유형 이름을 입력한 다음 다음과 같이 괄호 안에 API를 묶습니다.
class MyType { //PROP/CLASS/MODEL/SIGNAL/SLOT/ENUM declarations to define your API };
라이브러리 내에서 생성된 헤더 파일을 사용할 때 심볼 가시성을 설정하기 위해 클래스 속성을 정의해야 할 수도 있습니다. 이는 C++와 유사하게 class
키워드 뒤에 속성을 정의하여 수행할 수 있습니다. 다음 예에서는 "mysharedlib_global.h"
에 정의된 MYSHAREDLIB_EXPORT
매크로가 사용됩니다. 자세한 내용은 공유 라이브러리 만들기를 참조하세요.
#include "mysharedlib_global.h" class MYSHAREDLIB_EXPORT MyType { ... };
PROP
Q_PROPERTY 요소는 rep 파일에서 PROP 키워드를 사용하여 만듭니다. 구문은 PROP
키워드 뒤에 괄호로 묶인 정의가 오는데, 여기서 정의는 유형, 이름 및 (선택 사항으로) 기본값 또는 속성입니다.
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)
사용자 정의 유형 만들기에 대한 자세한 내용은 여기에서 확인할 수 있습니다.
기본적으로 속성에는 값이 변경될 때 발생하는 알림 신호뿐만 아니라 게터와 "푸시" 슬롯이 정의되어 있습니다. Qt Remote Objects 소스 개체의 알림 신호가 있어야 연결된 리플리카에 업데이트 전송을 트리거할 수 있습니다. 이전 버전의 QtRO에서 프로퍼티는 기본적으로 읽기/쓰기, 즉 게터와 세터가 있는 것으로 설정되어 있었습니다. 하지만 비동기식인 QtRO의 특성으로 인해 때때로 직관적이지 않은 동작이 발생했습니다. PROP에 READWRITE 속성을 설정하면 이전(게터 및 세터) 동작이 제공됩니다.
// 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
값이 변경될 때까지 차단해야 하는 경우 다음과 같은 조치가 필요합니다.
// 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는 속성 변경 요청을 위해 자동으로 생성된 슬롯을 제공하는 READPUSH를 기본값으로 설정합니다.
// 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)
또한 PROP 선언에 CONSTANT
, READONLY
, PERSISTED
, READWRITE
, READPUSH
, SOURCEONLYSETTER
키워드를 사용하여 프로퍼티가 구현되는 방식에 영향을 줄 수 있습니다. 값을 사용하지 않으면 기본값은 READPUSH입니다.
PROP(int lifeUniverseEverything=42 CONSTANT) PROP(QString name READONLY)
여기에는 몇 가지 미묘한 차이가 있습니다. CONSTANT PROP에는 SOURCE 쪽에 Q_PROPERTY 이 CONSTANT로 선언되어 있습니다. 그러나 복제본은 초기화될 때까지 정확한 값을 알 수 없으므로 초기화 중에 속성 값을 변경할 수 있도록 허용해야 합니다. READONLY의 경우 소스에는 세터나 푸시 슬롯이 없으며 복제본 측에는 푸시 슬롯이 생성되지 않습니다. PROP에 PERSISTED 특성을 추가하면 PROP이 노드에 설정된 QRemoteObjectAbstractPersistedStore 인스턴스(있는 경우)를 사용하여 PROP 값을 저장/복원하게 됩니다.
또 다른 미묘한 값은 비대칭 동작을 지정하는 또 다른 방법을 제공하는 소스 (특히 헬퍼 클래스, SimpleSource
)에 프로퍼티에 대한 공용 게터와 세터가 있지만 리플리카 쪽에서는 읽기 전용(알림 신호 포함)이 되는 SOURCEONLYSETTER입니다. 따라서 프로퍼티는 소스 측에서 완전히 제어할 수 있지만 레플리카 측에서만 관찰할 수 있습니다. SOURCEONLYSETTER는 모델 및 클래스 인스턴스에 대해 repc가 사용하는 모드로, 소스에서 가리키는 객체를 변경할 수 있지만 레플리카에서는 set<Prop> 또는 push<Prop> 메서드가 생성되지 않으므로 새 객체를 제공할 수 없습니다. 이는 가리키는 타입의 속성 동작에는 영향을 미치지 않으며 포인터 자체를 변경하는 기능에만 영향을 미칩니다.
CLASS
CLASS 키워드는 QObject 에서 파생된 객체에 대한 특수 Q_PROPERTY 요소를 생성합니다. 이러한 프로퍼티의 의미는 소스온리셋터와 동일합니다. 구문은 CLASS
키워드 뒤에 속성 이름과 괄호로 묶인 하위 객체 유형입니다.
// In .rep file class OtherClass { PROP(int value) } class MainClass { CLASS subObject(OtherClass) }
MODEL
MODEL 키워드는 QAbstractItemModel 에서 파생된 객체에 대한 특수 Q_PROPERTY 요소를 생성합니다. 이러한 속성의 의미는 SOURCEONLYSETTER와 동일합니다. 구문은 MODEL
키워드 다음에 속성 이름이 오고, 그 다음에 괄호로 (쉼표로 구분된) 복제본에 노출되어야 하는 역할이 괄호로 묶여 있습니다.
// In .rep file class CdClass { PROP(QString title READONLY) MODEL tracks(title, artist, length) }
SIGNAL
시그널 메서드는 리플리케이션 파일에서 SIGNAL 키워드를 사용하여 만듭니다.
사용법은 SIGNAL
뒤에 괄호로 묶인 원하는 서명을 선언하는 것입니다. 무효 반환값은 건너뛰어야 합니다.
SIGNAL(test()) SIGNAL(test(QString foo, int bar)) SIGNAL(test(QMap<QString,int> foo)) SIGNAL(test(const QString &foo)) SIGNAL(test(QString &foo))
Qt XML queued connections 에서와 마찬가지로 참조인 시그널의 매개변수는 레플리카로 전달될 때 복사됩니다.
SLOT
슬롯 메서드는 rep 파일에서 SLOT 키워드를 사용하여 생성됩니다.
사용법은 SLOT
뒤에 원하는 서명을 괄호로 묶어 선언하는 것입니다. 반환 값은 선언에 포함될 수 있습니다. 반환값을 생략하면 생성된 파일에 void가 사용됩니다.
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))
Qt queued connections 및 QtRO SIGNALS에서와 마찬가지로, 참조인 슬롯의 파라미터는 레플리카로 전달될 때 복사됩니다.
ENUM
열거형(C++ 열거형과 QtRO의 Q_ENUM 의 조합을 사용)은 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}
관련 항목: ENUM 타입, USE_ENUM 키워드
POD 타입
POD(Plain Old Data)는 C++ 구조체를 따라 간단한 데이터 컬렉션을 설명하는 용어입니다. 예를 들어 전화번호부에 대한 API가 있는 경우 인터페이스에서 '주소' 개념을 사용할 수 있습니다(주소에는 거리, 도시, 주, 국가 및 우편번호가 포함될 수 있음). POD 키워드를 사용하여 이와 같은 객체를 정의한 다음 클래스 정의의 PROP/SIGNAL/SLOT 정의에서 사용할 수 있습니다.
사용법은 POD
뒤에 생성된 유형의 이름과 쉼표로 구분된 유형 및 이름 쌍을 선언하고 유형/이름 쌍을 괄호로 묶는 것입니다.
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)
전체 예는 다음과 같습니다.
repc에서 생성된 코드는 각 POD에 대해 Q_GADGET 클래스를 생성하며, 해당 POD에 대해 정의된 각 유형에 해당하는 Q_PROPERTY 멤버가 있습니다.
라이브러리 내에서 생성된 헤더 파일을 사용하는 경우 심볼 표시 여부를 설정하기 위해 클래스 속성을 정의해야 할 수도 있습니다. 이는 POD
키워드 뒤에 속성을 정의하여 수행할 수 있습니다. 다음 예에서는 "mysharedlib_global.h"
에 정의된 MYSHAREDLIB_EXPORT
매크로가 사용됩니다. 자세한 내용은 공유 라이브러리 만들기를 참조하세요.
#include "mysharedlib_global.h" POD MYSHAREDLIB_EXPORT Foo(int bar)
ENUM 유형
클래스 내부에서 ENUM을 정의하는 것이 더 쉽고 깔끔한 경우가 많지만( ENUM 참조), 독립형 열거형 타입이 필요한 경우 클래스 정의 외부에서 ENUM 키워드를 사용하는 것이 도움이 될 수 있습니다. 이렇게 하면 헤더 파일에 마샬링 등을 처리하는 새 클래스가 생성됩니다. 이 경우 선언이 class
선언에 포함되지 않는다는 점을 제외하면 구문은 ENUM과 동일합니다.
관련 주제: ENUM, USE_ENUM 키워드
USE_ENUM 키워드
USE_ENUM 키워드는 ENUM 키워드를 통한 자동 생성 기능이 추가되기 전에 구현된 키워드입니다. 이전 버전과의 호환성을 위해 유지됩니다.
지시어
rep 파일은 인터페이스를 정의하지만 인터페이스에는 외부 요소가 필요한 경우가 많습니다. 이를 지원하기 위해 repc는 생성된 파일의 맨 위에 모든 (한 줄) 지시문을 포함합니다. 예를 들어 필요한 로직이나 데이터 유형을 지원하는 #include 또는 #define 지시문을 사용할 수 있습니다.
현재 repc 도구는 "#" 기호부터 줄 끝까지의 모든 것을 무시하고 생성된 파일에 추가합니다. 따라서 여러 줄의 #if/#else/#endif 문과 여러 줄의 매크로는 지원되지 않습니다.
#HEADER 및 #FOOTER 지시어
#HEADER
와 #FOOTER
라는 두 가지 특수 지시어가 있습니다. 이 지시어는 인터페이스 선언의 앞(HEADER) 또는 뒤(FOOTER)에 생성된 코드에 있는 그대로 넣어야 하는 콘텐츠를 정의하는 데 사용할 수 있습니다. 앞의 #HEADER
및 #FOOTER
토큰과 하나의 공백 문자는 제거됩니다.
다음 예제에서는 생성된 repc 클래스를 네임스페이스 안에 넣습니다.
#HEADER namespace MyNamespace { class MyType { ... }; #FOOTER } // namespace MyNamespace
CMake 함수
소스 및 복제본 유형을 생성하기 위한 CMake 함수는 다음과 같습니다.
Qt Remote Objects.rep 파일에서 소스 및 복제본 유형에 대한 C++ 헤더 파일을 생성합니다. | |
Qt Remote Objects.rep 파일에서 복제본 유형에 대한 C++ 헤더 파일을 생성합니다. | |
Qt Remote Objects.rep 파일에서 소스 유형에 대한 C++ 헤더 파일을 만듭니다. | |
QObject 헤더 파일에서 .rep 파일을 만듭니다. |
qmake 변수
REPC_REPLICA
복제본 헤더 파일을 생성하는 데 사용할 프로젝트의 모든 rep 파일 이름을 지정합니다.
예:
REPC_REPLICA = media.rep \ location.rep
생성된 파일은 rep_<replica file base>_replica.h
형식이 됩니다.
REPC_SOURCE
소스 헤더 파일을 생성하는 데 사용해야 하는 프로젝트의 모든 rep 파일 이름을 지정합니다.
예를 들어
REPC_SOURCE = media.rep \ location.rep
생성된 파일은 rep_<replica file base>_source.h
형식이 됩니다.
REPC_MERGED
결합된(소스 및 복제본) 헤더 파일을 생성하는 데 사용해야 하는 프로젝트의 모든 rep 파일 이름을 지정합니다.
예를 들어
REPC_MERGED = media.rep \ location.rep
생성된 파일은 rep_<replica file base>_merged.h
형식이 됩니다.
참고: 일반적으로 소스와 리플리케이트는 별도의 프로세스 또는 장치에 있으므로 이 변수는 일반적으로 사용되지 않습니다.
QOBJECT_REP
해당 .rep 파일을 생성하는 데 사용할 기존 QObject 헤더 파일의 이름을 지정합니다.
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.