当前位置: 首页 > article >正文

Linux基础IO(七)动静态库的制作与使用

目录一、回顾动静态链接二、什么是库库的本质三、库的制作静态库的封装法一:法二:法三:动态库的封装法一:法二:法三:四、总结一、回顾动静态链接mytest 是我们已经编译运行成功的一个C语言程序ldd 命令的作用是告诉你“运行这个程序它需要依赖哪些库文件以及这些库文件在系统的哪个路径下”。libc.so.6 是C 语言标准库。 指向实际位置。/lib64/libc.so.6 是 CentOS 系统下真实的库文件路径。系统告诉我们运行 mytest 必须去 /lib64/ 目录下找 C 标准库。我们看到的 libc.so.6 其实是一个软链接(快捷方式)。它真正指向的是具体的版本文件libc-2.17.so。1. 真实库文件名libc-2.17.so前缀 libLinux 下所有库文件的固定开头代表 library 库。核心名 c代表 C 语言标准库C Standard Library。版本号 -2.17这是库的具体版本号2 是主版本17 是次版本。后缀 .so代表 Shared Object动态共享库)也就是我们常说的动态库。2. 软链接名libc.so.6它是为了版本兼容而存在的“别名”。这里的 .6 是 ABI 版本号Application Binary Interface它保证了不同版本的库在二进制层面上的兼容性。程序永远依赖这个别名而不是带具体版本号的文件名这样系统升级库时只需要修改软链接指向程序就能无缝使用新版本。所以 libc-2.17.so 去掉前缀 lib 和后缀 .so剩下的 c-2.17 才是核心标识。而 libc.so.6 是它的兼容别名方便程序调用和系统升级。我们还可以是同 file 命令来查看文件是动态链接还是静态链接dynamically linked (uses shared libs) 的意思是程序是动态链接的运行时需要加载外部共享库(比如 libc.so.6)。C/C在使用gcc和g编译链接的时候默认使用动态链接。如果程序要使用静态链接的话加 -static并且在Linux中.so是动态库文件.a是静态库文件二、什么是库本质上说库是一种可执行代码的二进制形式可以被操作系统载入内存中执行这张图显示的是Ubuntu 和 CentOS 下 C/C 动静态库的位置对比:1. 先分清动态库 vs 静态库动态库 .so 结尾Shared Object运行时才加载程序体积小依赖系统库。静态库 .a 结尾Archive编译时直接打包进程序程序体积大运行时不依赖外部库。2. Ubuntu 与 CentOS 的库路径对比C 语言库libc类型Ubuntu路径CentOS路径说明动态库/lib/x86_64-linux-gnu/libc-2.31.so/lib64/libc-2.17.so真实动态库文件带版本号静态库/lib/x86_64-linux-gnu/libc.a/lib64/libc.a静态库用于静态链接C 语言库libstdc类型Ubuntu 路径CentOS 路径说明动态库/usr/lib/gcc/x86_64-linux-gnu/9/libstdc.so/lib64/libstdc.so.6动态库/软链接静态库/usr/lib/gcc/x86_64-linux-gnu/9/libstdc.a/usr/lib/gcc/x86_64-redhat-linux/4.8.2/libstdc.a静态库“Ubuntu 和 CentOS 下C/C 动静态库的存放位置、命名规则、软链接结构完全一致只是目录不同。”我们现在有这几个文件:我们先一次性编译所有源码文件直接生成可执行文件编译器会把 main.c主程序、mystdio.c 、mystring.c 功能实现全部编译并链接成一个独立可执行文件 target 。直接执行 ./target 即可正常运行输出 write file done! 和 这是我自己的strlen函数! 。我们还可以这样:gcc -c 源文件.c -o 目标文件.o : -c 参数的作用是只编译不链接把 .c 源码编译成 .o 目标文件二进制中间产物。每个 .c 对应一个 .o但还没完成最终链接不能直接运行。gcc -o target main.o mystdio.o mystring.o : 这条命令是把多个 .o 目标文件链接成一个可执行文件 target 。编译器会遍历所有 .o解析符号引用比如 main.o 里调用的 mystrlen 函数)在其他 .o 里找到实现合并成一个完整的可执行程序。生成的 target 和直接编译源码的效果完全一致体积 13184 字节运行时零依赖直接 ./target 就能输出结果。所以从上面两种方法我们可以得出 : 形成可执行程序时第一种方法是直接把源文件一次性编译成可执行第二种方法是把源文件先编译成.o文件再把.o文件链接成可执行程序第二种方法也是编译链接文件的最佳实践方法。这个 Makefile 就是自动把所有 .c 编译成 .o再把所有 .o 链接成可执行程序 target最后用 make clean 一键清理。那有一个问题 : 假设有多个.c 源文件,我们把其中一个源文件编译成.o文件时和其他的源文件有关系吗? 答案是没有关系 , 这些由.c文件编译成的.o文件只有在链接的时候才有依赖关系,还要注意的是只有 .c 文件才会被编译成 .o 文件.h 文件不会因为.c 文件是实现文件里面写的是函数、变量的具体代码逻辑编译器会把它翻译成机器码生成 .o 文件。而 .h 文件是头文件本质是接口声明/宏定义/类型声明它不会被单独编译成 .o。头文件是被 .c 文件 #include 进去和 .c 一起参与编译。库的本质现在我们知道在编译阶段时当我们执行 gcc -c main.c 或 gcc -c mystring.c 时编译器会把 .c 源码翻译成 .o 文件。并且是单文件独立运作的。编译 mystring.o 时不需要 main.c 的存在。编译 main.o 时也不需要 mystring.c 的存在。此时它们之间没有任何依赖关系谁断了都不影响谁生成。但是在链接时当执行 gcc main.o mystring.o mystdio.o -o target 时链接器Linker会把所有 .o 文件打包合并统一组装。并且链接器还会负责把 main 里调用的函数比如 my_strlen)在 mystring.o 里找到并连起来。如果少一个 .o链接就会报错。这时在链接阶段才会建立依赖关系。既然链接前的 .o 文件是独立的那么如果我们把 .o 文件打包压缩就变成了 静态库( .a ) 。以后用的时候直接把我们打包好的静态库 libmystring.a 和 main.o 链接效果和刚才直接链接 .o 是一样的。所以库的本质就是 . o 文件而且是已经打包好的 .o 文件的集合。三、库的制作静态库的封装其实封装静态库有多种方法我们最开始是把功能代码写在 .c 文件里然后用 gcc -c 把这些 .c 编译成 .o 目标文件这些 .o 里面是真正的函数实现但还不能直接给别人用于是我们用 ar 命令把多个 .o 打包成 .a 静态库文件这一步就是封装库。同时我们把函数声明、宏定义写在 .h 头文件里这个头文件就是库的使用说明书没有它别人就不知道怎么调用库里的函数。所以给别人提供库时必须同时给头文件和库文件缺一不可。接下来就有多种使用这个库的方法法一:第一种方法就是将把库和头文件复制到系统默认目录首先我们先将 .o 文件进行打包封装:首先我们先将 .c 源文件编译成 .o 文件这些 .o 文件是独立的只包含各自 .c 文件的机器码互相之间没有依赖关系。第二步用 ar 命令打包成静态库( .a )ar -rc libmystdio.a *.oar 命令是静态库的核心制作命令ar ArchiverLinux 下用于打包目标文件的工具。-r replace —— 如果库已存在就替换其中的旧 .o 文件如果不存在就新建。-c create —— 强制创建库文件即使已存在也会覆盖。libmystdio.a 我们定义生成的静态库文件名Linux 静态库必须以 lib 开头.a 结尾。*.o 通配符把当前目录下所有 .o 文件mystdio.o 、mystring.o都打包进库。还要注意的是一定不能将 main 主函数所在的文件打包进静态库原因很简单静态库是“功能模块集合”静态库( .a )是可复用的功能模块比如我们封装的 mystdio、mystring是提供函数给别人调用。而 main 函数是程序的唯一入口点程序从 main 开始执行它是“调用别人的人”不是“被别人调用的人”。如果把 main.o 也打包进库别人用你的库时会得到两个 main 入口从而报错。那到这里就完了吗? 并没有。为什么会报错? 原因是这个 gcc -o target main.o 命令只告诉链接器“把 main.o 变成可执行文件”但完全没提 libmystdio.a 这个库。在链接器的视角只看到 main.o 里调用了 myfopen但 main.o 里没有这个函数的实现。也没收到任何指令要去我们封装的 libmystdio.a 静态库里找。并且 gcc 只去系统级的 /lib 、/usr/lib 、/lib64 、/usr/lib64 等目录找库。所以这里只能报错“我找不到这个函数的实现”。解决方法:这次我们成功链接并且 target 生成并成功运行。gcc -o target main.o -lmystdio -L./ // -lmystdio 告诉链接器“我要用 libmystdio.a 这个库。” // -L./ 告诉链接器“别去系统默认目录找了去我当前目录 ./ 找。”这个命令的含义是首先 gcc 编译器发起构建命令-o target 指定输出文件名生成的可执行文件叫 targetmain.o 是你的主程序目标代码输入文件-L./ 表示指定库路径意思是去当前目录找库文件。-lmystdio 表示对指定库名进行链接-l 是link(链接)mystdio 就是库名gcc 会在当前路径下自动搜索 libmystdio.a 或 libmystdio.so 。所以我们也可以写出静态库制作的Makefile这个 Makefile 是用来自动化构建静态库 libmystdio.a 它的核心逻辑是先把所有 .c 源文件编译成 .o 目标文件再将这些 .o 文件打包成静态库同时提供一键清理功能。具体来说第一行定义了要生成的静态库 libmystdio.a 依赖 mystdio.o 和 mystring.o下方的 ar -rc $ $^ 命令会把这两个依赖的 .o 文件打包成库其中 $ 代表目标库名$^ 代表所有依赖文件。接下来的 %.o:%.c 是通用模式规则意思是所有 .o 文件都依赖同名的 .c 文件下方的 gcc -c $ 会自动把对应的 .c 文件编译成 .o $ 代表当前依赖的 .c 文件。最后是清理规则.PHONY: clean 声明 clean 是伪目标避免和真实文件冲突clean 目标下的 rm -f *.o *.a 会删除所有生成的 .o 目标文件和 .a 静态库文件实现一键清理编译产物的效果。整个脚本运行后只要执行 make 就能自动完成从源码到静态库的构建流程执行 make clean 则可以快速恢复干净的开发环境是 Linux 下模块化开发和静态库封装的标准自动化方案。我们在制作库时以制作者的视角除了给用户提供库文件 .a 或 .so )还应给用户提供对应的头文件 .h )两者缺一不可。库文件比如 libmystdio.a 本质是把多个 .c 源文件的实现代码编译、打包后得到的二进制包里面存放着函数、变量的具体实现逻辑是程序运行时真正执行的机器码。而头文件 .h 则是库的“接口说明书”它只包含函数声明、宏定义、类型别名等内容不包含任何可执行代码作用是告诉使用者“这个库里有哪些函数可以调用、函数的参数和返回值是什么类型”让编译器在编译使用者的 main.c 时能完成语法检查和符号引用确保后续链接阶段能顺利找到库中的实现代码。简单来说库文件是“零件箱”装着所有功能的实现代码头文件是“零件说明书”告诉别人怎么使用这些零件。没有头文件使用者就不知道库中函数的调用格式编译器会报“未声明的函数”错误没有库文件链接器就找不到函数的具体实现会报“未定义的引用”错误。只有同时提供这两个文件别人才能像使用系统标准库一样通过 #include mystdio.h 引入接口声明再用 -lmystdio 链接你的库最终写出完整的可执行程序。我们可以在Makefile中对头文件进行相关处理 : 新增的 output 目标是整个流程的关键它先声明自己是伪目标然后依次执行四条命令第一条 mkdir -p mylib/include 强制创建 mylib/include 目录专门用来存放头文件第二条 mkdir -p mylib/lib 强制创建 mylib/lib 目录专门用来存放库文件第三条 cp *.h mylib/include 将当前目录下所有的头文件复制到 include 目录第四条 cp *.a mylib/lib 将生成的静态库文件复制到 lib 目录。执行 make output 后就会在当前目录生成一个 mylib 文件夹里面结构清晰include 放着接口声明lib 放着二进制实现使用者只需要把这个 mylib 文件夹拷贝到自己的工程里通过 -I 指定头文件路径、-L 指定库路径就能直接链接使用这就是工业级库的标准交付方式实现了接口和实现的严格分离方便分发和维护。我们只要执行 make output整个流程依然是先编译 .c 为 .o再打包成 libmystdio.a 库文件。然后在当前目录下创建 mylib 文件夹。在 mylib 里面再创建 include 和 lib 两个子文件夹。把当前目录下所有 .h 头文件复制到 mylib/include 里。把当前目录下所有 .a 静态库文件复制到 mylib/lib 里。mkdir -p 里的 -p 参数很关键它的作用是“如果目录已经存在就不报错直接跳过”所以反复执行 make output 也不会出问题只会覆盖旧文件。那么到现在为止作为一个库的制作者整个静态库就创建成功了但是作为用户任务还没有完成这个库又怎么使用呢?这一步就是把库“安装到系统目录”让用户可以像用系统标准库一样直接使用你的库。从上图可以看到我们把自己的头文件和静态库分别拷贝到了系统默认路径头文件mystdio.h和mystring.h被拷贝到 /usr/include/这是系统默认的头文件搜索目录用户写代码时直接 #includemystdio.h 就能找到接口声明。其次静态库 libmystdio.a 被拷贝到 /lib64/这是CentOS 系统默认的库文件搜索目录用户链接时直接用 -lmystdio 就能找到库的实现不需要再加 -L 指定库路径。这样做的好处是用户拿到你的库后完全不用关心库和头文件在哪就像使用 #include stdio.h 和 -lc 一样直接写代码、链接就能跑体验和系统自带的库一模一样。不过要注意因为 /usr/include 和 /lib64 是系统级目录普通用户没有写入权限所以必须用 sudo 提升权限才能执行拷贝操作这也是图里命令前面加 sudo 的原因。现在我们的库已经制作完成并且也已拷贝到系统的默认路径下为啥 gcc main.c 还会报错? 因为我们的库属于第三方库和系统自带的 libc 、libstdc 本质一样只是需要显式指定 -lmystdioh. 告诉编译器“我要用这个库”就能和系统库的使用体验完全一致了。gcc main.c -o main -I ./mylib/include/ -L ./mylib/lib/ -lmystdio如果我们用 sudo rm 把 /usr/include/mystdio.h 和 /lib64/libmystdio.a 给删掉。编译器去系统默认目录( /usr/include )找头文件结果发现这里被你删空了所以它直接报错停止编译根本没走到链接阶段。同时也间接验证了我们之前的知识点1. 如果没有头文件连编译都过不了。这证明了头文件是接口声明必不可少。2. 验证了系统默认路径的作用你之前把库安装到系统目录就是为了让编译器默认去 /usr/include 找头文件默认去 /lib64 找库文件。现在你把它们删了编译器就罢工了。3. 验证了 -l 参数的作用虽然你加了 -lmystdio 但因为头文件都没了编译器根本不会走到链接环节。先有头文件(编译)后有库(链接)。法二:除了将库搬进系统默认目录下使用库外还有没有其他方法也能正常使用库?答案是有的我们紧接着上面的内容当我们用 sudo rm 把 /usr/include/mystdio.h 和 /lib64/libmystdio.a 从系统默认目录删掉后还可以使用下面的命令重新找到库文件和头文件来正常使用库。gcc main.c -o main -I./mylib/include/ -L./mylib/lib/ -lmystdio参数含义为什么必须加-I./mylib/include/I Include指定头文件路径 因为你没把 mystdio.h 装到系统默认路径编译器找不到头文件所以必须手动告诉它“去 ./mylib/include 找头文件”-L./mylib/lib/L Library指定库文件路径 同理编译器默认不去你当前目录找库必须手动告诉它“去 ./mylib/lib 找 libmystdio.a ”-lmystdiol link链接库名告诉编译器你要链接的库名字是 mystdio 编译器会自动搜索 libmystdio.a 。如果只加 -I (只有头文件路径 编译阶段虽然能过因为 -I 告诉编译器去 ./mylib/include 找到了 mystdio.h函数声明没问题。但是链接阶段必报错 编译器只看到你调用了myfopen, mystrlen但你没告诉它去哪找实现代码(没加 -L 和 -l )所以会报 undefined reference (未定义的引用。只加 -I 和 -L(有头文件路径 库路径但没 -l )编译阶段能过因为头文件找到了。链接阶段还是报错因为你告诉了编译器“去 ./mylib/lib 这个文件夹找”但没告诉它“找哪个库”链接器不知道你要链接 libmystdio.a依然会报 undefined reference。这种方法不改动系统只是把库和头文件放在自己项目里的 mylib 目录编译时用 -I 指定头文件路径用 -L 指定库所在目录再用 -l 链接库名虽然命令长一点但不需要权限、不污染系统、更安全规范也是实际项目里最标准的做法。法三:第三种方法是使用软链接把库“映射”到系统目录:这条命令用 sudo 权限创建了一个软链接快捷方式-s 代表软链接意思是在系统目录 /lib64 里生成一个指向你项目中真实库文件 libmystdio.a 的快捷方式名字也叫 libmystdio.a。这样编译器就会把它当成系统库来处理后续编译时只需要 -lmystdio 就能找到库的实现而且这个快捷方式不占用实际磁盘空间只是一个指向原文件的指针。这条命令用来查看 /lib64 目录下 libmystdio.a 的详细信息-l 参数会显示文件类型、权限、大小和指向路径。从输出可以看到它是一个软链接开头 l 标识并且明确指向了你项目里的 libmystdio.a证明软链接创建成功。这条命令用 sudo 权限把当前项目 mylib/include 目录下所有 .h 头文件复制到系统默认头文件目录 /usr/include 这样编译器在编译 main.c 时能直接通过 #include mystdio.h 找到函数声明不需要再加 -I 指定头文件路径。这条命令是编译主程序并链接你的库-o main 指定生成可执行文件 main-lmystdio 告诉编译器链接 libmystdio.a。因为头文件已经在 /usr/include 、库文件通过软链接映射到 /lib64都在系统默认路径里所以编译器能自动找到并完成编译链接不需要额外的 -I 和 -L。总结一下就是先通过软链接把项目里的库“映射”到系统目录再把头文件拷贝到系统目录之后就可以像使用系统库一样只用 -lmystdio 完成编译既方便又能保持库文件在项目中可控是一种高效且安全的开发方式。动态库的封装不管是封装静态库还是动态库核心逻辑都是一样的都要先把 .c 源文件编译成 .o 目标文件这些 .o 里存放着函数的具体实现代码。都要配套 .h 头文件头文件里写函数声明、宏定义、类型别名是库的“接口说明书”没有它别人就不知道怎么调用库里的函数。交付给用户时都必须同时提供头文件( .h )和库文件( .a 或 .so )缺一不可。都可以通过 Makefile 自动化构建比如用模式规则自动编译 .c 为 .o用 output 目标把库和头文件整理成 mylib/include (放头文件)和 mylib/lib (放库文件的标准交付目录。我们现在命令行封装并打包然后再在 Makefile 中修改:gcc -fPIC -c *.c 是把所有 .c 源文件编译成满足动态库要求的 .o 目标文件-fPIC 是 gcc 的编译选项全称是 Position-Independent Code位置无关代码它的作用是让生成的 .o 目标文件里的机器码不依赖固定内存地址这样动态库加载到内存任意位置时都能正常执行是生成动态库的硬性要求——静态库不需要这个参数因为静态库会在编译时完整拷贝到可执行文件地址是固定的。再执行gcc -shared -o libmystdio.so *.o 把这些 .o 打包成动态库 libmystdio.so 两个参数配合起来就完成了动态库的核心构建流程。-shared 是 gcc 的链接选项作用是告诉编译器将多个 .o 目标文件打包生成动态共享库 .so 文件而不是生成普通的可执行文件。这个选项会让编译器保留所有符号引用不把代码嵌入可执行文件最终生成的 .so 文件可以被多个程序在运行时共享加载实现内存复用。静态库则是用 ar -rc 命令打包不需要这个选项。当我们执行 make output 后现在的目录里应该是被打包进了 libmystdio.so 库里的 .o 文件mylib/ 目录mylib/include/ 放着你的 .h 头文件接口声明)mylib/lib/ 放着 libmystdio.so(动态库函数实现。下一步就是编译 main.c 并链接你的动态库命令和静态库类似但要注意动态库的运行时依赖-I./mylib/include 告诉编译器去哪找头文件 mystdio.h-L./mylib/lib 告诉编译器去哪找动态库 libmystdio.so-lmystdio 告诉编译器要链接 libmystdio.so 这个动态库又有问题了为什么我们运行这个程序时不成功并且库显示 not found 因为我们编译时虽然用了 -L ./mylib/lib但这个参数只在编译链接时生效告诉编译器“去这个目录找库完成链接”并没有告诉运行时的系统加载器“去这个目录找库”。系统加载器在运行 ./main时只会去以下几个地方找动态库1. 系统默认库路径( /lib64、/usr/lib64 等)2. 环境变量 LD_LIBRARY_PATH 里的路径我们的 libmystdio.so 不在这些地方所以系统加载器找不到它就显示 not found 。那之前静态库为什么直接 ./main 就能跑因为静态库 .a 在编译链接阶段会把库里面的函数实现代码完整拷贝到最终的可执行文件里我们写 gcc main.c -o main -lmystdio 时编译器会把 libmystdio.a 里的myfopen 、mystrlen 等函数实现直接“粘”进 main 这个可执行文件里。生成的 main 是一个完全独立的程序它不再依赖任何外部库文件所有代码都在自己内部。所以你直接 ./main 就能跑系统根本不需要去外面找任何库自然也不会出现“找不到库”的报错。动态库为什么不行动态库.so在编译链接阶段只做了一件事记录依赖关系不拷贝任何代码我们写 gcc main.c -o main -lmystdio 时编译器只是确认“ main 里用到的函数在 libmystdio.so 里”然后在 main 里留个“调用入口”告诉系统“运行时去加载 libmystdio.so ”。生成的 main 是一个“空壳程序”它自己没有函数实现必须在运行时让系统加载器找到 libmystdio.so才能把代码读进来执行。所以你直接 ./main 时系统加载器找不到 libmystdio.so 就会报错。静态库编译时把代码拷进程序程序“吃饱了”运行时自给自足动态库编译时只留个“欠条”程序“饿肚子”运行时必须找系统要饭找库。解决方法:法一:sudo cp mylib/lib/libmystdio.so /lib64这一步是把我们自己的动态库 libmystdio.so 拷贝到了系统默认的库目录 /lib64 里。所以系统加载器 ld-linux-x86-64.so.2 在运行程序时会在系统默认库路径比如 /lib64 、/usr/lib64查找动态库我们把 libmystdio.so 放到了 /lib64正好是系统默认路径之一所以运行 ./main 时系统加载器自动去 /lib64 找到了 libmystdio.so 成功加载库代码。ldd main 也显示 libmystdio.so /lib64/libmystdio.so证明库依赖已经被正确解析。程序最终输出“我自己的string len 函数”说明整个动态链接流程完全打通。法二:第二种方法是创建软链接sudo ln -s 源路径 /lib64/libmystdio.so这是在系统库目录 /lib64 里创建一个软链接符号链接相当于给你的真实动态库 libmystdio.so 做了一个“快捷方式”。从 ll 输出可以看到/lib64/libmystdio.so - 你的项目路径 文件类型以 l 开头明确是软链接不占用实际磁盘空间。系统加载器会把这个软链接当成真实库文件自动去系统默认路径查找效果和直接拷贝到系统目录完全一致。法三:第三种方法是动态库的临时环境变量法:LD_LIBRARY_PATH 是 Linux 系统中动态链接器的环境变量专门用来告诉系统“除了默认路径外还要去哪些目录找动态库”。执行的 export LD_LIBRARY_PATH$LD_LIBRARY_PATH:/你的库路径是把自己的动态库目录追加到原有环境变量中不会覆盖系统原有的路径配置保证系统库如 libc.so.6仍能正常找到。从 echo $LD_LIBRARY_PATH 输出可以看到你的库路径已经被成功加入环境变量列表。需要注意的是 LD_LIBRARY_PATH 是“找库的目录列表”只需要告诉系统“去哪个目录找”系统会自动在目录里匹配库名不需要也不能把具体库文件名加进去。语法上 LD_LIBRARY_PATH 只接受目录路径不能写具体文件名否则系统会把它当成目录名去查找反而找不到库。运行时系统会去这个目录里找和你编译时 -lmystdio 对应的 libmystdio.so 文件自动匹配。ldd main 输出显示 libmystdio.so /你的项目路径/libmystdio.so说明系统加载器已经能通过 LD_LIBRARY_PATH 找到你的动态库。直接 ./main 即可运行输出“我自己的string len 函数”证明临时环境变量法下动态库加载和函数调用完全正常。四、总结本文详细介绍了Linux系统中动静态库的创建与使用方法。静态库.a在编译时将代码嵌入程序运行时无需依赖动态库.so在运行时加载实现内存共享。制作库需将.c文件编译为.o目标文件静态库用ar命令打包动态库需加-fPIC和-shared选项。使用库时需同时提供头文件和库文件可通过三种方式1拷贝到系统目录2指定路径-I/-L3创建软链接。动态库运行时还需配置LD_LIBRARY_PATH环境变量或安装到系统目录。文章通过具体命令演示了库的封装、安装和使用全过程。谢谢大家的观看!

