LLVMシステム入門

概要

LLVMプロジェクトへようこそ!

LLVMプロジェクトには複数のコンポーネントがあります。プロジェクトのコア自体は「LLVM」と呼ばれています。これには、中間表現を処理し、それをオブジェクトファイルに変換するために必要なすべてのツール、ライブラリ、ヘッダーファイルが含まれています。ツールには、アセンブラ、逆アセンブラ、ビットコードアナライザー、およびビットコードオプティマイザーが含まれます。また、基本的な回帰テストも含まれています。

Cのような言語は、Clangフロントエンドを使用します。このコンポーネントは、C、C ++、Objective C、およびObjective C ++コードをLLVMビットコードにコンパイルし、そこからLLVMを使用してオブジェクトファイルにコンパイルします。

他のコンポーネントには、libc++ C++標準ライブラリLLDリンカーなどがあります。

ソースコードの取得とLLVMのビルド

  1. LLVM(Clangなどのサブプロジェクトを含む)をチェックアウトします

    • git clone https://github.com/llvm/llvm-project.git

    • または、Windowsの場合

      git clone --config core.autocrlf=false https://github.com/llvm/llvm-project.git

    • ストレージを節約し、チェックアウト時間を短縮するために、shallow cloneを実行することをお勧めします。たとえば、LLVMプロジェクトの最新リビジョンを取得するには、次を使用します。

      git clone --depth 1 https://github.com/llvm/llvm-project.git

    • リポジトリのユーザーブランチ(積み重ねられたプルリクエストと元に戻すために使用)に関心がない可能性があります。この構成を使用すると、git fetch(またはgit pull)からそれらをフィルター処理できます。

git config --add remote.origin.fetch '^refs/heads/users/*'
git config --add remote.origin.fetch '^refs/heads/revert-*'
  1. LLVMとClangを構成およびビルドします

    • cd llvm-project

    • cmake -S llvm -B build -G <generator> [options]

      一般的なビルドシステムジェネレータは次のとおりです

      • NinjaNinjaビルドファイルを生成するため。ほとんどのllvm開発者はNinjaを使用しています。

      • Unix Makefiles — make互換の並列makeファイルを生成するため。

      • Visual Studio — Visual Studioプロジェクトとソリューションを生成するため。

      • Xcode — Xcodeプロジェクトを生成するため。

      • より包括的なリストについては、CMakeドキュメントを参照してください。

      一般的なオプション

      • -DLLVM_ENABLE_PROJECTS='...' — 追加でビルドしたいLLVMサブプロジェクトのセミコロン区切りのリスト。clang、clang-tools-extra、lldb、lld、polly、またはcross-project-testsのいずれかを含めることができます。

        たとえば、LLVM、Clang、およびLLDをビルドするには、-DLLVM_ENABLE_PROJECTS="clang;lld"を使用します。

      • -DCMAKE_INSTALL_PREFIX=directory — LLVMツールとライブラリをインストールする場所のフルパス名をdirectoryに指定します(デフォルトは/usr/local)。

      • -DCMAKE_BUILD_TYPE=type — ビルドの最適化レベルとデバッグ情報を制御します。typeの有効なオプションは、DebugReleaseRelWithDebInfo、およびMinSizeRelです。詳細については、CMAKE_BUILD_TYPEを参照してください。

      • -DLLVM_ENABLE_ASSERTIONS=ON — アサーションチェックを有効にしてコンパイルします(デフォルトはデバッグビルドではON、他のすべてのビルドタイプではOFFです)。

      • -DLLVM_USE_LINKER=lld — システムにインストールされていることを前提として、lldリンカーでリンクします。これにより、デフォルトのリンカーが遅い場合、リンク時間を大幅に短縮できます。

      • -DLLVM_PARALLEL_{COMPILE,LINK,TABLEGEN}_JOBS=N — 同時に並列で実行するコンパイル/リンク/tablegenジョブの数を制限します。リンクは多くのメモリを使用する可能性があるため、これは特に重要です。LLVMのビルド中にメモリの問題が発生した場合は、これを設定して、同時に実行するコンパイル/リンク/tablegenジョブの最大数を制限してみてください。

    • cmake --build build [--target <target>]または、上記のビルドシステムを直接指定します。

      • デフォルトのターゲット(つまり、cmake --build buildまたはmake -C build)は、すべてのLLVMをビルドします。

      • check-allターゲット(つまり、ninja check-all)は、すべてが正常に動作していることを確認するために回帰テストを実行します。

      • CMakeは、各ツールとライブラリのビルドターゲットを生成し、ほとんどのLLVMサブプロジェクトは独自のcheck-<project>ターゲットを生成します。

      • シリアルビルドの実行は遅くなります。速度を向上させるには、並列ビルドを実行してみてください。これはNinjaではデフォルトで行われます。makeの場合は、オプション-j NNを使用します。ここで、NNは並列ジョブの数、たとえば、利用可能なCPUの数です。

    • LLVMのみをビルドし、他のサブプロジェクトをビルドしない基本的なCMakeとビルド/テストの呼び出し

      cmake -S llvm -B build -G Ninja -DCMAKE_BUILD_TYPE=Debug

      ninja -C build check-llvm

      これにより、デバッグ情報を使用してLLVMビルドが設定され、LLVMがコンパイルされてLLVMテストが実行されます。

    • CMakeオプションの詳細については、CMakeを参照してください

    • ビルドまたはテストの失敗が発生した場合は、下記を参照してください。

LLVMの構成とコンパイルの詳細については、「LLVM入門」セクションを参照してください。ソースコードツリーのレイアウトについては、「ディレクトリレイアウト」を参照してください。

