Help us understand the problem. What is going on with this article?

CMakeで大きめのプロジェクトを構成するためのメモ

More than 3 years have passed since last update.

http://qiita.com/shibukawa/items/88e868d68beb5722f335

ここ2週間ぐらい、CMakeジェネレータのqtpmの改良を続けてきました。生成されたファイル自身は、いろいろな試行錯誤の結果が凝縮されたものです。こういう意図をもってこのように変更してきたよ、というのをまとめます。

ちなみに、生成するCMakeLists.txtはライブラリ用とアプリ用と2パターンあり、ライブラリ用の完成品は上記のリンクに貼っています。アプリ用の完成品はこのページの下部にあります。あと、書きながらちょちちょいミスを見つけて手修正したところもあるので、まだ検証が漏れている所も少しあります。特にWindows周り。検証して間違いがあったら適宜修正していきます。

大規模とは何か?

まずは大きいプロジェクトとは何か、というところから。簡単に説明すると、独立した部品に分けられるようなアプリを想定しています。独立した部品は個別のパッケージに入ります。その中には、サンプルコードとテストコードがあります。ビルドするとライブラリとなって、親のプロジェクトから使われます。

・・・・ここまでは問題なさそうに見えますが、実はそうではないです。

独立したライブラリのアーカイブを親プロジェクトに読み込ませる方式の欠点

最初から独立性の高い単独の部品で、仕様が決まってブレがないならこれで問題はありませんが、実際はそう順調にはいかず、部品と親のアプリを行ったり来たりする必要があります。最初のqtpmの設計では、ライブラリプロジェクトをビルドしてインストールすると、親アプリの決まったフォルダにライブラリとヘッダファイルが格納され、親アプリはそれを使うというものでした。Qt Creatorなどは、CMakeを再実行してプロジェクトをリロードしないと、プロジェクトのツリーに表示されず、#includeでも補完されません。例えば、新しいメソッドが必要になったときはQt Creatorの場合は次のような手順が必要でした。

  1. 子ライブラリ側にメソッドを追加
  2. 子ライブラリを一旦ビルド(親プロジェクトに新しいヘッダ入る)
  3. 親のプロジェクトを更新(CMake実行)して、ヘッダを認識
  4. メソッドの補完ができるようになる。

子ライブラリのメソッドの引数などを編集するたびにいちいちビルドしてリロードするのが必要です。CMakeがネイティブのプロジェクトファイルではない(元はqmake)というのもありますが、リズム良く開発できません。実際には独立したコードになるとしても、開発時にはもう少し密結合でやらないと不便きわまりないです。

子のプロジェクトのソースを直接参照できる形式にする

当初の設計では、link_libraries()と、include_directories()で疎結合を実現していましたが、今は単独でも使えるCMakeLists.txtをadd_subdirectory()で読み込む構造にしています。vendorというフォルダが子のライブラリが入るところですが、そこをadd_subdirectory()すると、Qt CreatorやCLion上からは階層化されたひとつのプロジェクトとして扱うことができます。オリジナルのソース・ファイルを直接参照しているため、メソッドの引数の変更でリロードしたりする必要はなくなりました。

スクリーンショット 2016-03-26 0.16.45.png

ただし、Qt Creatorでは、親プロジェクトを開いている場合には読み込まれた側のプロジェクトだけでビルドしたりはできないため、独立性を維持するのにはもう一工夫必要です。

子供だけでも独立して使えるCMakeLists.txtにする

今はnpm3方式というか、親プロジェクトのvendorフォルダにすべての依存パッケージを一階層のフォルダに集めています。node.jsであれば、ファイルの読み込みも動的なので、順番に親をたどっていく、みたいなことが可能ですが、そもそもC++の場合はnode.jsと違って同じライブラリのバージョン違いをリンクすることはない(やろうとしても恐怖しか無い!)のと、CMakeでそこまでの柔軟性を持たせるのは不可能ではないかもしれないけど難しいでしょう。ただでさえ読みやすいと言えないCMakeLists.txtのファイルの見通しも悪くなります。そのためフラットな階層にしました。

add_subdirectory()はいくつかの制約があります。

  1. 基本的に今いるフォルダよりも上のフォルダを参照するのはイレギュラー(という方針)
  2. イレギュラーな使い方をする場合は、読み込むフォルダだけではなく、作業フォルダも第二引数で指定する必要がある
  3. 基本的に、1つのライブラリに対して、それに依存する親がたくさんいても1度だけ呼び出す。複数回呼び出すとエラーになる

