C_C++ 编译器和调试器以及静态库、动态库使用

C_C++ 编译器和调试器以及静态库、动态库使用
C_C++ 编译器和调试器以及静态库、动态库使用

C/C++ 编译器和调试器以及静态库、动态库使用汇总

阅读提示:本文是C/C++ 编译器和调试器以及静态库、动态库使用汇总

大多数unix系统下面的调试器的使用方法如下:

gdb介绍

GNU 的调试器称为gdb,该程序是一个交互式工具,工作在字符模式。在X Window 系统中,有一个gdb 的

前端图形工具,称为xxgdb。gdb 是功能强大的调试程序,可完成如下的调试任务:

* 设置断点;

* 监视程序变量的值;

* 程序的单步执行;

* 修改变量的值。

在可以使用gdb 调试程序之前,必须使用-g 选项编译源文件。可在makefile 中如下定义CFLAGS 变量:

CFLAGS = -g

运行gdb 调试程序时通常使用如下的命令:

gdb progname

在gdb 提示符处键入help,将列出命令的分类,主要的分类有:

* aliases:命令别名

* breakpoints:断点定义;

* data:数据查看;

* files:指定并查看文件;

* internals:维护命令;

* running:程序执行;

* stack:调用栈查看;

* statu:状态查看;

* tracepoints:跟踪程序执行。

键入help 后跟命令的分类名,可获得该类命令的详细清单。

gdb 的常用命令

命令解释

break NUM 在指定的行上设置断点。

bt 显示所有的调用栈帧。该命令可用来显示函数的调用顺序。

clear 删除设置在特定源文件、特定行上的断点。其用法为:clear FILENAME:NUM。continue 继续执行正在调试的程序。该命令用在程序由于处理信号或断点而

导致停止运行时。

display EXPR 每次程序停止后显示表达式的值。表达式由程序定义的变量组成。

file FILE 装载指定的可执行文件进行调试。

help NAME 显示指定命令的帮助信息。

info break 显示当前断点清单,包括到达断点处的次数等。

info files 显示被调试文件的详细信息。

info func 显示所有的函数名称。

info local 显示当函数中的局部变量信息。

info prog 显示被调试程序的执行状态。

info var 显示所有的全局和静态变量名称。

kill 终止正被调试的程序。

list 显示源代码段。

make 在不退出gdb 的情况下运行make 工具。

next 在不单步执行进入其他函数的情况下,向前执行一行源代码。

print EXPR 显示表达式EXPR 的值。

gdb 使用范例

-----------------

清单一个有错误的C 源程序bugging.c

-----------------

#include

#include

static char buff [256];

static char* string;

int main ()

{

printf ("Please input a string: ");

gets (string);

printf ("\nYour string is: %s\n", string);

}

-----------------

上面这个程序非常简单,其目的是接受用户的输入,然后将用户的输入打印出来。该程序使用了一个未经过初

始化的字符串地址string,因此,编译并运行之后,将出现Segment Fault 错误:

$ gcc -o test -g test.c

$ ./test

Please input a string: asfd

Segmentation fault (core dumped)

为了查找该程序中出现的问题,我们利用gdb,并按如下的步骤进行:

1.运行gdb bugging 命令,装入bugging 可执行文件;

2.执行装入的bugging 命令;

3.使用where 命令查看程序出错的地方;

4.利用list 命令查看调用gets 函数附近的代码;

5.唯一能够导致gets 函数出错的因素就是变量string。用print 命令查看string 的值;6.在gdb 中,我们可以直接修改变量的值,只要将string 取一个合法的指针值就可以了,为此,我们在第

11 行处设置断点;

7.程序重新运行到第11 行处停止,这时,我们可以用set variable 命令修改string 的取值;

8.然后继续运行,将看到正确的程序运行结果。

运行gcc/egcs

GCC 是GNU 的C 和C++ 编译器。实际上,GCC 能够编译三种语言:C、C++ 和Object C(C 语言的一种面向对象扩展)。利用gcc 命令可同时编译并连接C 和C++ 源程序。如果你有两个或少数几个C 源文件,也可以方便地利用GCC 编译、连接并生成可执行文件。例如,假设你有

两个源文件main.c 和factorial.c 两个源文件,现在要编译生成一个计算阶乘的程序。

清单factorial.c

-----------------------

#include

#include

int factorial (int n)

{

if (n <= 1)

return 1;

else

return factorial (n - 1) * n;

}

-----------------------

-----------------------

清单main.c

-----------------------

#include

#include

int factorial (int n);

int main (int argc, char **argv)

{

int n;

if (argc < 2) {

printf ("Usage: %s n\n", argv [0]);

return -1;

}

else {

n = atoi (argv[1]);

printf ("Factorial of %d is %d.\n", n, factorial (n));

}

return 0;

}

-----------------------

利用如下的命令可编译生成可执行文件,并执行程序:

$ gcc -o factorial main.c factorial.c

$ ./factorial 5

Factorial of 5 is 120.

GCC 可同时用来编译C 程序和C++ 程序。一般来说,C 编译器通过源文件的后缀名来判断是C 程序还是C+

+ 程序。在Linux 中,C 源文件的后缀名为.c,而C++ 源文件的后缀名为.C 或.cpp。但是,gcc 命令只能编译C++ 源文件,而不能自动和C++ 程序使用的库连接。因此,通常使用g++ 命令来完

完成C++ 程序的编译和连接,该程序会自动调用gcc 实现编译。

假设我们有一个如下的C++ 源文件(hello.C):

#include

void main (void)

{

cout << "Hello, world!" << endl;

}

则可以如下调用g++ 命令编译、连接并生成可执行文件:

$ g++ -o hello hello.C

$ ./hello

Hello, world!

gcc/egcs 的主要选项

选项解释

-ansi 只支持ANSI 标准的C 语法。这一选项将禁止GNU C 的某些特色,

例如asm 或typeof 关键词。

-c 只编译并生成目标文件。

-DMACRO 以字符串“1”定义MACRO 宏。

-DMACRO=DEFN 以字符串“DEFN”定义MACRO 宏。

-E 只运行C 预编译器。

-g 生成调试信息。GNU 调试器可利用该信息。

-IDIRECTORY 指定额外的头文件搜索路径DIRECTORY。

-LDIRECTORY 指定额外的函数库搜索路径DIRECTORY。

-lLIBRARY 连接时搜索指定的函数库LIBRARY。

-m486 针对486 进行代码优化。

-o FILE 生成指定的输出文件。用在生成可执行文件时。

-O0 不进行优化处理。

-O 或-O1 优化生成代码。

-O2 进一步优化。

-O3 比-O2 更进一步优化,包括inline 函数。

-shared 生成共享目标文件。通常用在建立共享库时。

-static 禁止使用共享连接。

-UMACRO 取消对MACRO 宏的定义。

-w 不生成任何警告信息。

-Wall 生成所有警告信息。

SCO UNIX下面dbaxtra的调试技术

在sco unix下编程大多离不开C语言,即使是数据库应用也有很多是与c搭配使用的,例如informix esql/c 就可以在c语言中嵌入sql 语句。很多人认为在unix下写程序是件很痛苦的事情,其中一个很重要原因是不知道在unix下怎样调试程序。其实在sco unix源码调试器是dbxtra或dbXtra,linux下是gdb。它们类似turbo c的调试器,可以跟踪源码变量。在unix 下调试程序有如下传统方法

一、在要调试语句之前,输出要调试的变量,利用printf()函数。

二、写日志文件,把结果输出到文件中避免屏幕混乱,利用fprintf()函数。

三、利用sco 内置调试器dbxtra或dbXtra。

dbxtra 适用字符界面,在sco unix的图形界面用dbXtra。(编按:请注意大小写)

以下是dbxtra基本命令:

c cont 在断点后继续执行

d delet

e 删除所设断点

h help 帮助

e edit 编辑源程序

n next 源程序区的内容向下翻一屏。

p print 显示变量

q quit 退出dbxtra

r run 运行程序,直到遇上设置的断点

rr rerun 再次运行

s step 单步运行

st stop 设置断点

j status 显示当前断点

t where 显示当前状态,列出所有设置的变量值

di display 开显示窗,用于查看变量

ud undisplay 删除显示窗的条目

f forward 源程序区的内容向上翻一屏。

B backward 源程序区的内容向下翻一屏。

Stopi stop inst 设置断点

tracei trace inst跟踪子程序

dbxtra [options] [objectfile ]

dbxtra 在启动时有个参数-Idir值得一提.我们在编写一个较大程序的时候,通常源程序和编译生成的可执行文件都放在不同的目录中,这样便于管理。默认dbxtra将在可执行文件所在的目录下找匹配c的源程序。当我们启动时,指定-I参数,dbxtra就会到我们指定的目录下找匹配的c程序。例如:

dbxtra -I"\work\c" program1

源程序在用cc编译时要带上-g 参数,这样是加上符号表等调试信息。只有这样编译过的文件,dbxtra才可以调试。调试信息使源代码和机器码关联。

下面这个C程序输出结果和我们的预想结果不一样,说明某些地方有错误。我们用调试器

来调试它:

程序一:

t.c

main()

{ int i=10 ,*p1;

float j=1.5,*p2;

p1=&

p2=&

p2=p1;

printf("%d,%d\n",*p1,*p2);

}

首先带上-g参数编译cc -g -o t t.c

启动调试器dbxtra t

屏幕显示:

1.main()

2.{ int i=10 ,*p1;

3. float j=1.5,*p2;

4. p1=&

5. p2=&

6. p2=p1;

7. printf("%d,%d\n",*p1,*p2);

8.}

C[browse] File:t.c Func.-

Readubg symbolic information

Type 'help' for help

(dbxtra)

(dbxtra)

设置断点:

(dbxtra)stop at 5

运行:

(dbxtra) run

程序自动在第5行停下。

这时我们可以看变量的值。

(dbxtra) print *p1

单步执行。

(dbxtra) step

程序将执行第5行源码,指针将移到第6行。

(dbxtra) print *p2

(dbxtra)step

程序执行了第6行源码后,将指针移到第7行。

(dbxtra)print *p1 , *p2

我们发现在执行了第6行源码后,*p1,*p2的值就不对了,所以问题就出在第6行上。仔细检查后发现指针p1指向整型,指针p2指向实型。它们之间的赋值要进行强制类型转换。这种错误在C程序中是很常见的。

有时我们在调试一些程序时,要在整个程序运行中时刻监视莫些变量的值,例如程序一中我们要时刻了解*p1,*p2的值,除了在每一行程序执行完后,打print *p1,*p2外,还可以开一个显示窗口。

(dbxtra)display *p1,*p2

用undisplay 删掉不想要的变量。

有些程序运行时要带参数,mycat /etc/passwd 在调试时候

(dbxtra) run '/etc/passwd'

再运行时,无需再写一遍参数。

(dbxtra)rerun

在涉及到curses库编程或屏幕有大量的人机界面时,为了调试方便,我们可以把程序输出结果重定向到个虚屏。

(dbxtra)run >/dev/tty03

当然要先把tty03 disable 掉。(disable tty03)

创建和使用静态库

详细的使用情况,请大家man手册,这里只介绍一下。静态库相对的比较简单。

创建一个静态库是相当简单的。通常使用ar 程序把一些目标文件(.o)组合在一起,成为一个单独的库,然后运行ranlib,以给库加入一些索引信息。

创建和使用共享库

特殊的编译和连接选项

-D_REENTRANT 使得预处理器符号_REENTRANT 被定义,这个符号激活一些宏特性。-fPIC 选项产生位置独立的代码。由于库是在运行的时候被调入,因此这个选项是必需的,因为在编译的时候,装入内存的地址还不知道。如果不使用这个选项,库文件可能不会正确运行。

-shared 选项告诉编译器产生共享库代码。

-Wl,-soname -Wl 告诉编译器将后面的参数传递到连接器。而-soname 指定了共享库的soname。

#可以把库文件拷贝到/etc/ld.so.conf 中列举出的任何目录中,并以

root 身份运行ldconfig;或者#运行export LD_LIBRARY_PA TH='pwd',它把当前路径加到库搜索路径中去。

使用高级共享库特性

1. ldd 工具

ldd 用来显示执行文件需要哪些共享库, 共享库装载管理器在哪里找到了需要的共享库. 2. soname

共享库的一个非常重要的,也是非常难的概念是soname——简写共享目标名(short for shared object name)。这是一个为共享库(.so)文件而内嵌在控制数据中的名字。如前面提到的,每一个程序都有一个需要使用的库的清单。这个清单的内容是一系列库的soname,如同ldd 显示的那样,共享库装载器必须找到这个清单。

soname 的关键功能是它提供了兼容性的标准。当要升级系统中的一个库时,并且新库的soname 和老的库的soname 一样,用旧库连接生成的程序,使用新的库依然能正常运行。这个特性使得在Linux 下,升级使用共享库的程序和定位错误变得十分容易。

在Linux 中,应用程序通过使用soname,来指定所希望库的版本。库作者也可以通过保留或者改变soname 来声明,哪些版本是相互兼容的,这使得程序员摆脱了共享库版本冲突问题的困扰。

查看/usr/local/lib 目录,分析MiniGUI 的共享库文件之间的关系

3. 共享库装载器

当程序被调用的时候,Linux 共享库装载器(也被称为动态连接器)也自动被调用。它的作用是保证程序所需要的所有适当版本的库都被调入内存。共享库装载器名字是ld.so 或者是ld-linux.so,这取决于Linux libc 的版本,它必须使用一点外部交互,才能完成自己的工作。然而它接受在环境变量和配置文件中的配置信息。

文件/etc/ld.so.conf 定义了标准系统库的路径。共享库装载器把它作为搜索路径。为了改变这个设置,必须以root 身份运行ldconfig 工具。这将更新/etc/ls.so.cache 文件,这个文件其实是装载器内部使用的文件之一。

可以使用许多环境变量控制共享库装载器的操作(表1-4+)。

表1-4+ 共享库装载器环境变量

变量含义

LD_AOUT_LIBRARY_PATH 除了不使用a.out 二进制格式外,与LD_LIBRARY_PATH 相同。

LD_AOUT_PRELOAD 除了不使用a.out 二进制格式外,与LD_PRELOAD 相同。

LD_KEEPDIR 只适用于a.out 库;忽略由它们指定的目录。

LD_LIBRARY_PA TH 将其他目录加入库搜索路径。它的内容应该是由冒号

分隔的目录列表,与可执行文件的PA TH 变量具有相同的格式。

如果调用设置用户ID 或者进程ID 的程序,该变量被忽略。

LD_NOW ARN 只适用于a.out 库;当改变版本号是,发出警告信息。

LD_PRELOAD 首先装入用户定义的库,使得它们有机会覆盖或者重新定义标准库。

使用空格分开多个入口。对于设置用户ID 或者进程ID 的程序,

只有被标记过的库才被首先装入。在/etc/ld.so.perload 中指定

了全局版本号,该文件不遵守这个限制。

4. 使用dlopen

另外一个强大的库函数是dlopen()。该函数将打开一个新库,并把它装入内存。该函数主要用来加载库中的符号,这些符号在编译的时候是不知道的。比如Apache Web 服务器利用这个函数在运行过程中加载模块,这为它提供了额外的能力。一个配置文件控制了加载模块的过程。这种机制使得在系统中添加或者删除一个模块时,都不需要重新编译了。

可以在自己的程序中使用dlopen()。dlopen() 在dlfcn.h 中定义,并在dl 库中实现。它需要两个参数:一个文件名和一个标志。文件名可以是我们学习过的库中的soname。标志指明是否立刻计算库的依赖性。如果设置为RTLD_NOW 的话,则立刻计算;如果设置的是RTLD_LAZY,则在需要的时候才计算。另外,可以指定RTLD_GLOBAL,它使得那些在以后才加载的库可以获得其中的符号。

当库被装入后,可以把dlopen() 返回的句柄作为给dlsym() 的第一个参数,以获得符号在库中的地址。使用这个地址,就可以获得库中特定函数的指针,并且调用装载库中的相应函数。

LINUX动态链接库的使用

一、编写合格的动态链接库头文件

C语言的头文件,可供一个或多个程序引用,里面一般定义程序所需的常量,自定义类型及函数原型说明等.其中的函数原型说明,则供编译器检查语法,用于排除引用参数时类型不一致的错误.只有编写合格的动态链接库头文件,程序员才能正确使用动态链接库内的函数.

动态链接库头文件要采用C语言标准格式,其中的动态函数原型定义,不必象上文介绍的那样用(*动态函数名)的描述形式.请看下面的例子每行开始的数字为所在行行号,为笔者添加,供注解使用)

1 /* adatetime.h : 纵横软件制作中心雨亦奇(zhsoft@https://www.360docs.net/doc/f48948395.html,)编写, 2002-03-06. */

2

3 #ifndef __DATETIME_H

4

5 #define __DATETIME_H

6

7 /* 日期结构*/

8 typedef struct

9 {

10 int year;

11 int mon;

12 int day;

13 }DATETYPE;

14

15 /* 时间结构*/

16 typedef struct

17 {

18 char hour;

19 char min;

20 char sec;

21 }TIMETYPE;

22

23 int getdate(DATETYPE *d); /* 取当前日期*/

24 int gettime(TIMETYPE *t); /* 取当前时间*/

