static link:關於gcc連線靜態庫的幾種方式
開發一個應用程式不可避免要使用多個第三方庫(library).
預設情況下,gcc採用動態連線的方式連線第三方庫,比如指定-lpng
,連線程式就會去找libpng.so
。
gcc提供了一個-static
引數,可以改變gcc預設的連線方式,GNU官網上關於gcc連線選項的手冊《3.14 Options for Linking》中有說明:如下
這個-static
選項是個大殺器,指定了這個選項,gcc在連線時對專案所有的依賴庫都嘗試去搜索名為lib<name>.a
的靜態庫檔案,完成靜態連線,如果找不到就報錯了。這裡指的所有是不僅指我們常用的第三方庫比如jpeg,png,opencv,zlib,...
libgcc,libstdc++,libc,libm...
,總之就是linux kernal之外的所有庫。而且還要包括所有被間接引用的第三方庫,比如png
這個庫在編譯時還用到了zlib
,那麼靜態連線png
的時候,就要帶上zlib
的庫:-lpng -lz
,
這可麻煩大了,要把這些東西全靜態連線,這得有多大?呵呵,這事兒我幹過,十幾兆位元組總是有的,取決你的程式用到多少第三方庫。
這種全靜態連線有啥用處呢?也有用,就是你的程式自帶乾糧,只需要一個linux kernal就能跑了。
但是實際應用中,我們絕大多數應用場景不需要這麼做,即使在嵌入式系統中也不一定必要,尤其是嵌入式系統的儲存容量受限,這麼一隻大象裝都裝不下。所以我們大多數情況下需要有選擇的進行靜態編譯,-static
如何有選擇的進行靜態編譯呢?
最簡單的方式直接在連線引數中以全路徑指定連線庫就好了: your/path/lib<name>.a
但這種形式對管理結構簡單而且自己寫Makefile的小型專案還好,當一個專案結構複雜,有時需要靜態連線有時需要動態連線,這種頻繁的修改編譯指令碼的方式,可維護性就太差了。
-Bstatic
gnu的連線程式ld提供了一個-Bstatic
選項用於對指定的庫靜態連線,ld的官方手冊《2.1 Command Line Options》有說明,如下:
大意就是-Bstatic
引數指定對跟在它後面的所有庫執行靜態連線,如下就指定LDFLAGS
對png
這個庫靜態連線,ld會自動去搜索libpng.a
-Bstatic -lpng -lz
-l:filename
如果你覺得上面一種靜態連線方式不適合你,可以看看ld的官方手冊《2.1 Command Line Options》中關於-l
引數的說明,如下:
注意上面的說明中紅框標註的內容,如果-l:filename
格式指定一個檔名,連線程式直接去找這個檔名了,不會再像使用-lname
時將name擴充套件成lib<name>.a
格式的檔名.
所以使用 -l:libpng.a
這樣的形式來指定連線庫,就指定了靜態連線png
庫。
當然如果庫的位置不在gcc預設搜尋路徑中,要用-L
引數另外指定搜尋庫的路徑,否則連線程式不知道該從哪裡找到filename
。
-L/your/library/path -l:libmylib.a