CPack
CPackの主な機能と特徴
-
多様なパッケージフォーマットのサポート: CPackは、WindowsのNSISインストーラー、macOSのDMG、LinuxのDEBやRPMパッケージ、tar.gz、ZIPなど、非常に多くのパッケージフォーマットに対応しています。これにより、異なるOSやプラットフォーム向けに一貫した方法でパッケージを作成できます。
-
CMakeとの統合: CPackはCMakeに深く統合されています。CMakeLists.txtファイル内で
include(CPack)
コマンドを使用し、いくつかの変数を設定するだけで、プロジェクトのビルドプロセスの一部としてパッケージングを自動化できます。 -
設定の柔軟性: CPackの動作は、
CPACK_
で始まる多くの変数によって制御されます。例えば、パッケージ名、バージョン、ライセンス情報、インストールディレクトリ、生成するパッケージの種類などを細かく設定できます。 -
コンポーネントベースのパッケージング: ソフトウェアが複数の独立したコンポーネントから構成されている場合、CPackは各コンポーネントを個別にパッケージングする機能を提供します。これにより、ユーザーは必要なコンポーネントだけを選択してインストールできるようになります。
-
インストールプロセスのカスタマイズ: インストーラーにカスタムスクリプト(例:インストール前後の処理、GUIのカスタマイズなど)を組み込むことも可能です。これにより、より複雑なインストール要件にも対応できます。
CPackの基本的な使い方(CMakeLists.txtでの設定例)
CMakeLists.txtファイルでCPackを有効にするには、通常、以下の手順を踏みます。
-
プロジェクト情報の定義: パッケージの基本的な情報を定義します。
project(MySoftware VERSION 1.0.0)
-
インストールルールの定義: どのファイルをどこにインストールするかを定義します。
install()
コマンドを使用します。install(TARGETS MyExecutable DESTINATION bin) install(FILES MyConfig.txt DESTINATION etc)
-
CPackモジュールのインクルード: CPack機能を使用するために、モジュールをインクルードします。
include(CPack)
CMakeLists.txtを設定した後、ビルドディレクトリで以下のコマンドを実行します。
cmake -S . -B build
cmake --build build
cpack --config build/CPackConfig.cmake
または、CMakeのビルドターゲットとしてpackage
ターゲットも利用できます。
cmake --build build --target package
これにより、設定された形式(例:.exe, .deb, .rpmなど)のインストールパッケージがビルドディレクトリ内に生成されます。
CPackにおける一般的なエラーとトラブルシューティング
-
- エラーの原因:
include(CPack)
がCMakeLists.txtに含まれていない。install()
コマンドでインストールルールが正しく定義されていない。CPACK_GENERATOR
変数が設定されていないか、サポートされていないジェネレータが指定されている。cpack
コマンドの実行方法が間違っている(例:--config
オプションで正しいCPackConfig.cmake
を指定していない)。
- トラブルシューティング:
include(CPack)
の確認: CMakeLists.txtのどこかでinclude(CPack)
が呼び出されていることを確認してください。通常は、project()
コマンドの後、かつinstall()
コマンドの後に配置します。install()
ルールの確認: どのファイルがどこにインストールされるべきか、install()
コマンドで正しく指定されているか確認してください。CPackは、これらのインストールルールに基づいてパッケージを作成します。CPACK_GENERATOR
の設定: どの種類のパッケージを生成したいか、set(CPACK_GENERATOR "NSIS" "DEB")
のように明示的に指定しているか確認してください。cpack
コマンドの確認: ビルドディレクトリ(cmake -S . -B build
でbuild
とした場合)でcpack --config build/CPackConfig.cmake
を実行しているか確認してください。また、cmake --build build --target package
も便利です。CPackConfig.cmake
の確認: 生成されたCPackConfig.cmake
ファイルの内容を直接見て、意図した設定になっているか確認するのも有効です。
- エラーの原因:
-
インストーラーが期待通りに動作しない、またはエラーで終了する
- エラーの原因:
- 特定のジェネレータ(NSIS、RPMなど)に特有の依存関係が不足している(例: NSISジェネレータを使用するのにNSISがインストールされていない)。
install()
パスに問題がある(例:DESTINATION
がOSの標準的なディレクトリ構造と合わない)。- パッケージ化されたファイルに実行権限がない、またはパスが通っていない。
- カスタムスクリプト(NSISの場合など)にエラーがある。
- トラブルシューティング:
- ジェネレータの依存関係: 使用しているCPackジェネレータが要求する外部ツールやライブラリがシステムにインストールされているか確認してください。例えば、NSISジェネレータにはNSIS本体、RPMジェネレータには
rpmbuild
が必要です。 - インストールパスの確認:
install(TARGETS MyTarget DESTINATION bin)
のように、DESTINATION
がターゲットOSの標準的なインストールパスに準拠しているか確認してください。Windowsではbin
、lib
など、Linuxでは/usr/local/bin
、/usr/local/lib
などを考慮します。 - 権限の問題: Linux系のシステムでは、インストールされた実行ファイルやスクリプトに必要な実行権限があるか確認してください。
install(PROGRAMS ...)
やinstall(SCRIPTS ...)
を使用する場合、CMakeが自動的に実行権限を付与しますが、手動でコピーする場合は注意が必要です。 - 詳細なログの確認:
cpack -V
(verboseモード)やcpack --debug
オプションを使用して、より詳細なデバッグ情報を出力させ、エラーメッセージを探してください。
- ジェネレータの依存関係: 使用しているCPackジェネレータが要求する外部ツールやライブラリがシステムにインストールされているか確認してください。例えば、NSISジェネレータにはNSIS本体、RPMジェネレータには
- エラーの原因:
-
パッケージのサイズが非常に大きい、または不要なファイルが含まれている
- エラーの原因:
- ビルドアーティファクト(中間ファイル、デバッグシンボルなど)が誤って
install()
ルールに含まれている。 install()
コマンドのDIRECTORY
オプションで、意図せず多くのファイルがインストール対象になっている。
- ビルドアーティファクト(中間ファイル、デバッグシンボルなど)が誤って
- トラブルシューティング:
install()
ルールの見直し:install()
コマンドで指定しているファイルやディレクトリを注意深く確認し、本当に必要なものだけが含まれていることを確認してください。例えば、install(DIRECTORY build_dir/ DESTINATION .)
のようにすると、ビルドディレクトリ全体がコピーされてしまう可能性があります。EXCLUDE_FROM_ALL
/EXCLUDE_FROM_INSTALL
: 不要なファイルやディレクトリをパッケージから除外するために、install()
コマンドのEXCLUDE_FROM_INSTALL
オプションや、CPack変数(例:CPACK_SOURCE_INSTALLED_DIRECTORIES
)を適切に設定することを検討してください。- デバッグシンボルの除外: リリースビルドでは、デバッグシンボルを除外することでパッケージサイズを大幅に削減できます。ビルド設定でデバッグシンボルを生成しないようにするか、CPackのオプションで除外するように設定してください。
- エラーの原因:
-
CPackの変数が期待通りに設定されていない
- エラーの原因:
- 変数のスペルミス(例:
CPACK_PACKAGE_VERSION
がCPACK_PACKAGE_VERSOIN
になっている)。 - 変数が設定されるタイミングが不適切(例:
include(CPack)
の前にCPack変数を設定していない)。 CMakeCache.txt
に古い値がキャッシュされている。
- 変数のスペルミス(例:
- トラブルシューティング:
- スペルチェック: CPack変数のスペルを何度も確認してください。公式ドキュメントで正しい変数名を参照するのが最も確実です。
- 設定のタイミング:
include(CPack)
コマンドの前にCPack変数を設定することを強く推奨します。これにより、CPackモジュールがロードされる際にそれらの変数を適切に解釈できます。 - キャッシュのクリア:
CMakeCache.txt
ファイルを手動で削除し、cmake
コマンドを再実行することで、キャッシュされた古い値をクリアできます。これは多くのCMake関連の問題で有効な手段です。 message()
コマンドでの確認:message(STATUS "CPACK_PACKAGE_NAME: ${CPACK_PACKAGE_NAME}")
のように、CMakeLists.txt内で変数の中身を出力させ、意図した値になっているか確認してください。
- エラーの原因:
-
コンポーネントベースのパッケージングが機能しない
- エラーの原因:
install(COMPONENT ...)
が正しく使用されていない。CPACK_COMPONENTS_ALL
やCPACK_COMPONENT_PROPERTY
などのCPack変数が設定されていない。
- トラブルシューティング:
install(COMPONENT ...)
の確認: 各install()
コマンドで、どのコンポーネントに属するかをCOMPONENT
オプションで指定しているか確認してください。- コンポーネントのプロパティ設定: 各コンポーネントの表示名、説明、グループなどを
CPACK_COMPONENT_PROPERTY
で設定しているか確認してください。 - ジェネレータのサポート: 全てのCPackジェネレータがコンポーネントベースのインストールを完全にサポートしているわけではありません。特にシンプルなアーカイブ形式ではサポートされない場合があります。
- エラーの原因:
- シンプルなケースから始める: CPackの設定で問題が発生した場合は、まず非常にシンプルなプロジェクトで必要最小限のパッケージング設定を試してみてください。それが機能することを確認してから、徐々に複雑な設定を追加していくと、問題の切り分けが容易になります。
- CMakeのドキュメント: CPackの公式ドキュメントは非常に包括的です。特定のジェネレータや変数に関する詳細な情報が必要な場合は、ここを参照するのが最も確実です。
CPackConfig.cmake
のレビュー: CMakeが生成するCPackConfig.cmake
ファイルは、CPackがどのような設定で動作しようとしているかを示す重要な情報源です。このファイルの内容を確認することで、間違いや予期しない設定を見つけることができます。cpack -V
/cpack --debug
: 詳細な出力を得て、何が起こっているかを理解するのに役立ちます。
基本的なC++アプリケーションのパッケージング例
この例では、簡単なC++の実行ファイルをビルドし、それをNSIS(Windowsインストーラー)とtar.gz(Linux/macOS向けアーカイブ)でパッケージングする方法を示します。
プロジェクト構造
.
├── CMakeLists.txt
├── main.cpp
└── README.md
main.cpp
#include <iostream>
#include <string>
int main() {
std::cout << "Hello from MySimpleApp!" << std::endl;
std::cout << "This application is built using CMake and packaged with CPack." << std::endl;
std::cout << "Version: 1.0.0" << std::endl;
return 0;
}
README.md
(パッケージに含めるファイル)
# MySimpleApp
This is a simple application to demonstrate CMake and CPack.
CMakeLists.txt
# 1. プロジェクトの定義
cmake_minimum_required(VERSION 3.10)
project(MySimpleApp VERSION 1.0.0 LANGUAGES CXX)
# 2. 実行ファイルのビルド
add_executable(MySimpleApp main.cpp)
# 3. インストールルールの定義
# 実行ファイルを 'bin' ディレクトリにインストール
install(TARGETS MySimpleApp
RUNTIME DESTINATION bin) # RUNTIME は実行ファイル(Windowsの.exeなど)を意味します
# README.md をドキュメントディレクトリにインストール
install(FILES README.md
DESTINATION share/doc/${PROJECT_NAME}) # Linux/macOSでの一般的なドキュメントパス
# 4. CPackモジュールのインクルード
# CPack関連の変数は、CPackをインクルードする前に設定することを推奨します。
include(CPack)
# 5. CPackの一般的な設定
set(CPACK_PACKAGE_NAME "${PROJECT_NAME}") # パッケージ名
set(CPACK_PACKAGE_VENDOR "MyCompany") # 開発元
set(CPACK_PACKAGE_VERSION ${PROJECT_VERSION}) # プロジェクトのバージョンを使用
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "A simple application demonstrating CMake and CPack.")
set(CPACK_PACKAGE_HOMEPAGE_URL "https://example.com/mysimpleapp")
set(CPACK_PACKAGE_CONTACT "[email protected]")
set(CPACK_PACKAGE_INSTALL_DIRECTORY "${PROJECT_NAME}") # Windowsインストーラーのデフォルトインストールディレクトリ名
# 生成するパッケージ形式の指定
# WindowsではNSIS、Linux/macOSではTGZ(tar.gz)が一般的
if(WIN32)
set(CPACK_GENERATOR "NSIS")
# NSISインストーラーのオプション設定例
set(CPACK_NSIS_DISPLAY_NAME "${CPACK_PACKAGE_NAME} ${CPACK_PACKAGE_VERSION}")
set(CPACK_NSIS_HELP_LINK "https://example.com/mysimpleapp/help")
set(CPACK_NSIS_URL_INFO_ABOUT "https://example.com/mysimpleapp")
set(CPACK_NSIS_MENU_LINKS
"desktop" "${PROJECT_NAME}" "RUN" "$INSTDIR\\bin\\${PROJECT_NAME}.exe"
"startmenu" "${PROJECT_NAME}" "RUN" "$INSTDIR\\bin\\${PROJECT_NAME}.exe"
)
elseif(UNIX) # Linux と macOS (Darwin) は UNIX と見なされます
set(CPACK_GENERATOR "TGZ") # tar.gz アーカイブ
# Linux特有のパッケージ(DEB/RPM)が必要な場合は、追加のモジュールが必要
# 例えば、DEBの場合:
# set(CPACK_GENERATOR "DEB")
# set(CPACK_DEBIAN_PACKAGE_SECTION "utils")
# set(CPACK_DEBIAN_PACKAGE_PRIORITY "optional")
# set(CPACK_DEBIAN_FILE_NAME_FORMAT DEB_PACKAGE_NAME-DEB_PACKAGE_VERSION_DEB_PACKAGE_ARCHITECTURE.deb)
# set(CPACK_DEBIAN_PACKAGE_DEPENDS "libc6, libstdc++6")
# (RPMも同様にCPACK_RPM_... 変数を設定)
endif()
# パッケージに含めるライセンスファイル(オプション)
# set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/LICENSE.txt")
# CPackが生成するパッケージのファイル名をカスタマイズ(オプション)
# 例: MySimpleApp-1.0.0-Windows.exe
set(CPACK_PACKAGE_FILE_NAME "${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}-${CMAKE_SYSTEM_NAME}")
ビルドとパッケージングの手順
-
mkdir build cd build cmake ..
-
プロジェクトのビルド
cmake --build .
-
CPackによるパッケージの生成
cpack --config CPackConfig.cmake
または、CMakeのビルドシステムに統合された
package
ターゲットを使用します。cmake --build . --target package
上記のコマンドを実行すると、build
ディレクトリ内に指定された形式(Windowsでは.exe
、Linux/macOSでは.tar.gz
)のパッケージファイルが生成されます。
コンポーネントベースのパッケージング例
ソフトウェアが複数の独立した部分(コンポーネント)から構成され、ユーザーがインストール時にそれらを選択できるようにしたい場合に、コンポーネントベースのパッケージングを使用します。
CMakeLists.txt
(抜粋)
# ... (プロジェクト定義、実行ファイルビルドなどは上記と同様) ...
# 実行ファイルを「Core」コンポーネントとしてインストール
install(TARGETS MySimpleApp
RUNTIME DESTINATION bin
COMPONENT Core) # コンポーネント名を指定
# README.md を「Documentation」コンポーネントとしてインストール
install(FILES README.md
DESTINATION share/doc/${PROJECT_NAME}
COMPONENT Documentation) # コンポーネント名を指定
# CPackモジュールをインクルード
include(CPack)
# CPackの一般的な設定は上記と同様
# コンポーネントの設定
# CPackによって、どのコンポーネントがインストールされるかを定義
# 各コンポーネントにはプロパティを設定可能 (例: 表示名、説明、デフォルトで選択するかどうか)
set(CPACK_COMPONENTS_ALL
Core
Documentation
)
# Core コンポーネントのプロパティ
set(CPACK_COMPONENT_Core_DISPLAY_NAME "Application Core")
set(CPACK_COMPONENT_Core_DESCRIPTION "The main executable and essential files.")
set(CPACK_COMPONENT_Core_REQUIRED TRUE) # このコンポーネントは必須
# Documentation コンポーネントのプロパティ
set(CPACK_COMPONENT_Documentation_DISPLAY_NAME "User Documentation")
set(CPACK_COMPONENT_Documentation_DESCRIPTION "User manual and additional documentation.")
set(CPACK_COMPONENT_Documentation_GROUP "Documentation") # グループ化することも可能
set(CPACK_COMPONENT_Documentation_DISABLED TRUE) # デフォルトで選択しない
# (オプション) グループのプロパティ設定
set(CPACK_COMPONENT_GROUP_Documentation_DISPLAY_NAME "Additional Documentation")
set(CPACK_COMPONENT_GROUP_Documentation_DESCRIPTION "Various documentation files.")
コンポーネントベースのパッケージをビルドすると
WindowsのNSISインストーラーの場合、インストールウィザードで「Custom Setup」を選択すると、「Application Core」と「User Documentation」という選択肢が表示され、ユーザーはどちらをインストールするか選択できるようになります。
INSTALL_RPATH
/BUILD_RPATH
(Linux): Linux環境で共有ライブラリを使用する場合、パッケージングされたアプリケーションが正しくライブラリを見つけられるように、CMAKE_INSTALL_RPATH
やCMAKE_BUILD_RPATH
を設定することが重要になる場合があります。- パッケージングのデバッグ:
cpack -V
(verbose)やcpack --debug
オプションを使用すると、CPackがパッケージを作成する過程で何が起こっているか、より詳細なログを確認できます。問題が発生した際に非常に役立ちます。 - カスタムスクリプト:
NSISやRPMなどのジェネレータでは、インストール前後に実行されるカスタムスクリプトを指定できます。これは、
CPACK_NSIS_PREINSTALL_SCRIPT
やCPACK_RPM_PRE_INSTALL_SCRIPT
などの変数で設定します。
CPackの代替となるパッケージング方法
CPackの主な代替手段としては、大きく分けて「各プラットフォームネイティブのパッケージ管理システムを直接利用する方法」と「汎用的なクロスプラットフォームのパッケージングツールを利用する方法」があります。
プラットフォームネイティブなパッケージ管理システム/ツールを直接利用する
これは、対象とするOSの標準的なパッケージ形式やツールを直接使うアプローチです。CPackはこれらのツールのラッパーを提供していますが、直接使用することでより高度な制御や、CPackがサポートしていない特殊なケースに対応できる場合があります。
汎用的なクロスプラットフォームのパッケージングツール/スクリプトを利用する
特定のプラットフォームに依存しない、より汎用的なアプローチです。
- 自動更新の要件
アプリケーション自体に更新機能が必要か。 - メンテナンス性
パッケージングスクリプトや定義ファイルの管理のしやすさ。 - 開発チームのスキルセット
特定のツールの知識や経験。 - 配布チャネル
ウェブサイトからのダウンロード、パッケージマネージャー、商用ストアなど。 - 複雑性
パッケージングするソフトウェアの構造、依存関係、インストール時の要件。 - ターゲットプラットフォーム
Windows, Linux (どのディストリビューションか), macOS, モバイルなど。