2013年12月12日木曜日

cmakeで任意のコマンドの実行結果を変数に取得して使う方法

次のようなパイプを含んだワンライナーの結果をcmake中の変数に取得したいとしましょう。

awk '{print $2}' ../qmldir | head -n1 | tr . / | tr -d \n

QMLを扱わない方のために、最初にawkの処理対象になっている../qmldirの中身の例を紹介しておきます。今回は単純な2行のテキストファイルです。

module com.mycompany.qmlcomponents
plugin untitled

先のワンライナーの結果は、

com/mycompany/qmlcomponents

となります。

このワンライナーをcmake中で実行して結果を取得するには次のようにCMakeLists.txtに仕込みます。

execute_process(
  COMMAND awk "{print $2}" ${PROJECT_SOURCE_DIR}/qmldir
  COMMAND head -n1
  COMMAND tr . /
  COMMAND tr -d \n
  OUTPUT_VARIABLE qmldir_output
)

set(qmldir $ENV{QML2_IMPORT_PATH}/${qmldir_output})

message(STATUS "qmldir: ${qmldir}")

ここで、今回は${PROJECT_SOURCE_DIR}は ../ となると仮定して読み進めて下さい。

CMakeLists.txtにexecute_processを記述すると任意のコマンドを実行し、その標準出力、エラー出力、実行結果を得られます。

上記の例ではOUTPUT_VARIABLE qmldir_outputとしている部分が標準出力をcmakeの変数qml_outputへ取得するオプションです。

他に、かつ同時にERROR_VARIALBE、RESULT_VARIABLEでエラー出力、実行結果を変数に取得する事もでき、VARIABLEをFILEにすればファイルに取得する事もできます。

問題(cmakeの癖)はexecute_processのCOMMANDの書き方です。先ず、パイプしたいコマンド単位で分けて考えて複数のCOMMANDを記述します。複数のCOMMANDは | で接続して実行されます。

それから、注意として、実は COMMAND で定義するパラメーターはコマンド1つのステートメントではありません。COMMANDの第一パラメーターがコマンド、第二パラメーターがコマンドの第一パラメーター、第三パラメーターがコマンドの第二パラメーター、・・・となります。

つまり、 COMMAND "head -n1" とか書くとcmakeがエラーで死にます。また、スペースで区切るのはコマンドに渡すパラメーター単位なので、 COMMAND awk {print $2} ${PROJECT_SOURCE_DIR}/qmldir なんて書くとご丁寧なことに{printと$2}で別々のパラメーターとしてawkに渡されます。それ以前に{でパースエラーにもなりますが。

上記の例では、qmldir_outputに取得した内容にcmake実行時の環境変数QML2_IMPORT_PATHを手前にくっつけた変数qmldirを定義して、messageでそれを出力しています。

参考:

  1. http://www.cmake.org/cmake/help/cmake2.6docs.html#command:execute_process
  2. http://marc.info/?l=cmake&m=124516815811834
  3. http://stackoverflow.com/questions/13037230/how-do-i-initialize-a-cmake-variable-with-the-result-of-a-shell-command/13037728

0 件のコメント:

コメントを投稿