CMake file(STRINGS)解析含特殊字符配置文件异常问题排查
问题:CMake读取含特殊字符的CONFIG文件解析异常
在项目编译系统中,需读取CONFIG文件的每一行生成config.h头文件,使用CMake的file(STRINGS)获取每行内容时,遇到包含[];等特殊字符的行,解析结果不符合预期。
CONFIG文件片段
CONFIG_FEAT_A=y CONFIG_FEAT_B=y CONFIG_SOME_CHARS=" ,.;:-_)]}" CONFIG_SIZE=0
CMakeLists.txt片段
file(STRINGS ${CMAKE_BINARY_DIR}/.config ConfigContents) foreach(NameAndValue ${ConfigContents}) string(REGEX REPLACE "^[ ]+" "" NameAndValue ${NameAndValue}) string(REGEX MATCH "^CONFIG[^=]+" NAME ${NameAndValue}) string(REPLACE "${NAME}=" "" VALUE ${NameAndValue}) if(NAME AND NOT "${VALUE}" STREQUAL "") if(${VALUE} STREQUAL "y") file(APPEND ${CONFIG_H} "#define ${NAME} 1\n") elseif(${VALUE} STREQUAL "m") file(APPEND ${CONFIG_H} "#define ${NAME} 2\n") elseif(${VALUE} STREQUAL "n") file(APPEND ${CONFIG_H} "#undef ${NAME}\n") else() if(NOT "${VALUE}" STREQUAL "") file(APPEND ${CONFIG_H} "#define ${NAME} ${VALUE}\n") endif() endif() endif() endforeach()
解析结果异常情况
前两行可正常生成:
#define CONFIG_FEAT_A 1 #define CONFIG_FEAT_B 1
但第三行与第四行被错误合并,且丢失;字符:
#define CONFIG_SOME_CHARS " ,.:-_)]}";CONFIG_SIZE=0
问题原因
- 列表分隔符冲突:CMake中
;是列表元素的默认分隔符,file(STRINGS)读取到含;的行时,会将该行拆分成多个列表项。后续foreach遍历列表时,会把原本的一行内容拆成多段,还错误拼接下一行内容。 - 值提取逻辑缺陷:用
string(REPLACE "${NAME}=" "" VALUE ${NameAndValue})提取值时,如果VALUE中恰好包含${NAME}=子串,会触发错误替换。
解决方案
改用file(READ)读取整个文件内容,手动按换行符拆分每行,避免;被当作列表分隔符;同时改用更可靠的方式提取变量名和值:
# 读取整个CONFIG文件内容 file(READ ${CMAKE_BINARY_DIR}/.config ConfigContent) # 将换行符替换为分号,生成每行对应的列表元素 string(REPLACE "\n" ";" ConfigContents ${ConfigContent}) foreach(NameAndValue ${ConfigContents}) # 跳过空行 if(NameAndValue STREQUAL "") continue() endif() # 去除行首空格 string(REGEX REPLACE "^[ ]+" "" NameAndValue ${NameAndValue}) # 匹配CONFIG开头的变量名(到第一个=为止) string(REGEX MATCH "^CONFIG[^=]+" NAME ${NameAndValue}) if(NOT NAME) continue() endif() # 计算变量名加等号的长度,截取后面的内容作为值 string(LENGTH "${NAME}=" NAME_LEN) string(SUBSTRING "${NameAndValue}" ${NAME_LEN} -1 VALUE) if(NOT "${VALUE}" STREQUAL "") if(${VALUE} STREQUAL "y") file(APPEND ${CONFIG_H} "#define ${NAME} 1\n") elseif(${VALUE} STREQUAL "m") file(APPEND ${CONFIG_H} "#define ${NAME} 2\n") elseif(${VALUE} STREQUAL "n") file(APPEND ${CONFIG_H} "#undef ${NAME}\n") else() file(APPEND ${CONFIG_H} "#define ${NAME} ${VALUE}\n") endif() endif() endforeach()
效果说明
修改后,CONFIG文件中的特殊字符不会再触发列表拆分问题,每行内容都会被正确解析,生成的config.h内容如下:
#define CONFIG_FEAT_A 1 #define CONFIG_FEAT_B 1 #define CONFIG_SOME_CHARS " ,.;:-_)]}" #define CONFIG_SIZE 0
内容的提问来源于stack exchange,提问作者Kyon930
相关产品推荐
相关产品推荐

