news 2026/9/22 9:47:45

Infer 项目分析实战:构建系统集成、编译数据库与多语言捕获完整指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Infer 项目分析实战:构建系统集成、编译数据库与多语言捕获完整指南

Infer 项目分析实战:构建系统集成、编译数据库与多语言捕获完整指南

【免费下载链接】inferA static analyzer for Java, C, C++, and Objective-C项目地址: https://gitcode.com/gh_mirrors/infer/infer

本篇技术指南围绕 Facebook Infer 静态分析器如何"接进"你的构建流程展开:它支持哪些编译器和构建系统、每种集成方式的最稳用法、编译数据库(compilation database)的底层处理机制,以及遇到不受支持的构建系统时如何用--force-integration兜底。读完本文,你将能够把 Infer 接入 ant、Buck、cmake、Gradle、Make、Maven、Xcodebuild、xctool 等常见构建体系,并对 Java、C/C++/Objective-C 代码执行完整或增量分析。

Infer 支持的编译器与构建系统总览

Infer 分析文件的入口是编译器命令:官方支持通过javac(Java)与clang(C/C++/Objective-C)直接分析。也可以把gcc作为入口,但 Infer 内部仍会用clang来编译你的代码,因此如果你的代码无法用clang编译,这条路就可能走不通。

从源码结构看,Infer 支持的构建系统在 infer/src/base/Config.ml 中通过build_system_exe_assoc表显式登记,多个可执行文件可以映射到同一个构建系统,其中第一个条目用于打印当前运行模式:

构建系统可识别的前端可执行文件
antant
buck2buckbuck2
gradlegradlegradlew
javajava
javacjavac
kotlinckotlinc
clangccclanggccclang++c++g++
hackchackc
makemakeconfigurecmakewaf
mavenmvnmvnw
ndk-buildndk-build
pythonpython3
rebar3rebar3
rustrustc
swiftswiftc
erlangerlc
xcodebuildxcodebuild

注意:cmake也出现在该表中并映射到 make 模式(见后文"cmake"一节的两种用法),而configurewaf这类脚本同样按 make 模式处理。每个构建系统对应一种"驱动模式",infer run -- <build command>会把命令分发到对应的驱动实现,这一逻辑位于 infer/src/integration/Driver.ml 的mode_of_build_command。某个构建系统具体如何被支持,可查看infer capture --help手册中的 SYNOPSIS 部分。

用编译器直接分析单个文件

分析单文件项目是最简单的用法,直接以编译命令作为 infer 的参数即可:

infer run -- javac Hello.java infer run -- clang -c file.c

这里--之后的内容会被原样交给真正的编译器执行。文件照常被编译,同时被 Infer 翻译成内部中间表示用于后续分析——这意味着没有被编译的文件也不会被分析。因此在对整个项目做首次分析前,务必先执行 clean(如make cleangradle clean),确保编译器编译了全部文件,Infer 也随之分析全部文件(参见 Infer 工作流两阶段说明)。

主流构建系统集成实战

ant

infer run -- ant

Buck

对 Buck 项目,把要分析的 target 作为参数传入:

infer run -- buck <buck target>

这会计算传入 target 中的 Infer 告警列表。若希望同时分析所有传递依赖(transitive dependencies):

infer run -- buck --deep <buck target>

需要注意:--deep与普通 Buck 编译模式的区别仅对 Java 项目有效,对其他类型的项目,--deep选项不产生任何效果。从 Driver.ml 的源码看,buck2 模式下还会依据指定的 buck 模式(Clang/Erlang/Java/Python)选择对应的驱动实现。

cmake

最稳健的方式是让 cmake 生成编译数据库,再交给 Infer 处理:

cd build cmake -DCMAKE_EXPORT_COMPILE_COMMANDS=1 .. cd .. infer run --compilation-database build/compile_commands.json

另一种方式是"欺骗" cmake 使用 infer 替代系统编译器(infer 在 PATH 上以同名包装器覆盖编译器):

cd build infer compile -- cmake .. infer run -- make -j 4

