1. 程式人生 > >static link:關於gcc連線靜態庫的幾種方式

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,...

,還包括gcc編譯器自帶的庫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引數指定對跟在它後面的所有庫執行靜態連線,如下就指定LDFLAGSpng這個庫靜態連線,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

在這裡插入圖片描述

參考資料