建立變數

回報問題 {14. {14. 回報問題 /3 {/13 {14.

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

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

Bazel 會提供「預先定義的」變數和「自訂」變數;這些變數是在依附元件目標中定義,且僅供依附於這些變數的目標使用。

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

使用

標示為 "Subject to 'Make variant' substitution" 的屬性可參照「Make」變數 FOO,如下所示:

my_attr = "prefix $(FOO) suffix"

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

my_attr = "prefix bar suffix"

如果 FOO 不符合消耗目標的已知變數,Bazel 就會失敗並顯示錯誤。

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

my_attr = "prefix $@ suffix"

如要將 $ 寫入為字串常值 (也就是為避免變數展開),請編寫 $$

預先定義的變數

任何目標中標示為「Subject to 'Make variant' substitution」的任何屬性都能參照預先定義的「Make」變數。

如要查看這些變數的清單和特定建構選項集的值,請執行

bazel info --show_make_env [build options]

然後查看最有大寫字母的輸出行。

查看預先定義變數的範例

工具鍊選項變數

  • COMPILATION_MODEfastbuilddbgopt。(瞭解詳情)

路徑變數

  • BINDIR:針對目標架構產生的二進位樹狀結構。

    請注意,在主機架構中執行的程式可能會使用不同的樹狀結構,以便支援跨平台程式碼編譯。

    如果您想從 genrule 內執行工具,建議取得路徑為 $(execpath toolname),其中 toolname 必須列於 genruletools 屬性中。

  • GENDIR:針對目標架構產生的程式碼樹狀結構基礎。

機器架構變數

  • TARGET_CPU:目標架構的 CPU,例如 k8

預先定義的 Genrule 變數

以下內容特別適用於 genrulecmd 屬性,在使該屬性正常運作的情況下,通常十分重要。

查看預先定義的 Genrule 變數範例

  • OUTSgenruleouts 清單。如果只有一個輸出檔案,也可以使用 $@
  • SRCSgenrulesrcs 清單 (或更精確來說:與 srcs 清單中標籤相對應的檔案路徑名稱)。如果只有一個來源檔案,則也可以使用 $<
  • <SRCS (如果是單一檔案)。否則會觸發建構錯誤。
  • @OUTS (如果是單一檔案)。否則會觸發建構錯誤。
  • RULEDIR:目標的輸出目錄,也就是與 genfilesbin 樹狀結構下含有目標的套件名稱相對應的目錄。如果是 //my/pkg:my_genrule,即使 //my/pkg:my_genrule 的輸出內容位於子目錄,也一律會以 my/pkg 結尾。

  • @D:輸出目錄。如果 outs 有一個項目,則會展開為包含該檔案的目錄。如果有多個項目,這會在 genfiles 樹狀結構中展開為套件的根目錄,即使所有輸出檔案都位於同一個子目錄中

    注意:請使用 RULEDIR 而非 @D,因為 RULEDIR 的語意較簡單,且無論輸出檔案數量為何,行為都相同。

    如果 genrule 需要產生暫存中繼檔案 (或許是因為使用一些其他工具 (例如編譯器) 所致),則應嘗試將檔案寫入 @D (雖然 /tmp 也可以寫入),並在完成前將其移除。

    特別要避免寫入包含輸入內容的目錄。這些檔案可能位於唯讀檔案系統中。即使沒有執行這項操作,來源樹狀結構仍會移至垃圾桶。

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

預先定義的變數 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。因此 exec 路徑是 bazel-out/cpu-opt-exec-hash/bin/testapp/app。這個額外的前置字串可讓您建構相同的目標 (例如同一個建構中的兩個不同的 CPU),而不會互相衝突。

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

  • rootpath:代表已建構二進位檔在執行階段尋找依附元件時,可以使用的路徑是相對於主要存放區的執行檔案目錄子目錄。注意:只有在啟用 --enable_runfiles 時才能使用這種做法,在 Windows 上並非預設情況。如需跨平台支援,請改用 rlocationpath

    這與 execpath 類似,但會移除上述設定前置字串。在上述範例中,這表示 empty.sourceapp 都使用純工作區相關路徑:testapp/empty.sourcetestapp/app

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

    這與 execpath 有相同的「僅限一項輸出」規定。

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

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

    外部存放區 repo 中檔案的 rlocationpath 開頭是 repo/,後面接著存放區相關路徑。

    如要在執行階段尋找依附元件,建議使用執行檔案程式庫,將此路徑傳遞至二進位檔,並使用執行檔案程式庫解析為檔案系統路徑。與 rootpath 相比,後者可以在所有平台上運作,甚至在沒有執行檔案目錄的情況下也能正常運作。

    這與 execpath 有相同的「僅限一項輸出」規定。

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

execpathsrootpathsrlocationpathslocationsexecpathrootpathrlocationpathslocation 的複數形式。這類查詢支援產生多個輸出內容的標籤,在這種情況下,每項輸出內容會以空格分隔。零輸出規則和格式錯誤的標籤會產生建構錯誤。

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

標籤不一定要採用標準格式,例如 foo:foo//somepkg:foo 皆可。

自訂變數

標示為「Subject to 'Make variant' substitution」的任何屬性皆可參照自訂「Make」變數,但這類變數僅限取決於定義這些變數的其他目標。

最佳做法是所有變數都應自訂,除非有充分理由將變數放入核心 Bazel 中。這樣 Bazel 就不必載入可能耗用大量資源的依附元件,進而提供使用 TAR 可能並不在乎的變數。

C++ 工具鍊變數

這是在 C++ 工具鍊規則中定義,適用於設定 toolchains = ["@bazel_tools//tools/cpp:current_cc_toolchain"] 部分規則 (例如 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 支援多個架構,這包含用來選取正確架構的旗標。
  • NM:Crosstool 的「nm」指令。
  • OBJCOPY:來自與 C/C++ 編譯器相同套件的 objcopy 指令。
  • STRIP:來自 C/C++ 編譯器相同套件的移除指令。

Java 工具鍊變數

以下是 Java 工具鍊規則中的定義,凡是設定 toolchains = ["@bazel_tools//tools/jdk:current_java_runtime"] (或對應主機工具鍊對等項目的 "@bazel_tools//tools/jdk:current_host_java_runtime") 的規則都可以使用。

JDK 中的大部分工具不應直接使用。與上游工具相比,內建 Java 規則使用更複雜的 Java 編譯和封裝方法,例如介面 Jars、標頭介面 Jars,以及高度最佳化的 Jar 封裝和合併實作。

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

  • JAVA:「java」指令 (Java 虛擬機器)。請避免這種情況,並盡可能使用 java_binary 規則。可以是相對路徑。如果您在叫用 java 前變更目錄,就必須先擷取工作目錄,才能變更目錄。
  • JAVABASE:包含 Java 公用程式的基本目錄。可以是相對路徑。檔案會有一個「bin」子目錄。

Starlark 定義的變數

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

查看 Starlark 定義變數範例