Ubuntu下gcc的静态库与动态库的生成与使用

目录

LInux中函数库的类型

一、用gcc生成.a静态库

        1.编辑生成例子程序 hello.h 、hello.c和main.c          

                2.将hello.c编译成.o文件

                3.由.o文件创建静态库

                4.在程序中使用静态库

二、用gcc创建动态库文件 

        1.由.o文件创建动态库

         2.在程序中使用动态库

        3.当静态库与动态库同名时,gcc命令会使用哪个库

三、实操1

        1.构建新文件夹,编写程序

        2.静态库.a文件的生成与使用

        3.共享库.so文件的生成与使用

 四、实操2

        1.c程序的编写

        2.用gcc分别把三个.c文件分别编译成3个.o目标文件

        3.将目标文件生成静态.a文件 并与main函数连接

         4.观测静态库文件大小

         5.将目标文件生成动态库.so文件并与main函数连接

        6.观测动态库文件大小 并与静态库文件大小进行比较

五、总结

六、参考资料


LInux中函数库的类型

函数库分为静态库和动态库。

静态库:

在程序编译时会被连接到目标代码中,程序运行是则不需要静态库的存在。

动态库:

在程序编译时不会被连接到目标代码中,而是程序运行时载入的。

两者区别:前者是编译连接的,后者是程序运行载入的。
 

一、用gcc生成.a静态库

        1.编辑生成例子程序 hello.h 、hello.c和main.c          

          先创建一个目录,保存本次练习的文件

          输入指令 mkdir test1(创建目录)                       

          cd test1(选中该目录路径)

          然后用vim、nano或者gedit等文本编辑器生成所需要的三个文件。我用的是vim。

          hello.c是函数库的源程序,其中包含了公用函数hello,该函数将在屏幕上输出“Hello XXX!”。hello.h为该函数库的头文件。main.c为测试库文件的主程序,在主程序中调用了公用函数hello。

三个程序如下:

hello.h

#ifndef HELLO_H
#define HELLO_H
void hello(const char*name);
#endif//HELLO_H

hello.c

#include<stdio.h>
void hello(const char*name)
{
    printf("Hello %s!\n",name);
}

main.c

#include"hello.h"
int main()
{
    hello("everyone");
    return 0;
}

                2.将hello.c编译成.o文件

输入命令 gcc -c hello.c

我们可以运行ls命令看看是否生成了hello.o文件

 如图所示,则成功生成了hello.o文件

                3.由.o文件创建静态库

静态库的文件名的命名规范是以lib为前缀,紧接着跟静态库名,扩展名为.a。例如:我们将创建的静态库名为myhello,则静态库文件名就是libmyhello.a。(在创建和使用静态库时,需要注意这点       点)

输入命令 ar -crv libmyhello.a hello.o 生成静态库

同样的可以用ls命令查看是否成功生成静态库

 如图,已经有了libmyhello.a,则生成静态库成功

                4.在程序中使用静态库

要是用静态库中内部的函数,只需要在使用到这些公用函数的源程序包含这些公用函数的原型声明,然后再用gcc命令生成目标文件时指明静态库名,gcc将会从静态库中将公用函数连接到目标文件中。注意,gcc会在静态库名前加上前缀lib,然后追加.a得到的静态库文件名来查找静态库文件。以下介绍了三种方法:

第一种:

输入命令 gcc -o hello main.c -L. -lmyhello

自定义的库时,main.c还可放在-L. 和 -lmyhello 之间,但是不能放在它俩之后,否则会同时myhello没定义,但是是系统的库时,如g++ -o main (-L/usr/lib) -lpthread main.cpp就不出错。

方法二:

输入命令 gcc main.c libmyhello.a -o hello

方法三:

先输入命令 gcc -c main.c 生成main.o文件

再输入命令 gcc -o hello main.o libmyhello.a 生成可执行文件

再输入命令 ./hello 运行

二、用gcc创建动态库文件 

        1.由.o文件创建动态库

动态库文件名命名规范和静态库文件名命名规范类似,也是在动态库名增加前缀lib,但其文件扩展名为.so。例如:我们将创建的动态库名为myhello,则动态库文件名就是libmyhello.so。

输入命令 gcc -shared -fPIC -o libmyhello.so hello.o 创建动态库

也可通过ls命令查看动态库是否创建成功

         2.在程序中使用动态库

在程序中使用动态库和使用静态库完全一样,也是在使用到这些公用函数的源程序中包含这些公用函数的原型声明,然后再用gcc命令生成目标文件时指明动态库名进行编译。我们先运行gcc命令生成目标文件,在运行它看看结果。

输入命令 gcc -o hello main.c -L. -lmyhello(或 gcc main.c libmyhello.so -o hello 不会出错(没有libmyhello的话,会出错),但是接下来 ./hello 会提示出错,因为虽然连接时用的是当前目录的动态库,但是运行时,是到 /usr/lib 中找库文件的,将文件 libmyhello.so 复制到目录 /usr/lib 中就OK了(即输出命令 sudo cp libmyhello.so /usr/lib ),然后再运行 ./hello 就没问题了)

 如上图,成功了。这也进一步说明了动态库在程序运行时是必要的。

        3.当静态库与动态库同名时,gcc命令会使用哪个库

