Почему CMake явно ссылается на системные файлы хоста при кросс-компиляции агента Net-SNMP, несмотря на то, что используется правильный файл набора инструментов?

Я разрабатываю субагент Net-SNMP, конечной целью которого будет плата ARM, поэтому я с помощью CMake, чтобы упростить управление сборкой собственных и кросс-компилированных версий. Я начал тестировать его на своей хост-платформе (x86_64), и он отлично работает с этим файлом CMakeLists.txt:

cmake_minimum_required (VERSION 2.6)

project (snmp_agent C)

set(snmp_agent_VERSION_MAJOR 1)
set(snmp_agent_VERSION_MINOR 0)

# Defines path to the net-snmp-config script
set(NETSNMPCONFIG "${CMAKE_FIND_ROOT_PATH}/usr/bin/net-snmp-config")

# Gets compiling flags and libs linked to Net-SNMP
execute_process(COMMAND "${NETSNMPCONFIG}" "--base-cflags" OUTPUT_VARIABLE NETSNMPCFLAGS)
execute_process(COMMAND "${NETSNMPCONFIG}" "--agent-libs" OUTPUT_VARIABLE NETSNMPLIBS)

# Removes leading/trailing spaces from net-snmp-config output
string(STRIP ${NETSNMPCFLAGS} NETSNMPCFLAGS)
string(STRIP ${NETSNMPLIBS} NETSNMPLIBS)

# Prints compilation and linker flags used in Net-SNMP package
message("Net-SNMP package CFLAGS: ${NETSNMPCFLAGS}")
message("Net-SNMP package LIBS: ${NETSNMPLIBS}")

# Setting libs and compilation flags variables
set(LIBS "${NETSNMPLIBS}")
set(STRICT_FLAGS "-Wall -Wstrict-prototypes")
set(CFLAGS "-I. ${STRICT_FLAGS} ${NETSNMPCFLAGS}")

# Sets prefix for files created by 'mib2c' for the wanted MIB
set(ENT_PHYSICAL_ENTRY "scalars/entPhysicalEntry")

# Source files created by 'mib2c' and then user customized
set(USER_SRCS
    ${ENT_PHYSICAL_ENTRY}.c
  )

# Setting subagent sources
set(SRCS ${USER_SRCS}
    ${CMAKE_PROJECT_NAME}.c
  )

# Finds the required Net-SNMP lib paths and assigns them to variables
find_library(NETSNMPAGENT "netsnmpagent")
message("Found ${NETSNMPAGENT}")
find_library(NETSNMPMIBS "netsnmpmibs")
message("Found ${NETSNMPMIBS}")
find_library(NETSNMP "netsnmp")
message("Found ${NETSNMP}")

# Sets the flags to be used for compiling and linking the executable
set_source_files_properties(${SRCS} COMPILE_FLAGS ${CFLAGS})
add_executable(${CMAKE_PROJECT_NAME} ${SRCS})
target_link_libraries(${CMAKE_PROJECT_NAME} ${NETSNMPAGENT} ${NETSNMPMIBS} ${NETSNMP})

Я использую отдельный каталог сборки, поэтому не смешиваю файлы сборки и исходные файлы, которые остаются вместе с файлом CMakeLists.txt, поэтому вывод этих команд...

cd ~/git/snmp_agent # CMakeLists.txt is in here along with source files
mkdir build
cd build
cmake ..

...составляет:

claudio@slackdev:~/git/snmp_agent/build$ cmake ..
-- The C compiler identification is GNU 5.3.0
-- Check for working C compiler: /usr/bin/cc
-- Check for working C compiler: /usr/bin/cc -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Detecting C compile features
-- Detecting C compile features - done
Net-SNMP package CFLAGS: -DNETSNMP_ENABLE_IPV6 -fno-strict-aliasing -O2 -fPIC -Ulinux -Dlinux=linux -D_REENTRANT -D_GNU_SOURCE -fwrapv -fno-strict-aliasing -pipe -fstack-protector-strong -I/usr/local/include -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_FORTIFY_SOURCE=2 -I/usr/lib64/perl5/CORE -I/usr/include/libnl3 -I/usr/include
Net-SNMP package LIBS: -L/usr/lib64 -lnetsnmpmibs -lsensors -lpci -ldl -lnetsnmpagent -lwrap -lnsl -Wl,-E -Wl,-rpath,/usr/lib64/perl5/CORE -lnetsnmp -lcrypto -lnl-3 -lm
Found /usr/lib64/libnetsnmpagent.so
Found /usr/lib64/libnetsnmpmibs.so
Found /usr/lib64/libnetsnmp.so
-- Configuring done
-- Generating done
-- Build files have been written to: /home/claudio/git/snmp_agent/build