相关文章:

Linux基础IO(七)动静态库的制作与使用

目录 一、回顾动静态链接 二、什么是库 库的本质 三、库的制作 静态库的封装 法一: 法二: 法三: 动态库的封装 法一: 法二: 法三: 四、总结 一、回顾动静态链接 mytest 是我们已经编译运行成功的一个C语言程序,ldd 命令的作用是告诉你“运行这个程序&a…...

Fish Speech 1.5开源模型优势:MIT许可证、完整训练代码、可微调架构

Fish Speech 1.5开源模型优势:MIT许可证、完整训练代码、可微调架构 1. 引言:重新定义语音合成的开源方案 如果你正在寻找一个既强大又灵活的文本转语音解决方案,Fish Speech 1.5绝对值得你的关注。这个由Fish Audio开源的新一代TTS模型&am…...

ofa_image-caption_coco_distilled_en保姆级部署:NVIDIA Container Toolkit配置与GPU资源隔离实践

ofa_image-caption_coco_distilled_en保姆级部署:NVIDIA Container Toolkit配置与GPU资源隔离实践 安全声明:本文仅讨论技术实现方案,所有内容均基于公开技术文档和标准实践,不涉及任何敏感或受限制的技术应用。 1. 项目概述与核心…...

Qwen3-4B-Thinking-GGUF部署效果展示:vLLM吞吐提升与Chainlit响应实测

