2015. 7. 29. 22:13

Using the Meta-Object Compiler (moc) 소개

Using the Meta-Object Compiler (moc)

메타-오브젝트 컴파일러 (moc) 사용하기


The Meta-Object Compiler, moc, is the program that handles Qt's C++ extensions.

메타-오브젝트 컴파일러라고 불리는 moc 는 Qt 의 C++ 확장들을 다루고 있습니다.

The moc tool reads a C++ header file. If it finds one or more class declarations that contain the Q_OBJECT macro, it produces a C++ source file containing the meta-object code for those classes. Among other things, meta-object code is required for the signals and slots mechanism, the run-time type information, and the dynamic property system.

moc 도구는 C++ 의 헤더 파일을 읽습니다. 만약 하나 이상의 클래스 선언들 중에 Q_OBJECT 매크로를 포함하고 있다면, 그들의 클래스들을 위한 메타-오브젝트 코드를 포함하는 C++ 소스 파일을 생성합니다. 다른 걸 재쳐두고, 메타-오브젝트 코드는 런-타임(실행-중) 자료 형 정보인 시그널과 슬롯 메커니즘과 동적 속성 시스템의 요구에 대응하기 위해 사용 됩니다.

The C++ source file generated by moc must be compiled and linked with the implementation of the class.

moc 에 의해 생성된 C++ 소스 파일은 반드시 구현된 클래스와 함께 컴파일과 링크 작업이 이뤄져야 합니다.

If you use qmake to create your makefiles, build rules will be included that call the moc when required, so you will not need to use the moc directly. For more background information on moc, see Why Does Qt Use Moc for Signals and Slots?

만약 qmake 를 사용하여 당신의 makefile 들을 만들게 한다면, 필요시 moc 를 불리게 하는 규칙을 빌드 규칙에 포함시켜서, moc 를 직접 부를 필요가 없게 해야 할 필요가 있습니다. moc 에 대한 배경 정보를 추가로 필요로 한다면, 왜 Qt 는 시그널과 슬롯을 위해 Moc 를 사용합니까? 를 참고 하시기 바랍니다.

Usage

사용법

moc is typically used with an input file containing class declarations like this:

moc 는 아래와 같은 클래스 선언을 포함하는 입력 파일을 포함시 보통 사용됩니다.

class MyClass : public QObject
{
    Q_OBJECT

public:
    MyClass(QObject *parent = 0);
    ~MyClass();

signals:
    void mySignal();

public slots:
    void mySlot();
};

In addition to the signals and slots shown above, moc also implements object properties as in the next example. The Q_PROPERTY() macro declares an object property, while Q_ENUMS() declares a list of enumeration types within the class to be usable inside the property system.

시그널과 슬롯들이 위에 보이는 것과 더불어, moc 는 또한 다음 예제 처럼 객체 속성을 구현합니다. Q_PROPERTY() 매크로는 객체의 속성을 선언하는 매크로인 반면, Q_ENUMS 은 속성 시스템 내부에서 유용하게 될 열거형 자료형의 목록을 선언합니다.

In the following example, we declare a property of the enumeration type Priority that is also called priority and has a get function priority() and a set function setPriority().

다음의 예제에서, 우리는 priority() 함수로 priority (우선 순위) 값을 읽어오고 setPriority() 함수로 값을 지정할 수 있는 Priority (우선순위) 라는 형의 선언을 볼 수 있습니다.

class MyClass : public QObject
{
    Q_OBJECT
    Q_PROPERTY(Priority priority READ priority WRITE setPriority)
    Q_ENUMS(Priority)

public:
    enum Priority { High, Low, VeryHigh, VeryLow };

    MyClass(QObject *parent = 0);
    ~MyClass();

    void setPriority(Priority priority) { m_priority = priority; }
    Priority priority() const { return m_priority; }

private:
    Priority m_priority;
};

The Q_FLAGS() macro declares enums that are to be used as flags, i.e. OR'd together. Another macro,Q_CLASSINFO(), allows you to attach additional name/value pairs to the class's meta-object:

Q_FLAGS() 매크로는 플래그 (속성 깃발 값) 형으로 사용될 자료형을 선언하며, 이들은 (부연 설명하자면) OR 연산자로 합쳐질 수 있습니다. 다른 매크로 Q_CLASSINFO() 은 클래스의 메타-객체와 짝이 되는 부가적인 이름/값을 추가할 수 있게 해줍니다.

