【Linux我做主】探秘gcc/g++和动静态库

news2025/5/19 23:31:09

@TOC

Linux编译器gcc/g++的使用

github地址

有梦想的电信狗

前言

在软件开发的世界中,编译器如同匠人的工具,将人类可读的代码转化为机器执行的指令。

对于Linux开发者而言,gccg++是构建C/C++程序的核心工具链,掌握它们的原理和使用技巧是每一位开发者成长的必经之路。

本文将深入剖析从源代码到可执行程序的完整生命周期,揭示预处理、编译、汇编、链接四大阶段的神秘面纱,探讨动静态库的本质差异,解密DebugRelease版本背后的工程权衡。

无论您是初探Linux开发的爱好者,还是希望夯实编译原理的进阶者,本文都将为您呈现一场理论与实践并重的技术之旅。


C/C++可执行程序的形成过程

C/C++源文件.c或.cpp源文件形成可执行程序需要经历预处理、编译、汇编、链接四个过程,接下来依次介绍各个时期的特点以及Linux下的编译器gcc/g++是如何实现这些过程的。

预处理 (Preprocessing)

​输入文件​: .c/.cpp 源文件
​输出文件​: .i 文件(预处理后的文本文件,预处理后依然是.c/.cpp 文件)
​工具​: 预处理器

