待我强大给你天下 發表於 2022-7-1 14:45:00

linux 动态库、静态库

<p><span style="color: rgba(255, 0, 0, 1)"><strong>库:可执行的二进制代码,不可以独立执行(没有main函数入口)</strong></span></p>
<p><span style="color: rgba(255, 0, 0, 1)"><strong>库是否兼容:取决于编译器、汇编器、链接器</strong></span></p>
<p>&nbsp;</p>
<p><span style="color: rgba(255, 0, 0, 1)">linux链接静态库(.a):将库中用到的函数的代码指令,写入到可执行文件中、运行时无依赖</span></p>
<p><span style="color: rgba(255, 0, 0, 1)">linux链接动态库(共享库.so):在可执行程序中记录了库中函数的符号表信息,执行时再找库,找不到,则无法执行。</span></p>
<p><span style="color: rgba(255, 0, 0, 1)"><strong>程序默认使用动态库</strong></span></p>
<h2><span style="background-color: rgba(0, 255, 255, 1)"><strong>1、静态库</strong></span></h2>
<p>静态库命名:libxxx.a,在编译的第4步使用,链接阶段</p>
<h3><strong>1.1制作静态库:</strong></h3>
<p>(1)gcc -c xxx.c -o xxx.o&nbsp; &nbsp; &nbsp; &nbsp; //.c文件制作成.o文件 gcc -c&nbsp; 只编译,不链接,生成目标文件</p>
<p>(2)ar -rcs libxxxx.a xxx.o aaaa.o&nbsp; //使用ar工具制作静态库。ar是linux压缩备份命令,可以将多个文件打包成一个备份文件</p>
<p>(3)编译链接库 gcc test.c&nbsp; -o a.out&nbsp;libxxxx.a</p>
<p>(4)ar -t 查看libxxxx.a是由哪些.o文件构成。</p>
<div class="cnblogs_code">
<pre>   ar -<span style="color: rgba(0, 0, 0, 1)">t 显示静态库的内容
   ar </span>-<span style="color: rgba(0, 0, 0, 1)">d 从库中删除成员文件
   ar </span>-<span style="color: rgba(0, 0, 0, 1)">r 在库中加入成员文件,若存在,则替换
   ar </span>-<span style="color: rgba(0, 0, 0, 1)">c 创建一个库
   ar </span>-s 无论ar命令是否修改了库内容,都强制重新生成库符号表</pre>
</div>
<p>&nbsp;</p>
<h3><strong>1.2 静态库示例</strong></h3>
<p>main.c 源码</p>
<div class="cnblogs_code"><img src="https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif" id="code_img_closed_bbe9c959-1e5e-480f-ae7e-e71562ccb41a" class="code_img_closed"><img src="https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif" id="code_img_opened_bbe9c959-1e5e-480f-ae7e-e71562ccb41a" class="code_img_opened" style="display: none">
<div id="cnblogs_code_open_bbe9c959-1e5e-480f-ae7e-e71562ccb41a" class="cnblogs_code_hide">
<pre><span style="color: rgba(0, 0, 0, 1)"># cat main.c
#include </span>&lt;stdio.h&gt;

<span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> main()
{
      </span><span style="color: rgba(0, 0, 255, 1)">int</span> a = <span style="color: rgba(128, 0, 128, 1)">2</span>,b = <span style="color: rgba(128, 0, 128, 1)">3</span>,c = <span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">;
      printf(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">c = %d\n</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">, test_lib_a(a,b));
      printf(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">c = %d\n</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">, test_lib_b(a,b));
      printf(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">c = %d\n</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">, test_lib_c(a,b));
      </span><span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">;
}</span></pre>
</div>
<span class="cnblogs_code_collapse">View Code</span></div>
<p>test_lib_a.c、test_lib_b.c、test_lib_c.c源码</p>
<div class="cnblogs_code"><img src="https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif" id="code_img_closed_68772023-0fc7-41d6-9677-0e04b732d7a9" class="code_img_closed"><img src="https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif" id="code_img_opened_68772023-0fc7-41d6-9677-0e04b732d7a9" class="code_img_opened" style="display: none">
<div id="cnblogs_code_open_68772023-0fc7-41d6-9677-0e04b732d7a9" class="cnblogs_code_hide">
<pre><span style="color: rgba(0, 0, 0, 1)"># cat test_lib_a.c
#include </span>&lt;stdio.h&gt;

