2015/11/21

[arm]Cortex-MでもLLVMを使ってみたかったが、失敗した

静的解析のことを調べていたら、LLVMが出てきた。
そういえば、Objective-CのときはLLVMだったよなぁ、と薄い記憶しかない。
が、Interface誌の2015年3月号に特集もあったので、あれから半年以上経っているのでもっと使えるようになっているはず。

そう、私だってCortex-MでLLVMしてみたいのだ。


うちの環境は、Windows7 64bitがメインなので、ここで使いたい。
Cortex-Mのビルドはcygwinを使っているが、コンパイラはGCC ARM EmbeddedからWin32版を落としているので、同じような感じになるのかな?

 

How To Build On ARM

ここがLLVMのページにある説明のだが、クロスコンパイルについては「NOT tailored」ということで、まだ整備されていないと読めばよいのか。
つまり、ここに書いてある説明は、ARM上でARMのビルドをするセルフコンパイルについてということだろう。

あまり気にしてなかったけど、LLVMとClangって別々なのですな。
Wikipediaで見ると、「ClangはLLVM上で動作することを意図している」とあり、

  • LLVM : バックエンド
  • Clang : C/C++/Objective-C/Objective-C++向けコンパイラフロントエンド

となっている。

コンパイルのフロントエンドとバックエンドってなんじゃろう、と思ってInterface誌を見ると、フロントエンドがソースファイルを解析して、バックエンドがバイナリに変換する、といっているようだ。
フロントエンドとバックエンドの間は「中間言語」がインターフェースになっていて、フロントエンドが何言語用であっても中間言語にさえ変換しておけば、あとはバックエンドが中間言語をうまいこと処理してくれるということだろう。
確か、GCC4から大きく変わりましたよー、というアナウンスがあったときも同じようなことを言ってたように思う。

そうなると、クロスコンパイルで差し替えになるのは、ClangというよりもLLVMの方になるのかな?
まあ、そこら辺はやっていけばわかるだろう。


How To Cross-Compile Clang/LLVM using Clang/LLVM
Cross-compilation using Clang

クロスコンパイルについてはこちらを、ということだ。
上のリンクは、LLVM/Clang自体をクロスコンパイルしてセルフビルドできるようにしているのかな?
下のリンクは「using Clang」だから、こちらが私の思うクロスコンパイルの方だ。
「Clang 3.8」となっているが、正式リリースされているのは3.7みたい(2015/11/21)。

ARMのサポートは全部じゃない、とあるが、Interface誌ではLLVM3.5からthumbのオブジェクトも一気に吐いてくれると書いてあるので、とりあえずLLVM3.5以降ならよいのかな?
ダウンロードページに、64bit用Windows向けのプレビルド版LLVM3.7.0があるので、それをインストールしてみよう。
"c:\Program Files\LLVM"に入るが、まあいいだろう。

こんなソースをコンパイルしてみた。

hello.c

  1: volatile int a;
  2: 
  3: int main(void)
  4: {
  5:     int i;
  6:     
  7:     for (i=0; i<10; i++) {
  8:         a += i;
  9:     }
 10:     
 11:     return 0;
 12: }

特に何かするわけでもないが、最適化されて中身が空っぽということはないだろう。

>clang hello.c
/usr/bin/ld: unrecognised emulation mode: i386pep
Supported emulations: i386pe
clang.exe: error: linker command failed with exit code 1 (use -v to see invocation)

えっ。
ldは、cygwinにパスを通してある方のが呼ばれているようだけど、そもそもなんでclangがldを呼び出すのだろう?
インストールされているパスを見ると、lld.exeというのがあり、これはLLVM Linkerらしい。
じゃあ、これを呼び出せばよいのに。。。

LLVM Clang の Windows へのインストールと使い方 | プログラマーズ雑記帳
こちらを読むと、どうもWindowsで動かすときには「gcc互換」と「VisualStudio互換」があるらしい。
gcc互換の場合はMinGWを使うらしく、includeファイルなどもそっちを使うとのこと。
うぅ・・・。

c++ - (clang / llvm-mc / lld) hello world (x86-64 windows & linux) - Stack Overflow
こっちも、lld開発者の人が「clang to use lld is to make a symlink to lld named ld」と書いているので、ldを使っているように読める。

でもねぇ。lld.exeって30MBもあるのだよ。
もうちょっと小さくてもいいやん、と思ってしまう。

 

では、と-cをつけてオブジェクトだけ生成させて確認する。

