GCC制作Library---shared 部分相当不错

原帖地址http://blog.csdn.net/alex_ww/archive/2009/09/12/4544207.aspx

Library   可分成三种,   static     shared     dynamically loaded    

1. Static libraries

Static 
链接库用于静态链接,简单讲是把一堆   object   檔用   ar(archiver)   包装集合起来,文件名以   `.a'  结尾。优点是执行效能通常会比后两者快,而且因为是静态链接,所以不易发生执行时找不到   library   或版本错置而无法执行的问题。缺点则是档案较大,维护度较低;例如   library   如果发现   bug   需要更新,那么就必须重新连结执行档。  

1.1  编译  

编译方式很简单,先例用   `-c'  编出   object  檔,再用   ar  包起来即可。  

____ hello.c ____
#include
void hello(){ printf("Hello "); }

____ world.c ____
#include
void world(){ printf("world."); }

____ mylib.h ____
void hello();
void world();

$ gcc -c hello.c world.c /* 
编出   hello.o    world.o */
$ ar rcs libmylib.a hello.o world.o /* 
包成   limylib.a */

这样就可以建出一个档名为   libmylib.a  的檔。输出的档名其实没有硬性规定,但如果想要配合   gcc    '-l'  参数来连结,一定要以   `lib'  开头,中间是你要的   library   名称,然后紧接着   `.a'  结尾。  

1.2  使用  

____ main.c ____
#include "mylib.h"
int main() {
hello();
world();
}

使用上就像与一般的   object  档连结没有差别。  

$ gcc main.c libmylib.a

也可以配合   gcc    `-l'  参数使用  

$ gcc main.c -L. -lmylib

`-Ldir' 
参数用来指定要搜寻链接库的目录,   `.'  表示搜寻现在所在的目录。通常默认会搜   /usr/lib    /lib  等目录。  
`-llibrary'  参数用来指定要连结的链接库     'mylib'  表示要与   mylib   进行连结,他会搜寻   library   名称前加   `lib'   后接   `.a'   的档案来连结。  

$ ./a.out
Hello world.


2. Shared libraries

Shared library 
会在程序执行起始时才被自动加载。因为链接库与执行档是分离的,所以维护弹性较好。有两点要注意,   shared library   是在程序起始时就要被加载,而不是执行中用到才加载,而且在连结阶段需要有该链接库才能进行连结。  

首先有一些名词要弄懂,   soname     real name     linker name    

soname 
用来表示是一个特定   library  的名称,像是   libmylib.so.1  。前面以   `lib'  开头,接着是该   library  的名称,然后是   `.so'  ,接着  
是版号,用来表名他的界面;如果接口改变时,就会增加版号来维护兼容度。  

real name 
是实际放有   library   程序的文件名,后面会再加上   minor  版号与  
release 
版号,像是   libmylib.so.1.0.0   

一般来说,版号的改变规则是   (   印象中在   APress-Difinitive Guide to GCC   中有提到,但目前手边没这本书   )   ,最后缀的   release   版号用于程序内容的修正,接口完全没有改变。中间的   minor   用于有新增加接口,但相旧接口没改变,所以与旧版本兼容。最前面的   version   版号用于原接口有移除或改变,与旧版不兼容时。  

linker name   是用于连结时的名称,是不含版号的   soname  ,如   : libmylib.so    
通常   linker name     real name   是用   ln  指到对应的   real name  ,用来提供弹性与维护性。  

2.1 
编译  
shared library
  的制作过程较复杂。  

$ gcc -c -fPIC hello.c world.c

编译时要加上   -fPIC  用来产生   position-independent code   。也可以用   -fpic   参数。   (   不太清楚差异,只知道   -fPIC  较通用于不同平台,但产生的   code   较大,而且编译速度较慢   )    

$ gcc -shared -Wl,-soname,libmylib.so.1 -o libmylib.so.1.0.0 /
hello.o world.o

-shared 
表示要编译成   shared library
-Wl 
用于参递参数给   linker   ,因此   -soname     libmylib.so.1   会被传给   linker   处理。  
-soname
  用来指名   soname    limylib.so.1
library
  会被输出成   libmylib.so.1.0.0 (   也就是   real name)

若不指定   soname  的话,在编译结连后的执行档会以连时的   library   档名为   soname   ,并载入他。否则是载入   soname   指定的   library   档案。  

可以利用   objdump  来看   library    soname    

$ objdump -p libmylib.so | grep SONAME
SONAME libmylib.so.1

