Linux下C++C编译⽣成.a或者.so库⽂件
最近因为阅读源码的⼯作,需要⾃⼰编译⼀些 .so ⽂件或者 .a ⽂件,查了⼀些资料,写了⼀些⽰例,记录⼀下。
静态库和动态库
⼀般程序编译的过程可以分为编译和链接两个阶段。链接阶段,需要把所有的obj⽂件(.o)链接起来,⽣成可执⾏程序,这个过程可以链接其他外部的库⽂件。 有时候也有省略写法。
gcc -c test.c        #源⽂件编译,⽣成 .o ⽂件
gcc -o test test.o  #将Obj⽂件链接,可以多个⽂件
linux下gcc编译的四个步骤
#省略写法
gcc test.c            #默认⽣成 a.out
gcc -o test test.c    #两个阶段省略成⼀个
库⽂件⾥的具体实现时对⽤户透明的,只是提供功能函数,⽽⽤户不能知道库⽂件爱你的源码实现。如
果你不想开源你的具体实现,你就可以只提供库⽂件供别⼈使⽤。库⽂件分为静态库和动态库⽂件:
静态库:⼀般情况下也就是 .a ⽂件。静态库就是指在链接的过程中,将库⽂件所有数据都整合到⽬标代码,这样⽣成的可执⾏⽂件执⾏时就不再需要外部库⽀持,随便哪⾥运⾏。这样就导致了静态库编译⽣成的可执⾏库⽂件较⼤,⽽且当库⽂件需要更新改变时,可执⾏⽂件也必须重新编译⽣成。
动态库:⼀般情况下就是 .so ⽂件。与静态库不同,动态库⽂件在链接时不会将所有的代码实现整合到⽬标代码中,⽽是在可执⾏程序执⾏到相应位置时才会去库⽂件中搜索相应的⽅法。所以动态库链接⽣成的函数就⽐较⼩,⽽且库⽂件更新时,只需要重新⽣成库⽂件就可以了,不需要重新编译可执⾏程序。这就给库⽂件升级更新带来了极⼤的便利。
库⽂件的编译⽣成
静态库的编译⽣成
静态库的编译⽣成需要⽤到 ar 指令,链接过程参数 -L 表⽰库⽂件路径,-l 表⽰库⽂件名称。库⽂件要以 lib{name}.a 命名格式,name指库⽂件的名字。
写⼀个测试⼩程序,三个⽂件,funTest.c, funTest.h 和 testMain.c ,testMain.c调⽤ ⼀个 库函数输出:
// funTest.h    头⽂件进⾏函数接⼝定义
#include <stdio.h>
void printa();
//--------------------------------------------
// funTest.c    源⽂件中实现
#include "funTest.h"
void printa(){
printf("print a\n");
}
//-------------------------------------------
// testMain.c 主程序⽂件,调⽤库函数
#include "funTest.h"
int main()
{
printa();
return 0;
}
三个⽂件代码如上所⽰,编译过程如下所⽰。写完我发现,库⽂件的链接过程和.o⽂件类似,咋⼀看起来似乎直接使⽤.o⽂件更⽅便,那为什么不直接使⽤.o⽂件呢?其实⼀般情况下,库⽂件都是第三⽅库,⽽且由多个.o⽂件编译⽽成。.
# 正常情况下,就直接将object⽂件链接⼀起编译⽣成可执⾏程序就⾏了
gcc -c funTest.c
gcc -o testMain testMain.c funTest.o
# 库⽂件形式下
gcc -c funTest.c                                # 编译⽣成funa.o
ar -rsv libfunTest.a funTest.o                  # ar指令,编译⽣成静态库⽂件
gcc -o testMain testMain.c -L./ -lfunTest      # 链接静态库⽂件,⽣成可执⾏⽂件
动态库的编译⽣成
动态库即是⼀般是指的.so ⽂件,与静态库相对应,动态库在编译链接过程中并不会把所有代码都编译进去,编译成的可执⾏⽂件也必须调⽤动态库才能正确运⾏,程序执⾏到相应位置才会去动态库中寻函数实现。这样编译出来的可执⾏程序较⼩,且动态库可随时升级,⽽不需要重新编译⽣成可执⾏⽂件。
动态库的编译需要⽤到 -fPIC 和 -shared 两个参数,本来跟静态库⼀样通过-L 和 -l 两个参数进⾏库⽂件路径和⽂件名的指定,但是到动态库的时候就没有成功,就直接指定了。
# 动态库编译⽣成
gcc -o libtest.so -fPIC -shared funa.c
gcc -o testMain testMain.c ./libtest.so        # 直接指定动态库位置
测试程序还是同上静态库的程序,然后做个试验,将funa.c修改,再次重新⽣成动态库,⽽不再重新编译⽣成 testMain 可执⾏⽂件。
#include "funa.h"
void printa(){
printf("print a; after modification\n");
}
执⾏观察结果:结果成功改变。说明动态库的更新便捷性,不需要重新编译⽣成可执⾏⽂件。
库⽂件的依赖
⽣成的可执⾏⽂件可以通过查看库⽂件依赖看是否编译成功,命令 ldd ;如果显⽰不⼤库⽂件,则是库⽂件链接失败。

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。