`
loyalbluer
  • 浏览: 41414 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
文章分类
社区版块
存档分类
最新评论

Linux动态链接库编程入门

阅读更多
动态链接库是一种通用的软件组件技术,是多种操作系统中提供基本服务的方式。比如Win32内核就是3个DLL文件构成。这种技术在Linux操作系统下也有对应的实现,就是Linux标准对象Standard Ojbect,对应的文件扩展名为.so。

  下面通过一个简单的例子开始介绍Linux标准对象。
  我们的标准对象文件含有一个函数,不需要声明export导出符号,只需要编译器设置即可。如下:

#include <stdio.h>
#include <stdlib.h>

void show() {
  printf("Standard Object by gashero\n");
}

  保存为myso.c文件,按照如下编译:

$ gcc -fPIC -shared -o libmyso.so myso.c

  执行生成一个libmyso.so文件,按照Linux标准对象的命名惯例,应该在库名称之前加上"lib"前缀,尽管不是必须的。编译开关-fPIC代表函数符号可以重定向,-shared代表编译结果是一个标准对象。

  不同于Win32DLL,Linux标准对象中的所有函数都是直接导出的,都可以被调用程序所访问。下面我们编写调用程序:

#include <stdio.h>

int main() {
  printf("Invoke my so\n");
  show();
  return 0;
}

  保存为invoke.c,按照如下gcc开关编译:

$ gcc -o test invoke.c ./libmyso.so

  编译生成test可执行文件。如上编译条件的最后一条需要是所调用的标准对象文件名,注意必须含有路径。如果只是使用libmyso.so,则必须确保这个文件在可访问的PATH下面。本例所使用的文件名"./libmyso.so"是当前路径下的,使用了相对路径。

  如下测试结果:

$ ./test
Invoke my so
Standard Object by gashero

  希望上文的例子可以对大家有所帮助。

如何在 Linux 下调试动态链接库

大家都知道在 Linux 可以用 gdb 来调试应用程序,当然前提是用 gcc 编译程序时要加上

-g 参数。
我这篇文章里将讨论一下用 gdb 来调试动态链接库的问题。


  首先,假设我们准备这样的一个动态链接库:

QUOTE:
库名称是: ggg
动态链接库文件名是: libggg.so
头文件是: get.h
提供这样两个函数调用接口:
    int get ();
    int set (int a);

要生成这样一个动态链接库,我们首先编写这样一个头文件:

[Copy to clipboard]
CODE:
/************关于本文档********************************************
*filename: get.h
*purpose:  一个动态链接库头文件示例
*tided by: zhoulifa(zhoulifa@163.com) 周立发 (http://zhoulifa.9999mb.com)
Linux 爱好者 Linux 知识传播者 SOHO 族 开发者 最擅长 C 语言
*date time: 2006-11-15 21:11:54
*Note: 任何人可以任意复制代码并运用这些文档,当然包括你的商业用途
* 但请遵循 GPL
*Hope:希望越来越多的人贡献自己的力量,为科学技术发展出力
* 科技站在巨人的肩膀上进步更快!感谢有开源前辈的贡献!
*感谢 vcclass@hotmail.com 提供原始代码,

我在他的基础上整理了此文
*********************************************************************/
int get ();
int set (int a);

然后准备这样一个生成动态链接库的源文件:

[Copy to clipboard]
CODE:
/************关于本文档********************************************
*filename:  get.cpp
*purpose: 一个动态链接库源文件示例
*tided by: zhoulifa(zhoulifa@163.com) 周立发 (http://zhoulifa.9999mb.com)
Linux 爱好者 Linux 知识传播者 SOHO 族 开发者 最擅长 C 语言
*date time:2006-11-15 21:11:54
*Note: 任何人可以任意复制代码并运用这些文档,当然包括你的商业用途
* 但请遵循 GPL
*Hope:希望越来越多的人贡献自己的力量,为科学技术发展出力
* 科技站在巨人的肩膀上进步更快!感谢有开源前辈的贡献!
*感谢 vcclass@hotmail.com 提供原始代码,

我在他的基础上整理了此文
*********************************************************************/
#include <stdio.h>

#include "get.h"



static int x=0;

int get ()

{

        printf ("get x=%d\n", x);

        return x;

}

int set (int a)

{

        printf ("set a=%d\n", a);

        x = a;

        return x;

}

然后我们用 GNU 的 C/C++ 编译器来生成动态链接库,编译命令如下:

QUOTE:
g++ get.cpp -shared -g -DDEBUG -o libggg.so

这样我们就准备好了动态链接库了,下面我们编写一个应用程序来调用此动态链接库,源代码如下:

[Copy to clipboard]
CODE:
/************关于本文档********************************************
*filename: pk.cpp
*purpose: 一个调用动态链接库的示例
*tided by: zhoulifa(zhoulifa@163.com) 周立发 (http://zhoulifa.9999mb.com)
Linux 爱好者 Linux 知识传播者 SOHO 族 开发者 最擅长 C 语言
*date time:2006-11-15 21:11:54
*Note: 任何人可以任意复制代码并运用这些文档,当然包括你的商业用途
* 但请遵循 GPL
*Hope:希望越来越多的人贡献自己的力量,为科学技术发展出力
* 科技站在巨人的肩膀上进步更快!感谢有开源前辈的贡献!
*感谢 vcclass@hotmail.com 提供原始代码,

我在他的基础上整理了此文
*********************************************************************/
#include <stdio.h>

#include "get.h"

int main (int argc, char** argv)

{

        int a = 100;

        int b = get ();

        int c = set (a);

        int d = get ();



        printf ("a=%d,b=%d,c=%d,d=%d\n",a,b,c,d);

        return 0;

}

编译此程序用下列命令,如果已经把上面生成的 libggg.so 放到了库文件搜索路径指定的文件目录,比如 /lib 或 /usr/lib 之类的,就用下面这条命令:

QUOTE:
g++ pk.cpp -o app -Wall -g -lggg

否则就用下面这条命令:

QUOTE:
g++ pk.cpp -o app -Wall -g -lggg -L`pwd`

下面我们就开始调试上面命令生成的 app 程序吧。如果已经把上面生成的 libggg.so 放到了库文件搜索路径指定的文件目录,比如 /lib或 /usr/lib 之类的,调试就顺利完成,如下



QUOTE:
linux#gdb">zhoulifa@linux#gdb ./app
GNU gdb 6.4-debian
Copyright 2005 Free Software Foundation,Inc.
GDB is free software, covered by the GNU

General Public License, and you are
welcome to change it and/or distribute

copies of it under certain conditions.
Type "show copying" to see theconditions.


There is absolutely no warranty for GDB.

Type "show warranty" for details.This GDB was configured as "i486-linux-

gnu"...Using host libthread_db library"/lib/tls/i686/cmov/libthread_db.so.1".

(gdb) b main    /* 这是在程序的 main 处设置断点 */
Breakpoint 1 at 0x804853c: file pk.cpp,line 7.
(gdb) b set      /* 这是在程序的 set 处设置断点 */
Function "set" not defined.
Make breakpoint pending on future shared

library load? (y or [n]) y /* 这里必须选择 y 调试程序才会跟踪到动态链接库内部去

*/Breakpoint 2 (set) pending.
(gdb) run /* 开始运行我们的程序,直到遇见断点时暂停 */
Starting program: /data/example/c/app
Breakpoint 3 at 0xb7f665f8: file get.cpp,line 11.
Pending breakpoint "set" resolved

Breakpoint 1, main (argc=1,argv=0xbf990504) at pk.cpp:7
7               int a = 100;
(gdb) n     /* 继续执行程序的下一行代码

*/
8               int b = get ();
(gdb) n      /* 程序执行到了我们断点所在的动态链接库了 */
get x=0
9               int c = set (a);(gdb) n

Breakpoint 3, set (a=100) at get.cpp:11
11              printf ("set a=%d\n", a);

(gdb) list   /* 查看当前代码行周围的代码,证明我们已经跟踪到动态链接库的源代码里面了 */
6               printf ("get x=%d\n", x);
7               return x;
8       }
9       int set (int a)
10      {
11              printf ("set a=%d\n", a);
12              x = a;
13              return x;
14      }
(gdb) n
set a=100
12              x = a;(gdb) n
13              return x;(gdb) n
14      }
(gdb) n
main (argc=1, argv=0xbf990504) at

pk.cpp:10
10              int d = get ();
(gdb) n
get x=100
11              printf ("a=%d,b=%d,c=%

d,d=%d\n",a,b,c,d);
(gdb) n
a=100,b=0,c=100,d=100
12              return 0;
(gdb) c
Continuing.

Program exited normally.
(gdb) quit  /* 程序顺利执行结束 */zhoulifa@linux#

如果我们没有把动态链接库放到指定目录,比如/lib里面,调试就会失败,过程如下:

QUOTE:
zhoulifa@linux# gdb ./app
GNU gdb 6.4-debian
Copyright 2005 Free Software Foundation,

Inc.
GDB is free software, covered by the GNU

General Public License, and you arewelcome to change it and/or distribute

copies of it under certain conditions.


Type "show copying" to see theconditions.
There is absolutely no warranty for GDB.

Type "show warranty" for details.
This GDB was configured as "i486-linux-

gnu"...Using host libthread_db library

"/lib/tls/i686/cmov/libthread_db.so.1".

(gdb) b main
Breakpoint 1 at 0x804853c: file pk.cpp,

line 7.
(gdb) b set
Function "set" not defined.
Make breakpoint pending on future shared

library load? (y or [n]) y
Breakpoint 2 (set) pending.
(gdb) run  /* 虽然调试操作都一样,但程序执行失败 */
Starting program: /data/example/c/app
/data/example/c/app: error while loading

shared libraries: libggg.so: cannot open

shared object file: No such file or

directory

Program exited with code 0177.
(gdb) quit
zhoulifa@linux#
本次实验的环境是:
CPU:AMD Athlon(tm) 64 Processor 3000+
内存:512M
OS:Ubuntu GNU/Linux 6.06 dapper LTS
gcc:gcc 版本 4.0.3 (Ubuntu 4.0.3-1ubuntu5)

Linux下使用动态链接库

使用动态链接库,我认为,再比较大的程序运行过程中,是一种很有优势的。所以就花了一天时间来学习一下。

使用动态链接库,需要了解一下内容

头文件:
<dlfcn.h>
函数:
void *dlopen(const char *filename, int flag);
const char *dlerror(void);
void *dlsym(void *handle, char *symbol);
int dlclose(void *handle);


相关的信息可以通过 man dlopen查询

在编译动生成态链接库的时候,
需要参数 -shared

在使用动态链接库的时候,
需要参数 -ldl

其他相关参数有
-fpic -fPIC  -rdynamic

如有库函数文件Lib.c, 主函数文件Main.c
则有如下Makefile

all: comple link

comple:
    gcc -c Lib.c -o Lib.o
    gcc -c Main.c -o Main.o

link:
    gcc -shared Lib.o -o Lib.so
    gcc -ldl Main.o -o Main


另外,在C++中使用动态连接库的时候,请注意:
必须用
extern "C"
{
}
将动态苦定义为C的编译连接方式

否则由于C++命名方式于C不同,会造成生成的动态链接库不能使用(无法定位或函数)

文章选取的例子非常简单,上手容易,只是为了讲述静态与动态链接库的生成和链接过
    程,还有他们之间的区别。以下例子在 gcc 4.1.1 下顺利通过。


文件预览 (补充)
文件目录树如下,如你所见,非常简单。

   1. libtest/ 
   2. |-- lt.c 
   3. |-- lt.h 
   4. `-- test.c 