最後の制約が結構厳しいので、基本的にルートになったプロジェクトでのみ、add_subdirectory()を呼ぶようにしました。ルートというのは、アプリケーションの場合もありますし、他に依存しているライブラリを独立してビルド・テストするときは、ライブラリプロジェクトであってもルートになりえます。

ルートでは、直接依存している子だけではなく、孫や曾孫などのすべての依存パッケージを洗い出して、add_subdirectory()を呼び出します。そんでもって、そのパッケージのsrcフォルダをinclude_directories()で#include可能なようにします。

ライブラリの場合はルートにもなりえるし、他のプロジェクトの子にもなりえるということで、子を呼び出す前に、QTPM_IS_ROOT_PROJECT=FALSEという変数を設定するようにしました。これがあったら、include_directories()を呼ぶけど、add_subdirectory()は呼ばない、とすることで解決しました。

後は、親プロジェクトの一部としてフォルダに取り込まれているけど、そのライブラリだけテストしたい!ということは当然あります。その場合には、そのライブラリが依存しているパッケージは同じ階層にフラットにいます。泥臭い方法ですが、上のフォルダ名がvendorだったら、他のライブラリは同じ階層に、なければ自分のフォルダ内のvendorフォルダにある、という想定をすることで、作業フォルダ内でもそのままテストを実行できたりできるようにしました。

CMakeLists.txt
if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/../../vendor)
    set(VENDOR_PATH ${CMAKE_CURRENT_SOURCE_DIR}/..)
else()
    set(VENDOR_PATH ${CMAKE_CURRENT_SOURCE_DIR}/vendor)
endif()

CMakeLists.txtの内容自体は、ワークフォルダの絶対パスがどこかとか、子として取り込まれているかそうじゃないかによっては内容が変わらないようにもしました。子のパッケージをqtpm getで取得する際に、 --git を付けると、git cloneするようになるので、作業フォルダ内でテストした結果、そのままpushすることもできます。このあたりも、$GOPATH内でファイルを編集するといろいろラクなGolangを目標にしました。

子プロジェクトは静的リンクライブラリにする

当初はダイナミックリンクライブラリにしてました。まあMacであれば問題はなかったのですが、Windowsの方はもろもろ大変でした。大変さのわりに、今時あまり苦労する価値もないかなと思って静的リンクライブラリにしました。

CMakeで共有ライブラリを作ること自体は簡単です。

add_library(ライブラリ名 SHARED ソースファイル)

とやればOKです。installはちょっと特殊です。

install(TARGETS ライブラリ名
    ARCHIVE ディレクトリ1
    LIBRARY ディレクトリ2
    RUNTIME ディレクトリ3)

ディレクトリ2は、Macの.dylibや、他のUnix系OSの.soの保存先です。ARCHIVEは、Windowsで実行ファイルに読み込む、.dllを読み込む.libファイルです。RUNTIMEは、.dllです。あとWindowsで辛いのは、__declspec(dllexport)__declspec(dllimport)を、きちんと整合性をとって指定してビルドしなければならない点です。ライブラリはうまくいったのですが、ライブラリパッケー内のサンプルコードなどでうまくリンクできず、修正も面倒だったので静的ライブラリにすることにしました。add_library()のタグをSTATICにすればライブラリ自体は静的になります。

ダイアルアップ回線で一生懸命ダウンロードしてインストールしたライブラリを、いろんなプログラムからありがたく利用させていただくような時代ではなく、最近のストア配布などは必要ライブラリを全部サンドボックスに押し込めて配布してしまうため、今の時代は共有ライブラリのメリットと言われてきたことはもはや存在しないも同然です。むしろ互換性とかより大変な問題があります。SxSという文字を見ただけで死ぬ人が何人かいるはず。

一部.soにもメリットはあって、ライブラリが他の.soへのリンクを持つことができます。つまりアプリは自分が直接参照している.soだけをリンクすれば、孫や曾孫のライブラリの共有ライブラリを意識する必要はありませんでした。今回静的化したので、実行ファイルやサンプル、テストのビルドでは、必要なライブラリを集めてきてリンクする処理を明示的に行っています。

