首页 > 系统相关 >linux动态库和静态库 --20240225

linux动态库和静态库 --20240225

时间:2024-02-25 23:23:58浏览次数:21  
标签:gcc 动态 -- 代码 20240225 静态 linux test main

设计库的目的
1)程序更加简洁,不需要维护太多的源文件

2)保护三方厂商的知识产权

gcc常用指令
复习一波gcc的常用指令:

-E :仅执行预处理(不要编译、汇编或链接)。

-S :只编译(不汇编或链接)。

-c :编译和汇编,但不链接。

-o <file> :指定输出文件。

-pie :创建一个动态链接、位置无关的可执行文件。

-I :指定头文件的包含路径。

-L :指定链接库的包含路径。

-shared :创建共享库/动态库。

-static :使用静态链接。

-fPIC/fpic :生成与位置无关的代码。

-std :指定语言版本,如-std=c++11,gcc默认的语言为c++11。

--help :显示帮助信息。

--version :显示编译器版本信息。

静态库
linux静态库一般以lib为前缀,以.a为后缀,中间是自己定义的库的名字,即最终静态库的名字为:

libxxx.a

静态库的制作:

借用网上的一张图:

要先经过三个步骤,预编译、编译、汇编

该三个步骤可以通过gcc -c来直接完成。获取到二进制格式的目标文件 .o 格式,然后通过linux提供的ar工具将目标文件进行打包就可以获得静态库libxxx.a文件了。

ar工具相关参数说明(ar --help):

Usage: ar [emulation options] [-]{dmpqrstx}[abcDfilMNoPsSTuvV] [--plugin <name>] [member-name] [count] archive-file file...
ar -M [<mri-script]
commands:
d - delete file(s) from the archive
m[ab] - move file(s) in the archive
p - print file(s) found in the archive
q[f] - quick append file(s) to the archive
r[ab][f][u] - replace existing or insert new file(s) into the archive
s - act as ranlib
t - display contents of archive
x[o] - extract file(s) from the archive
command specific modifiers:
[a] - put file(s) after [member-name]
[b] - put file(s) before [member-name] (same as [i])
[D] - use zero for timestamps and uids/gids (default)
[U] - use actual timestamps and uids/gids
[N] - use instance [count] of name
[f] - truncate inserted file names
[P] - use full path names when matching
[o] - preserve original dates
[u] - only replace files that are newer than current archive contents
generic modifiers:
[c] - do not warn if the library had to be created
[s] - create an archive index (cf. ranlib)
[S] - do not build a symbol table
[T] - make a thin archive
[v] - be verbose
[V] - display the version number

举个例子,创建一个静态库

准备的文件如下:

.
├── include
│ └── test.h
└── test.c

// test.h #include <stdio.h> void test();
// test.c #include "include/test.h" void test() {   printf("hello world"); }

1)将源文件进行汇编,生成test.o文件

gcc -c test.c -I include/

2)用ar工具进行打包成静态库

ar rcs libtest.a *o

3)将libtest.a静态库和test.h文件发布测试

// main.c

int main()
{
    test();
}

将libtest.a、test.h、main.c放置于一个目录下,使用

gcc main.c -o main.out -L ./ -ltest

便可生成main.out的可执行文件

 

动态库(共享库)
动态链接库是程序运行加载时的库,运行的多个程序可以使用同一个加载到内存中的动态库,动态库也称共享库,后缀为.so,即shared object的缩写。动态库是有执行权限的,静态库没有执行权限。

linux动态库的命名规则:

libxxx.so

生成动态库是直接使用gcc命令并且需要添加-fPIC(-fpic)以及-shared参数。

-fpic称之为与位置无关的代码,与位置无关的意思就是说,进程是磁盘上运行的一个执行程序,执行几个执行程序就会得到一个虚拟地址空间,在这个虚拟地址空间中,需要加载一些代码,如果是静态库,就会直接打包到执行程序中,因此静态库的代码就会直接放在代码区,如果程序中用的是动态库,库里面的代码不会放到代码区的,会放到动态库加载区,动态库加载区的代码是随着程序的运行并且调用到库里面函数的时候才会加载代码,因此不同的进程中,如果说要调用这个动态库文件,对应的代码的位置都是不一样的,加了-fpic之后我们调用的这个库函数对应得代码在虚拟地址空间中用的是一个相对地址。如果是静态库,对应的代码都是绝对地址,静态库的文件已经被打包到应用程序中去了,所以代码的位置已经固定了。

借用网上的一张图:

与制作静态库的步骤基本类似,准备的文件一致。

1)将源文件进行汇编,生成test.o文件

gcc -c -fpic test.c -I include/

2)gcc -shared生成动态库

gcc -shared *o -o libtest.so

3)将libtest.so动态库和test.h文件发布测试,新建main.c如静态库第三点。

生成可执行程序

gcc main.c -o main.out -L ./ -ltest

在该目录下就可以执行main.out执行程序了