25

26 #endif

27

注:与上文的datetime.h文件比较,从该头文件第23,24行可以看到,动态函数getdate,gettime的原型定义改变了,不再使用(*getdate),(*gettime)的格式了(这种格式使用较为罗嗦).

二、正确编译与命名动态链接库

为了让GCC编译器生成动态链接库,编译时须加选项-shared.(这点须牢记)

LINUX系统中,为了让动态链接库能被系统中其它程序共享,其名字应符合“lib*.so*”这种格式.如果某个动态链接库不符合此格式,则LINUX的动态链接库自动装入程序(ld.so)将搜索不到此链接库,其它程序也无法共享之.

格式中,第一个*通常表示为简写的库名,第二个*通常表示为该库的版本号.如:在我的系统中,基本C动态链接库的名字为libc.so.6,线程pthread动态链接库的名字为libpthread.so.0等等.本文例子所生成的动态链接库的名字为libmy.so,虽没有版本号,但也符合所要求的格式.

生成该动态链接库的维护文件makefile-lib内容如下:

1 # makefile : 纵横软件制作中心雨亦奇编写, 2002-03-07.

2

3 all : libmy.so

4

5 SRC = getdate.c gettime.c

6

7 TGT = $(SRC:.c=.o)

8

9 $(SRC) : adatetime.h

10 @touch $@

11

12 %.o : %.c

13 cc -c $?

14

15 # 动态链接库(libmy.so)生成

16 libmy.so : $(TGT)

17 cc -s -shared -o $@ $(TGT)

18

运行命令:

$ make -f makefile-lib

$

即生成libmy.so库.

注: 维护文件中,第17行用-shared选项以生成动态链接库,用-s选项以去掉目标文件中的符号表,从而减小文件长度.

三、共享动态链接库

3.1 动态链接库配置文件

为了让动态链接库为系统所使用,需要维护动态链接库的配置文件--/etc/ld.so.conf.此文件内,存放着可被LINUX共享的动态链接库所在目录的名字(系统目录/lib,/usr/lib除外),各个目录名间以空白字符(空格,换行等)或冒号或逗号分隔.一般的LINUX发行版中,此文件均含一个共享目录/usr/X11R6/lib,为X window窗口系统的动态链接库所在的目录.

下面看看我的系统中此文件的内容如何:

# cat /etc/ld.so.conf

/usr/X11R6/lib

/usr/zzz/lib

#

由上可以看出,该动态库配置文件中,增加了一个/usr/zzz/lib目录.这是我自己新建的共享库目录,下面存放我新开发的可供系统共享的动态链接库.

3.2 动态链接库管理命令

为了让动态链接库为系统所共享,还需运行动态链接库的管理命令--ldconfig.此执行程序存放在/sbin目录下.

ldconfig命令的用途,主要是在默认搜寻目录(/lib和/usr/lib)以及动态库配置文件/etc/ld.so.conf 内所列的目录下,搜索出可共享的动态链接库(格式如前介绍,lib*.so*),进而创建出动态装入程序(ld.so)所需的连接和缓存文件.缓存文件默认为/etc/ld.so.cache,此文件保存已排好序的动态链接库名字列表.

ldconfig通常在系统启动时运行,而当用户安装了一个新的动态链接库时,就需要手工运行这个命令.

ldconfig命令行用法如下:

ldconfig [-v|--verbose] [-n] [-N] [-X] [-f CONF] [-C CACHE] [-r ROOT] [-l] [-p|--print-cache] [-c FORMAT] [--format=FORMAT] [-V] [-?|--help|--usage] path...

ldconfig可用的选项说明如下:

(1) -v或--verbose : 用此选项时,ldconfig将显示正在扫描的目录及搜索到的动态链接库,还有它所创建的连接的名字.

(2) -n : 用此选项时,ldconfig仅扫描命令行指定的目录,不扫描默认目录(/lib,/usr/lib),也不扫描配置文件/etc/ld.so.conf所列的目录.

(3) -N : 此选项指示ldconfig不重建缓存文件(/etc/ld.so.cache).若未用-X选项,ldconfig照常更新文件的连接.

(4) -X : 此选项指示ldconfig不更新文件的连接.若未用-N选项,则缓存文件正常更新.

(5) -f CONF : 此选项指定动态链接库的配置文件为CONF,系统默认为/etc/ld.so.conf.

(6) -C CACHE : 此选项指定生成的缓存文件为CACHE,系统默认的是/etc/ld.so.cache,此文件存放已排好序的可共享的动态链接库的列表.

(7) -r ROOT : 此选项改变应用程序的根目录为ROOT(是调用chroot函数实现的).选择此项时,系统默认的配置文件/etc/ld.so.conf,实际对应的为ROOT/etc/ld.so.conf.如用-r /usr/zzz时,打开配置文件/etc/ld.so.conf时,实际打开的是/usr/zzz/etc/ld.so.conf文件.用此选项,可以大大增加动态链接库管理的灵活性.

通常情况下,ldconfig搜索动态链接库时将自动建立动态链接库的连接.选择此项时,将进入专家模式,需要手工设置连接.一般用户不用此项.

(9) -p或--print-cache : 此选项指示ldconfig打印出当前缓存文件所保存的所有共享库的名字.

(10) -c FORMAT 或--format=FORMAT : 此选项用于指定缓存文件所使用的格式,共有三种:old(老格式),new(新格式)和compat(兼容格式,此为默认格式).

(11) -V : 此选项打印出ldconfig的版本信息,而后退出.

(12) -? 或--help 或--usage : 这三个选项作用相同,都是让ldconfig打印出其帮助信息,而后退出.

举三个例子:

例1:

# ldconfig -p

793 libs found in cache `/etc/ld.so.cache'

libzvt.so.2 (libc6) => /usr/lib/libzvt.so.2

libzvt.so (libc6) => /usr/lib/libzvt.so

libz.so.1.1.3 (libc6) => /usr/lib/libz.so.1.1.3

libz.so.1 (libc6) => /lib/libz.so.1

......

#

注: 有时候用户想知道系统中有哪些动态链接库,或者想知道系统中有没有某个动态链接库,这时,可用-p选项让ldconfig输出缓存文件中的动态链接库列表,从而查询得到.例子中,ldconfig命令的输出结果第1行表明在缓存文件/etc/ld.so.cache中找到793个共享库,第2行开始便是一系列共享库的名字及其全名(绝对路径).因为实际输出结果太多,为节省篇幅,以......表示省略的部分.

例2:

# ldconfig -v

/lib:

liby.so.1 -> liby.so.1

libnss_wins.so -> libnss_wins.so

......

/usr/lib:

libjscript.so.2 -> libjscript.so.2.0.0

libkspell.so.2 -> libkspell.so.2.0.0

......

/usr/X11R6/lib:

libmej-0.8.10.so -> libmej-0.8.10.so

libXaw3d.so.7 -> libXaw3d.so.7.0

......

#

注: ldconfig命令在运行正常的情况下,默认不输出什么东西.本例中用了-v选项,以使ldconfig 在运行时输出正在扫描的目录及搜索到的共享库,用户可以清楚地看到运行的结果.执行结束后,ldconfig将刷新缓存文件/etc/ld.so.cache.

例3:

# ldconfig /usr/zhsoft/lib

#

注: 当用户在某个目录下面创建或拷贝了一个动态链接库,若想使其被系统共享,可以执行一下"ldconfig 目录名"这个命令.此命令的功能在于让ldconfig将指定目录下的动态链接库被系统共享起来,意即:在缓存文件/etc/ld.so.cache中追加进指定目录下的共享库.本例让系统共享了/usr/zhsoft/lib目录下的动态链接库.需要说明的是,如果此目录不在/lib,/usr/lib及/etc/ld.so.conf文件所列的目录里面,则再度运行ldconfig时,此目录下的动态链接库可能不被系统共享了.

3.3 动态链接库如何共享

了解了以上知识,我们可以采用以下三种方法来共享动态链接库

注:均须在超级用户状态下操作,以我的动态

链接库libmy.so共享过程为例)

(1)拷贝动态链接库到系统共享目录下,或在系统共享目录下为该动态链接库建立个连接(硬连接或符号连接均可,常用符号连接).这里说的系统共享目录,指的是LINUX动态链接库存放的目录,它包含/lib,/usr/lib以及/etc/ld.so.conf文件内所列的一系列目录.

# cp libmy.so /lib

# ldconfig

#

或:

# ln -s `pwd`/libmy.so /lib

# ldconfig

#

(2)将动态链接库所在目录名追加到动态链接库配置文件/etc/ld.so.conf中.

# pwd >> /etc/ld.so.conf

# ldconfig

#

(3)利用动态链接库管理命令ldconfig,强制其搜索指定目录,并更新缓存文件,便于动态装入. # ldconfig `pwd`

#

需要说明的是,这种操作方法虽然有效,但效果是暂时的,供程序测试还可以,一旦再度运行ldconfig,则缓存文件内容可能改变,所需的动态链接库可能不被系统共享了.与之相比较,前两种方法是可靠的方法,值得业已定型的动态链接库共享时采用.前两种方法还有一个特点,即最后一条命令都是ldconfig,也即均需要更新一下缓存文件,以确保动态链接库的共享生效.

四、含有动态函数的程序的编译

4.1 防止编译因未指定动态链接库而出错

当一个程序使用动态函数时,编译该程序时就必须指定含所用动态函数的动态链接库,否则编译将会出错退出.如本文示例程序ady.c的编译(未明确引用动态链接库libmy.so):

# cc -o ady ady.c

/tmp/ccL4FsJp.o: In function `main':