关于第二种方式的原理见下文 Make 一节:cmake 在build_system_exe_assoc中被映射到 make 模式,因此infer compile -- cmake ..捕获的仍是 make 风格命令,随后infer run -- make -j 4复用已捕获的结果。

Gradle

infer run -- gradle <gradle task, e.g. "build"> infer run -- ./gradlew <gradle task, e.g. "build">

gradlegradlew都映射到 gradle 构建系统。如果项目要求增量式(incremental)构建系统的改动级分析,可结合--reactive模式使用,详见下文"全局与增量工作流"。

Make

Make 集成通过在运行时修改PATH,把 make 调用的 C/C++/Objective-C 或 Java 编译器替换为 infer 包装器来实现:

infer run -- make <make target>

这个机制并不总是有效:如果 Makefile 硬编码了编译器的绝对路径(例如直接调用/usr/bin/gcc而非gcc),由于集成依赖 PATH 覆盖,这类调用会绕过包装器。仓库中 infer/lib/wrappers/ 目录存放了这些包装器:ccclangclang++g++gccc++均为指向bin/infer的符号链接,而 javac 是一个 bash 脚本——它通过INFER_OLD_PATH找到宿主javac,先执行宿主编译器,再以infer capture --continue -- javac <args>触发捕获,并用INFER_COMPILER_WRAPPER_IN_RECURSION防止包装器自我递归调用。

Maven

infer run -- mvn <maven target>

mvnmvnw均映射到 Maven 模式。

Xcodebuild

iOS/macOS 项目最稳健的方式是先生成编译数据库,再交给 Infer:

xcodebuild <your build options> | tee xcodebuild.log xcpretty -r json-compilation-database -o compile_commands.json < xcodebuild.log > /dev/null infer run --skip-analysis-in-path Pods --clang-compilation-db-files-escaped compile_commands.json

注意--clang-compilation-db-files-escaped:Xcode 产出的编译命令是经过 shell 转义的,因此需要这一选项(对应源码中的compilation_database_escaped,见 Config.ml)。--skip-analysis-in-path Pods用正则匹配并跳过Pods路径下的文件。

Infer 也提供直接替换 xcodebuild 所用编译器的集成方式。例如对 iOS 应用:

infer run -- xcodebuild -target <target name> -configuration <build configuration> -sdk iphonesimulator

此外还有一种基于xcpretty的替代集成:给 infer 传入--xcpretty即可,xcodebuild 的输出会经 xcpretty 管道转为编译数据库。该选项在 Config.ml 中定义为--xcpretty(默认关闭),其底层实现在 CaptureCompilationDatabase.ml:get_compilation_database_files_xcodebuild通过进程管道运行xcodebuild | xcpretty --report json-compilation-database --output <tmp>,把产物作为转义形式的编译数据库交给捕获流程。

xctool

与 Xcode 的编译数据库路线一致:

xctool.sh <your build options> -reporter json-compilation-database:compile_commands.json infer run --skip-analysis-in-path Pods --clang-compilation-db-files-escaped compile_commands.json

编译数据库(Compilation Database):最通用的集成方式

cmake、Xcode、Buck 等许多构建系统都能生成编译数据库(JSON 格式的 compile_commands 文件)。Infer 可以直接消费该文件,从而绕开对具体构建系统的识别:

infer --compilation-database compile_commands.json

对应选项定义在 Config.ml:--compilation-database可以多次指定,且与--compilation-database-escaped(针对 Xcode 这类含 shell 转义参数的数据库)并存。

从源码看,这一模式的处理链路如下:

  1. 在 Driver.ml,当命令行其余参数为空且检测到--clang-compilation-dbs(或--compilation-database)时,进入ClangCompilationDB {db_files}模式;
  2. CaptureCompilationDatabase.capture 把所有数据库路径转为绝对路径,并通过CompilationDatabase.from_json_files解析 JSON;
  3. 对每条编译命令,create_cmd(CaptureCompilationDatabase.ml)把可执行文件替换为 wrappers 目录下的clang/clang++(依据命令后缀是否含++判断),并追加-fsyntax-only -fno-builtin参数——即只做语法层面的前端捕获,不产生真实目标文件;
  4. is_skipped(第 87-90 行)用--skip-analysis-in-path提供的正则对源文件相对路径做匹配,匹配上的文件不参与捕获;--skip-analysis-in-path-skips-compilation可进一步控制这些路径是否连编译都跳过(Config.ml,默认false,即仍然编译);
  5. 捕获任务通过进程池按--jobs并行执行(第 56-62 行)。