Qwen3-4B-Thinking-GGUF部署效果展示:vLLM吞吐提升与Chainlit响应实测 1. 开篇:当推理速度遇上交互体验 最近在折腾大模型本地部署,发现了一个挺有意思的组合:Qwen3-4B-Thinking-2507-GPT-5-Codex-Distill-GGUF模型,…...

Linux 硬件 (内存等)

内存情况 参考链接: https://worktile.com/kb/ask/379072.html # dmidecode -t memory # dmidecode 3.4 Getting SMBIOS data from sysfs. SMBIOS 3.4.1 present.<...

【STM32】知识点介绍六:外设定时器

文章目录一、外设定时器二、定时计算三、库函数四、代码思路一、外设定时器 1.定义   设置定时时间&#xff08;定时周期&#xff09;&#xff0c;超时后则执行指定操作的硬件。 2.STM32F407定时器特征   具有基本的定时功能&#xff0c;也有 PWM 输出&#xff08;灯光亮…...

大棚搭配种植指南

第一部分&#xff1a;植物间相互作用的四大机制 化学通讯与忌避作用&#xff1a;植物释放的挥发性气味&#xff08;如葱蒜的硫化物、香草的萜烯类&#xff09;可直接驱赶害虫&#xff0c;或掩盖主作物气味&#xff0c;干扰害虫定位。这是驱虫组合的核心。根系分泌与土壤改良&am…...