代码
#lt.c

   1. /* lt.c
   2.  *
   3.  */ 
   4.  
   5. #include <stdio.h> 
   6.  
   7. void myprint(void) 
   8. { 
   9.   printf("Linux library test!\n"); 
  10. } 



# lt.h

   1. /* lt.h
   2.  * 
   3.  */ 
   4.  
   5. void myprint(void); 



#test.c

   1. /* test.c
   2.  *
   3.  */ 
   4.  
   5. #include "lt.h" 
   6.  
   7. int main(void) 
   8. { 
   9.   myprint(); 
  10.   return 0; 
  11. } 


先看静态库
首先做成静态库 liblt.a 。

   1. $ gcc -c lt.c -o lt.o 
   2. $ ar cqs liblt.a lt.o 




再者,链接,这里指定了静态库的位置,注意文件顺序不可乱序。

   1. $ gcc test.o liblt.a -o test 



这个时候再来看他的引用库情况。

   1. $ ldd test 
   2.         linux-gate.so.1 =>  (0xffffe000) 
   3.         libc.so.6 => /lib/libc.so.6 (0xb7e29000) 
   4.         /lib/ld-linux.so.2 (0xb7f6e000) 



动态库
做成动态库 liblt.so 。

   1. $ gcc -c lt.c -o lt.o 
   2. $ gcc -shared -Wall -fPIC lt.o -o liblt.so 



