*
運行 gcc/egcs
*
gcc/egcs 的主要選項
*
gdb
*
gdb 的常用命令
*
gdb 使用範例
*
其他程序/庫工具 (ar, objmp, nm, size, strings, strip, ...)
* 創建和使用靜態庫
* 創建和使用共享庫
* 使用高級共享庫特性
1.7.1 運行 gcc/egcs
Linux 中最重要的軟體開發工具是 GCC。GCC 是 GNU 的 C 和 C++ 編譯器。實際上,GCC 能夠編譯三種語言:C、C++ 和 Object C(C 語言的一種面向對象擴展)。利用 gcc 命令可同時編譯並連接 C 和 C++ 源程序。
#DEMO#: hello.c
如果你有兩個或少數幾個 C 源文件,也可以方便地利用 GCC 編譯、連接並生成可執行文件。例如,假設你有兩個源文件 main.c 和 factorial.c 兩個源文件,現在要編譯生成一個計算階乘的程序。
-----------------------
清單 factorial.c
-----------------------
#include <stdio.h>
#include <stdlib.h>
int factorial (int n)
{
if (n <= 1)
return 1;
else
return factorial (n - 1) * n;
}
-----------------------
-----------------------
清單 main.c
-----------------------
#include <stdio.h>
#include <stdlib.h>
int factorial (int n);
int main (int argc, char **argv)
{
int n;
if (argc < 2) {
printf ("Usage: %s n\n", argv [0]);
return -1;
}
else {
n = atoi (argv[1]);
printf ("Factorial of %d is %d.\n", n, factorial (n));
}
return 0;
}
-----------------------
利用如下的命令可編譯生成可執行文件,並執行程序:
$ gcc -o factorial main.c factorial.c
$ ./factorial 5
Factorial of 5 is 120.
GCC 可同時用來編譯 C 程序和 C++ 程序。一般來說,C 編譯器通過源文件的後綴名來判斷是 C 程序還是 C++ 程序。在 Linux 中,C 源文件的後綴名為 .c,而 C++ 源文件的後綴名為 .C 或 .cpp。
但是,gcc 命令只能編譯 C++ 源文件,而不能自動和 C++ 程序使用的庫連接。因此,通常使用 g++ 命令來完成 C++ 程序的編譯和連接,該程序會自動調用 gcc 實現編譯。假設我們有一個如下的 C++ 源文件(hello.C):
#include <iostream.h>
void main (void)
{
cout << "Hello, world!" << endl;
}
則可以如下調用 g++ 命令編譯、連接並生成可執行文件:
$ g++ -o hello hello.C
$ ./hello
Hello, world!
1.7.2 gcc/egcs 的主要選項
表 1-3 gcc 命令的常用選項
選項 解釋
-ansi 只支持 ANSI 標準的 C 語法。這一選項將禁止 GNU C 的某些特色,
例如 asm 或 typeof 關鍵詞。
-c 只編譯並生成目標文件。
-DMACRO 以字元串「1」定義 MACRO 宏。
-DMACRO=DEFN 以字元串「DEFN」定義 MACRO 宏。
-E 只運行 C 預編譯器。
-g 生成調試信息。GNU 調試器可利用該信息。
-IDIRECTORY 指定額外的頭文件搜索路徑DIRECTORY。
-LDIRECTORY 指定額外的函數庫搜索路徑DIRECTORY。
-lLIBRARY 連接時搜索指定的函數庫LIBRARY。
-m486 針對 486 進行代碼優化。
-o FILE 生成指定的輸出文件。用在生成可執行文件時。
-O0 不進行優化處理。
-O 或 -O1 優化生成代碼。
-O2 進一步優化。
-O3 比 -O2 更進一步優化,包括 inline 函數。
-shared 生成共享目標文件。通常用在建立共享庫時。
-static 禁止使用共享連接。
-UMACRO 取消對 MACRO 宏的定義。
-w 不生成任何警告信息。
-Wall 生成所有警告信息。
#DEMO#
MiniGUI 的編譯選項
1.7.3 gdb
GNU 的調試器稱為 gdb,該程序是一個互動式工具,工作在字元模式。在 X Window 系統中,
有一個 gdb 的前端圖形工具,稱為 xxgdb。gdb 是功能強大的調試程序,可完成如下的調試
任務:
* 設置斷點;
* 監視程序變數的值;
* 程序的單步執行;
* 修改變數的值。
在可以使用 gdb 調試程序之前,必須使用 -g 選項編譯源文件。可在 makefile 中如下定義
CFLAGS 變數:
CFLAGS = -g
運行 gdb 調試程序時通常使用如下的命令:
gdb progname
在 gdb 提示符處鍵入help,將列出命令的分類,主要的分類有:
* aliases:命令別名
* breakpoints:斷點定義;
* data:數據查看;
* files:指定並查看文件;
* internals:維護命令;
* running:程序執行;
* stack:調用棧查看;
* statu:狀態查看;
* tracepoints:跟蹤程序執行。
鍵入 help 後跟命令的分類名,可獲得該類命令的詳細清單。
#DENO#
1.7.4 gdb 的常用命令
表 1-4 常用的 gdb 命令
命令 解釋
break NUM 在指定的行上設置斷點。
bt 顯示所有的調用棧幀。該命令可用來顯示函數的調用順序。
clear 刪除設置在特定源文件、特定行上的斷點。其用法為:clear FILENAME:NUM。
continue 繼續執行正在調試的程序。該命令用在程序由於處理信號或斷點而
導致停止運行時。
display EXPR 每次程序停止後顯示表達式的值。表達式由程序定義的變數組成。
file FILE 裝載指定的可執行文件進行調試。
help NAME 顯示指定命令的幫助信息。
info break 顯示當前斷點清單,包括到達斷點處的次數等。
info files 顯示被調試文件的詳細信息。
info func 顯示所有的函數名稱。
info local 顯示當函數中的局部變數信息。
info prog 顯示被調試程序的執行狀態。
info var 顯示所有的全局和靜態變數名稱。
kill 終止正被調試的程序。
list 顯示源代碼段。
make 在不退出 gdb 的情況下運行 make 工具。
next 在不單步執行進入其他函數的情況下,向前執行一行源代碼。
print EXPR 顯示表達式 EXPR 的值。
1.7.5 gdb 使用範例
-----------------
清單 一個有錯誤的 C 源程序 bugging.c
-----------------
#include <stdio.h>
#include <stdlib.h>
static char buff [256];
static char* string;
int main ()
{
printf ("Please input a string: ");
gets (string);
printf ("\nYour string is: %s\n", string);
}
-----------------
上面這個程序非常簡單,其目的是接受用戶的輸入,然後將用戶的輸入列印出來。該程序使用了
一個未經過初始化的字元串地址 string,因此,編譯並運行之後,將出現 Segment Fault 錯誤:
$ gcc -o test -g test.c
$ ./test
Please input a string: asfd
Segmentation fault (core mped)
為了查找該程序中出現的問題,我們利用 gdb,並按如下的步驟進行:
1.運行 gdb bugging 命令,裝入 bugging 可執行文件;
2.執行裝入的 bugging 命令;
3.使用 where 命令查看程序出錯的地方;
4.利用 list 命令查看調用 gets 函數附近的代碼;
5.唯一能夠導致 gets 函數出錯的因素就是變數 string。用 print 命令查看 string 的值;
6.在 gdb 中,我們可以直接修改變數的值,只要將 string 取一個合法的指針值就可以了,為
此,我們在第 11 行處設置斷點;
7.程序重新運行到第 11 行處停止,這時,我們可以用 set variable 命令修改 string 的取值;
8.然後繼續運行,將看到正確的程序運行結果。
#DEMO#
1.7.6 其他程序/庫工具
strip:
nm:
size:
string:
1.7.7 創建和使用靜態庫
創建一個靜態庫是相當簡單的。通常使用 ar 程序把一些目標文件(.o)組合在一起,成為一個單獨的庫,然後運行 ranlib,以給庫加入一些索引信息。
1.7.8 創建和使用共享庫
特殊的編譯和連接選項
-D_REENTRANT 使得預處理器符號 _REENTRANT 被定義,這個符號激活一些宏特性。
-fPIC 選項產生位置獨立的代碼。由於庫是在運行的時候被調入,因此這個
選項是必需的,因為在編譯的時候,裝入內存的地址還不知道。如果
不使用這個選項,庫文件可能不會正確運行。
-shared 選項告訴編譯器產生共享庫代碼。
-Wl,-soname -Wl 告訴編譯器將後面的參數傳遞到連接器。而 -soname 指定了
共享庫的 soname。
# 可以把庫文件拷貝到 /etc/ld.so.conf 中列舉出的任何目錄中,並以
root 身份運行 ldconfig;或者
# 運行 export LD_LIBRARY_PATH='pwd',它把當前路徑加到庫搜索路徑中去。
1.7.9 使用高級共享庫特性
1. ldd 工具
ldd 用來顯示執行文件需要哪些共享庫, 共享庫裝載管理器在哪裡找到了需要的共享庫.
2. soname
共享庫的一個非常重要的,也是非常難的概念是 soname——簡寫共享目標名(short for shared object name)。這是一個為共享庫(.so)文件而內嵌在控制數據中的名字。如前面提到的,每一個程序都有一個需要使用的庫的清單。這個清單的內容是一系列庫的 soname,如同 ldd 顯示的那樣,共享庫裝載器必須找到這個清單。
soname 的關鍵功能是它提供了兼容性的標准。當要升級系統中的一個庫時,並且新庫的 soname 和老的庫的 soname 一樣,用舊庫連接生成的程序,使用新的庫依然能正常運行。這個特性使得在 Linux 下,升級使用共享庫的程序和定位錯誤變得十分容易。
在 Linux 中,應用程序通過使用 soname,來指定所希望庫的版本。庫作者也可以通過保留或者改變 soname 來聲明,哪些版本是相互兼容的,這使得程序員擺脫了共享庫版本沖突問題的困擾。
查看/usr/local/lib 目錄,分析 MiniGUI 的共享庫文件之間的關系
3. 共享庫裝載器
當程序被調用的時候,Linux 共享庫裝載器(也被稱為動態連接器)也自動被調用。它的作用是保證程序所需要的所有適當版本的庫都被調入內存。共享庫裝載器名字是 ld.so 或者是 ld-linux.so,這取決於 Linux libc 的版本,它必須使用一點外部交互,才能完成自己的工作。然而它接受在環境變數和配置文件中的配置信息。
文件 /etc/ld.so.conf 定義了標准系統庫的路徑。共享庫裝載器把它作為搜索路徑。為了改變這個設置,必須以 root 身份運行 ldconfig 工具。這將更新 /etc/ls.so.cache 文件,這個文件其實是裝載器內部使用的文件之一。
可以使用許多環境變數控制共享庫裝載器的操作(表1-4+)。
表 1-4+ 共享庫裝載器環境變數
變數 含義
LD_AOUT_LIBRARY_PATH 除了不使用 a.out 二進制格式外,與 LD_LIBRARY_PATH 相同。
LD_AOUT_PRELOAD 除了不使用 a.out 二進制格式外,與 LD_PRELOAD 相同。
LD_KEEPDIR 只適用於 a.out 庫;忽略由它們指定的目錄。
LD_LIBRARY_PATH 將其他目錄加入庫搜索路徑。它的內容應該是由冒號
分隔的目錄列表,與可執行文件的 PATH 變數具有相同的格式。
如果調用設置用戶 ID 或者進程 ID 的程序,該變數被忽略。
LD_NOWARN 只適用於 a.out 庫;當改變版本號是,發出警告信息。
LD_PRELOAD 首先裝入用戶定義的庫,使得它們有機會覆蓋或者重新定義標准庫。
使用空格分開多個入口。對於設置用戶 ID 或者進程 ID 的程序,
只有被標記過的庫才被首先裝入。在 /etc/ld.so.perload 中指定
了全局版本號,該文件不遵守這個限制。
4. 使用 dlopen
另外一個強大的庫函數是 dlopen()。該函數將打開一個新庫,並把它裝入內存。該函數主要用來載入庫中的符號,這些符號在編譯的時候是不知道的。比如 Apache Web 伺服器利用這個函數在運行過程中載入模塊,這為它提供了額外的能力。一個配置文件控制了載入模塊的過程。這種機制使得在系統中添加或者刪除一個模塊時,都不需要重新編譯了。
可以在自己的程序中使用 dlopen()。dlopen() 在 dlfcn.h 中定義,並在 dl 庫中實現。它需要兩個參數:一個文件名和一個標志。文件名可以是我們學習過的庫中的 soname。標志指明是否立刻計算庫的依賴性。如果設置為 RTLD_NOW 的話,則立刻計算;如果設置的是 RTLD_LAZY,則在需要的時候才計算。另外,可以指定 RTLD_GLOBAL,它使得那些在以後才載入的庫可以獲得其中的符號。
當庫被裝入後,可以把 dlopen() 返回的句柄作為給 dlsym() 的第一個參數,以獲得符號在庫中的地址。使用這個地址,就可以獲得庫中特定函數的指針,並且調用裝載庫中的相應函數。
② Linux .so庫的使用
新建一個sort.c文件,寫一個最簡單的排序
使用 gcc -o libsort.so -fPIC -shared sort.c 產生libsort.so庫。
.so庫有兩種調用方法:
新建main.c文件:
使用命令 gcc -o main main.c -lsort -L. 編譯。
新建main2.c文件:
使用命令 gcc -o main2 main2.c -ldl 編譯。動態載入.so庫的話需要-ldl。
運行./main2後輸出遞增序列,調用成功。
③ gcc 生成動態庫時-fpic選項是什麼意思
使用 -fPIC 選項,會生成 PIC 代碼。.so 要求為 PIC,以達到動態鏈接的目的,否則,無法實現動態鏈接。x0dx0anon-PIC 與 PIC 代碼的區別主要在於 access global data, jump label 的不同。x0dx0a比如一條 access global data 的指令,x0dx0anon-PIC 的形勢是:ld r3, var1x0dx0aPIC 的形式則是:ld r3, var1-offset@GOT,意思是從 GOT 表的 index 為 var1-offset 的地方處x0dx0a指示的地址處裝載一個值,即 var1-offset@GOT 處的4個 byte 其實就是 var1 的地址。這個地址只有在運行的時候才知道,x0dx0a是由 dynamic-loader(ld-linux.so) 填進去的。x0dx0a再比如 jump label 指令x0dx0anon-PIC 的形勢是:jump printf ,意思是調用 printf。x0dx0aPIC 的形式則是:jump printf-offset@GOT,意思是跳到 GOT 表的 index 為 printf-offset 的地方處x0dx0a指示的地址去執行,這個地址處的代碼擺放在 .plt section,每個外部函數對應一段這樣的代碼,其功能是呼叫x0dx0adynamic-loader(ld-linux.so) 來查找函數的地址(本例中是 printf),然後將其地址寫到 GOT 表的 index 為 printf-offset 的地方,x0dx0a同時執行這個函數。這樣,第2次呼叫 printf 的時候,就會直接跳到 printf 的地址,而不必再查找了。x0dx0aGOT 是 data section, 是一個 table, 除專用的幾個 entry,每個 entry 的內容可以再執行的時候修改;x0dx0aPLT 是 text section, 是一段一段的 code,執行中不需要修改。x0dx0a每個 target 實現 PIC 的機制不同,但大同小異。x0dx0a比如 MIPS 沒有 .plt, 而是叫 .stub,功能和 .plt 一樣。
④ linux有什麼命令可以提取指定的字元串
1. 例子
提取字元串以下字元串 error: 與 : 之間的子字元串。並消除空格。
"src/network/misc/nv_net_udp.c:17:fatalerror:nv_net_tools.h:Nosuchfileordirectory"1
2. 命令
echo"src/network/misc/nv_net_udp.c:17:fatalerror:nv_net_tools.h:Nosuchfileordirectory"|sed-r's/.*error:(.*):.*/1/'|seds/[[:space:]]//g1
該命令涉及 sed 命令的』反向引用』章節, 1 代表 (.*)
3. 結果
nv_net_tools.h1
4. 拓展 : 解決編譯錯誤
leon$makeclean&&makeallarm-hisiv100nptl-linux-gcc-c-fPIC-Wall-g-ggdb-O0-DHI3518_CHIP-DLINUX-I./src/include-I./src/include/common-I./src/include/camera-I./src/include/conf-I./src/include/log-I./src/include/network-I./src/include/upnp-I/home/leon/nvc/arm-hisiv100nptl-linux/includesrc/common/nv_conf.c-obuild/objs/hi3518/src/common/nv_conf.o/*省略中間部分*/arm-hisiv100nptl-linux-gcc-c-fPIC-Wall-g-ggdb-O0-DHI3518_CHIP-DLINUX-I./src/include-I./src/include/common-I./src/include/camera-I./src/include/conf-I./src/include/log-I./src/include/network-I./src/include/upnp-I/home/leon/nvc/arm-hisiv100nptl-linux/includesrc/network/misc/nv_net_udp.c-obuild/objs/hi3518/src/network/misc/nv_net_udp.o
src/network/misc/nv_net_udp.c:17:fatalerror:nv_net_tools.h:Nosuchfileordirectory
compilationterminated.make:***[build/objs/hi3518/src/network/misc/nv_net_udp.o]Error112345678
note: 在以上編譯過程中我們發現,編譯器提示說找不到nv_net_tools.h文件,而現實中我們也不需要這個文件的包含了,需要刪除包含nv_net_tools.h 文件中的該行代碼。
5.字元串提取 (命令行)
目標字元串
"from":"0802070975","to":"0802071013","url":"http://cn.update.mynetvue.com:8060/firmware/.tar.gz","md5":"","level":012
需要提取 from , to, url , md5, level 等5個關鍵字後面的內容。
//提取 from 內容echo
"from":"0802070975","to":"0802071013","url":"http://cn.update.mynetvue.com:8060/firmware/.tar.gz","md5":"","level":0|sed"s/.*from:(.*)/1/"|cut-d','-f1
//提取 to 內容echo
"from":"0802070975","to":"0802071013","url":"http://cn.update.mynetvue.com:8060/firmware/.tar.gz","md5":"","level":0|sed"s/.*to:(.*)/1/"|cut-d','-f1
//提取 url 內容echo
"from":"0802070975","to":"0802071013","url":"http://cn.update.mynetvue.com:8060/firmware/.tar.gz","md5":"","level":0|sed"s/.*url:(.*)/1/"|cut-d','-f1
//提取 md5 內容echo
"from":"0802070975","to":"0802071013","url":"http://cn.update.mynetvue.com:8060/firmware/.tar.gz","md5":"","level":0|sed"s/.*md5:(.*)/1/"|cut-d','-f1
//提取 level 內容echo
"from":"0802070975","to":"0802071013","url":"http://cn.update.mynetvue.com:8060/firmware/.tar.gz","md5":"","level":0|sed"s/.*level:(.*)/1/"|cut-d','-f112345678910111213141516
6.字元串提取 (腳本文件)
ret_val=""from":"0804020982","to":"0804020998","url":"http://cn.update.mynetvue.com:8060/firmware/.tar.gz","md5":"","level":0"
echoret_valis:[$ret_val]from="$(echo$ret_val|sed's/.*from":(.*)/1/'|cut-d','-f1|sed's/"//g')"
echofrom:$from
to="$(echo$ret_val|sed's/.*to":(.*)/1/'|cut-d','-f1|sed's/"//g')"
echoto:$to
url="$(echo$ret_val|sed's/.*url":(.*)/1/'|cut-d','-f1|sed's/"//g')"
echourl:$url
md5="$(echo$ret_val|sed's/.*md5":(.*)/1/'|cut-d','-f1|sed's/"//g')"
echomd5:$md5
level="$(echo$ret_val|sed's/.*level":(.*)/1/'|cut-d','-f1|sed's/"//g')"
echolevel:$
執行結果:
ret_valis:["from":"0804020982","to":"0804020998","url":"http://cn.update.mynetvue.com:8060/firmware/.tar.gz","md5":"","level":0]
from:0804020982
to:0804020998
url:http://cn.update.mynetvue.com:8060/firmware/.tar.gzmd5:
level:0
I.總結
要注意命令行執行,與腳本文件執行之間的差異性。
⑤ matlab在linux下生成的動態鏈接庫怎麼用
動態庫的生成
1>首先生成目標文件,但是此時要加編譯器選項-fpic和鏈接器選項-shared,
gcc -fpic -c add.c
gcc -fpic -c sub.c
生成中間文件add.o和sub.o
2>其次生成動態庫
gcc -shared –o libtiger.so add.o sub.o
生成動態庫libtiger.so,libtiger.so就是我們生成的目標動態庫。我們以後使用動態庫和main.c程序生成可執行程序
說明:
以上兩部也可以合成一步搞定:
gcc -fpic -shared add.c sub.c -o libtiger.so
2.使用動態鏈接庫
在編譯程序時,使用動態鏈接庫和靜態庫是一致的,使用」-l庫名」的方式,在生成可執行文件的時候會鏈接庫文件。
1>使用命令:
gcc -o main main.c -L ./ -ltiger
2>-L指定動態鏈接庫的路勁,-ldtiger鏈接庫函數tiger。-ltiger是動態庫的調用規則。Linux系統下的動態庫命名方式是lib*.so,而在鏈接時表示位-l*,*是自己命名的庫名。
3>但是程序會提示如下錯誤
error while loading shared libraries: libtiger.so: cannot open shared object file: No such file or direct
這是因為程序運行時沒有找到動態鏈接庫造成的。程序編譯時鏈接動態庫和運行時使用動態鏈接庫的概念是不同的,在運行時,程序鏈接的動態鏈接庫需要在系統目錄下才行。
4>使用以下方法可以解決此問題
a. 在linux下最方便的解決方案是拷貝libtiger.so到絕對目錄 /lib 下(但是,要是超級用戶才可以,因此要使用sudo哦,親)。就可以生成可執行程序了
b.第二種方法是:將動態鏈接庫的目錄放到程序搜索路徑中,可以將庫的路徑加到環境變數LD_LIBRARY_PATH中實現:
export LD_LIBRARY_PATH=`pwd`:$LD_LIBRARY_PATH
⑥ 面試 | Linux 下的動態鏈接庫問題
在 Linux 開發時,我們經常會看到一些形如 xxx.so 的名稱出現,其中 so 是 Shared Object 的縮寫,即可以共享的目標文件,也就是我們所稱為的動態鏈接庫,和在 Windows 下大家玩 游戲 時遇到的 xxx.dll 錯誤中的文件是一個類型的。
面試中經常會問到以下問題:
庫是寫好的現有的,成熟的,可以復用的代碼。現實中每個程序都要依賴很多基礎的底層庫,不可能每個人的代碼都從零開始,因此庫的存在意義非同尋常。本質上來說庫是一種可執行代碼的二進制形式,可以被操作系統載入內存執行。
庫有兩種:
在一個程序的編譯過程中,分為以下幾個步驟: 預處理 , 編譯 , 匯編 , 鏈接 。本文中討論的鏈接庫就是針對最後一個步驟「鏈接」而言的。
動態庫和靜態庫的區別
左圖為靜態鏈接庫,右圖為動態鏈接庫
對於靜態鏈接庫而言在鏈接階段,會將匯編生成的「目標文件.o」與引用到的庫一起鏈接打包到可執行文件中。因此對應的鏈接方式稱為靜態鏈接:
靜態鏈接可以理解為最後生成了一個「單文件免安裝綠色版」的程序,優點在於移植的時候只需要移動這一個文件,缺點在於文件體積非常大,為了解決這樣的問題,就有了動態鏈接庫。動態鏈接庫在程序編譯時並不會被連接到目標代碼中,而是在程序運行時才被載入。
動態庫連接到系統空間,如果多個程序連接了同一個庫,那麼只需要一份,優點在於編譯程序的時候不會將對應的庫文件全部打包在生成的程序中,而是保留了到對應庫的鏈接,缺點就是移植的時候如果只移動了對應的程序沒有安裝相關的庫的話,就會看到類似以下喜聞樂見的結果了。
在 Linux 下一個動態庫有y三個不同名字的文件組成:
當程序在內部列出所需要的鏈接庫時,僅僅使用 soname。當你創建一個鏈接庫時,使用 real name。安裝一個新的鏈接庫時,把它復制到一個DLL文件夾里,然後運行程序 ldconfig。ldconfig 檢查存在的 real name 文件,並且創建指向它符號鏈接 soname 文件。可能大家比較常見到的有 libsodium 等。
有了上面關於庫的一些基礎知識之後,我們可以開始嘗試創建一個動態庫來供程序使用了。
比如我們有一個求最大值的函數 max(int a,int b,int c) ,放在文件 max.c 中文件內容如下:
可以通過:
將其編譯為共享庫,-fPIC是編譯選項,PIC是 Position Independent Code 的縮寫,表示要生成位置無關的代碼,這是動態庫需要的特性; -shared是鏈接選項,告訴 gcc 生成動態庫而不是可執行文件。為了讓用戶知道我們的動態庫中有哪些介面可用,我們需要編寫對應的頭文件,比如可以寫一個 max.h :
設置一個驅動函數來測試我們編寫的動態庫:
通過 gcc test.c -L. -lmax來生成 a.out,其中-lmax表示要鏈接 libmax.so,-L.表示搜索要鏈接的庫文件時包含當前路徑。
但是這樣直接運行的話,會出現一個錯誤:
由於 Linux 是通過/etc/ld.so.cache文件搜尋要鏈接的動態庫的,而 /etc/ld.so.cache 是 ldconfig 程序讀取 /etc/ld.so.conf 文件生成的,本次使用的動態庫 libmax.so 並不在對應的目錄下,就會導致程序無法找到對應的動態鏈接庫,這樣我們的解決方法有二:
小結
動態鏈接庫是各個系統中的一個重要的組成部分且在 Linux 開發相關領域中尤為重要,也是一個面試的高頻考點,除了動態鏈接庫以外,還有以下相關知識也是高頻考點,在面試前一定要准備好:
本文作者:Nova Kwok