在使用STATIC 代码静态验证工具(后文简略为 ' STATIC ' **)**的过程中,客户最常遇到的困难之一就是工具链的设置问题。
工具链设置之所以困难,是因为不清楚为什么需要输入各种设定项,而且一旦出错,很难排查和解决。
为了帮助那些对工具链设置不熟悉的用户,本篇文章将为您简单易懂地整理出以下内容:
为什么需要进行工具链设置、STATIC是如何提取工具链信息的,以及一个简单的设置流程示例。
为什么需要进行工具链设置
要理解为什么需要进行工具链设置,首先需要了解C/C++代码是如何被转换为可执行文件的。
C/C++源代码会经过以下三个主要步骤,最终生成操作系统可以执行的程序:
预处理阶段(Preprocessing)
在进行C/C++开发时,为了减少重复代码的使用并提高可读性,通常会使用宏 和头文件。

<图1> 预处理阶段
预处理阶段的作用就是展开定义的宏,并将分散的头文件整合成一个源代码文件,从而生成一个"翻译单元"(Translation Unit)。
编译阶段(Compiling)
在经过预处理之后,编译器会以预处理后的代码为基础,正式开始编译工作。
<图2> 编译阶段
这一过程可以大致分为以下四个阶段:
-
1. 词法分析 ( Lexical Analysis ) 读取源代码并将其拆分为构成程序的最小单元(即"词法单元",Token)。 例如,变量名、关键字、运算符等都会被识别为各自的标记。
-
2. 语法分析( Syntax Analysis) 对词法分析得到的标记进行语法检查,确认它们是否符合语言的语法规则。 在此阶段会生成"抽象语法树"(AST,Abstract Syntax Tree)。 AST是一种以树状结构层次化地表示程序结构的方式,是后续分析与优化的基础。
-
3. 语义分析(Semantic Analysis) 在生成的AST基础上,进一步理解程序的实际含义。 不仅检查语法是否正确,还会识别语义错误(Semantic Error),比如将整数与字符串相加、除零等不合逻辑或错误的运算。
-
4. 中间代码生成(Intermediate Code Generation) 在完成语法和语义分析之后,基于AST生成中间代码,作为转换为机器码前的中间步骤。 中间代码通常是与平台无关的形式,之后会用于最终代码的生成和优化过程。
链接阶段(Linking)
在完成编译阶段后,每个源文件会生成一个名为目标文件(Object File)的文件。但这些目标文件还不是最终的可执行文件,因为其中涉及到的外部函数或全局变量等信息的地址尚未确定,仍需进一步处理。
链接阶段(Linking)就是将这些目标文件与所需的库文件连接起来,生成操作系统可以执行的完整的可执行文件(Binary)的过程。链接过程主要包括以下三个步骤:
-
1. 符号解析与地址确定 识别各个目标文件中散布的函数和全局变量等"符号(Symbol)",并为它们分配内存地址,使它们相互连接。这一过程的关键是找到在其他文件中定义的函数或变量,并将其正确连接起来。
-
2. 库文件合并 将程序中使用的标准库或用户自定义库与目标文件进行合并。对于需要外部引用的函数或类,从库中提取相应的实现并进行链接。像
printf()
、std::vector
这样的标准函数也是在这个阶段被链接进来的。 -
3. 生成可执行文件 当所有符号都已正确链接、内存地址也全部确认后,就会生成一个操作系统能够识别和执行的二进制可执行文件。
-
-
<图3> 链接阶段
正如所见,从C/C++源代码生成最终可执行文件的过程中,会经历预处理、编译、链接等多个阶段,而每个阶段中编译器的设置和环境都会产生重要影响。
STATIC之所以需要了解这些构建过程,是因为它在进行静态分析时会模拟整个构建流程。因为,只有准确知道用户使用了哪种编译器和设置了哪些选项,才能进行精确的静态分析。
因此,工具链设置不仅仅是简单的参数输入,更是提升STATIC 分析准确性和可信度的必要步骤。
STATIC如何提取工具链设置信息
为了让STATIC 能够对源代码进行准确的分析 ,必须完整反映出用户实际使用的编译环境信息。 为此,STATIC 使用了其自主开发的工具 CSBUILD,来自动提取并整理用户的工具链设置信息。
CSBUILD 主要执行以下三个核心任务:

