【Linux】动态库和静态库——动态库和静态库的打包和使用、gcc编译、拷贝到系统默认的路径、建立软连接

文章目录

  • 动态库和静态库
    • 1.静态库和动态库的介绍
    • 2.静态库的打包和使用
      • 2.1生成静态库
      • 2.2使用静态库的三种方式
        • 2.2.1gcc编译
        • 2.2.2拷贝到系统默认的路径
        • 2.2.3建立软连接
    • 3.动态库的打包和使用
      • 3.1生成动态库
      • 3.2使用动态库
      • 3.3解决加载不到动态库的方法

动态库和静态库

1.静态库和动态库的介绍

  静态库和动态库是两种不同的程序库,它们在编译和链接阶段有不同的应用方式和特点。

  静态库(Static Library):

  静态库是在编译时被全部链接到目标程序中,一同生成可执行文件,所以生成的可执行文件较大,但运行时不需要链接其他库。静态库的后缀通常为.a或.lib。在程序发布时,通常只需要提供静态库和可执行文件,而不需要源代码。

  动态库(Dynamic Library):

  动态库在程序运行时才被加载和链接,所以多个程序可以共享相同的动态库代码,从而节省内存。动态库的后缀通常为.so(Linux)或.dll(Windows)。动态库的代码需要满足能够被加载到不同进程的不同地址,因此需要进行特别的编译处理。动态库在程序运行时由操作系统负责加载和链接,因此如果程序需要更新某个模块,只需要更新相应的动态库即可,而不需要重新编译整个程序。

  静态库和动态库的主要区别在于链接时间和使用方式。静态库在编译时链接到目标程序中,而动态库在程序运行时才被加载和链接。此外,静态库和动态库的打包和分发方式也不同,静态库需要和可执行文件一起发布,而动态库只需要提供动态库文件即可。

  静态库(后缀为 .a):程序在编译链接的时候把库的代码链接到可执行文件中。程序运行的时候将不再需要静态库。

  动态库(后缀为 .so):程序在运行的时候才去链接动态库的代码,多个程序共享使用库的代码。

            

2.静态库的打包和使用

  静态库的打包原理基于链接器的工作原理,将各个目标文件中的代码和符号合并到一起,以便在其他项目中进行使用。先将所有目标文件(.c文件)编译为(.o文件),然后把目标文件(.o文件)打包在一起,生成一个或多个静态库文件。 这个过程通常使用ar命令(在Linux和类Unix系统中)或lib命令(在Windows系统中)完成。

  打包过程中,需要将所有的目标文件组织到一个归档文件中,形成静态库。这个归档文件是一个持久的数据库,包含了目标文件的名称、创建时间和修改时间等信息。在链接阶段,链接器会从静态库中提取需要的目标文件,将其链接到最终的可执行文件中。

  

2.1生成静态库

  我们假设使用mymath.c和mymath.h模拟为静态库。下面是制作和打包静态库的过程。

  假设我们的main.c想要编译外部的两个源文件和头文件(mymath.c和mymath.h)。

  mymath.h

#pragma once#include <stdio.h>extern int myerrno;int add(int x, int y);
int sub(int x, int y);
int mul(int x, int y);
int div(int x, int y);

  
  mymath.c

#include "mymath.h"int myerrno = 0;int add(int x, int y)
{return x + y;
}
int sub(int x, int y)
{return x - y;
}
int mul(int x, int y)
{return x * y;
}
int div(int x, int y)
{if(y == 0){myerrno = 1;return -1;}return x / y;
}

  
  main.c

#include "mymath.h"
//#include "myinc/mymath.h"int main()
{extern int myerrno;//printf("1+1=%d\n", add(1,1));int n=div(10,0);//C语言实例化是从右向左,所以myerrno输出的是0printf("10/0=%d, errno=%d\n", n, myerrno);//gcc默认的链接方式是动态链接//没有动态库就默认使用静态库链接return 0;
}  

  

  经过下面的make操作,生成.a静态库文件。

在这里插入图片描述

static-lib=libmymath.a//将我们静态库的名称命名为static-lib$(static-lib):mymath.o//如何使用mymath.o构建static-libar -rc $@ $^//构建静态库 目标文件 依赖文件
mymath.o:mymath.c//如何使用mymath.c构建mymath.ogcc -c $^//编译到.o文件.PHONY:clean//伪目标
clean:      //清除所有的.o  .a  和static-lib文件rm -rf *.o *.a static-lib.PHONY:output//打包文件
output:mkdir -p static-lib/include//创建目录includemkdir -p static-lib/my-static-lib//创建目录my-static-libcp *.h static-lib/include//拷贝所有.h文件到includecp *.a static-lib/my-static-lib//拷贝所有.a文件到my-static-lib

  

  此时的文件为,我们进行make操作:

在这里插入图片描述

  

  我们可以看到生成了mymath.o文件和我们需要的打包好的静态库libmymath.a文件。此时我们就需要使用这个静态库libmymath.a了。

在这里插入图片描述
  

  顺带着打包一下,将.h和.a文件放入一个static-lib文件中。

在这里插入图片描述
在这里插入图片描述

  

2.2使用静态库的三种方式

2.2.1gcc编译

  当前的文件下输入 gcc main.c -I ./头文件的路径 -L ./库文件的路径 -l 链接库的名称 即可生成我们的可编译程序。

在这里插入图片描述
  

  注意上面的代码所含的内容缺一不可:

  缺少头文件和库文件,链接出错。

在这里插入图片描述
  
  缺少库文件,链接出错。

在这里插入图片描述

  
  找不到链接库的名称,链接出错。

在这里插入图片描述

  
  虽然链接出错,但是仍然可以汇编为.o文件。

在这里插入图片描述

  

2.2.2拷贝到系统默认的路径

  拷贝文件到系统路径同样可以实现静态库的使用:

  sudo cp static-lib/include/mymath.h /usr/include/

   sudo cp static-lib/my-static-lib/libmymath.a /lib64/libmymath.a

在这里插入图片描述
  

  gcc 无法直接编译我们的main.c文件还是需要我们告诉编译器其中的静态库的名字才可以,-l mymath

在这里插入图片描述
  

  但是一般不推荐,这样会对我们系统的路径造成污染,删除:

在这里插入图片描述

  

2.2.3建立软连接

  软链接应用广泛,可以快速找到.h和.c文件。

  使用时,main函数的头文件要修改为文件的路径。

//#include "mymath.h"
#include "myinc/mymath.h"//使用软链接时编译

  软链接includesudo ln -s /home/wu1/study_liunx/2024_1_23动静态库测试/static-lib/include /usr/include/myinc

  软链接.a静态库sudo ln -s /home/wu1/study_liunx/2024_1_23动静态库测试/static-lib/my-static-lib/libmymath.a /lib64/libmymath.a

  解除链接:sudo unlink/usr/include/myinc sudo unlink/lib64/libmymath.a

在这里插入图片描述

            

3.动态库的打包和使用

  动态库的打包原理是将多个相对独立的部分按照模块化的方式拆分成不同的文件,并在程序运行时才将这些模块链接在一起形成一个完整的程序。与静态库不同,动态库不会将所有代码和数据都包含在最终的可执行文件中,而是在程序运行时由操作系统动态加载到内存中。

  打包动态库时,需要将各个目标文件(.o文件)编译为动态库文件(.so文件),以便在程序运行时被加载和链接。 这个过程通常使用gcc命令,并指定-fPIC-shared选项,以便生成位置无关代码和共享库。

  

3.1生成动态库

  和上面生成的.a类似,动态库是后缀为.so的文件,我们下面使用mylog.h mylog.c myprint.h myprint.c进行动态库的打包实现。

  main.c

#include "mylog.h"
#include "myprint.h"int main()
{Print();Log("这是一个动态库打包的测试");return 0;
}  

  
  mylog.h

#pragma once#include <stdio.h>void Log(const char*);

  
  mylog.c

#include "mylog.h"void Log(const char*info)
{printf("Warning: %s\n", info);
}

  
  myprint.h

#pragma once#include <stdio.h>void Print();

  
  myprint.c

#include "myprint.h"void Print()
{printf("hello new world!\n");printf("hello new world!\n");printf("hello new world!\n");printf("hello new world!\n");
}

  

  经过下面的make操作,生成.so静态库文件。
在这里插入图片描述

dy-lib=libmymethod.so//将我们动态库的名称命名为dy-lib.PHONY:all//伪目标为dy-lib文件
all: $(dy-lib)$(dy-lib):mylog.o myprint.o//将mylog.o和myprint.o文件打包为动态库文件gcc -shared -o $@ $^//形成共享库(可执行程序加载内存)mylog.o:mylog.c//将.c文件编译为.o文件gcc -fPIC -c $^//-fPIC产生与位置无关码
myprint.o:myprint.cgcc -fPIC -c $^.PHONY:clean//伪目标删除操作
clean:rm -rf *.o *.so dy-lib.PHONY:output//打包动态库
output:mkdir -p dy-lib/includemkdir -p dy-lib/my-dy-libcp *.h dy-lib/includecp *.so dy-lib/my-dy-lib

  

  此时的文件为,我们进行make操作:

在这里插入图片描述
  

  我们将我们的头文件和.so文件打包为了dy-lib文件。