/tmp/ccL4FsJp.o(.text+0x43): undefined reference to `gettime'

collect2: ld returned 1 exit status

#

注: 因为ady.c所含的动态函数getdate,gettime不在系统函数库中,所以连接时出错.

4.2 编译时引用动态链接库的几种方式

(1)当所用的动态链接库在系统目录(/lib,/usr/lib)下时,可用编译选项-l来引用.即:

# cc -lmy -o ady ady.c

#

注:编译时用-l选项引用动态链接库时,库名须使用其缩写形式.本例的my,表示引用libmy.so 库.若引用光标库libncurses.so,须用-lncurses.注意,-l选项与参数之间不能有空格,否则会出错.

(2)当所用的动态链接库在系统目录(/lib,/usr/lib)以外的目录时,须用编译选项-L来指定动态链接库所在的目录(供编译器查找用),同时用-l选项指定缩写的动态链接库名.即:

# cc -L/usr/zzz/lib -lmy -o ady ady.c

#

(3)直接引用所需的动态链接库.即:

# cc -o ady ady.c libmy.so

#

# cc -o ady ady.c /lib/libmy.so

#

等等.其中,动态链接库的库名可以采用相对路径形式(文件名不以/开头),也可采用绝对路径形式(文件名以/开头).

五、动态链接程序的运行与检查

5.1 运行

编译连接好含动态函数的程序后,就可以运行它了.动态链接程序因为共享了系统中的动态链接库,所以其空间占用很小.但这并不意味功能的减少,它的执行与静态连接的程序执行,效果完全相同.在命令提示符下键入程序名及相关参数后回车即可,如下例:

$ ady

动态链接库高级应用示范

当前日期: 2002-03-11

当前时间: 19:39:06

$

5.2 检查

检查什么?检查动态链接程序究竟需要哪些共享库,系统中是否已有这些库,没有的话,用户好想办法把这些库装上.

怎么检查呢?这里,告诉你一个实用程序--ldd,这个程序就是专门用来检查动态链接程序依赖哪些共享库的.

ldd命令行用法如下:

ldd [--version] [-v|--verbose] [-d|--data-relocs] [-r|--function-relocs] [--help] FILE...

各选项说明如下:

(1) --version : 此选项用于打印出ldd的版本号.

(2) -v 或--verbose : 此选项指示ldd输出关于所依赖的动态链接库的尽可能详细的信息.

(3) -d 或--data-relocs : 此选项执行重定位,并且显示不存在的函数.

(4) -r 或--function-relocs : 此选项执行数据对象与函数的重定位,同时报告不存在的对象.

(5) --help : 此选项用于打印出ldd的帮助信息.

注: 上述选项中,常用-v(或--verbose)选项.

ldd的命令行参数为FILE...,即一个或多个文件名(动态链接程序或动态链接库).

例1:

$ ldd ady

libmy.so => ./libmy.so (0x40026000)

libc.so.6 => /lib/libc.so.6 (0x40028000)

/lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x40000000)

$

注: 每行=>前面的,为动态链接程序所需的动态链接库的名字,而=>后面的,则是运行时系统实际调用的动态链接库的名字,所需的动态链接库在系统中不存在时,=>后面将显示"not found",括号所括的数字为虚拟的执行地址.本例列出ady所需的三个动态链接库,其中libmy.so为自己新建的动态链接库,而libc.so.6与/lib/ld-linux.so.2均为系统的动态链接库,前一个为基本C库,后一个动态装入库(用于动态链接库的装入及运行).

例2:

$ ldd -v ady

libmy.so => ./libmy.so (0x40026000)

libc.so.6 => /lib/libc.so.6 (0x40028000)

/lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x40000000)

Version information:

./ady:

libc.so.6 (GLIBC_2.1.3) => /lib/libc.so.6

libc.so.6 (GLIBC_2.0) => /lib/libc.so.6

./libmy.so:

libc.so.6 (GLIBC_2.1.3) => /lib/libc.so.6

libc.so.6 (GLIBC_2.0) => /lib/libc.so.6

/lib/libc.so.6:

ld-linux.so.2 (GLIBC_2.1.1) => /lib/ld-linux.so.2

ld-linux.so.2 (GLIBC_2.2.3) => /lib/ld-linux.so.2

ld-linux.so.2 (GLIBC_2.1) => /lib/ld-linux.so.2

ld-linux.so.2 (GLIBC_2.2) => /lib/ld-linux.so.2

ld-linux.so.2 (GLIBC_2.0) => /lib/ld-linux.so.2

$

注:本例用-v选项以显示尽可能多的信息,所以例中除列出ady所需要的动态链接库外,还列出了程序所需动态链接库版本方面的信息.

小结: 在LINUX动态链接库的高级应用中,关键有两点,一是如何让动态链接库为LINUX系统所共享,二是编译连接程序时如何做.让动态链接库为系统所共享,主要是用ldconfig管理命令,维护好系统共享库的缓存文件/etc/ld.so.cache.编译连接时如何做?注意连接上所用的动态链接库就可以了。

静态链接库lib和动态链接库dll区别

1.什么是静态连接库,什么是动态链接库 静态链接库与动态链接库都是共享代码的方式,如果采用静态链接库,则无论你愿不愿意,lib 中的指令都全部被直接包含在最终生成的EXE 文件中了。但是若使用DLL,该DLL 不必被包含在最终EXE 文件中,EXE 文件执行时可以“动态”地引用和卸载这个与EXE 独立的DLL 文件。静态链接库和动态链接库的另外一个区别在于静态链接库中不能再包含其他的动态链接库或者静态库,而在动态链接库中还可以再包含其他的动态或静态链接库。静态链接库与静态链接库调用规则总体比较如下。 对于静态链接库(比较简单): 首先,静态链接库的使用需要库的开发者提供生成库的.h头文件和.lib文件。 生成库的.h头文件中的声明格式如下: extern "C" 函数返回类型函数名(参数表); 在调用程序的.cpp源代码文件中如下: #include "..\lib.h" #pragma comment(lib,"..\\debug\\libTest.lib") //指定与静态库一起链接 第二,因为静态链接库是将全部指令都包含入调用程序生成的EXE文件中。因此如果用的是静态链接库,那么也就不存在“导出某个函数提供给用户使用”的情况,要想用就得全要!要不就都别要!:) 对于动态链接库: 动态链接库的使用,根据不同的调用方法,需要提供不同的资源: 1. 静态加载------程序静态编译的时候就静态导入dll,这样的话就需要提供给库 使用者(C客户)如下文件:*.lib文件和.dll文件和*.h。其有2个坏处: 1 程序一开始运行就需要载入整个dll,无法载入程序就不能开始运行; 2 由于载入的是整个dll,需要耗费资源较多 其调用方法如下: #include "..\lib.h" #pragma comment(lib,"..\\debug\\libTest.lib") 但是这种方式的话可以调用Class method. 2.动态加载-----那么只需要提供dll文件。 因此调用程序若想调用DLL中的某个函数就要以某种形式或方式指明它到底想调用哪一个函数。但是无法调用Class method了。 如果要调用Dll中的function,需要经历3个步骤: Handle h=LoadLibrary(dllName) --> GetProcAddress(h,functionName) 返回函数指针,通过函指针调用其function-->FreeLibrary(h) 例如:Another.dll有一个int Add(int x,int y)函数。则完整的调用过程如下:

GCC编译动态和静态链接库

我们通常把一些公用函数制作成函数库,供其它程序使用。函数库分为静态库和动态库两种。静态库在程序编译时会被连接到目标代码中,程序运行时将不再需要该静态库。动态库在程序编译时并不会被连接到目标代码中,而是在程序运行是才被载入,因此在程序运行时还需要动态库存在。本文主要通过举例来说明在Linux中如何创建静态库和动态库,以及使用它们。 在创建函数库前,我们先来准备举例用的源程序,并将函数库的源程序编译成.o文件。 第1步:编辑得到举例的程序--hello.h、hello.c和main.c; hello.c(见程序2)是函数库的源程序,其中包含公用函数hello,该函数将在屏幕上输出"Hello XXX!"。hello.h(见程序1)为该函数库的头文件。main.c(见程序3)为测试库文件的主程序,在主程序中调用了公用函数hello。 1.#ifndef HELLO_H 2.#define HELLO_H 3. 4.void hello(const char *name); 5. 6.#endif //HELLO_H 复制代码 程序1: hello.h 1.#include 2. 3.void hello(const char *name) 4.{ 5.printf("Hello %s!\n", name); 6.} 复制代码 程序2: hello.c 1.#include "hello.h" 2. 3.int main() 4.{ 5.hello("everyone"); 6.return 0; 7.} 复制代码 程序3: main.c

第2步:将hello.c编译成.o文件; 无论静态库,还是动态库,都是由.o文件创建的。因此,我们必须将源程序hello.c通过g cc先编译成.o文件。 在系统提示符下键入以下命令得到hello.o文件。 # gcc -c hello.c # 我们运行ls命令看看是否生存了hello.o文件。 # ls hello.c hello.h hello.o main.c # 在ls命令结果中,我们看到了hello.o文件,本步操作完成。 下面我们先来看看如何创建静态库,以及使用它。 第3步:由.o文件创建静态库; 静态库文件名的命名规范是以lib为前缀,紧接着跟静态库名,扩展名为.a。例如:我们将创建的静态库名为myhello,则静态库文件名就是libmyhello.a。在创建和使用静态库时,需要注意这点。创建静态库用ar命令。 在系统提示符下键入以下命令将创建静态库文件libmyhello.a。 # ar crv libmyhello.a hello.o # 我们同样运行ls命令查看结果: # ls hello.c hello.h hello.o libmyhello.a main.c # ls命令结果中有libmyhello.a。 第4步:在程序中使用静态库; 静态库制作完了,如何使用它内部的函数呢?只需要在使用到这些公用函数的源程序中包含这些公用函数的原型声明,然后在用gcc命令生成目标文件时指明静态库名,gcc将会从静态库中将公用函数连接到目标文件中。注意,gcc会在静态库名前加上前缀lib,然后追加

lib和dll文件的区别和联系

(1)lib是编译时需要的,dll是运行时需要的。 如果要完成源代码的编译,有lib就够了。 如果也使动态连接的程序运行起来,有dll就够了。 在开发和调试阶段,当然最好都有。 (2)一般的动态库程序有lib文件和dll文件。lib文件是必须在编译期就连接到应用程序中的,而dll文件是运行期才会被调用的。如果有dll文件,那么对应的lib文件一般是一些索引信息,具体的实现在dll文件中。如果只有lib文件,那么这个lib文件是静态编译出来的,索引和实现都在其中。静态编译的lib文件有好处:给用户安装时就不需要再挂动态库了。但也有缺点,就是导致应用程序比较大,而且失去了动态库的灵活性,在版本升级时,同时要发布新的应用程序才行。 (3)在动态库的情况下,有两个文件,一个是引入库(.LIB)文件,一个是DLL文件,引入库文件包含被DLL导出的函数的名称和位置,DLL包含实际的函数和数据,应用程序使用LIB文件链接到所需要使用的DLL文件,库中的函数和数据并不复制到可执行文件中,因此在应用程序的可执行文件中,存放的不是被调用的函数代码,而是DLL中所要调用的函数的内存地址,这样当一个或多个应用程序运行是再把程序代码和被调用的函数代码链接起来,从而节省了内存资源。从上面的说明可以看出,DLL和.LIB文件必须随应用程序一起发行,否则应用程序将会产生错误。 一、开发和使用dll需注意三种文件 1、 dll头文件 它是指dll中说明输出的类或符号原型或数据结构的.h文件。当其它应用程序调用dll时,需要将该文件包含入应用程序的源文件中。 2、 dll的引入库文件 它是dll在编译、链接成功后生成的文件。主要作用是当其它应用程序调用dll时,需要将该文件引入应用程序。否则,dll无法引入。 3、 dll文件(.dll) 它是应用程序调用dll运行时,真正的可执行文件。dll应用在编译、链接成功后,.dll文件即存在。开发成功后的应用程序在发布时,只需要有.exe文件和.dll文件,不必有.lib文件和dll头文件。 动态链接库 (DLL) 是作为共享函数库的可执行文件。动态链接提供了一种方法,使进程可以调用不属于其可执行代码的函数。函数的可执行代码位于一个 DLL 中,该 DLL 包含一个或多个已被编译、链接并与使用它们的进程分开存储的函数。DLL 还有助于共享数据和资源。多个应用程序可同时访问内存中单个 DLL 副本的内容。 动态链接与静态链接的不同之处在于:动态链接允许可执行模块(.dll 文件或 .exe 文件)仅包含在运行时定位 DLL 函数的可执行代码所需的信息。在静态链接中,链接器从静态链接库获取所有被引用的函数,并将库同代码一起放到可执行文件中。 使用动态链接代替静态链接有若干优点。DLL 节省内存,减少交换操作,节省磁盘空间,更易于升级,提供售后支持,提供扩展 MFC 库类的机制,支持多语言程序,并使国际版本的创建轻松完成。 lib与dll文件最大区别在调用方面 dll可以静态陷入 lib与DLL 从这一章起,我讲述的内容将特定于windows平台。其实这篇文章也可看作是我在windows下的开发经验总结,因为以后我决定转unix了。 前面有一章说编译与链接的,说得很简略,其实应该放到这一章一块儿来说的。许多单讲

FORTRAN静态库动态库的生成

FORTRAN静态库、动态库的生成、维护与调用 闫昊明2006-9-10 一、FORTRAN静态库的生成与维护 FORTRAN 静态库是经过编译的代码块,它与主程序相对独立,可以被主程序调用,是FORTRAN工程类型之一. 静态库包含一系列子程序,但不包括主程序. 静态库一般具有LIB扩展名并包含目标代码,且静态库存放在它们特定的目录中. FORTRAN静态库在组织大型程序和在不同程序之间共享子程序等方面具有较大的优点,其重要性不言而喻. 当将静态库与主程序联系起来时,在主程序中调用静态库中的任何子程序将编译到相应的可执行程序. 应用静态库的时候,只有所需要的子程序才在编译过程中插入到可执行文件(.EXE),这意味着这种可执行文件将比包含所有的子程序所生成的可执行文件小. 而且,不必担心哪些子程序是需要的,哪些是不需要的,编译器将替你做出选择. 同时,当更改静态库中的子程序时,相应的应用程序可以不做任何改变,而只需要对其进行重新的编译链接,即可获得新的结果,这无疑也是方便的. 目前,常用的FORTRAN静态库有很多种,WINDOWS操作系统下的Compaq Visual FORTRAN version 6.5(简称CVF65)自带的数学统计库IMSL就是一个非常全面的静态库,可以用来解决线性代数和统计学上的很多经典问题. 此外,在NCAR互联网站有很多有用的FORTRAN子程序(网址:https://www.360docs.net/doc/f48948395.html,/softlib/mathlib.html),其中包括地球物理科学问题、离散和快速Fourier变换、可分离的椭圆微分方程、插值、Legendre多项式、普通数学问题、本征值问题求解、线性方程求解、非线性方程求解、常微分方程求解、特殊函数、统计学等常用子程序集等. 这些FORTRAN子程序可以解决很多基础性的问题,因此有很高的利用价值. 在WINDOWS操作系统下,可以用两个命令分别生成静态库. 一个是用‘nmake’命令,它一般用来编译原来应用在UNIX环境下的FORTRAN子程序集,在编译过程中要读取makefile文件中的编译命令,类似于在UNIX下安装软件. 另一个是用‘lib’命令,它可以在WINDOWS环境下编译任何需要集成为静态库的子程序集. 编译静态库在DOS命令行环境下比较方便,以后的命令行都指在此环境下运行. 在编译静态库前,首先要安装CVF65,其次要完成要编译的FORTRAN子程序(*.f90). 对于FORTRAN子程序,最好用FORTRAN90的标准来完成,应该放弃FORTRAN77标准。FORTRAN90是FORTRAN语言从结构化走向面向对象化的重要一步,使FORTRAN语言更加接近C++。在FORTRAN90标准中,对数组的操作既增强了功能又简化了使用,此外自由格式、MODULE、动态数组、指针等的应用大大丰富了FORTRAN语言,使得编程更加轻松。目前,FORTRAN95和FORTRAN2000标准也在应用,它们与FORTRAN90标准比较类似,主要的改进在并行运算方面,因此目前在单机上应用的主要还是FORTRAN90. 在DOS命令行环境下,进入到FORTRAN子程序所在的子目录,然后按下面两个步骤生成FORTRAN静态库. (1)键入“df *.f90 /c”,回车,可以看到CVF65编译器对所有的FORTRAN子程序(*.f90)进行编译,生成*.obj文件(注意,编译时,/c中的“c”必须小写). (2)键入“lib *.obj /out:libname.lib”,回车,可以看到链接生成libname.lib静态库. 需要注意的是,每次加入新的子程序或对静态库中的子程序修改以后,都要按上述两个步骤重新进行编译链接. 生成静态库以后,可用“dumpbin /linkermember libname.lib”来查看静态库中可用的子程序名称. 也可执行“lib /list libname.lib”来查看静态库中的*.obj文件. 当然,也可以在CVF65集成环境下,生成静态库. 步骤如下:

编译生成动态库时,被关联的静态库会被编译到动态库里面

动态库调用静态库. 生成动态库: 需要的目标文件得用-fPIC选项生成. 而静态库所需的目标文件可以不用-fPIC选项. 一个应用程序调用动态库, 而这个动态库其中的函数调用某静态库时,如何生成应用程序呢? 例: /////// static.h void static_print(); ///////static.cpp #include #include "static.h" void static_print() { std::cout<<"This is static_print function"< #include "shared.h" #include "static.h" void shared_print() { std::cout<<"This is shared_print function"; static_print(); } ////////test.cpp #include "share.h" int main() { shared_print(); return 0; } 方法一: 静态库的.o文件也用-fPIC生成. 生成动态库时把静态库加入. 生成应用程序时只加载动态库 g++ -c -fPIC static.cpp // 生成static.o ar -r libstatic.a static.o // 生成静态库libstatic.a g++ -c -fPIC shared.cpp // 生成shared.o g++ -shared shared.o -lstatic -o libshared.so // 生成动态库libshared.so 注: -shared是g++的选项,与shared.o无关. -lstatic选项把libstatic.a的函数加入动态库中. g++ test.cpp -lshared -o test.exe // link libshared.so 到test.exe中. 方法二: 静态库的.o文件不用-fPIC生成. 生成动态库时不加静态库. 生成应用程序时加载动态库和静态库. g++ -c static.cpp // 生成static.o ar -r libstatic.a static.o // 生成静态库libstatic.a g++ -c -fPIC shared.cpp // 生成shared.o g++ -shared shared.o -o libshared.so // 生成动态库libshared.so 注: -shared是g++的选项,与shared.o无关. 这时如果加-lstatic. error:relocation R_X86_64_32 against `a local symbol' can not be used when making a shared object; recompile with -fPIC

