CMakeでクロスコンパイルするときのtoolchain fileの書き方
CMakeでクロスコンパイルする場合、まず出てくるのが toolchain file です。
普通のビルドでは、CMakeがホスト環境を見てコンパイラを探します。一方でクロスコンパイルでは、ビルドする環境と実行する環境が違います。そのため、どのターゲット向けに、どのコンパイラでビルドするのかを先に渡す必要があります。
CMake公式の toolchains ドキュメントでも、クロスコンパイルでは toolchain file を指定する流れになっています。
https://cmake.org/cmake/help/latest/manual/cmake-toolchains.7.html#cross-compiling
sysrootまで含めた設定は CMakeのクロスコンパイルでsysrootを設定する理由 に分けています。まずはこの記事で toolchain file の最小構成だけ見ます。
最小のtoolchain file
Linuxホスト上で、ARM向けLinuxバイナリを作る例です。
# toolchains/arm-linux.cmake
set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_SYSTEM_PROCESSOR arm)
set(CMAKE_C_COMPILER arm-linux-gnueabihf-gcc)
set(CMAKE_CXX_COMPILER arm-linux-gnueabihf-g++)
ひとまず見るのはこの4つです。
| 変数 | 内容 |
|---|---|
CMAKE_SYSTEM_NAME |
ターゲットOS |
CMAKE_SYSTEM_PROCESSOR |
ターゲットCPU |
CMAKE_C_COMPILER |
Cコンパイラ |
CMAKE_CXX_COMPILER |
C++コンパイラ |
CMAKE_SYSTEM_NAME はターゲット側のOSを表します。
https://cmake.org/cmake/help/latest/variable/CMAKE_SYSTEM_NAME.html
ホストがLinuxでも、ターゲットが別環境ならここでターゲット側を指定します。
CMake実行時に指定する
toolchain file は configure 時に指定します。
cmake -S . -B build-arm \
-DCMAKE_TOOLCHAIN_FILE=toolchains/arm-linux.cmake
または、CMake 3.21以降なら --toolchain でも指定できます。
cmake -S . -B build-arm \
--toolchain toolchains/arm-linux.cmake
toolchain file はCMakeの初期段階で読み込まれるため、ビルドディレクトリを作った後に差し替えるとキャッシュと噛み合わないことがあります。
切り替えるなら、別のbuildディレクトリを使う方が分かりやすいです。
cmake -S . -B build-native
cmake -S . -B build-arm --toolchain toolchains/arm-linux.cmake
同じ設定を何度も使う場合は、CMakePresets.json にtoolchain fileを持たせる方法もあります。preset側の基本は CMakePresets.jsonで最初に設定しておくべきこと にまとめています。
CMakeLists.txt側は普通に書く
CMakeLists.txt 側は、できるだけ普通のCMakeとして書きます。
cmake_minimum_required(VERSION 3.20)
project(MyApp LANGUAGES C CXX)
add_executable(my_app
src/main.cpp
)
ターゲット環境の違いは toolchain file に寄せます。
CMakeLists.txt に arm-linux-gnueabihf-g++ のようなコンパイラ名を直接書き始めると、ホストビルドや別ターゲットへの切り替えがしづらくなります。
toolchain file内で避けたい変数
公式ドキュメントでは、toolchain file内で CMAKE_SOURCE_DIR や CMAKE_BINARY_DIR を使うのは避けた方がよいとされています。
https://cmake.org/cmake/help/latest/manual/cmake-toolchains.7.html#cross-compiling
toolchain file は try_compile() などの中でも読み込まれることがあり、そのときに source/binary の意味が変わるためです。
パスを組み立てたい場合は、CMAKE_CURRENT_LIST_DIR を使うのが扱いやすいです。
set(toolchain_dir ${CMAKE_CURRENT_LIST_DIR})
set(CMAKE_C_COMPILER ${toolchain_dir}/../bin/arm-linux-gnueabihf-gcc)
set(CMAKE_CXX_COMPILER ${toolchain_dir}/../bin/arm-linux-gnueabihf-g++)
まず確認すること
クロスコンパイルが動かないときは、まずこのあたりを確認します。
- toolchain fileをconfigure時に指定しているか
- buildディレクトリを使い回していないか
CMAKE_SYSTEM_NAMEがターゲットOSになっているかCMAKE_CXX_COMPILERが実際に存在するか- コンパイラ単体で実行できるか
コンパイラのパスが間違っている状態でCMake側を見ても、だいたい遠回りになります。
コンパイラ指定までは通るのに、ヘッダーやライブラリの探索で失敗する場合は CMakeのクロスコンパイルでsysrootを設定する理由 と CMakeのクロスコンパイルでfind_packageがホストを見に行くときの設定 を見ると原因を分けやすくなります。
まとめ
CMakeでクロスコンパイルする最初の設定は、toolchain fileに寄せます。
CMAKE_SYSTEM_NAMEでターゲットOSを指定するCMAKE_SYSTEM_PROCESSORでターゲットCPUを指定するCMAKE_C_COMPILER/CMAKE_CXX_COMPILERでクロスコンパイラを指定する- configure時に
--toolchainまたはCMAKE_TOOLCHAIN_FILEで渡す - buildディレクトリはターゲットごとに分ける
まずはこの形で、ネイティブビルドとクロスビルドを分離しておくのが扱いやすいです。
次に見る内容としては、ターゲット環境のヘッダーやライブラリを扱う sysrootの設定 が近いです。