先删除除.c 和 .h 外所有的文件,恢复成我们刚刚编程完举例程序状态

输入命令 sudo rm -f hello hello.o /usr/lib/libmyhello.so

                ls

再来创建静态库文件libmyhello.a和动态库libmyhello.so

输入命令 gcc -c hello.c

                ar -crv libmyhello.a hello.o

                gcc -shared -fPIC -o libmyhello.so hello.o

                ls

运行gcc命令来使用函数库 myhello 生成目标文件 hello,并运行程序 hello

输入命令 gcc -o hello main.c -L. lmyhello

                ./hello

 如图红框所标识的地方,发现在执行可执行文件时,会报一个错误,可见当静态库和动态库同时存在的时候,程序会优先使用动态库。(按照上面一样的操作将文件路径复制到 /usr/lib 下即可解决报错问题)

三、实操1

        1.构建新文件夹,编写程序

mkdir test2

cd test2

A1.c

#include<stdio.h>
void print1(int arg);
{
    printf("A1 print arg:%d\n",arg);
}

A2.c

#include<stdio.h>
void print2(char *arg)
{
    printf("A2 printf arg:%s\n",arg);
}

A.h

#ifndef A_H
#define A_H
void print1(int);
void print2(char *);
#endif

test.c

#include<stdlib.h>
#include"A.h"
int main()
{
    print1(1);
    print2("test");
    exit(0);
}

        2.静态库.a文件的生成与使用

gcc -c A1.c A2.c

 ar crv libafile.a A1.o A2.o

 gcc -o test test.c libafile.a

./test

        3.共享库.so文件的生成与使用

gcc -c -fpic A1.c A2.c 

gcc -shared *.o -o libafile.so 

 gcc -o test test.c libafile.so

./test

此处会报错,问题在于路径,只需要通过以下命令将其放在 /usr/lib 目录下即可

sudo cp libafile.so /usr/lib

./test

 四、实操2

        1.c程序的编写

mkdir test3

cd test3

lcx.c

float x2x(int a,int b)
{
    float ans;
    ans=a+b;
    return ans;
}

lcy.c

float x2y(int a,int b)
{
    float ans;
    ans=a-b;
    return ans;
}

lc.h

#ifndef LC_H
#define LC_H
float x2x(int a,int b);
float x2y(int a,int b);
#endif

main.c

#include<stdio.h>
#include"lc.h"
int main()
{
    int a,b;
    a=8;
    b=5;
    float ans1;
    float ans2;
    ans1=x2x(a,b);
    ans2=x2y(a,b);
    printf("%f\n",ans1);
    printf("%f\n",ans2);
    return 0;
}

        2.用gcc分别把三个.c文件分别编译成3个.o目标文件

gcc -c lcx.c lcy.c main.c

ls

        3.将目标文件生成静态.a文件 并与main函数连接

ar crv libic.a lcx.o lcy.o

ls

gcc -o main main.o libic.a

         4.观测静态库文件大小

在linux下可使用 “ls -l” 或者 “ls -al” 或者 “ll” 命令查看文件及目录详情

         5.将目标文件生成动态库.so文件并与main函数连接

gcc -shared -fPIC -o libic.so lcx.o lcy.o

ls

gcc -o main main.o libic.so

        6.观测动态库文件大小 并与静态库文件大小进行比较

 将二者进行对比,发现静态库较动态库而言,占用空间更少。

五、总结

通过上述几个程序基于Ubuntu中gcc生成静态库和动态库的练习,让我进一步明白了静态库与动态库之间的差别。同时也培养了处理问题的耐心,在不断的网上查阅资料后能处理所遇到的各种问题。也让我看到了这和代码编辑器完全不同,虽然这种方式更复杂,但却能让我对代码的编译过程有更清晰更深刻的理解与认识。

六、参考资料

浏览https://mooc1.chaoxing.com/ueditorupload/read?objectId=dc36405faf8e7dc66d657fcc6b780cd7&fileOriName=%25E7%2594%25A8gcc%25E7%2594%259F%25E6%2588%2590%25E9%259D%2599%25E6%2580%2581%25E5%25BA%2593%25E5%2592%258C%25E5%258A%25A8%25E6%2580%2581%25E5%25BA%2593.pdf浏览https://mooc1.chaoxing.com/ueditorupload/read?objectId=07cf0524899ab88f4d59af8e05a94d8a&fileOriName=%25E9%259D%2599%25E6%2580%2581%25E5%25BA%2593.a%25E4%25B8%258E.so%25E5%25BA%2593%25E6%2596%2587%25E4%25BB%25B6%25E7%259A%2584%25E7%2594%259F%25E6%2588%2590%25E4%25B8%258E%25E4%25BD%25BF%25E7%2594%25A8.pdf

猜你喜欢

转载自blog.csdn.net/qq_55894922/article/details/126851431
今日推荐