基于Appium+pytest+Allure的App UI自动化测试框架实战(含完整项目架构与落地指南)

前言 在移动应用测试中&#xff0c;UI自动化测试能有效降低重复手工测试成本&#xff0c;提升版本迭代的回归测试效率。本文将详细分享一套基于 AppiumpytestPythonAllure 构建的高可维护、易扩展的App UI自动化测试框架&#xff0c;包含完整的项目架构设计、环境配置、测试流…...

ubuntu22.04相关教程存档

ubuntu22.04 windows10双系统安装 【Windows 10 和 Ubuntu 双系统的安装和卸载】 https://www.bilibili.com/video/BV1554y1n7zv/ 下载ubuntu22.04系统镜像&#xff1a;https://ubuntu.com/download/alternative-downloads 下载Rufus&#xff1a;https://rufus.ie/zh/ ubuntu2…...

MedGemma Medical Vision Lab惊艳效果展示:X-Ray影像中文问答精准分析案例集

MedGemma Medical Vision Lab惊艳效果展示&#xff1a;X-Ray影像中文问答精准分析案例集 1. 引言&#xff1a;AI如何看懂医学影像 想象一下&#xff0c;你是一位医学生&#xff0c;面对一张复杂的X光片&#xff0c;想要快速了解其中的关键信息。或者你是一位医学研究者&#…...

