Kurallar

. Sorun bildirin Kaynağı göster Gece · 7,3 · 7,2 · 7,1 · 7,0 · 6,5

Kural, Bazel'in gerçekleştirdiği bir dizi işlemi tanımlar Bir dizi çıkış üretmek için kullanılan girişler, Kuralın tarafından döndürülen sağlayıcılar uygulama işlevi hakkında daha fazla bilgi edinin. Örneğin, bir C++ ikili kuralı şunları yapabilir:

  1. .cpp kaynak dosyası (giriş) alın.
  2. Kaynak dosyalarda g++ komutunu çalıştırın (işlem).
  3. Yürütülebilir çıktıyı ve diğer dosyaları içeren DefaultInfo sağlayıcısını iade edin kullanılabilir hale getirmektir.
  4. CcInfo sağlayıcısını, ve bağımlılıklarını konuşacağız.

Bazel açısından bakıldığında g++ ve standart C++ kitaplıkları da ekleyin. Kural yazarı olarak, yalnızca kullanıcı tarafından sağlanan aynı zamanda yürütülmesi için gereken tüm araçlar ve kitaplıkların işlemlerdir.

Herhangi bir kural oluşturmadan veya değiştirmeden önce Bazel'in geliştirme aşamalarına göz atın. Üç noktayı anlamanız önemlidir, aşamalarından (yükleme, analiz ve yürütme) oluşur. Proje zaman çizelgesini kurallar ve makrolar arasındaki farkı anlamak için makrolar hakkında bilgi edinin makrolarında da yer alır. Başlamak için önce Kurallar Eğitimi'ni inceleyin. Ardından, bu sayfayı referans olarak kullanın.

Bazel'in kendisinde birkaç kural oluşturulmuştur. Bu yerel kurallar, örneğin cc_library ve java_binary, belirli diller için temel destek sağlar. Kendi kurallarınızı tanımlayarak dil ve araçlar için de benzer destek özellikleri ekleyebilirsiniz. temel olarak desteklemediğini unutmayın.

Bazel, Starlark'ın dili. Bu kurallar .bzl dosyalarına yazılır. Bu dosyalar BUILD dosyadan doğrudan yüklenebilir.

Kendi kuralınızı tanımlarken kuralınızın hangi özellikleri desteklediğine ve ve çıktılarını nasıl ürettiğini konuştuk.

Kuralın implementation işlevi, analiz aşamasından erişilebilir. Bu işlev, harici komutlar verebilirsiniz. Bunun yerine, bu araçtan yararlanmak için işlemleri sonraki aşamalarda devreye girerek kuralın çıktılarını gerekir.

Kural oluşturma

Bir .bzl dosyasında yeni bir kural tanımlamak için rule işlevini kullanın kuralına ekleyin ve sonucu genel bir değişkende depolayın. rule çağrısı, özellikler ve uygulama işlevi:

example_library = rule(
    implementation = _example_library_impl,
    attrs = {
        "deps": attr.label_list(),
        ...
    },
)

Bu, example_library adlı bir kural türünü tanımlar.

rule çağrısı, kuralın yürütülebilir çıkış (executable=True ile) veya özel olarak yürütülebilir bir test (test=True ile). İkincisi ise kural bir test kuralı ise ve kuralın adı _test ile bitmelidir.

Hedef örneklendirme

Kurallar yüklenebilir ve BUILD dosyalarında çağrılabilir:

load('//some/pkg:rules.bzl', 'example_library')

example_library(
    name = "example_target",
    deps = [":another_target"],
    ...
)

Bir derleme kuralına yapılan her çağrı, hiçbir değer döndürmez ancak belirir. Buna, kuralın tetiklenmesi denir. Bu, Hedefin özellikleri için yeni hedef ve değerler girin.

Kurallar, Starlark işlevlerinden de çağrılabilir ve .bzl dosyalarına yüklenebilir. Kuralları çağıran Starlark işlevleri Starlark makroları olarak adlandırılır. Starlark makroları sonuçta BUILD dosyalarından çağrılmalıdır ve yalnızca BUILD olduğunda yükleme aşamasında çağrılır dosyaları, hedefleri örneklendirmek için değerlendirilir.

Özellikler

Özellik, bir kural bağımsız değişkenidir. Özellikler, bir uygulamasına yönlendirmediği takdirde bağımlılıklarını gösteren bir grafik oluşturuyorsunuz.

srcs veya deps gibi kurala özgü özellikler, haritadan geçilerek tanımlanır özellik adlarından şemalara (attr modülü) rule öğesinin attrs parametresine ekleyin. Şunlar gibi ortak özellikler name ve visibility, tüm kurallara dolaylı olarak eklenir. Ek bilgiler özelliklerinin dolaylı olarak yürütülebilir ve test kurallarını uygulayın. Şu özellikte olan özellikler: bir kurala dolaylı olarak eklendiğinde, attrs

Bağımlılık özellikleri

Kaynak kodunu işleyen kurallar, genellikle işlenecek aşağıdaki özellikleri tanımlar bağımlılık türlerini görebilirsiniz:

  • srcs, hedefin işlemleri tarafından işlenen kaynak dosyaları belirtir. Çoğu zaman özellik şeması, sıralama için hangi dosya uzantılarının beklendiğini belirtir kuralının işlediği kaynak dosyayı oluşturur. Başlık dosyaları olan dil kuralları tarafından işlenen başlıklar için genellikle ayrı bir hdrs özelliği belirtir. ve tüketicilerini hedefler.
  • deps, bir hedef için kod bağımlılıklarını belirtir. Özellik şeması Bu bağımlıların hangi sağlayıcıları sağlaması gerektiğini belirtin. ( Örneğin, cc_library, CcInfo sağlar.)
  • data, çalışma zamanında yürütülebilir herhangi bir dosya için kullanıma sunulacak dosyaları belirtir Bu da hedefe bağlıdır. Bu, rastgele dosyaların belirtiliyor.
example_library = rule(
    implementation = _example_library_impl,
    attrs = {
        "srcs": attr.label_list(allow_files = [".example"]),
        "hdrs": attr.label_list(allow_files = [".header"]),
        "deps": attr.label_list(providers = [ExampleInfo]),
        "data": attr.label_list(allow_files = True),
        ...
    },
)

Bunlar, bağımlılık özelliklerine örnektir. Belirttiği herhangi bir özellik: giriş etiketi ( attr.label_list attr.label veya attr.label_keyed_string_dict) belirli bir türdeki bağımlılıkları belirtir arasında bir hedef ile etiketleri (veya ilgili Label nesne) söz konusu özellikte listelenir. tanımlanmıştır. Bu etiketlerin depo ve muhtemelen yolu çözümlendi ve tanımlanan hedefe göre belirlenir.

example_library(
    name = "my_target",
    deps = [":other_target"],
)

example_library(
    name = "other_target",
    ...
)

Bu örnekte other_target, my_target bağımlılığıdır ve dolayısıyla Önce other_target analiz edilir. Zaman çizelgesinde döngü varsa bağımlılık grafiğini görebilirsiniz.

Özel özellikler ve örtülü bağımlılıklar

