编译语言的自动构建步骤
GitHub 托管的运行器始终预装 autobuild 所需的软件。若在 GitHub Actions 中使用自托管运行器,则可能需要自行安装额外软件才能使用 autobuild 进程。此外,如果仓库需要特定版本的构建工具,也可能需要手动安装。
注意
如果工作流使用 language 矩阵,autobuild 会尝试为矩阵中列出的每种编译语言执行构建。未使用矩阵时,autobuild 会尝试构建仓库中源码文件数量最多的受支持编译语言。除 Go 之外,若未提供显式的构建命令,其他编译语言的分析将会失败。
构建 C/C++
CodeQL 支持对 C/C++ 代码使用 none、autobuild 或 manual 三种构建模式。
当为包含 C/C++ 代码的仓库启用默认设置时,构建模式会自动设为 none。
无构建(C/C++)
CodeQL 将通过源文件扩展名推断 C/C++ 编译单元。对于每个发现的源文件,编译标志和包含路径会在不需要实际构建命令的情况下通过检查代码库自动推断。
C/C++ 无构建分析的准确性
在某些情况下,不使用 autobuild 或手动构建步骤而直接创建 CodeQL C/C++ 数据库可能会导致结果不够准确,例如当
- 代码严重依赖自定义宏/定义且这些宏在现有头文件中不可用时
- 代码库拥有大量外部依赖时
可以通过以下措施提升分析的准确性
- 将自定义宏和定义放入相关源文件包含的头文件中
- 确保外部依赖(头文件)可在系统包含目录或工作区中找到
- 在目标平台上运行抽取。例如,使用 Windows 运行器分析 Windows 项目,以获取平台特定的头文件和编译器
C/C++ 自动构建概览
| 支持的系统类型 | 系统名称 |
|---|---|
| 操作系统 | Windows、macOS 与 Linux |
| 构建系统 | Windows:MSBuild 与构建脚本 Linux 与 macOS:Autoconf、Make、CMake、qmake、Meson、Waf、SCons、Linux Kbuild 以及构建脚本 |
autobuild 步骤的行为取决于抽取运行所在的操作系统。
Windows 自动检测
在 Windows 上,autobuild 步骤会尝试通过以下方式自动检测适用于 C/C++ 的构建方法
- 在最靠近仓库根目录的解决方案(
.sln)或项目(.vcxproj)文件上调用MSBuild.exe。如果autobuild在相同(最短)深度检测到多个解决方案或项目文件,它会尝试全部构建。 - 调用看起来像构建脚本的文件——依次尝试 build.bat、build.cmd、build.exe。
Linux 与 macOS 自动检测
在 Linux 与 macOS 上,autobuild 步骤会检查仓库中的文件以判断使用的构建系统
- 首先在根目录查找构建系统。
- 若未找到,则在子目录中搜索唯一包含 C/C++ 构建系统的目录。
- 运行相应的配置命令。
C/C++ 运行器要求
在 Ubuntu Linux 运行器上,autobuild 可能会尝试自动安装检测到的配置和构建步骤所需的依赖。默认情况下,此行为在 GitHub 托管的运行器上是启用的,在自托管运行器上则禁用。可通过在环境中将 CODEQL_EXTRACTOR_CPP_AUTOINSTALL_DEPENDENCIES 设置为 true 或 false 来显式开启或关闭此功能。有关如何为单个工作流定义环境变量的更多信息,请参阅 将信息存储在变量中。
对于自托管运行器,除非启用了自动依赖安装,否则通常需要手动安装 gcc 编译器,且某些项目可能还需要 clang 或 msvc 可执行文件。还需要安装项目所依赖的构建系统(例如 msbuild、make、cmake、bazel)以及实用工具(如 python、perl、lex、yacc)。如果启用了自动依赖安装,必须确保运行器使用 Ubuntu 系统并且能够在不输入密码的情况下执行 sudo apt-get。
Windows 运行器需要将 powershell.exe 加入 PATH。
构建 C#
CodeQL 支持对 C# 代码使用 none、autobuild 或 manual 三种构建模式。
当为包含 C# 代码的仓库启用默认设置时,构建模式会自动设为 none。
无构建(C#)
在创建包含所有源文件和依赖的数据库之前,CodeQL 会恢复依赖并生成少量额外的源文件,以获得更准确的结果。
依赖恢复采用多种启发式和策略。主要信息来源包括:*.csproj、*.sln、nuget.config、packages.config、global.json 与 project.assets.json。如果组织为私有 NuGet 源配置了凭据,也会使用它们,详见 代码扫描默认设置对私有注册表的访问 以及 确定代码扫描默认设置是否使用过私有注册表。
以下生成的源文件是可选的,但会显著提升 CodeQL 数据库的正确性
- 全局生成的
using指令,用于处理 MSBuild 的隐式using特性。 - ASP.NET Core 视图文件(
.cshtml)会转换为.cs文件。
依赖程序集名称、生成的源文件、私有源中的依赖以及仓库中的源码会一起编译,用以创建 CodeQL 数据库。
C# 无构建分析的准确性
在未进行完整构建的情况下创建 CodeQL 数据库,依赖于能够成功恢复依赖并将仓库中的源码一起编译。若依赖恢复或源码编译出现问题,可能会影响 CodeQL 数据库的准确性以及代码扫描结果的可靠性。
可以通过以下措施提升分析的准确性
- 请确保能够访问公共互联网,或保证能够访问私有 NuGet 源,详见 代码扫描默认设置对私有注册表的访问。
- 检查仓库是否需要同一 NuGet 依赖的多个版本。CodeQL 只会使用一个版本,通常在出现多个版本时选取更新的版本。此策略在某些仓库中可能不适用。
- 检查是否引用了多个 .NET 版本,例如
net48、net5.0、netstandard1.6。CodeQL 只会使用一个版本,通常会选择出现的最高版本,这可能导致使用较低版本 .NET 的文件只能部分分析。 - 避免类名冲突,否则可能导致方法调用目标缺失,从而影响数据流分析。
C# 自动构建概览
| 支持的系统类型 | 系统名称 |
|---|---|
| 操作系统 | Windows、macOS 与 Linux |
| 构建系统 | .NET 与 MSBuild,以及构建脚本 |
Windows 自动检测
autobuild 过程会尝试通过以下方式自动检测适合 C# 的构建方法
- 在最靠近根目录的解决方案(
.sln)或项目(.csproj)文件上调用dotnet build。 - 在最靠近根目录的解决方案或项目文件上调用
MSBuild.exe。若autobuild检测到多个同等深度的解决方案或项目文件,它会尝试全部构建。 - 调用看起来像构建脚本的文件——依次尝试
build.bat、build.cmd、build.exe。
C#(Windows)运行器要求
在自托管运行器上进行 .NET Core 应用开发时,需要安装 .NET SDK(用于 dotnet)。
进行 .NET Framework 应用开发时,需要 Microsoft Build Tools(用于 msbuild)和 NuGet CLI(用于 nuget)。
Windows 运行器需要将 powershell.exe 加入 PATH。
如果计划使用 build-mode: none 创建 CodeQL 数据库,则还需要能够访问公共互联网,或者确保能够访问私有 NuGet 源。
Linux 与 macOS 自动检测
- 在最靠近根目录的解决方案(
.sln)或项目(.csproj)文件上调用dotnet build。 - 在最靠近根目录的解决方案或项目文件上调用
MSBuild。若autobuild检测到多个同等深度的解决方案或项目文件,它会尝试全部构建。 - 调用看起来像构建脚本的文件——依次尝试
build与build.sh。
C#(Linux 与 macOS)运行器要求
在自托管运行器上进行 .NET Core 应用开发时,需要安装 .NET SDK(用于 dotnet)。
进行 .NET Framework 应用开发时,需要 Mono 运行时(用于运行 mono、msbuild 或 nuget)。
如果计划使用 build-mode: none 创建 CodeQL 数据库,则还需要能够访问公共互联网,或者确保能够访问私有 NuGet 源。
手动构建时 CodeQL 为 C# 编译器注入的标志
CodeQL 跟踪器通过拦截构建过程并将信息转发给相应的 CodeQL 语言提取器,实现对所有编译语言的抽取。它会向 C# 编译器的调用中注入特定标志,以确保每个组件都被构建并包含在 CodeQL 数据库中,这可能导致 C# 代码的实际构建方式与您在 CodeQL 分析期间的预期不同。
/p:MvcBuildViews=true
将此选项设为 true 时,ASP.NET MVC 项目的视图会在构建过程中预编译,这有助于捕获错误并提升性能。跟踪器注入此标志,以确保 CodeQL 能发现并突出可能通过这些视图生成代码进行的数据流安全问题。更多信息请参阅 Microsoft Learn 中的 向 MVC 应用程序添加视图。
/p:UseSharedCompilation=false
将此选项设为 false 会禁用共享编译特性,可能导致构建时间变慢。当未显式指定 /p:UseSharedCompilation=false 时,msbuild 会启动编译器服务器进程,所有编译均由该单一进程完成。然而,CodeQL 跟踪器需要检查新创建进程的参数。
/p:EmitCompilerGeneratedFiles=true
将此选项设为 true 会在构建过程中生成编译器生成的文件。该选项会让编译器生成额外的源文件,以支持正则表达式增强、序列化、Web 视图生成等功能。这些生成产物通常不会写入磁盘,设为 true 后会强制写入磁盘,以便提取器能够处理这些文件。
对于某些遗留项目以及使用 .sqlproj 文件的项目,注入的 /p:EmitCompilerGeneratedFiles=true 属性可能导致 msbuild 出现意外问题。有关排查信息,请参阅 C# 编译器意外失败。
构建 Go
CodeQL 支持对 Go 代码使用 autobuild 或 manual 两种构建模式。
Go 自动构建概览
| 支持的系统类型 | 系统名称 |
|---|---|
| 操作系统 | Windows、macOS 与 Linux |
| 构建系统 | Go 模块、dep 与 Glide,以及包括 Makefile 和 Ninja 脚本在内的构建脚本 |
Go 自动检测
autobuild 过程会尝试在抽取所有 .go 文件之前,自动检测并安装 Go 仓库所需的依赖。
- 依次尝试执行
make、ninja、./build或./build.sh(顺序如列),直至其中一个命令成功且随后执行go list ./...亦成功,表明所需依赖已安装。 - 如果上述命令均未成功,则查找
go.mod、Gopkg.toml或glide.yaml,并分别执行go get(除非使用 vendoring)、dep ensure -v或glide install以尝试安装依赖。 - 最后,如果仍未找到上述依赖管理器的配置文件,则重新组织仓库目录结构以适配
GOPATH,并使用go get安装依赖。抽取完成后,目录结构会恢复正常。 - 抽取仓库中所有 Go 代码,等同于运行
go build ./...。
注意
如果使用默认设置,系统会查找 go.mod 文件,以自动安装兼容的 Go 语言版本。
Go 提取器选项
默认情况下,结尾为 _test.go 的测试代码不会被分析。可在使用 CodeQL CLI 时通过选项 --extractor-option extract_tests=true 覆盖此行为,或将环境变量 CODEQL_EXTRACTOR_GO_OPTION_EXTRACT_TESTS 设置为 true。
此外,默认会排除 vendor 目录。若需分析该目录,可在使用 CodeQL CLI 时传递 --extractor-option extract_vendor_dirs=true,或将环境变量 CODEQL_EXTRACTOR_GO_OPTION_EXTRACT_VENDOR_DIRS 设置为 true。
构建 Java 和 Kotlin
CodeQL 支持以下构建模式。
- Java:
none、autobuild或manual - Kotlin:
autobuild或manual
首次为仓库启用默认设置时,如果仅检测到 Java 代码,则构建模式设为 none;若检测到 Kotlin,或 Java 与 Kotlin 同时存在,则构建模式设为 autobuild。
如果之后在使用 none 构建模式的仓库中添加了 Kotlin 代码,CodeQL 分析会发出警告,说明不支持 Kotlin。此时需要禁用默认设置并重新启用。重新启用后,构建模式会切换为 autobuild,以便同时分析两种语言。或者,可以改为高级设置。更多信息请参阅 警告:在未构建的项目中检测到 X 个 Kotlin 文件,无法处理。
Java 无构建
在创建数据库之前,CodeQL 会尝试运行 Gradle 或 Maven 来提取准确的依赖信息(但不会实际执行构建),然后从所有 Java 文件中生成数据库。每个根级别的 Maven 或 Gradle 项目文件(在其祖先目录中不存在其他构建脚本的文件)都会被查询以获取依赖信息,并在冲突时优先选择更新的依赖版本。有关运行 Maven 或 Gradle 所需的运行器要求,请参阅 Java 运行器要求。
如果组织为私有 Maven 注册表配置了访问凭据,也会使用它,详见 代码扫描默认设置对私有注册表的访问 与 确定代码扫描默认设置是否使用了私有注册表。
Java 无构建分析的准确性
在未进行构建的情况下创建 CodeQL Java 数据库,可能会比使用 autobuild 或手动构建步骤得到的结果更不准确,尤其在以下情况下:
- 无法查询 Gradle 或 Maven 构建脚本的依赖信息,且基于 Java 包名的依赖猜测不准确。
- 仓库在构建过程中会生成代码。如果使用其他模式创建 CodeQL 数据库,这些生成的代码会被分析。
可以通过以下措施提升分析的准确性
- 请确保能够访问公共互联网,或保证能够访问私有制品仓库,详见 代码扫描默认设置对私有注册表的访问。
- 检查仓库是否需要同一依赖的多个版本。CodeQL 只能使用一个版本,通常会选择更新的版本。此策略在某些仓库中可能不适用。
- 检查是否有多个 JDK API 版本被不同的 Java 源文件引用。当出现多个版本时,CodeQL 会使用任意构建脚本要求的最高版本。这可能导致需要较低 JDK 版本的文件只能部分分析。例如,若部分文件需要 JDK 8,而某些构建脚本要求 JDK 17,则 CodeQL 会使用 JDK 17,导致需要 JDK 8 的文件只能部分分析。
- 避免类名冲突(例如多个文件中定义
org.myproject.Test),否则可能导致方法调用目标缺失,进而影响数据流分析。
Java 自动构建概览
| 支持的系统类型 | 系统名称 |
|---|---|
| 操作系统 | Windows、macOS 与 Linux(无限制) |
| 构建系统 | Gradle、Maven 与 Ant |
Java 自动检测
autobuild 过程会通过以下策略确定 Java 代码库使用的构建系统
- 在根目录搜索构建文件,优先检查 Gradle、随后 Maven,最后是 Ant。
- 运行找到的第一个构建文件。如果同时存在 Gradle 与 Maven 文件,则使用 Gradle 文件。
- 否则,在根目录的直接子目录中搜索构建文件。如果只有一个子目录包含构建文件,则运行该子目录中识别出的第一个文件(采用与步骤 1 相同的优先级)。如果多个子目录都包含构建文件,则报告错误。
Java 运行器要求
如果使用自托管运行器,需要预装所需的 Java 版本。
-
若运行器仅用于分析需要单一 Java 版本的仓库,则必须安装相应的 JDK,并确保其在
PATH环境变量中(以便能够找到java与javac)。 -
若运行器需要同时支持多个 Java 版本,则必须安装相应的 JDK 版本,并可通过
toolchains.xml文件进行指定。该文件是 Apache Maven 常用的配置文件,用于声明工具的位置、版本以及使用工具所需的其他配置。详情请参阅 Apache Maven 文档中的 使用工具链指南。
以下可执行文件在多数 Java 项目中可能需要,并应在 PATH 中可用,但并非所有项目都必须使用它们:
mvn(Apache Maven)gradle(Gradle)ant(Apache Ant)
同时还需安装项目依赖的构建系统(例如 make、cmake、bazel)以及实用工具(如 python、perl、lex、yacc),具体视项目而定。
Windows 运行器需要将 powershell.exe 加入 PATH。
构建 Rust
CodeQL 对 Rust 代码仅支持 none 构建模式。
Rust 无构建
CodeQL 使用 rust-analyzer 编译并运行构建脚本(build.rs 文件)以及宏代码,但不会执行完整构建。数据库会从所有 Rust 文件创建。必须存在 Cargo.toml 或 rust-project.json 文件。
Rust 运行器要求
Rust 分析需要预先安装 rustup 与 cargo。
构建 Swift
CodeQL 支持对 Swift 代码使用 autobuild 或 manual 构建模式。
Swift 自动构建概览
| 支持的系统类型 | 系统名称 |
|---|---|
| 操作系统 | macOS |
| 构建系统 | Xcode |
autobuild 过程会尝试从 Xcode 项目或工作区中构建最大的目标。
Swift 代码的代码扫描默认使用 macOS 运行器。由于 GitHub 托管的 macOS 运行器成本高于 Linux 与 Windows 运行器,建议仅构建需要分析的代码。有关 GitHub 托管运行器计费的更多信息,请参阅 GitHub Actions 计费。
Swift 代码的代码扫描不支持在属于 Actions Runner Controller(ARC)的运行器上执行,因为 ARC 运行器仅使用 Linux,而 Swift 需要 macOS 运行器。不过,你可以混合使用 ARC 运行器和自托管的 macOS 运行器。更多信息请参阅 Actions Runner Controller。
在 CodeQL 分析工作流中自定义 Swift 编译
Swift 构建支持 xcodebuild 与 swift build。建议在构建时仅针对单一架构,例如对 xcodebuild 使用 ARCH=arm64,或对 swift build 使用 --arch arm64。
可以向 xcodebuild 传递 archive 与 test 选项。但推荐使用标准的 xcodebuild 命令,因为它通常是最快的,并且足以满足 CodeQL 成功扫描的全部需求。
进行 Swift 分析时,必须始终在生成 CodeQL 数据库之前显式安装通过 CocoaPods 或 Carthage 管理的依赖。