动态库和静态库 | 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模型部署在本地或私有云上。
498 7
|
11天前
|
人工智能 Java Serverless
阿里云函数计算助力AI大模型快速部署
随着人工智能技术的快速发展,AI大模型已经成为企业数字化转型的重要工具。然而,对于许多业务人员、开发者以及企业来说,探索和利用AI大模型仍然面临诸多挑战。业务人员可能缺乏编程技能,难以快速上手AI模型;开发者可能受限于GPU资源,无法高效构建和部署AI应用;企业则希望简化技术门槛,以更低的成本和更高的效率利用AI大模型。
63 12
|
9天前
|
人工智能 缓存 异构计算
云原生AI加速生成式人工智能应用的部署构建
本文探讨了云原生技术背景下,尤其是Kubernetes和容器技术的发展,对模型推理服务带来的挑战与优化策略。文中详细介绍了Knative的弹性扩展机制,包括HPA和CronHPA,以及针对传统弹性扩展“滞后”问题提出的AHPA(高级弹性预测)。此外,文章重点介绍了Fluid项目,它通过分布式缓存优化了模型加载的I/O操作,显著缩短了推理服务的冷启动时间,特别是在处理大规模并发请求时表现出色。通过实际案例,展示了Fluid在vLLM和Qwen模型推理中的应用效果,证明了其在提高模型推理效率和响应速度方面的优势。
云原生AI加速生成式人工智能应用的部署构建
|
13天前
|
机器学习/深度学习 存储 人工智能
【AI系统】训练后量化与部署
本文详细介绍了训练后量化技术,涵盖动态和静态量化方法,旨在将模型权重和激活从浮点数转换为整数,以优化模型大小和推理速度。通过KL散度等校准方法和量化粒度控制,文章探讨了如何平衡模型精度与性能,同时提供了端侧量化推理部署的具体实现步骤和技术技巧。
37 1
【AI系统】训练后量化与部署
|
1月前
|
存储 人工智能 搜索推荐
Memoripy:支持 AI 应用上下文感知的记忆管理 Python 库
Memoripy 是一个 Python 库,用于管理 AI 应用中的上下文感知记忆,支持短期和长期存储,兼容 OpenAI 和 Ollama API。
91 6
Memoripy:支持 AI 应用上下文感知的记忆管理 Python 库
|
18天前
|
人工智能 监控 Serverless
《主动式智能导购AI助手构建》解决方案部署测评
在数字化时代,智能导购AI助手已成为提升客户体验和销售效率的重要工具。本文将基于个人体验,对《主动式智能导购AI助手构建》解决方案的部署过程进行详细评测。
37 3
|
3天前
|
人工智能 API Windows
免费部署本地AI大语言模型聊天系统:Chatbox AI + 马斯克grok2.0大模型(简单5步实现,免费且比GPT4.0更好用)
本文介绍了如何部署本地AI大语言模型聊天系统,使用Chatbox AI客户端应用和Grok-beta大模型。通过获取API密钥、下载并安装Chatbox AI、配置模型,最终实现高效、智能的聊天体验。Grok 2大模型由马斯克X-AI发布,支持超长文本上下文理解,免费且易于使用。
25 0
|
1月前
|
人工智能 安全 网络安全
揭秘!大模型私有化部署的全方位安全攻略与优化秘籍,让你的AI项目稳如磐石,数据安全无忧!
【10月更文挑战第24天】本文探讨了大模型私有化部署的安全性考量与优化策略,涵盖数据安全、防火墙配置、性能优化、容器化部署、模型更新和数据备份等方面,提供了实用的示例代码,旨在为企业提供全面的技术参考。
98 6
|
2月前
|
人工智能 C语言 Windows
Ollama部署在线ai聊天
本文介绍了如何在Windows系统上安装和部署AI聊天模型Ollama,包括安装步骤、模型安装、运行模型项目,以及使用Ollama生成C语言平衡二叉树的完整代码。
100 2
Ollama部署在线ai聊天
|
2月前
|
人工智能 数据安全/隐私保护 UED
RAG让AI大模型更懂业务解决方案部署使用体验
根据指导文档,部署过程得到了详细步骤说明的支持,包括环境配置、依赖安装及代码示例,确保了部署顺利进行。建议优化知识库问题汇总,增加部署失败案例参考,以提升用户体验。整体解决方案阅读与部署体验良好,有助于大型语言模型在特定业务场景的应用,未来可加强行业适应性和用户隐私保护。
73 5
下一篇
DataWorks