linux 静态库和动态库应用简介

【遗留问题】    makefile 写法;

 

1. linux/windows 动态库和静态库区别:

 linux:windows
动态库名称

xxx.so (201806做的项目,使用linux动态库,这样目标程序比较小;

如何在makefile中增加动态库的调用)

xxx.dll
静态库名称xxx.axxx.lib
 

2. 静态库和动态库区别:
 

1)最大区别: 加载的时刻不同    
    静态库在程序编译阶段加载,可能使目标程序变大
    动态库在程序运行阶段加载,目标程序相对较小。
2)库文件是否可删除
    静态库编译完成可以删除库文件
    动态库编译完成必须保留库文件
3)制作库文件命令不同
    接口文件一致,创建目标文件过程一致,但    制作库文件命令不同,使用流程不同
    静态库: ar  crs  libhello.a  hello.o
    动态库: gcc  -shared  -fPIC  hello.o  -o  libhelllo.so   (-fPIC,表示-fPIC 作用于编译阶段,告诉编译器产生与位置无关代码(Position-Independent Code))
4)不论是静态库还是动态库都存在潜在的隐患。
    (不知库文件的函数功能是否有木马或病毒,或其他函数操作)


3. 静态库的制作:

1)编写功能函数 ==》功能实现  ==》不能有main函数
    hello.c   ==》只做一个hello功能。
    hello.h   ==》接口文件,用于声明功能函数。
2)编译功能函数为目标文件:
     gcc -c hello.c -o hello.o
3)使用目标文件制作静态库:
     ar crs  libhello.a    hello.o
     注意:目标静态库必须以lib开头,以.a 结尾。
4)使用静态库:
    4.1 编写测试单元main.c
    4.2 将测试代码与库同时编译
        gcc main.c -L. -l hello  (-L. :表示当前路径;        -l  :后面跟库文件名字;)

    4.3 验证库的执行效果
        ./a.out  ==> hello xxx
备注:
        -L:

-l

 

3.1 静态库简单应用:

编写将printf打印函数,打印一个字符串,并制作一个静态库文件;(程序中,只能1个main函数,接口函数只提供接口,供其他函数调用。)

如下是main函数:

[root@llz test]# cat main.c 
#include "hello.h"

int main(int argc, const char *argv[])
{
    
    char * name = "zhangsan";

    hello(name);

    return 0;
}

如下是打印接口函数,只提供接口,接口函数声明在.h文件中,该.c 文件中不能包含main函数。
[root@llz test]# cat hello.c 
#include <stdio.h>

int hello( char * name)
{
    printf("hello %s \n",name);
    return  0;
}

[root@llz test]# cat hello.h 
#ifndef _HELLO_H_
#define _HELLO_H_

int  hello(char *name);

#endif

编译生成的文件:

-rwxr-xr-x. 1 root root 4802 6月  23 15:59 a.out
-rw-r--r--. 1 root root   99 7月  28 2016 hello.c
-rw-r--r--. 1 root root   70 7月  28 2016 hello.h
-rw-r--r--. 1 root root  868 6月  23 15:58 hello.o
-rw-r--r--. 1 root root 1010 6月  23 15:58 libhello.a
-rw-r--r--. 1 root root  153 8月   6 2017 main.c

 

4. 动态库制作(共享库):

1)编写功能函数
    hello.c
    hello.h
2)将功能函数编译成目标文件
    gcc -c hello.c -o hello.o                   【命令有时会执行失败】
3)制作动态库
    gcc -shared -fPIC hello.o -o libhello.so
4)使用测试环境测试动态库
    4.1 )编写main.c 测试代码
    4.2 )拷贝目标动态库到系统路径
                cp libhello.so    /usr/lib
               或  export LD_LIBRARY_PATH=/mnt/nfs/1615/io/06

    4.3 )编译测试单元
            gcc main.c -L. -l hello
    4.4 )执行测试单元
            ./a.out   ==>hello xxx
