頭文件與庫文件搜索路徑相關問題

在交叉編譯的時候我們需要用到其他的庫,在 config 時候可以通過 “-I” 來指定頭文件目錄,但是每次都需要設置的話難免有些麻煩,找到一個簡單的方法。看下文的紅色部分。

有大量的環境變量可供設置以影響 GCC 編譯程序的方式。利用這些變量的控制也可使用合適的命令行選項。一些環境變量設置在目錄名列表中。這些名字和 PATH 環境變量使用的格式相同。特殊字符 PATH_SEPARATOR (安裝編譯程序的時候定義)用在目錄名之間。在 UNIX 系統中,分隔符是冒號,而 Windows 系統中爲分號。

C_INCLUDE_PATH

編譯 C 程序時使用該環境變量。該環境變量指定一個或多個目錄名列表,查找頭文件,就好像在命令行中指定 -isystem 選項一樣。會首先查找 -isystem 指定的所有目錄。

==> 也見 CPATH 、 CPLUS_INCLUDE_PATH 和 OBJC_INCLUDE_PATH 。

COMPILER_PATH

該環境變量指定一個或多個目錄名列表,如果沒有指定 GCC_EXEC_PREFIX 定位子程序,編譯程序會在此查找它的子程序。

==> 也見 LIBRARY_PATH 、 GCC_EXEC_PREFIX 和 -B 命令行選項。

CPATH

編譯 C 、 C++ 和 Objective-C 程序時使用該環境變量。該環境變量指定一個或多個目錄名列表,查找頭文件,就好像在命令行中指定 -l 選項一樣。會首先查找 -l 指定的所有目錄。

==> 也見 C_INCLUDE_PATH 、 CPLUS_INCLUDE_PATH 和 OBJC_INCLUDE_PATH 。

CPLUS_INCLUDE_PATH

編譯 C++ 程序時使用該環境變量。該環境變量指定一個或多個目錄名列表,查找頭文件,就好像在命令行中指定 -isystem 選項一樣。會首先查找 -isystem 指定的所有目錄。

==> 也見 CPATH 、 C_INCLUDE_PATH 和 OBJC_INCLUDE_PATH 。

DEPENDENCIES_OUTPUT

爲文件名設置該環境變量會讓預處理程序將基於依賴關係的 makefile 規則寫入文件。不會包括系統頭文件名字。

如果環境變量設置爲單名,被看作是文件名字,而依賴關係規則的名字來自源文件名字。如果定義中有兩個名字,則第二個名字是用作依賴關係規則的目標名。 設置該環境變量的結果和使用命令行選項 -MM 、 -MF 和 -MT 的組合是一樣的。

==> 也見 SUNPRO_DEPENDENCIES 。

GCC_EXEC_PREFIX

如果定義了該環境變量,它會作爲編譯程序執行的所有子程序名字的前綴。例如,如果將變量設置爲 testver 而不是查找 as ,彙編器首先會在名字 testveras 下查找。如果在此沒有找到,編譯程序會繼續根據它的普通名進行查找。可在前綴名中使用斜線指出路徑名。

GCC_EXEC_PREFIX 的默認設置爲 prefix /lib/gcc-lib/ ,這裏的 prefix 是安裝編譯程序時 configure 腳本指定的名字。該前綴也用於定位標準連接程序文件,包含進來作爲可執行程序的一部分。

如果使用 -B 命令行選項,會重寫該設置。

==> 也見 COMPILER_PATH 。

LANG 該環境變量用於指出編譯程序使用的字符集,可創建寬字符文字、串文字和註釋。

定義 LANG 爲 C-JIS ,指出預處理程序將多字節字符按照 JIS (日語工業標準)字符進行解釋。 C-SJIS 可用來指出 Shift -JIS 字符而 C-EUCJP 指出日文 EUC 。

如果沒有定義 LANG ,或定義爲不可識別,函數 mblen() 被用來確定字符寬度,而 mbtowc() 用來將多字節序列轉換爲寬字符。

LC_ALL 如果設置,該環境變量的值重寫 LC_MESSAGES 和 LC_CTYPE 的所有設置。

LC_CTYPE 該環境變量指出引用串中定義的多字節字符的字符分類。主要用於確定字符串的字符邊界,字符編碼需要用引號或轉義符,可被錯誤地解釋爲字符串的結尾或特殊字符串。對 Australian English ,可將它設置爲 en_AU ; 對 Mexican Spanish ,可將它設置爲 es_MX 。如果沒有設置該變量,默認爲 LANG 變量的值,或如果沒有設置 LANG ,那就使用 C 英語行爲。也見 LC_ALL 。