在这里插入图片描述

在这里插入图片描述
  

3.2使用动态库

  和上面使用静态库一样,我们链接头文件和库文件,而且找到链接库的名称即可。

  gcc main.c -I ./dy-lib/include/ -L ./dy-lib/my-dy-lib -l mymethod

  

  但是在链接的时候,会报错。因为动态库在哪里也要告诉系统——加载器,加载同样也需要过程。

在这里插入图片描述
  

  进行动态库的软链接,ldd成功找到链接。

在这里插入图片描述

  

  运行成功。

在这里插入图片描述

  

3.3解决加载不到动态库的方法

  1.拷贝到系统默认的库路径 /lib64 /usr/lib64/

  2.在系统默认的库路径 /ib64 /usr/lib64/下建立软连接

  3.将自己的库所在的路径,添加到系统的环境变量LD LIBRARY PATH中

  4. /etc/ld.so.conf.d 建立自己的动态库路径的配置文件,然后重新ldconfiq即可

  实际情况,我们用的库都是别人的成熟的库,都采用直接安装到系统的方式。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/653537.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

多线程 之 静态代理

什么是静态代理&#xff1f; 静态代理是一种思想&#xff0c;找一个代理负责一些琐事&#xff0c;自己则专注于一件大事。 有哪些具体的表现&#xff1f; 在日常生活中做饭就是这样&#xff0c;会做饭的人需要做饭&#xff0c;那么其他的人就来帮他打杂&#xff0c;这样做饭的…

JavaScript的冒泡与捕获

1.概念。 冒泡事件&#xff1a;微软公司提出的&#xff0c;事件由子元素传递到父元素的过程叫做冒泡&#xff08;false&#xff09;。 捕获事件&#xff1a;网景公司提出的&#xff0c;事件由父元素传递到子元素的过程叫做事件捕获&#xff08;ture&#xff09;。 2.冒泡事件与…

vscode copilot怎么去掉提示代码(ghost text or incline completion)

原因&#xff1a;最近在刷题&#xff0c;被这个提示烦死了&#xff0c;记录一下怎么关掉&#xff0c;防止将来需要开启找不到了XD. 1.直接ctrlshiftp召唤设置 2.输入preferences: open usr settings找到如图第一个 3.去掉这个方框的勾选 ps直接在extension里disable不行呢 不…

使用宝塔面板部署Node.js+Mysql服务和Vue3-Admin项目到云服务器上

准备工作 一台云服务器&#xff0c;可以先用免费试用一个月的服务器进行练手&#xff1b;我这里选择的是腾讯云的轻量云服务器&#xff1b; 1、在云服务器上安装宝塔面板 宝塔面板官网地址&#xff1a;https://www.kancloud.cn/chudong/bt2017/424209 1.1 安装Xshell脚本工…

你好,C++对象

你好&#xff0c;对象 面向对象开发对象的定义 类与对象类的定义类的访问限定符及封装类的实例化类对象模型结构体内存对齐规则 this指针this指针的引入 this指针的特性 类的默认成员函数构造函数析构函数拷贝构造函数结语 面向对象开发 对象的定义 对象的含义是指具体的某一…

MySQL 聚集与非聚集索引

文章目录 1.聚集索引1.1 介绍1.2 优点1.3 缺点 2.非聚集索引3.区别参考文献 MySQL 中&#xff0c;根据索引树叶结点存放数据行还是数据行的地址&#xff0c;可以将索引分为两类&#xff1a; 存放数据行&#xff1a;聚集索引存放数据行地址&#xff1a;非聚集索引 InnoDB 使用聚…

Keil-C语言小总结

1、 &取地址符&#xff0c;*取地址内容 int *ptr;//声明指针 2、ptr &c; // 将c的地址赋值给指针变量ptr 3、可选参数函数 4、C宏定义 5、 memset&#xff1a;最快的数据清零函数 void *memset(void *s, int ch, size_t n); 分别是 字符串 要值的数据&#xff08;0…

TensorFlow2实战-系列教程4:数据增强:keras工具包/Data Augmentation

&#x1f9e1;&#x1f49b;&#x1f49a;TensorFlow2实战-系列教程 总目录 有任何问题欢迎在下面留言 本篇文章的代码运行界面均在Jupyter Notebook中进行 本篇文章配套的代码资源已经上传 对于图像数据&#xff0c;将其进行翻转、放缩、平移、旋转操作就可以得到一组新的数据…

分布式ID(3):雪花算法生成ID之UidGenerator(百度开源的分布式唯一ID生成器)

