Linux 生成静态库

news2025/3/12 13:39:55

文章目录

  • 前提小知识
  • 生成和使用.a库操作步骤

在应用程序中,有一些公共的代码需要反复使用的,可以把这些代码制作成“库文件”;在链接的步骤中,可以让链接器在“库文件”提取到我们需要使用到的代码,复制到生成的可执行文件中。

在使用到库文件的代码时候,需要库文件代码的头文件。并且在我们使用到库文件代码的应用程序源代码中,包含这些库文件代码的头文件

前提小知识

  • 代码编译的过程:
    我们C源文件是如何生成可执行文件的:
    C源文件 -> 预处理 -> 编译 -> 汇编 -> 链接 -> 可执行文件。
    在这里插入图片描述
  • .代码行一开始就包含h文件的作用
    参考文章:.h文件的作用
      在C语言中,如果在第一行定义了一个变量/函数,在第二行可以使用这个变量/函数;而如果在第二行定义了一个变量/函数,在第一行想使用这个变量/函数,则会找不到这个变量/函数。
      代码行一开始就包含.h头文件的其中一个作用是:
      把一些变量/函数的声明在前面的行中,即使这些变量/函数的定义实现在 使用到这些变量/函数的语句的后面,这语句也能通过变量/函数的声明去找到变量/函数的定义实现
 1 /*test1.c*/
 2 void main(void)
 3 {
 4   prtstr(); 
 5 }
 6 
 7 void prtstr(void)
 8 {
 9   printf("Hello World!\n"); 
10 }

test1.c 编译失败→_→。
prtstr()这个函数来说,他没有单独的声明,只有定义,那么 就从他定义的行开始,到文件结束 可以被使用。
main()函数的引用点上,prtstr()还没有起作用,所以会编译出错。

 1 /*test1.c*/
 2 void prtstr(void);
 3 void main(void)
 4 {
 5   prtstr(); 
 6 }
 7 
 8 void prtstr(void)
 9 {
10   printf("Hello World!\n"); 
11 }

test1.c 编译成功。
prtstr()这个函数来说,他单独的声明了,从他声明的行开始,到文件结束 起作用。
所以main()函数的使用prtstr(),编译也不会出错。

生成和使用.a库操作步骤

  1. 编译源代码,生成.o目标文件,如:gcc -c test.c
  2. 使用ar指令打包ar -rv libtest.a test.o
    注:ar命令可以用来创建、修改库,也可以从库中提出单个模块。
    r:在库中插入模块(替换)。当插入的模块名已经在库中存在,则替换同名的模块。如果若干 模块中有一个模块在库中不存在,ar显示一个错误消息,并不替换其他同名模块。默认的情况下,新的成员增加在库的结尾处,可以使用其他任选项来改变增加的 位置。
    v: 该选项用来显示执行操作选项的附加信息。
  3. 使用编译好的库文件, 如: gcc main.c -L. -ltest -o main
    注:-L/path, 以上-L.表示在当前目录下;-lxxx把库文件的lib和扩展名去掉,所以以上 -ltest 就可以是libtest.a了
    注:为了保证c++代码能正常使用c的库文件,在接口函数的头文件里要使用以下几行代码,其中宏__cplusplus是c++自定义的。
    注:main.c 中需要包含libtest.a库中的函数头文件,否则会出现找不到函数/变量定义的问题。
    #ifdef __cplusplus
    extern “C” {
    #endif

    #ifdef __cplusplus
    }
    #endif
    加上extern "C"后,会指示编译器这部分代码按C语言(而不是C++)的方式进行编译

管理Linux环境下的C/C++大型项目,如果有一个智能的Build System会起到事半功倍的效果,本文描述Linux环境下大型工程项目子目录Makefile的一种通用写法,使用该方法,当该子目录内的文件有增删时无需对Makefile进行改动,可以说相当的智能。

下面先贴代码(为减小篇幅,一些非关键的代码被去掉,本方法的局限是用于一个C文件生成一个可执行文件的场合):

ROOTDIR = .