C语言程序静态库和动态库的创建及其应用

C语言程序静态库和动态库的创建及其应用 在用c写程序时,很多时候需要存储一些简单的数据,如果为此而用mysql数据库就有些大才小用了,可以把这些数据以结构的形写入文件,然后再需要时读取文件,取出数据。 如下是定义函数的源文件和头文件: 源文件struct.c: #include "struct.h" //第一个参数是要写入的文件名,第二个参数是缓冲区,第三个参数是缓冲区大小,第四个参数是打开文件流的形态,返回TRUE表示写入成功,返回FALSE表示写入失败int writeStruct(const char *fileName,char *buffer,int bufferLen,char *mode){ int ret; FILE *fileID = NULL; fileID = fopen(fileName,mode); if (fileID == NULL){ perror("fopen"); goto writeEnd; } rewind(fileID); ret = fwrite(buffer,bufferLen,1,fileID); if (ret <= 0){ perror("fwrite"); goto writeEnd; } if (fileID != NULL){ fclose(fileID); fileID = NULL; } return TRUE;

writeEnd: if (fileID != NULL){ fclose(fileID); fileID = NULL; } return FALSE; } //第一个参数是要读取的文件名,第二个参数是缓冲区,第三个参数是缓冲区大小,第四个参数是打开文件流的形态,返回TRUE表示读取成功,返回FALSE表示读取失败int readStruct(const char *fileName,char *buffer,int bufferLen,char *mode){ int ret; FILE *fileID = NULL; fileID = fopen(fileName,mode); if (fileID == NULL){ perror("fopen"); goto readEnd; } rewind(fileID); memset(buffer,0,sizeof(buffer)); ret = fread(buffer,bufferLen,1,fileID); if (ret >= 0){ strcat(buffer,"\0"); }else{ perror("fread") ; goto readEnd; } if (fileID != NULL){ fclose(fileID); fileID = NULL; }