Varsayılan değere sahip bir bağımlılık özelliği dolaylı bağımlılık oluşturur. Google dolaylı bir hedeftir çünkü kullanıcının aramadığı hedef grafiğin bir parçası olduğu için, BUILD dosyasında belirtin. Örtülü bağımlılıklar, bir projeniz için bir kural ile araç arasındaki ilişki (ör. (derleyici) içerir. Kullanıcılar çoğu zaman aracını kullanın. Kuralın uygulama işlevinde bu aynı olduğunu göreceksiniz.

Kullanıcının çalıştırmasına izin vermeden bir örtülü bağımlılık sağlamak bu değeri geçersiz kılarsanız, özelliğe bir ad vererek özelliği gizli hale getirebilirsiniz bir alt çizgi (_) ile başlayan reklamlar gösterilir. Özel özelliklerin varsayılan değeri olmalıdır değerler. Gizli özellikleri kullanmak genellikle ve bildirmeyi konuştuk.

example_library = rule(
    implementation = _example_library_impl,
    attrs = {
        ...
        "_compiler": attr.label(
            default = Label("//tools:example_compiler"),
            allow_single_file = True,
            executable = True,
            cfg = "exec",
        ),
    },
)

Bu örnekte, example_library türündeki her hedefin şu derleyicide bağımlılık: //tools:example_compiler. Bu da example_library öğesinin uygulama işlevini kullanarak kullanıcı etiketini giriş olarak aktarmamış olsa bile derleyici tarafından görüntülenebilir. Başlangıç _compiler gizli bir özellik olduğu için ctx.attr._compiler bu kuralın tüm hedeflerinde her zaman //tools:example_compiler değerini gösterir türü. Alternatif olarak, compiler özelliğini alt çizgi çizin ve varsayılan değeri koruyun. Bu, kullanıcıların farklı bir yerine farklı bir derleyici kullanabilir, ancak derleyicinin kodu ile ilgili bilgi sahibi değildir etiket.

Dolaylı bağımlılıklar genellikle aynı modelde bulunan araçlar için depoyu etkinleştirmelisiniz. Araç yürütme platformuna veya farklı bir depoya kuralının söz konusu aracı bir araç zincirinden edinmesi gerekir.

Çıkış özellikleri

Çıkış özellikleri, örneğin attr.output ve attr.output_list ise bir çıkış dosyası bildirin. anlamına gelir. Bunlar bağımlılık özelliklerinden iki şekilde ayrılır:

  • Tanımlanan hedeflere başvurmak yerine çıkış dosyası hedeflerini tanımlarlar olduğunu anlayabilir.
  • Çıkış dosyası hedefleri, şunun yerine örneklenen kural hedefine dayanır: tam tersi.

Genellikle çıkış özellikleri yalnızca bir kuralın çıkış oluşturması gerektiğinde kullanılır hedef ada dayalı olamayan kullanıcı tanımlı adlara sahip olmalıdır. Bir kural bir çıktı özelliği olduğundan bu genellikle out veya outs olarak adlandırılır.

Önceden beyan edilmiş çıkışları oluşturmanın tercih edilen yöntemi çıkış özellikleridir. projenin başarısına komut satırında istendiğinde.

Uygulama işlevi

Her kural için bir implementation işlevi gerekir. Bu işlevler yalnızca analiz aşamasında olması ve yükleme aşamasında oluşturulan hedeflerin grafik eylemlerin belirlenmesine yardımcı olur. Dolayısıyla, uygulama işlevleri dosya okuyamaz veya yazamaz.

Kural uygulama işlevleri genellikle gizlidir (baştaki alt çizgi) ekleyin. Geleneksel olarak, kurallarıyla aynı şekilde adlandırılırlar ancak _impl ile birlikte.

Uygulama işlevleri tam olarak bir parametre alır: kural bağlamı, geleneksel olarak ctx olarak adlandırılır. Bunlar, providers için de geçerli olacaktır.

Hedefler

Bağımlılıklar analiz zamanında Target olarak gösterilir nesneler'i tıklayın. Bu nesneler, hedefin uygulama işlevi yürütüldü.

ctx.attr her bir kullanıcının adına karşılık gelen alanlar içeriyor Her bir doğrudan temsil eden Target nesneyi içeren bağımlılık özelliği bu özellik üzerinden gelen bağımlılığı ifade eder. label_list özellikleri için bu liste Targets. label özellikleri için bu, tek bir Target veya None değeridir.

Bir hedefin uygulama işlevi, sağlayıcı nesnelerinin bir listesini döndürür:

return [ExampleInfo(headers = depset(...))]

Bunlara dizin gösterimi ([]) kullanılarak erişilebilir. Sağlayıcı türü şu şekildedir: kullanabilirsiniz. Bunlar özel sağlayıcılar Starlark veya Starlark olarak kullanılabilen yerel kural sağlayıcıları kullanabilirsiniz.

Örneğin bir kural, başlık dosyalarını hdrs özelliği aracılığıyla alıyor ve derleme işlemleri ile bağlantılı olarak, hedefin ve tüketicilerinin toplayabilirsiniz:

def _example_library_impl(ctx):
    ...
    transitive_headers = [hdr[ExampleInfo].headers for hdr in ctx.attr.hdrs]

Bir struct öğesinin hedefin uygulama işlevini çağırın:

return struct(example_info = struct(headers = depset(...)))

Sağlayıcılar, Target nesnesinin ilgili alanından alınabilir:

transitive_headers = [hdr.example_info.headers for hdr in ctx.attr.hdrs]

Bu stil kesinlikle önerilmez ve kurallar taşınması gerekir.

Dosyalar

Dosyalar File nesneleriyle temsil edilir. Bazel sırasında dosya G/Ç işlemleri gerçekleştirdiğinde, bu nesneler doğrudan okuma veya yazma imkanı sunar. Bunun yerine, geri bildirim veren (bkz. ctx.actions) işlevlerini kullanarak ve Eylem grafiği.

File, bir kaynak dosya veya oluşturulmuş bir dosya olabilir. Oluşturulan her dosya tam olarak bir işlemin sonucu olmalıdır. Kaynak dosyalar şunun çıktısı olamaz: herhangi bir işlem.

Her bir bağımlılık özelliği için, karşılık gelen ctx.files, tüm varsayılan çıkışların listesini içerir bağımlılıklarını görebilirsiniz:

def _example_library_impl(ctx):
    ...
    headers = depset(ctx.files.hdrs, transitive=transitive_headers)
    srcs = ctx.files.srcs
    ...

ctx.file, şunlar için tek bir File veya None içerir: özellikleri allow_single_file=True olarak ayarlanmış bağımlılık özellikleri. ctx.executable, ctx.file ile aynı şekilde davranır ancak yalnızca özellikleri executable=True olarak ayarlanmış bağımlılık özelliklerine ilişkin alanları içerir.

Çıkışları bildirme

Analiz aşamasında, bir kuralın uygulama işlevi çıktılar oluşturabilir. Yükleme aşamasında tüm etiketlerin bilinmesi gerektiğinden, bu ek etiketler çıkışların etiketi yok. Çıkışlar için File nesne aşağıdakileri kullanarak oluşturulabilir: ctx.actions.declare_file ve ctx.actions.declare_directory. Çoğu zaman Çıkışların adları hedefin adına göre belirlenir. ctx.label.name:

def _example_library_impl(ctx):
  ...
  output_file = ctx.actions.declare_file(ctx.label.name + ".output")
  ...

Önceden beyan edilmiş çıkışlar için (ör. şunun için oluşturulanlar) çıkış özellikleri, bunun yerine File nesneleri alınabilir ctx.outputs öğesinin ilgili alanlarından kaldırın.

İşlemler

Eylemde, kontrol grubu için bir dizi girdiden bir dizi çıkışın nasıl oluşturulacağını örnek: "hello.c'de gcc'yi çalıştır ve hello.o'yu al". Bir eylem oluşturulduğunda Bazel komutu hemen çalıştırmaz. Projeyi bir bağımlılık grafiğine kaydeder, Çünkü bir eylem, bir başka işlemin sonucuna bağlı olabilir. Örneğin, C'de, bağlayıcı, derleyiciden sonra çağrılmalıdır.

Eylem oluşturan genel amaçlı işlevler şurada tanımlanmıştır: ctx.actions:

ctx.actions.args, verimli bir şekilde kullanılabilir. işlemler için bağımsız değişkenleri biriktirme. Yok sayılana kadar yürütme süresi:

def _example_library_impl(ctx):
    ...

    transitive_headers = [dep[ExampleInfo].headers for dep in ctx.attr.deps]
    headers = depset(ctx.files.hdrs, transitive=transitive_headers)
    srcs = ctx.files.srcs
    inputs = depset(srcs, transitive=[headers])
    output_file = ctx.actions.declare_file(ctx.label.name + ".output")

    args = ctx.actions.args()
    args.add_joined("-h", headers, join_with=",")
    args.add_joined("-s", srcs, join_with=",")
    args.add("-o", output_file)

    ctx.actions.run(
        mnemonic = "ExampleCompile",
        executable = ctx.executable._compiler,
        arguments = [args],
        inputs = inputs,
        outputs = [output_file],
    )
    ...

İşlemler, giriş dosyalarının bir listesini veya alt kümesini alır ve şunları içeren (boş olmayan) bir liste oluşturur: çıkış dosyası olarak da kullanabilirsiniz. Giriş ve çıkış dosyaları grubu, analiz aşamasından geçti. Projenin değerine göre bağımlılıklarından gelen sağlayıcılar dahil olmak üzere bir sonucudur. Örneğin, işleminiz sıkıştırılmış dosya açma komutunu çalıştırıyorsa hangi dosyaların şişirilmesini beklediğinizi belirtmelidir (sıkıştırmayı açmadan önce). Dahili olarak değişken sayıda dosya oluşturan işlemler, bunları bir tek dosya (zip, tar veya başka bir arşiv biçimi gibi) desteklemez.

İşlemlerde tüm girişler listelenmelidir. Kullanılmayan girişlerin girilmesi ancak verimsizdir.

İşlemler tüm çıkışlarını oluşturmalıdır. Başka dosyalar yazabilirler ama Çıktılarda olmayan hiçbir şey tüketicilere sunulmayacak. Beyan edilen tüm çıkışlar bir işlem yapılarak yazılmalıdır.

Eylemler yalın işlevlerle karşılaştırılabilir: Yalnızca giriş yapmalı ve bilgisayar bilgilerine, kullanıcı adı, saat ve ağ veya G/Ç cihazları (okuma girişleri ve yazma çıkışları hariç) Bu önemlidir. Çünkü çıktı, önbelleğe alınıp yeniden kullanılır.

Bağımlılıklar Bazel tarafından çözülür ve hangi işlemlerin yürütüldü. Bağımlılık grafiğinde bir döngü varsa bu bir hatadır. Oluşturuluyor bir eylem, yürütüleceğini garanti etmez. Bu, ilgili kararın proje için gereken unsurlardır.

Sağlayıcılar

Sağlayıcılar, bir kuralın diğer kurallara açıkladığı ona güvenmeniz gerekir. Bu veriler; çıkış dosyaları, kitaplıklar, aktarılacak parametreler içerebilir bir aracın komut satırında veya hedef tüketicilerinin bilmesi gereken herhangi bir şey konu.

Bir kuralın uygulama işlevi yalnızca örneklenmiş hedefin acil bağımlılıklarını tarafından bilinmesi gereken, hedefin bağımlılıklarından elde edilen bir depset şeklinde biriktirme yoluyla elde edilir.

Bir hedefin sağlayıcıları, tarafından döndürülen Provider nesnelerin listesi ile belirtilir işlevi görür.

Eski uygulama işlevleri, uygulama işlevi struct sağlayıcı nesneleridir. Bu stil kesinlikle önerilmez ve kurallar taşınması gerekir.

Varsayılan çıkışlar

Bir hedefin varsayılan çıkışları, aşağıdaki durumlarda varsayılan olarak istenen çıkışlardır: komut satırında derleme için hedef istenir. Örneğin, java_library hedefi //pkg:foo için varsayılan çıkış olarak foo.jar kullanılıyor. bazel build //pkg:foo komutu tarafından oluşturulur.

Varsayılan çıkışlar, şu öğenin files parametresiyle belirtilir: DefaultInfo:

def _example_library_impl(ctx):
    ...
    return [
        DefaultInfo(files = depset([output_file]), ...),
        ...
    ]

DefaultInfo, bir kural uygulaması veya files tarafından döndürülmezse parametresi belirtilmemiş, DefaultInfo.files varsayılan olarak tümü önceden bildirilmiş çıkışlar (genellikle çıkış özellikleri).

İşlem gerçekleştiren kurallar, bu çıkışlar olsa bile varsayılan çıkışlar sağlamalıdır doğrudan kullanılmaları beklenmez. Grafikte bulunmayan işlemler istenen çıkışlar kısaltılır. Bir çıktı yalnızca hedefin tüketicileri tarafından kullanılıyorsa hedef ayrı olarak oluşturulduğunda bu işlemler gerçekleştirilmez. Bu yalnızca başarısız olan hedefi yeniden oluşturmak, hata ayıklamayı zorlaştıracağından, yeniden üretmemelidir.

Çalıştırma dosyaları

Çalıştırma dosyaları, bir hedef tarafından çalışma zamanında kullanılan bir dosya kümesidir. süre) ekleyebilirsiniz. Yürütme aşamasında Bazel, çalıştırma dosyalarını işaret eden sembolik bağlantılar içeren bir dizin ağacı. Bu aşama ortamına ekleyebilirsiniz.