class MyClass : public QObject
{
    Q_OBJECT
    Q_CLASSINFO("Author", "Oscar Peterson")
    Q_CLASSINFO("Status", "Active")

public:
    MyClass(QObject *parent = 0);
    ~MyClass();
};

The output produced by moc must be compiled and linked, just like the other C++ code in your program; otherwise, the build will fail in the final link phase. If you use qmake, this is done automatically. Whenever qmake is run, it parses the project's header files and generates make rules to invoke moc for those files that contain a Q_OBJECT macro.

moc 로 출력되는 산출물은 다른 C++ 코드와 마찬가지로 사용자의 프로그램에서 반드시 컴파일되고 링크되어야 합니다. 그렇지 않으면 마지막 링크 과정에서 빌드가 실패하게 될 것입니다. 만약 qmake 를 사용한다면, 이 과정은 자동으로 이뤄집니다. qmake 가 실행 될 때마다, 프로젝트의 헤더 파일들을 해석하여 Q_OBJECT 매크로가 포함되어 있는 파일들을 대상으로 moc 가 호출되는 make (빌드) 규칙을 생성합니다.

If the class declaration is found in the file myclass.h, the moc output should be put in a file called moc_myclass.cpp. This file should then be compiled as usual, resulting in an object file, e.g., moc_myclass.obj on Windows. This object should then be included in the list of object files that are linked together in the final building phase of the program.

만약 클래스 선언이 myclass.h 에서 발견된다면, moc 는 moc_myclass.cpp 라고 불리는 파일을 만들어 낼 것입니다. 이는 평상시 처럼 컴파일 되어 윈도우 상에 moc_myclass.obj 와 같은 결과물을 생성합니다. 이 오브젝트 파일은 오브젝트 파일들의 목록에 포함되어 프로그램 마지막 빌드 과정에서 같이 링크 됩니다.

Writing Make Rules for Invoking moc

moc 를 호출하기 위한 규칙들을 작성하기

For anything but the simplest test programs, it is recommended that you automate running the moc. By adding some rules to your program's makefile, make can take care of running moc when necessary and handling the moc output.

프로그램을 테스트 하기 위한 목적으로는 moc 를 자동으로 실행하는 방법이 권장됩니다. 사용자 프로그램의 makefile 에 몇가지 규칙을 추가함으로, make 은 moc 출력을 다룰 필요가 있을 때 자동으로 다뤄지게 됩니다.

We recommend using the qmake makefile generation tool for building your makefiles. This tool generates a makefile that does all the necessary moc handling.

사용자의 makefile 들을 만들기 위한 makefile 생성 도구로 qmake 사용을 권장합니다. 이 도구는 moc 관리에 필요한 모든 작업을 다루는 makefile 을 만들어 줍니다.

If you want to create your makefiles yourself, here are some tips on how to include moc handling.

makefile 을 스스로 만드시길 원한다면, 여기 moc 다루기는 방법을 포함 하는 몇가지 팁이 있습니다.

For Q_OBJECT class declarations in header files, here is a useful makefile rule if you only use GNU make:

헤더 파일들내에 Q_OBJECT 클래스 선언에 대해서는, GNU make 를 사용했을 때 유용한 makefile 규칙이 있습니다.

moc_%.cpp: %.h
        moc $(DEFINES) $(INCPATH) $< -o $@

If you want to write portably, you can use individual rules of the following form:

간단하게 작성하고 싶으시면, 다음의 양식을 활용해 따로 만들어 사용할 수 있습니다.

moc_foo.cpp: foo.h
        moc $(DEFINES) $(INCPATH) $< -o $@

You must also remember to add moc_foo.cpp to your SOURCES (substitute your favorite name) variable and moc_foo.o or moc_foo.obj to your OBJECTS variable.

moc_foo.cpp 를 사용자가 사용하는 SOURCES (선호하는 이름으로 변경) 변수에 추가하는 것을 잊지 말으셔야 하고, moc_foo.o 또는 moc_foo.obj 를 OBJECTS 변수에도 추가해야 합니다.

Both examples assume that $(DEFINES) and $(INCPATH) expand to the define and include path options that are passed to the C++ compiler. These are required by moc to preprocess the source files.

두 예제 모두 C++ 컴파일러에게 전달되는 디파인 (define, 정의) 와 인클루드 (include) 경로는 $(DEFINES) 와 $(INCPATH) 를 사용하는 것으로 간주합니다.

While we prefer to name our C++ source files .cpp, you can use any other extension, such as .C.cc.CC.cxx, and .c++, if you prefer.

