C語言三方庫的調用和編寫

來源:https://www.jianshu.com/p/d7c516f7433e

1. 三方庫相關指令

gcc -l

-l 參數就是用來指定程序要鏈接的庫,-l 參數緊接着就是庫名,那麼庫名跟真正的庫文件名有什麼關係呢?就拿數學庫來說,他的庫名是 m,他的庫文件名是 libm.so,很容易看出,把庫文件名的頭lib 和尾 .so 去掉就是庫名了。好了現在我們知道怎麼得到庫名, 當我們自已要用到一個第三方提供的庫名字 libtest.so,那麼我們只要把 libtest.so 拷貝到 /usr/lib 裏,編譯時加上 -ltest 參數,我們就能用上 libtest.so 庫了(當然要用 libtest.so 庫裏的函數,我們還需要與 libtest.so 配套的頭文件)

gcc -L

放在/lib 和 /usr/lib 和 /usr/local/lib裏的庫直接用-l參數就能鏈接了,但如果庫文件沒放在這三個目錄裏,而是放在其他目錄裏,這時我們只用-l參數的話,鏈接還是會出錯,出錯信息大概是:“/usr/bin/ld: cannot find -lxxx”,也就是鏈接程序 ld 在那3個目錄裏找不到libxxx.so。這時另外一個參數-L就派上用場了,比如常用的X11 的庫,它在 /usr/X11R6/lib 目錄下,我們編譯時就要用 -L/usr/X11R6/lib -lX11 參數,-L 參數跟着的是庫文件所在的目錄名。再比如我們把libtest.so 放在/aaa/bbb/ccc 目錄下,那鏈接參數就是 -L/aaa/bbb/ccc -ltest

gcc -I

-I 參數是用來指定頭文件目錄,/usr/include 目錄一般是不用指定的,gcc 知道去那裏找,但是如果頭文件不在 /usr/include 裏我們就要用 -I 參數指定了,比如頭文件放在/myinclude 目錄裏,那編譯命令行就要加上 -I/myinclude 參數了,如果不加你會得到一個 "xxxx.h: No such file or directory" 的錯誤。-I 參數可以用相對路徑,比如頭文件在當前目錄,可以用 -I. 來指定。

gcc –shared

-shared該選項指定生成動態連接庫(讓連接器生成T類型的導出符號表,有時候也生成弱連接W類型的導出符號),不用該標誌外部程序無法連接。相當於一個可執行文件

gcc -fPIC

-fPIC:表示編譯爲位置獨立的代碼,不用此選項的話編譯後的代碼是位置相關的所以動態載入時是通過代碼拷貝的方式來滿足不同進程的需要,而不能達到真正代碼段共享的目的。

使用ar 命令創建或者操作靜態庫
ar archivefile objfile

archivefile:archivefile 是靜態庫的名稱

objfile:objfile 是已.o 爲擴展名的中間目標文件名,可以多個並列參數 意義

-r 將objfile 文件插入靜態庫尾或者替換靜態庫中同名文件

-x 從靜態庫文件中抽取文件objfile

-t 打印靜態庫的成員文件列表

-d 從靜態庫中刪除文件objfile

-s 重置靜態庫文件索引

-v 創建文件冗餘信息

-c 創建靜態庫文件

2. 調用三方庫

使用數學庫libm 舉例

編譯:gcc -g -Wall -o test1 test1.c –lm

通過l 指令,將libm 鏈接進程序

[root@izbp1e2kit9gbr3xm1zerrz clib]# ./test1 The cosine of 60.000000 degrees is 0.500000.

[root@izbp1e2kit9gbr3xm1zerrz clib]# find / -name "libm*"|grep libm*.so

/usr/lib/i686/nosegneg/libm.so.6

/usr/lib/libm.so.6

/usr/lib64/libm.so.6

/usr/lib64/libm.so

/usr/share/ltrace/libm.so.conf [root@izbp1e2kit9gbr3xm1zerrz clib]# ldd ldd: missing file arguments

