紫萌影业 發表於 2025-8-21 00:00:00

Linux下动态库.so和静态库.a的生成和使用指南

<div id="navCategory"><h5 class="catalogue">目录</h5><ul class="first_class_ul"><li>1. Linux下静态库和动态库的基本概念</li><li>2. 动态库<ul class="second_class_ul"><li>2.1 动态库如何生成</li><ul class="third_class_ul"><li>2.1.1 文件详情</li><li>2.1.2 编译生成动态库</li></ul><li>2.2 动态库如何使用</li><ul class="third_class_ul"><li>2.2.1 案例</li><li>2.2.2&nbsp;动态库错误记录</li></ul></ul></li><li>3. 静态库<ul class="second_class_ul"><li>3.1 静态库如何生成</li><ul class="third_class_ul"><li>3.1.1 文件详情</li><li>3.1.2 编译生成动态库</li></ul><li>3.2 静态库如何使用</li><ul class="third_class_ul"></ul></ul></li></ul></div><p class="maodian"></p><h2>1. Linux下静态库和动态库的基本概念</h2>
<p>库(Library)是一组预先编写好的程序代码,它们被打包在一起以供其他程序使用,从而避免了重复编写相同的代码。库可以分为静态库和动态库两种类型:</p>
<p><strong>静态库</strong></p>
<ul><li>作用:在程序编译的时候,将库编译进可执行程序中, 运行的时候不需要外部函数库</li><li>目录:默认库目录 /lib 或 /usr/lib 或 /usr/local/lib</li><li>后缀:libxxx.a</li><li>命名规范:静态库的名字一般为libxxxx.a,其中 xxxx 是该lib的名称</li></ul>
<p><strong>动态库</strong></p>
<ul><li>作用:在程序运行的时候,将库加载到程序中,运行的时候需要外部函数库</li><li>目录:默认的动态库搜索路径/lib;/usr/lib</li><li>后缀:libxxx.so</li><li>命名规范:动态库的名字一般为libxxxx.so.major.minor,xxxx 是该lib的名称,major是主版本号,minor是副版本号</li></ul>
<p>使用库的<strong>主要目的</strong>是:</p>
<ul><li>提高代码的重用性和可维护性</li><li>减少开发人员的工作量</li><li>并使程序更加模块化和易于扩展</li></ul>
<p><strong>常见的库包括:</strong></p>
<ul><li>标准库(如C标准库和C++标准库)</li><li>第三方库(如图形界面库、数据库访问库、网络通信库等)</li><li>自定义的库(根据项目需求编写的特定功能的库)</li></ul>
<p class="maodian"></p><h2>2. 动态库</h2>
<p class="maodian"></p><h3>2.1 动态库如何生成</h3>
<p>下面通过一个小栗子介绍如何生成一个动态库。</p>
<ul><li><strong>一个头文件:</strong>&nbsp;&nbsp;so_test.h</li><li><strong>头文件接口实现的三个c文件:</strong>so_test_a.c &nbsp;so_test_b.c &nbsp;so_test_c.c</li><li>我们将这几个文件编译成一个<strong>动态库:</strong>libtest.so</li></ul>
<p class="maodian"></p><h4>2.1.1 文件详情</h4>
<p>我在路径/root/host/my_program/asoc/include下创建四个文件</p>
<p><strong>一个头文件:</strong></p>
<div class="dxycode"><pre class="brush:bash;">vi so_test.h</pre></div>
<div class="dxycode"><pre class="brush:cpp;">#ifndef SO_TEST_H
#define SO_TEST_H
int addTwoiNum(int a, int b);
int subTwoiNum(int a, int b);
int mulTwoiNum(int a, int b);
#endif</pre></div>
<p><strong>三个.c文件:</strong></p>
<div class="dxycode"><pre class="brush:bash;">vi so_test_a.c</pre></div>
<div class="dxycode"><pre class="brush:cpp;">#include "so_test.h"
#include &lt;stdio.h&gt;
int addTwoiNum(int a, int b) {
return a + b;
}</pre></div>
<div class="dxycode"><pre class="brush:bash;">viso_test_b.c</pre></div>
<div class="dxycode"><pre class="brush:cpp;">#include "so_test.h"
#include &lt;stdio.h&gt;
int subTwoiNum(int a, int b) {
return a - b;
}</pre></div>
<div class="dxycode"><pre class="brush:bash;">vi so_test_c.c</pre></div>
<div class="dxycode"><pre class="brush:cpp;">#include "so_test.h"
#include &lt;stdio.h&gt;
int mulTwoiNum(int a, int b) {
return a * b;
}</pre></div>
<p class="maodian"></p><h4>2.1.2 编译生成动态库</h4>
<p>给文件附上权限:</p>
<div class="dxycode"><pre class="brush:bash;">chmod 777 so_test_a.c so_test_b.c so_test_c.c so_test.h </pre></div>
<p style="text-align:center"><img alt="" height="100" src="https://zhuji.jb51.net/uploads/allimg/20250821/2-250R1140511204.png" width="1063" /></p>
<p>接下来,我们将编译这些文件成一个动态库。</p>
<p>在Linux系统中可以使用<code>gcc</code>来完成这个任务。</p>
<div class="dxycode"><pre class="brush:bash;">gcc -c -Wall -Werror -fpic so_test_a.c
so_test_b.c
so_test_c.c
gcc -shared -o libtest.so so_test_a.o so_test_b.o so_test_c.o</pre></div>
<p><strong>第一行命令</strong>&nbsp;:</p>
<ul><li><code>-c</code>&nbsp;选项告诉编译器只编译源文件,而不进行链接。</li><li><code>-fpic</code>&nbsp;选项用于生成与位置无关的代码,这是动态链接库所必需的。</li></ul>
<p><strong>第二行命令:</strong></p>
<ul><li>使用 <code>-shared</code> 选项将目标文件链接成一个共享对象(动态库) <code>libtest.so</code>。</li></ul>
<p>现在,会得到一个名为 <code>libtest.so</code> 的动态库文件。</p>
<p style="text-align:center"><img alt="" height="148" src="https://zhuji.jb51.net/uploads/allimg/20250821/2-250R1140511295.png" width="1149" /></p>
<p class="maodian"></p><h3>2.2 动态库如何使用</h3>
<p>前面已经成功生成了一个动态链接库libtest.so,下面通过一个程序来调用这个库里的函数。</p>
<p>比如程序的源文件为:main.c【我创建的目录是/root/host/my_program/asoc/my_program】</p>
<div class="dxycode"><pre class="brush:cpp;">#include &lt;stdio.h&gt;
#include "so_test.h"
int main() {
int result_a, result_b, result_c;
int x = 10, y = 5;
// 调用动态库中的函数
result_a = addTwoiNum(x, y);
result_b = subTwoiNum(x, y);
result_c = mulTwoiNum(x, y);
// 打印结果
printf("Result of add: %d\n", result_a);
printf("Result of sub: %d\n", result_b);
printf("Result of mul: %d\n", result_c);
return 0;
}</pre></div>
<p>现在需要链接 <code>libtest.so</code> 到源文件。</p>
<p><strong>下面是编译模板:</strong></p>
<div class="dxycode"><pre class="brush:bash;">gcc -o main main.c -I/path/to/include -L/path/to/lib -ltest</pre></div>
<p>模板参数说明:</p>
<ul><li><code>-o main</code>:指定输出文件的名称为&nbsp;<code>main</code>。</li><li><code>main.c</code>:您的源文件。</li><li><code>-I/path/to/include</code>:指定要搜索头文件的路径。</li><li><code>-L/path/to/lib</code>:指定要搜索库文件的路径。</li><li><code>-ltest</code>:指定要链接的库文件名称。这里假设动态库文件名为&nbsp;<code>libtest.so</code>。</li></ul>
<p>请将&nbsp;<code>/path/to/include</code>&nbsp;和&nbsp;<code>/path/to/lib</code>&nbsp;替换为实际的路径。</p>
<p class="maodian"></p><h4>2.2.1 案例</h4>
<p><strong>【案例】如果头文件路径是 <code>/root/host/my_program/asoc/include/so_test.h</code>,动态库文件路径是 <code>/root/host/my_program/asoc/include/libtest.so</code>,可以这样编译 <code>main.c</code> 文件:</strong></p>
<div class="dxycode"><pre class="brush:bash;">gcc -o main main.c -I/root/host/my_program/asoc/include -L/root/host/my_program/asoc/include -ltest</pre></div>
<p>在这个命令中:</p>
<ul><li><code>-o main</code>:指定输出文件的名称为&nbsp;<code>main</code>。</li><li><code>main.c</code>:源文件。</li><li><code>-I/root/host/my_program/asoc/include</code>:指定要搜索头文件的路径。</li><li><code>-L/root/host/my_program/asoc/include</code>:指定要搜索库文件的路径。</li><li><code>-ltest</code>:指定要链接的库文件名称。</li></ul>
<p>链接完成会生成一个 main 的可执行文件,这个可执行文件到底有没有成功链接到动态链接库呢?</p>
<p>可以使用下面的命令来查看:</p>
<div class="dxycode"><pre class="brush:bash;">ldd main</pre></div>
<p style="text-align:center"><img alt="" height="167" src="https://zhuji.jb51.net/uploads/allimg/20250821/2-250R1140512127.png" width="708" /></p>
<p>这里说明虽然我们已经使用&nbsp;<code>-L</code> 选项指定了库文件的搜索路径,但是系统加载器在搜索动态库时还是会按照默认的路径<strong>&nbsp;/lib&nbsp; 或者&nbsp;/usr/lib&nbsp;</strong>的路径进行搜索,因此即使编译成功,但运行时仍找不到动态库。</p>
<p>要解决这个问题,可以尝试设置 <code>LD_LIBRARY_PATH</code> 环境变量来指定动态库的搜索路径。例如我的动态库.so是在路径/root/host/my_program/asoc/include下,则使用命令:</p>
<div class="dxycode"><pre class="brush:bash;">LD_LIBRARY_PATH=/root/host/my_program/asoc/include ./main</pre></div>
<p style="text-align:center"><img alt="" height="206" src="https://zhuji.jb51.net/uploads/allimg/20250821/2-250R1140512E0.png" width="1200" /></p>
<p>这样运行时就能够找到动态库 <code>libtest.so+运行成功!</code></p>
<p class="maodian"></p><h4>2.2.2&nbsp;动态库错误记录</h4>
<p>这个错误是在动态库执行的时候经常会遇到,说找不到这个.so文件,如果放在/lib或者/usr/lib下,那么默认就能找到。如果放在其他目录下,有 3 种解决方案:</p>
<ul><li>将.so 文件拷贝到 /usr/lib/文件夹下面</li><li>添加PATH环境变量【前面的案例就是使用这个解决】<br />export LD_LIBRARY_PATH=&lt;动态库所在的绝对路径&gt;</li><li>修改配置脚本<br />将动态库所在的路径加到&nbsp; /etc/ld.so.conf 文件里</li></ul>
<div class="dxycode"><pre class="brush:bash;">vim /etc/ld.so.conf</pre></div>
<p>添加后刷新</p>
<div class="dxycode"><pre class="brush:bash;">/sbin/ldconfig</pre></div>
<p class="maodian"></p><h2>3. 静态库</h2>
<p class="maodian"></p><h3>3.1 静态库如何生成</h3>
<p>下面通过一个小栗子介绍如何生成一个静态库。</p>
<ul><li><strong>一个头文件:</strong>&nbsp;&nbsp;vi staticlib.h</li><li><strong>头文件接口实现的三个c文件:</strong>staticlib.c</li><li>我们将这几个文件编译成一个<strong>静态库:</strong>libstatic.a</li></ul>
<p class="maodian"></p><h4>3.1.1 文件详情</h4>
<p>我在路径/root/host/my_program/asoc/include下创建下面的文件</p>
<div class="dxycode"><pre class="brush:bash;">vi staticlib.h</pre></div>
<div class="dxycode"><pre class="brush:cpp;">#ifndef __STATICLIB_H
#define __STATICLIB_H
int hello();
#endif</pre></div>
<div class="dxycode"><pre class="brush:bash;">vi staticlib.c</pre></div>
<div class="dxycode"><pre class="brush:cpp;">#include "staticlib.h"
#include &lt;stdio.h&gt;
int hello(){
printf("hello,this is static lib\n");
return 0;
}</pre></div>
<p class="maodian"></p><h4>3.1.2 编译生成动态库</h4>
<p>给文件附上权限:</p>
<div class="dxycode"><pre class="brush:bash;">chmod 777 staticlib.h staticlib.c</pre></div>
<p>使用编译器将 <code>staticlib.c</code> 编译成目标文件(<code>.o</code> 文件):</p>
<div class="dxycode"><pre class="brush:bash;">gcc -c staticlib.c -o staticlib.o</pre></div>
<p>使用 <code>ar</code> 命令将目标文件打包成静态库文件 <code>libstatic.a</code>:</p>
<div class="dxycode"><pre class="brush:bash;">ar rcs libstatic.a staticlib.o</pre></div>
<p>这样就生成了名为 <code>libstatic.a</code> 的静态库文件,其中包含了 <code>staticlib.o</code> 的内容。</p>
<p style="text-align:center"><img alt="" height="153" src="https://zhuji.jb51.net/uploads/allimg/20250821/2-250R1140512G8.png" width="1200" /></p>
<p class="maodian"></p><h3>3.2 静态库如何使用</h3>
<p>前面已经成功生成了一个动态链接库libtest.so,下面通过一个程序来调用这个库里的函数。</p>
<p>比如程序的源文件为:test.c【我创建的目录是/root/host/my_program/asoc/my_program】</p>
<p>内容如下:</p>
<div class="dxycode"><pre class="brush:cpp;">#include &lt;stdio.h&gt;
#include "staticlib.h"
int main() {
printf("Calling hello() function...\n");
hello();
return 0;
}</pre></div>
<p>接下来,需要编译 <code>main.c</code> 并链接静态库 <code>libstatic.a</code>。</p>
<div class="dxycode"><pre class="brush:bash;">gcc test.c -o test -I/root/host/my_program/asoc/include/ -L/root/host/my_program/asoc/include/ -lstatic</pre></div>
<p>参数说明:</p>
<ul><li>&nbsp;<code>-L</code>&nbsp;参数指定了编译器搜索库文件的路径</li><li><code>-lstatic</code>&nbsp;指定了要链接的静态库名字(注意,<code>lib</code>&nbsp;前缀和&nbsp;<code>.a</code>&nbsp;扩展名都不需要在此处指定)</li></ul>
<p>然后运行可执行文件 <code>test</code>:</p>
<div class="dxycode"><pre class="brush:bash;">./test</pre></div>
<p style="text-align:center"><img alt="" height="132" src="https://zhuji.jb51.net/uploads/allimg/20250821/2-250R11405121I.png" width="710" /></p>
<p>说明静态库链接成功!</p>
<p>以上就是【库函数】Linux下动态库.so和静态库.a的生成和使用的详细内容,更多相关资料请阅读琼殿技术社区其它文章!</p>
頁: [1]
查看完整版本: Linux下动态库.so和静态库.a的生成和使用指南