우리는 C++ 소스 파일 이름을 .cpp 로 지정하는 것을 선호하지만, 사용자는 .C, .cc, .CC, .cxx, .c++ 와 같이 좋아한다면 다른 확장자를 지정하여 쓸 수 있습니다.

For Q_OBJECT class declarations in implementation (.cpp) files, we suggest a makefile rule like this:

구현 파일 (.cpp) 들에 있는 Q_OBJECT 클래스 선언들에 대해서는, 우리는 다음과 같은 makefile 규칙을 제안합니다.

foo.o: foo.moc

foo.moc: foo.cpp
        moc $(DEFINES) $(INCPATH) -i $< -o $@

This guarantees that make will run the moc before it compiles foo.cpp. You can then put

이는 make 가 foo.cpp 를 컴파일 하기 전에 moc 를 실행하게 하는 것을 보장합니다. 당신은 이들을 

#include "foo.moc"

at the end of foo.cpp, where all the classes declared in that file are fully known.

foo.cpp 파일에서 선언 되어 있는 모든 클래스이 알려진 곳인 (파일의) 끝에 둘 수 있습니다.

Command-Line Options

커맨드-라인 (명령줄) 옵션

Here are the command-line options supported by the moc:

moc 에서 지원하는 커맨드-라인(명령줄) 옵션들이 있습니다.

OptionDescription
-o<file>Write output to <file> rather than to standard output.

출력 내용을 표준 출력(화면) 보다는 지정된 출력 파일이름인 <file> 로 저장합니다.

-f[<file>]Force the generation of an #include statement in the output. This is the default for header files whose extension starts with H or h. This option is useful if you have header files that do not follow the standard naming conventions. The <file> part is optional.

출력물에서 #include 의 생성을 강제로 지정합니다. 이는 생성되는 확장자가 H 나 h 로 시작할 때 기본 값으로 지정됩니다. 이 옵션은 표준 명명(이름 붙이기) 규정을 따르지 않는 헤더 파일들을 가지고 있을 때 유용한 옵션입니다. <file> 부분은 선택 사항입니다.

-iDo not generate an #include statement in the output. This may be used to run the moc on on a C++ file containing one or more class declarations. You should then #include the meta-object code in the .cpp file.

출력물에서 #include 을 생성하지 않습니다. 이 옵션은 하나 이상의 클래스 선언을 포함하고 있는 C++ 파일에 대해 moc 를 수행할 대 유용할 수 있습니다. 사용자는 수행 후 이 .cpp 파일에 메타-오브젝트 코드를 #include 처리 해야합니다.

-nw

Do not generate any warnings. (Not recommended.)

경고문을 출력하지 않습니다. (권장하지 않습니다.)

-p<path>Makes the moc prepend <path>/ to the file name in the generated #include statement.

moc prepend <path>/ 경로에 지정된 file name (파일명) 에 생성된 #include 구문을 생성하여 만듭니다.

-I<dir>

Add dir to the include path for header files.

헤더 파일을 추가하기 위해 dir 경로를 추가로 include 경로를 추가하여 지정합니다.

-EPreprocess only; do not generate meta-object code.

전처리 전용; 메타-오브젝트 코드를 만들지 않습니다.
-D<macro>[=<def>]

Define macro, with optional definition.

선택적으로 define 구문을 추가하기 위해 매크로를 정의합니다.

-U<macro>Undefine macro.

정의된 매크로를 해제 합니다.
-M<key=value>

Append additional meta data to plugins. If a class has Q_PLUGIN_METADATA specified, the key-value pair will be added to its meta data. This will end up in the Json object that gets resolved for the plugin at run time (accessible from QPluginLoader). This argument is typically used for tagging static plugins with information resolved by the build system.

플러그인들에 대해 추가적인 메타 정보를 첨부 합니다. 만약 클래스에서 Q_PLUGIN_METADATA 를 정의해 뒀다면, 키-값 쌍으로 구성된 정보가 메타 정보로 추가됩니다. 이는 실시간으로 플러그인에게 JSON 객체 형태로 전달 됩니다. (QPluginLoader 를 통해 접근 가능합니다.) 이 인수는 일반적으로 정적 플러그인의 정보를 빌드 시스템에 의해 정보를 정의하여 표시하는데 사용됩니다.

