如何在 Bazel 中集成 C/C++ 分析工具?
How to integrate C/C++ analysis tooling in Bazel?
我有一个代码分析工具,我想 运行 每个 cc_library(和 cc_binary,对问题的其余部分默默暗示)。该工具有一个 CLI 接口:
- 一个工具项目文件
- 编译器细节,例如类型大小、内置函数、宏等
- 要分析的文件
- 文件路径,包括,定义
- 规则(不)适用
- 要添加到项目的文件
- 将文件与构建数据同步的选项
- JSON编译数据库
- 解析构建日志
- 分析并生成分析报告
我一直在研究如何将其集成到 Bazel 中,以便自动更新要分析的文件以及相关的包含和定义,并正确缓存任何分析结果。生成 JSON 编译数据库(使用第三方库)或解析构建日志都需要单独的 运行 和更新源代码树。对于这个问题,我认为这是我正在尝试删除的解决方法。
到目前为止,我尝试过使用 aspects
,向任何库添加分析方面。总体思路是有一个包含库不变配置的基础项目文件,附加 cc_library 文件进行分析,最后触发分析生成报告。但是我在执行时遇到了麻烦,我什至不确定它是否可能。
到目前为止,这是我的方面实现,尝试遍历 cc_library 属性和目标编译上下文:
def _print_aspect_impl(target, ctx):
# Make sure the rule has a srcs attribute
if hasattr(ctx.rule.attr, 'srcs'):
# Iterate through the files
for src in ctx.rule.attr.srcs:
for f in src.files.to_list():
if f.path.endswith(".c"):
print("file: ")
print(f.path)
print("includes: ")
print(target[CcInfo].compilation_context.includes)
print("quote_includes: ")
print(target[CcInfo].compilation_context.quote_includes)
print("system_includes: ")
print(target[CcInfo].compilation_context.system_includes)
print("define: " + define)
print(ctx.rule.attr.defines)
print("local_defines: ")
print(ctx.rule.attr.local_defines)
print("") # empty line to separate file prints
return []
我想不通的是如何在编译库时获取所有包含和定义:
- 来自依赖的库,递归
- copts,定义,包括
- 来自工具链
- 特征,cxx_builtin_include_directories
问题:
- 我如何获得丢失的标志,继续介绍的技术?
- 我能以某种方式检索编译操作命令字符串吗?
- 已使用构建日志附加到分析项目API
- 完全是其他解决方案?
- 也许可以用
cc_toolchain
代替 aspects
...
方面是做到这一点的正确工具。您要查找的信息包含在 providers, fragments, and toolchains of the cc_*
rules the aspect has access to. Specifically, CcInfo has the target-specific pieces, the cpp fragment has the pieces configured from the command-line flag, and CcToolchainInfo 中,其中包含工具链中的部分。
CcInfo in target
告诉您当前目标是否有该提供程序,并且 target[CcInfo]
访问它。
rules_cc my_c_compile example 是我通常寻找基于 CcInfo 的完整编译器命令的地方。像这样的事情应该从方面起作用:
load("@rules_cc//cc:action_names.bzl", "C_COMPILE_ACTION_NAME")
load("@rules_cc//cc:toolchain_utils.bzl", "find_cpp_toolchain")
[in the impl]:
cc_toolchain = find_cpp_toolchain(ctx)
feature_configuration = cc_common.configure_features(
ctx = ctx,
cc_toolchain = cc_toolchain,
requested_features = ctx.features,
unsupported_features = ctx.disabled_features,
)
c_compiler_path = cc_common.get_tool_for_action(
feature_configuration = feature_configuration,
action_name = C_COMPILE_ACTION_NAME,
)
[in the loop]
c_compile_variables = cc_common.create_compile_variables(
feature_configuration = feature_configuration,
cc_toolchain = cc_toolchain,
user_compile_flags = ctx.fragments.cpp.copts + ctx.fragments.cpp.conlyopts,
source_file = src.path,
)
command_line = cc_common.get_memory_inefficient_command_line(
feature_configuration = feature_configuration,
action_name = C_COMPILE_ACTION_NAME,
variables = c_compile_variables,
)
env = cc_common.get_environment_variables(
feature_configuration = feature_configuration,
action_name = C_COMPILE_ACTION_NAME,
variables = c_compile_variables,
)
该示例仅处理 C 文件(而非 C++),您必须更改操作名称以及它适当使用片段的哪些部分。
您必须将 toolchains = ["@bazel_tools//tools/cpp:toolchain_type"]
和 fragments = ["cpp"]
添加到 aspect
调用才能使用它们。如果您使用的是旧版工具链解析,另请参阅 find_cc_toolchain.bzl 中关于 _cc_toolchain
属性的说明。
来自规则和工具链的信息已经结构化。根据您的分析工具的需要,直接提取它而不是生成完整的命令行可能更有意义。如果您想直接查看,大多数提供程序、片段和工具链都有详细的文档记录。
您可以将 required_providers = [CcInfo]
传递给 aspect
以将传播限制为包含它的规则,具体取决于您希望如何管理方面的传播。
Integrating with C++ Rules 文档页面还有更多信息。
我有一个代码分析工具,我想 运行 每个 cc_library(和 cc_binary,对问题的其余部分默默暗示)。该工具有一个 CLI 接口:
- 一个工具项目文件
- 编译器细节,例如类型大小、内置函数、宏等
- 要分析的文件
- 文件路径,包括,定义
- 规则(不)适用
- 要添加到项目的文件
- 将文件与构建数据同步的选项
- JSON编译数据库
- 解析构建日志
- 分析并生成分析报告
我一直在研究如何将其集成到 Bazel 中,以便自动更新要分析的文件以及相关的包含和定义,并正确缓存任何分析结果。生成 JSON 编译数据库(使用第三方库)或解析构建日志都需要单独的 运行 和更新源代码树。对于这个问题,我认为这是我正在尝试删除的解决方法。
到目前为止,我尝试过使用 aspects
,向任何库添加分析方面。总体思路是有一个包含库不变配置的基础项目文件,附加 cc_library 文件进行分析,最后触发分析生成报告。但是我在执行时遇到了麻烦,我什至不确定它是否可能。
到目前为止,这是我的方面实现,尝试遍历 cc_library 属性和目标编译上下文:
def _print_aspect_impl(target, ctx):
# Make sure the rule has a srcs attribute
if hasattr(ctx.rule.attr, 'srcs'):
# Iterate through the files
for src in ctx.rule.attr.srcs:
for f in src.files.to_list():
if f.path.endswith(".c"):
print("file: ")
print(f.path)
print("includes: ")
print(target[CcInfo].compilation_context.includes)
print("quote_includes: ")
print(target[CcInfo].compilation_context.quote_includes)
print("system_includes: ")
print(target[CcInfo].compilation_context.system_includes)
print("define: " + define)
print(ctx.rule.attr.defines)
print("local_defines: ")
print(ctx.rule.attr.local_defines)
print("") # empty line to separate file prints
return []
我想不通的是如何在编译库时获取所有包含和定义:
- 来自依赖的库,递归
- copts,定义,包括
- 来自工具链
- 特征,cxx_builtin_include_directories
问题:
- 我如何获得丢失的标志,继续介绍的技术?
- 我能以某种方式检索编译操作命令字符串吗?
- 已使用构建日志附加到分析项目API
- 完全是其他解决方案?
- 也许可以用
cc_toolchain
代替aspects
...
- 也许可以用
方面是做到这一点的正确工具。您要查找的信息包含在 providers, fragments, and toolchains of the cc_*
rules the aspect has access to. Specifically, CcInfo has the target-specific pieces, the cpp fragment has the pieces configured from the command-line flag, and CcToolchainInfo 中,其中包含工具链中的部分。
CcInfo in target
告诉您当前目标是否有该提供程序,并且 target[CcInfo]
访问它。
rules_cc my_c_compile example 是我通常寻找基于 CcInfo 的完整编译器命令的地方。像这样的事情应该从方面起作用:
load("@rules_cc//cc:action_names.bzl", "C_COMPILE_ACTION_NAME")
load("@rules_cc//cc:toolchain_utils.bzl", "find_cpp_toolchain")
[in the impl]:
cc_toolchain = find_cpp_toolchain(ctx)
feature_configuration = cc_common.configure_features(
ctx = ctx,
cc_toolchain = cc_toolchain,
requested_features = ctx.features,
unsupported_features = ctx.disabled_features,
)
c_compiler_path = cc_common.get_tool_for_action(
feature_configuration = feature_configuration,
action_name = C_COMPILE_ACTION_NAME,
)
[in the loop]
c_compile_variables = cc_common.create_compile_variables(
feature_configuration = feature_configuration,
cc_toolchain = cc_toolchain,
user_compile_flags = ctx.fragments.cpp.copts + ctx.fragments.cpp.conlyopts,
source_file = src.path,
)
command_line = cc_common.get_memory_inefficient_command_line(
feature_configuration = feature_configuration,
action_name = C_COMPILE_ACTION_NAME,
variables = c_compile_variables,
)
env = cc_common.get_environment_variables(
feature_configuration = feature_configuration,
action_name = C_COMPILE_ACTION_NAME,
variables = c_compile_variables,
)
该示例仅处理 C 文件(而非 C++),您必须更改操作名称以及它适当使用片段的哪些部分。
您必须将 toolchains = ["@bazel_tools//tools/cpp:toolchain_type"]
和 fragments = ["cpp"]
添加到 aspect
调用才能使用它们。如果您使用的是旧版工具链解析,另请参阅 find_cc_toolchain.bzl 中关于 _cc_toolchain
属性的说明。
来自规则和工具链的信息已经结构化。根据您的分析工具的需要,直接提取它而不是生成完整的命令行可能更有意义。如果您想直接查看,大多数提供程序、片段和工具链都有详细的文档记录。
您可以将 required_providers = [CcInfo]
传递给 aspect
以将传播限制为包含它的规则,具体取决于您希望如何管理方面的传播。
Integrating with C++ Rules 文档页面还有更多信息。