読者です 読者をやめる 読者になる 読者になる

😃 mattintosh note 📝

Hello Raspberry Pi!

Mac OS と CMake を使う時のメモ

Mac OS X CMake

CMake 2.8.10 における個人的なメモです。まだ慣れていないので誤りがあるかもしれません。随時追加していくので書きかけの部分があります。

CMake 変数

変数名 内容 展開 外部コマンド
CMAKE_SYSTEM システム名(フル) Darwin-10.8.0 uname -a
CMAKE_SYSTEM_NAME システム名 Darwin uname -n
CMAKE_SYSTEM_VERSION システムバージョン 10.8.0 uname -r
CMAKE_SYSTEM_PROCESSOR システムプロセッサー i386 uname -p

同様に CMAKE_HOST_SYSTEM_* という変数もある。

変数名 内容 例
CMAKE_<LANG>_COMPILER_ABI コンパイラの ABI(?) 空
CMAKE_<LANG>_COMPILER_ID コンパイラのベンダー名 GNU
CMAKE_<LANG>_COMPILER_VERSION コンパイラのバージョン 4.2.1
CMAKE_<LANG>_FLAGS_DEBUG
CMAKE_<LANG>_FLAGS_RELEASE
CMAKE_<LANG>_FLAGS_MINSIZEREL
CMAKE_<LANG>_FLAGS_RELWITHDEBINFO
コンフィグレーション別のフラグ設定 -O3 -DNDEBUG
CMAKE_INTERNAL_PLATFORM_ABI システムの ABI(?) 空
CMAKE_LIBRARY_ARCHITECTURE ターゲットアーキテクチャのライブラリディレクトリ名。
変数名 内容 例
CMAKE_OSX_SYSROOT 多分、CMAKE_XCODE_SELECT によって自動検出される。定義すればコンパイラフラグ -isysroot [sdk path] などが追加される。Xcode 4.3 以降ではどうなるか不明。 /Developer/SDKs/MacOSX10.6.sdk
CMAKE_OSX_ARCHITECTURES 定義すればコンパイラフラグに -arch [arch] が追加される。複数の場合は値をセミコロンで区切る。 x86_64
CMAKE_OSX_DEPLOYMENT_TARGET 定義すればコンパイラフラグに -mmacosx-version-min=[version] が追加される。 10.6

基本的な CMake コマンド

file()

ファイル操作を行うコマンド。

サブコマンド 動作
file(WRITE ファイル名 "文字列") 文字列をファイルに出力します。(新規または上書き)
file(APPEND ファイル名 "文字列") 文字列をファイルに出力します。(追記)
file(STRINGS ファイル名 変数) ファイルの内容を取得します。
file(GLOB 変数 [相対パス] [パターン]) 相対パスまたはパターンのファイルまたはディレクトリを検索して変数(リスト)に出力します。
file(GLOB_RECURSE 変数 [相対パス] [パターン]) 相対パスまたはパターンのファイルまたはディレクトリを再帰的に検索して変数(リスト)に出力します。
file(RENAME 旧ファイル名 新ファイル名) 旧ファイル名から新ファイル名にリネーム(ムーブ)します。
file(REMOVE ファイル1 ファイル2 …) ファイルを削除します。
file(REMOVE_RECURSE ファイル1 ファイル2 …) ファイルまたはディレクトリを再帰的に削除します。
file(MAKE_DIRECTORY ディレクトリ1 ディレクトリ2 …) ディレクトリを作成します。

少し特殊な file(COPY) と file(INSTALL) もあります。前者はステータス表示なし、後者はステータス表示ありです。ファイルには複数のファイルを指定できます(リストでの指定も可)。install() は make install 時に動作しますが、file(INSTALL) は CMake コマンド実行時に動作します。

file(COPY ファイル DESTINATION ディレクトリ
    [FILE_PERMISSIONS パーミッション]
    [DIRECTORY_PERMISSIONS パーミッション]
    [NO_SOURCE_PERMISSIONS]
    [USE_SOURCE_PERMISSIONS]
    [FILES_MATCHING]
    [PATTERN パターン] [EXCLUDE]
    [REGEX 正規表現] [EXCLUDE]
    [PERMISSIONS パーミッション]
)

PATTERN は複数指定可能ですが、1回の PATTERN に対して指定できるパターンは1種類なので複数のパターンを指定したい場合は都度 PATTERN を使用することになります。EXCLUDE はその前にあるパターンもしくは正規表現に該当するファイルを除外します。

パーミッションの種類

install() や file(COPY|INSTALL) で使用します。ユーザー_権限 という書式で、例えば所有者対して実行を許可する場合は OWNER_EXECUTE になります。

  • ユーザー: OWNER、GROUP、WORLD
  • 権限: READ、WRITE、EXECUTE

外部コマンドの実行 execute_process()

外部コマンドの出力結果を変数に入れたいときなどに使う。

http://www.cmake.org/cmake/help/v2.8.10/cmake.html#command:execute_process

書式

execute_process (COMMAND コマンド1 COMMAND コマンド2 OUTPUT_VARIABLE 変数名 OUTPUT_STRIP_TRAILING_WHITESPACE)

