为什么工具链文件在CMake中执行了几次?

Why is the toolchain file executed a few times in CMake?

在尝试使用 SDCC 编译器创建交叉编译 CMake 工具链模板时,我遇到了一个非常奇怪的问题。

this link所述,如果toolchain.cmake文件定义了一个CMAKE_SYSTEM_NAME,CMake会在Module/Platform下寻找${CMAKE_SYSTEM_NAME}.cmake的文件目录。这个文件应该定义特定于平台的选项。就我而言,我使用它来查找 sdcc 编译器并设置一些编译器标志。

这对我来说很好用。使用 cmake -DCMAKE_MODULE_PATH="${PATH_TO_MY_MODULES}" -DCMAKE_TOOLCHAIN_FILE="${PATH_TO_MY_TOOLCHAIN}" -DSDCC_SYSROOT="SOME_VALUE",CMake 找到所有正确的工具链和平台文件。

在配置过程中,工具链和平台文件似乎被执行(不确定这是否正确)几次。在前几次,我在 CMake 命令中传递的变量 SDCC_SYSROOT 具有预期的值 SOME_VALUE。但是,同一个变量 SDCC_SYSROOT 似乎在上次执行这些 toolchain/platform 文件时丢失了值。所以他们是空的。这会导致我的脚本生成致命错误。

toolchain.cmake内容如下:

set(CMAKE_SYSTEM_NAME SDCC_PIC_16F877A)

# Finding resource settings
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)

# Set default MCU family and model
if (NOT MICROCHIP_FAMILY)
  set(MICROCHIP_FAMILY "pic16")
endif()

if (MICROCHIP_MODEL STREQUAL "pic16")
  set(MICROCHIP_MODEL "16f877a")
endif()


# Need a better way to detect the supported models here
if (NOT MICROCHIP_FAMILY STREQUAL "pic16" AND NOT MICROCHIP_MODEL STREQUAL "16f877a")
  message(FATAL_ERROR "Settings not supported. Please drop a request.")
endif()

if (NOT SDCC_ROOT)
  message(FATA_ERROR "Need to provide the root (from toolchain.)")
endif()

# Cache those variables
set(SDCC_ROOT "${SDCC_ROOT}"
  CACHE INTERNAL "Root directory of SDCC installation")

set(MICROCHIP_FAMILY "${MICROCHIP_FAMILY}"
  CACHE INTERNAL "Family of the chip to compile for")

set(MICROCHIP_MODEL "${MICROCHIP_MODEL}"
  CACHE INTERNAL "Model of the chip to compile for")

Module/Platform/SDCC_PIC_16F877A.cmake 文件包含以下内容:

# Check if the shit exists
message("!!! The value of root is ${SDCC_ROOT}")
if (NOT SDCC_ROOT)
  message(FATAL_ERROR
    "SDCC_ROOT is not defined. Please set this variable e.g.\n"
    "cmake -DSDCC_ROOT=\"C:/Program Files/sdcc\"")
endif()

# Finding the compilers
find_program(CMAKE_C_COMPILER
  sdcc
  PATHS ${SDCC_ROOT}
  PATH_SUFFIXES "bin"
  DOC "path to the SDCC C compiler.")

我的 CMakeLists.txt 如下:

cmake_minimum_required(VERSION 3.10)
project(PicExample)

message("THE COMPILER IS ${CMAKE_C_COMPILER}")

add_executable(pic_example main.c)

我从我的 project/build 目录调用的内容和我得到的错误:

 cmake -DCMAKE_MODULE_PATH:FILEPATH="/mnt/c/Users/mathe/Desktop/coding/sdcc-pic-template/Modules" -DCMAKE_TOOLCHAIN_FILE:FILEPATH="/mnt/c/Users/mathe/Desktop/coding/sdcc-pic-template/Modules/toolchain.cmake" -DSDCC_ROOT="testing/" ..
