Linux操作系统~尝试自己制作并使用动静态库

news2025/2/24 9:10:16

目录

1.动态库和静态库到底是什么

(1).静态库 vs 动态库

(2).动态链接和静态链接的优劣

(3).ldd指令

2.自己制作静态库

(1).打包静态库

(2).ar指令

3.如何用我们的库

4.自己制作动态库

(1).打包动态库

(2).动态库在运行的时候也要给出库的路径


1.动态库和静态库到底是什么

首先我们需要知道什么是动静态库

1.一般库分为两种:静态库和动态库

在Linux中,

  • 如果是动态库:库文件是以.so作为后缀的
  • 如果是静态库:库文件是以.a作为后缀的

2.库文件的命名:libXXXX.so...   or   libYYYY.a...

库的真实名字:去掉lib前缀,去掉.a...,so...后缀,剩下的就是库名称!

3.c++文件的后缀可以是.cpp   .cc   .cxx

换成别的后缀名就没办法通过编译


(1).静态库 vs 动态库

静态库:.a  (windows中是.lib)

动态库:.so  (windows中是.dll)

  • 静态链接是指编译链接时,把库文件的代码全部加入到可执行文件中,因此生成的文件比较大,但在运行时也就不再需要库文件了。其后缀名一般为“.a”
  • 动态链接与之相反,在编译链接时并没有把库文件的代码加入到可执行文件中,而是在程序执行时(需要用到库中的内容时)由运行时的链接文件加载库,多个程序共享使用库的代码。这样可以节省系统的开销。动态库一般后缀名为“.so”

gcc 在编译时默认使用动态库,使用file指令可以看出来

[zebra@VM-8-12-centos test6]$ file test6
test6: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.32, BuildID[sha1]=c27bd79ff83896bc7afa2c4b8418a0c308d663ab, not stripped
[zebra@VM-8-12-centos test6]$ 

(2).动态链接和静态链接的优劣

指定test.c使用静态链接的方式链接库(gcc默认采用动态链接)

$ gcc hello.c -o h_static -static

用file命令可以看到确实是采用了静态链接

[zebra@VM-8-12-centos test6]$ g++ -o test6_static test6.cpp -std=c++11 -static
[zebra@VM-8-12-centos test6]$ ll
total 1608
-rwxrwxr-x 1 zebra zebra    9112 Nov 22 19:49 a.out
-rw-rw-r-- 1 zebra zebra      73 Nov  4 16:30 Makefile
-rwxrwxr-x 1 zebra zebra    8976 Nov 11 16:23 test6
-rw-rw-r-- 1 zebra zebra     249 Nov 15 19:53 test6.cpp
-rwxrwxr-x 1 zebra zebra 1612816 Nov 22 19:50 test6_static
[zebra@VM-8-12-centos test6]$ file test6_static 
test6_static: ELF 64-bit LSB executable, x86-64, version 1 (GNU/Linux), statically linked, for GNU/Linux 2.6.32, BuildID[sha1]=eaeab76d92e3a8c6622b3e706dda1f7688b99132, not stripped
[zebra@VM-8-12-centos test6]$ 

我们发现静态链接生成的可执行文件比动态链接大很多。

动态链接的优劣:节省内存和硬盘的空间,下载传输比较方便。(库没了就运行不了)

静态链接的优劣:可移植性强,移植的时候不需要将库移植过去。(会比较占空间)

        动态库可以在多个程序间共享,所以动态链接使得可执行文件更小,节省了磁盘空间。操作系统采用虚拟内存机制允许物理内存中的一份动态库被要用到该库的所有进程共用,节省了内存和磁盘空间。


(3).ldd指令

ldd 可执行程序

可以查看当前程序用了哪些动态库

[zebra@VM-8-12-centos test6]$ ldd test6
        linux-vdso.so.1 =>  (0x00007ffeb0589000)
        libstdc++.so.6 => /home/zebra/.VimForCpp/vim/bundle/YCM.so/el7.x86_64/libstdc++.so.6 (0x00007fc8a81d3000)
        libm.so.6 => /lib64/libm.so.6 (0x00007fc8a7ed1000)
        libgcc_s.so.1 => /lib64/libgcc_s.so.1 (0x00007fc8a7cbb000)
        libc.so.6 => /lib64/libc.so.6 (0x00007fc8a78ed000)
        /lib64/ld-linux-x86-64.so.2 (0x00007fc8a8554000)
[zebra@VM-8-12-centos test6]$ 

2.自己制作静态库

        我们vim打开libc库文件发现是乱码,因为库本身就是二进制文件,那么我们如何得知一个库给我们提供了什么方法?

        一套完整的库:1.库文件本身。2.头文件(是文本形式的,会说明库中暴露出来的方法的基本使用)。3.说明文档