使用Automake生成Makefile及动态库和静态库的创建

使用Automake生成Makefile及动态库和静态库的创建使用Automake 创建和使用静态库 1. 目录结构如下: [c-sharp]view plaincopy 1.example 2.|——src 目录(存放源代码文件) 3. |——hello.c 4.|——lib 目录(存放用来生成库的文件) 5. |——test.c 用来生成静态库libhello.a 6.|——include 目录(存放程序中使用的头文件) 7. |——hello.h 2. 编写的各个目录下的源文件 [c-sharp]view plaincopy 1.hello.h 文件 2.extern void print(char *); 3.test.c 文件 4.#include 5.void print(char *msg) 6.{ 7.print(“%s/n”, msg); 8.} 9.hello.c 文件 10.#include “hello.h” 11.int main() 12.{ 13.print(“Hello static library!”);//这里用到的是静态库中的函数 14.return 0; 15.} 3. 编写lib/Makefile.am 文件

[c-sharp]view plaincopy 1.noinst_LIBRARIES=libhello.a 2.libhello_a_SOURCES=test.c 3.AUTOMAKE_OPTIONS=foreign 第一行noinst 表示生成的是静态库,不需要make install ,直接制定它的位置和名字就 可以使用。 第二行表示用来生成静态库的源文件。如果要把静态库生成到其他地方,可以在=后面 加上路径(建议用绝对路径,并将所要用到的静态库生成在同一个文件夹下,如lib)。 第三行AUTOMAKE_OPTIONS 是Automake 的选项。Automake 主要是帮助开发 GNU 软 件的人员来维护软件,所以在执行Automake 时,会检查目录下是否存在标准GNU 软件中 应具备的文件,例如 'NEWS'、'AUTHOR'、 'ChangeLog' 等文件。设置为foreign 时,Automake 会改用一般软件的标准来检查。如果不加这句的话,需要在autoconf之前,先执行touch NEWS README AUTHORS ChangeLog 来生成'NEWS'、'AUTHOR'、 'ChangeLog' 等文件4. 编写src/Makefile.am 文件 [c-sharp]view plaincopy 1.AUTOMAKE_OPTIONS=foreign 2.INCLUDES= -I../include 3.bin_PROGRAMS=hello 4.hello_SOURCES=hello.c 5.hello_LDADD=../lib/libhello.a 第二行指定头文件的位置,-I 是idirafter 的缩写。../include 指定头文件的位置,..是上 一级目录,也就是这里的example 目录。 第三行指定生成可执行文件名hello,在这里可执行文件生成在src 下,建议将可执行文 件生成到一个特定的文件夹下,让它和源代码分开,如/root/test 目录下。写法为: [c-sharp]view plaincopy 1.bin_PROGRAMS=/root/test/hello,后面的第四、五行也相对应地变为: 2._root_test_hello_SOURCES=hello.c 3._root_test_hello_LDADD=../lib/libhello.a

VC++动态链接库创建和调用全过程详解

1.概论 先来阐述一下DLL(Dynamic Linkable Library)的概念,你可以简单的把DLL看成一种仓库,它提供给你一些可以直接拿来用的变量、函数或类。在仓库的发展史上经历了“无库-静态链接库-动态链接库”的时代。 静态链接库与动态链接库都是共享代码的方式,如果采用静态链接库,则无论你愿不愿意,lib中的指令都被直接包含在最终生成的EXE文件中了。但是若使用DLL,该DLL不必被包含在最终EXE文件中,EXE文件执行时可以“动态”地引用和卸载这个与EXE独立的DLL文件。静态链接库和动态链接库的另外一个区别在于静态链接库中不能再包含其他的动态链接库或者静态库,而在动态链接库中还可以再包含其他的动态或静态链接库。 对动态链接库,我们还需建立如下概念: (1)DLL 的编制与具体的编程语言及编译器无关 只要遵循约定的DLL接口规范和调用方式,用各种语言编写的DLL都可以相互调用。譬如Windows提供的系统DLL(其中包括了Windows的API),在任何开发环境中都能被调用,不在乎其是Visual Basic、Visual C++还是Delphi。 (2)动态链接库随处可见 我们在Windows目录下的system32文件夹中会看到kernel32.dll、user32.dll和gdi32.dll,windows的大多数API都包含在这些DLL中。kernel32.dll中的函数主要处理内存管理和进程调度;user32.dll中的函数主要控制用户界面;gdi32.dll中的函数则负责图形方面的操作。 一般的程序员都用过类似MessageBox的函数,其实它就包含在user32.dll这个动态链接库中。由此可见DLL对我们来说其实并不陌生。 (3)VC动态链接库的分类 Visual C++支持三种DLL,它们分别是Non-MFC DLL(非MFC动态库)、MFC Regular DLL(MFC规则DLL)、MFC Extension DLL(MFC扩展DLL)。 非MFC动态库不采用MFC类库结构,其导出函数为标准的C接口,能被非MFC或MFC编写的应用程序所调用;MFC规则DLL 包含一个继承自CWinApp的类,但其无消息循环;MFC扩展DLL采用MFC的动态链接版本创建,它只能被用MFC类库所编写的应用程序所调用。 由于本文篇幅较长,内容较多,势必需要先对阅读本文的有关事项进行说明,下面以问答形式给出。 问:本文主要讲解什么内容? 答:本文详细介绍了DLL编程的方方面面,努力学完本文应可以对DLL有较全面的掌握,并能编写大多数DLL程序。 问:如何看本文? 答:本文每一个主题的讲解都附带了源代码例程,可以随文下载(每个工程都经WINRAR压缩)。所有这些例程都由笔者编写并在VC++6.0中调试通过。