链接方法I,拷贝到系统库里再链接,让gcc自己查找

   1. $ sudo cp liblt.so /usr/lib 
   2. $ gcc -o test test.o -llt 


这里我们可以看到了 -llt 选项,-l[lib_name] 指定库名,他会主动搜索
lib[lib_name].so 。这个搜索的路径可以通过 gcc --print-search-dirs来查找。

链接方法II,手动指定库路径

   1. $ cc -o test test.o -llt -B /path/to/lib


这里的-B 选项就添加 /path/to/lib 到gcc搜索的路径之中。这样链接没有问题但是方法II
中手动链接好的程序在执行时候仍旧需要指定库路径(链接和执行是分开的)。需要添加系
统变量 LD_LIBRARY_PATH :

   1. $ export LD_LIBRARY_PATH=/path/to/lib 



这个时候再来检测一下test程序的库链接状况(方法I情况)

   1. $ ldd test 
   2.         linux-gate.so.1 =>  (0xffffe000) 
   3.         liblt.so => /usr/lib/liblt.so (0xb7f58000) 
   4.         libc.so.6 => /lib/libc.so.6 (0xb7e28000) 
   5.         /lib/ld-linux.so.2 (0xb7f6f000) 


恩,是不是比静态链接的程序多了一个 liblt.so ?恩,这就是静态与动态的最大区别,静
态情况下,他把库直接加载到程序里,而在动态链接的时候,他只是保留接口,将动态库与
程序代码独立。这样就可以提高代码的可复用度,和降低程序的耦合度。

