UNIX环境下用C语言写静态库与动态库

静态库,动态库用UNIX 的术语来说,或者叫做归档文件(archive 常以.a 结尾)和共享对象(share object 常以lib 开头.so 结尾)更为准确。静态库,动态库可能是WINDOWS 下的术语,但两者的概念是一样的。下面统一说静态库和动态库。

静态库,就是一大堆object (CC ,CC 在LINUX 下其实是软件链接到GCC 的,编译后默认为.o 结尾的)的集合。静态库就是用ar 等工具集合在一起。在编译的时候,连接器就会将这部分代码嵌入到目标代码里。

动态库,也是一大堆object 的集合(编译成动态或静态,只是编译选项的不同)。不同的时,在编译的时候,连接器并没有将这部分代码嵌入到目标代码里,而在运行时的时候,才加载代码。

由此,一般情况下用静态库一般都比动态库大。

一、静态库编写

以简单起见,写个非常简单例子。

//hello.h

#ifndef _HELLO_H

#define _HELLO_H

void sayhello(const char* msg);

void saygoodbye(const char* msg);

#endif

//hello.c

#include "hello.h"

#include <unistd.h>

#include <string.h>

#include <stdio.h>

void sayhello(const char* msg)

{

char wel[] = "welcome to invoke sayhello function/n";

char hellomsg[BUFSIZ] = "hello, ";

write(STDOUT_FILENO, wel, strlen(wel)+1);

strcat(hellomsg, msg);

strcat(hellomsg, "/n");

write(STDOUT_FILENO, hellomsg, strlen(hellomsg)+1);

}

void saygoodbye(const char* msg)

{

char wel[] = "welcome to invoke saygoodbye function/n";

char goodbyemsg[BUFSIZ] = "goodbye, ";

write(STDOUT_FILENO, wel, strlen(wel)+1);

strcat(goodbyemsg, msg);

strcat(goodbyemsg, "/n");

write(STDOUT_FILENO, goodbyemsg, strlen(goodbyemsg)+1);

}

先编译

[[email protected] hellolib]$ gcc -Wall -c hello.c

上面命令将产生hello.o 的obj 文件。(PS 一下:注意到bogon 了吗?你可以猜测我的网络环境)。-Wall 表示打开所有的编译警告。-c 表示只编译不连接。

再创建静态库

[[email protected] hellolib]$ ar -cru libhello.a hello.o

一般库文件是以lib 开头的,链接的时候不必指定lib 前缀。-cru 表示创建并替换为最新的。具体各个参数参看ar 的man 页。为了方便,抄袭一些来,鲁迅说拿来主义。

Option Name Example

-d Delete ar -d <archive> <objects>

-r Replace ar -r <archive> <objects>

-t Table list ar -t <archive>

-x Extract ar -x <archive> <objects>

-v Verbose ar -v

-c Create ar -c <archive>

-ru Update object ar -ru <archive> <objects>

至此,文件如下

[[email protected] hellolib]$ ls

hello.c hello.h hello.o libhello.a

测试

//statictest.c

#include "hello.h"

int main(int argc, char**argv)

{

char msg[] = "heidong";

sayhello(msg);

saygoodbye(msg);

return 0;

}

编译

[[email protected] hellolib]$ gcc -o statictest.o statictest.c -L. -lhello

-L. 表示将当前目录添加到库查找目录里。系统标准的库目录是/usr/lib, /lib, /usr/local/lib 等等。-lhello 表示连接libhello 这个静态库。

测试

[[email protected] hellolib]$ ./statictest.o

welcome to invoke sayhello function

hello, heidong

welcome to invoke saygoodbye function

goodbye, heidong

工作了。

二、动态库

代码依然是用上面的,但是编译的选项却不同。

编译

[[email protected] hellolib]$ gcc -c hello.c -fPIC

[[email protected] hellolib]$ gcc -shared hello.o -o libhello.so

[[email protected] hellolib]$ gcc -o statictest.o statictest.c -L. -lhello

-fPIC 表示位置独立的。具体是什么的缩写不知道。第一行生成 hello.o ,第二行将生成动态库libhello.so 。第三行的意思我上面所说的一样。

测试

[[email protected] hellolib]$ ./statictest.o

./statictest.o: error while loading shared libraries: libhello.so: cannot open shared object file: No such file or directory

咦,出错,原因就是找不到 libhello.so 这个动态库。有两个解决办法。第一,最简单的就是将库文件复制到系统库目录。需要根用户权限。第二种办法,添加 LD_LIBRARY_PATH 环境变量为所在库的目录。

再次测试

