CMake生成器表达式未被评估。

31

我不明白自己做错了什么。 每次我都得到字符串 "$<TARGET_FILE:tgt1>",而不是库的路径。

我创建了虚拟项目。

这是我的根CMakeLists.txt文件:

cmake_minimum_required (VERSION 3.0) # also tried 2.8 with the same result
set(PROJECT_NAME CMP0026)

add_subdirectory(src)

set(TGT_PATH $<TARGET_FILE:tgt1>)
message(STATUS "${TGT_PATH}")

这是我的src/CMakeLists.txt文件

add_library(tgt1 a.c)

文件 a.c 已创建并为空。

我尝试了以下生成器:Visual Studio 2013 Win64、Ninja 和 MingW Makefile。对于后两者,我使用了从 这里 下载的 Android 工具链。

我期望最后一个 message(STATUS 命令会打印出库文件的完整路径。然而,所有变体都打印出字符串 $<TARGET_FILE:tgt1>

1个回答

56

生成器表达式在配置时间(CMake解析CMakeLists、执行add_target()message()等命令时)不会被评估。此时,生成器表达式只是一个字面字符串-字符$后跟<,然后是T,然后是...

生成器表达式的评估发生在生成时间(这就是它们被称为“生成器表达式”的原因)。生成时间发生在解析和处理所有CMake代码之后,并且CMake开始处理其中的数据以生成构建系统文件。只有在那时,它才拥有评估生成器表达式所必需的所有信息。

因此,您只能在生成时间或更晚的时间(如构建时间)中使用生成器表达式。一个人为的例子是:

add_custom_target(
  GenexDemo
  COMMAND ${CMAKE_COMMAND} -E echo "$<TARGET_FILE:tgt1>"
  VERBATIM
)

在配置时,CMake将把字面字符串$<TARGET_FILE:tgt1>记录为COMMAND的参数。然后在生成时(对于每个配置,已知tgt1的位置并且不会再改变),它将用生成器表达式替换它。


谢谢。现在我明白了。因此,在我的情况下,最好的选择是切换到旧的CMP0026行为。 - wl2776
@wl2776 问题是,您在配置时间真的需要位置吗? - Angew is no longer proud of SO
1
@wl2776 你不能使用 file(GENERATE) 吗?它可以展开生成器表达式。 - Angew is no longer proud of SO
1
@wl2776 我并不是说file(GENERATE)可以完全替代;它不能。你可以通过正常运行文件来configure_file,然后file(READ)已配置的输出,并将其用作file(GENERATE)的输入。或者用string(CONFIGURE)替换中间文件配置步骤。 - Angew is no longer proud of SO
有一个关于cmake邮件列表的帖子讨论了这个问题:http://public.kitware.com/pipermail/cmake/2015-April/060350.html - Patrick B.
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接