CMake中添加编译器标志的列表是否产生错误结果?

25

我需要在我的 CMake 文件(CMake 2.8.10.2)中为我的 C 和 C++ 编译行添加各种标志。我看到有些人使用 add_definitions,但据我所见那是用于预处理器标志 (-D)。我有一些不想传递给预处理器的标志。

因此,我一直在尝试修改 CMAKE_C_FLAGSCMAKE_CXX_FLAGS。我看到有些人使用类似以下的内容:

set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -new -flags -here")

但后来我在cmake文档中读到这样做的效率较低,正确的方法是使用 list(APPEND ...),像这样:

list(APPEND CMAKE_C_FLAGS -new -flags -here)

然而,当我这样做时,我的编译行包含了由分号分隔的标志,并且这是语法错误。我读到现在列表是内部存储的,但我想当我使用变量时这个问题会被cmake解决。这似乎非常基础; 我做错了什么吗?我的意思是,如果除了想要一个分号分隔的值列表(除了Windows %PATH%设置之外),这些列表还有什么用处呢?即使文档建议它不太有效/合适,我是否应该使用引号版本?


1
我使用宏来实现set()方法,因为复制时很容易出现变量名称不匹配的情况:宏(追加 名称 项目) set(${name} "${${name}} ${item}") endmacro() - Trass3r
2个回答

29
在CMake中,"list"是一串由分号分隔的项目字符串。例如:
set(FOO "a")
list(APPEND FOO "b") # now FOO="a;b"
list(APPEND FOO "c") # now FOO="a;b;c"

在CMake中,由空格分隔的字符串只是一个字符串,而不是列表。使用string(APPEND)命令来追加它。例如:

在CMake中,由空格分隔的字符串只是一个字符串,而不是列表。使用string(APPEND)命令来追加它。例如:

set(FOO "a")
string(APPEND FOO " b") # now FOO="a b"
string(APPEND FOO " c") # now FOO="a b c"

在缺少 string(APPEND) 命令的旧版本CMake中,你应该使用 set 命令替代。例如:

set(FOO "a")
set(FOO "${FOO} b")
set(FOO "${FOO} c")

根据您刚才解释的逻辑,set(FOO "${FOO} b") 将“b”添加到最后一个现有项(即“x;y;z”将变为“x;y;z b”)。您需要单独引用参数:set(FOO "${FOO}" "b")。对于编译器标志来说,这不是什么大问题,因为那些分离的参数将在传递给编译器之前被连接成空格,但最好还是避免这种情况。当然,您可以通过使用 list(APPEND ...) 来避免这个问题,但即使是这样,您也需要小心地单独引用参数。 - Arthur Tacca

9
在这种情况下,通常会使用set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -new -flags -here")技术。
你说得对,在大多数其他情况下,CMake可以将分号分隔的列表转换为编译器可以理解的内容(例如可执行文件中的源文件列表),但在这种情况下,CMake将标志作为单个完整的字符串传递给编译器/链接器。
如果你真的想保留标志列表作为CMake列表,那么在退出CMakeLists.txt之前,你需要自己将列表"翻译"成一个CMAKE_C_FLAGS的单个字符串值,但这是不寻常的。

3
更简洁的习惯用语是 string(APPEND CMAKE_C_FLAGS " -new-flags")。它的意思是在现有的 CMAKE_C_FLAGS 变量中追加一个新的标志,这个标志是 -new-flags - Chadversary

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