动态库和静态库 | AI工程化部署

简介: 我们在编写接口或者使用第三方应用时,都会打包或者引入.so或者.a文件。这个so就是动态库,.a文件就是静态库 【1月更文挑战第5天】

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

我们在编写接口或者使用第三方应用时,都会打包或者引入.so或者.a文件。这个so就是动态库,.a文件就是静态库。

具体的,动态库和静态库是在C语言中用来组织和共享代码的两种方式。

静态库(Static Library)是一组预编译的对象文件的集合,它们被组合成一个单一的文件。当使用静态库时,链接器会将库中的代码和数据复制一份到最终的可执行文件中。这意味着可执行文件会包含所有需要的函数和数据,使得程序可以独立运行。静态库的文件扩展名通常为 .a(Unix-like系统)或 .lib(Windows系统)。

动态库(Dynamic Library)是一组目标文件的集合,它们在程序运行时被加载到内存中。当程序运行时,操作系统会加载动态库中的代码和数据,多个程序可以共享已加载的库,这样可以减少内存占用并方便对库文件进行更新。动态库的文件扩展名通常为 .so(Unix-like系统)或 .dll(Windows系统)。

动态库和静态库区别在于:

  1. 静态库的代码和数据会被复制到可执行文件中,程序独立运行;而动态库的代码和数据是在程序运行时加载到内存中,多个程序可以共享已加载的库。
  2. 静态库会增加可执行文件的大小,动态库不会影响可执行文件的大小。
  3. 静态库在程序编译时就已经链接到可执行文件中,而动态库则是在程序运行时动态加载的。

应用场景:

  • 静态库常用于需要独立运行且不需要频繁更新的程序,或者在无法依赖外部动态库的环境下使用。
  • 动态库常用于需要共享代码、减少内存占用或者便于库文件更新的场景。

我们知道,在编译c语言程序时,会生成.o的中间文件和最终可执行文件,其中".o"文件是编译器生成的目标文件,它包含了源代码文件编译后的机器代码和相关的符号表信息。".elf"文件是可执行和可链接格式(Executable and Linkable Format)文件,它包含了程序的可执行代码、数据、符号表和其他信息,用于在操作系统中执行程序。通常,".o"文件是编译后的中间文件,而".elf"文件是最终的可执行文件。而本质上看,静态库和动态库都是众多.o文件的集合。

2.如何编译

编译动态库和静态库的过程略有不同。以下是具体的步骤:

静态库

假设你有一个叫做hello.c的文件,你想把它编译成一个静态库。以下是步骤:

  1. 首先,你需要使用gcc编译hello.c,但是你需要使用-c标志来生成一个对象文件而不是一个完整的程序。这将生成一个hello.o文件。
gcc -c hello.c
  1. 然后,你使用ar命令来创建静态库。此命令会生成libhello.a文件。
ar rcs libhello.a hello.o

ar命令的rcs选项执行以下操作:

  • r:替换旧的对象文件(如果存在)。
  • c:创建新的库(如果不存在)。
  • s:创建一个对象文件索引(对于库的链接很重要)。

动态库

如果你有一个源文件hello.c,你想要编译成一个动态库。以下是步骤:

  1. 首先,你需要使用gcc编译hello.c,但是你需要使用-c标志来生成一个对象文件而不是一个完整的程序。这将生成一个hello.o文件。
gcc -c -fPIC hello.c

-fPIC标志告诉gcc生成位置无关代码(PIC),这是创建共享库所必需的。

  1. 然后,你可以使用gcc命令和-shared选项来创建动态库。这将生成一个libhello.so共享库。
gcc -shared -o libhello.so hello.o

-shared选项告诉链接器创建一个共享库。

在链接时,需要使用-L-l选项指定库的路径和名称。

例如,如果你的程序名为main.c,并且你想链接之前创建的静态库或动态库,你可以这样做:

对于静态库:

gcc main.c -L. -lhello -o main

对于动态库:

gcc main.c -L. -lhello -o main

请注意,-L.告诉链接器在当前目录中查找库,-lhello告诉它链接到libhello库(无论是.a还是.so)。程序的输出在-o后指定,这里是main

特别注意的是,动态库需要加上-fPIC, 在cmake里动态库关键字为share,静态库为static