cv_resnet101_face-detection_cvpr22papermogface快速上手:5分钟启动本地化人脸预处理系统

cv_resnet101_face-detection_cvpr22papermogface快速上手&#xff1a;5分钟启动本地化人脸预处理系统 你是不是也遇到过这样的问题&#xff1f;想在自己的电脑上跑一个人脸检测程序&#xff0c;结果光是配环境、下模型、写代码就折腾了大半天&#xff0c;最后还不一定能跑起来…...

GTE中文Large模型惊艳效果:中文微信公众号文章主题演化分析

GTE中文Large模型惊艳效果&#xff1a;中文微信公众号文章主题演化分析 1. 引言&#xff1a;从海量文章中洞察趋势 每天&#xff0c;中文互联网上产生数以百万计的微信公众号文章&#xff0c;涵盖了科技、教育、健康、娱乐等各个领域。如何从这些海量文本中发现有价值的信息趋…...

MiniCPM-V-2_6模型版本管理:Ollama中多版本minicpm-v模型共存方案

MiniCPM-V-2_6模型版本管理&#xff1a;Ollama中多版本minicpm-v模型共存方案 1. 引言&#xff1a;当新版本模型遇上旧习惯 如果你最近在Ollama里尝试了MiniCPM-V-2_6&#xff0c;可能会遇到一个挺常见的问题&#xff1a;想用新版本&#xff0c;但之前部署的旧版本&#xff0…...