EXE_DIR = ./bin
CFLAGS = -I$(INCLUDE_DIR) -I$(LIB_INC) -Wall
LFLAGS = -L$(LIB_DIR)

objects := $(patsubst %.c,%.o,$(wildcard *.c))
executables := $(patsubst %.c,%,$(wildcard *.c))

all : $(objects)
$(objects) :%.o : %.c
    @mkdir -p ./bin$
    $(CROSS_COMPILE)gcc -c $(CFLAGS) $< -o $@
    $(CROSS_COMPILE)gcc $(CFLAGS) $< -o $(subst .o, ,$(EXE_DIR)/$@) $(LFLAGS) $(LIBS)
clean:
    @rm -f *.o rm -f $(executables)
    @rm -rf ./bin
distclean: clean

假如当前目录里面有a.c b.c两个文件

      Makefile 里的函数跟它的变量很相似——使用的时候,你用一个$符号跟左圆括号,函数名,空格后跟一列由逗号分隔的参数,最后用右圆括号结束。例如,在GNU Make里有一个叫'wildcard' 的函数,它有一个参数,功能是展开成一列所有符合由其参数描述的文件名,文件间以空格间隔。像这个命令:
 
    objects= $(wildcard *.c)   
 
  会产生一个所有以'.c' 结尾的文件列表(本例结果为a.c b.c),然后存入变量objects里。   
 
  另一个有用的函数是 patsubst ( patten substitude,匹配替换的缩写)函数。它需要3个参数——第一个是一个需要匹配的式样,第二个表示用什么来替换它,第三个是一个需要处理由空格分隔的序列。我们将两个函数合起来用:
 
objects := $(patsubst %.c,%.o,$(wildcard *.c))
 会被处理为:
objects := a.o b.o
 同理:
executables := $(patsubst %.c,%,$(wildcard *.c))
 会被处理为:
executables := a b
 
%o:所有以“.o”结尾的目标,也就是a.o b.o
 
依赖模式“%.c”:取模式“%.o”的%,也就是foo bar,并为其加上.c后缀,即a.c,b.c
 

$<:表示所有依赖目标集,也就是a.c b.c
 
$@:表示目标集,也就是a.o b.o
 
命令前加@,表示在终端中不打印,如@mkdir -p ./bin
 
$(objects) : %.o: %.c
        $(CROSS_COMPILE)gcc -c $(CFLAGS) $< -o $@
 

即可翻译为: 


a.o b.o : a.c b.c    $(CROSS_COMPILE)gcc -c $(CFLAGS) (a.c b.c) -o (a.o b.o)
 
明白了这些,这种Makefile的写法就可以完全掌握了。
命令:ls -d(只显示当前文件夹)
CC = gcc                                    
CFLAGS = -Wall -g 
BIN = main.out
SUBDIR = $(shell ls -d */)      //调用shell命令 ls -d */ 列出当前目录的子目录,不包含当前目录中的文件
ROOTSRC = $(wildcard *.c )      //$(wildcard  *.c)表示从当前目录中查找*.c的文件/文件夹
ROOTOBJ = $(ROOTSRC: %.c = %.o) //把ROOTSRC字符串中的.c结尾的字符串替换为.o结尾的字符串, %.c是GNUMake的写法,相当于shell的*.c
SUBSRC = $(shell find $(SUBDIR) -name ‘*.c‘) //调用shell命令在当前目录的子目录中查找名字为 *.c 的所有文件
SUBOBJ = $(SUBSRC: %.c = %.o)    //在SUBSRC字符串中把.c结尾的字符串替换为.o结尾的字符串

$(BIN) : $(ROOTOBJ) $(SUBOBJ)   //gcc生成main.out文件
    $(CC) $(CFLAGS)  -o $@  $^
.c.o:                          //表示.c 文件 依赖于 .o文件
    $(CC) $(CFLAGS) -c $<  -o  $@
clean:
    rm -f  $(BIN) $(ROOTOBJ) $(SUBOBJ)

-g选项是指可以用gdb调试

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

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

相关文章

ARMV8的64位指令

