CMake で C# のプロジェクトを作ろうとしてハマった話


泣きごと

半年ほど前からCMake が C# に対応しているらしいということで,試しに使って見ようと思ったら盛大にハマってしまいましたorz

cmake の中のファイルをいじることで一応の問題解決はできましたが,英語以外の環境だと同じ所でハマる人が出そうです。

試した環境

  • Windows 7 (64 bit) 日本語版
  • CMake 3.9.3 (2017.9.24 時点で最新)
  • Visual Studio Community 2017

構成

以下のような構成 (詳細はこちら) を作って cmake してみたところ……

simple-cs-project/
├─ build/
│  ├─ CMakeGenerate.txt (中で cmake している。)
│  └─ project/
│     └─ ソリューションファイルやプロジェクトのファイルができる予定
└─ src/
   ├─ CMakeLists.txt
   └─ main.cs

エラー

> cd build
> CMakeGenerate.bat

(中略)
-- The CSharp compiler identification is Microsoft Visual Studio 2017
-- The CSharp compiler version is \
(中略)
CMake Error at D:/cmake-learning/simple-cs-project/build/project/CMakeFiles/3.9.3/CMakeCSharpCompiler.cmake:10:
  Parse error.  Function missing ending ")".  Instead found unterminated
  string with text ")

  ".
Call Stack (most recent call first):
  CMakeLists.txt:5 (enable_language)


CMake Error: Could not find cmake module file: D:/cmake-learning/simple-cs-project/build/project/CMakeFiles/3.9.3/CMakeCSharpCompiler.cmake
-- Configuring incomplete, errors occurred!
See also "D:/cmake-learning/simple-cs-project/build/project/CMakeFiles/CMakeOutput.log".
See also "D:/cmake-learning/simple-cs-project/build/project/CMakeFiles/CMakeError.log".

という塩梅で cmake が通らない......。

原因

バッチを実行したときのログからも推すに,C# コンパイラのバージョンがうまく取れていません。

cmake の中をのぞいてみると,C# コンパイラのバージョンを以下のように取得していました。

cmake/share/cmake-3.9/Modules/CMakeDetermineCSharpCompiler.cmake(LL.26-30)
  execute_process(COMMAND "${CMAKE_CSharp_COMPILER}" "/help" OUTPUT_VARIABLE output)
  string(REPLACE "\n" ";" output "${output}")
  foreach(line ${output})
    string(TOPPER ${line} line)
    string(REGEX REPLACE "^.*COMPILER.*VERSION[^\\.0-9]*([\\.0-9]+).*$" "\\1" version "${line}")

要するに,cmake としては Compiler version という文字列が出現することを期待しているんだけれど,手元の環境で試すと以下のようになる。

> csc.exe /help

Microsoft (R) Visual C# Compiler バージョン 2.3.2.62116 (8522b473)
Copyright (C) Microsoft Corporation. All rights reserved.
()

Σ「バージョン」!!

ご丁寧に日本語で出力していただいた結果,cmake がコケているようです。

対応

「バージョン」が「version」 になればよいわけなので,コンパイラが出力する言語を英語に切り替えてあげれば問題を回避できます。 コンパイラが出力する言語は /preferreduilang オプションで指定できます。

> csc.exe /help /preferreduilang:en-US

Microsoft (R) Visual C# Compiler version 2.3.2.62116 (8522b473)
Copyright (C) Microsoft Corporation. All rights reserved.

ということで,cmake/share/cmake-3.9/Modules/CMakeDetermineCSharpCompiler.cmake の L. 26 を以下のように修正したところ,無事に cmake できるようになりました。

cmake/share/cmake-3.9/Modules/CMakeDetermineCSharpCompiler.cmake(L.26)
- execute_process(COMMAND "${CMAKE_CSharp_COMPILER}" "/help" OUTPUT_VARIABLE output)
+ execute_process(COMMAND "${CMAKE_CSharp_COMPILER}" "/help /preferreduilang:en-US" OUTPUT_VARIABLE output)

へびの足

Visual Studio 2017 の csc.exe には /version というオプションがあって,言語に関係なく一撃でバージョン値を取得できました。 CMake 的には Visual Studio 2010 より前のバージョンには非対応ということなので,2010 以降の csc.exe で /version オプションが使えるなら,こっちに乗り換えるというのが筋なのかもしれません (ちゃんと調べていません)。