[[email protected] hellolib]$ export LD_LIBRARY_PATH=./

[[email protected] hellolib]$ ./statictest.o

welcome to invoke sayhello function

hello, heidong

welcome to invoke saygoodbye function

goodbye, heidong

Ok 啦。

可以用ldd 查看依赖于哪些库。

[[email protected] hellolib]$ ldd statictest.o

linux-gate.so.1 => (0x00ddf000)

libhello.so => ./libhello.so (0x00e98000)

libc.so.6 => /lib/libc.so.6 (0x00b2a000)

/lib/ld-linux.so.2 (0x00232000)

可见,除了我们的库外,还有额外三个。 libc.so.6 为标准C 的库, lib/ld-linux.so.2为动态连接/加载的库。至于第一个,不太清楚,网上说是“linux-gate.so.1 文件目前在文件系统中根本就不被支持  它只是一个虚拟的DSO (译者注virtual DSO :dynamically shared object ),一个在每个进程的存储空间(process’ memory )指定的地址点被内核暴露出来的共享对象”

三、运行时加载动态库

就是在程序运行的过程中动态地加载动态库(和WINDOWS 下的LoadLibrary 一样)。四个关键的函数:

#include <dlfcn.h>

void *dlopen( const char *filename, int flag );

const char *dlerror( void );

void *dlsym( void *handle, char *symbol );

int dlclose( void *handle );

例子:

#include <unistd.h>

#include <stdio.h>

#include <dlfcn.h>

#include <stdlib.h>

int main(int argc, char**argv)

{

void (*sayhello)(const char*);

void (*saygoodbye)(const char*);

void* handle = NULL;

char* err;

handle = dlopen("libhello.so", RTLD_LAZY);

if(handle == NULL){

fprintf(stderr, "%s/n", dlerror());

exit(-1);

}

sayhello = dlsym(handle, "sayhello");

err = dlerror();

if(err != NULL){

fprintf(stderr, "%s/n", err);

}else{

sayhello("heidong");

}

saygoodbye = dlsym(handle, "saygoodbye");

err = dlerror();

if(err != NULL){

fprintf(stderr, "%s/n", err);

}else{

saygoodbye("heidong");

}

saygoodbye = dlsym(handle, "sssssssaygoodbye");

err = dlerror();

if(err != NULL){

fprintf(stderr, "%s/n", err);

}else{

saygoodbye("heidong");

}

dlclose(handle);

return 0;

}

编译+测试

[[email protected] hellolib]$ gcc -Wall -ldl dynamicload.c -o dynamicload.out

[[email protected] hellolib]$ ./dynamicload.out

welcome to invoke sayhello function

hello, heidong

welcome to invoke saygoodbye function

goodbye, heidong

./libhello.so: undefined symbol: sssssssaygoodbye

[[email protected] hellolib]$

最后一个没有,所以出错。

四、一些常用工具

4.1 file, 测试文件类型:

[[email protected] hellolib]$ file libhello.so

libhello.so: ELF 32-bit LSB shared object, Intel 80386, version 1 (SYSV), not stripped

[[email protected] hellolib]$ file statictest.o

statictest.o: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), for GNU/Linux 2.6.9, dynamically linked (uses shared libs), for GNU/Linux 2.6.9, not stripped

[[email protected] hellolib]$

4.2 size 测试可执行文件的代码。

[[email protected] hellolib]$ size statictest.o

text data bss dec hex filename

1167 264 8 1439 59f statictest.o

text 为代码段,data 为已经初始化的变量,bbs 为未初始为的变量。Dec 和hex 分别为前三个之和的十进制和十六进制表示。

4.3 nm 查看有哪些导出函数。

[[email protected] hellolib]$ nm libhello.so | grep " T "

00000784 T _fini

00000308 T _init

000005cb T saygoodbye

0000046c T sayhello

4.4 objdump 类似windows 下的dumpbin 。

[[email protected] hellolib]$ objdump -d libhello.so

libhello.so: file format elf32-i386

Disassembly of section .init:

00000308 <_init>:

308: 55 push %ebp

309: 89 e5 mov %esp,%ebp

30b: 83 ec 08 sub $0x8,%esp

时间: 2024-07-28 16:54:48

UNIX环境下用C语言写静态库与动态库的相关文章

UNIX环境下的命令行调试工具: gdb

UNIX环境下的命令行调试工具: gdb 如果需要使用gdb调试程序,请在gcc时加上-g选项. 下面的命令部分是简化版,比如使用l代替list等等. 1.基本命令 1)进入GDB #gdb test test是要调试的程序,由gcc test.c -g -o test生成.进入后提示符变为(gdb) . 2)查看源码 (gdb) l 源码会进行行号提示. 如果需要查看在其他文件中定义的函数,在l后加上函数名即可定位到这个函数的定义及查看附近的其他源码.或者:使用断点或单步运行,到某个函数处使用

在vs 2015环境下,c语言和汇编混编操作简析(更新中......)

在VS 2015环境下如何混编. 在新建工程里也会发现了很多问题, 应用程序类型分为:windows应用程序,控制台应用程序,DLL,静态库 静态库: 静态库是指在我们的应用中,有一些公共代码是需要反复使用,就把这些代码编译为"库"文件:在链接步骤中,连接器将从库文件取得所需的代码,复制到生成的可执行文件中的这种库. 程序编译一般需经预处理.编译.汇编和链接几个步骤.静态库特点是可执行文件中包含了库代码的一份完整拷贝:缺点就是被多次使用就会有多份冗余拷贝. 静态库和动态库是两种共享程序

在windows下用C语言写socket通讯实例

原文:在windows下用C语言写socket通讯实例 From:Microsoft Dev Center #undef UNICODE #define WIN32_LEAN_AND_MEAN #include <windows.h> #include <winsock2.h> #include <ws2tcpip.h> #include <stdlib.h> #include <stdio.h> // Need to link with Ws2

每天一点GO语言——Linux环境下安装Go语言环境以及编写Go语言程序初体验

每天一点GO语言--Linux环境下安装Go语言环境以及编写Go语言程序初体验 一.安装Go语言环境 [[email protected] opt]# yum -y install wget git [[email protected] opt]# wget -c https://studygolang.com/dl/golang/go1.10.3.linux-amd64.tar.gz [[email protected] opt]# tar -zxvf go1.10.3.linux-amd64

Linux下Gcc生成和使用静态库和动态库详解

参考文章:http://blog.chinaunix.net/uid-23592843-id-223539.html 一.基本概念 1.1什么是库 在windows平台和linux平台下都大量存在着库. 本质上来说库是一种可执行代码的二进制形式,可以被操作系统载入内存执行. 由于windows和linux的平台不同(主要是编译器.汇编器和连接器的不同),因此二者库的二进制是不兼容的. 本文仅限于介绍linux下的库. 1.2库的种类 linux下的库有两种:静态库和共享库(动态库). 二者的不同

Linux编译多个不同目录下的文件以及静态库、动态库的使用

先看两篇博文,作为基础知识.如果对C/C++编译链接过程都了解的话,可以跳过不看. http://www.firedragonpzy.com.cn/index.php/archives/2556 http://www.cppblog.com/shifan3/archive/2007/01/05/17325.html 一.  编译不同目录下的多个文件 各个文件的布局如下: head.h文件的代码: [cpp] view plaincopy #ifndef  HEAD_H #define  HEAD

【转】Linux下gcc生成和使用静态库和动态库详解

一.基本概念 1.1 什么是库 在Windows平台和Linux平台下都大量存在着库. 本质上来说,库是一种可执行代码的二进制形式,可以被操作系统载入内存执行. 由于windows和linux的平台不同(主要是编译器.汇编器和连接器的不同),因此二者的库的二进制是不兼容的. 本文仅限于介绍linux下的库. 1.2 库的种类 linux下的库有两种:静态库和共享库(动态库). 二者的不同点在于代码被载入的时刻不同. 静态库的代码在编译过程中已经被载入可执行程序,因此体积较大. 共享库的代码是在可

[转]Linux下用gcc/g++生成静态库和动态库(Z)

Linux下用gcc/g++生成静态库和动态库(Z) 2012-07-24 16:45:10|  分类: linux |  标签:链接库  linux  g++  gcc  |举报|字号 订阅 在 linux 下,库文件一般放在 /usr/lib 和 /lib 下, 静态库的名字一般为 libxxxx.a ,其中 xxxx 是该 lib 的名称 动态库的名字一般为 libxxxx.so.major.minor , xxxx 是该 lib 的名称, major 是主版本号, minor 是副版本号

Linux下静态库与动态库

一.基本概念 1.1.什么是库        在 windows 平台和 linux 平台下都大量存在着库. 本质上来说库是一种可执行的二进制代码(但不可以独立执行),可以被操作系统载入内存执行. 由于 windows 和 linux 的平台不同(主要是编译器.汇编器和连接器 的不同),因此二者库的二进制是不兼容的. 本文仅限于介绍 linux 下的库. 1.2. 库的种类 linux下的库有两种:静态库和共享库(动态库). 二者的不同点在于代码被载入的时刻不同: 静态库的代码在编译过程中已经被