Запустив make, он отлично строится:

claudio@slackdev:~/git/snmp_agent/build$ make
Scanning dependencies of target snmp_agent
[ 25%] Building C object CMakeFiles/snmp_agent.dir/scalars/entPhysicalEntry.c.o
[ 50%] Building C object CMakeFiles/snmp_agent.dir/snmp_agent.c.o
[100%] Linking C executable snmp_agent
[100%] Built target snmp_agent

Этот snmp_agent работает как субагент agentX, подключаясь к основному snmpd главному агенту и надлежащим образом отвечая на запросы SNMP к entPhysicalEntry скалярным объектам.

Хорошо, пока все хорошо. Проблема заключается в том, что когда я пытаюсь кросс-компилировать это, он делает то же самое на моей конечной цели, то есть на плате ARMv7 Allwinner A20. У меня уже есть кросс-тулчейн для него, который я создал с помощью Crosstool-NG. Он находится в ПУТИ поиска и его инструменты начинаются с префикса armv7-a20_allwinner-linux-gnueabihf. Чтобы использовать его, я настроил следующий файл набора инструментов, названный armv7-a20_allwinner-linux-gnueabihf.cmake:

# the name of the target operating system
SET(CMAKE_SYSTEM_NAME Linux)

# which C and C++ compiler to use
SET(CMAKE_C_COMPILER   armv7-a20_allwinner-linux-gnueabihf-gcc)
SET(CMAKE_CXX_COMPILER armv7-a20_allwinner-linux-gnueabihf-g++) 

# here is the target environment located
SET(CMAKE_FIND_ROOT_PATH  "$ENV{HOME}/arm_rootfs") 

# adjust the default behaviour of the FIND_XXX() commands:
# search headers and libraries in the target environment, search 
# programs in the host environment
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)

Используя другой каталог сборки для версии ARM, CMake должен выбрать правильные пути, указывающие на корневую файловую систему ARM, которая является копией того, что будет на SD-карте целевой платы:

cd ~/git/snmp_agent # CMakeLists.txt and armv7-a20_allwinner-linux-gnueabihf.cmake are here
mkdir build-arm
cd build-arm
cmake -DCMAKE_TOOLCHAIN_FILE=../armv7-a20_allwinner-linux-gnueabihf.cmake ..

Обратите внимание, что, по-видимому, CMake работает нормально, поскольку все найденные пути относятся к корневой файловой системе ARM:

claudio@slackdev:~/git/snmp_agent/build-arm$ cmake -DCMAKE_TOOLCHAIN_FILE=../cmake_defs/armv7-a20_allwinner-linux-gnueabihf.cmake ..
-- The C compiler identification is GNU 6.3.0
-- Check for working C compiler: /home/claudio/x-tools/armv7-a20_allwinner-linux-gnueabihf/bin/armv7-a20_allwinner-linux-gnueabihf-gcc
-- Check for working C compiler: /home/claudio/x-tools/armv7-a20_allwinner-linux-gnueabihf/bin/armv7-a20_allwinner-linux-gnueabihf-gcc -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Detecting C compile features
-- Detecting C compile features - done
Net-SNMP package CFLAGS: -DNETSNMP_ENABLE_IPV6 -fno-strict-aliasing -O2 -march=armv7-a -mfpu=vfpv3-d16 -mfloat-abi=hard -Ulinux -Dlinux=linux -D_REENTRANT -D_GNU_SOURCE -fwrapv -fno-strict-aliasing -pipe -fstack-protector-strong -I/usr/local/include -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_FORTIFY_SOURCE=2 -I/usr/lib/perl5/CORE -I/usr/include/libnl3 -I/usr/include
Net-SNMP package LIBS: -L/usr/lib -lnetsnmpmibs -lsensors -lpci -ldl -lnetsnmpagent -lwrap -lnsl -Wl,-E -Wl,-rpath,/usr/lib/perl5/CORE -lnetsnmp -lcrypto -lnl-3 -lm
Found /home/claudio/arm_rootfs/usr/lib/libnetsnmpagent.so
Found /home/claudio/arm_rootfs/usr/lib/libnetsnmpmibs.so
Found /home/claudio/arm_rootfs/usr/lib/libnetsnmp.so
-- Configuring done
-- Generating done
-- Build files have been written to: /home/claudio/git/snmp_agent/build-arm