[特殊字符] mPLUG-Owl3-2B多模态工具效果展示:支持<|image|>标记的官方Prompt对齐实测

mPLUG-Owl3-2B多模态工具效果展示&#xff1a;支持<|image|>标记的官方Prompt对齐实测 1. 多模态交互新体验 今天要给大家展示一个特别实用的多模态工具——基于mPLUG-Owl3-2B模型开发的本地图文交互工具。这个工具最大的特点是完全解决了原生模型调用时的各种报错问题…...

Audio Pixel Studio快速上手:移动端Safari/Chrome浏览器兼容性实测报告

Audio Pixel Studio快速上手&#xff1a;移动端Safari/Chrome浏览器兼容性实测报告 1. 引言&#xff1a;为什么关注移动端兼容性 Audio Pixel Studio作为一款基于Streamlit开发的轻量级音频处理工具&#xff0c;其核心价值在于随时随地创作音频内容。但在实际使用中&#xff…...

PP-DocLayoutV3真实案例:某省档案馆日均万页文档结构化处理效果对比

PP-DocLayoutV3真实案例&#xff1a;某省档案馆日均万页文档结构化处理效果对比 1. 项目背景与挑战 某省档案馆承担着全省历史档案的数字化保存与利用工作。随着数字化进程的推进&#xff0c;他们面临着一个巨大的挑战&#xff1a;每天需要处理上万页的纸质档案扫描件&#x…...