核心过程:

  1. 展开所有 #include 指令,递归插入头文件内容
  2. 处理 #define 宏定义,执行文本替换。
  3. 条件编译处理(#ifdef, #ifndef, #endif 等)
  4. 删除所有注释(///* */),删除所有空行和空白。
  5. 添加行标记(#line 指令)供调试使用
  6. 处理 #pragma 编译器指令
  • 使用gcc编译器仅完成预处理步骤
    示例:gcc -E main.c -o main.i

编译 (Compilation)

​输入文件​: .i 文件
​输出文件​: .s 文件(汇编代码文件)
​工具​: 编译器(如 gcc, clang

  • 编译是消耗时间和资源最多的步骤。

核心过程:

  1. ​词法分析​​:将源代码分解为 Token 流,检查语法
  2. ​语法分析​​:构建抽象语法树(AST)
  3. ​语义分析​​:类型检查、作用域验证等
  4. ​中间代码生成​​:生成平台无关的中间表示(如 LLVM IR)
  5. ​代码优化​​:进行死代码消除、循环优化等
  6. ​目标代码生成​​:生成特定 CPU 架构的汇编代码

了解了以上过程,我们认识到,**宏不会进行类型检查和语法分析**的原因是:

  • 宏进行的是文本替换,在预处理阶段进行

  • 语法检查是在编译阶段进行的。

    因此常说宏是类型不安全的

    将预处理后的文件翻译成汇编语言指令:

    示例:gcc -S main.i -o main.s


汇编 (Assembly)

  • 将汇编指令翻译成机器指令的过程。

    ​输入文件​: .s 文件
    ​输出文件​: .o/.obj 文件(二进制目标文件)
    ​工具​: 汇编器

核心过程:

  1. 将助记符形式的汇编代码转换为机器指令(二进制操作码)
  2. 生成符号表(记录函数/变量地址信息)
  3. 生成重定位表(标记需要链接时修正的地址)
  4. 生成节区信息(text/data/bss 等段)

可执行文件的格式:

  • Linux: ELF 格式(Executable and Linkable Format)
  • Windows: COFF 格式(Common Object File Format)

示例:gcc -c main.s -o main.o


链接 (Linking)

​输入文件​: .o 文件 + 静态库或动态库(.a/.lib
​输出文件​: 可执行文件(.exe(windows下) 或有执行权限的文件(Linux下))
​工具​: 链接器

核心过程:

  1. ​符号解析​​:匹配所有未定义符号与其定义
  2. ​地址分配​​:
    • 地址回填:给每个目标文件分配运行时内存地址
    • 数据段合并:合并相同类型的节区(如多个.text段合并)
  3. ​重定位修正​​:根据实际地址修改代码中的引用
  4. ​解析库依赖​​:
    • 静态链接:直接将库代码复制到可执行文件中
    • 动态链接:生成导入表记录共享库信息

链接类型:

类型特点文件扩展名
静态链接代码体积大,无运行时依赖.a (Linux) .lib (Windows)
动态链接代码体积小,需要运行时环境支持.so (Linux) .dll (Windows)

示例:gcc main.o -o main

在进行多文件编译时,对每个文件进行单独编译,最终一起链接。


完整流程示例

# 完整编译流程(隐含执行所有阶段)
gcc main.c -o main

# 分步执行(显式控制每个阶段)
gcc -E main.c -o main.i    # 预处理
gcc -S main.i -o main.s    # 编译
gcc -c main.s -o main.o    # 汇编
gcc main.o -o main         # 链接

gcc/g++如何完成可执行程序的形成过程

形成过程

例如有源文件main.c,现要分步骤对其进行编译形成可执行文件。

  • 预处理

    • gcc -E main.c -o main.i该指令告诉gcc,现在开始进行程序的翻译,预处理结束后停止。
  • 编译

    • gcc -S main.i -o main.s该指令告诉gcc,对预处理过后的.i文件进行处理,编译结束后停止。
  • 汇编

    • gcc -c main.s -o main.o该指令告诉gcc,汇编结束后停止。
    • 形成的.o文件是可重定位目标二进制文件,简称目标文件。windows下是.obj文件,不可以独立执行,虽然已经是二进制格式了,但需要链接后才可以执行。
      在这里插入图片描述
  • 链接

    • gcc main.o -o main 将可重定位目标二进制文件,和库链接形成可执行程序。

最常用的命令行编译指令

我们在进行单个源文件的编译时,如果没有查看中间文件的需求,则直接使用gcc一步完成编译

gcc test.c  #默认生成的程序名为a.out
gcc test.c -o test   # 指定可执行程序的名字为 test

在这里插入图片描述

选项记忆小妙招

预处理、编译、汇编三个过程的选项分别是-E -S -c

  • 刚好组成ESc

预处理、编译、汇编三个过程形成的文件的后缀依次是.i .s .o

  • 三个字母组成iso,恰好是操作系统的镜像文件的后缀名。

gcc编译的其他常用选项

  • -E: 只激活预处理,这个不生成文件,你需要把它重定向到一个输出文件里面。
  • -S: 编译到汇编语言,不进行汇编和链接
  • -c 编译到目标代码
  • -o 文件输出到文件
  • -static 此选项对生成的文件采用静态链接。gcc编译在链接库时默认采用动态链接。
  • -g 生成调试信息。GNU 调试器可利用该信息。
  • -shared 此选项将尽量使用动态库,所以生成文件比较小,但是需要系统有动态库.
  • -O0-O1-O2-O3 编译器的优化选项的4个级别,-O0表示没有优化,-O1为缺省值,-O3优化级别最高
  • -w 不生成任何警告信息。
  • -Wall 生成所有警告信息。

g++相关

对于以上操作和选项,gcc所有的编译操作和命令选项同样适用于g++,只不过编译的源程序变成了.cpp文件。

g++和gcc的区别

编译器主要语言支持次要语言支持
gccC语言C++(需显式指定)
g++C++(ISO标准)C(不推荐)

关键区别

  • gcc默认作为C语言编译器
  • g++默认作为C++编译器,g++既可编译C语言,也可以编译C++
预定义宏差异
编译器默认宏
gcc__STDC__
g++__cplusplus

示例检测:

#ifdef __cplusplus
    cout << "C++环境";  // g++会执行
#else
    printf("C环境");    // gcc可能执行
#endif
使用场景指南

推荐使用g++的情况

  • 纯C++项目开发
  • 使用STL/模板等C++特性
  • 需要异常处理/RTTI特性
  • 混合C/C++代码(作为主要编译器)

推荐使用gcc的情况

  • 纯C语言项目开发
  • 需要严格C标准兼容
  • 嵌入式开发(配合-ffreestanding
  • 内核开发等底层编程
对比总结表
特性gccg++
默认标准C17C++17
标准库链接需手动-lstdc++自动链接
文件后缀处理根据后缀判断强制C++模式
函数重载不支持支持
异常处理默认禁用默认启用
RTTI需手动开启默认启用
启动代码C启动程序C++启动程序
预定义宏STDC__cplusplus

链接与库:初始动静态库

上文在介绍链接过程时,提到了​​输入文件​.o 与静态库或动态库(.a/.lib)的链接共同形成可执行文件,那么什么是库呢?

  • 同时思考

我们的C程序中,并没有定义printf的函数实现,且在预编译中包含的头文件<stdio.h>中也只有该函数的声明,而没有定义函数的实现,那么,是在哪里实现printf函数的呢?

最后的答案是:系统把这些函数实现都被做到名为 libc.so.6 的库文件中去了,在没有特别指定时,gcc会到系统默认的搜索路径/usr/include下进行查找,也就是链接到 libc.so.6 库函数中去,这样就能实现函数printf了,而这也就是链接的作用

什么是库?

库(Library)是预编译的二进制代码集合,包含可重用的函数/类/资源。在链接过程中,编译器会将.o目标文件与静态库(.a/.lib)或动态库(.so/.dll)链接,最终生成可执行文件。

库分为动态库和静态库。

  • Linux下的头文件和库默认搜索路径在/usr/include目录下
    在这里插入图片描述

动态库

  • 概念
    动态库Dynamic Library)是一种在程序​​运行时​​被动态加载到内存的二进制代码库,其核心设计目标是实现代码的​​共享复用​​和​​资源优化​​。

动态库的代码不会在编译时直接嵌入可执行文件,而是由操作系统的动态链接器(如ld-linux.so)在程序启动时或运行期间(通过dlopen())按需加载到内存。

  • 特点
    • 文件扩展名:Linux下为.so(Shared Object),Windows为.dll
    • 运行时加载:程序运行时由动态链接器加载到内存
    • 共享性:多个程序可共享同一份动态库实例
    • 版本控制:通过符号版本机制支持ABI兼容更新

静态库

  • 概念
    静态库是指编译链接时,把库文件的代码全部加入到可执行文件中,因此生成的文件比较大,但在运行时也就不再需要库文件了。其后缀名一般为.a
  • 特点
    • 文件扩展名:Linux下为.a(Archive),Windows为.lib
    • 编译时链接:库代码直接嵌入到最终可执行文件中
    • 独立性:不依赖外部库文件即可运行
    • 体积代价:导致可执行文件体积显著增大

  • 库存在的意义
  1. 代码复用:避免重复造轮子
  2. 模块化开发:解耦复杂系统
  3. 知识产权保护:分发二进制而非源码
  4. 降低维护成本:更新库文件无需重新编译主程序
  5. 节省存储空间:动态库可被多个进程共享
  6. **关于学习和工作:**在学习阶段,我们是适度的造轮子;而在工作阶段,我们最好找已有的解决方案。

gcc的默认链接方式及file和ldd命令

  • Linux中,gcc编译形成可执行程序,默认采用的是动态链接,需要系统提供动态库。
  • Linux中,如果想以静态链接的方式形成可执行程序,需要在编译时添加-static选项,并且系统需要提供静态库。

在这里插入图片描述

  • test_dygcc默认的编译程序,默认采用动态链接。

  • test_staticgcc指定静态链接时的编译程序,可以明显的看到程序的体积大了很多。

  • 我们可以通过file命令来查看可执行程序的链接方式。
    在这里插入图片描述

  • 可以使用ldd命令查看可执行程序已链接的动态库
    在这里插入图片描述
    可以看到:

  • 动态链接形成的test_dy链接了一些动态库

  • 静态链接形成的test_static没有已链接的动态库

动静态库优缺点对比

特性静态库动态库
文件体积显著增大较小
内存占用独立占用共享内存
部署复杂度简单(单文件)需确保库文件存在
更新维护需重新编译替换库文件即可
启动速度较快(无加载开销)略慢(需要加载)
适用场景嵌入式、独立工具大型应用、系统级服务
  • 动态库因为是共享库,可以有效的节省资源,包括(磁盘空间、内存空间、网络空间等)。动态库一旦缺失,会导致各个程序都无法运行。
  • 静态库,不依赖库,程序可以独立运行。但体积大,消耗资源。

总结

  • 动态链接的库,就叫动态库,静态链接的库,就叫静态库。
  1. 如果我们没有静态库,但要在编译时使用-static选项,这是不可行的。
  2. 如果我们没有动态库,只有静态库,且能静态库被编译器找到,则可以正常链接。
  3. -static选项的本质是改变编译器链接模式的优先级。-static只适配一次,会将所有的链接要求全部变成静态链接。
  4. 在一个程序中,既会有动态库,也会有静态库,一般都是动静态库混合使用的。

CentOS下安装静态库

一般的Linux系统,默认只提供了动态库,静态库库需要我们自行进行安装。

C语言静态库

sudo yum install glibc-static

C++静态库

sudo yum install libstdc++-static

验证安装

# 查找静态库路径
sudo find /usr/ -name "libc.a"
sudo find /usr/ -name "libstdc++.a"
  • 查找结果如下
    在这里插入图片描述

开发建议

  1. 优先使用动态库:适用于大多数桌面/服务器应用
  2. 谨慎选择静态库:考虑磁盘空间和内存限制
  3. 混合使用策略:关键模块静态链接,通用功能动态链接
  4. ABI兼容性:动态库更新时保持向后兼容

Debug与Release软件简介

gcc编译器在不增加特殊选项时,默认采用release版本编译形成可执行程序

核心概念

Debug版本

  • 编译特性:包含调试符号(-g)可以被追踪调试、禁用优化(-O0)
  • 文件体积:可执行文件略大(形成可执行文件时,添加了调试信息)
  • 典型用途
    • 开发阶段调试
    • 崩溃问题分析
    • 性能问题定位

Release版本

  • 编译特性:启用优化(-O2/-O3)、去除调试符号
  • 文件体积:可执行文件较小
  • 典型用途
    • 生产环境部署
    • 性能敏感场景
    • 正式版本发布
  • debug版本软件包含了调试信息,因此软件的体积更大一些
    在这里插入图片描述
  • gcc编译器在不增加特殊选项时,默认采用release版本编译形成可执行程序
  • 我们在编译时添加-g选项,可形成包含调试信息的可执行程序
  • 那么选项-DDEBUG又有什么含义呢?

场景引入:

在这里插入图片描述

两个命令-g-DDEBUG两个选项生成的程序虽然都用于调试,但包含的信息不同,具体区别如下:

  1. gcc test.c -o test_Debug -DDEBUG
    -DDEBUG:定义预处理宏DEBUG,用于在编译时启用代码中#ifdef DEBUG控制的调试逻辑(如打印日志、额外检查等)。
    不包含调试符号:生成的程序没有嵌入调试信息(如变量名、行号),无法直接通过调试器(如GDB)进行源码级调试。
    程序行为可能不同:如果代码依赖DEBUG宏控制逻辑,test_DEBUG会执行这些调试相关的代码。
    • -DDEBUG选项的本质是在源程序文件中添加了DEBUG宏,用于在编译时启用代码中#ifdef DEBUG控制的调试逻辑。
  2. gcc test.c -o test_debug -g
    -g:嵌入调试符号,允许使用调试器跟踪变量、设置断点等。
    不启用DEBUG:除非代码中已定义或通过其他方式启用,否则#ifdef DEBUG的代码不会编译到程序中。
    程序行为与未启用DEBUG宏的版本一致(假设代码逻辑依赖该宏)。
关键区别:
选项调试符号(-g启用DEBUG宏(-DDEBUG
test_Debug❌ 无✔️ 启用
test_debug✔️ 有❌ 未启用(除非代码已定义)
结论:

是否属于“Debug模式”:取决于定义。若认为需同时包含调试符号和调试代码,则两者均不完全;若接受部分特性,则分别属于不同维度的调试版本。
信息差异:两者包含的信息不同test_Debug可能包含更多调试输出但难以用调试器分析;test_debug便于调试但可能缺少DEBUG宏控制的代码。


Debug和Release核心差异对比

特性Debug版本Release版本
编译选项-g -O0-O2/-O3
符号表包含完整调试信息通常去除
代码优化无优化(保留原始逻辑)高度优化(可能改变执行流)
执行速度较慢快(提升20%-300%)
内存占用较高较低
逆向难度容易(保留符号)困难

readelf命令查看调试信息

在这里插入图片描述

高级控制技巧

条件编译宏

#ifdef NDEBUG
// Release模式专用代码
#else
// Debug模式专用代码
#endif

总结

通过本文的探索,我们揭开了gcc/g++编译器从源代码到二进制程序的全流程面纱。从预处理阶段的宏展开到编译阶段的语法树构建,从汇编指令的生成到链接时的符号解析,每一个环节都彰显着计算机科学的精妙设计。

理解动静态库的取舍之道,掌握Debug版本的调试信息嵌入,这些知识不仅让我们在日常开发中游刃有余,更赋予了我们优化程序性能、诊断疑难问题的关键能力。


以上就是本文的所有内容了,如果觉得文章写的不错,还请留下免费的赞和收藏,也欢迎各位大佬在评论区交流

分享到此结束啦
一键三连,好运连连!

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

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

相关文章

Vue3中发送请求时,如何解决重复请求发送问题?

文章目录 前言一、问题演示二、使用步骤1.One组件2.Two组件封装工具函数处理请求 总结 前言 在开发过程中&#xff0c;重复请求发送问题可能会导致数据不一致、服务器压力增加或用户操作异常。以下是解决重复请求问题的常见方法和最佳实践&#xff1a; 一、问题演示 我们看着…

观察者模式:从博客订阅到消息队列的解耦实践

观察者模式&#xff1a;从博客订阅到消息队列的解耦实践 一、模式核心&#xff1a;用事件驱动实现对象间松耦合 在新闻 APP 中&#xff0c;当热点事件发生时需要实时通知所有订阅用户&#xff1b;在电商系统中&#xff0c;库存变化需触发价格监控模块重新计算。这类场景的核心…

ReportLab 导出 PDF(页面布局)

ReportLab 导出 PDF&#xff08;文档创建&#xff09; ReportLab 导出 PDF&#xff08;页面布局&#xff09; ReportLab 导出 PDF&#xff08;图文表格) PLATYPUS - 页面布局和排版 1. 设计目标2. 开始3. Flowables3.1. Flowable.draw()3.2. Flowable.drawOn(canvas,x,y)3.3. F…

【CVE-2024-10929】ARM CPU漏洞安全通告

安全之安全(security)博客目录导读 目录 一、概述 二、CVE详情 三、受影响产品 四、建议措施 五、致谢 六、版本历史 一、概述 在部分基于Arm架构的CPU中发现了一个潜在安全问题&#xff0c;称为Spectre-BSE&#xff08;Branch Status Eviction&#xff0c;分支状态驱逐…

OpenCV 图形API(33)图像滤波-----高斯模糊函数gaussianBlur()

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 使用高斯滤波器对图像进行模糊处理。 该函数使用指定的高斯核对源图像进行滤波。输出图像必须与输入图像具有相同的类型和通道数。 cv::gapi::g…

【2025最新版】火鸟门户v8.5系统源码+PC、H5、小程序 +数据化大屏插件

一.介绍 火鸟地方门户系统V8.5源码 系统包含4端&#xff1a; PCH5小程序APP 二.搭建环境 系统环境&#xff1a;CentOS、 运行环境&#xff1a;宝塔 Linux 网站环境&#xff1a;Nginx 1.2.22 MySQL 5.6 PHP-7.4 常见插件&#xff1a;fileinfo &#xff1b; redis 三.测…

关于 传感器 的详细解析,涵盖定义、分类、工作原理、常见类型、应用领域、技术挑战及未来趋势,结合实例帮助理解其核心概念

以下是关于 传感器 的详细解析&#xff0c;涵盖定义、分类、工作原理、常见类型、应用领域、技术挑战及未来趋势&#xff0c;结合实例帮助理解其核心概念&#xff1a; 一、传感器的定义与核心功能 1. 定义 传感器&#xff08;Sensor&#xff09;是一种能够将物理量&#xff…

EtherCAT转ProfiNet边缘计算网关配置优化:汽车制造场景下PLC与机器人协同作业案例

1.行业背景与需求分析 智能汽车焊装车间是汽车制造的核心工艺环节&#xff0c;某德国豪华品牌在其上海MEB工厂新建的焊装车间中&#xff0c;采用西门子S7-1500PLC作为ProfiNet主站&#xff0c;负责整线协调与质量追溯&#xff1b;同时部署KUKAKR1500Titan机器人&#xff08;Eth…

HTTP协议 --- 超文本传输协议 和 TCP --- 传输控制协议

是基于 TCP 协议的 80 端口的一种 C/S 架构协议。 特点&#xff1a;无状态 --- 数据传输完成后&#xff0c;会断开 TCP 连接&#xff0c;哪怕浏览器还正常运行。 请求报文 --- 方法 响应报文 --- 状态码 是一种面向连接的可靠传输协议 。 面向连接 --- 在传输数据之前&am…

类和对象(下篇)(详解)

【本节目标】 1. 再谈构造函数 2. Static成员 3. 友元 4. 内部类 5. 再次理解封装 1. 再谈构造函数 1.1 构造函数体赋值 在创建对象时&#xff0c;编译器通过调用构造函数&#xff0c;给对象中各个成员变量一个合适的初始值。 #include <iostream> using name…

LeetCode【剑指offer】系列(位运算篇)

剑指offer15.二进制中1的个数 题目链接 题目&#xff1a;编写一个函数&#xff0c;输入是一个无符号整数&#xff08;以二进制串的形式&#xff09;&#xff0c;返回其二进制表达式中数字位数为 ‘1’ 的个数&#xff08;也被称为 汉明重量).&#xff09;。 思路一&#xff…

网络安全领域的AI战略准备:从概念到实践

网络安全领域的AI准备不仅涉及最新工具和技术的应用&#xff0c;更是一项战略必需。许多企业若因目标不明确、数据准备不足或与业务重点脱节而未能有效利用AI技术&#xff0c;可能面临严重后果&#xff0c;包括高级网络威胁数量的激增。 AI准备的核心要素 构建稳健的网络安全…

MacOs下解决远程终端内容复制并到本地粘贴板

常常需要在服务器上捣鼓东西&#xff0c;同时需要将内容复制到本地的需求。 1-内容是在远程终端用vim打开&#xff0c;如何用vim的类似指令达到快速复制到本地呢&#xff1f; 假设待复制的内容&#xff1a; #include <iostream> #include <cstring> using names…

基于PAI+专属网关+私网连接:构建全链路 Deepseek 云上私有化部署与模型调用架构

DeepSeek - R1 是由深度求索公司推出的首款推理模型&#xff0c;该模型在数学、代码和推理任务上的表现优异&#xff0c;市场反馈火爆。在大模型技术商业化进程中&#xff0c;企业级用户普遍面临四大核心挑战&#xff1a; 算力投入成本高昂&#xff1a;构建千亿参数级模型的训…

【cocos creator 3.x】cocos creator2.x项目升级3.x项目改动点

1、基本改动 基本改动&#xff1a;去掉了cc.&#xff0c;改成在顶部添加导入 项目升级时候直接将cc.去掉&#xff0c;根据提示添加引用 node只保留position,scale,rotation,layer 其余属性如opacity&#xff0c;如果需要使用需要在节点手动添加UIOpacity组件 3d层和ui层分开…

List基础与难度题

1. 向 ArrayList 中添加元素并打印 功能描述&#xff1a; 程序创建一个空的 ArrayList 集合&#xff0c;用于存储字符串类型的元素。向该 ArrayList 中依次添加指定的字符串元素。使用增强型 for 循环遍历 ArrayList 中的所有元素&#xff0c;并将每个元素打印输出到控制台。 …

Oracle19C低版本一天遭遇两BUG(ORA-04031/ORA-600)

昨天帮朋友看一个系统异常卡顿的案例&#xff0c;在这里分享给大家 环境&#xff1a;Exadata X8M 数据库版本19.11 1.系统报错信息 表象为系统卡顿&#xff0c;页面无法刷出&#xff0c;登陆到主机上看到节点1 系统等待存在大量的 cursor: pin S wait on X等待 查看两个节…

【4.1.-4.20学习周报】

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 摘要Abstract一、方法介绍1.1HippoRAG 1.2HippoRAG2二、实验2.1实验概况2.2实验代码2.3实验结果 总结 摘要 本博客介绍了论文《From RAG to Memory: Non-Parametri…

python学习—合并多个word文档

系列文章目录 python学习—合并TXT文本文件 python学习—统计嵌套文件夹内的文件数量并建立索引表格 python学习—查找指定目录下的指定类型文件 python学习—年会不能停&#xff0c;游戏抽签抽奖 python学习—循环语句-控制流 python学习—合并多个Excel工作簿表格文件 pytho…

[Python] UV工具入门使用指南——小试牛刀

背景 MCP开发使用到了uv&#xff0c;简单记录一下&#xff1a; 为什么MCP更推荐使用uv进行环境管理&#xff1f; MCP 依赖的 Python 环境可能包含多个模块&#xff0c;uv 通过 pyproject.toml 提供更高效的管理方式&#xff0c;并且可以避免 pip 的一些依赖冲突问题。…