COMMAND は複数指定可能。これらはパイプで繋がれるようになっている。複数のコマンドを別に実行(sh で言う ; を使う場合)することは恐らくできないので execute_process() で追加する。CMake コマンド部分では改行することも可能。OUTPUT_STRIP_TRAILING_WHITESPACE は最後の改行を取り除く。OUTPUT_VARIABLE 以外にもエラーコードを格納する変数や入出力ファイルの指定なども可能。

シングルクオートはシンタックスエラーになる可能性がある。また、CMake コマンド用のバックスラッシュと外部コマンド用のバックスラッシュが混在するので外部コマンド用のバックスラッシュは \\ になる。

例えば otool と awk を併用し、実行ファイルのリンクを変数に配列(リスト)として登録する場合は以下、以下のような方法が考えられる。

execute_process (
  COMMAND otool -L ${EXECUTABLE}
  # awk の正規表現のバックスラッシュは「\」ではなく「\\」になる
  COMMAND awk "NR >= 2 && $1 !~ /(\\/usr\\/lib|\\/System|@executable_path)\\// { printf \"%s;\", $1 }"
  OUTPUT_VARIABLE
    FOO
  # ↑この時点では「var1;var2;var3;(var4)」という状態になっていて、「var4」は空の状態
)
# list (REMOVE_ITEM <list> <value>) で空の要素を取り除く
list (REMOVE_ITEM FOO "")

# 最後の要素だけであれば list(REMOVE_AT <list> <index>) でも取り除くことができる
#list (REMOVE_AT FOO -1)

# 再度変数にセットして「ver4」を取り除いてもいいかもしれない
#set (FOO ${FOO})

awk の出力をもう少しまともに書けば空の要素を取り除く作業は必要ないと思う。list(REMOVE_ITEM) と list(REMOVE_AT) の違いは前者が値による削除、後者がインデックスによる削除。

※作業状態によっては「空の要素が含まれるリストは作成できない」といったポリシー違反が発生するのでセミコロンの位置を前に移して cut カットコマンドなどで削除する必要があるかもしれません。

ループ foreach() … endforeach()

http://www.cmake.org/cmake/help/v2.8.10/cmake.html#command:foreach

書式

# パターン1
foreach(ループ変数 引数1 引数2)
  コマンド1
  コマンド2
endforeach(ループ変数)

# パターン2
foreach(ループ変数 ${リスト})
  コマンド1
  コマンド2
endforeach(ループ変数)

# パターン3
foreach(ループ変数 IN LISTS リスト名)
  コマンド1
  コマンド2
endforeach(ループ変数)

リストに関しては二種類の方法があり、変数を展開して引数にする方法と純粋にリストとして渡す方法がある。前者の場合は恐らくスペースを含む要素があった場合に正しく動作しない可能性がある(試してない)。後者の場合は空の要素が含まれているとエラーになる。

CMake で Info.plist を作成する

Info.plist を手動で作成する場合、CMake のテンプレートを利用することができます。${CMAKE_ROOT}/Modules/MacOSXBundleInfo.plist.in を使用します。

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>CFBundleDevelopmentRegion</key>
    <string>English</string>
    <key>CFBundleExecutable</key>
    <string>${MACOSX_BUNDLE_EXECUTABLE_NAME}</string>
    <key>CFBundleGetInfoString</key>
    <string>${MACOSX_BUNDLE_INFO_STRING}</string>
    <key>CFBundleIconFile</key>
    <string>${MACOSX_BUNDLE_ICON_FILE}</string>
    <key>CFBundleIdentifier</key>
    <string>${MACOSX_BUNDLE_GUI_IDENTIFIER}</string>
    <key>CFBundleInfoDictionaryVersion</key>
    <string>6.0</string>
    <key>CFBundleLongVersionString</key>
    <string>${MACOSX_BUNDLE_LONG_VERSION_STRING}</string>
    <key>CFBundleName</key>
    <string>${MACOSX_BUNDLE_BUNDLE_NAME}</string>
    <key>CFBundlePackageType</key>
    <string>APPL</string>
    <key>CFBundleShortVersionString</key>
    <string>${MACOSX_BUNDLE_SHORT_VERSION_STRING}</string>
    <key>CFBundleSignature</key>
    <string>????</string>
    <key>CFBundleVersion</key>
    <string>${MACOSX_BUNDLE_BUNDLE_VERSION}</string>
    <key>CSResourcesFileMapped</key>
    <true/>
    <key>LSRequiresCarbon</key>
    <true/>
    <key>NSHumanReadableCopyright</key>
    <string>${MACOSX_BUNDLE_COPYRIGHT}</string>
</dict>
</plist>

MacOSXBundleInfo.pist.in には既に変数が記述されているので呼び出し元になる CMake ファイルに以下の変数をセットしておくだけ。

MACOSX_BUNDLE_SHORT_VERSION_STRING に関しては string(SUBSTRING) を使って MACOSX_BUNDLE_LONG_VERSION_STRING の値から取得してもいいかもしれません。

string (SUBSTRING "${PROJECT_VERSION}" 0 3 MACOSX_BUNDLE_SHORT_VERSION_STRING)

あとは configure_file() をかければ変数が展開されて Info.plist が作成されます。

configure_file ("${CMAKE_ROOT}/Modules/MacOSXBundleInfo.plist.in" "${BUNDLE_CONTENTS_DIR}/Info.plist")

execute_process() で defaults コマンドを使って出力する方法もあります。