スタンドアロンビルド

スタンドアロンビルドを使用すると、システムに既に存在する、事前にビルドされたclangまたはllvmライブラリに対してサブプロジェクトをビルドできます。

(上記のように)llvm-projectの標準チェックアウトからのソースコードを使用してスタンドアロンビルドを実行できますが、sparse checkoutまたはリリースページで入手可能なtarballからビルドすることもできます。

スタンドアロンビルドの場合、他のプロジェクトのスタンドアロンビルドで消費できるように適切に構成されたllvmインストールが必要です。これはディストリビューションが提供するLLVMインストールである可能性があります。または、次のように自分でビルドすることもできます。

cmake -G Ninja -S path/to/llvm-project/llvm -B $builddir \
      -DLLVM_INSTALL_UTILS=ON \
      -DCMAKE_INSTALL_PREFIX=/path/to/llvm/install/prefix \
      < other options >

ninja -C $builddir install

llvmがインストールされたら、スタンドアロンビルド用にプロジェクトを構成するには、次のようにCMakeを呼び出します。

cmake -G Ninja -S path/to/llvm-project/$subproj \
      -B $buildir_subproj \
      -DLLVM_EXTERNAL_LIT=/path/to/lit \
      -DLLVM_ROOT=/path/to/llvm/install/prefix

注意点:

  • スタンドアロンビルドは、LLVMNがビルドされた元のフォルダではないフォルダで実行する必要があります($builddir!=$builddir_subproj)。

  • LLVM_ROOTはllvmインストールのプレフィックスを指す必要があります。たとえば、llvmが/usr/bin/usr/lib64にインストールされている場合は、-DLLVM_ROOT=/usr/を渡す必要があります。

  • LLVM_ROOTオプションとLLVM_EXTERNAL_LITオプションの両方が、すべてのサブプロジェクトのスタンドアロンビルドを実行するために必要です。各サブプロジェクトに必要な追加オプションは、以下の表に記載されています。

以下の表にリストされているサブプロジェクトでは、check-$subprojビルドターゲットとinstallビルドターゲットがサポートされています。

サブプロジェクト

必須のサブディレクトリ

必須のCMakeオプション

llvm

llvm、cmake、third-party

LLVM_INSTALL_UTILS=ON

clang

clang、cmake

CLANG_INCLUDE_TESTS=ON(check-clangのみに必要)

lld

lld, cmake

スタンドアロンのclangをビルドする例

#!/bin/sh

build_llvm=`pwd`/build-llvm
build_clang=`pwd`/build-clang
installprefix=`pwd`/install
llvm=`pwd`/llvm-project
mkdir -p $build_llvm
mkdir -p $installprefix

cmake -G Ninja -S $llvm/llvm -B $build_llvm \
      -DLLVM_INSTALL_UTILS=ON \
      -DCMAKE_INSTALL_PREFIX=$installprefix \
      -DCMAKE_BUILD_TYPE=Release

ninja -C $build_llvm install

cmake -G Ninja -S $llvm/clang -B $build_clang \
      -DLLVM_EXTERNAL_LIT=$build_llvm/utils/lit \
      -DLLVM_ROOT=$installprefix

ninja -C $build_clang

要件

LLVMシステムを使い始める前に、以下の要件を確認してください。必要なハードウェアとソフトウェアを事前に知っておくことで、トラブルを回避できる可能性があります。

ハードウェア

LLVMは以下のホストプラットフォームで動作することが知られています

OS

アーキテクチャ

コンパイラ

Linux

x861

GCC、Clang

Linux

amd64

GCC、Clang

Linux

ARM

GCC、Clang

Linux

Mips

GCC、Clang

Linux

PowerPC

GCC、Clang

Linux

SystemZ

GCC、Clang

Solaris

V9 (Ultrasparc)

GCC

DragonFlyBSD

amd64

GCC、Clang

FreeBSD

x861

GCC、Clang

FreeBSD

amd64

GCC、Clang

NetBSD

x861

GCC、Clang

NetBSD

amd64

GCC、Clang

OpenBSD

x861

GCC、Clang

OpenBSD

amd64

GCC、Clang

macOS2

PowerPC

GCC

macOS

x86

GCC、Clang

Cygwin/Win32

x861, 3

GCC

Windows

x861

Visual Studio

Windows x64

x86-64

Visual Studio

  1. Pentiumプロセッサ以上でコード生成がサポートされています

  2. 32ビットABIのみでコード生成がサポートされています

  3. Win32ベースのシステムでLLVMモジュールを使用するには、-DBUILD_SHARED_LIBS=Onを指定してLLVMを構成できます。

デバッグビルドには多くの時間とディスク容量が必要であることに注意してください。LLVMのみのビルドでは、約1〜3 GBの容量が必要です。LLVMとClangのフルビルドでは、約15〜20 GBのディスク容量が必要です。必要な正確な容量はシステムによって異なります。(これは、すべてのデバッグ情報と、ライブラリが複数のツールに静的にリンクされているためです)。

ディスク容量が限られている場合は、選択したツールまたは選択したターゲットのみをビルドできます。リリースビルドでは、必要な容量が大幅に少なくなります。

LLVMスイートは他のプラットフォームでもコンパイルできる可能性がありますが、保証されているわけではありません。コンパイルが成功した場合、LLVMユーティリティは、LLVMビットコードのアセンブル、逆アセンブル、分析、および最適化ができるはずです。コード生成も同様に機能するはずですが、生成されたネイティブコードはプラットフォームでは機能しない場合があります。

ソフトウェア