Qwen3-0.6B-FP8企业应用:低算力服务器部署多语言知识引擎

Qwen3-0.6B-FP8企业应用&#xff1a;低算力服务器部署多语言知识引擎 1. 引言&#xff1a;当大模型遇见“小”服务器 如果你是一家中小企业的技术负责人&#xff0c;或者是一个独立开发者&#xff0c;是不是经常有这样的困扰&#xff1a;看到那些动辄几十亿、上百亿参数的大模…...

SeqGPT-560M中文优化深度解析:针对简体中文语义理解的Prompt设计技巧

SeqGPT-560M中文优化深度解析&#xff1a;针对简体中文语义理解的Prompt设计技巧 1. 引言&#xff1a;当AI能“秒懂”你的中文 想象一下&#xff0c;你拿到一个全新的AI模型&#xff0c;不需要准备海量数据&#xff0c;也不需要花几天几周去训练它&#xff0c;只需要告诉它“…...

Qwen3-ForcedAligner-0.6B效果展示:多人交叉对话音频→说话人分离+字级时间戳

Qwen3-ForcedAligner-0.6B效果展示&#xff1a;多人交叉对话音频→说话人分离字级时间戳 1. 引言&#xff1a;当AI能听懂每个人的声音 想象这样一个场景&#xff1a;一场多人参与的线上会议&#xff0c;大家热烈讨论&#xff0c;发言此起彼伏。会议结束后&#xff0c;你需要整…...

实时手机检测-通用参数详解:backbone/neck/head结构与性能关系

