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

news2024/10/6 6:49:10

文章目录

  • 动态库和静态库
    • 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输出的是0
    printf("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-lib
	ar -rc $@ $^//构建静态库 目标文件 依赖文件
mymath.o:mymath.c//如何使用mymath.c构建mymath.o
	gcc -c $^//编译到.o文件

.PHONY:clean//伪目标
clean:      //清除所有的.o  .a  和static-lib文件
	rm -rf *.o *.a static-lib
	
.PHONY:output//打包文件
output:
	mkdir -p static-lib/include//创建目录include
	mkdir -p static-lib/my-static-lib//创建目录my-static-lib
	cp *.h static-lib/include//拷贝所有.h文件到include
	cp *.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.c
	gcc -fPIC -c $^

.PHONY:clean//伪目标删除操作
clean:
	rm -rf *.o *.so dy-lib

.PHONY:output//打包动态库
output:
	mkdir -p dy-lib/include
	mkdir -p dy-lib/my-dy-lib
	cp *.h dy-lib/include
	cp *.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.coloradmin.cn/o/1418489.html

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

相关文章

“坦克大战”项目设计文档

「坦克大战」项目的设计文档 功能设计 游戏部分 ​ 在存在 障碍物 的地图上&#xff0c;玩家需要操作一辆绿色的坦克与敌对的灰色坦克作战。 坦克 以及其发射的 炮弹 均会被障碍物所阻挡。玩家用键盘上的 wasd按键 控制坦克移动&#xff0c;用 鼠标 控制炮弹发射方向&#x…

删除倒数第N个结点---链表Oj

https://leetcode.cn/problems/remove-nth-node-from-end-of-list/description/?envType=study-plan-v2&envId=top-100-liked 1、常规解法 删除倒数第N个结点,那就是删除整数第(len - N + 1)个结点,我们只需要找到第len-N个结点,让它的next指向倒数第N个结点…

赛氪荣获“2023天津高新技术企业大会支持单位”

1月23日上午&#xff0c;2023天津市高新技术企业大会新闻发布会在天开高教科技园核心区综合服务中心召开&#xff0c;市高企协以及来自高校、企业、社会组织等80余人现场参会。 大会组委会秘书长张博航介绍到&#xff1a;“本次大会将实现自开办以来的多个首次&#xff0c;首次…

【刷题】 leetcode 面试题 08.05.递归乘法

递归乘法 1 题目描述2 思路一&#xff08;返璞归真版&#xff09;3 思路二&#xff08;二进制乘法器版&#xff09;4 思路三&#xff08;变态版&#xff09;Thanks♪(&#xff65;ω&#xff65;)&#xff89;谢谢阅读下一篇文章见&#xff01;&#xff01;&#xff01; 1 题目…

CTF CRYPTO 密码学-7

题目名称&#xff1a;敲击 题目描述&#xff1a; 让我们回到最开始的地方 0110011001101100011000010110011101111011011000110110010100110011011001010011010100110000001100100110001100101101001101000011100001100011001110010010110100110100011001000011010100110000…

2024年第04周农产品价格报告

一、摘要 农产品价格监测主要涉及对畜禽类产品、水产品、蔬菜类产品、水果类产品的价格&#xff0c;以周为单位&#xff0c;进行变化情况的数据监测。其中&#xff0c;蔬菜类产品共18种&#xff0c;分别为大白菜、西红柿、黄瓜、青椒、芹菜、土豆、白萝卜、茄子、豆角、胡萝卜…

论文精读--BERT

不像视觉领域&#xff0c;在Bert出现之前的nlp领域还没有一个深的网络&#xff0c;使得能在大数据集上训练一个深的神经网络&#xff0c;并应用到很多nlp的任务上 Abstract We introduce a new language representation model called BERT, which stands for Bidirectional En…

IDEA中git的使用和代码对比神器Beyond Compare

和多同学idea配置好了&#xff0c;但是使用却不知道怎么使用。 我这里说说idea中使用的几招常用操作。如&#xff1a;提交&#xff0c;拉取&#xff0c;推送&#xff0c;合并&#xff0c;取消合并&#xff0c;撤回本地提交。 以及一些刚接触idea使用git的怕把公司代码搞砸了的同…

遗传算法改进leach协议(附MATLAB代码)

LEACH&#xff08;低能量自适应聚簇层次&#xff09;协议是无线传感器网络中最早的、最具有影响力的分簇协议之一。它通过随机选举一些传感器节点作为簇头&#xff0c;其他节点加入其中一个簇头组成一个簇&#xff0c;然后簇头负责汇聚数据并将数据发送给基站&#xff0c;从而达…

UE4运用C++和框架开发坦克大战教程笔记(十五)(第46~48集)

UE4运用C和框架开发坦克大战教程笔记&#xff08;十五&#xff09;&#xff08;第46~48集&#xff09; 46. 批量加载 UClass 功能测试批量加载多个同类 UClass 资源 47. 创建单个资源对象测试加载并创建单个 UClass 资源对象 48. 创建同类资源对象 46. 批量加载 UClass 功能 逻…

【HTML 基础】元素和标签

文章目录 1. <p> - 段落标签2. <h1> - <h6> - 标题标签3. <a> - 超链接标签4. <img> - 图片标签5. <ul>, <ol>, <li> - 列表标签无序列表有序列表 总结 HTML&#xff08;Hypertext Markup Language&#xff09;是构建 Web 页面…

Prometheus 监控系统的初步了解与系统搭建

目录 目录 目录 前言 Prometheus的相关知识 Prometheus特点 Prometheus的存储引擎&#xff1a;TSDB Prometheus的组件 1.核心组件&#xff1a;prometheus server Prometheus server又分为三个部分&#xff1a; 2.exports 3.client Library 4.cadvisor 5.blackbox-ex…

二维数组的学习

前言 在前面我们学习了一维数组&#xff0c;但是有的问题需要用二位数组来解决。 二维数组常称为矩阵&#xff0c;把二维数组写成行和列的排列形式&#xff0c;可以有助于形象化的理解二维数组的逻辑结构。 一、二维数组的定义 二维数组定义的一般格式&#xff1a; 数据类型 数…

【前端web入门第二天】03 表单-下拉菜单 文本域 label标签 按钮 【附注册信息综合案例】

文章目录: 1. 下拉菜单 2. 文本域3.label标签 4.按钮- button 4.1 reset重置按钮结合form表单区域使用 5.无语义的布局标签 6.字符实体 注册信息综合案例 表单第二节 1. 下拉菜单 标签: select嵌套option,select是下拉菜单整体&#xff0c;option是下拉菜单的每一项。 代码…

自媒体必备,这10个免费素材网站,一定要收藏~

自媒体必备素材库&#xff0c;视频、图片、音效、各种类型BGM&#xff0c;这10个网站都能找到&#xff0c;免费下载可商用&#xff0c;朋友们赶紧收藏一波~ 视频素材 1、菜鸟图库 https://www.sucai999.com/video.html?vNTYwNDUx 菜鸟图库虽然是个设计素材网站&#xff0c;但…

文物预防性保护新高度:守护历史,个性化定制保护方案

一、西安市研究院宣布西安长安曹家堡村发现2823座古代遗迹 深藏于西安长安曹家堡村地下的2823座古代遗迹&#xff0c;在西安文物维护考古研究院的用心调研下&#xff0c;逐渐揭开了神秘面纱。其中&#xff0c;已有1088座陵墓重见天日&#xff0c;出土的文物琳琅满目&#xff0…

如何实现Win系统ssh连接Ubuntu使用vscode远程敲代码

最近&#xff0c;我发现了一个超级强大的人工智能学习网站。它以通俗易懂的方式呈现复杂的概念&#xff0c;而且内容风趣幽默。我觉得它对大家可能会有所帮助&#xff0c;所以我在此分享。点击这里跳转到网站。 文章目录 前言1、安装OpenSSH2、vscode配置ssh3. 局域网测试连接…

【.NET Core】深入理解C#中的特殊字符

【.NET Core】深入理解C#中的特殊字符 文章目录 【.NET Core】深入理解C#中的特殊字符一、概述二、$-- 字符串内插2.1 内插字符串的结构2.2 内插原始字符串字面量2.3 特殊字符2.4 内插字符串编译 三、-- 逐字字符串标识符四、“”“--原始字符串文本 一、概述 特殊字符是预定义…

Vite+Electron快速构建一个VUE3桌面应用(一)

一. 简介 首先&#xff0c;介绍下vite和Electron。 Vite是一种新型前端构建工具&#xff0c;能够显著提升前端开发体验。Electron是一个使用 JavaScript、HTML 和 CSS 构建桌面应用程序的框架。 嵌入Chromium和Node.js到二进制的 Electron 允许您保持一个 JavaScript 代码代码…

elementui-table组件列表中的tooltip内容过长超出屏幕换行显示

elementui-table组件列表中的tooltip内容过长超出屏幕换行显示 el-table列属性中带的有show-overflow-tooltip&#xff0c;可以设置内容超出列宽度显示为…&#xff0c;并且有tooltip提示&#xff0c;但是内容过多时&#xff0c;提示会超出屏幕&#xff1a; 但是el-table组件…