LLVMをコンパイルするには、いくつかのソフトウェアパッケージがインストールされている必要があります。以下の表は、必要なパッケージを示しています。「パッケージ」列は、LLVMが依存するソフトウェアパッケージの一般的な名前です。「バージョン」列には、パッケージの「動作することが確認されている」バージョンが示されています。「注記」列には、LLVMがパッケージを使用する方法やその他の詳細が記載されています。

パッケージ

バージョン

注記

CMake

>=3.20.0

Makefile/ワークスペースジェネレーター

python

>=3.8

自動テストスイート1

zlib

>=1.2.3.4

圧縮ライブラリ2

GNU Make

3.79, 3.79.1

Makefile/ビルドプロセッサ3

PyYAML

>=5.1

ヘッダージェネレーター4

  1. llvm/testディレクトリで自動テストスイートを実行する場合、またはPythonライブラリ、ユーティリティ、またはバインディングを利用する場合は、このソフトウェアが必要になります。

  2. オプション。選択したLLVMツールに圧縮/解凍機能を追加します。

  3. オプション。CMakeでサポートされている他のビルドツールを使用できます。

  4. New Headergenでlibcをビルドする場合のみ必要です。主にlibcで使用されます。

さらに、コンパイルホストには、通常の多くのUnixユーティリティがあることが予想されます。具体的には、次のものがあります。

  • ar - アーカイブライブラリビルダー

  • bzip2 - ディストリビューション生成用のbzip2コマンド

  • bunzip2 - ディストリビューションチェック用のbunzip2コマンド

  • chmod - ファイルのアクセス許可を変更する

  • cat - 出力連結ユーティリティ

  • cp - ファイルをコピーする

  • date - 現在の日付/時刻を出力する

  • echo - 標準出力に出力する

  • egrep - 拡張正規表現検索ユーティリティ

  • find - ファイルシステム内のファイル/ディレクトリを検索する

  • grep - 正規表現検索ユーティリティ

  • gzip - ディストリビューション生成用のgzipコマンド

  • gunzip - ディストリビューションチェック用のgunzipコマンド

  • install - ディレクトリ/ファイルをインストールする

  • mkdir - ディレクトリを作成する

  • mv - ファイルを移動(名前変更)する

  • ranlib - アーカイブライブラリのシンボルテーブルビルダー

  • rm - ファイルとディレクトリを削除する

  • sed - 出力を変換するためのストリームエディター

  • sh - makeビルドスクリプト用のBourneシェル

  • tar - ディストリビューション生成用のテープアーカイブ

  • test - ファイルシステム内のものをテストする

  • unzip - ディストリビューションチェック用のunzipコマンド

  • zip - ディストリビューション生成用のzipコマンド

ホストC++ツールチェーン(コンパイラと標準ライブラリの両方)

LLVMはホストC++コンパイラに対して非常に要求が高く、そのためコンパイラのバグを露呈する傾向があります。また、C++言語とライブラリの改善と開発を適度に追跡しようとしています。そのため、LLVMをビルドするには、最新のホストC++ツールチェーン(コンパイラと標準ライブラリの両方)が必要です。

LLVMは、コーディング標準に文書化されているC++のサブセットを使用して記述されています。この言語バージョンを強制するために、ビルドシステムで最も一般的なホストツールチェーンの特定の最小バージョンをチェックします。

  • Clang 5.0

  • Apple Clang 10.0

  • GCC 7.4

  • Visual Studio 2019 16.7

これらのツールチェーンよりも古いものは動作する可能性がありますが、特別なオプションでビルドシステムを強制する必要があり、実際にはサポートされているホストプラットフォームではありません。また、これらのコンパイラの古いバージョンでは、LLVMがクラッシュしたり、誤ってコンパイルされたりすることがよくありました。

ICCやxlCなどのあまり広く使用されていないホストツールチェーンの場合、LLVMで使用されているすべてのC++機能をサポートするには、非常に新しいバージョンが必要になる可能性があることに注意してください。

ホストツールチェーンの一部として使用すると失敗することがわかっている特定のソフトウェアバージョンを追跡します。これには、リンカーが含まれることもあります。

GNU ld 2.16.X。ldリンカーの2.16.Xバージョンの一部では、「.gnu.linkonce.t.*」シンボルが破棄されたセクションで定義されているという非常に長い警告メッセージが生成されます。これらのメッセージは誤りであり、リンケージは正しいので、無視しても安全です。これらのメッセージは、ld 2.17を使用すると表示されなくなります。

GNU binutils 2.17:Binutils 2.17には、LLVMをビルドすると、非常に長いリンク時間(数秒ではなく数分)が発生するバグが含まれています。新しいバージョン(2.17.50.0.4以降)にアップグレードすることをお勧めします。

GNU Binutils 2.19.1 Gold:このバージョンのGoldには、位置独立コードでLLVMをビルドすると断続的な失敗を引き起こすバグが含まれていました。症状は、循環依存関係に関するエラーです。新しいバージョンのGoldにアップグレードすることをお勧めします。

最新のホストC++ツールチェーンの入手

このセクションは、主にLinuxと古いBSDに適用されます。macOSでは、十分に新しいXcodeが必要です。そうでない場合は、アップグレードが必要になる可能性が高くなります。Windowsには「システムコンパイラ」がないため、Visual Studio 2019(以降)または最新バージョンのmingw64のいずれかをインストールする必要があります。FreeBSD 10.0以降には、システムコンパイラとして最新のClangがあります。