-- The C compiler identification is GNU 9.3.0
-- The CXX compiler identification is GNU 9.3.0
!!! The value of root is testing/
!!! The value of root is testing/
-- Check for working C compiler: /usr/bin/cc
FATA_ERRORNeed to provide the root (from toolchain.)
!!! The value of root is
CMake Error at /mnt/c/Users/mathe/Desktop/coding/sdcc-pic-template/Modules/Platform/SDCC_PIC_16F877A.cmake:4 (message):
  SDCC_ROOT is not defined.  Please set this variable e.g.

  cmake -DSDCC_ROOT="C:/Program Files/sdcc"
Call Stack (most recent call first):
  /usr/share/cmake-3.16/Modules/CMakeSystemSpecificInformation.cmake:26 (include)
  /mnt/c/Users/mathe/Desktop/coding/sdcc-pic-template/build/CMakeFiles/CMakeTmp/CMakeLists.txt:3 (project)


CMake Error at /usr/share/cmake-3.16/Modules/CMakeTestCCompiler.cmake:44 (try_compile):
  Failed to configure test project build system.
Call Stack (most recent call first):
  CMakeLists.txt:2 (project)


-- Configuring incomplete, errors occurred!
See also "/mnt/c/Users/mathe/Desktop/coding/sdcc-pic-template/build/CMakeFiles/CMakeOutput.log".

为什么工具链文件被 CMake 多次“执行”并且在最近的运行中无法访问缓存?我发现交叉编译的 CMake 文档非常困难,尤其是当您使用非标准编译器时。

我知道其他人以前也遇到过同样的问题,但我并不是简单地要求一个简单的 hacky 解决方案(设置环境变量)。我实际上想知道为什么会发生这种情况(之前的答案没有解决)。

为了确定编译器或库是否支持某些功能,CMake 使用try_compile 方法:在配置阶段,它创建单独的 CMake 项目并立即配置和构建它。因为它是一个单独的项目,所以它的配置与主项目的步骤相同,并且也会加载工具链文件

try_compile 可由(用户)项目用于检查库或编译器的功能。有许多 CMake 模块在其实现中使用 try_compile。例如。 CheckSymbolExists.

try_compile 也被 CMake 本身使用,在平台文件中,当它为编译器执行基本检查时。在您的日志中,您可以找到以下行:

CMake Error at /usr/share/cmake-3.16/Modules/CMakeTestCCompiler.cmake:44 (try_compile)

除了try_compile,新的CMake项目是在ExternalProject_Add命令中创建的。该创建还伴随着工具链文件的读取。 (更准确地说,新项目不是在处理 ExternalProject_Add 调用时创建的,而是在配置相应项目时创建的。此配置在主项目的构建阶段执行。)

Tsyvarev 回答了为什么在 CMake 中多次使用工具链。 TLDR; CMake 需要它进行多次 try_compile() 调用,它在内部用于错误检查和其他事情。

This works just fine for me. -DCMAKE_MODULE_PATH="${PATH_TO_MY_MODULES}" -DCMAKE_TOOLCHAIN_FILE="${PATH_TO_MY_TOOLCHAIN}" -DSDCC_SYSROOT="SOME_VALUE",

您需要做的就是解决您的问题。

本质上,您是将一个参数传递给您的工具链文件。这个论点 SDCC_SYSROOT 本质上超出了范围。

解决这个问题是你需要做的。

# Use list(APPEND) rather than set() so that any variables added by CMake aren't lost!
#
# Here is the docs for this variable: 
# https://cmake.org/cmake/help/latest/variable/CMAKE_TRY_COMPILE_PLATFORM_VARIABLES.html
list(APPEND CMAKE_TRY_COMPILE_PLATFORM_VARIABLES ${SDCC_SYSROOT})

如果您想查看您的工具链脚本执行了多少次,请尝试在其中调用 message() 以获取乐趣。

如果您真的感兴趣,请查看您的构建文件夹,看看 CMake 正在做什么。

如果您想知道我是如何知道这些信息的,那是因为我阅读了 Craig Scott 的 CMake 一书中的工具链部分“专业 CMake: 实用指南

这是一个link:https://crascit.com/professional-cmake/