From fd9e5429a37f24780f5e27c08ecb470d5d36e93a Mon Sep 17 00:00:00 2001 From: Torsten Rasmussen Date: Fri, 23 Sep 2022 12:37:42 +0200 Subject: [PATCH] cmake: detect sysroot for cross-compile toolchains Fixes: #49587 Try to detect sysroot for cross-compile toolchain if not specified by the user with `-DSYSROOT_DIR=`. First, the C compiler is asked if it knows its sysroot, some C compilers are able to return the sysroot, as an example: > $ arm-none-eabi-gcc -print-sysroot > /bin/../arm-none-eabi > $ but majority of gcc-based C compilers seems to return empty string: > $ arm-zephyr-eabi-gcc --print-sysroot > $ in such cases, the cross-compiler target CMake file will try to discover the sysroot by searching for libc.a, starting one level up from the compiler location. If no sysroot candidate is found, a warning will be printed to the user. If a single sysroot candidate is found, this candidate will be selected. If multiply sysroot candidates are found, a warning is printed, and the first candiate in the list is selected. User may select another candidate with `-DSYSROOT_DIR=`. Signed-off-by: Torsten Rasmussen --- cmake/toolchain/cross-compile/target.cmake | 63 +++++++++++++++++++++- 1 file changed, 62 insertions(+), 1 deletion(-) diff --git a/cmake/toolchain/cross-compile/target.cmake b/cmake/toolchain/cross-compile/target.cmake index 5a1a0e51313..d28985cf67d 100644 --- a/cmake/toolchain/cross-compile/target.cmake +++ b/cmake/toolchain/cross-compile/target.cmake @@ -1,3 +1,64 @@ # SPDX-License-Identifier: Apache-2.0 -# This file intentionally left blank. +if(NOT SYSROOT_DIR) + # When using cross-compile, the generic toolchain will be identical to the + # target toolchain, hence let's ask the compiler if it knows its own sysroot. + # Some gcc based compilers do have this information built-in. + execute_process(COMMAND ${CMAKE_C_COMPILER} --print-sysroot + RESULT_VARIABLE return_val + OUTPUT_VARIABLE reported_sysroot + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + if(NOT return_val AND NOT "${reported_sysroot}" STREQUAL "") + set(SYSROOT_DIR "${reported_sysroot}" CACHE INTERNAL "Sysroot reported by ${CMAKE_C_COMPILER}") + else() + # Let's try to lookup a sysroot. + # Compiler is expected to be located in `bin/` so we go one folder up for search. + cmake_path(GET CMAKE_C_COMPILER PARENT_PATH search_path) + cmake_path(SET search_path NORMALIZE "${search_path}/..") + file(GLOB_RECURSE libc_dirs RELATIVE ${search_path} ${search_path}/**/libc.a ) + + # Did we find any candidates ? + list(LENGTH libc_dirs libc_dirs_length) + if(${libc_dirs_length} GREATER 0) + list(TRANSFORM libc_dirs REPLACE "libc.a$" "") + list(SORT libc_dirs COMPARE NATURAL) + list(GET libc_dirs 0 sysroot) + set(sysroot_candidates ${sysroot}) + + foreach(dir ${libc_dirs}) + string(FIND "${dir}" "${sysroot}" index) + if(${index} EQUAL -1) + set(sysroot ${dir}) + list(APPEND sysroot_candidates ${sysroot}) + endif() + endforeach() + + # We detect the lib folders, the actual sysroot is up one level. + list(TRANSFORM sysroot_candidates REPLACE "/lib[/]?$" "") + + list(LENGTH sysroot_candidates sysroot_candidates_length) + if(sysroot_candidates_length GREATER 1) + list(TRANSFORM sysroot_candidates PREPEND "${search_path}") + string(REPLACE ";" "\n" sysroot_candidates_str "${sysroot_candidates}") + + message(WARNING "Multiple sysroot candidates found: ${sysroot_candidates_str}\n" + "Use `-DSYSROOT_DIR=` to select sysroot.\n" + ) + endif() + + # Use first candidate as sysroot. + list(GET sysroot_candidates 0 chosen_sysroot) + cmake_path(SET SYSROOT_DIR NORMALIZE "${search_path}/${chosen_sysroot}") + endif() + + if(SYSROOT_DIR) + set(SYSROOT_DIR "${SYSROOT_DIR}" CACHE INTERNAL "Sysroot discovered") + message(STATUS "Found sysroot: ${SYSROOT_DIR}") + else() + message(WARNING "No sysroot found, build may not work.\n" + "Use `-DSYSROOT_DIR=` to specify sysroot to use.\n" + ) + endif() + endif() +endif()