建立變數

回報問題 查看來源 Nightly · 8.4 · 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 會因錯誤而失敗。

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

my_attr = "prefix $@ suffix"

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

預先定義的變數

任何標示為「Subject to 'Make variable' substitution」(須遵守「建立變數」替代規則) 的屬性,都可以參照預先定義的「建立」變數。

如要查看特定建構選項組合的變數清單及其值,請執行

bazel info --show_make_env [build options]

並查看以大寫字母開頭的輸出行。

查看預先定義變數的範例

工具鍊選項變數

路徑變數

  • 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/pkg:my_genrule 的輸出內容位於子目錄中也一樣。

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

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

    如果 genrule 需要產生臨時中繼檔案 (可能是使用編譯器等其他工具的結果),則應嘗試將這些檔案寫入 @D (雖然 /tmp 也可寫入),並在完成前移除這些檔案。

    請特別避免寫入含有輸入內容的目錄。這些檔案可能位於唯讀檔案系統中。即使不是,這麼做也會將來源樹狀結構丟到垃圾桶。

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

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

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

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

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

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

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

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

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

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

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

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

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

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

自訂變數

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

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

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:供 genrule 使用的 C/C++ 編譯器最少旗標集。具體來說,如果 CC 支援多個架構,這會包含選取正確架構的標記。
  • NM:來自 crosstool 的「nm」指令。
  • OBJCOPY:與 C/C++ 編譯器同套件的 objcopy 指令。
  • STRIP:與 C/C++ 編譯器同套件的 strip 指令。

Java 工具鍊變數

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

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

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

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

Starlark 定義的變數

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

請參閱 Starlark 定義的變數範例