<图4> 工具链设置提取流程
1. 收集分析所需的信息
CSBUILD会全面收集进行代码编译所需的各种信息,不仅包括源代码文件列表,还包括所使用的编译器类型与版本、编译时的选项、宏定义、系统头文件与用户自定义头文件路径等。
通过这些信息,STATIC可以在尽可能接近用户真实开发环境的条件下读取和分析代码。
2. 验证收集到的信息
CSBUILD会测试所收集的信息是否能够成功编译,以提前发现是否存在缺失的文件或路径配置错误等问题。
由于STATIC的分析是基于 AST(抽象语法树)进行的,一旦发生编译错误,将难以进行准确的分析。
因此,通过验证步骤可以最大限度地减少错误,并在必要时引导用户进行修复。
3. 上传至服务器
通过验证的信息会被转换成STATIC分析服务器能够识别的标准格式,并进行压缩上传。
服务器由此可以准确还原用户的实际开发环境,从而提供更加可靠和高质量的分析结果。
STATIC 的目标不仅是分析源代码本身,更是要理解代码所处的开发环境和配置 。 CSBUILD正是为了自动化这一过程而开发的工具,它有效降低了繁琐的工具链设置负担,让任何人都能更轻松地使用静态分析工具。
收集分析所需的信息
为考虑到用户所处的各种开发环境,STATIC提供了两种方式,帮助用户便捷地收集进行分析所需的信息:
1. SPEC 模式
SPEC 模式 是指用户手动编写 JSON 格式的文件 ,在其中输入分析所需的源代码列表、编译器信息、编译选项等。 虽然这种方式略显繁琐,但如果用户希望自由配置或精细调整构建环境,SPEC 模式就是一个非常有用的选择。
2. Build Hook 模式
Build Hook 模式 是在用户实际构建项目的过程中,自动收集分析所需信息 的一种方式。 这一模式的关键技术就是Hooking。Hooking 是将开发者编写的 Hook 库插入到构建过程中,拦截 API 调用、消息传递或事件流程等信息的技术。
正如前文所述,STATIC 的工作原理与编译器非常相似,因此在构建过程中通过 Hooking 获取的所有信息,几乎可以涵盖进行静态分析所需的全部配置。 借助 Hooking 技术,STATIC 能够自然且全面地提取分析配置,无需用户额外操作,提升了分析的准确性与便捷性。

<图5> Hooking 流程
此外,用户还可以选择不同的方式来收集源代码中所使用的头文件。
-
·Built-in 方式 : 该方式使用STATIC内置的预处理解析器(Parser)对源代码进行直接分析,从中提取出所需的头文件。 适用于不依赖实际构建过程、希望快速分析源代码的场景。
-
·Original 方式 : 该方式是在用户实际的构建环境中执行构建任务,并在过程中原样提取出实际使用到的头文件。 这种方式可以最大限度地还原真实环境,确保分析结果与实际构建一致。
用户可根据项目特性和分析需求,灵活选择最合适的头文件收集方法。
验证
在前一阶段收集到信息的基础上,STATIC 会在内部验证这些信息是否能够用于实际编译。
STATIC 分析器并不真正进行编译,而是通过生成 AST **(抽象语法树)**来执行静态分析。 因此,如果代码无法正常编译,AST 也将无法正确生成,最终分析也会失败。
通过这个过程,可以验证所收集的信息是否准确,提前防止分析错误的发生。
上传服务器
CSBUILD会将上述过程中收集到的源代码、编译器信息、编译选项以及分析配置等内容,按照与服务器约定好的格式进行保存,并进行压缩后上传至服务器。
用户的工具链设置流程
前面我们已经了解了为什么在 C/C++ 项目中需要进行复杂的工具链设置,以及STATIC是如何在内部收集这些信息的。
接下来,我们来看一下STATIC用户在实际使用过程中进行工具链设置的具体流程。
Build Hook 模式

<图6> Build Hook 模式画面
Build Hook 模式是在用户的实际环境中执行构建的同时,自动收集分析所需信息的一种方式。
首先,在STATIC 设置界面的顶部,启用 Build Hooking 开关。
使用此模式时,需要输入构建命令和编译器的安装路径。

<图7> Configuration 过程
选择用于构建项目的编译器,并添加所使用的系统头文件路径。 如果有需要额外添加或排除的编译选项 ,可以分别填写在 "Configuration to add" 和 "Configuration to exclude" 中。
其中的 preprocessor 条目是用于选择之前提到的头文件收集方式,可选择 Original 或 Built-in 模式。
SPEC 模式

<图8> Build Hooking 开关关闭后添加文件的流程
SPEC 模式是用户手动输入要分析的文件及环境配置信息的方式。
首先,在STATIC 设置界面顶部,将 Build Hooking 开关关闭 。 然后,手动添加需要进行分析的源文件。

<图9> 编译信息,头文件路径输入流程
接下来,输入所使用的编译器信息 和头文件路径 。 在这个过程中,与 Build Hook 模式不同,无需单独选择头文件收集方式。
由于 SPEC 模式并不会在用户环境中实际执行构建,因此默认使用STATIC内置的 解析器 (Built-in Parser ) 来收集头文件。 换句话说,分析环境完全依赖于用户所输入的信息来构建。
总结
STATIC 通过静态分析,在bug 实际发生之前就提前发现潜在问题,帮助开发者节省大量时间与成本,并显著提升代码质量。
此外,STATIC 还提供了多种编码风格规范检查规则 ,即使不是 bug,也能帮助找出可优化的代码,进一步改善代码结构。
尤其是在 C/C++ 这类开发环境多样且复杂的语言中,工具链配置常常令人望而却步。 STATIC 致力于简化和自动化这一流程,让任何人都能轻松开展静态代码分析工作。