Çalıştırma dosyaları, kural oluşturulurken manuel olarak eklenebilir. runfiles yöntemi ile runfiles nesne oluşturulabilir ctx.runfiles olarak ayarlanmış ve DefaultInfo için runfiles parametresi. Yürütülebilir çıktısı: executable rules (yürütülebilir kurallar), çalıştırma dosyalarına dolaylı olarak eklenir.

Bazı kurallar, genellikle data; çıkışları bir hedef çalıştırmanız gerekir. Ayrıca, çalıştırma dosyaları data ve genellikle nihai yürütme işlemine kod sağlayabilecek özelliklerden srcs (ilişkilendirilmiş data ile filegroup hedef içerebilir) ve deps.

def _example_library_impl(ctx):
    ...
    runfiles = ctx.runfiles(files = ctx.files.data)
    transitive_runfiles = []
    for runfiles_attr in (
        ctx.attr.srcs,
        ctx.attr.hdrs,
        ctx.attr.deps,
        ctx.attr.data,
    ):
        for target in runfiles_attr:
            transitive_runfiles.append(target[DefaultInfo].default_runfiles)
    runfiles = runfiles.merge_all(transitive_runfiles)
    return [
        DefaultInfo(..., runfiles = runfiles),
        ...
    ]

Özel sağlayıcılar

