动态库 sl 和 so文件的区别

动态库 sl 和 so文件的区别,第1张

我们通常把一些公用函数制作成函数库,供其它程序使用。

函数库分为静态库和动态库两种。

静态库在程序编译时会被连接到目标代码中,程序运行时将不再需要该静态库。

动态库在程序编译时并不会被连接到目标代码中,而是在程序运行是才被载入,因此在程序运行时还需要动态库存在。

本文主要通过举例来说明在Linux中如何创建静态库和动态库,以及使用它们。

在创建函数库前,我们先来准备举例用的源程序,并将函数库的源程序编译成.o文件

第1步:编辑得到举例的程序--hello.h、hello.c和main.c

hello.h(见程序1)为该函数库的头文件。

hello.c(见程序2)是函数库的源程序,其中包含公用函数hello,该函数将在屏幕上输出"Hello XXX!"。

main.c(见程序3)为测试库文件的主程序,在主程序中调用了公用函数hello。

程序1: hello.h

#ifndef HELLO_H

#define HELLO_H

void hello(const char *name)

#endif //HELLO_H

程序2: hello.c

#include

void hello(const char *name)

{

printf("Hello %s!/n", name)

}

程序3: main.c

#include "hello.h"

int main()

{

hello("everyone")

return 0

}

第2步:将hello.c编译成.o文件

无论静态库,还是动态库,都是由.o文件创建的。因此,我们必须将源程序hello.c通过gcc先编译成.o文件。

在系统提示符下键入以下命令得到hello.o文件。

# gcc -c hello.c

#

(注1:本文不介绍各命令使用和其参数功能,若希望详细了解它们,请参考其他文档。)

(注2:首字符"#"是系统提示符,不需要键入,下文相同。)

我们运行ls命令看看是否生存了hello.o文件。

# ls

hello.c hello.h hello.o main.c

#

(注3:首字符不是"#"为系统运行结果,下文相同。)

在ls命令结果中,我们看到了hello.o文件,本步 *** 作完成。

下面我们先来看看如何创建静态库,以及使用它。

第3步:由.o文件创建静态库

静态库文件名的命名规范是以lib为前缀,紧接着跟静态库名,扩展名为.a。例如:我们将创建的静态库名为myhello,则静态库文件名就是libmyhello.a。在创建和使用静态库时,需要注意这点。创建静态库用ar命令。

在系统提示符下键入以下命令将创建静态库文件libmyhello.a。

# ar cr libmyhello.a hello.o

#

我们同样运行ls命令查看结果:

# ls

hello.c hello.h hello.o libmyhello.a main.c

#

ls命令结果中有libmyhello.a。

第4步:在程序中使用静态库

静态库制作完了,如何使用它内部的函数呢?只需要在使用到这些公用函数的源程序中包含这些公用函数的原型声明,然后在用gcc命令生成目标文件时指明静态库名,gcc将会从静态库中将公用函数连接到目标文件中。注意,gcc会在静态库名前加上前缀lib,然后追加扩展名.a得到的静态库文件名来查找静态库文件。

在程序3:main.c中,我们包含了静态库的头文件hello.h,然后在主程序main中直接调用公用函数hello。下面先生成目标程序hello,然后运行hello程序看看结果如何。

# gcc -o hello main.c -L. -lmyhello

# ./hello

Hello everyone!

#

我们删除静态库文件试试公用函数hello是否真的连接到目标文件 hello中了。

# rm libmyhello.a

