Boost C++ Libraries Home Libraries People FAQ More

PrevUpHomeNext

Frequently Asked Questions 常見問題

How do I get the current value of feature in Jamfile? 我如何獲得 Jamfile 中的特性的當前值?
I'm getting "Duplicate name of actual target" error. What does it mean? 我得到了"實際目標重名"的錯誤。它是什麼意思?
Accessing environment variables 訪問環境變量
How to control properties order? 如何控制屬性的順序?
How to control the library order on Unix? 如何控制 Unix 上的庫順序?
Can I get output of external program as a variable in a Jamfile? 我可以獲取引部程序的輸出並用作 Jamfile 中的一個變量嗎?
How to get the project root (a.k.a. Jamroot.jam) location? 如何獲得工程的根(又稱 Jamroot.jam)的位置?
How to change compilation flags for one file? 如何修改一個文件的編譯選項?
Why are the dll-path and hardcode-dll-paths properties useful? 為什麼 dll-pathhardcode-dll-paths 是有用的?
Targets in site-config.jam 在 site-config.jam 中的目標
Header-only libraries 只有頭文件的庫

How do I get the current value of feature in Jamfile? 我如何獲得 Jamfile 中的特性的當前值?

This is not possible, since Jamfile does not have "current" value of any feature, be it toolset, build variant or anything else. For a single invocation of bjam, any given main target can be built with several property sets. For example, user can request two build variants on the command line. Or one library is built as shared when used from one application, and as static when used from another. Obviously, Jamfile is read only once, so generally, there's no single value of a feature you can access in Jamfile.
這是不可能的,因為 Jamfile 的任何特性都不存在 "當前" 值,無論是工具集、構建變體或其它東西。對於 bjam 的一次調用,任何給定的主目標可以按多個屬性集來構建。例如,用戶可以在命令行請求兩個構建變體。或者,一個庫可以在用於某個應用時構建為共享的,而在用 於另一個應用時又構建為靜態的。顯然,Jamfile 只被讀入一次,因此通常來說,對於你在 Jamfile 中可以訪問的特性,沒有單一的值。

A feature has a specific value only when building a target, and there are two ways how you can use that value:
只有在構建一個目標時,特性才具有一個特定的值,你有兩種方法可以使用這個值:

I'm getting "Duplicate name of actual target" error. What does it mean? 我得到了"實際目標重名"的錯誤。它是什麼意思?

The most likely case is that you're trying to compile the same file twice, with almost the same, but differing properties. For example:
最有可能的情況是,你試圖以幾乎相同的屬性兩次編譯同一個文件。例如:

exe a : a.cpp : <include>/usr/local/include ;
exe b : a.cpp ;

The above snippet requires two different compilations of 'a.cpp', which differ only in 'include' property. Since the 'include' property is free, Boost.Build can't generate two objects files into different directories. On the other hand, it's dangerous to compile the file only once -- maybe you really want to compile with different includes.
以上片斷要求 'a.cpp' 的兩次不同編譯,區別只在於 'include' 屬性。因為 'include' 屬性是自由的,所以 Boost.Build 不能在不同目錄下生成兩個目標文件。另一方面,只編譯一次又是危險的 -- 也許你真的是想以不同的包含文件來編譯。

To solve this issue, you need to decide if file should be compiled once or twice.
要解決這個問題,你需要決定該文件是要編譯一次還是兩次。

  1. Two compile file only once, make sure that properties are the same:
    兩個編譯文件只編譯一次,則要確保兩個屬性完全一樣:

    exe a : a.cpp : <include>/usr/local/include ;
    exe b : a.cpp : <include>/usr/local/include ;
  2. If changing the properties is not desirable, for example if 'a' and 'b' target have other sources which need specific properties, separate 'a.cpp' into it's own target:
    如果你不是想修改屬性,例如,如果 'a' 和 'b' 目標具有不同的源,需要特定的屬性,那麼可以將 'a.cpp' 獨立到一個目標中:

    obj a_obj : a.cpp : <include>/usr/local/include ;
    exe a : a_obj ;
  3. To compile file twice, you can make the object file local to the main target:
    要編譯文件兩次,那麼你可以讓目標文件局部於主目標:

     exe a : [ obj a_obj : a.cpp ] : <include>/usr/local/include ;
    exe b : [ obj a_obj : a.cpp ] ;

A good question is why Boost.Build can't use some of the above approaches automatically. The problem is that such magic would require additional implementation complexities and would only help in half of the cases, while in other half we'd be silently doing the wrong thing. It's simpler and safe to ask user to clarify his intention in such cases.
一個好問題是,為什麼 Boost.Build 不能自動使用以上某個方法。問題是,這樣的方式需要更多的實現複雜性,而只對一半的情況有幫助,而在另一半情況下,我們還是會無聲無息地做錯事。在這種情況下,要求用戶澄清意圖更為簡單和安全。