Sağlayıcılar, provider kullanılarak tanımlanabilir. işlevini kullanın:

ExampleInfo = provider(
    "Info needed to compile/link Example code.",
    fields={
        "headers": "depset of header Files from transitive dependencies.",
        "files_to_link": "depset of Files from compilation.",
    })

Daha sonra kural uygulama işlevleri, sağlayıcı örneklerini oluşturup döndürebilir:

def _example_library_impl(ctx):
  ...
  return [
      ...
      ExampleInfo(
          headers = headers,
          files_to_link = depset(
              [output_file],
              transitive = [
                  dep[ExampleInfo].files_to_link for dep in ctx.attr.deps
              ],
          ),
      )
  ]
Sağlayıcıların özel başlatılması

Bir sağlayıcının örneklendirmesini özel mantığıyla başlayalım. Bu, tüm iletişim türlerinin belirli değişkenliklere uyum sağlar veya kullanıcılara örnek alınıyor.

Bu,init provider işlevini kullanın. Bu geri çağırma yapılırsa provider() değişikliklerinin döndürme türü, iki değerin toplamı olacak şekilde değişir: provider init kullanılmadığında normal döndürülen değer ve "ham" sembolü oluşturucu"dur.

Bu durumda, sağlayıcı sembolü çağrıldığında, doğrudan yeni bir örnek oluşturursa bağımsız değişkenleri init geri çağırmasına yönlendirir. İlgili içeriği oluşturmak için kullanılan geri çağırmanın döndürülen değeri, değerler ile alan adları (dizeler) arasında bir dikt eşleme alanı olmalıdır; bu, yeni örneğin alanlarını başlatmak için kullanılır. Lütfen geri çağırmanın herhangi bir imzası olabilir ve bağımsız değişkenler imzayla eşleşmiyorsa doğrudan geri çağırma işlemi çağrılmış gibi bir hata bildirilir.

Buna karşılık, ham oluşturucu init geri çağırmasını atlar.

Aşağıdaki örnekte, bağımsız değişkenlerini önceden işlemek ve doğrulamak için init kullanılmaktadır:

# //pkg:exampleinfo.bzl

_core_headers = [...]  # private constant representing standard library files

# It's possible to define an init accepting positional arguments, but
# keyword-only arguments are preferred.
def _exampleinfo_init(*, files_to_link, headers = None, allow_empty_files_to_link = False):
    if not files_to_link and not allow_empty_files_to_link:
        fail("files_to_link may not be empty")
    all_headers = depset(_core_headers, transitive = headers)
    return {'files_to_link': files_to_link, 'headers': all_headers}

ExampleInfo, _new_exampleinfo = provider(
    ...
    init = _exampleinfo_init)

export ExampleInfo

Daha sonra bir kural uygulaması, sağlayıcıyı şu şekilde örneklendirebilir:

    ExampleInfo(
        files_to_link=my_files_to_link,  # may not be empty
        headers = my_headers,  # will automatically include the core headers
    )

Ham oluşturucu, alternatif kamu fabrikası işlevlerini tanımlamak için kullanılabilir init mantığına uygun değildir. Örneğin, exampleinfo.bzl'de tanımlanabilir:

def make_barebones_exampleinfo(headers):
    """Returns an ExampleInfo with no files_to_link and only the specified headers."""
    return _new_exampleinfo(files_to_link = depset(), headers = all_headers)

Genellikle, ham kurucu, adı alt çizgi (yukarıda _new_exampleinfo) olduğundan kullanıcı kodu yüklenemez ve rastgele sağlayıcı örnekleri oluşturabilirsiniz.

init için başka bir kullanım da kullanıcının sağlayıcıyı aramasını engellemektir. ve bunun yerine bir fabrika işlevi kullanmaya zorlama:

def _exampleinfo_init_banned(*args, **kwargs):
    fail("Do not call ExampleInfo(). Use make_exampleinfo() instead.")

ExampleInfo, _new_exampleinfo = provider(
    ...
    init = _exampleinfo_init_banned)

def make_exampleinfo(...):
    ...
    return _new_exampleinfo(...)

Yürütülebilir kurallar ve test kuralları

Yürütülebilir kurallar, bir bazel run komutu tarafından çağrılabilecek hedefleri tanımlar. Test kuralları, yürütülebilir özel bir tür yürütülebilir kuraldır. Yürütülebilir kurallar; hedefler de bazel test komutuyla çağrılır. Yürütülebilir ve test kuralları, ilgili executable veya rule çağrısında True adlı kullanıcıya yönelik test bağımsız değişkeni:

example_binary = rule(
   implementation = _example_binary_impl,
   executable = True,
   ...
)

example_test = rule(
   implementation = _example_binary_impl,
   test = True,
   ...
)

Test kurallarının adları _test ile biten adlara sahip olmalıdır. (Hedef adlarını da sık sık test edin kurallara göre _test ile biter, ancak bu zorunlu değildir.) Test dışı kurallar kullanabilirsiniz.

Her iki kural türü de yürütülebilir bir çıktı dosyası oluşturmalıdır (bu dosya, önceden beyan edilmesi gerekir.) run veya test komutları tarafından çağrılacaktır. Anlatmak için Bir kural çıkışlarından hangisinin bu yürütülebilir olarak kullanılacağını Bazel, bunu Döndürülen DefaultInfo işlevinin executable bağımsız değişkeni sağlar. Bu executable, kuralın varsayılan çıkışlarına eklenir (böylece hem executable hem de files adlı cihaza iletmesi gerekmez). Aynı zamanda, runfiles eklenir:

def _example_binary_impl(ctx):
    executable = ctx.actions.declare_file(ctx.label.name)
    ...
    return [
        DefaultInfo(executable = executable, ...),
        ...
    ]

Bu dosyayı oluşturan işlem, dosyadaki yürütülebilir biti ayarlamalıdır. Örneğin, ctx.actions.run veya Bunun yapılması gereken ctx.actions.run_shell işlemi işlem tarafından çağrılan temel araç tarafından uygulanır. Örneğin, ctx.actions.write işlemi, is_executable=True geçin.

