24
12

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

CMAKE_BUILD_TYPEのUPPER CASEにご用心

Last updated at Posted at 2018-05-25

CMAKE_BUILD_TYPE とは

cmakeを用いてビルドするとき、-DCMAKE_BUILD_TYPEを指定すると、(きちんとCMakeLists.txtが書かれているプロジェクトなら)適切なオプションを付けてビルドが行われる。

$ cmake -DCMAKE_BUILD_TYPE=Release  # -O2 とか -DNDEBUG とかが付く
$ cmake -DCMAKE_BUILD_TYPE=Debug  # -O0 とか -g とかが付く

ここによると、値としてはempty, Debug, Release, RelWithDebInfo, MinSizeRelなどが許されているらしい。

事実1: 値はcase insensitive

$ cmake -DCMAKE_BUILD_TYPE=Debug  # -g が付く
$ cmake -DCMAKE_BUILD_TYPE=debug  # -g が付く
$ cmake -DCMAKE_BUILD_TYPE=DEBUG  # -g が付く
$ cmake -DCMAKE_BUILD_TYPE=DeBuG  # -g が付く

大文字小文字は区別されず、DebugでもDEBUGでも通ってしまう。

事実2: Invalid valueに対して警告が出ない

$ cmake -DCMAKE_BUILD_TYPE=Dedug  # typoだが、警告は出ない

cmake-DCMAKE_BUILD_TYPEは、<Option>が指定されるとCMAKE_C((XX)?)_FLAGS_<OPTION>に含まれるオプションをコンパイルオプションに追加する。

つまり、

CMakeLists.txt
set(CMAKE_CXX_FLAGS "-std=c++14 -Wall")
set(CMAKE_CXX_FLAGS_DEBUG "-g -O0")
set(CMAKE_CXX_FLAGS_RELEASE "-O3 -DNDEBUG")

となっていた場合、

$ cmake  # gcc <target> -std=c++14 -Wall
$ cmake -DCMAKE_BUILD_TYPE=Debug  # gcc <target> -std=c++14 -Wall -g -O0
$ cmake -DCMAKE_BUILD_TYPE=Release  # gcc <target> -std=c++14 -Wall -O3 -DNDEBUG

のようにオプションが決まる。

ここで、例えば

$ cmake -DCMAKE_BUILD_TYPE=Dedug  # ...?

のように存在しないオプションを指定した場合、cmakeはエラーを出してはくれず、単に

$ cmake -DCMAKE_BUILD_TYPE=Dedug  # gcc <target> -std=c++14 -Wall

と、あたかも

set(CMAKE_CXX_FLAGS_DEDUG "")

何も指定しない変数が定義されているかのように振る舞ってくれる。

事実3: CMakeLists.txt 内で複雑な処理をする奴がいる

CMakeLists.txt内では単にコンパイル対象を指定するだけでなく、cmake languageに従って様々な操作を行うことができる。

例えば、pybind11/tools/pybind11Tools.cmakeの中では、

tools/pybind11Tools.cmake
...
  if (NOT MSVC AND NOT ${CMAKE_BUILD_TYPE} MATCHES Debug)
    # Strip unnecessary sections of the binary on Linux/Mac OS
...

という操作が行われている。
${MSVC}FALSEで、かつ${CMAKE_BUILD_TYPE}が正規表現Debugにマッチしないなら、実行ファイルのstripを行うセクションだ。

見ると分かる通り、この部分はcase sensitiveである。Debugと正確に一致するかどうかのみを見ており、DEBUGdebugでは通らない。

結果: エラーも出ないのに、-gも付いているのに、なぜかデバッグシンボルが付かない

$ cmake -DCMAKE_BUILD_TYPE=DEBUG

とすると、

  • cmake
    • case insensitiveなので、-DCMAKE_BUILD_TYPE=Debugと認識し、エラーや警告は出ない。仮にそう認識しなかったとしてもどちらにせよcmakeはエラーや警告を出さない。
  • CMakeLists.txt
    • 各自が勝手に書いているので、case sensitiveかもしれない。その場合-DCMAKE_BUILD_TYPE=Debugとは区別される。もちろんそんなtypoでエラーを出すような機構は基本的にない。

となって、結局想定外の挙動になってしまう。

まとめ

-DCMAKE_BUILD_TYPEの値はDebugなど、大文字から始まるcamel case。
間違えてもcmakeは怒ってはくれないし、DEBUGとかdebugとか書いててもほとんどの環境で通じてしまうので、問題が発生するまで気づけない(そして問題が発生しても表面には出てこない)。
十分注意して使用してほしい。

24
12
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
24
12

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?