CPack

2025-05-31

CPackの主な機能と特徴

  1. 多様なパッケージフォーマットのサポート: CPackは、WindowsのNSISインストーラー、macOSのDMG、LinuxのDEBやRPMパッケージ、tar.gz、ZIPなど、非常に多くのパッケージフォーマットに対応しています。これにより、異なるOSやプラットフォーム向けに一貫した方法でパッケージを作成できます。

  2. CMakeとの統合: CPackはCMakeに深く統合されています。CMakeLists.txtファイル内でinclude(CPack)コマンドを使用し、いくつかの変数を設定するだけで、プロジェクトのビルドプロセスの一部としてパッケージングを自動化できます。

  3. 設定の柔軟性: CPackの動作は、CPACK_で始まる多くの変数によって制御されます。例えば、パッケージ名、バージョン、ライセンス情報、インストールディレクトリ、生成するパッケージの種類などを細かく設定できます。

  4. コンポーネントベースのパッケージング: ソフトウェアが複数の独立したコンポーネントから構成されている場合、CPackは各コンポーネントを個別にパッケージングする機能を提供します。これにより、ユーザーは必要なコンポーネントだけを選択してインストールできるようになります。

  5. インストールプロセスのカスタマイズ: インストーラーにカスタムスクリプト(例:インストール前後の処理、GUIのカスタマイズなど)を組み込むことも可能です。これにより、より複雑なインストール要件にも対応できます。

CPackの基本的な使い方(CMakeLists.txtでの設定例)

CMakeLists.txtファイルでCPackを有効にするには、通常、以下の手順を踏みます。

  1. プロジェクト情報の定義: パッケージの基本的な情報を定義します。

    project(MySoftware VERSION 1.0.0)
    
  2. インストールルールの定義: どのファイルをどこにインストールするかを定義します。install()コマンドを使用します。

    install(TARGETS MyExecutable DESTINATION bin)
    install(FILES MyConfig.txt DESTINATION etc)
    
  3. 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 buildbuildとした場合)でcpack --config build/CPackConfig.cmakeを実行しているか確認してください。また、cmake --build build --target packageも便利です。
      • CPackConfig.cmakeの確認: 生成されたCPackConfig.cmakeファイルの内容を直接見て、意図した設定になっているか確認するのも有効です。
  1. インストーラーが期待通りに動作しない、またはエラーで終了する

    • エラーの原因:
      • 特定のジェネレータ(NSIS、RPMなど)に特有の依存関係が不足している(例: NSISジェネレータを使用するのにNSISがインストールされていない)。
      • install()パスに問題がある(例: DESTINATIONがOSの標準的なディレクトリ構造と合わない)。
      • パッケージ化されたファイルに実行権限がない、またはパスが通っていない。
      • カスタムスクリプト(NSISの場合など)にエラーがある。
    • トラブルシューティング:
      • ジェネレータの依存関係: 使用しているCPackジェネレータが要求する外部ツールやライブラリがシステムにインストールされているか確認してください。例えば、NSISジェネレータにはNSIS本体、RPMジェネレータにはrpmbuildが必要です。
      • インストールパスの確認: install(TARGETS MyTarget DESTINATION bin)のように、DESTINATIONがターゲットOSの標準的なインストールパスに準拠しているか確認してください。Windowsではbinlibなど、Linuxでは/usr/local/bin/usr/local/libなどを考慮します。
      • 権限の問題: Linux系のシステムでは、インストールされた実行ファイルやスクリプトに必要な実行権限があるか確認してください。install(PROGRAMS ...)install(SCRIPTS ...)を使用する場合、CMakeが自動的に実行権限を付与しますが、手動でコピーする場合は注意が必要です。
      • 詳細なログの確認: cpack -V(verboseモード)やcpack --debugオプションを使用して、より詳細なデバッグ情報を出力させ、エラーメッセージを探してください。
  2. パッケージのサイズが非常に大きい、または不要なファイルが含まれている

    • エラーの原因:
      • ビルドアーティファクト(中間ファイル、デバッグシンボルなど)が誤って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のオプションで除外するように設定してください。
  3. CPackの変数が期待通りに設定されていない

    • エラーの原因:
      • 変数のスペルミス(例: CPACK_PACKAGE_VERSIONCPACK_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内で変数の中身を出力させ、意図した値になっているか確認してください。
  4. コンポーネントベースのパッケージングが機能しない

    • エラーの原因:
      • install(COMPONENT ...)が正しく使用されていない。
      • CPACK_COMPONENTS_ALLCPACK_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}")

ビルドとパッケージングの手順

  1. mkdir build
    cd build
    cmake ..
    
  2. プロジェクトのビルド

    cmake --build .
    
  3. 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_RPATHCMAKE_BUILD_RPATHを設定することが重要になる場合があります。
  • パッケージングのデバッグ: cpack -V(verbose)やcpack --debugオプションを使用すると、CPackがパッケージを作成する過程で何が起こっているか、より詳細なログを確認できます。問題が発生した際に非常に役立ちます。
  • カスタムスクリプト: NSISやRPMなどのジェネレータでは、インストール前後に実行されるカスタムスクリプトを指定できます。これは、CPACK_NSIS_PREINSTALL_SCRIPTCPACK_RPM_PRE_INSTALL_SCRIPTなどの変数で設定します。


CPackの代替となるパッケージング方法

CPackの主な代替手段としては、大きく分けて「各プラットフォームネイティブのパッケージ管理システムを直接利用する方法」と「汎用的なクロスプラットフォームのパッケージングツールを利用する方法」があります。

プラットフォームネイティブなパッケージ管理システム/ツールを直接利用する

これは、対象とするOSの標準的なパッケージ形式やツールを直接使うアプローチです。CPackはこれらのツールのラッパーを提供していますが、直接使用することでより高度な制御や、CPackがサポートしていない特殊なケースに対応できる場合があります。

汎用的なクロスプラットフォームのパッケージングツール/スクリプトを利用する

特定のプラットフォームに依存しない、より汎用的なアプローチです。

  • 自動更新の要件
    アプリケーション自体に更新機能が必要か。
  • メンテナンス性
    パッケージングスクリプトや定義ファイルの管理のしやすさ。
  • 開発チームのスキルセット
    特定のツールの知識や経験。
  • 配布チャネル
    ウェブサイトからのダウンロード、パッケージマネージャー、商用ストアなど。
  • 複雑性
    パッケージングするソフトウェアの構造、依存関係、インストール時の要件。
  • ターゲットプラットフォーム
    Windows, Linux (どのディストリビューションか), macOS, モバイルなど。