一番最初の項目で、親のプロジェクトから直接参照するならライブラリ化は必要ないと思われるかもしれませんが、ユニットテストなどの実行ファイルのビルドは早くなります。ライブラリ化してからlink_librariesしないで、直接必要なファイルを渡すと、CMakeはそれぞれの実行ファイルのターゲットごとに同じファイルを何度もビルドしてしまいます。

もちろん、ダイナミックローダブルライブラリというか、プラグインは動的ロードの目的あってのものなので、この限りではありません。

Qtならではの事情

CMakeはQt用の設定ももろもろ持っています。

CMakeLists.txt
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTOUIC ON)
set(CMAKE_AUTORCC ON)
set(CMAKE_INCLUDE_CURRENT_DIR ON)

if(DEFINED ENV{QTDIR})
    set(CMAKE_PREFIX_PATH "$ENV{QTDIR}")
endif()

find_package(Qt5Core REQUIRED)
find_package(Qt5Gui REQUIRED)
find_package(Qt5Widgets REQUIRED)

まずはCMAKE_AUTO_X系のパラメータですが、これを設定しておくと、Qt専用のファイルも、他のプログラムで変換することなく、直接ライブラリや実行ファイルのソースとして使用できるようになります。この3点セットはまとめて設定すると良いでしょう。上からそれぞれ、次のコマンドを裏で呼び出すようになります。

  • C++のコードでリフレクションができるようにしたり、シグナル・スロット・列挙型などのQt専用の拡張が入ったコードを変換するmoc機能の呼び出し
  • UICはビジュアルのデザイナーツールで作ったQtのui定義ファイルを、C++ヘッダに変換するuicコマンドの呼び出し
  • RCCは.qrcのリソースをソースコードにしてバイナリに直接埋め込むrccコマンドの呼び出し

CMAKE_INCLUDE_CURRENT_DIRは、上記の変換ツールが生成したヘッダファイルを再配置なしにコードから参照できるようにするためのものです。

$ENV{QTDIR}はqtpmがQtの場所を伝えるために環境変数で渡しています。CMakeのCMAKE_PREFIX_PATHにこれを登録すると、CMakeがQtのモジュールや変換コマンドの置き場を知ることができます。

テスト

CMakeはCTestというテストランナーを持っています。失敗時に0以外の数値を返す単独の実行ファイルにさえなれば、CTestが使えます。実行ファイル内にはそれぞれの言語の好きなテスティングフレームワークを組み合わせることができますが、今回はQtを使っているのでQTestを使います。

CMakeでテストを有効にするのは、enable_testing()を呼び出すだけです。これでCTestが有効になり、cmake実行後のフォルダで、make testでテストが実行できるようになります。後はテスト用にビルドした実行ファイルをadd_testします。Qtのテスト用のパッケージQtTestを組み込んだのと、enable_testing()以外は通常の実行ファイルのビルドと同じですね。

CMakeLists.txt
enable_testing()
find_package(Qt5Test REQUIRED)

add_executable(qtcbor_test qtcbor_test.cpp)
add_test(NAME qtcbor_test COMMAND qtcbor_test)
qt5_use_modules(qtcbor_test Test Core)
target_link_libraries(qtcbor_test qtcbor )

QTestを使うと、Qtの機能のリフレクションを使ってテストメソッドを探しに行くことができるため、テストコードの登録メソッドを手で追加する必要はありません。あやしいマクロの秘奥義を炸裂させているようなコードよりも見た目もすっきりしていてC++っぽいコードになります。まぁ、今どきのIDEはVC++6.0と違ってマクロをくししてもきちんとハイライトしてくれたりするんでしょうけど。

#include "qttobubus/private/proxy.h"
#include "sample.h"
#include <QString>
#include <QtTest>

class TestProxy : public QObject
{
    Q_OBJECT
public:
    TestProxy() {}

private Q_SLOTS:
    void testProxyRegister()
    {
        auto proxy = new Proxy(QSharedPointer<QObject>(new Sample()));
        QVERIFY(proxy->hasMethod("testFunction"));
        QVERIFY(!proxy->hasMethod("noExistFunction"));

        auto result = proxy->call("testFunction", QVariantList{10});
        QCOMPARE(result.toInt(), 100);

        auto result2 = proxy->call("testFunction", QVariantList{20});
        QCOMPARE(result2.toInt(), 200);

        auto result3 = proxy->call("testFunction2", QVariantList{"name", QVariantList{6.5, true}});
        QCOMPARE(result3.toString(), QString("called"));
    }
};

QTEST_APPLESS_MAIN(TestProxy)

