not*_*eus 3 c++ clang-format bazel
现在,我有一个非常愚蠢的漂亮打印脚本,该脚本做了一点git-fu查找(无条件地)格式化的文件,然后通过clang-format -i运行它们。这种方法有几个缺点:
过去,我能够使用CMake进行处理,这些处理具有一些好特性,我想在bazel中重现这些特性:
在CMake-land中,我受SCons代理目标欺骗的启发使用了这种策略:
介绍一个虚拟目标(例如source-> source.formatted)。与该目标关联的操作有两件事:a)运行clang-format -i source,b)输出/触摸名为source.formatted的文件(如果source.formatted比source更新,则对于合理的文件系统,这保证了合理的文件系统)不需要重新格式化)
添加一个虚拟目标(target_name.aggregated_formatted),该目标汇总与特定库/可执行目标的源相对应的所有.formatted文件
使库/可执行目标依赖于target_name.aggregated_formatted作为预构建步骤
任何帮助将不胜感激。
@abergmeier是正确的。通过实现宏及其组件,使我们更进一步。
我们将在中使用C ++ Stage 1教程bazelbuild/examples。
让我们先搞砸hello-world.cc:
#include <ctime>
#include <string>
#include <iostream>
std::string get_greet(const std::string& who) {
return "Hello " + who;
}
void print_localtime() {
std::time_t result =
std::time(nullptr);
std::cout << std::asctime(std::localtime(&result));
}
int main(int argc, char** argv) {
std::string who = "world";
if (argc > 1) {who = argv[1];}
std::cout << get_greet(who) << std::endl;
print_localtime();
return 0;
}
Run Code Online (Sandbox Code Playgroud)
这是BUILD文件:
cc_binary(
name = "hello-world",
srcs = ["hello-world.cc"],
)
Run Code Online (Sandbox Code Playgroud)
由于cc_binary通常不了解clang-format或不了解任何东西,因此我们创建一个名为的宏clang_formatted_cc_binary并将其替换cc_binary。现在,BUILD文件如下所示:
load(":clang_format.bzl", "clang_formatted_cc_binary")
clang_formatted_cc_binary(
name = "hello-world",
srcs = ["hello-world.cc"],
)
Run Code Online (Sandbox Code Playgroud)
接下来,创建一个名为的文件clang_format.bzl,该宏名为clang_formatted_cc_binary,只是一个包装器native.cc_binary:
# In clang_format.bzl
def clang_formatted_cc_binary(**kwargs):
native.cc_binary(**kwargs)
Run Code Online (Sandbox Code Playgroud)
此时,您可以构建cc_binary目标,但尚未运行clang-format。我们需要添加一个中间规则来执行该操作clang_formatted_cc_binary,我们将其称为clang_format_srcs:
def clang_formatted_cc_binary(name, srcs, **kwargs):
# Using a filegroup for code cleaniness
native.filegroup(
name = name + "_unformatted_srcs",
srcs = srcs,
)
clang_format_srcs(
name = name + "_formatted_srcs",
srcs = [name + "_unformatted_srcs"],
)
native.cc_binary(
name = name,
srcs = [name + "_formatted_srcs"],
**kwargs
)
Run Code Online (Sandbox Code Playgroud)
请注意,我们已native.cc_binary使用格式化的文件替换了的源,但保留了名称以允许在BUILD文件中就地替换cc_binary-> clang_formatted_cc_binary。
最后,我们将clang_format_srcs在同一clang_format.bzl文件中编写规则的实现:
def _clang_format_srcs_impl(ctx):
formatted_files = []
for unformatted_file in ctx.files.srcs:
formatted_file = ctx.actions.declare_file("formatted_" + unformatted_file.basename)
formatted_files += [formatted_file]
ctx.actions.run_shell(
inputs = [unformatted_file],
outputs = [formatted_file],
progress_message = "Running clang-format on %s" % unformatted_file.short_path,
command = "clang-format %s > %s" % (unformatted_file.path, formatted_file.path),
)
return struct(files = depset(formatted_files))
clang_format_srcs = rule(
attrs = {
"srcs": attr.label_list(allow_files = True),
},
implementation = _clang_format_srcs_impl,
)
Run Code Online (Sandbox Code Playgroud)
该规则遍历目标srcs属性中的每个文件,声明带有formatted_前缀的“虚拟”输出文件,并clang-format在未格式化的文件上运行以生成虚拟输出。
现在,如果您运行bazel build :hello-world,Bazel将在格式化文件上clang_format_srcs运行cc_binary编译操作之前运行这些操作。我们可以通过运行证明这bazel build与--subcommands标志:
$ bazel build //main:hello-world --subcommands
..
SUBCOMMAND: # //main:hello-world_formatted_srcs [action 'Running clang-format on main/hello-world.cc']
..
SUBCOMMAND: # //main:hello-world [action 'Compiling main/formatted_hello-world.cc']
..
SUBCOMMAND: # //main:hello-world [action 'Linking main/hello-world']
..
Run Code Online (Sandbox Code Playgroud)
查看的内容formatted_hello-world.cc,就像clang-format它的工作一样:
#include <ctime>
#include <string>
#include <iostream>
std::string get_greet(const std::string& who) { return "Hello " + who; }
void print_localtime() {
std::time_t result = std::time(nullptr);
std::cout << std::asctime(std::localtime(&result));
}
int main(int argc, char** argv) {
std::string who = "world";
if (argc > 1) {
who = argv[1];
}
std::cout << get_greet(who) << std::endl;
print_localtime();
return 0;
}
Run Code Online (Sandbox Code Playgroud)
如果只需要格式化的源代码而无需编译它们,则可以直接使用_formatted_srcs后缀运行构建目标clang_format_srcs:
$ bazel build //main:hello-world_formatted_srcs
INFO: Analysed target //main:hello-world_formatted_srcs (0 packages loaded).
INFO: Found 1 target...
Target //main:hello-world_formatted_srcs up-to-date:
bazel-bin/main/formatted_hello-world.cc
INFO: Elapsed time: 0.247s, Critical Path: 0.00s
INFO: 0 processes.
INFO: Build completed successfully, 1 total action
Run Code Online (Sandbox Code Playgroud)
您也许可以使用方面来实现这一点。由于不确定,Bazel 开发人员可能会指出这是否确实可能。
如果您熟悉规则和操作等,快速而肮脏的方法(类似于 CMake hackery)是编写一个宏。例如cc_library你会这样做:
def clean_cc_library(name, srcs, **kwargs):
lint_sources(
name = "%s_linted" % name,
srcs = srcs,
)
pretty_print_sources(
name = "%s_pretty" % name,
srcs = ["%s_linted"],
)
return native.cc_library(
name = name,
srcs = ["%s_pretty"],
**kwargs
)
Run Code Online (Sandbox Code Playgroud)
那么你当然需要将 every 替换cc_library为clean_cc_library. 和lint_sources是pretty_print_sources您必须自己实施并需要生成已清理文件列表的规则。