Try `ldd --help' for more information. [root@izbp1e2kit9gbr3xm1zerrz clib]# ldd test1

linux-vdso.so.1 => (0x00007ffd6716e000)

libm.so.6 => /lib64/libm.so.6 (0x00007f8d4da70000) libc.so.6 => /lib64/libc.so.6 (0x00007f8d4d6a3000)

/lib64/ld-linux-x86-64.so.2 (0x00007f8d4dd7d000)
#include <stdio.h> 
#include <stdlib.h>
#include <pthread.h>
#include <sys/syscall.h>
#include <sys/types.h>

#define MAX_NUM 1000

// thread callback

static void* _run(void* arg) { int piyo = 10;

char* name = (char*)arg; int i;

for(i = 0; i < MAX_NUM; ++i) {

printf("[thread %u]: <%d, hi!> from %s\n", syscall(SYS_gettid), i,

name);

sleep(1);

}

return NULL;

}

#define _INT_PTX (3)

char* thread_name[] = {"A", "B", "C", "D", "E", "F", "G", "H"};

int main(void) { int i;

pthread_t tx[_INT_PTX];

puts("main beign");

printf("main thread id :%u\n",/*syscall(SYS_gettid)*/getpid());

for(i=0; i<_INT_PTX; ++i) {

//create threads

rt = pthread_create(tx+i, NULL, _run, thread_name[i]); if(rt < 0) {

printf("pthread_create create error! rt = %d, i=%d\n", rt, i); break;

}

}

for(i=0; i<_INT_PTX; ++i) { pthread_join(tx[i], NULL);

}

puts("end");

return 0;

}

編譯命令

gcc -Wall -g -o FightingSaintBuddha.out FightingSaintBuddha.c -lpthread

3. 編寫三方庫

linux 下有兩種庫:動態庫和靜態庫(共享庫) 二者的不同點在於代碼被載入的時刻不同。

靜態庫的代碼在編譯過程中已經被載入可執行程序,因此體積比較大。

動態庫(共享庫)的代碼在可執行程序運行時才載入內存,在編譯過程中僅簡單的引用,因此代碼體積比較小。

不同的應用程序如果調用相同的庫,那麼在內存中只需要有一份該動態庫(共享庫)的實例。

靜態庫和動態庫的最大區別,靜態情況下,把庫直接加載到程序中,而動態庫鏈接的時候,它只是保留接口,將動態庫與程序代碼獨立,這樣就可以提高代碼的可複用度,和降低程序的耦合度。

靜態庫在程序編譯時會被連接到目標代碼中,程序運行時將不再需要該靜態庫。

動態庫在程序編譯時並不會被連接到目標代碼中,而是在程序運行是才被載入,因此在程序運行時還需要動態庫存在

自己編寫動態庫

不同的UNIX 系統,鏈接動態庫方法,實現細節不一樣

編譯PIC 型.o 中間文件的方法一般是採用 C 語言編譯器的-KPIC 或者-fpic 選項,有的

UNIX 版本C語言編譯器默認帶上了PIC標準.創建最終動態庫的方法一般採用C語言編譯器的-G或者-shared選項,或者直接使用工具ld創建。

最主要的是GCC 命令行的一個選項:

-shared該選項指定生成動態連接庫(讓連接器生成T類型的導出符號表,有時候也生成弱連接W類型的導出符號),不用該標誌外部程序無法連接。相當於一個可執行文件

-fPIC:表示編譯爲位置獨立的代碼,不用此選項的話編譯後的代碼是位置相關的所以動態載入時是通過代碼拷貝的方式來滿足不同進程的需要,而不能達到真正代碼段共享的目的。

-L.:表示要連接的庫在當前目錄中

-ltest:編譯器查找動態連接庫時有隱含的命名規則,即在給出的名字前面加上 lib,後面加上.so 來確定庫的名稱

LD_LIBRARY_PATH:這個環境變量指示動態連接器可以裝載動態庫的路徑。當然如果有 root 權限的話,可以修改/etc/ld.so.conf 文件,然後調用

/sbin/ldconfig 來達到同樣的目的,不過如果沒有 root 權限,那麼只能採用輸出

LD_LIBRARY_PATH 的方法了。


#ifndef  CACULATE_HEAD   #define  CACULATE_HEAD

//add

int add(int a, int b); int sub(int a, int b); int div(int a, int b); int mul(int a, int b);

#endif

#include "caculate.h"

int add(int a, int b)

{

return (a+b);

}

編譯生成 so

gcc -g -Wall -shared -fpic caculate.c -o libcac.so

gcc -g Wall test2.c -o test2 -L./-lcac

gcc -g -Wall test3.c -o test3.out -lbl

自己編寫靜態庫

使用ar命令創建或者操作靜態庫

gcc -o caculate.o -c caculate.c

ar -rcs libcac.a caculate.o

gcc -g -Wall test2.c -o test4.out -L.libcac.a

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章