Linux系統下,進入一個lib目錄,通常會看到有兩種libraries:.a的static library,.so的shared library。so是shared object的首字母。static library在編譯/連接的時候,會被合併到可執行文件裡。所以,編譯時要有.a,但執行時無須有.a文件。shared library在編譯時沒有併入可執行文件。如果用到shared library,那麼執行時必須要讓系統能找到這個shared library。

一、文件名

libevdocument.a
libevdocument.so (符號連接,連到libevdocument.so.2.0.0)
libevdocument.so.2 (符號連接,連到libevdocument.so.2.0.0) (有人稱它為soname)
libevdocument.so.2.0.0 (有人稱它為real name)
第一個文件是static library,第二個供連接器ld使用(當你用-l參數時),第三個供dynamic loader使用,第四個才是實際的shared library文件。
2.0.0是版本號。如果可執行文件要求動態連接到libevdocument.so.2,那麼libevdocument.so.2.1應該要能滿足它的要求,只要大版本號一致,接口應該不變。而libevdocument.so.1和libevdocument.so.2的接口就不一定一樣。

二、執行時

ldd foo
可以查看執行foo需要用到哪些shared libraries. (foo為可執行文件的文件名)

shared library是通過dynamic loader(或者叫dynamic linker)來load的。dynamic loader的路徑是寫在每個可執行文件裡的。可用readelf -l foo | grep interpreter來查看,通常是
/lib/ld-linux.so.2
(這是編譯可執行文件時,由gcc的SPECS決定的。)

在可執行文件被執行前,操作系統會先調用dynamic loader,也就是ld-linux.so.2,後者會根據可執行文件裡的庫名稱(也就是soname,例如libhello.so.1)來尋找相應的shared library。搜索路徑的順序是:
1. LD_LIBRARY_PATH
2. 可執行文件包含的RPATH
    *要生成帶有RPATH的可執行文件:在連接時加上參數-R /home/lws/lib
    *用readelf -d foo | grep RPATH可以查看可執行文件的RPATH。
3. 配置文件ld.so.conf指定的目錄,例如/usr/lib/local。
4. 系統默認的/lib,/usr/lib。

三、如果要自己寫library,請看這裡

編譯library,源代碼沒什麼特別的。都是先用gcc -c編譯成.o文件。
要static library用ar命令打包成.a文件。
ar rcs libmylib.a hello.o world.o
要dynamic library
編譯.o時加-fPIC選項。然後用以下命令:
$ gcc -shared -Wl,-soname,libmylib.so.1 -o libmylib.so.1.0.0 hello.o world.o

###这里要说的是 "-Wl,-soname,libmylib.so.1" 它后面是连续的,不能分开,不然就出错;
其中-shared告訴gcc說要編譯shared library。
-Wl表示參數-soname,libmylib.so.1傳給連接器ld。相當於ld -soname libmylib.so.1。soname必須的,必須給.so文件添加soname。用$ objdump -p libmylib.so | grep SONAME可以查看soname。
問題:如果soname和文件名不符會怎樣?

四、使用library編譯其他程序時

包含相應的.h文件,或者聲明要用到的函數。然後:
$ gcc main.c  -lmylib
如果你的庫文件命名是以lib開頭,例如libhello.so.1或者libhello.a。連接的時候可以用-lhello參數。Linux的連接器 ld,會在搜索路徑理查找libhello.so和libhello.a。ld的搜索路徑是在配置、編譯ld源代碼的時候指定的,查看ld的搜索路徑,請 輸入:
ld –verbose | grep SEARCH
另外,也可以在gcc加上-L選項,臨時添加搜索目錄。所以,我把hello稱為libhello.so.1、libhello.a的 -l option 名,因為它只在-l選項裡用到。也有些人把它叫做linker name。
當然,不用-l參數也可以。可以直接給出庫文件名,例如假設libhello.so.1在當前路徑,那麼gcc foo libhello.so.1效果和gcc foo -L. -lhello一樣。

使用shared library,如果不想把它安裝到系統默認的library search path中。可以給連接器指定-R參數,例如:-R /home/lws/lib

举例:

 