Но при запуске make он разваливается при поиске /usr/include/gnu/stubs.h. Если мы попытаемся повторить make с VERBOSE=1, мы увидим, что вызов gcc использует пути относительно хост-компьютера:

claudio@slackdev:~/git/snmp_agent/build-arm$ make VERBOSE=1
/usr/bin/cmake -H/home/claudio/git/snmp_agent -B/home/claudio/git/snmp_agent/build-arm --check-build-system CMakeFiles/Makefile.cmake 0
/usr/bin/cmake -E cmake_progress_start /home/claudio/git/snmp_agent/build-arm/CMakeFiles /home/claudio/git/snmp_agent/build-arm/CMakeFiles/progress.marks
make -f CMakeFiles/Makefile2 all
make[1]: Entering directory 'snmp_agent/build-arm'
make -f CMakeFiles/snmp_agent.dir/build.make CMakeFiles/snmp_agent.dir/depend
make[2]: Entering directory 'snmp_agent/build-arm'
cd /home/claudio/git/snmp_agent/build-arm && /usr/bin/cmake -E cmake_depends "Unix Makefiles" /home/claudio/git/snmp_agent /home/claudio/git/snmp_agent /home/claudio/git/snmp_agent/build-arm /home/claudio/git/snmp_agent/build-arm /home/claudio/git/snmp_agent/build-arm/CMakeFiles/snmp_agent.dir/DependInfo.cmake --color=
make[2]: Leaving directory 'snmp_agent/build-arm'
make -f CMakeFiles/snmp_agent.dir/build.make CMakeFiles/snmp_agent.dir/build
make[2]: Entering directory 'snmp_agent/build-arm'
[ 25%] Building C object CMakeFiles/snmp_agent.dir/scalars/entPhysicalEntry.c.o
/home/claudio/x-tools/armv7-a20_allwinner-linux-gnueabihf/bin/armv7-a20_allwinner-linux-gnueabihf-gcc     -I. -Wall -Wstrict-prototypes -DNETSNMP_ENABLE_IPV6 -fno-strict-aliasing -O2 -march=armv7-a -mfpu=vfpv3-d16 -mfloat-abi=hard -Ulinux -Dlinux=linux -D_REENTRANT -D_GNU_SOURCE -fwrapv -fno-strict-aliasing -pipe -fstack-protector-strong -I/usr/local/include -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_FORTIFY_SOURCE=2 -I/usr/lib/perl5/CORE -I/usr/include/libnl3 -I/usr/include -o CMakeFiles/snmp_agent.dir/scalars/entPhysicalEntry.c.o   -c /home/claudio/git/snmp_agent/scalars/entPhysicalEntry.c
In file included from /usr/include/features.h:392:0,
                 from /usr/include/stdio.h:27,
                 from /usr/include/net-snmp/net-snmp-includes.h:14,
                 from /home/claudio/git/snmp_agent/scalars/entPhysicalEntry.c:7:
/usr/include/gnu/stubs.h:7:27: fatal error: gnu/stubs-32.h: No such file or directory
 # include <gnu/stubs-32.h>
                           ^