其他构建系统与 --force-integration 兜底

如果 Infer 无法识别你的构建命令,会报出如下错误:

$ infer run -- foo Usage Error: Unsupported build command foo

该错误由 Config.ml 中的build_system_of_exe_name抛出——build_system_exe_assoc反向查找可执行文件名失败时,它会以 UserError 终止并提示使用--force-integration。其错误信息会列出所有受支持的构建系统。

如果构建系统与上表某一项行为一致,可用--force-integration强制走同一种集成。例如让foo表现得与make相同:

infer run --force-integration make -- foo

在 Driver.ml 中,force_integration指定的构建系统只在原始发起进程is_originator)中生效,子进程仍按实际可执行文件名识别;其命令行定义见 Config.ml,类型为build_system option(Config.mli)。

如果你的构建系统更加特殊、无法输出编译数据库,可以尝试先手工生成 compile_commands.json 再走编译数据库模式;若仍不可行,则需要反馈给 Infer 社区寻求支持。

让分析更快、更完整的两个实践要点

  1. 并行加速:Infer 可以并行运行编译命令,例如infer run -- make -j8。编译数据库模式的并行度则受--jobs控制,见run_compilation_database中的进程池实现(CaptureCompilationDatabase.ml)。
  2. 分析前先 clean:对项目首次运行 Infer 前执行clean(make 项目用make clean,Gradle 用gradle clean,依此类推),否则增量构建系统可能跳过已编译文件,导致 Infer 漏分析。

全局分析与增量分析(reactive 模式)衔接

虽然本页聚焦构建系统接入,但两种运行模式直接影响你如何调用上述命令,见 Infer 工作流文档 的完整说明,要点如下:

  • 默认(全局)模式:infer run -- <build command>每次都会删除旧infer-out/并全量分析;首次运行前需 clean 构建产物。
  • 增量(reactive)模式:infer run --reactive -- <build command>保留infer-out/,只分析改动文件及其依赖,适合增量构建系统的日常开发循环;可用--continue把多次改动合并为一次分析,也可单独执行infer run --reactive --continue -- analyze对当前改动做隔离分析。
  • 分析结果输出在标准输出及infer-out/report.txt,可在同一目录运行infer explore查看每个告警的详细错误轨迹。

延伸阅读

  • Infer 工作流(capture/analyze 两阶段与全局/增量模式)
  • 从零开始的 Infer 使用入门
  • 各构建系统的 SYNOPSIS 细节:infer capture --helpinfer run --help
  • 编译器包装器实现:infer/lib/wrappers/javac 与 infer/lib/wrappers/ 下指向bin/infer的符号链接
  • 构建系统识别与驱动分发:infer/src/base/Config.ml、infer/src/integration/Driver.ml
  • 编译数据库捕获实现:infer/src/integration/CaptureCompilationDatabase.ml

【免费下载链接】inferA static analyzer for Java, C, C++, and Objective-C项目地址: https://gitcode.com/gh_mirrors/infer/infer

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/22 6:20:41

ESP32双网络语音识别实战:唤醒词与命令词协同架构设计

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/22 6:19:32

国产AI生成PPT动画实测:效率提升10倍?以YOLO讲解为例

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/22 1:04:59

ABAP源码解析实战:SCAN ABAP-SOURCE自动化技巧

1. 从重复劳动到自动化&#xff1a;ABAP源码解析的实战技巧在SAP项目实施过程中&#xff0c;我们经常会遇到需要从大量ABAP代码中提取特定信息的场景。以我最近处理的CRM工单流程代码为例&#xff0c;include程序LCRM_ORDER_OWF03包含了608行状态判断逻辑&#xff0c;其中分布着…

作者头像 李华