CPackによるインストーラパッケージ作成動作の整備¶
- 目次
- CPackによるインストーラパッケージ作成動作の整備
RTCBuilderがコンポーネント生成時に使用するテンプレートを修正し、Windows用インストーラmsiとLinuxパッケージ(deb/rpm)の動作を整えた。
OpenRTM-aist 1.2.0版ではC++とPython RTCのみ対応しており、Javaは動作確認していない。
今回の整備での主な変更点¶
- Python用のCMakeLists.txt、とくにCPack関連の記述様式がC++と異なっていたので、極力C++に合わせるように書き替えた
- C++はcpack_options.cmake.inで定義していたが、PythonはCMakeLists.txtに直接記述していた、など
- WindowsインストーラではWiXだけに対応し、NSIS対応をやめた
- WiX使用時、cmakeが用意しているmsi用テンプレートを利用できるので、RTCBuilderで用意していたwix.xsl.inは不要となった
- Linuxパッケージ(deb or rpm)の自動判定とアーキテクチャを取得するための処理を追加
- 各インストーラパッケージ(msi, deb, rpm)ごとのパッケージファイル名命名規則を整える
- FindOpenRTMPython.cmakeを生成しなくなったので、これを利用している処理を外す
- IDLコンパイルが必要なRTCの場合、インストール時にIDLコンパイルを実行する(Linux/Windowsどちらも)
- doxygenドキュメント用設定ファイルを更新(デフォルトではドキュメント生成機能はOFF)
- Windows用msiで、アップグレードGUID用の設定を追加
NSIS対応をやめた理由¶
WiXとNSISの両方に対応しようとしたが、下記の問題を解決できずで断念し、テンプレートから外している
- 生成したインストーラexeを実行中のGUI画面に表示されるインストールパスの問題。
WiXと同様にインストール先のパスを表示させるようにすると、パスの区切りを判断できず、下記のように長い名前のフォルダになり、
そのままGUIの処理を進めると実際にこのディレクトリにインストールされてしまう
「OpenRTM-aist1.2.0ComponentsC++Category」
WiXでは、「OpenRTM-aist/1.2.0/Components/C++/Category」と解釈してくれるのだが。。。
- デフォルトで、アンインストール用のUninstall.exeを生成してくれる
- コントロールパネルにも表示されるように設定しているので、このexeの生成は不要なのだが、CPackNSISの設定から外す方法が見当たらなかった
- Uninstall.exeの名前をどのプロジェクト用なのか分かるように設定してみたが反映されなかった
- Uninstall.exeの動作は問題なかったが、ファイル名を変更できなかったことにより、同じディレクトリ下に複数のRTCをインストール
すると、Uninstall.exeが上書きされる状態を回避できなかった。sample dir ├─ RTC_A ├─ RTC_B └─ Uninstall.exe ←RTC AとBで、後からインストールした方のアンインストール用で上書きされる
■準備¶
インストーラ、パッケージ作成に必要なソフトウエアをインストールする
Windows¶
OpenRTM-aistのインストール時に示しているソフトウエア以外に、下記のインストールが必要
- Wix Toolset
- msiインストーラを作成するために必要
http://wixtoolset.org/ - 2017/05/12時点で、v3.11が最新版です
https://github.com/wixtoolset/wix3/releases/download/wix311rtm/wix311.exe
- msiインストーラを作成するために必要
- Graphviz
- ドキュメントに依存関係図も含めたい場合に必要 ←この図はお勧め!
http://www.graphviz.org/Download_windows.php - msiを使ってインストールすると、32bitパスの方へインストールされる。
- パスを通してくれないので手動で追加することになる
C:\Program Files (x86)\Graphviz2.38\bin
- インストール確認としては、コマンドプロンプトでバージョンが表示されればOK
>dot -V dot - graphviz version 2.38.0 (20140413.2041)
- RTCBuilderで生成したRTCは、デフォルトでドキュメントビルドがOFFになっているので、ONにする必要がある
- こうしてCMakeを実行すると、「BUILD_DOCUMENTATION」にレ点が入って終了となる
- OpenRTM-aistは32bit版と64bit版の両方をインストールし、VCVerChangerで切り替えてドキュメント生成を確認していたところ、
64bit環境ではCMakeで「BUILD_DOCUMENTATION」が有効にならなかった場合があった - もしかしたらパスの順番が関係しているかもしれない。最終的にPATHの順番が下記の設定で32bit, 64bitを切り替えてもOKを確認した
- ドキュメントに依存関係図も含めたい場合に必要 ←この図はお勧め!
- C:\Program Files\CMake\bin
- C:\Program Files\doxygen\bin
- C:\Program Files (x86)\Graphviz2.38\bin
Linux¶
- 下記の一括インストール用スクリプトでパッケージ作成環境を構築
http://svn.openrtm.org/OpenRTM-aist/trunk/OpenRTM-aist/build/pkg_install_ubuntu.sh
http://svn.openrtm.org/OpenRTM-aist/trunk/OpenRTM-aist/build/pkg_install_debian.sh
http://svn.openrtm.org/OpenRTM-aist/trunk/OpenRTM-aist/build/pkg_install_fedora.sh
- インストールオプションは「-c」を指定する。C++、Pythonの両方に対応したい場合は次のように実行する。
$ sudo sh pkg_install_ubuntu.sh -l c++ -l python -c --yes
■CMakeLists.txtでの変更¶
プロジェクトディレクトリ下にある一番トップのCMakeLists.txtについて
(1)パッケージシステムを検出する処理を追加¶
- Windowsか、Linuxかを判断する
- Raspbianも対応している
- 設定は次の通り
function(get_dist ARG0) if(NOT ${CMAKE_SYSTEM_NAME} MATCHES "Linux") set(${ARG0} ${CMAKE_SYSTEM_NAME} PARENT_SCOPE) return() endif() foreach(dist Debian Ubuntu RedHat Fedora CentOS Raspbian) execute_process( COMMAND grep ${dist} -s /etc/issue /etc/os-release /etc/redhat-release /etc/system-release OUTPUT_VARIABLE dist_name ) if(${dist_name} MATCHES ${dist}) set(${ARG0} ${dist} PARENT_SCOPE) return() endif() endforeach() endfunction(get_dist) function(get_pkgmgr ARG0) get_dist(DIST_NAME) if(${DIST_NAME} MATCHES "Debian" OR ${DIST_NAME} MATCHES "Ubuntu" OR ${DIST_NAME} MATCHES "Raspbian") set(${ARG0} "DEB" PARENT_SCOPE) return() endif() if(${DIST_NAME} MATCHES "RedHat" OR ${DIST_NAME} MATCHES "Fedora" OR ${DIST_NAME} MATCHES "CentOS") set(${ARG0} "RPM" PARENT_SCOPE) return() endif() endfunction(get_pkgmgr) get_dist(DIST_NAME) MESSAGE(STATUS "Distribution is ${DIST_NAME}") ←★ get_pkgmgr(PKGMGR) if(PKGMGR AND NOT LINUX_PACKAGE_GENERATOR) set(LINUX_PACKAGE_GENERATOR ${PKGMGR}) if(${PKGMGR} MATCHES "DEB") execute_process(COMMAND dpkg --print-architecture OUTPUT_VARIABLE CPACK_DEBIAN_PACKAGE_ARCHITECTURE OUTPUT_STRIP_TRAILING_WHITESPACE) message(STATUS "Package manager is ${PKGMGR}. Arch is ${CPACK_DEBIAN_PACKAGE_ARCHITECTURE}.") ←★ endif() if(${PKGMGR} MATCHES "RPM") execute_process(COMMAND uname "-m" OUTPUT_VARIABLE CPACK_RPM_PACKAGE_ARCHITECTURE OUTPUT_STRIP_TRAILING_WHITESPACE) message(STATUS "Package manager is ${PKGMGR}. Arch is ${CPACK_RPM_PACKAGE_ARCHITECTURE}.") ←★ endif() endif()
- CMakeの結果、Windows環境では下記が表示される
Distribution is Windows
- Linuxの場合はパッケージの種類(deb/rpm)とアーキテクチャ(amd64/i386, i686)も表示される
Distribution is Ubuntu Package manager is DEB. Arch is amd64.
(2)インストール先のパスを指定¶
インストーラ(msi)、パッケージ(deb/rpm)をインストールするパスを指定する。
- RTCBuilderでの「基本」タブの「モジュールカテゴリ」で指定した名前のディレクトリ下にインストールされる
- CMakeLists.txtでの設定は次の通り
set(PROJECT_TYPE "c++/Category")
- デフォルトの「Category」のままとした場合、生成したパッケージのデフォルトのインストール先は下記となる
- 生成したRTCのプロジェクト名がAAAで、OpenRTM-aist1.2.0版で作成した場合(C++とPythonに対応)
- Windows msi 32bit
C:/Program Files (x86)/OpenRTM-aist/1.2.0/Components/C++/Category/AAA C:/Program Files (x86)/OpenRTM-aist/1.2.0/Components/Python/Category/AAA
- Linux
/usr/share/openrtm-1.2/components/c++/Category/AAA /usr/share/openrtm-1.2/components/python/Category/AAA
- このインストール先を定義しているCMakeLists.txtでの設定は次の通り
if(WIN32) set(OPENRTM_SHARE_PREFIX "OpenRTM-aist/${RTM_VER}/Components/${PROJECT_TYPE}") set(INSTALL_PREFIX ${PROJECT_NAME}) if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) set(CMAKE_INSTALL_PREFIX "${OPENRTM_DIR}Components/${PROJECT_TYPE}/${PROJECT_NAME}" CACHE PATH "..." FORCE) endif() else(WIN32) set(OPENRTM_SHARE_PREFIX "share/openrtm-${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}") set(INSTALL_PREFIX "${OPENRTM_SHARE_PREFIX}/components/${PROJECT_TYPE}/${PROJECT_NAME}") endif(WIN32)
- 補足
- 「OPENRTM_SHARE_PREFIX」はWindows/Linuxそれぞれの環境用に定義したが、Windowsでは最終的に使っていない
- 「INSTALL_PREFIX」はsrc/CMakeLists.txtで利用している
- 「CMAKE_INSTALL_PREFIX」これを定義しないと、cmakeのconfigure結果のCMAKE_INSTALLPREFIXが、「C:/Program Files (x86)/${PROJECT_NAME}」のパスになってしまう
- Windows msi 32bit
(3)MAINTAINER情報の設定¶
- RTCBuilderでの「ドキュメント生成」タブの「作成者・連絡先」で入力された内容が反映される。
この時「name <mail address>」の書式で入力してもらうように画面右に説明を加えている - 入力例
set(PROJECT_MAINTAINER "Noriaki Ando <n-ando@aist.go.jp>")
- RTCBuilderでの入力がないと、デフォルトとしてunknownとなる
set(PROJECT_MAINTAINER "unknown")
- この設定の反映先
- ソースコード
- doxygenドキュメント ・・・メールアドレスを<>で括っていない場合、doxygenドキュメントでの表記がおかしくなる(上記の例では「@aist」が抜け落ちる)
- debパッケージ情報 ・・・「$less パッケージ名.deb」で表示される
- msiのプロパティ、rpmパッケージ情報には含まれない
■cmake/cpack_options.cmake.inでの変更¶
cpackでインストールパッケージ(msi, deb, rpm)を生成する際の設定。
(1)Linuxのdeb/rpmパッケージ名の書式を定義¶
- deb
if(CPACK_DEBIAN_PACKAGE_ARCHITECTURE) set(CPACK_PACKAGE_FILE_NAME "@PROJECT_NAME_LOWER@_@PROJECT_VERSION@_@CPACK_DEBIAN_PACKAGE_ARCHITECTURE@") endif(CPACK_DEBIAN_PACKAGE_ARCHITECTURE)
- rpm
if(CPACK_RPM_PACKAGE_ARCHITECTURE) set(CPACK_PACKAGE_FILE_NAME "@PROJECT_NAME@-@PROJECT_VERSION@-@CPACK_RPM_PACKAGE_ARCHITECTURE@") endif(CPACK_RPM_PACKAGE_ARCHITECTURE)
(2)Windows用WIXの設定¶
set(CPACK_GENERATOR "WIX") set(CPACK_RESOURCE_FILE_LICENSE "@CMAKE_CURRENT_SOURCE_DIR@/cmake/License.rtf") set(CPACK_PACKAGE_FILE_NAME "@PROJECT_NAME@@PROJECT_SHORT_VER@_rtm@RTM_SHORT_VER@_${CPACK_SYSTEM_NAME}") set(CPACK_PACKAGE_EXECUTABLES "@PROJECT_EXECUTABLES@") ←★C++のスタートメニュー用設定。Python RTCでは含まれない。(補足参照) set(CPACK_PACKAGE_NAME ${CPACK_PACKAGE_FILE_NAME}) set(CPACK_UNINSTALL_NAME @PROJECT_NAME@) set(CPACK_PACKAGE_INSTALL_DIRECTORY "@OPENRTM_SHARE_PREFIX@") # Windows WiX package settings if(${CPACK_GENERATOR} MATCHES "WIX") set(CPACK_WIX_CULTURES "ja-jp") set(CPACK_WIX_UPGRADE_GUID @UPGRADE_GUID@) set(CPACK_WIX_PRODUCT_ICON "@PROJECT_SOURCE_DIR@/cmake\\rt_middleware_logo.ico") set(CPACK_WIX_UI_BANNER "@PROJECT_SOURCE_DIR@/cmake/rt_middleware_banner.bmp") set(CPACK_WIX_UI_DIALOG "@PROJECT_SOURCE_DIR@/cmake/rt_middleware_dlg.bmp") set(CPACK_WIX_PROPERTY_ARPURLINFOABOUT "http://www.openrtm.org") endif()
CPACK_WIX_UPGRADE_GUID¶
- この変数は定義していない。このため自動でGUID値が割り当てられるが、Visual Studioでビルドすると下記のwarningが出る。
生成したmsiファイルは、cxx_test100_rtm120_win32.msiCPack warning : CPACK_WIX_UPGRADE_GUID implicitly set to 943BC397-D307-4F60-A8E1-D13E981DBE68 . Please refer to the documentation on how and why you might want to set this explicitly.
- アップグレード動作の確認
- 上記のGUIDが割り当てられたのは、msiファイル名からプロジェクト「cxx_test」でバージョン番号は1.0.0
- バージョン番号を1.1.0にして、CPACK_WIX_UPGRADE_GUIDを定義する
- 一番トップのCMakeLists.txtのバージョン番号。実際の修正はRTCBuilder上で行わないと、RTC.xml内のバージョン番号と
整合性が取れなくなるので注意。set(PROJECT_VERSION 1.1.0 CACHE STRING "cxx_test version")
- 一番トップのCMakeLists.txtでUPGRADE_GUIDを定義する
- デフォルトは値を定義していない
set(UPGRADE_GUID "")
このままVisual StudioでPACKAGEのビルドをすると、自動で値が割り当てられるので、1.0.0版のGUIDをセットするset(UPGRADE_GUID "943BC397-D307-4F60-A8E1-D13E981DBE68")
同じGUIDを持つ古いバージョンがインストールされていればアンインストールしてからインストールする動作になる。
最初から手動でGUIDを生成してセットしておくのがお勧めの処理です。
- UPGRADE_GUIDを設定している場合の具体的なテスト結果
- インストールパスに関係するカテゴリを変えてmsiを作ってみる
- cxx_testプロジェクト1.0.0版でカテゴリを「Control」とした場合のインストール先
C:/Program Files (x86)/OpenRTM-aist/1.2.0/Components/C++/Control/cxx_test
- RTCBUilderでバージョン番号を1.1.0にし、カテゴリを「hogehoge」にしてmsiを生成する
- msiを実行すると、GUIで示されるインストール先のパスが「C:\Program Files (x86)\OpenRTM-aist\1.2.0\Components\C++\Control」となる。
このまま処理を進めると、Control\cxx_testが新しいものと入れ替わる。cxx_test/RTC.xmlを見ればバージョン番号が上がっていることを確認できる。 - このmsiを実行する前に古い1.0.0バージョンを手動でアンインストールしていれば、新しい1.1.0版のインストール先はhogehogeになる。
C:/Program Files (x86)/OpenRTM-aist/1.2.0/Components/C++/hogehoge/cxx_test
このことから、UPGRADE_GUIDの設定が効いていると判断できる。
補足:スタートメニューへの登録設定¶
- RTCBuilderが生成するC++とPythonのCMakeファイル(CMakeLists.txt等)は元々造りが異なっていた
- 今回の修正で、極力Python側の設定をC++と同じになるように修正したが、インストーラに含めるファイルの登録方法等に違いがある
- このことが影響しているのか、Python RTCのスタートメニューへの登録はC++とは別々の方法で実現できた
- C++のスタートメニュー設定
set(PROJECT_EXECUTABLES ${PROJECT_NAME}Comp "${PROJECT_NAME}Comp.exe") ←CMakeLists.txtで定義 set(CPACK_PACKAGE_EXECUTABLES "@PROJECT_EXECUTABLES@") ←cmake/cpack_options.cmake.inで定義
- Pythonのスタートメニュー設定
set_property(INSTALL "${INSTALL_PREFIX}/${PROJECT_NAME}Comp.py" PROPERTY CPACK_START_MENU_SHORTCUTS "${PROJECT_NAME}Comp.py") ←CMakeLists.txtで定義
■doc/CMakeLists.txtでの変更¶
ドキュメントを生成するために整備。Doxygenでの動作だけ確認し、Sphinx用の処理は従来のままのコメントアウトで確認していない。
- 下記処理をコメントインして、パッケージにドキュメントが含まれるようにした
install(DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/html/doxygen/html" DESTINATION "${INSTALL_PREFIX}" COMPONENT documentation)
- 上記はdoxygenが生成するhtmlディレクトリをインストールパッケージに含むというものである
- インストールされるディレクトリ構造は以下となる
└─cxx_test │ cxx_test.dll │ cxx_test.lib │ cxx_testComp.exe │ RTC.xml │ └─html │ index.html │ : │ └─search
- デフォルトでドキュメントは生成しない(OFF)になっているので、生成する場合は一番トップのCMakeLists.txtでONに変更する必要がある
option(BUILD_DOCUMENTATION "Build the documentation" ON)
doxyfileの設定¶
今回整備した設定
- graphvizで生成される図のRTCのファイル名をフルパス表示にしない
- FULL_PATH_NAMES = YES
- STRIP_FROM_PATH =
@PROJECT_SOURCE_DIR
@
- include, importのファイル名をフルパス表示にしない
- STRIP_FROM_INC_PATH =
@PROJECT_SOURCE_DIR
@
- STRIP_FROM_INC_PATH =
- Java/PythonのRTCの場合、言語により適合した出力形式にする
- OPTIMIZE_OUTPUT_JAVA = YES ←★C++ならばNOにしている
- この指定により、ドキュメントの名前空間タブ名がパッケージとなる
- ドキュメントの文字コードはUTF-8と指定しているが、RTCプロジェクトにShift-JISのソースがあった場合にnkfで自動変換し、文字化けしないようにする
- INPUT_FILTER = "nkf -w"
- FILTER_SOURCE_FILES = YES
- nkfのインストール:Windows環境はOpenRTM-aistのmsiにて、Linux環境はpkg_install_***.shのスクリプトにてインストールされる
■Pythonパッケージインストール時のIDLコンパイル処理¶
サービスポートを持つPython RTCは、パッケージインストール時にIDLコンパイルを実行するように定義する。
また、RTCアンインストール時はIDLコンパイルで生成されたファイルを削除し、ゴミが残らないようにする。
Windows¶
- Windows環境ではWiXの CustomAction としてこれらの動作を定義する
- wxsファイルは、cmakeが用意しているmsi用テンプレートを利用しているので、これに対するpatchファイルで定義する
- IDLコンパイル用スクリプト、アンインストール時の削除用スクリプトをそれぞれShift-JISファイルで用意する
- idlcompile.bat
- delete.bat
- patchファイルを用意する(cmake/wix_patch.xml.in)
<CPackWiXPatch> <CPackWiXFragment Id="#PRODUCT"> <CustomAction Id="PostinstAction" ExeCommand="idlcompile.bat" Execute="deferred" Impersonate="no" FileKey="CM_FP_component.@PROJECT_NAME@.idlcompile.bat"/> <CustomAction Id="PrermAction" ExeCommand="delete.bat" Execute="deferred" Impersonate="no" FileKey="CM_FP_component.@PROJECT_NAME@.delete.bat"/> <InstallExecuteSequence> <Custom Action="PostinstAction" Before="InstallFinalize"> NOT Installed </Custom> </InstallExecuteSequence> <InstallExecuteSequence> <Custom Action="PrermAction" Before="RemoveFiles"> Installed </Custom> </InstallExecuteSequence> </CPackWiXFragment> </CPackWiXPatch>
- デフォルトのインストール先はOpenRTM-aistのインストールディレクトリなので、実行権限を付ける
- Execute="deferred":カスタムアクションを管理者権限で動作させる
- Impersonate="no":カスタムアクションは昇格された権限を必要とする
- idlcompile.batに対する設定
- Before="InstallFinalize":管理者権限での実行と条件を付けたら、InstallInitialize actionとInstallFinalize actionの間で実行する必要があるため
- delete.batに対する設定
- Before="RemoveFiles":この設定で実現できるまでの経緯は以下の通り
- インストーラのアクションの順番は変更できるようだが、一応以下の順番になっている
http://wix-tutorial-ja.github.io/ch03/01-queueing-up.htmlAppSearch LaunchConditions ValidateProductID CostInitialize FileCost CostFinalize InstallValidate InstallInitialize --------------- 管理者権限でのアクションを指定するのは、ここから ProcessComponents UnpublishFeatures RemoveShortcuts RemoveFiles InstallFiles CreateShortcuts RegisterUser RegisterProduct PublishFeatures PublishProduct --------------- ここまで InstallFinalize RemoveExistingProducts
- 下記の4パターンを試すが、いずれもNG
After="InstallInitialize", Before="InstallFinalize", After="RemoveFiles", After="RemoveShortcuts" - この設定ではアンインストール時に下記メッセージが出るうえ、インストールしたファイル一式、コントロールパネルとレジストリの
設定も残ったままでどうにもできない状態になった。There is a problem with this Windows Installer package. A programn required for this install to complete could not be run.
- フリーのツールgeekで強制削除を実行することで削除できた
http://www.gigafree.net/system/install/geekuninstaller.html - アンインストールの過程で、delete.batを削除された後だと動作しませんから、「RemoveFiles」の前として指定したらOKだった
- インストーラのアクションの順番は変更できるようだが、一応以下の順番になっている
- Before="RemoveFiles":この設定で実現できるまでの経緯は以下の通り
- patchファイルは下記で定義している
- トップのCMakeLists.txt
set(WIX_PATCH_FILE "${CMAKE_CURRENT_BINARY_DIR}/wix_patch.xml") configure_file("cmake/wix_patch.xml.in" ${WIX_PATCH_FILE} @ONLY)
- cmake/cpack_options.cmake.in
set(CPACK_WIX_PATCH_FILE "@WIX_PATCH_FILE@")
- トップのCMakeLists.txt
Linux¶
- Linux環境は、postinst と prerm に定義してあげれば実現できる
- postinst:インストール後に実行するスクリプト
- prerm :アンインストール前に実行するスクリプト
- IDLコンパイル用スクリプトは、idlcompile.sh
- postinst.in
#!/bin/sh # postinst script set -e cd /usr/@INSTALL_PREFIX@ sh idlcompile.sh
- prerm.in
#!/bin/sh # prerm script sudo rm -rf /usr/@INSTALL_PREFIX@
- postinst, preremは下記で定義している
- トップのCMakeLists.txt
# postinst, prerm settings if(UNIX) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/postinst.in ${CMAKE_CURRENT_SOURCE_DIR}/postinst @ONLY ) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/prerm.in ${CMAKE_CURRENT_SOURCE_DIR}/prerm @ONLY ) endif()
- cmake/cpack_options.cmake.in
- debパッケージ用の設定
set(CPACK_DEBIAN_PACKAGE_CONTROL_EXTRA "@CMAKE_SOURCE_DIR@/postinst;@CMAKE_SOURCE_DIR@/prerm")
- rpmパッケージ用の設定
set(CPACK_RPM_POST_INSTALL_SCRIPT_FILE "@CMAKE_SOURCE_DIR@/postinst") set(CPACK_RPM_POST_UNINSTALL_SCRIPT_FILE "@CMAKE_SOURCE_DIR@/prerm")
- debパッケージ用の設定
- トップのCMakeLists.txt