BazelCon 2022 findet vom 16. bis 17. November in New York und online statt.
Jetzt anmelden

Anleitung zu Regeln

Mit Sammlungen den Überblick behalten Sie können Inhalte basierend auf Ihren Einstellungen speichern und kategorisieren.

Starlark ist eine Python-ähnliche Konfigurationssprache, die ursprünglich in Istio entwickelt wurde und seitdem von anderen Tools übernommen wird. Die Dateien BUILD und .bzl von Istio werden in einem „Starlark“-Dialekt verfasst. Häufig wird er einfach als „Starlark“ bezeichnet, insbesondere wenn man betont, dass ein Diese Funktion wird in der Build-Sprache ausgedrückt und nicht als integrierter oder „nativer“ Teil von Istio. Istio ergänzt die Kernsprache mit zahlreichen Build-Funktionen wieglob .genrule .java_binary usw.

Weitere Informationen finden Sie in der Dokumentation zu Bazel und Starlark sowie zur Regel SIG-Vorlage (in englischer Sprache). für neue Regelsätze.

Leere Regel

Erstellen Sie zum Erstellen Ihrer ersten Regel die Datei foo.bzl:

def _foo_binary_impl(ctx):
    pass

foo_binary = rule(
    implementation = _foo_binary_impl,
)

Wenn du die Funktion rule aufrufst, musst du eine Callback-Funktion definieren. Die Logik wird hier verwendet. Sie können die Funktion jedoch vorerst leer lassen. Das Argument ctx enthält Informationen zum Ziel.

Sie können die Regel laden und aus einer BUILD-Datei verwenden.

Erstelle eine BUILD-Datei im selben Verzeichnis:

load(":foo.bzl", "foo_binary")

foo_binary(name = "bin")

Jetzt kann das Ziel erstellt werden:

$ bazel build bin
INFO: Analyzed target //:bin (2 packages loaded, 17 targets configured).
INFO: Found 1 target...
Target //:bin up-to-date (nothing to build)

Auch wenn die Regel nichts tut, verhält sie sich bereits wie andere Regeln: Sie hat einen obligatorischen Namen, unterstützt jedoch gängige Attribute wie visibility, testonly und tags.

Bewertungsmodell

Bevor Sie fortfahren, sollten Sie wissen, wie der Code ausgewertet wird.

Aktualisieren Sie foo.bzl mit einigen Druckbelegen:

def _foo_binary_impl(ctx):
    print("analyzing", ctx.label)

foo_binary = rule(
    implementation = _foo_binary_impl,
)

print("bzl file evaluation")

und BUILD:

load(":foo.bzl", "foo_binary")

print("BUILD file")
foo_binary(name = "bin1")
foo_binary(name = "bin2")

ctx.label entspricht dem Label des zu analysierenden Ziels. Das Objekt ctx enthält viele nützliche Felder und Methoden. Eine vollständige Liste finden Sie in der API-Referenz.

Fragen Sie den Code ab:

$ bazel query :all
DEBUG: /usr/home/bazel-codelab/foo.bzl:8:1: bzl file evaluation
DEBUG: /usr/home/bazel-codelab/BUILD:2:1: BUILD file
//:bin2
//:bin1

Hier sind einige Hinweise:

  • „BZL-Dateibewertung“ wird zuerst gedruckt. Bevor die Datei BUILD ausgewertet wird, wertet Bazel alle Dateien aus, die sie lädt. Wenn mehrere BUILD-Dateien foo.bzl laden, wird nur „bzl fileEvaluation“ (bzl-Dateibewertung) angezeigt, da das Ergebnis der Auswertung durch Bazel im Cache gespeichert wird.
  • Die Callback-Funktion _foo_binary_impl wird nicht aufgerufen. Die Istio-Abfrage lädt BUILD Dateien, analysiert aber keine Ziele.

Verwenden Sie zum Analysieren der Ziele den cquery-Befehl (konfigurierte Abfrage) oder den Befehl build:

