4
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

libclang/libLLVM を Windows(MinGW) 向けに llvm-mingw でクロスコンパイルするメモ(10.0.0 or later)

Last updated at Posted at 2020-03-06

背景

  • Windows で libclang/libLLVM(+ libcxx) を使いたい C++ アプリがある(e.g. C++ JIT など)
  • MLIR を Windows 向けにビルドしたい

llvm-mingw がありますが, libclang.dll などは提供されていない.

Windows 環境でビルドするのはめんどいので, Linux からクロスコンパイルしてみます.

クロスコンパイル情報

オフィシャルのページはなんかわかりずらいです...

llvm-mingw のビルドスクリプトや, Docker.cross あたりの実際の例を見るのがよいでしょう.

手順概要

  • A. ホスト環境で通常の gcc/clang を使って clang-tblgen, llvm-tblgen をビルドする
  • B. clang/LLVM を llvm-mingw の linux クロスコンパイラでビルドする
    • A でビルドした clang-tblgen, llvm-tblgen を使う

Ryzen5 1500X でビルドには 1 時間ちょっとかかります.
いい CPU(e.g. Threadripper 3990X)を用意するとよいでしょう.

ビルド環境

  • Ubuntu 18.04
  • host compiler: gcc(Ubuntu 標準) or clang-8 or later
  • llvm-project
    • tag llvmorg-10.0.0
  • ディスク空き容量 20 GB が理想(最低でも 10 GB ほど必要)
  • llvm-mingw 20200325 prebuilt https://github.com/mstorsjo/llvm-mingw/releases
  • cmake, ninja
  • Windows は, x86 windows を想定

最近(?)ですと, clang/libcxx など含め, llvm-project で一式管理 & ビルドが推奨のようです.

制約事項

9.0.1(llvm-mingw 20191230) では, compiler-rt(asan) のクロスコンパイルがうまくいきませんでした. 10.0.0(llvm-mingw 20200325) を使いましょう.

手順

