Skip to content

Commit ccebc1a

Browse files
Add Rules For Clang-Format [BUILD-305] (#5)
Co-authored-by: Isaac Torres <[email protected]>
1 parent 6e28b4b commit ccebc1a

File tree

6 files changed

+176
-0
lines changed

6 files changed

+176
-0
lines changed

clang_format/.clang-format

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# Complete list of style options can be found at:
2+
# http://clang.llvm.org/docs/ClangFormatStyleOptions.html
3+
---
4+
Language: Cpp
5+
BasedOnStyle: Google
6+
Standard: Cpp11
7+
BinPackParameters: false
8+
BinPackArguments: false
9+
...

clang_format/BUILD

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
load(":choose_clang_format.bzl", "choose_clang_format")
2+
3+
filegroup(
4+
name = "clang_format_config_default",
5+
srcs = [".clang-format"],
6+
)
7+
8+
label_flag(
9+
name = "clang_format_config",
10+
build_setting_default = ":clang_format_config_default",
11+
visibility = ["//visibility:public"],
12+
)
13+
14+
choose_clang_format(
15+
name = "clang_format_bin",
16+
visibility = ["//visibility:public"],
17+
)
18+
19+
filegroup(
20+
name = "_clang_format_bin",
21+
srcs = [":clang_format_bin"],
22+
)
23+
24+
sh_binary(
25+
name = "clang_format",
26+
srcs = [
27+
"run_clang_format.sh",
28+
],
29+
args = [
30+
"format_all",
31+
"$(location :_clang_format_bin)",
32+
"$(location :clang_format_config)",
33+
],
34+
data = [
35+
":_clang_format_bin",
36+
":clang_format_config",
37+
],
38+
visibility = ["//visibility:public"],
39+
)
40+
41+
exports_files(
42+
glob(["*.bzl"]) + ["run_clang_format.sh"] + [".clang-format"],
43+
visibility = ["//visibility:public"],
44+
)

clang_format/choose_clang_format.bzl

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
def _choose_clang_format(ctx):
2+
out = ctx.actions.declare_file("clang_format_bin.sh")
3+
4+
ctx.actions.run_shell(
5+
outputs = [out],
6+
command = """
7+
if command -v clang-format-14 &> /dev/null
8+
then
9+
echo clang-format-14 \\"\\$@\\" > {0}
10+
elif command -v clang-format &> /dev/null
11+
then
12+
echo clang-format \\"\\$@\\" > {0}
13+
else
14+
err_msg='clang-format-14 / clang-format: command not found'
15+
echo $err_msg
16+
echo "echo "$err_msg">&2" >> {0}
17+
echo "exit 1" >> {0}
18+
fi
19+
""".format(out.path),
20+
)
21+
22+
return [DefaultInfo(files = depset([out]))]
23+
24+
choose_clang_format = rule(
25+
implementation = _choose_clang_format,
26+
)

clang_format/clang_format_check.bzl

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
def _check_format(ctx, exe, config, infile, clang_format_bin):
2+
output = ctx.actions.declare_file(infile.path + ".clang-format.txt")
3+
4+
args = ctx.actions.args()
5+
6+
args.add("check_file")
7+
args.add(clang_format_bin.path)
8+
args.add(infile.path)
9+
args.add(output.path)
10+
11+
ctx.actions.run(
12+
inputs = [clang_format_bin, infile, config],
13+
outputs = [output],
14+
executable = exe,
15+
arguments = [args],
16+
mnemonic = "ClangFormat",
17+
progress_message = "Check clang-format on {}".format(infile.short_path),
18+
)
19+
return output
20+
21+
def _extract_files(ctx):
22+
files = []
23+
if hasattr(ctx.rule.attr, "srcs"):
24+
for src in ctx.rule.attr.srcs:
25+
files += [src for src in src.files.to_list() if src.is_source]
26+
27+
if hasattr(ctx.rule.attr, "hdrs"):
28+
for hdr in ctx.rule.attr.hdrs:
29+
files += [hdr for hdr in hdr.files.to_list() if hdr.is_source]
30+
31+
return files
32+
33+
def _clang_format_check_aspect_impl(target, ctx):
34+
# if not a C/C++ target, we are not interested
35+
if not CcInfo in target:
36+
return []
37+
38+
exe = ctx.attr._clang_format.files_to_run
39+
config = ctx.attr._clang_format_config.files.to_list()[0]
40+
clang_format_bin = ctx.attr._clang_format_bin.files.to_list()[0]
41+
files = _extract_files(ctx)
42+
43+
outputs = []
44+
for file in files:
45+
if file.basename.endswith((".c", ".h", ".cpp", ".cc", ".hpp")):
46+
outputs.append(_check_format(ctx, exe, config, file, clang_format_bin))
47+
48+
return [
49+
OutputGroupInfo(report = depset(direct = outputs)),
50+
]
51+
52+
clang_format_check_aspect = aspect(
53+
implementation = _clang_format_check_aspect_impl,
54+
fragments = ["cpp"],
55+
attrs = {
56+
"_clang_format": attr.label(default = Label("//clang_format:clang_format")),
57+
"_clang_format_config": attr.label(default = "//clang_format:clang_format_config"),
58+
"_clang_format_bin": attr.label(default = Label("//clang_format:clang_format_bin")),
59+
},
60+
)

clang_format/examplerc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
build:clang-format-check --aspects //bazel/clang_format:clang_format_check.bzl%clang_format_check_aspect
2+
build:clang-format-check --output_groups=report

clang_format/run_clang_format.sh

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
#! /bin/bash
2+
# Usages:
3+
# run_clang_format format_all <CLANG_FORMAT_BIN> <CLANG_FORMAT_CONFIG>
4+
# run_clang_format check_file <CLANG_FORMAT_BIN> <INPUT> <OUTPUT>
5+
set -ue
6+
7+
format_all() {
8+
CLANG_FORMAT_CONFIG=$(realpath $1)
9+
10+
cd $BUILD_WORKSPACE_DIRECTORY
11+
if ! test -f .clang-format; then
12+
echo ".clang-format file not found. Bazel will copy the default .clang-format file."
13+
cp $CLANG_FORMAT_CONFIG .
14+
fi
15+
git describe --tags --abbrev=0 --always \
16+
| xargs -I % git diff --diff-filter=ACMRTUXB --name-only --line-prefix=`git rev-parse --show-toplevel`/ % -- '*.[ch]' '*.cpp' '*.cc' '*.hpp' \
17+
| xargs clang-format-14 -i
18+
}
19+
20+
check_file() {
21+
INPUT=$1
22+
OUTPUT=$2
23+
24+
$CLANG_FORMAT_BIN $INPUT --dry-run -Werror > $OUTPUT
25+
}
26+
27+
ARG=$1
28+
CLANG_FORMAT_BIN=$(realpath $2)
29+
shift 2
30+
31+
if [ "$ARG" == "format_all" ]; then
32+
format_all "$@"
33+
elif [ "$ARG" == "check_file" ]; then
34+
check_file "$@"
35+
fi

0 commit comments

Comments
 (0)