[Linux]链接,静态库和动态库

[Linux]链接,静态库和动态库 Filename:[Linux]链接,静态库和动态库 Version:V1.0 Date:12/01/2009 Author:S.C.Leon ============================================================== ======= 在Linux中创建静态库和动态库 一、基本概念 1.1什么是库 在windows平台和linux平台下都大量存在着库。 本质上来说库是一种可执行代码的二进制形式,可以被操作系统载入内存执行。由于windows和linux的平台不同(主要是编译器、汇编器和连接器的不同),因此二者库的二进制是不兼容的。 本文仅限于介绍linux下的库。 1.2库的种类 linux下的库有两种:静态库和共享库(动态库)。 二者的不同点在于代码被载入的时刻不同。 静态库的代码在编译过程中已经被载入可执行程序,因此体积较大。 共享库的代码是在可执行程序运行时才载入内存的,在编译过程中仅简单的引用,因此代码体积较小。 1.3库存在的意义 库是别人写好的现有的,成熟的,可以复用的代码,你可以使用但要记得遵守许可协议。 现实中每个程序都要依赖很多基础的底层库,不可能每个人的代码都从零开始,因此库的存在意义非同寻常。 共享库的好处是,不同的应用程序如果调用相同的库,那么在内存里只需要有一份该共享库的实例。

1.4库文件是如何产生的在linux下 静态库的后缀是.a,它的产生分两步 Step 1.由源文件编译生成一堆.o,每个.o里都包含这个编译单元的符号表 Step 2.ar命令将很多.o转换成.a,成文静态库 动态库的后缀是.so,它由gcc加特定参数编译产生。 具体方法参见后文实例。 1.5库文件是如何命名的,有没有什么规范 在linux下,库文件一般放在/usr/lib和/lib下, 静态库的名字一般为libxxxx.a,其中xxxx是该lib的名称 动态库的名字一般为libxxxx.so.major.minor,xxxx是该lib的名称,major是主版本号,minor是副版本号 1.6如何知道一个可执行程序依赖哪些库 ldd命令可以查看一个可执行程序依赖的共享库, 例如# ldd /bin/lnlibc.so.6 => /lib/libc.so.6 (0×40021000)/lib/ld-linux.so.2 => /lib/ld- linux.so.2 (0×40000000) 可以看到ln命令依赖于libc库和ld-linux库 1.7可执行程序在执行的时候如何定位共享库文件 当系统加载可执行代码时候,能够知道其所依赖的库的名字,但是还需要知道绝对路径 此时就需要系统动态载入器(dynamic linker/loader) 对于elf格式的可执行程序,是由ld-linux.so*来完成的,它先后搜索elf文件的DT_RPATH段—环境变量LD_LIBRARY_PATH—/etc/ld.so.cache文件列表— /lib/,/usr/lib目录找到库文件后将其载入内存 如:export LD_LIBRARY_PATH=’pwd’ 将当前文件目录添加为共享目录 1.8在新安装一个库之后如何让系统能够找到他 如果安装在/lib或者/usr/lib下,那么ld默认能够找到,无需其他操作。

linux下静态库与动态库的区别

静态库与动态库 什么是库 库是写好的,现有的,成熟的,可以复用的代码。现实中每个程序都要依赖很多基础的底层库,不可能每个人的代码都从零开始,因此库的存在意义非同寻常。 本质上来说,库是一种可执行代码的二进制形式,可以被操作系统载入内存执行。库有两种:静态库(.a、.lib)和动态库(.so、.dll)。 所谓静态、动态是指链接。回顾一下,将一个程序编译成可执行程序的步骤: 静态库 之所以称为【静态库】,是因为在链接阶段,会将汇编生成的目标文件.o与引用到的库一起链接打包到可执行文件中。因此对应的链接方式称为静态链接。 试想一下,静态库与汇编生成的目标文件一起链接为可执行文件,那么静态库必定跟.o文件格式相似。其实一个静态库可以简单看成是一组目标文件(.o/.obj 文件)的集合,即很多目标文件经过压缩打包后形成的一个文件。静态库特点总结如下: ?静态库对函数库的链接是放在编译时期完成的。 ?程序在运行时与函数库再无瓜葛,移植方便。

?浪费空间和资源,因为所有相关的目标文件与牵涉到的函数库被链接合成一个可执行文件。 Linux下创建与使用静态库 Linux静态库命名规则 Linux静态库命名规范,必须是"lib[your_library_name].a":lib为前缀,中间是静 态库名,扩展名为.a。 创建静态库(.a) 通过上面的流程可以知道,Linux创建静态库过程如下: ?首先,将代码文件编译成目标文件.o(StaticMath.o) g++ -c StaticMath.cpp 注意带参数-c,否则直接编译为可执行文件 ?然后,通过ar工具将目标文件打包成.a静态库文件 ar -crv libstaticmath.a StaticMath.o 生成静态库libstaticmath.a 图3.Linux下使用静态库 大一点的项目会编写makefile文件(CMake等等工程管理工具)来生成静态库,输入多个命令太麻烦了。 使用静态库 Linux下使用静态库,只需要在编译的时候,指定静态库的搜索路径(-L选 项)、指定静态库名(不需要lib前缀和.a后缀,-l选项)。 g++ TestStaticLibrary.cpp -L../StaticLibrary -lstaticmath

动态链接库及静态链接库(windows下的.dll.lib和linux下的.so.a)

ln -S libhello.so.1.0 libhello.so.1 ln -S libhello.so.1 libhello.so 使用库 当要使用静态的程序库时,连接器会找出程序所需的函数,然后将它们拷贝到执行文件, 由于这种拷贝是完整的,所以一旦连接成功,静态程序库也就不再需要了。然而,对动态库而言,就不是这样。动态库会在执行程序内留下一个标记,指明当程序执行时,首先必须载入这个库。由于动态库节省空间,linUX下进行连接的缺省操作是首先连接动态库,也就 是说,如果同时存在静态和动态库,不特别指定的话,将与动态库相连接。 现在假设有一个叫hello的程序开发包,它提供一个静态库libhello.a 一个动态库libhello.so,一个头文件hello.h,头文件中提供Sayhello()这个函数 /* hello.h */ void Sayhello(); 另外还有一些说明文档。这一个典型的程序开发包结构 1. 与动态库连接] linux默认的就是与动态库连接,下面这段程序testlib.c使用hello库中的Sayhello()函数 /*testlib.c*/ #i nclude #i nclude int mai n() { Sayhello(); return 0; } 使用如下命令进行编译 $gcc -C testlib.c -o testlib.o 用如下命令连接: $gcc testlib.o -lhello -o testlib 在连接时要注意,假设libhello.o和libhello.a都在缺省的库搜索路径下/usr/lib下,如果在

3.动态库的路径问题 为了让执行程序顺利找到动态库,有三种方法:

Windows静态库和动态库演练

Windows的静态库和动态库: 演练:创建和使用静态库 在本演练中,您将创建一个静态库(LIB),其中包含可供其他应用程序使用的有用例程。使用静态库是重用代码的一种绝佳方式。您不必在自己创建的每个程序中重新实现这些例程,而只需对这些例程编写一次,然后从需要该功能的应用程序引用它们即可。 本演练涵盖以下内容: 创建新的静态库项目 向静态库添加类 创建引用静态库的应用程序 在控制台应用程序中使用静态库的功能 运行应用程序 先决条件 本主题假定您具备C++语言的基础知识。 创建新的静态库项目 从“文件”菜单中,选择“新建”,然后选择“项目…”。 从“项目类型”窗格中,选择“Visual C++”下的“Win32”。 从“模板”窗格中,选择“Win32控制台应用程序”。 为项目选择一个名称,如“MathFuncsLib”,并将其输入“名称”字段。为解决方案选择一个名称,如“StaticLibrary”,并将其输入“解决方案名称”字段。 按“确定”启动Win32应用程序向导。在“Win32应用程序向导”对话框的“概述”页中,按“下一步”。

