流行り(?)の LLVM/Clang を Windows(MSYS)に導入してみたが、思った以上に大変だった。
やり方をここにメモしておく。

ダウンロード

LLVM Download Page から、

  • LLVM source code
  • Clang source code

を落としてきて展開する。

なお、手元の MSYS 環境では、Clang を展開する際にエラーが出て停止した。

$ tar fxz clang-3.0.tar.gz
tar: clang-3.0.src/tools/scan-build/c++-analyzer: Cannot create symlink to `ccc-analyzer': No such file or directory
tar: Exiting with failure status due to previous errors

symlink を作成できなくてエラーが発生しているようだ。
仕方がないので、Cygwin で展開した。

展開が終わったら、Clang をフォルダごと LLVM の tools フォルダに移動する。

$ mv clang-3.0.src/ llvm-3.0.src/tools/

なんとなく格好悪いので、clang-3.0.src を clang にリネームしておく。

ビルド

Python が必要なので、あらかじめインストールしてパスを通しておく。

Clang は必要なインクルードファイルが不足しているので、MinGW のものを使う。
インクルードパスはハードコーディングで、ソースコードに書き加える必要がある。
そこでまず、GCC の C と C++ のインクルードパスを調べる。

$ gcc -v -x c /dev/null -fsyntax-only
(中略)
#include <...> search starts here:
 C:/MinGW/msys/1.0/local/include
 c:\mingw64\bin\../lib/gcc/x86_64-w64-mingw32/4.6.1/include
 c:\mingw64\bin\../lib/gcc/x86_64-w64-mingw32/4.6.1/../../../../include
 c:\mingw64\bin\../lib/gcc/x86_64-w64-mingw32/4.6.1/include-fixed
 c:\mingw64\bin\../lib/gcc/x86_64-w64-mingw32/4.6.1/../../../../x86_64-w64-mingw32/include
End of search list.
(後略)

$ gcc -v -x c++ /dev/null -fsyntax-only
(中略)
#include <...> search starts here:
 C:/MinGW/msys/1.0/local/include
 c:\mingw64\bin\../lib/gcc/x86_64-w64-mingw32/4.6.1/include/c++
 c:\mingw64\bin\../lib/gcc/x86_64-w64-mingw32/4.6.1/include/c++/x86_64-w64-mingw32
 c:\mingw64\bin\../lib/gcc/x86_64-w64-mingw32/4.6.1/include/c++/backward
 c:\mingw64\bin\../lib/gcc/x86_64-w64-mingw32/4.6.1/include
 c:\mingw64\bin\../lib/gcc/x86_64-w64-mingw32/4.6.1/../../../../include
 c:\mingw64\bin\../lib/gcc/x86_64-w64-mingw32/4.6.1/include-fixed
 c:\mingw64\bin\../lib/gcc/x86_64-w64-mingw32/4.6.1/../../../../x86_64-w64-mingw32/include
End of search list.
(後略)

次に clang/lib/Frontend/InitHeaderSearch.cpp を編集する。
“FIXME: temporary hack: hard-coded paths” で検索すると 2 箇所引っかかる。
それぞれ、C と C++ 用のサーチパスに対応しており、以下のような要領でパスを追加する。

// InitHeaderSearch::AddDefaultCIncludePaths 関数
// FIXME: temporary hack: hard-coded paths.
AddPath("C:/MinGW/msys/1.0/local/include", System, true, false, false);
AddPath("C:/MinGW64/lib/gcc/x86_64-w64-mingw32/4.6.1/include", System, true, false, false);
AddPath("C:/MinGW64/include", System, true, false, false);
AddPath("C:/MinGW64/lib/gcc/x86_64-w64-mingw32/4.6.1/include-fixed", System, true, false, false);
AddPath("C:/MinGW64/x86_64-w64-mingw32/include", System, true, false, false);

// InitHeaderSearch::AddDefaultCPlusPlusIncludePaths 関数
// FIXME: temporary hack: hard-coded paths.
AddPath("C:/MinGW/msys/1.0/local/include", CXXSystem, true, false, false);
AddPath("C:/MinGW64/lib/gcc/x86_64-w64-mingw32/4.6.1/include/c++", CXXSystem, true, false, false);
AddPath("C:/MinGW64/lib/gcc/x86_64-w64-mingw32/4.6.1/include/c++/x86_64-w64-mingw32", CXXSystem, true, false, false);
AddPath("C:/MinGW64/lib/gcc/x86_64-w64-mingw32/4.6.1/include/c++/backward", CXXSystem, true, false, false);
AddPath("C:/MinGW64/lib/gcc/x86_64-w64-mingw32/4.6.1//include", CXXSystem, true, false, false);
AddPath("C:/MinGW64/include", CXXSystem, true, false, false);
AddPath("C:/MinGW64/lib/gcc/x86_64-w64-mingw32/4.6.1/include-fixed", CXXSystem, true, false, false);
AddPath("C:/MinGW64/x86_64-w64-mingw32/include", CXXSystem, true, false, false);

‘\’ は ‘/’ に変換しておく。
インクルードパスにさえ気を付ければ、特に問題はないはず。

$ mkdir build
$ cd build
$ ../llvm-3.0.src/configure --disable-docs --enable-targets=x86,x86_64,cpp --prefix=/opt/llvm
$ make
$ make install

完了後にパスを通す。

$ export PATH=$PATH:/opt/llvm/bin

インクルードパスが正しく設定できているかチェックする。
AddPath で追加したフォルダが表示されていれば問題ない(と思う)。

$ clang -v -x c /dev/null -fsyntax-only
(中略)
#include <...> search starts here:
 C:/MinGW/msys/1.0/local/include
 C:/MinGW64/lib/gcc/x86_64-w64-mingw32/4.6.1/include
 C:/MinGW64/include
 C:/MinGW64/lib/gcc/x86_64-w64-mingw32/4.6.1/include-fixed
 C:/MinGW64/x86_64-w64-mingw32/include
 C:/MinGW/msys/1.0/opt/llvm/bin/../lib/clang/3.0/include
 C:/MinGW/msys/1.0/opt/llvm/bin/../lib/clang/3.0/../../../include
 /mingw/include
 c:/mingw/include
End of search list.
(後略)

$ clang -v -x c++ /dev/null -fsyntax-only
(中略)
#include <...> search starts here:
 C:/MinGW/msys/1.0/local/include
 C:/MinGW64/lib/gcc/x86_64-w64-mingw32/4.6.1/include/c++
 C:/MinGW64/lib/gcc/x86_64-w64-mingw32/4.6.1/include/c++/x86_64-w64-mingw32
 C:/MinGW64/lib/gcc/x86_64-w64-mingw32/4.6.1/include/c++/backward
 C:/MinGW64/lib/gcc/x86_64-w64-mingw32/4.6.1//include
 C:/MinGW64/include
 C:/MinGW64/lib/gcc/x86_64-w64-mingw32/4.6.1/include-fixed
 C:/MinGW64/x86_64-w64-mingw32/include
 C:/MinGW/msys/1.0/opt/llvm/bin/../lib/clang/3.0/include
 C:/MinGW/msys/1.0/opt/llvm/bin/../lib/clang/3.0/../../../include
 /mingw/include
 c:/mingw/include
End of search list.
(後略)

テスト

GCC の代わりに使ってみる。オプションは GCC と同じ。C++11 を使いたければ、-std=c++0x を付ける。

// hello.c
#include <stdio.h>

int main(void)
{
    printf("Hello, Clang!\n");
    return 0;
}
$ clang -m32 hello.c -o hello32
$ clang -m64 hello.c -o hello64
$ ./hello32
Hello, Clang!
$ ./hello64
Hello, Clang!

x86_64 版 MinGW では、-m32/-m64 を忘れないように注意。

おまけ

ビットコードを直接生成する

$ clang -emit-llvm hello.c
clang: error: 'i386-pc-mingw32': unable to pass LLVM bit-code files to linker

なぜか、上手くいかない。

LLVM アセンブリコードを生成する

$ clang -emit-llvm -S hello.c

hello.s が生成される。テキストファイルなので、閲覧や編集も可能である。
(追記)
LLVM アセンブリコードの拡張子は、.ll が使われることが多いようだ。
.s では、ホストのアセンブリコードと紛らわしいので、-o で .ll の出力を与えることが望ましいのかもしれない。

LLVM アセンブリコードからビットコードを生成する

$ llvm-as hello.s

hello.s.bc が生成される。バイナリファイルなので、中を覗いても訳が分からない。

ビットコードを最適化する

$ opt -O3 hello.s.bc -o hello.opt.bc

LLVM アセンブリコード/ビットコードから対象アーキテクチャ用のアセンブリコードを生成する

$ llc -O3 -march=x86 -mtriple=i686-pc-mingw32 hello.opt.bc -o hello32.s
$ llc -O3 -march=x86-64 -mtriple=x86_64-mingw32 hello.opt.bc -o hello64.s

-march に指定可能なものは、llc –version で調べることができる。
-mtriple は ABI 指定が必要な時のみ。

as でアセンブルし、ld でリンクすることで、実行ファイルが生成できる。

$ as --32 hello32.s -o hello32.o
$ as --64 hello64.s -o hello64.o
$ gcc -m32 hello32.o -o hello32
$ gcc -m64 hello64.o -o hello64
$ ./hello32
Hello, Clang!
$ ./hello64
Hello, Clang!

C++ に書き戻す

期待していたものとはちょっと違った。

$ llc -O3 -march=cpp hello.opt.bc

llvm 関連のインクルードファイルががっつり並ぶ、謎のソースコードが生成される。
これをどう利用すればいいのか…。

【参考】

Clang – Getting Started
KMC Staff Blog:Clang と LLVM を使ってみる。
llcの概要 – LLVM wiki