Как интегрировать симпатичную печать как часть сборки в bazel

Прямо сейчас, у меня есть действительно тупой скрипт для красивой печати, который делает немного мерзавца, чтобы найти файлы для форматирования (безоговорочно), а затем запускает их через clang-format -i. Этот подход имеет несколько недостатков:

  1. Есть определенные файлы, которые огромны и требуют много времени для красивой печати.
  2. Красивая печать всегда выполняется, независимо от того, изменился ли базовый файл или нет.

В прошлом я мог делать что-то с CMake, у которого было несколько приятных свойств, которые я хотел бы воспроизвести на bazel:

  1. Только когда-либо строить код после он прошел через распечатывание / красивую печать / и т. д.
  2. Только что-то изменилось, что изменилось.
  3. Красивые вещи для печати независимо от того, находится ли это под VC или нет

В CMake-land я использовал эту стратегию, основанную на хитрости прокси-цели для SCons:

  1. Введите фиктивную цель (например, source -> source.formatted). Действие, связанное с этой целью, делает две вещи: a) запустить clang-format -i source, b) вывести / коснуться файла с именем source.formatted (это гарантирует, что для приемлемых файловых систем, если source.formatted новее, чем source, source не нужно переформатировать)

  2. Добавьте фиктивную цель (target_name.aggregated_formatted), которая объединяет все отформатированные файлы, соответствующие источникам конкретной библиотеки / исполняемой цели

  3. Сделать библиотеки / исполняемые цели зависимыми от target_name.aggregated_formatted в качестве шага перед сборкой

Любая помощь будет принята с благодарностью.

3

Решение

Возможно, вы сможете использовать аспекты для этого. Будучи неуверенным, 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 это правила, которые вы должны реализовать самостоятельно и должны составить список очищенных файлов.

4

Другие решения

@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
3

По вопросам рекламы ammmcru@yandex.ru
Adblock
detector