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

Plattformen

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

Bazel kann Code auf einer Vielzahl von Hardware, Betriebssystemen und Systemkonfigurationen erstellen und testen. Dabei werden viele verschiedene Versionen von Build-Tools wie Verknüpfungs- und Compilern verwendet. Bazel bietet ein Konzept von Einschränkungen und Plattformen, um diese Komplexität zu verwalten. Eine Einschränkung ist eine Dimension, in der sich Build- oder Produktionsumgebungen unterscheiden können, z. B. CPU-Architektur, Vorhandensein oder Fehlen einer GPU oder die Version eines vom System installierten Compilers. Eine Plattform ist eine benannte Sammlung von Auswahlmöglichkeiten für diese Einschränkungen und stellt die Ressourcen dar, die in einer bestimmten Umgebung verfügbar sind.

Durch die Modellierung der Umgebung als Plattform kann Bazel automatisch die entsprechenden Toolchains für Build-Aktionen auswählen. Plattformen können auch in Kombination mit der Regel config_setting verwendet werden, um konfigurierbare Attribute zu schreiben.

Bazel erkennt drei Rollen, die eine Plattform erfüllen kann:

  • Host: Die Plattform, auf der Bazel selbst ausgeführt wird.
  • Ausführung: eine Plattform, auf der Build-Tools Build-Aktionen ausführen, um Zwischen- und Endausgaben zu generieren.
  • Ziel: eine Plattform, auf der sich eine endgültige Ausgabe befindet und die sie ausführt.

Bazel unterstützt die folgenden Build-Szenarien für Plattformen:

  • Einzelplattform-Builds (Standardeinstellung): Host-, Ausführungs- und Zielplattformen sind identisch. Beispiel: Erstellung einer ausführbaren Linux-Datei auf Ubuntu, die auf einer Intel x64-CPU ausgeführt wird.

  • Cross-Compilation-Builds: Host- und Ausführungsplattformen sind identisch, die Zielplattform ist jedoch anders. Beispiel: Sie erstellen eine iOS-App unter macOS, die auf einem MacBook Pro ausgeführt wird.

  • Plattformübergreifende Builds – Host-, Ausführungs- und Zielplattformen sind alle unterschiedlich.

Einschränkungen und Plattformen definieren

Der mögliche Bereich für Plattformen wird mithilfe der Regeln constraint_setting und constraint_value in BUILD-Dateien definiert. constraint_setting erstellt eine neue Dimension, während constraint_value einen neuen Wert für eine bestimmte Dimension erstellt. Gemeinsam definieren sie effektiv eine Aufzählung und ihre möglichen Werte. Mit dem folgenden Snippet einer BUILD-Datei wird beispielsweise eine Einschränkung für die glibc-Version des Systems mit zwei möglichen Werten eingeführt.

constraint_setting(name = "glibc_version")

constraint_value(
    name = "glibc_2_25",
    constraint_setting = ":glibc_version",
)

constraint_value(
    name = "glibc_2_26",
    constraint_setting = ":glibc_version",
)

Einschränkungen und ihre Werte können für verschiedene Pakete im Arbeitsbereich definiert werden. Sie werden mit einem Label referenziert und unterliegen den üblichen Sichtbarkeitseinstellungen. Wenn die Sichtbarkeit dies zulässt, können Sie eine vorhandene Einschränkungseinstellung erweitern, indem Sie einen eigenen Wert dafür definieren.

Mit der Regel platform wird eine neue Plattform mit bestimmten Auswahlmöglichkeiten für Einschränkungswerte eingeführt. Im Folgenden wird eine Plattform mit dem Namen linux_x86 erstellt, die alle Umgebungen beschreibt, auf denen ein Linux-Betriebssystem auf einer x86_64-Architektur mit der glibc-Version 2.25 ausgeführt wird. Weitere Informationen zu den integrierten Einschränkungen von Bazel finden Sie unten.

platform(
    name = "linux_x86",
    constraint_values = [
        "@platforms//os:linux",
        "@platforms//cpu:x86_64",
        ":glibc_2_25",
    ],
)

Allgemein nützliche Einschränkungen und Plattformen

Das Bazel-Team unterhält ein Repository mit Einschränkungsdefinitionen für die gängigsten CPU-Architekturen und Betriebssysteme, um für eine konsistente Umgebung zu sorgen. Diese befinden sich alle unter https://github.com/bazelbuild/platforms.

Bazel wird mit der folgenden speziellen Plattformdefinition ausgeliefert: @local_config_platform//:host. Dies ist der automatisch erkannte Wert der Hostplattform. Er stellt die automatisch erkannte Plattform für das System dar, auf dem Bazel ausgeführt wird.

Plattform für einen Build angeben

Sie können die Host- und Zielplattformen für einen Build mit den folgenden Befehlszeilen-Flags angeben:

  • --host_platform – Standardeinstellung: @bazel_tools//platforms:host_platform
  • --platforms – Standardeinstellung: @bazel_tools//platforms:target_platform

Inkompatible Ziele überspringen

