ClangはLLVMのC/C++フロントエンドで、静的解析のコードを追加することがで きる。LLVMについては最適化処理に注目が集まっている。今回はClangに静的 解析コードを追加する為の前準備としてMac上にsvnで取得したClang/LLVMをコ ンパイルしてインストールする(Xcodeに梱包されているものとは別に導入)。
1. Clang
Clangのページに手順が記載されている。
1.1. ソースコードの取得
Clangのページに記載されている手順でソースコードを取得する。
$ svn co http://llvm.org/svn/llvm-project/llvm/trunk llvm $ cd llvm/tools $ svn co http://llvm.org/svn/llvm-project/cfe/trunk clang $ cd ../.. $ cd llvm/tools/clang/tools $ svn co http://llvm.org/svn/llvm-project/clang-tools-extra/trunk extra $ cd ../../../.. $ cd llvm/projects $ svn co http://llvm.org/svn/llvm-project/compiler-rt/trunk compiler-rt $ cd ../..
1.2. ビルド
configureを実行してmake。
$ mkdir llvm.build $ cd llvm.build/ $ ../llvm/configure --prefix=$HOME --enable-optimized $ make $ make install
--enable-optimizedを入れないと出来上がったClangによるビルドは時間が掛 かってしまう。Clang/LLVM内部をデバッグするつもりがない場合は指定した方 が良い。
2. デフォルトのインクルードパスの問題
下記のソースコードclang++でビルド。
$ cat hello.cpp #include <iostream> int main() { std::cout << "hello, world\n"; return 0; }
Xcodeのclang++のデフォルトのインクルードパス。
$ /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang++ -v hello.cpp <snip> ignoring nonexistent directory "/usr/include/c++/v1" #include "..." search starts here: #include <...> search starts here: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../lib/c++/v1 /usr/local/include /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../lib/clang/5.0/include /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include /usr/include /System/Library/Frameworks (framework directory) /Library/Frameworks (framework directory) End of search list. <snip>
今回導入したclang++のデフォルトのインクルードパス。
$ ~/bin/clang++ -v hello.cpp <snip> ignoring nonexistent directory "<HOME>/bin/../include/c++/v1" ignoring nonexistent directory "/usr/include/c++/v1" #include "..." search starts here: #include <...> search starts here: /usr/local/include /<HOME>/bin/../lib/clang/3.5/include /usr/include /System/Library/Frameworks (framework directory) /Library/Frameworks (framework directory) End of search list. hello.cpp:1:10: fatal error: 'iostream' file not found #include <iostream> ^ 1 error generated.
xcode配下のclang++は以下のヘッダを使用している。
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/c++/v1/iostream
LLVMのconfigureでXcodeと同じインクルードパスを見るようにしてやればいい はずだが、オプションがよく分からずじまい。応急処置としてclang++のラッ パースクリプトで-Iオプションを使って読みにいく手もできそうだが、ここで はLLVM向けのlibcxxを$HOME配下に別途インストールする。
3. libcxxのインストール
こちらのページに記載されている手順でソースコードを取得する。
3.1. ソースコードの取得
$ svn co http://llvm.org/svn/llvm-project/libcxx/trunk libcxx
3.2. ビルド
$ mkdir libcxx.build $ cd libcxx.build $ cmake -G "Unix Makefiles" ../libcxx \ -DCMAKE_INSTALL_PREFIX="$HOME" $ make install
3.3. 実行
先ほどのhello.cppをclang++でビルド。
$ clang++ -v hello.cpp <snip> ignoring nonexistent directory "/usr/include/c++/v1" #include "..." search starts here: #include <...> search starts here: /<HOME>/bin/../include/c++/v1 /usr/local/include /<HOME>/bin/../lib/clang/3.5/include /usr/include /System/Library/Frameworks (framework directory) /Library/Frameworks (framework directory) End of search list. "<HOME>/bin/ld" -demangle -dynamic -arch x86_64 -macosx_version_min 10.9.0 -o a.out /var/folders/69/sm58mrhx0bvg0qbgvljzgs0r0000gn/T/hello-a55cfc.o -lc++ -lSystem /<HOME>/bin/../lib/clang/3.5/lib/darwin/libclang_rt.osx.a $ ./a.out hello, world $
<HOME>/bin/ldについてはMacの/usr/bin/ldへのシンボリックリンクを使用し ている。PATHからldを探して、システムのldを使うのがデフォルト動作なんだ ろうか? llvm-ldがないのでllvm-linkとかのコマンド群を使うのが正当な気 がするが。そもそもllvm-ldがldの置き換えという訳ではないのかな。
$ /usr/bin/ld -v @(#)PROGRAM:ld PROJECT:ld64-224.1 configured to support archs: armv6 armv7 armv7s arm64 i386 x86_64 armv6m armv7m armv7em LTO support using: LLVM version 3.3svn, from Apple Clang 5.0 (build 500.2.79)
4. The LLVM Linker(上手く実行できてない)
LLVM向けのリンカのThe LLVM Linkerというものがあった。
Clangと同様にLLVMのソースツリー配下に置く。
$ cd llvm/tools/ $ svn co http://llvm.org/svn/llvm-project/lld/trunk lld
4.2. ビルド
Clangと同様にLLVMのソースツリーと一緒にビルドする。lldはcmakeでビルド する必要があるのでLLVMをcmakeでビルドする(cmakeによるLLVMビルド方法)。 http://llvm.org/docs/CMake.html
$ cd ../.. $ mkdir llvm.build $ cd llvm.build $ cmake -G "Unix Makefiles" ../llvm/ \ -DCMAKE_CXX_FLAGS="-std=c++11" \ -DCMAKE_INSTALL_PREFIX="$HOME" \ -DCMAKE_BUILD_TYPE="Release" $ make $ make install
CMAKE_CXX_FLAGSに"-std=c++11"を設定しない場合、以下のエラーが発生した。
CMake Error at tools/lld/CMakeLists.txt:99 (message): lld requires c++11. Clang and gcc require -std=c++0x or -std=c++11 to enter this mode. Please set CMAKE_CXX_FLAGS accordingly.
4.3. 実行
$HOME/bin/ldを$HOME/bin/lldへのシンボリックリンクに変更して実行。う まくいかず。少なくともmacosx_version_minオプションを解析するコードは lldにあるのだが・・・。使い方の問題か?
"/<HOME>/bin/ld" -dynamic -arch x86_64 -macosx_version_min 10.9.0 -o a.out /var/folders/69/sm58mrhx0bvg0qbgvljzgs0r0000gn/T/hello-5908c6.o -lc++ -lSystem /<HOME>/bin/../lib/clang/3.5/lib/darwin/libclang_rt.osx.a warning: ignoring unknown argument: -arch warning: ignoring unknown argument: -macosx_version_min lld: unknown input file format for file x86_64 clang-3.5: error: linker command failed with exit code 1 (use -v to see invocation)
ノイズの多い内容だが、とりあえずldは/usr/bin/ldを使うようにする。