Что вызывает дублирование сборок одной и той же цели в Bazel?

Мы видим дубликаты сборок одной и той же цели в Bazel и задаемся вопросом, что может быть причиной этого.

Вот пример вывода:

      [52,715 / 55,135] 12 action running
    Bazel package: some-pkg - Target: a_target - Generating files at bazel-out/host/bin/some-pkg/a_target_generate [for host]; 264s remote-cache, processwrapper-sandbox
    Bazel package: some-pkg - Target: a_target - Generating files at bazel-out/k8-fastbuild/bin/some-pkg/a_target_generate; 264s remote-cache, processwrapper-sandbox
    ...

Нам не удалось выявить проблему. Похоже, это происходит только в Linux, но не на Mac.

Цель a_targetэто custom_ruleцель. Он должен быть независимым от платформы.

      custom_rule = rule(
    attrs = dict(
       ...
        _custom_rule_java_binary = attr.label(
            cfg = "host",
            default = Label("//tools/bazel/build/rules/custom-rule:custom_rule_bin"),
            executable = True,
        ),
        _singlejar = attr.label(
            cfg = "host",
            default = Label("@bazel_tools//tools/jdk:singlejar"),
            executable = True,
            allow_files = True,
        ),
    ),
    implementation = ...,
)

custom_rule_binопределяется следующим образом:

      java_library(
    name = "custom_rule",
    srcs = glob(["src/main/java/**/*.java"]),
    deps = [
        ...,
    ],
)

java_binary(
    name = "custom_rule_bin",
    visibility = ["//visibility:public"],
    main_class = "...",
    runtime_deps = [
        "@org_slf4j_simple",
        ":custom_rule",
        "//some-pkg:some_pkg", # same some-pkg where a_target is built twice
    ],
)

Разница в том, что один говорит « для хоста », а другой нет. Кто-нибудь знает, что такое дополнительная сборка « для хоста »?

У меня есть ощущение, что это как-то связано с cfgатрибут пользовательского правила. Вероятно, это происходит из какого-то примера кода. Мы используем одно и то же значение для всех наших правил, которые генерируют код. Это настраиваемое правило является особенным, поскольку для запуска и создания дополнительного кода требуется код из приложения, создаваемого Bazel.

Любые идеи ценятся, почему hostбудет неправильным и каково будет правильное значение.

Любые идеи/советы, как это отлаживать?

1 ответ

Во-первых, одно замечание заключается в том, что конфигурация хоста в основном устарела, а «exec» обычно предпочтительнее. Некоторая информация об этом находится здесь: https://bazel.build/rules/rules#configurations.

Происходит то, что эта цель зависит от нескольких конфигураций, и поэтому bazel создаст эту цель в каждой конфигурации. Вы можете использовать cquery, чтобы выяснить, что происходит

В качестве очень простого примера:

      genrule(
  name = "gen_bin",
  outs = ["bin"],
  srcs = [":gen_lib"],
  exec_tools = [":gen_tool"],
  cmd = "touch $@",
)

genrule(
  name = "gen_tool",
  outs = ["tool"],
  srcs = [":gen_lib"],
  cmd = "touch $@",
)

genrule(
  name = "gen_lib",
  outs = ["lib"],
  cmd = "touch $@; sleep 10",
)

Строительство bin, bazel запускает правило gen_lib дважды (параллельно):

      $ bazel build bin
INFO: Analyzed target //:bin (5 packages loaded, 16 targets configured).
INFO: Found 1 target...
[1 / 5] 2 actions running
    Executing genrule //:gen_lib; 1s linux-sandbox
    Executing genrule //:gen_lib; 1s linux-sandbox

bazel configдает конфигурации, которые в данный момент находятся в графе сборки в памяти:

      $ bazel config
Available configurations:
5b39bc31deb1f1d37f1f858e7eec3964394eacce5bede4456dd59d417af4a6e9 (exec)
723da02ae6d0c5577e98242c8f06ca1bd1c6d7b295c97345ac31b844bfe8f79c
8960923b9e7dc13418be101268efd8e57d80283213d18174705345598b699c6b
fd805cc1de357c04c7abac1b40bae600e3d9ee56a8d17af0c28b5031ca09bfb9 (host)

тогда cquery:

      $ bazel cquery "rdeps(//..., gen_lib)"
INFO: Analyzed 3 targets (0 packages loaded, 1 target configured).
INFO: Found 3 targets...
//:gen_lib (5b39bc3)
//:gen_lib (8960923)
//:gen_tool (5b39bc3)
//:gen_bin (8960923)
//:gen_tool (8960923)
INFO: Elapsed time: 0.052s
INFO: 0 processes.
INFO: Build completed successfully, 0 total actions

(cquery дает первые 7 цифр хэша конфигурации)

--output=graphдает точечный график, который немного полезнее:

      $ bazel cquery "rdeps(//..., gen_lib)" --output=graph > /tmp/graph
$ xdot /tmp/graph

Таким образом, gen_bin находится в целевой конфигурации (8960923) и зависит от gen_lib, поэтому gen_lib также будет встроен в целевую конфигурацию.

gen_bin также зависит от gen_tool через атрибут exec_tools, а exec_tools строит все в конфигурации exec (5b39bc3).

gen_tool также зависит от gen_lib, а поскольку gen_tool находится в конфигурации exec, версия gen_lib создается в конфигурации exec.

(Есть также другая версия gen_tool в целевой конфигурации в выходных данных, и это артефакт использования в аргументе «universe» rdeps(), поскольку //...захватит каждую цель. Точно так же, делая bazel build //...вызовет двойную сборку gen_tool.)

Другие вопросы по тегам