首页 > 其他分享 >动态共享库/静态共享库

动态共享库/静态共享库

时间:2023-01-05 10:11:06浏览次数:31  
标签:gcc 动态 静态 add ## xiaocer 共享 include localhost

0.前言

在学习如何制作静态库和共享库之前,我们来了解GCC编译器的基本工作流程和GCC常用参数的使用。

1.GCC基本工作流程

现在假设有一个helloworld.c源程序,功能是只打印HelloWorld

  1. 将C源程序进行预处理(预处理一般做的工作是将宏替换和头文件展开 ):gcc -E helloworld.c > helloworld.i,注意>与>>的区别.这里呢,helloworld.i文件只是存储gcc -E helloworld.c的结果。
  2. 将helloworld.i文件生成汇编代码:gcc -S helloworld.i,这条命令会生成后缀名.s的文件,里面是一些汇编指令。
  3. 将存放汇编指令的文件编译成二进制文件:gcc -c helloworld.s,这条命令会生成后缀名为.o的二进制文件.
  4. gcc helloworld.o将二进制文件默认生成a.out文件;如果需要指定生成的目标文件名则:gcc helloworld.o -o app
  5. ./a.out即可运行。上面的基本流程我们可以用下图表示:
    gcc编译基本流程.png

2.gcc编译器的常用参数

hello.c如下

#include <stdio.h>
#include <head.h>

int returnMess(int val)
{
        return val;
}
int main()
{
#ifdef DEBUG
        printf("HelloWorld");
#endif
        printf("%d",returnMess(100));
        return 0;
}

  1. -I:指示待编译的头文件的路径。比如说main主函数所在的源程序中包含了其他自定义的头文件,编译的时候为了将它包含进来,可以用-I选项指示自定义的头文件所在的路径。
##hello.c中包含了自定义的头文件head.h,这个文件在/home/xiaocer/练习/include下
##这样生成a.out可执行文件
[xiaocer@localhost practice]gcc hello.c -I ../include
  1. -O:优化选项,其值有0~3。默认的编译选项为O0,表示不做任何优化。
##对hello.c文件采用二级优化来编译
[xiaocer@localhost practice]$ gcc hello.c -I ../include -D DEBUG -o result -O2
  1. -D:指定宏编译。指定宏编译如下:
[xiaocer@localhost practice]gcc hello.c -I ../include -D DEBUG  -o result
  1. -L:指定包含的库路径
  2. -l:指定包含的库名,Linux下库名一般是libxxx.so(动态库)或者libxxx.a(静态库),指定库名的时候只要-l xxx
  3. -g:在最终编译生成的可执行文件中加入调试信息有利于调试
  4. -Wall:显示编译时期所有的警告信息
[xiaocer@localhost practice]$ gcc hello.c -I ../include -o result.exe -Wall
  1. -lstdc++:用GCC编译器编译C++写的源程序。比如说
[xiaocer@localhost practice]$ gcc hello.cpp -lstdc++
  1. -o:指定编译生成的目标可执行文件的文件名,如果不指定则默认生成a.out文件。
  2. -c:将源文件编译成.o为后缀名的二进制文件
##将hello.c编译成二进制文件
[xiaocer@localhost practice]$ gcc hello.c -c -I ../include
  1. -E:将源文件输出到标准输出设备默认为Linux终端,输出前进行宏替换和头文件展开。
  2. -S:将编译成.s为后缀名结尾的汇编文件。

3.静态库的制作

  1. Linux系统下静态库名一般是libxxx.a,而windows下呢是以后缀名为.lib结尾的。
  2. 制作步骤:
    1. 将需要制作成静态库的源文件编译成以.o为后缀名的二进制文件
    2. 使用ar rcs libxxx.a yyy.o yyy1.o yyy2.o命令将二进制文件打包。ar:archived意为归档的。
  3. 示例:
    1. 现在有add.c这个实现好的源文件,里面是实现两个整数的相加算法的一个函数add()。现在提供给客户使用add这个函数提供的功能,但是又不想提供add.c这个源文件给客户暴露add函数具体的实现。所以呢,可以将add.c 制作成静态库libadd.a,然后同add函数的声明所在的头文件add.h提供给客户即可。
    ##现在在/home/xiaocer/练习/include目录下有add.h和add.c两个文件
    ##将add.c源文件编译成add.o这个二进制文件
    [xiaocer@localhost include]$ gcc add.c -c -I ./
    ##将二进制文件打包成静态库,这样就会生成一个libadd.a这个文件
    [xiaocer@localhost include]$ ar rcs libadd.a add.o
    
    1. 静态库制作好后现在提供给客户使用。客户拿到libadd.a文件后,在hello.c文件中使用add这个函数功能。hello.c文件内容如下:
    #include <stdio.h>
    #include <head.h>
    #include <add.h>
    
    int returnMess(int val)
    {
            return val;
    }
    int main()
    {
            int a;
    #ifdef DEBUG
            printf("HelloWorld");
    #endif
            printf("%d\n",returnMess(100));
            printf("%d\n",add(50,50));
            return 0;
    }
    
    
    1. 然后呢我们根据之前学的gcc编译命令对hello.c进行编译如下:
    ##静态库在/home/xiaocer/练习/include下,hello.c在/home/xiaocer/练习/practice下
    ##静态库名为add
    [xiaocer@localhost practice]$ gcc hello.c -I ../include -o result.exe -L ../include -l add
    ##这样可以编译成result.exe可执行文件
    [xiaocer@localhost practice]$ ./result.exe
    ##运行成功表示制作静态库成功
    

