Linux下.ko, .o, .so, .a, .la文件


.o file - the unlinked output of the compiler - an object file

.a - out of using ar to "pack" several .o files into an object archive file. It is an efficient way of keeping track of and being able to access object modules during the link edit phase of compilation.

.so - shared object library - created by the linker from .o files. These shared libraries
are loaded into memory and accessed (all at one time) by lots of processes in the system. This saves memory.


Another way of reasoning about the differences is that .a files are linked in at compile time and .so files are linked in at run time. 

So when you compile a source file that calls functions in a .a file the code for those functions gets included, but when you call functions in a .so file they get included when you run the program.




Linux下文件的类型是不依赖于其后缀名的,但一般来讲:

.ko 是Linux 2.6内核使用的动态连接文件的后缀名,也就是模块文件,用来在Linux系统启动时加载内核模块

.o 是目标文件,相当于windows中的.obj文件

.so 为共享库,是shared object,用于动态连接的,和dll差不多

.a 为静态库,是好多个.o合在一起,用于静态连接

.la 为libtool自动生成的一些共享库,vi编辑查看,主要记录了一些配置信息。可以用如下命令查看file *.la来查看文件类型

创建.a库文件和.o库文件:

  $ gcc -c mylib.c

  $ ar -r mylib.a mylib.o

动态链接库*.so的编译与使用

1、动态库的编译

下面通过一个例子来介绍如何生成一个动态库。这里有一个头文件,三个.c文件:

so_test.h

test_a.c

test_b.c

test_c.c

我们将这几个文件编译成一个动态库:libtest.so。

 

代码

 

so_test.h:

#include <stdio.h>

#include <stdlib.h>

void test_a();

void test_b();

void test_c();

 

test_a.c:

#include \"so_test.h\"

void test_a()

