Linux c编程之静态库与动态库

一、库的说明

  库是用于提供特定功能的函数接口的集合,以文件形式存在。在linux系统中,分动态链接库和静态链接库两种,简称动态库和静态库。其中,静态库文件以.a为后缀为名,动态库文件以.so为后缀名。

二、动态库和静态库的区别

  • 静态库在程序编译时链接到目标程序中,在程序运行时不需要静态库文件。由于静态库中的文件都编译到了整个程序中,导致目标程序体积变大。
  • 动态库在程序编译时不会被链接到目标程序中,可执行文件体积较小。程序在运行的时候加载动态库,因此需要保证程序运行所在的环境中有相应的动态库文件

三、静态库的生成和使用

3.1 静态库的生成

源码:
catlog.c:

#include <stdio.h>

int cat_log_show_str(char *info)
{
    printf("%s: %s\n", __FUNCTION__, info);

    return 0;
}

int cat_log_show_digit(int digit)
{
    printf("%s: %d\n", __FUNCTION__, digit);

    return 0;
}

catlog.h:

#ifndef __CAT_LOG_H__
#define __CAT_LOG_H__

int cat_log_show_str(char *info);
int cat_log_show_digit(int digit);

#endif

生成库命令:

gcc -c catlog.c
ar cr libcatlog.a catlog.o
ranlib libcatlog.a

3.2 静态库查看

查看库文件中由哪些文件组成:

$ ar -t libcatlog.a 
catlog.o

列出目标文件中的符号:

$ nm -s libcatlog.a 
Archive index:
cat_log_show_str in catlog.o
cat_log_show_digit in catlog.o

catlog.o:
000000000000002e T cat_log_show_digit
0000000000000000 T cat_log_show_str
0000000000000010 r __FUNCTION__.2179
0000000000000030 r __FUNCTION__.2183
                 U printf

3.3 静态库的使用

  使用静态库中的函数时,需要包含静态库对应的头文件,并且在编译时指定通过-l链接的库名libcatlog.a
源码分析:
catlog.c:

#include <stdio.h>

int cat_log_show_str(char *info)
{
    printf("%s: %s\n", __FUNCTION__, info);

    return 0;
}

int cat_log_show_digit(int digit)
{
    printf("%s: %d\n", __FUNCTION__, digit);

    return 0;
}

catlog.h:

#ifndef __CAT_LOG_H__
#define __CAT_LOG_H__

int cat_log_show_str(char *info);
int cat_log_show_digit(int digit);

#endif

main.c:

#include <stdio.h>

#include "catlog.h"

int main(int argc, char *argv[])
{
    cat_log_show_str("hello world");
    cat_log_show_digit(5);

    return 0;
}

Makefile:

all: lib bin
lib:
	gcc -c catlog.c
	ar cr libcatlog.a catlog.o
	ranlib libcatlog.a
bin:
	gcc main.c -L. -lcatlog

clean:
	rm *.o
	rm *.a
	rm a.out

测试:

$ ./a.out 
cat_log_show_str: hello world
cat_log_show_digit: 5

四、动态库的生成和使用

4.1 动态库的生成

源码:
catlog.c:

#include <stdio.h>

int cat_log_show_str(char *info)
{
    printf("%s: %s\n", __FUNCTION__, info);

    return 0;
}

int cat_log_show_digit(int digit)
{
    printf("%s: %d\n", __FUNCTION__, digit);

    return 0;
}

catlog.h:

#ifndef __CAT_LOG_H__
#define __CAT_LOG_H__

int cat_log_show_str(char *info);
int cat_log_show_digit(int digit);
#endif

动态库的编译:

$ gcc -fPIC -c catlog.c
$ gcc -shared -o libcatlog.so catlog.o

4.2 动态库的查看

查看符号:

$ nm -s libcatlog.so 
0000000000201038 B __bss_start
0000000000000727 T cat_log_show_digit
00000000000006f5 T cat_log_show_str
0000000000201038 b completed.6973
                 w __cxa_finalize@@GLIBC_2.2.5
0000000000000610 t deregister_tm_clones
0000000000000680 t __do_global_dtors_aux
0000000000200e08 t __do_global_dtors_aux_fini_array_entry
0000000000201030 d __dso_handle
0000000000200e18 d _DYNAMIC
0000000000201038 D _edata
0000000000201040 B _end
0000000000000758 T _fini
00000000000006c0 t frame_dummy
0000000000200e00 t __frame_dummy_init_array_entry
0000000000000858 r __FRAME_END__
0000000000000780 r __FUNCTION__.2179
00000000000007a0 r __FUNCTION__.2183
0000000000201000 d _GLOBAL_OFFSET_TABLE_
                 w __gmon_start__
00000000000005b0 T _init
                 w _ITM_deregisterTMCloneTable
                 w _ITM_registerTMCloneTable
0000000000200e10 d __JCR_END__
0000000000200e10 d __JCR_LIST__
                 w _Jv_RegisterClasses
                 U printf@@GLIBC_2.2.5
