建立變數

回報問題 查看來源 Nightly · 8.3 · 8.2 · 8.1 · 8.0 · 7.6

「製作」變數是可擴充字串變數的特殊類別,適用於標示為「須代入『製作』變數」的屬性。

舉例來說,這些路徑可用於將特定工具鍊路徑插入使用者建構的建構動作。

Bazel 提供預先定義的變數 (適用於所有目標),以及自訂變數 (定義於依附目標中,僅適用於依附目標)。

「Make」一詞的由來是歷史因素:這些變數的語法和語意原本是為了與 GNU Make 相符。

使用

標示為「須遵守『製作變數』替代規則」的屬性可以參照「製作」變數 FOO,如下所示:

my_attr = "prefix $(FOO) suffix"

換句話說,任何符合 $(FOO) 的子字串都會擴展為 FOO 的值。如果該值為 "bar",最終字串會變成:

my_attr = "prefix bar suffix"

如果 FOO 不對應至取用目標已知的變數,Bazel 會失敗並顯示錯誤訊息。

名稱為非字母符號的「Make」變數 (例如 @) 也可以只使用貨幣符號參照,不必加上括號。例如:

my_attr = "prefix $@ suffix"

如要將 $ 寫成字串常值 (即防止變數擴充),請寫入 $$.

Predefined variables

Predefined "Make" variables can be referenced by any attribute marked as "Subject to 'Make variable' substitution" on any target.

To see the list of these variables and their values for a given set of build options, run

bazel info --show_make_env [build options]

and look at the top output lines with capital letters.

See an example of predefined variables.

Toolchain option variables

Path variables

  • BINDIR: The base of the generated binary tree for the target architecture.

    Note that a different tree may be used for programs that run during the build on the host architecture, to support cross-compiling.

    If you want to run a tool from within a genrule, the recommended way to get its path is $(execpath toolname), where toolname must be listed in the genrule's tools attribute.

  • GENDIR: The base of the generated code tree for the target architecture.

Machine architecture variables

  • TARGET_CPU: The target architecture's CPU, e.g. k8.

Predefined genrule variables

The following are specially available to genrule's cmd attribute and are generally important for making that attribute work.

See an example of predefined genrule variables.

  • OUTS: The genrule's outs list. If you have only one output file, you can also use $@.
  • SRCS: The genrule's srcs list (or more precisely: the path names of the files corresponding to labels in the srcs list). If you have only one source file, you can also use $<.
  • <: SRCS, if it is a single file. Else triggers a build error.
  • @: OUTS, if it is a single file. Else triggers a build error.
  • RULEDIR: The output directory of the target, that is, the directory corresponding to the name of the package containing the target under the genfiles or bin tree. For //my/pkg:my_genrule this always ends in my/pkg, even if //my/pkg:my_genrule's outputs are in subdirectories.

  • @D: The output directory. If outs has one entry, this expands to the directory containing that file. If it has multiple entries, this expands to the package's root directory in the genfiles tree, even if all output files are in the same subdirectory!

    Note: Use RULEDIR over @D because RULEDIR has simpler semantics and behaves the same way regardless of the number of output files.

    If the genrule needs to generate temporary intermediate files (perhaps as a result of using some other tool like a compiler), it should attempt to write them to @D (although /tmp will also be writable) and remove them before finishing.

    Especially avoid writing to directories containing inputs. They may be on read-only filesystems. Even if not, doing so would trash the source tree.

Note: If the filenames corresponding to the input labels or the output filenames contain spaces, ', or other special characters (or your genrule is part of a Starlark macro which downstream users may invoke on such files), then $(SRCS) and $(OUTS) are not suitable for interpolation into a command line, as they do not have the semantics that "${@}" would in Bash.

One workaround is to convert to a Bash array, with

mapfile SRCS <<< "$$(sed -e 's/ /\\n/g' <<'genrule_srcs_expansion'
$(SRC)
genrule_srcs_expansion
),然後在後續指令列中使用 "$$\{SRCS[@]}" 取代 $(SRCS)。更強大的做法是改為編寫 Starlark 規則。