换个目录就可能执行不了了,原因分析:

通过gcc main.c -o main.out -L ./ -ltest生成的main.out执行程序只包含这个动态库的名称已经调用程序的源代码,因此执行可执行程序的时候只有调用程序的源代码加载到进程的代码区。动态库的代码随用随加载,不调用就不会加载到进程中。

解决方式可以将libtest.so文件放到存储动态库的系统目录/lib/下就可以运行了。

关于动态链接器和相关解决方案可以参考:

linux静态库和动态库

5、extern "C"
我们修改一下第四点中的main.c文件为main.cpp,并修改其内容为:

#include <iostream>

int main()
{
    test();
}

用g++链接第四点中生成的libtest.so动态库:

g++ main.cpp -o main -L . -ltest

会出现以下的报错:

我们可以得出:

c++中不能直接调用c编译器编译的代码,我们需要对test()函数进行提前声明,修改main.cpp为:

#include <iostream>

extern "C"{
    extern void test();
}

int main()
{
    test();
}

告诉编译器,将接下来的代码当成c语言来进行处理,目的是支持c++和c的混合编程。

标签:gcc,动态,--,代码,20240225,静态,linux,test,main
From: https://www.cnblogs.com/lethe1203/p/18033327

相关文章

  • extern、const、register、static、inline关键字 --20240225
    extern关键字extern关键字有两种用法:1、用于声明一个全局变量或函数的外部链接性2、extern"C"是一个语言特性,用于告诉编译器按照C语言的方式对待指定的代码块,以确保与C语言兼容 用法一:用于声明一个全局变量或函数的外部链接性//file1.c#include<stdio.h>intn......
  • 23 design patterns
    ///-----------------23个设计模式是7个原则的具体形式,7原则是23个模式的凝练------------------//////-----------------target:高内聚、低耦合------------------///1.软件设计模式结构类比就是结构class或者是结构体行为类比class里面的函数创造的话,是构造出结构,让......
  • filter拦截与放行
    @WebFilter(urlPatterns="/*")publicclassLoginChechedFilterimplementsFilter{//拦截方法,只要资源链接被拦截就会触发此方法@OverridepublicvoiddoFilter(ServletRequestservletRequest,ServletResponseservletResponse,FilterChainfilterChain)throwsIO......
  • 完整登录功能实现
    1、导入pom.xml依赖<dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt</artifactId><version>0.9.1</version></dependency></dependencies>2、生成和解析令牌类的书写privatestatic......
  • ssts-hospital-web-master项目实战记录十四:项目迁移-模块实现(log-local)
    记录时间:2024-02-25一、log-local模块实现framework/config/index.ts//终端日志文件配置constLogTerminalInfoDir='D:\\LogInfo\\LogTerminalInfo\\'constLogTerminalInfoFileNamePrefix='LogTerminalInfo'//错误页面快照文件配置constLogErrorPageSnapshotFil......
  • 【Python】conda基本使用、pip换源、pip超时问题解决
    conda问题往期笔记conda安装:https://www.cnblogs.com/mllt/p/Anaconda-install.htmlconda基础操作https://www.cnblogs.com/mllt/p/jqsj_base_000.html创建环境命令行创建环境的方式见上文“conda基础操作”后面的链接文章。在此演示的是使用pycharm创建conda虚拟环境......
  • 学习记录
    三、进行部署1.安装Nginx软件商店-搜索Nginx-进行安装2.Nginx配置软件商店-已安装-Nginx-设置-配置修改62行的listen888;为监听888端口65行root/www/server/phpmyadmin;表示在此路径下去寻找将62行的listen888改为80将64行的index.html改为combine.html,因为一会儿要上传的网页......
  • 类的集成和类成员的访问控制
    1.被sealed修饰的类代表不能做为基类: 2.一个类最多只能有一个基类3.子类的访问级别不能超过父类的访问级别,可和父类的访问级别持平; 4.继承 5.当父类中的构造器有参数时,子类的构造器的写法6.由以上4、5点说明构造器是不能被子类所继承的:7.访问级别是受最上层级别......
  • SHOI游记
    写在前面我现在只是一个实力平庸的初二选手,侥幸在NOIP中获得了279分,勉强有机会参加省选。我深知进队本就困难,更何况初中生人数的限制。初中有不少实力在我之上的选手,所以我明白,进队的希望是极其渺茫的。当我明白这点,我便将这次的目标从进队,放到了在这次考前的集训中摄取更多的知......
  • 智能AI客服系统+企业专属AI知识库实现原理+配置教程
    企业专属AI知识库实现原理知识库是GPT用户咨询问题,调用文本转向量接口将问题转为向量数据,向量化搜索知识数据库,将相关知识文本整合后发送给GPT聊天补全接口 知识库服务主要基于以下两个接口:OpenAI聊天接口(/v1/chat/completions)OpenAI向量生成接口(/v1/embeddings......