$ bazel build :all
DEBUG: /usr/home/bazel-codelab/foo.bzl:8:1: bzl file evaluation
DEBUG: /usr/home/bazel-codelab/BUILD:2:1: BUILD file
DEBUG: /usr/home/bazel-codelab/foo.bzl:2:5: analyzing //:bin1
DEBUG: /usr/home/bazel-codelab/foo.bzl:2:5: analyzing //:bin2
INFO: Analyzed 2 targets (0 packages loaded, 0 targets configured).
INFO: Found 2 targets...

Wie Sie sehen, wird _foo_binary_impl jetzt zweimal aufgerufen – einmal für jedes Ziel.

Einige Leser werden bemerken, dass „bzl fileEvaluation“ noch einmal gedruckt wird. Die Bewertung von „foo.bzl“ wird jedoch nach dem Aufruf von bazel query im Cache gespeichert. Waze wertet den Code nicht neu aus, sondern gibt nur die Druckereignisse wieder. Unabhängig vom Cache-Status erhalten Sie dieselbe Ausgabe.

Dateien erstellen

Aktualisieren Sie die Regel so, dass eine Datei generiert wird, um sie noch nützlicher zu machen. Deklariere zuerst die Datei und gib ihr einen Namen. Erstellen Sie in diesem Beispiel eine Datei mit demselben Namen wie das Ziel:

ctx.actions.declare_file(ctx.label.name)

Wenn Sie bazel build :all jetzt ausführen, erhalten Sie eine Fehlermeldung:

The following files have no generating action:
bin2

Bei jeder Deklaration einer Datei müssen Sie festlegen, wie die Datei generiert werden soll. Erstellen Sie mit ctx.actions.write eine Datei mit dem angegebenen Inhalt.

def _foo_binary_impl(ctx):
    out = ctx.actions.declare_file(ctx.label.name)
    ctx.actions.write(
        output = out,
        content = "Hello\n",
    )

Der Code ist gültig, aber es werden keine Aktionen ausgeführt:

$ bazel build bin1
Target //:bin1 up-to-date (nothing to build)

Die Funktion ctx.actions.write hat eine Aktion registriert, mit der Istio das Generieren der Datei gelernt hat. Die Datei wird aber erst erstellt, nachdem sie tatsächlich angefordert wurde. Der letzte Schritt besteht darin, sagst, dass die Datei eine Ausgabe der Regel und keine temporäre Datei ist, die in der Regelimplementierung verwendet wird.

def _foo_binary_impl(ctx):
    out = ctx.actions.declare_file(ctx.label.name)
    ctx.actions.write(
        output = out,
        content = "Hello!\n",
    )
    return [DefaultInfo(files = depset([out]))]

Sehen Sie sich später die Funktionen DefaultInfo und depset an. Nehmen wir vorerst an, dass die letzte Zeile die Möglichkeit bietet, die Ausgaben einer Regel auszuwählen.

Führen Sie nun den folgenden Befehl aus:

$ bazel build bin1
INFO: Found 1 target...
Target //:bin1 up-to-date:
  bazel-bin/bin1

$ cat bazel-bin/bin1
Hello!

Sie haben eine Datei erstellt.

Attribute

Um die Regel nützlicher zu machen, fügen Sie mithilfe des Moduls attr neue Attribute hinzu und aktualisieren Sie die Regeldefinition.

Fügen Sie ein String-Attribut namens username hinzu:

foo_binary = rule(
    implementation = _foo_binary_impl,
    attrs = {
        "username": attr.string(),
    },
)

Als Nächstes legen Sie sie in der Datei BUILD fest:

foo_binary(
    name = "bin",
    username = "Alice",
)

Verwende ctx.attr.username, um auf den Wert in der Callback-Funktion zuzugreifen. Beispiel:

def _foo_binary_impl(ctx):
    out = ctx.actions.declare_file(ctx.label.name)
    ctx.actions.write(
        output = out,
        content = "Hello {}!\n".format(ctx.attr.username),
    )
    return [DefaultInfo(files = depset([out]))]

Sie können das Attribut als obligatorisch festlegen oder einen Standardwert festlegen. Sehen Sie sich die Dokumentation von attr.string an. Sie können auch andere Attributtypen verwenden, z. B. boolesch oder Liste mit Ganzzahlen.