Eski davranış olarak, yürütülebilir kurallarda önceden tanımlanmış özel ctx.outputs.executable çıkışı. Bu dosya, DefaultInfo kullanarak bir uygulama belirtmezseniz varsayılan olarak yürütülebilir; olmaması gerekir geri alınamaz. Bu çıkış mekanizması şunları desteklemediği için kullanımdan kaldırıldı: yürütülebilir dosyanın adını analiz sırasında özelleştirme.

Örneklere bakın yürütülebilir kural ve test kuralını inceleyin.

Yürütülebilir kurallar ve test kurallarının doğrudan tanımlanmış özellikleri vardır. tüm kurallara uymalıdır. Varsayılan dolaylı yoldan eklenen özellikler değiştirilemez ancak özel bir kuralı Starlark makrosu içine sarmalayarak varsayılan:

def example_test(size="small", **kwargs):
  _example_test(size=size, **kwargs)

_example_test = rule(
 ...
)

Runfiles konumu

Yürütülebilir bir hedef bazel run (veya test) ile çalıştırıldığında, Runfiles dizini yürütülebilir dosyanın bitişiğindedir. Yollar aşağıdaki gibi ilişkilidir:

# Given launcher_path and runfile_file:
runfiles_root = launcher_path.path + ".runfiles"
workspace_name = ctx.workspace_name
runfile_path = runfile_file.short_path
execution_root_relative_path = "%s/%s/%s" % (
    runfiles_root, workspace_name, runfile_path)

Runfiles dizininin altındaki File yolu şuna karşılık gelir: File.short_path

Doğrudan bazel tarafından yürütülen ikili program, kök dizesine bitişik runfiles dizini. Ancak, çalıştırma dosyalarından from olarak adlandırılan ikili programlar aynı varsayıma sahiptir. Her ikili, bu sorunun etkilerini azaltmak için bir ortam veya komut satırı kullanarak runfiles kökünü parametre olarak kabul edin bağımsız değişken/bayrak. Bu, ikili programların doğru standart çalıştırma dosyası kökünü iletmesine olanak tanır çağrılmasını sağlar. Bu ayar belirtilmezse ikili program, bunun çağırın ve bitişikteki Runfiles dizinini arayın.

İleri düzey konular

Çıkış dosyalarını isteme

Tek bir hedefin birden fazla çıkış dosyası olabilir. bazel build komutu çalıştırıldığında, komuta verilen hedeflerin bazı çıktılarının, makine öğreniminin istenebilir. Bazel, yalnızca istenen bu dosyaları ve bunların bağımlılığın doğrudan veya dolaylı olarak değişmesidir. (Eylem grafiği olarak yalnızca Bazel, öğesinin geçişli bağımlıları olarak erişilebilen işlemleri istenen dosyalar.)

Varsayılan çıkışlara ek olarak önceden bildirilmiş tüm çıkışlar komut satırında açıkça istenmesine izin verilmez. Kurallar, önceden tanımlanmış çıkış özellikleri aracılığıyla çıkışlar sağlar. Böyle bir durumda, kullanıcı kuralı örneklendirirken çıkışlar için etiketler açık bir şekilde seçer. Elde etmek için Çıkış özellikleri için File nesneleri; karşılık gelen özelliği ctx.outputs. Kurallar önceden beyan edilmiş çıkışları dolaylı yoldan tanımlayabilirsiniz. eklemiştir; ancak bu özellik kullanımdan kaldırılmıştır.

Varsayılan çıkışların yanı sıra koleksiyonlar olan çıkış grupları da vardır. bir dizi çıkış dosyası ekleyebilirsiniz. Bu istekler --output_groups. Örneğin, Örneğin, //pkg:mytarget hedefi debug_files içeren bir kural türündeyse bu dosyalar bazel build //pkg:mytarget --output_groups=debug_files çalıştırılarak oluşturulabilir. Önceden bildirilmemiş çıkışların etiketi olmadığından yalnızca varsayılan çıkışlarda veya çıkışta görünerek istenebilir. grubu.

Çıkış grupları OutputGroupInfo sağlayıcısı. Çoğu modelin aksine yerleşik sağlayıcılar, OutputGroupInfo rastgele adlara sahip parametreler alabilir şu ada sahip çıkış grupları tanımlamak için kullanılır:

def _example_library_impl(ctx):
    ...
    debug_file = ctx.actions.declare_file(name + ".pdb")
    ...
    return [
        DefaultInfo(files = depset([output_file]), ...),
        OutputGroupInfo(
            debug_files = depset([debug_file]),
            all_files = depset([output_file, debug_file]),
        ),
        ...
    ]

Ayrıca çoğu sağlayıcının aksine OutputGroupInfo, hem aspect ve bu özelliğin uygulandığı kural hedefi, ancak aynı çıkış gruplarını tanımlamazlar. Böyle bir durumda, sağlayıcı birleştirilir.

OutputGroupInfo işlevinin genellikle belirli sıralamaları aktarmak için kullanılmaması gerektiğini unutmayın. tüketicilerin eylemlerine kadar çeşitli dosyalar sunar. Tanımla kurallara özel sağlayıcılar kullanabilirsiniz.

Yapılandırmalar

Farklı bir mimari için C++ ikili programı derlemek istediğinizi düşünün. İlgili içeriği oluşturmak için kullanılan karmaşık bir yapıda olabilir ve birkaç adım içerebilir. Bazı orta düzey derleyici ve kod oluşturucu gibi ikili programların yürütme platformu (barındırıcınız, veya uzaktaki bir yürütücü). Nihai çıkış gibi bazı ikili programlar hedef mimari.

Bu nedenle, Bazel'in "yapılandırmalar" daha fazla bilgi edineceksiniz. İlgili içeriği oluşturmak için kullanılan en üstteki hedefler (komut satırında istenenler) "hedef" yürütme platformunda çalışması gereken araçlar ise "yönlendirerek" yapılandırma. Kurallar, uygulamanıza bağlı olarak (ör. iletilen CPU mimarisini değiştirmek için) ekler. Bazı durumlarda, farklı cihazlar için aynı kitaplık yapılandırmanın üç yolu vardır. Böyle bir durumda analiz edilir ve birden fazla kez.

Varsayılan olarak Bazel, hedefin kendisi, başka bir deyişle geçişler olmadan. Bağımlılık hedefin oluşturulması için gereken özel bir araç varsa, exec yapılandırmasına geçiş olduğunu belirtir. Bu, aracın ve onun tüm özelliklerini bağımlılıkları belirlemenize yardımcı olur.

Her bir bağımlılık özelliğinde, bağımlılıkların olup olmadığına karar vermek için cfg kullanabilirsiniz. aynı yapılandırmada derlemesi veya bir yönetici yapılandırmasına geçiş yapması gerekir. Bir bağımlılık özelliği executable=True bayrağına sahipse cfg ayarlanmalıdır açık bir şekilde belirtmelisiniz. Bu, hatalı kullanım için yanlışlıkla bir araç oluşturulmasını önlemek amacıyla yapılandırma. Örneği inceleyin

Genel olarak, aynı yapılandırmayı kullanabilir.

Derlemenin bir parçası olarak yürütülen araçlar (derleyiciler veya kod oluşturucular gibi) yürütülmelidir. Bu durumda, cfg="exec" değerini belirtir.

