Arm 用 Compiler-rt ビルトインのクロスコンパイル方法¶
はじめに¶
このドキュメントには、x86_64 Linux マシンから Arm ターゲット向けの compiler-rt のビルトイン部分をビルドおよびテストする方法に関する情報が含まれています。
このドキュメントでは Arm と Linux に焦点を当てていますが、一般的な原則は compiler-rt でサポートされている他のターゲットにも適用されるはずです。他のターゲットに関するさらなる貢献は大歓迎です。
このドキュメントの手順は、LLVM 以外のライブラリとプログラムに依存しています。これらの依存関係をインストールおよび構成するには多くの方法があるため、ここでの手順を自分のローカル環境に合わせて調整する必要がある場合があります。
前提条件¶
このユースケースでは、Debian ベースの Linux システムで cmake を使用し、x86_64 ホストからハードフロート Armv7-A ターゲットへのクロスコンパイルを行います。可能な限り多くの LLVM ツールを使用しますが、GNU 同等のツールを使用することも可能です。
LLVM/clang の ビルド (llvm-tools と llvm-config 用)
ARM ターゲットをサポートする clang 実行ファイル
compiler-rt ソースコード
qemu-arm ユーザーモードエミュレータ
arm-linux-gnueabihf sysroot
この例では、ninja を使用します。
clang と LLVM への依存関係の詳細については、https://compiler-rt.llvm.org/ を参照してください。
LLVM と compiler-rt のソースコードの入手方法については、https://llvm.dokyumento.jp/docs/GettingStarted.html を参照してください。はじめにガイドでは compiler-rt を projects サブディレクトリに配置していますが、これは必須ではありません。v6-M、v7-M、v7-EM 用の BaremetalARM.cmake キャッシュを使用する場合は、compiler-rt を runtimes ディレクトリに配置する必要があります。
qemu-arm
は、お使いの Linux ディストリビューションのパッケージとして入手できるはずです。
満たすのが最も複雑な前提条件は arm-linux-gnueabihf sysroot です。理論的には、Linux ディストリビューションのマルチアーキテクチャサポートを使用してビルドの依存関係を満たすことができますが、残念ながら /usr/local/include が追加されているため、ホストのインクルードファイルの一部が選択されます。sysroot を提供する最も簡単な方法は、arm-linux-gnueabihf ツールチェーンをダウンロードすることです。これは、次の場所にあります。* https://developer.arm.com/open-source/gnu-toolchain/gnu-a/downloads (gcc 8 以降) * https://releases.linaro.org/components/toolchain/binaries/ (gcc 4.9~7.3)
Arm 用 Compiler-rt ビルトインのビルド¶
次の cmake オプションを使用して、compiler-rt のスタンドアロンビルドを行います。
path/to/compiler-rt
-G Ninja
-DCMAKE_AR=/path/to/llvm-ar
-DCMAKE_ASM_COMPILER_TARGET="arm-linux-gnueabihf"
-DCMAKE_ASM_FLAGS="build-c-flags"
-DCMAKE_C_COMPILER=/path/to/clang
-DCMAKE_C_COMPILER_TARGET="arm-linux-gnueabihf"
-DCMAKE_C_FLAGS="build-c-flags"
-DCMAKE_EXE_LINKER_FLAGS="-fuse-ld=lld"
-DCMAKE_NM=/path/to/llvm-nm
-DCMAKE_RANLIB=/path/to/llvm-ranlib
-DCOMPILER_RT_BUILD_BUILTINS=ON
-DCOMPILER_RT_BUILD_LIBFUZZER=OFF
-DCOMPILER_RT_BUILD_MEMPROF=OFF
-DCOMPILER_RT_BUILD_PROFILE=OFF
-DCOMPILER_RT_BUILD_SANITIZERS=OFF
-DCOMPILER_RT_BUILD_XRAY=OFF
-DCOMPILER_RT_DEFAULT_TARGET_ONLY=ON
-DLLVM_CONFIG_PATH=/path/to/llvm-config
build-c-flags
は、C-make コンパイラチェックに合格し、compiler-rt をコンパイルし、テストを実行する場合はテストをコンパイルおよびリンクするのに十分なものでなければなりません。clang でクロスコンパイルする場合は、ターゲットとする Arm アーキテクチャのコードを生成するための十分な情報を渡す必要があります。Arm ターゲットを選択し、Armv7-A アーキテクチャを選択し、Arm 命令または Thumb 命令のどちらを使用するかを選択する必要があります。例:
--target=arm-linux-gnueabihf
-march=armv7a
-mthumb
GCC arm-linux-gnueabihf ツールチェーンを使用する場合は、インクルードファイルとライブラリを選択するために次のフラグが必要です。
--gcc-toolchain=/path/to/dir/toolchain
--sysroot=/path/to/toolchain/arm-linux-gnueabihf/libc
この例では、すべてのコマンドラインオプションを CMAKE_C_FLAGS
と CMAKE_ASM_FLAGS
の両方に追加します。build-c-flags
を簡素化するために使用できる、これらのオプションの一部を個別に渡すための cmake フラグがあります。
-DCMAKE_C_COMPILER_TARGET="arm-linux-gnueabihf"
-DCMAKE_ASM_COMPILER_TARGET="arm-linux-gnueabihf"
-DCMAKE_C_COMPILER_EXTERNAL_TOOLCHAIN=/path/to/dir/toolchain
-DCMAKE_SYSROOT=/path/to/dir/toolchain/arm-linux-gnueabihf/libc
cmake が完了したら、ninja builtins
でビルトインをビルドできます。
qemu-arm を使用した Compiler-rt ビルトインのテスト¶
ビルトインライブラリをテストするには、テストを有効にし、テストケース用のコンパイラとフラグを設定するためのいくつかの cmake フラグを追加する必要があります。qemu-arm
でテストを実行したいことも cmake に伝える必要があります。
-DCOMPILER_RT_EMULATOR="qemu-arm -L /path/to/armhf/sysroot
-DCOMPILER_RT_INCLUDE_TESTS=ON
-DCOMPILER_RT_TEST_COMPILER="/path/to/clang"
-DCOMPILER_RT_TEST_COMPILER_CFLAGS="test-c-flags"
/path/to/armhf/sysroot
は、「build-c-flags」に渡されたものと同じである必要があります。
「test-c-flags」には、ターゲット、アーキテクチャ、gcc-toolchain、sysroot、arm/thumb の状態を含める必要があります。CMAKE_C_COMPILER_EXTERNAL_TOOLCHAIN
などの追加の cmake 定義は、テストをビルドする際には適用されません。「build-c-flags」にこれらをすべて配置した場合は、それらを繰り返すことができます。テストのリンクに lld を使用したい場合は、"-fuse-ld=lld
を追加します。
cmake が完了したら、ninja check-builtins
を使用してテストをビルドして実行できます。
トラブルシューティング¶
cmake の試行コンパイル段階が失敗する¶
初期段階で、cmake は単純な C プログラムをコンパイルしてリンクして、ツールチェーンが機能しているかどうかをテストしようとします。
この段階では、--sysroot=
と --gcc-toolchain=
オプションがコンパイラに渡されていない場合、リンク時に多くの場合失敗します。CMAKE_C_FLAGS
と CMAKE_C_COMPILER_TARGET
フラグを確認してください。
ツールチェーンが機能していることを確認するために、cmake の外部で簡単な例をビルドすると役に立つ場合があります。例:clang --target=arm-linux-gnueabi -march=armv7a --gcc-toolchain=/path/to/gcc-toolchain --sysroot=/path/to/gcc-toolchain/arm-linux-gnueabihf/libc helloworld.c
clang がホストのヘッダーファイルを使用する¶
Debian ベースのシステムでは、arm-linux-gnueabi と arm-linux-gnueabihf のマルチアーキテクチャサポートをインストールできます。多くの場合、--gcc-toolchain=
と --sysroot=
が提供されていない場合でも、clang はこのマルチアーキテクチャサポートを正常に使用できます。残念ながら、clang は /usr/include/arm-linux-gnueabihf
の前に /usr/local/include
を追加するため、ホストのヘッダーファイルをコンパイルするときにエラーが発生します。
ビルトインをビルドするには、マルチアーキテクチャサポートは不十分です。別の arm-linux-gnueabihf ツールチェーンを使用する必要があります。
clang にターゲットが渡されない¶
clang にターゲットが指定されない場合、通常はホストターゲットが使用されます。これにより、Arm アセンブリ言語ファイルが理解されず、error: unknown directive .syntax unified
などのエラーメッセージが表示されます。
--target
がないか、正しく設定されていないかどうかを確認するには、エラーメッセージの clang の呼び出しを確認してください。原因は通常、CMAKE_ASM_FLAGS
に --target
が含まれていないか、CMAKE_ASM_COMPILER_TARGET
が存在しないことです。
Arm アーキテクチャが指定されない¶
--target=arm-linux-gnueabihf
は、デフォルトで arm アーキテクチャ v4t を使用します。これは、synch_and_fetch ソースファイルで使用されているバリア命令をアセンブルできません。
原因は通常、CMAKE_ASM_FLAGS
から -march=armv7a
が不足していることです。
Compiler-rt はビルドされるが、テストのビルドに失敗する¶
テストのビルドに使用されるフラグは、ビルトインのビルドに使用されるフラグと同じではありません。c フラグは COMPILER_RT_TEST_COMPILE_CFLAGS
によって提供され、CMAKE_C_COMPILER_TARGET
、CMAKE_ASM_COMPILER_TARGET
、CMAKE_C_COMPILER_EXTERNAL_TOOLCHAIN
、CMAKE_SYSROOT
フラグは適用されません。
COMPILER_RT_TEST_COMPILE_CFLAGS
に必要なすべての情報が含まれていることを確認してください。
他のターゲットへの変更¶
Arm ソフトフロートターゲット¶
Arm ハードフロートターゲットの指示は、sysroot とターゲットをソフトフロート相当のものに置き換えることで、ソフトフロートターゲットに使用できます。使用するターゲットは次のとおりです。
-DCMAKE_C_COMPILER_TARGET=arm-linux-gnueabi
浮動小数点命令を使用するかどうかによっては、浮動小数点命令を使用する場合に-mfloat-abi=softfp
などの追加のc-flagsが必要になる場合があり、ソフトウェア浮動小数点エミュレーションには-mfloat-abi=soft -mfpu=none
が必要です。
ソフトフロートには、arm-linux-gnueabi GNUツールチェーンを使用する必要があります。
AArch64 ターゲット¶
Arm の指示は、sysroot、エミュレータ、ターゲットを AArch64 相当のものに置き換えることで、AArch64 に使用できます。
-DCMAKE_C_COMPILER_TARGET=aarch64-linux-gnu
-DCOMPILER_RT_EMULATOR="qemu-aarch64 -L /path/to/aarch64/sysroot
CMAKE_C_FLAGS と COMPILER_RT_TEST_COMPILER_CFLAGS には、"--sysroot=/path/to/aarch64/sysroot --gcc-toolchain=/path/to/gcc-toolchain"
も必要になる場合があります。
Armv6-m、Armv7-m、および Armv7E-M ターゲット¶
Armv7-A と同様の方法でライブラリをビルドしてテストすることは可能ですが、より困難です。主な問題は次のとおりです。
ベアメタルシステム用の
qemu-arm
ユーザーモードエミュレータはありません。qemu-system-arm
を使用できますが、設定がはるかに困難です。コンパイラrtをコンパイルするターゲットには、サフィックス-none-eabiが付いています。これはclangのBareMetalドライバを使用し、デフォルトではcmakeコンパイラチェックに合格するために必要なライブラリを見つけません。
compiler-rtのArmv6-M、Armv7-M、Armv7E-MビルドはArmv7-Aでサポートされている命令のみを使用するため、Armv7-A用にビルドして実行されたテストケースを使用して、Armv7-Aで使用したのと同じqemu-arm
を使用してテストを実行することのメリットのほとんどを得ることができます。これにより、組み込み関数がバイナリにリンクされ、テストが正しく実行されるかどうかがテストされますが、組み込み関数がArmv7-AではサポートされているがArmv6-M、Armv7-M、Armv7E-Mではサポートされていない命令を使用しているかどうかは検出されません。
cmakeコンパイルテストに合格するには、CMAKE_CFLAGS
を介して、cmakeテストのリンクに成功するために必要なライブラリを渡す必要があります。CMAKE_TRY_COMPILE_TARGET=STATIC_LIBRARY
を使用してリンクステップをスキップできるため、cmakeバージョン3.6以降を使用することを強くお勧めします。
-DCMAKE_TRY_COMPILE_TARGET_TYPE=STATIC_LIBRARY
-DCOMPILER_RT_OS_DIR="baremetal"
-DCOMPILER_RT_BUILD_BUILTINS=ON
-DCOMPILER_RT_BUILD_SANITIZERS=OFF
-DCOMPILER_RT_BUILD_XRAY=OFF
-DCOMPILER_RT_BUILD_LIBFUZZER=OFF
-DCOMPILER_RT_BUILD_PROFILE=OFF
-DCMAKE_C_COMPILER=${host_install_dir}/bin/clang
-DCMAKE_C_COMPILER_TARGET="ご使用の *-none-eabi ターゲット"
-DCMAKE_ASM_COMPILER_TARGET="ご使用の *-none-eabi ターゲット"
-DCMAKE_AR=/path/to/llvm-ar
-DCMAKE_NM=/path/to/llvm-nm
-DCMAKE_RANLIB=/path/to/llvm-ranlib
-DCOMPILER_RT_BAREMETAL_BUILD=ON
-DCOMPILER_RT_DEFAULT_TARGET_ONLY=ON
-DLLVM_CONFIG_PATH=/path/to/llvm-config
-DCMAKE_C_FLAGS="build-c-flags"
-DCMAKE_ASM_FLAGS="build-c-flags"
-DCOMPILER_RT_EMULATOR="qemu-arm -L /path/to/armv7-A/sysroot"
-DCOMPILER_RT_INCLUDE_TESTS=ON
-DCOMPILER_RT_TEST_COMPILER="/path/to/clang"
-DCOMPILER_RT_TEST_COMPILER_CFLAGS="test-c-flags"
Armv6-M組み込み関数は、ソフトフロートABIを使用します。Armv7-Aのテストをコンパイルする際には、テストc-flagsに"-mthumb -mfloat-abi=soft -mfpu=none"
を含める必要があります。qemu-arm
には、Armv7-Aソフトフロートabi sysrootを使用する必要があります。
テストケースに使用されるリンカーによっては、compiler-rtのMプロファイルオブジェクトとテストのAプロファイルオブジェクトの間でBuildAttributeの不一致が発生する可能性があります。lldリンカーはプロファイルBuildAttributeをチェックしないため、COMPILER_RT_TEST_COMPILER_CFLAGS
に-fuse-ld=lldを追加することで、テストをリンクするために使用できます。
cmake キャッシュを使用した代替方法¶
Armv6-M、Armv7-M、またはArmv7E-Mに対してcompiler-rtをビルドするがテストしない場合は、clang/cmake/cachesにあるBaremetalARM.cmakeレシピを使用するのが最も簡単な方法です。
GNU ARM Embeddedツールチェーンによって提供されるような、ベアメタルsysrootが必要です。
ライブラリは、次のcmakeオプションを使用してビルドできます。
-DBAREMETAL_ARMV6M_SYSROOT=/path/to/bare/metal/toolchain/arm-none-eabi
-DBAREMETAL_ARMV7M_SYSROOT=/path/to/bare/metal/toolchain/arm-none-eabi
-DBAREMETAL_ARMV7EM_SYSROOT=/path/to/bare/metal/toolchain/arm-none-eabi
-C /path/to/llvm/source/tools/clang/cmake/caches/BaremetalARM.cmake
/path/to/llvm
注記 レシピが機能するには、compiler-rtソースをllvm/runtimesディレクトリにチェックアウトする必要があります。clangとlldもチェックアウトする必要があります。