{

    printf(\"this is in test_a...\\n\");

}

 

test_b.c:

#include \"so_test.h\"

void test_b()

{

    printf(\"this is in test_b...\\n\");

}

 

test_c.c:

#include \"so_test.h\"

void test_c()

{

    printf(\"this is in test_c...\\n\");

}

$ gcc test_a.c test_b.c test_c.c -fPIC -shared -o libtest.so

2、动态库的链接

在1、中,我们已经成功生成了一个自己的动态链接库libtest.so,下面我们通过一个程序来调用这

个库里的函数。程序的源文件为:test.c。

#include \"so_test.h\"

int main()

{

    test_a();

    test_b();

    test_c();

    return 0;

}

 

将test.c与动态库libtest.so链接生成执行文件test:

  $ gcc test.c -L. -ltest -o test

测试是否动态连接,如果列出libtest.so,那么应该是连接正常了

  $ ldd test

  这时应该会报找不到libtest.so,这里我们再执行一下:

  $ sudo cp libtest.so /usr/lib

  把这个库拷贝到系统默认的库路径即可,这样只是临时测试使用,更合理的方法看后面介绍

执行test,可以看到它是如何调用动态库中的函数的。

 

3、编译参数解析

最主要的是GCC命令行的一个选项:

-shared 该选项指定生成动态连接库(让连接器生成T类型的导出符号表,有时候也生成

    弱连接W类型的导出符号),不用该标志外部程序无法连接。相当于一个可执行文件

-fPIC:表示编译为位置独立的代码,不用此选项的话编译后的代码是位置相关的所以动

    态载入时是通过代码拷贝的方式来满足不同进程的需要,而不能达到真正代码段共享的目的。

-L.:表示要连接的库在当前目录中

-ltest:编译器查找动态连接库时有隐含的命名规则,即在给出的名字前面加上lib,后面加上.so来确定库的名称

    LD_LIBRARY_PATH:这个环境变量指示动态连接器可以装载动态库的路径。

当然如果有root权限的话,可以修改/etc/ld.so.conf文件,然后调用/sbin/ldconfig来

达到同样的目的,不过如果没有root权限,那么只能采用输出LD_LIBRARY_PATH的方法了。

4、注意

调用动态库的时候有几个问题会经常碰到,有时,明明已经将库的头文件所在目录 通过 “-I

”include进来了,库所在文件通过“-L”参数引导,并指定了“-l”的库名,但通过ldd命令察看时,

就是死活找不到你指定链接的so文件,这时你 要作的就是通过修改LD_LIBRARY_PATH或

者/etc/ld.so.conf文件来指定动态库的目录。通常这样做就可以解决库无法链接的问题 了。

makefile里面怎么正确的编译和连接生成.so库文件,然后又是在其他程序的makefile里面如何编译

和连接才能调用这个库文件的函数????

答:

你需要告诉动态链接器、加载器ld.so在哪里才能找到这个共享库,可以设置环境变量把库的

路径添加到库目录/lib和/usr/lib,LD_LIBRARY_PATH=$(pwd),这种方法采用命令行方法不太方便,一种替

代方法

^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^注释^^^^^^^^^^^^^^^^^^^^^^^^^^^^

LD_LIBRARY_PATH可以在/etc/profile还是~/.profile还是./bash_profile里设置,或者.bashrc里

改完后运行source /etc/profile或. /etc/profile

更好的办法是添入/etc/ld.so.conf, 然后执行/sbin/ldconfig

^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^注释^^^^^^^^^^^^^^^^^^^^^^^^^^^^

是把库路径添加到/etc/ld.so.conf,然后以root身份运行ldconfig

也可以在连接的时候指定文件路径和名称-I -L.

GCC=gcc

CFLAGS=-Wall -ggdb -fPIC

#CFLAGS=

all: libfunc test

libfunc:func.o func1.o

$(GCC) -shared -Wl,-soname,libfunc.so.1 -o libfunc.so.1.1 $<

ln -sf libfunc.so.1.1 libfunc.so.1

ln -sf libfunc.so.1 libfunc.so

***********************************************注释

************************************************

ln -s是用来创建软链接,也就相当于windows中的快捷方式,在当前目录中创建上一级目录中的文件

ttt的命名为ttt2软链接的命令是ln -s ../ttt ttt2,如果原文件也就是ttt文件删除的话,ttt2也变成了

空文件。

ln -d是用来创建硬链接,也就相当于windows中文件的副本,当原文件删除的时候,并不影响“副本

”的内容。

编译目标文件时使用gcc的-fPIC选项,产生与位置无关的代码并能被加载到任何地址:

gcc –fPIC –g –c liberr.c –o liberr.o

使用gcc的-shared和-soname选项;

使用gcc的-Wl选项把参数传递给连接器ld;

使用gcc的-l选项显示的连接C库,以保证可以得到所需的启动(startup)代码,从而避免程序在使

用不同的,可能不兼容版本的C库的系统上不能启动执行。

gcc –g –shared –Wl,-soname,liberr.so –o liberr.so.1.0.0 liberr.o –lc

建立相应的符号连接:

ln –s liberr.so.1.0.0 liberr.so.1;

ln –s liberr.so.1.0.0 liberr.so;

在MAKEFILE中:

$@

表示规则中的目标文件集。在模式规则中,如果有多个目标,那么,\"$@\"就是匹配于目标中模式

定义的集合。

$%

仅当目标是函数库文件中,表示规则中的目标成员名。例如,如果一个目标是\"foo.a(bar.o)\",

那么,\"$%\"就是\"bar.o\",\"$@\"就是\"foo.a\"。如果目标不是函数库文件(Unix下是[.a],Windows下是

[.lib]),那么,其值为空。

$<

依赖目标中的第一个目标名字。如果依赖目标是以模式(即\"%\")定义的,那么\"$<\"将是符合模

式的一系列的文件集。注意,其是一个一个取出来的。

$?

所有比目标新的依赖目标的集合。以空格分隔。

$^

所有的依赖目标的集合。以空格分隔。如果在依赖目标中有多个重复的,那个这个变量会去除重

复的依赖目标,只保留一份。

*********************************************注释

***********************************************************************

test: test.o libfunc

$(GCC) -o test test.o -L. -lfunc

%.o:%.c

$(GCC) -c $(CFLAGS) -o $@ $<

clean:

rm -fr *.o

rm -fr *.so*

rm -fr test

要生成.so文件,cc要带-shared 参数;要调用.so的文件,比如libfunc.so,可以在cc命令最后加上

-lfunc,还要视情况加上-L/usr/xxx 指出libfunc.so的路径;这样,在你要编译的源文件中就可以调用

libfunc.so这个库文件的函数.

前面的都说的差不多了,最后提醒一下最好提供一个接口头文件

动态加载,用dlopen,dlclose,dlsym


展开阅读全文

没有更多推荐了,返回首页