建立變數

回報問題 查看原始碼 Nightly · 8.0 7.4 . 7.3 · 7.2 · 7.1 · 7.0 · 6.5

「Make」變數是可展開的字串變數特殊類別,可用於標示為「Subject to 'Make variable' substitution」的屬性。

例如,您可以使用這些路徑,將特定工具鍊路徑插入使用者建構的建構動作。

Bazel 提供預先定義變數,可供所有目標使用,也提供自訂變數,可在依附元件目標中定義,且僅供依附元件目標使用。

之所以使用「Make」一詞,是因為這個詞彙源自歷史:這些變數的語法和語意原本是為了與 GNU Make 相符。

使用

標示為「Subject to 'Make variable' substitution」的屬性可參照「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:表示 Bazel 執行建構動作的 execroot 底下的路徑。

    在上例中,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

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

    這項要求與 execpath 的「僅限一個輸出項目」相同。

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

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

    外部存放區 repo 中檔案的 rlocationpath 會以 repo/ 開頭,後面接著存放區相對於路徑。

    將這個路徑傳遞至二進位檔,並使用 runfiles 程式庫將其解析為檔案系統路徑,是執行階段尋找依附元件的首選方法。與 rootpath 相比,這個方法的優點是可在所有平台上運作,即使無法使用 runfiles 目錄也沒問題。

    這項要求與 execpath 的「僅限一個輸出項目」相同。

  • locationexecpathrootpath 的同義詞,視展開的屬性而定。這是 Starlark 推出前的舊版行為,除非您確實知道這項行為對特定規則的影響,否則不建議使用。詳情請參閱 #2475

execpathsrootpathsrlocationpathslocations 分別是 execpathrootpathrlocationpathlocation 的複數變化版本。它們支援產生多個輸出的標籤,在這種情況下,每個輸出項目會以空格分隔列出。零輸出規則和格式錯誤的標籤會產生建構錯誤。

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

標籤不必採用標準格式:foo:foo//somepkg:foo 都沒問題。

自訂變數

自訂「Make」變數可由任何標示為「Subject to 'Make variable' substitution」的屬性參照,但僅限於依賴定義這些變數的其他目標。

最佳做法是,除非有非常充分的理由將變數納入核心 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:一組最少的標記,可讓 C/C++ 編譯器供 genrules 使用。具體來說,如果 CC 支援多個架構,這個值會包含旗標,用於選取正確的架構。
  • DUMPBIN:Microsoft Visual Studio 中的 Microsoft COFF 二進位檔轉儲程式 (dumpbin.exe)。
  • NM:crosstool 中的「nm」指令。
  • OBJCOPY:與 C/C++ 編譯器相同套件的 objcopy 指令。
  • STRIP:與 C/C++ 編譯器相同套件的去除指令。

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 定義變數的範例