共有ライブラリの作成

以下のセクションでは、共有ライブラリを作成する際に注意すべき点を挙げています。

共有ライブラリのシンボルの使用

アプリケーションや他のライブラリなどのクライアントが使用することを意図した共有ライブラリに含まれるシンボル(関数、変数、クラス)は、特別な方法でマークする必要があります。これらのシンボルはパブリック・シンボルと呼ばれ、エクスポートされたり、一般に公開されたりします。

残りのシンボルは外部から見えないようにする。ほとんどのプラットフォームでは、コンパイラーはデフォルトでこれらのシンボルを非表示にします。一部のプラットフォームでは、これらのシンボルを非表示にするには特別なコンパイラー・オプションが必要です。

共有ライブラリをコンパイルする際には、エクスポート用にマークしておく必要があります。クライアントから共有ライブラリを使用するには、プラットフォームによっては特別なインポート宣言も必要になります。

ターゲットプラットフォームによっては、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 VS Tools の Qt CreatorQt VS Tools のライブラリウィザードは、これらの設定を行うスケルトンを提供します。

ヘッダーファイルに関する考察

通常、クライアントは共有ライブラリのパブリックヘッダーファイルのみをインクルードします。これらのライブラリは、デプロイ時に別の場所にインストールされるかもしれません。したがって、共有ライブラリのビルド時に使用された他の内部ヘッダーファイルを除外することが重要です。

例えば、共有ライブラリがハードウェア・デバイスをラップするクラスを提供し、サードパーティ・ライブラリによって提供されたそのデバイスへのハンドルを含んでいるかもしれません:

#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++ プログラミングの本で説明されているPointer to implementationイディオムを利用することで回避できます。値セマンティクスを持つクラスについては、QSharedDataPointer の使用を検討してください。

バイナリの互換性

共有ライブラリーをロードするクライアントが正しく動作するためには、使用されるクラスのメモリー・レイアウトが、クライアントのコンパイルに使用されたライブラリー・バージョンのメモリー・レイアウトと正確に一致していなければなりません。言い換えれば、クライアントが実行時に見つけるライブラリは、コンパイル時に使用されたバージョンとバイナリ互換性がなければなりません。

クライアントが自己完結型のソフトウェア・パッケージで、必要なライブラ リをすべて出荷している場合、これは通常問題にはなりません。

しかし、クライアント・アプリケーションが、別のインストール・パッケージやオペレーティング・システムに属する共有ライブラリに依存している場合は、共有ライブラリのバージョン管理方式を考え、どのレベルでバイナリ互換性を維持するかを決定する必要があります。例えば、同じメジャーバージョン番号のQtライブラリは、バイナリ互換性が保証されています。

バイナリ互換性を維持すると、クラスに加えられる変更に制限が生じます。KDE - Policies/Binary Compatibility Issues With C++ に良い説明があります。これらの問題は、ライブラリ設計の最初から考慮されるべきです。可能な限り、情報隠蔽の原則とPointer to implementationテクニックを使用することをお勧めします。

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