@<file>Read additional command-line options from <file>. Each line of the file is treated as a single option. Empty lines are ignored. Note that this option is not supported within the options file itself (i.e. an options file can't "include" another file).

<file> 을 읽어서 추가적인 명령-줄 옵션을 가져옵니다. 각 줄은 단일 옵션 값으로 간주 됩니다. 빈 줄들은 무시 됩니다. 이 옵션은 다른 파일 내의 옵션들에 대해서는 지원하지 않습니다. (예. 옵션들을 포함한 파일은 다른 (옵션) 파일을 "include" 할 수 없습니다.)

-hDisplay the usage and the list of options.

옵션들의 사용법과 목록들을 보여줍니다.
-vDisplay moc's version number.

moc 의 버전 번호를 표시합니다.
-FdirOS X. Add the framework directory dir to the head of the list of directories to be searched for header files. These directories are interleaved with those specified by -I options and are scanned in a left-to-right order (see the manpage for gcc). Normally, use -F /Library/Frameworks/

OS X 용으로 헤더 파일들을 검색하는 프레임워크 디렉토리 목록들의 시작 경로를 dir 로 추가합니다. 이들 경로들은 (일일이) 끼워 넣는 방식의 옵션인 -I 옵션으로 추가할 수 있으며, (-F 로 추가시) 왼쪽-에서-오른쪽 순서대로 검색 됩니다. (gcc 용 manpage 참고). 일반적으로 -F /Library/Frameworks/ 을 사용합니다.

You can explicitly tell the moc not to parse parts of a header file. moc defines the preprocessor symbol Q_MOC_RUN. Any code surrounded by

사용자는 헤더 파일의 일부를 해석하지 말게끔 moc 에게 명시적으로 알려줄 수 있습니다. moc 는 전처리기인 Q_MOC_RUN 을 사용 어떤 코드든 다음과 같은 방법으로

#ifndef Q_MOC_RUN
    ...
#endif

is skipped by the moc.

감싸서 moc 의 작업을 피할 수 있습니다.

Diagnostics

진단

moc will warn you about a number of dangerous or illegal constructs in the Q_OBJECT class declarations.

moc 는 Q_OBJECT 클래스 선언에서 선언되는 위험하거나 규정에 위반되는 다수의 생성들을 경고할 것입니다.

If you get linkage errors in the final building phase of your program, saying that YourClass::className() is undefined or that YourClass lacks a vtable, something has been done wrong. Most often, you have forgotten to compile or #include the moc-generated C++ code, or (in the former case) include that object file in the link command. If you use qmake, try rerunning it to update your makefile. This should do the trick.

만약 빌드의 마지막 단계에서 링크 오류를, YourClass:className() 가 정의 되어 있지 않거나 YourClass 가 vtable (가상 메소드/함수 테이블) 이 빠져 있다는 형태로 받는다면, 뭔가 잘못 되어가고 있었다는 것을 나타냅니다. 대부분 사용자가 컴파일을 잊어버렸거나 moc 가 생성한 C++ 코드를  #include 로 포함하지 않아서 발상해거나, (혹은 전자인 경우) 링크 명령문에서 오브젝트 파일을 포함하지 않아서 문제가 발생됩니다. 만약 당신이 qmake 를 사용하고 있다면, makefile 을 갱신하여 다시 시도해보시기 바랍니다. 이 동작으로 효과가 있어야 합니다.

Limitations

제약

moc does not handle all of C++. The main problem is that class templates cannot have the Q_OBJECT macro. Here is an example:

moc 는 모든 C++ 를 다루지 않습니다. 가장 중요한 문제는 클래스 탬플릿들은 Q_OBJECT 매크로를 가지지 못합니다. 여기 예제가 있습니다.

class SomeTemplate<int> : public QFrame
{
    Q_OBJECT
    ...

signals:
    void mySignal(int);
};

The following constructs are illegal. All of them have alternatives which we think are usually better, so removing these limitations is not a high priority for us.

(Q_OBJECT 매크로) 이후 생성들은 규칙에 어긋납니다. 대부분 더 좋은 대체방안들이 많아서 이러한 제약사항을 제거하는 것은 우리 (Qt 개발자) 들에게는 높은 순위의 작업은 아닙니다.

Multiple Inheritance Requires QObject to Be First

다중 상속에서는 QObject 를 가장 먼저 요청됩니다.

If you are using multiple inheritance, moc assumes that the first inherited class is a subclass of QObject. Also, be sure that only the first inherited class is a QObject.

만약 다중 상속을 사용한다면, moc 는 우선 상속 받은 클래스를 QObject 의 자식 클래스로 생각합니다. 또한 QObject 를 먼저 상속 받게끔 하는 것이 보장 되어야 합니다.

// correct
class SomeClass : public QObject, public OtherClass
{
    ...
};

Virtual inheritance with QObject is not supported.

QObject 를 사용한 가상 상속은 지원되지 않습니다.

Function Pointers Cannot Be Signal or Slot Parameters

함수 포인터들은 시그널 또는 슬롯 파라미터로 될 수 없습니다.

In most cases where you would consider using function pointers as signal or slot parameters, we think inheritance is a better alternative. Here is an example of illegal syntax:

대부분의 경우 개발자가 함수 포인터를 시그널 이나 슬롯의 파라미터로 쓸려고 고려할 수 있겠지만, 우리는 상속을 더 좋은 대체 방법으로 생각하고 있습니다. 여기 규정에 어긋나는 예제가 있습니다.

class SomeClass : public QObject
{
    Q_OBJECT

public slots:
    void apply(void (*apply)(List *, void *), char *); // WRONG
};

You can work around this restriction like this:

당신은 위 제약 사항을 다음과 같이 해결할 수 있습니다.

typedef void (*ApplyFunction)(List *, void *);

class SomeClass : public QObject
{
    Q_OBJECT

public slots:
    void apply(ApplyFunction, char *);
};

It may sometimes be even better to replace the function pointer with inheritance and virtual functions.

종종 상속과 가상 함수를 써서 함수 포인터를 대체해서 쓰는 게 보통 훨씬 좋을 수 있습니다.

Enums and Typedefs Must Be Fully Qualified for Signal and Slot Parameters

Enum 형과 Typedef 형들은 반드시 시그널과 슬롯 파라미터의 요구사항에 만족해야 합니다.

When checking the signatures of its arguments, QObject::connect() compares the data types literally. Thus,Alignment and Qt::Alignment are treated as two distinct types. To work around this limitation, make sure to fully qualify the data types when declaring signals and slots, and when establishing connections. For example:

인수의 특징값들을 검사할 때, QObject::connect() 는 자료형을 문자 그대로 비교합니다. 그러므로 Alignment 와 Qt:Alignment 는 서로 다른 형으로 다뤄집니다. 이러한 제약을 해결하기 위해, (시그널과 슬롯을) 연결할 때, 시그널과 슬롯을 선언할 때, 자료형을 온전하게 만족시키는지 확인 해야합니다. 예제 입니다

class MyClass : public QObject
{
    Q_OBJECT

    enum Error {
        ConnectionRefused,
        RemoteHostClosed,
        UnknownError
    };

signals:
    void stateChanged(MyClass::Error error);
};

(클래스의 네임 스페이스를 준수하고 있습니다.)

Nested Classes Cannot Have Signals or Slots

상속 받은 클래스들은 시그널과 슬롯을 가지지 못합니다.

Here's an example of the offending construct:

여기 문제가 되는 생성을 예제입니다.

class A
{
public:
    class B
    {
        Q_OBJECT

    public slots:   // WRONG
        void b();
    };
};

Signal/Slot return types cannot be references

시그널/슬롯은 (주소) 참조형으로 반환될 수 없습니다.

Signals and slots can have return types, but signals or slots returning references will be treated as returning void.

시그널과 슬롯들은 반환 형(리턴 타입) 을 가질 수 있습니다만, 시그널과 슬롯은 참조형으로 반환시 void 형으로 반환되는 것과 같이 취급 될 것입니다.

Only Signals and Slots May Appear in the signals and slots Sections of a Class

시그널과 슬롯들은 클래스의 signals 와 slots 영역에서만 등장할 수 있습니다.

moc will complain if you try to put other constructs in the signals or slots sections of a class than signals and slots.

moc 는 시그널과 슬롯 영역이 아닌 다른 곳에서 를 signals 또는 slots 생성하면 (경고 메시지를 내며) 불평할 것입니다.

See also Meta-Object SystemSignals and Slots, and Qt's Property System.

같이 보기 Meta-Object SystemSignals and Slots, 과 Qt's Property System.

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

'소프트웨어 > Qt' 카테고리의 다른 글

Why Does Qt Use Moc for Signals and Slots?  (0) 2015.08.11
The Meta-Object System 소개  (0) 2015.08.08
0031 - GUI 프로그래밍 소개 / 프로젝트 내 파일  (0) 2015.07.28
Session Management 소개  (0) 2015.07.27
QApplication 소개  (0) 2015.07.25