另外在链接so库的时候,编译器是如何通过-l后面的名字寻找相对应的so库呢,动态链接库的有一定的寻找顺序:

  • rpath 指定的目录;
  • 环境变量 LD_LIBRARY_PATH 指定的目录;
  • runpath 指定的目录;
  • /etc/ld.so.cache 缓存文件,通常包含 /etc/ld.so.conf 文件编译出的二进制俩别哦(比如 CentOS 上,该文件会使用 include 从而使用 ld.so.conf.d 目录下面所有的 *.conf 文件,这些都会缓存在 ld.so.cache 中)
  • 系统默认路径,比如 /lib,/usr/lib。

在编译时若使用 -z nodefaultlib 选项编译,则会跳过 4 和 5。至于 runpath,和 rpath 类似,都是二进制(ELF)文件的动态 section 属性(分别为 DT_RUNPATH 和 DT_RPATH),唯一区别就是是否优先于 LD_LIBRARY_PATH 来查找

3.如何使用

动态库和静态库使用分为隐式使用和显示打开,其中隐式使用就是通过-l直接链接到主程序中,而显示使用时通过dlopen的方式在程序使用的时候打开so文件并获取通过dlsym相应的函数接口。

这里详细介绍下dlopen的方式。

#include <stdio.h>
#include <dlfcn.h>
#include <iostream>

