源文件能在工程导入后正常显示,并不代表头文件就一定能被工具正确地解析出来。很多人在配置C/C++test的时候,都会碰到两个很实际的问题:头文件的路径究竟该怎么设,以及头文件解析失败了又该怎么去处理。要想把这两件事弄明白,重点就得放在编译器、头文件所在的目录、那些用到的宏定义,还有当初真实构建时用的参数,这几样东西是不是都能对得上。C/C++test分析源文件的时候,其实是直接去读它的内容,而头文件则是通过源文件里include的关系,被间接带进分析范围的;如果单独挑一个头文件出来,直接让它去跑分析,工具一般是不去单独处理它的。
一、C/C++test头文件路径怎么配置
配置头文件路径的时候,不能只简单地补一个include目录就算完事了。我们的工程里面,通常会包含好多个模块,还会用到芯片的SDK以及第三方的库,这时就要把项目自身的目录、编译器系统自带的标准目录,还有跟平台相关的那些依赖目录,全部理清楚。
1、先检查工程实际用到的编译命令
最好能在原始构建环境里面,先实际执行一次编译,把编译器是哪一个、都有哪些-I开头的路径、哪些-D定义的宏,以及要编译的源文件都包括哪些,这些信息先给确认下来。当通过命令行的方式来接入C/C++test的时候,这条编译命令是需要把编译器本身、编译参数和源文件都包含进去的;另外也可以利用构建跟踪,去生成一个BDF文件,或者把CMake生成的compile_commands.json直接导入进去,这样就可以让工具顺着我们项目真实的构建信息来跑了。
2、在工程属性里面把路径补充完整
如果用Eclipse界面来操作,可以在工程上面右键,进到它的属性页,然后打开【C/C++General】下面那个叫做【Preprocessor Include Paths Macros etc.】的选项;在里面有一个Providers页面,把【Parasoft C/C++test Include Paths provider】这一项给启用起来。这种方式对那些CDT托管的工程比较友好,能减少测试代码被错误标红,或者头文件跳来跳去却跳不过去的问题。
3、补齐平台和编译器的环境
碰到交叉编译的工程,还要专门确认一下编译器相关的环境变量有没有配好。Parasoft的文档里就提醒过,如果编译器族没有办法被自动识别出来,那么在启动Eclipse之前,就要先把PATH、LD_LIBRARY_PATH这类环境变量配好。要是芯片SDK的头文件、RTOS的头文件,还有工具链自带的那些头文件,都没有被纳入到当前的环境里,那么最后分析出来的结果肯定是不完整的。
4、尽量让路径保持稳定
在团队多人一起使用同一套工程的时候,项目的头文件最好不要长期依赖某一个人电脑上的临时目录。更好的做法是,用统一的工作区路径、构建脚本里的变量,或者用CI环境里的变量来管理它们,避免出现在自己本机一切正常,换到别的同事电脑上就全部报错的情况。
二、C/C++test头文件解析失败怎么处理
头文件解析一旦失败,不要一看到控制台里跳出一大堆报错,就急急忙忙地反复去添加目录。这个时候,先去看控制台里蹦出来的第一条预处理错误,比起后面跟着出来的一大串语法错误,第一条往往更能告诉我们问题到底出在了哪里。
1、先从抓不到文件的报错入手
当看见控制台出现“file not found”,或者“cannot open include file”这类提示的时候,首先要确认的是,头文件在磁盘上的真实位置到底在哪里,然后再把这个位置,跟编译命令里带着的-I路径去做一个对照,看看到底差在了哪里。很多时候,就是因为路径的层级多写了一层,或者少写了一层,再不然就是把相对路径放在了一个错误的工作目录下面,这些都会直接导致解析失败。
2、接着去查宏定义有没有漏
很多头文件里面,会根据芯片的型号、编译器的类型、操作系统的名称,还有各种功能的开关,去走不同的分支;缺少了某个关键的-D参数以后,工具很可能就会跑进一个错误的代码分支里去,紧接着后面就会连续报出类型没定义、结构体找不到,还有条件编译一类的异常。在动手处理的时候,一定要把原始构建脚本里用到的那些宏,也一起带入到工具里来,不能只把include目录复制一份就完了。
3、确认编译器配置是不是一致
像GCC、Clang、Visual C++,还有那些嵌入式的编译器,它们对扩展语法的支持本来就是有差别的。一个原工程明明在本地可以正常编译出来,但是换到C/C++test里面,却冒出来一大堆语法错误,这个时候就要回头去检查一下,工具里当前选中的那个编译器配置,到底是不是跟真实的工具链对应得起来。文档里面也很明确地建议过,一旦编译器识别不对劲,应该先去看一看启动时的环境。
4、检查一些特殊路径引起的问题
在某些比较特殊的场景下,比如说在QNX GCC的环境里,如果C/C++test这个工具的安装目录的名字当中带有空格,那么预处理阶段就有可能会出现异常。一旦碰上这类跟工具链本身相关的问题,可以试试把它挪到一个不带空格的路径下面,再去验证一下。
三、C/C++test头文件配置还要检查什么
当最基础的路径都补全了以后,还要把目光放到分析的范围和缓存的状态上面去。不然的话,虽然控制台里的错误看上去消失了,可实际的项目很可能仍然没有按照我们预想的样子进入分析。
1、记住要从源文件来触发分析
头文件本身只是一个被间接分析的对象,要想检查某个头文件里面是不是有规则方面的问题,正确的做法是去挑一个真正包含了它的源文件,或者干脆直接选中整个项目的根目录,再把分析跑起来。
2、记得刷新构建的数据
每当源代码有新加入的文件、切换了分支,或者修改了构建脚本以后,都是需要去重新生成一次BDF,或者重新生成compile_commands.json的。要是继续抱着旧的构建数据不撒手,那工具读到的东西,就仍然是老的路径和老的那些宏定义。
3、必要的时候可以把控制台的详细程度调高
进入【Parasoft】→【Preferences】→【Console】这个设置里面,把详细程度切换到High这一档。到了高详细模式下面,控制台会开始显示警告信息,还有实际被执行的那些命令行,这样就很方便我们去核对,到底是缺了哪一个include路径,还是少配了哪一个宏。
总结
所以,讲到底,C/C++test里头关于头文件路径应该怎么配置,核心的思路就是让工具能够读到真实的编译环境,这里面是要把编译器、以-I打头的路径、以-D定义的宏,还有源文件的范围,这四样东西一样都不少地喂给它。而头文件解析失败了要怎么处理,建议的顺序是先抓住控制台里的第一条预处理错误,再顺着文件的真实位置、那些宏定义有没有带齐、编译器的具体配置,还有构建数据是不是最新这几个方向去查。只要能把工程的构建链路给理顺了,后面不论是做静态分析还是跑单元测试,都不至于被一串毫不相干的报错给死死拖住。