🐤

CMake: "clang++ is not able to compile a simple test program" エラー対処方法

2022/09/04に公開

はじめに

x86_64マシンでARM64ターゲット向けにCMakeでクロスビルドする場合に、使い方次第では遭遇する以下のエラーの対処方法についてまとめています。

[   +5 ms] Failed to cmake:
-- The CXX compiler identification is Clang 10.0.0
-- Check for working CXX compiler: /usr/bin/clang++
-- Check for working CXX compiler: /usr/bin/clang++ -- broken
-- Configuring incomplete, errors occurred!
See also "/hoge/CMakeFiles/CMakeOutput.log".
See also "/hoge/CMakeFiles/CMakeError.log".
           
CMake Error at /usr/share/cmake-3.16/Modules/CMakeTestCXXCompiler.cmake:53 (message):
The C++ compiler
           
"/usr/bin/clang++"
           
is not able to compile a simple test program.
           
It fails with the following output:
           
Change Dir: /hoge/CMakeFiles/CMakeTmp
           
Run Build Command(s):/hoge/arm64-sysroot/usr/bin/make cmTC_9cca1/fast && /lib/ld-linux-aarch64.so.1: No such file or directory
           
CMake will not be able to correctly generate this project.
Call Stack (most recent call first):
CMakeLists.txt:2 (project)

原因

try_compileする際のコンパイラのバイナリがホストPCのものではなく、指定したsysroot側のものを参照利用しているためです。

try_compileは、CMakeファイルの中のproject()を指定したところまでの設定で実行される様子です。そのため、project()が記述されているところまでの設定が不適切である場合、このエラーに遭遇する可能性があります。

クロスビルド時のsysrootの指定方法

そもそも、クロスビルドする場合、通常はターゲット (ARM64) のsysrootを指定すると思います。この場合、以下の2つのやり方があります。

  1. CMakeファイルの中でCMAKE_SYSROOTオプションを利用
  2. cmakeコマンドを打つ時のコマンドオプション-DCMAKE_SYSROOTを利用

エラーが起きるケース

cmakeコマンドで-DCMAKE_SYSROOTを指定している場合、必然的にproject()の前にsysrootが設定されてしまっている状態になるため、この問題が起きる可能性があります。

対策と結論

結論としては、try_compileが実行される時点でホスト側のツールチェーン(コンパイラ)が利用されるようにしましょう。

  1. makeコマンドで-DCMAKE_SYSROOTを指定せず、CMakeファイルの中でCMAKE_SYSROOTオプションを利用する(かつproject()の記述の後)
  2. cmakeコマンドの-DCMAKE_SYSROOTオプションを利用する場合、以下のようにproject()の前にset(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)を記述する
cmake_minimum_required(VERSION 3.15)
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) // projectの前にこれを記述する
project(runner LANGUAGES CXX)

のどちらかになります。

CMAKE_FIND_ROOT_PATH_MODE_PROGRAM 変数

find_program()でプログラムをサーチする際にCMAKE_FIND_ROOT_PATHおよびCMAKE_SYSROOTで設定されているパスを参照するかどうかを設定します。NEVERを設定することで必ずホスト側のプログラムが利用されるようになります。

参考文献

https://github.com/sony/flutter-elinux/pull/129

Discussion