一、介绍 ARMv8 体系结构最大的改变是增加了一个新的 64 位的指令集&#xff0c;这是早前 ARM 指令集 的有益补充和增强。它可以处理 64 位宽的寄存器和数据并且使用 64 位的指针来访问内存。这 个新的指令集称为 A64 指令集&#xff0c;运行在 AArch64 状态。 ARMv8 兼容旧的…

PawSQL for TDSQL:腾讯云TDSQL数据库性能优化全攻略

TDSQL 作为腾讯云推出的分布式数据库&#xff0c;凭借其高扩展性、高可用性和高性能等优势&#xff0c;广泛应用于金融、互联网、政务等领域。随着业务的不断增长和数据量的爆炸式增长&#xff0c;如何优化 TDSQL 数据库的性能&#xff0c;成为众多企业和开发者面临的挑战。本文…

T-SQL 语言基础:表运算符与联接

目录 介绍表运算符概述交叉联接内联接外联接联接实例总结引用 1. 介绍 在这篇博客中&#xff0c;主要涉及 T-SQL 中的表运算符与联接。联接操作是 SQL 查询中最常用的操作之一&#xff0c;它允许我们在多个表之间进行数据关联。通过了解不同类型的联接及其应用场景&#xff…

jumpserver 网络安全 网络安全 authenticity

1.1 计算机安全的概念 1.1.1 计算机安全最核心的三个关键目标(CIA)&#xff1a; 保密性(Confidentiality)--①数据保密性&#xff08;确保隐私或秘密不向非授权者泄密或使用&#xff09;&#xff1b; ②隐私性&#xff08;确保个人能够控制或确定其自身相关的信息&#xff09…

Spring Cloud之远程调用OpenFeign参数传递

