CMake中set(var ${var} value)与set(var "${var}" value)工作机制解析
CMake两种set写法差异的底层原因
先看两种代码的实际运行效果:
无引号的代码示例
message("foo: ${foo}") set(foo ${foo} abc) message("foo: ${foo}") set(foo ${foo} def) message("foo: ${foo}") set(foo ${foo} ghi) message("foo: ${foo}")
输出:
foo: foo: abc foo: abc;def foo: abc;def;ghi
带引号的代码示例
message("foo: ${foo}") set(foo "${foo}" abc) message("foo: ${foo}") set(foo "${foo}" def) message("foo: ${foo}") set(foo "${foo}" ghi) message("foo: ${foo}")
输出:
foo: foo: ;abc foo: ;abc;def foo: ;abc;def;ghi
下面从CMake底层参数解析和变量展开逻辑拆解差异原因:
1. 无引号写法的逻辑
当foo还未定义时,${foo}会展开成空字符串。CMake在解析不带引号的参数时,会自动忽略空字符串参数——也就是说,set(foo ${foo} abc)实际等价于set(foo abc),直接把foo赋值为abc。
后续每次调用set(foo ${foo} def)时,${foo}是之前的列表值(比如第一次赋值后的abc),展开后作为单个参数传递,和def一起被set命令合并成新的分号分隔列表,所以结果依次是abc;def、abc;def;ghi。
2. 带引号写法的逻辑
同样,未定义的${foo}展开成空字符串,但引号会强制CMake把这个空字符串当作一个有效的独立参数。此时set(foo "${foo}" abc)实际接收到的参数是foo、空字符串、abc,CMake会把这两个值合并成列表,也就是;abc(空元素在前,abc在后,分号是CMake列表的默认分隔符)。
后续调用set(foo "${foo}" def)时,${foo}是之前的列表;abc,被引号包裹后会被当作一个完整的字符串";abc"传递,再加上def参数,合并后就得到;abc;def,重复操作就会得到;abc;def;ghi。
核心差异点
说白了,问题本质是CMake对空参数的处理规则:
- 不用引号时,未定义变量展开的空字符串会被参数解析器直接跳过,不会成为列表的一部分;
- 用引号包裹时,空字符串会被保留为列表里的一个正式空元素,后续每次赋值都会带着这个空元素叠加新内容。
内容的提问来源于stack exchange,提问作者starball
相关产品推荐
相关产品推荐