Accessing environment variables 訪問環境變量

Many users would like to use environment variables in Jamfiles, for example, to control location of external libraries. In many cases you better declare those external libraries in the site-config.jam file, as documented in the recipes section. However, if the users already have the environment variables set up, it's not convenient to ask them to set up site-config.jam files as well, and using environment variables might be reasonable.
許多用戶喜歡在 Jamfiles 中使用環境變量,例如,控制外部庫的位置。在多數情況下,你最好在 site-config.jam 文件中聲明這些外部庫,正如 recipes 一節 中所說的。不過,如果用戶已經設置了環境變量,再讓他們設置 site-config.jam 文件就不夠方便了,這時使用環境變量可能是合理的。

In Boost.Build V2, each Jamfile is a separate namespace, and the variables defined in environment is imported into the global namespace. Therefore, to access environment variable from Jamfile, you'd need the following code:
在 Boost.Build V2 中,每個 Jamfile 都有一個獨立的名字空間,而環境變量則被導入到全局名字空間。因此,要從 Jamfile 訪問環境變量,你需要以下代碼:

import os ;
local SOME_LIBRARY_PATH = [ os.environ SOME_LIBRARY_PATH ] ;
exe a : a.cpp : <include>$(SOME_LIBRARY_PATH) ;

How to control properties order? 如何控制屬性的順序?

For internal reasons, Boost.Build sorts all the properties alphabetically. This means that if you write:
由於內部原因,Boost.Build 會按字母序對所有屬性進行排序。這意味著如果你寫了:

exe a : a.cpp : <include>b <include>a ;

then the command line with first mention the "a" include directory, and then "b", even though they are specified in the opposite order. In most cases, the user doesn't care. But sometimes the order of includes, or other properties, is important. For example, if one uses both the C++ Boost library and the "boost-sandbox" (libraries in development), then include path for boost-sandbox must come first, because some headers may override ones in C++ Boost. For such cases, a special syntax is provided:
那 麼在命令行中首先會出現 "a" 包含目錄,然後才是 "b",雖然它們是按相反的順序指定的。在多數情況下,用戶並不關心這一點。但是有時候包含目錄的順序,或者其它屬性的順序是很重要的。例如,如果你同時 使用了 C++ Boost 庫和 "boost-sandbox" (正在開發的庫),那麼 boost-sandbox 的包含路徑必須先出現,因為有些頭文件可能要覆蓋 C++ Boost 的頭文件。為此,提供了一個特殊的語法:

exe a : a.cpp : <include>a&&b ; 

The && symbols separate values of an property, and specify that the order of the values should be preserved. You are advised to use this feature only when the order of properties really matters, and not as a convenient shortcut. Using it everywhere might negatively affect performance.
符號 && 用於分隔一個屬性的值,並指定這些值的順序要被保留。建議你只在屬性的順序確實重要時才使用此特性,而不是把它作為一個方便的縮寫來用。到外使用它可能會產生負面的性能影響。

How to control the library order on Unix? 如何控制 Unix 上的庫順序?

On the Unix-like operating systems, the order in which static libraries are specified when invoking the linker is important, because by default, the linker uses one pass though the libraries list. Passing the libraries in the incorrect order will lead to a link error. Further, this behaviour is often used to make one library override symbols from another. So, sometimes it's necessary to force specific order of libraries.
在類Unix的操作系統上,在調用鏈接器時所指定的靜態庫的順序是很重要的,因為缺省情況下,鏈接器只會掃一遍庫列表。以錯誤的順序傳遞庫文件會導致鏈接錯誤。而且,這一行為通常被用於以一個庫覆蓋另一個庫的符號。所以,有時候必須強迫指定庫的順序。

Boost.Build tries to automatically compute the right order. The primary rule is that if library a "uses" library b, then library a will appear on the command line before library b. Library a is considered to use b is b is present either in the sources of a or in its requirements. To explicitly specify the use relationship one can use the <use> feature. For example, both of the following lines will cause a to appear before b on the command line:
Boost.Build 會嘗試自動計算正確的順序。主要的規則是,如果 a 庫"使用"了 b 庫,則 a 庫在命令行中應出現在 b 庫之前。a 庫使用 b 庫是指,b 出現在 a 的源中,或者出現在它的要求中。要明確指定這種使用關係,你可以用 <use> 特性。例如,下面兩行都會導致在命令行中 a 在 b 之前出現:

