📢 Webサイト閉鎖と移転のお知らせ
このWebサイトは2026年9月に閉鎖いたします。
新しい記事は移転先で追加しております。(旧サイトでは記事を追加しておりません)
| (同じ利用者による、間の20版が非表示) | |||
| 1行目: | 1行目: | ||
== 概要 == | == 概要 == | ||
Qt Creatorにおいて、静的ライブラリおよび動的ライブラリを作成して、他のQtプロジェクトにリンクする手順を記載する。<br> | Qt Creatorにおいて、静的ライブラリおよび動的ライブラリを作成して、他のQtプロジェクトにリンクする手順を記載する。<br> | ||
<br><br> | |||
== 外部リンケージの制限 == | |||
==== --version-scriptオプションによるAPI制限 ==== | |||
マップファイルに公開する関数を指定して、コンパイラのビルドオプション (<code>LDFLAGS</code>) に<code>-Wl,--version-script,<マップファイル名>.map</code>を付加する。<br> | |||
LDFLAGS+=-Wl,--version-script,<マップファイル名>.map | |||
<br> | |||
<マップファイル名>.map | |||
{ | |||
global: | |||
<公開する関数名 1>; | |||
<公開する関数名 2>; | |||
<公開する関数名 3>; | |||
local: *; | |||
}; | |||
<br> | |||
==== 公開する関数に__attribute__((visibility("default")))を付加する ==== | |||
コンパイラのビルドオプションに<code>-fvisibility=hidden</code>を付加する場合、まず全ての関数が非公開になる。<br> | |||
次に、公開する関数名の前に<code>__attribute__((visibility("default")))</code>を付加する。<br> | |||
<br> | |||
<code>__attribute__((visibility(...)))</code>が付加されることにより、<br> | |||
除外されるものを除いて、コンパイルで生成される全てのグローバルシンボルに指定された動的な可視性のタイプを属性を付ける。<br> | |||
<br><br> | |||
== 外部リンケージの確認 == | |||
==== nmコマンドの使用 ==== | |||
<code>nm</code>コマンドを実行して、外部リンケージを確認することができる。<br> | |||
nm -D <ライブラリファイル名> | |||
# または | |||
nm -D --defined-only <ライブラリファイル名> | |||
<br><br> | <br><br> | ||
| 18行目: | 48行目: | ||
プロジェクトをビルドして、静的ライブラリを生成する。<br> | プロジェクトをビルドして、静的ライブラリを生成する。<br> | ||
生成されたライブラリは、Windowsの場合は<code>.lib</code>拡張子、Linuxの場合は<code>.a</code>拡張子である。<br> | 生成されたライブラリは、Windowsの場合は<code>.lib</code>拡張子、Linuxの場合は<code>.a</code>拡張子である。<br> | ||
<br> | |||
==== プロジェクト構造 ==== | |||
# プロジェクト構造の例 | |||
mylib/ | |||
├── mylib.pro # Qtプロジェクトファイル | |||
├── CMakeLists.txt # CMakeプロジェクトファイル (CMakeを使用する場合) | |||
├── mylib.h # ヘッダファイル | |||
├── mylib.cpp # 実装ファイル | |||
└── mylib_global.h # エクスポートマクロ (オプション) | |||
<br> | |||
==== QMakeを使用する場合 ==== | |||
変数 <code>TEMPLATE</code> に <code>lib</code>、変数 <code>CONFIG</code> に <code>lib</code> または <code>staticlib</code> を指定する必要がある。<br> | |||
<syntaxhighlight lang="make"> | |||
QT -= gui # GUIが不要な場合 | |||
QT += core # 最低限必要なQtモジュール | |||
TARGET = mylib | |||
TEMPLATE = lib | |||
CONFIG += staticlib # スタティックライブラリとして設定 | |||
# C++標準の指定 | |||
CONFIG += c++17 | |||
# 出力ディレクトリ | |||
DESTDIR = $$PWD/lib | |||
# ソースファイル | |||
SOURCES += \ | |||
mylib.cpp | |||
# ヘッダファイル | |||
HEADERS += \ | |||
mylib.h \ | |||
mylib_global.h | |||
# インストール設定 (オプション) | |||
unix { | |||
target.path = /usr/lib | |||
INSTALLS += target | |||
} | |||
</syntaxhighlight> | |||
<br> | |||
==== CMakeを使用する場合 ==== | |||
<syntaxhighlight lang="cmake"> | |||
# CMakeLists.txtファイル | |||
cmake_minimum_required(VERSION 3.21) | |||
project(mylib VERSION 1.0.0 LANGUAGES CXX) | |||
# C++標準の設定 | |||
set(CMAKE_CXX_STANDARD 17) | |||
set(CMAKE_CXX_STANDARD_REQUIRED ON) | |||
# Qtパッケージの検索 | |||
# Qt 5の場合 | |||
# find_package(Qt5 REQUIRED COMPONENTS Core) | |||
# Qt 6の場合 | |||
find_package(Qt6 REQUIRED COMPONENTS Core) | |||
# ソースファイルとヘッダーファイル | |||
set(SOURCES | |||
mylib.cpp | |||
) | |||
set(HEADERS | |||
mylib.h | |||
mylib_global.h | |||
) | |||
# スタティックライブラリの作成 | |||
add_library(mylib STATIC ${SOURCES} ${HEADERS}) | |||
# Qtモジュールとリンク | |||
# Qt 5の場合 | |||
# target_link_libraries(mylib PUBLIC Qt5::Core) | |||
# Qt6の場合 | |||
target_link_libraries(mylib PUBLIC Qt6::Core) | |||
# インクルードディレクトリの公開 | |||
target_include_directories(mylib PUBLIC | |||
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}> | |||
$<INSTALL_INTERFACE:include> | |||
) | |||
# 出力ディレクトリの設定 | |||
set_target_properties(mylib PROPERTIES | |||
ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/lib" | |||
) | |||
# インストール設定 (オプション) | |||
install(TARGETS mylib | |||
ARCHIVE DESTINATION lib | |||
) | |||
install(FILES ${HEADERS} | |||
DESTINATION include/mylib | |||
) | |||
</syntaxhighlight> | |||
<br> | |||
==== ソースファイルの例 ==== | |||
<syntaxhighlight lang="c++"> | |||
// mylib.cppファイル | |||
#include "mylib.h" | |||
MyLib::MyLib() : m_internalValue(0) | |||
{ | |||
} | |||
QString MyLib::getVersion() | |||
{ | |||
return "1.0.0"; | |||
} | |||
int MyLib::add(int a, int b) | |||
{ | |||
return a + b; | |||
} | |||
QString MyLib::processText(const QString &input) | |||
{ | |||
return input.toUpper(); | |||
} | |||
</syntaxhighlight> | |||
<br> | |||
<syntaxhighlight lang="c++"> | |||
// mylib.hファイル | |||
#ifndef MYLIB_H | |||
#define MYLIB_H | |||
#include <QString> | |||
class MyLib | |||
{ | |||
private: | |||
int m_internalValue; | |||
public: | |||
MyLib(); | |||
// ライブラリの機能 | |||
static QString getVersion(); | |||
int add(int a, int b); | |||
QString processText(const QString &input); | |||
}; | |||
#endif // MYLIB_H | |||
</syntaxhighlight> | |||
<br> | |||
<syntaxhighlight lang="c++"> | |||
// mylib_global.hファイル | |||
#ifndef MYLIB_GLOBAL_H | |||
#define MYLIB_GLOBAL_H | |||
// スタティックライブラリの場合は空でOK | |||
// 将来的にダイナミックライブラリに変更する場合に備える | |||
#endif // MYLIB_GLOBAL_H | |||
</syntaxhighlight> | |||
<br> | <br> | ||
==== 静的ライブラリのリンク ==== | ==== 静的ライブラリのリンク ==== | ||
| 43行目: | 237行目: | ||
<br> | <br> | ||
以下の例では、動的ライブラリとしてダイアログ(QDialogの派生クラス)を作成している。 | 以下の例では、動的ライブラリとしてダイアログ(QDialogの派生クラス)を作成している。 | ||
<syntaxhighlight lang="c++"> | |||
#ifndef LIBDIALOG_GLOBAL_H | |||
#define LIBDIALOG_GLOBAL_H | |||
#include <QtCore/qglobal.h> | |||
#if define(Q_OS_WIN) // Windows | |||
#if defined(LIBDIALOG_LIBRARY) | |||
#define LIBDIALOG_EXPORT __declspec(dllexport) | |||
#else | |||
#define LIBDIALOG_EXPORT | |||
#endif | |||
#elif defined(Q_OS_LINUX) // Linux | |||
#if defined(LIBDIALOG_LIBRARY) | |||
#define LIBDIALOG_EXPORT Q_DECL_EXPORT | |||
#else | |||
#define LIBDIALOG_EXPORT Q_DECL_IMPORT | |||
#endif | |||
#endif | |||
#endif // LIBDIALOG_GLOBAL_H | |||
</syntaxhighlight> | |||
<br> | |||
<syntaxhighlight lang="c++"> | <syntaxhighlight lang="c++"> | ||
// LibDialog.h | // LibDialog.h | ||
| 49行目: | 266行目: | ||
#define LIBDIALOG_H | #define LIBDIALOG_H | ||
#include " | #include "LibDialog_global.h" | ||
#include <QDialog> | #include <QDialog> | ||
class | class LIBDIALOG_EXPORT LibDialog : public QDialog | ||
{ | { | ||
public: | public: | ||
| 78行目: | 295行目: | ||
aファイルの<code>.a</code>拡張子を<code>.lib</code>拡張子に変更する必要がある。</u><br> | aファイルの<code>.a</code>拡張子を<code>.lib</code>拡張子に変更する必要がある。</u><br> | ||
<br> | <br> | ||
==== 動的ライブラリのリンク ==== | ==== 動的ライブラリのリンク ==== | ||
動的ライブラリをQtプロジェクトにリンクするには、以下の手順を行う。<br> | |||
<br> | <br> | ||
# | # Qt Creatorのメイン画面左の[プロジェクト]ペインから、プロジェクト名を右クリックして、[ライブラリを追加]を選択する。 | ||
# [ライブラリの追加]画面が開くので、以下の項目を設定する。<br> | # [ライブラリの追加]画面が開くので、以下の項目を設定する。<br> | ||
#* [ライブラリの種類] | #* [ライブラリの種類]画面は、[外部ライブラリ]を選択する。 | ||
#* [外部ライブラリ] | #* [外部ライブラリ]画面は、ライブラリのリンク方法とライブラリのパスを選択する。 | ||
#*: [ライブラリファイル:] | #*: [ライブラリファイル:]項目は、動的ライブラリファイルのパスを入力する。(<u>動的ライブラリの<code>.so</code>ファイルまたは<code>.a</code>ファイルを指定</u>) | ||
#*: [インクルードパス:]項目は、動的ライブラリのヘッダファイルが存在するパスを入力する。 | |||
#*: [リンク方法]は、[ダイナミック]を選択する。 | #*: [リンク方法]は、[ダイナミック]を選択する。 | ||
# これにより、動的ライブラリとして、Qtプロジェクトにリンクすることができる。<br><u>Qtプロジェクトのビルドは不要である。</u> | # これにより、動的ライブラリとして、Qtプロジェクトにリンクすることができる。<br><u>Qtプロジェクトのビルドは不要である。</u> | ||
<br> | <br> | ||
次に、動的ライブラリの機能を使用するため、動的ライブラリのヘッダファイルをインクルードする。<br> | 次に、動的ライブラリの機能を使用するため、動的ライブラリのヘッダファイルをインクルードする。<br> | ||
# | # Qt Creatorのメイン画面左の[プロジェクト]ペインから、プロジェクト名を右クリックして、[既存のファイルの追加...]を選択する。 | ||
# | # ファイル選択ダイアログから、動的ライブラリのヘッダファイルを選択する。<br>ヘッダファイルをインクルードすることにより、動的ライブラリの機能が使用できるようになる。 | ||
# <u>ただし、動的ライブラリはQT Creatorから独立して実行されるため、実行ファイルと同じディレクトリに動的ライブラリを配置する必要がある。</u> | # <u>ただし、動的ライブラリはQT Creatorから独立して実行されるため、実行ファイルと同じディレクトリに動的ライブラリを配置する必要がある。</u> | ||
<syntaxhighlight lang="c++"> | <syntaxhighlight lang="c++"> | ||
| 104行目: | 323行目: | ||
dialog.show(); | dialog.show(); | ||
return a.exec(); | |||
} | |||
</syntaxhighlight> | |||
<br> | |||
==== 動的ライブラリの明示的リンク ==== | |||
Qtには、動的ライブラリの関数を簡単に使用するために、QLibraryクラスが用意されている。<br> | |||
<br> | |||
明示的リンクを使用して、動的ライブラリの関数を呼び出す手順は、以下の通りである。<br> | |||
# 動的ライブラリの関数において、C言語のグローバル関数として定義する。 | |||
# 動的ライブラリを生成する。 | |||
# 動的ライブラリを呼び出す側の実行ファイルと同じディレクトリに、動的ライブラリを配置する。 | |||
# QLibraryクラスを使用して、動的ライブラリの関数を呼び出す。 | |||
<br> | |||
以下の構成を持つ2つのプロジェクトを作成したとする。<br> | |||
* プロジェクト構成 | |||
** 動的ライブラリ | |||
**: Utils | |||
** 実行ファイル | |||
**: Moc | |||
<br> | |||
まず、Utilsプロジェクトにおいて、関数のみを定義したUtils.cppファイルを作成する。<br> | |||
<syntaxhighlight lang="c++"> | |||
// Utils_global.h | |||
#ifndef UTILS_GLOBAL_H | |||
#define UTILS_GLOBAL_H | |||
#include <QtCore/qglobal.h> | |||
#if defined(Q_OS_WIN) // Windows | |||
#if defined(UTILS_LIBRARY) | |||
#define UTILS_EXPORT __declspec(dllexport) | |||
#else | |||
#define UTILS_EXPORT | |||
#endif | |||
#elif defined(Q_OS_LINUX) // Linux | |||
#if defined(UTILS_LIBRARY) | |||
#define UTILS_EXPORT Q_DECL_EXPORT | |||
#else | |||
#define UTILS_EXPORT Q_DECL_IMPORT | |||
#endif | |||
#endif | |||
#endif // LIBDIALOG_GLOBAL_H | |||
</syntaxhighlight> | |||
<br> | |||
<syntaxhighlight lang="c++"> | |||
// Utils.cpp | |||
#include "Utils_global.h" | |||
#include <iostream> | |||
extern "C" UTILS_EXPORT void SampleHello(int count) | |||
{ | |||
while(--count) | |||
{ | |||
fprintf(stdout, "Hello!!"); | |||
} | |||
} | |||
</syntaxhighlight> | |||
<br> | |||
次に、Mocプロジェクト(動的ライブラリを使用する側)から、動的ライブラリの関数を呼び出す。<br> | |||
<br> | |||
QLibraryクラスから呼び出す関数は、必ず、C言語のグローバル関数として定義すること。<br> | |||
これは、マングリングしていない元の名前から関数を呼び出すためである。<br> | |||
<br> | |||
<u>※注意</u><br> | |||
<u>Windowsでは、動的ライブラリから関数を呼び出すには、<code>__declspec(dllexport)</code>を関数の前に付加すること。</u><br> | |||
<br> | |||
QLibraryクラスのコンストラクタには、<code>.so</code>拡張子または<code>.dll</code>拡張子を付加しないライブラリ名を渡す。<br> | |||
動的ライブラリをリンクするには、<code>load</code>メソッドを実行する。<br> | |||
次に、<code>resolve</code>メソッドを使用して呼び出す関数名を渡して、関数が存在する場合は関数ポインタが返る。<br> | |||
関数名や型が間違っている場合は、0が返る。<br> | |||
<br> | |||
もし、関数内でグローバル変数の値が変更された場合、次の関数を呼び出した時でも、グローバル変数の値を保持し続ける。<br> | |||
<syntaxhighlight lang="c++"> | |||
// main.cpp | |||
#include <QApplication> | |||
#include <QLibrary> | |||
using SampleFunc = void (*)(int); | |||
int main(int argc, char * argv[]) | |||
{ | |||
QApplication a(argc, argv); | |||
// 動的ライブラリをリンクする | |||
QLibrary lib("Utils"); | |||
lib.load(); | |||
// 動的ライブラリの関数を取得する | |||
SampleFunc Func = (SampleFunc)lib.resolve("SampleHello"); | |||
if(Func != 0) | |||
{ | |||
Func(10); | |||
} | |||
return a.exec(); | return a.exec(); | ||
} | } | ||
</syntaxhighlight> | </syntaxhighlight> | ||
<br><br> | <br><br> | ||
== ライブラリとバイナリ互換性 == | |||
==== バイナリ互換性とは ==== | |||
大規模なソフトウェアの場合、複数の機能を再利用したり、プラグイン等を開発するためにライブラリを使用することが多い。<br> | |||
静的ライブラリまたは動的ライブラリをリンクしてソフトウェアから機能を利用する。<br> | |||
<br> | |||
しかし、ライブラリを開発する上で、機能の追加または削除した場合、バイナリ互換性の問題が発生することがある。<br> | |||
<br> | |||
バイナリ互換性とは、ライブラリとそれをリンクしたソフトウェアの間に互換性があるかということである。<br> | |||
例えば、以下のようなライブラリを開発したとする。<br> | |||
<syntaxhighlight lang="c++"> | |||
// Plugin_global.h | |||
#ifndef PLUGIN_GLOBAL_H | |||
#define PLUGIN_GLOBAL_H | |||
#include <QtCore/qglobal.h> | |||
#if defined(Q_OS_WIN) // Windows | |||
#if defined(PLUGIN_LIBRARY) | |||
#define PLUGIN_EXPORT __declspec(dllexport) | |||
#else | |||
#define PLUGIN_EXPORT | |||
#endif | |||
#elif defined(Q_OS_LINUX) // Linux | |||
#if defined(PLUGIN_LIBRARY) | |||
#define PLUGIN_EXPORT Q_DECL_EXPORT | |||
#else | |||
#define PLUGIN_EXPORT Q_DECL_IMPORT | |||
#endif | |||
#endif | |||
#endif // PLUGIN_GLOBAL_H | |||
</syntaxhighlight> | |||
<br> | |||
<syntaxhighlight lang="c++"> | |||
// Plugin.h | |||
#ifndef PLUGIN_H | |||
#define PLUGIN_H | |||
#include "Plugin_global.h" | |||
class PLUGIN_EXPORT Plugin | |||
{ | |||
public: | |||
Plugin(); | |||
virtual ~Plugin(); | |||
private: | |||
int version; | |||
}; | |||
#endif // PLUGIN_H | |||
</syntaxhighlight> | |||
<br> | |||
<syntaxhighlight lang="c++"> | |||
// Plugin.cpp | |||
#include "Plugin.h" | |||
Plugin::Plugin() | |||
{ | |||
} | |||
Plugin::~Plugin() | |||
{ | |||
} | |||
</syntaxhighlight> | |||
以下に、上記のライブラリをリンクするソフトウェアを記述する。<br> | |||
<syntaxhighlight lang="c++"> | |||
// main.h | |||
#include <iostream> | |||
// Pluginクラスを継承 | |||
class MyPlugin : public Plugin | |||
{ | |||
public: | |||
MyPlugin() : version(0) | |||
{ | |||
} | |||
~MyPlugin() | |||
{ | |||
} | |||
void printVersion() | |||
{ | |||
std::cout << "MyPlugin version : " << version << std::endl; | |||
} | |||
private: | |||
int myVersion; | |||
}; | |||
</syntaxhighlight> | |||
<br> | |||
<syntaxhighlight lang="c++"> | |||
// main.cpp | |||
#include <iostream> | |||
int main() | |||
{ | |||
MyPlugin plugin; | |||
plugin.printVersion(); | |||
return 0; | |||
} | |||
</syntaxhighlight> | |||
<br> | |||
次に、以下の例のように、ライブラリの機能を追加したとする。<br> | |||
機能を追加したライブラリを生成して、それを利用側のソフトウェアに再リンクする時、エラーを出力してクラッシュする。 | |||
(利用側のソフトウェアも再ビルドする場合は、正常に読み込まれる) | |||
これは、派生クラスのメモリレイアウトが変更されたからである。 | |||
(クラスの機能を追加することにより、メンバ変数またはメンバ関数のオフセット値が変更される) | |||
<syntaxhighlight lang="c++"> | |||
// Plugin.h | |||
#ifndef PLUGIN_H | |||
#define PLUGIN_H | |||
#include "Plugin_global.h" | |||
#include <string> | |||
class PLUGIN_EXPORT Plugin | |||
{ | |||
public: | |||
Plugin(); | |||
virtual ~Plugin(); | |||
private: | |||
int version; | |||
std::string author; | |||
}; | |||
#endif // PLUGIN_H | |||
</syntaxhighlight> | |||
<br> | |||
==== バイナリ互換性を保つ方法 ==== | |||
バイナリ互換性を保つ方法として、Pimplイディオムを使用する。<br> | |||
Pimplは、元々プライベートの実装を隠蔽するために使用されるイディオムである。<br> | |||
<br> | |||
バイナリ互換性を保つためにPimplを使用する理由として、<br> | |||
変数を1つのクラスにまとめて、後からソースコードを変更してもオフセット値が変化しない利点がある。<br> | |||
<br> | |||
以下の例では、Implクラスを使用することで、Pluginクラスに存在したプライベートメンバの実装をまとめて隠蔽している。<br> | |||
このように、メンバ変数およびメンバ関数を他クラス(ここでは、Implクラス)にまとめて記述することで、<br> | |||
後から変更があってもクラッシュすることは無い。<br> | |||
<br> | |||
これが、Pimplを使用したバイナリ互換性の保ち方である。<br> | |||
<syntaxhighlight lang="c++"> | |||
// Impl.h | |||
#ifndef IMPL_H | |||
#define IMPL_H | |||
#include <string> | |||
class Impl | |||
{ | |||
public: | |||
int version; | |||
std::string author; | |||
}; | |||
#endif // IMPL_H | |||
</syntaxhighlight> | |||
<br> | |||
<syntaxhighlight lang="c++"> | |||
// Plugin_global.h | |||
#ifndef PLUGIN_GLOBAL_H | |||
#define PLUGIN_GLOBAL_H | |||
#include <QtCore/qglobal.h> | |||
#if defined(Q_OS_WIN) // Windows | |||
#if defined(PLUGIN_LIBRARY) | |||
#define PLUGIN_EXPORT __declspec(dllexport) | |||
#else | |||
#define PLUGIN_EXPORT | |||
#endif | |||
#elif defined(Q_OS_LINUX) // Linux | |||
#if defined(PLUGIN_LIBRARY) | |||
#define PLUGIN_EXPORT Q_DECL_EXPORT | |||
#else | |||
#define PLUGIN_EXPORT Q_DECL_IMPORT | |||
#endif | |||
#endif | |||
#endif // PLUGIN_GLOBAL_H | |||
</syntaxhighlight> | |||
<br> | |||
<syntaxhighlight lang="c++"> | |||
// Plugin.h | |||
#ifndef PLUGIN_H | |||
#define PLUGIN_H | |||
#include "Plugin_global.h" | |||
#include "Impl.h" | |||
#include <memory> | |||
class PLUGIN_EXPORT Plugin | |||
{ | |||
public: | |||
Plugin(); | |||
virtual ~Plugin(); | |||
private: | |||
std::unique_ptr<Impl> pImpl; | |||
}; | |||
#endif // PLUGIN_H | |||
</syntaxhighlight> | |||
<br> | |||
<syntaxhighlight lang="c++"> | |||
// Plugin.cpp | |||
#include "Plugin.h" | |||
#include "Impl.h" | |||
#include <memory> | |||
Plugin::Plugin() : pImpl(std::make_unique<Impl>()) | |||
{ | |||
} | |||
Plugin::~Plugin() | |||
{ | |||
} | |||
</syntaxhighlight> | |||
<br><br> | |||
== 静的ライブラリと動的ライブラリの切り替え == | |||
静的ライブラリは、他のプロジェクトに組み込んで使用できるのに対して、動的ライブラリは、実行時に動的にリンクされる違いがある。<br> | |||
しかし、プロジェクトによっては、静的ライブラリと動的ライブラリのビルドを切り替えたい場合もある。<br> | |||
<br> | |||
以下に、静的ライブラリと動的ライブラリのビルドを切り替える方法を記載する。<br> | |||
<br> | |||
まず、動的ライブラリ(ここではMyLib)としてプロジェクトを作成する。<br> | |||
この時、以下のようなプロジェクトファイルが生成される。<br> | |||
# ...略 | |||
TARGET = MyLib | |||
TEMPLATE = lib | |||
DEFINES += MYLIB_LIBRARY | |||
CONFIG += c++17 | |||
SOURCES += MyLib.cpp | |||
HEADERS += MyLib.h\ | |||
mylib_global.h | |||
# ...略 | |||
<br> | |||
上記のままでは、ビルド時に動的ライブラリしか生成されない。<br> | |||
そのため、上記のプロジェクトファイルを以下のように変更する。<br> | |||
<code>MAKE_MYLIB_DLL</code>マクロを定義して、値がtrue以外の場合、静的ライブラリを生成するように設定している。<br> | |||
# ...略 | |||
TARGET = MyLib | |||
TEMPLATE = lib | |||
DEFINES += MYLIB_LIBRARY | |||
CONFIG += c++17 | |||
MAKE_MYLIB_DLL = false # trueの場合は動的ライブラリを生成する | |||
# falseの場合は静的ライブラリを生成する | |||
equals(MAKE_MYLIB_DLL, true) { | |||
DEFINES += MYLIB_LIBRARY | |||
DEFINES += DEFINE_SHARED_EXPORT | |||
} | |||
else { | |||
CONFIG += staticlib | |||
} | |||
# ...略 | |||
<br> | |||
次に、グローバルヘッダファイル(xxx_global.h)を変更する。<br> | |||
<code>DEFINED_SHARED_EXPORT</code>マクロが定義されていない場合、<code>MYLIBSHARED_EXPORT</code>マクロを未定義にしているため、動的ライブラリは生成されない。<br> | |||
<br> | |||
この設定のみで、静的ライブラリと動的ライブラリの切り替えができる。<br> | |||
<syntaxhighlight lang="c++"> | |||
#ifndef MYLIB_GLOBAL_H | |||
#define MYLIB_GLOBAL_H | |||
#include <QtCore/qglobal.h> | |||
#ifdef Q_OS_WIN // Windows | |||
#if defined(MYLIB_LIBRARY) | |||
#define MYLIBSHARED_EXPORT __declspec(dllexport) | |||
#else | |||
#define MYLIBSHARED_EXPORT | |||
#endif | |||
#elif Q_OS_LINUX // Linux | |||
#if defined(MYLIB_LIBRARY) | |||
#define MYLIBSHARED_EXPORT Q_DECL_EXPORT | |||
#else | |||
#define MYLIBSHARED_EXPORT Q_DECL_IMPORT | |||
#endif | |||
#endif | |||
#ifndef DEFINE_SHARED_EXPORT | |||
#define MYLIBSHARED_EXPORT | |||
#endif | |||
#endif // MYLIB_GLOBAL_H | |||
</syntaxhighlight> | |||
<br><br> | |||
== 関数名の確認 == | |||
soファイル (共有ライブラリファイル) に公開されている関数名を確認する場合、stringsコマンドでは不十分である。<br> | |||
stringsコマンドは、バイナリファイルから単純に文字列を抽出するため、関数名だけでなく他の多くの不要な文字列も含まれる。<br> | |||
<br> | |||
公開されている関数名やシンボルを確認する場合、以下に示すコマンドを使用する。<br> | |||
<br> | |||
これは、ライブラリの動的シンボルテーブルが表示されて、公開されている関数を確認することができる。<br> | |||
共有ライブラリの公開されている関数名を簡単に確認することができる。<br> | |||
<br> | |||
* <code>nm -D <ライブラリファイル></code>コマンド | |||
*: バイナリファイルからシンボル情報を表示する。 | |||
*: 関数名やシンボルが確認できる。 | |||
*: <br> | |||
*: また、<code>-D</code>オプションを付加すると、共有ライブラリの動的シンボルのみが表示できる。 | |||
*: <br> | |||
* <code>readelf -Ws <ライブラリファイル></code>コマンド | |||
*: シンボルテーブルを表示する。 | |||
*: <br> | |||
*: これにより、関数や変数の情報を含むシンボルテーブルが表示される。 | |||
*: 出力のType列でFUNCと表示されているものが関数である。 | |||
*: <br> | |||
* <code>objdump -T <ライブラリファイル></code> | |||
*: 詳細な情報を出力する。 | |||
<br><br> | |||
__FORCETOC__ | __FORCETOC__ | ||
[[カテゴリ:Qt]] | [[カテゴリ:Qt]] | ||