LC_MESSAGES 該環境變量指出編譯程序使用何種語言發出診斷消息。對 Australian English ,可設置爲 en_AU ; 對 MexicanSpanish ,可設置爲 es_MX 。如果變量沒有設置,使用 LANG 變量的默認值,或如果沒有設置 LANG ,那就使用 C 英語行爲。也見 LC_ALL 。

LD_LIBRARY_PATH 該環境變量不會影響編譯程序,但程序運行的時候會有影響。變量指定一個目錄列表,程序會查找該列表定位共享庫。只有當未在編譯程序的目錄中找到共享庫的時候,執行程序必須設置該變量。

LD_RUN_PATH 該環境變量不會影響編譯程序,但程序運行的時候會有影響。該變量在運行時指出文件的名字,運行的程序可由此得到它的符號名字和地址。地址不會重新載入,因而可能符號引用其他文件中的絕對地址。這和 ld 工具使用 -R 選項完全一樣。

LIBRARY_PATH

該環境變量可設置爲一個或多個目錄名字列表,連接程序會搜尋該目錄,以查找特殊連接程序文件,和由 -l (字母 l )命令行選項指定名字的庫。 由 -L 命令行選項指定的目錄在環境變量的前面,首先被查找。

==> 也見 COMPILER_PATH 。

OBJC_INCLUDE_PATH

在編譯 Objective-C 程序的時候使用該環境變量。一個或多個目錄名的列表由環境變量指定,用來查找頭文件,就好像在命令行中指定 -isystem 選項一樣。所有由 -isystem 選項指定的目錄會首先被查找。

==> 也見 CPATH 、 CPLUS_INCLUDE_PATH 和 C_INCLUDE_PATH 。

SUNPRO_OUTPUT

爲文件名設置該環境變量會令預處理程序將基於依賴關係的 makefile 規則寫入文件。會包含系統頭文件名。如果環境變量被設置爲單個名字,它將會被當作文件名,依賴關係規則中的名字將由源文件的名字中獲得。如果定義中有兩個名字,第二個名字就是依賴關係規則中的目標名。設置該環境變量的結果與在命令行中使用參數 -M 、 -MF 和 -MT 的效果一樣。

==> 參見 DEPENDENCIES_OUTPUT 。

Linux 指定動態庫路徑

衆所周知, Linux 動態庫的默認搜索路徑是 /lib 和 /usr/lib 。動態庫被創建後,一般都複製到這兩個目錄中。當程序執行時需要某動態庫,並且該動態庫還未加載到內存中,則系統會自動到這兩個默認搜索路徑中去查找相應的動態庫文件,然後加載該文件到內存中,這樣程序就可以使用該動態庫中的函數,以及該動態庫的其它資源了。在 Linux 中,動態庫的搜索路徑除了默認的搜索路徑外,還可以通過以下三種方法來指定。

方法一:在配置文件 /etc/ld.so.conf 中指定動態庫搜索路徑。

可以通過編輯配置文件 /etc/ld.so.conf 來指定動態庫的搜索路徑,該文件中每行爲一個動態庫搜索路徑。每次編輯完該文件後,都必須運行命令 ldconfig 使修改後的配置生效 。我們通過例 1 來說明該方法。

例 1 :

我們通過以下命令用源程序 pos_conf.c (見程序 1 )來創建動態庫 libpos.so ,詳細創建過程請參考文 [1] 。

# gcc -c pos_conf.c

# gcc -shared -fPCI -o libpos.so pos_conf.o

#

#include

void pos()

{

printf("/root/test/conf/lib/n");

}

程序 1: pos_conf.c

接着通過以下命令編譯 main.c (見程序 2 )生成目標程序 pos 。

# gcc -o pos main.c -L. -lpos

#

void pos();

int main()

{

pos();

return 0;

}

程序 2: main.c

然後把庫文件移動到目錄 /root/test/conf/lib 中。

# mkdir -p /root/test/conf/lib

# mv libpos.so /root/test/conf/lib

#

最後編輯配置文件 /etc/ld.so.conf ,在該文件中追加一行 "/root/test/conf/lib" 。

運行程序 pos 試試。

# ./pos