>clang -c hello.c

これでhello.oができる。
できるのだが、gccで生成したobjectファイルと構成が違うようなのだ。
cygwinのfileコマンドで見ても、gccの方は「MS Windows COFF Intel 80386 object file」と読むのだが、llvmの方は単なるデータファイルとしてみてしまう。
だから、ld.exeを呼び出してもダメだったんじゃなかろうか?
バイナリエディタで見ると、同じようなものは含んでいそうだけど、頭の方が違うので構造が違うんだろうな。

 

めんどくさくなってきたので、cygwinのLLVM/Clangをインストールした。
こちらは3.5.2だった。

$ clang -o hello hello.c

普通にコマンドができた。

$ clang -c hello.c
$ file hello.o

COFFファイルになっている。
うーん。

Windows版のclangとMinGWのldで動くとするならば、MinGWのldで認識できるオブジェクトをclangが生成しているということだろう。
cygwinのfileコマンドも、データベースから参照しているだけだと思うので、それに入っていなければわからないだろうし。
そういうのは、後で考えよう。


では、cygwin上でCortex-M用にビルドしてみよう。

$ clang -target arm-eabi -mcpu=cortex-m0 hello.c
error: unable to create target: 'No available targets are compatible with this triple, see -version for the available
      targets.'
1 error generated.

あら。。。
-versionでターゲットを見て見ろ、と。

$ clang -version
clang: error: unknown argument: '-version'
clang: error: no input files

エラーになるやん!

$ clang -v
clang version 3.5.2 (tags/RELEASE_352/final)
Target: i386-pc-windows-cygnus
Thread model: posix

このTargetの中にARMも追加されればよいのだろうか?
Windows版ではこう出てきた。

>clang -v
clang version 3.7.0 (tags/RELEASE_370/final)
Target: x86_64-w64-windows-gnu
Thread model: posix

うーん・・・・・・・・・。

Thieves of BeagleBoard: ARMクロスコンパイル用clang
こちらを見ると、llvmをビルドしているようなので、私もそうしよう。


http://llvm.org/releases/download.html#3.7.0

ここから、いりそうな気がするものをダウンロード。

  • LLVM
  • Clang
  • compiler-rt
  • LLD
  • LLDB

LLVMを解凍して、その中のtoolsフォルダ内に残りを解凍。
解凍した後、フォルダ名は変更するみたい(Interface誌を見て)。
そして、どこかに作業用のフォルダを掘って、そこに移動して、cmakeをたたく。

$ cd tools
$ 適当に解凍してリネーム
$ cd ..
$ mkdir build
$ cd build
$ cmake -Wno-dev ..

-Wno-devは、警告がうっとうしいので入れただけで、特に意味はない。
私の環境では、SWIGとlibxml2がなかったので、それも入れてやり直した。
Ocamlも見つからないと言われたけど、インストールしたんだけどなぁ。
そこは無視したが、最後に「done」と出てきたのでよしとする。

「done」したけど、どうしていいのかわからん・・・。
http://llvm.org/docs/CMake.html
ここを見ると、--buildしているので、まねしよう。

$ cmake --build .

時間がかかりそう。
オプションで、ビルド対象のターゲットを指定できるみたいだから、それをした方がよかったのかも。
それと、今回はnRF51822で使うつもりだから、C++はいらないのだな。


