在使用gcc編譯連線生成可執行檔案時,經常會碰到變數未定義、鏈結時或者執行可執行檔案時找不到相應的動態庫等問題,本文首先介紹了gcc在編譯時標頭檔案路徑相關選項以及搜尋路徑順序,然後討論了編譯成可執行檔案時動態庫的搜尋路徑順序,最後說明了生成可執行檔案後,執行檔案時動態庫的搜尋路徑順序。搞清楚這三個搜尋路徑,在用gcc碰到的未定義變數或搜尋不到動態庫的問題,基本上都可以解決了。
標頭檔案路徑編譯時相關選項
gcc可以使用選項-i(注意是大寫)來指定標頭檔案搜尋路徑,即標頭檔案所在的資料夾。指定的路徑即可以是絕對路徑也可以是相對路徑。比如當前路徑下有檔案hello.c和include/testhead.h,則有兩種方法訪問這個標頭檔案:
hello.c中#include "include/testhead.h"直接指定標頭檔案的路徑,然後可以直接編譯不需要選項-i了,即gcc hello.c。
hello.c中#include "testhead.h",在編譯時使用:gcc -i include hello.c或者gcc -i ./include hello.c,在編譯選項中指定標頭檔案的路徑。
另外選項-nostdinc使編譯器不再系統預設的頭檔案目錄裡面找標頭檔案,一般和-i聯合使用,明確限定標頭檔案的位置。
兩種不型別的標頭檔案#include<>和#include""搜尋規則
1)使用<>包含的標頭檔案一般會先搜尋-i選項後的路徑(即用gcc編譯時的-i選項,注意是大寫),之後就是標準的系統標頭檔案路徑。
2)而用""號包含的標頭檔案會首先搜尋當前的工作目錄,之後的搜尋路徑才是和<>號包含的標頭檔案所搜尋的路徑一樣的路徑。
標頭檔案搜尋順序
標頭檔案搜尋順序是不會遞迴在目錄下搜尋的,搜尋順序規則如下(這裡是指<>型別標頭檔案搜尋規則,因為」」型別標頭檔案首先搜尋當前的工作目錄,之後的搜尋路徑是和<>號包含的標頭檔案所搜尋的路徑一樣):
首先由引數-i指定的路徑(指定路徑有多個路徑時,按指定路徑的順序搜尋)。
然後找gcc的環境變數 c_include_path(這個變數是搜尋c語言的標頭檔案使用)和cplus_include_path(針對c++的標頭檔案),設定環境變數的方法與通常是一樣的,比如在.bashrc或.profile中新增,比如:
export c_include_path="$home/github"
最後找預設的目錄
/usr/local/include
libdir/gcc/target/version/include
/usr/target/include
/usr/include
對於c++程式,還會在libdir/../include/c++/version中查詢這裡的target是指gcc的編譯配置的標準名字,version是gcc在用的版本。比如用gcc -v hello.cpp得到的相關路徑查詢資訊是:
動態庫相關選項
假如我們有兩個原始檔,乙個是dltest.c**如下:
#include void test_dl()
另外乙個原始檔**hello.c如下:
void test_dl();
int main(void)
通過執行命令gcc -shared -fpic -o libdltest.so dltest.c來建立動態庫檔案libdltest.so。這裡選項-shared告訴聯結器原始碼是生成乙個共享庫,而不是可執行檔案。選項-fpic引數宣告鏈結庫的**段是可以共享的,使生成的物件模組採用浮動的(可重定位的)位址,pic 代表「位置無關**」(position independent code)。請注意這次我們編譯的共享庫的名字叫做libdltest.so,這也是linux共享庫的乙個命名的慣例了:字尾使用so,而名稱使用lib***x格式。建立好共享庫後,就可以使用命令gcc -l./ -ldltest hello.c來連線動態庫生成可執行檔案。選項-l是把其後路徑加入到搜尋庫檔案的路徑列表中;選項-l指定搜尋指定名的庫。注意使用的名字是dltest,而鏈結的是libdltest.so,這種方式是linux通常做法。
動態庫搜尋路徑
動態庫搜尋路徑分兩種情況,一種是編譯生成可執行檔案時,另外一種是執行可執行檔案時。編譯生成可執行檔案時,動態庫的搜尋路徑順序如下:
首先gcc會找-l選項;
然後再找gcc的環境變數library_path,可以在.profile設定這個環境變數,並且可以通過選項-v檢視gcc最終編譯時library_path的值;
再找內定目錄 /lib:/usr/lib: /usr/local/lib,這些都是當初compile gcc時寫在程式內的。
注意上面索順序是不會遞迴在目錄下搜尋的。生成可執行檔案後,執行檔案時,動態庫的搜尋路徑順序如下:
首先編譯目標**時指定的動態庫搜尋路徑,就是用選項-wl,rpath指定程式在執行時動態庫的搜尋路徑,比如gcc -wl,-rpath,include -l. -ldltest hello.c,在執行檔案時會搜尋路徑./include;
環境變數ld_library_path指定的動態庫搜尋路徑;
配置檔案/etc/ld.so.conf中指定的動態庫搜尋路徑,即在配置檔案中新增動態庫的絕對路徑,然後執行指令ldconfig是配置檔案生效;
預設的動態庫搜尋路徑/lib;
預設的動態庫搜尋路徑/usr/lib。
同樣上面索順序是不會遞迴在目錄下搜尋的。通常使用動態庫簡單做法是:把生成的so檔案拷貝到/usr/lib中,這樣不管是生成可以執行檔案時,還是執行程式時,都能找到需要的so檔案。
參考資料
gcc指定標頭檔案路徑及動態鏈結庫路徑
include 直接到系統指定的某些目錄中去找某些標頭檔案。include 先到原始檔所在資料夾去找,然後再到系統指定的某些目錄中去找某些標頭檔案。1.會在預設情況下指定到 usr include資料夾 更深層次的是乙個相對路徑,gcc可執行程式的路徑是 usr bin gcc,那麼它在實際工作時指...
gcc指定標頭檔案及動態鏈結庫路徑
在利用源 進行軟體編譯的過程中,經常會出現以下錯誤 include 直接到系統指定的某些目錄中去找某些標頭檔案。include 先到原始檔所在資料夾去找,然後再到系統指定的某些目錄中去找某些標頭檔案。那麼gcc如何確定標頭檔案搜尋路徑呢?q 檔案路徑有多種,那麼先後順序如何?i 指定的路徑 gcc ...
gcc指定標頭檔案和動態庫的方法
本文詳細介紹了linux 下gcc標頭檔案指定方法,以及搜尋路徑順序的問題。另外,還總結了,gcc動態鏈結的方法以及路徑指定,同樣也討論了搜尋路徑的順序問題。本文包含了很多的例子,具有很強的操作性,希望讀者自己去走一遍。一.include 與 include include 直接到系統指定的某些目錄...