<span style="color: rgba(0, 0, 255, 1)">int</span> test_lib_a(<span style="color: rgba(0, 0, 255, 1)">int</span> a, <span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> b)
{
      printf(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">%s\n</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">, __FUNCTION__);
      </span><span style="color: rgba(0, 0, 255, 1)">return</span> a +<span style="color: rgba(0, 0, 0, 1)"> b;
}
#
# cat test_lib_b.c
#include </span>&lt;stdio.h&gt;

<span style="color: rgba(0, 0, 255, 1)">int</span> test_lib_b(<span style="color: rgba(0, 0, 255, 1)">int</span> a, <span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> b)
{
      printf(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">%s\n</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">, __FUNCTION__);
      </span><span style="color: rgba(0, 0, 255, 1)">return</span> a +<span style="color: rgba(0, 0, 0, 1)"> b;
}
# cat test_lib_c.c
#include </span>&lt;stdio.h&gt;

<span style="color: rgba(0, 0, 255, 1)">int</span> test_lib_c(<span style="color: rgba(0, 0, 255, 1)">int</span> a, <span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> b)
{
      printf(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">%s\n</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">, __FUNCTION__);
      </span><span style="color: rgba(0, 0, 255, 1)">return</span> a +<span style="color: rgba(0, 0, 0, 1)"> b;
}
# cat test_lib_a.c
#include </span>&lt;stdio.h&gt;

<span style="color: rgba(0, 0, 255, 1)">int</span> test_lib_a(<span style="color: rgba(0, 0, 255, 1)">int</span> a, <span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> b)
{
      printf(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">%s\n</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">, __FUNCTION__);
      </span><span style="color: rgba(0, 0, 255, 1)">return</span> a +<span style="color: rgba(0, 0, 0, 1)"> b;
}
#
# cat test_lib_b.c
#include </span>&lt;stdio.h&gt;

<span style="color: rgba(0, 0, 255, 1)">int</span> test_lib_b(<span style="color: rgba(0, 0, 255, 1)">int</span> a, <span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> b)
{
      printf(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">%s\n</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">, __FUNCTION__);
      </span><span style="color: rgba(0, 0, 255, 1)">return</span> a +<span style="color: rgba(0, 0, 0, 1)"> b;
}
# cat test_lib_c.c
#include </span>&lt;stdio.h&gt;

