![]() |
B2
擁有一種直譯式的程序語言。b2
中的語句包含規則(程序)定義、規則呼叫、流程控制結構、變數賦值以及其他語言支援。
B2
將其輸入檔案視為以空白分隔的詞彙,但有兩個例外:雙引號 (") 可以括住空白字元以將其嵌入詞彙中,以及規則動作定義中匹配大括號 ({}) 之間的所有內容都被視為單個字串。反斜線 (\) 可以跳脫雙引號或任何單個空白字元。
B2
要求所有詞彙,包括冒號 (:) 和分號 (;),都必須以空白字元(空格、Tab 或換行)圍繞。
B2
關鍵字(在本文件中提及)是保留字,通常必須以雙引號 (") 括起來才能用作任意詞彙,例如變數或目標名稱。
註解以 #
字元開頭,並延伸到該行的結尾。
b2
的基本資料實體是目標。建置目標是要更新的檔案。來源目標是用於更新建置目標的檔案。建置目標和來源目標統稱為檔案目標,並且建置目標通常也是其他建置目標的來源目標。虛擬目標是表示對其他目標的依賴關係的符號,但它們本身並不與任何實際檔案關聯。
檔案目標的識別碼通常是檔案的名稱,可以是絕對路徑、相對於 b2
呼叫目錄的路徑或僅是本地名稱(無目錄)。最常見的情況是最後一種,實際檔案路徑是使用 $(SEARCH)
和 $(LOCATE)
特殊變數綁定的。請參閱下面的SEARCH 和 LOCATE 變數。本地檔名可以選擇性地使用 grist(一個用於確保唯一性的字串值)來限定。識別碼格式為 file(member) 的檔案目標是程式庫成員(通常是 Unix 上的 ar
(1) 封存檔)。
每當目標綁定到檔案系統中的位置時,Boost Jam 都會尋找名為 BINDRULE
的變數(首先在被綁定的目標上,然後在全域模組中)。如果非空,=$(BINDRULE[1])= 會指定一個規則,該規則會使用目標的名稱及其綁定的路徑來呼叫。由 =$(BINDRULE[1])= 指定的規則的簽名應符合以下內容
rule bind-rule ( target : path )
此功能對於正確的標頭檔掃描很有用,因為許多編譯器會先在包含 #include
指令的檔案所在的目錄中搜尋 #include
檔案。$(BINDRULE)
可用於記錄該目錄。
b2
語言的基本實體稱為規則。一個規則由兩個部分組成:程序和動作。程序是由一系列 jam 語句組成,當規則被調用時會執行;動作是在更新規則的建構目標時要執行的作業系統 shell 命令。
規則可以返回值,這些值可以用 "[ 規則 參數 ... ]" 展開成一個列表。規則的值是其最後一個語句的值,但只有以下語句具有值:'if'(所選分支的值)、'switch'(所選情況的值)、set(結果變數的值)和 'return'(其參數的值)。請注意,'return' 並不會實際導致返回,也就是說,除非它是規則主體內執行的最後一個區塊的最後一個語句,否則它是一個無操作指令。
用於定義和調用規則的 b2
語句如下:
定義規則的程序,取代任何先前的定義。
rule rulename { statements }
定義規則的更新動作,取代任何先前的定義。
actions [ modifiers ] rulename { commands }
調用規則。
rulename field1 : field2 : ... : fieldN ;
在目標特定變數的影響下調用規則。
on target rulename field1 : field2 : ... : fieldN ;
用作參數時,會展開為所調用規則的返回值。
[ rulename field1 : field2 : ... : fieldN ] [ on target rulename field1 : field2 : ... : fieldN ]
調用規則時會使用 欄位1 到 欄位N 中的值。它們可以在程序的語句中被引用為 $(1)
到 $(N)
(最多 9 個),並且只有前兩個可以在動作的 命令 中被引用為 $(1)
和 $(2)
。$(<)
和 $(>)
分別與 $(1)
和 $(2)
同義。
規則分為兩類:更新規則(帶動作)和純程序規則(不帶動作)。更新規則將參數 $(1)
和 $(2)
分別視為建構目標和來源,而純程序規則可以接受任意參數。
當調用更新規則時,其更新動作會在執行規則的程序之前添加到与其建構目標 ($(1)
) 相關聯的動作中。之後,為了在更新階段建構目標,命令 會被傳遞到作業系統命令 shell,其中 $(1)
和 $(2)
會被目標名稱的綁定版本取代。請參閱上文的綁定。
規則調用可以透過變數間接進行
$(var) field1 : field2 : ... : fieldN ; on target $(var) field1 : field2 : ... : fieldN ; [ $(var) field1 : field2 : ... : fieldN ] [ on target $(var) field1 : field2 : ... : fieldN ]
變數的值指定要調用的規則(或多個規則)。對於 $(變數)
值列表中的每個元素,都會調用一個規則。欄位 欄位1 : 欄位2 : ...
會作為每個調用的參數傳遞。對於 [ ... ] 形式,返回值是所有調用返回值的串連。
支援以下動作修飾符
actions bind 變數
$(變數)
將會被綁定值取代。
actions existing
$(>)
只包含目前存在的來源目標。
actions ignore
忽略命令的返回狀態。
actions piecemeal
命令會被重複調用,每次使用 $(>)
的一個子集,子集的大小足以容納在此作業系統的命令緩衝區中。
actions quietly
動作不會回顯到標準輸出。
actions together
針對相同建構目標多次調用相同動作的 $(>)
會被合併在一起。
actions updated
$(>)
只包含標記為要更新的來源目標。
您可以描述規則接受的引數,並在規則中透過名稱引用它們。例如,以下程式碼會在控制台中印出「我很抱歉,Dave」
rule report ( pronoun index ? : state : names + ) { local he.suffix she.suffix it.suffix = s ; local I.suffix = m ; local they.suffix you.suffix = re ; ECHO $(pronoun)'$($(pronoun).suffix) $(state), $(names[$(index)]) ; } report I 2 : sorry : Joe Dave Pete ;
形式引數列表(在規則宣告中以「:
」分隔)中的每個名稱都會繫結到對應實際引數的一個元素,除非其後接著以下修飾符之一
符號 |
前述符號的語義 |
---|---|
|
可選 |
|
繫結到零個或多個未繫結的實際引數元素。當 |
|
繫結到一個或多個未繫結的實際引數元素。 |
會檢查實際和形式引數之間的矛盾,這會導致 b2
以錯誤碼退出
### argument error # rule report ( pronoun index ? : state : names + ) # called with: ( I 2 foo : sorry : Joe Dave Pete ) # extra argument foo ### argument error # rule report ( pronoun index ? : state : names + ) # called with: ( I 2 : sorry ) # missing argument names
如果您省略形式引數列表,則如同「經典」Jam 一樣,所有檢查都會被略過。然而,引數列表可以大幅提高規則的可靠性和可讀性,因此強烈建議您在編寫任何新的 Jam 程式碼時使用它們。
B2
擁有一組不斷增長的內建規則,所有這些規則都是沒有更新動作的純程序規則。它們分為三組:第一組構建相依性圖;第二組修改它;第三組只是工具程式規則。
rule DEPENDS ( targets1 * : targets2 * )
建立直接相依性:使每個 targets1 都依賴於每個 targets2。一般來說,如果 targets2 本身被重建或比 targets1 新,則 targets1 將被重建。
rule INCLUDES ( targets1 * : targets2 * )
建立同級相依性:使任何依賴於任何 targets1 的目標也依賴於每個 targets2。這反映了一個原始程式檔包含另一個原始程式檔時產生的相依性:從原始程式檔構建的物件同時依賴於原始程式檔和被包含的原始程式檔,但兩個原始程式檔彼此不依賴。例如
DEPENDS foo.o : foo.c ; INCLUDES foo.c : foo.h ;
在此範例中,「foo.o
」依賴於「foo.c
」和「foo.h
」。
六個規則 ALWAYS
、LEAVES
、NOCARE
、NOTFILE
、NOUPDATE
和 TEMPORARY
修改相依性圖,以便 b2
在其目標繫結階段以不同方式處理目標。請參閱上方的繫結。通常,如果目標遺失、其檔案系統修改時間早於其任何相依項(遞迴)或其任何相依項正在更新,b2
就會更新目標。可以透過呼叫以下規則來更改此基本行為
rule ALWAYS ( targets * )
使 目標 無論是否為最新狀態都會被重建(它們仍然必須在依存圖中)。這用於 `clean` 和 `uninstall` 目標,因為它們沒有依存關係,否則看起來永遠不需要建置。最好將其應用於也是 NOTFILE
目標的目標,但它也可以用於強制更新實際檔案。
rule LEAVES ( targets * )
使每個 目標 只依賴於其葉子來源,而不依賴於任何中間目標。這使得它不受其依存關係更新的影響,因為「葉子」依存關係是指那些沒有自己的依存關係且沒有更新動作的依存關係。這允許目標僅在原始來源檔案更改時才更新。
rule NOCARE ( targets * )
使 b2
忽略找不到也無更新動作來建置的 目標。通常對於此類目標,b2
會發出警告,然後跳過依賴於這些遺失目標的其他目標。Jambase
中的 HdrRule
在標頭檔掃描期間找到的標頭檔名上使用 NOCARE
,以讓 b2
知道包含的檔案可能不存在。例如,如果 #include
位於 #ifdef
中,則包含的檔案實際上可能不存在。
對於具有建置動作的目標:如果其建置動作以非零返回碼退出,則仍會建置依存目標。
rule NOTFILE ( targets * )
將 目標 標記為偽目標而不是真實檔案。不會檢查時間戳記,因此只有在目標的依存關係更新或目標也被標記為 ALWAYS
時,才會執行此類目標上的動作。預設的 b2
目標「all
」是一個偽目標。在 Jambase
中,NOTFILE
用於定義其他幾個方便的偽目標。
rule NOUPDATE ( targets * )
導致忽略 目標 上的時間戳記。這有兩個作用:首先,一旦建立目標,它將永遠不會更新;其次,手動更新目標不會導致其他目標更新。例如,在 Jambase
中,此規則由 MkDir
規則應用於目錄,因為 MkDir
只關心目標目錄是否存在,而不關心它上次更新的時間。
rule TEMPORARY ( targets * )
將 目標 標記為臨時目標,允許在更新了依賴於它們的其他目標之後將其移除。如果缺少 TEMPORARY
目標,b2
會使用目標父項的時間戳記。Jambase
使用 TEMPORARY
標記建置後存檔在程式庫中的目標檔,以便在存檔後可以將其刪除。
rule FAIL_EXPECTED ( targets * )
為了處理預期建置動作會失敗的目標(例如,在測試斷言或編譯時期型別檢查是否正常運作時),Boost Jam 提供了與 NOCARE
等規則風格相同的 FAIL_EXPECTED
規則。在目標更新期間,傳遞給 FAIL_EXPECTED
的建置動作的返回程式碼會被反轉:如果失敗,則相依目標的建置會如同成功般繼續進行。如果成功,則會略過相依目標。
rule RMOLD ( targets * )
當用於建置目標的規則失敗時,B2
會移除磁碟上可能存在的任何目標檔案。然而,預設情況下,相依性建置失敗的目標並不會被移除。RMOLD
規則會在其任何相依性建置失敗時移除其引數。
rule ISFILE ( targets * )
ISFILE
將目標標記為必須是檔案。這會改變 b2
搜尋目標的方式,使其忽略非檔案的檔案系統項目(例如目錄)的相符項目。這可以避免在標頭搜尋路徑中碰巧有名為 exception 的目錄時,#include "exception"
發生相符的情況。
此功能目前尚未完全實作。
ECHO
和 EXIT
這兩個規則是工具程式規則,僅用於 b2
的解析階段。
rule EXIT ( message * : result-value ? )
將 *訊息* 輸出到標準輸出,然後如果沒有提供 *結果值*,則以失敗狀態退出;否則,以提供的 *結果值* 退出。
由於難以區分這些是內建規則還是語言的一部分(例如 "include
"),因此 "Echo
"、"echo
"、"Exit
" 和 "exit
" 也可作為 ECHO
和 EXIT
的別名。
GLOB
規則會執行檔名萬用字元比對。
rule GLOB ( directories * : patterns * : downcase-opt ? )
使用與 switch 陳述式中模式相同的萬用字元。它的呼叫方式是在 "[ ]
" 內作為規則呼叫的引數使用。例如:"FILES = [ GLOB dir1 dir2 : *.c *.h ]
" 會將 FILES
設定為 dir1
和 dir2
中 C 原始程式碼和標頭檔的清單。產生的檔名是包含目錄的完整路徑名稱,但模式僅套用於不含目錄的檔名。
如果提供了 downcase-opt,則檔名會在與模式比對之前轉換為全小寫;您可以使用此選項以小寫模式執行不區分大小寫的比對。如果作業系統提供混合大小寫的路徑,則傳回的路徑仍將保留混合大小寫。在 Windows NT 和 Cygwin 上,檔名在比對之前一律會轉換為小寫。
MATCH
規則執行模式比對。
rule MATCH ( regexps + : list * )
將 egrep
(1) 風格的正規表達式 regexps 與 list 中的字串進行比對。結果是 list 中每個字串以及 regexps 中每個正規表達式的相符 ()
子表達式清單。
rule BACKTRACE ( )
傳回一個四元組清單:filename line module rulename...,描述呼叫堆疊中每個較淺層級。此規則可用於從 Jam 規則產生有用的診斷訊息。
rule UPDATE ( targets * )
傳統的 Jam 將命令列中任何非選項元素視為要更新的目標名稱。這阻礙了對命令列更複雜的處理。現在再次啟用了此功能,但對 UPDATE
規則進行了額外更改,以便靈活地更改要更新的目標清單。UPDATE
規則有兩個作用:
如果沒有使用 UPDATE
規則指定目標,則不會更新任何目標。為了以更有用的方式支援更新清單的更改,該規則還會傳回先前在更新清單中的目標。這樣就可以新增目標,例如:
local previous-updates = [ UPDATE ] ; UPDATE $(previous-updates) a-new-target ;
rule W32_GETREG ( path : data ? )
僅針對 Win32 平台定義。它會讀取 Windows 的登錄。『path』是資訊的位置,而『data』是要取得的值的名稱。如果省略『data』,則會傳回『path』的預設值。『path』值必須符合 MS 金鑰路徑格式,並且必須以其中一個預先定義的根金鑰作為前綴。照常:
HKLM
』等同於『HKEY_LOCAL_MACHINE
』。HKCU
』等同於『HKEY_CURRENT_USER
』。HKCR
』等同於『HKEY_CLASSES_ROOT
』。不支援其他預先定義的根金鑰。
目前支援的資料類型:『REG_DWORD
』、『REG_SZ
』、『REG_EXPAND_SZ
』、『REG_MULTI_SZ
』。類型為『REG_DWORD
』的資料將轉換為字串,『REG_MULTI_SZ
』轉換為字串清單,而類型為『REG_EXPAND_SZ
』的資料中的環境變數將替換為其定義的值。類型為『REG_SZ
』和其他不支援類型的資料將放入字串中而不進行修改。如果無法接收資料的值,則只會傳回一個空清單。例如:
local PSDK-location = [ W32_GETREG HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\MicrosoftSDK\\Directories : "Install Dir" ] ;
rule W32_GETREGNAMES ( path : result-type )
僅適用於 win32 平台。它會讀取 Windows 的登錄檔。「路徑」是資訊的位置,「結果類型」則為「subkeys
」或「values
」。關於「路徑」格式和限制的更多資訊,請參閱 W32_GETREG
。
根據「結果類型」,規則會返回下列其中一項
subkeys
「路徑」所有直接子機碼的名稱。
values
由「路徑」指定的登錄機碼中包含的值的名稱。機碼的「預設」值僅在其值已在登錄檔中設定時才會出現在返回的清單中。
如果無法辨識「結果類型」,或無法擷取要求的資料,則規則會返回空清單。範例
local key = "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\App Paths" ; local subkeys = [ W32_GETREGNAMES "$(key)" : subkeys ] ; for local subkey in $(subkeys) { local values = [ W32_GETREGNAMES "$(key)\\$(subkey)" : values ] ; for local value in $(values) { local data = [ W32_GETREG "$(key)\\$(subkey)" : "$(value)" ] ; ECHO "Registry path: " $(key)\\$(subkey) ":" $(value) "=" $(data) ; } }
rule SHELL ( command : * )
SHELL
會執行 命令,然後返回 命令 的標準輸出。 SHELL
僅適用於 C 函式庫中具有 popen()
函式的平台。在沒有正常運作的 popen()
函式的平台上,SHELL
會實作為無運算指令。 SHELL
適用於 Unix、MacOS X 和大多數 Windows 編譯器。在 Windows 下的 Metrowerks 編譯器上,SHELL
是無運算指令。有一組可變的允許選項作為額外引數
exit-status
除了輸出之外,已執行命令的結果狀態也會作為結果的第二個元素返回。
no-output
不要擷取命令的輸出。而是返回一個空的字串值 ("") 來取代輸出。
由於 Perforce/Jambase 定義了一個會隱藏內建規則的 SHELL
規則,因此在這種情況下,COMMAND
可用作 SHELL
的別名。
rule SPLIT_BY_CHARACTERS ( string : delimiters )
SPLIT_BY_CHARACTERS
會根據 分隔符號 中出現的任何分隔符號字元來分割指定的 字串,並返回結果清單。
rule FILE_OPEN ( filename : mode )
FILE_OPEN
規則會開啟指定的檔案並返回檔案描述元。 模式 參數可以是「w」或「r」。請注意,目前只有 UPDATE_NOW
規則可以使用產生的檔案描述元編號。
rule UPDATE_NOW ( targets * : log ? : ignore-minus-n ? )
如果更新成功,`UPDATE_NOW` 會立即更新指定的目標,並回傳非空字串。如果有 `log` 參數,則指定一個檔案描述符,所有建置輸出都會重新導向到該檔案。如果指定了 `ignore-minus-n` 參數,即使在命令列上指定了 `-n` 參數,目標仍會被更新。
`B2` 有幾個簡單的流程控制語句
for var in list { statements }
針對 `list` 中的每個元素執行 `statements`,並將變數 `var` 設定為元素值。
if cond { statements } [ else { statements } ]
執行顯而易見的操作;`else` 子句是可選的。`cond` 由以下組成:
a
如果任何 `a` 元素是非零長度字串,則為 true
`a` = `b`
列表 `a` 與列表 `b` 的每個字串都相符
`a` != `b`
列表 `a` 與列表 `b` 不相符
`a` < `b`
字串 `a[i]` 小於字串 `b[i]`,其中 `i` 是列表 `a` 和 `b` 中第一個不匹配的元素
`a` <= `b`
每個 `a` 字串都小於或等於其對應的 `b` 字串
`a` > `b`
字串 `a[i]` 大於字串 `b[i]`,其中 `i` 是第一個不匹配的元素
`a` >= `b`
每個 `a` 字串都大於或等於其對應的 `b` 字串
`a` in `b`
如果 `a` 的所有元素都可以在 `b` 中找到,或者如果 `a` 沒有任何元素,則為 true
! `cond`
條件不成立
`cond` && `cond`
邏輯與
`cond` || `cond`
邏輯或
( `cond` )
優先級群組
include file ;
使 `b2` 讀取指定的 `file` 檔案。該 `file` 檔案像一般目標一樣被綁定(參見上面的綁定),但與一般目標不同的是, include `file` 檔案無法被建置。
include `file` 檔案會在解析階段插入到輸入串流中。主要的輸入檔案和所有 include 的檔案都被視為單個檔案;也就是說,`b2` 不會從 include 的檔案中推斷出任何範圍邊界。
local vars [ = values ] ;
在封閉的 {}
區塊內建立新的 變數,並遮蔽它們可能具有的任何先前值。當目前的區塊結束時,變數的先前值會被恢復。任何被呼叫的規則或被包含的檔案都會看到局部值,而不是先前的值(這有時被稱為動態作用域)。local 陳述式可以出現在任何地方,即使在區塊之外(在這種情況下,當輸入結束時,先前的值會被恢復)。如果存在 值,則 變數 會被初始化為這些值,否則保持未初始化。
return values ;
在規則主體中,return 陳述式設定規則呼叫的返回值。它不會導致規則返回;規則的值實際上是執行的最後一個陳述式的值,因此 return 應該是規則「自然」返回之前執行的最後一個陳述式。
switch value { case pattern1 : statements ; case pattern2 : statements ; ... }
switch 陳述式執行零個或一個封閉的 陳述式,取決於哪個(如果有的話)是第一個其 模式 與 值 匹配的 case。 模式 值不會進行變數展開。模式值可以包含以下萬用字元:
?
匹配任何單個字元
*
匹配零個或多個字元
[字元]
匹配 字元 中的任何單個字元
[^字元]
匹配不在 字元 中的任何單個字元
\x
匹配 x(跳脫其他萬用字元)
while cond { statements }
當 條件 在進入時仍然為真時,重複執行 陳述式。(請參閱上方 if 下的 條件 運算式語法說明)。
B2
變數是包含零個或多個元素的列表,每個元素都是一個字串值。未定義的變數與具有空列表的變數無法區分,但是,已定義的變數可能有一個或多個元素為空字串。所有變數都以 $(變數)
的形式引用。
變數可以是全域的,也可以是目標特定的。在後一種情況下,變數僅在更新特定目標期間採用給定值。
變數的定義方式如下:
variable = elements ; variable += elements ; variable on targets = elements ; variable on targets += elements ; variable default = elements ; variable ?= elements ;
前兩種形式設定全域 變數。第三種和第四種形式設定目標特定的變數。=
運算子將 變數 的任何先前元素替換為 元素;+=
運算將 元素 新增到 變數 的元素列表中。最後兩種形式是同義的:它們設定全域 變數,但前提是它先前未設定。
更新指令中引用的變數將被其值替換;目標特定值優先於全域值。作為引數($(1)
和 $(2)
)傳遞給動作的變數將被其繫結值替換;在動作上可以使用「bind
」修飾符,使其他變數被繫結值替換。請參閱上面的動作修飾符。
B2
變數不會重新匯出到執行更新動作的 shell 環境中,但更新動作可以透過 $(variable)
參考 b2
變數。
在解析過程中,b2
會對每個不是關鍵字或規則名稱的詞彙執行變數展開。這種嵌入了變數參考的詞彙會被零個或多個詞彙取代。變數參考的格式為 $(v)
或 $(vm)
,其中 v 是變數名稱,m 是可選的修飾符。
規則動作中的變數展開與陳述式中的變數展開類似,不同之處在於動作字串會在空格處進行詞彙化,而不管引號為何。
變數展開後詞彙的結果是詞彙組成部分的「乘積」,其中每個組成部分是一個字面上的子字串或是一個替換變數參考的列表。例如:
$(X) -> a b c t$(X) -> ta tb tc $(X)z -> az bz cz $(X)-$(X) -> a-a a-b a-c b-a b-b b-c c-a c-b c-c
變數名稱和修飾符本身可以包含變數參考,這也參與乘積運算。
$(X) -> a b c $(Y) -> 1 2 $(Z) -> X Y $($(Z)) -> a b c 1 2
由於這種乘積展開,如果詞彙中的任何變數參考未定義,則展開的結果是一個空列表。如果任何變數元素是空字串,則結果會傳播非空元素。
$(X) -> a "" $(Y) -> "" 1 $(Z) -> -$(X)$(Y)- -> -a- -a1- -- -1- -$(X)$(Z)- ->
變數元素的字串值可以被解析為 grist 和與檔名相關的組成部分。變數的修飾符用於選擇元素、選擇組成部分和替換組成部分。修飾符如下:
[n]
選擇編號為 n 的元素(從 1 開始)。如果變數包含的元素少於 n 個,則結果是一個零元素列表。n 可以是負數,在這種情況下,會返回從最後一個元素向左數的第 n 個元素。
[n-m]
選擇編號從 n 到 m 的元素。n 和 m 可以是負數,在這種情況下,它們指的是從最後一個元素向左數的元素。
[n-]
選擇從編號 n 到最後一個的元素。n 可以是負數,在這種情況下,它指的是從最後一個元素向左數的元素。
:B
選擇檔名基底(不含副檔名)。
:S
選擇(最後一個)檔名字尾(副檔名)。
:M
選擇壓縮檔成員名稱。
:D
選擇目錄路徑。
:P
選擇父目錄。
:G
選擇 grist(額外資訊,用於區分不同版本的檔案)。
:U
將小寫字母替換為大寫字母。
:L
將大寫字母替換為小寫字母。
:T
將所有反斜線 ("\") 轉換為正斜線 ("/")。例如:
x = "C:\\Program Files\\Borland" ; ECHO $(x:T) ;
會印出 "C:/Program Files/Borland"
:W
從 Cygwin 呼叫基於 Windows 的工具時,傳遞真正的 Windows 樣式路徑可能很重要。:W
修飾符,**僅限在 Cygwin 下**,使用 cygwin_conv_to_win32_path
函式將 cygwin 路徑轉換為 Win32 路徑。在其他平台上,字串保持不變。例如:
x = "/cygdrive/c/Program Files/Borland" ; ECHO $(x:W) ;
在 Cygwin 上會印出 "C:\Program Files\Borland"
:chars
選擇 chars 中列出的組成部分。
:G=grist
以 grist 取代 grist。
:D=path
以 path 取代目錄。
:B=base
以 base 取代檔案名的基本部分。
:S=suf
以 suf 取代檔案名的副檔名。
:M=mem
以 mem 取代壓縮檔成員名稱。
:R=root
如果尚未設定根目錄,則在整個檔案名前加上 root。
:E=value
如果變數未設定,則將 value 指派給該變數。
:J=joinval
將清單元素串連成單個元素,以 joinval 分隔。
在 VMS 上,$(var:P)
是 $(var:D)
的父目錄。
Boost Jam 允許您在迴圈中直接宣告迴圈控制的區域變數
x = 1 2 3 ;
y = 4 5 6 ;
for local y in $(x)
{
ECHO $(y) ; # prints "1", "2", or "3"
}
ECHO $(y) ; # prints "4 5 6"
在展開表達式期間,b2
也會尋找格式為 =@(filename:Efilecontents)
的子表達式,並在使用設定為 filecontents
的內容建立指定檔案後,以 filename
取代該表達式。這對於建立編譯器回應檔案和其他「內部」檔案很有用。展開在解析和動作執行期間都有效。因此,可以在三個建置階段中的任何一個階段建立檔案。
本節討論對 b2
具有特殊意義的變數。所有這些變數都必須在全域模組中定義或使用——在具名模組內使用這些變數將不會產生預期的效果。請參閱 模組。
這兩個變數控制檔案目標名稱與檔案系統中位置的繫結。一般來說,$(SEARCH)
用於尋找現有的原始碼,而 $(LOCATE)
用於修復建置目標的位置。
已設定根目錄(絕對路徑)的檔案目標會照原樣繫結。未設定根目錄的檔案目標名稱通常也照原樣繫結,因此是相對於目前目錄,但 $(LOCATE)
和 $(SEARCH)
的設定會改變這一點
$(LOCATE)
,則目標會相對於 $(LOCATE)
中的第一個目錄進行繫結。只有第一個元素用於繫結。$(SEARCH)
,則目標會繫結到 $(SEARCH)
中目標檔案已存在的第一個目錄。$(SEARCH)
搜尋失敗,則目標仍然會相對於目前目錄進行繫結。$(SEARCH)
和 $(LOCATE)
都應該針對目標設定,而不是全域設定。如果它們被設定為全域,b2
將會對所有檔案繫結使用相同的路徑,這不太可能產生合理的結果。當您編寫自己的規則時,尤其是那些不是基於 Jambase 的規則,您可能需要直接設定 $(SEARCH)
或 $(LOCATE)
。幾乎所有在 Jambase 中定義的規則都會將 $(SEARCH)
和 $(LOCATE)
分別設定為它們正在尋找的來源和它們建立的目標的合理值。
這兩個變數控制標頭檔掃描。$(HDRSCAN)
是一個 egrep(1)
模式,用 () 包圍檔名,用於在原始程式檔中尋找檔案包含語句。Jambase 使用 $(HDRPATTERN)
作為 $(HDRSCAN)
的模式。$(HDRRULE)
是要使用掃描結果呼叫的規則的名稱:掃描的檔案是目標,找到的檔案是來源。這是 b2
透過變數設定呼叫規則的唯一地方。
要執行標頭檔掃描,$(HDRSCAN)
和 $(HDRRULE)
都必須設定,而且它們應該針對目標設定,而不是全域設定。如果它們被設定為全域,則所有檔案(包括可執行檔和程式庫)都會被掃描標頭檔包含語句。
標頭檔包含的掃描並不精確,但至少是動態的,因此不需要執行類似 makedepend(GNU)
的程式來建立靜態依存關係檔案。掃描機制傾向於包含(也就是說,它更有可能返回編譯器實際上沒有使用的檔名,而不是遺漏包含檔案),因為它無法判斷 #include
行是否在 #ifdefs
或其他條件邏輯內。在 Jambase
中,HdrRule
將 NOCARE
規則應用於掃描期間找到的每個標頭檔,這樣如果檔案不存在也不會導致編譯失敗,b2
就不会在意。
此外,正規表示式的掃描僅適用於包含的檔名實際上在原始程式檔中的情況。它無法處理允許使用變數名稱包含檔案的語言(就像 Jam
語言本身一樣)。
有時需要禁止某些動作的平行執行。例如:
Craig McPeeters 擴展了 Perforce Jam 來解決此類問題,並且該擴展已整合到 Boost.Jam 中。
可以透過在目標上設定名為 SEMAPHORE
的變數,為任何目標分配一個信號量。變數的值是信號量名稱。它必須與任何已宣告目標的名稱不同,但在其他方面是任意的。
信號量的語義是,在一組具有相同信號量的目標中,無論「-j
」選項如何,一次只能更新一個目標。
一些 Jam 內建變數可用於識別執行時期平台
OS
作業系統識別字串
OSPLAT
底層架構(如果適用)
MAC
在 MAC 平台上為 true
NT
在 NT 平台上為 true
OS2
在 OS2 平台上為 true
UNIX
在 Unix 平台上為 true
VMS
在 VMS 平台上為 true
JAMDATE
b2
啟動時的日期和時間,以 ISO-8601 UTC 值表示。
JAMUNAME
uname(1) 指令的輸出(僅限 Unix)
JAMVERSION
b2
版本,目前為「3.1.19」
JAM_VERSION
一個預先定義的全局變數,包含兩個元素,表示 Boost Jam 的版本號。Boost Jam 版本從「03
」「00
」開始。早期版本的 Jam
不會自動定義 JAM_VERSION
。
當 b2
執行規則的動作區塊時,它會 fork 並執行 shell,將動作區塊作為參數傳遞給 shell。Shell 的呼叫可以由 $(JAMSHELL)
控制。例如,Unix 上的預設值為
JAMSHELL = /bin/sh -c % ;
%
會被動作區塊的文字取代。
B2
不直接支援跨多個主機的平行建置,因為這很大程度上取決於本機環境。要跨多個主機平行建置,您需要編寫自己的 shell 來提供對多個主機的存取。然後您需要重新設定 $(JAMSHELL)
以參考它。
就像 b2
將 %
展開為規則的動作區塊的文字一樣,它會將 !
展開為多程序的槽號。槽號在 1 到命令列上 -j
旗標允許的並行作業數之間變化。有了這個,就可以編寫一個多主機 shell。例如
#!/bin/sh # This sample JAMSHELL uses the SunOS on(1) command to execute a # command string with an identical environment on another host. # Set JAMSHELL = jamshell ! % # # where jamshell is the name of this shell file. # # This version handles up to -j6; after that they get executed # locally. case $1 in 1|4) on winken sh -c "$2";; 2|5) on blinken sh -c "$2";; 3|6) on nod sh -c "$2";; *) eval "$2";; esac
可以將 __TIMING_RULE__
和 __ACTION_RULE__
設定為規則的名稱,以便 b2
在目標的動作完成**後**呼叫。它們都提供有關已完成動作的診斷資訊。對於 __TIMING_RULE__
,規則的呼叫方式如下
rule timing-rule ( args * : target : start end user system )
而 __ACTION_RULE__
的呼叫方式如下
rule action-rule ( args * : target : command status start end user system : output ? )
兩者的參數皆為
args
__TIMING_RULE__
或 __ACTION_RULE__
中規則名稱後面的任何值都會在此處傳遞。
target
已建置的 b2
目標。
command
動作主體中執行的指令的文字。
status
已執行指令的整數結果。
start
已執行指令的起始時間戳記,以 ISO-8601 UTC 值表示。
end
已執行指令的完成時間戳記,以 ISO-8601 UTC 值表示。
使用者 (user)
已執行指令所耗用的使用者 CPU 秒數,以浮點數表示。
系統 (system)
已執行指令所耗用的系統 CPU 秒數,以浮點數表示。
輸出 (output)
指令的輸出,以單一字串表示。輸出內容反映了 -pX
選項的使用。
如果目標同時設定了兩個變數,則兩者都會被呼叫,先呼叫 __TIMING_RULE__
,然後呼叫 __ACTION_RULE__
。
Boost Jam 引進了對模組的支援,為規則和變數提供了一些基本的命名空間保護。同時也引進了一個新的關鍵字「module
」。本節描述的功能是基本功能,意味著它們旨在提供編寫 Jam 規則所需的操作,以提供更優雅的模組介面。
module expression { ... }
{ ... }
內的程式碼會在由評估運算式命名的模組內執行。規則定義可以在模組自身的命名空間中找到,也可以在全域模組的命名空間中以 *模組名稱*.規則名稱 的形式找到,因此在模組內,該模組中的其他規則可以始終在不需限定的情況下被呼叫。
module my_module { rule salute ( x ) { ECHO $(x), world ; } rule greet ( ) { salute hello ; } greet ; } my_module.salute goodbye ;
當在目前模組的命名空間中找不到被呼叫的規則時,會在全域模組的命名空間中查找,因此跨模組的限定呼叫可以正常運作。
module your_module
{
rule bedtime ( ) { my_module.salute goodnight ; }
}
每個模組都有自己的一組動態巢狀變數範圍。當執行從模組 A 傳遞到模組 B 時,所有來自 A 的變數繫結都將失效,並由屬於 B 的繫結取代。這同樣適用於區域變數和全域變數。
module A { x = 1 ; rule f ( ) { local y = 999 ; # becomes visible again when B.f calls A.g B.f ; } rule g ( ) { ECHO $(y) ; # prints "999" } } module B { y = 2 ; rule f ( ) { ECHO $(y) ; # always prints "2" A.g ; } }
存取其他模組變數的唯一方法是進入該模組。
rule peek ( module-name ? : variables + ) { module $(module-name) { return $($(>)) ; } }
請注意,由於現有的變數繫結會在每次進入新的模組範圍時發生變化,因此參數繫結將失效。這就解釋了上述 peek 規則中使用「$(>)
」的原因。
local rule rulename...
該規則在目前模組中區域宣告。它不會以限定名稱的形式輸入到全域模組中,且其名稱不會出現在以下結果中:
[ RULENAMES module-name ]
rule VARNAMES ( module ? )
傳回指定模組中所有變數繫結的名稱清單。如果省略 模組,則傳回全域模組中所有變數繫結的名稱。
這包括在呼叫 VARNAMES
時尚未返回的呼叫堆疊中任何規則的區域變數。
IMPORT
允許跨模組的規則名稱別名。
rule IMPORT ( source_module ? : source_rules * : target_module ? : target_rules * )
IMPORT
規則會將規則從來源模組 (source_module)複製到目標模組 (target_module) 作為本地規則。如果來源模組或目標模組未提供,則指的是全域模組。來源規則 (source_rules)指定要從來源模組匯入哪些規則;目標規則 (target_rules)指定在目標模組中賦予這些規則的名稱。如果來源規則包含來源模組中不存在的規則名稱,或者它包含的項目數量與目標規則不同,則會發出錯誤。例如:
# import m1.rule1 into m2 as local rule m1-rule1. IMPORT m1 : rule1 : m2 : m1-rule1 ; # import all non-local rules from m1 into m2 IMPORT m1 : [ RULENAMES m1 ] : m2 : [ RULENAMES m1 ] ;
EXPORT
允許跨模組的規則名稱別名。
rule EXPORT ( module ? : rules * )
EXPORT
規則將來源模組 (source_module)
中的規則 (rules)標記為非本地規則(因此可以匯出)。如果規則的元素未在模組 (module) 中命名規則,則會發出錯誤。例如:
module X { local rule r { ECHO X.r ; } } IMPORT X : r : : r ; # error - r is local in X EXPORT X : r ; IMPORT X : r : : r ; # OK.
rule CALLER_MODULE ( levels ? )
CALLER_MODULE
會傳回包含呼叫其呼叫者的模組範圍的名稱(如果提供了 levels 參數,則將其解釋為要遍歷呼叫堆疊的額外層級的整數,以找到模組)。如果範圍屬於全域模組,或者如果不存在此類模組,則傳回空清單。例如,以下程式碼會印出「{Y} {X}」
module X { rule get-caller { return [ CALLER_MODULE ] ; } rule get-caller's-caller { return [ CALLER_MODULE 1 ] ; } rule call-Y { return Y.call-X2 ; } } module Y { rule call-X { return X.get-caller ; } rule call-X2 { return X.get-caller's-caller ; } } callers = [ X.get-caller ] [ Y.call-X ] [ X.call-Y ] ; ECHO {$(callers)} ;
rule DELETE_MODULE ( module ? )
DELETE_MODULE
會從指定的模組(或全域模組,如果未提供模組)中移除所有變數繫結和其他未被參考的規則,並將其記憶體釋放回系統。
雖然它不會影響目前正在執行的規則,直到它們完成,但使用 DELETE_MODULE
時應格外小心,因為它會立即清除任何其他規則和所有變數(包括該模組中的區域變數)。由於動態繫結的工作方式,被區域變數遮蔽的變數將不會被銷毀,因此結果可能非常難以預測。