공유 라이브러리 만들기

다음 섹션에서는 공유 라이브러리를 만들 때 고려해야 할 몇 가지 사항을 나열합니다.

공유 라이브러리에서 심볼 사용하기

애플리케이션이나 다른 라이브러리 등 클라이언트에서 사용하려는 공유 라이브러리에 포함된 심볼(함수, 변수 또는 클래스)은 특별한 방법으로 표시해야 합니다. 이러한 심볼은 내보내거나 공개적으로 표시되는 공개 심볼이라고 합니다.

나머지 기호는 외부에서 보이지 않아야 합니다. 대부분의 플랫폼에서 컴파일러는 기본적으로 이러한 심볼을 숨깁니다. 일부 플랫폼에서는 이러한 심볼을 숨기려면 특별한 컴파일러 옵션이 필요합니다.

공유 라이브러리를 컴파일할 때는 내보내기용으로 표시해야 합니다. 클라이언트에서 공유 라이브러리를 사용하려면 일부 플랫폼에서는 특별한 가져오기 선언도 필요할 수 있습니다.

대상 플랫폼에 따라 Qt는 필요한 정의가 포함된 특수 매크로를 제공합니다:

  • Q_DECL_EXPORT 공유 라이브러리를 컴파일할 때 사용되는 심볼의 선언에 추가해야 합니다.
  • Q_DECL_IMPORT 공유 라이브러리를 사용하는 클라이언트를 컴파일할 때 사용되는 심볼 선언에 추가해야 합니다.

이제 공유 라이브러리 자체를 컴파일하든 공유 라이브러리를 사용하는 클라이언트만 컴파일하든 올바른 매크로가 호출되는지 확인해야 합니다. 일반적으로 이 문제는 특수 헤더를 추가하여 해결할 수 있습니다.

mysharedlib라는 공유 라이브러리를 만들고 싶다고 가정해 보겠습니다. 이 라이브러리의 특수 헤더인 mysharedlib_global.h 는 다음과 같습니다:

#include <QtCore/QtGlobal>

#if defined(MYSHAREDLIB_LIBRARY)
#  define MYSHAREDLIB_EXPORT Q_DECL_EXPORT
#else
#  define MYSHAREDLIB_EXPORT Q_DECL_IMPORT
#endif

라이브러리의 각 헤더에 다음을 지정합니다:

#include "mysharedlib_global.h"

MYSHAREDLIB_EXPORT void foo();
class MYSHAREDLIB_EXPORT MyClass...

그런 다음 라이브러리 자체를 빌드할 때 컴파일러에 MYSHAREDLIB_LIBRARY 가 정의되어 있는지 확인해야 합니다. 이 작업은 라이브러리의 빌드 시스템에서 수행됩니다. CMake를 사용하는 경우 공유 라이브러리 대상을 보강합니다:

target_compile_definitions(mysharedlib PRIVATE MYSHAREDLIB_LIBRARY)

qmake를 사용하는 경우 공유 라이브러리의

DEFINES += MYSHAREDLIB_LIBRARY

를 공유 라이브러리의 .pro 파일에 추가합니다.

참고: 라이브러리 마법사는 Qt CreatorQt VS 도구의 라이브러리 마법사는 이러한 것들을 설정하는 스켈레톤을 제공합니다.

헤더 파일 고려 사항

일반적으로 클라이언트는 공유 라이브러리의 공용 헤더 파일만 포함합니다. 이러한 라이브러리는 배포 시 다른 위치에 설치될 수 있습니다. 따라서 공유 라이브러리를 구축할 때 사용된 다른 내부 헤더 파일을 제외하는 것이 중요합니다.

예를 들어, 라이브러리에서 하드웨어 장치를 래핑하고 타사 라이브러리에서 제공하는 해당 장치에 대한 핸들을 포함하는 클래스를 제공할 수 있습니다:

#include <footronics/device.h>

class MyDevice {
private:
    FOOTRONICS_DEVICE_HANDLE handle;
};

집계 또는 다중 상속을 사용할 때 Qt Widgets Designer 에서 만든 양식에서도 비슷한 상황이 발생합니다:

#include "ui_widget.h"

class MyWidget : public QWidget {
private:
    Ui::MyWidget m_ui;
};

라이브러리를 배포할 때 내부 헤더 footronics/device.h 또는 ui_widget.h 에 대한 종속성이 없어야 합니다.

다양한 C++ 프로그래밍 서적에 설명된 구현 이디엄에 대한 포인터를 사용하면 이러한 문제를 피할 수 있습니다. 값 의미론이 있는 클래스의 경우 QSharedDataPointer 을 사용하는 것이 좋습니다.

바이너리 호환성

공유 라이브러리를 로드하는 클라이언트가 올바르게 작동하려면 사용 중인 클래스의 메모리 레이아웃이 클라이언트를 컴파일하는 데 사용된 라이브러리 버전의 메모리 레이아웃과 정확히 일치해야 합니다. 즉, 런타임에 클라이언트가 찾은 라이브러리는 컴파일 시 사용된 버전과 바이너리 호환이 가능해야 합니다.

클라이언트가 필요한 모든 라이브러리를 제공하는 독립형 소프트웨어 패키지인 경우에는 일반적으로 문제가 되지 않습니다.

그러나 클라이언트 애플리케이션이 다른 설치 패키지나 운영 체제에 속하는 공유 라이브러리에 의존하는 경우 공유 라이브러리에 대한 버전 관리 체계를 고려하고 바이너리 호환성을 어느 수준으로 유지할지 결정해야 합니다. 예를 들어 같은 메이저 버전 번호의 Qt 라이브러리는 바이너리 호환성을 보장합니다.

바이너리 호환성을 유지하면 클래스에 적용할 수 있는 변경 사항에 몇 가지 제한이 있습니다. 이에 대한 좋은 설명은 KDE - 정책/바이너리 호환성 문제에서 찾을 수 있습니다. 이러한 문제는 라이브러리 설계를 시작할 때부터 고려해야 합니다. 가능하면 정보 숨김 원칙과 포인터 투 구현 기법을 사용하는 것이 좋습니다.

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