Arm g++交叉编译器-isystem参数强制头文件C链接引发模板编译错误
Arm g++交叉编译器-isystem参数导致模板C链接错误的问题与解决
问题场景
该问题类似OpenBSD下G默认将系统头文件按C链接处理的情况,但发生在Arm g交叉编译器环境中:通过-isystem指定包含目录后,头文件内的C++模板被编译器判定为C链接,触发编译错误。
涉及文件
mbed/can.h
template <typename T> void ftest2(T t) { }
src/outer.cpp
template <typename T> void ftest0(T t) { } #include <can.h> template <typename T> void ftest1(T t) { }
编译命令及错误信息
执行编译命令:
/arm-none-eabi-gcc/7.3.1-1.2.2/.content/bin/arm-none-eabi-g++ \ -isystem"mbed" \ -c "src/outer.cpp"
报错内容:
In file included from src/outer.cpp:2:0: mbed/can.h:1:1: error: template with C linkage template <typename T> void ftest2(T t) { }
问题分析
cpp文件内的两个模板定义均正常编译,仅通过-isystem引入的头文件出现错误。原因是部分版本的GCC会对-isystem指定的目录做特殊处理,隐式将其中的头文件按C语言规则解析,而C语言不支持模板语法,因此报错。
必须使用-isystem的原因是实际场景中mbed代码目录存在大量需要屏蔽的警告,-isystem会自动屏蔽系统目录级别的警告。Stack Overflow上有相关评论提及该现象,但未给出解决方案:
给后续读者提个醒:如果用-isystem而非-I向gcc传递包含目录,部分版本可能会隐式应用C链接。——Jan Schatz 2019年7月1日15:02
解决方法
方法1:显式声明头文件的C++链接
在mbed/can.h中添加C链接声明,强制编译器用C规则解析该文件:
#ifdef __cplusplus extern "C++" { #endif template <typename T> void ftest2(T t) { } #ifdef __cplusplus } #endif
该方法从代码层面解决问题,兼容性最好,不会影响其他编译逻辑。
方法2:临时放宽编译检查(不推荐)
添加-fpermissive编译选项,让编译器忽略该类型的错误,但此选项可能掩盖其他潜在的代码问题,仅适合临时应急:
/arm-none-eabi-gcc/7.3.1-1.2.2/.content/bin/arm-none-eabi-g++ \ -isystem"mbed" \ -fpermissive \ -c "src/outer.cpp"
方法3:替代-isystem,单独屏蔽警告
如果可以放弃-isystem,改用-I指定包含目录,同时针对mbed目录的警告类型逐个屏蔽:
/arm-none-eabi-gcc/7.3.1-1.2.2/.content/bin/arm-none-eabi-g++ \ -I"mbed" \ -Wno-unused-variable \ -Wno-sign-compare \ -c "src/outer.cpp"
根据实际出现的警告,添加对应的-Wno-xxx选项,既能屏蔽mbed目录的警告,又不会触发C链接的错误。
内容的提问来源于stack exchange,提问作者avigt
相关产品推荐
相关产品推荐