Aksi takdirde, çalışma zamanında kullanılan yürütülebilir dosyalar (örneğin bir testin parçası olarak) oluşturulmalıdır. Bu durumda, cfg="target" değerini belirtir.

cfg="target" aslında herhangi bir şey yapmaz. Tam anlamıyla kullanıcıların kural tasarımcılarının amaçlarını açıkça belirtmelerine yardımcı olur. executable=False olduğunda, Yani cfg isteğe bağlıdır. Yalnızca okunabilirliğe gerçekten yardımcı olduğu durumlarda bunu ayarlayın.

Ayrıca, şunu kullanmak için cfg=my_transition kullanabilirsiniz: geçişlere izin veren kullanıcı tanımlı geçişleri yapılandırma değiştirme konusunda çok daha fazla esneklikle dezavantajı yapı grafiğini daha geniş ve daha az anlaşılır hale getirir.

Not: Geçmişte Bazel'in yürütme platformu kavramı yoktu. Bunun yerine tüm derleme işlemlerinin ana makinede çalıştırıldığı kabul ediliyordu. Bu nedenle, tek bir "ana makine" vardır "host" (ana makine) geçiş , ana makine yapılandırmasında bağımlılık oluşturmak için kullanılabilecek bir kod içerir. Birçok kural "ana makine"yi kullanmaya devam edin ancak bu şu anda desteği sonlandırıldı ve "exec" kullanmak için taşınıyor birkaç geçiş yapabilirsiniz.

"Ana makine" ile arasında çok sayıda fark vardır ve "exec" yapılandırma:

  • "ana makine" terminal, "exec" değildir: "Ana makine"de bir bağımlılık bulunduğunda yapılandırmasında başka geçişe izin verilmez. Başarılı bir şekilde ilerlerken "yürütme" işlemi gerçekleştirildiğinde yapılandırma geçişleri yapılandırma.
  • "ana makine" monolitiktir, "exec" değildir: Yalnızca bir "ana makine" vardır. yapılandırma, ancak farklı bir "yönetici" olabilir her yürütme için yapılandırma platformu.
  • "ana makine" Bazel ile aynı makinede veya belirli bir makinede birbirine çok benzer. Artık bu geçerli değil: Derlemeyi çalıştırabilirsiniz. yerel makinenizde veya uzaktaki bir yürütücüde çalışırken Uzak yürütücünün yerel cihazınızla aynı CPU ve işletim sistemi olmasını üretiliyor.

Hem "exec" hem de ve "host" (ana makine) yapılandırmalarda aynı seçenek değişikliklerini uygular (örneğin, --compilation_mode için --host_compilation_mode değerini ayarla, --cpu öğesini şuradan ayarla: --host_cpu vb.) Aradaki fark "ana makine"nin yapılandırma şununla başlar: "exec" değerine sahipken, diğer tüm işaretlerin default değerleri yapılandırma hedef yapılandırmaya bağlı olarak flag'lerin geçerli değerleriyle başlar.

Yapılandırma parçaları

Kurallar erişebilir yapılandırma parçalarını cpp, java ve jvm. Ancak, gerekli tüm parçalar şurada tanımlanmalıdır: için şu adımları izleyin:

def _impl(ctx):
    # Using ctx.fragments.cpp leads to an error since it was not declared.
    x = ctx.fragments.java
    ...

my_rule = rule(
    implementation = _impl,
    fragments = ["java"],      # Required fragments of the target configuration
    host_fragments = ["java"], # Required fragments of the host configuration
    ...
)

ctx.fragments, yalnızca hedef için yapılandırma parçalarını sağlar yapılandırma. Ana makine yapılandırmasının parçalarına erişmek istiyorsanız Bunun yerine ctx.host_fragments.

Normalde, çalıştırma dosyaları ağacındaki bir dosyanın göreli yolu dosyanın göreli yolunu gösterir. Bu bir nedenden dolayı farklı olması gerekiyorsa, root_symlinks veya symlinks bağımsız değişken. root_symlinks, dosyalarını içermelidir. Bu dizindeki yollar, runfiles dizininin köküne göre belirlenir. İlgili içeriği oluşturmak için kullanılan symlinks sözlüğü aynı ancak yolların başında dolaylı olarak çalışma alanı adını tıklayın.

    ...
    runfiles = ctx.runfiles(
        root_symlinks = {"some/path/here.foo": ctx.file.some_data_file2}
        symlinks = {"some/path/here.bar": ctx.file.some_data_file3}
    )
    # Creates something like:
    # sometarget.runfiles/
    #     some/
    #         path/
    #             here.foo -> some_data_file2
    #     <workspace_name>/
    #         some/
    #             path/
    #                 here.bar -> some_data_file3

symlinks veya root_symlinks kullanılıyorsa iki farklı eşleme yapmamaya dikkat edin dosyalarını çalıştırma ağacında aynı yola yönlendirir. Bu, derlemenin başarısız olmasına neden olur bir hata mesajı alır. Bu sorunu düzeltmek için Çakışmayı kaldırmak için ctx.runfiles bağımsız değişken. Bu kontrol, kuralınızı kullanan tüm hedeflerin yanı sıra bu kurallara bağlı olan her türlü hedef belirler. Bu durum, özellikle aracınızın geçişli olarak kullanılması ihtimali varsa risklidir. başka bir araçla; sembolik bağlantı adları bir aracın çalışma dosyalarında benzersiz olmalıdır ve tüm bağımlılıklarını fark edebilirsiniz.

Kod kapsamı

coverage komutu çalıştırıldığında, derlemenin belirli hedefler için kapsam araçları eklemesi gerekebilir. İlgili içeriği oluşturmak için kullanılan derleme, gerekli araçları içeren kaynak dosyaların listesini de toplar. Alt kümesi bayrakla kontrol edilen, ancak bayrakla kontrol edilen --instrumentation_filter. Test hedefleri hariç tutulmadığı sürece --instrument_test_targets belirtilir.

Bir kural uygulaması, derleme sırasında kapsam araçları eklerse bunu uygulama işlevinde hesaba katmalıdır. ctx.coverage_instrumented, "true" değerini döndürür. kapsam modunu uygular:

# Are this rule's sources instrumented?
if ctx.coverage_instrumented():
  # Do something to turn on coverage for this compile action

Kapsam modunda her zaman açık olması gereken mantık (hedefin kaynaklarının gerekli olup olmadığına) bağlı olarak, ctx.configuration.coverage_enabled.

Kural, derlemeden önce bağımlılıklarından gelen kaynakları doğrudan içeriyorsa (başlık dosyaları gibi) kullanıyorsanız, ve bağımlılıkların hangi kaynaklara yer verilmelidir:

# Are this rule's sources or any of the sources for its direct dependencies
# in deps instrumented?
if (ctx.configuration.coverage_enabled and
    (ctx.coverage_instrumented() or
     any([ctx.coverage_instrumented(dep) for dep in ctx.attr.deps]))):
    # Do something to turn on coverage for this compile action