注意:
    1)动态库有时候有版本要求:
          so.xx.yy
          xx 代表主版本
          yy 代表副版本
    2)如下语句表示定义自己的库文件到指定目录:
            export LD_LIBRARY_PATH=/mnt/nfs/1615/io/06 

4.1. 动态库简单应用:

定义一个结构体,计算并打印出该结构体的大小;注意:打印函数使用动态库实现;

1)编写打印功能函数:func_file.c

#include <stdio.h>

#include "func_file.h"

int func_printf(int len)
{
    if (len < 0) {
        printf("input len is invalue, len:%d\n", len);
        return 1;
    }

    printf("len = %d\n", len);
    return 0;
}

2)编写打印功能函数头文件:func_file.h

#ifndef FUNC_FILE_H
#define FUNC_FILE_H

int func_printf(int len);

#endif

3)编译功能函数,并生成动态库:libfunc_file.so

编译目标文件后,由目标文件生成动态库时失败了。。。如下图所示:

解决办法编译器已经提示了:recompile with -fPIC

但是我们应该重新编译谁带上这个参数呢?经过我几番折腾,发现如下情况:

1、编译.o文件的时候,没有加参数-fPIC,这问题个在gcc version 3.4.6版本没有发生,可能那个编译器默认都给加上吧。

2、当前程序中有用到某个静态库,那个静态库编译.o文件的时候没有加上-fPIC(静态库其实就是.o文件打包)。补充一点:我发现手写Makefile时即使不加-fPIC也没有这个问题,这一点很郁闷,这个只在用automake工具编译出.a文件时才出现过。

知道原因了,解决办法自然有了,保证你编译.o文件的时候,都加上-fPIC,这样你才能编译出动态库来。

 

创建 PIC 的编译器标志是 -fPIC.创建共享库的链接器标志是 -shared。

-fPIC 作用于编译阶段,告诉编译器产生与位置无关代码(Position-Independent Code),则产生的代码中,没有绝对地址,全部使用相对地址,故而代码可以被加载器加载到内存的任意位置,都可以正确的执行。

这正是共享库所要求的,共享库被加载时,在内存的位置不是固定的。

4)动态库的使用:即在 main.c 函数中调用

链接动态库编译 主函数后,可执行文件 a.out 无法执行(如下图所示):

原因:是因为系统没有找到库文件,系统默认是去/lib和/user/lib中寻找动态库文件;

https://blog.csdn.net/rainbowchou/article/details/78220581

解决方法有三个:

一)将库文件放在系统默认寻找的目录下,即/lib和/user/lib下(不建议)

二)临时改变环境变量来增加路径,新开的shell就会失效

    export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:.

三)改变配置文件来增加路径,一直可用

 有两种方法可达成,选一即可。

1、在终端上输入sudo  gedit  ~/.bashrc,在最后一行加入    export LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH

保存退出,终端执行Source ~/.bashrc,重新加载脚本文件。

使用echo  $LD_LIBRARY_PATH,可看环境变量是否添加成功。

再次执行程序,应该就没问题了


2、在/etc/ld.so.conf.d里添加一个xxx.conf文件(xxx为自定义的名字);

    xxx.conf中添加库文件的存放目录,保存退出后,在终端输入以下命令进行刷新:

    sudo ldconfig

现在执行程序也应该没问题了

 

使用 export 的方式实现:

 

 

总结:

    无论是动态库还是静态库,从用户使用角度来说,都只是一个接口函数,调用该接口可完成相应的功能;使用者不需过多的关注库接口函数的实现,只需关注接口函数及形参即可;使用库函数优点:

    一方面是方面,分模块开发时,使功能模块具有强独立性;

    另一方面,在比较大的工程中,某些模块复用复用比较多,则可封装成动态库的形式,在程序运行阶段调用,这样可节省编译的内核尺寸;

    还要就是防止泄漏本公司的代码给其他公司,也封装成动态库或静态库的形式给客户。

 

Linux-C动态库与静态库的编译与调用

https://blog.csdn.net/nanfeibuyi/article/details/81203021

https://blog.csdn.net/lhl_blog/article/details/87914237

  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值