compilation terminated.
CMakeFiles/snmp_agent.dir/build.make:62: recipe for target 'CMakeFiles/snmp_agent.dir/scalars/entPhysicalEntry.c.o' failed
make[2]: *** [CMakeFiles/snmp_agent.dir/scalars/entPhysicalEntry.c.o] Error 1
make[2]: Leaving directory 'snmp_agent/build-arm'
CMakeFiles/Makefile2:67: recipe for target 'CMakeFiles/snmp_agent.dir/all' failed
make[1]: *** [CMakeFiles/snmp_agent.dir/all] Error 2
make[1]: Leaving directory 'snmp_agent/build-arm'
Makefile:83: recipe for target 'all' failed
make: *** [all] Error 2

Странно то, что /usr/include/gnu/stubs.h из корневой файловой системы ARM не имеет ничего общего с stubs-32.h:

/* This file is automatically generated.
   This file selects the right generated file of `__stub_FUNCTION' macros
   based on the architecture being compiled for.  */


#if !defined __ARM_PCS_VFP
# include <gnu/stubs-soft.h>
#endif
#if defined __ARM_PCS_VFP
# include <gnu/stubs-hard.h>
#endif

Но если вы посмотрите на тот же файл из хост-системы, которая является машиной x86_64, мы можем догадаться, почему он пытался найти stubs-32.h (помните, что мы пытаемся скомпилировать для ARM, поэтому он не найдет определение символа __x86_64__):

/* This file is automatically generated.
   This file selects the right generated file of `__stub_FUNCTION' macros
   based on the architecture being compiled for.  */


#if !defined __x86_64__
# include <gnu/stubs-32.h>
#endif
#if defined __x86_64__ && defined __LP64__
# include <gnu/stubs-64.h>
#endif
#if defined __x86_64__ && defined __ILP32__
# include <gnu/stubs-x32.h>
#endif

Почему это происходит, поскольку в файле набора инструментов четко указано, что библиотеки и включения следует искать ТОЛЬКО по пути, заданному CMAKE_FIND_ROOT_PATH?

ОБНОВЛЕНИЕ (проблема еще не решена полностью!):

После того, как я принял ответ от @Tsyvarev, я дважды проверил свой файл CMakeLists.txt и обнаружил, что, пытаясь заставить его работать, я сделал хак, вручную установив CMAKE_FIND_ROOT_PATH в качестве префикса каждого включения компилятора. (-I), возвращенный net-snmp-config, что, очевидно, не является идеальным решением. Это, наряду с CMAKE_SYSROOT, заставляет его работать, но CMAKE_SYSROOT сам по себе не добавляет префикс к путям включения:

# This is the manually hacked line:
set(NETSNMPCFLAGS "-DNETSNMP_ENABLE_IPV6 -fno-strict-aliasing -O2 -march=armv7-a -mfpu=vfpv3-d16 -mfloat-abi=hard -Ulinux -Dlinux=linux -D_REENTRANT -D_GNU_SOURCE -fwrapv -fno-strict-aliasing -pipe -fstack-protector-strong -I${CMAKE_FIND_ROOT_PATH}/usr/local/include -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_FORTIFY_SOURCE=2 -I${CMAKE_FIND_ROOT_PATH}/usr/lib/perl5/CORE -I${CMAKE_FIND_ROOT_PATH}/usr/include/libnl3 -I${CMAKE_FIND_ROOT_PATH}/usr/include")

set(LIBS "${NETSNMPLIBS}")

set(STRICT_FLAGS "-Wall -Wstrict-prototypes")
set(CFLAGS "-I. ${STRICT_FLAGS} ${NETSNMPCFLAGS}")

person Claudio    schedule 15.06.2017    source источник
comment
В Stack Overflow мы стараемся не смешивать проблемы и решения в одном (вопросном) сообщении. Вместо этого спрашивающему разрешено самостоятельно ответить на свой вопрос. Пожалуйста, переместите содержимое раздела ОКОНЧАТЕЛЬНОЕ РЕШЕНИЕ в свой собственный ответ.   -  person Tsyvarev    schedule 16.06.2017
comment
Кроме того, в Stack Overflow мы стараемся поддерживать вопрос с последней информацией. Так что, если вы включили какой-то блок информации в сообщение с вопросом, но позже сочли эту информацию бесполезной, просто удалите этот блок. Например, вывод make V=1 определенно заменяет вывод make, поэтому вы можете безопасно удалить последний. Все предыдущие версии вопроса хранятся в истории изменений.   -  person Tsyvarev    schedule 16.06.2017
comment
Хорошо.. это имеет смысл. Я сделаю это, спасибо.   -  person Claudio    schedule 24.06.2017


