Yapılandırılabilir özellikler, yaygın olarak select()
olarak bilinen, kullanıcıların değerleri açıp kapatmalarına olanak tanıyan bir Bazel özelliğidir.
derleme kuralı özelliklerinin geri kalanı.
Bu, örneğin otomatik olarak oluşturulan bir çoklu platform kitaplığı için kullandığında veya makinenin kendisi için özelleştirilebilen, özellik tarafından yapılandırılabilen ikili program.
Örnek
# myapp/BUILD
cc_binary(
name = "mybinary",
srcs = ["main.cc"],
deps = select({
":arm_build": [":arm_lib"],
":x86_debug_build": [":x86_dev_lib"],
"//conditions:default": [":generic_lib"],
}),
)
config_setting(
name = "arm_build",
values = {"cpu": "arm"},
)
config_setting(
name = "x86_debug_build",
values = {
"cpu": "x86",
"compilation_mode": "dbg",
},
)
Bu, bağımlılıklarını komut satırındaki işaretlere göre "seçen" bir cc_binary
tanımlar. Özellikle, deps
şu şekilde dönüştürülür:
Komut | deps = |
bazel build //myapp:mybinary --cpu=arm |
[":arm_lib"] |
bazel build //myapp:mybinary -c dbg --cpu=x86 |
[":x86_dev_lib"] |
bazel build //myapp:mybinary --cpu=ppc |
[":generic_lib"] |
bazel build //myapp:mybinary -c dbg --cpu=ppc |
[":generic_lib"] |
select()
, config_setting
hedeflerine atıfta bulunan etiketler olan yapılandırma koşullarına göre seçilecek bir değer için yer tutucu görevi görür. Yapılandırılabilir bir özellikte select()
kullanıldığında özellik
farklı koşullar geçerli olduğunda etkili bir şekilde farklı değerler uygular.
Eşleşmeler net olmalıdır: Birden fazla koşul eşleşirse şu durumlardan biri geçerlidir:
* Hepsi aynı değere çözümlenir. Örneğin, linux x86'da çalışırken
Her iki dal da "hello" olarak çözümlendiği için {"@platforms//os:linux": "Hello", "@platforms//cpu:x86_64": "Hello"}
.
* Birinin values
özelliği, diğer tüm kullanıcıların katı bir üst kümesidir. Örneğin, values = {"cpu": "x86", "compilation_mode": "dbg"}
, açık bir values = {"cpu": "x86"}
uzmanlığıdır.
Yerleşik //conditions:default
koşulu, başka hiçbir koşul eşleşmediğinde otomatik olarak eşleşir.
Bu örnekte deps
kullanılsa da select()
, srcs
, resources
, cmd
ve diğer özelliklerin çoğunda aynı şekilde çalışır. Az sayıda özellik
yapılandırılabilir değildir ve bunlar açık bir şekilde açıklamalıdır. Örneğin, config_setting
'nin kendi values
özelliği yapılandırılamaz.
select()
ve bağımlılıkları
Belirli özellikler, bir hedefin altındaki tüm geçişli bağımlılıkların derleme parametrelerini değiştirir. Örneğin, genrule
tools
değeri --cpu
değerini şunun CPU olarak değiştirir:
çalıştırılan Bazel'i çalıştıran makine (çapraz derleme sayesinde farklı
hedefin oluşturulduğu CPU'dan daha yüksek olur). Bu bir
yapılandırma geçişi.
O dönemin
#myapp/BUILD
config_setting(
name = "arm_cpu",
values = {"cpu": "arm"},
)
config_setting(
name = "x86_cpu",
values = {"cpu": "x86"},
)
genrule(
name = "my_genrule",
srcs = select({
":arm_cpu": ["g_arm.src"],
":x86_cpu": ["g_x86.src"],
}),
tools = select({
":arm_cpu": [":tool1"],
":x86_cpu": [":tool2"],
}),
)
cc_binary(
name = "tool1",
srcs = select({
":arm_cpu": ["armtool.cc"],
":x86_cpu": ["x86tool.cc"],
}),
)
çalışıyor
$ bazel build //myapp:my_genrule --cpu=arm
x86
geliştirici makinesinde derlemeyi g_arm.src
, tool1
ve
x86tool.cc
. my_genrule
'a bağlı her iki select
de my_genrule
'un --cpu=arm
'yi içeren derleme parametrelerini kullanır. tools
özelliği, tool1
ve onun geçişli bağımlılıkları için --cpu
değerini x86
olarak değiştirir. tool1
üzerindeki select
, tool1
'ın --cpu=x86
içeren derleme parametrelerini kullanır.
Yapılandırma koşulları
Yapılandırılabilir bir özellikteki her anahtar, bir config_setting
veya constraint_value
etiketine referans verir.
config_setting
, şunların bir koleksiyonudur:
beklenen komut satırı işareti ayarları. Bunları bir hedef içine alarak
yönetimi kolay, "standart" farklı yerlerden başvurabileceği koşullar.
constraint_value
, çoklu platform davranışı için destek sağlar.
Yerleşik işaretler
--cpu
gibi işaretler Bazel'e yerleştirilmiştir: Derleme aracı, tüm projelerdeki tüm derlemeler için bunları doğal olarak anlar. Bunlar, config_setting
etiketinin values
özelliğiyle belirtilir:
config_setting(
name = "meaningful_condition_name",
values = {
"flag1": "value1",
"flag2": "value2",
...
},
)
flagN
, işaret adı (--
olmadan, yani "--cpu"
yerine "cpu"
) bağımsız değişkenidir. valueN
, bu işaret için beklenen değer bağımsız değişkenidir. values
'daki her giriş eşleşirse :meaningful_condition_name
eşleşir. Sipariş alakasız.
valueN
, komut satırında ayarlanmış gibi ayrıştırılır. Bunun anlamı şudur:
values = { "compilation_mode": "opt" }
boyutubazel build -c opt
ifadesiyle eşleşiyorvalues = { "force_pic": "true" }
boyutubazel build --force_pic=1
ifadesiyle eşleşiyorvalues = { "force_pic": "0" }
boyutubazel build --noforce_pic
ifadesiyle eşleşiyor
config_setting
yalnızca hedef davranışı etkileyen işaretleri destekler. Örneğin, --show_progress
yalnızca Bazel'in ilerleme durumunu kullanıcıya bildirme şeklini etkilediği için buna izin verilmez. Hedefler, sonuçlarını oluşturmak için bu işareti kullanamaz. Desteklenen flag'lerin tam grubu
belgelendirir. Pratikte, "anlamlı" olan çoğu işaret çalışır.
Özel işaretler
Kendi projenize özel işaretlerinizi Starlark derleme ayarları Yerleşik flag'lerin aksine bu nedenle, Bazel bunların referans etiketleriyle referans verir.
Bunlar, config_setting
öğesinin flag_values
özelliğiyle tetiklenir:
config_setting(
name = "meaningful_condition_name",
flag_values = {
"//myflags:flag1": "value1",
"//myflags:flag2": "value2",
...
},
)
Davranış, yerleşik işaretler ile aynıdır. Buraya bakın örneği inceleyelim.
--define
özel işaretler için alternatif bir eski söz dizimidir (örneğin,
--define foo=bar
) tıklayın. Bu,
values özelliği
(values = {"define": "foo=bar"}
) veya
define_values özelliği
(define_values = {"foo": "bar"}
). --define
yalnızca geriye dönük olarak desteklenir
uyumluluk. Mümkün olduğunda Starlark derleme ayarlarını tercih edin.
values
, flag_values
ve define_values
bağımsız olarak değerlendirilir. Tüm config_setting
değerleri eşleşirse eşleşme gerçekleşir.
Varsayılan koşul
Yerleşik koşul (//conditions:default
) başka koşul olmadığında eşleşir
şununla eşleşir:
"Tam olarak bir eşleşme" nedeniyle kuralı, eşleşmesi olmayan yapılandırılabilir bir özellik
ve hiçbir varsayılan koşul "no matching conditions"
hatası vermez. Bu, beklenmedik ayarlardan kaynaklanan sessiz hatalara karşı koruma sağlayabilir:
# myapp/BUILD
config_setting(
name = "x86_cpu",
values = {"cpu": "x86"},
)
cc_library(
name = "x86_only_lib",
srcs = select({
":x86_cpu": ["lib.cc"],
}),
)
$ bazel build //myapp:x86_only_lib --cpu=arm
ERROR: Configurable attribute "srcs" doesn't match this configuration (would
a default condition help?).
Conditions checked:
//myapp:x86_cpu
Daha net hatalar için select()
'ın no_match_error
özelliğini kullanarak özel mesajlar ayarlayabilirsiniz.
Platformlar
Komut satırında birden fazla bayrak belirtme olanağı, ancak her seferinde her birini ayrı ayrı ayarlamak zahmetli olabilir. bir hedef oluşturmanız gerekir. Platformlar bunları basit paketlerde birleştirmenize olanak tanır.
# myapp/BUILD
sh_binary(
name = "my_rocks",
srcs = select({
":basalt": ["pyroxene.sh"],
":marble": ["calcite.sh"],
"//conditions:default": ["feldspar.sh"],
}),
)
config_setting(
name = "basalt",
constraint_values = [
":black",
":igneous",
],
)
config_setting(
name = "marble",
constraint_values = [
":white",
":metamorphic",
],
)
# constraint_setting acts as an enum type, and constraint_value as an enum value.
constraint_setting(name = "color")
constraint_value(name = "black", constraint_setting = "color")
constraint_value(name = "white", constraint_setting = "color")
constraint_setting(name = "texture")
constraint_value(name = "smooth", constraint_setting = "texture")
constraint_setting(name = "type")
constraint_value(name = "igneous", constraint_setting = "type")
constraint_value(name = "metamorphic", constraint_setting = "type")
platform(
name = "basalt_platform",
constraint_values = [
":black",
":igneous",
],
)
platform(
name = "marble_platform",
constraint_values = [
":white",
":smooth",
":metamorphic",
],
)
Platform, komut satırında belirtilebilir. Platformun constraint_values
alt kümesini içeren config_setting
'leri etkinleştirerek bu config_setting
'lerin select()
ifadelerinde eşleşmesine olanak tanır.
Örneğin, my_rocks
öğesinin srcs
özelliğini calcite.sh
olarak ayarlamak için
çalıştırabileceğiniz
bazel build //my_app:my_rocks --platforms=//myapp:marble_platform
Platformlar olmadan şuna benzer şekilde görünebilir:
bazel build //my_app:my_rocks --define color=white --define texture=smooth --define type=metamorphic
select()
, constraint_value
'leri doğrudan da okuyabilir:
constraint_setting(name = "type")
constraint_value(name = "igneous", constraint_setting = "type")
constraint_value(name = "metamorphic", constraint_setting = "type")
sh_binary(
name = "my_rocks",
srcs = select({
":igneous": ["igneous.sh"],
":metamorphic" ["metamorphic.sh"],
}),
)
Böylece, ortak bir metin kullanmanız gerektiğinde config_setting
standartlarından tasarruf edebilirsiniz.
tek değerlerle karşılaştırmalı olarak görebilirsiniz.
Platformlar hâlâ geliştirme aşamasındadır. Bkz. dokümanları inceleyin.
select()
birleştiriliyor
select
, aynı özellikte birden çok kez görünebilir:
sh_binary(
name = "my_target",
srcs = ["always_include.sh"] +
select({
":armeabi_mode": ["armeabi_src.sh"],
":x86_mode": ["x86_src.sh"],
}) +
select({
":opt_mode": ["opt_extras.sh"],
":dbg_mode": ["dbg_extras.sh"],
}),
)
select
, başka bir select
içinde görünemez. selects
içine yerleştirmeniz gerekiyorsa ve özelliğiniz değerler olarak başka hedefler alıyorsa ara hedef kullanın:
sh_binary(
name = "my_target",
srcs = ["always_include.sh"],
deps = select({
":armeabi_mode": [":armeabi_lib"],
...
}),
)
sh_library(
name = "armeabi_lib",
srcs = select({
":opt_mode": ["armeabi_with_opt.sh"],
...
}),
)
Birden fazla koşul eşleştiğinde eşleşmesi için bir select
değerine ihtiyacınız varsa VE zincirleme işlemini kullanabilirsiniz.
VEYA zincirleme
Aşağıdakileri göz önünde bulundurun:
sh_binary(
name = "my_target",
srcs = ["always_include.sh"],
deps = select({
":config1": [":standard_lib"],
":config2": [":standard_lib"],
":config3": [":standard_lib"],
":config4": [":special_lib"],
}),
)
Çoğu koşul aynı dep ile değerlendirilir. Ancak bu söz dizimi okunması ve bakımı zordur. [":standard_lib"]
öğesini birden fazla kez tekrarlamak zorunda olmasaydım
kez.
Seçeneklerden biri, değeri bir BUILD değişkeni olarak önceden tanımlamaktır:
STANDARD_DEP = [":standard_lib"]
sh_binary(
name = "my_target",
srcs = ["always_include.sh"],
deps = select({
":config1": STANDARD_DEP,
":config2": STANDARD_DEP,
":config3": STANDARD_DEP,
":config4": [":special_lib"],
}),
)
Bu, bağımlılığı yönetmeyi kolaylaştırır. Ama yine de gereksiz yineleme.
Daha doğrudan destek için aşağıdakilerden birini kullanın:
selects.with_or
İlgili içeriği oluşturmak için kullanılan
with_or
makrosu Skylib
selects
modülü doğrudan bir select
içinde OR
koşulları destekler:
load("@bazel_skylib//lib:selects.bzl", "selects")
sh_binary(
name = "my_target",
srcs = ["always_include.sh"],
deps = selects.with_or({
(":config1", ":config2", ":config3"): [":standard_lib"],
":config4": [":special_lib"],
}),
)
selects.config_setting_group
İlgili içeriği oluşturmak için kullanılan
config_setting_group
makrosu Skylib
selects
modül OR
birden çok config_setting
'yı destekler:
load("@bazel_skylib//lib:selects.bzl", "selects")
config_setting(
name = "config1",
values = {"cpu": "arm"},
)
config_setting(
name = "config2",
values = {"compilation_mode": "dbg"},
)
selects.config_setting_group(
name = "config1_or_2",
match_any = [":config1", ":config2"],
)
sh_binary(
name = "my_target",
srcs = ["always_include.sh"],
deps = select({
":config1_or_2": [":standard_lib"],
"//conditions:default": [":other_lib"],
}),
)
selects.with_or
'ün aksine farklı hedefler, :config1_or_2
'yi farklı özelliklerde paylaşabilir.
Bir koşul diğerlerinin net bir "uzmanlığı" olmadığı veya tümü aynı değere çözüme ulaşmadığı sürece birden fazla koşulun eşleşmesi hatadır. Ayrıntılı bilgi için buraya göz atın.
VE zincirleme
Birden fazla koşul eşleştiğinde eşleşmesi için bir select
dalına ihtiyacınız varsa Skylib makrosu config_setting_group'u kullanın:
config_setting(
name = "config1",
values = {"cpu": "arm"},
)
config_setting(
name = "config2",
values = {"compilation_mode": "dbg"},
)
selects.config_setting_group(
name = "config1_and_2",
match_all = [":config1", ":config2"],
)
sh_binary(
name = "my_target",
srcs = ["always_include.sh"],
deps = select({
":config1_and_2": [":standard_lib"],
"//conditions:default": [":other_lib"],
}),
)
VEYA zincirleme işleminin aksine, mevcut config_setting
'ler bir select
içinde doğrudan AND
edilemez. Bunları açıkça bir config_setting_group
içine sarmanız gerekir.
Özel hata mesajları
Varsayılan olarak, hiçbir koşul eşleşmediğinde select()
öğesinin bağlı olduğu hedef aşağıdaki hatayla başarısız olur:
ERROR: Configurable attribute "deps" doesn't match this configuration (would
a default condition help?).
Conditions checked:
//tools/cc_target_os:darwin
//tools/cc_target_os:android
Bu, no_match_error
ile özelleştirilebilir
özellik:
cc_library(
name = "my_lib",
deps = select(
{
"//tools/cc_target_os:android": [":android_deps"],
"//tools/cc_target_os:windows": [":windows_deps"],
},
no_match_error = "Please build with an Android or Windows toolchain",
),
)
$ bazel build //myapp:my_lib
ERROR: Configurable attribute "deps" doesn't match this configuration: Please
build with an Android or Windows toolchain
Kural uyumluluğu
Kural uygulamaları, yapılandırılabilir yapılandırmanın çözülmüş değerlerini alır özellikleri hakkında daha fazla bilgi edinin. Örneğin:
# myapp/BUILD
some_rule(
name = "my_target",
some_attr = select({
":foo_mode": [":foo"],
":bar_mode": [":bar"],
}),
)
$ bazel build //myapp/my_target --define mode=foo
Kural uygulama kodu, ctx.attr.some_attr
değerini [":foo"]
olarak görür.
Makrolar select()
ifadelerini kabul edip yerel öğelere iletebilir
kurallar. Ancak doğrudan manipüle edemezler. Örneğin, bir makronun
select({"foo": "val"}, ...)
to
select({"foo": "val_with_suffix"}, ...)
Bunun iki nedeni vardır.
Öncelikle, select
'nin hangi yolu seçeceğini bilmesi gereken makrolar çalışamaz çünkü makrolar, işaret değerleri bilinmeden önce gerçekleşen Bazel'in yükleme aşamasında değerlendirilir.
Bu, yakın zamanda değişmesi pek olası olmayan temel bir Bazel tasarım kısıtlamasıdır.
İkinci olarak, tüm select
yollarında iterasyon yapması gereken makrolar teknik olarak mümkün olsa da tutarlı bir kullanıcı arayüzüne sahip değildir. Bunu değiştirmek için daha fazla tasarım çalışması gerekir.
Bazel sorgusu ve cquery
Bazel query
, Bazel'in
yükleme aşamasında.
Bu, bu işaretler derlemenin ilerleyen aşamalarında (analiz aşamasında) değerlendirilmediğinden, bir hedefin hangi komut satırı işaretlerini kullandığını bilmediği anlamına gelir.
Bu nedenle, hangi select()
dallarının seçildiğini belirleyemez.
Bazel cquery
, Bazel'in analiz aşamasından sonra çalışır. Bu nedenle, tüm bu bilgilere sahiptir ve select()
'ları doğru şekilde çözebilir.
Aşağıdakileri göz önünde bulundurun:
load("@bazel_skylib//rules:common_settings.bzl", "string_flag")
# myapp/BUILD
string_flag(
name = "dog_type",
build_setting_default = "cat"
)
cc_library(
name = "my_lib",
deps = select({
":long": [":foo_dep"],
":short": [":bar_dep"],
}),
)
config_setting(
name = "long",
flag_values = {":dog_type": "dachshund"},
)
config_setting(
name = "short",
flag_values = {":dog_type": "pug"},
)
query
, :my_lib
kullanıcısının bağımlılıklarına yüksek tahmini bir değer verir:
$ bazel query 'deps(//myapp:my_lib)'
//myapp:my_lib
//myapp:foo_dep
//myapp:bar_dep
cquery
ise tam bağımlılıklarını gösterir:
$ bazel cquery 'deps(//myapp:my_lib)' --//myapp:dog_type=pug
//myapp:my_lib
//myapp:bar_dep
SSS
select() işlevi makrolarda neden çalışmıyor?
select() işlevi kurallarda çalışıyor. Ayrıntılar için Kural uyumluluğu bölümüne bakın.
Bu sorunun genellikle temel nedeni, select() işlevinin makrolarda çalışmamasıdır. Bunlar kurallardan farklıdır. Bkz. kurallar ve makrolar ile ilgili dokümanlar anlamanıza yardımcı olabilir. Aşağıda uçtan uca bir örnek verilmiştir:
Bir kural ve makro tanımlayın:
# myapp/defs.bzl
# Rule implementation: when an attribute is read, all select()s have already
# been resolved. So it looks like a plain old attribute just like any other.
def _impl(ctx):
name = ctx.attr.name
allcaps = ctx.attr.my_config_string.upper() # This works fine on all values.
print("My name is " + name + " with custom message: " + allcaps)
# Rule declaration:
my_custom_bazel_rule = rule(
implementation = _impl,
attrs = {"my_config_string": attr.string()},
)
# Macro declaration:
def my_custom_bazel_macro(name, my_config_string):
allcaps = my_config_string.upper() # This line won't work with select(s).
print("My name is " + name + " with custom message: " + allcaps)
Kuralı ve makroyu örneklendirin:
# myapp/BUILD
load("//myapp:defs.bzl", "my_custom_bazel_rule")
load("//myapp:defs.bzl", "my_custom_bazel_macro")
my_custom_bazel_rule(
name = "happy_rule",
my_config_string = select({
"//tools/target_cpu:x86": "first string",
"//third_party/bazel_platforms/cpu:ppc": "second string",
}),
)
my_custom_bazel_macro(
name = "happy_macro",
my_config_string = "fixed string",
)
my_custom_bazel_macro(
name = "sad_macro",
my_config_string = select({
"//tools/target_cpu:x86": "first string",
"//third_party/bazel_platforms/cpu:ppc": "other string",
}),
)
sad_macro
, select()
öğesini işleyemediği için derleme başarısız oldu:
$ bazel build //myapp:all
ERROR: /myworkspace/myapp/BUILD:17:1: Traceback
(most recent call last):
File "/myworkspace/myapp/BUILD", line 17
my_custom_bazel_macro(name = "sad_macro", my_config_stri..."}))
File "/myworkspace/myapp/defs.bzl", line 4, in
my_custom_bazel_macro
my_config_string.upper()
type 'select' has no method upper().
ERROR: error loading package 'myapp': Package 'myapp' contains errors.
sad_macro
'yi yoruma aldığınızda derleme başarılı olur:
# Comment out sad_macro so it doesn't mess up the build.
$ bazel build //myapp:all
DEBUG: /myworkspace/myapp/defs.bzl:5:3: My name is happy_macro with custom message: FIXED STRING.
DEBUG: /myworkspace/myapp/hi.bzl:15:3: My name is happy_rule with custom message: FIRST STRING.
Bazel, derlemenin komut satırı işaretlerini okumadan önce makrolar tanım gereği değerlendirildiği için bu durum değiştirilemez. Demek ki yeterli select() işlevini değerlendirmek için bilgi kullanır.
Ancak makrolar, select()
öğelerini kurallara opak blob olarak iletebilir:
# myapp/defs.bzl
def my_custom_bazel_macro(name, my_config_string):
print("Invoking macro " + name)
my_custom_bazel_rule(
name = name + "_as_target",
my_config_string = my_config_string,
)
$ bazel build //myapp:sad_macro_less_sad
DEBUG: /myworkspace/myapp/defs.bzl:23:3: Invoking macro sad_macro_less_sad.
DEBUG: /myworkspace/myapp/defs.bzl:15:3: My name is sad_macro_less_sad with custom message: FIRST STRING.
select() neden her zaman doğru sonucunu döndürüyor?
Makrolar (kurallar değil) tanımı gereği select()
'leri değerlendiremediğinden bunu yapmaya yönelik her girişim genellikle hata oluşturur:
ERROR: /myworkspace/myapp/BUILD:17:1: Traceback
(most recent call last):
File "/myworkspace/myapp/BUILD", line 17
my_custom_bazel_macro(name = "sad_macro", my_config_stri..."}))
File "/myworkspace/myapp/defs.bzl", line 4, in
my_custom_bazel_macro
my_config_string.upper()
type 'select' has no method upper().
Mantıksal değerler, sessizce başarısız olan özel bir durumdur. Bu nedenle, özellikle bunlar konusunda dikkatli olmanız gerekir:
$ cat myapp/defs.bzl
def my_boolean_macro(boolval):
print("TRUE" if boolval else "FALSE")
$ cat myapp/BUILD
load("//myapp:defs.bzl", "my_boolean_macro")
my_boolean_macro(
boolval = select({
"//tools/target_cpu:x86": True,
"//third_party/bazel_platforms/cpu:ppc": False,
}),
)
$ bazel build //myapp:all --cpu=x86
DEBUG: /myworkspace/myapp/defs.bzl:4:3: TRUE.
$ bazel build //mypro:all --cpu=ppc
DEBUG: /myworkspace/myapp/defs.bzl:4:3: TRUE.
Bunun nedeni, makroların select()
içeriğini anlamamasıdır.
Aslında değerlendirdikleri şey select()
nesnesinin kendisi. Kaynak:
Pythonik tasarım
istisnaları çözülmezse çok az sayıda istisna dışında tüm
otomatik olarak doğru değerini döndürür.
select() öğesini bir dikt gibi okuyabilir miyim?
Makrolar daha önce değerlendirildiği için seçimleri değerlendiremez
Bazel, derlemenin komut satırı parametrelerinin ne olduğunu bilir. Örneğin, her değere son ek eklemek için en azından select()
sözlüğünü okuyabilir mi?
Kavramsal olarak bu mümkündür, ancak henüz bir Bazel özelliği değildir.
Bugün yapabilirsiniz, düz bir sözlük hazırlayıp
select()
:
$ cat myapp/defs.bzl
def selecty_genrule(name, select_cmd):
for key in select_cmd.keys():
select_cmd[key] += " WITH SUFFIX"
native.genrule(
name = name,
outs = [name + ".out"],
srcs = [],
cmd = "echo " + select(select_cmd + {"//conditions:default": "default"})
+ " > $@"
)
$ cat myapp/BUILD
selecty_genrule(
name = "selecty",
select_cmd = {
"//tools/target_cpu:x86": "x86 mode",
},
)
$ bazel build //testapp:selecty --cpu=x86 && cat bazel-genfiles/testapp/selecty.out
x86 mode WITH SUFFIX
Hem select()
hem de yerel türleri desteklemek istiyorsanız şunları yapabilirsiniz:
$ cat myapp/defs.bzl
def selecty_genrule(name, select_cmd):
cmd_suffix = ""
if type(select_cmd) == "string":
cmd_suffix = select_cmd + " WITH SUFFIX"
elif type(select_cmd) == "dict":
for key in select_cmd.keys():
select_cmd[key] += " WITH SUFFIX"
cmd_suffix = select(select_cmd + {"//conditions:default": "default"})
native.genrule(
name = name,
outs = [name + ".out"],
srcs = [],
cmd = "echo " + cmd_suffix + "> $@",
)
select() neden bind() ile çalışmıyor?
Çünkü bind()
bir BUILD kuralı değil, bir WORKSPACE kuralıdır.
Workspace kuralları belirli bir yapılandırmaya sahip değildir ve BUILD kurallarıyla aynı şekilde değerlendirilmez. Bu nedenle, bind()
içindeki bir select()
aslında belirli bir şubeye göre değerlendirilemez.
Bunun yerine, bu tür bir çalışma zamanında belirleme yapmak için actual
özelliğinde select()
ile alias()
kullanmalısınız. Bu
doğru çalışır. Çünkü alias()
bir DERLE kuralıdır ve
yapılandırma.
Gerekirse bir bind()
'ün alias()
'u hedeflemesini bile sağlayabilirsiniz.
$ cat WORKSPACE
workspace(name = "myapp")
bind(name = "openssl", actual = "//:ssl")
http_archive(name = "alternative", ...)
http_archive(name = "boringssl", ...)
$ cat BUILD
config_setting(
name = "alt_ssl",
define_values = {
"ssl_library": "alternative",
},
)
alias(
name = "ssl",
actual = select({
"//:alt_ssl": "@alternative//:ssl",
"//conditions:default": "@boringssl//:ssl",
}),
)
Bu kurulumla --define ssl_library=alternative
ayarını ve tüm hedefleri geçirebilirsiniz
//:ssl
veya //external:ssl
öğesine bağlı olan işlemler alternatifi görür.
şu adreste bulunuyor: @alternative//:ssl
.
select() işlevim neden beklediğimi seçmiyor?
//myapp:foo
, beklediğiniz koşulu seçmeyen bir select()
içeriyorsa
hata ayıklamak için cquery ve bazel config
tuşlarını kullanın:
//myapp:foo
, oluşturmakta olduğunuz üst düzey hedefse şunu çalıştırın:
$ bazel cquery //myapp:foo <desired build flags>
//myapp:foo (12e23b9a2b534a)
Farklı bir hedef //bar
oluşturuyorsanız
//myapp:foo'u alt grafiğinde bir yere yazın, şunu çalıştırın:
$ bazel cquery 'somepath(//bar, //myapp:foo)' <desired build flags>
//bar:bar (3ag3193fee94a2)
//bar:intermediate_dep (12e23b9a2b534a)
//myapp:foo (12e23b9a2b534a)
//myapp:foo
öğesinin yanındaki (12e23b9a2b534a)
, şu öğenin karmasıdır:
//myapp:foo
ürününün select()
sorununu çözümleyen yapılandırma. Değerlerini bazel config
ile inceleyebilirsiniz:
$ bazel config 12e23b9a2b534a
BuildConfigurationValue 12e23b9a2b534a
Fragment com.google.devtools.build.lib.analysis.config.CoreOptions {
cpu: darwin
compilation_mode: fastbuild
...
}
Fragment com.google.devtools.build.lib.rules.cpp.CppOptions {
linkopt: [-Dfoo=bar]
...
}
...
Ardından bu çıktıyı her config_setting
tarafından beklenen ayarlarla karşılaştırın.
//myapp:foo
, aynı derlemede farklı yapılandırmalarda bulunabilir. Bkz.
doğru verileri almak için somepath
kullanma konusunda rehberlik için cquery docs
bir.
select()
neden platformlarla çalışmıyor?
Bazel, belirli bir platformun olup olmadığını kontrol eden yapılandırılabilir özellikleri desteklemiyor hedef platformdur. Çünkü anlamları belirsizdir.
Örneğin:
platform(
name = "x86_linux_platform",
constraint_values = [
"@platforms//cpu:x86",
"@platforms//os:linux",
],
)
cc_library(
name = "lib",
srcs = [...],
linkopts = select({
":x86_linux_platform": ["--enable_x86_optimizations"],
"//conditions:default": [],
}),
)
Bu BUILD
dosyasında, hedef platform hemselect()
@platforms//cpu:x86
ve @platforms//os:linux
kısıtlamaları, ancak geçerli değildir.
:x86_linux_platform
burada tanımlansın mı? BUILD
dosyasının yazarı ve kullanıcı
farklı fikirleri olabilir.
Bunun yerine ne yapmalıyım?
Bunun yerine, şununla herhangi bir platformla eşleşen bir config_setting
tanımlayın:
şu kısıtlamaları dikkate almanız gerekir:
config_setting(
name = "is_x86_linux",
constraint_values = [
"@platforms//cpu:x86",
"@platforms//os:linux",
],
)
cc_library(
name = "lib",
srcs = [...],
linkopts = select({
":is_x86_linux": ["--enable_x86_optimizations"],
"//conditions:default": [],
}),
)
Bu süreç belirli anlamları tanımlayarak kullanıcılara neyin ne anlama geldiğini net bir şekilde istenen koşulları karşılamasını sağlar.
Platformda select
yapmak istiyorum.
Derleme gereksinimleriniz özellikle platformun kontrol edilmesini gerektiriyorsa
config_setting
içindeki --platforms
işaretinin değerini çevirebilir:
config_setting(
name = "is_specific_x86_linux_platform",
values = {
"platforms": ["//package:x86_linux_platform"],
},
)
cc_library(
name = "lib",
srcs = [...],
linkopts = select({
":is_specific_x86_linux_platform": ["--enable_x86_optimizations"],
"//conditions:default": [],
}),
)
Bazel ekibi bu yöntemi önermez. Bu yöntem, derlemenizi aşırı derecede kısıtlar ve beklenen koşul eşleşmediğinde kullanıcıları şaşırtır.