預先定義的來源/輸出路徑變數

預先定義的變數 execpathexecpathsrootpathrootpathslocationlocations 會採用標籤參數 (例如 $(execpath //foo:bar)),並替換該標籤表示的檔案路徑。

如果是來源檔案,這是相對於工作區根目錄的路徑。如果是規則的輸出檔案,這是檔案的輸出路徑 (請參閱下方的輸出檔案說明)。

查看預先定義路徑變數的範例

  • execpath:表示 execroot 下方的路徑,Bazel 會在此執行建構動作。

    在上述範例中,Bazel 會在工作區根目錄中,由 bazel-myproject 符號連結連結的目錄中,執行所有建構動作。來源檔案 empty.source 會連結至路徑 bazel-myproject/testapp/empty.source。因此,其執行路徑 (即根目錄下方的子路徑) 為 testapp/empty.source。這是建構動作可用來尋找檔案的路徑。

    輸出檔案的暫存方式類似,但也會加上子路徑前置字串 bazel-out/cpu-compilation_mode/bin (或工具的輸出內容:bazel-out/cpu-opt-exec-hash/bin)。在上述範例中,//testapp:app 是工具,因為它出現在 show_app_outputtools 屬性中。因此,輸出檔案 app 會寫入 bazel-myproject/bazel-out/cpu-opt-exec-hash/bin/testapp/app。因此,執行路徑為 bazel-out/cpu-opt-exec-hash/bin/testapp/app。這個額外前置字元可讓您在同一個建構中,為兩個不同的 CPU 建構相同目標,而不會互相覆寫結果。

    傳遞至這個變數的標籤必須代表一個檔案。如果是代表來源檔案的標籤,這項屬性會自動設為 true。如果是代表規則的標籤,規則必須只產生一個輸出內容。如果這個值為 false 或標籤格式錯誤,建構作業就會失敗並顯示錯誤訊息。

  • rootpath:表示建構的二進位檔可用於在執行階段尋找依附元件的路徑,該路徑相對於與主要存放區對應的 runfiles 目錄子目錄。注意:這項功能僅適用於啟用 --enable_runfiles 的情況,但 Windows 預設不會啟用這項功能。請改用 rlocationpath,以支援跨平台。

    這與 execpath 類似,但會移除上述設定前置字元。以上述範例來說,這表示 empty.sourceapp 都使用純粹的工作區相對路徑:testapp/empty.sourcetestapp/app

    外部存放區中檔案的 rootpath 會以 ../repo/ 開頭,後方為存放區相對路徑。repo

    這與 execpath 具有相同的「僅限一個輸出內容」規定。

  • rlocationpath:建構的二進位檔可傳遞至 Runfiles 程式庫的 Rlocation 函式的路徑,以便在執行階段尋找依附元件 (在 Runfiles 目錄中,或使用 Runfiles 資訊清單)。

    這與 rootpath 類似,因為兩者都不含設定前置字元,但不同之處在於,這項屬性一律以存放區名稱開頭。在上述範例中,這表示 empty.sourceapp 會產生下列路徑:myproject/testapp/empty.source myproject/testapp/app

    外部存放區中檔案的 rlocationpath 會以 repo/ 開頭,後方為存放區相對路徑。repo

    將這個路徑傳遞至二進位檔,並使用 Runfiles 程式庫將其解析為檔案系統路徑,是在執行階段尋找依附元件的偏好做法。相較於 rootpath,這項工具的優點是適用於所有平台,即使執行檔目錄無法使用也沒問題。

    這與 execpath 具有相同的「僅限一個輸出內容」規定。

  • location:視展開的屬性而定,可以是 execpathrootpath 的同義字。這是 Starlark 前的舊版行為,除非您確實瞭解特定規則的作用,否則不建議使用。詳情請參閱 #2475

execpathsrootpathsrlocationpathslocations 分別是 execpathrootpathrlocationpathlocation 的複數變體。標籤可產生多個輸出內容,這時每個輸出內容會以空格分隔列出。如果規則沒有輸出內容,或標籤格式錯誤,就會產生建構錯誤。

所有參照的標籤都必須出現在取用目標的 srcs、輸出檔案或 deps 中。否則建構作業會失敗。C++ 目標也可以參照 data 中的標籤。

標籤不一定要採用標準形式:foo:foo//somepkg:foo 都可以。

自訂變數

任何標示為「Subject to 'Make variable' substitution」(須代入「Make」變數) 的屬性,都可以參照自訂「Make」變數,但只有在目標依附於定義這些變數的其他目標時,才能參照。

除非有充分理由將所有變數納入核心 Bazel,否則建議您一律使用自訂變數。這樣一來,Bazel 就不必載入可能耗費資源的依附元件,來提供取用目標可能不在意的變數。

C++ 工具鍊變數

下列項目定義於 C++ 工具鍊規則中,且適用於任何設定 toolchains = ["@bazel_tools//tools/cpp:toolchain_type"] 的規則。部分規則 (例如 java_binary) 會在規則定義中隱含納入 C++ 工具鍊。這些變數會自動繼承。

內建 C++ 規則比「對其執行編譯器」複雜許多,為了支援各種編譯模式 (例如 *SAN、ThinLTO、含/不含模組),並確保在多個平台上快速執行測試的同時,也能仔細最佳化二進位檔,內建規則會盡可能確保在每個可能產生的內部動作中,都設定正確的輸入、輸出和指令列標記。

這些變數是備用機制,語言專家會在極少數情況下使用。如果您想使用這些規則,請先與 Bazel 開發人員聯絡

  • ABI:C++ ABI 版本。
  • AR:crosstool 的「ar」指令。
  • C_COMPILER: C/C++ 編譯器 ID,例如 llvm
  • CC:C 和 C++ 編譯器指令。

    強烈建議您一律搭配使用 CC_FLAGSCC。否則請自行承擔風險。

  • CC_FLAGS:供 genrule 使用的 C/C++ 編譯器最少旗標集。具體來說,如果 CC 支援多個架構,這會包含選取正確架構的標記。
  • DUMPBIN:Microsoft COFF 二進位檔案傾印工具 (dumpbin.exe),位於 Microsoft Visual Studio 中。
  • NM:來自 crosstool 的「nm」指令。
  • OBJCOPY:與 C/C++ 編譯器同一個套件中的 objcopy 指令。
  • STRIP:與 C/C++ 編譯器同一個套件的 strip 指令。

Java 工具鍊變數

以下是在 Java 工具鍊規則中定義的項目,適用於任何設定 toolchains = ["@rules_java//toolchains:current_java_runtime"] 的規則 (或主機工具鍊對應項目 "@rules_java//toolchains:current_host_java_runtime")。

JDK 中的大部分工具都不應直接使用。內建的 Java 規則使用的 Java 編譯和封裝方法,比上游工具可表達的方法複雜許多,例如介面 JAR、標頭介面 JAR,以及經過高度最佳化的 JAR 封裝和合併實作項目。

這些變數是備用機制,語言專家會在極少數情況下使用。如果您想使用這些規則,請先與 Bazel 開發人員聯絡

  • JAVA:「java」指令 (Java 虛擬機器)。請盡量避免這種做法,改用 java_binary 規則。可能是相對路徑。如果必須在叫用 java 前變更目錄,請先擷取工作目錄,再進行變更。
  • JAVABASE:包含 Java 公用程式的基本目錄。可能是相對路徑。其中會有「bin」子目錄。

Starlark 定義的變數

規則和工具鍊編寫者可以傳回 TemplateVariableInfo 提供者,定義完全自訂的變數。然後,任何透過 toolchains 屬性依附這些規則的規則,都可以讀取這些值:

請參閱 Starlark 定義的變數範例