2. 安裝
若要從 GitHub 提供的官方版本安裝 B2,請按照下列步驟操作:
-
解壓縮版本。在命令列中,前往解壓縮樹狀結構的根目錄。
-
執行
.\bootstrap.bat
(在 Windows 上)或./bootstrap.sh
(在其他作業系統上)。 -
執行
$ ./b2 install --prefix=PREFIX
其中 PREFIX 是您要安裝 B2 的目錄。
-
選擇性地將
PREFIX/bin
新增至您的 PATH 環境變數。
$ PREFIX/bin/b2
應該會建置一個簡單的可執行檔。
ℹ
|
需要具備 C++11 功能的編譯器才能建置 b2 引擎。但是使用 b2 引擎和建置系統不需要 C++11。 |
3. 教學
本節將引導您了解 B2 的最基本功能。我們將從「Hello, world」範例開始,學習如何使用函式庫,並以測試和安裝功能結束。
3.1. Hello, world
B2 可以建構的最簡單專案儲存在 example/hello/
目錄中。該專案由一個名為 Jamfile
的檔案描述,其中包含
exe hello : hello.cpp ;
即使是這種簡單的設定,您也可以做一些有趣的事情。首先,只要呼叫 b2
就會藉由編譯和連結 hello.cpp
來建置 hello
可執行檔。預設情況下,會建置除錯變體。現在,若要建置 hello
的發行變體,請呼叫
b2 release
請注意,除錯和發行變體是在不同的目錄中建立的,因此您可以在變體之間切換,甚至同時建置多個變體,而無需任何不必要的重新編譯。讓我們在專案的 Jamfile
中新增另一行來擴充範例
exe hello2 : hello.cpp ;
現在讓我們再次建置專案的除錯和發行變體
b2 debug release
請注意,已連結 hello2
的兩個變體。由於我們已經建置了 hello
的兩個變體,因此不會重新編譯 hello.cpp;相反地,現有的物件檔案只會連結到 hello2
的對應變體中。現在讓我們移除所有已建置的產品
b2 --clean debug release
也可以建置或清除特定目標。以下兩個命令分別只會建置或清除 hello2
的除錯版本。
b2 hello2
b2 --clean hello2
3.2. 屬性
為了表示目標組態的各個方面,例如除錯和發行變體,或可移植的單執行緒和多執行緒建置,B2 使用具有相關值的功能。例如,debug-symbols
功能可以具有 on
或 off
的值。屬性只是一個(功能、值)配對。當使用者啟動建置時,B2 會自動將要求的屬性轉譯為適當的命令列旗標,以呼叫編譯器和連結器等工具集元件。
可以組合許多內建功能來產生任意建置組態。以下命令會建置專案的 release
變體,並停用內嵌並啟用除錯符號
b2 release inlining=off debug-symbols=on
命令列上的屬性會以語法指定
feature-name=feature-value
我們在 b2
呼叫中看到的 release
和 debug
只是指定 variant
功能值的簡寫方式。例如,上面的命令也可以這樣寫
b2 variant=release inlining=off debug-symbols=on
variant
是如此常用,以至於它被賦予了特殊狀態,作為隱含功能 — B2 只會從其值的其中一個名稱推斷其身分。
功能的完整描述可以在名為「功能與屬性」的章節中找到。
3.2.1. 建置要求和目標需求
在命令列上指定的一組屬性構成建置要求—對建置所要求目標(或,如果未明確要求目標,則為目前目錄中的專案)的所需屬性的描述。用於建置目標的實際屬性通常是建置要求和衍生自專案 Jamfile
(及其其他 Jamfile,如名為「專案階層」的章節中所述)的屬性的組合。例如,#include
的標頭檔位置通常不會在命令列上指定,而是在 Jamfile 中描述為目標需求,並自動與這些目標的建置要求合併。多執行緒編譯是另一個典型的目標需求範例。下面的 Jamfile 片段說明了如何指定這些需求。
exe hello
: hello.cpp
: <include>boost <threading>multi
;
建置 hello
時,以上指定的兩個需求將始終存在。如果 b2
命令列上給出的建置要求與目標需求明確衝突,則目標需求通常會覆寫(或,對於像 <include>
這樣的「自由」功能,[1] 擴充)建置要求。
☀
|
<include> 功能的值相對於使用它的 Jamfile 的位置。 |
3.3. 專案階層
到目前為止,我們只考慮了一個專案的範例,其中包含一個使用者撰寫的 Jamfile
檔案。典型的較大程式碼庫將由組織成樹狀結構的許多專案組成。樹狀結構的頂端稱為專案根目錄。每個子專案都由專案根目錄的後代目錄中名為 Jamfile
的檔案定義。子專案的父專案由祖先目錄中最近的 Jamfile 檔案定義。例如,在下列目錄配置中
top/ | +-- Jamfile | +-- app/ | | | +-- Jamfile | `-- app.cpp | `-- util/ | +-- foo/ . | . +-- Jamfile . `-- bar.cpp
專案根目錄為 top/
。top/app/
和 top/util/foo/
中的專案是根專案的直接子專案。
ℹ
|
當我們提到以正常字型設定的「Jamfile」時,表示名為 Jamfile 或 Jamroot 的檔案。當我們需要更明確時,檔名將設定為「Jamfile 」或「Jamroot 」。 |
專案會從其父專案繼承所有屬性(例如需求)。繼承的需求會與子專案指定的任何需求合併。例如,如果 top/Jamfile
具有
<include>/home/ghost/local
在命令列上未明確指定任何目標的情況下呼叫 b2
會建置根目錄中的專案。建置專案並不會自動建置其子專案,除非父專案的 Jamfile 明確要求這樣做。在我們的範例中,top/Jamfile
可能包含
build-project app ;
這會在建置 top/
中的專案時,同時建置 top/app/
中的專案。然而,只有在 top/
或 top/app/
中的目標需要時,才會建置 top/util/foo/
中的目標。
3.4. 相依目標
當建置目標 X
時,如果需要先建置另一個目標 Y
(例如必須與 X 連結的程式庫),則 Y
稱為 X
的相依性,而 X
則稱為 Y
的相依者。
為了了解目標相依性,讓我們繼續上面的範例,看看 top/app/Jamfile
如何使用 top/util/foo
中的程式庫。如果 top/util/foo/Jamfile
包含
lib bar : bar.cpp ;
那麼要在 top/app/Jamfile
中使用此程式庫,我們可以寫入
exe app : app.cpp ../util/foo//bar ;
雖然 app.cpp
參照的是一般的原始碼檔案,但 ../util/foo//bar
參照的是另一個目標:在 ../util/foo
的 Jamfile 中宣告的程式庫 bar
。
☀
|
某些其他建置系統具有特殊的語法來列出相依程式庫,例如 LIBS 變數。在 B2 中,您只需將程式庫新增至來源清單即可。 |
假設我們使用以下方式建置 app
b2 app optimization=full define=USE_ASM
哪些屬性會用於建置 foo
?答案是某些特性會被傳播 — B2 會嘗試使用具有相同傳播特性值的相依性。<optimization>
特性會被傳播,因此 app
和 foo
都會以完全最佳化進行編譯。但是 <define>
不會被傳播:它的值會按原樣新增至 a.cpp
的編譯器標誌,但不會影響 foo
。
讓我們進一步改進這個專案。程式庫可能有一些標頭檔,必須在編譯 app.cpp
時使用。我們可以手動將必要的 #include
路徑新增至 app
需求中作為 <include>
特性的值,但這樣所有使用 foo
的程式都會重複這項工作。更好的解決方案是以這種方式修改 util/foo/Jamfile
project
: usage-requirements <include>.
;
lib foo : foo.cpp ;
使用需求不會套用至正在宣告的目標,而是套用至其相依者。在此範例中,<include>.
將套用至所有直接相依於 foo
的目標。
另一個改進是使用符號識別碼來參照程式庫,而不是 Jamfile
的位置。在大型專案中,一個程式庫可以被許多目標使用,如果它們都使用 Jamfile
的位置,則目錄組織的變更會帶來許多工作。解決方案是使用專案 ID — 未與目錄配置關聯的符號名稱。首先,我們需要透過將以下程式碼新增至 Jamfile
來指派專案 ID
use-project /library-example/foo : util/foo ;
其次,我們修改 app/Jamfile
以使用專案 ID
exe app : app.cpp /library-example/foo//bar ;
/library-example/foo//bar
語法用於參照 ID 為 /library-example/foo
的專案中的目標 bar
。我們已經實現了目標 — 如果程式庫移動到不同的目錄,則只需要修改 top/Jamfile
。請注意,專案 ID 是全域的 — 不允許兩個 Jamfile 將相同的專案 ID 指派給不同的目錄。
☀
|
如果您希望某個專案中的所有應用程式都連結到特定的程式庫,則可以避免透過使用
|
3.5. 靜態和共享程式庫
程式庫可以是靜態的,這表示它們包含在使用它們的可執行檔中,也可以是共享的(又稱為動態的),這表示它們僅從可執行檔中參照,並且必須在執行時可用。B2 可以建立和使用這兩種類型的程式庫。
從 lib
目標產生的程式庫類型由 link
特性的值決定。預設值為 shared
,要建置靜態程式庫,該值應為 static
。您可以在命令列上要求靜態建置
b2 link=static
或在程式庫的需求中
lib l : l.cpp : <link>static ;
我們也可以使用 <link>
屬性來針對每個目標表示連結需求。例如,如果特定的可執行檔只能透過程式庫的靜態版本正確建置,我們可以如下所示將可執行檔的目標參照限定到該程式庫
exe important : main.cpp helpers/<link>static ;
無論在 b2
命令列上指定什麼引數,important
都只會與 helpers
的靜態版本連結。
如果您使用在其他專案中定義的程式庫(您無法變更的程式庫),但您仍然希望在所有情況下都靜態(或動態)連結到該程式庫,則在目標參照中指定屬性特別有用。如果該程式庫被許多目標使用,則您可以在所有地方都使用目標參照
exe e1 : e1.cpp /other_project//bar/<link>static ;
exe e10 : e10.cpp /other_project//bar/<link>static ;
但這絕非方便。更好的方法是引入一個間接層級。建立一個參照 foo
的靜態(或動態)版本的本機 alias
目標
alias foo : /other_project//bar/<link>static ;
exe e1 : e1.cpp foo ;
exe e10 : e10.cpp foo ;
alias 規則專門用於重新命名對目標的參照,並可能變更屬性。
☀
|
當一個程式庫使用另一個程式庫時,您將第二個程式庫放在第一個程式庫的來源清單中。例如
無論使用哪種連結類型,這都有效。當 |
ℹ
|
(非 UNIX 系統的注意事項)。通常,共享程式庫必須安裝到動態連結器的搜尋路徑中的目錄。否則,無法啟動使用共享程式庫的應用程式。在 Windows 上,動態連結器的搜尋路徑由 PATH 環境變數提供。當您使用 B2 測試設施時,此限制會被取消 — PATH 變數會在執行可執行檔之前自動調整。 |
3.6. 條件和替代方案
有時,需要在目標的建置屬性之間維護特定的關係。例如,您可能希望在程式庫以共享方式建置時,或在建置目標的 release
變體時,設定特定的 #define
。這可以使用條件需求來達成。
lib network : network.cpp
: <link>shared:<define>NETWORK_LIB_SHARED
<variant>release:<define>EXTRA_FAST
;
在上面的範例中,每當使用 <link>shared
建置 network
時,<define>NETWORK_LIB_SHARED
也會出現在其屬性中。此外,每當建置其 release 變體時,<define>EXTRA_FAST
都會出現在其屬性中。
有時,建置目標的方式差異很大,以至於使用條件需求描述它們會很困難。例如,假設一個程式庫實際上使用不同的原始碼檔案,具體取決於用於建置它的工具集。我們可以使用目標替代方案來表達這種情況
lib demangler : dummy_demangler.cpp ; # (1)
lib demangler : demangler_gcc.cpp : <toolset>gcc ; # (2)
lib demangler : demangler_msvc.cpp : <toolset>msvc ; # (3)
在建置 demangler
時,B2 會將每個替代方案的需求與建置屬性進行比較,以找到最佳匹配項。例如,在使用 <toolset>gcc
建置時,將會選取替代方案 (2),而使用 <toolset>msvc
建置時,將會選取替代方案 (3)。在所有其他情況下,將會建置最通用的替代方案 (1)。
3.7. 預先建置的目標
若要連結到未在 Jamfile 中提供建置指示的程式庫,您需要建立具有適當 file
屬性的 lib
目標。目標替代方案可用於將多個程式庫檔案與單一概念目標關聯。例如
# util/lib2/Jamfile
lib lib2
:
: <file>lib2_release.a <variant>release
;
lib lib2
:
: <file>lib2_debug.a <variant>debug
;
此範例為 lib2
定義了兩個替代方案,並為每個替代方案命名一個預先建置的檔案。當然,沒有來源。而是使用 <file>
特性來指定檔案名稱。
宣告預先建置的目標後,它可以像任何其他目標一樣使用
exe app : app.cpp ../util/lib2//lib2 ;
與任何目標一樣,選取的替代方案取決於從 lib2
的相依者傳播的屬性。如果我們建置 app
的 release 和 debug 版本,它將分別與 lib2_release.a
和 lib2_debug.a
連結。
系統程式庫 — 那些會由工具集透過搜尋某些預先確定的路徑自動找到的程式庫 — 應該宣告得幾乎像一般程式庫一樣
lib pythonlib : : <name>python22 ;
我們再次不指定任何來源,而是提供一個應傳遞給編譯器的 name
。如果使用 gcc 工具集將可執行目標連結到 pythonlib
,則 -lpython22
會出現在命令列中(其他編譯器可能會使用不同的選項)。
我們也可以指定工具集應該在哪裡尋找程式庫
lib pythonlib : : <name>python22 <search>/opt/lib ;
當然,目標替代方案可以像平常一樣使用
lib pythonlib : : <name>python22 <variant>release ;
lib pythonlib : : <name>python22_d <variant>debug ;
在「site-config.jam 中的目標」章節中,說明了預先建置目標的更進階用法。
4. 概述
B2 有兩個部分 — 一個具有其自己的直譯語言的建置引擎,以及使用該語言實作的 B2 本身。當您在命令列上輸入 b2
時,事件的鏈結如下
-
B2 可執行檔嘗試尋找 B2 模組並載入頂層模組。確切的程序在「初始化」章節中描述。
-
頂層模組會載入使用者定義的組態檔案
user-config.jam
和site-config.jam
,這些檔案會定義可用的工具集。 -
會讀取目前目錄中的 Jamfile。這反過來可能會導致讀取其他 Jamfile。因此,會建立一個專案樹狀結構,其中專案內有目標。
-
最後,使用命令列上指定的建置要求,B2 會決定應建置哪些目標以及如何建置。該資訊會傳遞回 Boost.Jam,由 Boost.Jam 負責實際執行排定的建置動作命令。
因此,若要能夠成功使用 B2,您只需要了解四件事
-
有關 Boost.Jam 語言的一些基本知識。請參閱「Boost.Jam 語言」章節。
4.1. 概念
B2 有一些獨特的概念,本節將介紹這些概念。解釋這些概念的最佳方法是與更經典的建置工具進行比較。
當使用任何 make 風格時,您會直接指定目標以及用於從其他目標建立它們的命令。下面的範例使用硬編碼的編譯器呼叫命令,從 a.c
建立 a.o
。
a.o: a.c
g++ -o a.o -g a.c
這是一個相當低階的描述機制,很難根據使用的編譯器和作業系統調整命令、選項和建立的目標集。
為了提高可攜性,大多數現代建置系統都提供一組較高階的函式,這些函式可用於建置描述檔案中。請考慮以下範例
add_program ("a", "a.c")
這是一個函式呼叫,它會建立從原始碼檔案 a.c
建立可執行檔所需的目標。根據設定的屬性,可以使用不同的命令列。但是,add_program
是較高階但相當薄的層級。所有目標都會在剖析建置描述時立即建立,這使得無法執行多變體建置。通常,任何建置屬性的變更都需要完整重新設定建置樹狀結構。
為了支援真正的多變體建置,B2 引入了「中繼目標定義主要目標中繼目標」metatarget 的概念 — 這是一個在剖析建置描述時建立的物件,稍後可以使用特定的建置屬性來呼叫,以產生實際的目標。
考慮以下範例
exe a : a.cpp ;
當剖析此宣告時,B2 會建立一個中繼目標,但尚未決定必須建立哪些檔案或必須使用哪些命令。在剖析所有建置檔案後,B2 會考量在命令列上要求的屬性。假設您已使用以下指令叫用 B2:
b2 toolset=gcc toolset=msvc
在這種情況下,中繼目標將會被呼叫兩次,一次使用 toolset=gcc
,另一次使用 toolset=msvc
。這兩個呼叫都會產生具體的目標,這些目標將具有不同的副檔名並使用不同的命令列。
另一個關鍵概念是建置屬性。建置屬性是一個影響建置過程的變數。它可以在命令列上指定,並在呼叫中繼目標時傳遞。雖然所有建置工具都有類似的機制,但 B2 的不同之處在於它要求預先宣告所有建置屬性,並提供一組具有可移植語義的大型屬性。
最後一個概念是屬性傳播。B2 不要求每個中繼目標都以相同的屬性呼叫。相反地,「頂層」中繼目標會以命令列上指定的屬性呼叫。每個中繼目標都可以選擇擴增或覆寫某些屬性(特別是使用需求機制,請參閱 名為「需求」的章節)。然後,相依性中繼目標會以修改後的屬性呼叫,並產生在建置過程中使用的具體目標。當然,相依性中繼目標可能會反過來修改建置屬性,並具有它們自己的相依性。
如需更深入地探討需求和概念,您可以參考 SYRCoSE 2009 B2 文章。
4.2. Boost.Jam 語言
本節將描述 Boost.Jam 語言的基本知識 — 足以撰寫 Jamfile。如需更多資訊,請參閱 Boost.Jam 文件。
Boost.Jam 具有一個直譯的程序語言。在最低層級,Boost.Jam 程式由變數和規則(Jam 中函式的術語)組成。它們被分組到模組中 — 有一個全域模組和一些具名的模組。除此之外,Boost.Jam 程式還包含類別和類別實例。
a = b ;
此程式碼會將值 b
指派給變數 a
。在這裡,=
和 ;
是關鍵字,而 a
和 b
是常值。
⚠
|
所有語法元素,甚至是關鍵字,都必須以空格分隔。例如,省略 ; 前面的空格字元將導致語法錯誤。 |
如果您想要使用與某個關鍵字相同的常值,則可以引用該值
a = "=" ;
Boost.Jam 中的所有變數都具有相同的類型 — 字串清單。若要定義變數,請像上一個範例一樣將值指派給它。未定義的變數與具有空值的變數相同。可以使用 $(variable)
語法存取變數。例如
a = $(b) $(c) ;
規則是透過指定規則名稱、參數名稱和每個參數允許的值清單大小來定義。
rule example
(
parameter1 :
parameter2 ? :
parameter3 + :
parameter4 *
)
{
# rule body
}
當呼叫此規則時,作為第一個引數傳遞的清單必須恰好有一個值。作為第二個引數傳遞的清單可以有一個值或為空。其餘兩個引數可以任意長,但第三個引數不得為空。
以下概述了 Boost.Jam 語言的陳述式
helper 1 : 2 : 3 ;
x = [ helper 1 : 2 : 3 ] ;
此程式碼會使用指定的引數呼叫具名的規則。當必須在某些表示式內使用呼叫的結果時,您需要在呼叫周圍加上括號,如第二行所示。
if cond { statements } [ else { statements } ]
這是一個常規的 if 陳述式。條件由以下組成
-
常值(如果至少有一個字串不為空,則為 true)
-
比較:
a 運算子 b
,其中運算子是=
、!=
、<
、>
、⇐
或>=
之一。比較是在左引數和右引數中的每個字串之間成對進行的。 -
邏輯運算:
! a
、a && b
、a || b
-
分組:
( cond )
for var in list { statements }
為清單中的每個元素執行陳述式,將變數 var
設定為元素值。
while cond { statements }
在進入時,只要 cond 保持 true,就會重複執行陳述式。
return values ;
此陳述式應僅在規則內使用,並將 values
傳回給規則的呼叫者。
import module ;
import module : rule ;
第一種形式會匯入指定的模組。該模組中的所有規則都可以使用限定名稱:module.rule
。第二種形式只會匯入指定的規則,並且可以使用非限定名稱呼叫它們。
有時候,您需要指定在建立目標時要使用的實際命令列。在 Jam 語言中,您可以使用具名的動作來執行此操作。例如
actions create-file-from-another
{
create-file-from-another $(<) $(>)
}
這指定了一個名為 create-file-from-another
的具名動作。大括號內的文字是要叫用的命令。$(<)
變數將展開為產生的檔案清單,而 $(>)
變數將展開為來源檔案清單。
若要彈性地調整命令列,您可以定義一個與動作名稱相同的規則,並採用三個參數 — 目標、來源和屬性。例如
rule create-file-from-another ( targets * : sources * : properties * )
{
if <variant>debug in $(properties)
{
OPTIONS on $(targets) = --debug ;
}
}
actions create-file-from-another
{
create-file-from-another $(OPTIONS) $(<) $(>)
}
在此範例中,規則會檢查是否指定了某個建置屬性。如果是,則會設定變數 OPTIONS
,然後在動作內使用該變數。請注意,「在目標上」設定的變數只會在建置該目標的動作內可見,而不是全域可見。如果它們是全域設定的,則在兩個不相關的動作中使用名為 OPTIONS
的變數將是不可能的。
更多詳細資訊可以在 Jam 參考資料的 名為「規則」的章節中找到。
4.3. 設定
在啟動時,B2 會搜尋並讀取三個設定檔:site-config.jam
、user-config.jam
和 project-config.jam
。第一個通常由系統管理員安裝和維護,第二個供使用者修改。您可以編輯 B2 安裝的最上層目錄中的檔案,或在您的主目錄中建立副本並編輯副本。第三個用於專案特定的設定。下表說明了檔案的搜尋位置。
site-config.jam | user-config.jam | project-config.jam | |
---|---|---|---|
Linux |
|
|
…… |
Windows |
|
|
…… |
這些檔案中的任何一個也可以在命令列上覆寫。
☀
|
您可以使用 --debug-configuration 選項來尋找實際載入的設定檔。 |
通常,user-config.jam
只會定義可用的編譯器和其他工具(如需更進階的用法,請參閱名為「site-config.jam 中的目標」的章節)。工具是使用以下語法設定的
using tool-name : ... ;
using
規則會被賦予工具的名稱,並且會使該工具可供 B2 使用。例如,
using gcc ;
將使 GCC 編譯器可用。
☀
|
如果 tool 支援此用法,您可以將 using <tool> ; 放入需要 tool 的 Jamfile 中,而沒有其他引數。在所有其他情況下,using 規則應位於設定檔中。一般原則是,Jamfile 中的描述應保持可移植性,而設定檔則應為系統特定的。 |
所有受支援的工具都記錄在名為「內建工具」的章節中,包括它們採用的特定選項。以下是一些適用於大多數 C++ 編譯器的一般注意事項。
對於 B2 支援的所有開箱即用的 C++ 編譯器工具集,using
的參數清單都是相同的:toolset-name
、version
、invocation-command
和 options
。
如果您有一個編譯器,且編譯器可執行檔
-
具有其「一般名稱」並位於
PATH
中,或 -
已安裝在標準「安裝目錄」中,或
-
可以使用像 Windows 登錄檔這樣的全域系統找到。
它可以透過簡單地
using tool-name ;
進行設定。如果編譯器安裝在自訂目錄中,則應提供叫用編譯器的命令,例如
using gcc : : g++-3.2 ;
using msvc : : "Z:/Programs/Microsoft Visual Studio/vc98/bin/cl" ;
某些 B2 工具集將使用該路徑來執行叫用編譯器之前所需的其他動作,例如呼叫廠商提供的腳本來設定其所需的環境變數。當 C 和 C++ 的編譯器可執行檔不同時,必須指定 C++ 編譯器可執行檔的路徑。該命令可以是作業系統允許的任何命令。例如
using msvc : : echo Compiling && foo/bar/baz/cl ;
將會有效。
若要設定多個版本的工具集,只需多次叫用 using
規則即可
using gcc : 3.3 ;
using gcc : 3.4 : g++-3.4 ;
using gcc : 3.2 : g++-3.2 ;
using gcc : 5 ;
using clang : 3.9 ;
using msvc : 14.0 ;
請注意,在第一次呼叫 using
時,將會使用在 PATH
中找到的編譯器,並且不需要明確指定命令。
許多工具組都有一個 options
參數來微調設定。所有 B2 的標準編譯器工具組都接受四個選項 cflags
、cxxflags
、compileflags
和 linkflags
作為 options
,這些選項指定將永遠傳遞給相應工具的標誌。選項名稱標籤和值之間不得有空格。 cflags
功能的值直接傳遞給 C 編譯器,cxxflags
功能的值直接傳遞給 C++ 編譯器,而 compileflags
功能的值則傳遞給兩者。例如,要將 gcc
工具組配置為始終產生 64 位元程式碼,您可以這樣寫:
using gcc : 3.4 : : <compileflags>-m64 <linkflags>-m64 ;
如果需要多個相同類型的選項,可以用引號串聯,或使用選項標籤的多個實例。
using gcc : 5 : : <cxxflags>"-std=c++14 -O2" ;
using clang : 3.9 : : <cxxflags>-std=c++14 <cxxflags>-O2 ;
大多數工具可以使用同一工具的多個變體。這些變體以傳入的版本區分。因為這裡不能使用破折號「-」,所以慣例是使用波浪號「~」來區分變體。
using gcc : 5 : g++-5 : ; # default is C++ 98
using gcc : 5~c++03 : g++-5 : <cxxflags>-std=c++03 ; # C++ 03
using gcc : 5~gnu03 : g++-5 : <cxxflags>-std=gnu++03 ; # C++ 03 with GNU
using gcc : 5~c++11 : g++-5 : <cxxflags>-std=c++11 ; # C++ 11
using gcc : 5~c++14 : g++-5 : <cxxflags>-std=c++14 ; # C++ 14
這些變體隨後會像普通工具組一樣使用。
b2 toolset=gcc-5 stage
b2 toolset=gcc-5~c++14 stage
⚠
|
雖然用於指定工具組選項的語法與 Jamfile 中用於指定需求的語法非常相似,但工具組選項與功能不同。請勿嘗試在工具組初始化中指定功能值。 |
4.4. 呼叫
若要呼叫 B2,請在命令列輸入 b2
。接受三種命令列標記,順序不拘:
- 選項
-
選項以一或兩個破折號開頭。標準選項如下所列,每個專案都可以加入其他選項。
- 屬性
-
屬性指定您想要建置的詳細資訊(例如,偵錯或發行變體)。在語法上,所有包含等號的命令列標記都被視為指定屬性。最簡單的形式,屬性看起來像
feature=value
。 - 目標
-
所有既不是選項也不是屬性的標記,都指定要建置的目標。可用的目標完全取決於您正在建置的專案。
4.4.1. 範例
若要使用預設屬性建置目前目錄中 Jamfile 中定義的所有目標,請執行:
b2
若要建置特定目標,請在命令列上指定它們:
b2 lib1 subproject//lib2
若要請求某個屬性的特定值,請將 property=value
加入命令列:
b2 toolset=gcc variant=debug optimization=space
4.4.2. 選項
B2 識別以下命令列選項。
--help
-
呼叫線上說明系統。這會印出關於如何使用說明系統的一般資訊,以及其他的 --help* 選項。
--clean
-
清除目前目錄以及任何子專案中的所有目標。請注意,與 make 中的
clean
目標不同,您可以將--clean
與目標名稱一起使用來清除特定目標。 --clean-all
-
清除所有目標,無論它們在哪裡定義。特別是,它會清除父 Jamfile 中的目標,以及在其他專案根目錄下定義的目標。
--build-dir
-
變更正在建置的所有專案根目錄的建置目錄。當指定此選項時,所有 Jamroot 檔案都必須宣告專案名稱。專案根目錄的建置目錄將透過串聯
--build-dir
選項的值、Jamroot 中指定的專案名稱以及 Jamroot 中指定的建置目錄(如果未指定,則為bin
)來計算。當從唯讀媒體建置時,此選項特別有用,因為您無法修改 Jamroot。 --abbreviate-paths
-
透過縮寫每個組件來壓縮目標路徑。此選項有助於防止路徑變得比檔案系統支援的長度還長。另請參閱「目標路徑」章節。
--hash
-
使用 MD5 雜湊壓縮目標路徑。此選項有助於防止路徑變得比檔案系統支援的長度還長。此選項產生的路徑比
--abbreviate-paths
短,但代價是可理解性較低。另請參閱「目標路徑」章節。 --version
-
印出 B2 和 Boost.Jam 版本的相關資訊。
-a
-
導致重建所有檔案。
-n
-
不執行命令,僅印出它們。
-q
-
在第一個錯誤處停止,而不是繼續建置不依賴於失敗目標的目標。
-j N
-
並行執行最多 N 個命令。預設工作數是偵測到的可用 CPU 線程數。注意:在某些情況下,預設值可能大於配置的 CPU 資源,例如在某些虛擬化容器安裝中。
--config=filename
-
覆寫所有組態檔
--site-config=filename
-
覆寫預設的site-config.jam
--user-config=filename
-
覆寫預設的user-config.jam
--project-config=filename
-
覆寫預設的project-config.jam
--debug-configuration
-
產生關於載入 B2 和工具組檔案的偵錯資訊。
--debug-building
-
印出正在建置哪些目標以及使用哪些屬性。
--debug-generators
-
產生來自產生器搜尋程序的偵錯輸出。對於偵錯自訂產生器很有用。
-d0
-
隱藏所有資訊訊息。
-d N
-
啟用從 1 到 n 的累加偵錯層級。值如下:
-
顯示執行時用於建置目標的動作 (預設)。
-
顯示「靜默」動作,並顯示所有動作文字,因為它們會被執行。
-
顯示相依性分析,以及目標/來源時間戳/路徑。
-
顯示 shell 呼叫的引數和時序。
-
顯示規則呼叫和變數擴充。
-
顯示目錄/標頭檔/封存掃描,以及嘗試繫結到目標。
-
顯示變數設定。
-
顯示變數提取、變數擴充以及 '"if"' 表達式的評估。
-
顯示變數操作、掃描器標記和記憶體使用情況。
-
顯示規則的效能分析資訊,包括時序和記憶體。
-
顯示 Jamfile 的剖析進度。
-
顯示目標相依性圖。
-
顯示變更目標狀態(命運)。
-
-d +N
-
啟用偵錯層級
N
。 -o file
-
將更新動作寫入指定的檔案,而不是執行它們。
-s var=value
-
將變數
var
設定為 jam 語言解釋器的全域範圍內的value
,覆寫從環境匯入的變數。 --command-database=format
-
以 format 輸出編譯命令資料庫。目前,format 可以是:
json
。(有關詳細資訊,請參閱命令資料庫)。 --command-database-out=file
-
指定輸出命令資料庫的 file 路徑。
4.4.3. 屬性
在最簡單的情況下,建置是使用一組屬性執行的,您可以使用 feature=value
形式的元素在命令列上指定這些屬性。完整的功能清單可以在「內建功能」章節中找到。最常見的功能摘要如下。
功能 | 允許的值 | 注意事項 |
---|---|---|
variant |
debug,release |
|
link |
shared,static |
決定 B2 是否建立共享或靜態程式庫 |
threading |
single,multi |
使產生的二進位檔案具有執行緒安全。這需要原始程式碼本身的適當支援。 |
address-model |
32,64 |
明確要求產生 32 位元或 64 位元程式碼。這通常需要您的編譯器進行適當的設定。如果遇到問題,請參閱「C++ 編譯器」章節和您的編譯器文件。 |
toolset |
(取決於組態) |
要使用的 C++ 編譯器。有關詳細列表,請參閱「C++ 編譯器」章節。 |
include |
(任意字串) |
C 和 C++ 編譯器的其他包含路徑。 |
define |
(任意字串) |
C 和 C++ 編譯器的其他巨集定義。字串應為 |
cxxflags |
(任意字串) |
要傳遞給 C++ 編譯器的自訂選項。 |
cflags |
(任意字串) |
要傳遞給 C 編譯器的自訂選項。 |
linkflags |
(任意字串) |
要傳遞給 C++ 連結器的自訂選項。 |
runtime-link |
shared,static |
決定是否應使用 C 和 C++ 執行階段的共享或靜態版本。 |
如果您有多個版本的 C++ 工具組(例如在 user-config.jam
中設定,或是自動偵測到的,例如使用 msvc),您可以透過傳遞 toolset-version
作為 toolset
功能的值來請求特定版本,例如 toolset=msvc-8.0
。
如果某個功能具有一組固定的值,則可以在命令列上多次指定它。在這種情況下,所有內容都將建置多次 — 每個指定的功能值一次。例如,如果您使用:
b2 link=static link=shared threading=single threading=multi
那麼總共會執行 4 次建置。為了方便起見,您可以將這些值用逗號分隔,而不用在單獨的命令列元素中指定某個功能的所有請求值,例如:
b2 link=static,shared threading=single,multi
逗號只有在功能具有一組固定值時才具有這種特殊意義,因此:
b2 include=static,shared
不會被特殊對待。
多個功能可以使用正斜線分組。
b2 gcc/link=shared msvc/link=static,shared
這總共會建置 3 個不同的變體。
4.4.4. 目標
所有既不是選項也不是屬性的命令列元素都是要建置的目標名稱。請參閱「目標識別碼和參照」章節。如果未指定任何目標,則會建置目前目錄中的專案。
4.5. 宣告目標
主目標是使用者定義的具名實體,可以建置,例如可執行檔。宣告主目標通常使用「內建規則」章節中描述的主要目標規則之一完成。使用者也可以宣告自訂主要目標規則,如「主要目標規則」章節中所示。
rule rule-name (
main-target-name :
sources + :
requirements * :
default-build * :
usage-requirements * )
-
main-target-name
是用於在命令列上請求目標,以及從其他主要目標使用它的名稱。主要目標名稱可包含字母數字字元、破折號 (「-
」) 和底線 (「_
」)。 -
sources
是必須合併的原始檔和其他主要目標的清單。 -
requirements
是建置此主要目標時,必須始終存在的屬性清單。 -
default-build
是將使用的屬性清單,除非已指定相同功能的其他值,例如在命令列上或從相依目標傳播的值。 -
usage-requirements
是將傳播到所有使用此主要目標的主要目標的屬性清單,即傳播到其所有相依項目。
某些主要目標規則具有不同的參數清單,其在文件中明確說明。
目標的實際需求是透過使用明確指定的需求來精煉宣告目標的專案需求而獲得的。對於使用需求也是如此。更多詳細資訊請見名為「屬性精煉」的章節。
4.5.1. 名稱
主要目標的名稱有兩個用途。首先,它用於從其他目標和命令列參考此目標。其次,它用於計算產生的檔案名稱。通常,檔案名稱是透過在主要目標名稱後附加系統相關的後綴和字首而取得的。
主要目標的名稱可包含字母數字字元、破折號、底線和點。從其他目標解析參考時,整個名稱都很重要。對於判斷檔案名稱,只會採用第一個點之前的部分。例如
obj test.release : test.cpp : <variant>release ;
obj test.debug : test.cpp : <variant>debug ;
將產生兩個名為 test.obj
的檔案(在兩個不同的目錄中),而不是兩個名為 test.release.obj
和 test.debug.obj
的檔案。
4.5.2. 來源
來源清單指定應處理哪些內容以取得結果目標。大多數時候,它只是一個檔案清單。有時,您會希望自動建構來源檔的清單,而不是必須手動拼寫出來,在這種情況下,您可以使用 glob 規則。以下是兩個範例
exe a : a.cpp ; (1)
exe b : [ glob *.cpp ] ; (2)
-
a.cpp
是唯一的來源檔 -
此目錄中的所有
.cpp
檔案都是來源
除非您指定具有絕對路徑的檔案,否則該名稱會被視為相對於來源目錄的相對路徑 — 來源目錄通常是 Jamfile 所在的目錄,但可以依照名為「專案」的章節中所述的方式變更。
來源清單也可以參考其他主要目標。同一個專案中的目標可以依名稱參考,而其他專案中的目標必須使用目錄或符號專案名稱進行限定。目錄/專案名稱與目標名稱之間以雙斜線分隔。沒有特殊的語法來區分目錄名稱和專案名稱 — 雙斜線之前的部分會先作為專案名稱查找,然後再作為目錄名稱查找。例如
lib helper : helper.cpp ;
exe a : a.cpp helper ;
exe b : b.cpp ..//utils ; (1)
exe c : c.cpp /boost/program_options//program_options ;
-
由於所有專案 ID 都以斜線開頭,「..」是目錄名稱。
第一個 exe 使用同一個專案中定義的程式庫。第二個 exe 使用 Jamfile 高一層級定義的某個目標(很可能是程式庫)。最後,第三個目標使用 C++ Boost 程式庫,並使用其絕對符號名稱參考它。有關目標參考的更多資訊,請見名為「相依目標」的章節和名為「目標識別碼和參考」的章節。
4.5.3. 需求
需求是在建置目標時應始終存在的屬性。通常,它們是 include 和 define
exe hello : hello.cpp : <include>/opt/boost <define>MY_DEBUG ;
還有許多其他功能,列在名為「內建功能」的章節中。例如,如果一個程式庫只能靜態建置,或者由於編譯器錯誤而無法使用最佳化來編譯檔案,則可以使用。
lib util : util.cpp : <link>static ;
obj main : main.cpp : <optimization>off ;
lib network : network.cpp
: <link>shared:<define>NETWORK_LIB_SHARED
<variant>release:<define>EXTRA_FAST
;
在上面的範例中,每當以 <link>shared
建置 network
時,<define>NETWORK_LIB_SHARED
也會在其屬性中。
您可以在條件中使用多個屬性,例如
lib network : network.cpp
: <toolset>gcc,<optimization>speed:<define>USE_INLINE_ASSEMBLER
;
條件需求的更強大變體是間接條件需求。您可以提供一個規則,該規則將使用目前的建置屬性呼叫,並且可以計算要新增的其他屬性。例如
lib network : network.cpp
: <conditional>@my-rule
;
rule my-rule ( properties * )
{
local result ;
if <toolset>gcc <optimization>speed in $(properties)
{
result += <define>USE_INLINE_ASSEMBLER ;
}
return $(result) ;
}
此範例與前一個範例等效,但對於複雜的情況,間接條件需求可能更容易撰寫和理解。
為目標明確指定的需求通常與為包含專案指定的需求結合在一起。您可以使用語法在屬性前新增減號來讓目標完全忽略特定的專案需求,例如
exe main : main.cpp : -<define>UNNECESSARY_DEFINE ;
此語法是從父項忽略自由屬性(例如 define)的唯一方法。它對於普通屬性也很有用。請考慮以下範例
project test : requirements <threading>multi ;
exe test1 : test1.cpp ;
exe test2 : test2.cpp : <threading>single ;
exe test3 : test3.cpp : -<threading>multi ;
在此,test1
繼承了專案需求,並且始終會在多執行緒模式中建置。test2
目標覆寫專案的需求,並且始終會在單執行緒模式中建置。相較之下,test3
目標會從專案需求中移除屬性,並且會以單執行緒或多執行緒模式建置,具體取決於使用者請求哪個變體。
請注意,需求的移除完全是文字形式的:您需要指定完全相同的屬性來移除它。
4.5.4. 預設建置
default-build
參數是要使用的一組屬性,如果建置請求未指定集合中功能的其他值。例如
exe hello : hello.cpp : : <threading>multi ;
將建置多執行緒目標,除非使用者明確請求單執行緒版本。需求和 default-build 之間的差異在於,需求無法以任何方式覆寫。
4.5.5. 其他資訊
目標的建置方式可能差異很大,以至於使用條件需求描述它們會很困難。例如,假設程式庫實際上根據用於建置它的工具集使用不同的來源檔。我們可以使用目標替代來表達這種情況
lib demangler : dummy_demangler.cpp ; # alternative 1
lib demangler : demangler_gcc.cpp : <toolset>gcc ; # alternative 2
lib demangler : demangler_msvc.cpp : <toolset>msvc ; # alternative 3
在上面的範例中,當以 gcc
或 msvc
建置時,demangler
將使用特定於工具集的來源檔。否則,它將使用通用來源檔 dummy_demangler.cpp
。
可以內嵌宣告目標,也就是說,「sources」參數可以包含對其他主要規則的呼叫。例如
exe hello : hello.cpp
[ obj helpers : helpers.cpp : <optimization>off ] ;
將導致「helpers.cpp」始終在沒有最佳化的情況下編譯。參考內嵌主要目標時,其宣告的名稱必須以其父目標的名稱和兩個點作為字首。在上面的範例中,若要僅建置 helpers,應執行 b2 hello..helpers
。
當未在命令列上請求任何目標時,將會建置目前專案中的所有目標。如果目標應僅透過明確請求來建置,則可以使用 explicit 規則來表達。
explicit install_programs ;
4.6. 專案
如前所述,目標會分組到專案中,而每個 Jamfile 都是一個單獨的專案。專案很有用,因為它們允許我們將相關目標分組在一起、定義所有這些目標共有的屬性,以及為專案指派符號名稱,該符號名稱可用於參考其目標。
專案會使用 project
規則來命名,該規則具有以下語法
project id : attributes ;
在此,屬性是規則引數的序列,每個引數都以屬性名稱開頭,後接任意數量的建置屬性。下表中還顯示了屬性名稱清單及其處理方式。例如,可以寫入
project tennis
: requirements <threading>multi
: default-build release
;
可能的屬性列在下方。
專案 ID 是一種表示專案的簡短方式,與 Jamfile 的路徑名稱相反。它是與檔案系統無關的階層路徑,例如「boost/thread」。目標參考會利用專案 ID 來指定目標。
來源位置指定專案來源所在的目錄。
專案需求是適用於專案中所有目標以及所有子專案的需求。
預設建置是未明確指定任何建置請求時應使用的建置請求。
這些屬性的預設值在下表中給定。
屬性 | 名稱 | 預設值 | project 規則的處理方式 |
---|---|---|---|
專案 ID |
無 |
無 |
從「project」規則的第一個參數指派。假設它表示絕對專案 ID。 |
來源位置 |
|
專案的 jamfile 的位置 |
設定為傳遞的值 |
需求 |
|
父項的需求 |
父項的需求會使用傳遞的需求來精煉,並且結果會用作專案需求。 |
預設建置 |
|
無 |
設定為傳遞的值 |
建置目錄 |
|
如果父項未設定任何建置目錄,則為空。否則,父項的建置目錄會附加從父項到目前專案的相對路徑。 |
設定為傳遞的值,並解譯為相對於專案的位置。 |
除了定義專案和主要目標之外,Jamfile 通常會叫用各種公用程式規則。如需可在 Jamfile 中直接使用的規則完整清單,請見名為「內建規則」的章節。
每個子專案都會從其父專案繼承屬性、常數和規則,父專案由子專案上方祖先目錄中最近的 Jamfile 定義。最上層專案會在名為 Jamroot
或 Jamfile
的檔案中宣告。載入專案時,B2 會尋找 Jamroot
或 Jamfile
。它們的處理方式相同,但如果檔案名為 Jamroot
,則不會執行對父專案的搜尋。沒有父專案的 Jamfile
也會被視為最上層專案。
即使在子專案目錄中建置,父專案檔案也會始終在子專案的檔案之前載入,以便父專案中的每個定義始終可供其子專案使用。任何其他專案的載入順序都是未指定的。即使一個專案透過 use-project
或目標參考來參考另一個專案,也不應假設任何特定順序。
ℹ
|
將根專案設為特殊名稱「Jamroot 」可確保 B2 不會誤解它上方的目錄為專案根目錄,只因為該目錄包含 Jamfile。 |
4.7. 建置程序
當您描述目標時,您希望 B2 執行正確的工具並建立所需的目標。本節將描述兩件事:如何指定要建置的內容,以及如何實際建構主要目標。
最重要的一點是,在 B2 中,與其他建置工具不同,您宣告的目標不對應於特定檔案。您在 Jamfile 中宣告的內容更像是「元目標」。根據您在命令列上指定的屬性,每個元目標都會產生一組與請求的屬性對應的實際目標。同一個元目標很可能會使用不同的屬性建置多次,產生不同的檔案。
☀
|
這表示對於 B2 而言,您無法直接從 Jamfile 取得建置變體。使用者可能會要求數個變體,而且每個目標都可以使用不同的屬性來建置。 |
4.7.1. 建置請求
命令列會指定要建置哪些目標以及使用哪些屬性。例如:
b2 app1 lib1//lib1 toolset=gcc variant=debug optimization=full
這將會使用指定的屬性來建置兩個目標,"app1" 和 "lib1//lib1"。您可以使用目標 ID來參照任何目標,並指定任意屬性。某些屬性非常常見,因此可以省略屬性的名稱。例如,上述內容可以寫成:
b2 app1 lib1//lib1 gcc debug optimization=full
完整的語法(其中有一些額外的捷徑)在名為「呼叫」的章節中說明。
4.7.2. 建置主要目標
當您直接或間接地請求使用特定需求建置主要目標時,會執行下列步驟。會提供一些簡短的解釋,更詳細的資訊請參閱名為「建置流程」的章節。
-
套用預設建置。如果目標的 default-build 屬性指定了建置請求中不存在的功能值,則會新增該值。
-
選取要使用的主要目標替代方案。對於每個替代方案,我們會檢查有多少屬性同時存在於替代方案的需求和建置請求中。會選取具有最多匹配屬性的替代方案。
-
判斷「通用」屬性。建置請求會使用目標的需求進行精煉。也會處理需求中的條件屬性。最後,會新增功能的預設值。
-
建置來源清單和相依性屬性參照的目標。來源清單和屬性可以使用目標參照來參照其他目標。對於每個參照,我們會取得所有傳播的屬性,透過目標參照中指定的明確屬性進行精煉,並將產生的屬性做為建置請求傳遞給其他目標。
-
將建置相依性時產生的使用需求新增至「通用」屬性。當在先前的步驟中建置相依性時,它們會傳回建立的「實際」目標集合和使用需求。使用需求會新增至通用屬性,而產生的屬性集將用於建置目前的目標。
-
使用產生器建置目標。為了將來源轉換為所需的類型,B2 會使用「產生器」——對應於編譯器和連結器等工具的物件。每個產生器都會宣告它可以產生的目標類型以及它需要的來源類型。使用此資訊,B2 會判斷必須執行哪些產生器才能從特定來源產生特定目標。當產生器執行時,它們會傳回「實際」目標。
-
計算要傳回的使用需求。會展開使用需求中的條件屬性,並傳回結果。
5. 常見任務
本節說明 B2 支援的現成主要目標類型。除非另有說明,否則所有提及的主要目標規則都具有常見的簽章,如名為「宣告目標」的章節所述。
5.1. 程式
程式是使用 exe
規則建立的,該規則遵循通用語法。例如:
exe hello
: hello.cpp some_library.lib /some_project//library
: <threading>multi
;
這將會從來源建立一個可執行檔——在本例中,是一個 C++ 檔案、一個存在於同一目錄中的程式庫檔案,以及另一個由 B2 建立的程式庫。一般來說,來源可以包括 C 和 C++ 檔案、物件檔案和程式庫。B2 會自動嘗試轉換其他類型的目標。
☀
|
在 Windows 上,如果應用程式使用共用程式庫,且應用程式和程式庫都使用 B2 建置,則無法立即執行該應用程式,因為 PATH 環境變數應包含程式庫的路徑。這表示您必須手動新增路徑,或讓建置將應用程式和程式庫放置在同一目錄中。請參閱名為「安裝」的章節。 |
5.2. 程式庫
程式庫目標是使用 lib
規則建立的,該規則遵循通用語法。例如:
lib helpers : helpers.cpp ;
這將定義一個名為 helpers
的程式庫目標,該目標是從 helpers.cpp
來源檔案建置的。它可以是靜態程式庫或共用程式庫,取決於<link>
功能的值。
程式庫目標可以表示
-
應該從來源建置的程式庫,如上述範例所示。
-
系統上已存在的預建程式庫。可以使用它們的工具來搜尋這類程式庫(通常使用連結器的
-l
選項),或者建置系統可以預先知道它們的路徑。
預建程式庫的語法如下:
lib z : : <name>z <search>/home/ghost ;
lib compress : : <file>/opt/libs/compress.a ;
name
屬性指定程式庫的名稱,不含標準字首和字尾。例如,根據系統的不同,z
可能表示名為 z.so
、libz.a
或 z.lib
等的檔案。search
功能指定除了預設編譯器路徑之外,還可以在哪些路徑中搜尋程式庫。可以多次指定 search
,也可以省略它,在這種情況下,只會搜尋預設編譯器路徑。file
屬性指定檔案位置。
使用 file
功能和使用 name
與 search
功能組合之間的差異在於,file
更精確。
⚠
|
如果 /pool/release/a.so、/pool/release/b.so、/pool/debug/a.so 和 /pool/release/b.so 都存在,則連結器可能會從同一個目錄中取得 |
為了方便起見,允許使用下列語法:
lib z ;
lib gui db aux ;
其效果與
lib z : : <name>z ;
lib gui : : <name>gui ;
lib db : : <name>db ;
lib aux : : <name>aux ;
完全相同。當程式庫參照另一個程式庫時,您應該將該程式庫放入其來源清單中。這在所有情況下都會執行正確的操作。為了可攜性,您應該指定程式庫相依性,即使對於已搜尋和預建的程式庫也是如此,否則 Unix 上的靜態連結將無法運作。例如:
lib z ;
lib png : z : <name>png ;
ℹ
|
當程式庫將共用程式庫作為來源,或者靜態程式庫將另一個靜態程式庫作為來源時,任何連結到第一個程式庫的目標也會自動連結到其來源程式庫。 另一方面,當共用程式庫將靜態程式庫作為來源時,將會建置第一個程式庫,使其完全包含第二個程式庫。 如果您不希望共用程式庫包含其來源中指定的所有程式庫(尤其是靜態連結的程式庫),則需要使用下列程式碼:
這指定程式庫 |
使用需求對於定義程式庫目標通常非常有用。例如,假設您想要建置一個 helpers
程式庫,其介面在位於與 helpers.cpp
來源檔案相同目錄中的 helpers.hpp
標頭檔案中描述。然後,您可以將下列內容新增到位於同一個目錄中的 Jamfile:
lib helpers : helpers.cpp : : : <include>. ;
這會自動將定義目標的目錄(以及程式庫標頭檔案所在的目錄)新增到所有使用 helpers
程式庫的目標的編譯器包含路徑。此功能大大簡化了 Jamfile。
5.3. 別名
alias
規則會為一組目標提供替代名稱。例如,為了為下列程式碼中的其他三個目標的群組提供名稱 core
:
alias core : im reader writer ;
在命令列上或在任何其他目標的來源清單中使用 core
與明確使用 im
、reader
和 writer
相同。
alias
規則的另一個用途是變更建置屬性。例如,如果您想要靜態連結到 Boost Threads 程式庫,則可以撰寫下列程式碼:
alias threads : /boost/thread//boost_thread : <link>static ;
並且僅在您的 Jamfile 中使用 threads
別名。
您也可以為 alias
目標指定使用需求。如果您撰寫下列程式碼:
alias header_only_library : : : : <include>/usr/include/header_only_library ;
然後,在來源中使用 header_only_library
只會新增包含路徑。另請注意,當別名具有來源時,它們的使用需求也會傳播。例如:
lib library1 : library1.cpp : : : <include>/library/include1 ;
lib library2 : library2.cpp : : : <include>/library/include2 ;
alias static_libraries : library1 library2 : <link>static ;
exe main : main.cpp static_libraries ;
將會使用使用指定的靜態程式庫所需的額外包含來編譯 main.cpp
。
5.4. 安裝
本節說明安裝已建置目標和任意檔案的各種方式。
5.4.1. 基本安裝
為了安裝已建置的目標,您應該使用 install
規則,該規則遵循通用語法。例如:
install dist : hello helpers ;
這會導致將目標 hello
和 helpers
移動到相對於 Jamfile 目錄的 dist
目錄。可以使用 location
屬性來變更目錄
install dist : hello helpers : <location>/usr/bin ;
雖然您可以透過將目標名稱變更為 /usr/bin
來達到相同的效果,但使用 location
屬性會更好,因為它允許您使用助記符目標名稱。
當位置不固定,而是取決於建置變體或環境變數時,location
屬性特別方便。
install dist : hello helpers :
<variant>release:<location>dist/release
<variant>debug:<location>dist/debug ;
install dist2 : hello helpers : <location>$(DIST) ;
5.4.2. 安裝所有相依性
指定要安裝的所有程式庫名稱可能很乏味。install
允許您僅指定要安裝的頂層可執行目標,並自動安裝所有相依性。
install dist : hello :
<install-dependencies>on <install-type>EXE
<install-type>LIB
;
將會找到 hello
相依的所有目標,並安裝所有可執行檔或程式庫。更具體來說,對於每個目標,將遞迴地找到指定為來源或相依性屬性的其他目標。一個例外是,使用 use
功能參照的目標不會被考慮,因為該功能通常用於參照僅包含標頭檔的程式庫。如果指定了目標類型集,則只會安裝該類型的目標,否則將安裝所有找到的目標。
5.4.3. 保留目錄階層
預設情況下,install
規則會從其來源中移除路徑。因此,如果來源包含 a/b/c.hpp
,則 a/b
部分將被忽略。若要讓 install
規則保留目錄階層,您需要使用 <install-source-root>
功能來指定您要安裝的階層的根目錄。將保留該根目錄的相對路徑。例如,如果您寫入
install headers
: a/b/c.h
: <location>/tmp <install-source-root>a
;
將會建立名為 /tmp/b/c.h
的檔案。
可以使用 glob-tree
規則來尋找給定目錄下的所有檔案,以便輕鬆安裝整個目錄樹。
5.4.4. 安裝到多個目錄
當目標需要安裝到多個目錄時,可以使用 alias
規則。
alias install : install-bin install-lib ;
install install-bin : applications : /usr/bin ;
install install-lib : helper : /usr/lib ;
由於 install
規則僅複製目標,因此大多數自由功能[3]在 install
規則的要求中使用時不起作用。唯一重要的兩個是 dependency
和在 Unix 上的 dll-path
。
ℹ
|
(Unix 特有)在 Unix 上,使用 B2 建置的可執行檔通常包含所有已使用共用程式庫的路徑清單。對於安裝來說,這不是期望的結果,因此 B2 會使用空路徑清單重新連結可執行檔。您也可以使用 dll-path 功能為已安裝的可執行檔指定其他路徑。 |
5.5. 測試
B2 方便地支援執行單元測試。最簡單的方法是 unit-test
規則,它遵循 通用語法。例如
unit-test helpers_test : helpers_test.cpp helpers ;
unit-test
規則的行為類似於 exe 規則,但建立可執行檔後,也會執行該可執行檔。如果可執行檔傳回錯誤代碼,則建置系統也會傳回錯誤,並會在下次調用時嘗試執行可執行檔,直到執行成功。此行為可確保您不會錯過單元測試失敗。
下面列出了一些專門的測試規則
rule compile ( sources : requirements * : target-name ? )
rule compile-fail ( sources : requirements * : target-name ? )
rule link ( sources + : requirements * : target-name ? )
rule link-fail ( sources + : requirements * : target-name ? )
它們會獲得來源清單和需求。如果未提供目標名稱,則會改用第一個來源檔案的名稱。compile*
測試會嘗試編譯傳遞的來源。link*
規則會嘗試從所有傳遞的來源編譯和連結應用程式。compile
和 link
規則預期編譯/連結成功。compile-fail
和 link-fail
規則預期編譯/連結失敗。
有兩個專門的規則用於執行可執行檔,它們比 unit-test
規則更強大。run
規則具有以下簽章
rule run ( sources + : args * : input-files * : requirements * : target-name ?
: default-build * )
該規則會從提供的來源建置應用程式並執行它,並將 args
和 input-files
作為命令列引數傳遞。args
參數會逐字傳遞,並且 input-files
參數的值會被視為相對於包含 Jamfile 的路徑,並且如果 b2
是從不同的目錄調用,則會進行調整。run-fail
規則與 run
規則相同,只是它預期執行失敗。
本節中描述的所有規則,如果成功執行,都會建立一個特殊的清單檔,以指示測試已通過。對於 unit-test
規則,檔案名為 target-name.passed
,對於其他規則,則稱為 target-name.test
。run*
規則也會捕獲程式的所有輸出,並將其儲存在名為 target-name.output
的檔案中。
如果 preserve-test-targets
功能的值為 off
,則 run
和 run-fail
規則會在執行後移除可執行檔。這在某種程度上減少了持續測試環境的磁碟空間需求。preserve-test-targets
功能的預設值為 on
。
可以透過傳遞 --dump-tests
命令列選項來列印您的專案中宣告的所有測試目標清單(除了 unit-test
之外)。輸出將包含以下形式的行
boost-test(test-type) path : sources
可以將測試清單、B2 輸出以及測試通過時建立的 *.test
檔案的存在/不存在處理成人類可讀的測試狀態表。此類處理工具不包含在 B2 中。
以下功能可調整測試 meta 目標的行為。
testing.arg
-
定義在執行目標時,在輸入檔案清單之前要傳遞給目標的引數。
unit-test helpers_test : helpers_test.cpp helpers : <testing.arg>"--foo bar" ;
testing.input-file
-
指定要在引數後面的命令列上傳遞給可執行檔的檔案。由於目前實作中的限制,所有檔案都必須按字母順序指定。
testing.launcher
-
預設情況下,可執行檔會直接執行。有時,需要使用一些輔助命令執行可執行檔。您應該使用此屬性來指定輔助命令的名稱。例如,如果您寫入
unit-test helpers_test : helpers_test.cpp helpers : <testing.launcher>valgrind ;
用於執行可執行檔的命令將是
valgrind bin/$toolset/debug/helpers_test
test-info
-
測試的描述。這會顯示為
--dump-tests
命令列選項的一部分。
5.6. 自訂命令
對於大多數主要目標規則,B2 會自動找出要執行的命令。當您想要使用新的檔案類型或支援新的工具時,一種方法是擴展 B2 以平穩地支援它們,如 擴展器手冊中所述。但是,如果新工具僅在單一位置使用,則可能更容易直接指定要執行的命令。
可以使用三個主要目標規則來實現此目的。make
規則允許您透過執行您指定的命令,從任意數量的來源檔案建構單一檔案。notfile
規則允許您執行任意命令,而無需建立任何檔案。最後,generate
規則允許您使用 B2 的虛擬目標來描述轉換。這比 make
規則操作的檔案名稱層級更高,並允許您建立多個目標、根據屬性建立不同名稱的目標或使用多個工具。
當您想要使用特定命令從多個來源建立一個檔案時,會使用 make
規則。notfile
用於無條件執行命令。
假設您想要透過執行命令 in2out
從檔案 file.in
建立檔案 file.out
。以下是在 B2 中執行此操作的方式
make file.out : file.in : @in2out ;
actions in2out
{
in2out $(<) $(>)
}
如果您執行 b2
且 file.out
不存在,則 B2 會執行 in2out
命令來建立該檔案。有關指定動作的更多詳細資訊,請參閱名為「Boost.Jam 語言」的章節。
可能您只想無條件執行某些命令,而該命令不會建立任何特定檔案。為此,您可以使用 notfile
規則。例如
notfile echo_something : @echo ;
actions echo
{
echo "something"
}
與 make
規則的唯一區別是,目標的名稱不被視為檔案的名稱,因此 B2 將無條件執行該動作。
當您想要使用 B2 的虛擬目標而不是僅使用檔案名稱來表示轉換時,會使用 generate
規則。generate
規則具有標準的主要目標規則簽章,但您必須指定 generating-rule
屬性。屬性的值應採用 @規則名稱
的形式,具名的規則應具有以下簽章
rule generating-rule ( project name : property-set : sources * )
並將使用 project-target
類別的執行個體、主要目標的名稱、包含建置屬性的 property-set
類別的執行個體以及對應於來源的 virtual-target
類別的執行個體清單來呼叫。該規則必須傳回 virtual-target
執行個體的清單。可以透過檢視 build/virtual-target.jam
檔案來瞭解 virtual-target
類別的介面。B2 發行版中包含的 generate
範例說明了如何使用 generate
規則。
5.7. 預先編譯的標頭檔
預先編譯的標頭檔是一種透過建立某些標頭檔的部分處理版本來加速編譯的機制,然後在編譯期間使用該版本,而不是重複剖析原始標頭。B2 支援使用 gcc 和 msvc 工具集的預先編譯標頭檔。
若要使用預先編譯的標頭檔,請遵循以下步驟
-
建立一個標頭檔,其中包含您專案使用且想要預先編譯的標頭檔。最好只包含足夠穩定的標頭檔,例如來自編譯器和外部程式庫的標頭檔。B2 將會自動且按需包含標頭檔。
-
為預編譯標頭宣告一個新的 B2 目標,並將該預編譯標頭新增到您想要加速編譯的目標的原始碼中。
cpp-pch pch : pch.hpp ; exe main : main.cpp pch ;
如果您想在 C 程式中使用預編譯標頭,可以使用
c-pch
規則。
B2 發行版中的 pch
範例可以用作參考。
請注意以下事項:
-
用於編譯原始檔和預編譯標頭的建置屬性必須相同。請考慮使用專案需求來確保這一點。
-
預編譯標頭必須純粹作為改善編譯時間的方法,而不是為了減少
#include
陳述式的數量。如果原始檔需要包含某些標頭,請在原始檔中明確包含它,即使相同的標頭已從預編譯標頭包含。這樣可以確保您的專案即使在不支援預編譯標頭的情況下也能夠建置。 -
在 4.2 版本之前,gcc 編譯器不允許在預編譯標頭中使用匿名命名空間,這限制了它們的實用性。有關詳細資訊,請參閱 錯誤報告。
-
先前,B2 不會自動包含標頭,使用者必須在每個將使用預編譯標頭的原始檔的頂部包含該標頭。
5.8. 產生的標頭
通常,B2 會完全自動處理隱含的依賴性。例如,對於 C++ 檔案,會找到並處理所有 #include
陳述式。可能需要使用者協助的唯一方面是對產生檔案的隱含依賴性。
預設情況下,B2 會在一個主要目標內處理此類依賴性。例如,假設主要目標 "app" 有兩個來源,"app.cpp" 和 "parser.y"。後者來源會轉換為 "parser.c" 和 "parser.h"。然後,如果 "app.cpp" 包含 "parser.h",B2 會偵測到這個依賴性。此外,由於 "parser.h" 將產生到建置目錄中,因此該目錄的路徑會自動新增到 include 路徑。
使這個機制跨主要目標邊界工作是可行的,但會增加一些額外開銷。因此,如果存在對其他主要目標檔案的隱含依賴性,則必須使用 <implicit-dependency>
功能,例如:
lib parser : parser.y ;
exe app : app.cpp : <implicit-dependency>parser ;
上面的範例告訴建置系統,在掃描 "app" 的所有來源以尋找隱含的依賴性時,應將 "parser" 的目標視為潛在的依賴項。
5.9. 交叉編譯
B2 支援使用 gcc 和 msvc 工具集進行交叉編譯。
使用 gcc 時,您首先需要在 user-config.jam
中指定您的交叉編譯器(請參閱名為「組態」的章節),例如:
using gcc : arm : arm-none-linux-gnueabi-g++ ;
之後,如果主機和目標作業系統相同,例如 Linux,您可以直接要求使用此編譯器版本:
b2 toolset=gcc-arm
如果您想以與主機不同的作業系統為目標,您還需要指定 target-os
功能的值,例如:
# On windows box
b2 toolset=gcc-arm target-os=linux
# On Linux box
b2 toolset=gcc-mingw target-os=windows
有關允許的作業系統名稱的完整列表,請參閱 target-os 功能的文件。
使用 msvc 編譯器時,只能在 32 位元主機上交叉編譯到 64 位元系統。有關詳細資訊,請參閱 名為「64 位元支援」的章節。
5.10. 套件管理器
B2 支援從套件管理器自動或手動載入產生的建置檔案。例如,使用 Conan 套件管理器產生 conanbuildinfo.jam
檔案時,B2 會在載入專案的同一位置時自動載入這些檔案。包含的檔案可以在其載入的專案內容中定義目標和其他專案宣告。可以使用以下方式(依優先順序)控制載入哪些套件管理器檔案:
-
使用
use-packages
規則。 -
命令列引數
--use-package-manager=X
。 -
環境變數
PACKAGE_MANAGER_BUILD_INFO
。 -
內建的檔案偵測。目前包括:"conan"。
use-packages
規則
rule use-packages ( name-or-glob-pattern ? )
use-packages
規則允許人們在專案本身中指定要使用的套件定義種類,可以作為內建套件管理器支援的定義。例如:
use-packages conan ;
或指定 glob
模式來尋找具有定義的檔案。例如:
use-packages "packages.jam" ;
--use-package-manager
命令列選項
--use-package-manager=NAME
命令列選項允許人們以非侵入式的方式指定每次調用要使用哪種內建套件管理器類型。
PACKAGE_MANAGER_BUILD_INFO
變數
PACKAGE_MANAGER_BUILD_INFO
變數(取自環境或以 -sX=Y
選項定義)指定要用於尋找套件定義的 glob
模式。
內建偵測
有許多內建的 glob
模式支援常見的套件管理器。目前支援的模式如下:
-
Conan (
conan
):目前支援b2 generator
。
5.11. 搜尋專案
B2 支援自動搜尋參考的全域專案。例如,如果您參考了 /boost/predef
並具有一些最少的組態,B2 可以找到它的 B2 專案並自動解析參考。搜尋支援兩種模式:尋找常規的 B2 專案目錄,以及套件/組態樣式的單個 jam 檔案的載入。
5.11.1. 搜尋路徑
若要控制尋找哪些專案以及在哪裡找到專案,可以使用不同的方法:
-
B2_PROJECT_PATH
環境變數。 -
--project-search
命令列引數。 -
rule project-search
專案規則。
B2_PROJECT_PATH
和 --project-search
中的搜尋路徑指定一個 project-id 和 path 的鍵值列表。該鍵值列表的各部分(顧名思義)是一個路徑分隔符號分隔的列表。例如,如果我們有這兩個想要找到的專案:/zlib
和 /boost/asio
,則搜尋路徑可能如下所示:
Linux |
|
Windows、VxWorks |
|
VMS |
|
搜尋路徑規格中的 project-id 將該專案根目錄對應到指示的 path。B2 將使用該路徑來搜尋具有該 project-id 根目錄的任何專案和子專案。
5.11.2. 搜尋流程
無論如何指定搜尋路徑,搜尋方式都是相同的。搜尋包括搜尋 B2 專案目錄(即包含 jamfile 的目錄),或搜尋要包含的特別命名的 *.jam
檔案(類似於套件管理器支援如何包含 jam 檔案)。
對於給定形式為 /d1/d2/../dn
的 project-id,我們按以下順序搜尋:
-
在為
/
根目錄註冊的任何路徑中,d1/d2/../dn
處的專案。 -
在為
/d1/d2/../dn-1
根目錄註冊的任何路徑中,dn
處的專案。 -
在為
/d1/d2/../dn-1
根目錄註冊的任何路徑中,dn.jam
jamfile。 -
在為
/d1/d2/../dn-2
根目錄註冊的任何路徑中,dn-1_dn
處的專案。 -
在為
/d1/d2/../dn-2
根目錄註冊的任何路徑中,dn-1_dn.jam
jamfile。 -
依此類推,直到在為
/
根目錄註冊的任何路徑中搜尋專案d1_d2_.._dn
。 -
以及在為
/
根目錄註冊的任何路徑中搜尋 jamfiled1_d2_.._dn.jam
。
例如,使用此搜尋路徑:
-
/boost
:/usr/share/boost-1.81.0
,/home/user/boost-dev/libs
-
/
:/usr/share/b2/external
並給定要解析的 /boost/core
project-id,我們搜尋:
-
/usr/share/b2/external/boost/core/<jamfile>
-
/usr/share/boost-1.81.0/core/<jamfile>
-
/home/user/boost-dev/libs/core/<jamfile>
-
/usr/share/boost-1.81.0/core.jam
-
/home/user/boost-dev/libs/core.jam
-
/usr/share/boost-1.81.0/boost_core/<jamfile>
-
/home/user/boost-dev/libs/boost_core/<jamfile>
-
/usr/share/boost-1.81.0/boost_core.jam
-
/home/user/boost-dev/libs/boost_core.jam
-
/usr/share/b2/external/boost_core.jam
第一個專案 jamfile 將分配給該 project-id。或載入找到的第一個 *.jam
檔案。
5.12. 命令資料庫和 IDE 整合
許多 IDE 程式接受使用 compile_commands.json
檔案來了解您的專案建置方式和內容。B2 支援為您進行的任何建置產生此類檔案。B2 通過一個通用設施來支援此功能,該設施可從其執行的動作中提取命令。有兩個選項可以控制此功能。--command-database=format
選項表示為給定的 format 產生檔案。指定後會產生幾個效果:
-
它告訴 B2 開始觀察和提取動作中的命令(由工具集指定)。
-
它停用動作的執行。也就是說,等同於新增
-n
選項。 -
它啟用建置所有預設和指定的目標。也就是說,等同於新增
-a
選項。 -
它停用所有動作執行輸出。也就是說,就像指定
-d0
選項一樣。 -
在主要建置結束時,它會將觀察到的結果寫入到資料庫檔案中。
目前,僅支援 json
作為符合 Clang JSON 編譯資料庫格式規範的格式。
--command-database-out=file
選項控制產生檔案的名稱,以及可選的位置。預設情況下,file 是 compile_commands.json
,以遵循生態系統慣例。預設情況下,它是在以下位置之一產生:
-
相對於根專案的
build-dir
(如果專案指定)。使用預設 file 名稱或給定的名稱。 -
如果它是根目錄,則在絕對 file 路徑上。
-
在目前工作目錄中。
產生的資料庫中會填入以下欄位:
-
directory
- 這將始終是目前目錄,因為 B2 使所有路徑都相對於該目錄(或絕對路徑)。 -
file
- 記錄的每個動作的第一個來源。 -
command
- 工具集提取的引號括起來的完整命令。 -
output
- 記錄的每個動作的第一個目標檔案。由於 B2 可以同時建置多個變體,因此需要區分同一個來源檔案的多個編譯。
ℹ
|
每次調用 b2 時僅產生一個命令資料庫檔案。並且每次產生時,它都會覆蓋任何先前的此類檔案。 |
6. 參考
6.1. 一般資訊
6.1.1. 初始化
啟動後,B2 引擎 (b2
) 會立即載入實作建置系統的 Jam 程式碼。為此,它會在特定的安裝位置搜尋建置系統 bootstrap.jam
檔案。搜尋依據 b2(.exe)
執行檔的位置。
預設的 bootstrap.jam
在載入一些標準定義後,會載入 site-config.jam
和 user-config.jam
。
ℹ
|
為了維持向後相容性,如果存在名為 boost-build.jam 的檔案,也會被載入。搜尋會先從調用目錄開始,然後是其父目錄,依此類推直到檔案系統根目錄,最後是在環境變數 BOOST_BUILD_PATH 指定的目錄中搜尋。在 Unix 上,BOOST_BUILD_PATH 預設為 /usr/share/b2 。 |
6.2. 內建規則
本節包含可在 Jamfile 中使用的所有規則列表,包括定義新目標的規則和輔助規則。
exe
-
建立可執行檔。請參閱「程式」章節。
lib
-
建立函式庫檔案。請參閱「函式庫」章節。
install
-
安裝建置的目標和其他檔案。請參閱「安裝」章節。
alias
-
為其他目標建立別名。請參閱「別名」章節。
unit-test
-
建立會自動執行的可執行檔。請參閱「測試」章節。
compile
;compile-fail
;link
;link-fail
;run
;run-fail
-
用於測試的特殊規則。請參閱「測試」章節。
check-target-builds
-
check-target-builds
允許您根據某些 meta 目標是否建置來有條件地使用不同的屬性。這類似於autotools
專案中組態腳本的功能。函式簽章為rule check-target-builds ( target message ? : true-properties * : false-properties * )
此函式僅適用於將需求或使用需求傳遞給 meta 目標規則時。例如,如果要讓應用程式連結到可用的函式庫,必須使用以下方式
exe app : app.cpp : [ check-target-builds has_foo "System has foo" : <library>foo : <define>FOO_MISSING=1 ] ;
另一個範例,別名規則可用於整合組態選項,並使其對其他 meta 目標可用,如下所示
alias foobar : : : : [ check-target-builds has_foo "System has foo" : <library>foo : <library>bar ] ;
obj
-
建立物件檔案。當單一來源檔案必須使用特殊屬性進行編譯時很有用。
preprocessed
-
建立預處理的來源檔案。引數遵循通用語法。
glob
-
glob
規則接受 shell 模式的列表,並傳回專案來源目錄中符合模式的檔案列表。例如lib tools : [ glob *.cpp ] ;
也可以傳遞第二個引數,即排除模式的列表。結果將包含符合任何包含模式,且不符合任何排除模式的檔案列表。例如
lib tools : [ glob *.cpp : file_to_exclude.cpp bad*.cpp ] ;
glob-tree
-
glob-tree
類似於glob
,不同之處在於它會從包含 Jamfile 的目錄開始遞迴運作。例如ECHO [ glob-tree *.cpp : .svn ] ;
將會列印專案中所有 C++ 檔案的名稱。
.svn
排除模式會防止glob-tree
規則進入 Subversion 版本控制系統的管理目錄。 project
-
宣告專案 ID 和屬性,包括專案需求。請參閱「專案」章節。
use-project
-
將符號專案 ID 指派給指定路徑的專案。此規則需要更完善的文件說明!
explicit
-
explicit
規則採用單一參數,即目標名稱的列表。已命名的目標將被標記為明確的,並且只有在命令列上明確請求或其依賴項已建置時才會建置。將此與普通目標進行比較,普通目標在其包含專案建置時會隱式建置。 always
-
always
函式採用單一參數,即 meta 目標名稱的列表。由已命名的 meta 目標產生的目標將始終被視為過時的。請考慮以下範例exe hello : hello.cpp ; exe bye : bye.cpp ; always hello ;
如果請求建置
hello
,則始終會重新編譯。請注意,如果沒有請求建置hello
,例如,您僅在命令列上指定bye
,則不會重新編譯hello
。 constant
-
設定專案範圍的常數。採用兩個參數:變數名稱和值,並使指定的變數名稱在此 Jamfile 和任何子 Jamfile 中可存取。例如
constant VERSION : 1.34.0 ;
path-constant
-
與
constant
相同,不同之處在於該值被視為相對於 Jamfile 位置的路徑。例如,如果在目前目錄中調用b2
,並且helper
子目錄中的 Jamfile 具有path-constant DATA : data/a.txt ;
則變數
DATA
將設定為helper/data/a.txt
,如果從helper
目錄調用b2
,則變數DATA
將設定為data/a.txt
。 build-project
-
使其他專案建置。此規則採用單一參數,即相對於包含 Jamfile 的目錄名稱。當建置包含 Jamfile 時,也會建置位於該目錄的專案。目前,此規則的參數應該是目錄名稱。不允許使用專案 ID 或一般目標參考。
test-suite
-
此規則已棄用,等效於
alias
。 import-search
-
Jam 規則 import-search ( reference )
將指定的
reference
路徑新增至import
將搜尋的目錄集。reference
可以是普通目錄或已知專案路徑。如果給定專案路徑,將會搜尋並解析以包含參考中的任何子專案路徑。如果給定目錄,則其根目錄將相對於目前專案位置。範例專案路徑用法import-search /boost/config/checks ; import-search /boost/predef/tools/checks ;
6.3. 內建功能
本節說明 B2 中內建的功能。對於具有固定值集合的功能,會提供該集合,預設值會列在最前面。
address-model
-
允許值:
32
、64
。指定編譯器應產生 32 位元或 64 位元程式碼。此功能是否有效取決於所使用的編譯器、其版本、編譯器的設定方式以及
architecture
、instruction-set
功能的值。詳細資訊請參閱C++ 編譯器章節。 address-sanitizer
-
允許值:
on
、norecover
。啟用 Address Sanitizer。值
norecover
會停用 sanitizer 的復原功能。此功能是選用的,因此預設不會啟用任何 sanitizer。 allow
-
此功能用於允許執行特定的產生器。例如,只有在使用 Qt 函式庫時才能調用 Qt 工具。在這種情況下,
<allow>qt
將會是該函式庫的使用需求。 architecture
-
允許值:
x86
、ia64
、sparc
、power
、mips
、mips1
、mips2
、mips3
、mips4
、mips32
、mips32r2
、mips64
、parisc
、arm
、s390x
、loongarch
。指定要產生程式碼的通用處理器系列。
archiveflags
-
此功能的值會在建立靜態函式庫時,未經修改地傳遞給封存工具。
asmflags
-
此功能的值會未經修改地傳遞給組譯器。
asynch-exceptions
-
允許值:
off
、on
。選擇是否支援非同步 EH (例如,捕捉 SEGVs)。
build
-
允許值:
no
用於有條件地停用目標的建置。如果在建置目標時,屬性中包含
<build>no
,則會跳過該目標的建置。與條件需求結合使用,這可讓您在已知建置會失敗的組態中跳過建置某些目標。 cflags
;cxxflags
;linkflags
-
這些功能的值會未經修改地傳遞給對應的工具。對於
cflags
,這是 C 和 C++ 編譯器,對於cxxflags
,這是 C++ 編譯器,對於linkflags
,這是連結器。當您嘗試執行 B2 中較高層級功能無法實現的特殊操作時,這些功能非常方便。 compileflags
-
此功能的值會未經修改地傳遞給對應的工具。來自
compileflags
的值會套用至工具的所有語言編譯。 conditional
-
用於引入間接條件需求。值應具有以下格式
@rulename
其中 rulename 應該是一個規則的名稱,其簽章如下
rule rulename ( properties * )
將會針對每個具有其屬性的目標呼叫此規則,並應傳回任何其他屬性。另請參閱需求章節以取得範例。
coverage
-
允許值:
off
、on
。啟用程式碼檢測,以便在執行期間產生涵蓋範圍資料。
cxxflags
-
請參閱
<cflags>
。 cxxstd
-
允許值:
98
、03
、0x
、11
、1y
、14
、1z
、17
、2a
、20
、2b
、23
、2c
、26
、latest
。指定要使用其建置的 C++ 標準語言版本。所有自「98」以來的所有正式標準版本都已包含在內。也可以指定使用實驗性、正在進行中的
latest
版本。有些編譯器為實驗版本指定了中間版本,這些版本引領到發布的標準版本。這些版本以 GNU 命名法包含在內,如0x
、1y
、1z
、2a
、2b
和2c
。根據編譯器,latest
會對應到其中一個。
ℹ
|
這是一個選用 功能。因此,如果未指定,則會使用編譯器預設行為。 |
ℹ
|
請查閱工具組特定文件,以了解支援哪些 cxxstd 。 |
cxxstd-dialect
-
子功能:
cxxstd
的一部分允許的值:
iso
、gnu
、ms
。指示是否應使用非標準的方言。這些方言通常具有擴展功能或平台特定的功能。若未指定方言,則預設為 'iso',這會盡可能使用 ISO C++ 標準的一致性。
c++abi
-
如果編譯器支援多種 C++ ABI 變體,則選取特定的 C++ ABI 變體。
c++-template-depth
-
允許的值:任何正整數。
允許使用最大的模板實例化深度參數來配置 C++ 編譯器。特定的工具集可能支援也可能不支援此功能,具體取決於其編譯器是否提供對應的命令行選項。
ℹ由於目前 B2 實作中的一些內部細節,不可能讓功能的值都是正整數。作為一種變通方法,已為此功能定義了一組龐大的允許值,如果需要不同的值,使用者可以透過呼叫 `feature.extend` 規則輕鬆添加。 debug-symbols
-
允許的值:
on
、off
。指定產生的物件檔案、執行檔和程式庫是否應包含偵錯資訊。通常,此功能的值由 `variant` 功能隱式設定,但使用者可以明確指定。最常見的用法是建置帶有偵錯資訊的發行版本。
define
-
指定應該在命令列上定義的預處理器符號。您可以只指定符號(將不帶任何值定義),也可以同時指定符號和值,並以等號分隔。
def-file
-
提供一種為 Windows DLL 指定 def 檔案的方法。
dependency
-
引入對此功能值所命名之目標的依賴關係(因此,每當宣告的目標是最新的,它也會被帶到最新狀態)。此依賴關係不會以任何其他方式使用。
dll-path
(僅限 _Unix_)-
允許的值:共享程式庫的目錄路徑。
指定在執行目標時,系統應尋找共享程式庫的其他目錄。
⚠請注意,相對路徑將會附加相關 `jam` 檔案的目錄(如在 `b2` 命令列中提供的),因此 _嚴重地_ 限制了其實際使用! 有關詳細資訊,請參閱關於 `dll-path` 和 `hardcode-dll-paths` 的 FAQ 條目,以及 `hardcode-dll-paths` 功能,以自動為開發添加路徑。
embed-manifest
-
允許的值:
on
、off
。此功能特定於 `msvc` 工具集(請參閱 Microsoft Visual C++),並控制是否應將 manifest 檔案嵌入到執行檔和共享程式庫中,或將它們放置在旁邊。此功能對應於專案設定對話方塊中的 IDE 選項,位於「組態屬性」→「Manifest 工具」→「輸入和輸出」→「嵌入 Manifest」。
embed-manifest-file
-
此功能特定於 `msvc` 工具集(請參閱 Microsoft Visual C++),並控制應將哪些 manifest 檔案嵌入到執行檔和共享程式庫中。此功能對應於專案設定對話方塊中的 IDE 選項,位於「組態屬性」→「Manifest 工具」→「輸入和輸出」→「其他 Manifest 檔案」。
embed-manifest-via
-
此功能特定於 `msvc` 工具集(請參閱 Microsoft Visual C++),並控制是否應該透過連結器或 Manifest 工具嵌入 manifest。
exception-handling
-
允許的值:
on
、off
。停用例外狀況。
extern-c-nothrow
-
允許值:
off
、on
。選取是否預設將所有 `extern "C"` 函式視為 `nothrow`。
fflags
-
此功能的值在編譯 Fortran 原始碼時會未經修改地傳遞給工具。
file
-
當在預先建置的程式庫目標的需求中使用時,此功能會指定程式庫檔案的路徑。有關範例,請參閱 預先建置的目標。
find-shared-library
-
新增要連結的共享程式庫。通常應該優先選擇 `lib` 目標,而不是使用此功能。
find-static-library
-
新增要連結的靜態程式庫。通常應該優先選擇 `lib` 目標,而不是使用此功能。
flags
-
此功能用於工具的通用標誌(即非特定語言的標誌)。此功能的值會未經修改地傳遞給將建置目標的工具。
hardcode-dll-paths
(僅限 _Unix_)-
允許的值:
true
、false
。
預設為:true
(`exe`)、false
(`install`)
忽略對象:`lib`當使用 `<hardcode-dll-paths>true`(預設)建置 `exe` 可執行檔時,目標二進位檔將會與包含所有已使用共享程式庫目錄路徑的 _rpath 清單_連結。
當使用 `<hardcode-dll-paths>true` 安裝目標時,這些相同的路徑以及使用 `<dll-path>` 添加的任何路徑,都會傳播到產生的二進位檔。
此功能的目的是協助開發;產生的可執行檔(`exe`,但不是 `install` 目標)預設可以執行,而無需變更共享程式庫的系統路徑或將程式庫安裝到系統路徑。
有關詳細資訊,請參閱 FAQ 條目。 implicit-dependency
-
指出此功能值所命名的目標可能會產生包含在宣告之目標的原始碼中的檔案。有關更多資訊,請參閱 產生的標頭 一節。
force-include
-
指定一個包含路徑,該路徑必須以與在每個目標原始碼檔案的第一行出現 `#include "file"` 類似的方式包含。
如果在單個目標上多次使用,則不保證包含順序。
include
-
指定要傳遞給 C 和 C++ 編譯器的其他包含路徑。
inlining
-
允許的值:
off
、on
、full
。啟用內嵌。
install-package
-
指定已安裝檔案所屬的套件名稱。這用於某些平台上的預設安裝前綴。
install-<name>
-
指定 `install` 目標的安裝前綴。這些命名的安裝前綴預設會註冊
-
prefix
:如果屬性集中有 `<target-os>windows`,則為 `C:\<套件名稱>`,否則為 `/usr/local` -
exec-prefix
:`(prefix)` -
bindir
:`(exec-prefix)/bin` -
sbindir
:`(exec-prefix)/sbin` -
libexecdir
:`(exec-prefix)/libexec` -
libdir
:`(exec-prefix)/lib` -
datarootdir
:`(prefix)/share` -
datadir
:`(datarootdir)` -
sysconfdir
:`(prefix)/etc` -
sharedstatedir
:`(prefix)/com` -
localstatedir
:`(prefix)/var` -
runstatedir
:`(localstatedir)/run` -
includedir
:`(prefix)/include` -
oldincludedir
:`/usr/include` -
docdir
:`(datarootdir)/doc/<套件名稱>` -
infodir
:`(datarootdir)/info` -
htmldir
:`(docdir)` -
dvidir
:`(docdir)` -
pdfdir
:`(docdir)` -
psdir
:`(docdir)` -
lispdir
:`(datarootdir)/emacs/site-lisp` -
localedir
:`(datarootdir)/locale` -
mandir
:`(datarootdir)/man`
-
如果需要更多,可以使用 `stage.add-install-dir` 來新增。
instruction-set
-
允許的值:取決於使用的工具集。
指定應該為其產生程式碼的特定指令集。一般來說,程式碼可能無法在具有較舊/不同指令集的處理器上執行。
雖然 B2 允許此功能使用大量可能的值,但給定值是否有效取決於您使用的編譯器。有關詳細資訊,請參閱 C++ 編譯器 一節。
library
-
此功能幾乎等同於 `<source>` 功能,不同之處在於它僅在連結時生效。當您想要將 Jamfile 中的所有目標連結到特定程式庫時,`<library>` 功能優先於 `<source>X`,後者會將程式庫添加到所有目標,即使是那些與程式庫無關的目標。
library-path
-
添加到連結器將用於搜尋程式庫的目錄清單中。
leak-sanitizer
-
允許值:
on
、norecover
。啟用記憶體洩漏清理器。值 `norecover` 會停用清理器的恢復。此功能是選用的,因此預設不會啟用任何清理器。
linemarkers
-
允許的值:
off
。在預處理目標上,會變更行為以發出/省略行指令,例如 `#line` 和 `#*linenum*`。
注意:該值不會傳播。
link
-
允許的值:
shared
、static
控制程式庫的建置方式。
linkflags
-
請參閱
<cflags>
。 local-visibility
-
允許的值:
global
、protected
、hidden
。此功能具有與 `visibility` 功能相同的效果,但旨在由需要特定符號可見性的目標使用。與 `visibility` 功能不同,`local-visibility` 不會由目標依賴項繼承,並且僅會影響應用該功能的目標。
`local-visibility` 功能支援與 `visibility` 功能相同的值,且含義相同。預設情況下,如果未為目標指定 `local-visibility`,則會使用 `visibility` 功能的值。
location
-
指定目標的建置目錄。此功能主要與 `<install>` 規則一起使用。
location-prefix
-
將目標的建置目錄設定為專案的建置目錄,並以該功能的值作為前綴。有關範例,請參閱 目標路徑 一節。
mflags
-
此功能的值在編譯 Objective C 原始碼時會未經修改地傳遞給工具。
mmflags
-
編譯 Objective C++ 原始碼時,此功能的值會不經修改地傳遞給工具。
name
-
當用於預先構建的函式庫目標的需求時,此功能指定函式庫的名稱(函式庫檔案的名稱,不包含任何平台特定的後綴或前綴)。請參閱 預先構建的目標 以取得範例。
當用於
<install>
目標的需求時,它會指定目標檔案的名稱。 optimization
-
允許的值:
off
、speed
、space
、minimal
、debug
。啟用最佳化。
speed
為加速程式碼進行最佳化,space
為縮小二進位檔進行最佳化。 profiling
-
允許值:
off
、on
。啟用產生額外的程式碼來寫入效能分析資訊。
relevant
-
允許的值: 任何功能的名稱。
指出特定目標的相關其他功能。通常不需要明確管理它,因為 B2 在大多數情況下可以推斷出來。不相關的功能不會影響目標路徑,也不會導致衝突。
-
如果符合以下任何條件,則會認為功能是相關的
-
它被
toolset.flags
或toolset.uses-features
引用 -
它被產生器的需求使用
-
它是相關功能的子功能
-
它有相關的子功能
-
它是複合功能,並且任何組成的功能都是相關的
-
它會影響主要目標的目標替代選擇
-
它是傳播的功能,且與任何相依性相關
-
它與相同主要目標建立的任何相依性相關
-
它用於條件屬性的條件中,且對應的值是相關的
-
它被明確命名為相關的
-
-
在下列情況下,無法自動推斷相關功能
-
間接條件。解決方案:傳回
<relevant>結果功能:<relevant>條件功能
形式的屬性ℹ這實際上不是條件,儘管在大多數情況下它的功能類似於條件。特別是,它不支援條件中的多個以逗號分隔的元素,並且即使在不允許條件屬性的情況下也能正確運作 -
讀取屬性的動作規則。解決方案:新增 toolset.uses-features 來告知 B2 該功能實際上正在使用。
-
直接操作屬性集合的產生器和目標。解決方案:手動設定 <relevant>。
-
-
rtti
-
允許的值:
on
、off
。停用執行階段類型資訊。
runtime-debugging
-
允許的值:
on
、off
。指定產生的物件檔案、可執行檔和函式庫是否應包含僅對除錯有用的行為,例如斷言。通常,此功能的值會由
variant
功能隱式設定,但使用者可以明確指定。最常見的用法是建置帶有除錯輸出的發行版本。 runtime-link
-
允許的值:
shared
、static
控制應使用靜態或共享 C/C++ 執行階段。此功能的使用方式有一些限制,例如在某些編譯器上,使用靜態執行階段的應用程式根本不應使用共享函式庫,而在某些編譯器上,混合靜態和共享執行階段需要極其小心。請參閱您的編譯器文件以獲取更多詳細資訊。
search
-
當用於預先構建的函式庫目標的需求時,此功能會新增至搜尋函式庫檔案的目錄清單。請參閱 預先構建的目標 以取得範例。
source
-
<source>X
屬性對於建置目標具有與將 X 放入原始碼清單相同的效果。當您想要將相同的原始碼新增至專案中的所有目標時(您可以在需求中放入<source>
),或有條件地包含原始碼時(使用條件需求,請參閱 條件和替代方案 一節),它很有用。另請參閱<library>
功能。 staging-prefix
-
指定
install
目標的暫存前綴。如果存在,它將被用來代替命名目錄prefix
的路徑。範例project : requirements <install-prefix>x/y/z ; install a1 : a : <location>(bindir) ; # installs into x/y/z/bin install a2 : a : <location>(bindir) <staging-prefix>q ; # installs into q/bin
當您無法(或不想)在建置期間將建置成品放入其預定的位置時(例如在交叉編譯時),但仍然需要將這些預定的位置傳達給建置系統(例如產生組態檔案)時,此功能很有用。
stdlib
-
允許的值:
native
、gnu
、gnu11
、libc++
、sun-stlport
、apache
。指定要連結的 C++ 標準函式庫,以及在某些情況下要使用的函式庫 ABI
native
-
使用編譯器的預設值。
gnu
-
使用具有舊 ABI 的 GNU 標準函式庫 (又名 libstdc++)。
gnu11
-
使用具有新 ABI 的 GNU 標準函式庫。
libc++
-
使用 LLVM libc++。
sun-stlport
-
使用 Solaris Studio 編譯器提供的標準函式庫的 STLport 實作。
apache
-
使用 Solaris Studio 編譯器提供的 Apache stdcxx 版本 4 C++ 標準函式庫。
strip
-
允許值:
off
、on
。控制是否應剝離二進位檔—也就是移除運行不需要的所有內容。
ℹ此功能將會顯示在所有內容的目標路徑中,而不僅僅是二進位檔。 suppress-import-lib
-
抑制連結器建立匯入函式庫。
tag
-
用於自訂產生的檔案名稱。該值應具有以下形式
@rulename
其中 rulename 應該是一個規則的名稱,其簽章如下
rule tag ( name : type ? : property-set )
將為每個具有 B2 計算的預設名稱、目標類型和屬性集的目標呼叫規則。該規則可以傳回一個必須用作目標名稱的字串,或一個空字串,在這種情況下將使用預設名稱。
tag
功能最典型的用途是在函式庫目標名稱中編碼建置屬性或函式庫版本。您應該注意僅針對您關心的類型從標籤規則中傳回非空字串—否則,您最終可能會修改物件檔案、產生的標頭檔和其他目標的名稱,而更改名稱是沒有意義的。 target-os
-
允許的值:
aix
、android
、appletv
、bsd
、cygwin
、darwin
、freebsd
、haiku
、hpux
、iphone
、linux
、netbsd
、openbsd
、osf
、qnx
、qnxnto
、sgi
、solaris
、unix
、unixware
、windows
、vms
、vxworks
、freertos
。指定要產生程式碼的作業系統。您使用的編譯器應該是該作業系統的編譯器。此選項會導致 B2 使用適用於該作業系統的命名慣例,並相應地調整建置程序。例如,使用 gcc 時,它會控制是否為共享函式庫產生匯入函式庫。
有關交叉編譯的詳細資訊,請參閱 交叉編譯 一節。
threadapi
-
允許的值:
pthread
、win32
。選取執行緒實作。如果
<target-os>
為windows
,則預設值為win32
,否則為pthread
。 threading
-
允許的值:
single
、multi
控制是否應在多執行緒模式下建置專案。此功能不一定會更改編譯器中的程式碼產生,但它會導致編譯器連結到其他或不同的執行階段函式庫,並定義其他前置處理器符號(例如,Windows 上的
_MT
和 Linux 上的_REENTRANT
)。這些符號如何影響編譯的程式碼取決於程式碼本身。 thread-sanitizer
-
允許值:
on
、norecover
。啟用執行緒清理器。值
norecover
會停用清理器的恢復功能。此功能是可選的,因此預設情況下不會啟用清理器。 toolset
-
允許的值: 任何工具集模組。
選取將用於建置二進位目標的工具集。工具集模組的完整清單位於 內建工具 一節中。
undef
-
指定要取消定義的前置處理器符號。
undefined-sanitizer
-
允許值:
on
、norecover
。啟用未定義行為清理器。值
norecover
會停用清理器的恢復功能。此功能是可選的,因此預設情況下不會啟用清理器。 use
-
引入對此功能值命名的目標的相依性(因此每當宣告的目標是最新的時,它都會被更新),並將其使用需求新增至宣告的目標的建置屬性。該相依性不會以任何其他方式使用。主要的使用案例是當您想要應用某些函式庫的使用需求(例如
#include
路徑),但不想要連結到它時。 user-interface
-
允許的值:
console
、gui
、wince
、native
、auto
。指定可執行檔的環境,這會影響連結器將選取的進入點符號(或進入點函式)。此功能是 Windows 特有的。
console
-
主控台應用程式。
gui
-
應用程式不需要主控台(它應該建立自己的視窗)。
wince
-
應用程式旨在在具有 Windows CE 核心版本的裝置上運行。
native
-
應用程式在沒有子系統環境的情況下運行。
auto
-
應用程式在 Windows 的 POSIX 子系統中運行。
variant
-
允許的值:
debug
、release
、profile
。結合多個低階功能的功能,可以輕鬆請求常見的建置組態。
值
debug
會展開為<optimization>off <debug-symbols>on <inlining>off <runtime-debugging>on
值
release
會展開為<optimization>speed <debug-symbols>off <inlining>full <runtime-debugging>off
值
profile
會展開為與release
相同的值,再加上<profiling>on <debug-symbols>on
使用者可以使用
common
模組中的variant
規則來定義自己的建置變體。ℹ為了滿足習慣於各種 IDE 的人們的期望,除錯建置中會啟用執行階段除錯。 vectorize
-
允許的值:
off
、on
、full
。啟用向量化。
version
-
任何內建工具都不會使用此功能,但可以使用此功能,例如,透過
<tag>
功能調整目標的名稱。 visibility
-
允許的值:
global
、protected
、hidden
。指定編譯二進位檔中的預設符號可見性。並非所有平台都支援所有值,並且在某些平台(例如 Windows)上,根本不支援符號可見性。
支援的值具有以下含義
global
-
在 gcc 文件中又名為「default」。全域符號被視為公開,它們從共享函式庫中匯出,並且可以由另一個共享函式庫或可執行檔重新定義。
protected
-
又名為「symbolic」。受保護的符號從共享函式庫中匯出,但不能由另一個共享函式庫或可執行檔重新定義。某些平台(例如 OS X)不支援此模式。
hidden
-
隱藏符號不會從共享函式庫中匯出,也不能由在進程中載入的不同共享函式庫或可執行檔重新定義。在此模式下,必須在原始程式碼中明確標記公共符號,以便從共享函式庫匯出。這是建議的模式。
預設情況下,使用編譯器預設可見性模式(不新增任何編譯器標誌)。
ℹ在 Boost 超級專案的 Jamroot 檔案中,此屬性預設值設定為 hidden
。這表示 Boost 函式庫預設會以隱藏可見性 (hidden visibility) 建置,除非使用者使用不同的visibility
覆寫,或函式庫設定不同的local-visibility
(請參閱下方)。
warnings
-
允許的值:
on
、all
、extra
、pedantic
、off
。控制編譯器的警告層級。
on
-
啟用預設/"合理"的警告層級。
all
-
啟用大多數警告。
extra
-
啟用額外的、可能衝突的警告。
pedantic
-
啟用可能不重要且會衝突的警告。
off
-
停用所有警告。
預設值為
all
。
warnings-as-errors
-
允許值:
off
、on
。可以將警告視為錯誤,並在出現警告時中止編譯。
translate-path
-
用於導入自訂路徑特性轉譯。值應具有以下形式
@rulename
其中 rulename 應該是一個規則的名稱,其簽章如下
rule rulename ( feature value : properties * : project-id : project-location )
對於每個具有路徑特性 (path property) 的目標,都會呼叫此規則,並傳入路徑特性值、目標屬性、目標專案 ID 和目標專案位置。它應返回轉譯的路徑值。如果它不進行路徑轉譯,則不返回任何值。讓它執行預設的路徑轉譯。
lto
-
允許的值:
on
。啟用連結時間最佳化 (Link Time Optimizations),也稱為跨程序最佳化 (Interprocedural Optimizations) 或全程式最佳化 (Whole-Program Optimizations)。目前支援的工具組為 GNU C++、clang 和 Microsoft Visual C++。此特性為選用。
lto-mode
-
lto
的子特性允許的值:
full
、thin
、fat
。指定要使用的 LTO 類型。
full
-
使用單體式 LTO:在連結時,所有輸入都會合併到單一模組中。
thin
-
使用 clang 的 ThinLTO:每個編譯檔案都包含模組的摘要,這些摘要會合併到單一索引中。這可以避免將所有模組合併在一起,從而大大減少連結時間。
fat
-
產生 gcc 的 fat LTO 物件:編譯檔案同時包含適用於 LTO 的中間語言和適用於常規連結的物件程式碼。
response-file
-
允許的值:
auto
、file
、contents
。控制在建置適用目標時是否使用回應檔。對於
file
,會建立回應檔,並在動作中取代檔案名稱。對於contents
,動作中會取代內容 (:E=
),且不會建立回應檔。對於auto
,會根據內容的長度建立回應檔或取代內容,以便如果內容符合命令執行行長度限制,則會取代內容。否則,會建立回應檔,並在動作中取代檔案名稱。支援
clang-linux
和msvc
工具組。
6.4. 內建工具
B2 支援大量的 C++ 編譯器和其他工具。本節說明如何使用這些工具。
在使用任何工具之前,您必須宣告您的意圖,並可能指定有關工具組態的其他資訊。這是透過呼叫 using
規則來完成的,通常在您的 user-config.jam
中,例如
using gcc ;
可以像其他規則一樣傳遞其他參數,例如
using gcc : 4.0 : g++-4.0 ;
每個工具可以傳遞的選項記錄在後續章節中。
6.4.1. C++ 編譯器
本節列出所有支援 C++ 編譯器的 B2 模組,並記錄如何初始化每個模組。編譯器的支援模組名稱也是可用於明確要求該編譯器的 toolset
特性的值。
HP aC++ 編譯器
acc
模組支援 HP-UX 作業系統的 HP aC++ 編譯器。
該模組使用以下語法初始化
using acc : [version] : [c++-compile-command] : [compiler options] ;
如果您想設定多個編譯器版本,可以重複此陳述式多次。
如果未指定命令,將會在 PATH 中搜尋 aCC
二進位檔。
可以使用`<option-name>option-value 語法`提供以下選項
cflags
-
指定編譯 C 原始檔時要使用的其他編譯器旗標。
cxxflags
-
指定編譯 C++ 原始檔時要使用的其他編譯器旗標。
compileflags
-
指定編譯 C 和 C++ 原始檔時要使用的其他編譯器旗標。
linkflags
-
指定將傳遞給連結器的其他命令列選項。
Borland C++ 編譯器
borland
模組支援在 Microsoft Windows 上執行的 32 位元命令列 C 編譯器。這是所有 Borland C 和 C Builder 版本的 bcc32 可執行檔,以及較新版本 C Builder 上的命令列相容編譯器 bcc32c。
該模組使用以下語法初始化
using borland : [version] : [c++-compile-command] : [compiler options] ;
如果您想設定多個編譯器版本,可以重複此陳述式多次。
如果未指定命令,Boost.Build 將會在 PATH 中搜尋名為 bcc32
的二進位檔。
可以使用`<option-name>option-value 語法`提供以下選項
cflags
-
指定編譯 C 原始檔時要使用的其他編譯器旗標。
cxxflags
-
指定編譯 C++ 原始檔時要使用的其他編譯器旗標。
compileflags
-
指定編譯 C 和 C++ 原始檔時要使用的其他編譯器旗標。
linkflags
-
指定將傳遞給連結器的其他命令列選項。
user-interface
-
指定應用程式的使用者介面。有效的選擇為:
console
(主控台應用程式) 和gui
(Windows 應用程式)。
Comeau C/C++ 編譯器
como-linux
和 como-win
模組分別支援 Linux 和 Windows 上的 Comeau C/C++ 編譯器。
該模組使用以下語法初始化
using como : [version] : [c++-compile-command] : [compiler options] ;
如果您想設定多個編譯器版本,可以重複此陳述式多次。
如果未指定命令,B2 將會在 PATH 中搜尋名為 como
的二進位檔。
可以使用`<option-name>option-value 語法`提供以下選項
cflags
-
指定編譯 C 原始檔時要使用的其他編譯器旗標。
cxxflags
-
指定編譯 C++ 原始檔時要使用的其他編譯器旗標。
compileflags
-
指定編譯 C 和 C++ 原始檔時要使用的其他編譯器旗標。
linkflags
-
指定將傳遞給連結器的其他命令列選項。
在使用 Windows 版本的編譯器之前,您需要根據編譯器的文件設定必要的環境變數。特別是,應設定 COMO_XXX_INCLUDE 變數,其中 XXX 對應於使用的後端 C 編譯器。
Code Warrior
cw
模組支援 CodeWarrior 編譯器,該編譯器最初由 Metrowerks 生產,目前由 Freescale 開發。B2 僅支援以 x86 處理器為目標的編譯器版本。所有此類版本均由 Metrowerks 在收購之前發布,且不再銷售。已知可使用的最後一個版本為 9.4。
該模組使用以下語法初始化
using cw : [version] : [c++-compile-command] : [compiler options] ;
如果您想設定多個編譯器版本,可以重複此陳述式多次。
如果未指定命令,B2 將會在預設安裝路徑和 PATH 中搜尋名為 mwcc
的二進位檔。
可以使用`<option-name>option-value 語法`提供以下選項
cflags
-
指定編譯 C 原始檔時要使用的其他編譯器旗標。
cxxflags
-
指定編譯 C++ 原始檔時要使用的其他編譯器旗標。
compileflags
-
指定編譯 C 和 C++ 原始檔時要使用的其他編譯器旗標。
linkflags
-
指定將傳遞給連結器的其他命令列選項。
setup
-
在呼叫編譯器之前設定環境變數的命令。如果未指定,將會使用編譯器二進位檔旁邊的
cwenv.bat
。 compiler
-
編譯 C 和 C++ 原始檔的命令。如果未指定,將會使用
mwcc
。該命令將在執行設定指令碼並調整 PATH 變數之後呼叫。 linker
-
連結可執行檔和動態函式庫的命令。如果未指定,將會使用
mwld
。該命令將在執行設定指令碼並調整 PATH 變數之後呼叫。
Digital Mars C/C++ 編譯器
dmc
模組支援 Digital Mars C++ 編譯器。
該模組使用以下語法初始化
using dmc : [version] : [c++-compile-command] : [compiler options] ;
如果您想設定多個編譯器版本,可以重複此陳述式多次。
如果未指定命令,B2 將會在 PATH 中搜尋名為 dmc
的二進位檔。
可以使用`<option-name>option-value 語法`提供以下選項
cflags
-
指定編譯 C 原始檔時要使用的其他編譯器旗標。
cxxflags
-
指定編譯 C++ 原始檔時要使用的其他編譯器旗標。
compileflags
-
指定編譯 C 和 C++ 原始檔時要使用的其他編譯器旗標。
linkflags
-
指定將傳遞給連結器的其他命令列選項。
Embarcadero C++ 編譯器
embarcadero
模組支援在 Microsoft Windows 上執行的 32 位元命令列 C 編譯器 bcc32x 和 64 位元命令列 C 編譯器 bcc64 (均基於 clang)。這些是所有 Embarcadero C++ 版本的基於 clang 的 Windows 編譯器。
該模組使用以下語法初始化
using embarcadero : [version] : [c++-compile-command] : [compiler options] ;
如果您想設定多個編譯器版本,可以重複此陳述式多次。
version
:
如果指定了版本,該版本應為編譯器版本。如果未指定版本,Boost Build 將會找到最新安裝的 Embarcadero C 版本,並將其用於該版本。如果指定了版本,Boost Build 不會檢查是否與任何特定版本的 Embarcadero C 相符,因此您可以將該版本用作助憶符號來設定單獨的「版本」。
c++-compile-command
:
如果未指定 c-compile-command,Boost.Build 將會預設為 bcc64 編譯器。如果您指定 <address-model>32
編譯器選項,預設編譯器將會是 bcc32x。在這兩種情況下,如果未給出命令,Boost Build 將會假設編譯器位於 PATH 中。因此,如果您接受預設編譯器且 Embarcadero C 二進位目錄位於 PATH 中,則無需指定命令。
如果指定了命令,它將會按原樣用於呼叫編譯器。如果命令中包含 'bcc32x(.exe)' 或 'bcc64(.exe)',Boost Build 將會使用適當的編譯器來設定工具組。如果命令中不包含 'bcc32x(.exe)' 或 'bcc64(.exe)',Boost Build 將會使用預設編譯器來設定工具組。如果您有自己的命令,該命令中沒有 'bcc32x(.exe)',但會呼叫 'bcc32x(.exe)' 編譯器,請指定 <address-model>32
編譯器選項。
compiler options
:
可以使用`<option-name>option-value 語法`提供以下選項
cflags
-
指定編譯 C 和 C++ 原始檔時要使用的其他編譯器旗標。
cxxflags
-
指定編譯 C++ 原始檔時要使用的其他編譯器旗標。
linkflags
-
指定將傳遞給連結器的其他命令列選項。
asmflags
-
指定將傳遞給組譯器的其他命令列選項。
archiveflags
-
指定將傳遞給封存工具 (用於建立靜態函式庫) 的其他命令列選項。
address-model
-
此選項可用於指定 c++-compile-command 的討論中如上所述的預設編譯器。否則,位址模型不會用於初始化工具組。
user-interface
-
指定應用程式的使用者介面。有效的選擇為:
console
(主控台應用程式) 和gui
(Windows 應用程式)。 root
-
通常,Boost Build 將能夠自動判斷 Embarcadero C 安裝的根目錄。它會以各種方式執行此操作,但主要是透過檢查登錄項目。如果您指定了根目錄,它將會使用該路徑,且您指定的根目錄應該是您機器上 Embarcadero C 安裝的完整路徑 (不含尾隨的 \ 或 /)。除非 Boost Build 無法找到 Embarcadero C++ 根目錄,否則您不需要指定此選項。
- 範例
-
using embarcadero ;
將工具組設定為使用最新版本,並將 bcc64 作為編譯器。bcc64 編譯器必須位於 PATH 中。
using embarcadero : 7.40 ;
將工具組設定為使用 7.40 版本,並將 bcc64 作為編譯器。bcc64 編譯器必須位於 PATH 中。
using embarcadero : 7.40 : bcc32x ; using embarcadero : 7.40 : : <address-model>32 ;
將工具組設定為使用 7.40 版本,並將 bcc32x 作為編譯器。bcc32x 編譯器必須位於 PATH 中。
using embarcadero : : c:/some_path/bcc64 ;
設定工具組以使用最新版本,並指定完整命令。
using embarcadero : : full_command : <address-model>32 ;
設定工具組以使用最新版本,並指定完整命令,且使用 bcc32x 作為編譯器。
using embarcadero : : : <root>c:/root_path ;
設定工具組以使用最新版本,並使用 bcc64 作為編譯器,且指定安裝的根目錄。bcc64 編譯器必須在 PATH 中。
GNU C++
gcc
模組支援在 Linux、多個類 Unix 系統(包括 SunOS)以及 Windows(使用 Cygwin 或 MinGW)上的 GNU C++ 編譯器。
gcc
模組使用以下語法初始化
using gcc : [version] : [c++-compile-command] : [compiler options] ;
如果您想設定多個編譯器版本,可以重複此陳述式多次。
如果未明確指定版本,將會透過使用 -v
選項執行編譯器來自動偵測。如果未指定命令,則會在 PATH 中搜尋 g++
二進位檔。
可以使用`<option-name>option-value 語法`提供以下選項
asmflags
-
指定在編譯組譯器原始碼時會使用的其他編譯器旗標。
cflags
-
指定編譯 C 原始檔時要使用的其他編譯器旗標。
cxxflags
-
指定編譯 C++ 原始檔時要使用的其他編譯器旗標。
fflags
-
指定在編譯 Fortran 原始碼時會使用的其他編譯器旗標。
mflags
-
指定在編譯 Objective-C 原始碼時會使用的其他編譯器旗標。
mmflags
-
指定在編譯 Objective-C++ 原始碼時會使用的其他編譯器旗標。
compileflags
-
指定在編譯任何語言原始碼時會使用的其他編譯器旗標。
linkflags
-
指定將傳遞給連結器的其他命令列選項。
root
-
指定編譯器安裝的根目錄。只有在無法從編譯器命令偵測到此資訊時,才需要此選項,例如,如果指定的編譯器命令是使用者腳本。
archiver
-
指定用於產生靜態程式庫的歸檔工具命令。通常,它會使用 gcc 的
-print-prog-name
選項自動偵測,或預設為ar
,但在某些情況下,您可能想要覆蓋它,例如明確使用系統版本,而不是 gcc 附帶的版本。 rc
-
指定將與正在設定的 gcc 版本一起使用的資源編譯器命令。此設定僅在 Windows 上有意義,且僅在您計劃使用資源檔案時才有意義。預設情況下,將使用
windres
。 rc-type
-
指定資源編譯器的類型。該值可以是
windres
(用於 msvc 資源編譯器)或rc
(用於 borland 的資源編譯器)。
為了編譯 64 位元的應用程式,您必須指定 address-model=64
,且 instruction-set
功能應參考 64 位元的處理器。目前,這些包括 nocona
、opteron
、athlon64
和 athlon-fx
。
用於 Tru64 Unix 的 HP C++ 編譯器
hp_cxx
模組支援用於 Tru64 Unix 的 HP C++ 編譯器。
該模組使用以下語法初始化
using hp_cxx : [version] : [c++-compile-command] : [compiler options] ;
如果您想設定多個編譯器版本,可以重複此陳述式多次。
如果未指定命令,B2 將會在 PATH 中搜尋名為 hp_cxx
的二進位檔。
可以使用`<option-name>option-value 語法`提供以下選項
cflags
-
指定編譯 C 原始檔時要使用的其他編譯器旗標。
cxxflags
-
指定編譯 C++ 原始檔時要使用的其他編譯器旗標。
compileflags
-
指定編譯 C 和 C++ 原始檔時要使用的其他編譯器旗標。
linkflags
-
指定將傳遞給連結器的其他命令列選項。
Intel C++
intel-*
模組支援 Intel C++ 命令列編譯器。
該模組使用以下語法初始化
using intel : [version] : [c++-compile-command] : [compiler options] ;
如果您想設定多個編譯器版本,可以重複此陳述式多次。
如果未指定編譯器命令,則 B2 將會在 PATH 中尋找可執行檔 icpc
(在 Linux 上)或 icl.exe
(在 Windows 上)。
可以使用`<option-name>option-value 語法`提供以下選項
cflags
-
指定編譯 C 原始檔時要使用的其他編譯器旗標。
cxxflags
-
指定編譯 C++ 原始檔時要使用的其他編譯器旗標。
compileflags
-
指定編譯 C 和 C++ 原始檔時要使用的其他編譯器旗標。
linkflags
-
指定將傳遞給連結器的其他命令列選項。
root
-
對於 Linux 版本,指定編譯器安裝的根目錄。只有在無法從編譯器命令偵測到此資訊時才需要此選項,例如,如果指定的編譯器命令是使用者腳本。對於 Windows 版本,指定用於設定編譯器的
iclvars.bat
檔案(適用於 21(或 2021)之前的版本)或setvars.bat
檔案(適用於 21(或 2021)及更高版本)的目錄。指定root
選項而不指定編譯器命令,可讓使用者不必擔心他們是在編譯 32 位元或 64 位元程式碼,因為工具組將會使用iclvars.bat
或setvars.bat
批次檔自動設定適用位址模型的編譯器和編譯器命令。
Microsoft Visual C++
msvc
模組支援 Microsoft Windows 上的 Microsoft Visual C++ 命令列工具。下面列出了支援的產品和命令列工具版本
-
Visual Studio 2022-14.3
-
Visual Studio 2019-14.2
-
Visual Studio 2017—14.1
-
Visual Studio 2015—14.0
-
Visual Studio 2013—12.0
-
Visual Studio 2012—11.0
-
Visual Studio 2010—10.0
-
Visual Studio 2008—9.0
-
Visual Studio 2005—8.0
-
Visual Studio .NET 2003—7.1
-
Visual Studio .NET—7.0
-
Visual Studio 6.0,Service Pack 5—6.5
然後,使用者會呼叫 Boost Build 可執行檔,並將工具組設定為等於 msvc-[版本號碼]
,例如,要使用 Visual Studio 2019 進行建置,可以執行
.\b2 toolset=msvc-14.2 target
msvc
模組使用以下語法初始化
using msvc : [version] : [c++-compile-command] : [compiler options] ;
如果您想設定多個編譯器版本,可以重複此陳述式多次。
如果未明確指定版本,則會改用登錄中找到的最新版本。如果將特殊值 all
作為版本傳遞,則會設定登錄中找到的所有版本。如果指定了版本,但未指定命令,則會在該版本的標準安裝路徑中搜尋編譯器二進位檔,然後搜尋 PATH。
應該使用正斜線指定編譯器命令,並加上引號。
可以使用`<option-name>option-value 語法`提供以下選項
cflags
-
指定編譯 C 原始檔時要使用的其他編譯器旗標。
cxxflags
-
指定編譯 C++ 原始檔時要使用的其他編譯器旗標。
compileflags
-
指定編譯 C 和 C++ 原始檔時要使用的其他編譯器旗標。
linkflags
-
指定將傳遞給連結器的其他命令列選項。
assembler
-
編譯組譯器原始碼的命令。如果未指定,則會使用
ml
。執行設定腳本並調整 PATH 變數後,將會調用該命令。 compiler
-
編譯 C 和 C++ 原始碼的命令。如果未指定,則會使用
cl
。執行設定腳本並調整 PATH 變數後,將會調用該命令。 compiler-filter
-
用於管道傳遞執行編譯器輸出的命令。例如,將輸出傳遞至 STLfilt。
idl-compiler
-
編譯 Microsoft COM 介面定義檔案的命令。如果未指定,則會使用
midl
。執行設定腳本並調整 PATH 變數後,將會調用該命令。 linker
-
連結可執行檔和動態程式庫的命令。如果未指定,則會使用
link
。執行設定腳本並調整 PATH 變數後,將會調用該命令。 mc-compiler
-
編譯 Microsoft 訊息目錄檔案的命令。如果未指定,則會使用
mc
。執行設定腳本並調整 PATH 變數後,將會調用該命令。 resource-compiler
-
編譯資源檔案的命令。如果未指定,則會使用
rc
。執行設定腳本並調整 PATH 變數後,將會調用該命令。 setup
-
在調用此工具組中定義的任何工具之前,要執行的全域環境設定腳本的檔名。如果已為目前目標平台明確指定了目標平台專用腳本,則不會使用。使用的設定腳本將會將目標平台識別碼(x86、x86_amd64、x86_ia64、amd64 或 ia64)作為參數傳遞。如果未指定,則會根據使用的編譯器二進位檔選擇預設腳本,例如
vcvars32.bat
或vsvars32.bat
。 setup-amd64
;setup-i386
;setup-ia64
-
在調用此工具組中定義的任何工具之前,要執行的目標平台專用環境設定腳本的檔名。如果未指定,則會使用全域環境設定腳本。
64 位元支援
從 8.0 版開始,Microsoft Visual Studio 可以為 64 位元處理器產生二進位檔,包括 x86 的 64 位元版本(代號為 AMD64/EM64T)和 Itanium(代號為 IA64)。此外,還提供了本身在 64 位元模式下執行的編譯器,以獲得更好的效能。完整的編譯器組態清單如下(我們將 AMD64/EM64T 縮寫為 AMD64)
-
32 位元 x86 主機,32 位元 x86 目標
-
32 位元 x86 主機,64 位元 AMD64 目標
-
32 位元 x86 主機,64 位元 IA64 目標
-
64 位元 AMD64 主機,64 位元 AMD64 目標
-
64 位元 IA64 主機,64 位元 IA64 目標
即使在 64 位元的 Windows 上,也可以始終使用 32 位元主機編譯器。相反地,64 位元主機編譯器需要 64 位元主機處理器和 64 位元 Windows,但速度更快。預設情況下,只會安裝 32 位元主機、32 位元目標編譯器,且需要明確安裝其他編譯器。
若要使用 64 位元編譯,您應該
-
像往常一樣設定您的編譯器。如果您明確提供編譯器的路徑,請提供 32 位元編譯器的路徑。如果您嘗試指定任何 64 位元編譯器的路徑,則設定將無法運作。
-
編譯時,請使用
address-model=64
來產生 AMD64 程式碼。 -
若要產生 IA64 程式碼,請使用
architecture=ia64
當您產生 AMD64 程式碼且在 AMD64 上執行 64 位元 Windows 時,將會自動使用(AMD64 主機、AMD64 目標)編譯器。(IA64 主機、IA64 目標)編譯器永遠不會使用,因為沒有人有 IA64 機器可以測試。
據信 AMD64 和 EM64T 目標基本上是相容的。編譯器選項 /favor:AMD64
和 /favor:EM64T
僅由以 AMD64 為目標的編譯器接受,會使產生的程式碼針對特定版本的 64 位元 x86 進行調整。B2 會根據 `instruction-set` 功能的值來使用這些選項。
從 14.0 版開始,Microsoft Visual Studio 可以使用原生 arm64 工具來產生二進位檔,以針對 x86、x86_64 和 arm64 進行編譯。
Windows Runtime 支援
從 11.0 版開始,Microsoft Visual Studio 除了傳統的 Win32 桌面外,還可以產生 Windows 市集和手機的二進位檔。若要指定要以哪個 Windows API 集為目標,請使用 windows-api
功能。可用的選項為 desktop
、store
或 phone
。如果未指定,則會使用 desktop
。
使用 store
或 phone
時,指定的工具組會決定目標的 Windows 版本。提供下列選項
-
Windows 8.0:toolset=msvc-11.0 windows-api=store
-
Windows 8.1:toolset=msvc-12.0 windows-api=store
-
Windows Phone 8.0:toolset=msvc-11.0 windows-api=phone
-
Windows Phone 8.1:toolset=msvc-12.0 windows-api=phone
例如,使用以下項目為具有 ARM 架構的 Windows 市集 8.1 進行建置
.\b2 toolset=msvc-12.0 windows-api=store architecture=arm
請注意,當以 Windows Phone 8.1 為目標時,12.0 版不包括 vcvars phone 設定腳本。它們可以從此處單獨下載。
Sun Studio
sun
模組支援 Solaris 作業系統的 Sun Studio C++ 編譯器。
該模組使用以下語法初始化
using sun : [version] : [c++-compile-command] : [compiler options] ;
如果您想設定多個編譯器版本,可以重複此陳述式多次。
如果未指定命令,B2 將會在 /opt/SUNWspro/bin
和 PATH 中搜尋名為 CC
的二進位檔。
在複雜的 C 程式碼(例如 https://boost.dev.org.tw[Boost C 程式庫])上使用此編譯器時,建議在初始化 sun
模組時指定下列選項
-library=stlport4 -features=tmplife -features=tmplrefstatic
請參閱 Sun C++ 前端故事以取得詳細資訊。
可以使用`<option-name>option-value 語法`提供以下選項
cflags
-
指定編譯 C 原始檔時要使用的其他編譯器旗標。
cxxflags
-
指定編譯 C++ 原始檔時要使用的其他編譯器旗標。
compileflags
-
指定編譯 C 和 C++ 原始檔時要使用的其他編譯器旗標。
linkflags
-
指定將傳遞給連結器的其他命令列選項。
從 Sun Studio 12 開始,您可以使用 address-model=64
屬性來建立 64 位元的應用程式。
IBM Visual Age
vacpp
模組支援用於 AIX 作業系統的 IBM Visual Age C++ 編譯器。已知 7.1 和 8.0 版可以運作。
該模組使用以下語法初始化
using vacpp ;
此模組不接受任何初始化選項。編譯器應安裝在 /usr/vacpp/bin
目錄中。
較新版本的 Visual Age 稱為 XL C/C++。它們沒有使用 vacpp
模組進行測試。
6.4.2. 第三方函式庫
B2 為一些第三方 C++ 函式庫提供特殊支援,如下所述。
STLport 函式庫
STLport 函式庫是 C++ 執行時期函式庫的替代實作。B2 支援在 Windows 平台上使用該函式庫。Linux 由於每個 STLport 版本中的函式庫命名不同而受到阻礙,因此未正式支援。
在使用 STLport 之前,您需要使用以下語法在 user-config.jam
中進行配置
using stlport : version : header-path : library-path ;
其中 version 是 STLport 的版本,例如 5.1.4
,headers 是 STLport 標頭檔的所在位置,而 libraries 是 STLport 函式庫的所在位置。應始終提供版本,如果您使用的是 STLport 的 iostreams
實作,則應提供函式庫路徑。請注意,STLport 5.* 始終使用自己的 iostream
實作,因此需要函式庫路徑。
配置 STLport 後,您可以透過在命令列上請求 stdlib=stlport
來使用 STLport 進行建置。
zlib
提供對 zlib 函式庫的支援。zlib 可以配置為使用預先編譯的二進位檔,或從原始碼建置函式庫。
可以使用以下語法初始化 zlib
using zlib : version : options : condition : is-default ;
使用預建函式庫的選項
search
-
包含 zlib 二進位檔的目錄。
name
-
覆寫預設函式庫名稱。
include
-
包含 zlib 標頭檔的目錄。
如果未指定這些選項中的任何一個,則將改為使用環境變數 ZLIB_LIBRARY_PATH、ZLIB_NAME 和 ZLIB_INCLUDE。
從原始碼建置 zlib 的選項
source
-
zlib 原始碼目錄。預設為環境變數 ZLIB_SOURCE。
tag
-
設定 tag 屬性以調整函式庫的檔案名稱。使用預先編譯的二進位檔時會忽略。
build-name
-
用於已編譯函式庫的基本名稱。使用預先編譯的二進位檔時會忽略。
範例
# Find zlib in the default system location
using zlib ;
# Build zlib from source
using zlib : 1.2.7 : <source>/home/steven/zlib-1.2.7 ;
# Find zlib in /usr/local
using zlib : 1.2.7 : <include>/usr/local/include <search>/usr/local/lib ;
# Build zlib from source for msvc and find
# prebuilt binaries for gcc.
using zlib : 1.2.7 : <source>C:/Devel/src/zlib-1.2.7 : <toolset>msvc ;
using zlib : 1.2.7 : : <toolset>gcc ;
bzip2
提供對 bzip2 函式庫的支援。bzip2 可以配置為使用預先編譯的二進位檔,或從原始碼建置函式庫。
可以使用以下語法初始化 bzip2
using bzip2 : version : options : condition : is-default ;
使用預建函式庫的選項
search
-
包含 bzip2 二進位檔的目錄。
name
-
覆寫預設函式庫名稱。
include
-
包含 bzip2 標頭檔的目錄。
如果未指定這些選項中的任何一個,則將改為使用環境變數 BZIP2_LIBRARY_PATH、BZIP2_NAME 和 BZIP2_INCLUDE。
從原始碼建置 bzip2 的選項
source
-
bzip2 原始碼目錄。預設為環境變數 BZIP2_SOURCE。
tag
-
設定 tag 屬性以調整函式庫的檔案名稱。使用預先編譯的二進位檔時會忽略。
build-name
-
用於已編譯函式庫的基本名稱。使用預先編譯的二進位檔時會忽略。
範例
# Find bzip in the default system location
using bzip2 ;
# Build bzip from source
using bzip2 : 1.0.6 : <source>/home/sergey/src/bzip2-1.0.6 ;
# Find bzip in /usr/local
using bzip2 : 1.0.6 : <include>/usr/local/include <search>/usr/local/lib ;
# Build bzip from source for msvc and find
# prebuilt binaries for gcc.
using bzip2 : 1.0.6 : <source>C:/Devel/src/bzip2-1.0.6 : <toolset>msvc ;
using bzip2 : 1.0.6 : : <toolset>gcc ;
Python
提供對 python 語言環境的支援,以作為函式庫連結。
可以使用以下語法初始化 python
using python : [version] : [command-or-prefix] : [includes] : [libraries] : [conditions] : [extension-suffix] ;
使用 python 的選項
version
-
要使用的 Python 版本。應為 Major.Minor 格式,例如 2.3。不要包含子次要版本。
command-or-prefix
-
最好是調用 Python 直譯器的命令。或者,Python 函式庫和包含檔的安裝前置詞。如果為空,將從版本、平台的安裝模式以及 PATH 中可找到的 python 可執行檔來猜測。
includes
-
Python 標頭檔的包含路徑。如果為空,將會猜測。
libraries
-
Python 函式庫二進位檔的路徑。如果為空,將會猜測。在 MacOS/Darwin 上,您也可以傳遞 Python 框架的路徑。
conditions
-
如果指定,應該是一組屬性,當 B2 選擇要使用的 Python 配置時,會比對建置組態。
extension-suffix
-
一個字串,附加到擴充模組名稱的後面,在真正的檔案名稱副檔名之前。通常,我們會根據
<python-debugging>
功能的值來計算此值。但是,ubuntu 的python-dbg
套件使用 Windows 的慣例,將 _d 附加到偵錯建置擴充模組。我們無法偵測 ubuntu,也無法探查 python 以取得 "_d" 要求,如果您使用--with-pydebug
設定和建置 python,您將使用標準的 *nix 慣例。預設為 ""(或當目標為 windows 且設定 <python-debugging> 時為 "_d")。
範例
# Find python in the default system location
using python ;
# 2.7
using python : 2.7 ;
# 3.5
using python : 3.5 ;
# On ubuntu 16.04
using python
: 2.7 # version
: # Interpreter/path to dir
: /usr/include/python2.7 # includes
: /usr/lib/x86_64-linux-gnu # libs
: # conditions
;
using python
: 3.5 # version
: # Interpreter/path to dir
: /usr/include/python3.5 # includes
: /usr/lib/x86_64-linux-gnu # libs
: # conditions
;
# On windows
using python
: 2.7 # version
: C:\\Python27-32\\python.exe # Interperter/path to dir
: C:\\Python27-32\\include # includes
: C:\\Python27-32\\libs # libs
: <address-model>32 <address-model> # conditions - both 32 and unspecified
;
using python
: 2.7 # version
: C:\\Python27-64\\python.exe # Interperter/path to dir
: C:\\Python27-64\\include # includes
: C:\\Python27-64\\libs # libs
: <address-model>64 # conditions
;
6.4.3. 文件工具
B2 對 Boost 文件工具的支援如下所述。
xsltproc
若要使用 xsltproc,您首先需要使用以下語法進行設定
using xsltproc : xsltproc ;
其中 xsltproc 是 xsltproc 可執行檔。如果未指定 xsltproc,且設定了變數 XSLTPROC,則將使用 XSLTPROC 的值。否則,將在 PATH 中搜尋 xsltproc。
可以使用`<option-name>option-value 語法`提供以下選項
xsl:param
-
值應具有 name=value 的形式
xsl:path
-
為 xi:include 元素設定額外的搜尋路徑。
catalog
-
用於將遠端 URL 重寫為本機副本的目錄檔案。
xsltproc 模組提供以下規則。請注意,這些規則會對 jam 目標進行操作,並且旨在由另一個工具集(例如 boostbook)使用,而不是直接由使用者使用。
xslt
-
rule xslt ( target : source stylesheet : properties * )
執行 xsltproc 以建立單一輸出檔案。
xslt-dir
-
rule xslt-dir ( target : source stylesheet : properties * : dirname )
執行 xsltproc 以在目錄中建立多個輸出。
dirname
未使用,但由於歷史原因而存在。輸出目錄由目標決定。
boostbook
若要使用 boostbook,您首先需要使用以下語法進行設定
using boostbook : docbook-xsl-dir : docbook-dtd-dir : boostbook-dir ;
docbook-xsl-dir
是 DocBook XSL 樣式表目錄。如果未提供,我們會使用環境中的 DOCBOOK_XSL_DIR
(如果有的話)或在標準位置搜尋。否則,我們會讓 XML 處理器遠端載入樣式表。
docbook-dtd-dir
是 DocBook DTD 目錄。如果未提供,我們會使用環境中的 DOCBOOK_DTD_DIR
(如果有的話)或在標準位置搜尋。否則,我們會讓 XML 處理器遠端載入 DTD。
boostbook-dir
是包含 DTD 和 XSL 子目錄的 BoostBook 目錄。
boostbook 模組依賴於 xsltproc。對於 pdf 或 ps 輸出,它也依賴於 fop。
可以使用`<option-name>option-value 語法`提供以下選項
format
-
允許的值:
html
、xhtml
、htmlhelp
、onehtml
、man
、pdf
、ps
、docbook
、fo
、tests
。format
功能決定 boostbook 規則產生的輸出類型。
boostbook 模組定義了一個規則,用於建立遵循常見語法的目標。
boostbook
-
rule boostbook ( target-name : sources * : requirements * : default-build * )
建立 boostbook 目標。
doxygen
若要使用 doxygen,您首先需要使用以下語法進行設定
using doxygen : name ;
name
是 doxygen 命令。如果未指定,將在 PATH 中找到它。
當產生 BoostBook XML 時,doxygen 模組依賴於 boostbook 模組。
可以使用`<option-name>option-value 語法`提供以下選項
doxygen:param
-
所有
doxygen:param
的值都會新增至doxyfile
。 prefix
-
在產生 BoostBook XML 時,指定所有標頭檔的通用前置詞。此之前的所有內容都將被移除。
reftitle
-
在產生 BoostBook XML 時,指定函式庫參考區段的標題。
doxygen:xml-imagedir
-
在產生 BoostBook XML 時,指定放置從 LaTex 公式產生的影像的目錄。
⚠路徑是相對於目前工作目錄解釋,而不是相對於 Jamfile。這是為了符合 BoostBook 的行為。
doxygen 模組定義了一個規則,用於建立遵循常見語法的目標。
doxygen
-
rule doxygen ( target : sources * : requirements * : default-build * : usage-requirements * )
建立 doxygen 目標。如果目標名稱以 .html 結尾,則會產生 html 目錄。否則,它會產生 BoostBook XML。
6.5. 內建模組
本節說明 B2 提供的模組。import 規則允許在另一個模組或 Jamfile 中使用一個模組的規則。
6.5.1. modules
模組。
modules
模組定義用於處理模組的基本功能。
模組定義許多可以在其他模組中使用的規則。模組可以在頂層包含程式碼,以初始化模組。此程式碼會在第一次載入模組時執行。
ℹ
|
Jamfile 是一種由建置系統管理的特殊模組。儘管使用者無法直接載入它們,但模組的其他功能對於 Jamfile 仍然很有用。 |
每個模組都有自己的變數和規則命名空間。如果兩個模組 A 和 B 都使用名為 X 的變數,則每個模組都會獲得自己的 X 副本。它們不會以任何方式相互干擾。同樣,將規則匯入一個模組對任何其他模組沒有任何影響。
每個模組都有兩個特殊變數。$(file)
包含載入模組的檔案名稱,而 $(name)
包含模組的名稱。
ℹ
|
$(file) 不包含檔案的完整路徑。如果您需要此路徑,請使用 modules.binding 。 |
b2::modules::binding
Jam |
|
C++ |
|
傳回給定模組的檔案系統繫結。
例如,模組可以使用以下方式取得自己的位置
me = [ modules.binding $(__name__) ] ;
b2::modules::record_binding
Jam |
|
C++ |
|
此協助程式由 load 使用,以記錄每個已載入模組的繫結 (路徑)。
⚠
|
會忽略 module_name 。而是使用目前載入模組的內部追蹤來記錄繫結。 |
b2::modules::poke
Jam |
|
C++ |
|
設定模組內變數的數值。這是設定不同模組內模組變數最可靠的方法;它消除了因動態作用域而產生的名稱遮蔽問題。
例如,要在全域模組中設定變數
modules.poke : ZLIB_INCLUDE : /usr/local/include ;
b2::modules::peek
Jam |
|
C++ |
|
傳回模組內變數的數值。這是檢查不同模組內模組變數最可靠的方法;它消除了因動態作用域而產生的名稱遮蔽問題。
例如,要從全域模組讀取變數
local ZLIB_INCLUDE = [ modules.peek : ZLIB_INCLUDE ] ;
b2::modules::clone_rules
Jam |
|
C++ |
|
在 target_module
中定義從 source_module
匯出的所有規則的匯出副本。同時使其可在全域模組中使用限定詞,就像這些規則最初是在 target_module
中定義的一樣。
b2::modules::call_in
Jam |
|
C++ |
|
在給定的模組中在本機呼叫指定的規則。使用此方法呼叫接受規則名稱作為引數的規則,以便傳遞的規則可以在規則呼叫者的內容中調用(例如,如果規則存取模組全域變數或是一個本機規則)。請注意,以這種方式呼叫的規則最多可以接受 18 個參數。
範例
rule filter ( f : values * )
{
local m = [ CALLER_MODULE ] ;
local result ;
for v in $(values)
{
if [ modules.call-in $(m) : $(f) $(v) ]
{
result += $(v) ;
}
}
return result ;
}
b2::modules::call_locally
Jam |
|
C++ |
|
給定一個可能限定的規則名稱和引數,從規則中移除任何初始模組限定詞,並在該模組中調用它。如果沒有模組限定詞,則在全域模組中調用該規則。請注意,以這種方式呼叫的規則最多可以接受 18 個參數。
b2::modules::run_tests
Jam |
|
C++ |
|
為指定的模組執行內部 B2 單元測試。該模組的 test
規則在其自己的模組中執行,以消除測試模組相依性(例如 assert)對模組本身的任何無意影響。
b2::modules::load
Jam |
|
C++ |
|
如果尚未載入,則載入指示的模組。
module-name
-
要載入的模組名稱。
filename
-
檔案的(部分)路徑;預設為
$(module-name).jam
search
-
在其中搜尋檔案名稱的目錄。預設為
$(BOOST_BUILD_PATH)
。
b2::modules::import
Jam |
|
C++ |
|
載入指示的模組,並將規則名稱匯入到目前的模組中。rules-opt
的任何成員都將在呼叫者的模組中可用,且無需限定詞。rename-opt
的任何成員都將被視為呼叫者模組中規則的名稱,而不是它們在匯入模組中擁有的名稱。如果 rules-opt
= *
,則會將指示模組中的所有規則匯入到呼叫者的模組中。如果提供了 rename-opt
,則它必須與 rules-opt
具有相同數量的元素。
ℹ
|
import 規則在所有模組中都可用,且無需限定詞。 |
範例
import path ;
import path : * ;
import path : join ;
import path : native make : native-path make-path ;
6.5.2. class
模組。
b2::class::make
Jam |
|
C++ |
|
實例化給定類別的新執行個體,並使用給定的引數呼叫 init
。傳回執行個體 ID。
b2::class::is_derived
Jam |
|
C++ |
|
當給定類別衍生自給定的基底時,傳回 true。
6.5.3. errors
模組。
b2::jam::errors::backtrace
Jam |
|
C++ |
|
列印導致此規則呼叫者的堆疊回溯。每個引數都表示在回溯的第一行之後要列印的輸出列。
b2::jam::errors::error_skip_frames
Jam |
|
C++ |
|
b2::jam::errors::try-catch
Jam |
|
C++ |
|
這並非真正的例外處理機制,但它確實允許我們對錯誤檢查執行一些錯誤檢查。在 try 之後會隱藏錯誤,並記錄第一個錯誤。使用 catch 來檢查錯誤訊息是否符合預期。
Jam |
|
C++ |
|
開始尋找錯誤訊息。
Jam |
|
C++ |
|
停止尋找錯誤訊息;如果在錯誤呼叫中找不到訊息的引數,則會產生錯誤。
b2::jam::errors::error
Jam |
|
C++ |
|
列印帶有堆疊回溯的錯誤訊息並結束。
b2::jam::errors::user_error
Jam |
|
C++ |
|
與 'error' 相同,但產生的回溯只會包含使用者檔案。
b2::jam::errors::warning
Jam |
|
C++ |
|
列印帶有堆疊回溯的警告訊息並結束。
6.5.4. regex
模組。
包含使用規則運算式進行字串處理的規則。
-
"x*"
比對模式"x"
零次或多次。 -
"x+"
比對"x"
一次或多次。 -
"x?"
比對"x"
零次或一次。 -
"[abcd]"
比對字元"a"
、"b"
、"c"
和"d"
中的任何一個。例如"[a-z]"
的字元範圍會比對"a"
和"z"
之間的任何字元。"[^abc]"
比對不是"a"
、"b"
或"c"
的任何字元。 -
"x|y"
比對模式"x"
或模式"y"
。 -
(x)
比對"x"
並擷取它。 -
"^"
比對字串的開頭。 -
"$"
比對字串的結尾。 -
"<"
比對單字的開頭。 -
">"
比對單字的結尾。
另請參閱:MATCH
b2::regex_split
Jam |
|
C++ |
|
傳回以下子字串的清單
-
從開頭到第一次出現 'separator' 或到結尾,
-
在每次出現 'separator' 與下一次出現之間,
-
從最後一次出現 'separator' 到結尾。
如果不存在分隔符號,則結果只會包含一個元素。
b2::regex_split_each
Jam |
|
C++ |
|
傳回使用分隔符號模式將 regex.split 應用於清單的每個元素之串聯結果。
b2::regex_match
Jam |
|
C++ |
|
比對 string
與 pattern
,並傳回 indices
指示的元素。
b2::regex_transform
Jam |
|
C++ |
|
比對 list
的所有元素與 pattern
,並傳回由所有成功比對的索引所指示的元素清單。如果省略 indices
,則傳回所有成功比對的第一個帶括號群組清單。
b2::regex_escape
Jam |
|
C++ |
|
使用逸出符號 escape-symbol
來逸出給定字串中的 symbols
所有字元,並傳回逸出的字串。
b2::regex_replace
Jam |
|
C++ |
|
取代給定字串中比對字串的出現次數,並傳回新字串。比對字串可以是規則運算式。
-
string
— 要修改的字串。 -
match
— 要取代的字元。 -
replacement
— 要取代為的字串。
b2::regex_replace_each
Jam |
|
C++ |
|
取代給定字串清單中比對字串的出現次數,並傳回新字串的清單。比對字串可以是規則運算式。
-
list
— 要修改的字串清單。 -
match
— 搜尋運算式。 -
replacement
— 要取代為的字串。
b2::regex_grep
Jam |
|
C++ |
|
比對 directories
中經過 glob 處理的 files
與任何 patterns
,並回傳檔案清單及指定的 result_expressions
(file1, re1, re.., …)。result_expressions
是從 0
到 10
的索引,其中 0
代表完整比對。
6.5.5. set
模組。
用於操作唯一值集合的類別和函式。
b2::set
Set 類別包含唯一值。
b2::set::add
Jam |
|
C++ |
|
將 elements
加入集合。
b2::set::contains
Jam |
|
C++ |
|
判斷集合是否包含給定的 element
。
b2::set::difference
Jam |
|
C++ |
|
回傳 set1
中不屬於 set2
的元素。
6.5.6. string
模組。
b2::string_whitespace
Jam |
|
C++ |
|
回傳標準的空白字元集合,以單一字串表示。
b2::string_chars
Jam |
|
C++ |
|
將給定的 string
分割成一個字串列表,每個字串由 string
中的每個字元依序組成。
b2::string_abbreviate
Jam |
|
C++ |
|
對字串套用一組標準轉換,以產生一個不超過 5 個字元的縮寫。
b2::string_join
Jam |
|
C++ |
|
將給定的 strings
連接起來,並在每個字串之間插入給定的 separator
。
6.5.8. db
模組。
用於管理結構化資料的類別和函式。
b2::property_db
(property-db
)
以樹狀結構組織數值的容器,其鍵為數值樹狀路徑。支援陣列和物件(已命名字段)。
b2::property_db::emplace
Jam |
|
C++ |
|
設定或新增位於路徑 key
的元素,其值為 value
。路徑可以包含兩種位置項目:陣列索引或物件成員。陣列索引為 "[]" n
。其中 "[]"
表示陣列中的從零開始的索引,n
則為索引值。其他任何內容都會被視為成員欄位名稱。
6.5.9. path
執行各種路徑操作。路徑始終以「正規化」表示法表示。其中,路徑可以是
-
'.'
,或者 -
['/'] [ ( '..' '/' )* (token '/')* token ]
簡單來說,路徑可以是根路徑,'..'
元素只允許在開頭,而且除了只包含斜線的路徑之外,永遠不會以斜線結尾。
-
將原生路徑轉換為正規化形式。
-
建立路徑的原生表示法。
-
測試路徑是否為根路徑。
-
測試路徑是否有父目錄。
-
回傳沒有任何目錄元件的路徑。
-
回傳路徑的父目錄。如果沒有父目錄,則會發出錯誤。
-
回傳
path2
,使得[ join path path2 ] = "."
。路徑不能包含".."
元素或為根路徑。 -
連接傳遞的路徑元素。如果除了第一個元素之外的任何元素為根路徑,則會產生錯誤。略過任何空或未定義的路徑元素。
-
如果
path
是相對路徑,則會以root
為根目錄。否則,它會保持不變。 -
回傳目前的工作目錄。
-
rule glob ( dirs * : patterns + : exclude-patterns * )
回傳符合指定目錄中給定模式的檔案清單。目錄和模式都以可攜式路徑提供。每個模式都應該是非絕對路徑,且不能包含 "." 或 ".." 元素。模式中每個以斜線分隔的元素都可以包含下列特殊字元
-
'?' 符合任何字元
-
'*' 符合任意數量的字元
如果 e1 符合 p1,e2 符合 p2,依此類推,則檔案
$(d)/e1/e2/e3
(其中 'd' 在$(dirs)
中) 符合模式 p1/p2/p3。例如[ glob . : *.cpp ] [ glob . : */build/Jamfile ]
-
-
rule glob-tree ( roots * : patterns + : exclude-patterns * )
glob 的遞迴版本。建構檔案的 glob,同時也搜尋給定根目錄的子目錄。選用的一組排除模式將從結果中篩選出符合的項目。排除也適用於子目錄掃描,因此不會搜尋符合排除模式的目錄。
-
如果指定的檔案存在,則回傳 true。
-
rule all-parents ( path : upper_limit ? : cwd ? )
找出路徑的絕對名稱,並回傳所有父目錄的清單,從最直接的父目錄開始。父目錄以相對名稱回傳。如果指定了
upper_limit
,則會修剪其上方的目錄。 -
rule glob-in-parents ( dir : patterns + : upper-limit ? )
在
dir
的父目錄中搜尋patterns
,直到並包含upper_limit
(如果已指定),否則會搜尋到檔案系統的根目錄。 -
rule relative ( child parent : no-error ? )
假設
child
是parent
的子目錄,則回傳從parent
到child
的相對路徑。 -
rule relative-to ( path1 path2 )
回傳相對於 path1 的 path2 的最小路徑。
-
回傳作業系統用來查閱程式的路徑清單。
-
建立目錄和所有尚不存在的父目錄。
6.5.10. sequence
各種實用的列表函式。請注意,此模組中的演算法主要在呼叫者的模組命名空間中執行,因此本地規則可以用作函式物件。另請注意,大多數述詞可以是多元素列表。在這種情況下,除了第一個元素之外的所有元素都會附加到傳遞給由第一個元素命名的規則的第一個引數。
-
rule filter ( predicate + : sequence * )
回傳
$(sequence)
的元素e
,其中[ $(predicate) e ]
具有非空值。 -
rule transform ( function + : sequence * )
回傳一個新的序列,由
$(sequence)
的每個元素e
的[ $(function) $(e) ]
組成。 -
rule reverse ( s * )
以相反的順序回傳
s
的元素。 -
rule insertion-sort ( s * : ordered * )
使用 BinaryPredicate
ordered
插入排序s
。 -
rule merge ( s1 * : s2 * : ordered * )
使用 BinaryPredicate
ordered
合併兩個已排序的序列。 -
rule join ( s * : joint ? )
將
s
的元素合併為一個長字串。如果提供joint
,則會將其用作分隔符。 -
rule length ( s * )
找出任何序列的長度。
-
rule unique ( list * : stable ? )
從
list
中移除重複項。如果傳遞stable
,則元素的順序將保持不變。 -
rule max-element ( elements + : ordered ? )
回傳
elements
中的最大數字。如果沒有提供,則使用ordered
進行比較,否則使用numbers.less
。 -
rule select-highest-ranked ( elements * : ranks * )
回傳
elements
中對應於平行列表rank
中等於rank
中最大值的所有元素。
6.5.11. stage
此模組定義 install
規則,用於將一組目標複製到單一位置。
-
rule add-install-dir ( name : suffix ? : parent ? : options * )
定義一個已命名的安裝目錄。
例如,
add-install-dir foo : bar : baz ;
會建立功能<install-foo>
,並將名為(foo)
的目錄支援新增至install
規則。此規則會嘗試使用<install-foo>
屬性的值 (如果存在),否則會回溯到(baz)/bar
。引數
-
name
:目錄的名稱。 -
suffix
:附加到父目錄名稱的路徑後綴。 -
parent
:父目錄名稱的選用名稱。 -
options
:修改目錄處理方式的特殊選項。允許的選項-
package-suffix
:將套件名稱附加到預設值。例如add-install-dir foo : bar : baz : package-suffix ; install (foo) : a : <install-package>xyz ;
將
a
安裝到(baz)/bar/xyz
。
-
-
-
規則 install-dir-names ( )
傳回所有已註冊安裝目錄的名稱。
-
規則 get-dir ( name : property-set : package-name : flags * )
傳回具名安裝目錄的路徑。對於指定的
name=xyz
,如果property-set
中存在<install-xyz>
屬性的值,則此規則會使用它。否則,它會嘗試以遞迴方式建構路徑的預設值,取得name
已註冊的基準目錄名稱和相對路徑的路徑。例如stage.add-install-dir foo : bar : baz ; local ps = [ property-set.create <install-foo>x/y/z ] ; echo [ stage.get-dir foo : $(ps) : $(__name__) ] ; # outputs x/y/z ps = [ property-set.create <install-baz>a/b/c/d ] ; echo [ stage.get-dir foo : $(ps) : $(__name__) ] ; # outputs a/b/c/d/bar
引數
package-name
用於建構以package-suffix
選項註冊的具名目錄路徑,也用於在目標為 Windows 時建構install-prefix
。可用的
flags
-
staged
:考慮staging-prefix
。 -
relative
:傳回相對於其基準目錄的name
路徑。
-
-
規則 get-package-name ( property-set : project-module ? )
傳回在建構安裝位置時,將用於
install
目標的套件名稱。如果property-set
中存在<install-package>
屬性的值,則此規則會使用它。否則,它會使用project-module
的屬性推斷套件名稱。它會遍歷專案階層結構,直到根目錄,搜尋第一個具有 ID 的專案。如果找不到,則會使用根專案位置的基底名稱。如果project-module
為空,則會使用呼叫者模組 (這允許在專案 Jam 檔案中僅呼叫[ get-package-name $(ps) ]
)。
6.5.12. type
處理目標類型宣告,並定義支援類型目標的目標類別。
-
規則 register ( type : suffixes * : base-type ? )
註冊目標類型,可能衍生自
base-type
。在此處提供後綴清單,是使用指定的後綴單獨呼叫 register-suffixes 規則,以及使用第一個指定的後綴呼叫 set-generated-target-suffix 規則的捷徑。 -
規則 register-suffixes ( suffixes + : type )
指定具有
suffixes
中後綴的檔案會被識別為type
類型的目標。如果已為任何後綴指定不同的類型,則會發出錯誤。 -
如果類型已註冊,則傳回 true。
-
如果
type
未知,則會發出錯誤。 -
規則 set-scanner ( type : scanner )
設定將用於此類型的掃描器類別。
-
規則 get-scanner ( type : property-set )
傳回適用於
type
和property-set
的掃描器執行個體。 -
傳回給定類型的基準類型,如果給定類型不是衍生類型,則傳回 nothing。
-
依其與類型之間的距離順序,傳回給定類型及其所有基準類型。
-
依其與類型之間的距離順序,傳回給定類型及其所有衍生類型。
-
如果
type
等於base
,或具有base
作為其直接或間接基準,則傳回 true。 -
規則 set-generated-target-suffix ( type : properties * : suffix )
設定在產生具有指定屬性的
type
目標時要使用的檔案後綴。如果尚未為type
指定任何後綴,則可以使用不含屬性的方式呼叫。suffix
參數可以是空字串 (""
),以表示不應使用任何後綴。請注意,這不會導致具有
suffix
的檔案自動被識別為type
。兩種不同的類型可以針對其產生的檔案使用相同的後綴,但對於具有該後綴的檔案,只能自動偵測到一種類型。使用者應使用 register-suffixes 規則明確指定要使用哪一個。 -
規則 change-generated-target-suffix ( type : properties * : suffix )
變更先前為此類型/屬性組合註冊的後綴。如果尚未指定後綴,則會設定它。
-
規則 generated-target-suffix ( type : property-set )
傳回在產生具有指定屬性的
type
檔案時使用的後綴。 -
規則 set-generated-target-prefix ( type : properties * : prefix )
設定在產生具有指定屬性的
type
目標時應使用的目標前綴。如果尚未為type
指定任何前綴,則可以使用空屬性呼叫。prefix
參數可以是空字串 (""
),以表示不應使用任何前綴。使用範例:程式庫名稱在 Unix 上使用
"lib"
前綴。 -
規則 change-generated-target-prefix ( type : properties * : prefix )
變更先前為此類型/屬性組合註冊的前綴。如果尚未指定前綴,則會設定它。
-
規則 generated-target-prefix ( type : property-set )
傳回在產生具有指定屬性的
type
檔案時使用的前綴。 -
傳回給定檔案名稱的檔案類型。如果檔案名稱中有數個點,則會嘗試每個後綴。例如,對於名稱為 "file.so.1.2" 的檔案,將會嘗試後綴 "2"、"1" 和 "so"。
6.6. 內建類別
6.6.1. 類別 abstract-target
所有抽象目標的基底類別。
class abstract-target {
rule __init__ ( name : project )
rule name ( )
rule project ( )
rule location ( )
rule full-name ( )
rule generate ( property-set )
}
衍生自 abstract-target 的類別
-
project-target
-
main-target
-
basic-target
-
規則 init ( name : project )
name
-
Jamfile 中目標的名稱。
project
-
此目標所屬的 project。
-
規則 name ( )
傳回此目標的名稱。
-
規則 project ( )
傳回此目標的 project。
-
規則 location ( )
傳回宣告目標的位置。
-
規則 full-name ( )
傳回此目標的使用者可讀名稱。
-
使用指定的屬性產生此抽象目標的虛擬目標,除非目標需要某些功能的不同值。這是一個抽象方法,必須由衍生類別覆寫。
如果成功,則傳回
-
屬性集,其中包含要套用至相依項的使用需求
-
產生的虛擬目標清單,該清單可能為空。
如果
property-set
為空,則會以衍生類別特定的方式執行此目標的預設建置。
-
6.6.2. 類別 project-target
class project-target : abstract-target {
rule generate ( property-set )
rule build-dir ( )
rule main-target ( name )
rule has-main-target ( name )
rule find ( id : no-error ? )
# Methods inherited from abstract-target
rule name ( )
rule project ( )
rule location ( )
rule full-name ( )
}
此類別具有以下責任
-
維護此專案中主要目標的清單並建置它們。
-
覆寫 abstract-target.generate。產生此專案中包含的所有目標的虛擬目標。
如果成功,則傳回
-
屬性集,其中包含要套用至相依項的使用需求
-
產生的虛擬目標清單,該清單可能為空。
-
-
規則 build-dir ( )
傳回專案的根建置目錄。
-
規則 main-target ( name )
傳回對應於
name
的 main-target 類別執行個體。只能在專案完全載入後呼叫。 -
規則 has-main-target ( name )
傳回是否存在具有指定名稱的 main-target。只能在專案完全載入後呼叫。
-
規則 find ( id : no-error ? )
尋找並傳回具有指定 ID 的目標,相對於自身處理。ID 可以指定目標或檔案名稱,且目標優先。如果找不到目標,則可能會回報錯誤或傳回 nothing,具體取決於
no-error
參數。
6.6.3. 類別 main-target
class main-target : abstract-target {
rule generate ( property-set )
# Methods inherited from abstract-target
rule name ( )
rule project ( )
rule location ( )
rule full-name ( )
}
main-target 代表 Jamfile 中命名的最上層目標。
-
覆寫 abstract-target.generate。藉由尋找所有需求都滿足
property-set
的替代方案,並挑選需求集最長的替代方案,為此主要目標選取替代方案。傳回在該替代方案上呼叫 generate 的結果。如果成功,則傳回
-
屬性集,其中包含要套用至相依項的使用需求
-
產生的虛擬目標清單,該清單可能為空。
-
6.6.4. 類別 basic-target
class basic-target : abstract-target {
rule __init__ ( name : project : sources * : requirements * : default-build * : usage-requirements * )
rule generate ( property-set )
rule construct ( name : source-targets * : property-set )
# Methods inherited from abstract-target
rule name ( )
rule project ( )
rule location ( )
rule full-name ( )
}
實作從來源建構主要目標替代方案的最標準方式。允許來源為檔案或其他主要目標,並處理那些相依性目標的產生。
-
規則 init ( name : project : sources * : requirements * : default-build * : usage-requirements * )
name
-
目標的名稱
project
-
宣告目標所在的 project。
-
覆寫 abstract-target.generate。判斷最終建置屬性、產生來源,並呼叫 construct。此方法不應被覆寫。
如果成功,則傳回
-
屬性集,其中包含要套用至相依項的使用需求
-
產生的虛擬目標清單,該清單可能為空。
-
-
規則 construct ( name : source-targets * : property-set )
為此抽象目標建構虛擬目標。傳回 usage-requirements 屬性集和虛擬目標清單。應在衍生類別中覆寫。
6.6.5. 類別 typed-target
class typed-target : basic-target {
rule __init__ ( name : project : type : sources * : requirements * : default-build * : usage-requirements * )
rule type ( )
rule construct ( name : source-targets * : property-set )
# Methods inherited from abstract-target
rule name ( )
rule project ( )
rule location ( )
rule full-name ( )
# Methods inherited from basic-target
rule generate ( property-set )
}
typed-target 是最常見的目標替代方案類型。會針對每個類型自動定義用於建立類型目標的規則。
-
規則 init ( name : project : type : sources * : requirements * : default-build * : usage-requirements * )
-
規則類型 ( )
傳回目標的類型。
-
規則建構 ( name : source-targets * : property-set )
實作 basic-target.construct。嘗試使用適用於給定property-set的產生器建立正確類型的目標。傳回一個property-set,其中包含使用需求和虛擬目標列表。
ℹ此函數由basic-target.generate自動調用,不應由使用者直接調用。
6.6.6. 類別 property-set
用於儲存一組屬性的類別。
class property-set {
rule raw ( )
rule str ( )
rule propagated ( )
rule add ( ps )
rule add-raw ( properties * )
rule refine ( ps )
rule get ( feature )
}
身分與值之間存在 1<→1 的對應關係。該類別的任何兩個實例都不相等。為了維持此屬性,應使用 'property-set.create' 規則來建立新實例。實例是不可變的。
-
規則 raw ( )
傳回儲存屬性的 Jam 列表。
-
規則 str ( )
傳回儲存屬性的字串表示形式。
-
規則 propagated ( )
傳回一個 property-set,其中包含此 property-set 中所有propagated屬性。
-
傳回一個新的 property-set,其中包含此 property-set 和
ps
中的屬性聯集。ℹ如果 ps
包含非自由屬性,應覆蓋此物件中的值,請改用 refine。 -
規則 add-raw ( properties * )
連結 add,不同之處在於它接受屬性列表而不是 property-set。
-
透過覆蓋在
ps
中指定不同值的任何非自由和非條件屬性來精簡屬性。傳回產生的 property-set。 -
規則 get ( feature )
傳回
feature
的所有值。
6.7. 建置程序
建置程序的一般概述已在使用者文件中提供。本節提供額外的詳細資訊和一些特定規則。
總而言之,使用特定屬性建置目標包含以下步驟
-
套用預設建置,
-
選擇要使用的主要目標替代方案,
-
確定「常見」屬性,
-
建置來源列表和依賴屬性引用的目標,
-
將建置相依性時產生的使用需求新增至「常見」屬性,
-
使用產生器建置目標,
-
計算要傳回的使用需求。
6.7.2. 確定常見屬性
「常見」屬性是一個有些人工的術語。這是中繼屬性集,相依性的建置請求和建置目標的屬性都是從該集合中派生出來的。
由於預設建置和替代方案已處理完畢,因此我們只有兩個輸入:建置請求和需求。以下是有關常見屬性的規則。
-
非自由功能只能有一個值
-
需求中的非條件屬性始終存在於常見屬性中。
-
建置請求中的屬性存在於常見屬性中,除非它被需求中的屬性覆蓋。
-
如果建置請求或需求(非條件或條件)包含可擴充屬性(複合屬性或具有指定子功能值的屬性),則行為等同於明確地將所有擴充屬性分別新增至建置請求或需求中。
-
如果需求包含條件屬性,且此屬性的條件在常見屬性的上下文中為真,則條件屬性也應在常見屬性中。
-
如果這裡的其他規則未給定功能的任何值,則它在常見屬性中具有預設值。
這些規則是宣告式的。它們沒有指定如何計算常見屬性。但是,它們為使用者提供了足夠的資訊。重點是處理條件需求。條件可以透過建置請求中的屬性、非條件需求甚至另一個條件屬性來滿足。例如,以下範例會如預期般運作
exe a : a.cpp
: <toolset>gcc:<variant>release
<variant>release:<define>FOO ;
6.7.3. 目標路徑
有多個因素會決定具體檔案目標的位置。專案中的所有檔案都建置在 bin 目錄下,除非這被 build-dir 專案屬性覆蓋。bin 下有一個路徑,該路徑取決於用於建置每個目標的屬性。此路徑由所有非自由、非附帶屬性唯一確定。例如,給定一個包含以下內容的屬性集:<toolset>gcc
<toolset-gcc:version>4.6.1
<variant>debug
<warnings>all
<define>_DEBUG
<include>/usr/local/include
<link>static
,則路徑將為 gcc-4.6.1/debug/link-static
。 <warnings>
是一個附帶功能,而 <define>
和 <include>
是自由功能,因此它們不會影響路徑。
有時,B2 產生的路徑可能會變得過長。有一些命令列選項可以協助解決此問題。--abbreviate-paths
會將每個元素縮減為不超過五個字元。例如,link-static
會變成 lnk-sttc
。--hash
選項會使用 MD5 雜湊將路徑縮減為單一目錄。
有兩個功能會影響建置目錄。<location>
功能會完全覆蓋預設建置目錄。例如,
exe a : a.cpp : <location>. ;
會將 a
產生的所有檔案建置在 Jamfile 的目錄中。這通常不建議使用,因為它會排除變體建置。
<location-prefix>
功能會在專案的建置目錄下新增一個前置詞。例如,
exe a : a.cpp : <location-prefix>subdir ;
將在 bin/subdir/gcc-4.6.1/debug
中為 a
建立檔案
6.8. 定義
6.8.1. 功能和屬性
功能是建置組態的正規化(與工具集無關)方面,例如是否啟用內聯。功能名稱不得包含「>」字元。
建置組態中的每個功能都具有一個或多個相關的值。非自由功能的功能值不得包含尖括號 (「<
」)、冒號 (「:
」)、等號 (「=
」) 和破折號 (「-
」) 的標點符號字元。自由功能的功能值不得包含尖括號 (「<
」) 字元。
屬性是 (功能、值) 對,表示為 <feature>value。
子功能是一種僅在其父功能存在時才存在的功能,且其身分可以(在其父功能的上下文中)從其值導出。子功能的父功能永遠不能是另一個子功能。因此,功能及其子功能形成一個兩層階層結構。
功能 F 的值字串是 value-subvalue1-subvalue2
…-subvalueN
形式的字串,其中 value
是 F 的合法值,而 subvalue1
…subvalueN
是 F 的某些子功能的合法值,並以破折號 (「-
」) 分隔。例如,屬性 <toolset>gcc <toolset-version>3.0.1
可以使用值字串更簡潔地表示為 <toolset>gcc-3.0.1
。
屬性集是一組屬性(即,沒有重複的集合),例如:<toolset>gcc <runtime-link>static
。
屬性路徑是一個屬性集,其元素已聯結成以斜線分隔的單一字串。先前範例的屬性路徑表示形式為 <toolset>gcc/<runtime-link>static
。
建置規格是一個屬性集,完整描述用於建置目標的功能集。
6.8.2. 屬性有效性
對於自由功能,所有值都有效。對於所有其他功能,會明確指定有效值,而建置系統會回報使用無效功能值的錯誤。子屬性有效性可能會受到限制,以至於某些值僅在存在某些其他子屬性的情況下才有效。例如,可以指定 <gcc-target>mingw
屬性僅在存在 <gcc-version>2.95.2
的情況下才有效。
6.8.3. 功能屬性
每個功能都有零個或多個以下屬性的集合。功能屬性是關於當功能值出現在建置請求中時,建置系統應如何解讀功能值的底層描述。我們也參考屬性的屬性,因此,例如,附帶屬性是其功能具有附帶屬性的屬性。
-
假設附帶功能完全不會影響建置產品。因此,建置系統可能會對其建置規格僅在附帶功能方面有所不同的目標使用相同檔案。控制編譯器警告層級的功能是可能附帶功能的一個範例。
假設非附帶功能會影響建置產品,因此其建置規格在非附帶功能方面有所不同的目標檔案會放置在不同的目錄中,如目標路徑中所述。
-
此類功能會傳播到相依性。也就是說,如果使用傳播屬性建置主要目標,則當建置其任何相依性作為該主要目標的一部分時,建置系統會嘗試使用相同的屬性。例如,當請求最佳化可執行檔時,通常希望它與最佳化程式庫連結。因此,
<optimization>
功能會被傳播。 -
大多數的功能都有一組有限的允許值,並且在給定的建置規格中,只能從該集合中取一個值。另一方面,自由功能可以同時有多個值,且每個值都可以是任意字串。例如,可以同時定義多個前處理器符號。
<define>NDEBUG=1 <define>HAS_CONFIG_H=1
-
可選功能是指在建置規格中不一定要出現的功能。每個非可選的非自由功能都有一個預設值,當該功能的值在目標的需求或使用者建置請求中未另行指定時,就會使用該預設值。[功能的預設值由功能宣告中列出的第一個值給定。—— 將此處移至他處 - dwa]
-
通常,只有當功能的值與其預設值不同時,功能才會產生子變體目錄,這會導致功能的某些值出現不對稱的子變體目錄結構。對稱功能始終會產生對應的子變體目錄。
-
路徑功能的值指定一個路徑。該路徑會被視為相對於使用路徑功能的 Jamfile 目錄的路徑,並且當從不同目錄調用建置時,建置系統會適當地轉換該路徑。
-
只有隱含功能的值才能識別該功能。例如,使用者不需要寫「<toolset>gcc」,而可以簡單地寫「gcc」。隱含功能名稱也不會出現在變體路徑中,但其值會。因此:bin/gcc/…,而不是 bin/toolset-gcc/…。通常只有少數幾個此類功能,以避免可能的名稱衝突。
-
複合功能實際上對應於屬性群組。例如,建置變體是一個複合功能。當從一組建置屬性產生目標時,複合功能會被遞迴展開並新增到建置屬性集中,以便規則在必要時可以找到它們。非複合的非自由功能會覆寫建置屬性集中複合功能的元件。
-
依賴性功能的值是一個目標參考。當用於建置主要目標時,依賴性功能的值會被視為額外的依賴項。
例如,依賴性功能允許聲明程式庫 A 依賴於程式庫 B。因此,每當應用程式連結到 A 時,它也會連結到 B。將 B 指定為 A 的依賴項與將 B 新增到 A 的來源不同。
既非自由也非附帶的功能稱為基本功能。
6.8.4. 功能宣告
低階功能宣告介面是 feature
模組中的 feature
規則。
rule feature ( name : allowed-values * : attributes * )
可以使用 feature.extend
規則擴展功能的允許值。
6.8.5. 屬性精煉
當請求具有特定屬性的目標,且該目標需要一組屬性時,需要找到用於建置的屬性集。此過程稱為屬性精煉,並由以下規則執行
-
所需集合中的每個屬性都會新增到原始屬性集中。
-
如果原始屬性集包含具有不同值的非自由功能屬性,則會移除該屬性。
6.8.6. 條件屬性
有時,只針對其他屬性的特定組合應用某些需求是可取的。例如,您使用的其中一個編譯器會發出一個無意義的警告,您想透過將命令列選項傳遞給它來抑制該警告。您不希望將該選項傳遞給其他編譯器。條件屬性允許您執行此操作。它們的語法是
property ( "," property ) * ":" property
例如,上述問題可以透過以下方式解決
exe hello : hello.cpp : <toolset>yfc:<cxxflags>-disable-pointless-warning ;
語法也允許條件中有多個屬性,例如
exe hello : hello.cpp : <os>NT,<toolset>gcc:<link>static ;
6.8.7. 目標識別碼和參考
目標識別碼用於表示目標。語法是
target-id -> (target-name | file-name | project-id | directory-name) | (project-id | directory-name) "//" target-name project-id -> path target-name -> path file-name -> path directory-name -> path
此文法允許將某些元素識別為以下任一項
-
在目前 Jamfile 中宣告的目標名稱(請注意,目標名稱可能包含斜線)。
-
常規檔案,由絕對名稱或相對於專案來源位置的名稱表示。
-
專案 ID(目前,所有專案 ID 都以斜線開頭)。
-
另一個專案的目錄,由絕對名稱或相對於目前專案位置的名稱表示。
為了確定實際意義,會按此順序檢查可能的解釋。例如,有效的目標 ID 可能為
|
目前專案中的目標 |
|
常規檔案 |
|
專案「/boost/thread」 |
|
特定專案中的目標 |
|
特定目錄中的專案 |
基本原理:目標與專案由特殊分隔符號(而不僅僅是斜線)分隔,因為
-
它強調專案和目標是不同的事物。
-
它允許主要目標名稱包含斜線。
目標參考用於指定來源目標,並且可以額外指定該目標的所需屬性。它的語法如下
target-reference -> target-id [ "/" requested-properties ] requested-properties -> property-path
例如,
exe compiler : compiler.cpp libs/cmdline/<optimization>space ;
即使 compiler
可執行檔是為速度最佳化建置的,也會導致連結經過空間最佳化的 cmdline
程式庫版本。
7. 公用程式
7.1. 除錯器
7.1.1. 概觀
B2 帶有 Jamfile 的除錯器。若要執行除錯器,請使用 b2 -dconsole
啟動 B2。
$ b2 -dconsole (b2db) break gcc.init Breakpoint 1 set at gcc.init (b2db) run Starting program: /usr/bin/b2 Breakpoint 1, gcc.init ( ) at /usr/share/b2/tools/gcc.jam:74 74 local tool-command = ; (b2db) quit
7.1.2. 執行程式
run
命令用於啟動新的 b2
子處理程序進行除錯。run
的引數會傳遞到命令列。如果子處理程序已在執行中,則會在啟動新的子處理程序之前終止該子處理程序。
當程式暫停時,continue
將恢復執行。step
命令會將程式推進一個語句,並在進入另一個函數或從目前函數傳回時停止。next
與 step
類似,不同之處在於它會跳過函數調用。finish
會執行直到目前函數傳回。
kill
命令會立即終止目前的子處理程序。
7.1.3. 中斷點
中斷點是使用 break
命令設定的。中斷點的位置可以指定為函數的名稱(包括模組名稱),也可以指定為 file:line
形式的檔案名稱和行號。建立中斷點時,會為其指定唯一的 ID,該 ID 用於識別其他命令的中斷點。
(b2db) break Jamfile:10 Breakpoint 1 set at Jamfile:10 (b2db) break msvc.init Breakpoint 2 set at msvc.init
可以使用 disable
命令暫時停用中斷點。當中斷點停用時,子處理程序在命中中斷點時不會停止。可以使用 enable
重新啟動已停用的中斷點。
(b2db) disable 1 (b2db) enable 1
可以使用 delete
或 clear
永久移除中斷點。它們之間的區別在於 delete
採用中斷點 ID,而 clear
採用最初指定為要中斷的中斷點的位置。
(b2db) clear Jamfile:10 Deleted breakpoint 1 (b2db) delete 2
8. 擴充器手冊
8.1. 簡介
本節說明如何擴充 B2 以滿足您的本機需求,主要是為您擁有的非標準工具新增支援。在我們開始之前,請務必閱讀並理解元目標的概念 概念,這對於理解其餘內容至關重要。
目前版本的 B2 有三個層級的目標,如下所示。
- 元目標
-
從 Jamfile 中的宣告建立的物件。可以使用一組屬性來呼叫,以產生具體目標。
- 具體目標
-
對應於檔案或動作的物件。
- jam 目標
-
特定於 Boost.Jam 建置引擎的低階具體目標。本質上是一個字串,最常見的是檔案名稱。
在大多數情況下,您只需要處理具體目標以及從元目標建立具體目標的過程。很少需要擴展元目標層級。jam 目標通常僅在命令列模式內使用。
⚠
|
所有 Boost.Jam 與目標相關的內建函數,例如 DEPENDS 或 ALWAYS ,都對 jam 目標進行操作。將它們應用於元目標或具體目標沒有任何效果。 |
8.1.1. 元目標
元目標是一個物件,它會記錄 Jamfile 中指定的資訊,例如元目標種類、名稱、來源和屬性,並且可以使用特定屬性呼叫它以產生具體目標。在程式碼層級,它由衍生自 abstract-target 的類別的實例表示。[4]
generate 方法採用建置屬性(作為 property-set 類別的實例)並傳回包含以下內容的清單
-
作為前置元素 — 此呼叫的用法需求(property-set 的實例)
-
作為後續元素 — 建立的具體目標(
virtual-target
類別的實例。)
可以使用 targets.resolve-reference
函數透過目標 ID 查找元目標,並且 targets.generate-from-reference
函數可以查找和產生元目標。
abstract-target 類別有三個直接衍生類別
-
project-target 對應於專案,不適用於進一步的子類別化。此類別的 generate 方法會建置專案中所有未標記為明確的目標。
-
main-target 對應於專案中的目標,並且包含一個或多個目標替代方案。此類別也不應子類別化。此類別的 generate 方法會選擇要建置的替代方案,並呼叫該替代方案的 generate 方法。
-
basic-target 對應到特定的目標選項。這是一個基礎類別,具有許多衍生類別。generate 方法會處理目標需求和請求的建置屬性,以確定目標的最終屬性、建置所有來源,最後使用來源虛擬目標清單和最終屬性呼叫抽象的 construct 方法。
project-target 和 main-target 類別的實例是隱含建立的——當載入新的 Jamfiles 時,或當建立名稱尚未知的新目標選項時。從 basic-target 衍生的類別的實例通常是在 Jamfile 呼叫 meta 目標規則(例如 exe
)時建立的。
可以建立從 basic-target 衍生的自訂類別,並建立新的 meta 目標規則,以建立此類目標的實例。然而,在大多數情況下,會使用 basic-target 的特定子類別——typed-target。該類別與類型相關聯,並轉發給產生器以建構該類型的具體目標。此過程將在下面說明。當宣告新類型時,會自動定義新的 meta 目標規則。該規則會建立與該類型相關聯的類型目標的新實例。
8.1.2. 具體目標
具體目標由從 virtual-target
衍生的類別的實例表示。最常用的子類別是 file-target
。檔案目標與建立它的動作相關聯——action
類別的實例。而該動作又持有一個來源目標的清單。它還持有 property-set 實例,其中包含應該用於該動作的建置屬性。
以下是從另一個目標 source
建立目標的範例
local a = [ new action $(source) : common.copy : $(property-set) ] ;
local t = [ new file-target $(name) : CPP : $(project) : $(a) ] ;
第一行會建立 action
類別的實例。第一個參數是來源的清單。第二個參數是 Jam 層級的 action 名稱。第三個參數是應用於此動作的 property-set。第二行會建立目標。我們指定名稱、類型和專案。我們也傳遞先前建立的動作物件。如果動作建立數個目標,我們可以重複第二行數次。
在某些情況下,建立具體目標的程式碼可能會使用相同的屬性多次叫用。傳回對應到相同檔案的兩個不同 file-target
實例顯然會導致問題。因此,每當傳回目標時,您都應該透過 virtual-target.register
函式傳遞它們,除了允許 B2 追蹤為每個 meta 目標建立哪些虛擬目標外,這還會在必要時將目標取代為先前建立的相同目標。[5] 以下是一些範例
return [ virtual-target.register $(t) ] ;
return [ sequence.transform virtual-target.register : $(targets) ] ;
8.1.3. 產生器
理論上,B2 中的每種 meta 目標(例如 exe
、lib
或 obj
)都可以透過編寫新的 meta 目標類別來實作,該類別獨立於其他程式碼,找出要產生哪些檔案以及要使用哪些命令。然而,這會相當不靈活。例如,新增對新編譯器的支援將需要編輯數個 meta 目標。
實際上,大多數檔案都有特定的類型,而且大多數工具會取用和產生特定類型的檔案。為了利用這個事實,B2 定義了目標類型和產生器的概念,並具有特殊的 meta 目標類別 typed-target。目標類型僅是一個識別碼。它與一組對應該類型的檔案副檔名相關聯。產生器是工具的抽象概念。它會宣告它產生的類型,而且如果使用一組輸入目標叫用,它會嘗試建構已宣告類型的輸出目標。最後,typed-target 與特定的目標類型相關聯,並轉發該類型的產生器(或多個產生器)。
產生器是從 generator
衍生的類別的實例。generator
類別本身適用於常見情況。您可以定義衍生類別用於自訂情境。
8.2. 範例:一對一產生器
假設您正在撰寫產生 C++ 程式碼的應用程式。如果您曾經這樣做過,您就會知道這並不好。在字串常值中嵌入大量 C++ 程式碼非常笨拙。更好的解決方案是
-
撰寫要產生的程式碼的範本,在會變更的位置留下預留位置
-
在您的應用程式中存取範本,並將預留位置取代為適當的文字。
-
寫入結果。
這很容易實現。您撰寫特殊的逐字檔案,這些檔案只是 C++,只是檔案的第一行包含應該產生的變數名稱。建立一個簡單的工具,該工具會採用逐字檔案,並建立一個 cpp 檔案,其中包含一個 char*
變數,該變數的名稱取自逐字檔案的第一行,而其值是檔案正確引用的內容。
讓我們看看 B2 可以做些什麼。
首先,B2 不知道「逐字檔案」。因此,您必須註冊新的目標類型。以下程式碼會執行此操作
import type ;
type.register VERBATIM : verbatim ;
type.register 的第一個參數提供宣告類型的名稱。依照慣例,它是大寫。第二個參數是此類型檔案的後綴。因此,如果 B2 在來源清單中看到 code.verbatim
,它就知道它的類型是 VERBATIM
。
接下來,您告訴 B2 可以在一個建置步驟中將逐字檔案轉換為 C++ 檔案。產生器是建置步驟的範本,該步驟會將一個類型(或一組類型)的目標轉換為另一個類型。我們的產生器將稱為 verbatim.inline-file
;它會將 VERBATIM
檔案轉換為 CPP
檔案
import generators ;
generators.register-standard verbatim.inline-file : VERBATIM : CPP ;
最後,您必須告知 B2 用於進行轉換的 shell 命令。這是透過 actions
宣告完成的。
actions inline-file
{
"./inline-file.py" $(<) $(>)
}
現在,我們已準備好將所有內容整合在一起。將上面的所有程式碼放入檔案 verbatim.jam
中,將 import verbatim ;
新增至 Jamroot.jam
,並且可以在您的 Jamfile 中撰寫以下內容
exe codegen : codegen.cpp class_template.verbatim usage.verbatim ;
列出的逐字檔案會自動轉換為 C++ 來源檔案、編譯,然後連結到 codegen
可執行檔。
在後續章節中,我們將擴充此範例,並詳細檢閱所有機制。完整的程式碼位於 example/customization
目錄中。
8.3. 目標類型
我們在簡介中做的第一件事是宣告新的目標類型
import type ;
type.register VERBATIM : verbatim ;
類型是目標最重要的屬性。B2 可以自動產生必要的建置動作,僅因為您指定所需的類型(使用不同的主要目標規則),而且因為 B2 可以根據來源的副檔名猜測來源的類型。
type.register
規則的前兩個參數是新類型的名稱和與其關聯的副檔名清單。具有清單中副檔名的檔案將具有指定的目標類型。在從其他來源產生宣告類型的目標的情況下,將使用第一個指定的副檔名。
有時候,您想要根據建置屬性(例如工具集)變更用於產生的目標的後綴。例如,某些編譯器會將副檔名 elf
用於可執行檔。您可以使用 type.set-generated-target-suffix
規則
type.set-generated-target-suffix EXE : <toolset>elf : elf ;
新的目標類型可以從現有的類型繼承。
type.register PLUGIN : : SHARED_LIB ;
上述程式碼會定義從 SHARED_LIB
衍生而來的新類型。最初,新類型會繼承基礎類型的所有屬性,特別是產生器和後綴。通常,您會以某種方式變更新類型。例如,使用 type.set-generated-target-suffix
您可以設定新類型的後綴。或者您可以為新類型編寫特殊的產生器。例如,它可以為外掛程式產生其他中繼資訊。無論哪種方式,只要可以使用 SHARED_LIB
,就可以使用 PLUGIN
類型。例如,您可以將外掛程式直接連結到應用程式。
類型可以定義為「主要」,在這種情況下,B2 會自動宣告主要目標規則來建置該類型的目標。如需更多詳細資訊,請參閱稍後。
8.4. 掃描器
有時候,檔案可以透過某些 include 系統參照其他檔案。若要讓 B2 追蹤包含檔案之間的相依性,您需要提供掃描器。主要限制是,只能將一個掃描器指派給目標類型。
首先,我們需要為掃描器宣告新的類別
class verbatim-scanner : common-scanner
{
rule pattern ( )
{
return "//###include[ ]*\"([^\"]*)\"" ;
}
}
所有複雜的邏輯都在 common-scanner
類別中,您只需要覆寫傳回用於掃描的正規表示式的方法即可。正規表示式中的括號表示字串的哪個部分是包含的檔案的名稱。只會識別正規表示式中第一個括號群組;如果您無法以這種方式表達您想要的所有內容,您可以傳回多個正規表示式,每個正規表示式都包含要比對的括號群組。
之後,我們需要註冊掃描器類別
scanner.register verbatim-scanner : include ;
第二個參數的值(在此範例中為 include
)會指定包含應該搜尋包含檔案的路徑清單的屬性。
最後,我們將新的掃描器指派給 VERBATIM
目標類型
type.set-scanner VERBATIM : verbatim-scanner ;
這足以掃描 include 相依性。
8.5. 工具和產生器
本節將說明如何擴充 B2 以支援新工具。
對於每個額外的工具,都必須建立名為產生器的 B2 物件。該物件具有其接受和產生的特定目標類型。透過使用該資訊,B2 能夠自動叫用產生器。例如,如果您宣告一個產生器,該產生器會取得 D
類型的目標並產生 OBJ
類型的目標,則當將副檔名為 .d
的檔案放在來源清單中時,會導致 B2 叫用您的產生器,然後將產生的物件檔案連結到應用程式中。(當然,這需要您指定 .d
副檔名對應到 D
類型。)
每個產生器都應該是衍生自 generator
類別的類別實例。在最簡單的情況下,您不需要建立衍生類別,只需建立 generator
類別的實例即可。讓我們回顧一下我們在簡介中看到的範例。
import generators ;
generators.register-standard verbatim.inline-file : VERBATIM : CPP ;
actions inline-file
{
"./inline-file.py" $(<) $(>)
}
我們宣告一個標準產生器,指定其 ID、來源類型和目標類型。當呼叫時,產生器將會建立一個類型為 CPP
的目標,並以類型為 VERBATIM
的來源目標作為唯一的來源。但是實際產生檔案會使用哪個指令呢?在 B2 中,動作是使用具名的「動作」區塊指定的,並且在建立目標時應該指定動作區塊的名稱。依照慣例,產生器會使用與其自身 ID 相同的動作區塊名稱。因此,在上面的範例中,「inline-file」動作區塊將會被用來將來源轉換為目標。
產生器主要有兩種:標準產生器和組合產生器,它們分別使用 generators.register-standard
和 generators.register-composing
規則註冊。例如:
generators.register-standard verbatim.inline-file : VERBATIM : CPP ;
generators.register-composing mex.mex : CPP LIB : MEX ;
第一個(標準)產生器採用類型為 VERBATIM
的單一來源,並產生結果。第二個(組合)產生器採用任意數量的來源,這些來源的類型可以是 CPP
或 LIB
。組合產生器通常用於產生頂層目標類型。例如,在建置 exe
目標時呼叫的第一個產生器是與適當連結器相對應的組合產生器。
您還應該了解用於註冊產生器的兩個特定函式:generators.register-c-compiler
和 generators.register-linker
。第一個函式會為 C 檔案設定標頭依賴性掃描,第二個函式則會處理諸如搜尋函式庫之類的各種複雜問題。因此,當您新增對編譯器和連結器的支援時,應始終使用這些函式。
(需要一個關於 UNIX 的注意事項)
自訂產生器類別
標準產生器允許您指定來源和目標類型、動作以及一組旗標。如果您需要更複雜的東西,則需要建立一個具有您自己邏輯的新產生器類別。然後,您必須建立該類別的實例並註冊它。以下範例說明如何建立您自己的產生器類別
class custom-generator : generator
{
rule __init__ ( * : * )
{
generator.__init__ $(1) : $(2) : $(3) : $(4) : $(5) : $(6) : $(7) : $(8) : $(9) ;
}
}
generators.register
[ new custom-generator verbatim.inline-file : VERBATIM : CPP ] ;
此產生器的工作方式與我們上面定義的 verbatim.inline-file
產生器完全相同,但可以透過覆寫 generator
類別的方法來自訂行為。
有兩種方法值得關注。 run
方法負責整個流程 - 它採用多個來源目標,將它們轉換為正確的類型,並建立結果。當所有來源都轉換為正確的類型時,將會呼叫 generated-targets
方法以實際建立結果。
當您想要將額外的屬性新增到產生的目標或使用其他來源時,可以覆寫 generated-targets
方法。對於一個真實範例,假設您有一個程式分析工具,該工具應提供可執行檔的名稱以及所有來源的清單。當然,您不想手動列出所有來源檔案。以下說明 generated-targets
方法如何自動尋找來源清單
class itrace-generator : generator {
...
rule generated-targets ( sources + : property-set : project name ? )
{
local leaves ;
local temp = [ virtual-target.traverse $(sources[1]) : : include-sources ] ;
for local t in $(temp)
{
if ! [ $(t).action ]
{
leaves += $(t) ;
}
}
return [ generator.generated-targets $(sources) $(leafs)
: $(property-set) : $(project) $(name) ] ;
}
}
generators.register [ new itrace-generator nm.itrace : EXE : ITRACE ] ;
將會使用類型為 EXE
的單一來源目標來呼叫 generated-targets
方法。對 virtual-target.traverse
的呼叫將會傳回可執行檔所依賴的所有目標,並且我們會進一步尋找不是從任何事物產生的檔案。找到的目標會被新增到來源中。
可以覆寫 run
方法以完全自訂產生器的工作方式。特別是,可以完全自訂來源到所需類型的轉換。以下是另一個真實範例。Boost Python 函式庫的測試通常由兩部分組成:一個 Python 程式和一個 C++ 檔案。C++ 檔案會編譯成由 Python 程式載入的 Python 擴充模組。但在兩個檔案名稱相同的情況下,建立的 Python 擴充模組必須重新命名。否則,Python 程式將會匯入它自己,而不是匯入擴充模組。以下說明如何完成此操作
rule run ( project name ? : property-set : sources * )
{
local python ;
for local s in $(sources)
{
if [ $(s).type ] = PY
{
python = $(s) ;
}
}
local libs ;
for local s in $(sources)
{
if [ type.is-derived [ $(s).type ] LIB ]
{
libs += $(s) ;
}
}
local new-sources ;
for local s in $(sources)
{
if [ type.is-derived [ $(s).type ] CPP ]
{
local name = [ $(s).name ] ; # get the target's basename
if $(name) = [ $(python).name ]
{
name = $(name)_ext ; # rename the target
}
new-sources += [ generators.construct $(project) $(name) :
PYTHON_EXTENSION : $(property-set) : $(s) $(libs) ] ;
}
}
result = [ construct-result $(python) $(new-sources) : $(project) $(name)
: $(property-set) ] ;
}
首先,我們將所有來源分離為 Python 檔案、函式庫和 C++ 來源。對於每個 C++ 來源,我們會透過呼叫 generators.construct
並傳遞 C++ 來源和函式庫來建立單獨的 Python 擴充模組。在這一點上,如果需要,我們也會變更擴充模組的名稱。
8.6. 功能
通常,我們需要控制傳遞給已呼叫工具的選項。這是透過功能完成的。請考慮以下範例
# Declare a new free feature
import feature : feature ;
feature verbatim-options : : free ;
# Cause the value of the 'verbatim-options' feature to be
# available as 'OPTIONS' variable inside verbatim.inline-file
import toolset : flags ;
flags verbatim.inline-file OPTIONS <verbatim-options> ;
# Use the "OPTIONS" variable
actions inline-file
{
"./inline-file.py" $(OPTIONS) $(<) $(>)
}
我們首先定義一個新功能。然後,flags
呼叫會指出,每當執行 verbatim.inline-file 動作時,verbatim-options
功能的值將會被新增到 OPTIONS
變數中,並且可以在動作主體中使用。您需要查閱線上說明 (--help) 以尋找 toolset.flags
規則的所有功能。
雖然您可以定義任何一組功能並以任何方式解譯它們的值,但 B2 建議採用以下程式碼標準來設計功能。
大多數功能應該具有一組固定的值,這些值在其設計要使用的工具類別中是可移植的(與工具無關)。使用者不必針對確切的工具調整值。例如,<optimization>speed
對於所有 C++ 編譯器都具有相同的含義,使用者不必擔心傳遞給編譯器命令列的確切選項。
除了這種可移植的功能之外,還有特殊的「原始」功能,允許使用者在需要時將任何值傳遞給特定工具的命令列參數。例如,<cxxflags>
功能允許您將任何命令列選項傳遞給 C++ 編譯器。 <include>
功能允許您傳遞任何以 -I
開頭的字串,並且解譯是特定於工具的。(請參閱我可以使用 Boost.Jam 變數擷取外部程式輸出嗎? 以取得該功能的非常巧妙的用法範例)。當然,應該始終盡力使用可移植的功能,但這些功能仍然會作為後門提供,只是為了確保 B2 不會剝奪使用者的任何控制權。
使用可移植功能是一個好主意,因為
-
當可移植功能被賦予一組固定的值時,您可以使用該功能的不同設定來建置專案,而 B2 會自動為產生的檔案使用兩個不同的目錄。B2 不會嘗試分離使用不同原始選項建置的目標。
-
與「原始」功能不同,您不需要在 Jamfile 中使用特定的命令列旗標,而且它更有可能與其他工具搭配使用。
新增功能的步驟
新增功能需要三個步驟
-
宣告功能。為此,使用「feature.feature」規則。您必須決定一組功能屬性
-
如果您想要為一個目標設定的功能值自動傳播到其相依目標,則使其成為「propagated」。
-
如果功能沒有固定的值清單,則必須為「free」。例如,
include
功能是一個自由功能。 -
如果功能用於參考相對於 Jamfile 的路徑,則它必須是「path」功能。這些功能的值也會自動轉換為 B2 的內部路徑表示。例如,
include
是一個路徑功能。 -
如果功能用於參考某個目標,則它必須是「dependency」功能。
-
-
在特定於目標的變數中表示功能值。建置動作是透過 Boost.Jam 變數展開修改的命令範本。
toolset.flags
規則會將特定於目標的變數設定為功能的值。 -
使用變數。步驟 2 中設定的變數可以用在建置動作中以形成命令參數或檔案。
另一個範例
這是另一個範例。讓我們看看如何建立一個參考目標的功能。例如,在 Windows 上連結動態函式庫時,有時需要指定一個「DEF 檔案」,告訴應該匯出哪些函式。最好這樣使用此檔案
lib a : a.cpp : <def-file>a.def ;
實際上,此功能已經支援,但無論如何...
-
由於該功能參考目標,因此它必須是「dependency」。
feature def-file : : free dependency ;
-
其中一個關注 DEF 檔案的工具集是 msvc。應該將以下行新增到其中。
flags msvc.link DEF_FILE <def-file> ;
-
由於
msvc.link
動作未使用DEF_FILE
變數,因此我們需要將其修改為actions link bind DEF_FILE { $(.LD) .... /DEF:$(DEF_FILE) .... }
請注意
bind DEF_FILE
部分。它會告訴 B2 將DEF_FILE
中的內部目標名稱轉換為link
動作中的對應檔案名稱。如果沒有它,$(DEF_FILE)
的展開將會是一個奇怪的符號,不太可能對連結器有任何意義。我們幾乎完成了,除了將以下程式碼新增到
msvc.jam
rule link { DEPENDS $(<) : [ on $(<) return $(DEF_FILE) ] ; }
這是 B2 引擎中錯誤的因應措施,希望有一天可以修復。
變體和複合功能。
有時您想要為某些功能集建立捷徑。例如,release
是 <variant>
的值,並且是一組功能的捷徑。
可以定義您自己的建置變體。例如
variant crazy : <optimization>speed <inlining>off
<debug-symbols>on <profiling>on ;
將會使用指定的屬性集定義一個新的變體。您也可以擴充現有的變體
variant super_release : release : <define>USE_ASM ;
在這種情況下,super_release
將會展開為 release
指定的所有屬性,以及您指定的額外屬性。
您不限於僅使用 variant
功能。以下範例定義了一個全新的功能
feature parallelism : mpi fake none : composite link-incompatible ;
feature.compose <parallelism>mpi : <library>/mpi//mpi/<parallelism>none ;
feature.compose <parallelism>fake : <library>/mpi//fake/<parallelism>none ;
這將允許您指定功能 parallelism
的值,該值將展開以連結到必要的函式庫。
8.7. 主要目標規則
當您的目標規則僅應產生特定類型的目標時,第一種方法適用。在這種情況下,已經為您定義了規則!當您定義新類型時,B2 會自動定義對應的規則。規則的名稱是從類型的名稱中取得的,方法是將所有字母都小寫並將底線替換為破折號。例如,如果您建立一個包含以下內容的模組 obfuscate.jam
import type ;
type.register OBFUSCATED_CPP : ocpp ;
import generators ;
generators.register-standard obfuscate.file : CPP : OBFUSCATED_CPP ;
並匯入該模組,您將能夠在 Jamfile 中使用規則「obfuscated-cpp」,該規則會將來源轉換為 OBFUSCATED_CPP 類型。
第二種方法是編寫一個包裝規則,該規則會呼叫任何現有規則。例如,假設每個目錄只有一個函式庫,並且您希望目錄中的所有 cpp 檔案都編譯到該函式庫中。您可以使用以下方式實現此效果
lib codegen : [ glob *.cpp ] ;
如果您想要更簡單,您可以在 Jamroot.jam
檔案中新增以下定義
rule glib ( name : extra-sources * : requirements * )
{
lib $(name) : [ glob *.cpp ] $(extra-sources) : $(requirements) ;
}
允許您將 Jamfile 簡化為
glib codegen ;
請注意,由於您可以將自訂產生器與目標類型相關聯,因此建置的邏輯可能相當複雜。例如,boostbook
模組會宣告目標類型 BOOSTBOOK_MAIN
以及該類型的自訂產生器。如果您的主要目標規則並非微不足道,您可以將其作為範例。
8.8. 工具集模組
如果您的擴充功能只會在一個專案中使用,可以將它們放在獨立的 .jam
檔案中,並由您的 Jamroot.jam
匯入。如果擴充功能會用於許多專案,使用者會感謝您錦上添花。
using
規則提供載入和設定擴充功能的標準機制。為了使其運作,您的模組應提供一個 init
規則。該規則將會以傳遞給 using
規則的相同參數來呼叫。允許的參數集合由您決定。例如,您可以允許使用者指定路徑、工具版本和其他選項。
以下是一些有助於使 B2 更一致的準則
-
init
規則永遠不應失敗。即使使用者提供了不正確的路徑,您也應該發出警告並繼續。設定可能會在不同機器之間共用,並且一台機器上的錯誤值在另一台機器上可能是正確的。 -
偏好指定要執行的命令,而不是指定工具的安裝路徑。首先,這提供了更多的控制:可以指定
/usr/bin/g++-snapshot time g++
作為命令。其次,雖然某些工具具有邏輯上的「安裝根目錄」,但最好讓使用者不必記住特定工具是需要完整的命令還是路徑。
-
檢查多次初始化。使用者可能會嘗試多次初始化模組。您需要檢查這一點並決定該怎麼做。通常,除非您支援多個工具版本,否則重複初始化是使用者錯誤。如果可以在初始化期間指定工具的版本,請確保版本始終指定,或從不指定(在這種情況下,工具只會初始化一次)。例如,如果您允許
using yfc ; using yfc : 3.3 ; using yfc : 3.4 ;
那麼不清楚第一次初始化對應的是工具的 3.3 版、工具的 3.4 版還是其他版本。這可能會導致使用相同版本建置兩次。
-
如果可能,
init
必須可以不帶參數呼叫。在這種情況下,它應該嘗試自動偵測所有必要資訊,例如,透過在 PATH 或常見安裝位置中尋找工具。通常這是可行的,並允許使用者簡單地寫入using yfc ;
-
考慮使用
tools/common
模組中的設施。您可以看看tools/gcc.jam
如何在init
規則中使用該模組。
9. 常見問題
9.1. 如何在 Jamfile 中取得功能的目前值?
這是不可行的,因為 Jamfile 沒有任何功能的「目前」值,無論是工具集、建置變體還是其他任何東西。對於 B2 的單次執行,任何給定的主要目標都可以使用多個屬性集來建置。例如,使用者可以在命令列上請求兩個建置變體。或者,一個程式庫在從一個應用程式使用時會建置為共享的,而在從另一個應用程式使用時會建置為靜態的。每個 Jamfile 只會讀取一次,因此通常沒有任何單一功能值可以在 Jamfile 中存取。
功能只有在建置目標時才會有特定的值,並且有兩種方法可以使用該值
9.2. 我收到「實際目標名稱重複」錯誤。那是什麼意思?
最有可能的情況是您嘗試使用幾乎相同但屬性不同的方式編譯同一個檔案兩次。例如
exe a : a.cpp : <include>/usr/local/include ;
exe b : a.cpp ;
上面的程式碼片段需要編譯 a.cpp
兩次,它們僅在 include
屬性上有所不同。由於 include
功能宣告為 free
,因此 B2 不會為每個值建立單獨的建置目錄,而這兩個建置都會在同一個建置目錄中產生物件檔案。忽略這一點並僅編譯檔案一次將是危險的,因為不同的 include 可能會導致編譯完全不同的程式碼。
要解決這個問題,您需要決定是否應該編譯檔案一次或兩次。
-
要僅編譯檔案一次,請確保兩個目標請求的屬性相同
exe a : a.cpp : <include>/usr/local/include ; exe b : a.cpp : <include>/usr/local/include ;
或
alias a-with-include : a.cpp : <include>/usr/local/include ; exe a : a-with-include ; exe b : a-with-include ;
或者,如果您不希望
includes
屬性影響為建置的a
和b
可執行檔新增的任何其他來源的編譯方式obj a-obj : a.cpp : <include>/usr/local/include ; exe a : a-obj ; exe b : a-obj ;
請注意,在這兩種情況下,
include
屬性只會應用於建置這些物件檔案,而不會應用於可能為目標a
和b
新增的任何其他來源。 -
要編譯檔案兩次,您可以告訴 B2 將其編譯成兩個單獨的物件檔案,如下所示
obj a_obj : a.cpp : <include>/usr/local/include ; obj b_obj : a.cpp ; exe a : a_obj ; exe b : b_obj ;
或者,您可以使物件檔案目標對於主要目標而言是本機的
exe a : [ obj a_obj : a.cpp : <include>/usr/local/include ] ; exe b : [ obj a_obj : a.cpp ] ;
這會導致 B2 實際為您稍微更改產生的物件檔案名稱,從而避免任何衝突。
請注意,在這兩種情況下,
include
屬性只會應用於建置這些物件檔案,而不會應用於可能為目標a
和b
新增的任何其他來源。
一個很好的問題是,為什麼 B2 無法自動使用上述某些方法。問題在於,這種魔法只會在一半的情況下有所幫助,而在另一半的情況下,它會默默地做錯事。在這種情況下,要求使用者澄清他的意圖更簡單也更安全。
9.3. 存取環境變數
許多使用者希望在 Jamfile 中使用環境變數,例如,控制外部程式庫的位置。在許多情況下,最好在 site-config.jam 檔案中宣告這些外部程式庫,如配方章節中所述。但是,如果使用者已經設定了環境變數,他們可能不方便同時設定 site-config.jam 檔案,並且使用環境變數可能是合理的。
Boost.Jam 會自動將所有環境變數匯入其內建的 .ENVIRON 模組,因此使用者可以直接從那裡讀取它們,或使用輔助 os.environ 規則。例如
import os ;
local unga-unga = [ os.environ UNGA_UNGA ] ;
ECHO $(unga-unga) ;
或者更實際一點
import os ;
local SOME_LIBRARY_PATH = [ os.environ SOME_LIBRARY_PATH ] ;
exe a : a.cpp : <include>$(SOME_LIBRARY_PATH) ;
9.4. 如何控制屬性順序?
由於內部原因,B2 會依字母順序排序所有屬性。這表示如果您寫入
exe a : a.cpp : <include>b <include>a ;
那麼命令列將首先提到 a
include 目錄,然後是 b
,即使它們是以相反的順序指定的。在大多數情況下,使用者並不關心。但是,有時 include 或其他屬性的順序很重要。對於這種情況,提供了一種特殊語法
exe a : a.cpp : <include>a&&b ;
&&
符號分隔屬性值,並指定應該保留它們的順序。建議您僅在屬性順序確實重要時才使用此功能,而不是作為方便的捷徑。到處使用它可能會對效能產生負面影響。
9.5. 如何控制 Unix 上的程式庫連結順序?
在類 Unix 作業系統上,在叫用連結器時指定靜態程式庫的順序很重要,因為預設情況下,連結器會通過程式庫清單執行一次。以不正確的順序傳遞程式庫將會導致連結錯誤。此外,此行為通常用於使一個程式庫覆寫另一個程式庫中的符號。因此,有時需要強制執行特定的程式庫連結順序。
B2 嘗試自動計算正確的順序。主要規則是,如果程式庫 a
「使用」程式庫 b
,那麼程式庫 a
將會出現在命令列上,位於程式庫 b
之前。如果 b
出現在 a
程式庫的來源中,或其使用情況列在其需求中,則會認為程式庫 a
使用 b
。要明確指定 use
關係,可以使用 <use>
功能。例如,以下兩行都會導致 a
出現在命令列上的 b
之前
lib a : a.cpp b ;
lib a : a.cpp : <use>b ;
相同的方法也適用於搜尋的程式庫
lib z ;
lib png : : <use>z ;
exe viewer : viewer png z ;
9.6. 我可以使用 Boost.Jam 變數擷取外部程式輸出嗎?
SHELL
內建規則可以用於此目的
local gtk_includes = [ SHELL "gtk-config --cflags" ] ;
9.7. 如何取得專案根目錄(又稱為 Jamroot)位置?
您可能希望在 Jamfile 中使用專案的根目錄位置。若要存取它,只需使用以下程式碼在您的 Jamroot.jam
檔案中宣告路徑常數
path-constant TOP : . ;
之後,TOP
變數可以在每個 Jamfile 中使用。
9.8. 如何變更一個檔案的編譯旗標?
如果必須使用特殊選項編譯一個檔案,您需要明確為該檔案宣告一個 obj
目標,然後在您的 exe
或 lib
目標中使用該目標
exe a : a.cpp b ;
obj b : b.cpp : <optimization>off ;
當然,您可以使用其他屬性,例如指定特定的 C/C++ 編譯器選項
exe a : a.cpp b ;
obj b : b.cpp : <cflags>-g ;
您也可以使用條件屬性來進行更精細的控制
exe a : a.cpp b ;
obj b : b.cpp : <variant>release:<optimization>off ;
9.9. 為什麼dll-path
和hardcode-dll-paths
屬性很有用?
ℹ
|
這個條目是特定於 Unix 系統的。 |
在回答問題之前,讓我們先回顧一些關於共享程式庫的重點。共享程式庫可以被多個應用程式(或其他程式庫)使用,而無需在連結的二進位檔中實際包含該程式庫。這可以大大減少應用程式總大小。也可以在應用程式安裝後升級共享程式庫。
但是,為了啟動依賴於共享程式庫的應用程式,作業系統需要找到共享程式庫。動態連結器將會在系統定義的路徑清單中搜尋、載入程式庫並解析符號。這表示您應該變更系統定義的清單(由 LD_LIBRARY_PATH
環境變數提供)或將程式庫安裝到系統位置。這在開發時可能不方便,因為程式庫尚未準備好安裝,並且混淆系統路徑可能是不理想的。幸運的是,在 Unix 上還有另一種方法。
使用hardcode-dll-paths
和dll-path
功能,可以使用一個額外的程式庫目錄路徑清單連結目標,這些路徑將在系統路徑之前搜尋 — 這些路徑稱為「執行階段程式庫搜尋路徑」或「執行路徑」或「執行路徑清單」,具體取決於您正在閱讀哪個平台的說明文件 — 請參閱您平台的動態連結器手冊頁或維基百科以取得更多資訊。
ℹ
|
為了簡潔起見,我們將在下方使用 rpath 清單。 |
9.9.1. hardcode-dll-paths
用於exe
目標的hardcode-dll-paths
功能,對於開發特別有幫助;由於建置系統已經知道所有使用的共享程式庫的路徑,因此預設情況下會自動將它們新增到可執行檔的 rpath 清單中。
然而,當執行檔安裝後,情況就不同了;顯然,已安裝的執行檔不應包含指向您開發樹的硬編碼路徑。因此,install
規則會隱式地(即預設情況下)否定 hardcode-dll-paths
功能,方法是在必要時重新連結執行檔,而不使用自動路徑。
-
對於
exe
規則-
當
<hardcode-dll-paths>true
(預設值)時,所有包含已使用共享函式庫的目錄路徑,會自動加入到目標的 rpath 清單中。 -
需要明確的
<hardcode-dll-paths>false
屬性才能停用自動將目錄路徑加入到共享函式庫。
-
-
對於
install
規則-
如果需要,需要明確的
<hardcode-dll-paths>true
,才能將加入到來源目標的 rpath 清單傳播到install
目標。(這包括加入到來源目標的明確dll-path
項目。) -
預設情況下,隱式的
<hardcode-dll-paths>false
屬性將確保來源目標的 rpath 清單不會傳播到install
目標。
-
-
對於
lib
規則,<hardcode-dll-paths>
功能會被忽略。
9.9.2. dll-path
作為替代方案或補充,您可以使用 dll-path
功能,手動將明確的目錄路徑新增到 rpath 清單中。
例如
install installed : application : <dll-path>/usr/lib/snake
<location>/usr/bin ;
將允許應用程式找到放置在 /usr/lib/snake
目錄中的函式庫。
9.9.3. 結論
如果您將函式庫安裝到非標準位置並新增明確路徑,您可以更精確地控制將使用的函式庫。系統位置中名稱相同的函式庫不會被意外使用。如果您將函式庫安裝到系統位置且不新增任何路徑,系統管理員將擁有更多控制權。每個函式庫都可以單獨升級,並且所有應用程式都將使用新的函式庫。
哪種方法最好取決於您的情況。如果函式庫相對獨立,且可以被第三方應用程式使用,則應將它們安裝在系統位置。如果您有很多只能被您的應用程式使用的函式庫,則將它們安裝到非標準目錄並新增明確路徑是合理的,如上面的範例所示。另請注意,不同系統的指南在這方面有所不同。例如,Debian GNU 指南禁止任何額外的搜尋路徑,而 Solaris 指南則建議應始終使用它們。
(適用於客戶端目標 - 即使用共享函式庫的目標。)
規則 | 功能 | 值 | Rpath 清單新增 |
---|---|---|---|
|
|
|
所有共享函式庫目錄的絕對路徑。 |
|
|
|
(無) |
|
|
|
將來源( |
|
|
|
(無) |
|
|
已停用 |
(無) |
|
|
(絕對路徑) |
指定的絕對路徑。 |
|
|
(相對路徑) |
由指定的相對路徑組成,並附加命令列上指定的 jam 目錄路徑的路徑。 ⚠️ 警告:產生的路徑將取決於特定的命令列呼叫,因此在實際使用中受到嚴重限制。 |
9.10. site-config.jam 中的目標
最好宣告在給定系統上可用的標準函式庫。將目標宣告放在特定專案的 Jamfile 中並不是很好,因為函式庫的位置可能在不同的開發機器之間變化,然後這些宣告需要在不同的專案中重複。解決方案是在 B2 的 site-config.jam
設定檔中宣告目標
project site-config ;
lib zlib : : <name>z ;
回想一下,site-config.jam
和 user-config.jam
都是專案,而且您在 Jamfile 中可以做的所有事情,您也可以在這些檔案中做。因此,您宣告一個專案 ID 和一個目標。現在,可以寫入
exe hello : hello.cpp /site-config//zlib ;
在任何 Jamfile 中。
9.11. 僅標頭函式庫
在現代 C++ 中,函式庫通常僅由標頭檔組成,而沒有任何原始程式碼檔需要編譯。要使用此類函式庫,您需要將適當的 include 和可能的定義新增到您的專案。但是,對於大量外部函式庫,要記住哪些函式庫僅標頭檔,以及您必須連結到哪些函式庫會變得有問題。但是,使用 B2,可以將僅標頭函式庫宣告為 B2 目標,並且所有相依項都可以使用此類函式庫,而無需記住它是僅標頭函式庫還是非僅標頭函式庫。
可以使用 alias
規則宣告僅標頭函式庫,並將其 include 路徑指定為其使用需求的一部分,例如
alias my-lib
: # no sources
: # no build requirements
: # no default build
: <include>whatever ;
在 my-lib
的使用需求中指定的 include 會自動新增到其所有相依項的建置屬性中。相依項不需要關心 my-lib
是否為僅標頭或非僅標頭,並且有可能稍後將 my-lib
變成常規編譯函式庫,而無需將 include 新增到其相依項宣告中。
如果已經為定義僅標頭函式庫的專案宣告了適當的使用需求,則無需為 alias
目標重複它們
project my : usage-requirements <include>whatever ;
alias mylib ;
9.12. B2、b2
、bjam
和 Perforce Jam 之間有什麼區別?
B2 是完整建置系統的名稱。執行它的執行檔是 b2
。該執行檔是用 C 撰寫的,並實作了效能關鍵的演算法,例如相依性圖的遍歷和執行命令。它還實作了一種用於實作 B2 其餘部分的直譯語言。此執行檔正式稱為「B2 引擎」。
B2 引擎源自較早的建置工具 Perforce Jam。最初,只有少量的變更,並且檔名為 bjam
。後來,隨著越來越多的變更,名稱的相似性對使用者造成了損害,並且從 Boost 1.47.0 開始,執行檔的正式名稱已更改為 b2
。為了相容性,仍然會建立一個名為 bjam
的副本,但是我們鼓勵您在所有情況下都使用新名稱。
Perforce Jam 是一個重要的基礎,我們衷心感謝它的影響,但是對於今天的用戶來說,這些工具僅共享直譯語言的一些基本知識。
10. 其他工具
10.1. 文件工具
10.1.1. Asciidoctor
asciidoctor 工具將 ascidoc 文件格式轉換為各種後端格式,以供檢視或文件工具進一步處理。此工具支援基準 asciidoctor 發行版(即基於 Ruby 的工具)。
功能:asciidoctor-attribute
定義任意 asciidoctor 屬性。該功能的值應使用屬性的 CLI 語法指定。例如,要用作目標需求
html example : example.adoc :
<asciidoctor-attribute>idprefix=ex ;
這是一個 free
功能,並且不會 propagated
。也就是說,它僅適用於指定它的目標。
功能:asciidoctor-backend
指定用於從來源 asciidoc 產生輸出的 backend
。此功能會自動應用以符合建置目標類型。例如,當為 asciidoc
來源指定 html
目標時
html example : example.adoc ;
目標預設會取得 <asciidoctor-backend>html5
需求。每個目標類型的預設值為
-
html
:<asciidoctor-backend>html5
-
docbook
:<asciidoctor-backend>docbook45
-
man
:<asciidoctor-backend>manpage
-
pdf
:<asciidoctor-backend>pdf
要覆寫預設值,請將其指定為目標上的需求
docbook example : example.adoc :
<asciidoctor-backend>docbook5 ;
允許的 backend
值為:html5
、docbook45
、docbook5
、pdf
。
10.2. 其他工具
10.2.1. pkg-config
pkg-config 程式用於擷取系統中已安裝函式庫的資訊。它從特殊的中繼資料檔案中擷取有關套件的資訊。這些檔案以套件命名,並具有 .pc
副檔名。指定給 pkg-config 的套件名稱定義為中繼資料檔案的名稱,減去 .pc
副檔名。
功能:pkg-config
選擇已初始化的 pkg-config
設定之一。此功能會 propagated
到相依項。其用法在初始化一節中討論。
功能:pkg-config-define
此 free
功能將變數指派新增到 pkg-config 呼叫中。例如,
pkg-config.import mypackage : requirements <pkg-config-define>key=value ;
等同於在命令列上調用
pkg-config --define-variable=key=value mypackage ;
規則:import
匯入 pkg-config 套件的主要目標規則。當其消費者目標被建置時,將會使用取決於目前屬性集的引數來呼叫 pkg-config 命令。有影響的功能包括
-
<pkg-config-define>
:新增一個--define-variable
引數; -
<link>
:當<link>static
時,新增--static
引數; -
<link>
:當<link>static
時,新增--static
引數; -
<name>
:指定套件名稱(如果屬性不存在,則改用目標名稱); -
<version>
:指定套件版本範圍,可以多次使用,並且應該是由點分隔的數字序列,選擇性地以=
、<
、>
、⇐
或>=
開頭。
範例
pkg-config.import my-package
: requirements <name>my_package <version><4 <version>>=3.1 ;
初始化
要使用 pkg-config
工具,您需要在設定檔中使用 using
規則來宣告它
using pkg-config : [config] : [command] ... : [ options ] ... ;
-
config
:已初始化設定的名稱。名稱可以省略,在這種情況下,設定將成為預設設定。 -
command
:要執行的命令,包含任何額外引數。如果沒有給定命令,則會先檢查PKG_CONFIG
環境變數,如果為空,則使用字串pkg-config
。 -
options
:修改pkg-config
行為的選項。允許的選項為 -
<path>
:設定PKG_CONFIG_PATH
環境變數;允許多次出現。 -
<libdir>
:設定PKG_CONFIG_LIBDIR
環境變數;允許多次出現。 -
<allow-system-cflags>
:設定PKG_CONFIG_ALLOW_SYSTEM_CFLAGS
環境變數;允許多次出現。 -
<allow-system-libs>
:設定PKG_CONFIG_ALLOW_SYSTEM_LIBS
環境變數;允許多次出現。 -
<sysroot>
:設定PKG_CONFIG_SYSROOT_DIR
環境變數;允許多次出現。 -
<variable>
:向命令呼叫新增變數定義引數;允許多次出現。
類別 pkg-config-target
class pkg-config-target : alias-target-class {
rule construct ( name : sources * : property-set )
rule version ( property-set )
rule variable ( name : property-set )
}
由 import
規則傳回的物件類別。這些物件本身在需要更複雜的邏輯來使用套件的情況下可能會很有用。請參閱 提示 中的範例。
-
rule construct ( name : sources * : property-set )
覆寫alias-target.construct
。 -
rule version ( property-set )
傳回在property-set
環境下的套件版本。 -
rule variable ( name : property-set )
傳回在property-set
環境下套件中變數name
的值。
提示
使用多個設定
假設您有 2 個 .pc
檔案集合:一個用於平台 A,另一個用於平台 B。您可以初始化 pkg-config
工具的 2 個設定,每個設定對應於特定的集合
using pkg-config : A : : <libdir>path/to/collection/A ;
using pkg-config : B : : <libdir>path/to/collection/B ;
然後,您可以指定平台 A 的建置應使用設定 A,而平台 B 的建置應使用設定 B
project
: requirements
<target-os>A-os,<architecture>A-arch:<pkg-config>A
<target-os>B-os,<architecture>B-arch:<pkg-config>B
;
由於 project-config
、user-config
和 site-config
模組是 jamroot 模組的父模組,您可以將其放在任何這些檔案中。
根據屬性集選擇套件名稱
由於套件的檔案名稱應該以套件名稱加上 .pc
作為後綴,因此有些專案提出了命名方案,以允許同時安裝多個主要版本或建置變體。為了選擇與建置請求相對應的特定名稱,您可以在需求中使用 <conditional>
屬性
pkg-config.import mypackage : requirements <conditional>@infer-name ;
rule infer-name ( properties * )
{
local name = mypackage ;
local variant = [ property.select <variant> : $(properties) ] ;
if $(variant) = debug
{
name += -d ;
}
return <name>$(name) ;
}
common.format-name
規則在這種情況下非常有用。
根據套件版本或變數修改使用需求
有時您需要根據套件的版本或它定義的變數套用一些邏輯。為此,您可以在使用需求中使用 <conditional>
屬性
mypackage =
[ pkg-config.import mypackage : usage-requirements <conditional>@define_ns
] ;
rule extra-props ( properties * )
{
local ps = [ property-set.create $(properties) ] ;
local prefix = [ $(mypackage).variable name_prefix : $(ps) ] ;
prefix += [ $(mypackage).version $(ps) ] ;
return <define>$(prefix:J=_) ;
}
10.2.2. Sass
此工具將 SASS 和 SCSS 檔案轉換為 CSS。此工具明確支援用 C (sassc) 編寫的版本和原始 Ruby 實作 (scss),但其他變體也可能有效。除了本節中描述的工具特定功能外,該工具還會辨識 <flags>
和 <include>
功能。
功能:sass-style
設定輸出樣式。可用的值為
-
nested
:每個屬性都放在自己的行上,規則根據它們的巢狀深度縮排; -
expanded
:每個屬性都放在自己的行上,規則不縮排; -
compact
:每個規則都放在單行上,巢狀規則佔用相鄰的行,而不相關的規則組之間用換行符分隔; -
compressed
:佔用最小的空間:所有不必要的空白都被刪除,屬性值被壓縮以具有最小的表示形式。
此功能是optional
,並且不會propagated
到相依目標。如果沒有指定樣式,則如果屬性集包含屬性 <optimization>on
,則會選擇 compressed
樣式。否則,會選擇 nested
樣式。
11. 範例
11.1. 簡介
這裡我們包含一系列簡單到複雜的完全可運作範例,展示如何使用 Boost Build v2 來完成各種任務。它們展示了從簡單到進階的功能。如果您發現自己正在查看範例,但找不到您想要看到運作的內容,請發布到我們的支援列表,我們將嘗試提出解決方案並將其新增到此處供其他人學習。
11.2. 您好
此範例展示了一個非常基本的 Boost Build 專案設定,因此它會從單個來源檔案編譯單個可執行檔
hello.cpp
#include <iostream>
int main()
{
std::cout << "Hello!\n";
}
我們的 jamroot.jam
非常精簡,只為程式指定一個 exe
目標
jamroot.jam
exe hello : hello.cpp ;
建置範例會產生
> cd /example/hello
> b2
...found 8 targets...
...updating 4 targets...
common.mkdir bin/clang-darwin-4.2.1
common.mkdir bin/clang-darwin-4.2.1/debug
clang-darwin.compile.c++ bin/clang-darwin-4.2.1/debug/hello.o
clang-darwin.link bin/clang-darwin-4.2.1/debug/hello
...updated 4 targets...
> bin/clang-darwin-4.2.1/debug/hello
Hello!
ℹ
|
bin 子目錄中的實際路徑將取決於您的工具集。 |
11.3. 清理器
此範例展示了在使用 clang 或 gcc 工具集時如何啟用清理器
main.cpp
int main()
{
char* c = nullptr;
std::cout << "Hello sanitizers\n " << *c;
}
我們的 jamroot.jam
非常精簡,只為程式指定一個 exe
目標
jamroot.jam
exe main : main.cpp ;
可以透過將 on
或 norecover
傳遞給適當的清理器功能(例如 thread-sanitizer=on
)來啟用清理器。norecover
選項會導致程式在偵測到第一個清理器問題後終止。下列範例展示如何在簡單程式中啟用 address
和 undefined
清理器
> cd /example/sanitizers
> b2 toolset=gcc address-sanitizer=norecover undefined-sanitizer=on
...found 10 targets...
...updating 7 targets...
gcc.compile.c++ bin/gcc-7.3.0/debug/address-sanitizer-norecover/undefined-sanitizer-on/main.o
gcc.link bin/gcc-7.3.0/debug/address-sanitizer-norecover/undefined-sanitizer-on/main
...updated 7 targets...
執行產生的程式可能會產生類似於下列的輸出
> ./bin/gcc-7.3.0/debug/address-sanitizer-norecover/undefined-sanitizer-on/main
Hello sanitizers
main.cpp:6:43: runtime error: load of null pointer of type 'char'
ASAN:DEADLYSIGNAL
=================================================================
==29767==ERROR: AddressSanitizer: SEGV on unknown address 0x000000000000 (pc 0x55ba7988af1b bp 0x7ffdf3d76560 sp 0x7ffdf3d76530 T0)
==29767==The signal is caused by a READ memory access.
==29767==Hint: address points to the zero page.
#0 0x55ba7988af1a in main /home/damian/projects/boost/tools/build/example/sanitizers/main.cpp:6
#1 0x7f42f2ba1b96 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x21b96)
#2 0x55ba7988adb9 in _start (/home/damian/projects/boost/tools/build/example/sanitizers/bin/gcc-7.3.0/debug/address-sanitizer-norecover/undefined-sanitizer-on/main+0xdb9)
AddressSanitizer can not provide additional info.
SUMMARY: AddressSanitizer: SEGV /home/damian/projects/boost/tools/build/example/sanitizers/main.cpp:6 in main
==29767==ABORTING
ℹ
|
bin 子目錄中的實際路徑將取決於您的工具集和設定。呈現的輸出可能會因您的編譯器版本而異。 |
12. Boost.Jam 文件
Jam 是 make(1) 的替代品,它使建置簡單的東西變得簡單,並且使建置複雜的東西變得易於管理。
12.1. 建置 B2
在建置 B2
後安裝它,只需要將產生的可執行檔複製到您 PATH
中的某個位置。對於建置可執行檔,有一組 build
引導程式指令碼來適應特定的環境。這些指令碼採用一個可選引數,即要使用建置的工具集名稱。當未給定工具集時,會嘗試偵測可用的工具集並使用它。建置指令碼接受以下引數
build [toolset]
在不帶引數的情況下執行指令碼將讓您有最大的成功機會。在 Windows 平台上,從命令主控台中執行
cd jam source location
.\build.bat
在 Unix 類型平台上執行
cd jam source location
sh ./build.sh
對於 Boost 發行版中包含的 Boost.Jam 來源,jam 來源位置為 BOOST_ROOT/tools/build/src/engine
。
如果指令碼無法偵測到要用來建置的適當工具集,則您的特定工具集可能無法自動偵測。在這種情況下,您可以將工具集指定為第一個引數,這假設該工具集已在 PATH
中隨時可用。
ℹ
|
用於建置 Boost.Jam 的工具集獨立於用於 B2 的工具集。只需要一個版本的 Boost.Jam 即可使用 B2。 |
支援的工具集,以及它們是否可以自動偵測到,如下所示
指令碼 | 平台 | 工具集 | 偵測和注意事項 |
---|---|---|---|
|
Windows |
||
|
Microsoft Visual Studio C++ 2019
|
||
|
Microsoft Visual Studio C++ 2017
|
||
|
Microsoft Visual Studio C++ 2015
|
||
|
Microsoft Visual Studio C++ 2013
|
||
|
Embarcadero C++Builder
|
||
|
適用於 Windows 的 Intel C++ 編譯器
|
||
|
以 MinGW 設定的 GNU GCC
|
||
|
Comeau Computing C/C++ |
||
|
GNU GCC |
||
|
Clang LLVM |
||
|
GNU GCC |
||
|
Unix、Linux、Cygwin、Windows Bash 等 |
||
|
GNU GCC
|
||
|
Clang LLVM
|
||
|
適用於 Linux 的 Intel C++ (oneAPI)
|
||
|
SGI MIPSpro C++
|
||
|
適用於 True64 UNIX 的 Compaq C++ 編譯器
|
||
|
QNX Neutrino
|
||
|
IBM VisualAge C++
|
||
|
PGI 編譯器
|
||
|
Pathscale C++
|
||
|
Comeau Computing C/C++
|
||
|
Borland C++
|
||
|
HP-UX aCC
|
||
|
Sun Workshop 6 C++
|
建置的可執行檔會放置在 src/engine
目錄中。
build.sh
腳本支援額外的調用選項,可用來控制建置以及自訂編譯器。
build.sh [--option|--option=x] [toolset]
--help
-
顯示一些說明資訊,包括這些選項。
--verbose
-
顯示此腳本正在執行的訊息。
--debug
-
建置可執行檔的偵錯版本。預設是建置最佳化的可執行檔。
--guess-toolset
-
印出我們偵測到可供建置的工具集。這供外部腳本使用,例如 Boost 程式庫的主要引導腳本。
--cxx=CXX
-
要使用的編譯器可執行檔,取代偵測到的編譯器可執行檔。
--cxxflags=CXXFLAGS
-
要使用的編譯器旗標,除了偵測到的編譯器的旗標之外。
12.2. 語言
B2
有一個直譯的程序語言。b2
中的陳述式是規則(程序)定義、規則調用、流程控制結構、變數賦值,以及各種語言支援。
12.2.1. 詞法特性
B2
將其輸入檔案視為以空白分隔的符號,但有兩個例外:雙引號 (") 可以括住空白以將其嵌入符號中,且規則動作定義中成對的大括號 (\{}) 之間的所有內容都被視為單一字串。反斜線 (\) 可以逸出雙引號或任何單一空白字元。
B2
需要空白(空格、tab 或換行符號)來包圍所有符號,包括冒號 (:) 和分號 (;) 符號。
B2
關鍵字(在此文件中提及)是保留的,通常必須用雙引號 (") 引起來才能用作任意符號,例如變數或目標名稱。
註解以 #
字元開頭,並延伸至行尾。區塊註解以 #|
開頭,並延伸至下一個 |#
。
12.2.2. 目標
基本的 b2
資料實體是目標。建置目標是要更新的檔案。來源目標是用於更新建置目標的檔案。建置目標和來源目標統稱為檔案目標,且建置目標通常是其他建置目標的來源目標。偽目標是代表對其他目標的相依性的符號,但它們本身不與任何真實檔案相關聯。
檔案目標的識別符號通常是檔案的名稱,可以是絕對根目錄、相對於 b2
調用目錄或僅限本機(無目錄)。最常見的情況是最後一種,實際檔案路徑是使用 $(SEARCH)
和 $(LOCATE)
特殊變數綁定的。請參閱下方的 SEARCH 和 LOCATE 變數。本機檔案名稱可以選擇性地以 grist 限定,grist 是一個用於確保唯一性的字串值。具有 file(member) 形式的識別符號的檔案目標是程式庫成員(通常是 Unix 上的 ar
(1) 封存檔)。
12.2.3. 規則
基本的 b2
語言實體稱為規則。規則分為兩個部分定義:程序和動作。程序是要在調用規則時執行的 jam 陳述式主體;動作是當更新規則的建置目標時要執行的 OS shell 命令。
規則可以傳回值,這些值可以使用 "[ rule args … ]" 展開為清單。規則的值是其最後一個陳述式的值,但只有以下陳述式具有值:'if'(所選分支的值)、'switch'(所選 case 的值)、set(結果變數的值)和 '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 ]
規則以 field1 到 fieldN 中的值調用。它們可以在程序的陳述式中以 $(1)
到 $(N)
(最多 9 個)來引用,且前兩個只能在動作的 commands 中以 $(1)
和 $(2)
引用。$(<)
和 $(>)
與 $(1)
和 $(2)
同義。
規則分為兩類:更新規則(帶有動作)和純程序規則(沒有動作)。更新規則會將引數 $(1)
和 $(2)
分別視為建置目標和來源,而純程序規則可以採用任意引數。
當調用更新規則時,其更新動作會加入到與其建置目標 ($(1)
) 相關聯的動作中,然後再執行規則的程序。稍後,為了在更新階段建置目標,commands 會傳遞給 OS 命令 shell,其中 $(1)
和 $(2)
會替換為目標名稱的繫結版本。請參閱上方的繫結。
規則調用可以透過變數間接進行
$(var) field1 : field2 : ... : fieldN ;
on target $(var) field1 : field2 : ... : fieldN ;
[ $(var) field1 : field2 : ... : fieldN ]
[ on target $(var) field1 : field2 : ... : fieldN ]
變數的值會命名要調用的規則(或多個規則)。會針對 $(var)
的值清單中的每個元素調用規則。欄位 field1 : field2 : …
會作為每個調用的引數傳遞。對於 [ … ] 形式,傳回值是所有調用的傳回值的串連。
動作修飾詞
以下動作修飾詞可以理解
actions bind vars
-
$(vars)
將被替換為繫結值。 actions existing
-
$(>)
僅包含目前存在的來源目標。 actions ignore
-
命令的傳回狀態會被忽略。
actions piecemeal
-
命令會重複調用,其中
$(>)
的子集小到足以放入此 OS 上的命令緩衝區中。 actions quietly
-
動作不會回顯到標準輸出。
actions together
-
對同一建置目標多次調用相同動作時,來自多個調用的
$(>)
會被合併在一起。 actions updated
-
$(>)
僅包含本身標記為更新的來源目標。
引數清單
您可以描述規則接受的引數,並在規則內按名稱引用它們。例如,以下會將 "I’m sorry, 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 ;
除非在形式引數清單 (在規則宣告中以 :
分隔) 中的每個名稱都綁定到相應實際引數的單一元素,否則後面會跟著下列其中一個修飾詞
符號 | 先前符號的語意 |
---|---|
|
optional |
|
綁定到實際引數的零個或多個未繫結元素。當 |
|
綁定到實際引數的一個或多個未繫結元素。 |
會檢查實際和形式引數是否不一致,這會導致 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 程式碼使用引數清單。
12.2.4. 內建規則
B2
有一組不斷增長的內建規則,所有這些規則都是沒有更新動作的純程序規則。它們分為三組:第一組建置相依性圖;第二組修改相依性圖;第三組僅為公用程式規則。
相依性建置
修改繫結
六個規則 ALWAYS
、LEAVES
、NOCARE
、NOTFILE
、NOUPDATE
和 TEMPORARY
會修改相依性圖,以便 b2
在其目標繫結階段以不同方式處理目標。請參閱上方的繫結。通常,如果目標遺失、其檔案系統修改時間比其任何相依性(遞迴地)舊,或者其任何相依性正在更新,則 b2
會更新目標。可以透過調用下列規則來變更此基本行為
ALWAYS
rule ALWAYS ( targets * )
導致目標被重建,無論它們是否為最新狀態(它們仍必須在依賴關係圖中)。這用於 clean 和 uninstall 目標,因為它們沒有依賴關係,否則看起來永遠不需要建置。它最好應用於也是 NOTFILE
目標的目標,但它也可以用於強制更新真實檔案。
LEAVES
rule LEAVES ( targets * )
使每個目標僅依賴於其葉子來源,而不依賴於任何中間目標。這使其不受其依賴項更新的影響,因為「葉子」依賴項是那些沒有自己的依賴項且沒有更新動作的依賴項。這允許僅在原始原始檔變更時才更新目標。
NOCARE
rule NOCARE ( targets * )
導致 b2
忽略既找不到又沒有更新動作來建置它們的目標。通常,對於此類目標,b2
會發出警告,然後跳過依賴於這些遺失目標的其他目標。Jambase
中的 HdrRule
在標頭檔案掃描期間找到的標頭檔案名稱上使用 NOCARE
,以讓 b2
知道包含的檔案可能不存在。例如,如果 #include
在 #ifdef
內,則包含的檔案實際上可能不存在。
⚠
|
對於具有建置動作的目標:如果它們的建置動作以非零返回碼結束,則仍將建置相依的目標。 |
NOTFILE
rule NOTFILE ( targets * )
將目標標記為虛擬目標,而不是真實檔案。不檢查時間戳記,因此僅當目標的依賴項已更新,或目標也標記為 ALWAYS
時,才會執行對此類目標的操作。預設的 b2
目標 all
是一個虛擬目標。在 Jambase
中,NOTFILE
用於定義幾個額外的方便虛擬目標。
NOUPDATE
rule NOUPDATE ( targets * )
導致忽略目標上的時間戳記。這有兩個效果:首先,一旦建立目標,它將永遠不會被更新;其次,手動更新目標不會導致其他目標被更新。例如,在 Jambase
中,此規則由 MkDir
規則應用於目錄,因為 MkDir
只關心目標目錄是否存在,而不關心上次更新的時間。
TEMPORARY
rule TEMPORARY ( targets * )
將目標標記為暫時性的,允許在其他依賴於它們的目標更新後將其刪除。如果缺少 TEMPORARY
目標,b2
會使用目標父項的時間戳記。Jambase
使用 TEMPORARY
來標記在建置後歸檔在函式庫中的物件檔案,以便可以在歸檔後將它們刪除。
FAIL_EXPECTED
rule FAIL_EXPECTED ( targets * )
為了處理預期建置動作會失敗的目標(例如,在測試斷言或編譯時類型檢查是否正常工作時),Boost Jam 提供了與 NOCARE
等相同的樣式的 FAIL_EXPECTED
規則。在目標更新期間,FAIL_EXPECTED
參數的建置動作的返回碼會反轉:如果它失敗,則會繼續建置相依的目標,就好像它成功一樣。如果它成功,則會跳過相依的目標。
公用程式
ECHO
和 EXIT
這兩個規則是公用程式規則,僅在 `b2` 的剖析階段中使用。
EXIT
rule EXIT ( message * : result-value ? )
將message 傳送到標準輸出,然後在未給定result-value 的情況下以失敗狀態結束,否則以給定的result-value 結束。
Echo
、echo
、Exit
和 exit
被接受為 ECHO
和 EXIT
的別名,因為很難判斷這些是內建規則,而不是像 include
一樣屬於語言的一部分。
GLOB
GLOB
規則會執行檔案名稱 globbing。
rule GLOB ( directories * : patterns * : downcase-opt ? )
使用與 switch 陳述式中模式相同的萬用字元。透過在「[ ]」內的規則調用中用作參數來調用它。例如:FILES = [ GLOB dir1 dir2 : *.c *.h ]
將 FILES
設定為 dir1
和 dir2
中的 C 原始檔和標頭檔案的清單。產生的檔案名稱是完整路徑名稱,包括目錄,但該模式僅應用於不含目錄的檔案名稱。
如果提供了downcase-opt,則檔案名稱在與模式比對之前會轉換為全部小寫;您可以使用它來使用小寫模式進行不區分大小寫的比對。如果作業系統提供,則傳回的路徑仍將具有大小寫混合。在 Windows NT 和 Cygwin 以及 OpenVMS 上,檔案名稱總是在比對之前轉換為小寫。
GLOB_ARCHIVE
GLOB_ARCHIVE
規則會執行物件封存成員的名稱 globbing。
rule GLOB_ARCHIVE ( archives * : member-patterns * : downcase-opt ? : symbol-patterns ? )
與 GLOB
類似,此規則用於比對封存(靜態物件函式庫)中成員檔案的名稱。傳回成功比對的成員清單,否則傳回 null。產生的成員名稱以 archive-path(member-name)
的形式與包含封存的路徑名稱限定。成員模式僅用於比對成員名稱;如果未指定任何萬用字元,則會假設為完全比對。成員名稱通常對應於物件檔案名稱,因此具有平台特定性 - 在比對模式中使用平台定義的物件後綴可實現可攜性。
如果提供了downcase-opt,則成員名稱在與模式比對之前會轉換為全部小寫;您可以使用它來使用小寫模式進行不區分大小寫的比對。如果作業系統提供,則傳回的路徑仍將具有大小寫混合。在 Windows NT、Cygwin 和 OpenVMS 上,檔案名稱總是在比對之前轉換為小寫。
此外,可以在支援的平台(目前僅限 OpenVMS)上使用符號/函式模式比對成員。在這種情況下,會傳回包含相符符號的成員。成員和符號模式以 OR 條件應用,成員模式優先。在不支援的平台上,如果指定任何符號模式,則會傳回 null。
MATCH
MATCH
規則會執行模式比對。
rule MATCH ( regexps + : list * )
將 egrep
(1) 樣式的正規表示式regexps 與list 中的字串比對。結果是list 中每個字串的相符 ()
子表示式清單,以及 regexps 中每個正規表示式的相符 ()
子表示式清單。
BACKTRACE
rule BACKTRACE ( )
傳回四元組清單:filename line module rulename…,描述呼叫堆疊的每個較淺層級。此規則可用於從 Jam 規則產生有用的診斷訊息。
UPDATE
rule UPDATE ( targets * )
傳統的 jam 將命令列的任何非選項元素視為要更新的目標的名稱。這阻止了更複雜的命令列處理。現在再次啟用此功能,但對 UPDATE
規則進行了額外變更,以便可以靈活地變更要更新的目標清單。UPDATE 規則有兩個效果
-
它會清除要更新的目標清單,以及
-
導致更新指定的目標。
如果未透過 UPDATE
規則指定任何目標,則不會更新任何目標。為了支援以更有用的方式變更更新清單,該規則還會傳回先前在更新清單中的目標。這使得可以新增目標,例如
local previous-updates = [ UPDATE ] ;
UPDATE $(previous-updates) a-new-target ;
W32_GETREG
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" ] ;
W32_GETREGNAMES
rule W32_GETREGNAMES ( path : result-type )
僅針對 win32 平台定義。它會讀取 Windows 的登錄。'path' 是資訊的位置,而 'result-type' 是 subkeys
或 values
。如需 'path' 格式和約束的詳細資訊,請參閱 W32_GETREG
。
根據 'result-type',規則會傳回下列其中一項
子金鑰
-
'path' 的所有直接子金鑰的名稱。
值
-
由 'path' 給定的登錄金鑰中包含的值的名稱。金鑰的「預設」值只有在其值已在登錄中設定時才會出現在傳回的清單中。
如果無法辨識 'result-type',或無法擷取要求的資料,則規則會傳回空清單。範例
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) ;
}
}
SHELL
rule SHELL ( command : * )
SHELL
會執行命令,然後傳回命令的標準輸出。SHELL
僅適用於 C 函式庫中有 popen()
函式的平台。在沒有正常運作的 popen()
函式的平台上,SHELL
會被實作為空操作。SHELL
適用於 Unix、MacOS X 和大多數 Windows 編譯器。在 Windows 底下的 Metrowerks 編譯器上,SHELL
是空操作。有一組可變的選項可作為額外引數。
exit-status
-
除了輸出之外,執行命令的結果狀態會以結果的第二個元素傳回。
no-output
-
不擷取命令的輸出。而是傳回一個空的("")字串值來取代輸出。
strip-eol
-
從輸出中移除尾隨的行尾字元(如果有的話)。
因為 Perforce/Jambase 定義了一個會隱藏內建規則的 SHELL
規則,因此在這種情況下,COMMAND
可以用作 SHELL
的別名。
SPLIT_BY_CHARACTERS
rule SPLIT_BY_CHARACTERS ( string : delimiters )
SPLIT_BY_CHARACTERS
會根據分隔符號中存在的任何分隔符號字元分割指定的字串,並傳回產生的清單。
12.2.5. 流程控制
B2
有幾個簡單的流程控制陳述式
for var in 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
-
如果可以在 b 中找到 a 的所有元素,或者如果 a 沒有元素,則為 true
! cond
-
條件不成立
cond && cond
-
連詞
cond || cond
-
析取
( cond )
-
優先順序分組
include file ;
導致 b2
讀取指定的檔案。檔案會像一般目標一樣繫結(請參閱上面的繫結),但與一般目標不同的是,include 檔案無法建置。
include 檔案會在剖析階段插入到輸入串流中。主要輸入檔案和所有 include 的檔案會被視為單一檔案;也就是說,b2
不會從 include 的檔案推斷範圍界限。
local vars [ = values ] ;
在封閉的 {}
區塊內建立新的 vars,遮蔽它們可能有的任何先前值。當目前區塊結束時,會還原 vars 的先前值。呼叫的任何規則或包含的檔案都會看到本機值,而不是先前的值(這有時稱為動態範圍)。local 陳述式可以出現在任何地方,甚至在區塊之外(在這種情況下,會在輸入結束時還原先前的值)。如果存在,vars 會初始化為 values,否則會保持未初始化。
return values ;
在規則主體內,return 陳述式會設定規則調用的傳回值,並返回呼叫端。
switch value
{
case pattern1 : statements ;
case pattern2 : statements ;
...
}
switch 陳述式會執行零個或一個封閉的陳述式,具體取決於第一個其模式比對 value 的 case(如果有的話)。模式值不會進行變數展開。模式值可以包含下列萬用字元
?
-
比對任何單一字元
*
-
比對零個或多個字元
[chars]
-
比對 chars 中的任何單一字元
[^chars]
-
比對不在 chars 中的任何單一字元
\x
-
比對 x(逸出其他萬用字元)
while cond { statements }
只要 cond 在進入時保持為 true,就會重複執行陳述式。(請參閱上面 if 下的 cond 運算式語法說明)。
break ;
立即結束最接近的封閉 while 或 for 迴圈。
continue ;
跳到最接近的封閉 while 或 for 迴圈的頂端。
12.2.6. 變數
B2
變數是零個或多個元素的清單,每個元素都是字串值。未定義的變數與具有空清單的變數是無法區分的,但是,已定義的變數可能有一個或多個為 null 字串的元素。所有變數都參照為 $(variable)
。
變數可以是全域或目標特定的。在後者的情況下,變數只會在更新特定目標時採用給定的值。
變數的定義方式如下
variable = elements ;
variable += elements ;
variable on targets = elements ;
variable on targets += elements ;
variable default = elements ;
variable ?= elements ;
前兩種形式會全域設定 variable。第三種和第四種形式會設定目標特定的變數。=
運算子會將 variable 的任何先前元素取代為 elements;+=
運算會將 elements 加入 variable 的元素清單。最後兩種形式是同義的:它們會全域設定 variable,但前提是先前未設定。
更新命令中參照的變數會取代為它們的值;目標特定的值優先於全域值。作為引數 ($(1)
和 $(2)
) 傳遞給動作的變數會取代為它們的繫結值;bind
修飾符可以用於動作,以導致其他變數取代為繫結值。請參閱上面的動作修飾符。
B2
變數不會重新匯出到執行更新動作的 shell 環境,但更新動作可以使用 $(variable)
參照 b2
變數。
變數展開
在剖析期間,b2
會對不是關鍵字或規則名稱的每個 token 執行變數展開。具有內嵌變數參照的此類 token 會取代為零個或多個 token。變數參照的形式為 $(v)
或 $(vm)
,其中 v 是變數名稱,而 m 是選用的修飾符。
規則動作中的變數展開與陳述式中的變數展開類似,不同之處在於,不論是否加上引號,動作字串都會在空白處進行 token 化。
變數展開後 token 的結果是 token 組件的乘積,其中每個組件都是一個常值子字串或替換變數參照的清單。例如
$(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
由於此乘積展開,如果 token 中的任何變數參照未定義,則展開的結果會是空清單。如果任何變數元素是 null 字串,則結果會傳播非 null 元素
$(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
同樣地,在 OpenVMS 上使用時,
:W
修飾符會使用decc$to_vms
CRTL 函式將 POSIX 樣式路徑轉換為原生 VMS 樣式格式。此修飾符通常在動作區塊內使用,以在 VMS 特定命令中正確指定檔案路徑。例如x = "subdir/filename.c" ; ECHO $(x:W) ;
在 OpenVMS 上印出
[.subdir]filename.c
在其他平台上,字串不會變更。
:chars
-
選取 chars 中列出的組件。
例如,
:BS
會選取檔名(基底名稱和副檔名)。 :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 分隔。
:O=value
-
設定變數評估的語意選項。value 的格式對於變數或產生的檔案展開是特定的。
在 VMS 上,$(var:P)
是 $(var:D)
的父目錄。
:⇐value
-
在評估變數展開之後,將指定的 value 加到展開運算式值的元素前。
:>=value
-
在評估變數展開之後,將指定的 value 加到展開運算式值的元素後。
本機 For 迴圈變數
Boost Jam 允許您在迴圈中宣告本機 for 迴圈控制變數
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:E=filecontents)
的子表達式,並在建立具有設定為 filecontents
內容的指定檔案後,將該表達式替換為 filename
。這對於建立編譯器回應檔和其他「內部」檔案很有用。展開在剖析和動作執行期間都有效。因此,可以在三個建置階段中的任何階段建立檔案。此展開遵循與變數展開相同的修飾符。產生的檔案展開接受以下 (:O=
) 展開選項值:
F
-
始終將
@()
引用替換為產生的檔案名稱。 C
-
始終將
@()
引用替換為內容,即:E=value
表達式中的值。 FC
或CF
-
根據內容 (
:E=value
) 的長度,替換為檔案或內容。如果命令的長度短於允許的命令長度限制,它將在動作中替換為內容。否則,該引用將替換為檔案名稱。
內建變數
本節討論對 b2
具有特殊意義的變數。所有這些都必須在全域模組中定義或使用——在具名模組中使用這些變數不會產生預期的效果。請參閱模組。
SEARCH 和 LOCATE
這兩個變數控制檔案目標名稱與檔案系統中位置的繫結。通常,$(SEARCH)
用於尋找現有的來源,而 $(LOCATE)
用於修正建置目標的位置。
根目錄(絕對路徑)的檔案目標會按原樣繫結。未根目錄的檔案目標名稱通常也會按原樣繫結,因此相對於目前目錄,但 $(LOCATE)
和 $(SEARCH)
的設定會改變這種情況
-
如果設定了
$(LOCATE)
,則目標會繫結到$(LOCATE)
中第一個目錄的相對位置。只有第一個元素用於繫結。 -
如果設定了
$(SEARCH)
,則目標會繫結到$(SEARCH)
中已存在目標檔案的第一個目錄。 -
如果
$(SEARCH)
搜尋失敗,則目標仍然會繫結到目前目錄的相對位置。
$(SEARCH)
和 $(LOCATE)
都應該針對特定目標設定,而不是全域設定。如果它們是全域設定的,則 b2
會將相同的路徑用於所有檔案繫結,這不太可能產生合理的結果。在編寫您自己的規則時,尤其是不基於 Jambase 中的規則時,您可能需要直接設定 $(SEARCH)
或 $(LOCATE)
。Jambase 中定義的幾乎所有規則都會將 $(SEARCH)
和 $(LOCATE)
分別設定為尋找的來源和建立的目標的合理值。
HDRSCAN 和 HDRRULE
這兩個變數控制標頭檔掃描。$(HDRSCAN)
是一個 egrep(1)
模式,其中檔案名稱周圍有 (),用於尋找來源檔案中的檔案包含陳述式。Jambase
使用 $(HDRPATTERN)
作為 $(HDRSCAN)
的模式。$(HDRRULE)
是要調用以取得掃描結果的規則名稱:掃描的檔案是目標,找到的檔案是來源。這是 b2
透過變數設定調用規則的唯一位置。
必須同時設定 $(HDRSCAN)
和 $(HDRRULE)
才能進行標頭檔掃描,並且它們應該針對特定目標設定,而不是全域設定。如果它們是全域設定的,則所有檔案(包括可執行檔和程式庫)都會被掃描標頭檔包含陳述式。
對標頭檔包含的掃描並不精確,但至少是動態的,因此無需執行類似 makedepend(GNU)
的動作來建立靜態相依性檔案。掃描機制會偏向於包含 (也就是說,它比遺漏包含檔案更有可能傳回編譯器實際未使用的檔案名稱),因為它無法判斷 #include
行是否位於 #ifdefs
或其他條件邏輯內。在 Jambase
中,HdrRule
會將 NOCARE
規則套用到掃描期間找到的每個標頭檔,以便如果檔案尚未存在,則不會導致編譯失敗,b2
也不會在意。
此外,掃描規則運算式只適用於包含的檔案名稱實際位於來源檔案中的情況。它無法處理允許使用變數名稱 (如同 Jam
語言本身) 包含檔案的語言。
信號量
有時需要禁止某些動作的平行執行。例如:
-
舊版本的 yacc 使用具有固定名稱的檔案。因此,執行兩個 yacc 動作是危險的。
-
您可能會想要執行平行編譯,但不要執行平行連結,因為連結是 i/o 繫結,只會變得更慢。
Craig McPeeters 擴充了 Perforce Jam 以解決此類問題,並且該擴充功能已整合到 Boost.Jam 中。
可以透過在該目標上設定名為 JAM_SEMAPHORE
的變數,將信號量指派給任何目標。變數的值是信號量名稱。它必須與任何宣告的目標名稱不同,否則可以是任意的。
信號量的語意是,在具有相同信號量的一組目標中,一次只能更新一個,無論 -j
選項如何。
Jam 版本
JAMDATE
-
b2
啟動時的日期和時間,以 ISO-8601 UTC 值表示。 JAMUNAME
-
uname(1) 命令的輸出 (僅限 Unix)
JAMVERSION
-
b2
版本,為語義三元組 "X.Y.Z"。 JAM_VERSION
-
具有兩個元素的一個預先定義的全域變數,表示 Boost Jam 的版本號碼。Boost Jam 版本從
03
00
開始。較早版本的Jam
不會自動定義JAM_VERSION
。
JAMSHELL
當 b2
執行規則的動作區塊時,它會分岔並執行 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__
可以將 __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__
中的規則名稱之後的任何值都會在此處傳遞。 目標
-
已建置的
b2
目標。 command
-
動作主體中已執行命令的文字。
status
-
已執行命令的整數結果。
start
-
已執行命令的起始時間戳記,以 ISO-8601 UTC 值表示。
end
-
已執行命令的完成時間戳記,以 ISO-8601 UTC 值表示。
user
-
已執行命令所花費的使用者 CPU 秒數,以浮點數值表示。
system
-
已執行命令所花費的系統 CPU 秒數,以浮點數值表示。
output
-
命令的輸出,為單一字串。輸出的內容會反映
-pX
選項的使用。
ℹ
|
如果同時為目標設定了這兩個變數,則會同時呼叫這兩個變數,先呼叫 __TIMING_RULE__ ,然後呼叫 __ACTION_RULE__ 。 |
12.2.7. 模組
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 ]
VARNAMES
規則
rule VARNAMES ( module ? )
傳回指定模組中所有變數綁定的名稱清單。如果省略 module,則會傳回全域模組中所有變數綁定的名稱。
ℹ
|
這包括呼叫堆疊中規則內,在 VARNAMES 呼叫時尚未傳回的任何區域變數。 |
IMPORT
規則
IMPORT
允許跨模組的規則名稱別名
rule IMPORT ( source_module ? : source_rules *
: target_module ? : target_rules * )
IMPORT
規則會將 source_module 中的規則複製到 target_module 中作為區域規則。如果未提供 source_module 或 target_module,則會參照全域模組。source_rules 指定要從 source_module 匯入哪些規則;target_rules 指定要在 target_module 中給予這些規則的名稱。如果 source_rules 包含的名稱與 source_module 中的規則不符,或如果它包含的項目數與 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
規則
EXPORT
允許跨模組的規則名稱別名
rule EXPORT ( module ? : rules * )
EXPORT
規則會將 source_module
中的 rules 標記為非區域性(因此可以匯出)。如果 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.
CALLER_MODULE
規則
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)} ;
12.3. 其他
12.3.1. 診斷
除了通用錯誤訊息之外,b2
也可能會發出以下其中一項訊息
warning: unknown rule X
呼叫了一個尚未以 actions
或 rule
陳述式定義的規則。
using N temp target(s)
找到了標記為暫時性的目標(但仍然存在)。
updating N target(s)
目標已過期,將會更新。
can't find N target(s)
找不到原始程式檔,而且沒有任何動作可以建立這些檔案。
can't make N target(s)
由於找不到原始程式碼,因此無法建立其他目標。
warning: X depends on itself
目標直接或透過其來源相依於自身。
don't know how to make X
目標不存在,而且沒有定義任何動作來建立它。
X skipped for lack of Y
原始程式碼建置失敗,因此無法建置目標。
warning: using independent target X
使用 $(<)
或 $(>)
參照一個並非任何其他目標相依性的目標。
X removed
B2
在中斷後移除了部分建置的目標。
12.3.2. 錯誤、限制
為了成功進行平行建置,檔案之間的相依性必須正確拼寫出來,因為目標往往會以最快的優先順序進行建置。此外,請注意將固定名稱檔案丟入目前目錄的不可平行化命令,例如 yacc(1)
。
設定不佳的 $(JAMSHELL)
可能會導致無聲失敗。
12.3.3. 基本原理
本節摘自官方 Jam 文件,以及使用它和閱讀 Jambase 規則的經驗。我們在此重複這些資訊主要是因為它們對於理解和使用 Jam 至關重要,但並未整合在單一位置。其中一些資訊在官方文件中完全遺失。我們希望這對於任何希望熟悉 Jam 和 Boost 建置系統的人有所幫助。
-
Jam
rules
實際上是簡單的程序實體。將它們視為函式。引數以冒號分隔。 -
Jam 的目標是由任意字串識別的抽象實體。內建的
DEPENDS
規則會在具名目標之間的相依性圖表中建立連結。 -
請注意,關於內建
INCLUDES
規則的原始 Jam 文件不正確:INCLUDES targets1 : targets2
會導致依賴於 targets1 成員的所有項目都依賴於 targets2 的所有成員。它會以奇特的方式執行此操作,方法是將 targets2 附加到 targets1 中所有項目的相依性清單的特殊尾部區段。這樣建立循環相依性似乎是可以的;事實上,當單一建置動作同時產生 targets1 和 targets2 時,它似乎是「正確的做法」。 -
當呼叫規則時,如果宣告了與規則同名的
actions
,則這些動作會新增至由規則第一個引數識別之目標的更新動作。如果宣告了相應的動作,則實際上可以呼叫未宣告的規則:該規則會被視為空白。 -
目標(
NOTFILE
目標除外)會透過稱為綁定的程序與檔案系統中的路徑建立關聯。綁定是根據目標特定SEARCH
和LOCATE
變數的設定,搜尋與目標名稱相同的檔案(無雜質)的程序。 -
除了區域和全域變數之外,jam 還允許您在目標上設定變數。目標特定變數值通常無法讀取,而且僅在以下內容中生效
-
在更新動作中,變數值會先在第一個引數(正在更新的目標)命名的目標上尋找。由於 Jam 會在執行動作之前建置其整個相依性樹狀結構,因此 Jam 規則會將目標特定變數設定作為向相應動作提供參數的方式。
-
綁定完全由
SEARCH
和LOCATE
變數的目標特定設定控制,如此處所述。 -
在用於標頭檔掃描的特殊規則中,變數值會先在規則的第一個引數(正在掃描的原始程式檔)命名的目標上尋找。
-
-
變數的「繫結值」是與由變數命名的目標相關聯的路徑。在建置動作中,前兩個引數會自動取代為其繫結值。可以使用
bind
動作修飾詞選擇性地將目標特定變數取代為其繫結值。 -
請注意,Jam 文件中使用的「綁定」一詞表示一個包含三個子階段的處理階段:綁定(是的!)、更新判斷和標頭檔掃描。「綁定」一詞的重複使用可能會導致一些混淆。尤其是 Jam 文件中的「修改綁定」章節應將標題改為「修改更新判斷」。
-
「雜質」只是一個 <字元> 形式的字串前置詞。它在 Jam 中用於根據較簡單的名稱建立唯一目標名稱。例如,檔案名稱
test.exe
可能會被不同子專案中的目標使用,或是用於「相同」抽象目標的偵錯和發行版本。每個繫結至名為「test.exe」的檔案的不同目標都有其自己唯一的雜質前置詞。Boost 建置系統也充分利用 Jam 在雜質邊界上分割字串的能力,有時會在字串開頭串連多個帶有雜質的元素。使用雜質而不是使用絕對路徑來識別目標的原因有兩個-
目標的位置並非總是僅可從使用者在 Jamfile 中放置的內容衍生而來,有時也取決於繫結程序。仍然需要某種機制來明確識別具有相同名稱的目標。
-
雜質允許我們針對每個建置目標使用統一的抽象識別碼,而與目標檔案位置無關(如設定 ALL_LOCATE_TARGET 所允許)。
-
-
當從具有 $(var:G) 的名稱中擷取雜質時,結果會包含前導和尾隨角括號。當使用
$(var:G=expr)
將雜質新增至名稱時,會先移除現有的雜質。然後,如果expr
為非空白,則會根據需要新增前導 <s 和尾隨 >s 以形成 <expr2> 的形式;然後會將 <expr2> 前置。 -
當呼叫 Jam 時,它會將所有環境變數設定匯入到對應的 Jam 變數中,然後匯入所有命令列 (-s…) 變數設定。名稱以 PATH、Path 或 path 結尾的變數會在 OS 特定路徑清單分隔符號邊界上分割為字串清單(例如,UNIX 使用「:」,Windows 使用「;」)。所有其他變數都會在空格 (" ") 邊界上分割。Boost Jam 會修改該行為,允許變數使用引號括住。
-
值為空清單或完全由空字串組成的變數具有負邏輯值。因此,例如,以下程式碼允許可由使用者輕鬆覆寫的合理非空白預設值
MESSAGE ?\= starting jam... ; if $(MESSAGE) { ECHO The message is: $(MESSAGE) ; }
如果使用者想要特定訊息,他會使用
-sMESSAGE=message text
呼叫 jam。如果他不想要任何訊息,他會使用-sMESSAGE=
呼叫 jam,而且不會列印任何內容。 -
Jam 中命令列選項的剖析可能相當不直觀,關於其他 Unix 程式如何接受選項。選項有兩種變體被接受為有效
-
-xvalue
,以及 -
-x 值
.
-
13. 實作參考
這包括 B2 引擎程式碼內部的參考文件。儘管面向 Jam 的建置系統介面也在引擎中實現,但它們記錄在一般參考章節中。此處將深入探討,包括引擎機制和資料結構的部分。它是為那些對引擎本身進行變更的人而設計的。
13.1. b2::list_cref
b2 值的容器,這是一個對 LIST
的非擁有參考。主要遵循隨機存取容器的行為。
13.1.1. b2::list_cref
概觀
struct list_cref
{
// types
struct iterator;
using size_type = int32_t;
using value_type = OBJECT *;
// construct/copy/destroy
list_cref() = default;
list_cref(const list_cref &) = default;
list_cref(list_cref && other);
explicit list_cref(LIST * l);
list_cref & operator=(const list_cref &) = default;
// iterators
iterator begin() const;
iterator end() const;
// capacity
bool empty() const B2_NOEXCEPT;
size_type length() const B2_NOEXCEPT;
size_type size() const B2_NOEXCEPT;
// element access
value_type & operator[](size_type i) const;
// list operations
bool contains(value_ref a) const;
list_ref slice(size_type i, size_type j = -1) const;
bool operator==(const list_cref & b) const;
bool operator==(const list_ref & b) const;
// data access
LIST * data() const B2_NOEXCEPT;
LIST * operator*() const B2_NOEXCEPT;
protected:
friend struct iterator;
LIST * list_obj = nullptr;
};
13.2. b2::list_ref
b2 值的容器,這是一個對 LIST
的擁有參考。主要遵循隨機存取容器的行為。並且作為擁有參考,將根據需要分配、複製、移動 LIST
物件。
13.2.1. b2::list_ref
概觀
struct list_ref : private list_cref
{
// types
using list_cref::iterator;
using list_cref::size_type;
using list_cref::value_type;
using list_cref::begin;
using list_cref::end;
using list_cref::empty;
using list_cref::length;
using list_cref::size;
using list_cref::operator[];
using list_cref::contains;
using list_cref::operator==;
using list_cref::data;
using list_cref::operator*;
// construct/copy/destroy
list_ref() = default;
list_ref(list_ref && other);
list_ref(const list_cref & other);
list_ref(const list_ref & other);
explicit list_ref(value_ref o);
explicit list_ref(LIST * l, bool own = false);
list_ref(iterator i, const iterator & e);
~list_ref();
// modifiers
LIST * release();
void reset(LIST * new_list = nullptr);
list_ref & append(const list_ref & other);
list_ref & append(list_cref other);
list_ref & operator+(const list_ref & other);
list_ref & operator+(const list_cref & other);
list_ref & push_back(OBJECT * value);
template <typename... T>
list_ref & push_back(T... value);
template <typename T>
list_ref & operator+(T value);
list_ref & pop_front();
list_ref & operator=(list_ref && other);
// list operations
inline list_ref & slice(size_type i, size_type j = -1);
inline list_cref cref() const;
};
13.2.2. b2::list_ref
建構/複製/銷毀
b2::list_ref::list_cref
inline list_ref::list_ref(list_ref && other) // (1)
inline list_ref::list_ref(const list_cref & other) // (2)
inline list_ref::list_ref(const list_ref & other) // (2)
inline list_ref::list_ref(value_ref o) // (3)
inline list_ref::list_ref(LIST * l, bool own) // (4)
inline list_ref::list_ref(iterator i, const iterator & e) // (5)
-
列表的資料從
other
移動。 -
從
other
複製列表。 -
使用初始給定的元素值建立新列表。
-
如果
own == true
取得資料l
的所有權,否則複製它。 -
使用來自
[i,e)
範圍的元素填滿新列表。 ==b2::list_ref
修飾詞 ===b2::list_ref::release
inline LIST * list_ref::release()
傳回列表資料,放棄其所有權。此列表會保持在空的有效狀態。 === b2::list_ref::reset
inline void list_ref::reset(LIST * new_list)
將列表資料替換為給定的 new_list
。目前的列表會連同列表中的元素一起釋放。 === b2::list_ref::append
inline list_ref & list_ref::append(const list_ref & other)
inline list_ref & list_ref::append(list_cref other)
inline list_ref & list_ref::operator+(const list_ref & other)
inline list_ref & list_ref::operator+(const list_cref & other)
將來自 other
列表的元素 (複製) 新增到此列表的末尾。所有函數都會傳回對列表的參考,以允許鏈接。例如:list_ref() + "one" + "two"
。 === b2::list_ref::push_back
inline list_ref & list_ref::push_back(OBJECT * value)
template <typename... T>
inline list_ref & list_ref::push_back(T... value) // (1)
template <typename... T>
inline list_ref & list_ref::operator+(T value) // (2)
-
新增從給定引數建構的值。即透過呼叫
value::make(value…)
。 -
新增可轉換為
value_type
的value
。
將單個值新增到列表的末尾。會傳回列表以允許鏈接。 === b2::list_ref::pop_front
inline list_ref & list_ref::pop_front()
13.3. b2::lists
「列表的列表」的容器,擁有 LOL
物件的實例。介面允許 LOL
的內聯組成。
13.3.1. b2::lists
概觀
struct lists
{
// types
using size_type = int32_t;
// construct/copy/destroy
lists();
lists(lists && other);
~lists();
// capacity
bool empty() const B2_NOEXCEPT;
size_type size() const B2_NOEXCEPT;
size_type length() const B2_NOEXCEPT;
size_type max_size() const B2_NOEXCEPT;
size_type capacity() const B2_NOEXCEPT;
// element access
list_cref operator[](size_type i) const;
// modifiers
void push_back(const list_cref & l);
void push_back(list_ref && l);
lists & operator|(const list_cref & l);
lists & operator|(LIST * l);
lists & operator|(list_ref && l);
lists & operator|=(list_ref && l);
lists & append(const lists & lol);
lists & operator|(const lists & lol);
void swap(LOL & other);
void clear();
// display
void print() const;
// data access
LOL * data() const B2_NOEXCEPT;
operator LOL *() const B2_NOEXCEPT;
private:
mutable LOL lol;
};
13.3.4. b2::lists
元素存取
b2::lists::operator[]
inline list_cref lists::operator[](int32_t i) const
傳回在給定 i
索引處的列表的常數參考 (即 list_cref
)。== b2::lists
修飾詞 === b2::lists::push_back
inline void lists::push_back(const list_cref & l)
inline void lists::push_back(list_ref && l)
將給定列表新增到 LOL
的末尾。 === b2::lists::operator|
inline lists & lists::operator|(const list_cref & l)
inline lists & lists::operator|(LIST * l)
inline lists & lists::operator|(list_ref && l)
inline lists & lists::operator|=(list_ref && l)
將給定列表新增到 LOL
的末尾。這會傳回此物件,使其可以將新增鏈接到單個陳述式中。 === b2::lists::swap
inline void lists::swap(LOL & other)
將來自 other
的資料與此資料交換。 === b2::lists::clear
inline void lists::clear()
解除配置任何列表項目,並將長度重設為零。 == b2::lists
元素存取 === b2::lists::print
inline void lists::print() const
將列表輸出到 cout,以冒號 (:
) 分隔,並以空格分隔元素。 == b2::lists
資料存取 === b2::lists::data
inline LOL * lists::data() const B2_NOEXCEPT
inline lists::operator LOL *() const B2_NOEXCEPT
傳回底層的 LOL
物件。
14. 歷史記錄
14.1. 版本 5.2.1
此修補程式還原了為 Dinkumware std 程式庫定義 _HAS_EXCEPTIONS=0
的變更。它具有變更 ABI 的不良影響。更好的做法是讓使用者程式碼處理關閉例外狀況,同時將警告視為錯誤,並讓使用者自行消除警告來取得來自 std 程式庫的警告/錯誤。
此修補程式也修正了在已經初始化版本時要求初始化任何 msvc 工具組版本 (using msvc ;
) 的情況。它不會因為版本已在使用中而發生錯誤,而是將已初始化的 msvc 工具組集合視為滿足一般初始化 msvc 的要求。
14.2. 版本 5.2.0
此版本中包含來自常規貢獻者 Nikita 和 Dmitry 的許多修正。有幾個新功能。首先是能夠在搜尋的程式庫中使用 dll-path
。這使得更好地支援系統/外部程式庫成為可能。第二個新功能是新增產生 compile_commands.json
以進行 IDE 和工具整合。這是一個長期以來的願望項目。
-
新增:新增支援產生
compile_commands.json
命令資料庫,以進行一些 IDE 整合。 — René Ferdinand Rivera Morell -
新增:新增用於結構化資料管理的模組 (
db
)。具有可以輸出為 JSON 資料的property-db
類別。 — René Ferdinand Rivera Morell -
新增:允許將 dll-path 新增至搜尋程式庫的使用需求。這使得調整平台上動態程式庫的搜尋路徑成為可能。 — Dmitry Arkhipov
-
修正當執行模組的遞迴匯入時,模組的錯誤遞迴載入。遞迴載入會導致堆疊溢位。 — René Ferdinand Rivera Morell
-
預設為在 FreeBSD 和 OpenBSD 上使用 Clang 建置。 — Nikita Kniazev
-
修正引擎中針對
OS=SUNOS
和OS=SOLARIS
的 Solaris/SunOS 偵測。 — Nikita Kniazev -
允許多次使用
using
來預設初始化一些工具。這些工具是asciidoctor
、fop
、gettext
、pkg-config
、python
、sass
和saxonhe
。 — Dmitry Arkhipov -
修正 ac 模組中使用會導致不正確組態檢查的相關功能。 — Dmitry Arkhipov
-
修正特定硬體上針對位址模型的 -m31、-m32、-m64 的應用,並避免在一般情況下不支援時新增它們。 — Nikita Kniazev
-
修正引擎開機載入建置時未針對 Windows 正確附加資訊清單。 — Nikita Kniazev
-
修正 clang-win 工具組的
embed-manifest-via=linker
。 — Nikita Kniazev -
修正不正確的
unknown
OS 名稱,改為使用正確的none
。這是正確建置 emscripten 工具組所需要的。 — Nikita Kniazev -
修正:對於 msvc 工具組,僅註冊已要求初始化的版本。 — Nikita Kniazev
-
修正:在每次測試後,抑制多餘的
1 file(s) copied.
訊息。 — Nikita Kniazev -
修正:改善處理安裝目錄的方式。 — Dmitry Arkhipov
-
修正:對於 msvc 工具組,識別 Visual Studio 2022 v17.10.0,它使用工具鏈版本 14.40.33807。 — Dmitry Andric
-
修正:對於 msvc 工具組,exception-handling=off 應為 Dinkumware/MSSTL 定義
_HAS_EXCEPTIONS=0
。 — Nikita Kniazev
14.3. 版本 5.1.0
這主要是錯誤修正版本,以解決影響 Boost 程式庫的問題。不過,有一個「重大」變更。在執行較大的建置時,可能會很難找到建置失敗。為了方便找出問題,建置結束時的簡要摘要輸出現在不再那麼簡短。它現在包含已略過和失敗的目標的已排序列表。這些列表的輸出會反映一般略過/失敗的項目。因此,可以在輸出的其餘部分中快速搜尋相同的字串。
-
新增:將失敗和略過目標的列表新增到建置摘要的末尾,以方便找到失敗的項目。 — René Ferdinand Rivera Morell
-
新增:將
mpi.run-flags
新增至mpi
工具組,以允許將任意旗標套用至執行 mpi 目標。例如,這允許新增--oversubscribe
旗標,以便執行任務多於可用節點的測試。 — René Ferdinand Rivera Morell -
修正當標頭掃描嘗試掃描空白檔案名稱時發生的錯誤。 — René Ferdinand Rivera Morell
-
讓 C/C++/ObjC include 指令掃描模式更加嚴格,以避免嘗試掃描空白檔案名稱。 — Andrey Semashev
-
修正 mingw 連結器命令,以始終使用正斜線取代反斜線。 — Christian Seiler
-
修正 QCC 偵錯建置旗標。QCC 工具組正在使用舊版且不再支援的偵錯符號選項。 — John McFarlane
14.4. 版本 5.0.1
-
修正較舊版本 GCC 和 Clang 工具組針對引擎的編譯錯誤。我們現在支援使用 GCC 4.7 和 Clang 3.6 或更新版本來建置引擎。 — René Ferdinand Rivera Morell
-
修正
import-search
因為不正確的原生與非原生路徑處理而無法在 Windows 上找到匯入。 — René Ferdinand Rivera Morell -
支援使用
target-os=xyz
進行 B2 的交叉編譯安裝。 — René Ferdinand Rivera Morell
14.5. 版本 5.0.0
這是 B2 的新時代。這個新的主要版本旨在將核心建置系統從 Jam 實作轉換為 C++ 實作。此初始版本僅是此轉換的開始,透過使用新的 Jam/C++ 原生繫結系統在 C++ 中實作一些最基本的功能。儘管這是一個主要版本,但目標仍然是對現有專案建置檔案保持回溯相容性。但是,其他 Jam 檔案不能保證此回溯相容性。
-
新增:支援字串 (原始 Jam 值類型)、數字 (浮點數) 和物件 (類別的實例) 的 Jam 原生變體值。 — René Ferdinand Rivera Morell
-
新功能:將
class
、errors
、modules
、regex
、set
、string
和sysinfo
等 Port 模組移植到 C++。 — René Ferdinand Rivera Morell -
新功能:將
bootstrap.jam
移植到 C++,並改用build-system.jam
作為尋找組建檔的索引檔。 — René Ferdinand Rivera Morell -
新功能:新增
require-b2
內建規則,用於驗證特定 Jam 檔所需的 B2 版本。 — René Ferdinand Rivera Morell -
新功能:新增
regex.grep
內建函式,使用 regex 比對執行平行(如果可用)檔案內容搜尋。 — René Ferdinand Rivera Morell -
新功能:使內部部分執行緒安全,以支援平行內建函式。目前包含 Jam 值、雜湊表和檔案系統。 — René Ferdinand Rivera Morell
-
新功能:新增
import-search
專案規則,以宣告額外的import
搜尋路徑,這些路徑指向搜尋的專案位置或其他目錄。 — René Ferdinand Rivera Morell -
修正
OPT_SEMAPHORE
的一致性使用,並修正JAM_SEMAPHORE
的文件。 — Thomas Brown -
修正 mingw 的封存動作失敗問題。 — René Ferdinand Rivera Morell
‼
|
不再支援或測試使用 VisualStudio 2013 (即 MSVC 12) 組建 B2。為了解決缺少的 C++11 功能而進行的工程工作變得太多。而且也佔用了其他改進的時間。 |
14.7. 版本 4.10.0
此版本包含許多錯誤修正,同時也感謝 Nikita 清理和重構了許多工具組。
-
新功能:掃描組譯器檔案以尋找 C 前處理器包含。 — Nikita Kniazev
-
修正:從基礎工具組繼承產生器覆寫。 — Nikita Kniazev
-
新功能:新增 linemarkers 功能,此功能會在前處理目標上變更行為以發出/省略行指令,如
#line
和#<linenum>
。 — Nikita Kniazev -
修正 QNX 的編譯器名稱。 — James Choi
-
修正 openssl 名稱處理。 — Dmitry Arkhipov
-
修正 clang-win 組譯器路徑推導。 — Nikita Kniazev
-
修正工具組子功能需求繼承。 — Nikita Kniazev
-
統一 clang-linux 工具組與 gcc 工具組的編譯和連結。 — Nikita Kniazev
-
修正 msvc 工具組的相同目錄 pch 標頭產生。 — Nikita Kniazev
-
實作
--durations
,此功能會依執行時間報告頂層目標。 — Nikita Kniazev -
變更 clang-darwin 以從 clang-linux 繼承並統一編譯命令。 — Nikita Kniazev
-
修正 clang-linux 以不覆寫 RPATH_OPTION。 — Nikita Kniazev
-
修正不小心執行不應該執行的組態檢查(如 Alexander Grund 所回報)。方法是將
<build>no
條件評估變更為短路。 — Nikita Kniazev -
修正相同的工具組覆寫(inherit-overrides)。 — Nikita Kniazev
-
新功能:新增使用 C 處理器處理組譯來源檔案的功能。 — Nikita Kniazev
-
許多內部測試的改進和清理。 — Nikita Kniazev
-
統一 gcc 和 clang-linux 的 soname 選項處理,並在 Windows 上停用它。 — Nikita Kniazev
-
統一 gcc/mingw 連結共享和匯入程式庫。 — Nikita Kniazev
-
修正 pdb 產生順序和命名問題。 — Nikita Kniazev
-
統一 clang-darwin 與 gcc 的連結。 — Nikita Kniazev
-
修正 mingw/msys/cygwin、winthreads/pthread 不一致的問題,以修正編譯器旗標。 — Nikita Kniazev
-
透過從 clang-linux 繼承來統一 clang-vxworks。 — Nikita Kniazev
-
不要儲存空的組態快取和記錄。 — Nikita Kniazev
-
修正產生器自訂規則名稱繼承。這會影響 cygwin/mingw 連結。 — Nikita Kniazev
-
修正 testing.execute=off 以正確執行失敗行為。 — Nikita Kniazev
-
修正 use-project 與原生路徑。 — René Ferdinand Rivera Morell
-
修正 msvc 自動組態版本優先順序。現在,無論是從登錄檔找到還是其他方式找到,msvc 工具組都會以正確的最新到最舊順序進行組態。 — René Ferdinand Rivera Morell
-
新功能:新增對自動搜尋外部專案以取得全域目標和專案參考的支援。 — René Ferdinand Rivera Morell
14.9. 版本 4.9.5
-
改善替代比對錯誤訊息以包含更多內容。 — René Ferdinand Rivera Morell
-
修正在從另一個
use-project
包含的專案內執行use-project
時的錯誤。 — René Ferdinand Rivera Morell -
支援 ARM64 上的原生 msvc 編譯器。 — Stephen Just
-
PCH 修正:修正 msvc pch 包含目錄;修正 msvc pch 標頭名稱;修正建置 pch 時遺失的 gcc
-ftemplate-depth
。 — Nikita Kniazev -
新功能:
clang-win
在PATH
中找不到時,在預設安裝位置搜尋編譯器執行檔。 — Nikita Kniazev -
修正
clang-win
以支援版本化的 winsdk bin 位置。 — Nikita Kniazev
14.10. 版本 4.9.4
-
修正某些平台/編譯器上因 varargs 結束標記的無效垃圾讀取是
int
而非nullptr
而造成的當機。 -
不要在 Windows 上強制使用 Windows 路徑分隔符號給 GCC。因為它會混淆 Cygwin GCC 的相對包含路徑處理。 — René Ferdinand Rivera Morell
-
將
common-requirements
新增至專案宣告,以便簡化宣告requirements
和usage-requirements
的相同內容。 — René Ferdinand Rivera Morell -
新增將目標傳遞至專案
explicit
規則的功能,以減少在有許多目標時重複explicit
目標。 — René Ferdinand Rivera Morell -
使 coverage 功能成為非偶發且與連結不相容。 — Thomas Brown
-
使用基於 PATH 的查詢來尋找
sh
。對於 Gentoo Prefix 之類的情況,我們希望使用前置詞中的 Bourne shell,而不是主要系統中可能過時的版本。 — David Seifert
14.13. 版本 4.9.1
-
修正 b2 開發樹中起始僅限開發路徑至引導載入檔的錯誤計算。 — René Ferdinand Rivera Morell
-
修正在 boost-build 規則中指定路徑載入引導載入檔的最終備用方案中的錯誤路徑計算。 — René Ferdinand Rivera Morell
14.14. 版本 4.9.0
此版本主要進行內部清理和重組。最重要的是:修正所有記憶體洩漏、使用 boost-build
規則自動啟動組建系統、Jam Python 介面以及未維護的 Python 組建系統 Port。
-
為
optimization
功能新增minimal
和debug
選項。 — René Ferdinand Rivera Morell -
新增 Rocket Lake、Alder Lake、Sapphire Rapids 和 Zen 3 指令集。 — Andrey Semashev
-
移除所有結束時的記憶體洩漏,並修正所有 ASAN 錯誤。 — René Ferdinand Rivera Morell
-
移除使用
boost-build.jam
作為初始化組態檔。 — René Ferdinand Rivera Morell -
移除不完整的組建系統 Port 和 Jam 引擎 Python 支援擴充功能。 — René Ferdinand Rivera Morell
-
修正在 macOS 上使用
darwin
和clang
工具組時無法執行 arm+x86 組合建置的問題。 — René Ferdinand Rivera Morell -
修正在 macOS 上使用
clang
工具組時無法執行跨編譯的問題。 — René Ferdinand Rivera Morell -
修正使用
gcc
和clang
工具組將大量長名稱物件檔案收集到靜態封存時發生的錯誤。 — René Ferdinand Rivera Morell -
修正在
build.sh
引擎組建腳本中偵測 QCC 的問題。 — René Ferdinand Rivera Morell -
修正 intel-win 工具組遺失的組譯旗標。 — René Ferdinand Rivera Morell
-
修正 msvc 工具組連結動作可能超出命令列長度限制的錯誤。 — René Ferdinand Rivera Morell
-
新功能:將 "t" 模式新增至
FILE_OPEN
內建規則,在評估時會提供檔案內容。 — René Ferdinand Rivera Morell
⚠
|
此版本移除使用 boost-build.jam 和 boost-build 規則進行初始化。仍然會搜尋並載入 boost-build.jam 以避免中斷現有操作。但它被視為已棄用,並將在未來版本中移除。 |
14.16. 版本 4.8.1
-
修正由於遺失
EXIT_SUCCESS
和EXIT_FAILURE
巨集而在 9.0 之前的舊版 macOS/XCode 上組建引擎的問題。 — René Ferdinand Rivera Morell
14.17. 版本 4.8.0
-
新功能:新增對 LoongArch 的支援。 — Zhang Na
-
將引擎組建變更為在有靜態 Intel 程式庫時使用它們,而不是使用 C++ 執行階段靜態程式庫,以修正靜態 C++ 執行階段不可用的系統。 — Alain Miniussi
-
重新排序 msvc
cflags
和cxxflags
,並新增compileflags
,以修正使用者無法覆寫旗標的問題。 — Peter Dimov -
不要在
clang-linux
上引用RPATH
,以修正使用雙引號使其可以使用$ORIGIN
的問題。 — Dimitry Andric -
修正 kFreeBSD 上的
b2
執行檔偵測。 — Laurent Bigonville -
將
.ipp
副檔名新增至標頭掃描和有效的 C++ 檔案。 — Jim King -
修正來源目標使用需求中存在
build=no
時遺失的安裝目標。 — Dmitry Arkhipov -
將一些未來版本的 C++ 新增至
cxxstd
功能。 — René Ferdinand Rivera Morell -
修正引擎中的許多記憶體洩漏。 — René Ferdinand Rivera Morell
-
將
abort
/exit
呼叫變更為清理例外處理,以允許引擎中的記憶體清理。 — René Ferdinand Rivera Morell
14.18. 版本 4.7.2
-
修正如果 icpx 不在 PATH 中但 icpc 在 PATH 中,則組態 intel-linux 工具組時的錯誤。 — Mark E. Hamilton
-
現在 VS 2019 及更高版本支援,將
cxxstd=20
新增至 msvc 工具組。 — Peter Dimov
14.20. 版本 4.7.0
此版本進行了許多修正和內部清理。但也新增了 VS 2022 預覽工具組的自動偵測和引導載入。
-
新功能:新增 vc143 (又名 VS2022,又名 cl.exe 17.x) 工具組支援。包含建置引擎和自動偵測預先發布工具組。 — Sergei Krivonos
-
允許別名目標繼續,即使使用需求中存在
<build>no
。這允許組合可能包含選用目標(如測試)的別名目標。 — Dmitry Arkhipov -
修正 gcc 工具組中
JAMSHELL
的使用。 — René Ferdinand Rivera Morell -
修正編譯 b2 引擎,使其在跨架構模擬環境中執行時可以運作。也就是說,當在 QEMU 64 位元主機中執行 arm 二進位檔時。 — René Ferdinand Rivera Morell
-
在 64 位元主機上預設使用 64 位元 MSVC。 — Matt Chambers
-
移除僅限資源 DLL 的
/NOENTRY
選項,以允許正確連結。 — gnaggnoyil -
修正於 OpenBSD 上編譯引擎時
unix
的重新定義錯誤。 — Brad Smith -
修正在 iOS 和 AppleTV 上使用 clang 建置時出現額外的無法辨識編譯器選項的問題。 — Konstantin Ivlev
-
將遺失的 Boost.JSON 新增至
boost
支援模組。 — Dmitry Arkhipov -
在 clang-win 工具組中新增 arm/arm64 目標支援。 — Volo Zyko
-
避免 qt5 的執行緒模型相關警告。 — psandana
-
統一 Clang 和 GCC 的 PCH 建立。— Nikita Kniazev
-
將 Objective-C 支援移至 GCC 工具鏈。— Nikita Kniazev
-
支援 Xilinx ZYNQ 的指令集功能值。— Thomas Brown
-
MIPS:新增通用 MIPS 架構。— YunQiang Su
-
修正 MSVC 編譯器上的預處理。— Nikita Kniazev
14.21. 版本 4.6.1
-
修正使用 cygwin64 建置 b2 引擎的問題。— René Ferdinand Rivera Morell
-
修正從編譯器執行檔偵測 clang 工具鏈版本的問題。— Nikita Kniazev
14.22. 版本 4.6.0
此版本總結了一些新功能,讓使用某些工具鏈變得更容易(感謝 Nikita)。現在也可以在命令列上指定空的標誌功能,例如 cxxfalgs=
,並且忽略它們。這有助於縮短 CI 腳本,因為它們不需要特別處理這些情況。與往常一樣,還有許多錯誤修正和調整。感謝所有為此版本做出貢獻的人。
-
新功能: 允許透過在命令列上使用
toolset=clang-xx
將 clang 工具鏈自動配置為特定版本。— Nikita Kniazev -
新功能: 在 gcc 和 msvc 工具鏈上自動且按需包含 pch 標頭,以鏡像 clang 功能。— Nikita Kniazev
-
新功能: 當命令列上指定的值為空時,標記為「free」和「optional」的功能現在將被忽略。因此,可以在命令列上指定
cxxflags=
而不會發生錯誤。— René Ferdinand Rivera Morell -
保留
bootstrap.sh
的調用引數以轉發到build.sh
腳本。— tkoecker -
移除
buils.sh
中local
的使用,使其與某些功能不完全的 shell 相容。— Tanzinul Islam -
解決 busybox shell 中
build.sh
的 shell 陣列參照錯誤。— tkoecker -
檢查是否需要
-pthread
才能在某些平台上使用 gcc 建置引擎。— tkoecker -
預設在 MacOS 上使用 clang。— Stéphan Kochen
-
新增
/python//numpy
目標,用作傳達版本特定屬性的依賴項。— Peter Dimov -
在使用自訂
cxx
工具鏈建置引擎時,從環境變數CXX
和CXXFLAGS
新增 cxx 和 cxxflags 的預設值。— Samuel Debionne 和 René Ferdinand Rivera Morell -
修正當只有編譯器執行檔位於
PATH
中時,偵測intel-linux
工具鏈安裝的問題。— René Ferdinand Rivera Morell -
修正不具有取得執行檔路徑的原生方法的平台(如 OpenBSD)的
b2
執行檔路徑判斷。— René Ferdinand Rivera Morell -
修正
property.find
錯誤訊息。— Thomas Brown
14.23. 版本 4.5.0
一些小修正,以改善一些舊問題。
-
重新啟用產生器將
property-set
作為第一項傳回的功能。— Andrew McCann -
修正範例以在成功時傳回 0。— Mateusz Łoskot
-
處理
config_toolset.bat
中 CXX 路徑中的空格。 -
修正 Conan b2 產生器連結和 pkg-config 文件建置錯誤。— René Ferdinand Rivera Morell
14.24. 版本 4.4.2
此版本是 B2 在 Build Frameworks Group 的新家的第一個版本。
-
將文件和原始碼中對 boost.org 的參照變更為指向對等的 bfgroup 資源。— René Ferdinand Rivera Morell
-
B2 網站和文件的新主題。— René Ferdinand Rivera Morell
14.25. 版本 4.4.1
小修補程式,以修正 macOS 預設引擎編譯器遺失的修正。
-
修正在 macOS/Xcode 上引擎建置預設為 gcc 而不是 clang 的問題。— René Ferdinand Rivera Morell
14.26. 版本 4.4.0
除了各種修正之外,此版本還為某些工具鏈引入了「動態」回應檔支援。這表示在大多數情況下(如果工具鏈支援),不會產生回應檔。而是展開命令以直接包含選項。
-
新功能: 新增
response-file
功能來控制工具鏈動作中回應檔的使用類型。— René Ferdinand Rivera Morell -
新功能: 為
@()
展開新增:O=value
變數修飾詞。— René Ferdinand Rivera Morell -
新功能: 為變數參照完全展開後的前綴和後綴值新增
:⇐value
和:>=value
變數修飾詞。— René Ferdinand Rivera Morell -
新功能: 在 clang-win 和 clang-darwin 上實作 PCH。— Nikita Kniazev
-
新功能: 新增對 Intel oneAPI 版本到 intel-linux 工具鏈的支援。— René Ferdinand Rivera Morell
-
新功能: 新增對 Intel oneAPI 版本到 intel-windows 工具鏈的支援。— Edward Diener
-
移除一次一個連結限制。曾經這是一個效能調整,因為硬體和軟體無法一次執行多個連結。常見的設定配備更好。— René Ferdinand Rivera Morell
-
修正在 AIX 上使用 GCC 建置引擎的問題。— René Ferdinand Rivera Morell
-
支援將引擎建置為 32 位元或 64 位元定址模型。— René Ferdinand Rivera Morell
-
在 GNU/Hurd 上建置 b2 引擎的基本支援。— Pino Toscano
-
將「borland」工具鏈更新為 bcc32c 以建置 B2。— Tanzinul Islam
-
確保 Embarcadero 工具鏈名稱僅為「embtc」。— Tanzinul Islam
-
調整 Emscripten 2.0 對於封存檔的預設行為變更。— Basil Fierz
-
修正啟動程式的路徑以實現向後相容性。— René Ferdinand Rivera Morell
-
新增遺失的 BOOST_ROOT 到啟動程式搜尋。— René Ferdinand Rivera Morell
-
修正 FreeBSD 上引擎編譯的問題。— René Ferdinand Rivera Morell
-
將 MSVC 預設為原生平台,並移除不明確的隱式定址模型 ARM/ARM64 值。— Nikita Kniazev
-
修正 b2 引擎建置的 MIPS32 偵測。— Ivan Melnikov
-
啟用在 Windows 上使用 clang 建置 b2 引擎。— Gei0r
-
修正在 Intel Linux icpc 上建置 b2 引擎的問題。— Alain Miniussi
-
重構
build.sh
以修正許多錯誤,並避免使用常見的環境變數。— René Ferdinand Rivera Morell -
移除配置檢查的相關功能限制。— René Ferdinand Rivera Morell
-
重新格式化配置檢查輸出,以合理的簡短形式告知檢查的變體。— René Ferdinand Rivera Morell
-
支援在 Windows Bash 上使用 Mingw 建置引擎。— René Ferdinand Rivera Morell
14.27. 版本 4.3.0
此版本中有許多個別的修正。非常感謝大家做出貢獻。特別感謝 Nikita 對 msvc 的許多改進以及在所有編譯器中對支援漏洞的填補。
Dmitry、Edward 和 Nkita 提供了一些值得注意的新功能
-
新功能: 新增
force-include
功能以在所有來源之前包含標頭。— Nikita Kniazev -
新功能: 基於 clang-5 的 Embarcadero C++ 編譯器的部分支援。— Edward Diener
-
新功能: 實作使用功能的可配置安裝前綴。— Dmitry Arkhipov
-
新功能: 新增
translate-path
功能。translate-path 功能允許在每個目標的基礎上使用提供的規則進行自訂路徑處理。這可以用於支援自訂路徑語法。— René Ferdinand Rivera Morell -
新功能: 新增可攜式 B2 系統安裝選項。這允許 b2 執行檔和建置系統檔案並排存在。因此,可以將其 (重新) 定位在磁碟上的任何位置。很快就會用於支援 Windows 和其他安裝程式。這消除了啟動程式對
boost-build.jam
檔案的需求。讓使用者更容易開始使用。— René Ferdinand Rivera Morell -
解除從 VS Preview 命令提示字元建置的問題。— Marcel Raad
-
修正 macOS darwin 工具鏈上的編譯器版本檢查。— Bo Anderson
-
移除 GCC 上的 pch 目標命名限制。— Nikita Kniazev
-
選取適當的 QNX 目標平台。— Alexander Karzhenkov
-
對 Windows 上的 b2 引擎建置進行各種空間和效能改進。— Nikita Kniazev
-
為每個編譯器填寫額外且吹毛求疵的警告選項。— Nikita Kniazev
-
包含引擎 IO 失敗的 OS 錯誤原因。— Nikita Kniazev
-
使用 /Zc:inline 和 /Zc:throwingNew 標誌以獲得更好的語言一致性。— Nikita Kniazev
-
為 C++20 新增 cxxstd 值 20。— Andrey Semashev
-
在 MSVC 上平行編譯 B2 引擎。— Nikita Kniazev
-
使用新的 x86 目標更新指令集功能。— Andrey Semashev
-
將 /nologo 傳遞給 Windows 編譯器上的 rc。— Nikita Kniazev
-
修正在條件屬性中的否定。— Nikita Kniazev
-
移除提早退出的剩餘資訊清單產生。— Nikita Kniazev
-
修正時間戳記差異計算。— Nikita Kniazev
-
將遺失的組譯器選項新增至 clang-win.jam,以啟用 Context 的建置。— Peter Dimov
-
使用
:BS
範例更新稀疏的:chars
文件。— Nikita Kniazev -
修正靜態連結 linux 上的 boost-python 的問題。— Joris Carrier
-
正在進行的引擎建置警告清除。— René Ferdinand Rivera Morell
-
允許使用回應檔的工具鏈進行自我測試。— René Ferdinand Rivera Morell
-
將
Jambase
移植到原生 C++。因此,移除了原始 Jam 啟動程式中最古老的部分之一。— René Ferdinand Rivera Morell
14.28. 版本 4.2.0
此版本主要是引擎的小修正和清理。特別是,啟動程式/建置流程現在清楚地傳達 C++11 的要求。
-
新增
saxonhe_dir
動作。— Richard Hodges -
新增在 Windows MSVC 上針對歷史 Boost 版本的 CI 測試。— René Ferdinand Rivera Morell
-
在建置引擎時檢查 C++11 的支援。包括有關該事實的資訊性錯誤訊息。— René Ferdinand Rivera Morell
-
使用最新的
bison
版本更新 Jam 文法剖析器。— René Ferdinand Rivera Morell -
允許根
b2 b2
引擎建置工作,即使bison
文法產生器不可用。— René Ferdinand Rivera Morell -
在至少 Windows、macOS 和 Linux 上無警告的引擎建置。— René Ferdinand Rivera Morell
-
清理 Windows 引擎建置以一致地使用 ANSI Win32 API。— Mateusz Loskot
-
修正 b2 引擎在偵測到 Jam 語言錯誤時不會提早結束並顯示錯誤的問題。— Mateusz Loskot
-
列印本機模組的說明,即目前目錄。— Thomas Brown
14.29. 版本 4.1.0
此版本中有許多小型錯誤修正。但也有些新功能。現在有一個 lto
功能來指定 LTO 的使用方式以及種類。現有的 stdlib
功能現在具有真實值和某些工具鏈的對應選項。但最重要的是,所有功能都有新的文件。
感謝所有為此版本貢獻這些變更的使用者
-
對 intel-vin 19.0 支援 VS2019。— Edward Diener
-
修正在 Cygwin 上建置
b2
時,關於-std=gnu11
的編譯器警告。— Andrey Semashev -
新增為個別標頭建立多個 PCH 的範例。— René Ferdinand Rivera Morell
-
為 GCC 工具鏈新增 QNX 執行緒標誌。— Aurelien Chartier
-
修正在建置 b2 引擎時,IBM 和 Sun 編譯器的版本選項 — Juan Alday
-
在
b2
引擎中將strings.h
重新命名為jam_strings.h
,以避免與 POSIXstrings.h
標頭衝突。— Andrey Semashev -
為 IBM 編譯器的新增
cxxstd
功能選項。— Edward Diener -
對 intel-win 工具鏈進行許多修正。— Edwad Diener
-
為基於 gcc 的工具鏈新增 z15 指令集。— Neale Ferguson
-
改善從 Cygwin shell 使用 MSVC 的體驗。— Michael Haubenwallner
-
新增 LTO 功能以及對 gcc 和 clang 工具鏈的對應支援。— Dmitry Arkhipov
-
修正當來源沒有類型時的錯誤。— Peter Dimov
-
新增功能的說明文件。— Dmitry Arkhipov
-
針對 clang、gcc 和 sun 工具鏈增強
stdlib
功能以及對應的說明文件。— Dmitry Arkhipov -
安裝規則現在明確僅建立它建立的直接目標。— Dmitry Arkhipov
-
新增 msvc 工具鏈的 armasm (32 位元和 64 位元) 支援。— Michał Janiszewski
-
修正自訂未版本化的 gcc 工具鏈規格的錯誤。— Peter Dimov
-
允許在 gcc 工具鏈規格中覆寫 arflags。— hyc
-
修正已找到的 libs 沒有傳遞到 clang-win 連結命令列的問題。— Peter Dimov
-
更新 intel-win 工具鏈以支援 Intel C++ 19.1。— Edward Diener
-
偵測 b2 引擎中作業系統的 MIPS32 和 MIPS64 差異。 — YunQiang Su
14.30. 版本 4.0.1
此修補程式版本修正了一個次要問題,該問題發生在嘗試配置使用非版本標籤覆蓋工具集版本的工具集時。目前已知只有在以下情況下才會發生此問題:(a)將工具集版本配置為類似“tot”的內容 (b)在 Boost 1.72.0 中,當它建立 cmake 安裝成品時。此問題的修復由 Peter Dimov 提供。
14.31. 版本 4.0.0
經過多年的開發,建置系統的格局以及編譯器的格局都發生了巨大變化。此版本標誌著 B2 開始轉型為 C++ 實作。最初,這意味著引擎將作為 C++ 原始碼進行編譯,但該原始碼仍然是基礎 C 實作。隨著時間的推移,它將轉換為引擎和建置系統中的 C++ 程式碼庫。此開始版本的一些變更:
-
需要 C++ 11 來建置引擎。
-
簡化了建置腳本,使其更易於維護。
-
使用 C++ 優化進行建置可立即提升效能。
此版本中的其他變更
-
新增支援使用預建的 OpenSSL。 — Damian Jarek
-
定義 riscv 架構功能。 — Andreas Schwab
-
新增 ARM64 作為 MSVC 的有效架構。 — Marc Sweetgall
-
為 gcc 和 clang 設定來自 coverage 功能的覆蓋率標誌。 — Damian Jarek
-
在 gcc/clang 中新增 s390x CPU 和支援。 — Neale Ferguson
-
支援匯入 pkg-config 套件。 — Dmitry Arkhipov
-
支援記憶體洩漏清除工具。 — Damian Jarek
-
修復 clang-win 中遺失的
/manifest
選項,以修正名稱中帶有 "update" 的 exe 檔的管理員提升問題。 — Peter Dimov -
將
freertos
新增至os
功能。 — Thomas Brown -
預設並行任務(
-jX
)為可用的 CPU 執行緒數量。 — René Ferdinand Rivera Morell -
更簡單的覆蓋率功能。 — Hans Dembinski
-
更好的清除工具堆疊。 — James E. King III
⚠
|
此版本中,並行任務的預設數量已從「1」變更為核心數量。在某些情況下,此預設值可能大於已配置的 CPU 資源,例如在某些虛擬化容器安裝中。 |
附錄 A:授權
除了 B2 是以 Boost 軟體授權 - 版本 1.0 授權外,B2 還使用了其他以不同方式授權的程式庫,如下所示。
A.1. MIT 授權
MIT License
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
- JSON for Modern C++
-
版權 (c) 2013-2022 Niels Lohmann