// g++ dlopen_test.cpp -o test -ldl
int main(int argc, char* argv[]){
   
    void *handle;
    int (*hello)();

    // 打开动态库
    handle = dlopen("./libso21.so", RTLD_LAZY);
    if (!handle) {
   
        fprintf(stderr, "%s\n", dlerror());
        return 1;
    }

    // 获取动态库中的函数指针
    *(void **)(&hello) = dlsym(handle, "hello_world_so");
    if (!hello) {
   
        fprintf(stderr, "%s\n", dlerror());
        dlclose(handle);
        return 1;
    }

    // 调用动态库中的函数
    (*hello)();


    // 关闭动态库
    dlclose(handle);

通过dlopen的方式,编译并不会检查so的正确性,只会在运行时加载so到内存中,并获取相应的函数。

4.查看动态库和静态库信息

通常我们需要查看打包的动态库和静态库是否符合要求,链接是否正常以及是否包含相应的函数符号等,有一些命令可以帮助我们更可了解它们。

  1. patchelf:该命令可以用来修改ELF可执行文件的动态链接器(即解释器),RPATH,或者动态符号表。主要用于处理库路径问题,有时候运行某个程序时,系统找不到其依赖的库,可以通过这个命令来修改。

    使用示例:patchelf --set-rpath /path/to/lib your_program

    这个命令将程序二进制文件中的rpath设置为/path/to/lib

  2. nm:这个命令可以显示从目标文件的符号表中列出符号。默认情况下,nm会按照字母顺序列出符号。

    使用示例:nm /path/to/libyourlib.so

    这个命令将列出动态库文件libyourlib.so中的所有符号。

  3. ldd:这个命令可以用来查看可执行文件或者动态库所依赖的其他动态库文件。它会列出所有的依赖库以及这些库的位置。

    使用示例:ldd /path/to/your_program

    这个命令将列出可执行文件your_program依赖的所有动态库的位置。

  4. objdump:这个命令可以显示一个或多个目标文件的信息。它可以显示二进制文件的详细信息,包括文件头,节信息,符号表等。

    使用示例:objdump -x /path/to/your_program

    这个命令将显示可执行文件your_program的详细信息。

  5. readelf:这是一个用于显示ELF格式文件信息的程序。它可以显示ELF文件的各种信息,包括文件头信息,节信息,段信息,符号表等。

    使用示例:readelf -a /path/to/your_program

    这个命令将显示可执行文件your_program的所有ELF信息。

请记住,每一个命令都有很多选项可以使用,这里只是提供了一些基本示例。一定要查阅对应命令的man手册以获取更详细的信息。

目录
相关文章
|
1月前
|
人工智能 并行计算 安全
从零到一,打造专属AI王国!大模型私有化部署全攻略,手把手教你搭建、优化与安全设置
【10月更文挑战第24天】本文详细介绍从零开始的大模型私有化部署流程,涵盖需求分析、环境搭建、模型准备、模型部署、性能优化和安全设置六个关键步骤,并提供相应的示例代码,确保企业能够高效、安全地将大型AI模型部署在本地或私有云上。
386 7
|
1月前
|
人工智能 安全 网络安全
揭秘!大模型私有化部署的全方位安全攻略与优化秘籍,让你的AI项目稳如磐石,数据安全无忧!
【10月更文挑战第24天】本文探讨了大模型私有化部署的安全性考量与优化策略,涵盖数据安全、防火墙配置、性能优化、容器化部署、模型更新和数据备份等方面,提供了实用的示例代码,旨在为企业提供全面的技术参考。
94 6
|
2月前
|
人工智能 C语言 Windows
Ollama部署在线ai聊天
本文介绍了如何在Windows系统上安装和部署AI聊天模型Ollama,包括安装步骤、模型安装、运行模型项目,以及使用Ollama生成C语言平衡二叉树的完整代码。
89 2
Ollama部署在线ai聊天
|
2月前
|
人工智能 数据安全/隐私保护 UED
RAG让AI大模型更懂业务解决方案部署使用体验
根据指导文档,部署过程得到了详细步骤说明的支持,包括环境配置、依赖安装及代码示例,确保了部署顺利进行。建议优化知识库问题汇总,增加部署失败案例参考,以提升用户体验。整体解决方案阅读与部署体验良好,有助于大型语言模型在特定业务场景的应用,未来可加强行业适应性和用户隐私保护。
66 5
|
1月前
|
人工智能 分布式计算 数据可视化
大模型私有化部署全攻略:硬件需求、数据隐私、可解释性与维护成本挑战及解决方案详解,附示例代码助你轻松实现企业内部AI应用
【10月更文挑战第23天】随着人工智能技术的发展,企业越来越关注大模型的私有化部署。本文详细探讨了硬件资源需求、数据隐私保护、模型可解释性、模型更新和维护等方面的挑战及解决方案,并提供了示例代码,帮助企业高效、安全地实现大模型的内部部署。
84 1
|
1月前
|
人工智能 分布式计算 数据可视化
大模型私有化部署全攻略:硬件需求、数据隐私、可解释性与维护成本挑战及解决方案详解,附示例代码助你轻松实现企业内部AI应用
【10月更文挑战第23天】随着人工智能技术的发展,大模型在各领域的应用日益广泛。然而,将其私有化部署到企业内部面临诸多挑战,如硬件资源需求高、数据隐私保护、模型可解释性差、更新维护成本高等。本文探讨了这些挑战,并提出了优化硬件配置、数据加密、可视化工具、自动化更新机制等解决方案,帮助企业顺利实现大模型的私有化部署。
86 1
|
2月前
|
Serverless 数据安全/隐私保护 前端开发
大模型代码能力体验报告之贪吃蛇小游戏《一》:Claude.ai篇 - 生成、预览和快速部署的serverless一条龙
本文介绍了通过Claude.ai生成并优化Web版贪吃蛇游戏的过程,展示了其强大的代码生成功能及用户友好的界面设计。从初始版本的快速生成到根据用户反馈调整游戏速度,再到提供多种实用工具如文件管理、版本控制和一键部署,Claude.ai不仅是一个代码助手,更像是一个全面的serverless开发平台。文中还呼吁国内厂商关注此类技术的发展。
|
2月前
|
人工智能 弹性计算 自然语言处理
《触手可及,函数计算玩转 AI 大模型》解决方案体验与部署评测
在AI技术快速发展的背景下,大模型正推动各行业的智能化转型。企业为抓住机遇,纷纷寻求部署AI大模型以满足特定业务需求。阿里云函数计算凭借按量付费、卓越弹性和快速交付等优势,为企业提供了高效、安全的AI大模型部署方案。本文将详细介绍阿里云函数计算的技术解决方案及其在文生文、图像生成和语音生成等领域的应用实例,展示其在降低成本、提高效率和增强灵活性方面的显著优势。
|
2月前
|
人工智能 自然语言处理 搜索推荐
【通义】AI视界|微软Copilot Studio推出新功能,帮助企业更便捷地构建和部署AI代理
本文介绍了近期科技领域的五大重要动态:马斯克旗下xAI发布首个API,苹果内部研究显示ChatGPT比Siri准确率高25%,微软Copilot Studio推出新功能,霍尼韦尔与谷歌合作引入Gemini AI,浑水创始人建议买入科技七巨头股票。更多资讯请访问【通义】。
|
3月前
|
存储 人工智能 弹性计算
函数计算部署 AI 大模型解决方案测评
函数计算部署 AI 大模型解决方案测评