Visual Studio 2015 Update 1でコンパイラが追加されました。Visual C++でコンパイルしたオブジェクトコードとリンクできるClangです。デバッグ情報なども互換で、おそらくVC++でコンパイルしたものと遜色なく扱えるものと思います。

名称はClang with Microsoft CodeGenのようです。Clang/C2という表記も見かけます。オリジナルのClangそのままではなく、後段の最適化・コード生成の部分をVisual C++のもの(c2.dll)に取り替えたものだからです。

より詳しい紹介と導入方法はClang with Microsoft CodeGenがでたので試す – Qiitaを見ると良いでしょう。

さて、このClang/C2をコマンドプロンプトで使ってみました。それについて書きます。

コマンドラインで使うための準備

VisualStudio 2015 x86 Native Tools コマンドプロンプトを起動します。そうしたら、このコマンドを実行します。途中で改行されているかもしれませんが、実際には1行です。

SET PATH=C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\Clang 3.7\bin;%PATH%

これで準備完了です。

2016年8月27日追記: Visual Studio 2015 Update 2あたりからパスがC:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\Clang 3.7\bin\x86に変わっています。

Hello world

まずはHello worldを書いてみましょう。

// hello.cpp: clangでコンパイルする
 
#include <iostream>
 
void ShowHelloWorld()
{
  std::cout << "Hello world" << std::endl;
}
// main.cpp: clでコンパイルする
 
void ShowHelloWorld();
 
int main()
{
  ShowHelloWorld();
}

これを以下のコマンドラインでコンパイル・実行します。

T:\>clang -c -o hello.obj hello.cpp
T:\>cl /Fe hello.exe main.cpp hello.obj
T:\>hello.exe
Hello world

見てのとおり、hello.cppはclang、main.cppはcl (Visual C++)でコンパイルし、リンクしています。extern "C"は使っていませんが、ちゃんとリンクできて動いています。

これでもいけます。

T:\>cl /c main.cpp
T:\>clang -o hello.exe hello.cpp main.cpp
T:\>hello.exe
Hello world

例外処理

次は例外処理を使ってみます。

// throw.cpp: clangでコンパイルする
 
#include <stdexcept>
#include <string>
 
[[noreturn]]
void throw_with_msg(const std::string& msg)
{
  throw std::runtime_error(msg);
}
// main.cpp: clでコンパイルする
 
#include <iostream>
#include <stdexcept>
#include <typeinfo>
 
[[noreturn]]
void throw_with_msg(const std::string& msg);
 
int main()
{
  try
  {
    throw_with_msg("my error");
  }
  catch (const std::exception& e)
  {
    std::cout << "type: " << typeid(e).name() << std::endl;
    std::cout << "what: " << e.what() << std::endl;
  }
}
T:\>clang -fexceptions -o throw.obj -c throw.cpp
T:\>cl /EHsc /Fe throw.exe main.cpp throw.obj
T:\>throw.exe
type: class std::runtime_error
what: my error

例外処理も動きます。例外処理を通じてC++オブジェクトも受け渡せていますし、typeidも使えます。

ランタイムライブラリを選ぶ

このclangでコンパイルする際には、clと同じVisual C++のランタイムライブラリが使用されます。上記コードでstd::coutオブジェクトやstd::string型を使っていてうまくいったのは、そういうわけです。

ランタイムの種類はプリプロセッサ定義で選べます。違う種類を混在させると、リンクで失敗したり警告が出たりします。そこはcl.exeだけでコンパイルするときと同じです。

  • DLL版ランタイム (/MD)
    clang -D_DLL -c -o hello.obj hello.cpp
    cl /MD /Fe hello.exe main.cpp hello.obj
    
  • DLL版デバッグ用ランタイム (/MDd)
    clang -D_DLL -D_DEBUG -c -o hello.obj hello.cpp
    cl /MDd /Fe hello.exe main.cpp hello.obj
    
  • 静的リンク版ランタイム (/MT)
    clang -c -o hello.obj hello.cpp
    cl /MT /Fe hello.exe main.cpp hello.obj
    
  • 静的リンク版デバッグ用ランタイム (/MTd)
    clang -D_DEBUG -c -o hello.obj hello.cpp
    cl /MTd /Fe hello.exe main.cpp hello.obj
    

感想

前々から作っていると公表されていたのですが、やはり実際触ってみると驚きです。別世界だと思っていた2つのコンパイラが協同するのですから。

従来からのVisual C++コンパイラ(cl.exe)との使い分けをどうしたら良いのか、これから考えないといけないですね。


スポンサード リンク

この記事のカテゴリ

  • ⇒ Clang/C2をコマンドプロンプトで使ってみる
  • ⇒ Clang/C2をコマンドプロンプトで使ってみる