从“Win32应用程序向导”的“应用程序设置”页中,选择“应用程序类型”下的“静态库”。 从“Win32应用程序向导”的“应用程序设置”页中,取消选择“附加选项”下的“预编译头”。 按“完成”创建项目。 向静态库添加类 若要为新类创建头文件,请从“项目”菜单中选择“添加新项…”。将显示“添加新项”对话框。从“类别”窗格中,选择“Visual C++”下的“代码”。从“模板”窗格中选择“头文件(.h)”。为头文件选择一个名称,如“MathFuncsLib.h”,并按“添加”。将显示一个空白文件。 添加一个名为“MyMathFuncs”的简单类,以执行常见的算术运算,如加、减、乘和除。代码应与以下内容类似: //MathFuncsLib.hnamespace MathFuncs{class MyMathFuncs{public: //Returns a+b static double Add(double a,double b);//Returns a-b static double Subtract(double a,double b);//Returns a*b static double Multiply(double a,double b);//Returns a/b//Throws DivideByZeroException if b is0static double Divide(double a,double b);};} 若要为新类创建源文件,请从“项目”菜单中选择“添加新项…”。将显示“添加新项”对话框。从“类别”窗格中,选择“Visual C++”下的“代码”。从“模板”窗格中,选择“C++文件(.cpp)”。为源文件选择一个名称,如“MathFuncsLib.cpp”,并按“添加”。将显示一个空白文件。 在源文件中实现“MyMathFuncs”的功能。代码应与以下内容类似: //MathFuncsLib.cpp//compile with:/c/EHsc#include"MathFuncsLib.h"#include using namespace std;namespace MathFuncs{double MyMathFuncs::Add(double a,double b){return a+b;}double MyMathFuncs::Subtract(double a,double b){return a-b;}double MyMathFuncs::Multiply(double a,double b){return a*b;}double MyMathFuncs::Divide(double a,double b){if(b==0) {throw new invalid_argument("b cannot be zero!");}return a /b;}}

MinGW_Eclipse开发静态库和动态库

MinGW_EclipseCDT开发C++动态库、静态库本文主要介绍C++使用MinGW进行跨平台开发时如何创建与使用静态库、动态库。 文章分为以下几个部分: 第一部分介绍了Linux和MinGW使用Gcc编译器创建和使用静态库与动态库的基本方法。 第二部分介绍了MinGW与MSVC库间的转换及其调用。

第一部分GCC系列编译器下的静态库与动态库 一什么是库 所谓库就是已经写好的,成熟的,可以复用的代码—这些代码往往不开源,但在实践中非常有用。现实中每个程序都要依赖很多基础的底层库,不可能每个人的代码都从零开始,C语言中有stdio和stdlib等;C++中有STL和Boost都是程序员不可缺少的库。 本质上来说库是一种可执行代码的二进制形式,可以被操作系统载入内存执行。 库有两种:静态库(文件后缀分别为.a、.lib)和动态库(文件后缀分别为.so、.dll)。 所谓静态、动态是指链接。回顾一下,将一个程序编译成可执行程序的步骤: 图:编译过程 二静态库 之所以称之为静态库,因为编译器在链接阶段,会将汇编生成的目标文件.o与引用到的库一起链接打包到可执行文件中。因此对应的链接方式称为静态链接。 试想一下,静态库与汇编生成的目标文件一起链接为可执行文件,那么静态库必定跟.o文件格式相似。其实一个静态库可以简单看成是一组目标文件(.o/.obj文件)的集合,即很多目标文件经过压缩打包后形成的一个文件。静态库特点总结: ●静态库对函数库的链接是放在编译时期完成的。 ●程序在运行时与函数库再无瓜葛,移植方便。 ●浪费空间和资源,因为所有相关的目标文件与牵涉到的函数库被链接合成一个可执行文件。 编译器在编译时将目标文件压缩到一起,并且对其进行编号和索引,以便于查找和检索。一般创建静态库的步骤如图所示:

linux下静态链接库和动态链接库编译和使用[1]

Linux 下编译链接动静态库 2010年03月29日星期一 17:11 Linux 版本是 Red Hat 9 ,内核版本是 2.4.18 输入 which gcc 查看 gcc 的位置在 /usr/bin/gcc gcc -v 查看 gcc 编译前的配置信息 --prefix=/usr 说明了安装目录 没有 --with-headers 说明默认的 include 就在安装目录下 所以 gcc 默认的 include 目录是 /usr/include ,要包含另一个目录, 可以用 -I dir 选项包含该目录,想要更方便的可以 在 /etc/profile 中添加一个环境变量 C_INCLUDE_PATH C_INCLUDE_PATH="your include path" export C_INCLUDE_PATH gcc 默认的 lib 目录很多,一般是 /lib 和 /usr/lib 可以输入 gcc -print-search-dirs 查看 同样可以在编译时通过 -L dir 来添加,也可以在 /etc/profile 中添加 LD_LIBRARY_PATH="your ldlib path" export LD_LIBRARY_PATH 还有就是可以/etc/ld.so.conf中添加目录,这对于安装别的库很方便 当然修改了库文件后需要运行一下ldconfig 自己制作交叉编译工具太复杂了,直接下一个arm-linux-gcc-3.4.1.tar.bz2 tar jxvf arm-linux-gcc-3.4.1.tar.bz2 -C / 解压缩到根目录下 其实由于压缩包带的目录是 usr/local/arm/3.4.1 所以实际还是在 /usr/local/arm/3.4.1 目录下 在bin中可以看到各个工具 arm-linux-gcc ... 输入 ./arm-linux-gcc -v 可以看到配置信息 有 --with-headers=/usr/local/arm/3.4.1/arm-linux/include 说明了默认的include目录 输入 ./arm-linux-gcc -print-search-dirs 查看搜索的 lib 目录,主要的库文件还是在 /usr/local/arm/3.4.1/arm-linux/lib目录下. arm-linux-gcc 3.4.1 可以用来编译2.6的内核 而编译bootloader还是用原来的2.95.2版的 arm-linux-gcc 程序的预处理、编译、链接都可以由gcc完成,gcc会自动调用cpp来做预处理,ld来进行链接。其中对库的链接是很重要的一部分,有静态库和动态库两种,静态库以 .a 为后缀,ld会把静态库中的代码拷到待链接的程序中,形成完整的可执行的程序。而链接动态库生成可执行程序又分为静态调用和动态调用,静态调用是在程序中包含头文件直接调用库函数,也叫显式调用,程序被加载的同时也加载了库,在加载时完成真正的地址链接。而动态调用则不需要包含头文件,在程序中使用库加载函数dlopen来加载库,使用dlsym来获取所需函数的地址,所以是在需要时才加载动态库,也是隐式调用。这样编译时和库就没有关系,不需要链接了。

gcc 生成动态库和静态库

gcc生成静态库和动态库 我们通常把一些公用函数制作成函数库,供其它程序使用。函数库分为静态库和动态库两种。 静态库在程序编译时会被连接到目标代码中,程序运行时将不再需要该静态库。动态库在程序编译时并不会被连接到目标代码中,而是在程序运行是才被载入,因此在程序运行时还需要动态库存在。 在创建函数库前,我们先来准备举例用的源程序,并将函数库的源程序编译成.o文件。 第1步:编辑得到举例的程序--hello.h、hello.c和main.c; hello.c(见程序2)是函数库的源程序,其中包含公用函数hello,该函数将在屏幕上输出" Hello XXX!"。hello.h(见程序1)为该函数库的头文件。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 我们运行ls命令看看是否生存了hello.o文件。 # ls hello.c hello.h hello.o main.c 在ls命令结果中,我们看到了hello.o文件,本步操作完成。 下面我们先来看看如何创建静态库,以及使用它。 第3步:由.o文件创建静态库; 静态库文件名的命名规范是以lib为前缀,紧接着跟静态库名,扩展名为.a。例如:我们将创建的静态库名为myhello,则静态库文件名就是libmyhello.a。在创建和使用静态库时,需要注意这点。创建静态库用ar命令。 在系统提示符下键入以下命令将创建静态库文件libmyhello.a。 # ar crv libmyhello.a hello.o 我们同样运行ls命令查看结果: # ls

相关文档
最新文档