静态库和动态库
引言
将多个目标文件打包到一起,形成一个文件,叫库
库文件名字都是以lib开头的
本次我们将《UNIX环境高级编程》(第三版)的error.c源码打包成静态库或者动态库
#ifndef __ERROR_H__
#define __ERROR_H__
/**
* Nonfatal error related to a system call.
* Print a message and return.
*/
void err_ret(constchar*fmt,...);
/**
* Fatal error related to a system call.
* Print a message and terminate.
*/
void err_sys(constchar*fmt,...);
/**
* Nonfatal error unrelated to a system call.
* Error code passed as explict parameter.
* Print a message and return.
*/
void err_cont(int error,constchar*fmt,...);
/**
* Fatal error unrelated to a system call.
* Error code passed as explict parameter.
* Print a message and terminate.
*/
void err_exit(int error,constchar*fmt,...);
/**
* Fatal error related to a system call.
* Print a message, dump core, and terminate.
*/
void err_dump(constchar*fmt,...);
/**
* Nonfatal error unrelated to a system call.
* Print a message and return.
*/
void err_msg(constchar*fmt,...);
/**
* Fatal error unrelated to a system call.
* Print a message and terminate.
*/
void err_quit(constchar*fmt,...);
#endif/* __ERROR_H__ */
代码1 error.h头文件
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<errno.h>/* for definition of errno */
#include<stdarg.h>/* ISO C variable aruments */
#include"error.h"
#define MAXLINE 4096/* max line length */
staticvoid err_doit(int,int,constchar*, va_list);
void err_ret(constchar*fmt,...)
{
va_list ap;
va_start(ap, fmt);
err_doit(1, errno, fmt, ap);
va_end(ap);
}
void err_sys(constchar*fmt,...)
{
va_list ap;
va_start(ap, fmt);
err_doit(1, errno, fmt, ap);
va_end(ap);
exit(1);
}
void err_cont(int error,constchar*fmt,...)
{
va_list ap;
va_start(ap, fmt);
err_doit(1, error, fmt, ap);
va_end(ap);
}
void err_exit(int error,constchar*fmt,...)
{
va_list ap;
va_start(ap, fmt);
err_doit(1, error, fmt, ap);
va_end(ap);
exit(1);
}
void err_dump(constchar*fmt,...)
{
va_list ap;
va_start(ap, fmt);
err_doit(1, errno, fmt, ap);
va_end(ap);
abort();/* dump core and terminate */
exit(1);/* shouldn't get here */
}
void err_msg(constchar*fmt,...)
{
va_list ap;
va_start(ap, fmt);
err_doit(0,0, fmt, ap);
va_end(ap);
}
void err_quit(constchar*fmt,...)
{
va_list ap;
va_start(ap, fmt);
err_doit(0,0, fmt, ap);
va_end(ap);
exit(1);
}
staticvoid err_doit(int errnoflag,int error,constchar*fmt, va_list ap)
{
char buf[MAXLINE];
vsnprintf(buf, MAXLINE-1, fmt, ap);
if(errnoflag)
{
snprintf(buf+strlen(buf), MAXLINE-strlen(buf)-1,": %s",
strerror(error));
}
strcat(buf,"\n");
fflush(stdout);/* in case stdout and stderr are the same */
fputs(buf, stderr);
fflush(NULL);/* flushes all stdio output streams */
}
代码2. error.h的实现
静态库
静态库都是以.a作为后缀,表示Archive
例如: libmy.a (my就是库名)
创建静态库
编译
gcc -c -static a.c b.c ...
1) -static可选,可阻止gcc使用共享库
不使用共享库会使可执行文件变大,但会减少运行时间开销
2) 写头文件(里面是那些函数的声明)
源文件可以是多个或一个,里面是想要放到库中的函数的定义
打包
ar r libxxx.a a.o b.o ...
ar[选项] 归档文件名 目标文件列表
-r 将指定文件插入文档,如果存在则更新
示例: ar r libxxx.a *.o
-t 显示目标文件列表
示例: ar t libxxx.a
使用静态库
写调用源程序: main.c
第一种方式
gcc libxxx.a main.c(或者main.o) -o main
第二种方式
如果没有配置LIBRARY_PATH的环境变量,可以采用如下方式编译:
gcc -lxxx(静态库名) -LXXX(静态库所在的路径) main.c -o main
或者-l和xxx空一个空格
gcc -l xxx -L XXX main.c -o main
或者加-static选项
gcc -static -lxxx -LXXX main.c -o main
其中-static表示如果同时存在同名的动态库和静态库,使用静态库(默认使用动态库)
示例:
gcc main.c -lerror -Llib
第三种方式
如果libxxx.a在LIBRARY_PATH的指定目录中,还可以采用如下方式编译
gcc -lxxx main.c -o main
配置环境变量LIBRARY_PATH
export LIBRARY_PATH=库文件所在的路径
第三方静态库示例
sqrt函数
库: libm.a (/usr/lib/libm.a)
头文件: math.h (/usr/include/math.h)
静态库的优缺点
运行时不再依赖静态库,代码已经嵌入到可执行文件中
升级时需要重新编译链接
动态库
又叫共享对象库(shared object library,简称共享库)