目录 OpenFeign参数传递 传递单个参数 传递多个参数 传递对象 传递JSON OpenFeign参数传递 传递单个参数 服务提供方product-service RequestMapping("/product") RestController public class ProductController {Autowiredprivate ProductService productSe…

网络安全之文件上传漏洞

一&#xff0c;文件上传漏洞的原因&#xff1a; 文件上传漏洞的存在主要是因为开发者未对用户上传的文件进行充分的安全验证&#xff0c;导致攻击者可以上传恶意文件&#xff08;如 WebShell、恶意脚本等&#xff09;到服务器&#xff0c;进而控制服务器或实施进一步攻击。 常…

Fast DDS Security--仿问控制

Fast DDS中提供了两种级别的仿问控制&#xff1a; 1 Domain Governance: 定义域级别的安全策略&#xff08;全局规则&#xff09;. 2 DomainParticipant Permissions &#xff1a; 定义参与者的具体权限&#xff08;个体规则&#xff09; 先说一下Domain Governance&#xf…

为什么大模型网站使用 SSE 而不是 WebSocket?

在大模型网站&#xff08;如 ChatGPT、Claude、Gemini 等&#xff09;中&#xff0c;前端通常使用 EventSource&#xff08;Server-Sent Events, SSE&#xff09; 来与后端对接&#xff0c;而不是 WebSocket。这是因为 SSE 更适合类似流式文本生成的场景。下面我们详细对比 SSE…

基于Matlab设计GUI图像处理交互界面

Image-Processing-GUI 项目说明 本博文提供了完整的代码和使用教程&#xff0c;适合新入门的朋友参考&#xff0c;完整代码资源文件请转至文末的下载链接。 本项目是《Matlab实践》中图像处理软件题目&#xff0c;本项目实现的具体内容如下 基于Matlab设计GUI交互界面图像的…

osg安装编译第三方,完整详细过程。 libtiff/tif config.vc.hdoes not exist

第三方安装包下载地址 GitHub - bjornblissing/osg-3rdparty-cmake: CMake scripts for building OpenSceneGraph third party libraries. 在计算机中的布局 D:\CPlus\osg\src\osg-3rdparty\osg-3rdparty-cmake三层布局&#xff0c;src 放置源码 执行里面的批处理文件&#…

RSA算法:开启现代密码学的数学之钥

一、RSA算法简介 RSA&#xff08;Rivest-Shamir-Adleman&#xff09;是当今应用最广泛的非对称加密算法&#xff0c;由三位科学家Ron Rivest、Adi Shamir和Leonard Adleman于1977年提出。它的核心思想是利用数论中的难题&#xff0c;构建一对数学上关联的密钥——公钥用于加密…

Android Compose Surface 完全指南:从入门到花式操作

今天咱们来聊聊 Compose 世界里那个既基础又强大的组件——Surface。这个看似简单的矩形区域&#xff0c;实际藏着不少宝藏玩法&#xff0c;准备好你的 IDE&#xff0c;咱们发车&#xff01; 一、Surface 是什么&#xff1f; 简单说&#xff0c;Surface 就是个自带背景和样式…

Deepin通过二进制方式升级部署高版本 Docker

一、背景&#xff1a; 在Deepin系统中通过二进制方式升级部署高版本 Docker&#xff0c;下面将详细介绍二进制方式升级部署高版本 Docker 的具体步骤。 二、操作步骤 1.根据需求下载二进制文件&#xff0c;下载地址如下&#xff1a; https://mirrors.tuna.tsinghua.e…

python中time模块的常用方法及应用

Python 的 time 模块是自带的标准模块&#xff0c;不需要额外安装&#xff0c;可以直接通过import time的方式导入并使用其中的函数和类。该模块提供了与时间相关的各种功能&#xff0c;以下是一些常用方法及其应用场景和示例&#xff1a; ### 1. time.time() - **功能**&…

【RTSP】客户端(一):RTSP协议实现

概述 RTSP主要功能总结 RTSP本质是一个应用层协议&#xff0c;主要用于控制实时数据的传递&#xff0c;例如音视频流。RTSP的传输方式与HTTP类似&#xff0c;与HTTP不同在于RTSP主要用于控制传输媒体服务器上的流媒体会话。所以其是一个 客户端-服务器模型&#xff0c;客户端需…

SpringBoot(一)--搭建架构5种方法

目录 一、⭐Idea从spring官网下载打开 2021版本idea 1.打开创建项目 2.修改pom.xml文件里的版本号 2017版本idea 二、从spring官网下载再用idea打开 三、Idea从阿里云的官网下载打开 ​编辑 四、Maven项目改造成springboot项目 五、从阿里云官网下载再用idea打开 Spri…

【工控】线扫相机小结 第五篇

背景介绍 线扫相机通过光栅尺的脉冲触发&#xff0c; 我在调试线扫过程中&#xff0c;发现图像被拉伸&#xff0c;预设调节分配器。图像正常后&#xff0c;我提高的相机的扫描速度&#xff08;Y轴动的更快了&#xff09;。 动的更快的发现&#xff0c;图像变短了&#xff08;以…

【STM32F103C8T6】DMA数据转运ADC多通道

前言 本节为代码部分&#xff0c;知识点在这【江协科技STM32】DMA直接存储器存储-学习笔记-CSDN博客 查看数据地址&#xff1a; uint8_t aa 0x88;int main(void) {OLED_Init();OLED_ShowHexNum(1,1,aa,4); //显示十六进制数 OLED_ShowHexNum(2,1,(uint32_t)&aa,8);wh…

计算机网络--访问一个网页的全过程

文章目录 访问一个网页的全过程应用层在浏览器输入URL网址http://www.aspxfans.com:8080/news/index.aspboardID5&ID24618&page1#r_70732423通过DNS获取IP地址生成HTTP请求报文应用层最后 传输层传输层处理应用层报文建立TCP连接传输层最后 网络层网络层对TCP报文进行处…

JVM G1垃圾回收器详细解析

G1内存布局 Garbage First(简称G1)收集器摒弃了传统垃圾收集器的严格的内存划分&#xff0c;而是采用了基于Region的内存布局形式和局部回收的设计思路。 G1垃圾收集器把Java堆划分为2048个大小相等的独立的Region&#xff0c;每个Region大小取值范围为1-32MB&#xff0c;且必…