若不指名   -soname   参数的话,则   library   不会有这个字段数据。  

在编译后再用   ln  来建立   soname    linker name  两个档案。  
$ ln -s libmylib.so.1.0.0 libmylib.so
$ ln -s libmylib.so.1.0.0 libmylib.so.1


2.2 
使用  

与使用   static library  同。  

$ gcc main.c libmylib.so

以上直接指定与   libmylib.so  连结。  

或用  

$ gcc main.c -L. -lmylib

linker
  会搜寻   libmylib.so  来进行连结。  

如果目录下同时有   static     shared library   的话,会以   shared   为主。  
使用   -static  参数可以避免使用   shared   连结。  

$ gcc main.c -static -L. -lmylib

此时可以用   ldd  看编译出的执行档与   shared   链接库的相依性  
$ldd a.out
linux-gate.so.1 => (0xffffe000)
libmylib.so.1 => not found
libc.so.6 => /lib/libc.so.6 (0xb7dd6000)
/lib/ld-linux.so.2 (0xb7f07000)
输出结果显示出该执行文件需要   libmylib.so.1  这个   shared library    
会显示   not found  因为没指定该   library   所在的目录,所找不到该   library    

因为编译时有指定   -soname   参数为   libmylib.so.1  的关系,所以该执行档会加载   libmylib.so.1   。否则以   libmylib.so   连结,执行档则会变成要求加载   libmylib.so

$ ./a.out
./a.out: error while loading shared libraries: libmylib.so.1:
cannot open shared object file: No such file or directory

因为找不到   libmylib.so.1  所以无法执行程序。  
有几个方式可以处理。  

a. 
  libmylib.so.1  安装到系统的   library   目录,如   /usr/lib    
b. 
设定   /etc/ld.so.conf  ,加入一个新的   library   搜寻目录,并执行   ldconfig
更新快取  
c. 
设定   LD_LIBRARY_PATH  环境变量来搜寻   library
这个例子是加入当前目录来搜寻要载作的   library
$ LD_LIBRARY_PATH=. ./a.out
Hello world.

3. Dynamically loaded libraries

Dynamicaaly loaded libraries 
才是像   windows  所用的   DLL  ,在使用到  
时才加载,编译连结时不需要相关的   library   。动态载入库常被用于像   plug-ins  
的应用。  

3.1  使用方式  
动态加载是透过一套   dl function   来处理。  
#include
void *dlopen(const char *filename, int flag);
开启加载   filename  指定的   library    
void *dlsym(void *handle, const char *symbol);
取得   symbol  指定的   symbol name     library   被加载的内存地址。  
int dlclose(void *handle);
关闭   dlopen   开启的   handle    
char *dlerror(void);
传回最近所发生的错误讯息。  

____ dltest.c ____
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>

#include <dlfcn.h>

int main() {
void *handle;
void (*f)();
char *error;

/* 
开启之前所撰写的   libmylib.so  链接库   */
handle = dlopen("./libmylib.so", RTLD_LAZY);
if( !handle ) {
fputs( dlerror(), stderr);
exit(1);
}

/* 
取得   hello function    address */
f = dlsym(handle, "hello");
if(( error=dlerror())!=NULL) {
fputs(error, stderr);
exit(1);
}
/* 
呼叫该   function */
f();
dlclose(handle);
}

编译时要加上   -ldl  参数来与   dl library  连结  
$ gcc dltest.c -ldl
结果会印出   Hello  字符串  
$ ./a.out
Hello

关于   dl   的详细内容请参阅   man dlopen

--
参考数据   :

Creating a shared and static library with the gnu compiler [gcc]
http://www.adp-gmbh.ch/cpp/gcc/create_lib.html

Program Library HOWTO
http://tldp.org/HOWTO/Program-Library-HOWTO/index.html

APress - Definitive Guide to GCC

------------------------------------------------------------------------------------------------------------------

Makefile


GCC=gcc
CFLAGS=-Wall -fPIC
all: libmylib
libmylib:hello.o    world.o
    $(GCC) -shared -Wl,-soname,libmylib.so.1 -o libmylib.so.1.0.0 hello.o world.o
    ln -sf libmylib.so.1.0.0 libmylib.so
    ln -sf libmylib.so.1.0.0 libmylib.so.1
%.o:%.c
    $(GCC) -c $(CFLAGS) -o $@ $<

clean:
    rm -fr *.o
    rm -fr *.so*

-------------------------------------------------------------------------------------------------------------------

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值