ただし、一部のLinuxディストリビューションと他の古いBSDには、非常に古いバージョンのGCCがある場合があります。これらの手順は、このようなシステムでもコンパイラをアップグレードするのに役立ちます。ただし、可能な限り、これらの要件を満たす最新のシステムコンパイラを備えた最新バージョンのディストリビューションを使用することをお勧めします。以前のバージョンのClangとlibc++をホストコンパイラとしてインストールするのは魅力的ですが、libc++は比較的最近までLinuxでビルドするように適切にテストまたは設定されていませんでした。その結果、このガイドでは、ブートストラップの最初のホストとしてlibstdc++と最新のGCCを使用し、次にClang(および場合によってはlibc++)を使用することをお勧めします。

最初のステップは、最新のGCCツールチェーンをインストールすることです。ユーザーがバージョンの要件で苦労した最も一般的なディストリビューションは、Ubuntu Precise、12.04 LTSです。このディストリビューションの場合、簡単なオプションの1つは、ツールチェーンテストPPAをインストールし、それを使用して最新のGCCをインストールすることです。ask ubuntu stack exchangeと、更新されたコマンドを含むgithub gistで、これに関する非常に素晴らしい議論があります。ただし、すべてのユーザーがPPAを使用できるわけではなく、他の多くのディストリビューションがあるため、GCCをソースからビルドしてインストールする必要がある場合があります(または、あなたがコンパイラ開発をしている場合は、単に役に立つだけです)。最近では、これも非常に簡単に行えます。

特定のバージョンのGCCをインストールするための簡単な手順

% gcc_version=7.4.0
% wget https://ftp.gnu.org/gnu/gcc/gcc-${gcc_version}/gcc-${gcc_version}.tar.bz2
% wget https://ftp.gnu.org/gnu/gcc/gcc-${gcc_version}/gcc-${gcc_version}.tar.bz2.sig
% wget https://ftp.gnu.org/gnu/gnu-keyring.gpg
% signature_invalid=`gpg --verify --no-default-keyring --keyring ./gnu-keyring.gpg gcc-${gcc_version}.tar.bz2.sig`
% if [ $signature_invalid ]; then echo "Invalid signature" ; exit 1 ; fi
% tar -xvjf gcc-${gcc_version}.tar.bz2
% cd gcc-${gcc_version}
% ./contrib/download_prerequisites
% cd ..
% mkdir gcc-${gcc_version}-build
% cd gcc-${gcc_version}-build
% $PWD/../gcc-${gcc_version}/configure --prefix=$HOME/toolchains --enable-languages=c,c++
% make -j$(nproc)
% make install

詳細については、優れたGCC wikiエントリを参照してください。この情報のほとんどはここから得ました。

GCCツールチェーンを入手したら、LLVMのビルドを構成して、ホストコンパイラとC++標準ライブラリに新しいツールチェーンを使用するようにします。新しいバージョンのlibstdc++はシステムライブラリ検索パスにないため、リンク時(-L)および実行時(-rpath)に見つけられるように、追加のリンカーフラグを渡す必要があります。CMakeを使用している場合、この呼び出しによって動作するバイナリが生成されるはずです

% mkdir build
% cd build
% CC=$HOME/toolchains/bin/gcc CXX=$HOME/toolchains/bin/g++ \
  cmake .. -DCMAKE_CXX_LINK_FLAGS="-Wl,-rpath,$HOME/toolchains/lib64 -L$HOME/toolchains/lib64"