Kurallar, aynı zamanda hangi özelliklerin InstrumentedFilesInfo sağlayıcısıyla oluşturulan kapsam, coverage_common.instrumented_files_info instrumented_files_info öğesinin dependency_attributes parametresi şunları içermelidir: deps ve benzeri kod bağımlılıkları dahil tüm çalışma zamanı bağımlılık özellikleri bağımlılıklarını (ör. data) sağlar. source_attributes parametresi, kuralın kaynak dosya özellikleri:

def _example_library_impl(ctx):
    ...
    return [
        ...
        coverage_common.instrumented_files_info(
            ctx,
            dependency_attributes = ["deps", "data"],
            # Omitted if coverage is not supported for this rule:
            source_attributes = ["srcs", "hdrs"],
        )
        ...
    ]

InstrumentedFilesInfo döndürülmezse her biri için varsayılan bir tane oluşturulur araç dışı bağımlılık özelliğinin ayarlanmamış olması cfg yerine "host" veya "exec" olarak değiştirin) dependency_attributes (Bu ideal bir davranış değildir çünkü Örneğin, source_attributes yerine dependency_attributes içinde srcs, ancak bu tüm kurallar için açık kapsam yapılandırılması ihtiyacını ortadan kaldırır. bağımlılık zinciri olabilir.)

Doğrulama İşlemleri

Bazen derleme hakkında bir şeyler doğrulamanız gerekir bu doğrulamayı yapmak için gereken bilgiler yalnızca yapılarda mevcuttur (kaynak dosyalar veya oluşturulan dosyalar). Bu bilgiler yapılarda bulunduğundan kurallar analiz sırasında bu doğrulamayı yapamaz, çünkü kurallar dosyası olarak da kaydedebilir. Bunun yerine, yürütme sırasında bu doğrulamayı yapması gerekir. Zaman işlem başarısız olursa işlem ve dolayısıyla derleme de başarısız olur.

Çalıştırılabilecek doğrulamalara örnek olarak statik analiz, hata analizi, bağımlılık ve tutarlılık kontrolleri ile stil kontrolleri.

Doğrulama işlemleri, parçaları hareket ettirerek derleme performansının iyileştirilmesine de yardımcı olabilir birçok işlem bulunur. Örneğin, derleme ve hata analizi yapan tek bir işlem işlemi, derleme işlemi ve linting işlemi olarak ayrılmış bir listedir. işlemi, doğrulama işlemi olarak ve diğer işlemlerle paralel olarak çalıştırılabilir.

Bu "doğrulama işlemleri" genellikle başka bir yerde kullanılan hiçbir şey üretmez. çünkü yalnızca girdileriyle ilgili birtakım iddialarda bulunmaları gerekiyor. Bu bir soruna işaret eder: Doğrulama işlemi gerçekten bir kural, derlemenin başka bir yerinde kullanılırsa işlemin çalıştırılmasını nasıl sağlar? Önceden yaklaşım, doğrulama işlemi çıktısının boş bir değer ve bu çıktıyı başka önemli bilgilerin girişlerine yapay olarak şu işlemi yapabilirsiniz:

Bu yöntem işe yarar çünkü Bazel, derleme işlemi sırasında her zaman doğrulama işlemini ancak bunun önemli dezavantajları vardır:

  1. Doğrulama işlemi, derlemenin kritik yolundadır. Çünkü Bazel derleme işlemini çalıştırmak için boş çıkış gerektiğini düşünürse önce doğrulama işlemine tabi tutulur. Ancak, derleme işlemi girişi yoksayar. Bu, paralelliği azaltır ve derlemeleri yavaşlatır.

  2. Derlemedeki diğer işlemler derleme işlemini seçerseniz doğrulama işlemlerinin boş çıkışlarının bu işlemleri de yapabilirsiniz (örneğin, java_library kaynak jar çıkışı). Bu derleme işlemi yerine çalıştırılabilecek yeni eylemlerin sonradan eklenir ve boş doğrulama çıkışı yanlışlıkla bırakılır.

Bu sorunların çözümü Doğrulamalar Çıktı Grubu'nu kullanmaktır.

Doğrulamalar Çıkış Grubu

Doğrulamalar Çıkış Grubu, diğer doğrulama işlemleri için kullanılmayan çıktıları oluşturur. Böylece bunların yapay olarak girişlerine eklenir.