lib a : a.cpp b ;
lib a : a.cpp : <use>b ;

The same approach works for searched libraries, too:
相同的方法也適用於庫的查找:

lib z ;
lib png : : <use>z ;
exe viewer : viewer png z ;

Can I get output of external program as a variable in a Jamfile? 我可以獲取引部程序的輸出並用作 Jamfile 中的一個變量嗎?

The SHELL builtin can be used for the purpose:
內建的 SHELL 可用於此目的:

local gtk_includes = [ SHELL "gtk-config --cflags" ] ;

How to get the project root (a.k.a. Jamroot.jam) location? 如何獲得工程的根(又稱 Jamroot.jam)的位置?

You might want to use your project's root location in your Jamfiles. To access it just declare a path constant in your Jamroot.jam file using:
你可能想在你的 Jamfiles 中使用你的工程的根的位置。要獲得它,只需在你的 Jamroot.jam 中如下聲明一個路徑常量:

path-constant TOP : . ;

After that, the TOP variable can be used in every Jamfile.
然後,變量 TOP 就可以在各個 Jamfile 中使用了。

How to change compilation flags for one file? 如何修改一個文件的編譯選項?

If one file must be compiled with special options, you need to explicitly declare an obj target for that file and then use that target in your exe or lib target:
如果一個文件必須以特定的選項來編譯,你就需要為該文件明確聲明一個 obj 目標,然後在你的 exelib 目標中使用該目標:

exe a : a.cpp b ;
obj b : b.cpp : <optimization>off ;

Of course you can use other properties, for example to specify specific compiler options:
當然你可以使用其它屬性,如指定特定的編譯選項:

exe a : a.cpp b ;
obj b : b.cpp : <cflags>-g ;

You can also use conditional properties for finer control:
你還可以用 條件屬性 來更好地控制:

exe a : a.cpp b ;
obj b : b.cpp : <variant>release:<optimization>off ;

Why are the dll-path and hardcode-dll-paths properties useful? 為什麼 dll-pathhardcode-dll-paths 是有用的?

(This entry is specific to Unix system.)Before answering the questions, let's recall a few points about shared libraries. Shared libraries can be used by several applications, or other libraries, without physically including the library in the application. This can greatly decrease the total size of applications. It's also possible to upgrade a shared library when the application is already installed. Finally, shared linking can be faster.
(這 一條是專用於 Unix 系統的)。在回答這個問題之前,我們來回顧一下有關共享庫的幾個要點。共享庫可以被多個應用程序或其它庫所使用,而無需在應用程序中物理包含該庫。這可以 顯著減小應用程序的大小總和。還可以在應用程序已經安裝後對某個共享庫進行升級。最後,共享庫也會快一些。

However, the shared library must be found when the application is started. The dynamic linker will search in a system-defined list of paths, load the library and resolve the symbols. Which means that you should either change the system-defined list, given by the LD_LIBRARY_PATH environment variable, or install the libraries to a system location. This can be inconvenient when developing, since the libraries are not yet ready to be installed, and cluttering system paths is undesirable. Luckily, on Unix there's another way.
不過,共享庫必須在應用程序啟動時被查找到。動態鏈接器會在一個系統定義的路徑列表中查找,裝入庫並解釋符號。這意味著你要麼就修改由 LD_LIBRARY_PATH 環境變量給出的系統定義的列表,要麼就將庫安裝到某個系統庫的位置。這在開發的時候會不太方便,因為這些庫還沒有準備好被安裝,而且把系統路徑搞亂也是不受歡迎的。幸好,在 Unix 上還有其它的辦法。

An executable can include a list of additional library paths, which will be searched before system paths. This is excellent for development, because the build system knows the paths to all libraries and can include them in executables. That's done when the hardcode-dll-paths feature has the true value, which is the default. When the executables should be installed, the story is different.
可執行文件可以包含一個額外庫路徑的列表,它會在系統路徑之前被搜索。這對於開發是很適用的,因為構建系統知道所有庫的路徑,可以把它們包含到可執行文件中。當 hardcode-dll-paths 特性具有 true 值時就會這麼做,這是缺省的。當可執行文件要被安裝時,情況就不一樣了。

Obviously, installed executable should not hardcode paths to your development tree. (The stage rule explicitly disables the hardcode-dll-paths feature for that reason.) However, you can use the dll-path feature to add explicit paths manually. For example:
顯然,已安裝的可執行文件不應當對你的開發樹的路徑進行硬編碼。(為此,stage 規則明確禁止了 hardcode-dll-paths 特性)。但是,你可以用 dll-path 特性來手工地顯式增加路徑。例如:

stage installed : application : <dll-path>/usr/lib/snake
<location>/usr/bin ;

will allow the application to find libraries placed to /usr/lib/snake.
將允許應用程序查找位於 /usr/lib/snake 的庫。

If you install libraries to a nonstandard location and add an explicit path, you get more control over libraries which will be used. A library of the same name in a system location will not be inadvertently used. If you install libraries to a system location and do not add any paths, the system administrator will have more control. Each library can be individually upgraded, and all applications will use the new library.
如果你將庫安裝在一個非標準的位置,並增加一個明確的路徑,你就對使用哪個庫有了更多的控制。在系統位置中的同名庫不會被不小心使用。如果你將庫安裝在系統的位置且沒有增加任何路徑,則系統管理員具有更多的控制。每個庫可以獨立地升級,所有應用程序都將使用新的庫。

Which approach is best depends on your situation. If the libraries are relatively standalone and can be used by third party applications, they should be installed in the system location. If you have lots of libraries which can be used only by your application, it makes sense to install it to a nonstandard directory and add an explicit path, like the example above shows. Please also note that guidelines for different systems differ in this respect. The Debian guidelines prohibit any additional search paths, and Solaris guidelines suggest that they should always be used.
哪 種方法最好,取決於你的具體情況。如果庫是相對獨立的,可以被第三方應用程序所使用,則應該安裝在系統的位置。如果你有大量的庫只被你的應用程序使用,則 安裝在一個非標準目錄中並增加明確路徑是合理的,如上例所示。另請注意,不同的系統在這方面有不同的準則。Debian 的準則是禁止任何額外的搜索路徑,而 Solaris 的準則是建議應該總是使用它們。

Targets in site-config.jam 在 site-config.jam 中的目標

It is desirable to declare standard libraries available on a given system. Putting target declaration in Jamfile is not really good, since locations of the libraries can vary. The solution is to declare the targets in site-config.jam:
對一個給定系統聲明可用的標準庫是可取的。將目標聲明放在 Jamfile 中不太好,因為庫的位置會變化。解決的方法是,將在 site-config.jam 中聲明這些目標:

project site-config ;
lib zlib : : <name>z ;

Recall that both site-config.jam and user-config.jam are projects, and everything you can do in a Jamfile you can do in those files. So, you declare a project id and a target. Now, one can write:
回想一下,site-config.jamuser-config.jam 都是工程,你在一個 Jamfile 中可以做的任何事情,都可以在這兩個文件中做。所以你聲明了一個工程 id 和一個目標。現在,你可以在任何一個 Jamfile 中這樣寫:

exe hello : hello.cpp /site-config//zlib ;

in any Jamfile.

Header-only libraries 只有頭文件的庫

In modern C++, libraries often consist of just header files, without any source files to compile. To use such libraries, you need to add proper includes and, maybe, defines, to your project. But with large number of external libraries it becomes problematic to remember which libraries are header only, and which are "real" ones. However, with Boost.Build a header-only library can be declared as Boost.Build target and all dependents can use such library without remebering if it's header-only or not.
在 現代 C++ 中,庫通常只包含有頭文件,而沒有任何要編譯的源文件。要使用這種庫,你需要向你的工程加入適當的包含,也許還有定義。但是,由於存在大量的外部庫,要記 住哪些庫是只有頭文件的,哪些庫是"真實"的,是很困難的。不過,對於 Boost.Build,一個只有頭文件的庫可以被聲明為 Boost.Build 目標,所有依賴於它的目標可以使用這個庫而無須記住它是否只有頭文件。

Header-only libraries are declared using the alias rule, that specifies only usage requirements, for example:
只有頭文件的庫可以用 alias 規則來聲明,它只指明了使用要求,例如:

alias mylib 
: # no sources
: # no build requirements
: # no default build
: <include>whatever
;

The includes specified in usage requirements of mylib are automatically added to build properties of all dependents. The dependents need not care if mylib is header-only or not, and it's possible to later make mylib into a regular compiled library.
mylib 的使用要求中所指定的包含關係會自動被增加到所有依賴於它的目標的構建屬性中。依賴目標無需關心 mylib 是否只有頭文件,稍後還可以將 mylib 變成一個普通的已編譯的庫。

If you already have proper usage requirements declared for project where header-only library is defined, you don't need to duplicate them for the alias target:
如果你已經為定義了只有頭文件的庫的工程聲明了適當的使用要求,那麼你就不需要為 alias 目標重複它們:

project my : usage-requirements <include>whatever ;
alias mylib ;


PrevUpHomeNext