#创建共享连接文件 项目运行时由系统加载程序加载

实例:

/* head.h */

#ifndef _HELLO_H_

#define _HELLO_H_

 

#include <stdio.h>

#include <stdlib.h>

 

extern void print_hello(void);

extern int getmax(int x, int y);

extern int getage(int age);

 

#endif

 

/* age.c */

#include "head.h"

 

int getage(int age)

{

    return age;

 

/* hello.c */

#include "head.h"

 

void print_hello()

{

    printf("Hello World!\n");

}

 

/* max.c */

#include "head.h"

 

int getmax(int x, int y)

{

    return (x>y?x:y);

}

 

/* test.c */

#include "head.h"

 

int main (int argc, char *argv[])

{

    int age = 23, x = 10, y = 30;

    print_hello();

    printf("max:%d\n", getmax(x, y));

    printf("age:%d\n", getage(age));

    return 0;

}

 

[root@linux-64 test.so]# gcc -shared -fpic -O2 -Wall -o libtest.so age.c hello.c max.c

[root@linux-64 test.so]# ls

head.h age.c hello.c max.c test.c libtest.so

#这里不需要头文件了,因为在创建库文件libtest.so时已经编译进去了;

[root@linux-64 test.so]# gcc -o test test.c ./libtest.so   

[root@linux-64 test.so]# ./test 

Hello World!

max:30

age:23

或者 将libtest.so放到/usr/lib64目录下 这样下面-I. -L.都不需要了;

[root@linux-64 test.so]# gcc -o test test.c -I. -L. -ltest   

# -I 表示要包含头文件的位置,-L 表示要包含库文件的位置,当前默认为当前目录;

[root@linux-64 test.so]# ./test 

Hello World!

max:30

age:23

 

#现在将libtest.so 拷贝到系统/usr/lib64目录下,并且将可执行文件test放在其他的目录下,直接运行也是成功的

[root@linux-64 test]# ./test

Hello World!

max:30

age:23

#但当删除/usrlib64/libtest.so文件再运行时就报如下错误:

[root@linux-64 test]# ./test

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

 

 

#注意不要将-fPIC写成-fpic

[root@linux-64 test.so]# gcc -fPIC -g -c -Wall age.c

[root@linux-64 test.so]# gcc -fPIC -g -c -Wall max.c 

[root@linux-64 test.so]# gcc -fPIC -g -c -Wall hello.c

[root@linux-64 test.so]# ls

age.c  age.o  head.h  hello.c  hello.o  libtest.so  max.c  max.o  test  test.c

#编译.so文件

[root@linux-64 test.so]# gcc -shared -Wl -soname libtest.so.1 -o libtest.so.1.0.1 age.o hello.o max.o -lc

gcc: libtest.so.1: No such file or directory

gcc: unrecognized option '-soname'

[root@linux-64 test.so]# gcc -shared -Wl, -soname, libtest.so.1 -o libtest.so.1.0.1 age.o hello.o max.o -lc

gcc: libtest.so.1: No such file or directory

gcc: unrecognized option '-soname,'

#注意这里-Wl和后面的,-soname,libtest.so是连在一起的,是它的参数,表示将参数传给连接器ld;相当于 ld -soname libtest.so.1;

[root@linux-64 test.so]# gcc -shared -Wl,-soname,libtest.so.1 -o libtest.so.1.0.1 age.o hello.o max.o -lc

[root@linux-64 test.so]# ls

age.c  age.o  head.h  hello.c  hello.o  libtest.so.1.0.0  max.c  max.o  test  test.c

#编译成静态库文件  – libtest.a

[root@linux-64 test.so]# ar rcs libtest.a age.o max.o hello.o

[root@linux-64 test.so]# ls

age.c  age.o  head.h  hello.c  hello.o  libtest.a  libtest.so.1.0.0  max.c  max.o  test  test.c

 

#详细介绍该方面的文档连接:

http://blog.sina.com.cn/s/blog_4b9b714a0100ieam.html




Related posts

coded by nessus
分享:  DeliciousGReader鲜果豆瓣CSDN网摘
Trackback

no comment untill now

Add your comment now

无觅相关文章插件