Q:我们在C/C++中,为什么有时候写代码的时候,有时候是.h里面放上声明,.c/.cpp放入实现?为什么要这么设计呢? ?

因为我们要制作库!,更加方便使用。之后给别人用的时候,库文件和头文件都给,这样库文件就可以封装起来(转换成二进制文件)了。(毕竟是自己写出来的代码,不想给别人看,只想给别人用,那就转换成二进制文件)

如果是要开源的代码,写在同一个文件里面,后缀名可以是.hpp

头文件第一行:#pragma once:为了避免同一个文件被include多次

        如果我们没有打包成库,.h文件(include的时候要写正确路径,或者借用环境)和.cc文件是分离的,此时编译的时候需要把.cc文件也要带上,否则会报错

如:

[zebra@VM-8-12-centos test12_libtest]$ g++ -o test test.cc ./test_lib/add.cc ./test_lib/mul.cc
[zebra@VM-8-12-centos test12_libtest]$ ll
total 24
-rw-rw-r-- 1 zebra zebra   69 Nov 22 20:14 Makefile
-rwxrwxr-x 1 zebra zebra 9048 Nov 22 20:24 test
-rw-rw-r-- 1 zebra zebra  245 Nov 22 20:24 test.cc
drwxrwxr-x 2 zebra zebra 4096 Nov 22 20:16 test_lib
[zebra@VM-8-12-centos test12_libtest]$ 

(1).打包静态库

1.将所有.c源文件文件编译成.o

2.使用ar命令将所有.o文件打包在一起,这就是一个库了


(2).ar指令

ar是gnu归档工具,rc表示(replace and create),类似tar,zip

生成静态库

[zebra@VM-8-12-centos test_lib]$ ar -rc test_lib.a add.o mul.o(这里使用了$@ $^)

$@表示目标

$^表示所有的依赖

$<表示第一个依赖

%.o表示所有以.o结尾的文件(Makefile中特有的通配符)

使用Makefile生成test_lib.a

[zebra@VM-8-12-centos test_lib]$ make

g++ -c -o add.o add.cc

g++ -c -o mul.o mul.cc

ar -rc test_lib.a add.o mul.o

[zebra@VM-8-12-centos test_lib]$ ll

total 32

-rw-rw-r-- 1 zebra zebra   59 Nov 22 20:24 add.cc

-rw-rw-r-- 1 zebra zebra   82 Nov 22 20:10 add.h

-rw-rw-r-- 1 zebra zebra 1248 Nov 22 20:43 add.o

-rw-rw-r-- 1 zebra zebra  192 Nov 22 20:43 Makefile

-rw-rw-r-- 1 zebra zebra   60 Nov 22 20:24 mul.cc

-rw-rw-r-- 1 zebra zebra   35 Nov 22 20:07 mul.h

-rw-rw-r-- 1 zebra zebra 1248 Nov 22 20:43 mul.o

-rw-rw-r-- 1 zebra zebra 2714 Nov 22 20:43 test_lib.a

查看静态库中的目录列表

[zebra@VM-8-12-centos test_lib]$ ar -tv test_lib.a 

rw-rw-r-- 1001/1001   1248 Nov 22 20:43 2022 add.o

rw-rw-r-- 1001/1001   1248 Nov 22 20:43 2022 mul.o

t:列出静态库中的文件

v:verbose 详细信息

3.所以静态库的本质就是把所有的.c源文件编译成.o,然后打包放到一个.a文件中

4.我们还可以加两个指令,output和install分别用来打包生成库文件和头文件,或者安装(这样使用头文件和库文件就不需要加上路径了,但是只有本次启动服务器有效,除非修改配置文件)

 注意一下这里库的名字,一定要是lib+名称,否则后面链接库的时候会出错!!!


3.如何用我们的库

使用指令g++ -o test test.cc -std=c++11 -I ./output_lib -L ./output_lib -ltest

注意:

        1.如果include里面已经指明头文件路径,这里可以不加这个选项

        2.库名称必须是lib+名字(可以跟上.a后缀),这里链接库的时候把lib去掉,变成-l+去掉lib后的库名称(实际上库的真实名字就应该去掉lib)

#include<iostream>
#include"./output_lib/add.h"
#include"./output_lib/mul.h"
using namespace std;
int main()
{
    int a = 3;
    int b = 4;
    int sum = add(a,b);
    int multi = mul(a,b);
    cout << sum << endl << multi << endl;
}

[zebra@VM-8-12-centos test12_libtest]$ make

g++ -o test test.cc -std=c++11 -I ./output_lib -L ./output_lib -ltest


4.自己制作动态库

(1).打包动态库

        和动态库不同的是,生成.o文件的时候,需要加上-fPIC选项;生成库文件的时候,gcc加上-shared选项,而不需要使用ar指令了。

libtest.so:add.o mul.o