rpathの設定に失敗すると、ほとんどのLLVMバイナリは起動時に、libstdc++.so.6: version `GLIBCXX_3.4.20' not foundのようなローダーからのメッセージで失敗します。これは、-rpathリンカーフラグを調整する必要があることを意味します。

このメソッドは、すべての実行ファイルのrpathに絶対パスを追加します。これはローカル開発には問題ありません。ビルドしたバイナリを古いシステムでも実行できるように配布する場合は、libstdc++.so.6lib/ ディレクトリにコピーしてください。LLVMの出荷バイナリはすべて $ORIGIN/../lib を指すrpathを持っているため、そこに libstdc++.so.6 があれば見つけられます。配布されないバイナリにはrpathが設定されておらず、libstdc++.so.6 を見つけることができません。上記の libstdc++.so.6 への絶対パスを追加するには、cmakeに -DLLVM_LOCAL_RPATH="$HOME/toolchains/lib64" を渡してください。これらのバイナリは配布されないため、絶対ローカルパスを持つことは問題ありません。

Clangをビルドする際、ブートストラップの一部として新しいホストとして使用するには、それ に最新のC++標準ライブラリへのアクセス権を与える必要があります。これを行う簡単な方法は2つあります。1つはClangと一緒にlibc++をビルド(およびインストール)し、-stdlib=libc++ コンパイルおよびリンクフラグで使用する方法です。もう1つは、ClangをGCCと同じプレフィックス(上記の$HOME/toolchains)にインストールする方法です。Clangは自身のプレフィックス内でlibstdc++を探し、見つかればそれを使用します。また、ClangがGCCツールチェーンを探すための明示的なプレフィックスを--gcc-toolchain=/opt/my/gcc/prefixフラグで追加することもできます。このフラグは、新しくビルドしたClangを使用してブートストラップするときに、コンパイルとリンクの両方のコマンドに渡します。

LLVMを始める

このガイドの残りの部分は、LLVMを起動して実行できるようにし、LLVM環境に関する基本的な情報を提供することを目的としています。

このガイドの後半のセクションでは、LLVMソースツリーの一般的なレイアウト、LLVMツールチェーンを使用した簡単な例、LLVMに関する詳細情報を見つけたり、メールでヘルプを得たりするためのリンクについて説明します。

用語と表記

このマニュアルでは、ローカルシステムと作業環境に固有のパスを示すために、以下の名前が使用されています。これらは設定する必要のある環境変数ではなく、以下のドキュメントで使用される文字列にすぎません。以下の例では、これらの名前をそれぞれローカルシステム上の適切なパス名に置き換えるだけで済みます。これらのパスはすべて絶対パスです。

SRC_ROOT

これは、LLVMソースツリーの最上位ディレクトリです。

OBJ_ROOT

これは、LLVMオブジェクトツリーの最上位ディレクトリです(つまり、オブジェクトファイルとコンパイルされたプログラムが配置されるツリーです。SRC_ROOTと同じにすることができます)。

パッチの送信

Contributingを参照してください。

コミットの二分探索

LLVMでgit bisectを使用する方法については、LLVMコードの二分探索を参照してください。

変更の取り消し

gitを使用して変更を取り消す場合、デフォルトのメッセージは「This reverts commit XYZ」になります。コミットメッセージの最後にこれを残し、その前にコミットが取り消される理由の詳細を追加してください。簡単な説明や、問題を示すボットへのリンクがあれば十分です。

ローカルLLVM構成

リポジトリをチェックアウトしたら、LLVMスイートのソースコードをビルドする前に構成する必要があります。このプロセスではCMakeを使用します。通常のconfigureスクリプトとは異なり、CMakeは要求された形式でビルドファイルを生成し、さまざまな*.incファイルとllvm/include/llvm/Config/config.h.cmakeを生成します。

変数は、コマンドラインで-D<変数名>=<値>の形式を使用してcmakeに渡されます。次の変数は、LLVMの開発者が使用する一般的なオプションの一部です。

  • CMAKE_C_COMPILER

  • CMAKE_CXX_COMPILER

  • CMAKE_BUILD_TYPE

  • CMAKE_INSTALL_PREFIX

  • Python3_EXECUTABLE

  • LLVM_TARGETS_TO_BUILD

  • LLVM_ENABLE_PROJECTS

  • LLVM_ENABLE_RUNTIMES

  • LLVM_ENABLE_DOXYGEN

  • LLVM_ENABLE_SPHINX

  • LLVM_BUILD_LLVM_DYLIB

  • LLVM_LINK_LLVM_DYLIB

  • LLVM_PARALLEL_LINK_JOBS

  • LLVM_OPTIMIZED_TABLEGEN

詳細については、よく使用されるCMake変数のリストを参照してください。

LLVMを構成するには、次の手順に従います。

  1. オブジェクトルートディレクトリに移動します。

    % cd OBJ_ROOT
    
  2. cmakeを実行します。

    % cmake -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=<type> -DCMAKE_INSTALL_PREFIX=/install/path
      [other options] SRC_ROOT
    

LLVMスイートのソースコードのコンパイル

autotoolsとは異なり、CMakeではビルドタイプは構成時に定義されます。ビルドタイプを変更する場合は、次の呼び出しでcmakeを再実行できます。

% cmake -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=<type> SRC_ROOT

実行間で、CMakeはすべてのオプションに設定された値を保持します。CMakeには、次のビルドタイプが定義されています。

Debug

これらのビルドはデフォルトです。ビルドシステムは、最適化されていないツールとライブラリを、デバッグ情報とアサートを有効にしてコンパイルします。

Release

これらのビルドでは、ビルドシステムはツールとライブラリを最適化を有効にしてコンパイルし、デバッグ情報は生成しません。CMakeのデフォルトの最適化レベルは-O3です。これは、CMakeコマンドラインでCMAKE_CXX_FLAGS_RELEASE変数を設定することで構成できます。

RelWithDebInfo

これらのビルドはデバッグ時に役立ちます。最適化されたバイナリをデバッグ情報付きで生成します。CMakeのデフォルトの最適化レベルは-O2です。これは、CMakeコマンドラインでCMAKE_CXX_FLAGS_RELWITHDEBINFO変数を設定することで構成できます。

LLVMを構成したら、OBJ_ROOTディレクトリに入り、次のコマンドを発行することでビルドできます。

% make

ビルドが失敗した場合は、こちらを確認して、LLVMをコンパイルできないことがわかっているGCCのバージョンを使用しているかどうかを確認してください。

マシンに複数のプロセッサがある場合は、GNU Makeによって提供される並列ビルドオプションの一部を使用することもできます。たとえば、次のコマンドを使用できます。

% make -j2

LLVMソースコードを操作する際に役立つ、いくつかの特別なターゲットがあります。

make clean

ビルドによって生成されたすべてのファイルを削除します。これには、オブジェクトファイル、生成されたC/C++ファイル、ライブラリ、および実行可能ファイルが含まれます。

make install

LLVMのヘッダーファイル、ライブラリ、ツール、およびドキュメントを、CMAKE_INSTALL_PREFIXで指定された$PREFIXの下の階層にインストールします。デフォルトは/usr/localです。

make docs-llvm-html

-DLLVM_ENABLE_SPHINX=Onで構成した場合、これはOBJ_ROOT/docs/htmlにHTML形式のドキュメントを含むディレクトリを生成します。

LLVMのクロスコンパイル

LLVM自体をクロスコンパイルできます。つまり、ビルドが行われるプラットフォームとは異なるプラットフォームでホストされるLLVM実行可能ファイルとライブラリを作成できます(カナディアンクロスビルド)。クロスコンパイル用のビルドファイルを生成するために、CMakeはCMAKE_TOOLCHAIN_FILE変数を提供します。この変数は、CMakeテスト操作中に使用されるコンパイラフラグと変数を定義できます。

このようなビルドの結果は、ビルドホストでは実行できないが、ターゲットで実行できる実行可能ファイルになります。例として、次のCMake呼び出しは、iOSをターゲットとするビルドファイルを生成できます。これは、最新のXcodeがインストールされたmacOSで機能します。

% cmake -G "Ninja" -DCMAKE_OSX_ARCHITECTURES="armv7;armv7s;arm64"
  -DCMAKE_TOOLCHAIN_FILE=<PATH_TO_LLVM>/cmake/platforms/iOS.cmake
  -DCMAKE_BUILD_TYPE=Release -DLLVM_BUILD_RUNTIME=Off -DLLVM_INCLUDE_TESTS=Off
  -DLLVM_INCLUDE_EXAMPLES=Off -DLLVM_ENABLE_BACKTRACES=Off [options]
  <PATH_TO_LLVM>

注:iOS SDKの制限により、iOS用にビルドする場合は、追加のフラグを渡す必要があります。

クロスコンパイルの詳細については、Clang/LLVMを使用したClang/LLVMのクロスコンパイル方法およびクロスコンパイル全般に関するClangドキュメントを確認してください。

LLVMオブジェクトファイルの場所

LLVMビルドシステムは、単一のLLVMソースツリーを複数のLLVMビルド間で共有できます。したがって、同じソースツリーを使用して、複数の異なるプラットフォームまたは構成に対してLLVMをビルドできます。

  • LLVMオブジェクトファイルが存在する必要がある場所にディレクトリを変更します。

    % cd OBJ_ROOT
    
  • cmakeを実行します。

    % cmake -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=Release SRC_ROOT
    

LLVMビルドは、LLVMソースツリーと一致する構造をOBJ_ROOTの下に作成します。ソースファイルがソースツリーに存在する各レベルには、OBJ_ROOTに対応するCMakeFilesディレクトリがあります。そのディレクトリの下には、.dirで終わる名前の別のディレクトリがあり、その下に各ソースのオブジェクトファイルがあります。

例:

% cd llvm_build_dir
% find lib/Support/ -name APFloat*
lib/Support/CMakeFiles/LLVMSupport.dir/APFloat.cpp.o

オプションの構成項目

binfmt_miscモジュールをサポートするLinuxシステムで実行していて、システムでrootアクセス権を持っている場合は、LLVMビットコードファイルを直接実行するようにシステムを設定できます。これを行うには、次のようなコマンドを使用します(モジュールをすでに使用している場合は、最初のコマンドは必要ない場合があります)。

% mount -t binfmt_misc none /proc/sys/fs/binfmt_misc
% echo ':llvm:M::BC::/path/to/lli:' > /proc/sys/fs/binfmt_misc/register
% chmod u+x hello.bc   (if needed)
% ./hello.bc

これにより、LLVMビットコードファイルを直接実行できます。Debianでは、上記の「echo」コマンドの代わりに、このコマンドを使用することもできます。

% sudo update-binfmts --install llvm /path/to/lli --magic 'BC'

ディレクトリレイアウト

LLVMソースベースに関する有用な情報の1つは、doxygenドキュメントで、https://llvm.dokyumento.jp/doxygen/で入手できます。以下は、コードレイアウトの簡単な紹介です。

llvm/cmake

システムビルドファイルを生成します。

llvm/cmake/modules

llvmユーザー定義オプションのビルド構成。コンパイラバージョンとリンカーフラグをチェックします。

llvm/cmake/platforms

Android NDK、iOS システム、および MSVC をターゲットとする非 Windows ホスト用のツールチェーン構成。

llvm/examples

  • LLVM をカスタム言語のコンパイラとして使用する方法を示すいくつかの簡単な例 - 低レベル化、最適化、コード生成など。

  • Kaleidoscope チュートリアル: Kaleidoscope 言語のチュートリアルでは、手書きのレキサー、パーサー、AST、および LLVM を使用したコード生成サポート(静的(事前)コンパイルとさまざまな Just In Time (JIT) コンパイルのアプローチを含む)を含む、自明でない言語用の優れた小さなコンパイラの実装について説明します。完全な初心者向けの Kaleidoscope チュートリアル

  • BuildingAJIT: LLVM の ORC JIT API が LLVM の他の部分とどのように相互作用するかを示す、BuildingAJIT チュートリアルの例。また、ユースケースに適したカスタム JIT を構築するために、それらをどのように再結合するかを教えます。

llvm/include

LLVM ライブラリからエクスポートされたパブリック ヘッダー ファイル。3 つの主要なサブディレクトリ

llvm/include/llvm

すべての LLVM 固有のヘッダー ファイルと、LLVM のさまざまな部分のサブディレクトリ: Analysis, CodeGen, Target, Transforms など...

llvm/include/llvm/Support

LLVM に付属しているが、必ずしも LLVM 固有ではない汎用サポート ライブラリ。たとえば、一部の C++ STL ユーティリティとコマンドライン オプション処理ライブラリは、ここにヘッダー ファイルを格納します。

llvm/include/llvm/Config

cmake によって構成されたヘッダー ファイル。これらは「標準」の UNIX および C ヘッダー ファイルをラップします。ソース コードは、cmake が生成する条件付き #include を自動的に処理するこれらのヘッダー ファイルを含めることができます。

llvm/lib

ほとんどのソース ファイルはここにあります。コードをライブラリに入れることで、LLVM は ツール間でのコードの共有を容易にします。

llvm/lib/IR/

Instruction や BasicBlock などのコア クラスを実装するコア LLVM ソース ファイル。

llvm/lib/AsmParser/

LLVM アセンブリ言語パーサー ライブラリのソース コード。

llvm/lib/Bitcode/

ビットコードの読み書きのコード。

llvm/lib/Analysis/

コールグラフ、誘導変数、自然ループ識別など、さまざまなプログラム分析。

llvm/lib/Transforms/

積極的なデッド コード削除、スパース条件付き定数伝播、インライン化、ループ不変コード モーション、デッド グローバル削除など、IR から IR へのプログラム変換。

llvm/lib/Target/

コード生成のターゲット アーキテクチャを記述するファイル。たとえば、llvm/lib/Target/X86 は X86 マシン記述を保持します。

llvm/lib/CodeGen/

コード ジェネレーターの主要部分: 命令セレクター、命令スケジューリング、およびレジスタ割り当て。

llvm/lib/MC/

ライブラリは、マシン コード レベルでコードを表現および処理します。アセンブリとオブジェクト ファイルの出力処理をします。

llvm/lib/ExecutionEngine/

インタープリターおよび JIT コンパイルされたシナリオで、ランタイム時にビットコードを直接実行するためのライブラリ。

llvm/lib/Support/

llvm/include/ADT/ および llvm/include/Support/ のヘッダー ファイルに対応するソース コード。

llvm/bindings

C または C++ 以外の言語で記述されたプログラムが LLVM インフラストラクチャを利用できるようにするための、LLVM コンパイラ インフラストラクチャのバインディングが含まれています。LLVM プロジェクトは、OCaml および Python 用の言語バインディングを提供します。

llvm/projects

厳密には LLVM の一部ではないが、LLVM と一緒に出荷されるプロジェクト。これは、LLVM ビルド システムを活用する独自の LLVM ベースのプロジェクトを作成するためのディレクトリでもあります。

llvm/test

LLVM インフラストラクチャの機能テスト、回帰テスト、およびその他の健全性チェック。これらは、徹底的でなくても、迅速に実行され、広範囲をカバーすることを目的としています。

test-suite

LLVM のための包括的な正確性、パフォーマンス、およびベンチマーク テスト スイート。これは、さまざまなライセンスの下で大量のサードパーティ コードが含まれているため、別の git リポジトリ <https://github.com/llvm/llvm-test-suite> に含まれています。詳細については、テスト ガイド ドキュメントを参照してください。

llvm/tools

上記のライブラリから構築された実行可能ファイルで、ユーザー インターフェイスの主要部分を形成します。ツール名 -help と入力すると、常にツールのヘルプを表示できます。以下は、最も重要なツールの簡単な紹介です。詳細については、コマンド ガイドを参照してください。

bugpoint

bugpoint は、クラッシュまたは誤コンパイルのいずれであっても、問題を引き起こす最小限のパス数や命令数に与えられたテスト ケースを絞り込むことにより、最適化パスまたはコード生成バックエンドをデバッグするために使用されます。bugpoint の使用方法の詳細については、HowToSubmitABug.html を参照してください。

llvm-ar

アーカイバーは、指定された LLVM ビットコード ファイルを含むアーカイブを生成します。オプションで、高速ルックアップ用のインデックスを含めることができます。

llvm-as

アセンブラーは、人間が読める LLVM アセンブリを LLVM ビットコードに変換します。

llvm-dis

逆アセンブラーは、LLVM ビットコードを人間が読める LLVM アセンブリに変換します。

llvm-link

当然のことながら、llvm-link は複数の LLVM モジュールを単一のプログラムにリンクします。

lli

lli は、LLVM ビットコードを直接実行できる LLVM インタープリターです (ただし、非常に遅いです...)。それをサポートするアーキテクチャ (現在は x86、Sparc、および PowerPC) では、デフォルトで、lli は Just-In-Time コンパイラーとして機能し (機能がコンパイルされている場合)、インタープリターよりもはるかに高速にコードを実行します。

llc

llc は、LLVM ビットコードをネイティブ コード アセンブリ ファイルに変換する LLVM バックエンド コンパイラーです。

opt

opt は LLVM ビットコードを読み取り、一連の LLVM から LLVM への変換 (コマンドラインで指定) を適用し、結果のビットコードを出力します。'opt -help' は、LLVM で利用可能なプログラム変換のリストを取得するのに適しています。

opt は、入力 LLVM ビットコード ファイルに対して特定の分析を実行し、結果を出力することもできます。主に分析をデバッグしたり、分析が何をするかを理解したりするのに役立ちます。

llvm/utils

LLVM ソース コードを扱うためのユーティリティ。インフラストラクチャの一部に対するコード ジェネレーターであるため、一部はビルド プロセスの一部です。

codegen-diff

codegen-diff は、LLC が生成するコードと LLI が生成するコードの違いを見つけます。これは、一方をデバッグしている場合に、もう一方が正しい出力を生成すると仮定して役立ちます。完全なユーザー マニュアルについては、`perldoc codegen-diff' を実行してください。

