函式

回報問題 查看來源 Nightly · 8.4 · 8.3 · 8.2 · 8.1 · 8.0 · 7.6

目錄

包裹

package(default_deprecation, default_package_metadata, default_testonly, default_visibility, features)

這個函式會宣告適用於套件中每項規則的中繼資料。套件 (BUILD 檔案) 中最多只能使用一次。

如要宣告適用於整個存放區中每項規則的中繼資料,請在存放區根目錄的 REPO.bazel 檔案中使用 repo() 函式。repo() 函式使用的引數與 package() 完全相同。

在檔案頂端的所有 load() 陳述式之後,任何規則之前,都應呼叫 package() 函式。

引數

屬性 說明
default_applicable_licenses

default_package_metadata 的別名。

default_visibility

標籤清單;預設值為 []

這個套件中頂層規則目標和符號巨集的預設可見度,也就是未在符號巨集中宣告的目標和符號巨集。如果目標或巨集指定 visibility 值,系統會忽略這項屬性。

如要詳細瞭解這項屬性的語法,請參閱 可見度說明文件。套件預設瀏覽權限不適用於 exports_files,後者預設為公開。

default_deprecation

字串;預設值為 ""

為這個套件中的所有規則設定預設 deprecation 訊息。

default_package_metadata

標籤清單;預設值為 []

設定預設中繼資料目標清單,套用至套件中的所有其他目標。 這些通常是與 OSS 套件和授權聲明相關的目標。 如需範例,請參閱 rules_license

default_testonly

布林值;預設值為 False,但以下註明的情形除外

為這個套件中的所有規則設定預設 testonly 屬性。

javatests 下的套件中,預設值為 True

features

字串清單;預設值為 []

設定會影響這個 BUILD 檔案語意的各種標記。

這項功能主要由建構系統人員使用,用來標記需要特殊處理的套件。除非建構系統人員明確要求,否則請勿使用這項功能。

範例

以下宣告表示這個套件中的規則僅對套件群組 //foo:target 的成員顯示。如果規則中含有個別顯示設定聲明,則會覆寫這項規格。
package(default_visibility = ["//foo:target"])

package_group

package_group(name, packages, includes)

這個函式會定義一組套件,並將標籤與該組套件建立關聯。標籤可在 visibility 屬性中參照。

套件群組主要用於控管顯示設定。來源樹狀結構中的每個套件都可以參照公開顯示的目標。私下可見的目標只能在自己的套件 (而非子套件) 中參照。在這兩個極端之間,目標可能會允許存取自己的套件,以及一或多個套件群組所描述的任何套件。如要進一步瞭解瀏覽權限系統,請參閱瀏覽權限屬性。

如果套件符合 packages 屬性,或已包含在 includes 屬性中提及的其他套件群組中,系統就會將該套件視為群組成員。

從技術上來說,套件群組是目標,但不是由規則建立,本身也沒有任何可視度保護措施。

引數

屬性 說明
name

名稱:必填

這個目標的專屬名稱。

packages

字串清單;預設值為 []

零或多個套件規格的清單。

每個套件規格字串可採用下列任一形式:

  1. 套件的完整名稱,不含存放區,開頭為雙斜線。舉例來說,//foo/bar 會指定具有該名稱的套件,且該套件與套件群組位於同一個存放區。
  2. 如上,但結尾有 /...。舉例來說, //foo/... 會指定 //foo 和所有子套件的集合。//... 會指定目前存放區中的所有套件。
  3. 字串 publicprivate,分別指定每個套件或沒有任何套件。(這份表單需要設定 --incompatible_package_group_has_public_syntax 旗標。)

此外,前兩種套件規格也可能以 - 為前置字元,表示這些規格遭到否定。