4.动态库的制作

  1. Linux系统下动态库名一般是libxxx.so,而Windows下的动态库文件的后缀名是.dll.
  2. 制作步骤:
    1. 将需要制作成动态库的源文件编译成二进制文件,编译的时候需要加上选项-fPIC(position-independent code),这样的话编译成与位置无关的代码。
    2. 将后缀名为.o的二进制文件打包,打包时使用-share选项
  3. 示例:还是以之前的add.c为例:
    1. 共享库的制作
    ##将add.c文件编译成与位置无关的代码
    [xiaocer@localhost include]$ gcc add.c -c -fPIC -I ./
    ##将二进制文件打包成libadd.so动态库
    [xiaocer@localhost include]$ gcc add.o -shared -o libadd.so
    
    1. 那么客户如何使用这个共享库呢?像下面这样:[xiaocer@localhost practice]$ ./result.exe
      1. 会报错:./result.exe: error while loading shared libraries: libadd.so: cannot open shared object file: No such file or directory这样直接运行是不可行的,因为可执行文件在运行时系统找不到libadd.so这个共享库的路径。我们来查看result.exe会使用到的共享库
        [xiaocer@localhost practice]$ ldd result.exe
        
      2. 然后发现 libadd.so => not found
    2. 所以我们还要介绍如何让可执行文件运行时能够加载自定义的共享库成功,这里有很多种方法。方法如下:
      1. 方法1:将共享库路径添加到环境变量LD_LIBRARY_PATH中
      ##我们来先查看该环境变量的值,发现啥都没有
      [xiaocer@localhost include]$ echo $LD_LIBRARY_PATH
      ##设置该环境变量的值。为了后面设置的该环境变量的值不会影响原来的值,需要加上:$LD_LIBRARY_PATH
      [xiaocer@localhost include]$ export LD_LIBRARY_PATH=/home/xiaocer/练习/include/:$LD_LIBRARY_PATH
      
      ##这时ldd result.exe一下显示libadd.so found
      ##再运行result.exe成功
      [xiaocer@localhost include]$ ./result.exe
      
      1. 方法2.配置一下连接器相关的配置文件(/etc/ld.so.conf文件)
      ##打开/etc/ld.so.conf这个文件
      [xiaocer@localhost include]$sudo vim /etc/ld.so.conf
      ##然后将需要加载的共享库的路径添加进去
      ##然后运行下面这条命令使的编辑生效
      [xiaocer@localhost include]$ sudo ldconfig -v
      ##这是再ldd result.exe发现成功
      ##运行可执行文件成功
      

标签:gcc,动态,静态,add,##,xiaocer,共享,include,localhost
From: https://www.cnblogs.com/xiaocer/p/17026780.html

相关文章

  • Nginx配置访问(预览或者,下载)静态资源
    配置方式:在nginx.conf中加上此配置#搭建文件预览 location^~/preview/{autoindexon;alias/intell/image/;#不同OS键入对应path即可#下列配置用于直接下载......
  • 伪共享(False Sharing)
    【参考】https://zhuanlan.zhihu.com/p/55917869【cachememory】cpu和主存间存在三级缓存L1,L2(单核独享)L3(多核共享)【L1和L2如何保持一致】mesi协议定义cacheline......
  • 软件开发入门教程网 Search之C++ 动态内存
       C++基本的输入输出   ......
  • MySQL event事件,定时按年份动态创建表
    参考资料:1、MySQL事件(定时任务):https://blog.51cto.com/u_15549234/5138457;2、mysql创建存储过程语法(MySQL创建存储过程sql语句):https://www.gaojipro.com/a/108616;3、my......
  • 动态NAT
    注意:将外部的ip地址池映射到内部地址池第一步:创建地址池 nataddress-group120.1.1.1020.1.1.100第二步:感兴趣数据流aclnumber2001 rule5permitsource192.168......
  • Linux下动、静态库的创建和调用
    静态库linux静态库命名规则:静态库的创建准备工作:以一个简单的计算器demo为例,首先建立并书写以下三个文件:Math.h声明四则基本运算#ifndef__MATH_H__#define_......
  • linux动态库加载相关
    查看编译时会链接的动态库ldconfig-v|greplibCmp添加编译时的动态链接目录到终端环境,然后启动,这种方式可以为不同的程序配置不同的加载路径exportLD_LIBRARY_PA......
  • GCC链接库的一个坑:动态库存在却提示未定义动态库的函数
    背景在GCC中已经指定链接库,然而编译时却提示动态库函数未定义!测试出现的错误提示如下:  [GMPY@13:48tmp]$gcc-otest-L.-lmylibtest.c /tmp/ccys......
  • windons下查看并关闭共享
    win+R输入cmd输入netshare显示出关闭想关闭的共享,例如:netshareC$deletenetshareD$deletenetshareE$deleteC$为需要的关闭的共享盘符,自行替换红框部分即可关闭想......
  • 内部类(成员,静态,匿名,局部)
    在成员内部类也可以被一些权限修饰符修饰成员内部类的地位相当于成员变量:定义格式:修饰符 class 类名 {}jdk16以前成员内部类不能定义静态变量,jdk16以后可以获取......