实时手机检测-通用参数详解&#xff1a;backbone/neck/head结构与性能关系 1. 模型概述与核心价值 实时手机检测-通用模型是一个专门用于检测图像中手机位置的高性能AI模型。这个模型基于DAMO-YOLO框架构建&#xff0c;在精度和速度方面都超越了传统的YOLO系列方法&#xff0…...

造相-Z-Image惊艳效果:特写人像8K输出细节放大图(毛孔/发丝/布料纹理)

造相-Z-Image惊艳效果&#xff1a;特写人像8K输出细节放大图&#xff08;毛孔/发丝/布料纹理&#xff09; 最近在折腾本地AI生图&#xff0c;总感觉有些模型要么速度慢&#xff0c;要么画质不够“真”。直到我试了基于通义千问Z-Image模型优化的“造相-Z-Image”引擎&#xff…...

Qwen3-TTS-VoiceDesign部署案例:跨国企业内部培训多语种语音课件

Qwen3-TTS-VoiceDesign部署案例&#xff1a;跨国企业内部培训多语种语音课件 1. 项目背景与需求 跨国企业经常面临一个共同挑战&#xff1a;如何高效制作多语言培训材料。传统方式需要聘请不同语种的配音演员&#xff0c;成本高、周期长&#xff0c;而且难以保证发音一致性。…...

StructBERT情感分析应用场景:短视频弹幕实时情感聚类与热词提取

StructBERT情感分析应用场景&#xff1a;短视频弹幕实时情感聚类与热词提取 1. 引言&#xff1a;弹幕数据的情感价值 你有没有在刷短视频时&#xff0c;被满屏的弹幕吸引过&#xff1f;那些快速滚动的文字&#xff0c;不仅是观众的真实反应&#xff0c;更是宝贵的情感数据金矿…...

Z-Image-GGUF效果实测:1024x1024输出在打印A3海报时的细节保留能力

Z-Image-GGUF效果实测&#xff1a;1024x1024输出在打印A3海报时的细节保留能力 1. 引言 最近在帮朋友设计一个线下活动的宣传海报&#xff0c;对方要求是A3尺寸&#xff0c;需要一张足够清晰、细节丰富的背景图。我试了几个常见的文生图模型&#xff0c;要么分辨率不够&#…...

CLIP ViT-H-14图文对话增强应用:结合LLM构建多模态问答系统

CLIP ViT-H-14图文对话增强应用&#xff1a;结合LLM构建多模态问答系统 1. 项目概述 在当今内容爆炸的时代&#xff0c;如何让机器真正理解图像内容并与人类进行自然对话&#xff0c;一直是AI领域的重要挑战。CLIP ViT-H-14图像编码服务为解决这一难题提供了强大工具。本文将…...

SiameseUIE在金融文档处理中的应用:实体识别与事件抽取实战案例

SiameseUIE在金融文档处理中的应用&#xff1a;实体识别与事件抽取实战案例 1. 引言&#xff1a;金融文档处理的挑战与机遇 金融行业每天产生海量的文档数据&#xff0c;从财报公告到风险报告&#xff0c;从合同协议到新闻资讯。这些文档中蕴含着大量有价值的信息&#xff0c…...

VideoAgentTrek-ScreenFilter一文详解:best.pt模型量化为FP16提升推理速度35%

VideoAgentTrek-ScreenFilter一文详解&#xff1a;best.pt模型量化为FP16提升推理速度35% 1. 引言&#xff1a;当目标检测遇上视频流 想象一下&#xff0c;你手头有一段视频&#xff0c;需要快速、准确地找出其中所有包含屏幕&#xff08;比如电脑显示器、手机、电视&#xf…...

SiameseUniNLU效果实测:中文商品评论中‘品牌-功能-体验’三维属性情感抽取成果

SiameseUniNLU效果实测&#xff1a;中文商品评论中‘品牌-功能-体验’三维属性情感抽取成果 1. 项目背景与模型介绍 在电商平台的海量商品评论中&#xff0c;用户往往同时表达对品牌、产品功能和实际体验的多维度感受。传统的情感分析方法通常只能判断整体情感倾向&#xff0…...

FLUX.小红书极致真实V2开源模型:支持商用授权的本地化图像生成方案

FLUX.小红书极致真实V2开源模型&#xff1a;支持商用授权的本地化图像生成方案 1. 项目简介 FLUX.小红书极致真实V2是一个基于FLUX.1-dev模型和小红书极致真实V2 LoRA开发的本地图像生成工具。这个方案专门针对消费级显卡进行了深度优化&#xff0c;让你在普通硬件上也能生成…...

STEP3-VL-10B实战案例:将PDF扫描件转为可编辑Word,保留公式与图表结构

STEP3-VL-10B实战案例&#xff1a;将PDF扫描件转为可编辑Word&#xff0c;保留公式与图表结构 你是不是经常遇到这样的烦恼&#xff1f;收到一份PDF格式的学术论文或者技术报告&#xff0c;里面全是扫描的图片&#xff0c;想要编辑里面的文字&#xff0c;却发现根本没法直接复…...