並ゲームプログラマの書き捨て場

ゲームプログラマやってる私の日記、雑記、備忘録、公開場所

clang for windows 3.5を入れてみた

2014年09月25日の記事

 

今まで「クラング」と読んでいました。「クラン」的な発音なんですね。djannです。

 

ふと見たらclang + llvmの3.5が出ていたので、今更ながら入れてみることにした。

私は生粋のWindows + Visual Studioユーザなので、3.4から提供され始めたclang for windowsインストーラを用いて、Visual Studio上でclangを使うことにした。

 

実に手厚いサポートがあるようで、旧バージョンを入れている状態でインストーラを起動すると

「旧バージョンがあるから、いったん消してから入れていい?」

とかわいらしく聞いてきてくれた。もちろんOKに決まっている。

 

 

さて、clang for windowsインストーラを用いた後は

1. C:\Program Files (x86)\LLVM\tools\msbuild\install.batを管理者権限で起動

2. Visual Studioでプロジェクト作成

3. プロジェクトのプロパティ -> 構成プロパティ -> プラットフォームツールセットをLLVM-sv20XXに設定

で、出来上がり。とても簡単だ。

 

f:id:djann:20141116185539p:plain

 

個人的には更にC/C++ -> コード生成 -> ランタイムライブラリを/MTdまたは/MTにするところまでが、プロジェクト作成の一連の作業となる。

スレッド生成時には基本的に_beginthreadexを用い、CreateThreadは使用しない(本の虫 MSVCのランタイムとスレッドとリソースリークの関係 参照)ので、配布先の環境でVisual Studioランタイムを必要とせず、起動しやすい静的リンク版で作る事が多い。

 

さて、では早速安定のHello, Worldを書いてみよう。

Visual Studio 2010では使えない機能を無駄に使う事で、ちゃんとclang for windowsが働いている事を確認するために、無駄に文字列リテラルを定義して標準出力へ文字列を出力する。

 

#include <iostream>

void operator"" _print( const char *param, std::size_t ){
	std::cout << param << std::endl;
}

int main()
{
	"Hello, World"_print;

	std::cin.get();
}

意気揚々とコンパイルを行うが、案の定正常に通らない。3.4の時も色々あったので通らなかったので、そんなものだろう。

と思ったのだが、見るとどうやら3.4の時とはエラー出力の内容が違っていた。

 

エラー    9    error : cannot compile this throw expression yet    C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xiosbase    315    4    cpp_test
エラー    10    error : cannot compile this throw expression yet    C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xiosbase    317    4    cpp_test
エラー    11    error : cannot compile this throw expression yet    C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xiosbase    319    4    cpp_test
・・・以下略

 

中高と英語の授業はほとんど受けていない程度の英語力で適当に読んでみると「まだthrow式(try式)をコンパイルできねーべ」とあるように見える。

 

なるほど試しに、main関数内にtry{} catch(int){}とだけ書いてみたが、同じように出力される。cl.exeとABIを合わせるのに、まだそこまで達していないということだろうか?

 

さて、ではどうしようか?MSBuild内でヘッダやライブラリのパスを別の場所へ指定。そこにVisual Studio付属のヘッダをコピーし、中身を書き換える事にでもしようか?だが、この一つの環境を動かすことだけにしては、労力がかかり過ぎだろう。

とりあえずVisual Studio付属のSTLを用いない方針も有りだと思いつつ、ひとまずヘッダ内を見てみる事にした。相変わらずマクロにマクロが重なっており、私のような一般人プログラマにはとても見辛い。

 

さて、最初のエラー文へ飛んでみると、_TRY_IO_BEGINというマクロが見えた。どのような定義か見てみると

#define _TRY_IO_BEGIN _TRY_BEGIN

となっている。では_TRY_BEGINはというと

#define _TRY_BEGIN try {

である。そしてそのどちらも、直前の行に

#if _HAS_EXCEPTIONS

とある。対応する#else側では、ただの中括弧開きが定義されているようだ。つまり例外が使われないようにするには、_HAS_EXCEPTIONSを0にすればいいようだ。

 

さて、では肝心の_HAS_EXCEPTIONSはどこでどう定義されていたかというと、yuals.hというヘッダ中で

#ifndef _HAS_EXCEPTIONS
#define _HAS_EXCEPTIONS 1
#endif /* _HAS_EXCEPTIONS */

と定義されている。

 

つまり、ヘッダのインクルード前に_HAS_EXCEPTIONS 0で定義してやれば行けるはずだ。というか、実際に行けた。

#define _HAS_EXCEPTIONS 0
#include <iostream>

とすることで、見事にエラーの一つもなくHello, Worldの出力を行う事が出来た。これで、Vista上での最新Visual Studio(2010までしか使えない)でもC++11対応のコードを書くことが出来る。実にハッピーだ。

 

 

※どこかでClang for WindowsVisual StudioC++のバージョン進捗を合わせているようで、Visual Studioで使えない機能は使えないと見た気がしたが、ユーザ定義リテラルもconstexprも使えるし、ラムダ式は言わずもがな。どの部分が Clang for Windowsだけ劣っているのか、あまり最新のものを知らない私には分からないのだが、誰か教えてくれないだろうか。

 

追記

なるほど、Clang for WindowsVisual Studioのヘッダとライブラリを用いているが故に、標準ライブラリ周りはVisual Studio準拠となってしまうということか。

逆に言えば、それ以外に関してはC++の機能について特別マイナスされている事は無く、毎回赤線が出てくる事を気にしなければ(または出さないように設定すれば)、言語機能だけは使える。ということのようだ。