Ответы (3)


Вам необходимо установить переменную CMAKE_SYSROOT для ссылки на "вот расположенная целевая среда».

В отличие от переменной CMAKE_FIND_ROOT_PATH, которая используется только в find_* командах CMAKE_SYSROOT также используется как подсказка для компилятора (опция --sysroot), поэтому компилятор выберет правильные включения.


В случае кросс-компиляции переменная CMAKE_FIND_ROOT_PATH используется для предоставления дополнительных поисковых префиксов для find_* команд. CMAKE_SYSROOT используется как префикс автоматически.

person Tsyvarev    schedule 15.06.2017
comment
Прямо на месте @Tsyvarev! Благодарю вас! - person Claudio; 15.06.2017
comment
Пожалуйста, ознакомьтесь с EDIT для полного решения - этот ответ, безусловно, помог добиться успеха компиляции, но не разрешил основное наблюдение (файлы, включаемые из хост-системы). - person Claudio; 16.06.2017

ОКОНЧАТЕЛЬНОЕ РЕШЕНИЕ:

Как объяснялось в вопросе UPDATE, ответ @Tsyvarev исправил часть ссылки, предоставив переключатель --sysroot компилятору, указывающий на корневую файловую систему для ARM, но проблема поиска stubs-32.h из хост-системы не т исправлено этим. Хотя это было частью решения, важно отметить, что основное наблюдение имело другую причину: переключатели include -I использовались непосредственно как CFLAGS для компилятора, заставляя его эффективно смотреть на хост-систему, поскольку они не имели префикса с префиксом путь корневой файловой системы для платы ARM (помните, что флаги выводились непосредственно сценарием net-snmp-config, который сообщал о флагах для собственной сборки ARM, поэтому с " нормальные" пути вместо этого). Чтобы исправить это, я использовал строковую команду CMake для удаления всех переключателей -I из переменной NETSNMPCFLAGS:

# Gets compiling flags and libs linked to Net-SNMP
execute_process(COMMAND "${NETSNMPCONFIG}" "--base-cflags" OUTPUT_VARIABLE NETSNMPCFLAGS)
execute_process(COMMAND "${NETSNMPCONFIG}" "--agent-libs" OUTPUT_VARIABLE NETSNMPLIBS)
# removes the include dir switches "-I" from the NETSNMPCFLAGS, since we don't want
# the compiler to include paths relative to the host system in the compilation
string(REGEX REPLACE "-I[a-zA-Z0-9/]*" "" NETSNMPCFLAGS ${NETSNMPCFLAGS})

set(STRICT_FLAGS "-Wall -Wstrict-prototypes")
set(CFLAGS "-I. ${STRICT_FLAGS} ${NETSNMPCFLAGS}")

и поместите корневую файловую систему в директиву include_directories:

# Sets the flags to be used for compiling and linking the executable
set_source_files_properties(${SRCS} COMPILE_FLAGS ${CFLAGS})
include_directories(${CMAKE_FIND_ROOT_PATH}/usr/include)
add_executable(${CMAKE_PROJECT_NAME} ${SRCS})
target_link_libraries(${CMAKE_PROJECT_NAME} ${NETSNMPAGENT} ${NETSNMPMIBS} ${NETSNMP})
person Claudio    schedule 24.06.2017

Причина, по которой cmake относится к файлам хоста, может быть связана с pkg-config.

См. этот документ о кросс-компиляции и pkg-config.

Я обновил свой файл toolchain.cmake следующим образом:

set(CMAKE_SYSROOT /home/windel/rpi-sysroot)

# Pkg config tweaks:
SET(ENV{PKG_CONFIG_LIBDIR} ${CMAKE_SYSROOT}/usr/lib/aarch64-linux-gnu/pkgconfig)
SET(ENV{PKG_CONFIG_SYSROOT_DIR} ${CMAKE_SYSROOT})
person Windel    schedule 26.03.2021