libclang, libllvm をビルドするには, Host 環境に clang-tblgen, llvm-tblgen(.td からコード生成)が必要になります. llvm-tblgen は clang/llvm prebuilt バイナリ(e.g. https://github.com/llvm/llvm-project/releases/tag/llvmorg-9.0.1 から落とせるもの)や apt などで手に入りますが, clang-tblgen はソースコードからビルドする必要があります.
(bintray とかで, どこかに prebuilt binary が転がっているといいのですが, 無さそうです)

以下の手順を reproduce するビルドスクリプトです.

llvm-project

したがって, まずは clang-tblgen をビルドする必要があります. いろいろバージョンごとでの違いを避けるためにも llvm-tblgen も同じバージョン(ソースコード)からビルドしてみます.

$ git clone https://github.com/llvm/llvm-project
$ cd llvm-project
$ git checkout llvmorg-9.0.1

tag は必要に応じて変えてください. llvmorg-x.y.z という形式になっています.

host(native) で llvm-tblgen, clang-tblgen, llvm-config のビルド

cmake bootstrap します. -G ninja で ninja ビルドがいいかと思いますが, make でも問題ありません.

distdir=`pwd`/dist-native

rm -rf build-native
mkdir build-native

cd build-native && cmake -G Ninja ../llvm \
   -DCMAKE_INSTALL_PREFIX=$distdir \
   -DLLVM_ENABLE_PROJECTS="clang" \
   -DLLVM_TARGETS_TO_BUILD="host" \
   -DCMAKE_BUILD_TYPE=MinSizeRel \
   -DLLVM_OPTIMIZED_TABLEGEN=On \
   -DLLVM_ENABLE_ASSERTIONS=ON \

LLVM_ENABLE_PROJECTS に "clang" を入れます. llvm-project repo ですと, clang フォルダ(llvm-project/clang)は自動で見つけてくれるようです.
CMAKE_BUILD_TYPE は Release でも 2GB ほどディスク消費します. MinSizeRel がよいかと思います.
-DLLVM_OPTIMIZED_TABLEGEN=On として, llvm-tblgen を最適化つきでビルドするとよいでしょう.
(ちなみに, Windows ネイティブで clang/llvm などビルドする場合は必須です. これを付けないと tblgen の処理がめちゃくちゃ遅くなります)

$ ninja && ninja install

でビルドとインストールします(ただ, インストールは必須ではない)

ビルドは, Ryzen5 1500X で 35 分ほどかかりました. Ryzen9 3950X(+ PCI Gen4 SSD) では 7 分ほどでした.

clang-tblgen は, cmake install でインストールされないので注意です!!!
手動でコピーしましょう.

llvm-mingw で Window バイナリのクロスコンパイル

一度に clang, libcxx などビルドするとうまく行かないようなので, ここでは llvm, clang だけビルドします.

-DCMAKE_CROSSCOMPILING=True で, クロスコンパイルすることを指定します.

どうも Host での llvm-config の設定も必要のようですので, LLVM_CONFIG_PATH で, llvm-config のパスを設定します.

rm -rf build
mkdir build

LLVM_TBLGEN_PATH=`pwd`/dist-native/bin/llvm-tblgen
CLANG_TBLGEN_PATH=`pwd`/dist-native/bin/clang-tblgen
LLVM_CONFIG_FILENAME=`pwd`/dist-native/bin/llvm-config

cd build && cmake -G Ninja ../llvm \
   -DCMAKE_CROSSCOMPILING=True \
   -DCMAKE_SYSTEM_NAME=Windows \
   -DLLVM_TABLEGEN=${LLVM_TBLGEN_PATH} \
   -DCLANG_TABLEGEN=${CLANG_TBLGEN_PATH} \
   -DLLVM_CONFIG_PATH=${LLVM_CONFIG_FILENAME} \
   -DCMAKE_C_COMPILER=/path/to/llvm-mingw-20191230-ubuntu-16.04/bin/x86_64-w64-mingw32-gcc \
   -DCMAKE_CXX_COMPILER=/path/to/llvm-mingw-20191230-ubuntu-16.04/bin/x86_64-w64-mingw32-g++ \
   -DCMAKE_RC_COMPILER=/path/to/llvm-mingw-20191230-ubuntu-16.04/bin/x86_64-w64-mingw32-windres \
   -DLLVM_ENABLE_PROJECTS="clang" \
   -DLLVM_TARGETS_TO_BUILD="X86" \
   -DCMAKE_BUILD_TYPE=MinSizeRel \
   -DLLVM_ENABLE_ASSERTIONS=ON

CMAKE_RC_COMPILER は指定しなくてもいいかもしれません.

libLLVM.dll が欲しい場合は, -DLLVM_BUILD_LLVM_DYLIB=On にします.

最新 master(clang/llvm 10 or later)だと, c-index-test で libxml2 で iconv.h が見つからないエラーが出ます. -DLLVM_ENALBE_LIBXML2=Off をつけると libxml2 をつかわないビルドになり解決します.

多少 warning が出ますが, これで cross compile できるはずです!

ちなみに -DCMAKE_BUILD_TYPE=RelWithDebInfo など, デバッグ情報ありだと 45 GB ほどディスク領域消費しますので注意です!
(主に bin が, static build のため一つ一つの .exe がとても大きい)

libXXXX だけ欲しいのであれば, tool 周りはビルド不要なので, -DLLVM_BUILT_TOOLS=NO とするのも手です.

llvm-mingw でのクロスコンパイルは, Ryzen5 1500X で 35 分ほどかかりました.

libcxx のビルド

llvm-mingw git repo の build-libcxx.sh を参考にしてビルドしましょう.

  • libunwind のクロスコンパイル
  • libcxxabi のクロスコンパイル
  • libcxx のクロスコンパイル

という手順になります. CMake の設定は結構ありますが, コンパイル自体はすぐに終わります.

compiler-rt

compiler-rt は optional です.
asan(address sanitizer)を使いたいときなどに必要になります.

compiler-rt は, llvm-mingw の clang クロスコンパイラだけあればビルドできます(libLLVM, libclang など他のプロジェクトには依存していない).

9.0 だとうまくいかないので, llvm-mingw 20200325(llvm 10.0.0)を使いましょう.

ビルド例は以下です.

#!/bin/bash

# --- config ---

LLVM_MINGW_DIR=/home/syoyo/local/llvm-mingw-20200325-ubuntu-18.04/

# --------------

curdir=`pwd`
distdir=`pwd`/dist-native
native_distdir=`pwd`/dist-native
builddir=`pwd`/build-compiler-rt-mingw-cross

arch=x86_64
buildarchname=x86_64

if [ -d "${builddir}" ]; then
  rm -rf ${builddir}
fi

mkdir ${builddir}

#  -DCMAKE_AR="${native_distdir}/bin/llvm-ar" \
#  -DCMAKE_RANLIB="${native_distdir}/bin/llvm-ranlib" \

cd ${builddir} && cmake \
  -G Ninja \
  -DCMAKE_BUILD_TYPE=MinSizeRel \
  -DCMAKE_INSTALL_PREFIX="${distdir}" \
  -DCMAKE_C_COMPILER=${LLVM_MINGW_DIR}/bin/${arch}-w64-mingw32-clang \
  -DCMAKE_CXX_COMPILER=${LLVM_MINGW_DIR}/bin/${arch}-w64-mingw32-clang++ \
  -DCMAKE_SYSTEM_NAME=Windows \
  -DCMAKE_C_COMPILER_WORKS=1 \
  -DCMAKE_CXX_COMPILER_WORKS=1 \
  -DCMAKE_C_COMPILER_TARGET=$buildarchname-windows-gnu \
  -DCOMPILER_RT_DEFAULT_TARGET_ONLY=TRUE \
  -DCOMPILER_RT_USE_BUILTINS_LIBRARY=TRUE \
  ../llvm-project/compiler-rt

cmake --build ${builddir} && cmake --build ${builddir} --target install

libspp(optional)

Stack smashing protector ライブラリです.
ランタイム時にスタック破壊を防ぐライブラリですかね.

ビルドは llvm-mingw repo を参照ください.
(libspp コードは gcc の一部となっています)

mingw ヘッダ/libc(?)の設定

libclang で C/C++ JIT などする場合, C のヘッダ, Windows 関連のヘッダ, C++ STL のヘッダなどが必要になります. llvm-mingw のパッケージを使えばよさそうですが, うまく行かない場合は, llvm-mingw git repo の mingw 関連のビルドスクリプトを参考にして, 追加でビルドが必要かもしれません.

libclang, libLLVM を使う C++ アプリのクロスコンパイル

.a でリンクだと指定順とかあって面倒なので, llvm/clang を SHARED でビルドしておくといいかもしれません.
(ただ, SHARED だと Bye サンプルがビルドできませんでした)

以下は shared(dll)バージョンでの解説です.

clang だけなぜか liblibclang.dll という名前になります.
リンク用の .a(MSVC で言う import library .lib)は, liblibclang.dll.a という名前になります.

/path/to/mingw-gcc file.cc -L/path/to/cross-mingw/lib -llibclang.dll

と言う感じで -l で指定すればリンクできます! -lunwind.dll で libunwind のリンクも必須になります.

TODO

  • libcxx のビルド
  • Wine で動作確認できるか試す
  • target triple を指定したほうがいいか?
  • 実際にビルドされた libclang, libLLVM が, C++ アプリでリンクできるかためす
  • SHARED ビルド(libLLVM.so, libclang.so), STATIC ビルドを試す.
  • compiler-rt が 10.0 or 最新 llvm-project repo でビルドできるか試す
  • 同様にして, aarch64 向けにクロスコンパイルする
4
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?