从Make迁移至CMake时GCC灵活数组成员编译报错咨询
先理清楚你代码里的核心问题:你写的struct Foo用了C语言的**灵活数组成员(FAM)**特性——也就是末尾的int a[];,但随后struct Bar把Foo作为成员放在了结构体内部,导致这个灵活数组成员并没有处于Bar的末尾,这就是触发编译报错的直接原因。下面逐个解答你的疑问:
1. 为何原Make构建系统可编译通过?
你的旧Make构建系统里,要么是给GCC加了允许这种非标准写法的编译开关,要么是GCC 6.2对这种违规使用FAM的检查没有6.3严格。GCC在不同版本间会调整警告/错误的严格程度,6.3可能把这种FAM的错误用法从警告升级成了错误;而你的旧Make编译选项里,大概率用了类似-Wno-error=pedantic或者专门关闭该检查的开关,所以能顺利编译通过。
2. 灵活数组成员(FAM)是否为GCC专属扩展?
没错,FAM是C99标准正式引入的特性,但C++标准里完全没有这个特性。GCC为了兼容C代码,给C也提供了这个扩展支持,它不属于C标准范畴。其他编译器(比如Clang)也有类似扩展,但写法可能略有差异,比如Clang允许int a[0];的写法,而GCC在C++里支持int a[];作为FAM。
3. 哪个命令行开关控制FAM的行为?
GCC里和FAM相关的核心开关有这些:
-pedantic:启用严格的ISO标准检查,此时在C++里使用FAM会触发警告(如果同时搭配-Werror就会变成错误)。-Wflexible-arrays:专门控制FAM相关的警告输出,而当代码出现FAM不在结构体末尾的违规情况时,GCC会把这个当成错误,除非你用-Wno-error=flexible-arrays来关闭该错误检查。
另外,旧版本GCC可能默认允许这种错误用法,而6.3开始默认将其标记为错误,这也是你在新版本GCC上遇到问题的原因之一。
4. 如何配置CMake使其与原Make构建系统的编译行为一致?
你需要在CMake里添加和旧Make完全一致的编译开关,来关闭这个错误检查。具体操作如下:
首先确认旧Make里使用的编译开关(比如-Wno-error=flexible-arrays或者-Wno-pedantic这类),然后修改你的CMake配置,给目标添加对应的编译选项:
cmake_minimum_required(VERSION 3.9) project(foo VERSION ${FOO_VERSION} DESCRIPTION "foo") set(CMAKE_CXX_STANDARD 14) set(CMAKE_C_STANDARD 99) add_executable(foo foo.cpp foo_backup.cpp main.cpp) set_target_properties(foo PROPERTIES VERSION ${PROJECT_VERSION}) target_include_directories(foo PUBLIC ${CMAKE_SOURCE_DIR}/lib/include ${CMAKE_SOURCE_DIR}/lib/include/bar) # 添加和旧Make一致的编译开关,适配FAM扩展 target_compile_options(foo PRIVATE # 先添加你旧Make里的所有严格警告开关,示例: -Wall -Wextra # 关闭FAM相关的错误检查 -Wno-error=flexible-arrays # 如果旧Make里关闭了pedantic错误,也加上这行 # -Wno-error=pedantic )
另外要注意:你的代码是C++文件但用了C的FAM扩展,所以不要在CMake里设置CMAKE_CXX_EXTENSIONS OFF——保持默认的ON状态,GCC才会允许这些非标准扩展,和旧Make的行为保持一致。
最后提一句:你提供的代码片段里struct Bar末尾少了分号,虽然可能是输入错误,但也要修正,避免额外的编译问题。
内容的提问来源于stack exchange,提问作者kreuzerkrieg

