【问题标题】:How to integrate C/C++ analysis tooling in Bazel?如何在 Bazel 中集成 C/C++ 分析工具?
【发布时间】:2021-11-20 05:08:21
【问题描述】:

我有一个代码分析工具,我想为每个 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 可以做些什么...

【问题讨论】:

    标签: bazel


    【解决方案1】:

    方面是做到这一点的正确工具。您要查找的信息包含在方面可以访问的cc_* 规则的providersfragmentstoolchains 中。具体来说,CcInfo 具有特定于目标的片段,cpp 片段具有从命令行标志配置的片段,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 attr 的注释。

    来自规则和工具链的信息已经结构化。根据您的分析工具的需求,直接提取它而不是生成完整的命令行可能更有意义。如果您想直接查看,大多数提供程序、片段和工具链都有详细记录。

    您可以将required_providers = [CcInfo] 传递给aspect 以将传播限制为包含它的规则,具体取决于您希望如何管理方面的传播。

    Integrating with C++ Rules 文档页面还有更多信息。

    【讨论】:

    • find_cpp_toolchain 在使用 --crosstool-top 时似乎不适用于方面。 print(ctx.rule.attr) 返回(除其他外)_cc_toolchain = <target //toolchains:cc_toolchain_suite>, _cc_toolchain_type = Label("@bazel_tools//tools/cpp:toolchain_type"),这意味着 _cc_toolchain 在那里,只是不像 find_cpp_toolchain 所期望的那样在 ctx.attr 中。倾向于用 --platforms 替换 --crosstool-top,但也许您知道更好的方法。
    • 平台还有其他优势,并且是未来的计划,所以如果可以的话,我会走这条路。但是,我认为ctx.attr._cc_toolchain 应该存在于find_cpp_toolchain,如果你将它添加到方面的属性(不是它所附加的规则,而是方面本身)?
    • 在方面实现中使用if hasattr(ctx.rule.attr, "_cc_toolchain") ... else find_cpp_toolchain() 似乎可行。可以说应该添加到 find_cpp_toolchain() 本身(在if hasattr(ctx, "rule") 下)。但是是的,平台就是这样。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多