套件群組包含符合至少一個正向規格的任何套件,且不符合任何負向規格。舉例來說,值 [//foo/..., -//foo/tests/...] 包含 //foo 的所有子套件,但這些子套件不得同時也是 //foo/tests 的子套件。(//foo 本身會納入,但 //foo/tests 本身不會。)

除了公開瀏覽權限外,無法直接指定目前存放區以外的套件。

如果缺少這項屬性,效果等同於將其設為空白清單,也等同於將其設為只包含 private 的清單。

注意:在 Bazel 6.0 之前,規格 //... 的舊版行為與 public 相同。啟用 --incompatible_fix_package_group_reporoot_syntax 後,系統會修正這項行為,而這是 Bazel 6.0 後的預設設定。

注意:在 Bazel 6.0 之前,如果這個屬性序列化為 bazel query --output=proto (或 --output=xml) 的一部分,則會省略開頭斜線。舉例來說,//pkg/foo/... 會輸出為 \"pkg/foo/...\"。啟用 --incompatible_package_group_includes_double_slash 後,系統就會修正這項行為。Bazel 6.0 以上版本預設會啟用這項設定。

includes

標籤清單;預設值為 []

這個套件群組包含的其他套件群組。

這項屬性中的標籤必須參照其他套件群組。 參考套件群組中的套件會視為這個套件群組的一部分。這是遞移關係,也就是說,如果套件群組 a 包含套件群組 b,而 b 包含套件群組 c,則 c 中的每個套件也會是 a 的成員。

如果搭配使用否定套件規格,請注意,系統會先獨立計算每個群組的套件組合,然後將結果聯集。也就是說,一個群組中排除的規格不會影響另一個群組中的規格。

範例

下列 package_group 宣告指定名為「tropical」的套件群組,其中包含熱帶水果。

package_group(
    name = "tropical",
    packages = [
        "//fruits/mango",
        "//fruits/orange",
        "//fruits/papaya/...",
    ],
)

下列宣告會指定虛構應用程式的套件群組:

package_group(
    name = "fooapp",
    includes = [
        ":controller",
        ":model",
        ":view",
    ],
)

package_group(
    name = "model",
    packages = ["//fooapp/database"],
)

package_group(
    name = "view",
    packages = [
        "//fooapp/swingui",
        "//fooapp/webui",
    ],
)

package_group(
    name = "controller",
    packages = ["//fooapp/algorithm"],
)

exports_files

exports_files([label, ...], visibility, licenses)

exports_files() 會指定屬於這個套件的檔案清單,這些檔案會匯出至其他套件。

如果套件的 BUILD 檔案直接參照屬於其他套件的來源檔案,則這些檔案必須透過 exports_files() 陳述式明確匯出。進一步瞭解檔案瀏覽權限

根據舊版行為,系統也會匯出提及為規則輸入內容的檔案,並維持預設可見度,直到 --incompatible_no_implicit_file_export 標記翻轉為止。不過,不應依賴這種行為,且應主動遷移。

引數

這個引數是目前套件中檔案名稱的清單。也可以指定可見度宣告,這樣檔案就會對指定目標顯示。如果未指定顯示設定,所有套件都能看到檔案,即使 package 函式中指定了套件預設顯示設定也一樣。也可以指定授權

範例

下列範例會匯出 golden.txt,也就是 test_data 套件中的文字檔,以便其他套件使用,例如在測試的 data 屬性中。

# from //test_data/BUILD

exports_files(["golden.txt"])

glob

glob(include, exclude=[], exclude_directories=1, allow_empty=True)

Glob 是一項輔助函式,可找出符合特定路徑模式的所有檔案,並傳回這些路徑的新可變動排序清單。Glob 只會搜尋自身套件中的檔案,且只會尋找來源檔案 (而非產生的檔案或其他目標)。

如果檔案的套件相對路徑符合任何 include 模式,且不符合任何 exclude 模式,結果就會包含來源檔案的標籤。

includeexclude 清單包含相對於目前套件的路徑模式。每個模式可由一或多個路徑區隔組成。與 Unix 路徑一樣,這些區隔會以 / 分隔。模式中的區隔會與路徑的區隔比對。片段可能包含 * 萬用字元:這會比對路徑片段中的任何子字串 (甚至是空白子字串),目錄分隔符 / 除外。您可以在一個路徑區段中多次使用這個萬用字元。此外,** 萬用字元可比對零或多個完整路徑片段,但必須宣告為獨立路徑片段。

範例:
  • foo/bar.txt 與這個套件中的 foo/bar.txt 檔案完全相符 (除非 foo/ 是子套件)
  • 如果檔案結尾為 .txt (除非 foo/ 是子套件),foo/*.txt 會比對 foo/ 目錄中的每個檔案
  • foo/a*.htm* 會比對 foo/ 目錄中以 a 開頭的每個檔案,然後是任意字串 (可能為空白),接著是 .htm,最後是另一個任意字串 (除非 foo/ 是子套件);例如 foo/axx.htmfoo/a.htmlfoo/axxx.html
  • foo/* 會比對 foo/ 目錄中的每個檔案 (除非 foo/ 是子封裝),即使 exclude_directories 設為 0,也不會比對 foo 目錄本身
  • foo/** 會比對套件第一層子目錄 foo/ 下每個非子套件子目錄中的每個檔案;如果 exclude_directories 設為 0,foo 目錄本身也會比對模式;在這種情況下,** 會視為比對零個路徑區隔
  • **/a.txt 符合這個套件目錄中的 a.txt 檔案,以及非子套件子目錄。
  • 如果結果路徑上至少有一個目錄稱為 bar,則 **/bar/**/*.txt 會比對這個套件中每個非子套件子目錄的每個 .txt 檔案,例如 xxx/bar/yyy/zzz/a.txtbar/a.txt (請注意,** 也會比對零個區段) 或 bar/zzz/a.txt
  • ** 會比對這個套件中每個非子套件子目錄的每個檔案
  • foo**/a.txt 是無效模式,因為 ** 必須做為獨立區段
  • foo/ 是無效模式,因為 / 後定義的第二個區段是空字串

如果啟用 exclude_directories 引數 (設為 1),結果會省略目錄類型的檔案 (預設為 1)。

如果 allow_empty 引數設為 False,且結果為空白清單,glob 函式會傳回錯誤。

請注意以下幾項重要限制和注意事項:

  1. 由於 glob() 會在 BUILD 檔案評估期間執行,因此 glob() 只會比對來源樹狀結構中的檔案,絕不會比對產生的檔案。如果您要建構的目標需要來源和產生的檔案,就必須將產生的檔案明確清單附加至 glob。請參閱下方的範例,瞭解 :mylib:gen_java_srcs

  2. 如果規則與相符的來源檔案同名,規則會「遮蔽」該檔案。

    如要瞭解這點,請記住 glob() 會傳回路徑清單,因此在其他規則的屬性 (例如 srcs = glob(["*.cc"])) 中使用 glob(),效果與明確列出相符路徑相同。舉例來說,如果 glob() 會產生 ["Foo.java", "bar/Baz.java"],但套件中也有名為「Foo.java」的規則 (雖然 Bazel 會發出警告,但這是允許的),則 glob() 的消費者會使用「Foo.java」規則 (其輸出內容),而不是「Foo.java」檔案。詳情請參閱 GitHub 問題 #10395

  3. Glob 可能會比對子目錄中的檔案。子目錄名稱可使用萬用字元。不過...
  4. 標籤不得跨越套件界線,且 glob 不會比對子套件中的檔案。

    舉例來說,如果 x/y 以套件形式存在 (無論是 x/y/BUILD 或套件路徑上的其他位置),則套件 **/*.cc 中的 glob 運算式 x 不會包含 x/y/z.cc。也就是說,glob 運算式的結果實際上取決於 BUILD 檔案是否存在,也就是說,如果沒有名為 x/y 的套件,或該套件已使用 --deleted_packages 標記為已刪除,則相同的 glob 運算式會包含 x/y/z.cc

  5. 上述限制適用於所有 glob 運算式,無論使用哪種萬用字元都一樣。
  6. 檔案名稱開頭為 . 的隱藏檔案,完全符合 *** 萬用字元。如要使用複合模式比對隱藏檔案,模式必須以 . 開頭。舉例來說,*.*.txt 會與 .foo.txt 相符,但 *.txt 不會。 隱藏目錄也會以相同方式比對。隱藏目錄可能包含不需要做為輸入內容的檔案,並增加不必要的 glob 檔案數量和記憶體消耗量。如要排除隱藏目錄,請將這些目錄新增至「exclude」清單引數。
  7. 「**」萬用字元有一個特殊情況:模式 "**" 不符合套件的目錄路徑。也就是說,glob(["**"], exclude_directories = 0) 會嚴格遞迴比對目前套件目錄下的所有檔案和目錄 (但當然不會進入子套件的目錄,請參閱先前的附註)。

一般來說,您應該嘗試提供適當的副檔名 (例如 *.html),而不是使用裸露的「*」做為 glob 模式。更明確的名稱不僅能自我記錄,還可確保您不會意外比對備份檔案,或是 emacs/vi/... 自動儲存的檔案。

編寫建構規則時,您可以列舉 glob 的元素。這樣一來,系統就能為每個輸入內容產生個別規則,例如:請參閱下方的擴展 glob 範例一節。

Glob 範例

從這個目錄中的所有 Java 檔案,以及 :gen_java_srcs 規則產生的所有檔案,建立 Java 程式庫。

java_library(
    name = "mylib",
    srcs = glob(["*.java"]) + [":gen_java_srcs"],
    deps = "...",
)

genrule(
    name = "gen_java_srcs",
    outs = [
        "Foo.java",
        "Bar.java",
    ],
    ...
)

將 testdata 目錄中的所有 txt 檔案 (experimental.txt 除外) 納入其中。 請注意,系統不會納入 testdata 子目錄中的檔案。如要納入這些檔案,請使用遞迴 glob (**) 模式。

sh_test(
    name = "mytest",
    srcs = ["mytest.sh"],
    data = glob(
        ["testdata/*.txt"],
        exclude = ["testdata/experimental.txt"],
    ),
)

遞迴 Glob 範例

讓測試依附於 testdata 目錄中的所有 txt 檔案,以及任何子目錄 (和子目錄的子目錄等)。含有 BUILD 檔案的子目錄會遭到忽略。(請參閱上方的限制和注意事項)。

sh_test(
    name = "mytest",
    srcs = ["mytest.sh"],
    data = glob(["testdata/**/*.txt"]),
)