<span style="color: rgba(0, 0, 255, 1)">int</span> test_lib_c(<span style="color: rgba(0, 0, 255, 1)">int</span> a, <span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> b)
{
      printf(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">%s\n</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">, __FUNCTION__);
      </span><span style="color: rgba(0, 0, 255, 1)">return</span> a +<span style="color: rgba(0, 0, 0, 1)"> b;
}</span></pre>
</div>
<span class="cnblogs_code_collapse">View Code</span></div>
<p>编译.c&nbsp; 查看生成的.o文件</p>
<div class="cnblogs_code">
<pre># gcc -c *<span style="color: rgba(0, 0, 0, 1)">.c
# ls
libtest_lib_all.amain.cmain.otest_lib_a.ctest_lib_a.otest_lib_b.ctest_lib_b.otest_lib_c.ctest_lib_c.o
# ar </span>-<span style="color: rgba(0, 0, 0, 1)">rcs libtest_lib.a test_lib_a.o test_lib_b.o test_lib_c.o
# gcc main.o </span>-o a.<span style="color: rgba(0, 0, 255, 1)">out</span><span style="color: rgba(0, 0, 0, 1)"> libtest_lib.a
# .</span>/a.<span style="color: rgba(0, 0, 255, 1)">out</span><span style="color: rgba(0, 0, 0, 1)">
test_lib_a
c </span>= <span style="color: rgba(128, 0, 128, 1)">5</span><span style="color: rgba(0, 0, 0, 1)">
test_lib_b
c </span>= <span style="color: rgba(128, 0, 128, 1)">5</span><span style="color: rgba(0, 0, 0, 1)">
test_lib_c
c </span>= <span style="color: rgba(128, 0, 128, 1)">5</span></pre>
</div>
<p>这三种方式编译也ok</p>
<div class="cnblogs_code"><img src="https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif" id="code_img_closed_1d77194a-96f5-478e-a30a-3989bb19703a" class="code_img_closed"><img src="https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif" id="code_img_opened_1d77194a-96f5-478e-a30a-3989bb19703a" class="code_img_opened" style="display: none">
<div id="cnblogs_code_open_1d77194a-96f5-478e-a30a-3989bb19703a" class="cnblogs_code_hide">
<pre># gcc test_lib_a.o test_lib_b.o test_lib_c.o main.o -o a.<span style="color: rgba(0, 0, 255, 1)">out</span>   <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">这种编译也ok</span>
<span style="color: rgba(0, 0, 0, 1)">#
# gcc test_lib_a.o test_lib_b.o test_lib_c.o main.c </span>-o a.<span style="color: rgba(0, 0, 255, 1)">out</span>   <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">这种编译也ok</span>
<span style="color: rgba(0, 0, 0, 1)">
# gcc main.c </span>-o a.<span style="color: rgba(0, 0, 255, 1)">out</span> libtest_lib.a</pre>
</div>
<span class="cnblogs_code_collapse">View Code</span></div>
<h2><span style="background-color: rgba(0, 255, 255, 1)"><strong>2、动态库</strong></span></h2>
<p>.so 库 (Shared Object&nbsp;),共享的目标文件</p>
<p>查看文件(动态库)的依赖 : ldd xxxxx</p>
<h3><strong>2.1 制作动态库</strong></h3>
<div class="cnblogs_code">
<pre># gcc -shared -fPIC -c *.c<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">需要带-shared -fPIC编译,否则无法做成动态库
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> gcc -shared -fPIC -o libxxxx.so bbbb.o cccc.o dddd.o</span>
# gcc -shared -fPIC -o libtest_lib.so test_lib_d.o test_lib_b.o test_lib_c.o</pre>
</div>
<h3><strong>2.2 动态库示例</strong></h3>
<p>test_lib_d.c 代码</p>
<div class="cnblogs_code"><img src="https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif" id="code_img_closed_f7bf9eb4-7262-434d-959a-2bc61a1bdd42" class="code_img_closed"><img src="https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif" id="code_img_opened_f7bf9eb4-7262-434d-959a-2bc61a1bdd42" class="code_img_opened" style="display: none">
<div id="cnblogs_code_open_f7bf9eb4-7262-434d-959a-2bc61a1bdd42" class="cnblogs_code_hide">
<pre><span style="color: rgba(0, 0, 0, 1)"># cat test_lib_d.c
#include </span>&lt;stdio.h&gt;