Wenn Sie für eine bestimmte Zielplattform erstellen, ist es oft wünschenswert, Ziele zu überspringen, die auf dieser Plattform nie funktionieren. Beispielsweise generiert der Windows-Gerätetreiber wahrscheinlich viele Compiler-Fehler beim Erstellen auf einem Linux-Computer mit //.... Mit dem Attribut target_compatible_with teilen Sie Bazel mit, welche Einschränkungen der Zielplattform für Ihren Code gelten.

Durch die einfachste Verwendung dieses Attributs wird ein Ziel auf eine einzelne Plattform beschränkt. Das Ziel wird nicht für eine Plattform erstellt, die nicht alle Einschränkungen erfüllt. Im folgenden Beispiel wird win_driver_lib.cc auf 64-Bit-Windows beschränkt.

cc_library(
    name = "win_driver_lib",
    srcs = ["win_driver_lib.cc"],
    target_compatible_with = [
        "@platforms//cpu:x86_64",
        "@platforms//os:windows",
    ],
)

:win_driver_lib ist nur für 64-Bit-Windows-Builds kompatibel und mit allen anderen nicht kompatibel. Die Inkompatibilität ist vorübergehend. Alle Ziele, die vorübergehend von einem inkompatiblen Ziel abhängen, werden selbst als inkompatibel angesehen.

Wann werden Ziele übersprungen?

Ziele werden übersprungen, wenn sie als inkompatibel gelten und als Teil einer Zielmustererweiterung in den Build aufgenommen werden. Mit den folgenden beiden Aufrufen werden beispielsweise alle inkompatiblen Ziele übersprungen, die in einer Zielmustererweiterung gefunden wurden.

$ bazel build --platforms=//:myplatform //...
$ bazel build --platforms=//:myplatform //:all

Inkompatible Tests in einem test_suite werden auf ähnliche Weise übersprungen, wenn test_suite in der Befehlszeile mit --expand_test_suites angegeben wird. Mit anderen Worten: test_suite-Ziele in der Befehlszeile verhalten sich wie :all und .... Die Verwendung von --noexpand_test_suites verhindert die Erweiterung und führt dazu, dass test_suite-Ziele mit inkompatiblen Tests ebenfalls inkompatibel sind.

Wenn Sie ein inkompatibles Ziel in der Befehlszeile explizit angeben, erhalten Sie eine Fehlermeldung und der Build ist fehlgeschlagen.

$ bazel build --platforms=//:myplatform //:target_incompatible_with_myplatform
...
ERROR: Target //:target_incompatible_with_myplatform is incompatible and cannot be built, but was explicitly requested.
...
FAILED: Build did NOT complete successfully

Ausdrucksstärkere Einschränkungen

Wenn Sie Einschränkungen flexibler ausdrücken möchten, verwenden Sie den @platforms//:incompatible constraint_value, der von keiner Plattform erfüllt wird.

Verwende select() zusammen mit @platforms//:incompatible, um kompliziertere Einschränkungen auszudrücken. Sie können damit beispielsweise die einfache ODER-Logik implementieren. Im Folgenden wird eine Bibliothek aufgeführt, die mit macOS und Linux kompatibel ist, jedoch nicht für andere Plattformen.

cc_library(
    name = "unixish_lib",
    srcs = ["unixish_lib.cc"],
    target_compatible_with = select({
        "@platforms//os:osx": [],
        "@platforms//os:linux": [],
        "//conditions:default": ["@platforms//:incompatible"],
    }),
)

Oben kann Folgendes interpretiert werden:

  1. Beim Targeting auf macOS hat das Ziel keine Einschränkungen.
  2. Beim Targeting auf Linux gibt es keine Einschränkungen für das Ziel.
  3. Andernfalls hat das Ziel die Einschränkung @platforms//:incompatible. Da @platforms//:incompatible zu keiner Plattform gehört, ist das Ziel nicht kompatibel.

Sie können die Einschränkungen mit skylib selects.with_or() verbessern.

Auf ähnliche Weise können Sie umgekehrte Kompatibilität ausdrücken. Im folgenden Beispiel wird eine Bibliothek beschrieben, die mit allem außer für ARM kompatibel ist.

cc_library(
    name = "non_arm_lib",
    srcs = ["non_arm_lib.cc"],
    target_compatible_with = select({
        "@platforms//cpu:arm": ["@platforms//:incompatible"],
        "//conditions:default": [],
    ],
)

Inkompatible Ziele mit bazel cquery erkennen

Sie können die IncompatiblePlatformProvider im bazel cqueryStarlark-Ausgabeformat verwenden, um inkompatible Ziele von kompatiblen Zielen zu unterscheiden.

Hiermit können inkompatible Ziele herausgefiltert werden. Im folgenden Beispiel werden nur Labels für kompatible Ziele gedruckt. Inkompatible Ziele werden nicht ausgegeben.

$ cat example.cquery

def format(target):
  if "IncompatiblePlatformProvider" not in providers(target):
    return target.label
  return ""


$ bazel cquery //... --output=starlark --starlark:file=example.cquery

Bekannte Probleme

Inkompatible Ziele ignorieren Sichtbarkeitsbeschränkungen.