#include "proxy_test.moc"

GUIアプリケーションのビルド

Windows(MinGW)

Qt 5.6は公式サポートしている環境は、WindowsだけでもVC 2013(32bit/64bit)、2015(32bit/64bit)、Windows Runtime(32bit/64bit/ARM x 2013/2015)、Windows Phone(ARM/32bit)、MinGW(32bit)とたくさんあって、列挙している内容にももれがあるかもしれないんですが、MinGWが一番お手軽な気がします。インストーラのオプションで、コンパイラとQtのツールの両方にパスが通ったコマンドプロンプトのショートカットができるので、両方一緒にそろって準備はラクです。今回もとりあえずMinGWでやりました。

ちなみに準公式も含めると、VC++2005からIntel C++ CompilerからWindows CEから、対応しています。さすがにVC++ 6.0は最近消えましたね。次の5.7からはC++11が必須になるのでVC++2005とかは消えるかと思いますが。

ちょっと厄介なのは、CMakeのMinGWターゲットだとリソースコンパイラが設定されてないため、それを呼び出すカスタムコマンドを登録しないといけない点です。リソースを設定しないとアイコンが付きません。今回はMacとのクロスビルド環境が作りたかったので、アイコンのソースは1024x1024のPNGという想定でいます。それをGolangの"github.com/Kodeworks/golang-image-ico"パッケージでicoファイルにしました。

次に、テンプレートエンジンを使って適用に以下のような.rcファイルも作っておきます。QiitaもさすがにWindowsのリソースファイルのコードハイライトはない模様。

#include "winver.h"

IDI_ICON1               ICON    DISCARDABLE     "WindowsAppIcon.ico"

VS_VERSION_INFO VERSIONINFO
 FILEVERSION バージョンの文字列
 PRODUCTVERSION バージョンの文字列
 FILEFLAGS 0x0L
 FILEFLAGSMASK 0x3fL
 FILEOS 0x00040004L
 FILETYPE 0x1L
 FILESUBTYPE 0x0L
BEGIN
    BLOCK "StringFileInfo"
    BEGIN
        BLOCK "000004b0"
        BEGIN
            VALUE "CompanyName", "組織名"
            VALUE "FileDescription", "説明"
            VALUE "FileVersion", "バージョン"
            VALUE "LegalCopyright", "著作権表示"
            VALUE "InternalName", "名前"
            VALUE "OriginalFilename", "名前.exe"
            VALUE "ProductName", "名前"
            VALUE "ProductVersion", "バージョン"
        END
    END
END

最後にビルドする用の設定です。たぶん、MinGW以外であればソースファイルに直接リソースのファイルを追加してあげればいいみたいですが、MinGWは.objファイルをリソースファイルコンパイラで作成し、その.objファイルをソースファイルに登録します。

CMakeLists.txt
if(WIN32)
  set(winres "Resources/windows.rc")
  if(MINGW)
    if(NOT CMAKE_RC_COMPILER)
      set(CMAKE_RC_COMPILER windres.exe)
    endif()
    set(winresobj "${CMAKE_CURRENT_BINARY_DIR}/windows.rc.obj")
    add_custom_command(OUTPUT "${winresobj}"
      COMMAND ${CMAKE_RC_COMPILER}
        -D GCC_WINDRES
        -I ${CMAKE_CURRENT_SOURCE_DIR}
        -I ${CMAKE_CURRENT_BINARY_DIR}
        -o ${winresobj}
        -i ${winres})
    set(${sources} "${winresobj}")
  else()
    set(${sources} ${winres})
  endif()
  add_executable(アプリ名 WIN32 src/main.cpp ${sources} qtresources/resource.qrc)
  qt5_use_modules(アプリ名 Core Gui...)
  target_link_libraries(アプリ名 何かリンクするライブラリ)
endif()

MacOSX

MacOSXもまずはアイコンを作ります。Golangにもicns形式のアイコン画像の作成モジュールがあったのですが、どうもRetinaじゃない環境のアイコンが化けてしまって、Appleのバイナリの仕様書を見る限り(超シンプル)問題なさそうではあったけどそのパッケージの修正をする余裕が無かったので、とりあえずStackOverflowで紹介されてた方法で作成することにしました。そのうちバグ修正してパッチ送りたい。

MacOSXの方はリソースファイルを作る必要はなく、CMakeの方でMACOSX_BUNDLEから始まる一連のコマンドを用意してくれているので、これを使います。${resources}は、.appの中のResourcesに入れたいファイル名が入っているものとします。

