Bazel 標籤

Bazel 標籤是字串參照,參照的對象是來源檔案和 BUILD.bazel 檔案中定義的項目。一般格式如下:

@<repository_name>//<package_name>:<target_name>

其中:

  • @<repository_name>// 會指定具名 Bazel 工作區的目錄。

    為方便起見,您可以簡寫為 //,代表目前的 Workspace (包含目前的 BUILD.bazel 檔案)。另請注意,@// 用於指定專案的根工作區,即使是在外部存放區中使用也是如此。

  • <package_name> 是套件的目錄路徑,相對於工作區目錄。舉例來說,在標籤 //src:main.cc 或 //src/lib:foo 中,套件名稱分別為 src 和 src/lib。

    這可以是空白,例如 //:BUILD.bazel 指向目前工作區頂層目錄中的建構檔案。

  • 如果是來源檔案,<target_name> 是相對於上層套件目錄的檔案路徑,可能包含子目錄部分。舉例來說,如果是 //src:main.cc 或 //src:extra/extra.cc,目標名稱分別為 main.cc 和 extra/extra.cc。

  • 如果是其他項目,<target_name> 對應於 BUILD.bazel 檔案中定義的項目 (建構構件、建構設定、設定條件等)。

    按照慣例,其 name 屬性不應包含目錄分隔符號 (極少數情況除外),以免與來源混淆。

    對於來自其他建構系統的開發人員來說,這可能會造成混淆,因為這些系統會區分建構圖中的項目類型 (例如 GN 會使用「目標」、「設定」、「工具鍊」和「集區」來指定不同項目)。

此外,也支援標籤的縮寫:

  • 如果標籤以存放區名稱開頭,且不含半形冒號,則為套件路徑,並指向名稱相同的項目。例如,//src/foo 等同於 //src/foo:foo。

  • 如果標籤開頭為半形冒號,則為相對於目前套件的名稱。舉例來說,src/foo/BUILD.bazel 中出現的「:bar」和「:extra/bar.cc」分別等同於 //src/foo:bar 和 //src/foo:extra/bar.cc。

  • 如果標籤沒有存放區名稱和冒號,一律是相對於目前套件的名稱,即使包含目錄分隔符號也一樣。例如,src/foo/BUILD.bazel 中的「bar/bar.cc」一律是指 //src/foo:bar/bar.cc。

    請注意,這與 //src/foo/bar:bar.cc 不同

相對標籤和套件擁有權

由於每個來源檔案只能屬於單一套件,因此相對標籤可能無效。舉例來說,在類似下列的專案中:

/home/user/project/
    WORKSPACE.bazel
    src/
        BUILD.bazel
        main.cc
        extra/
            extra.cc
        lib/
            BUILD.bazel
            foo.cc
            foo.h

foo.cc 檔案屬於 src/lib 套件,因此其標籤必須是 //src/lib:foo.cc。

在 src/BUILD.bazel 中使用 src:lib/foo.cc 等標籤會導致錯誤:

# From src/BUILD.bazel
cc_binary(
  name = "program",
  srcs = [
    "extra/extra.cc",
    "lib/foo.cc",       # Error: Label '//src:lib/foo.cc' is invalid because 'src/lib' is a subpackage
    "lib/foo.h"         # Error: Label '//src:lib/foo.h' is invalid because 'src/lib' is a subpackage
    "main.cc",
  ],
)

從其他套件存取來源檔案

根據預設,其他套件無法存取特定套件的來源檔案,且相對套件標籤無效,如下所示:

# From src/BUILD.bazel
cc_binary(
  name = "program",
  srcs = [
    "extra/extra.cc",
    "lib:foo.cc",    # Error: invalid label 'lib:foo.cc': absolute label must begin with '@' or '//'
    "lib:foo.h"      # Error: invalid label 'lib:foo.h': absolute label must begin with '@' or '//'
    "main.cc",
  ],
)

即使使用正確的絕對標籤,仍會發生錯誤:

# From src/BUILD.bazel
cc_binary(
  name = "program",
  srcs = [
    "extra/extra.cc",
    "//src/lib:foo.cc",    # Error: no such target '//src/lib:foo.cc': target 'foo.h' not declared in package 'src/lib'
    "//src/lib:foo.h"      # Error: no such target '//src/lib:foo.h': target 'foo.h' not declared in package 'src/lib'
    "main.cc",
  ],
)

您可以透過下列方式,直接存取套件界線以外的檔案:export_files()

# From src/lib/BUILD.bazel
export_files([
  "foo.cc" ,
  "foo.h" ,
])

# From src/BUILD.bazel
cc_binary(
  name = "program",
  srcs = [
    "extra/extra.cc",
    "//src/lib:foo.cc",    # OK
    "//src/lib:foo.h"      # OK
    "main.cc",
  ],
)

其他套件的目標存取權

BUILD.bazel 檔案中定義的標籤項目如非來源檔案,則不需要匯出,但其 visibility 屬性必須允許在自有套件外使用:

# From src/lib/BUILD.bazel
cc_library(
  name = " lib" ,
  srcs = [ " foo.cc"  ],
  hdrs = [ " foo.h"  ],
  visibility = [ " //visibility:public" ],  # Anyone can reference this directly!
)

# From src/BUILD.bazel
cc_binary(
  name = "program",
  srcs = [
    "extra/extra.cc",
    "main.cc",
  ],
  deps = [ "lib" ],   # OK!
)

根據預設,項目只會對同一個套件中的其他項目顯示。 如要變更這項設定,請使用 package() 指令,變更套件中定義的所有項目的預設顯示設定:

# From src/lib/BUILD.bazel

# Ensure that all items defined in this file are visible to anyone
package(default_visibility = ["//visibility:public"])

cc_library(
  name = " lib" ,
  srcs = [ "foo.cc" ],
  hdrs = [ "foo.h" ],
)

# From src/BUILD.bazel
cc_binary(
  name = "program",
  srcs = [
    "extra/extra.cc",
    "main.cc",
  ],
  deps = [ "lib" ],   # OK!
)

虛擬套件警告

請避免在專案中建立下列名稱的頂層目錄:

  • conditions
  • command_line_option
  • external
  • visibility

因為 Bazel 會在 BUILD.bazel 檔案的標籤中使用多個硬式編碼的「虛擬套件」。例如:

  //visibility:public
  //conditions:default
  //command_line_option:copt

external 的情況有點不同:它不會出現在 BUILD.bazel 檔案中,但用於內部管理外部存放區。如果將這個目錄當做專案目錄使用,會讓 Bazel 感到困惑

標準存放區名稱

自 Bazel 6.0 起,標籤中的存放區名稱也可以 @@ 開頭。

啟用選用的 BzlMod 功能後,這些標籤會做為外部存放區的替代標籤名稱,但必須是專屬名稱。在專案中使用複雜的遞移依附元件樹狀結構時,這點就非常重要。

舉例來說,@@com_acme_anvil.1.0.3 可能是專案自有 BUILD.bazel 檔案中以 @anvil 識別的工作區目錄的標準名稱,也可能是出現在外部存放區 (例如 @foo//:BUILD.bazel 內) 時的 @acme_anvil。這三個標籤都會參照相同目錄的內容。

標準存放區名稱不會顯示在 BUILD.bazel 檔案中,但會在分析階段 (執行查看標籤值的 Starlark 函式時) 或查看 Bazel 查詢結果時顯示。