Неустранимая ошибка CMake GTest (отсутствует stdlib.h) при кросс-компиляции - PullRequest
1 голос
/ 31 мая 2019

Настройка

У меня есть следующие файлы.

empty.cc:

#include <cstdlib>

CMakeLists.txt:

set(CMAKE_MINIMUM_VERSION 3.8)

cmake_minimum_required(VERSION ${CMAKE_MINIMUM_VERSION})

find_package(GTest REQUIRED)

set(gtest_test gtest-test)
add_executable(${gtest_test} empty.cc)
#target_link_libraries(${gtest_test} ${GTEST_LIBRARIES} ${GTEST_MAIN_LIBRARIES}) # Line A
target_link_libraries(${gtest_test} GTest::GTest GTest::Main) # Line B

toolchain.cmake:

set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_SYSTEM_VERSION 4.14.0)
set(CMAKE_SYSTEM_PROCESSOR arm)


set(CMAKE_C_COMPILER /opt/zynq/xtl/bin/arm-linux-musleabihf-gcc)
set(CMAKE_CXX_COMPILER /opt/zynq/xtl/bin/arm-linux-musleabihf-g++)

set(CMAKE_SYSROOT /opt/zynq/xtl/arm-linux-musleabihf)

set(CMAKE_FIND_ROOT_PATH /opt/zynq/xtl/arm-linux-musleabihf)

set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY BOTH)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE BOTH)
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE NEVER)


set(CMAKE_INSTALL_PREFIX /opt/zynq/xtl/arm-linux-musleabihf)

Задача

Я строю его, используя:

cmake -DCMAKE_TOOLCHAIN_FILE=../toolchain.cmake .. && make VERBOSE=1 -j

Когда я связываюсь с GTest, используя Line A, т.е. target_link_libraries(${gtest_test} ${GTEST_LIBRARIES} ${GTEST_MAIN_LIBRARIES}), тогда все в порядке. Но когда я использую Line B, то есть target_link_libraries(${gtest_test} GTest::GTest GTest::Main), я получаю следующую ошибку:

/opt/zynq/xtl/bin/arm-linux-musleabihf-g++ --sysroot=/opt/zynq/xtl/arm-linux-musleabihf   -isystem /opt/zynq/xtl/arm-linux-musleabihf/include   -o CMakeFiles/gtest-test.dir/empty.cc.o -c /home/xxx/git/cmake/cmake-with-gtest/empty.cc
In file included from /home/xxx/git/cmake/cmake-with-gtest/empty.cc:1:
/opt/zynq/xtl/arm-linux-musleabihf/include/c++/8.3.0/cstdlib:75:15: fatal error: stdlib.h: No such file or directory
 #include_next <stdlib.h>
               ^~~~~~~~~~
compilation terminated.
CMakeFiles/gtest-test.dir/build.make:62: recipe for target 
'CMakeFiles/gtest-test.dir/empty.cc.o' failed
make[2]: *** [CMakeFiles/gtest-test.dir/empty.cc.o] Error 1

g++ версия

...$ /opt/zynq/xtl/bin/arm-linux-musleabihf-g++ --version
arm-linux-musleabihf-g++ (GCC) 8.3.0
Copyright (C) 2018 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

Обычная сборка, т.е. не кросс-компиляция, работает нормально, используя

target_link_libraries(${gtest_test} ${GTEST_LIBRARIES} ${GTEST_MAIN_LIBRARIES}) # Line A

или

target_link_libraries(${gtest_test} GTest::GTest GTest::Main) # Line B

Вопрос

Почему использование одного способа связывания приводит к отсутствующему заголовку, а другой работает просто отлично?

1 Ответ

1 голос
/ 31 мая 2019

Известно, что использование -isystem для стандартного компилятора включает директивы breaks #include_next, которая широко используется для стандартных заголовочных файлов C ++. Смотрите, например этот вопрос: -система в системном каталоге включает в себя ошибки .

CMake имеет механизм фильтрации стандартных каталогов включения компилятора, который использует переменную CMAKE_ _IMPLICIT_INCLUDE_DIRECTORIES в качестве списка включаемых каталогов, которые необходимо отфильтровать. К сожалению, этот список не определяется автоматически с помощью компилятора (см. Закрытый отчет об ошибках: https://gitlab.kitware.com/cmake/cmake/issues/16291). Вместо этого каталог /usr/include (относительно sysroot) просто добавляется в этот список.

Поскольку в вашем компиляторе инструментария include каталог не является /usr/include, а /include, вам необходимо явно добавить этот каталог в список исключений:

# in toolchain.cmake
list(APPEND CMAKE_CXX_IMPLICIT_INCLUDE_DIRECTORIES ${CMAKE_SYSROOT}/include)
# Setting the exclude directory for C compiler is optional:
# C standard headers rarely use `#include_next` directive
list(APPEND CMAKE_C_IMPLICIT_INCLUDE_DIRECTORIES ${CMAKE_SYSROOT}/include)

Разница между

target_link_libraries(${gtest_test} ${GTEST_LIBRARIES} ${GTEST_MAIN_LIBRARIES}) # Line A

и

target_link_libraries(${gtest_test} GTest::GTest GTest::Main) # Line B

заключается в том, что Line B использует имена целей для связи и включает каталоги, связанные с этими целями, автоматически добавляются в ваш исполняемый файл. Вот почему вы получили -isystem.

Второй способ (Line B) рассматривается как «современный» и предлагается для использования во вновь создаваемом коде. Но оба метода должны работать.

...