<span style="color: rgba(0, 0, 255, 1)">int</span> test_lib_a(<span style="color: rgba(0, 0, 255, 1)">int</span> a, <span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> b)
{
      printf(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">%s but this test_lib_c.c\n</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">, __FUNCTION__);
      </span><span style="color: rgba(0, 0, 255, 1)">return</span> a +<span style="color: rgba(0, 0, 0, 1)"> b;
}</span></pre>
</div>
<span class="cnblogs_code_collapse">View Code</span></div>
<p>编译 .o 编译 .so</p>
<div class="cnblogs_code">
<pre># gcc -shared -fPIC -c *.c<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">编译.o 文件</span>
# gcc -shared -fPIC -o libtest_lib.so test_lib_d.o test_lib_b.o test_lib_c.o<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">编译动态库
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 查看编译生成的动态库.so和.o文件</span>
<span style="color: rgba(0, 0, 0, 1)"># ls
a.</span><span style="color: rgba(0, 0, 255, 1)">out</span>lib_pathlibtest_lib.somain.cmain.otest_lib_a.ctest_lib_a.otest_lib_b.ctest_lib_b.otest_lib_c.ctest_lib_c.o</pre>
</div>
<p>运行可执行文件</p>
<div class="cnblogs_code">
<pre># cp lib_path/libtest_lib.so /lib64/   <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">将库拷贝到动态库默认搜索路径/lib64下</span>
# ./a.<span style="color: rgba(0, 0, 255, 1)">out</span><span style="color: rgba(0, 0, 0, 1)">
test_lib_a but </span><span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)"> test_lib_c.c
c </span>= <span style="color: rgba(128, 0, 128, 1)">5</span><span style="color: rgba(0, 0, 0, 1)">
test_lib_b
c </span>= <span style="color: rgba(128, 0, 128, 1)">5</span><span style="color: rgba(0, 0, 0, 1)">
test_lib_c
c </span>= <span style="color: rgba(128, 0, 128, 1)">5</span></pre>
</div>
<h2><span style="background-color: rgba(0, 255, 255, 1)"><strong>3、链接库、链接头文件</strong></span></h2>
<p>-I(大写i):指定include包含文件的搜索路径.</p>
<p>-L&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; :指定链接所需库所在路径</p>
<p>-l(小写L):指定所需链接库的库名(比如链接libastatic.a) -lastatic</p>
<p>-static:&nbsp; &nbsp; &nbsp;:静态链接,但会导致所有的库都使用静态连接</p>
<p>-Wl,-Bdynamic:指明为动态链接</p>
<p>-Wl,-Bstatic:指明为静态链接</p>
<p>-Wl,-rpath=:指定文件搜索库路径</p>
<p><strong><span style="color: rgba(255, 0, 0, 1)">混合链接时:动态库在静态库前面链接时,必须在命令行最后使用动态连接的命令。(系统的运行库使用动态链接方式,结尾不是动态链接,会导</span></strong><strong><span style="color: rgba(255, 0, 0, 1)">致后面链接系统的库,去找到的是静态库)</span></strong></p>
<p><span style="color: rgba(255, 0, 0, 1)"><strong>混合链接时:优先链接动态库</strong></span></p>
<p>如下为证明优先链接动态库</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">编译生成静态库、动态库</span>
# ar -<span style="color: rgba(0, 0, 0, 1)">rcs libtest_lib_b.a test_lib_b.o
# ar </span>-<span style="color: rgba(0, 0, 0, 1)">rcs libtest_lib_c.a test_lib_c.o
# gcc </span>-shared -fPIC -<span style="color: rgba(0, 0, 0, 1)">o libtest_lib_a.so test_lib_d.o
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 动态库、静态库混合链接,且证明优先链接动态库</span>
# gcc main.c -o a.<span style="color: rgba(0, 0, 255, 1)">out</span> -L lib_path/ -Wl,-Bdynamic -ltest_lib_a -Wl,-Bstatic -ltest_lib_b -ltest_lib_c-Wl,-<span style="color: rgba(0, 0, 0, 1)">Bdynamic
#
# .</span>/a.<span style="color: rgba(0, 0, 255, 1)">out</span><span style="color: rgba(0, 0, 0, 1)">
.</span>/a.<span style="color: rgba(0, 0, 255, 1)">out</span>: error <span style="color: rgba(0, 0, 255, 1)">while</span> loading shared libraries: libtest_lib_a.so: cannot open shared <span style="color: rgba(0, 0, 255, 1)">object</span><span style="color: rgba(0, 0, 0, 1)"> file: No such file or directory
# mv lib_path</span>/libtest_lib_a.so /lib64/<span style="color: rgba(0, 0, 0, 1)">
#
# .</span>/a.<span style="color: rgba(0, 0, 255, 1)">out</span><span style="color: rgba(0, 0, 0, 1)">
test_lib_a but </span><span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)"> test_lib_c.c
c </span>= <span style="color: rgba(128, 0, 128, 1)">5</span><span style="color: rgba(0, 0, 0, 1)">
test_lib_b
c </span>= <span style="color: rgba(128, 0, 128, 1)">5</span><span style="color: rgba(0, 0, 0, 1)">
test_lib_c
c </span>= <span style="color: rgba(128, 0, 128, 1)">5</span>
<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">静态链接放在结尾,是有问题的</span>
# gcc main.c -o a.<span style="color: rgba(0, 0, 255, 1)">out</span> -L lib_path/ -Wl,-Bdynamic -ltest_lib_a -Wl,-Bstatic -ltest_lib_b -<span style="color: rgba(0, 0, 0, 1)">lte st_lib_c
</span>/usr/bin/ld: cannot find -<span style="color: rgba(0, 0, 0, 1)">lgcc_s
collect2: error: ld returned </span><span style="color: rgba(128, 0, 128, 1)">1</span><span style="color: rgba(0, 0, 0, 1)"> exit status
#