rm: remove regular file `libmyhello.a'? y

# ./hello

Hello everyone!

#

程序照常运行,静态库中的公用函数已经连接到目标文件中了。

我们继续看看如何在Linux中创建动态库。我们还是从.o文件开始。

第5步:由.o文件创建动态库文件

动态库文件名命名规范和静态库文件名命名规范类似,也是在动态库名增加前缀lib,但其文件扩展名为.so。例如:我们将创建的动态库名为myhello,则动态库文件名就是libmyhello.so。用gcc来创建动态库。

在系统提示符下键入以下命令得到动态库文件libmyhello.so。

# gcc -shared -fPCI -o libmyhello.so hello.o

#

我们照样使用ls命令看看动态库文件是否生成。

# ls

hello.c hello.h hello.o libmyhello.so main.c

#

第6步:在程序中使用动态库

在程序中使用动态库和使用静态库完全一样,也是在使用到这些公用函数的源程序中包含这些公用函数的原型声明,然后在用gcc命令生成目标文件时指明动态库名进行编译。我们先运行gcc命令生成目标文件,再运行它看看结果。

# gcc -o hello main.c -L. -lmyhello

# ./hello

./hello: error while loading shared libraries: libmyhello.so: cannot open shared object file: No such file or directory

#

哦!出错了。快看看错误提示,原来是找不到动态库文件libmyhello.so。程序在运行时,会在/usr/lib和/lib等目录中查找需要的动态库文件。若找到,则载入动态库,否则将提示类似上述错误而终止程序运行。我们将文件 libmyhello.so复制到目录/usr/lib中,再试试。

# mv libmyhello.so /usr/lib

# ./hello

Hello everyone!

#

成功了。这也进一步说明了动态库在程序运行时是需要的。

我们回过头看看,发现使用静态库和使用动态库编译成目标程序使用的gcc命令完全一样,那当静态库和动态库同名时,gcc命令会使用哪个库文件呢?抱着对问题必究到底的心情,来试试看。

先删除 除.c和.h外的 所有文件,恢复成我们刚刚编辑完举例程序状态。

# rm -f hello hello.o /usr/lib/libmyhello.so

# ls

hello.c hello.h main.c

#

在来创建静态库文件libmyhello.a和动态库文件libmyhello.so。

# gcc -c hello.c

# ar cr libmyhello.a hello.o

# gcc -shared -fPCI -o libmyhello.so hello.o

# ls

hello.c hello.h hello.o libmyhello.a libmyhello.so main.c

#

通过上述最后一条ls命令,可以发现静态库文件libmyhello.a和动态库文件libmyhello.so都已经生成,并都在当前目录中。然后,我们运行gcc命令来使用函数库myhello生成目标文件hello,并运行程序 hello。

# gcc -o hello main.c -L. -lmyhello

# ./hello

./hello: error while loading shared libraries: libmyhello.so: cannot open shared object file: No such file or directory

#

从程序hello运行的结果中很容易知道,当静态库和动态库同名时, gcc命令将优先使用动态库。

1.确实没什么标准可言,dll主要就是提供代码动态加载。所以它只需要让加载器能够找到正确的函数名就行了。保证链接过程不出错即可。大型API要遵循一些原则,是因为函数提供给其他人应用,而且是二进制格式发布。就算是自己的dll文档对函数的解释也要写清楚。以后维护升级保证dll内原始的函数原形不发生变化。没有什么模式需要你遵循。dll的内容也只是函数的集合而已。

2.dll分几种,其实只是可执行文件格式而已。so文件也是一种可执行格式(ELF格式)。计算机发展到现在可执行文件格式有多种变体。链接器和加载器.pdf 一书对可执行文件讲的比较详细,你肯定不是编译器和连接器的开发者。所以你不需要知道这么多。只需要知道可执行文件存放着我需要的代码,连接器把不同的库连接到一起,然后main函数就可以在执行过程中动态调用它们。推荐看:深入剖析Win32可移植可执行文件格式 链接器和加载器 两份资料

你去搜搜可执行文件格式,可以找到一些文章。

3.其实不许要注意什么,so性质和dll是一样的(存放着可执行代码,链接需要的信息,符号表等等。)。它们只是在不同平台下的动态链接库而已。对于dll到so注意什么???对于普通程序员没什么要注意的。我们只需要写出代码然后,使用连接器和编译器就可以了。细节问题是编译器和连接器加载器的实现者关心的。

4.COM即是一种可执行格式(dos时代),也是一种 “组件对象模型”。前者已经不主流了,后者不过时。com也是dll这些dll按照com规范提供固定名称的函数(俗称“接口”)。需要加载这些com的主程序,也遵循com规范调用这些函数。这样两边就能协同工作。

你写一个父类,让所有需要乃至这个头部和尾部文件的都继承这个类,在父类中分配变量

<?php

class CommonAction extends Action

{

function _initialize()

{

if(method_exists($this,'_initialize'))

{

$this->_initialize()

}

//获取相应的变量的值,并赋值

$header = $this->getHeader()//具体怎么获得这些头部和底部变量的值根据情况自定

$this->assign('header', $header)

}

}

?>

IndexAction.class.php

<?php

class IndexAction extends CommonAction

{

}

?>

在模板文件中包含公共头部与尾部

<include file="public::header"/>

<!---模板其他内容-->

<include file="public::footer"/>


欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/yw/11528970.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-05-16
下一篇 2023-05-16

发表评论

登录后才能评论

评论列表(0条)

保存