./pos: error while loading shared libraries: libpos.so: cannot open shared object file: No such file or directory

#

出錯了,系統未找到動態庫 libpos.so 。找找原因,原來在編輯完配置文件 /etc/ld.so.conf 後,沒有運行命令 ldconfig ,所以剛纔的修改還未生效。我們運行 ldconfig 後再試試。

# ldconfig

# ./pos

/root/test/conf/lib

#

程序 pos 運行成功,並且打印出正確結果。

方法二:通過環境變量 LD_LIBRARY_PATH 指定動態庫搜索路徑。

通過設定環境變量 LD_LIBRARY_PATH 也可以指定動態庫搜索路徑。當通過該環境變量指定多個動態庫搜索路徑時,路徑之間用冒號 " : " 分隔。下面通過例 2 來說明本方法。

例 2 :

我們通過以下命令用源程序 pos_env.c (見程序 3 )來創建動態庫 libpos.so 。

# gcc -c pos_env.c

# gcc -shared -fPCI -o libpos.so pos_env.o

#

#include

void pos()

{

printf("/root/test/env/lib/n");

}

程序 3: pos_env.c

測試用的可執行文件 pos 可以使用例 1 中的得到的目標程序 pos ,不需要再次編譯。因爲 pos_conf.c 中的函數 pos 和 pos_env.c 中的函數 pos 函數原型一致,且動態庫名相同,這就好比修改動態庫 pos 後重新創建該庫一樣。這也是使用動態庫的優點之一。

然後把動態庫 libpos.so 移動到目錄 /root/test/conf/lib 中。

# mkdir -p /root/test/env/lib

# mv libpos.so /root/test/env/lib

#

我們可以使用 export 來設置該環境變量,在設置該環境變量後所有的命令中,該環境變量都有效。

例如:

# export LD_LIBRARY_PATH=/root/test/env/lib

#

但本文爲了舉例方便,使用另一種設置環境變量的方法,既在命令前加環境變量設置,該環境變量只對該命令有效,當該命令執行完成後,該環境變量就無效了。如下述命令:

# LD_LIBRARY_PATH=/root/test/env/lib ./pos

/root/test/env/lib

#

程序 pos 運行成功,並且打印的結果是 "/root/test/env/lib" ,正是程序 pos_env.c 中的函數 pos 的運行結果。因此程序 pos 搜索到的動態庫是 /root/test/env/lib/libpos.so 。

方法三:在編譯目標代碼時指定該程序的動態庫搜索路徑。

還可以在編譯目標代碼時指定程序的動態庫搜索路徑。 -Wl, 表示後面的參數將傳給 link 程序 ld (因爲 gcc 可能會自動調用 ld )。這裏通過 gcc 的參數 "-Wl,-rpath," 指定(如例 3 所示)。當指定多個動態庫搜索路徑時,路徑之間用冒號 " : " 分隔。

例 3 :

我們通過以下命令用源程序 pos.c (見程序 4 )來創建動態庫 libpos.so 。

# gcc -c pos.c

# gcc -shared -fPCI -o libpos.so pos.o

#

#include

void pos()

{

printf(".//n");

}

程序 4: pos.c

因爲我們需要在編譯目標代碼時指定可執行文件的動態庫搜索路徑,所以需要用 gcc 命令重新編譯源程序 main.c( 見程序 2) 來生成可執行文件 pos 。

# gcc -o pos main.c -L. -lpos -Wl,-rpath,./

#

再運行程序 pos 試試。

# ./pos

./

#

程序 pos 運行成功,輸出的結果正是 pos.c 中的函數 pos 的運行結果。因此程序 pos 搜索到的動態庫是 ./libpos.so 。

example:

gcc -Wl,-rpath,/home/arc/test,-rpath,/lib/,-rpath,/usr/lib/,-rpath,/usr/local/lib test.c

以上介紹了三種指定動態庫搜索路徑的方法,加上默認的動態庫搜索路徑 /lib 和 /usr/lib ,共五種動態庫的搜索路徑,那麼它們搜索的先後順序是什麼呢?

在介紹上述三種方法時,分別創建了動態庫 ./libpos.so 、 /root/test/env/lib/libpos.so 和 /root/test/conf/lib/libpos.so 。我們再用源程序 pos_lib.c (見程序 5 )來創建動態庫 /lib/libpos.so ,用源程序 pos_usrlib.c (見程序 6 )來創建動態庫 /usr/lib/libpos.so 。