えーっと、約3時間半ビルドして、エラーが発生しました。。。

  1: Scanning dependencies of target lldbTarget
  2: [ 71%] Building CXX object tools/lldb/source/Target/CMakeFiles/lldbTarget.dir/ABI.cpp.o
  3: /cygdrive/e/Temp/llvm-3.7.0.src/tools/lldb/source/Target/ABI.cpp:1:0: 警告: -fPIC はターゲットでは無視されます (全てのコー ドは位置非依存です)
  4:  //===-- ABI.cpp -------------------------------------------------*- C++ -*-===//
  5:  ^
  6: In file included from /cygdrive/e/Temp/llvm-3.7.0.src/tools/lldb/include/lldb/Target/Process.h:13:0,
  7:                  from /cygdrive/e/Temp/llvm-3.7.0.src/tools/lldb/include/lldb/Core/ValueObject.h:33,
  8:                  from /cygdrive/e/Temp/llvm-3.7.0.src/tools/lldb/include/lldb/Core/ValueObjectConstResult.h:17,
  9:                  from /cygdrive/e/Temp/llvm-3.7.0.src/tools/lldb/source/Target/ABI.cpp:13:
 10: /cygdrive/e/Temp/llvm-3.7.0.src/tools/lldb/include/lldb/Host/Config.h:39:2: エラー: #error undefined platform
 11:  #error undefined platform
 12:   ^
 13: In file included from /cygdrive/e/Temp/llvm-3.7.0.src/tools/lldb/include/lldb/Core/Communication.h:23:0,
 14:                  from /cygdrive/e/Temp/llvm-3.7.0.src/tools/lldb/include/lldb/Target/Process.h:28,
 15:                  from /cygdrive/e/Temp/llvm-3.7.0.src/tools/lldb/include/lldb/Core/ValueObject.h:33,
 16:                  from /cygdrive/e/Temp/llvm-3.7.0.src/tools/lldb/include/lldb/Core/ValueObjectConstResult.h:17,
 17:                  from /cygdrive/e/Temp/llvm-3.7.0.src/tools/lldb/source/Target/ABI.cpp:13:
 18: /cygdrive/e/Temp/llvm-3.7.0.src/tools/lldb/include/lldb/Host/HostThread.h:45:5: エラー: ‘HostNativeThread’ does not name a type
 19:      HostNativeThread &GetNativeThread();
 20:      ^
 21: /cygdrive/e/Temp/llvm-3.7.0.src/tools/lldb/include/lldb/Host/HostThread.h:46:11: エラー: ‘HostNativeThread’ does not name a type
 22:      const HostNativeThread &GetNativeThread() const;
 23:            ^
 24: cc1plus: 警告: 認識できないコマンドラインオプション "-Wno-deprecated-register" です
 25: tools/lldb/source/Target/CMakeFiles/lldbTarget.dir/build.make:62: ターゲット 'tools/lldb/source/Target/CMakeFiles/lldbTarget.dir/ABI.cpp.o' のレシピで失敗しました
 26: make[2]: *** [tools/lldb/source/Target/CMakeFiles/lldbTarget.dir/ABI.cpp.o] エラー 1
 27: CMakeFiles/Makefile2:29330: ターゲット 'tools/lldb/source/Target/CMakeFiles/lldbTarget.dir/all' のレシピで失敗しました
 28: make[1]: *** [tools/lldb/source/Target/CMakeFiles/lldbTarget.dir/all] エラー 2
 29: Makefile:149: ターゲット 'all' のレシピで失敗しました
 30: make: *** [all] エラー 2

うーん、undefined platformが効いてるのかな。
tools/lldb/include/lldb/Host/Config.hを見てみよう。

__APPLE__
__ANDROID_NDK__
__linux__ || __GNU__
__FreeBSD__ || __FreeBSD_kernel__ || __OpenBSD__ || __NetBSD__
__MINGW__ || __MINGW32__
_MSC_VER

えっ、cygwinって__GNU__は持ってないの??

それに、LLDBってLLVMのシンボリックデバッガらしいではないか。
なくてもよいんでないか?
tools/CMakeLists.txtの最後にlldbが入ってるけど・・・

lldbフォルダを別の名前にして、ビルドし直し。


あれから5時間経ちました・・・。
CPUにもメモリにもタスクマネージャー上は余裕があるのだけど、ディスクがぐりぐり動いていて、そしてエラーです。

[ 67%] Linking CXX executable ../../../../bin/clang.exe
../../../../lib/libclangStaticAnalyzerCheckers.a(VLASizeChecker.cpp.o): シンボルを読み込むことができませんでした: Memory exhausted
collect2: エラー: ld はステータス 1 で終了しました
tools/clang/tools/driver/CMakeFiles/clang.dir/build.make:309: ターゲット 'bin/clang-3.7.exe' のレシピで失敗しました
make[2]: *** [bin/clang-3.7.exe] エラー 1
CMakeFiles/Makefile2:19960: ターゲット 'tools/clang/tools/driver/CMakeFiles/clang.dir/all' のレシピで失敗しました
make[1]: *** [tools/clang/tools/driver/CMakeFiles/clang.dir/all] エラー 2
Makefile:149: ターゲット 'all' のレシピで失敗しました
make: *** [all] エラー 2

ディスクの空きもあるのだけど、とりあえずPCを再起動しないと身動きが取れないです。
くそう、こっちも失敗かー。

0 件のコメント:

コメントを投稿

コメントありがとうございます。
スパムかもしれない、と私が思ったら、
申し訳ないですが勝手に削除することもあります。

注: コメントを投稿できるのは、このブログのメンバーだけです。