天天看點

再議GCC編譯時的靜态庫依賴順序問題

再議GCC編譯時的靜态庫依賴順序問題

假設有如三個源代碼檔案:

$ cat a.cpp

void a()

{

}

$ cat b.cpp

extern void a();

void b()

    a(); // 調用a.cpp中的a()

$ cat x.cpp

extern void b();

int main()

    b(); // 調用b.cpp中的b()

    return 0;

對應的Makefile檔案:

all: x

liba.a: a.o

libb.a: b.o

x: x.o liba.a libb.a # 問題出在這兒

    g++ -g -o $@ $^

a.o: a.cpp

    g++ -g -c $^

b.o: b.cpp

x.o: x.cpp

clean:

    rm -f a.o b.o x.o x

使用上面的Makefile編譯,将會遇到如下所示的“undefined reference”問題:

g++ -g -c x.cpp

g++ -g -c a.cpp

g++ -g -c b.cpp

g++ -g -o x x.o liba.a libb.a # 改成“g++ -g -o x x.o libb.a liba.a”即可解決

libb.a(b.o): In function `b()':

/tmp/b.cpp:2: undefined reference to `a()'

collect2: ld returned 1 exit status

make: *** [x] Error 1

這個問題的原因是b.cpp依賴a.cpp,gcc要求(實際是ld要求)libb.a須放在liba.a前面,即需要改成:g++ -g -o x x.o libb.a liba.a,也就是被依賴的庫需要放在後頭。

這是最正常的解決辦法,除此之外,隻需要加入--start-group和--end-group兩個連結參數,即可保持被依賴的庫放在前頭,也就是改成如下即可:g++ -g -o $@ -Wl,--start-group $^ -Wl,--end-group。

這裡的“-Wl,”表示後面跟着的參數是傳遞給連結器ld的,gcc不關心具體是啥。“--start-group”表示範圍的開始;“--end-group”表示範圍的結束,是可選的。位于“--end-group”之後的仍然要求被依賴的庫放在後頭。注意“--start-group”不能重複,相關連結參數:--whole-archive 和 --no-whole-archive。