1 UidGenerator官方地址 UidGenerator源码地址: https://github.com/baidu/uid-generator UidGenerator官方说明文档地址: https://github.com/baidu/uid-generator/blob/master/README.zh_cn.md 这边只做简单介绍,详细说明请看官方说明文档。 2 Snowflake算法 Snowfl…

spring boot学习第八篇:操作elastic search的索引和索引中的数据

前提参考&#xff1a;elastic search入门-CSDN博客 前提说明&#xff1a;已经安装好了elastic search 7.x版本&#xff0c;我的es版本是7.11.1 1、 pom.xml文件内容如下&#xff1a; <?xml version"1.0" encoding"UTF-8"?> <project xmlns&q…

空间计算时代催生新一波巨大算力市场需求

什么是空间计算&#xff1f; 空间计算是一种整合虚拟现实&#xff08;VR&#xff09;、增强现实&#xff08;AR&#xff09;、混合现实&#xff08;MR&#xff09;等技术的计算模式&#xff0c;旨在将数字信息与真实世界融合在一起。这种融合创造了一个全新的计算环境&#xff…

机房环境动力监控系统:S275远程控制网关助力高效管理

现场问题 1、机房安全隐患 机房存在意外断电、温湿度过高过低、漏水断路等隐患&#xff0c;传统监测手段难以提前发现和预警。 2、机房远程运维困难 因环境改变、非授权活动、设备状态变化等引起的事故&#xff0c;难以满足机房远程运维的可靠管控要求。 3、机房改造成本高…

菱形打印和十进制ip转二进制

1.菱形打印 用for循环 #!/bin/bashread -p "请输入菱形的大小&#xff1a;" num #打印向上的等腰三角形 for ((i1;i<num;i)) dofor ((jnum-1;j>i;j--))doecho -n " " #打印的是前面的空格donefor ((k1;k<2*i-1;k))doecho -n "*" #打印…

HCIE之BGP正则表达式(四)

BGP 一、AS-Path正则表达式数字| 等同于或的关系[]和.$ 一个字符串的结束_代表任意^一个字符串的开始()括号包围的是一个组合\ 转义字符* 零个或多个&#xff1f;零个或一个一个或多个 二、BGP对等体组三、BGP安全性 一、AS-Path正则表达式 正则表达式是按照一定模版匹配字符串…

Linux实验记录:使用RAID(独立冗余磁盘阵列)

前言&#xff1a; 本文是一篇关于Linux系统初学者的实验记录。 参考书籍&#xff1a;《Linux就该这么学》 实验环境&#xff1a; VmwareWorkStation 17——虚拟机软件 RedHatEnterpriseLinux[RHEL]8——红帽操作系统 目录 前言&#xff1a; 备注&#xff1a; 部署磁盘阵…

成功解决IndexError: index 0 is out of bounds for axis 1 with size 0.

成功解决IndexError: index 0 is out of bounds for axis 1 with size 0. &#x1f335;文章目录&#x1f335; &#x1f333;引言&#x1f333;&#x1f333;报错分析及解决方案&#x1f333;&#x1f333;参考文章&#x1f333;&#x1f333;结尾&#x1f333; &#x1f333;…

Cesium.js实现显示点位对应的自定义信息弹窗(数据面板)

零、相关技术选型&#xff1a; Vue2 Vuecli5 Cesium.js 天地图 一、需求说明 在使用2D地图&#xff08;天地图、高德地图等&#xff09;基于官方文档可以实现下面需求&#xff1a; 实现添加点位&#xff0c;并在点位附近显示对应的信息弹窗。 一般信息弹窗的显示方式有两种&am…

【数据结构1-2】二叉树

树形结构不仅能表示数据间的指向关系&#xff0c;还能表示出数据的层次关系&#xff0c;而有很明显的递归性质。因此&#xff0c;我们可以利用树的性质解决更多种类的问题。 但是在平常的使用中&#xff0c;我们并不需要使用这么复杂的结构&#xff0c;只需要建立一个包含int r…

【极数系列】Flink配置参数如何获取?(06)

文章目录 gitee码云地址简介概述01 配置值来自.properties文件1.通过路径读取2.通过文件流读取3.通过IO流读取 02 配置值来自命令行03 配置来自系统属性04 注册以及使用全局变量05 Flink获取参数值Demo1.项目结构2.pom.xml文件如下3.配置文件4.项目主类5.运行查看相关日志 gite…

sqli-labs第一关

1.判断是否存在注入&#xff0c;注入是字符型还是数字型? ?id1 and 11 ?id1 and 12 因为输入and 11与and 12 回显正常&#xff0c;所以该地方不是数字型。 ?id1 ?id1-- 输入单引号后报错&#xff0c;在单引号后添加--恢复正常&#xff0c;说明存在字符注入 2.猜解SQL查…