Linux系统编程-静态库和动态库

程序库分为静态库和动态库(共享库)

1、静态库

        每个应用程序调用静态库都会将整个静态库加载到程序内存中。

        优点:调用函数速度快,缺点:占用大量内存

2、动态库

        应用程序调用函数时,会去动态库文件调用,并不会将整个库加载到程序内存中。

        优点:不会占用大量内存,缺点:调用函数速度慢

即:一个浪费时间,一个浪费空间,使用的关键在于实际的项目需求

1、静态库

Linux/Unix创建静态库

1、gcc -c将.c文件转化为.o文件

gcc -c name.c -o name.o

2、用ar工具制作静态库(参数 r:导入;c:创建;s:更新索引)

ar rcs libMylib.a file1 file2

关于c/c++头文件宏定义的补充

        在学习静态库和头文件的对应之前,先回顾一下C/C++头文件.h的书写。

.h文件一般包括对应.cpp的全部声明(函数、宏等等)

但是一个完整的库文件(.h和.cpp)可能会在一个程序的不同文件中重复使用,如果重复使用该库文件的两个以上文件要编译成一个可执行文件,那么.h文件里面的声明就会被重复声明,发生大量的声明冲突此时使用结合#ifndef、#endif的宏定义就显得很重要。

//下面这句话的意思就是:如果没有定义_MYLIB_H_这个宏,那么执行#ifndef 和 #endif之间的语句
#ifndef _MYLIB_H_
//下面这句话的意思就是:定义_MYLIB_H_这个宏,此时即使这个文件可能会被二次解析,
//但由于上面#ifndef的存在,下面的声明并不会二次执行
#define _MYLIB_H_ 

//命名规范 文件名字全部大写,前后均加_,其中.也换成_

...//声明
...//声明
...//声明
//在endif之前完成全部的声明

#endif

 静态库的使用和头文件的对应

        如果单纯的在编译时使用静态库,而不去编写和调用相关的头文件,那么函数的声明将无法完成,也就无法进行正常的使用,所以每个库都需要一个对应的头文件去让调用方可以完成对调用函数的声明。

        静态库在编译时的使用:

gcc .cpp文件 静态库文件名 -o 执行文件名

在Linux开发环境下,库文件一般放在目录的lib文件夹中,头文件一般在inc文件夹中,此时gcc的编译命令如下:

gcc test.cpp ./lib/test.a -o test.out -I ./inc

test.cpp是需要编程的文件,test.a是ar打包好的静态库,在inc文件夹内有test.h头文件,使用-I 参数进行调用(当头文件和编译文件在一个文件夹可以省略),-o 对生成可执行文件的命名。

2、动态库

概念学习:地址回填

        以gcc编译的链接阶段发生的main函数的地址回填解释,假设有如下一段代码:

int main(){
    void func1();//函数func1
    void func2();//函数func2
    return 0;
}

gcc编译共有四个过程,其中前面三个阶段main函数都没有分配确切内存地址,此时func1和func2函数的地址都是以main函数作为参照,即只要main函数地址确定,就能确定func1和func2的地址。而gcc第四个阶段的链接就会发生地址回填,此时main函数的地址会得到确切的分配,然后func1和func2根据确切的main函数地址,由原来的参照地址,转化为确切的唯一地址。

        而动态库就会用到类似的概念,通过将.c文件生成与地址无关的代码。

概念学习:数据段合并

        数据段合并(Data Segment Merging)是一种编译器优化技术,用于合并相邻的数据段或节(Sections)中具有相同初始化内容的数据。在编程中,程序中的全局变量和静态变量通常被分配在数据段中。如果有多个全局变量或静态变量具有相同的初始化值,编译器可以使用数据段合并技术将它们合并为一个共享的数据段,以减少可执行文件的大小和内存消耗。

Linux/Unix创建和使用动态库

 1、gcc -c生成.o文件(生成与位置无关的代码,参数:-fPIC)

gcc .cpp文件 静态库文件名 -o 执行文件名 -fPIC

2、gcc -shared 制作动态库

gcc -shared -o lib库名.so .o文件...

注意点:后缀名为.so文件;.o文件群必须都是使用-fPIC生成的.o文件;

3、编译可执行程序时,指定所使用的动态库。

gcc test.c -o test.out -l 库名 -L 库路径 -I 头文件路径

注意:库名和静态库有区别,这里的库名需要去掉lib和.so。

4、走到这就会很顺利的生成test.out文件,但是如果使用./test.out就会报错

        报错原因:

                        链接器:        工作于链接阶段,即-l(小写L) 和 -L

                        动态链接器:工作于程序运行阶段,工作时需要提供动态库所在目录位置。

        解决办法:

                1、修改当前进程(控制台)的动态库链接的LD_LIBRARY_PATH环境变量。

                

export LD_LIBRARY_PATH=动态库文件路径

        这种修改,会在关闭当前控制台后,新的控制台上失效。

                2、修改配置文件。

                3、将该动态库移动到默认的动态库里面。

        后面两种解决办法我并没有进行测试,所以建议百度更全面的解决办法。

你可能感兴趣的:(Linux后台,linux,运维,服务器)