Прямо сейчас, у меня есть действительно тупой скрипт для красивой печати, который делает немного мерзавца, чтобы найти файлы для форматирования (безоговорочно), а затем запускает их через clang-format -i. Этот подход имеет несколько недостатков:
В прошлом я мог делать что-то с CMake, у которого было несколько приятных свойств, которые я хотел бы воспроизвести на bazel:
В CMake-land я использовал эту стратегию, основанную на хитрости прокси-цели для SCons:
Введите фиктивную цель (например, source -> source.formatted). Действие, связанное с этой целью, делает две вещи: a) запустить clang-format -i source, b) вывести / коснуться файла с именем source.formatted (это гарантирует, что для приемлемых файловых систем, если source.formatted новее, чем source, source не нужно переформатировать)
Добавьте фиктивную цель (target_name.aggregated_formatted), которая объединяет все отформатированные файлы, соответствующие источникам конкретной библиотеки / исполняемой цели
Сделать библиотеки / исполняемые цели зависимыми от target_name.aggregated_formatted в качестве шага перед сборкой
Любая помощь будет принята с благодарностью.
Возможно, вы сможете использовать аспекты для этого. Будучи неуверенным, Bazel-dev, вероятно, укажет это, если это действительно возможно.
Если вы знакомы с Правилами и Действиями и тому подобным, быстрый и грязный способ (который похож на взлом CMake) состоит в написании макроса. Например, 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
)
Тогда вам, конечно, нужно заменить каждый cc_library
с clean_cc_library
, А также lint_sources
а также pretty_print_sources
это правила, которые вы должны реализовать самостоятельно и должны составить список очищенных файлов.
@abergmeier прав. Давайте сделаем еще один шаг вперед, реализовав макрос и его компоненты.
Мы будем использовать учебник C ++ 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;
}
Это файл BUILD:
cc_binary(
name = "hello-world",
srcs = ["hello-world.cc"],
)
поскольку cc_binary
ничего не знает о clang-format
или linting в общем, давайте создадим макрос с именем 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"],
)
Затем создайте файл с именем clang_format.bzl
с макросом по имени clang_formatted_cc_binary
это просто обертка native.cc_binary
:
# In clang_format.bzl
def clang_formatted_cc_binary(**kwargs):
native.cc_binary(**kwargs)
На этом этапе вы можете построить 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
)
Обратите внимание, что мы заменили native.cc_binary
Источники с отформатированными файлами, но сохранили имя для возможности замены на месте cc_binary
-> clang_formatted_cc_binary
в файлах BUILD.
Наконец, мы напишем реализацию 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,
)
Это правило проходит через каждый файл в целевой srcs
атрибут, объявляя «фиктивный» выходной файл с formatted_
префикс и работает clang-format
в неотформатированном файле для создания фиктивного вывода.
Теперь, если вы бежите bazel build :hello-world
Базель будет управлять действиями в 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']
..
Глядя на содержание 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;
}
Если вам нужны только отформатированные исходники без их компиляции, вы можете запустить build the target с помощью команды _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