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

Starlark-Sprache

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

Diese Seite bietet eine Übersicht über Starlark, ehemals Skylark, der in Bazel verwendete Sprache. Eine vollständige Liste der Funktionen und Typen finden Sie in der Bazel API-Referenz.

Weitere Informationen zur Sprache finden Sie im GitHub-Repository von Starlark.

Die verbindliche Spezifikation der Starlark-Syntax und des Verhaltens finden Sie in der Starlark-Sprachspezifikation.

Syntax

Die Syntax von Starlark ist von Python3 inspiriert. Dies ist eine gültige Syntax in Starlark:

def fizz_buzz(n):
  """Print Fizz Buzz numbers from 1 to n."""
  for i in range(1, n + 1):
    s = ""
    if i % 3 == 0:
      s += "Fizz"
    if i % 5 == 0:
      s += "Buzz"
    print(s if s else i)

fizz_buzz(20)

Die Semantik von Starlark kann von Python abweichen, aber die Verhaltensunterschiede sind selten, außer in Fällen, in denen Starlark einen Fehler auslöst. Die folgenden Python-Typen werden unterstützt:

Veränderlichkeit

Starlark bevorzugt Unveränderlichkeit. Es sind zwei veränderliche Datenstrukturen verfügbar: Listen und Wörterbücher. Änderungen an änderbaren Datenstrukturen, z. B. das Anfügen eines Werts an eine Liste oder das Löschen eines Eintrags in einem Wörterbuch, sind nur für Objekte gültig, die im aktuellen Kontext erstellt wurden. Wenn ein Kontext abgeschlossen ist, sind seine Werte nicht mehr änderbar.

Das liegt daran, dass Bazel-Builds parallel ausgeführt werden. Während eines Builds erhalten jede .bzl- und jede BUILD-Datei einen eigenen Ausführungskontext. Jede Regel wird auch in ihrem eigenen Kontext analysiert.

Sehen wir uns ein Beispiel mit der Datei foo.bzl an:

# `foo.bzl`
var = [] # declare a list

def fct(): # declare a function
  var.append(5) # append a value to the list

fct() # execute the fct function

Bazel erstellt var beim Laden von foo.bzl. var ist daher Teil des foo.bzl-Kontexts. Wenn fct() ausgeführt wird, erfolgt dies im Kontext von foo.bzl. Nach Abschluss der Auswertung von foo.bzl enthält die Umgebung den unveränderlichen Eintrag var mit dem Wert [5].

Wenn ein anderer bar.bzl Symbole aus foo.bzl lädt, bleiben die geladenen Werte unveränderlich. Daher ist der folgende Code in bar.bzl ungültig:

# `bar.bzl`
load(":foo.bzl", "var", "fct") # loads `var`, and `fct` from `./foo.bzl`

var.append(6)  # runtime error, the list stored in var is frozen

fct()          # runtime error, fct() attempts to modify a frozen list

Globale Variablen, die in bzl-Dateien definiert sind, können nicht außerhalb der bzl-Datei geändert werden, in der sie definiert wurden. Wie im obigen Beispiel mit bzl-Dateien sind die von Regeln zurückgegebenen Werte unveränderlich.

Unterschiede zwischen BUILD- und BZL-Dateien

BUILD-Dateien registrieren Ziele über Aufrufe von Regeln. .bzl-Dateien bieten Definitionen für Konstanten, Regeln, Makros und Funktionen.

Native Funktionen und native Regeln sind globale Symbole in BUILD-Dateien. bzl-Dateien müssen mit dem native-Modul geladen werden.

Es gibt zwei syntaktische Einschränkungen in BUILD-Dateien: 1) Die Deklaration von Funktionen ist illegal und 2) *args und **kwargs-Argumente sind nicht zulässig.

Unterschiede zu Python

  • Globale Variablen sind unveränderlich.

  • for-Anweisungen sind auf der obersten Ebene nicht zulässig. Verwenden Sie sie stattdessen in Funktionen. In BUILD-Dateien können Sie Ausweitungen verwenden.

  • if-Anweisungen sind auf der obersten Ebene nicht zulässig. Es können jedoch if-Ausdrücke verwendet werden: first = data[0] if len(data) > 0 else None.

  • Deterministische Reihenfolge für Iteration über Wörterbücher.

  • Recursion ist nicht zulässig.

  • Der Typ "int" ist auf vorzeichenbehaftete 32-Bit-Ganzzahlen beschränkt. Überläufe lösen einen Fehler aus.

  • Das Ändern einer Sammlung während der Iteration ist ein Fehler.

  • Mit Ausnahme von Gleichheitstests werden Vergleichsoperatoren <, <=, >=, > usw. nicht über Werttypen definiert. Kurz gesagt: 5 < 'foo' gibt einen Fehler aus und 5 == "5" gibt "false" zurück.

  • Bei Tupeln ist ein nachgestelltes Komma nur gültig, wenn das Tupel zwischen Klammern steht, also wenn Sie (1,) anstelle von 1, schreiben.

  • Schlüsselwörter dürfen keine doppelten Schlüssel haben. Dies ist beispielsweise ein Fehler: {"a": 4, "b": 7, "a": 1}.

  • Strings werden in Anführungszeichen gesetzt, z. B. wenn Sie repr aufrufen.

  • Strings sind nicht iterierbar.

Die folgenden Python-Funktionen werden nicht unterstützt:

  • implizite Stringverkettung (expliziten Operator + verwenden).
  • Verkettete Vergleiche (z. B. 1 < x < 5)
  • class (siehe struct-Funktion).
  • import (siehe load-Anweisung).
  • while, yield.
  • Float und Typen festlegen.
  • Generatoren und Generatorausdrücke
  • is (verwenden Sie stattdessen ==).
  • try, raise, except, finally (siehe fail für schwerwiegende Fehler)
  • global, nonlocal.
  • die meisten integrierten Funktionen, die meisten Methoden.