0000000000000640 t register_tm_clones
0000000000201038 d __TMC_END__

4.3 动态库的使用

catlog.c:

#include <stdio.h>

int cat_log_show_str(char *info)
{
    printf("%s: %s\n", __FUNCTION__, info);

    return 0;
}

int cat_log_show_digit(int digit)
{
    printf("%s: %d\n", __FUNCTION__, digit);

    return 0;
}

catlog.h:

#ifndef __CAT_LOG_H__
#define __CAT_LOG_H__

int cat_log_show_str(char *info);
int cat_log_show_digit(int digit);

#endif

main.c:

#include <stdio.h>

#include "catlog.h"

int main(int argc, char *argv[])
{
    cat_log_show_str("hello world");
    cat_log_show_digit(5);

    return 0;
}

Makefile:

all: lib bin
lib:
	gcc -fPIC -c catlog.c
	gcc -shared -o libcatlog.so catlog.o
bin:
	gcc main.c -L. -lcatlog

clean:
	rm *.o
	rm *.so
	rm a.out

查看程序链接的动态库:

$ ldd a.out 
	linux-vdso.so.1 =>  (0x00007fff0a49d000)
	**libcatlog.so** => /usr/lib/**libcatlog.so** (0x00007f85510f7000)
	libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f8550d32000)
	/lib64/ld-linux-x86-64.so.2 (0x00007f8551316000)

测试:

$ ./a.out
./a.out: error while loading shared libraries:
libcatlog.so: cannot open shared object file: 
No such file or directory

  出现上面的错误原因是程序默认在系统目录/lib/和/usr/lib/目录下搜索动态库,因此在实际应用中都会将动态库安装(拷贝)到/lib/或/usr/lib/目录下

$ cp libcatlog.so /usr/lib/

  再次运行,程序正常。有时尽管已经将动态库安装(拷贝)到/lib/或/usr/lib/目录下,但依然提示上述错误,则需要执行ldconfig命令刷新一下

测试:

$ ./a.out 
cat_log_show_str: hello world
cat_log_show_digit: 5

  除了将动态库安装(拷贝)到/lib/或/usr/lib/目录下外,还可以通过环境变量LD_LIBRARY_PATH指定额外的动态库搜索路径,当程序在默认路径/lib/和/usr/lib/下找不到动态库时,会在LD_LIBRARY_PATH指定的路径下搜索动态库,这个方法,对于临时测试是很有用的。

五、动态库和静态库的优先级

  在一般的开源库中,会同时生成动态库和静态库。如果路径下同时存在动态库和静态库时,程序在链接时会优先选择动态库,测试如下:
catlog.c:

#include <stdio.h>

int cat_log_show_str(char *info)
{
    printf("%s: %s\n", __FUNCTION__, info);

    return 0;
}

int cat_log_show_digit(int digit)
{
    printf("%s: %d\n", __FUNCTION__, digit);

    return 0;
}

catlog.h:

#ifndef __CAT_LOG_H__
#define __CAT_LOG_H__

int cat_log_show_str(char *info);
int cat_log_show_digit(int digit);

#endif

main.c:

#include <stdio.h>

#include "catlog.h"

int main(int argc, char *argv[])
{
    cat_log_show_str("hello world");
    cat_log_show_digit(5);

    return 0;
}

Makefile:

all: lib-static lib-dynamic bin
lib-dynamic:
	gcc -fPIC -c catlog.c
	gcc -shared -o libcatlog.so catlog.o
lib-static:
	gcc -c catlog.c
	ar cr libcatlog.a catlog.o
	ranlib libcatlog.a

bin:
	gcc main.c -L. -lcatlog

clean:
	rm *.o
	rm *.so
	rm a.out

编译后,生成动态库和静态库,使用ldd查看a.out的链接库

$ ldd a.out 
	linux-vdso.so.1 =>  (0x00007fff2ab5c000)
	**libcatlog.so** => /usr/lib/libcatlog.so (0x00007fd931b6e000)
	libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fd9317a9000)
	/lib64/ld-linux-x86-64.so.2 (0x00007fd931d8d000)

  修改Makefile如下,重新编译,只生成静态库,这时可以看到程序没有链接libcatlog.so

$ ldd a.out 
	linux-vdso.so.1 =>  (0x00007fff5b7fc000)
	libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f65327c9000)
	/lib64/ld-linux-x86-64.so.2 (0x00007f6532bab000)

六、动态库和静态库的特点及应用

  • 静态库和程序编译在一起,部署时不需要静态库文件
  • 动态库在程序运行时加载,因此,部署程序时需要同时安装动态库
  • 使用静态库的程序由于包含了静态库,程序会比较大,而使用动态库的程序会比较小
  • 无论是动态库还是静态库,都会有对应的头文件供用户编程使用
  • 向第三方提供功能模块或SDK时,一般不提供源码,而是使用动态库或静态库的形式,这样可以避免核心技术泄密
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

浪游东戴河

你就是这个世界的唯一

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值