從這個目錄和所有子目錄中的所有 Java 檔案建立程式庫,但路徑包含名為 testing 的目錄除外。請盡量避免使用這種模式,因為這可能會降低建構增量,進而增加建構時間。

java_library(
    name = "mylib",
    srcs = glob(
        ["**/*.java"],
        exclude = ["**/testing/**"],
    ),
)

擴展 Glob 範例

在目前目錄中為 *_test.cc 建立個別 genrule,計算檔案中的行數。

# Conveniently, the build language supports list comprehensions.
[genrule(
    name = "count_lines_" + f[:-3],  # strip ".cc"
    srcs = [f],
    outs = ["%s-linecount.txt" % f[:-3]],
    cmd = "wc -l $< >$@",
 ) for f in glob(["*_test.cc"])]

如果上述 BUILD 檔案位於套件 //foo 中,且套件包含三個相符的檔案 (a_test.cc、b_test.cc 和 c_test.cc),則執行 bazel query '//foo:all' 會列出所有產生的規則:

$ bazel query '//foo:all' | sort
//foo:count_lines_a_test
//foo:count_lines_b_test
//foo:count_lines_c_test

選取

select(
    {conditionA: valuesA, conditionB: valuesB, ...},
    no_match_error = "custom message"
)

select() 是輔助函式,可讓規則屬性設定。 它可以取代任何屬性指派的右側,因此其值取決於指令列 Bazel 標記。舉例來說,您可以使用這項功能定義平台專屬的依附元件,或根據規則是在「開發人員」還是「發布」模式中建構,嵌入不同的資源。