# 动态库使用的不是ar指令,而是使用g++指令,加上-shared选项

g++ -shared -o $@ $^

# 动态库在生成.o文件的时候,需要加上-fPIC选项

%.o:%.cc

g++ -fPIC -c -o $@ $^

# 和静态库一样

.PHONY:clean

clean:

rm -rf *.o libtest.so output_lib_dynamic

# 和静态库一样

.PHONY:output

output:

mkdir output_lib_dynamic

cp -rf *.h output_lib_dynamic

cp -rf libtest.so output_lib_dynamic

# 和静态库一样

.PHONY:install

install:

cp *.h /usr/include

cp libtest.so /lib64


(2).动态库在运行的时候也要给出库的路径

        静态库在运行的时候不需要找库,所以运行的时候直接./mytest就行了,在编译的时候需要指定。

        动态库在运行的时候需要找库,所以除了在编译期间告诉编译器库在哪里,在运行期间也需要告诉加载器库在哪里

g++编译只是告知编译器头文件库路径在哪里,当程序编译好的时候,此时已经和编译无关了!

解决方法:

使用环境变量LD_LIBARARY_PATH(针对动态库)

//先获取当前库文件所在路径

[zebra@VM-8-12-centos output_lib_dynamic]$ pwd

/home/zebra/cpp/test/test12_libtest/output_lib_dynamic

//然后修改环境变量

[zebra@VM-8-12-centos output_lib_dynamic]$ export

LD_LIBRARY_PATH=/home/zebra/cpp/test/test12_libtest/output_lib_dynamic

注意:这个环境变量在下次添加的时候就会没掉。 

        当然,也可以把库文件和头文件放到系统默认的目录下,或者更新配置文件,不过最好不要这么做。

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

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

相关文章

Java基础之《netty(4)—NIO之Channel》

一、基本介绍 1、NIO的通道类似于流&#xff0c;但有些区别 &#xff08;1&#xff09;通道可以同时进行读写&#xff0c;而流只能读或者只能写 &#xff08;2&#xff09;通道可以实现异步读写数据 &#xff08;3&#xff09;通道可以从缓冲读数据&#xff0c;也可以写数据到…

C++模板基础和STL之string

泛型编程之模板 使用实际调用的函数不是同一个&#xff0c;因为不同类型参数&#xff0c;函数栈帧中开辟的空间不一样。参数不一样&#xff0c;所以调用的函数也不一样。使用模板速度必重载速度更快&#xff0c;因为是编译器直接生成。而STL就叫标准模板库。 template<cla…

Activity的生命周期

文章目录Activity的生命周期一.返回栈二.Activity状态1.运行状态2.暂停状态3.停止状态4.销毁状态三.Activity的生存期onCreate()onStart()onResume()onPause()onStop()onDestroy()onRestart()完整生存期可见生存期前台生存期Activity的生命周期图体验Activity的生命周期编写三个…

PTA题目 阅览室

天梯图书阅览室请你编写一个简单的图书借阅统计程序。当读者借书时&#xff0c;管理员输入书号并按下S键&#xff0c;程序开始计时&#xff1b;当读者还书时&#xff0c;管理员输入书号并按下E键&#xff0c;程序结束计时。书号为不超过1000的正整数。当管理员将0作为书号输入时…

机器人工程考研难易主观感受和客观数据

简易版&#xff08;共性&#xff09;&#xff1a; 主观反馈&#xff1a;越来越难 客观数据&#xff1a;研究生录取人数越来越多&#xff0c;比例也越来越高 看起来矛盾&#xff0c;其实并非如此。 详细数据&#xff1a; 80后是指1980年至1989年出生的人口&#xff0c;对应2…

MySQL_07:单行函数

文章目录一、函数的基本理解1.函数的理解1.1内置函数的基本理解1.2不同DBMS函数的差异1.3MySQL的内置函数的分类2.图解多行函数和单行函数二、单行函数1.数值函数1.1基本函数1.2角度与弧度互换函数1.3三角函数1.4指数与对数1.5进制间转换2.字符串函数3.日期和时间函数3.1获取日…

python常用操作之使用多个界定符(分隔符)分割字符串

本系列文章会总结python中各种常见及常用的内置方法、对不同数据结构的操作&#xff0c;参考书籍《python cookbook》第三版 分割字符串单个界定符分割字符串代码演示多个界定符分割字符串代码演示注意总结在日常学习及工作中&#xff0c;不论是在解析数据还是在产出输出&#…

【LeetCode】No.98. Validate Binary Search Tree -- Java Version

题目链接&#xff1a;https://leetcode.com/problems/validate-binary-search-tree/ 1. 题目介绍&#xff08;Validate Binary Search Tree&#xff09; Given the root of a binary tree, determine if it is a valid binary search tree (BST). 【Translate】&#xff1a; 给…

