Linux系统编程入门1——库文件制作

文章目录

  • 前言
  • 什么是库文件
      • 库的解释
      • 库文件分类
    • 静态库制作
      • 静态库命名规则:
      • 制作静态库文件
        • 文件目录如下
        • 编译文件
        • 生成库文件
        • 移动库文件至合适目录
        • 使用并编译运行
    • 动态库制作
      • 动态库命名规范
      • 制作动态库文件
        • 文件目录如下
        • 编译生成 .o 文件
        • 生成动态库文件
        • 移动库文件至合适目录
        • 使用并编译运行
        • 动态库工作原理
        • 永久环境变量设置
    • 静态库与动态库的对比
        • 程序编译执行的过程
      • 静态库的优缺点
        • 优点
        • 缺点
      • 动态库的优缺点
        • 优点
        • 缺点
    • 总结
  • 最后

前言

本篇主要介绍的 库文件,包括静态库文件和动态库文件的使用及其他基本知识,相对比较基础和底层,对于后面对多线程编程的理解有很大帮助。本文所使用的环境为虚拟机 Ubuntu系统,使用 xshell 进行远程连接调试,所有示例均经过测试无误。

什么是库文件

库的解释

库文件是一类可以供使用者直接使用的变量、函数或类,属于一种特殊程序,在实际编写时与一般程序的区别不大,只是库不能单独运行

使用库可以实现代码保密,方便不熟和分发

库文件分类

  • 静态库:在程序的链接阶段被复制到了程序中
  • 动态库(共享库):在链接阶段没有被复制到程序中,而是在程序运行时由系统动态加载到内存中供程序调用

静态库制作

静态库命名规则:

Linux下和windows下对库的命名规则不一致

Linux : libxxx.a

  • lib : 前缀(固定)
  • xxx : 库的名字,自己起
  • .a : 后缀(固定)

Windows : libxxx.lib

使用 gcc 获得 .o 文件,将 .o 文件打包,使用 ar 工具(archive)

ar rcs libxxx.a xxx.o xxx.o

r – 将文件插入备存文件中
c – 建立备存文件
s – 索引

制作静态库文件

gcc -c xxx.c -----生成 .o 文件
ar rcs libcalc.a —lib表示生成库文件的名称,calc 才是库的名称

例如,在有如下文件下的多个文件,现在要制作 静态库文件Linux系统编程入门1——库文件制作_第1张图片

文件目录如下

在该文件夹下,有放置头文件的文件夹 include,齐下放置头文件 head.h,有静态库文件夹,等会先生成静态库,然后放置静态库文件,程序入口点函数:main.c 以及各个函数文件夹下的各个函数文件 *.c

main.c

#include 
#include "head.h"

int main()
{
    int a = 20;
    int b = 12;
    printf("a = %d, b = %d\n", a, b);
    printf("a + b = %d\n", add(a, b));
    printf("a - b = %d\n", subtract(a, b));
    printf("a * b = %d\n", multiply(a, b));
    printf("a / b = %f\n", divide(a, b));
    return 0;
}

下面是各个文件:

//add.c
#include 
#include "head.h"

int add(int a, int b)
{
    return a+b;
}

//div.c
#include 
#include "head.h"

double divide(int a, int b)
{
    return (double)a/b;
}

//mult.c
#include 
#include "head.h"

int multiply(int a, int b)
{
    return a*b;
}
//sub.c
#include 
#include "head.h"

int subtract(int a, int b)
{
    return a-b;
}

编译文件

然后进入src 目录,对src 目录下的文件进行编译,生成 .o 文件
但是在编译时要注意,这几个文件都是在头文件 head.h 下的,所以就要包含头文件,使用编译选项 -I ,寻找头文件,就需要回到上一级目录,然后进入头文件目录

gcc -c add.c sub.c mult.c div.c -I ../include/

就可以成功生成 .o 文件了image

下一步对这些 .o 文件进行打包,生成 库文件

生成库文件

使用 ar 命令进行生成

ar rcs libsuanshu.a add.o div.o mult.o sub.o

这里是使用 ar 工具进行打包rcs 参数含义如下:
r – 将文件插入备存文件中
c – 建立备存文件
s – 索引
其中libsuanshu 为库文件,表示生成库文件的名称,calc 才是库的名称

移动库文件至合适目录

使用 mv 命令进行移动,移动到父目录下的lib 文件夹下

mv libsuanshu.a ../lib/

查看目录结构如图Linux系统编程入门1——库文件制作_第2张图片

使用并编译运行

编译运行文件时需要链接头文件和库文件(访问库文件才可以正常访问到各个文件)使用选项 -I 来访问头文件,使用 -L 来访问库文件,-l 表明访问的库文件名称(库文件名称是没有lib的)-o 可以生成运行文件,app 即为运行文件的文件名

