靜態庫鏈接動態庫時,如何使用該靜態庫【轉】

(轉自:https://blog.csdn.net/newchenxf/article/details/51735600)


網上有各種靜態庫的創建&使用的例子,但都是超級簡單的例子,比如,靜態庫,就直接來個printf(),就完事了!
其實,實際使用時,靜態庫會複雜很多,比如會調用很多其他的動態庫。
下圖就是個例子:
這裏寫圖片描述

假設libXXX.a用了libpthread.so的函數「pthread_create」,那libXXX.a在鏈接時,有沒有把「pthread_create」函數copy到自己身上,使其完全獨立?main.c在鏈接時,只需要鏈接libXXX.a,還是連libpthread.so也要鏈接?!這就是我要討論的內容!

爲了證實問題,我們寫個測試程序吧。一個是libXXX.a,一個是main.c。

1 靜態庫文件libXXX.a源代碼

static_lib_example.h

  
  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
//static_lib_example.h #ifndef STATIC_LIB_EXAMPLE_H_INCLUDED #define STATIC_LIB_EXAMPLE_H_INCLUDED int testFunc(int x); #endif

static_lib_example.c

  
  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
//static_lib_example.c #include "static_lib_example.h" #include <stdio.h> #include <pthread.h> /* this function is run by the second thread */ void *thread_exe(void *x_void_ptr) { /* increment x to 100 */ int *x_ptr = (int *)x_void_ptr; while(++(*x_ptr) < 100); printf("x increment finished\n"); return NULL; } int testFunc(int x) { printf(" testFunc %i\n",x); pthread_t inc_x_thread; int y; /* create a second thread which executes thread_exe(&y) */ if(pthread_create(&inc_x_thread, NULL, thread_exe, &y)) { fprintf(stderr, "Error creating thread\n"); return 1; } return 0; }

一個頭文件,一個原文件,很簡單。
好吧,然後得來個Makefile

  
  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
#chenxf make file #some notice #target: prerequisites - the rule head #[email protected] - means the target #$^ - means all prerequisites #$< - means just the first prerequisite OUT_LIB = libstatic_lib_example.a LIB_SRC := static_lib_example.c TEMP_O := static_lib_example.o $(TEMP_O): $(LIB_SRC) @gcc -c -o [email protected] $^ all: $(OUT_LIB) $(OUT_LIB): $(TEMP_O) @ar rcs [email protected] $^ clean: @rm -r *.a *.o

其實Makefile相當於2句命令。所以你不寫Makefile,敲下面2句command也行。

gcc -c static_lib_example.c -o static_lib_example.o

ar rcs libstatic_lib_example.a static_lib_example.o

好了,編譯結果如下:

ls

libstatic_lib_example.a Makefile static_lib_example.c static_lib_example.h static_lib_example.o


2. 調用靜態庫的程序main.c源代碼

我們就寫一個main.c,它會鏈接libstatic_lib_example.a,並調用函數testFunc(int x)

  
  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
//main.c #include "static_lib_example.h" int main(int argc, char* argv[]) { testFunc(100); return 1; }

3 編譯main.c的情況分析

編譯main.c(只需要一個命令,就不寫Makefile啦)

gcc -g -O3 -Wall main.c -o main -I/home/chenxf/static_lib_sample/ -L/home/chenxf/static_lib_sample/ -lstatic_lib_example

-I表示頭文件的路徑
-L表示庫的路徑,即libstatic_lib_example.a的路徑。

上面的命令,表示main程序,只鏈接靜態庫libXXX.a。(好吧,就是libstatic_lib_example.a啦,幹嘛這麼糾結名字!^^)

編譯結果

/home/chenxf/static_lib_sample/libstatic_lib_example.a(static_lib_example.o):在函數‘testFunc’中:
static_lib_example.c:(.text+0x86):對‘pthread_create’未定義的引用
static_lib_example.c:(.text+0xd4):對‘pthread_join’未定義的引用
collect2: error: ld returned 1 exit status

出錯啦!!!!!!
在main.c鏈接的時候,說找不到pthread_create了!

看來,靜態庫libXXX.a並沒有把動態庫的函數copy到自己身上,只留了符號表,所以main.c要用libXXX.a時,還必須鏈接動態庫libpthread.so。也就是

gcc -g -O3 -Wall main.c -o main -I/home/chenxf/static_lib_sample/ -L/home/chenxf/static_lib_sample/ -static -lstatic_lib_example -lpthread

(libpthread.so在默認的系統庫目錄/usr/lib,不需要再寫-L/usr/lib/)

這樣一寫,就OK啦!編譯就成功了!

我們還可以用 nm 工具,來確認libXXX.a到底有木有把pthread_create()函數copy到自己身上。

  
  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
chenxf@chenxf-PC:~/static_lib_sample$ nm libstatic_lib_example.a static_lib_example.o: U fwrite U printf U pthread_create U pthread_join U puts U stderr 0000000000000040 T testFunc 0000000000000000 T thread_exe

U表示僅僅調用,而沒有定義。也就是該庫並不獨立,而是依賴於其他庫,比如libpthread.so

3 總結

總結一下成果吧!
這裏寫圖片描述
如果有靜態庫libXXX.a,它有個函數叫testFunc(),該函數用了其他的動態庫的函數,比如libAA.so的AA()函數,libBB.so的BB()函數,libCC.so的CC()函數,那麼,該libXXX.a對這些動態庫的調用仍是動態調用,而不是把動態庫的相關函數copy到自己身上。

任何其他程序,想用libXXX.a,鏈接時都需要鏈接libXXX.a所依賴的動態庫。
至於程序跑起來時,動態庫是否要在現場?這個就跟編譯程序加不加-static有關係了。
請看我另一博文就知道。gcc-static命令

anyway,知道真相的你,是不是覺得靜態庫不方便?!
我也覺得!
個人看法是,如果你要寫的靜態庫libXXX.a是完全獨立的,比如裏面只有一些數學運算,不依賴與其他動態庫,那靜態庫挺好的,任何用他的程序,只需要鏈接時用到,程序跑起來,就不需要它在現場了!

但是,如果你要寫的庫,依賴很多其他的庫,那你還是改寫成動態庫吧!否則,作爲寫其他程序的人,如果要用你的庫,那寫Makefile時,還得知道你到底依賴了什麼動態庫,否則編譯都編譯不過,多痛苦啊!!!

4 源碼

給出源碼。
https://github.com/xf420811/static_lib_test