如何在Bazel的cc_library规则中生成cool_app.h的预处理输出?
为Bazel构建的C++头文件生成预处理输出
问题描述
我用Bazel构建C++项目,完全不熟悉Bazel,只会复制现有规则或者给规则添加源文件。当前有如下cc_library规则:
cc_library( name = "cool_app", srcs = ["cool_app.cpp"], hdrs = ["cool_app.h"], deps = ["//modules/common"], )
我想为cool_app.h生成预处理后的可读输出,能否通过给这个现有规则添加选项实现?
更新补充
cool_app.h的内容如下:
#pragma once #define ENUM_INIT_LIST \ ADD_VALUE(First) \ ADD_VALUE(Second) \ #define ADD_VALUE(topic) topic, enum class Topic : int { Invalid = -1, TOPIC_INIT_LIST LAST_ENUM_ELEMENT, }; #undef ADD_VALUE #define ADD_VALUE(topic) Topic::topic, constexpr auto kAvailableTopics = std::initializer_list<Topic>({TOPIC_INIT_LIST}); #undef ADD_VALUE
我需要保存预处理后的输出,最终要得到类似这样的可读内容:
#pragma once enum class Topic : int { Invalid = -1, First, Second, LAST_ENUM_ELEMENT, }; constexpr auto AvailableTopics = std::initializer_list<Topic>({ Topic::First, Topic::Second, });
解决方案
没办法直接给现有的cc_library规则添加选项来生成预处理输出——你需要新增一个专门的规则来完成这个任务。Bazel内置的cc_library是用来编译库的,不负责生成预处理文件这类辅助输出。
最直接的方式是用Bazel的genrule调用C++编译器的预处理命令,具体步骤如下:
1. 添加genrule规则到BUILD文件
在你的BUILD文件里新增如下规则:
genrule( name = "preprocess_cool_app_h", srcs = ["cool_app.h"], outs = ["cool_app_preprocessed.h"], cmd = "$(CXX) -E -P -x c++ $< | sed 's/kAvailableTopics/AvailableTopics/g' > $@", tools = ["@bazel_tools//tools/cpp:cpp_compiler"], )
参数说明:
-E:让编译器只执行预处理步骤,不进行编译、汇编等后续操作-P:移除预处理生成的行号和文件标记,让输出更干净易读-x c++:明确指定处理的是C++文件,避免编译器因头文件后缀产生识别问题sed命令用于将原文件中的kAvailableTopics替换为你想要的AvailableTopics,如果不需要修改变量名,可以去掉这部分$<代表规则的输入源文件(这里就是cool_app.h),$@代表规则的输出文件
2. 处理依赖(如果有)
如果cool_app.h依赖//modules/common中的头文件,需要把这些依赖的头文件加入srcs,并在编译命令中添加包含路径:
genrule( name = "preprocess_cool_app_h", srcs = ["cool_app.h", "//modules/common:common_hdrs"], # 假设common模块有导出头文件的规则 outs = ["cool_app_preprocessed.h"], cmd = "$(CXX) -E -P -x c++ -I$(GENDIR)/modules/common $< | sed 's/kAvailableTopics/AvailableTopics/g' > $@", tools = ["@bazel_tools//tools/cpp:cpp_compiler"], )
3. 运行生成命令
在项目根目录执行以下命令:
bazel build //path/to/your/package:preprocess_cool_app_h
生成的预处理文件会位于bazel-bin/path/to/your/package/cool_app_preprocessed.h路径下。
如果后续需要频繁生成预处理文件,可以封装自定义Bazel规则,但对于新手来说,genrule是最快速上手的方案。
内容的提问来源于stack exchange,提问作者dEmigOd
相关产品推荐
相关产品推荐

