zoukankan      html  css  js  c++  java
  • 22、【C++基础】静态库和动态库

    一、C/C++编程中相关文件后缀(以Linux系统下为例):

    1 .a:              静态库(archive)
    2 .c/.cpp:        C/C++源程序
    3 .h/.hpp:        C/C++源程序的头文件
    4 .i:              经过预处理后的C/C++源程序
    5 .o:             对象文件
    6 .s:             汇编语言代码
    7 .so:            动态链接库

      本质上来说库是一种可执行代码的二进制形式,可以被操作系统载入内存运行。

    库有两种:

      静态库(Linux操作系统下是以.a做后缀,Windows操作系统下以.lib做后缀)

      动态库(Linux操作系统下是以.so做后缀,Windows操作系统下以.dll做后缀)。

    静态库是编译器生成的.o对象文件的集合,静态库另外一个名字叫归档文件(archive),管理这种归档文件的工具叫ar.

    常用的编译命令(命令行编译C源程序使用gcc,编译C++源程序使用g++,此处以g++编译C++源程序为例):

    假设需要编译的源程序有hello.cpp和world.cpp,则

    1 $g++ -Wall hello.cpp 

      这是最简单的编译命令,-Wall是 warn all的缩写,即显示在编译过程中的所有警告信息。编译器编译源代码文件生成对象文件.o, 链接对象文件得到可执行文件,并删除对象文件。由于此处未指定可执行程序的文件名,编译器默认输出a.out

    1 $g++ -Wall hello.cpp -o hello                    //此处使用-o指定输出的可执行文件的名字,-o代表output。
    2 $g++ -c -Wall hello.cpp -o hello                 //选项-c 表示compile, 指示编译器只完成编译过程生成对象文件,不执行链接过程。
    3 $g++ -c -Wall hello.cpp world.cpp                //此命令可以一次性生成多个对象文件
    4 $g++ -c -Wall hello.cpp world.cpp -o hello       //此命令将两个源文件分别编译为对象文件且将其链接为可执行文件hello
    5 $g++ -E hello.cpp -o hello.i                     //选项-E这是编译器只进行预编译处理
    6 $g++ -S hello.cpp -o hello.s                     //此命令生成汇编代码

    二、Linux环境下创建并使用静态库:

      要创建一个静态库,首先要编译出库中需要的对象文件,则:

    1 $g++ -c -Wall hello.cpp world.cpp

      指令ar配合参数-crv可以创建一个新库并将之前创建好的对象文件插入。如果库不存在,则参数-r将创建一个新库,并将对象模块添加到归档文件中。下面的命令将创建一个包含上述两个对象文件的名为libhelloworld.a的静态库:

    1 $ar -crv libhelloworld.a hello.o world.o  // 比较大的项目会编写makefile文件来生成静态库。

      Linux静态库命名规范,必须是lib[your_library_name].a,其中lib为前缀,中间是静态库名,扩展名为.a

       Linux下使用静态库,只需要在编译的时候,指定静态库的搜索路径(-L选项),指定静态库名(不需要lib前缀和.a后缀,-l选项),假设打包生成的libhelloworld.a静态库放在../StatiLibrary目录下,则:

    1 $g++ testStaticLibrary.cpp -L ../StaticLibrary -l helloworld  //编译生成可执行文件

    三、Linux环境下创建并使用动态库:

      为什么要使用动态库?

         1.使用静态库会造成空间浪费。

         2. 静态库对程序的更新,部署和发布带来麻烦,如果静态库libhelloworld.a更新了,所有使用它的应用程序都需要重新编译,发布给用户。

      动态库在程序编译时并不会被链接到目标文件中,而是在程序运行时才被载入。不同的应用程序如果调用相同的库,那么在内存里只需要一份该共享库的实例,规避了空间浪费问题。

      动态链接库的命名形式为 lib[your_library_name].so ,前缀是lib,后缀是.so。在文件系统中,your_library_name仅是一个链接到实际动态库的链接。对于动态库而言,每个库实际上都有另一个名字给编译器使用,它是一个指向库镜像文件的链接文件lib[your_library_name].so

      创建动态库的过程中,首先生成目标文件,此时要加编译器选项-fPIC

    1 $g++ -fPIC -c hello.cpp world.cpp

      -fPIC创建与地址无关的编译程序(pic:position independent code),是为了能够在多个应该程序间共享。

        生成动态库,此时要加链接器选项-shared

    1 $g++ -shared -o libhelloworld.so hello.o world.o

      引用动态库编译成可行文件(跟静态库文件一样):

    1 $g++ testStaticLibrary.cpp -L ../StaticLibrary -l helloworld

    发现报错了!!!那么,在执行的时候是如何定位共享库文件的呢?

      当系统加载可执行代码时候,能够知道其所依赖的库的名字,但是还需要知道绝对路径。此时就需要系统动态载入器(dynamic linker/loader)

      对于elf格式的可执行程序,是由ld-linux.so*来完成的,它先后搜索elf文件的 DT_RPATH段—环境变量LD_LIBRARY_PATH/etc/ld.so.cache文件列表—/lib/,/usr/lib 目录找到库文件后将其载入内存。

    如何让系统能够找到它:

      如果安装在/lib或者/usr/lib下,那么ld默认能够找到,无需其他操作。

      如果安装在其他目录,需要将其添加到/etc/ld.so.cache文件中,步骤如下:

        编辑/etc/ld.so.conf文件,加入库文件所在目录的路径

        运行ldconfig ,该命令会重建/etc/ld.so.cache文件

    通常情况下,我们将创建的动态库复制到/usr/lib下面,然后运行测试程序。

  • 相关阅读:
    hadoop系列二:HDFS文件系统的命令及JAVA客户端API
    hadoop系列一:hadoop集群安装
    解决tomcat下面部署多个项目log4j的日志输出会集中输出到一个项目中的问题
    HandlerMethodArgumentResolver数据绑定无效
    MyBatis 元素类型为 "configuration" 的内容必须匹配 ".....
    jquery.uploadify 异常 “__flash__removeCallback”未定义
    fusioncharts图例(legend)属性
    Flex Error #2156问题
    HTML注释引起的问题
    Asp.net Mvc4 使用Cas单点登录
  • 原文地址:https://www.cnblogs.com/Long-w/p/9629190.html
Copyright © 2011-2022 走看看