gcc main.c -o app -I ./include/ -L ./lib/ -l suanshu

编译通过之后,就会生成一个可执行文件 app了Linux系统编程入门1——库文件制作_第3张图片

下面运行这个程序:Linux系统编程入门1——库文件制作_第4张图片

动态库制作

动态库命名规范

Linux : libxxx.so

  • lib : 前缀(固定)
  • xxx : 库的名字,自己起
  • .so : 后缀(固定)

在Linux下是一个可执行文件
Windows : libxxx.dll

制作动态库文件

gcc 得到 .o 文件,得到和位置无关的代码
gcc -c –fpic/-fPIC a.c b.c
gcc 得到动态库
gcc -shared a.o b.o -o libcalc.so

文件目录如下

首先在文件夹下的多个文件如图:Linux系统编程入门1——库文件制作_第5张图片

编译生成 .o 文件

gcc -c -fpic add.c div.c mult.c sub.c

编译成功:image

生成动态库文件

无关位置,生成动态库文件

gcc -shared add.o sub.o mult.o div.o -o libcalc.so

生成 .so 文件image

移动库文件至合适目录

将动态库文件放到文件 的lib 文件夹下:Linux系统编程入门1——库文件制作_第6张图片

使用并编译运行

基于以上的目录结构,就可以正常的进行编译运行了
-o 生成名为 app 的可执行文件,-I 包含头文件 ,-L 包含库文件, -l 表明需要的库文件

gcc main.c -o app -I include/ -L lib -l calc 

现在可以编译成功,但是还不可以直接运行,如果直接进行运行,就会出现如下报错:image

这里涉及动态库的工作原理:

动态库工作原理

GCC 进行链接时,动态库的代码不会被打包到可执行程序中 ( 静态库中代码打包到可执行程序中 )

所以在使用动态库时,就需要在程序启动之后先把动态库 动态的 加载到内存中,**ldd (list dynamic dependencies)命令检查动态库依赖关系 **

这里通过该命令就可以看到,该程序需要的库文件是没有找到的Linux系统编程入门1——库文件制作_第7张图片

通过报错也可以看到,如果要正常的运行程序,就需要定位共享库文件

此时就需要系统的动态载入器来获取该绝对路径。对于elf格式的可执行程序,是由ld-linux.so来完成的,它先后搜索elf文件的 DT_RPATH段 ——> 环境变量LD_LIBRARY_PATH ——> /etc/ld.so.cache文件列表 ——> /lib/, /usr/lib目录找到库文件后将其载入内存。

在这其中,可以修改的是环境变量

export LD_LIBRARY_PATH=$LD_LIBRART_PATH:/home/william/clearn/lession04/library/lib

使用 $ 来获取环境变量的值,然后再拼接动态库的地址

这样,就可以正确的添加到访问动态库了
Linux系统编程入门1——库文件制作_第8张图片

然后程序就可以正常的运行了
Linux系统编程入门1——库文件制作_第9张图片

但是这种方式只是暂时的,并不是永久的,如果下次再次运行,该环境变量就会失效

永久环境变量设置

进入系统环境变量控制文件,写入环境变量

sudo vim /etc/profile

最后插入这里的环境变量

export LD_LIBRARY_PATH=$LD_LIBRART_PATH:/home/william/clearn/lession04/library/lib

然后再更新设置就可以了

source/etc/profile

除了这个方法之外,还有可以修改文件列表

我们是无法直接对 /etc/ld.so.cache 文件进行修改的,因为它是二进制文件

可以退而求其次,对 /etc/ld.so.conf 文件进行修改

sudo vim /etc/ld.so.conf

在这个文件中,加入 动态库的 地址 就可以,保存退出image

然后进行更新刚刚的设置

sudo ldconfig

这样就完成了修改

静态库与动态库的对比

程序编译执行的过程

Linux系统编程入门1——库文件制作_第10张图片

静态库的优缺点

优点

  • 静态库被打包到应用程序中加载速度快
  • 发布程序无需提供静态库,移植方便

缺点

  • 消耗系统资源,浪费内存
  • 更新、部署、发布麻烦

动态库的优缺点

优点

  • 可以实现进程间资源共享(共享库)(别的应用可以方便的使用该库)
  • 更新、部署、发布简单
  • 可以控制何时加载动态库

缺点

  • 加载速度比静态库慢
  • 发布程序时需要提供依赖的动态库

总结

要熟悉静态库与动态库,了解各自的优缺点,了解其制作方法。

最后

感谢观赏,一起提高,慢慢变强

你可能感兴趣的:(Linux开发,linux,服务器)