インストール - LLVM
概要
LLVMプロジェクトは、モジュール化され再利用可能なコンパイラとツールチェイン技術の集合体である。
イリノイ大学の研究プロジェクトとして始まり、任意のプログラミング言語の静的 / 動的コンパイルをサポートできる、SSAベースの近代的なコンパイル戦略を提供することを目的としていた。
その後、LLVMは多くのサブプロジェクトからなるアンブレラプロジェクトに成長して、その多くは、学術研究において広く利用されるだけでなく、様々な商用およびオープンソースプロジェクトによって稼働している。
LLVMの主なサブプロジェクトを、以下に示す。
- LLVMコアライブラリ
- ソースコードやターゲットに依存しない最新のオプティマイザと、多くの一般的なCPUに対応したコード生成機能を提供する。
- これらのライブラリは、LLVM中間表現(LLVM IR)として知られる指定されたコード表現を中心に構築されている。
- LLVMコアライブラリは文書化されており、LLVMをオプティマイザやコード生成器として使用するための独自の言語の考案(または既存のコンパイラの移植)が容易である。
- Clang
- LLVMネイティブのC / C++ / Objective-Cコンパイラにおいて、速いコンパイル、非常に有用なエラーと警告メッセージ、優れたソースレベルツールを構築するためのプラットフォームを提供することを目的としている。
- Clang Static Analyzerとclang-tidyは、コードのバグを自動的に見つけるツールであり、C / C++コードを解析するライブラリとしてClangフロントエンドを使用して構築できる。
- libc++およびlibc++ ABIプロジェクト
- libc++およびlibc++ ABIプロジェクトは、LLVMプロジェクトの重要な部分を構成している。
- これらは、C++標準ライブラリの実装を提供することを目的としている。
- libc++は、C++標準ライブラリの実装そのものを指す。
- このプロジェクトは、C++ 11やC++ 14といった比較的新しい規格を含む、C++言語標準に完全に準拠することを目指している。
- 同時に、高性能な実装を提供することも重視しており、効率的なコード生成と実行時のパフォーマンスの両立を図っている。
- 一方、libc++ ABIは、Application Binary Interfaceの実装を担当する。
- ABIは、コンパイルされたプログラムの各部分が互いにどのように相互作用するかを定義する低レベルの仕様である。
- libc++ ABIは、libc++と密接に連携して動作し、異なるコンパイラや異なるバージョンのライブラリ間での互換性を確保する重要な役割を果たす。
- これらのプロジェクトの主な目標には、ポータビリティの向上、異なるプラットフォーム間での一貫性の確保、そして最新のC++機能のサポートが含まれる。
- また、オープンソースコミュニティの貢献を積極的に受け入れ、継続的な改善と拡張を行っている。
- libc++とlibc++ ABIは、特にClangコンパイラと組み合わせて使用されることが多いが、他のコンパイラでも利用可能である。
- これらのプロジェクトは、C++開発者に信頼性の高い、最新の標準に準拠したツールセットを提供することにより、C++エコシステム全体の発展に貢献している。
- compiler-rtプロジェクト
- compiler-rtは、LLVMプロジェクトの重要なサブプロジェクトの1つである。
- その主な目的は、コンパイラがターゲットマシン上で効率的に動作するために必要な低レベルのサポート機能を提供することである。
- compiler-rtは、__fixunsdfdi等の低レベルコードジェネレータサポートルーチンや、
- ターゲットがコアIR操作を実装するための短いネイティブ命令列を持っていない場合に発生するその他のコールの高度に調整された実装を提供している。
- これらのルーチンは、特定のハードウェアアーキテクチャで直接サポートされていない操作を実行するために使用される。
- 例えば、64ビット整数演算が32ビットプロセッサ上で必要な場合、compiler-rtがその実装を提供する。
- また、compiler-rtは様々なサニタイザと呼ばれる動的テストツールのランタイムライブラリも実装している。
- これらのツールは、メモリエラー、データ競合、未定義動作等のバグを検出するのに役立つ。
- また、AddressSanitizer、ThreadSanitizer、MemorySanitizer、DataFlowSanitizer等の動的テストツールのランタイムライブラリの実装を提供しており、
- これらはプログラムの実行時に問題を検出し報告する。
- compiler-rtの重要な特徴の1つは、その移植性である。
- 様々なアーキテクチャとOSに対応するように設計されており、LLVMベースのコンパイラがさまざまなプラットフォームで効率的に動作することを可能にしている。
- さらに、compiler-rtはプロファイリングやコードカバレッジツールのサポートも提供している。
- これらは、プログラムのパフォーマンス分析やテストの品質向上に役立つ。
- compiler-rtは非常に最適化された実装を提供することにより、生成されるコードの効率を高める。
- これは特に、組み込みシステムや高性能コンピューティング等、パフォーマンスが重要な分野で重要である。
- compiler-rtプロジェクトは、LLVMエコシステムの中で重要な役割を果たしており、高品質で効率的なコード生成を可能にする基盤となっている。
- MLIRサブプロジェクト
- MLIR (Multi-Level Intermediate Representation) は、LLVMプロジェクトの一部として開発された革新的なコンパイラインフラストラクチャである。
- 再利用可能で拡張性のあるコンパイラ基盤を構築するための新しいアプローチである。
- MLIRは、ソフトウェアの断片化の対処、異種ハードウェアに対するコンパイルの改善、ドメイン固有のコンパイラを構築するコストを大幅に削減する等、既存のコンパイラの接続を支援することを目的としている。
- MLIRの特徴的な点は、その柔軟性と拡張性にある。
- 従来のコンパイラインフラストラクチャとは異なり、MLIRは単一の固定された中間表現 (IR) を使用するのではなく、多様なレベルの抽象化を表現できる枠組みを提供する。
- これにより、高レベルの言語構造から低レベルのハードウェア固有の命令まで、幅広い抽象化レベルを扱うことができる。
- この柔軟性により、MLIRは様々な用途に適用可能である。
- 例えば、機械学習フレームワークの最適化、ハードウェアアクセラレータ向けのコード生成、ドメイン固有言語 (DSL) の実装等に活用されている。
- MLIRの重要な概念の1つに "方言 (Dialect)" がある。
- これは特定のドメインや抽象化レベルに特化したIRの集合で、開発者は自身のニーズに合わせて新しい方言を定義できる。
- この機能により、MLIRは様々な分野やハードウェアに対して高度にカスタマイズ可能となっている。
- また、MLIRは既存のコンパイラインフラストラクチャとの統合も容易である。
- LLVM、GCC、カスタムバックエンドとも連携できるよう設計されている。
- これにより、既存のツールチェーンを活用しつつ、新しい最適化や変換を導入することが可能になる。
- MLIRプロジェクトは活発に開発が進められており、コンパイラ技術の未来を形作る重要な役割を果たしている。
- 特に、異種コンピューティングの時代において、MLIRの柔軟性と拡張性は非常に価値があると考えられている。
- OpenMPサブプロジェクト
- ClangのOpenMP実装で使用するためのOpenMPランタイムを提供する。
- pollyプロジェクト
- 多面体モデルを用いて、自動並列化やベクトル化だけでなく、キャッシュローカリティ最適化のスイートも実装している。
- libclcプロジェクト
- OpenCL標準ライブラリの実装を目的としている。
- KLEEプロジェクト
- KLEEプロジェクトは、LLVMのサブプロジェクトとして開発された強力なシンボリック実行エンジンであり、
- ソフトウェアの品質と信頼性を向上させるための強力なツールである。
- その名前は、"Kleene Symbolic Execution Engine" に由来している。
- KLEEの主な目的は、プログラムの自動テストと検証を行うことである。
- これを実現するために、KLEEはプログラムのすべての可能な実行パスを探索し、各パスの条件を分析する。
- この過程で、バグや潜在的な問題を特定して、それらを再現するためのテストケースを自動生成する。
- KLEEの動作原理は、プログラムの入力をシンボリック (抽象的) な値として扱うことにある。
- これにより、具体的な入力値を使用する通常のテストよりも、はるかに広範囲のプログラム動作を分析することができる。
- KLEEの特筆すべき機能として、高カバレッジのテストケース生成がある。
- KLEEはバグを発見した時、KLEEはそのバグを再現するための具体的な入力値を提供する。
- これは開発者にとって非常に有用であり、バグの修正と検証を容易することが可能である。
- 定理証明器を用いてプログラムの動的パスの評価を行い、バグの発見や関数の性質を証明する"記号的仮想機械"を実装している。
- また、KLEEは単にバグを見つけるだけでなく、プログラムの正確性を証明するためにも使用できる。
- 特定の条件下でプログラムが正しく動作することを形式的に検証することが可能である。
- KLEEの応用範囲は広く、システムソフトウェア、組み込みシステム、セキュリティ重視のアプリケーション等、高い信頼性が要求される分野で特に有効である。
- ただし、KLEEの使用には一定の必要であり、また、複雑なプログラムや大規模なコードベースに対しては計算コストが高くなる可能性がある。
- LLDプロジェクト
- LLD (LLVM Linker) は、indeed、LLVMプロジェクトの一部として開発されているリンカである。
- その主な目的は、既存のシステムリンカのドロップイン置き換えで、高速な代替品となることである。
- モジュール性、柔軟性、そして何よりも速度に重点を置いて設計されています。
- LLDの特徴の1つは、その速度である。
- 従来のリンカと比較して、LLDは非常に高速に動作する。
- これは特に大規模なプロジェクトや頻繁な再コンパイルが必要な開発環境で重要である。
- また、LLDはクロスプラットフォーム対応を強く意識しており、
- Windows、MacOS、Linux等の主要なOSに対応しており、各プラットフォーム固有のオブジェクトファイル形式やバイナリ形式を扱うことができる。
- さらに、LLDはLLVMのエコシステムと緊密に統合されており、
- LLVMの他のツールやライブラリとシームレスに連携することができ、効率的なツールチェーンの構築が可能になる。
- LLDの設計は、モジュール性を重視しており、新しいターゲットや機能の追加が容易になり、メンテナンス性も向上している。
- LLDプロジェクトはLLVMエコシステムの重要な構成要素として、高速で効率的なリンク処理を提供することを目指している。
- BOLTプロジェクト
- BOLT (Binary Optimization and Layout Tool) は、ポストリンクオプティマイザであり、実行プロファイルを利用してコードレイアウトを最適化することで性能向上を図る。
- BOLTの主な特徴は、既にコンパイルされたバイナリに対して最適化を行うことである。
- これにより、コンパイル時には予測できなかった実行時の挙動を考慮した最適化が可能になる。
- 最適化のプロセスを以下に示す。
- (サンプリングプロファイラで収集した実行プロファイルをもとに、ソフトウェアのコードレイアウトを最適化することにより、高速化を実現する)
- まず、対象のバイナリを実行環境で動作させ、サンプリングプロファイラを使用して実行プロファイルを収集する。
- 次に、BOLTがこのプロファイル情報を解析して、頻繁に実行される関数やコードパスを特定する。
- そして、これらの情報をもとに、ホットなコードパスを近接して配置したり、コールドなコードを別の場所に移動したりすることにより、キャッシュの効率性を向上させる。
- BOLTのメリットとして、コンパイラの最適化とは独立して動作するため、既存のビルドプロセスを大きく変更することなく適用できる点がである。
- また、様々なアーキテクチャやコンパイラに対応しているため、幅広い環境で利用可能である。
- 実際の性能改善効果は、アプリケーションの特性やワークロードによって異なるが、大規模なサーバアプリケーション等では数パーセントから10%以上の速度向上が報告されている。
- 大規模なソフトウェアシステムの性能向上を目指す場合は、特に有用なツールである。
LLVMツールチェーン と GNUツールチェーンの比較
| 項目 | LLVM | GNU |
|---|---|---|
| コンパイラ フロントエンド |
Clang (C言語) Clang++ (C++言語) |
gcc (C言語) g++ (C++言語) |
| コンパイラ バックエンド |
LLVM (中間表現処理・最適化・コード生成) |
GCCバックエンド (GCC内部に組み込まれている) |
| アセンブラ | llvm-as | as (GNU Assembler) |
| リンカ | lld (LLVM Linker) | ld (GNU Linker) |
| その他ツール | llvm-objdump, llvm-ar, llvm-nm など | objdump, ar, nm など (binutilsに含まれる) |
| 設計思想 | モジュール化・ライブラリ指向 再利用可能 |
統合的・密結合 |
| 他言語での利用 | Rust, Swift, Julia など 多数の言語で採用 |
主にC/C++/Fortran系 |
| ステップ | LLVMツールチェーン | GNUツールチェーン |
|---|---|---|
| 入力 | ソースコード (.c, .cpp) | |
| ① 解析 | Clang / Clang++ 字句・構文・意味解析 |
gcc / g++ 字句・構文・意味解析 |
| ② 中間表現 | LLVM IR 中間表現形式 |
gcc内部形式 RTL/GIMPLE |
| ③ 最適化 | LLVM Optimizer 各種最適化パス |
gcc最適化 内部で最適化処理 |
| ④ コード生成 | LLVM Backend 機械語生成 |
gcc Backend 機械語生成 |
| ⑤ アセンブル | llvm-as LLVM Assembler |
as GNU Assembler |
| 中間生成物 | オブジェクトファイル (.o) | |
| ⑥ リンク | lld LLVM Linker |
ld GNU Linker |
| 出力 | 実行ファイル (a.out, .exe等) | |
- LLVM
- 各段階が独立したモジュールとして動作し、LLVM IRという共通の中間表現を使用
- GNU
- フロントエンドからバックエンドまでgccの中で統合的に処理される
LLVMのインストール
パッケージ管理システムからインストール
sudo zypper install llvm llvm-gold llvm-polly clang lldb lld
ソースコードからインストール
LLVMのインストールに必要なライブラリをインストールする。
# SUSE
sudo zypper install git ncurses-devel isl-devel xz-devel libedit-devel libxml2-devel libbsd-devel lua53 lua53-devel \
python3 python3-devel python3-pyaml python3-Pygments \ # Python 3.6を使用する場合
python311 python311-devel python311-PyYAML python311-Pygments \ # Python 3.11を使用する場合
doxygen # ドキュメントをビルドする場合
LLVMのGithubから、LLVMのソースコードをダウンロードする。
ダウンロードするファイルは、llvm-project-<バージョン>.src.tar.xzである。
ダウンロードしたLLVMのソースコードを解凍する。
tar xf llvm-project-<バージョン>.src.tar.xz
LLVMのビルドディレクトリを作成する。
cd llvm-project mkdir build && cd build
LLVMをビルドおよびインストールする。
cmake -G "Unix Makefiles" \
-DCMAKE_C_COMPILER=<GCC 8以降のgccコンパイラのパス> -DCMAKE_CXX_COMPILER=<GCC 8以降のg++コンパイラのパス> \
-DLLVM_TARGETS_TO_BUILD="X86;ARM;AArch64;AVR;MSP430" \ # x86, x86-64, ARM, AArch64, MSP430, AVR向けのLLVMをビルドする場合(指定しない場合は全てのアーキテクチャ)
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_INSTALL_PREFIX=<LLVMのインストールディレクトリ> \
-DLLVM_ENABLE_RTTI=ON \
-DLLVM_ENABLE_PROJECTS="clang;clang-tools-extra;flang;libclc;lld;lldb;mlir;openmp;polly" \
-DLLVM_ENABLE_RUNTIMES="compiler-rt;libc;libcxx;libcxxabi;libunwind;openmp" \
../llvm
make -j $(nproc)
make install
# または
cmake -G Ninja \
-DCMAKE_C_COMPILER=<GCC 8以降のgccコンパイラのパス> -DCMAKE_CXX_COMPILER=<GCC 8以降のg++コンパイラのパス> \
-DLLVM_TARGETS_TO_BUILD="X86;AArch64" \ # x86, x86-64, AArch64向けのLLVMをビルドする場合(デフォルトは全てのアーキテクチャ)
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_INSTALL_PREFIX=<LLVMのインストールディレクトリ> \
-DLLVM_ENABLE_RTTI=ON \
-DLLVM_ENABLE_PROJECTS="clang;clang-tools-extra;flang;libclc;lld;lldb;mlir;polly" \
-DLLVM_ENABLE_RUNTIMES="compiler-rt;libc;libcxx;libcxxabi;libunwind;openmp" \
../llvm
ninja -j $(nproc)
ninja install
ビルド向けオプションは、以下の通りである。
- LLVM_TARGETS_TO_BUILD
- セミコロンで区切られたリストで、どのターゲットをビルドしてLLVMにリンクするかを制御する。
- デフォルト値は
LLVM_ALL_TARGETSとして定義され、ツリー外のターゲットを含むように設定できる。 - デフォルト値は、
ARM、AArch64、AMDGPU、AVR、BPF、Hexagon、Lanai、Mips、MSP430、NVPTX、PowerPC、RISCV、Sparc、SystemZ、WebAssembly、X86、XCoreである。 - このオプションの値を
hostと指定すると、ホストアーキテクチャのみがコンパイルされる。 - 例えば、x86ホストPCでX86を指定するのと同じである。
- PYTHON_EXECUTABLE
- Pythonへのパスを渡すことで、CMakeに特定のPythonのバージョンを使用する。
- デフォルトでは環境変数PATHにあるPythonが使用される。
- LLVM_TARGETS_TO_BUILD
- ビルドするターゲットを選択する。
- これは、LLVMにどのターゲットをリンクするかを制御するセミコロンで区切られたリストである。
- デフォルトは、LLVM_ALL_TARGETSとして定義されている。
- デフォルトでは、以下のターゲットが含まれる。
- AArch64, AMDGPU, ARM, AVR, BPF, Hexagon, Lanai, Mips, MSP430, NVPTX, PowerPC, RISCV, Sparc, SystemZ, WebAssembly, X86, XCore
- LLVM_ENABLE_DOXYGEN
- ソースコードからdoxygenベースのドキュメントをビルドする。
- これは多くの出力を生成するため、デフォルトでは無効になっている。
- LLVM_ENABLE_PROJECTS
- 他のLLVMサブプロジェクトの内、どのプロジェクトを追加でビルドするかをセミコロンで区切ったリストで指定する。
- デフォルトでは空のリストである。
- ビルドできるプロジェクトは、以下の通りである。
- clang、clang-tools-extra、compiler-rt、cross-project-tests、flang、libc、libclc、libcxx、libcxxabi、libunwind、lld、lldb、mlir、openmp、polly、pstl
- LLVM_ENABLE_SPHINX
- Sphinxベースのドキュメントをビルドする。
- これは多くの出力を生成するため、デフォルトでは無効になっている。
- Sphinx 1.5以降を推奨する。
- LLVM_BUILD_LLVM_DYLIB
- libLLVM.soを生成する。
- このライブラリには、LLVMコンポーネントのデフォルトセットが含まれており、LLVM_DYLIB_COMPONENTSでオーバーライドすることができる。
- デフォルトでは、ほとんどのLLVMが含まれており、tools/llvm-shlib/CMakelists.txtで定義されている。
- このオプションはWindowsでは使用できない。
- LLVM_OPTIMIZED_TABLEGEN
- リリーステーブル生成器を構築する。
LLVMのインストール完了後、~/.profileファイル等に環境変数を設定する。
# ~/.profileファイル
export PATH="/<LLVMのインストールディレクトリ>/bin:$PATH"
export LLVM_INSTALL_DIR="<LLVMのインストールディレクトリ>"
export LDFLAGS="-L/<LLVMのインストールディレクトリ>/lib" # 不要の可能性あり
export CPPFLAGS="-I/<LLVMのインストールディレクトリ>/include" # 不要の可能性あり
LLVMのクロスコンパイル
LLVMの実行ファイルやライブラリにおいて、ビルドされるプラットフォームとは異なるプラットフォームでホストするためにインストールすることができる。
クロスコンパイル向けのビルドファイルを生成するために、-DCMAKE_TOOLCHAIN_FILEオプションを、LLVMのインストール時に使用するコンパイラフラグや変数を定義することができる。
AArch64
以下の例では、x64のホストPCおよびAArch64のターゲットPCにおけるLLVMツールチェーンをビルドおよびインストールしている。
※注意
LLVM / Clangをビルドする段階では、AArch64のシステムルートをオプションとして追加する必要はない。
# ビルドディレクトリの作成
mkdir build && cd build
# CMakeの設定
cmake -G Ninja \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_INSTALL_PREFIX=<LLVMツールチェーンのインストールディレクトリ> \
-DLLVM_ENABLE_PROJECTS="clang;clang-tools-extra;lld" \
-DLLVM_TARGETS_TO_BUILD="X86;AArch64" \
-DLLVM_DEFAULT_TARGET_TRIPLE=aarch64-linux-gnu \
-DLLVM_ENABLE_LLD=ON \
-DLLVM_ENABLE_LIBCXX=OFF \
-DLLVM_ENABLE_ASSERTIONS=OFF \
-DLLVM_OPTIMIZED_TABLEGEN=ON \
-DLLVM_PARALLEL_LINK_JOBS=2 \
../llvm
# ビルド
ninja -j$(nproc)
# インストール
ninja install
- -DCMAKE_BUILD_TYPE=Release
- 開発用途であればRelWithDebInfoでもよい。
- -DLLVM_ENABLE_PROJECTS="clang;clang-tools-extra;lld"
- 必要なプロジェクトを指定する。
- lld (LLVMリンカー) はクロスコンパイルで必要となる。
- -DLLVM_TARGETS_TO_BUILD="X86;AArch64"
- ホスト (x64) と ターゲット (AArch64) の両方を含める。
- これにより、両方のアーキテクチャ用にコンパイルできる。
- -DLLVM_DEFAULT_TARGET_TRIPLE=aarch64-linux-gnu
- デフォルトのターゲットをAArch64に設定する。
- ただし、Qtのビルドシステムでは明示的に指定することが多いため、このオプションは任意である。
- -DLLVM_ENABLE_LLD=ON
- LLDリンカーを有効化する。
- これは、クロスリンク時に便利である。
- -DLLVM_OPTIMIZED_TABLEGEN=ON
- ビルド時間を短縮するための最適化
- -DLLVM_PARALLEL_LINK_JOBS=2
- リンク処理の並列数を制限する。
- メモリ不足を防ぐため、システムRAMが16[GB]未満の場合は1または2に設定することを推奨する。
ARM EABIHF
ABI / HF
ABIとは、コンパイルされたバイナリコード同士がどのように通信し合うかを定めるプロトコルである。
ABIは関数を呼び出す際にどのレジスタを使うか、引数をどの順序でスタックに積むか、戻り値をどこに格納するか、構造体のメモリ配置はどうするか、といった細かい取り決めを規定している。
異なるABIでコンパイルされたライブラリとプログラムは、例え同じCPUアーキテクチャであっても正しく連携できない。
Hard Float ABIでは、浮動小数点演算の結果を浮動小数点専用のレジスタ (VFPレジスタ) を使用して関数間で受け渡す。
EABIHFは32ビットARM用のABIである。
- Raspberry Pi OS 32ビットでは、ARMv8でもEABIHF (hard-float) が使用可能。
- Raspberry Pi OS 64ビットでは、AAPCS64 (ARM Architecture Procedure Call Standard 64-bit) という別のABIを使用。
VFPレジスタ
Raspberry Pi 4以降でもVFPレジスタは存在するが、実装が進化している。
- ARMv7以前 (Raspberry Pi 2 / 3等)
- VFP (Vector Floating Point) が独立したコプロセッサ
- VFPv3 / VFPv4として実装
- NEONと一部統合
- ARMv8-A (Raspberry Pi 4以降)
- 浮動小数点とSIMDが完全に統合
- 32個の128ビットレジスタ (V0-V31) として実装
- これらは以下のようにアクセス可能である。
- 64ビット浮動小数点 : D0-D31
- 32ビット浮動小数点 : S0-S31
- 128ビットSIMD:V0-V31 (NEON)
32 / 64ビットで、利用できる機能やABIが異なるが、いずれにおいても浮動小数点演算用のレジスタは存在し、ハードウェアアクセラレーションが利用できる。
ビルド / インストール
mkdir build && cd build
cmake -G Ninja \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_INSTALL_PREFIX=<LLVMツールチェーンのインストールディレクトリ> \
-DLLVM_ENABLE_PROJECTS="clang;clang-tools-extra;lld" \
-DLLVM_TARGETS_TO_BUILD="X86;ARM;AArch64" \
-DLLVM_DEFAULT_TARGET_TRIPLE=arm-linux-gnueabihf \
-DLLVM_ENABLE_LLD=ON \
-DLLVM_ENABLE_LIBCXX=OFF \
-DLLVM_ENABLE_ASSERTIONS=OFF \
-DLLVM_OPTIMIZED_TABLEGEN=ON \
-DLLVM_PARALLEL_LINK_JOBS=2 \
../llvm
ninja -j $(nproc)
ninja install
Hard Float ABI用のCMakeツールチェーンファイルの例を以下に示す。
# ターゲットシステムの設定
set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_SYSTEM_PROCESSOR arm)
# システムルートのパス (Hard Float ABI用のシステムルート)
set(CMAKE_SYSROOT <Hard Float ABI用のシステムルートのフルパス>)
# LLVMツールチェーンのパス
set(LLVM_PATH <LLVMツールチェーンのインストールディレクトリ>)
# コンパイラの指定
set(CMAKE_C_COMPILER ${LLVM_PATH}/bin/clang)
set(CMAKE_CXX_COMPILER ${LLVM_PATH}/bin/clang++)
# ターゲットトリプルの設定
# Hard Float ABIを使用するため、末尾に"hf"を追加
set(CMAKE_C_COMPILER_TARGET arm-linux-gnueabihf)
set(CMAKE_CXX_COMPILER_TARGET arm-linux-gnueabihf)
# 検索パスの設定
set(CMAKE_FIND_ROOT_PATH ${CMAKE_SYSROOT})
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)
# コンパイラフラグの設定
# Hard Float ABIを明示的に指定し、適切なFPUも指定する
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -march=armv8-a -mfpu=neon-vfpv4 -mfloat-abi=hard")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=armv8-a -mfpu=neon-vfpv4 -mfloat-abi=hard")
# リンカーフラグ
# ライブラリパスをHard Float ABI用のディレクトリに変更
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-rpath-link,${CMAKE_SYSROOT}/lib/arm-linux-gnueabihf")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-rpath-link,${CMAKE_SYSROOT}/usr/lib/arm-linux-gnueabihf")
ARM EABI
Soft Float ABIでは、浮動小数点の値も汎用レジスタを使って受け渡す。
Soft Float ABIが必要になる場面は、古いARMプロセッサやFPU (浮動小数点演算ユニット) を持たない組み込みシステムである。
ARMv5 や ARMv6の一部のバリアント、コスト重視の産業用制御システムなどがこのカテゴリに入る。
これらのシステムでは、浮動小数点演算は全てソフトウェアでエミュレートされるため、VFPレジスタを使った受け渡しができない。
ただし、FPUを持つプロセッサであっても、Soft Float ABIでコンパイルすることは可能である。
この場合、FPUは利用されず全ての浮動小数点演算がソフトウェアで処理される。
これは、既存のSoft Float ABI用のライブラリとの互換性を保ちたい場合等に用いられる。
mkdir build && cd build
cmake -G Ninja \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_INSTALL_PREFIX=<LLVMツールチェーンのインストールディレクトリ> \
-DLLVM_ENABLE_PROJECTS="clang;clang-tools-extra;lld" \
-DLLVM_TARGETS_TO_BUILD="X86;ARM;AArch64" \
-DLLVM_DEFAULT_TARGET_TRIPLE=arm-linux-gnueabi \
-DLLVM_ENABLE_LLD=ON \
-DLLVM_ENABLE_LIBCXX=OFF \
-DLLVM_ENABLE_ASSERTIONS=OFF \
-DLLVM_OPTIMIZED_TABLEGEN=ON \
-DLLVM_PARALLEL_LINK_JOBS=2 \
../llvm
ninja -j $(nproc)
ninja install
Soft Float ABI用のCMakeツールチェーンファイルの例を以下に示す。
# ターゲットシステムの設定
set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_SYSTEM_PROCESSOR arm)
# システムルートのパス (Soft Float ABI用のシステムルート)
set(CMAKE_SYSROOT <Soft Float ABI用のシステムルートのフルパス>)
# LLVMツールチェーンのパス
set(LLVM_PATH <LLVMツールチェーンのインストールディレクトリ>)
# コンパイラの指定
set(CMAKE_C_COMPILER ${LLVM_PATH}/bin/clang)
set(CMAKE_CXX_COMPILER ${LLVM_PATH}/bin/clang++)
# ターゲットトリプルの設定
set(CMAKE_C_COMPILER_TARGET arm-linux-gnueabi)
set(CMAKE_CXX_COMPILER_TARGET arm-linux-gnueabi)
# 検索パスの設定
set(CMAKE_FIND_ROOT_PATH ${CMAKE_SYSROOT})
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)
# コンパイラフラグの設定
# Soft Float ABIを明示的に指定する
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -march=armv7-a -mfloat-abi=softfp")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=armv7-a -mfloat-abi=softfp")
# リンカーフラグ
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-rpath-link,${CMAKE_SYSROOT}/lib/arm-linux-gnueabi")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-rpath-link,${CMAKE_SYSROOT}/usr/lib/arm-linux-gnueabi")