Abhängigkeiten

Abhängigkeitsattribute wieattr.label undattr.label_list , deklarieren Sie eine Abhängigkeit vom Ziel, dem das Attribut gehört, zum Ziel, dessen Label im Wert des Attributs enthalten ist. Diese Art von Attribut bildet die Grundlage des Zieldiagramms.

In der Datei BUILD wird das Ziellabel als Stringobjekt angezeigt, z. B. //pkg:name. In der Implementierungsfunktion ist das Ziel als Target-Objekt zugänglich. Sehen Sie sich beispielsweise die vom Ziel zurückgegebenen Dateien an. Verwenden Sie dazu Target.files.

Mehrere Dateien

Standardmäßig können nur Ziele angezeigt werden, die durch Regeln erstellt wurden, z. B. ein foo_library()-Ziel. Wenn mit dem Attribut Ziele als Eingabedateien akzeptiert werden sollen (z. B. Quelldateien im Repository), tun Sie dies mit allow_files und eine Liste akzeptierter Dateiendungen angebenTrue So können Sie Dateiendungen zulassen:

"srcs": attr.label_list(allow_files = [".java"]),

Du kannst mit ctx.files.<attribute name> auf die Liste der Dateien zugreifen. So können Sie beispielsweise auf die Liste der Dateien im Attribut srcs zugreifen:

ctx.files.srcs

Einzelne Datei

Wenn Sie nur eine Datei benötigen, verwenden Sie allow_single_file:

"src": attr.label(allow_single_file = [".java"])

Auf diese Datei kann dann unter ctx.file.<attribute name> zugegriffen werden:

ctx.file.src

Dateien mit einer Vorlage erstellen

Sie können eine Regel erstellen, die eine CC-Datei basierend auf einer Vorlage generiert. Außerdem kannst du mit ctx.actions.write einen String ausgeben, der in der Regelimplementierungsfunktion erstellt wurde. Das hat jedoch zwei Probleme. Zu Beginn wird die Vorlage bei größerer Größe speichereffizienter, da sie in einer separaten Datei abgelegt werden kann und während der Analysephase keine großen Strings erstellt werden müssen. Zweitens ist die Verwendung einer separaten Datei für den Nutzer praktischer. Alternativ kannst du ctx.actions.expand_template verwenden, um eine Vorlagendatei zu ersetzen.

Erstellen Sie ein template-Attribut, um eine Abhängigkeit von der Vorlagendatei zu deklarieren:

def _hello_world_impl(ctx):
    out = ctx.actions.declare_file(ctx.label.name + ".cc")
    ctx.actions.expand_template(
        output = out,
        template = ctx.file.template,
        substitutions = {"{NAME}": ctx.attr.username},
    )
    return [DefaultInfo(files = depset([out]))]

hello_world = rule(
    implementation = _hello_world_impl,
    attrs = {
        "username": attr.string(default = "unknown person"),
        "template": attr.label(
            allow_single_file = [".cc.tpl"],
            mandatory = True,
        ),
    },
)

Nutzer können die Regel wie folgt verwenden:

hello_world(
    name = "hello",
    username = "Alice",
    template = "file.cc.tpl",
)

cc_binary(
    name = "hello_bin",
    srcs = [":hello"],
)

Wenn Sie die Vorlage nicht für den Endnutzer freigeben und immer denselben verwenden möchten, können Sie einen Standardwert festlegen und das Attribut auf „Privat“ setzen:

    "_template": attr.label(
        allow_single_file = True,
        default = "file.cc.tpl",
    ),

Attribute, die mit einem Unterstrich beginnen, sind privat und können nicht in einer BUILD-Datei festgelegt werden. Die Vorlage ist jetzt eine implizite Abhängigkeit: Jedes hello_world-Ziel ist von dieser Datei abhängig. Vergiss nicht, diese Datei für andere Pakete sichtbar zu machen. Aktualisiere dazu die Datei BUILD und verwende exports_files:

exports_files(["file.cc.tpl"])

Weitere Informationen