From 2703a56b26ba0a265b03129b53b5a10ff615e1d8 Mon Sep 17 00:00:00 2001 From: Krzysztof Naglik Date: Thu, 29 Sep 2022 15:11:56 +0200 Subject: [PATCH 1/5] bazel: Rules For Clang-Format [BUILD-305] --- .bazelrc | 2 + clang_format/BUILD | 27 ++++++++++++ clang_format/choose_clang_format.bzl | 20 +++++++++ clang_format/clang_format_check.bzl | 63 ++++++++++++++++++++++++++++ clang_format/run_clang_format.sh | 27 ++++++++++++ 5 files changed, 139 insertions(+) create mode 100644 .bazelrc create mode 100644 clang_format/BUILD create mode 100644 clang_format/choose_clang_format.bzl create mode 100644 clang_format/clang_format_check.bzl create mode 100755 clang_format/run_clang_format.sh diff --git a/.bazelrc b/.bazelrc new file mode 100644 index 00000000..d18ae2f7 --- /dev/null +++ b/.bazelrc @@ -0,0 +1,2 @@ +build:clang-format-check --aspects //bazel/clang_format:clang_format_check.bzl%clang_format_check_aspect +build:clang-format-check --output_groups=report diff --git a/clang_format/BUILD b/clang_format/BUILD new file mode 100644 index 00000000..984e80de --- /dev/null +++ b/clang_format/BUILD @@ -0,0 +1,27 @@ +load(":choose_clang_format.bzl", "choose_clang_format") + +choose_clang_format( + name = "clang_format_bin", + visibility = ["//visibility:public"], +) + +filegroup( + name = "_clang_format_bin", + srcs = [":clang_format_bin"], +) + +sh_binary( + name = "clang_format", + srcs = [ + "run_clang_format.sh", + ], + args = [ + "format_all", + "$(location :_clang_format_bin)", + ], + data = [ + ":_clang_format_bin", + "//:clang_format_config", + ], + visibility = ["//visibility:public"], +) diff --git a/clang_format/choose_clang_format.bzl b/clang_format/choose_clang_format.bzl new file mode 100644 index 00000000..404644ae --- /dev/null +++ b/clang_format/choose_clang_format.bzl @@ -0,0 +1,20 @@ +def _choose_clang_format(ctx): + out = ctx.actions.declare_file("clang_format_bin.sh") + + ctx.actions.run_shell( + outputs = [out], + command = """ + if command -v clang-format-14 &> /dev/null + then + echo clang-format-14 \\"\\$@\\" > {0} + else + echo clang-format \\"\\$@\\" > {0} + fi + """.format(out.path), + ) + + return [DefaultInfo(files = depset([out]))] + +choose_clang_format = rule( + implementation = _choose_clang_format, +) diff --git a/clang_format/clang_format_check.bzl b/clang_format/clang_format_check.bzl new file mode 100644 index 00000000..3bd44fe1 --- /dev/null +++ b/clang_format/clang_format_check.bzl @@ -0,0 +1,63 @@ +load("@bazel_tools//tools/cpp:toolchain_utils.bzl", "find_cpp_toolchain") + +def _check_format(ctx, exe, config, infile, clang_format_bin): + output = ctx.actions.declare_file(infile.basename + ".clang-format.txt") + + args = ctx.actions.args() + + args.add("check_file") + args.add(clang_format_bin.path) + args.add(infile.path) + args.add(output.path) + + ctx.actions.run( + inputs = [clang_format_bin, infile, config], + outputs = [output], + executable = exe, + arguments = [args], + mnemonic = "ClangFormat", + progress_message = "Check clang-format on {}".format(infile.short_path), + ) + return output + +def _extract_files(ctx): + files = [] + if hasattr(ctx.rule.attr, "srcs"): + for src in ctx.rule.attr.srcs: + files += [src for src in src.files.to_list() if src.is_source] + + if hasattr(ctx.rule.attr, "hdrs"): + for hdr in ctx.rule.attr.hdrs: + files += [hdr for hdr in hdr.files.to_list() if hdr.is_source] + + return files + +def _clang_format_check_aspect_impl(target, ctx): + # if not a C/C++ target, we are not interested + if not CcInfo in target: + return [] + + exe = ctx.attr._clang_format.files_to_run + config = ctx.attr._clang_format_config.files.to_list()[0] + clang_format_bin = ctx.attr._clang_format_bin.files.to_list()[0] + files = _extract_files(ctx) + + outputs = [] + for file in files: + if file.basename.endswith((".c", ".h", ".cpp", ".cc", ".hpp")): + outputs.append(_check_format(ctx, exe, config, file, clang_format_bin)) + + return [ + OutputGroupInfo(report = depset(direct = outputs)), + ] + +clang_format_check_aspect = aspect( + implementation = _clang_format_check_aspect_impl, + fragments = ["cpp"], + attrs = { + "_clang_format": attr.label(default = Label("//bazel/clang_format:clang_format")), + "_clang_format_config": attr.label(default = Label("//:clang_format_config")), + "_clang_format_bin": attr.label(default = Label("//bazel/clang_format:clang_format_bin")), + }, + toolchains = ["@bazel_tools//tools/cpp:toolchain_type"], +) diff --git a/clang_format/run_clang_format.sh b/clang_format/run_clang_format.sh new file mode 100755 index 00000000..bf8f4ff7 --- /dev/null +++ b/clang_format/run_clang_format.sh @@ -0,0 +1,27 @@ +#! /bin/bash +# Usages: +# run_clang_format format_all +# run_clang_format check_file +set -ue + +format_all() { + cd $BUILD_WORKSPACE_DIRECTORY + git ls-files '*.[ch]' '*.cpp' '*.cc' '*.hpp' | xargs $CLANG_FORMAT_BIN -i +} + +check_file() { + INPUT=$1 + OUTPUT=$2 + + $CLANG_FORMAT_BIN $INPUT --dry-run -Werror > $OUTPUT +} + +ARG=$1 +CLANG_FORMAT_BIN=$(realpath $2) +shift 2 + +if [ "$ARG" == "format_all" ]; then + format_all +elif [ "$ARG" == "check_file" ]; then + check_file "$@" +fi From 6614747bacb5374bd937bbbbfc18ba9b1c9afe5f Mon Sep 17 00:00:00 2001 From: Krzysztof Naglik Date: Thu, 29 Sep 2022 15:59:53 +0200 Subject: [PATCH 2/5] Use path of infile to distinguish two different files with the same file name e.g.: src/include/gnss-converters/internal/time_truth_v2.h include/gnss-converters/time_truth_v2.h --- clang_format/clang_format_check.bzl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang_format/clang_format_check.bzl b/clang_format/clang_format_check.bzl index 3bd44fe1..23d8160c 100644 --- a/clang_format/clang_format_check.bzl +++ b/clang_format/clang_format_check.bzl @@ -1,7 +1,7 @@ load("@bazel_tools//tools/cpp:toolchain_utils.bzl", "find_cpp_toolchain") def _check_format(ctx, exe, config, infile, clang_format_bin): - output = ctx.actions.declare_file(infile.basename + ".clang-format.txt") + output = ctx.actions.declare_file(infile.path + ".clang-format.txt") args = ctx.actions.args() From 375d2d7caf8ebb466f98aa1fed3e5f429d97fb47 Mon Sep 17 00:00:00 2001 From: Krzysztof Naglik Date: Thu, 29 Sep 2022 16:04:57 +0200 Subject: [PATCH 3/5] Remove toolchains --- clang_format/clang_format_check.bzl | 1 - 1 file changed, 1 deletion(-) diff --git a/clang_format/clang_format_check.bzl b/clang_format/clang_format_check.bzl index 23d8160c..beaa158f 100644 --- a/clang_format/clang_format_check.bzl +++ b/clang_format/clang_format_check.bzl @@ -59,5 +59,4 @@ clang_format_check_aspect = aspect( "_clang_format_config": attr.label(default = Label("//:clang_format_config")), "_clang_format_bin": attr.label(default = Label("//bazel/clang_format:clang_format_bin")), }, - toolchains = ["@bazel_tools//tools/cpp:toolchain_type"], ) From 9e8afdbcc79bae8890870cf1b53c2e0a2c90366a Mon Sep 17 00:00:00 2001 From: Krzysztof Naglik Date: Thu, 29 Sep 2022 16:53:16 +0200 Subject: [PATCH 4/5] Fail if cannot find clang-format --- clang_format/choose_clang_format.bzl | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/clang_format/choose_clang_format.bzl b/clang_format/choose_clang_format.bzl index 404644ae..69b2bf2c 100644 --- a/clang_format/choose_clang_format.bzl +++ b/clang_format/choose_clang_format.bzl @@ -7,8 +7,12 @@ def _choose_clang_format(ctx): if command -v clang-format-14 &> /dev/null then echo clang-format-14 \\"\\$@\\" > {0} - else + elif command -v clang-format &> /dev/null + then echo clang-format \\"\\$@\\" > {0} + else + echo "clang-format-14 / clang-format: command not found" + exit 1 fi """.format(out.path), ) From 64e0ec8e998009301242dad77431d97811d77c25 Mon Sep 17 00:00:00 2001 From: Krzysztof Naglik Date: Thu, 29 Sep 2022 17:54:55 +0200 Subject: [PATCH 5/5] Don't fail when cannot find clang-format --- clang_format/choose_clang_format.bzl | 6 ++++-- clang_format/clang_format_check.bzl | 2 -- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/clang_format/choose_clang_format.bzl b/clang_format/choose_clang_format.bzl index 69b2bf2c..ddd26909 100644 --- a/clang_format/choose_clang_format.bzl +++ b/clang_format/choose_clang_format.bzl @@ -11,8 +11,10 @@ def _choose_clang_format(ctx): then echo clang-format \\"\\$@\\" > {0} else - echo "clang-format-14 / clang-format: command not found" - exit 1 + err_msg='clang-format-14 / clang-format: command not found' + echo $err_msg + echo "echo "$err_msg">&2" >> {0} + echo "exit 1" >> {0} fi """.format(out.path), ) diff --git a/clang_format/clang_format_check.bzl b/clang_format/clang_format_check.bzl index beaa158f..defef733 100644 --- a/clang_format/clang_format_check.bzl +++ b/clang_format/clang_format_check.bzl @@ -1,5 +1,3 @@ -load("@bazel_tools//tools/cpp:toolchain_utils.bzl", "find_cpp_toolchain") - def _check_format(ctx, exe, config, infile, clang_format_bin): output = ctx.actions.declare_file(infile.path + ".clang-format.txt")