Skip to content

No-op transition causes dependencies to be rebuilt separately from default configuration #11196

@jayconrod

Description

@jayconrod

Description of the problem / feature request:

Suppose we have an x_binary rule with an incoming edge transition, which can change build settings based on attributes. Most of the time the attributes are not set, so the transition makes no changes (output settings are identical to inputs).

In cases where the transition makes no changes, Bazel should act as if no transition were applied. That is, if an x_binary depends on a file created by another target (x_library), the file should only be generated once, whether the x_library is a dependency of x_binary or the x_library is built directly in the default configuration.

Bugs: what's the simplest, easiest way to reproduce this bug? Please provide a minimal example if possible.

Here's a standalone workspace that reproduces this. x_library runs date and writes the output to a file. x_binary just collects files.

-- WORKSPACE --
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")

http_archive(
    name = "bazel_skylib",
    sha256 = "97e70364e9249702246c0e9444bccdc4b847bed1eb03c5a3ece4f83dfe6abc44",
    urls = [
        "https://mirror.bazel.build/github.com/bazelbuild/bazel-skylib/releases/download/1.0.2/bazel-skylib-1.0.2.tar.gz",
        "https://github.com/bazelbuild/bazel-skylib/releases/download/1.0.2/bazel-skylib-1.0.2.tar.gz",
    ],
)

load("@bazel_skylib//:workspace.bzl", "bazel_skylib_workspace")

bazel_skylib_workspace()

-- BUILD.bazel --
load(":def.bzl", "x_binary", "x_library")
load("@bazel_skylib//rules:common_settings.bzl", "string_setting")

x_binary(
    name = "bin",
    deps = ["lib"],
)

x_library(
    name = "lib",
)

string_setting(
    name = "x_setting",
    build_setting_default = "auto",
)

-- def.bzl --
def _x_transition_impl(settings, attr):
    return settings

x_transition = transition(
    implementation = _x_transition_impl,
    inputs = ["//:x_setting"],
    outputs = ["//:x_setting"],
)

def _x_binary_impl(ctx):
    return [DefaultInfo(files = depset(ctx.files.deps))]

x_binary = rule(
    implementation = _x_binary_impl,
    attrs = {
        "deps": attr.label_list(),
        "_whitelist_function_transition": attr.label(
            default = "@bazel_tools//tools/whitelists/function_transition_whitelist",
        ),
    },
    cfg = x_transition,
)

def _x_library_impl(ctx):
    f = ctx.actions.declare_file(ctx.label.name + ".txt")
    ctx.actions.run_shell(
        outputs = [f],
        command = 'date > "$1"',
        arguments = [f.path],
    )
    return [DefaultInfo(files = depset([f]))]

x_library = rule(
    implementation = _x_library_impl,
)

Building the binary produces one file:

$ bazel build :bin
Target //:bin up-to-date:
  bazel-out/darwin-fastbuild-ST-a8da75533bb21808e51b80cc48e0fbd4a22ad8179cfa2e2acc3ed4c1a7d740fe/bin/lib.txt

$ cat bazel-out/darwin-fastbuild-ST-a8da75533bb21808e51b80cc48e0fbd4a22ad8179cfa2e2acc3ed4c1a7d740fe/bin/lib.txt
Wed Apr 22 14:10:01 EDT 2020

Building the library produces a different file:

$ bazel build :lib
Target //:lib up-to-date:
  bazel-bin/lib.txt

$ cat bazel-bin/lib.txt
Wed Apr 22 14:04:00 EDT 2020

What operating system are you running Bazel on?

macOS 10.15.4

What's the output of bazel info release?

release 3.0.0

Metadata

Metadata

Assignees

Labels

P1I'll work on this now. (Assignee required)team-Configurabilityplatforms, toolchains, cquery, select(), config transitions

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions