Konfigurasi

Laporkan masalah Lihat sumber

Halaman ini membahas manfaat dan penggunaan dasar konfigurasi Starlark, API Bazel untuk menyesuaikan cara pembuatan project Anda. Panduan ini berisi cara menentukan setelan build dan memberikan contoh.

Hal ini memungkinkan untuk:

  • menentukan flag kustom untuk project Anda, sehingga tidak diperlukan lagi --define
  • menulis transisi untuk mengonfigurasi dependensi dalam konfigurasi yang berbeda dengan induknya (seperti --compilation_mode=opt atau --cpu=arm)
  • memasukkan nilai default yang lebih baik ke dalam aturan (seperti mem-build //my:android_app secara otomatis dengan SDK yang ditentukan)

dan banyak lagi, semuanya sepenuhnya dari file .bzl (tidak memerlukan rilis Bazel). Lihat repositori bazelbuild/examples untuk contohnya.

Setelan build yang ditentukan pengguna

Setelan build adalah bagian tunggal dari informasi konfigurasi. Bayangkan konfigurasi sebagai peta kunci/nilai. Menyetel --cpu=ppc dan --copt="-DFoo" akan menghasilkan konfigurasi yang terlihat seperti {cpu: ppc, copt: "-DFoo"}. Setiap entri adalah setelan build.

Flag tradisional seperti cpu dan copt adalah setelan native — kuncinya ditentukan dan nilainya ditetapkan di dalam kode bazel java native. Pengguna Bazel hanya dapat membaca dan menulisnya melalui command line dan API lain yang dikelola secara native. Mengubah flag native, dan API yang mengeksposnya, memerlukan rilis bazel. Setelan build yang ditentukan pengguna ditentukan dalam file .bzl (sehingga, tidak memerlukan rilis bazel untuk mendaftarkan perubahan). Parameter ini juga dapat disetel melalui command line (jika ditetapkan sebagai flags, lihat selengkapnya di bawah), tetapi juga dapat ditetapkan melalui transisi yang ditentukan pengguna.

Menentukan setelan build

Contoh menyeluruh

Parameter build_setting rule()

Setelan build adalah aturan seperti aturan lainnya, dan dibedakan menggunakan atribut build_setting dari fungsi rule() Starlark.

# example/buildsettings/build_settings.bzl
string_flag = rule(
    implementation = _impl,
    build_setting = config.string(flag = True)
)

Atribut build_setting menggunakan fungsi yang menentukan jenis setelan build. Jenis ini terbatas pada kumpulan jenis Starlark dasar seperti bool dan string. Lihat dokumentasi modul config untuk mengetahui detailnya. Mengetik yang lebih rumit dapat dilakukan dalam fungsi implementasi aturan. Informasi selengkapnya dapat dibaca di bawah.

Fungsi modul config menggunakan parameter boolean opsional, flag, yang ditetapkan ke false secara default. Jika flag disetel ke benar (true), setelan build dapat ditetapkan pada command line oleh pengguna serta secara internal oleh penulis aturan melalui nilai default dan transisi. Tidak semua setelan harus dapat disetel oleh pengguna. Misalnya, jika Anda sebagai penulis aturan memiliki beberapa mode debug yang ingin Anda aktifkan di dalam aturan pengujian, Anda tidak ingin memberi pengguna kemampuan untuk mengaktifkan fitur tersebut tanpa diskriminatif di dalam aturan non-pengujian lainnya.

Menggunakan ctx.build_setting_value

Seperti semua aturan, aturan setelan build memiliki fungsi penerapan. Nilai dasar jenis Starlark dari setelan build dapat diakses melalui metode ctx.build_setting_value. Metode ini hanya tersedia untuk objek ctx dari aturan setelan build. Metode implementasi ini dapat langsung meneruskan nilai setelan build atau melakukan pekerjaan tambahan pada nilai tersebut, seperti pemeriksaan jenis atau pembuatan struct yang lebih kompleks. Berikut cara mengimplementasikan setelan build berjenis enum:

# example/buildsettings/build_settings.bzl
TemperatureProvider = provider(fields = ['type'])

temperatures = ["HOT", "LUKEWARM", "ICED"]

def _impl(ctx):
    raw_temperature = ctx.build_setting_value
    if raw_temperature not in temperatures:
        fail(str(ctx.label) + " build setting allowed to take values {"
             + ", ".join(temperatures) + "} but was set to unallowed value "
             + raw_temperature)
    return TemperatureProvider(type = raw_temperature)

temperature = rule(
    implementation = _impl,
    build_setting = config.string(flag = True)
)

Menentukan flag string multi-set

Setelan string memiliki parameter allow_multiple tambahan yang memungkinkan flag ditetapkan beberapa kali pada command line atau di bazelrcs. Nilai defaultnya masih ditetapkan dengan atribut berjenis string:

# example/buildsettings/build_settings.bzl
allow_multiple_flag = rule(
    implementation = _impl,
    build_setting = config.string(flag = True, allow_multiple = True)
)
# example/BUILD
load("//example/buildsettings:build_settings.bzl", "allow_multiple_flag")
allow_multiple_flag(
    name = "roasts",
    build_setting_default = "medium"
)

Setiap setelan tanda tersebut diperlakukan sebagai satu nilai:

$ bazel build //my/target --//example:roasts=blonde \
    --//example:roasts=medium,dark

Hal di atas diurai menjadi {"//example:roasts": ["blonde", "medium,dark"]} dan ctx.build_setting_value akan menampilkan daftar ["blonde", "medium,dark"].

Membuat instance setelan build

Aturan yang ditentukan dengan parameter build_setting memiliki atribut build_setting_default wajib yang implisit. Atribut ini menggunakan jenis yang sama dengan yang dideklarasikan oleh parameter build_setting.

# example/buildsettings/build_settings.bzl
FlavorProvider = provider(fields = ['type'])

def _impl(ctx):
    return FlavorProvider(type = ctx.build_setting_value)

flavor = rule(
    implementation = _impl,
    build_setting = config.string(flag = True)
)
# example/BUILD
load("//example/buildsettings:build_settings.bzl", "flavor")
flavor(
    name = "favorite_flavor",
    build_setting_default = "APPLE"
)

Setelan standar

Contoh menyeluruh

Library Skylib menyertakan sekumpulan setelan standar yang dapat Anda buat instance-nya tanpa harus menulis Starlark kustom.

Misalnya, untuk menentukan setelan yang menerima serangkaian nilai string terbatas:

# example/BUILD
load("@bazel_skylib//rules:common_settings.bzl", "string_flag")
string_flag(
    name = "myflag",
    values = ["a", "b", "c"],
    build_setting_default = "a",
)

Untuk mengetahui daftar lengkapnya, lihat Aturan setelan build umum.

Menggunakan setelan build

Bergantung pada setelan build

Jika ingin membaca bagian informasi konfigurasi, target dapat langsung bergantung pada setelan build melalui dependensi atribut reguler.

# example/rules.bzl
load("//example/buildsettings:build_settings.bzl", "FlavorProvider")
def _rule_impl(ctx):
    if ctx.attr.flavor[FlavorProvider].type == "ORANGE":
        ...

drink_rule = rule(
    implementation = _rule_impl,
    attrs = {
        "flavor": attr.label()
    }
)
# example/BUILD
load("//example:rules.bzl", "drink_rule")
load("//example/buildsettings:build_settings.bzl", "flavor")
flavor(
    name = "favorite_flavor",
    build_setting_default = "APPLE"
)
drink_rule(
    name = "my_drink",
    flavor = ":favorite_flavor",
)

Bahasa mungkin ingin membuat kumpulan kanonis setelan build yang diandalkan oleh semua aturan untuk bahasa tersebut. Meskipun konsep native fragments tidak lagi ada sebagai objek hardcode di dunia konfigurasi Starlark, salah satu cara untuk menerjemahkan konsep ini adalah dengan menggunakan kumpulan atribut implisit umum. Contoh:

# kotlin/rules.bzl
_KOTLIN_CONFIG = {
    "_compiler": attr.label(default = "//kotlin/config:compiler-flag"),
    "_mode": attr.label(default = "//kotlin/config:mode-flag"),
    ...
}

...

kotlin_library = rule(
    implementation = _rule_impl,
    attrs = dicts.add({
        "library-attr": attr.string()
    }, _KOTLIN_CONFIG)
)

kotlin_binary = rule(
    implementation = _binary_impl,
    attrs = dicts.add({
        "binary-attr": attr.label()
    }, _KOTLIN_CONFIG)

Menggunakan setelan build pada command line

Serupa dengan sebagian besar flag native, Anda dapat menggunakan command line untuk menetapkan setelan build yang ditandai sebagai flag. Nama setelan build adalah jalur target lengkapnya menggunakan sintaksis name=value:

$ bazel build //my/target --//example:string_flag=some-value # allowed
$ bazel build //my/target --//example:string_flag some-value # not allowed

Sintaksis boolean khusus didukung:

$ bazel build //my/target --//example:boolean_flag
$ bazel build //my/target --no//example:boolean_flag

Menggunakan alias setelan build

Anda dapat menetapkan alias untuk jalur target setelan build agar lebih mudah dibaca di command line. Alias berfungsi mirip dengan flag native dan juga menggunakan sintaksis opsi tanda hubung ganda.

Tetapkan alias dengan menambahkan --flag_alias=ALIAS_NAME=TARGET_PATH ke .bazelrc Anda . Misalnya, untuk menyetel alias ke coffee:

# .bazelrc
build --flag_alias=coffee=//experimental/user/starlark_configurations/basic_build_setting:coffee-temp

Praktik Terbaik: Menetapkan alias beberapa kali akan menghasilkan alias terbaru yang diutamakan. Gunakan nama alias unik untuk menghindari hasil penguraian yang tidak diinginkan.

Untuk memanfaatkan alias, ketik alias tersebut sebagai ganti jalur target setelan build. Dengan contoh coffee di atas yang ditetapkan dalam .bazelrc pengguna:

$ bazel build //my/target --coffee=ICED

bukan

$ bazel build //my/target --//experimental/user/starlark_configurations/basic_build_setting:coffee-temp=ICED

Praktik Terbaik: Meskipun dapat menetapkan alias pada command line, membiarkannya dalam .bazelrc akan mengurangi ketidakteraturan command line.

Setelan build berjenis label

Contoh menyeluruh

Tidak seperti setelan build lainnya, setelan berjenis label tidak dapat ditentukan menggunakan parameter aturan build_setting. Sebagai gantinya, bazel memiliki dua aturan bawaan: label_flag dan label_setting. Aturan ini meneruskan penyedia target sebenarnya tempat setelan build ditetapkan. label_flag dan label_setting dapat dibaca/ditulis oleh transisi dan label_flag dapat disetel oleh pengguna seperti yang dapat dilakukan aturan build_setting lainnya. Satu-satunya perbedaan mereka adalah mereka tidak dapat ditentukan secara khusus.

Setelan berjenis label pada akhirnya akan menggantikan fungsi default yang terikat akhir. Atribut default batas akhir adalah atribut berjenis Label yang nilai akhir dapat terpengaruh oleh konfigurasi. Di Starlark, ini akan menggantikan configuration_field API.

# example/rules.bzl
MyProvider = provider(fields = ["my_field"])

def _dep_impl(ctx):
    return MyProvider(my_field = "yeehaw")

dep_rule = rule(
    implementation = _dep_impl
)

def _parent_impl(ctx):
    if ctx.attr.my_field_provider[MyProvider].my_field == "cowabunga":
        ...

parent_rule = rule(
    implementation = _parent_impl,
    attrs = { "my_field_provider": attr.label() }
)

# example/BUILD
load("//example:rules.bzl", "dep_rule", "parent_rule")

dep_rule(name = "dep")

parent_rule(name = "parent", my_field_provider = ":my_field_provider")

label_flag(
    name = "my_field_provider",
    build_setting_default = ":dep"
)

Setelan build dan select()

Contoh menyeluruh

Pengguna dapat mengonfigurasi atribut di setelan build menggunakan select(). Target setelan build dapat diteruskan ke atribut flag_values dari config_setting. Nilai yang cocok dengan konfigurasi diteruskan sebagai String, lalu diuraikan menjadi jenis setelan build yang akan dicocokkan.

config_setting(
    name = "my_config",
    flag_values = {
        "//example:favorite_flavor": "MANGO"
    }
)

Transisi yang ditentukan pengguna

Transisi konfigurasi memetakan transformasi dari satu target yang dikonfigurasi ke target lainnya dalam grafik build.

Aturan yang menetapkannya harus menyertakan atribut khusus:

  "_allowlist_function_transition": attr.label(
      default = "@bazel_tools//tools/allowlists/function_transition_allowlist"
  )

Dengan menambahkan transisi, Anda dapat dengan mudah memperluas ukuran grafik build. Tindakan ini akan menetapkan daftar yang diizinkan pada paket tempat Anda dapat membuat target aturan ini. Nilai default dalam blok kode di atas mengizinkan semuanya. Namun, jika ingin membatasi siapa yang menggunakan aturan, Anda dapat menetapkan atribut tersebut agar mengarah ke daftar yang diizinkan kustom. Hubungi bazel-discuss@googlegroups.com jika Anda memerlukan saran atau bantuan untuk memahami pengaruh transisi terhadap performa build Anda.

Menentukan

Transisi mendefinisikan perubahan konfigurasi antar-aturan. Misalnya, permintaan seperti "kompilasi dependensi saya untuk CPU yang berbeda dari induknya" ditangani oleh transisi.

Secara formal, transisi adalah fungsi dari konfigurasi input ke satu atau beberapa konfigurasi output. Sebagian besar transisi bersifat 1:1 seperti "ganti konfigurasi input dengan --cpu=ppc". Transisi 1:2+ juga dapat terjadi, tetapi memiliki batasan khusus.

Pada Starlark, transisi didefinisikan seperti aturan, dengan fungsi transition() dan fungsi implementasi.

# example/transitions/transitions.bzl
def _impl(settings, attr):
    _ignore = (settings, attr)
    return {"//example:favorite_flavor" : "MINT"}

hot_chocolate_transition = transition(
    implementation = _impl,
    inputs = [],
    outputs = ["//example:favorite_flavor"]
)

Fungsi transition() menggunakan fungsi implementasi, kumpulan setelan build yang akan dibaca(inputs), dan kumpulan setelan build yang akan ditulis (outputs). Fungsi implementasi memiliki dua parameter, settings dan attr. settings adalah kamus {String:Object} dari semua setelan yang dideklarasikan dalam parameter inputs untuk transition().

attr adalah kamus atribut dan nilai aturan tempat transisi dilampirkan. Jika dipasang sebagai transisi edge keluar, nilai atribut ini semuanya adalah resolusi pasca-select() yang dikonfigurasi. Jika dilampirkan sebagai transisi edge masuk, attr tidak menyertakan atribut apa pun yang menggunakan pemilih untuk me-resolve nilainya. Jika transisi tepi yang masuk pada --foo membaca atribut bar, kemudian memilih --foo untuk menetapkan atribut bar, akan ada kemungkinan transisi tepi masuk akan membaca nilai bar yang salah dalam transisi.

Fungsi implementasi harus menampilkan kamus (atau daftar kamus, jika terjadi transisi dengan beberapa konfigurasi output) nilai setelan build baru yang akan diterapkan. Keyset kamus yang ditampilkan harus berisi kumpulan setelan build yang diteruskan ke parameter outputs fungsi transisi. Ketentuan ini berlaku meskipun setelan build tidak benar-benar berubah selama transisi - nilai aslinya harus diteruskan secara eksplisit dalam kamus yang ditampilkan.

Menentukan transisi 1:2+

Contoh menyeluruh

Transisi tepi keluar dapat memetakan konfigurasi input tunggal ke dua atau beberapa konfigurasi output. Fungsi ini berguna untuk menentukan aturan yang memaketkan kode multi-arsitektur.

Transisi 1:2+ ditentukan dengan menampilkan daftar kamus dalam fungsi implementasi transisi.

# example/transitions/transitions.bzl
def _impl(settings, attr):
    _ignore = (settings, attr)
    return [
        {"//example:favorite_flavor" : "LATTE"},
        {"//example:favorite_flavor" : "MOCHA"},
    ]

coffee_transition = transition(
    implementation = _impl,
    inputs = [],
    outputs = ["//example:favorite_flavor"]
)

Mereka juga dapat menetapkan kunci kustom yang dapat digunakan oleh fungsi implementasi aturan untuk membaca dependensi individual:

# example/transitions/transitions.bzl
def _impl(settings, attr):
    _ignore = (settings, attr)
    return {
        "Apple deps": {"//command_line_option:cpu": "ppc"},
        "Linux deps": {"//command_line_option:cpu": "x86"},
    }

multi_arch_transition = transition(
    implementation = _impl,
    inputs = [],
    outputs = ["//command_line_option:cpu"]
)

Melampirkan transisi

Contoh menyeluruh

Transisi dapat dipasang di dua tempat: tepi masuk dan tepi keluar. Secara efektif, hal ini berarti aturan dapat mentransisikan konfigurasinya sendiri (transisi edge masuk) dan mentransisikan konfigurasi dependensinya (transisi edge keluar).

CATATAN: Saat ini tidak ada cara untuk melampirkan transisi Starlark ke aturan native. Jika Anda perlu melakukan hal ini, hubungi bazel-discuss@googlegroups.com untuk bantuan mencari solusi.

Transisi tepi yang masuk

Transisi tepi yang masuk diaktifkan dengan melampirkan objek transition (dibuat oleh transition()) ke parameter cfg rule():

# example/rules.bzl
load("example/transitions:transitions.bzl", "hot_chocolate_transition")
drink_rule = rule(
    implementation = _impl,
    cfg = hot_chocolate_transition,
    ...

Transisi tepi yang masuk harus berupa transisi 1:1.

Transisi tepi keluar

Transisi tepi keluar diaktifkan dengan melampirkan objek transition (dibuat oleh transition()) ke parameter cfg atribut:

# example/rules.bzl
load("example/transitions:transitions.bzl", "coffee_transition")
drink_rule = rule(
    implementation = _impl,
    attrs = { "dep": attr.label(cfg = coffee_transition)}
    ...

Transisi tepi keluar dapat berupa 1:1 atau 1:2+.

Lihat Mengakses atribut dengan transisi untuk mengetahui cara membaca kunci ini.

Transisi pada opsi native

Contoh menyeluruh

Transisi Starlark juga dapat mendeklarasikan pembacaan dan penulisan pada opsi konfigurasi build native melalui awalan khusus pada nama opsi.

# example/transitions/transitions.bzl
def _impl(settings, attr):
    _ignore = (settings, attr)
    return {"//command_line_option:cpu": "k8"}

cpu_transition = transition(
    implementation = _impl,
    inputs = [],
    outputs = ["//command_line_option:cpu"]

Opsi native yang tidak didukung

Bazel tidak mendukung transisi pada --define dengan "//command_line_option:define". Sebagai gantinya, gunakan setelan build kustom. Secara umum, penggunaan baru --define tidak disarankan untuk mendukung setelan build.

Bazel tidak mendukung transisi pada --config. Hal ini karena --config adalah flag "ekspansi" yang diperluas ke flag lain.

Yang terpenting, --config dapat menyertakan flag yang tidak memengaruhi konfigurasi build, seperti --spawn_strategy . Bazel sengaja didesain untuk tidak dapat mengikat flag tersebut ke masing-masing target. Artinya, tidak ada cara yang koheren untuk menerapkannya dalam transisi.

Sebagai solusinya, Anda dapat secara eksplisit itemkan tanda yang merupakan bagian dari konfigurasi dalam transisi Anda. Hal ini memerlukan mempertahankan ekspansi --config di dua tempat, yang merupakan noda UI yang diketahui.

Transisi aktif mengizinkan beberapa setelan build

Saat menetapkan setelan build yang mengizinkan beberapa nilai, nilai setelan harus ditetapkan dengan daftar.

# example/buildsettings/build_settings.bzl
string_flag = rule(
    implementation = _impl,
    build_setting = config.string(flag = True, allow_multiple = True)
)
# example/BUILD
load("//example/buildsettings:build_settings.bzl", "string_flag")
string_flag(name = "roasts", build_setting_default = "medium")
# example/transitions/rules.bzl
def _transition_impl(settings, attr):
    # Using a value of just "dark" here will throw an error
    return {"//example:roasts" : ["dark"]},

coffee_transition = transition(
    implementation = _transition_impl,
    inputs = [],
    outputs = ["//example:roasts"]
)

Transisi tanpa pengoperasian

Jika transisi menampilkan {}, [], atau None, ini adalah singkatan untuk mempertahankan semua setelan pada nilai aslinya. Cara ini mungkin lebih mudah daripada menetapkan setiap output ke dirinya sendiri secara eksplisit.

# example/transitions/transitions.bzl
def _impl(settings, attr):
    _ignore = (attr)
    if settings["//example:already_chosen"] is True:
      return {}
    return {
      "//example:favorite_flavor": "dark chocolate",
      "//example:include_marshmallows": "yes",
      "//example:desired_temperature": "38C",
    }

hot_chocolate_transition = transition(
    implementation = _impl,
    inputs = ["//example:already_chosen"],
    outputs = [
        "//example:favorite_flavor",
        "//example:include_marshmallows",
        "//example:desired_temperature",
    ]
)

Mengakses atribut dengan transisi

Contoh menyeluruh

Saat melampirkan transisi ke edge keluar (terlepas dari apakah transisi merupakan transisi 1:1 atau 1:2+), ctx.attr dipaksa menjadi daftar jika belum dilakukan. Urutan elemen dalam daftar ini tidak ditentukan.

# example/transitions/rules.bzl
def _transition_impl(settings, attr):
    return {"//example:favorite_flavor" : "LATTE"},

coffee_transition = transition(
    implementation = _transition_impl,
    inputs = [],
    outputs = ["//example:favorite_flavor"]
)

def _rule_impl(ctx):
    # Note: List access even though "dep" is not declared as list
    transitioned_dep = ctx.attr.dep[0]

    # Note: Access doesn't change, other_deps was already a list
    for other_dep in ctx.attr.other_deps:
      # ...


coffee_rule = rule(
    implementation = _rule_impl,
    attrs = {
        "dep": attr.label(cfg = coffee_transition)
        "other_deps": attr.label_list(cfg = coffee_transition)
    })

Jika transisinya adalah 1:2+ dan menyetel kunci kustom, ctx.split_attr dapat digunakan untuk membaca dependensi individual untuk setiap kunci:

# example/transitions/rules.bzl
def _impl(settings, attr):
    _ignore = (settings, attr)
    return {
        "Apple deps": {"//command_line_option:cpu": "ppc"},
        "Linux deps": {"//command_line_option:cpu": "x86"},
    }

multi_arch_transition = transition(
    implementation = _impl,
    inputs = [],
    outputs = ["//command_line_option:cpu"]
)

def _rule_impl(ctx):
    apple_dep = ctx.split_attr.dep["Apple deps"]
    linux_dep = ctx.split_attr.dep["Linux deps"]
    # ctx.attr has a list of all deps for all keys. Order is not guaranteed.
    all_deps = ctx.attr.dep

multi_arch_rule = rule(
    implementation = _rule_impl,
    attrs = {
        "dep": attr.label(cfg = multi_arch_transition)
    })

Lihat contoh lengkap di sini.

Integrasi dengan platform dan toolchain

Banyak flag native saat ini, seperti --cpu dan --crosstool_top yang terkait dengan resolusi toolchain. Di masa mendatang, transisi eksplisit pada jenis flag ini kemungkinan akan diganti dengan transisi pada platform target.

Pertimbangan memori dan performa

Penambahan transisi, dan juga konfigurasi baru, ke build Anda membutuhkan biaya: grafik build yang lebih besar, grafik build yang kurang mudah dipahami, dan build yang lebih lambat. Sebaiknya pertimbangkan biaya ini saat mempertimbangkan penggunaan transisi dalam aturan build Anda. Di bawah ini adalah contoh bagaimana transisi dapat menghasilkan pertumbuhan eksponensial grafik build Anda.

Build berperilaku buruk: studi kasus

Grafik skalabilitas

Gambar 1. Grafik skalabilitas yang menampilkan target level teratas dan dependensinya.

Grafik ini menunjukkan target tingkat teratas, //pkg:app, yang bergantung pada dua target, //pkg:1_0 dan //pkg:1_1. Kedua target ini bergantung pada dua target, //pkg:2_0 dan //pkg:2_1. Kedua target ini bergantung pada dua target, //pkg:3_0 dan //pkg:3_1. Ini berlanjut sampai //pkg:n_0 dan //pkg:n_1, yang keduanya bergantung pada satu target, //pkg:dep.

Membuat //pkg:app memerlukan \(2n+2\) target:

  • //pkg:app
  • //pkg:dep
  • //pkg:i_0 dan //pkg:i_1 untuk \(i\) di \([1..n]\)

Bayangkan Anda implement flag --//foo:owner=<STRING> dan //pkg:i_b menerapkan

depConfig = myConfig + depConfig.owner="$(myConfig.owner)$(b)"

Dengan kata lain, //pkg:i_b menambahkan b ke nilai lama --owner untuk semua dependensinya.

Tindakan ini akan menghasilkan target yang dikonfigurasi berikut:

//pkg:app                              //foo:owner=""
//pkg:1_0                              //foo:owner=""
//pkg:1_1                              //foo:owner=""
//pkg:2_0 (via //pkg:1_0)              //foo:owner="0"
//pkg:2_0 (via //pkg:1_1)              //foo:owner="1"
//pkg:2_1 (via //pkg:1_0)              //foo:owner="0"
//pkg:2_1 (via //pkg:1_1)              //foo:owner="1"
//pkg:3_0 (via //pkg:1_0 → //pkg:2_0)  //foo:owner="00"
//pkg:3_0 (via //pkg:1_0 → //pkg:2_1)  //foo:owner="01"
//pkg:3_0 (via //pkg:1_1 → //pkg:2_0)  //foo:owner="10"
//pkg:3_0 (via //pkg:1_1 → //pkg:2_1)  //foo:owner="11"
...

//pkg:dep menghasilkan \(2^n\) target yang dikonfigurasi: config.owner= "\(b_0b_1...b_n\)" untuk semua \(b_i\) di \(\{0,1\}\).

Hal ini membuat grafik build menjadi lebih besar secara eksponensial daripada grafik target, dengan konsekuensi memori dan performa yang sesuai.

TODO: Tambahkan strategi untuk pengukuran dan mitigasi masalah ini.

Bacaan lebih lanjut

Untuk detail selengkapnya tentang mengubah konfigurasi build, lihat: