工具鏈中庫和頭文件的搜索路徑

製作.so文件

我們的目標是製作共享庫,即.so文件。

 

首先,編譯stack.c:

$gcc -c -fPIC -o mystack.o mystack.c

-c表示只編譯(compile),而不連接。-o選項用於說明輸出(output)文件名。gcc將生成一個目標(object)文件mystack.o

注意-fPIC選項。PIC指Position Independent Code。共享庫要求有此選項,以便實現動態連接(dynamic linking)。

 

生成共享庫:

$gcc -shared -o libmystack.so mystack.o

庫文件以lib開始。共享庫文件以.so爲後綴。-shared表示生成一個共享庫。

 

這樣,共享庫就完成了。.so文件和.h文件都位於當前工作路徑(.)。

 

使用共享庫

我們編寫一個test.c,來實際調用共享庫:

複製代碼
#include <stdio.h>
#include "mystack.h"

/*
* call functions in mystack library
*/ void main(void) { ElementTP a; int i; STACK sk; sk = init_stack(); push(sk, 1); push(sk, 2); push(sk, 8); printf("Stack is null? %d\n", is_null(sk)); for (i=0; i<3; i++) { a = pop(sk); printf("pop: %d\n", a); } printf("Stack is null? %d\n", is_null(sk)); delete_stack(sk); }
複製代碼

注意,我們在程序的一開始include了mystack.h。

 

編譯上述程序。編譯器需要知道.h文件位置。

  • 對於#include "...",編譯器會在當前路徑搜索.h文件。你也可以使用-I選項提供額外的搜索路徑,比如-I/home/vamei/test。
  • 對於#include <...>,編譯器會在默認include搜索路徑中尋找。

編譯器還需要知道我們用了哪個庫文件,在gcc中:

  • 使用-l選項說明庫文件的名字。這裏,我們將使用-lmystack (即libmystack庫文件)。
  • 使用-L選項說明庫文件所在的路徑。這裏,我們使用-L. (即.路徑)。

如果沒有提供-L選項,gcc將在默認庫文件搜索路徑中尋找。

 

你可以使用下面的命令,來獲知自己電腦上的include默認搜索路徑:

$`gcc -print-prog-name=cc1` -v   

獲知庫默認搜索路徑:

$gcc -print-search-dirs

 

我們所需的.h和.so文件都在當前路徑,因此,使用如下命令編譯:

$gcc -o test test.c -lmystack -L.

將生成test可執行文件。

 

使用

$./test

執行程序

 

運行程序

儘管我們成功編譯了test可執行文件,但很有可能不能執行。一個可能是權限問題。我們需要有執行該文件的權限,見Linux文件管理背景知識

另一個情況是:

./test: error while loading shared libraries: libmystack.so: cannot open shared object file: No such file or directory

 

這是因爲操作系統無法找到庫。libmystack.so位於當前路徑,位於庫文件的默認路徑之外。儘管我們在編譯時(compile time)提供了.so文件的位置,但這個信息並沒有寫入test可執行文件(runtime)。可以使用下面命令測試:

$ldd test

ldd用於顯示可執行文件所依賴的庫。顯示:

    linux-vdso.so.1 =>  (0x00007fff31dff000)
    libmystack.so => not found
    libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fca30de7000)
    /lib64/ld-linux-x86-64.so.2 (0x00007fca311cb000)

這說明test可執行文件無法找到它所需的libmystack.so庫文件。

 

爲了解決上面的問題,我們可以將.so文件放入默認搜索路徑中。但有時,特別是多用戶環境下,我們不享有在默認搜索路徑寫入的權限。

一個解決方案是設置LD_LIBRARY_PATH環境變量。比如:

$export LD_LIBRARY_PATH=.

這樣,可執行文件執行時,操作系統將在先在LD_LIBRARY_PATH下搜索庫文件,再到默認路徑中搜索。環境變量的壞處是,它會影響所有的可執行程序。如果我們在編譯其他程序時,如果我們不小心,很可能導致其他可執行文件無法運行。因此,LD_LIBRARY_PATH環境變量多用於測試。

另一個解決方案,即提供-rpath選項,將搜索路徑信息寫入test文件(rpath代表runtime path)。這樣就不需要設置環境變量。這樣做的壞處是,如果庫文件移動位置,我們需要重新編譯test。使用如下命令編譯test.c:

$gcc -g -o test test.c -lmystack -L. -Wl,-rpath=.

-Wl表示,-rpath選項是傳遞給連接器(linker)。

發佈了121 篇原創文章 · 獲贊 39 · 訪問量 50萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章