C之(16)scan-build与clang-tidy使用
Author: Once Day Date: 2025年3月29日
一位热衷于Linux学习和开发的菜鸟,试图谱写一场冒险之旅,也许终点只是一场白日梦...
漫漫长路,有人对你微笑过嘛...
全系列文章可参考专栏: Linux实践记录_Once_day的博客-CSDN博客
参考文章:
- Clang C Language Family Frontend for LLVM
- 2.2. Command Line Usage: scan-build and CodeChecker --- Clang 21.0.0git documentation
- Clang Static Analyzer - 静态代码分析工具 - 煊奕 - 博客园
- 2.2. 命令行使用:scan-build 和 CodeChecker --- Clang 20.0.0git 文档 - Clang 编译器
- Clang-Tidy --- Extra Clang Tools 21.0.0git documentation
- c++静态代码扫描工具clang-tidy详细介绍-CSDN博客
- Clang-Tidy --- Extra Clang Tools 20.0.0git 文档 - Clang 编译器
文章目录
- C之(16)scan-build与clang-tidy使用
-
-
-
- [1. Clang项目介绍](#1. Clang项目介绍)
-
- [1.1 Clang概述](#1.1 Clang概述)
- [1.2 LLVM与Clang](#1.2 LLVM与Clang)
- [1.3 常用工具](#1.3 常用工具)
- [2. Scan-build介绍](#2. Scan-build介绍)
-
- [2.1 基础使用](#2.1 基础使用)
- [2.2 常见参数](#2.2 常见参数)
- [2.3 Gitlab流水线实践](#2.3 Gitlab流水线实践)
- [3. Clang-tidy介绍](#3. Clang-tidy介绍)
-
- [3.1 基础使用](#3.1 基础使用)
- [3.2 常见参数](#3.2 常见参数)
- [3.3 Vscode集成示例](#3.3 Vscode集成示例)
-
-
1. Clang项目介绍
1.1 Clang概述
Clang是一个由Apple主导开发的开源编译器前端项目,旨在提供一个现代化、高效、易于使用和可扩展的编译器工具链。Clang项目的主要目标是为C、C++、Objective-C等编程语言提供更好的编译支持,同时与底层的LLVM编译器基础设施紧密集成。
Clang采用模块化的架构设计,将编译过程分为词法分析、语法分析、语义分析、代码生成等多个阶段,每个阶段都有相应的库和工具来处理。这种模块化的设计使得Clang易于理解、维护和扩展,开发者可以方便地为Clang添加新的功能或优化现有功能。
Clang还注重提供友好的用户体验,它的错误诊断信息比传统编译器更加清晰、准确,帮助开发者快速定位和解决代码中的问题。此外,Clang还提供了一些额外的工具,如代码格式化、静态分析等,进一步提高了开发效率。
1.2 LLVM与Clang
LLVM和Clang是密切相关但又有所区别的项目,它们共同构成了一个完整的编译器工具链。
Clang是LLVM项目的一个子项目,主要负责编译器前端的工作,如词法分析、语法分析、语义分析等,将源代码转换为LLVM中间表示(IR)。
LLVM则主要负责编译器后端的工作,对Clang生成的LLVM IR进行优化、转换并生成目标平台的机器码。
Clang和LLVM的设计遵循模块化和可重用性的原则,它们之间通过标准的LLVM IR进行交互和衔接,形成了一个灵活、可扩展的编译器架构。
两者之间的区别:
- 功能定位:Clang主要是编译器前端,负责处理源代码并生成LLVM IR;LLVM则是编译器后端,负责对LLVM IR进行优化和目标代码生成。
- 适用语言:Clang主要支持C、C++、Objective-C等编程语言;LLVM则是语言无关的,可以支持多种编程语言。
- 工具集:Clang提供了一些额外的工具,如代码格式化、静态分析等;LLVM则提供了各种优化passes、JIT编译器、调试器等工具。
- 项目起源:Clang项目是由Apple主导开发的,旨在替代GCC;LLVM项目则起源于伊利诺伊大学厄巴纳-香槟分校,最初是一个研究项目。
1.3 常用工具
Clang项目除了提供核心的编译器功能外,还包含了一些非常实用的辅助工具,如Scan-build、Codechecker和Clang-tidy,这些工具可以帮助开发者提高代码质量、发现潜在缺陷并遵循最佳编程实践。
Scan-build是一个静态分析工具,它利用Clang的静态分析器对代码进行深入的分析,以发现潜在的缺陷和漏洞,如空指针解引用、内存泄漏、死锁等。Scan-build可以与现有的构建系统(如Make、CMake)无缝集成,并生成易于理解的HTML报告,帮助开发者快速定位和修复代码中的问题。Scan-build的分析过程是全面的,可以跨越不同的函数和文件,提供了比传统编译器警告更深入、更准确的缺陷检测能力。
Clang-tidy是一个基于Clang的代码检查和重构工具,它可以帮助开发者发现和修复代码中的风格问题、潜在缺陷以及现代C++的最佳实践偏离。Clang-tidy提供了一系列的检查规则(如命名规范、异常安全、性能优化等),开发者可以根据项目需求选择和配置这些规则。除了发现问题,Clang-tidy还可以自动应用修复,帮助开发者快速重构代码。与Scan-build不同,Clang-tidy主要关注代码风格和最佳实践,而不是深入的静态分析。
2. Scan-build介绍
2.1 基础使用
在ubuntu上安装Scan-build非常简单,如下所示:
bash
sudo apt-get install clang
sudo apt-get install llvm
sudo apt-get install clang-tools #包含工具集
scan-build 通过拦截编译命令来使用获取编译命令行,当在构建命令前加上 scan-build 时,scan-build 会将编译命令中的编译器(如 gcc、clang)替换为一个叫 ccc-analyzer
的 wrapper 程序。
ccc-analyzer
会先调用正常的编译器编译源文件,然后再调用 Clang 静态分析器分析源文件。静态分析器会模拟代码的执行过程,尝试找出各种潜在的 bug,如空指针解引用、内存泄露、死锁等。
分析器发现的问题会记录下来,生成一份 HTML 格式的报告。报告中列出了所有发现的问题,并提供了问题的代码位置、执行路径等详细信息。用户可以用浏览器查看这些 HTML 报告,了解代码中存在的各种潜在问题。
整个过程如下所示:
yacas
项目源文件 ==> [scan-build] ==> [ccc-analyzer] ==> [编译器]+[静态分析器] ==> [HTML报告] ==> 输出目录
可见,scan-build 本质上是通过"偷梁换柱"替换编译器,从而将静态分析器集成到项目的构建过程中,使代码分析变得透明和自动化。分析过程完全是静态的,不需要实际运行程序,因此比动态分析更快更轻量级。这种方式使得在大型项目中使用静态分析检查代码问题变得非常方便。
在构建命令前加上"scan-build"前缀即可对项目进行静态分析。支持make、xcodebuild等常见构建命令,例如:
bash
$ scan-build [scan-build options] <command> [command options]
$ scan−build make
scan-build会将构建命令后面的选项都传递给实际的构建命令,因此可以使用构建系统支持的各种选项,如指定并行构建的-j
选项:
bash
$ scan-build make -j4
scan-build的输出是一组HTML文件,代表分析过程发现的各种问题。默认存放在/tmp
目录下的一个子目录中。可以用-o
选项指定输出目录:
bash
$ scan-build -o ./analyze_results make
分析结果中包含一个index.html文件,在浏览器中打开它即可查看各种问题的报告。如果在scan-build时使用了-V
选项,构建结束后会自动打开该页面。
下面用一个简单的C源文件来演示操作:
c
#include <stdio.h>
int main()
{
int i;
printf("Hello, World!\n");
return i; // 返回未初始化的值
}
使用scan-build拦截编译命令并进行静态分析,通常情况下默认参数即可:
bash
onceday->output:$ scan-build gcc -c test.c
scan-build: Using '/usr/lib/llvm-18/bin/clang' for static analysis
test.c:7:5: warning: Undefined or garbage value returned to caller [core.uninitialized.UndefReturn]
7 | return i;
| ^~~~~~~~
1 warning generated.
scan-build: Analysis run complete.
scan-build: 1 bug found.
scan-build: Run 'scan-view /tmp/scan-build-2025-03-30-165354-2811989-1' to examine bug reports.
然后按照提示使用scan-view
查看结果,需要额外补充--host 10.52.25.98 --allow-all-hosts
参数,也就Web服务器监听的地址和允许访问的地址,根据实际情况填写即可。
bash
onceday->output:$ scan-view --host 10.52.25.98 --allow-all-hosts /tmp/scan-build-2025-03-30-165354-2811989-1
Starting scan-view at: http://10.52.25.98:8181
Use Ctrl-C to exit.
在浏览器访问对应网址,可以看到如下信息:

点击View Report可以查看详细的错误信息:

2.2 常见参数
参数名称 | 描述 |
---|---|
-o |
指定分析结果的输出目录。如果未指定,默认在 /tmp (Mac OS X 上为 TMPDIR)中创建一个目录存储报告 |
-h, --help |
显示帮助信息 |
-k, --keep-going |
在指定的构建命令中添加 "keep on going" 选项。目前支持 make 和 xcodebuild |
-v |
启用 scan-build 的详细输出。使用第二个和第三个 -v 会进一步增加详细程度 |
-V, --view |
在构建完成时,在 Web 浏览器中查看分析结果 |
--use-cc |
指定要用于编译的编译器路径。scan-build 会拦截编译命令,但它可能无法猜测项目使用的具体编译器 |
--use-c++ |
与 --use-cc 类似,但用于指定 C++ 编译器路径 |
--exclude |
指定静态分析器不分析此目录中的文件。适用于项目包含第三方库的情况 |
-enable-checker |
启用指定的检查器(Checker) |
-disable-checker |
禁用指定的检查器(Checker) |
-load-plugin |
使用 Clang 插件接口加载外部检查器 |
除此之外,scan-build 还支持所有传给构建命令的选项,如 make -j4
指定并行构建的线程数。控制分析过程输出格式的选项有 -plist
、-plist-html
、-sarif
等,可输出 HTML、plist 或 SARIF 格式的分析报告。
2.3 Gitlab流水线实践
在Gitlab流水线里面,可以将scan-build的静态分析自动化,并且根据检查的结果反馈流水线的成功状态。
编写一个辅助脚本,如下:
bash
#!/bin/bash
# 开启调试
# set -x
# 当前目录路径
export SOURCE_DIR=${SOURCE_DIR:-$(pwd)}
# 导入基本ANMK shell工具函数
source $SOURCE_DIR/scripts/utils.sh
# 定义参数
CHECK_ARGS="--status-bugs"
# 指定输出目录
OUTPUT_DIR="$SOURCE_DIR/clang-check"
rm -rf $OUTPUT_DIR
# 创建输出目录
mkdir -p $OUTPUT_DIR
INFO "OUTPUT_DIR: [$OUTPUT_DIR]"
# 运行检查命令
scan-build -o $OUTPUT_DIR $CHECK_ARGS make rebuild
if [ $? -ne 0 ]; then
ERROR "clang-check failed"
exit 1
fi
# 未检测到问题
INFO "clang-check success"
exit 0
gitlab-ci.yaml流水线配置如下:
yaml
develop-scan-build:
stage: local-build
tags:
- anmk-build
needs: []
script:
- echo "Check Netfpc Project - Develop Version - Scan Build"
- ./clang-check.sh
- echo "Check finished"
流水线运行效果如下:

3. Clang-tidy介绍
3.1 基础使用
ubuntu 24.04按照clang-tidy很简单:
bash
sudo apt install clang-tidy
Clang-Tidy支持不同场景下的使用:
- 集成于编译器:Clang-Tidy可以作为编译器的一部分运行,在编译过程中自动检测代码问题。这种方式使用简单,适合持续集成和自动化检查。
- 命令行工具:Clang-Tidy提供了灵活的命令行接口,可以对单个文件、目录或整个项目进行分析。通过指定不同的检查项和配置文件,可以自定义分析过程。
- 集成于IDE:许多流行的集成开发环境如Visual Studio、CLion等都内置了Clang-Tidy支持。开发者可以在编写代码时实时获得Clang-Tidy的反馈,并快速定位和修复问题。
Clang-Tidy不仅能发现问题,还可以自动修复其中的一部分。通过-fix
选项,Clang-Tidy可以直接修改源代码,减轻开发者的工作量。Clang-Tidy采用模块化设计,支持自定义检查规则。开发者可以根据项目需求,编写自己的检查模块,扩展Clang-Tidy的功能。
当作为命令行工具使用时,Clang-Tidy提供了灵活的选项和参数,以满足不同的分析需求。以下是一些常用的使用方式:
(1)分析单个文件:
bash
clang-tidy file.cpp -- -std=c++11 -Iinclude/
这个命令会对file.cpp进行静态分析,并使用C++11标准和include/目录作为头文件搜索路径。
(2)分析目录下的所有文件:
bash
clang-tidy src/*.cpp -- -std=c++14 -Iinclude/
这个命令会分析src/目录下的所有.cpp文件,使用C++14标准和include/目录作为头文件搜索路径。
(3)指定检查项:
bash
clang-tidy file.cpp -checks="-*,modernize-*,readability-*"
通过-checks
选项,可以指定启用或禁用特定的检查项。上述命令启用了modernize-
*和readability-*
两组检查,并禁用了其他所有检查。
(4)使用配置文件:
bash
clang-tidy file.cpp -config-file=.clang-tidy
通过-config-file
选项,可以指定一个配置文件,其中包含了自定义的检查项和编译器选项。这种方式适合于项目级别的统一配置管理。
(5)自动修复:
bash
clang-tidy file.cpp -fix -format-style=file
加上-fix
选项后,Clang-Tidy会自动修复能够确定的问题,并将修改后的代码写回源文件。-format-style
选项可以指定代码格式化风格。
(6)输出到文件:
bash
clang-tidy file.cpp -export-fixes=report.yaml
-export-fixes
选项可以将分析结果导出到一个文件中,方便后续处理和集成。
下面是命令行操作的一个简单演示:
bash
onceday->output:$ clang-tidy test.c -- -std=c11
1 warning generated.
/home/onceday/ease/libnetfpc/output/test.c:7:5: warning: Undefined or garbage value returned to caller [clang-analyzer-core.uninitialized.UndefReturn]
7 | return i;
| ^ ~
/home/onceday/ease/libnetfpc/output/test.c:5:5: note: 'i' declared without an initial value
5 | int i;
| ^~~~~
/home/onceday/ease/libnetfpc/output/test.c:7:5: note: Undefined or garbage value returned to caller
7 | return i;
| ^ ~
3.2 常见参数
Clang-Tidy 提供了许多参数,用于控制分析过程和自定义行为。以下是一些常见的参数:
名称 | 描述 |
---|---|
-checks= |
指定要启用或禁用的检查项。可以使用逗号分隔的列表,以"-"前缀表示禁用,无前缀表示启用。 如 -checks=-*,modernize-* 表示禁用所有检查,只启用 modernize- 相关的检查。 |
-config-file= |
指定一个配置文件,其中包含了自定义的检查项和编译器选项。 这样可以在项目级别上统一配置,方便管理。 |
-header-filter= |
指定一个正则表达式,用于过滤要分析的头文件。 只有匹配该表达式的头文件才会被分析。 |
-line-filter= |
指定一个正则表达式,用于过滤要分析的代码行。 只有匹配该表达式的代码行才会被分析。 |
-fix |
自动修复代码中的问题。 Clang-Tidy 会尝试自动修复能够安全修复的问题,并将修改后的代码写回源文件。 |
-format-style= |
指定代码格式化风格。 可以是预定义的风格名称(如 LLVM、Google),也可以是一个配置文件的路径。 |
-export-fixes= |
将分析结果导出到一个文件中,以便后续处理或集成到其他工具中。 导出的文件格式可以是 YAML 或 JSON。 |
-p= |
指定编译数据库的路径。 编译数据库包含了编译器选项和头文件搜索路径等信息,Clang-Tidy 需要这些信息来正确分析代码。 |
-extra-arg= |
向 Clang-Tidy 传递额外的编译器参数。 这对于一些特殊的编译选项或宏定义很有用。 |
-quiet |
抑制所有诊断信息的输出。 这在将 Clang-Tidy 集成到自动化流程中时很有用,以避免产生过多的噪音信息。 |
3.3 Vscode集成示例
在C/C++插件配置里面使能clang-tidy,并且关闭格式化功能,如下所示:

重点是使能C_CPP > Code Analysis > Clang Tidy: Enabled
。clang-tidy的配置不需要在这里填写,而是使用.clang-tidy
配置文件,这样每个项目都具有各自独立的配置。
Clang Tidy: Use Build Path
用于指定是否使用编译数据库(Compilation Database,一个 JSON 格式的文件),通常命名为 compile_commands.json
,其中包含了项目中每个源文件的编译命令和相关的编译选项。
Clang 工具链(如 Clang-Tidy、Clang-Format 等)可以利用编译数据库来获取正确的编译选项,如头文件搜索路径、宏定义等。这样,Clang 工具就能够准确地分析和处理源代码,而无需手动指定复杂的编译选项。
如果使用 CMake 构建项目,可以在 CMake 命令中添加 -DCMAKE_EXPORT_COMPILE_COMMANDS=ON
选项,这会让 CMake 在构建目录下生成 compile_commands.json
文件。
如果没有显式指定 -p
选项,Clang 工具会尝试在输入文件的所有父目录中搜索 compile_commands.json
文件。这个行为称为"编译数据库的自动发现",可以简化工具的使用。
如果项目没有使用 CMake,可以使用其他工具(如 Bear)来生成编译数据库。一旦生成了 compile_commands.json
,就可以将其路径传递给 -p
选项。
在VScode代码编辑界面,就可以很明显看到错误提示信息了(黄色波浪线):

Clang-tidy与VScode等IDE集成非常方便,由于Clang-tidy的报错很多与语法和编程风格有关,因此在编写代码阶段,实时反馈帮助很大。当然,是否采用建议要由对应的编码工程师来判断,毕竟容易出现误报或者"个人风格"强相关的问题。