参考:http://www-128.ibm.com/developerworks/cn/linux/sdk/dll/index.html
http://www.oklinux.cn/html/developer/java/20070630/33743.html
http://blog.csdn.net/wenxy1/archive/2005/12/15/553216.aspx
分享到:
评论

相关推荐

    头歌Linux系统编程之c编程入门

    3. **Linux编译C程序**:讲解如何在Linux下编译C程序,包括源代码的编译、链接以及静态库和动态库的使用。理解编译命令如`gcc`的不同选项,如 `-c`用于编译成目标文件,`-o`指定输出文件名。 4. **Linux时间编程**...

    《Linux下Qt编程入门》

    这可能涉及动态链接库的处理和Qt运行时环境的安装。 4. 扩展学习:除了基本的Qt编程,还可以深入学习网络编程、数据库集成、多线程、国际化、单元测试等高级主题,提升Qt开发技能。 总结,Linux下的Qt编程是一个...

    linux 编程教程 -- linux下编程入门

    Linux编程教程——Linux下编程入门 在Linux操作系统中进行编程是一项重要的技能,尤其对于系统级开发者和软件工程师来说。Linux提供了丰富的开发环境和工具,支持多种编程语言,如C、C++、Python、Java等。本教程将...

    linux下c语言编程入门

    ### Linux下C语言编程入门知识点概览 #### 1. Linux程序设计入门——基础知识 - **源程序的编译** - 在Linux环境下,C语言编程的编译工作主要依赖于GNU的`gcc`编译器。通过示例程序`hello.c`,我们可以了解编译...

    嵌入式linux C编程入门程序代码_2

    本主题将深入探讨嵌入式Linux C编程的基本概念、环境搭建、编程技巧以及常见问题,帮助初学者入门这一领域。 首先,理解嵌入式系统与通用计算机系统的区别至关重要。嵌入式系统是针对特定功能设计的计算机系统,...

    Linux操作系统C语言编程入门pd

    这个压缩包文件"Linux操作系统C语言编程入门pd"显然是一份关于这个主题的学习资料,可能是电子书或教程。以下将详细介绍Linux操作系统和C语言编程相关的知识点。 首先,Linux操作系统是一种开源、免费的类UNIX系统...

    linux环境C语言编程入门

    "Linux环境C语言编程入门"这本书籍旨在引导初学者掌握在Linux系统中编写、编译和调试C程序的基本技巧。 首先,C语言是一种强大的编程语言,它简洁、高效,且提供了对底层硬件的直接访问,因此在系统级编程中广泛...

    宫虎波的linux编程从入门到精通ppt

    PPT会涵盖C语言的基本语法、内存管理、动态链接库、错误处理等内容,同时还会讲解如何使用GCC编译器和GDB调试器进行程序开发和调试。 Linux的Shell脚本编写是提高工作效率的有效工具。通过学习如何编写Shell脚本,...

    Linux操作系统C语言编程入门

    总结来说,"Linux操作系统C语言编程入门"涵盖了从基本的C语言语法到Linux系统编程的各个方面,包括文件操作、进程控制、内存管理、错误处理、线程编程以及调试技巧。通过深入学习这些知识点,你将能够熟练地在Linux...

    Linux操作系统下C语言编程入门

    ### Linux操作系统下C语言编程入门知识点 #### 一、基础知识 - **源程序编译**:在Linux环境下,使用GNU的`gcc`编译器来编译C语言源程序是最常见的做法。例如,对于一个简单的C语言源文件`hello.c`,可以通过命令`...

    Linux操作系统C语言编程入门.pdf )

    ### Linux操作系统C语言编程入门知识点概述 #### 一、源程序编译 在Linux环境下进行C语言编程时,最常用的编译器是GNU的`gcc`。通过`gcc`可以将C语言源代码编译成可执行文件。例如,对于一个简单的`hello.c`文件,...

    linux操作系统下c语言编程入门

    ### Linux操作系统下C语言编程入门知识点详解 #### (一) 目录介绍 本文档将详细介绍在Linux操作系统环境下使用C语言进行编程的相关知识点。主要内容包括: 1. **Linux程序设计入门——基础知识** - 源程序编译 ...

Global site tag (gtag.js) - Google Analytics