![]() |
Home | Libraries | People | FAQ | More |
dll-path and hardcode-dll-paths
properties useful? 為什麼 dll-path
和 hardcode-dll-paths
是有用的? 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:
只有在構建一個目標時,特性才具有一個特定的值,你有兩種方法可以使用這個值:
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.
要解決這個問題,你需要決定該文件是要編譯一次還是兩次。
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 ;
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 ;
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 不能自動使用以上某個方法。問題是,這樣的方式需要更多的實現複雜性,而只對一半的情況有幫助,而在另一半情況下,我們還是會無聲無息地做錯事。在這種情況下,要求用戶澄清意圖更為簡單和安全。
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) ;
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.
符號 &&
用於分隔一個屬性的值,並指定這些值的順序要被保留。建議你只在屬性的順序確實重要時才使用此特性,而不是把它作為一個方便的縮寫來用。到外使用它可能會產生負面的性能影響。
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 ;
The SHELL
builtin can be used for the purpose:
內建的 SHELL
可用於此目的:
local gtk_includes = [ SHELL "gtk-config --cflags" ] ;
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 中使用了。
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
目標,然後在你的 exe 或 lib 目標中使用該目標:
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 ;
(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 的準則是建議應該總是使用它們。
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.jam 和 user-config.jam 都是工程,你在一個 Jamfile 中可以做的任何事情,都可以在這兩個文件中做。所以你聲明了一個工程 id 和一個目標。現在,你可以在任何一個 Jamfile 中這樣寫:
exe hello : hello.cpp /site-config//zlib ;
in any Jamfile.
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 ;