#include

void pos()

{

printf("/lib/n");

}

程序 5: pos_lib.c

#include

void pos()

{

printf("/usr/lib/n");

}

程序 6: pos_usrlib.c

這 樣我們得到五個動態庫 libpos.so ,這些動態庫的名字相同,且都包含相同函數原型 的公用函數 pos 。但存儲的位置不同和公用函數 pos 打印的結果不同。每個動態庫中的公用函數 pos 都輸出該動態庫所存放的位置。這樣我們可以通過執行例 3 中的可執行文件 pos 得到的結果不同獲知其搜索到了 哪個動態庫,從而獲得第 1 個動態庫搜索順序,然後刪除該動態庫,再執行程序 pos ,獲得第 2 個動態庫搜索路徑,再刪除第 2 個被搜索到的動態庫,如此往復, 將可得到 Linux 搜索動態庫的先後順序。 程序 pos 執行的輸出結果和搜索到的動態庫的對應關係如表 1 所示:

程序 pos 輸出結果

使用的動態庫

對應的動態庫搜索路徑指定方式

./

./libpos.so

編譯目標代碼時指定的動態庫搜索路徑

/root/test/env/lib

/root/test/env/lib/libpos.so

環境變量 LD_LIBRARY_PATH 指定的動態庫搜索路徑

/root/test/conf/lib

/root/test/conf/lib/libpos.so

配置文件 /etc/ld.so.conf 中指定的動態庫搜索路徑

/lib

/lib/libpos.so

默認的動態庫搜索路徑 /lib

/usr/lib

/usr/lib/libpos.so

默認的動態庫搜索路徑 /usr/lib

表 1: 程序 pos 輸出結果和動態庫的對應關係

創建各個動態庫,並放置在相應的目錄中。測試環境就準備好了。執行程序 pos ,並在該命令行中設置環境變量 LD_LIBRARY_PATH 。

# LD_LIBRARY_PATH=/root/test/env/lib ./pos

./

#

根據程序 pos 的輸出結果可知,最先搜索的是編譯目標代碼時指定的動態庫搜索路徑。然後我們把動態庫 ./libpos.so 刪除了,再運行上述命令試試。

# rm libpos.so

rm: remove regular file `libpos.so'? y

# LD_LIBRARY_PATH=/root/test/env/lib ./pos

/root/test/env/lib

#

根據程序 pos 的輸出結果可知,第 2 個動態庫搜索的路徑是環境變量 LD_LIBRARY_PATH 指定的。我們再把 /root/test/env/lib/libpos.so 刪除,運行上述命令。

# rm /root/test/env/lib/libpos.so

rm: remove regular file `/root/test/env/lib/libpos.so'? y

# LD_LIBRARY_PATH=/root/test/env/lib ./pos

/root/test/conf/lib

#

第 3 個動態庫的搜索路徑是配置文件 /etc/ld.so.conf 指定的路徑。刪除動態庫 /root/test/conf/lib/libpos.so 後再運行上述命令。

# rm /root/test/conf/lib/libpos.so

rm: remove regular file `/root/test/conf/lib/libpos.so'? y

# LD_LIBRARY_PATH=/root/test/env/lib ./pos

/lib

#

第 4 個動態庫的搜索路徑是默認搜索路徑 /lib 。我們再刪除動態庫 /lib/libpos.so ,運行上述命令。

# rm /lib/libpos.so

rm: remove regular file `/lib/libpos.so'? y

# LD_LIBRARY_PATH=/root/test/env/lib ./pos

/usr/lib

#

最後的動態庫搜索路徑是默認搜索路徑 /usr/lib 。

綜合以上結果可知,動態庫的搜索路徑搜索的先後順序是:

1. 編譯目標代碼時指定的動態庫搜索路徑;

2. 環境變量 LD_LIBRARY_PATH 指定的動態庫搜索路徑;

3. 配置文件 /etc/ld.so.conf 中指定的動態庫搜索路徑;

4. 默認的動態庫搜索路徑 /lib ;

5. 默認的動態庫搜索路徑 /usr/lib 。

在上述 1 、 2 、 3 指定動態庫搜索路徑時,都可指定多個動態庫搜索路徑,其搜索的先後順序是按指定路徑的先後順序搜索的。對此本文不再舉例說明,有興趣的讀者可以參照本文的方法驗證。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章