Qt 堆栈窗体QStackedWidget使用

QStackedWidget控件相当于一个容器&#xff0c;提供一个空间来存放一系列的控件&#xff0c;并且每次只能有一个控件是可见的&#xff0c;即被设置为当前的控件。QStackedWidget可用于创建类似于QTabWidget提供的用户界面。 它是一个构建在QStackedLayout类之上的方便布局小部件…

dolphinscheduler 2.0.6 负载均衡源码

目录&#x1f42c;官网介绍&#x1f42c;负载均衡&#x1f420;加权随机&#xff08;random&#xff09;&#x1f420;平滑轮询&#xff08;roundrobin&#xff09;&#x1f420;线性负载&#xff08;lowerweight&#xff09;&#x1f435;其它&#x1f42c;官网介绍 官网资料&…

【计算机网络】网络层:虚拟专用网

由于IP地址的紧缺&#xff0c;一个机构能够申请到的IP地址数往往远小于本机构拥有的主机数。 如果一个机构内部的计算机通信也采用TCP/IP协议&#xff0c;那么这些仅字机构内部使用的计算机就可以由本机构自行分配其IP地址。 本地地址&#xff08;专用地址&#xff0c;互联网对…

Java培训教程给bean的属性赋值

依赖注入的方式 1. 通过bean的setXxx()方法赋值 Hello World中使用的就是这种方式 2. 通过bean的构造器赋值 Spring自动匹配合适的构造器<bean id“book” class“com.atguigu.spring.bean.Book” > <constructor-arg value “10010”/> …

有位p8终于把珍藏多年的算法视频给分享出来了,总共3.81G

大厂面试都开始问算法了&#xff0c;要是你不会算法只能与大厂失之交臂。为了解决大家算法方面的缺失&#xff0c;小编特此分享算法的学习路线和学习视频&#xff0c;希望大家能够喜欢&#xff01;&#xff01;&#xff01; 左神算法-KMP算法及其扩展 左神算法-Morris遍历及其…

S2B2C供应链系统将引领商业模式!S2B2C供应链电商系统实现订单管理数智化

近年来随着5G、人工智能、区块链、大数据、物联网等技术的快速发展&#xff0c;带动了数字经济的升级发展&#xff0c;疫情的不断反复更是加速推动了数字经济新发展&#xff0c;产业数字化和数字产业化进程加快&#xff0c;促进了各行各业快速发展&#xff0c;S2B2C供应链系统模…

17【redux】

17 【redux】 引言 我们现在开始学习了 Redux &#xff0c;在我们之前写的案例当中&#xff0c;我们对于状态的管理&#xff0c;都是通过 state 来实现的&#xff0c;比如&#xff0c;我们在给兄弟组件传递数据时&#xff0c;需要先将数据传递给父组件&#xff0c;再由父组件…

[附源码]Python计算机毕业设计大学生志愿者管理系统

项目运行 环境配置&#xff1a; Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术&#xff1a; django python Vue 等等组成&#xff0c;B/S模式 pychram管理等等。 环境需要 1.运行环境&#xff1a;最好是python3.7.7&#xff0c;…

软件工程经济学期末复习

1、利润 收入-成本费用 2、资产 流动资产非流动资产 3、显性成本可以用货币计量&#xff0c;是可以在会计的帐目上反映出来的 4、领取什么保险应缴纳个人所得税 商业保险 某企业一项固定资产的原价为800 0000元&#xff0c;预计使用年限为6年&#xff0c;预计净残值为5 0…

软件测试linux面试相关的知识

一、常用的命令 ls&#xff08;查看目录下的内容&#xff0c;-a显示隐藏目录&#xff09; cd&#xff08;进入某个目录&#xff0c;cd .. 返回上一层目录&#xff0c;cd - 返回上一次的目录&#xff0c;cd / 返回根目录&#xff09; pwd&#xff08;显示当前绝对路径&#x…

阿里云易立:以增效促降本,容器服务全面进入智能化时代

容器技术已经跨越鸿沟&#xff0c;广泛应用于金融、通讯、制造、交通等千行百业。Kubernetes支撑的工作负载也从早期单一的互联网应用发展到数据库、AI、大数据等等&#xff0c;并覆盖了公共云、专有云、边缘云等多样化、动态的云环境。 11月5日&#xff0c;2022杭州 云栖大会…

在Windows7在部署Hadoop+Hbase

0. 准备工作 0.1 电脑上现在没有jdk 0.1 提前准备好文件 1. 现在开始安装jdk 1.8.0_60 安装成功&#xff0c;没啥问题 小疑问&#xff1a;自动配置好了环境变量? 1.1 小记 在安装jdk的时候&#xff0c;有三种小工具&#xff0c;可以根据需要选择性安装 JDKjre源代码 虽…