emacs/

LLVM アセンブリ ファイルおよび TableGen 記述ファイル用の Emacs および XEmacs の構文強調表示。それらの使用に関する情報については、README を参照してください。

getsrcs.sh

生成されていないすべてのソース ファイルを検索して出力します。ディレクトリをまたがって多くの開発を行いたい場合や、各ファイルを検索したくない場合に役立ちます。たとえば、LLVM ソース ツリーの先頭から xemacs `utils/getsources.sh` を実行する方法があります。

llvmgrep

LLVM の各ソース ファイルに対して egrep -H -n を実行し、llvmgrep のコマンドラインで指定された正規表現を渡します。これは、ソース ベースで特定の正規表現を検索するための効率的な方法です。

TableGen/

共通の TableGen 記述ファイルからレジスタ記述、命令セット記述、およびアセンブラーを生成するために使用されるツールが含まれています。

vim/

LLVM アセンブリ ファイルおよび TableGen 記述ファイル用の vim 構文強調表示。それらの使用方法については、README を参照してください。

LLVM ツールチェーンを使用した例

このセクションでは、ClangフロントエンドでLLVMを使用する例を示します。

clangを使った例

  1. まず、簡単なCファイルを作成し、「hello.c」という名前を付けます。

    #include <stdio.h>
    
    int main() {
      printf("hello world\n");
      return 0;
    }
    
  2. 次に、Cファイルをネイティブ実行可能ファイルにコンパイルします。

    % clang hello.c -o hello
    

    ClangはデフォルトでGCCと同じように動作します。標準の-Sおよび-c引数は通常どおり機能します(それぞれネイティブの.sファイルまたは.oファイルを生成します)。

  3. 次に、CファイルをLLVMビットコードファイルにコンパイルします。

    % clang -O3 -emit-llvm hello.c -c -o hello.bc
    

    -emit-llvmオプションを-Sまたは-cオプションとともに使用すると、コードのLLVM .llまたは.bcファイル(それぞれ)を出力できます。これにより、ビットコードファイルで標準のLLVMツールを使用できます。

  4. 両方の形式でプログラムを実行します。プログラムを実行するには、次のようにします。

    % ./hello
    

    % lli hello.bc
    

    2番目の例は、LLVM JIT、lliを起動する方法を示しています。

  5. llvm-disユーティリティを使用して、LLVMアセンブリコードを見てみましょう。

    % llvm-dis < hello.bc | less
    
  6. LLCコードジェネレーターを使用して、プログラムをネイティブアセンブリにコンパイルします。

    % llc hello.bc -o hello.s
    
  7. ネイティブアセンブリ言語ファイルをプログラムにアセンブルします。

    % /opt/SUNWspro/bin/cc -xarch=v9 hello.s -o hello.native   # On Solaris
    
    % gcc hello.s -o hello.native                              # On others
    
  8. ネイティブコードプログラムを実行します。

    % ./hello.native
    

    clangを使用してネイティブコードに直接コンパイルする場合(つまり、-emit-llvmオプションが存在しない場合)、ステップ6/7/8が自動的に実行されることに注意してください。