CMakeLists.txt
if(APPLE)
  set(MACOSX_BUNDLE_BUNDLE_NAME アプリ名)
  set(MACOSX_BUNDLE_GUI_IDENTIFIER "アプリ名")
  set(MACOSX_BUNDLE_ICON_FILE MacOSXAppIcon.icns)
  set_source_files_properties(Resources/MacOSXAppIcon.icns PROPERTIES MACOSX_PACKAGE_LOCATION "Resources")
  set_source_files_properties(${resources} PROPERTIES MACOSX_PACKAGE_LOCATION "Resources")
  set(MACOSX_BUNDLE_INFO_STRING "アプリ名-バージョン, Copyright 著作権")
  set(MACOSX_BUNDLE_SHORT_VERSION_STRING "${アプリ名_MAJOR_VERSION}.${アプリ名_MINOR_VERSION}" )
  set(MACOSX_BUNDLE_LONG_VERSION_STRING "${アプリ名_VERSION}")
  set(MACOSX_BUNDLE_BUNDLE_VERSION "${アプリ名_VERSION}")
  set(MACOSX_BUNDLE_COPYRIGHT "(C) 著作権")
  add_executable(アプリ名 MACOSX_BUNDLE ${sources} qtresources/resource.qrc ${resources} Resources/MacOSXAppIcon.icns)
  qt5_use_modules(アプリ名 Core Gui...)
  target_link_libraries(アプリ名 何かリンクするライブラリ)
endif()

これで.appファイルが作られます。

インストーラ作成

CMakeはCPackという、インストーラ作成機能が最初から入っています。WindowsはオープンソースなNSIS(Nullsoft Scriptable Install System)を使った、.exeになるインストーラ、WiXを使った、.msiになるインストーラが対応です。また、.zipなどの圧縮ファイルの他に、.rpmや.deb、Macの.pkgも対応します。

ちなみに、QtにはQt Installer Frameworkという、Qt専用のインストーラ作成ツールがあります。マルチプラットフォームですし、オンラインインストーラも作成できるすぐれものですが、今回はそこまで大きなものはターゲットにしていないので、シンプルな方向性で決めました。Qt Installer Frameworkの日本語解説は理音伊織(@IoriAYANE)さんの薄い本が唯一絶対の解説書になります。

Windows

WindowsはNSISとWiXの二択です。WiXの方が後から対応したのですが、いかんせん情報が全然なかったので、情報があったNSISにしてみました。一応、コンポーネントがいくつにも分かれて、詳細インストールで機能のON/OFFができるようなインストーラも作れますが、今回はまるっとインストールを前提としています。

まずは、ビルドした.exeを、windeployqtコマンドに渡します。.exeが利用している、一緒に配布すべきQtの.dllなどを一箇所に集めてくれます。なお、3D系の.dllとかもデフォルトでいろいろ持ってきてしまいますが、これはwindeployqtのオプションで切ることができます。このあたりのファイルサイズが結構大きいので、インストーラをダイエットしたいときはこのあたりをこまめに調整するといいと思います。あと必須オプションは--releaseです。デバッグ版はファイルサイズが数十倍あってめちゃ大きいので、まず使うことはないでしょう(デフォルトはデバッグ)。

下記のファイルは受け入れテスト的なスクリプトで生成したファイルなので、アプリ名がWorkbench7みたいなしょぼい名前ですがご了承ください。ビルドしてwindeployqtを実行したフォルダで、cpackコマンドを実行すると、インストーラが作成されます。