Bu grup, ne olursa olsun çıkışları her zaman istenmesi açısından --output_groups işaretinin değerine ve hedefin nasıl (örneğin, komut satırında, bağımlılık olarak veya (hedefin örtülü çıktıları). Normal önbelleğe alma ve artımlılığın hâlâ geçerlidir: doğrulama işlemine yapılan girişler değişmediyse ve doğrulama işlemi başarıyla tamamlandıysa doğrulama işlemi gerekir.

Bu çıkış grubunun kullanılması için doğrulama işlemlerinin bazı dosyalar üretmesi gerekir. boş bir alan olabilir. Bu, normal koşullarda çalışmayan bazı araçların çıkışlar oluşturacaksınız.

Bir hedefin doğrulama işlemleri üç durumda çalıştırılmaz:

  • Hedefe bir araç olarak ihtiyaç duyulduğunda
  • Hedefe dolaylı bir bağımlılık olarak dayanıldığında (örneğin, "_" ile başlayan özellik)
  • Hedef, ana makine veya yönetici yapılandırmasında oluşturulduğunda.

Bu hedeflerin kendine ait olduğu varsayılır. doğrulama hatalarını ortaya çıkaracak ayrı derlemeler ve testler oluşturun.

Doğrulamalar Çıkış Grubunu Kullanma

Doğrulamalar Çıktı Grubu _validation olarak adlandırılır ve diğer herhangi bir grup gibi kullanılır. çıkış grubu:

def _rule_with_validation_impl(ctx):

  ctx.actions.write(ctx.outputs.main, "main output\n")

  ctx.actions.write(ctx.outputs.implicit, "implicit output\n")

  validation_output = ctx.actions.declare_file(ctx.attr.name + ".validation")
  ctx.actions.run(
      outputs = [validation_output],
      executable = ctx.executable._validation_tool,
      arguments = [validation_output.path])

  return [
    DefaultInfo(files = depset([ctx.outputs.main])),
    OutputGroupInfo(_validation = depset([validation_output])),
  ]


rule_with_validation = rule(
  implementation = _rule_with_validation_impl,
  outputs = {
    "main": "%{name}.main",
    "implicit": "%{name}.implicit",
  },
  attrs = {
    "_validation_tool": attr.label(
        default = Label("//validation_actions:validation_tool"),
        executable = True,
        cfg = "exec"),
  }
)

Doğrulama çıkış dosyasının DefaultInfo veya girdiler. Bu kural türündeki bir hedef için doğrulama işlemi çalışmaya devam edecektir. Hedef, etikete veya hedefin örtülü çıkışlara doğrudan veya dolaylı olarak bağlıdırlar.

Genellikle doğrulama işlemlerinin sonuçlarının yalnızca emin olun ve diğer işlemlerin girişlerine eklenmez. paralellik kazançlarını ortadan kaldırabilir. Ancak, Bazel'in şu anda bu özelliği uygulanacak özel denetimler vardır. Bu nedenle, doğrulama işlemi çıkışlarının testlerinden yararlanırız. Örneğin:

load("@bazel_skylib//lib:unittest.bzl", "analysistest")

def _validation_outputs_test_impl(ctx):
  env = analysistest.begin(ctx)

  actions = analysistest.target_actions(env)
  target = analysistest.target_under_test(env)
  validation_outputs = target.output_groups._validation.to_list()
  for action in actions:
    for validation_output in validation_outputs:
      if validation_output in action.inputs.to_list():
        analysistest.fail(env,
            "%s is a validation action output, but is an input to action %s" % (
                validation_output, action))

  return analysistest.end(env)

validation_outputs_test = analysistest.make(_validation_outputs_test_impl)

Doğrulama İşlemleri İşareti

Doğrulama işlemlerinin çalıştırılması --run_validations komut satırı tarafından kontrol edilir işaretidir. Bu değer varsayılan olarak "true" (doğru) değerine ayarlanır.

Kullanımdan kaldırılan özellikler

Desteği sonlandırılan önceden beyan edilmiş çıkışlar

Önceden beyan edilmiş çıkışları kullanmanın desteği sonlandırılmış iki yöntemi vardır:

  • rule öğesinin outputs parametresi, Veri oluşturmak için çıkış özelliği adları ile dize şablonları arasında önceden beyan edilmiş çıkış etiketlerinden oluşur. Önceden bildirilmemiş çıkışları ve çıkışları açıkça DefaultInfo.files projesine ekliyor. Kural hedefinin önceden beyan edilmiş yerine çıkışı tüketen kurallar için giriş olarak etiketle çıkışının etiketine daha yakın olabilir.

  • Yürütülebilir kurallar için ctx.outputs.executable şunu belirtir: dönüştürülebilir. Sonucu açıkça belirtmeyi tercih edin, örneğin ctx.actions.declare_file(ctx.label.name) ve komutun , yürütülebilir dosyayı yürütülmesine izin verecek şekilde ayarlar. Açıkça yürütülebilir çıktıyı DefaultInfo executable parametresine iletin.

Kaçınılması gereken Runfiles özellikleri

ctx.runfiles ve runfiles türü, çoğu eski nedenlerle saklanan karmaşık bir özellik grubuna sahiptir. Aşağıdaki öneriler karmaşıklığı azaltmaya yardımcı olur:

  • Şu collect_data ve collect_default modlarını kullanmaktan kaçının: ctx.runfiles. Bu modlar, dosyaları kafa karıştırıcı şekillerde, sabit kodlu belirli bağımlılık kenarlarında çalıştırmasına yardımcı olur. Bunun yerine, dosyayı şu öğenin files veya transitive_files parametrelerini kullanarak ekleyin: ctx.runfiles kullanarak veya bağımlılıklardan gelen çalıştırma dosyalarını runfiles = runfiles.merge(dep[DefaultInfo].default_runfiles).

  • Şunlardan kaçının: data_runfiles ve default_runfiles DefaultInfo oluşturucu. Bunun yerine DefaultInfo(runfiles = ...) değerini belirtin. "Varsayılan" arasındaki fark ve "data" Runfiles'i yalnızca eski nedenler. Örneğin, bazı kurallar varsayılan çıkışlarını data_runfiles, ancak default_runfiles değil. Bunun yerine data_runfiles, kurallar her ikisi de varsayılan çıkışları içermeli ve Çalıştırma dosyaları sağlayan özelliklerden default_runfiles (genellikle data).

  • DefaultInfo kaynağından runfiles alınırken (genellikle yalnızca birleştirme içindir) çalıştırmanız için kullanılan dosyayı kullanıyorsanız, DefaultInfo.default_runfiles, DefaultInfo.data_runfiles değil.

Eski sağlayıcılardan taşıma

Geçmişte Bazel sağlayıcıları Target nesnesindeki basit alanlardı. Onlar noktaları, nokta operatörü kullanılarak erişildi ve işlevi tarafından döndürülen bir struct'a dönüştürülür.

Bu stil kullanımdan kaldırıldı ve yeni kodda kullanılmamalıdır; için aşağıdaki bilgilere bakın bazı ek bilgilere ulaşabilirsiniz. Yeni sağlayıcı mekanizması, addan kaçınıyor oluşturur. Ayrıca, bir sunucuya herhangi bir koda erişilmesini zorunlu kılarak sağlayıcı sembolü kullanarak almak için sağlayıcı örneği kullanabilirsiniz.

Şu an için, eski sağlayıcılar desteklenmektedir. Bir kural, aşağıdaki gibi eski ve modern sağlayıcılar:

def _old_rule_impl(ctx):
  ...
  legacy_data = struct(x="foo", ...)
  modern_data = MyInfo(y="bar", ...)
  # When any legacy providers are returned, the top-level returned value is a
  # struct.
  return struct(
      # One key = value entry for each legacy provider.
      legacy_info = legacy_data,
      ...
      # Additional modern providers:
      providers = [modern_data, ...])

dep, bu kuralın bir örneği için sonuçta elde edilen Target nesnesiyse sağlayıcılar ve içerikleri dep.legacy_info.x ve dep[MyInfo].y.

Döndürülen struct, providers'e ek olarak birkaç tane daha alabilir alanları veya bu alanlara karşılık gelen bir miras teşkil etmez sağlayıcı):

  • files, runfiles, data_runfiles, default_runfiles ve executable, aynı adlandırılmış alanlara karşılık gelir DefaultInfo. Herhangi bir DefaultInfo sağlayıcısı döndürecek.

  • output_groups alanı bir struct değeri alır ve OutputGroupInfo

provides kural bildirimlerinde ve providers bağımlılık bildirimleri özellikleri ile birlikte eski sağlayıcılar dize olarak aktarılır ve modern sağlayıcılar *Info sembolü ile geçilebilir. Dize yerine semboller kullanmayı unutmayın göz önünde bulundurun. Güncellemenin zor olduğu karmaşık veya büyük kural kümeleri için atomik bir yapıya sahip olduğunu fark ederseniz, bu diziyi takip etmeniz durumunda için şu adımları izleyin:

  1. Eski sağlayıcıyı oluşturan kuralları, hem eski sağlayıcıyı hem de eski sağlayıcıyı oluşturacak şekilde değiştirin ve modern sağlayıcılar için geçerlidir. Bunu belirten kurallar için eski sağlayıcıyı döndürmek için bu beyanı hem hem de eski ve modern sağlayıcılar için geçerli.

  2. Eski sağlayıcıyı kullanan kuralları, bunun yerine modern bir sağlayıcı. Herhangi bir özellik bildirimleri için eski sağlayıcı gerekiyorsa modern sağlayıcıyı gerektirecek şekilde de güncellenecektir. İsteğe bağlı olarak: bu çalışmayı, tüketicilerin aşağıdakilerden birini kabul etmesini/zorunlu kılmasını sağlayarak 1. adıma provider: Alan adını kullanarak eski sağlayıcının varlığını test etme hasattr(target, 'foo') veya FooInfo in target kullanan yeni sağlayıcı

  3. Eski sağlayıcıyı tüm kurallardan tamamen kaldırın.