基本用法如下:

sh_binary(
    name = "mytarget",
    srcs = select({
        ":conditionA": ["mytarget_a.sh"],
        ":conditionB": ["mytarget_b.sh"],
        "//conditions:default": ["mytarget_default.sh"]
    })
)

這樣一來,您就能透過 select 呼叫,將設定條件對應至相符值,取代一般標籤清單指派作業,進而設定 sh_binarysrcs 屬性。每個條件都是 config_settingconstraint_value 的標籤參照,如果目標的設定符合預期的值集,就會「相符」。mytarget#srcs 的值會變成與目前叫用相符的標籤清單。

注意:

  • 每次叫用時,只能選取一個條件。
  • 如果有多個條件相符,且其中一個是其他條件的特例,系統會優先採用特例。如果條件 B 具有與條件 A 相同的所有旗標和限制值,外加一些額外的旗標或限制值,則條件 B 會視為條件 A 的特例。這也表示專門化解析並非用於建立排序,如下方範例 2 所示。
  • 如果多個條件相符,且其中一個條件並非所有其他條件的特例,Bazel 會因錯誤而失敗,除非所有條件都解析為相同的值。
  • 如果沒有其他相符的條件,系統會將特殊虛擬標籤 //conditions:default 視為相符。如果省略這項條件,就必須符合其他規則,才能避免發生錯誤。
  • select 可以內嵌在較大的屬性指派中。因此 srcs = ["common.sh"] + select({ ":conditionA": ["myrule_a.sh"], ...}) srcs = select({ ":conditionA": ["a.sh"]}) + select({ ":conditionB": ["b.sh"]}) 都是有效運算式。
  • select 適用於大多數屬性,但並非全部。不相容的屬性會在說明文件中標示 nonconfigurable

    子檔案包

    subpackages(include, exclude=[], allow_empty=True)

    subpackages() 是輔助函式,與 glob() 類似,但會列出子封裝而非檔案和目錄。它與 glob() 使用相同的路徑模式,且可比對目前載入 BUILD 檔案的任何直接子套件。如需詳細說明和包含/排除模式的範例,請參閱 glob

    傳回的子套件清單會經過排序,並包含與 include 中指定模式相符的路徑,這些路徑與目前載入的套件相關,但不包含 exclude 中的路徑。

    範例

    以下範例會列出套件 foo/BUILD 的所有直接子套件:

    # The following BUILD files exist:
    # foo/BUILD
    # foo/bar/baz/BUILD
    # foo/bar/but/bad/BUILD
    # foo/sub/BUILD
    # foo/sub/deeper/BUILD
    #
    # In foo/BUILD a call to
    subs1 = subpackages(include = ["**"])
    
    # results in subs1 == ["sub", "bar/baz", "bar/but/bad"]
    #
    # 'sub/deeper' is not included because it is a subpackage of 'foo/sub' not of
    # 'foo'
    
    subs2 = subpackages(include = ["bar/*"])
    # results in subs2 = ["bar/baz"]
    #
    # Since 'bar' is not a subpackage itself, this looks for any subpackages under
    # all first level subdirectories of 'bar'.
    
    subs3 = subpackages(include = ["bar/**"])
    # results in subs3 = ["bar/baz", "bar/but/bad"]
    #
    # Since bar is not a subpackage itself, this looks for any subpackages which are
    # (1) under all subdirectories of 'bar' which can be at any level, (2) not a
    # subpackage of another subpackages.
    
    subs4 = subpackages(include = ["sub"])
    subs5 = subpackages(include = ["sub/*"])
    subs6 = subpackages(include = ["sub/**"])
    # results in subs4 and subs6 being ["sub"]
    # results in subs5 = [].
    #
    # In subs4, expression "sub" checks whether 'foo/sub' is a package (i.e. is a
    # subpackage of 'foo').
    # In subs5, "sub/*" looks for subpackages under directory 'foo/sub'. Since
    # 'foo/sub' is already a subpackage itself, the subdirectories will not be
    # traversed anymore.
    # In subs6, 'foo/sub' is a subpackage itself and matches pattern "sub/**", so it
    # is returned. But the subdirectories of 'foo/sub' will not be traversed
    # anymore.
    

    一般來說,建議使用者使用 skylib 的「subpackages」模組,而不是直接呼叫這個函式。