CMakeLists.txt
if(WIN32)
    install(TARGETS workbench7 ${dlls} RUNTIME DESTINATION bin COMPONENT applications)
    file(GLOB dlls ${CMAKE_CURRENT_BINARY_DIR}/*.dll)
    install(PROGRAMS ${dlls} DESTINATION bin COMPONENT applications)
    install(DIRECTORY
        ${CMAKE_CURRENT_BINARY_DIR}/iconengines
        ${CMAKE_CURRENT_BINARY_DIR}/imageformats
        ${CMAKE_CURRENT_BINARY_DIR}/platforms
        ${CMAKE_CURRENT_BINARY_DIR}/translations DESTINATION bin COMPONENT applications
        ${CMAKE_CURRENT_BINARY_DIR}/Resources)
    set(CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS_SKIP TRUE)
    include(InstallRequiredSystemLibraries)
    install(PROGRAMS ${CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS}
            DESTINATION programs
            COMPONENT applications)
    set(CPACK_PACKAGE_NAME "Workbench7")
    set(CPACK_PACKAGE_VENDOR "作者の名前")
    set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "Write your project description here")
    set(CPACK_PACKAGE_VERSION_MAJOR "${WORKBENCH7_MAJOR_VERSION}")
    set(CPACK_PACKAGE_VERSION_MINOR "${WORKBENCH7_MINOR_VERSION}")
    set(CPACK_PACKAGE_VERSION_PATCH "${WORKBENCH7_PATCH_VERSION}")
    set(CPACK_PACKAGE_VERSION "${WORKBENCH7_VERSION}")
    set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/LICENSE.rst")
    set(CPACK_PACKAGE_INSTALL_DIRECTORY "installer")
    set(CPACK_COMPONENT_APPLICATIONS_DISPLAY_NAME "applications (Workbench7)")
    set(CPACK_NSIS_MUI_ICON "Resources/WindowsAppIcon.ico")
    set(CPACK_NSIS_MUI_UNIICON "Resources/WindowsAppIcon.ico")
    set(CPACK_NSIS_MENU_LINKS "programs/workbench7" "Workbench7")
    include(CPack)
endif()

MacOSX

CPackでpkgファイルを作る場合は、その中で実行されるシェルスクリプトなどを用意する必要があるみたいです。ですが、Qtを使っている場合は、MacはCPackを使う必要もないでしょう。.macdeployqtに-dmgオプションを付けると、.appに必要なフレームワークを集めてきた後に、.dmgのイメージファイルを作成するところまでやってくれます。Applicationフォルダへのショートカットの入れ方はまだ分かってない(できない?)のですが、単独のアプリを配るならこれで問題ありません。コマンドラインツールも一緒に配りたいなどがあれば、.pkgの作り方を調べる必要があります。それかQt Installer Frameworkですかね。

完成したCMakeLists.txt

自分でCMakeLists.txtを書きたい人向けに、生成したファイルを置いておきます。

CMakeLists.txt
cmake_minimum_required(VERSION 3.1.0)

# project global setting

project(workbench7)

set(WORKBENCH7_MAJOR_VERSION 0)
set(WORKBENCH7_MINOR_VERSION 1)
set(WORKBENCH7_PATCH_VERSION 0)
set(WORKBENCH7_VERSION 0.1.0)

# qtpm setting

set(VENDOR_PATH ${CMAKE_CURRENT_SOURCE_DIR}/vendor)

# compiler setting

set(CMAKE_CXX_STANDARD 11)
if(MSVC)
  set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W4")
else()
  set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall")
endif()

# enable Qt

set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTOUIC ON)
set(CMAKE_AUTORCC ON)
set(CMAKE_INCLUDE_CURRENT_DIR ON)
include_directories(${CMAKE_CURRENT_BINARY_DIR})
if(DEFINED ENV{QTDIR})
    set(CMAKE_PREFIX_PATH "$ENV{QTDIR}")
endif()

find_package(Qt5Core REQUIRED)
find_package(Qt5Gui REQUIRED)
find_package(Qt5Widgets REQUIRED)
# include extra settings

include("${CMAKE_CURRENT_SOURCE_DIR}/CMakeExtra.txt" OPTIONAL)

# dependencies

set(QTPM_IS_ROOT_PROJECT FALSE)
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/vendor/github.com___shibukawa___package1 ${CMAKE_CURRENT_BINARY_DIR}/package1)
include("${CMAKE_CURRENT_SOURCE_DIR}/vendor/github.com___shibukawa___package1/CMakeExtra.txt" OPTIONAL)
include_directories(${VENDOR_PATH}/github.com___shibukawa___package1/src)
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/vendor/github.com___shibukawa___package2 ${CMAKE_CURRENT_BINARY_DIR}/package2)
include("${CMAKE_CURRENT_SOURCE_DIR}/vendor/github.com___shibukawa___package2/CMakeExtra.txt" OPTIONAL)
include_directories(${VENDOR_PATH}/github.com___shibukawa___package2/src)

# build setting

include_directories(src)

if(APPLE)
  set(MACOSX_BUNDLE_BUNDLE_NAME Workbench7)
  set(MACOSX_BUNDLE_GUI_IDENTIFIER "Workbench7")
  set(MACOSX_BUNDLE_ICON_FILE MacOSXAppIcon.icns)
  set_source_files_properties(Resources/MacOSXAppIcon.icns PROPERTIES MACOSX_PACKAGE_LOCATION "Resources")
  set(MACOSX_BUNDLE_INFO_STRING "Workbench7-0.1.0, Copyright 2016 shibukawa.yoshiki")
  set(MACOSX_BUNDLE_SHORT_VERSION_STRING "${WORKBENCH7_MAJOR_VERSION}.${WORKBENCH7_MINOR_VERSION}" )
  set(MACOSX_BUNDLE_LONG_VERSION_STRING "${WORKBENCH7_VERSION}")
  set(MACOSX_BUNDLE_BUNDLE_VERSION "${WORKBENCH7_VERSION}")
  set(MACOSX_BUNDLE_COPYRIGHT "(C) 2016 shibukawa.yoshiki")
  add_executable(workbench7 MACOSX_BUNDLE src/main.cpp Resources/MacOSXAppIcon.icns)
elseif(WIN32)
  set(winres "${CMAKE_CURRENT_SOURCE_DIR}/windows.rc")
  if(MINGW)
    if(NOT CMAKE_RC_COMPILER)
      set(CMAKE_RC_COMPILER windres.exe)
    endif()
    set(winresobj "${CMAKE_CURRENT_SOURCE_DIR}/windows.rc.obj")
    add_custom_command(OUTPUT "${winresobj}"
      COMMAND ${CMAKE_RC_COMPILER}
        -D GCC_WINDRES
        -I ${CMAKE_CURRENT_SOURCE_DIR}
        -I ${CMAKE_CURRENT_BINARY_DIR}
        -o ${winresobj}
        -i ${winres})
    set(${sources} "${winresobj}")
  else()
    set(${sources} ${winres})
  endif()
  add_executable(workbench7 WIN32 src/main.cpp ${sources})
else()
  add_executable(workbench7 src/main.cpp)
endif()
qt5_use_modules(workbench7 Core Gui Widgets)
target_link_libraries(workbench7 package1 package2)

# installer setting

if(WIN32)
    install(TARGETS workbench7 ${dlls} RUNTIME DESTINATION bin COMPONENT applications)
    file(GLOB dlls ${CMAKE_CURRENT_BINARY_DIR}/*.dll)
    install(PROGRAMS ${dlls} DESTINATION bin COMPONENT applications)
    install(DIRECTORY
        ${CMAKE_CURRENT_BINARY_DIR}/iconengines
        ${CMAKE_CURRENT_BINARY_DIR}/imageformats
        ${CMAKE_CURRENT_BINARY_DIR}/platforms
        ${CMAKE_CURRENT_BINARY_DIR}/translations DESTINATION bin COMPONENT applications)
    set(CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS_SKIP TRUE)
    include(InstallRequiredSystemLibraries)
    install(PROGRAMS ${CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS}
            DESTINATION programs
            COMPONENT applications)
    set(CPACK_PACKAGE_NAME "Workbench7")
    set(CPACK_PACKAGE_VENDOR "shibukawa.yoshiki")
    set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "Write your project description here")
    set(CPACK_PACKAGE_VERSION_MAJOR "${WORKBENCH7_MAJOR_VERSION}")
    set(CPACK_PACKAGE_VERSION_MINOR "${WORKBENCH7_MINOR_VERSION}")
    set(CPACK_PACKAGE_VERSION_PATCH "${WORKBENCH7_PATCH_VERSION}")
    set(CPACK_PACKAGE_VERSION "${WORKBENCH7_VERSION}")
    set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/LICENSE.rst")
    set(CPACK_PACKAGE_INSTALL_DIRECTORY "installer")
    set(CPACK_COMPONENT_APPLICATIONS_DISPLAY_NAME "applications (Workbench7)")
    set(CPACK_NSIS_MUI_ICON "${CMAKE_CURRENT_BINARY_DIR}/WindowsAppIcon.ico")
    set(CPACK_NSIS_MUI_UNIICON "${CMAKE_CURRENT_BINARY_DIR}/WindowsAppIcon.ico")
    set(CPACK_NSIS_MENU_LINKS "programs/workbench7" "Workbench7")
    include(CPack)
endif()
future
ITを武器とした課題解決型のコンサルティングサービスを提供します
http://future-architect.github.io/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした