- 浏览: 25736 次
- 性别:
- 来自: 北京
最新评论
1.什么是库
在windows平台和linux平台下都大量存在着库。
本质上来说库是一种可执行代码的二进制形式,可以被操作系统载入内存执行。
由于windows和linux的本质不同,因此二者库的二进制是不兼容的。
本文仅限于介绍linux下的库。
2.库的种类
linux下的库有两种:静态库和共享库(动态库)。
二者的不同点在于代码被载入的时刻不同。
静态库的代码在编译过程中已经被载入可执行程序,因此体积较大。
静态库的后缀名为.a文件.当程序与一个静态库链接时,该程序用到的外部函数的机器码被从库中复制到最终生成的可执行文件中.
共享库的代码是在可执行程序运行时才载入内存的,在编译过程中仅简单的引用,因此代码体积较小.
一个与共享库链接的可执行文件仅仅包含它用到的函数相关的一个表格,而不是那个函数的整个机器码.在可执行文件开始运行以前,外部函数的机器码由操作系统从磁盘上的该共享库中复制到内存中.
3.库存在的意义
库是别人写好的现有的,成熟的,可以复用的代码,你可以使用但要记得遵守许可协议。
现实中每个程序都要依赖很多基础的底层库,不可能每个人的代码都从零开始,因此库的存在意义非同寻常。
共享库的好处是,不同的应用程序如果调用相同的库,那么在内存里只需要有一份该共享库的实例。
4.例子源码:
hello.h
#ifndef HELLO_H
#define HELLO_H
void hello (const char *name);
void bye(void);
#endif
hello.c
#include <stdio.h>
#include "hello.h“
void hello(const char *name){
printf("Hello,%s!/n",name);
}
bye.c
#include <stdio.h>
#include "hello.h“
void bye(void){
printf("Goodbye!/n");
}
main.c
#include <stdio.h>
int main(){
hello("everyone");
bye();
return 0;
}
然后编译生成hello.c 和 bye.c 的目标文件
gcc -c hello.c ==> hello.o
gcc -c bye.c ==> bye.o
然后生成静态库和动态库
ar cr libhello.a hello.o bye.o
ar是GNU的归档器,可以从对象生成静态库 cr 代表 "creat andd replace".如果库文件不存在则会创建.如果库文件已经存在,任何与它同名的原始文件将被命令上指定的新文件取代.
归档工具ar也提供了"内容列表"的选项"t"来列出已有库中的对象文件:
ar t libhello.a
hello.o
bye.o
创建动态库
gcc -g -Wall -shared hello.o bye.o -o libhello.so
然后链接生成最终的目标文件
gcc -g -Wall main.c -L. -lhello
在libhello.a和libhello.so同时存在时默认为动态链接,若想为静态链接加 -static 参数
gcc -g -Wall -static main.c -L. -lhello
若为动态需要改变环境变量
若不改变环境变量在编译时不会出现任何问题,但若运行时出错
./hello: error while loading shared libraries: libhello.so: cannot open shared object file: No such file or directory
LD_LIBRARY_PATH是Linux环境变量名,该环境变量主要用于指定查找共享库(动态链接库)时除了默认路径之外的其他路径。(该路径在 默认路径之前查找)
移植程序时的经常碰到需要使用一些特定的动态库,而这些编译好的动态库放在我们自己建立的目录里,这时可以将这些目录设置到LD_LIBRARY_PATH中。
当执行函数动态链接.so时,如果此文件不在缺省目录下‘/usr/local/lib’ and ‘/usr/lib’.
那么就需要指定环境变量LD_LIBRARY_PATH
若在当前目录下使用
export LD_LIBRARY_PATH=.
很多时候需要把一组代码编译成一个库,这个库在很多项目中都要用到。
1)程序文件 (虽然实际上没太大必要)
文件目录结构
- [www@zhoubc test]$ tree
- |-- main.c
- |-- stack
- | |-- is_empty.c
- | |-- pop.c
- | |-- push.c
- | |-- stack.c
- | |-- stack.h
[www@zhoubc test]$ tree |-- main.c |-- stack | |-- is_empty.c | |-- pop.c | |-- push.c | |-- stack.c | |-- stack.h
代码所示
/* @package: stack/stack.c */ char stack[512]; int top = -1;
- /* @package:stack/push.c */
- extern char stack[512];
- extern int top;
- void push( char c){
- stack[++top] = c;
- }
/* @package:stack/push.c */ extern char stack[512]; extern int top; void push(char c){ stack[++top] = c; }
- /* @package:stack/pop.c */
- extern char stack[512];
- extern int top;
- char pop( void ){
- return stack[top--];
- }
/* @package:stack/pop.c */ extern char stack[512]; extern int top; char pop(void){ return stack[top--]; }
/* @package:stack/is_empty.c */ extern int top; int is_empty(){ return top == -1; }
- /* @package:stack/stack.h */
- #ifndef STACK_H
- #define STACK_H
- extern void push( char c);
- extern char pop( void );
- extern int is_empty();
- #endif
/* @package:stack/stack.h */ #ifndef STACK_H #define STACK_H extern void push(char c); extern char pop(void); extern int is_empty(); #endif
主函数:
- /* @package:main.c */
- #include <stdio.h>
- #include "stack.h"
- int main(){
- extern char stack[512];
- push('a' );
- printf("%d \n" ,stack[0]);
- return 0;
- }
/* @package:main.c */ #include <stdio.h> #include "stack.h" int main(){ extern char stack[512]; push('a'); printf("%d \n",stack[0]); return 0; }
2)
把stack.c
、push.c
、pop.c
、is_empty.c
编译成目标文件
- [www@zhoubc test]$ gcc -c stack/*.c
- [www@zhoubc test]$ ls
- is_empty.o main.c pop.o push.o stack stack.o
[www@zhoubc test]$ gcc -c stack/*.c [www@zhoubc test]$ ls is_empty.o main.c pop.o push.o stack stack.o
3)打包成一个静态库libstack.a
- [www@zhoubc test]$ ar rs libstack.a *.o
- ar: creating libstack.a
- 或
- [www@zhoubc test]$ ar r libstack.a *.o
- [www@zhoubc test]$ranlib libstack.a
[www@zhoubc test]$ ar rs libstack.a *.o ar: creating libstack.a 或 [www@zhoubc test]$ ar r libstack.a *.o [www@zhoubc test]$ranlib libstack.a
解析:
库文件名都是以lib
开头的,静态库以.a
作为后缀,表示Archive
ar :把目标文件打包成静态库.
选项r:
表示将后面的文件列表添加到文件包,如果文件包不存在就创建它,如果文件包中已有同名文件就替换成新的
选项s
:专用于生成静态库的,表示为静态库创建索引,这个索引被链接器使用.ranlib
命令也可以为静态库创建索引
4)编译链接在一起
[www@zhoubc test]$ gcc main.c -L. -lstack -Istack -o main
-L
选项告诉编译器去哪里找需要的库文件,-L.
表示在当前目录找(注意,即使库文件就在当前目录,编译器默认也不会去找的,所以-L.
选项不能少)
-lstack
告诉编译器要链接libstack
库
-I
选项告诉编译器去哪里找头文件
5)运行
[www@zhoubc test]$ ./main 97
=================================================================================
共享库
共享库使用:程序第一次执行或者第一次调用某个库函数时,用动态连接方法将程序与共享库函数相连接。这减少了每个可执行文件的长度,但增加了一些运行时间开销。——只在程序运行时才载入内存的,在编译过程中只简单的引用。
共享库的优点是库函数的新版本代替老版本而无需对使用该库的程序重新连接编辑。
目录结构
[www@zhoubc src]$ tree . |-- pop.c `-- push.c
1)编译、汇编到目标代码,不进行链接
- [www@zhoubc src]$ gcc -fPIC -c pop.c push.c
- [www@zhoubc src]$ tree
- .
- |-- pop.c
- |-- pop.o
- |-- push.c
- `-- push.o
[www@zhoubc src]$ gcc -fPIC -c pop.c push.c [www@zhoubc src]$ tree . |-- pop.c |-- pop.o |-- push.c `-- push.o
参数说明:
-f
后面跟一些编译选项.
PIC
是其中一种,表示生成位置无关代码
-fPIC:生成与位置无关的代码.因为共享库链接的时候都是使用的是相对地址,所以必须指定这一项。
2)建立共享库
- [www@zhoubc src]$ gcc -shared -o libstack.so pop.o push.o
- [www@zhoubc src]$ tree
- .
- |-- libstack.o
- |-- pop.c
- |-- pop.o
- |-- push.c
- `-- push.o
[www@zhoubc src]$ gcc -shared -o libstack.so pop.o push.o [www@zhoubc src]$ tree . |-- libstack.o |-- pop.c |-- pop.o |-- push.c `-- push.o
参数说明
-shared:代表要建立共享库.
3)测试共享库
[www@zhoubc src]$ gcc main.c -L./ -lstack
-L.
选项,编译器可以在./目录下找到libstack.so文件
执行
- [www@zhoubc src]$ ./a.out
- ./a.out: error while loading shared libraries: libstack.so: cannot open shared object file: No such file or directory
[www@zhoubc src]$ ./a.out ./a.out: error while loading shared libraries: libstack.so: cannot open shared object file: No such file or directory
错误解决
- [www@zhoubc src]$ ldd a.out
- linux-gate.so.1 => ( 0x00d59000 )
- libstack.so => not found
- libc.so.6 => /lib/libc.so. 6 ( 0x00a68000 )
- /lib/ld-linux.so.2 ( 0x00a44000 )
[www@zhoubc src]$ ldd a.out linux-gate.so.1 => (0x00d59000) libstack.so => not found libc.so.6 => /lib/libc.so.6 (0x00a68000) /lib/ld-linux.so.2 (0x00a44000)
ldd 命令查看可执行文件依赖于哪些共享库.
ldd模拟运行一遍a.out,在运行过程中做动态链接,从而得知这个可执行文件依赖于哪些共享库,每个共享库都在什么路径下,加载到进程地址空间的什么地址.
共享库路径的搜索顺序:
- 首先在环境变量
LD_LIBRARY_PATH
所记录的路径中查找。 - 然后从缓存文件
/etc/ld.so.cache
中查找。这个缓存文件由ldconfig
命令读取配置文件/etc/ld.so.conf
之后生成. - 如果上述步骤都找不到,则到默认的系统路径中查找,先是/usr/lib然后是/lib
解决问题:
<1>指定搜索路径
[www@zhoubc src]$LD_LIBRARY_PATH=./
<2>把绝对路径添加到/etc/ld.so.cache中,然后运行ldconfig——常用方法
<3>把so文件拷到/usr/lib或/lib目录。
<4>在编译可执行文件的时候就把so的路径写死在可执行文件中。
[www@zhoubc src]$ gcc main.c -g -L./ -lstack -Wl,-rpath,./
-Wl,-rpath,./
表示-rpath ./
是由gcc
传递给链接器的选项,表示搜索路径.
-Wl,option代表把选项option传给链接器.
=========================================================================
共享库和静态库
链接共享库和链接静态库区别 :
链接共享库 只是指定了动态链接器和该程序所需要的库文件,并没有真的做链接,可执行文件调用的库函数仍然是未定义符号,要在运行时做动态链接 。——在编译和加载的时候都需要,没有真正编译进可执行文件。
链接静态库 链接器会把静态库中的目标文件取出来和可执行文件真正链接在一起.——只在编译的时候需要
发表评论
-
转 嵌入式研发人员的核心竞争力浅谈
2012-08-31 14:12 692夜深人静,万籁俱寂, ... -
飞鸽传书项目中 sqlite数据库应用
2012-08-27 20:08 1363Sqlite3数据库使用注释 飞秋项目接近尾声,各 ... -
条件编译 消息队列 实现的聊天程序
2012-08-07 08:51 967#include <sys/types.h> # ... -
转 mount挂载参数含义
2012-07-28 10:36 11405挂接命令(mount) 首先,介绍一下挂接(mou ... -
转 我的Android之旅——学习、项目、心态
2012-07-28 10:37 1865我的Androi ... -
C语言动态库静态库
2012-07-26 12:22 2988我们在编写一个C语言程 ...
相关推荐
动态库的制作: 方法一: gcc -c -fPIC add.c sub.c div.c mul.c //-c表示生成.o目标文件,-f后加一些编译选项,PIC表示与位置无关 gcc -shared -o libmymath.so add.o sub.o mul.o div....
linux C 动态库和静态库生成及使用笔记
默认编译是静态库,但考虑到 linux 上动态库使用较多,所以使用 -DBUILD_SHARED_LIBS=ON 参数编译为动态库。 在 centos 7 下使用 gcc 4.8.5 + cmake 3.16.9 编译,包含 bin, include, lib, lib64, share 五个目录,...
动态库的制作: 方法一: gcc -c -fPIC add.c sub.c div.c mul.c //-c表示生成.o目标文件,-f后加一些编译选项,PIC表示与位置无关 gcc -shared -o libmymath.so add.o sub.o mul.o div.o//创建共享库mymath,添加...
Linux下Gcc生成和使用静态库和动态库详解Linux下Gcc生成和使用静态库和动态库详解
嵌入式linux中静态库和动态库的制作简单事例
Linux C 静态链接库 动态链接库 简单介绍 看完本例子,可以入门了。。。。
1.编译生成静态库 gcc -c libdemo.c -o libdemo.o ar rcs libdemo.a libdemo.o gcc testdemo.c -o testdemo -static -L. -ldemo 运行: ./testdemo
linux下C语言,通过gcc生成静态库和动态库
NetBeans的远程Linux C开发实践(远程调试)——包含了远程链接动态库静态库的方法
linux系统编程-静态库-动态库的制作-gdb调试常见段错误-c语言实现
文中是linux下 C++动态库 实现接口提供类导出的一个例子 注意其中使用函数返回基类指针的用法,因为Linux的动态链接库不能像MFC中那样直接导出类 一、介绍 如何使用dlopen API动态地加载C++函数和类,是Unix C++...
Linux静态库与动态库实例详解 1. Linux 下静态链接库编译与使用 首先编写如下代码: // main.c #include test.h int main(){ test(); return 0; } // test.h #include using namespace std; void test(); // test...
创建静态库(.a)通过上面的流程可以知道,Linux创建静态库过程如下:l 首先,将代码文件编译成目标文件.o(StaticMath.o)g++ -c Sta
库的存在极大的提高了C/C++程序的复用性,但是库对于初学者来说有些难以驾驭,本文从Linux的角度浅谈Linux下的静态库、动态库和动态加载库。 Linux库类型 Linux下可以创建两种类型的库: 1、静态库(.a): 在...
动态库和静态库在C/C++开发中很常见,相比静态库直接被编译到可执行程序,动态库运行时加载使得可执行程序的体积更小,更新动态库可以不用重新编译可执行程序等诸多好处。作者是一个Linux后台开发,这些知识经常用到...
Linux下,库分为静态库和共享库。 库的生成 静态库:库名:Libxxx.a,lib是库的前缀,xxx是库名,.a为静态库的后缀。 第一步:将需要生成静态库的.c文件转换为编译后的.o文件 命令:gcc -S mian.o mian.c 第二步...
因此,这里我将为大家介绍如何给其它开发者创建可供使用的静态库或动态库。而应用开发者如何去连接这些生成的静态库或动态库。由于现在Android Studio已经比较成熟,因此以下描述将基于Android Studio的目录布局。 ...
linux下的库有两种:静态库和共享库(动态库)。 二者的不同点在于代码被载入的时刻不同。 静态库的代码在编译过程中已经被载入可执行程序,因此体积较大。 共享库的代码是在可执行程序运行时才载入内存的,在编译...