# gcc main.c </span>-o a.<span style="color: rgba(0, 0, 255, 1)">out</span> -L lib_path/ -Wl,-Bstatic -ltest_lib_b -ltest_lib_c -Wl,-Bdynamic -lte st_lib_a</pre>
</div>
<h3><span style="background-color: rgba(255, 255, 255, 1)"><strong>3.1、解决动态库链接问题</strong></span></h3>
<div class="cnblogs_code">
<pre>./a.<span style="color: rgba(0, 0, 255, 1)">out</span>: error <span style="color: rgba(0, 0, 255, 1)">while</span> loading shared libraries: libtest_lib.so: cannot open shared <span style="color: rgba(0, 0, 255, 1)">object</span> file: No such file or directory</pre>
</div>
<p>上面问题核心原因是,编译时候能链接到动态库,可执行文件执行时找链接不到库。</p>
<p><strong>解决办法1:</strong></p>
<table border="0">
<tbody>
<tr>
<td>1、拷贝库到默认链接路径下,即拷贝库到/lib、/lib64、/usr/lib下</td>
</tr>
<tr>
<td>2、编译时,指定库运行时库搜索路径。即加上前缀-Wl(小写L), -R(或-rpath)。-Wl,-rpath=./lib_path -L./lib_path</td>
</tr>
<tr>
<td>3、环境变量LD_LIBRARY_PATH指定的动态库搜索路径。export LD_LIBRARY_PATH=./lib_path</td>
</tr>
<tr>
<td>4、配置文件/etc/ld.so.conf中指定的动态库搜索路径</td>
</tr>
</tbody>
</table>
<div class="cnblogs_code">
<pre># gcc main.c -o a.<span style="color: rgba(0, 0, 255, 1)">out</span>-Wl,-rpath=./lib_path -L./lib_path -ltest_lib</pre>
</div>
<p>&nbsp;</p>
<h3><span>3.2、库链接顺序</span></h3>
<p><span style="color: rgba(255, 0, 0, 1)"><strong>注意:库的链接顺序为从左到右,即A依赖B,则-lA -lB。越基础的库越放在右边</strong></span></p>
<h2><span style="background-color: rgba(0, 255, 255, 1)"><strong>4、查看库的属性:</strong></span></h2>
<p>&nbsp;</p>
<p>(1)ldd xxxx&nbsp; //查看xxx文件的依赖库</p>
<p>(2)已经启动的,查看进程号,cat /proc/PID/maps&nbsp; //可以查看到可执行文件已加载的库</p>
<p>(3)xxx-linux-objdump -x file-name | grepp NEEDED&nbsp;</p>
<p>(4)xxx-linux-readelf -a file-name | grep Shared<br><br></p>
<p><strong>参考</strong>:</p>
<p>https://www.cnblogs.com/xingmuxin/p/11416518.html</p>
<p><em id="__mceDel">https://zhuanlan.zhihu.com/p/349122842</em></p>
<p>https://blog.csdn.net/JoshYueby/article/details/105528682&nbsp;</p>
<p>https://blog.csdn.net/yueguangmuyu/article/details/117655920</p><br><br>
来源:https://www.cnblogs.com/tzj-kernel/p/16418709.html
頁: [1]
查看完整版本: linux 动态库、静态库