静态编译与动态编译

概念和比较


   库可以有三种使用的形式:静态、共享和动态。静态库的代码在编译时就已连接到开发人员开发的应用程序中,而共享库只是在程序开始运行时才载入,在编译时,只是简单地指定需要使用的库函数。动态库则是共享库的另一种变化形式。动态库也是在程序运行时载入,但与共享库不同的是,使用的库函数不是在程序运行开 始,而是在程序中的语句需要使用该函数时才载入。动态库可以在程序运行期间释放动态库所占用的内存,腾出空间供其它程序使用。由于共享库和动态库并没有在程序中包括库函数的内容,只是包含了对库函数的引用,因此代码的规模比较小。


静态编译,会在连接的时候就将需要使用的库(一般是从.a文件)编译进可执行文件之中,故而在程序执行的时候就不需要调用.a文件了。这种方式优点是文件的执行不需要依赖其他的库,因此增加了文件的独立性。缺点就是当功能复杂,代码量大的时候,可执行文件会过于庞大。造成文件的加载和初始化比较困难,尤其是硬件很一般的情况下。


  同时,静态编译虽然保证了程序一定的独立不依赖性,但是如果库文件升级,要想使用更优的库文件,则必须重新编译。


   动态编译则不同,一般先把库函数编译成.so动态库。在链接的时候,可执行文件中并不会包含要使用的库函数,只是说明要使用哪些动态库.so文件。这种方式的优点是,链接后的可执行文件比较小,便于加载使用,而且也对内存要求没有静态编译那么高。相对应,由于要使用一些.so文件,因此可执行文件必须依赖于其他动态库文件.so文件,在程序移动等时候都需要考虑其依赖关系。一个好处是,动态库更新后,可执行文件不用重新编译就可使用新动态库的优化特性,只要接口和.so文件名匹配。


生成静态库:


  1. $ gcc -c func.c -o func.o 产生目标文件

  2. $ ar rcs libfunc.a func.o  用目标文件产生静态库

  3. $ gcc main.c -o main -static -L. -lfunc 链接产生可执行文件

  4. $ ./main 


生成动态库:


1$ gcc -fPIC -cfunc.c -o func.o 同样产生目标文件,不管动态还是静态连接,首先要产生目标文件.o文件


2$ gcc -shared -olibfunc.so.1.0.0 func.o  gcc –share产生共享库文件


3$ ln -slibfunc.so.1.0.0 libfunc.so   对版本的一个控制,便于连接


4$ gcc main.c -o main-L. –lfunc     链接产生可执行文件


5$ exportLD_LIBRARY_PATH=$(pwd) 配置动态库文件,这个也可以通过编辑/etc/ld.so.conf,在其中加入库文件的目录来实现。同时使用ldconfig来更新动态库。


遇到下面问题一般是动态库没有配置正确:


libmyhello.so:cannot open shared object file: No such


6$ ./main


如果将 so文件 copy到系统 lib目录(/usr/lib),则最后 2步就不用了。


需要注意:

不管是动态编译还是静态编译,都只是说明了库文件的使用方式。但是,链接时候使用的命令都是一样。只是编译工具会自动根据库文件的类型选择链接方式,要不要把库函数包含进可执行文件中。特别注意的是,如果目录下存在同名的静态库和动态库文件,则默认会使用动态编译方式。比如同时存在libmyhello.alibmyhello.so.


最后还有 3个小知识:


1.   nm 命令:列出目标文件或 2进制文件的所有符号。

2.ldd命令:列出为了使程序正常运行所需要的所有共享库。ldd lmp_linux.


3. /etc/ld.so.conf 文件:除了标准目录(/lib/usr/lib)之外,链接器 和加载器搜索共享库时要检查的其他目录,和这个文件相关的一个命令是:ldconfig






















在Qt中,第三方可以通过静态编译动态编译两种方式进行使用。 1. 静态编译静态编译是指将第三方的代码编译静态(.a或.lib文件),并将静态链接到应用程序中,生成一个单独的可执行文件。这种方式需要在.pro文件中指定要链接的静态,例如: ``` LIBS += -lmylib ``` 其中,`mylib`是要链接的静态名字。 静态编译的优点是运行时需要动态加载第三方,提高了启动速度和效率。但缺点是可执行文件较大,易扩展和更新。 2. 动态编译动态编译是指将第三方的代码编译动态(.dll或.so文件),并在运行时通过libloaderapi函数手动加载动态,并通过QLibrary类获取动态中的函数地址,然后直接调用该函数。这种方式需要在代码中显式加载动态,例如: ``` QLibrary mylib("mylib.dll"); mylib.load(); ``` 然后通过QLibrary的resolve方法获取函数地址,例如: ``` void (*myFunc)() = (void (*)()) mylib.resolve("myFunc"); ``` 其中,`myFunc`是要调用的函数名。 动态编译的优点是灵活性高,可以根据实际需要动态加载和卸载第三方,便于扩展和更新。但缺点是运行时需要动态加载第三方,影响了启动速度和效率。 需要注意的是,在使用第三方时,需要遵循一些规范和最佳实践,以确保正确性和安全性。特别是在获取函数地址时,需要确保函数名的正确性和类型匹配,否则可能导致运行时错误和安全漏洞。同时,在编译和链接时,需要遵循第三方的使用规范,以确保文件的正确链接和使用。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值