一般的な問題

LLVMのビルドまたは使用に問題がある場合、またはLLVMに関するその他の一般的な質問がある場合は、よくある質問ページを参照してください。

メモリとビルド時間が限られている場合は、makeの代わりにninjaを使用してビルドしてみてください。cmakeで次のオプションを設定することを検討してください。

  • -G Ninja このオプションを設定すると、makeの代わりにninjaを使用してビルドできます。ninjaでビルドすると、特にインクリメンタルビルドでビルド時間が大幅に改善され、メモリ使用量が改善されます。

  • -DLLVM_USE_LINKER このオプションをlldに設定すると、LinuxなどのELFベースのプラットフォームでのLLVM実行可能ファイルのリンク時間が大幅に短縮されます。初めてLLVMをビルドする場合で、lldがバイナリパッケージとして利用できない場合は、GNU ldのより高速な代替としてgoldリンカーを使用することを検討してください。

  • -DCMAKE_BUILD_TYPE ビルドの最適化レベルとデバッグ情報を制御します。この設定はRAMとディスクの使用量に影響を与える可能性があります。詳細については、CMAKE_BUILD_TYPEを参照してください。

  • -DLLVM_ENABLE_ASSERTIONS このオプションは、デバッグビルドではデフォルトでON、リリースビルドではデフォルトでOFFになっています。前のオプションで述べたように、リリースビルドタイプを使用してアサーションを有効にすることは、デバッグビルドタイプを使用する良い代替手段になる可能性があります。

  • -DLLVM_PARALLEL_LINK_JOBS 同時に実行するジョブの数に等しく設定します。これはmakeで使用される-jオプションに似ていますが、リンクジョブのみを対象としています。このオプションはninjaでのみ使用できます。ビルドプロセス中に使用されるメモリの量を大幅に削減するため、ジョブ数を非常に少なくしたい場合があります。メモリが限られている場合は、これを1に設定することをお勧めします。

  • -DLLVM_TARGETS_TO_BUILD ビルドするターゲットに等しく設定します。これをX86に設定することもできます。ただし、llvm-project/llvm/lib/Targetディレクトリ内にターゲットの完全なリストがあります。

  • -DLLVM_OPTIMIZED_TABLEGEN これをONに設定して、ビルド中に完全に最適化されたtablegenを生成します。これにより、ビルド時間が大幅に改善されます。これは、デバッグビルドタイプを使用している場合にのみ役立ちます。

  • -DLLVM_ENABLE_PROJECTS コンパイルするプロジェクト(clang、lldなど)に等しく設定します。複数のプロジェクトをコンパイルする場合は、項目をセミコロンで区切ります。セミコロンで問題が発生した場合は、単一引用符で囲んでみてください。

  • -DLLVM_ENABLE_RUNTIMES コンパイルするランタイム(libcxx、libcxxabiなど)に等しく設定します。複数のランタイムをコンパイルする場合は、項目をセミコロンで区切ります。セミコロンで問題が発生した場合は、単一引用符で囲んでみてください。

  • -DCLANG_ENABLE_STATIC_ANALYZER clang静的アナライザーが不要な場合は、このオプションをOFFに設定します。これにより、ビルド時間がわずかに改善されます。

  • -DLLVM_USE_SPLIT_DWARF デバッグビルドが必要な場合は、これをONに設定することを検討してください。これにより、リンカーへのメモリ負荷が軽減されます。これにより、バイナリにデバッグ情報が含まれないため、リンクがはるかに高速になります。ただし、DWARFオブジェクトファイル(拡張子.dwo付き)の形式でデバッグ情報が生成されます。これは、LinuxなどのELFを使用するホストプラットフォームにのみ適用されます。