Android NDK CMake配置C++17遇编译警告问题排查
你遇到的这个问题我之前也碰过——多个-std=参数叠加后,最后那个-std=gnu++11直接覆盖了前面设的C17选项,导致Clang实际还是按C11编译,所以结构化绑定才会弹出“是C++17扩展”的警告。下面一步步给你理清楚:
先搞懂-std=gnu++11从哪来
你已经搜到了,它来自Android SDK自带的CMake模块:cmake/3.6.4111459/share/cmake-3.6/Modules/Compiler/Clang-CXX.cmake里的CMAKE_CXX11_EXTENSION_COMPILE_OPTION变量。这个是CMake针对Clang默认加的选项,而且因为是最后追加到编译参数里的,所以不管你之前在gradle或CMakeLists里设了-std=c++1z还是-std=c++17,都会被它覆盖掉。
为啥明明设了C++17还会有警告?
因为最后那个-std=gnu++11生效了,Clang实际是按C11标准编译的。结构化绑定是C17才有的特性,在C++11里属于“扩展”,所以编译器会抛出那个警告。
彻底解决的两种方案
方案一:直接替换默认的扩展选项(你当前用的方法)
在CMakeLists.txt的开头(最好在cmake_minimum_required之后)加一行:
set(CMAKE_CXX11_EXTENSION_COMPILE_OPTION "-std=c++17")
这个操作直接把CMake默认的C11扩展选项换成了C17,确保最后生效的是你要的标准,警告自然就没了。
方案二:用CMake官方推荐的标准设置(更规范)
CMake有专门的变量来管理C标准,比手动改编译选项靠谱多了,还能满足你“要纯C17而非GNU扩展”的需求:
# 指定使用C++17标准 set(CMAKE_CXX_STANDARD 17) # 强制要求编译器支持C++17,不支持就报错 set(CMAKE_CXX_STANDARD_REQUIRED ON) # 禁用GNU扩展,用纯标准C++ set(CMAKE_CXX_EXTENSIONS OFF)
用这个方法,CMake会自动帮你处理编译参数,不用再担心被默认选项覆盖。
额外小优化:统一gradle里的设置
为了避免参数混乱,建议把gradle里的cppFlags也改成C++17:
cppFlags "-std=c++17 -fexceptions"
这样前后设置统一,也减少参数叠加的问题。
以后再遇到类似问题的排查技巧
如果下次又找不到某个编译参数的来源,可以试试这些方法:
- 在gradle的
externalNativeBuild.cmake.arguments里加--verbose,看更详细的构建日志,追踪参数是怎么来的 - 到CMake构建目录下执行
cmake -LAH,能列出所有CMake变量的取值,很容易找到和-std=相关的配置 - 搜索Android SDK/NDK里的CMake模块文件,默认的编译选项大多藏在这些地方
内容的提问来源于stack exchange,提问作者Scindix

