精华内容
参与话题
问答
  • 无聊,遂准备写一篇博客,介绍一下C和C++运行,只因发现工作几年的人对此一知半解的大有人在。    在使用VC构建项目时,经常会遇到下面的链接错误:      初学者面对这些错误常常不知所错:...

    from :http://blog.csdn.net/ithzhang/article/details/20160009

     

    周五晚,小雨,少见的未加班。无聊,遂准备写一篇博客,介绍一下C和C++运行库,只因发现工作几年的人对此一知半解的大有人在。
      
      在使用VC构建项目时,经常会遇到下面的链接错误:
     

                       


      初学者面对这些错误常常不知所错:libcmt.lib是什么东西?msvcrtd.dll又是干吗用的?在使用VC++时我们也常常对下面的运行库配置项感到疑惑,它们到底究竟是什么意思呢?甚至一些工作了很多年的程序员也对此一知半解。今天让我们来了解一下它们。
        

    从C和C++运行库说起

      为了提高C语言的开发效率,C标准定义了一系列常用的函数,称为C库函数。C标准仅仅定义了函数原型,并没有提供实现。因此这个任务留给了各个支持C语言标准的编译器。每个编译器通常实现了标准C的超集,称为C运行时库(C Run Time Libray) ,简称CRT。对于VC++编译器来说,它提供的CRT库支持C标准定义的标准C函数,同时也有一些专门针对windows系统特别设计的函数。
      与C语言类似,C++也定义了自己的标准,同时提供相关支持库,我们把它称为C++运行时库或C++标准库。
      由于C++对C的兼容性,C++标准库包括了C标准库,除此之外还包括IO流和标准模板库STL。

    VC++在何处实现C和C++运行库

      VC++完美的支持C和C++标准,因此也就按照C和C++的标准定义的函数原型实现了上述运行时库。为了方便有不同需求的客户的使用,VC++分别实现了动态链接库DLL版本和静态库LIB版本。同时为了支持程序调试且不影响程序的性能,又分别提供了对应的调试版本。调试版本的名称在Release版本名称后添了字母d。

      对于C运行时库CRT,VC6.0、VC2005、VC2008和VC2010均提供了DLL版本和LIB版本。上述各个编译器提供的LIB版的CRT库,均实现在libcmt.lib。对应的调试版名称为libcmtd.lib。

      而DLL版本名称根据编译器不同而不同,我们可以从名称上加以分辨。
      VC6.使用的CRT库的DLL版本在MSVCRT.DLL中实现, 对应调试版本为MSVCRTD.LIB。
      VC2005使用的CRT库的DLL版本在MSVCR80.DLL中实现,对应调试版本为MSVCR80.DLL。
      VC2008使用的CRT库的DLL版本在MSVCR90.DLL中实现,对应调试版本为MSVCR90D.DLL。
      VC2010使用的CRT库的DLL版本在MSVCR100.DLL中实现,对应调试版本为MSVCR100D.DLL。

      C++标准兼容C标准,但VC各版本将C++编译器使用的C标准库与C编译器使用的C运行库一起实现,它们使用相同的运行库。

      对于C++标准库中的IO流和STL,VC6.0、VC2005、VC2008和VC2010也提供了DLL版本和LIB版本。
      LIB版均实现在libcpmt.lib中,对应的调试版本为libcpmtd.lib。

      不同版本的编译器实现的DLL也不相同。
      VC6.使用的C++类库的 DLL版本在MSVCP60.DLL中实现, 对应调试版本为MSVCP60D.LIB。
      VC2005使用的C++类库的DLL版本在MSVCP80.DLL中实现,对应调试版本为MSVCP80.DLL。
      VC2008使用的C++类库的 DLL版本在MSVCP90.DLL中实现,对应调试版本为MSVCP90D.DLL。
      VC2010使用的C++类库的DLL版本在MSVCP100.DLL中实现,对应调试版本为MSVCP100D.DLL。

      在各个版本的编译器中,我们可以通过配置选项来设置程序使用的C和C++运行时库的类型。如下图(其他版本编译器大同小异):
      
       
      MT选项:链接LIB版的C和C++运行库。在链接时就会在将C和C++运行时库集成到程序中成为程序中的代码,程序体积会变大。
      MTd选项:LIB的调试版。
      MD选项:使用DLL版的C和C++运行库,这样在程序运行时会动态的加载对应的DLL,程序体积会减小,缺点是在系统没有对应DLL时程序无法运行。
      MDd选项:表示使用DLL的调试版。
      在《由使用LeakDialog时遇到的问题而引出的一些分析》这篇文章中的实验一,使用VC6.0的默认配置没有拦截到内存泄露。其原因是VC6.0的控制台项目默认配置是静态链接CRT库(单线程版,后面会介绍)。

    动态版(DLL)和静态版(LIB)C和C++运行库的优缺点

      因为静态版必须把C和C++运行库复制到目标程序中,所以产生的可执行文件会比较大。同时对于使用多个模块的大型软件来说,如果每个模块均选择静态链接C或C++运行库,在程序运行时就会存在多个运行库。在链接时也会出现重复定义的问题,如文章首第一张图所示。
      使用DLL版的C和C++运行库,程序在运行时动态的加载对应的DLL。程序体积变小,但一个很大的问题就是一旦找不到对应DLL,程序将无法运行。假设使用VC6.0并选择使用MD选项构建,那么当用户使用VC2005来使用这个DLL时很可能出现找不到MSVCRT.DLL或MSVCP60.DLL的情况。

      在这里介绍一个很好的工具:Dependency Walker,可以用来分析DLL的依赖关系,同时查看DLL导出的函数,使用方法请Google。
      使用该工具打开MSVCRT.DLL,如下图:
       
      我们可以在其中找到我们经常使用使用的C函数,如printf ,getchar,malloc等。
      打开MSVCP100.DLL,也可以找到这些C函数:

        
      在开发的过程中我们也会遇到如下图的链接错误,LIBCD.lib究竟是何方神圣呢?

                             
      它其实是LIBC.lib的调试版,而LIBC.lib是只有在VC6.0才会使用的静态库,该库是CRT的单线程版,用于支持单线程版本的CRT。VC2005等更高版本的编译器已经不再提供单线程版本,转而使用多线程版的MSVCR80.DLL或libcmt.lib。

      当遇到上述符号定义冲突的链接错误时,可以选择忽略libcd.lib。

    展开全文
  • 静态库编译和使用

    2020-06-21 18:46:24
    静态库是在程序编译时直接将静态库编译进去,运行时不再需要将库的符号内容加载到内存,编译出来的程序占用空间也会变大。如果静态库修改了,就需要重新编译调用库的程序。 编译的话,直接就使用上次的代码进行编译...

    上次简单写了个动态库的示例,详情见https://blog.csdn.net/weixin_34153142/article/details/106458435
    今天讲一下静态库的编译和使用吧。
    静态库是在程序编译时直接将静态库编译进去,运行时不再需要将库的符号内容加载到内存,编译出来的程序占用空间也会变大。如果静态库修改了,就需要重新编译调用库的程序。
    编译的话,直接就使用上次的代码进行编译:

    gcc -c test_lib.c -o test_lib.o
    ar crv libtest.a test_lib.o
    可以用nm查看静态库中的符号表:
    在这里插入图片描述
    正是我们之前写的两个接口。这样就可以编译出静态库了。
    怎么使用,我用一个github上的一个crc的库来进行简单的说明。
    源码地址 https://github.com/lammertb/libcrc
    下载直接make就可以编译出静态库以及代码中的一个测试文件,这里我们重新写。编译过程以及中间详细信息如下:
    在这里插入图片描述
    静态库符号表和头文件的内容差不多,这里不展示。直接将静态库和头文件拷贝到我们自己的代码路径下。创建test.c文件

    #include <stdio.h>
    #include "checksum.h"
    
    int main(int argc, char **argv)
    {
        FILE *fp = NULL;
        unsigned char prev_byte;
        unsigned int crc_32_val = 0;
        int ch;
    
        if (argc != 2) {
            printf("USAGE: ./file_crc file_name\n");
            return -1;
        }
        
        fp = fopen( argv[1], "rb" );
        if (NULL == fp) {
            printf("open file %s fail\n", argv[1]);
            return -1;
        }
        
        while( ( ch=fgetc( fp ) ) != EOF ) {
            crc_32_val = update_crc_32(crc_32_val, (unsigned char)ch);
    
            prev_byte = (unsigned char) ch;
        }
        
        printf("file %s crc = %u\n", argv[1], crc_32_val);
        
        fclose(fp);
        fp = NULL;
        
        return 0;
    }
    

    编译:

    gcc test.c -I . -L . -lcrc
    

    因为测试代码中写的是计算文件的crc,所以我们在代码目录下创建一个测试文件出来。
    在这里插入图片描述
    执行一下看看。
    在这里插入图片描述
    可以看出,当文件改变时,文件的crc校验值是改变的,同时我们静态库的使用也测试完成。
    在这里插入图片描述
    我们看下这几个文件,几行代码编译出的可执行文件a.out大小居然又11K字节,那是因为编译过程直接将crc的库包含进去了,所以文件占用会变大。
    我之前的测试库,因为体积太小,动态库和静态库编译出的可执行文件基本没差。后续大伙可能在交叉开发中,遇到这种情况,考虑裁剪flash的时候,可以综合考虑两种编译方式,再决定最终是使用动态库或静态库。

    展开全文
  • Linux-C动态库与静态库编译与调用

    万次阅读 多人点赞 2018-07-25 16:44:24
    Linux-C动态库与静态库编译与调用 一、简述 记录-Linux-C动态库与静态库编译与调用。将实现某部分功能的代码封装成库文件,以方便调用,或者是对代码进行保护加密。应用场景:有时想将某代码提供给别人用,...

    Linux-C动态库与静态库的编译与调用

    一、简述

              记录-Linux-C动态库与静态库的编译与调用。将实现某部分功能的代码封装成库文件,以方便调用,或者是对代码进行保护加密。应用场景:有时想将某代码提供给别人用,但是又不想公开源代码,这时可以将代码封装成库文件。在开发中调用其他人员编写的库。

          动态库特点:
            1,库的代码不会编译进程序里面,所以动态库编译的程序比较小。
            2,由动态库编译的程序依赖于系统的环境变量有没有这个库文件,没有则运行不了。

         静态库特点:
            1,库的代码会编译进程序里面,所以静态库编译的程序比较大
            2,由静态库编译的程序不用依赖于系统的环境变量,所以环境变量有没有这个库文件,也可以运行。

     

    二、动态库的编译与调用

           1、创建目录:mkdir dynamic;进入dynamic目录:cd dynamic;新建c文件:vi func.c

                   

           2、编辑func.c内容如下,(记得保存)

                  

           3、 将func.c编译为动态库,编译命令:

                gcc func.c -o func.o -c -fPIC
                gcc func.o -shared -o libfunc.so               (注其中libfunc.so,lib为前缀,.so是后缀,中间func是库的名字)

                   

           4、 在dynamic路径下新建main.c文件:vi main.c;在main.c中调用动态库中的func()函数。

                  

           5、    因为fun.c与main.c在同一路径,避免干扰,删除fun.c,func.o文件;命令:rm func.c func.o

                 

          6、    编译main.c并调用动态库libfunc.so。命令:gcc main.c -o main -L 库的路径 -l 库名    

                  gcc main.c -o main -L . -l func            (点代表当前路径)

                 

          7、   执行main,找不到库

                  

           8、 需要将动态库拷贝一份到/usr/lib/路径下,命令:sudo cp libfunc.so /usr/lib     (需要超级权限);执行:./main

                  

    三、静态库的编译与调用

            1、创建目录:mkdir static;进入static目录:cd static;新建c文件:vi func.c

                  

            2、编辑func.c内容如下,(记得保存)      

                  

         3、 将func.c编译为静库,编译命令:

                gcc func.c -o func.o -c 
                ar -crv libfunc.a func.o               (注lib为前缀,静态库以.a为后缀,中间部分func为库的名字)

                

         4、 在static路径下新建main.c文件:vi main.c;在main.c中调用静态库中的func()函数。

                

         5、    因为fun.c与main.c在同一路径,避免干扰,删除fun.c,func.o文件;命令:rm func.c func.o

               

         6、 编译main.c并调用静态库libfunc.so。命令:gcc main.c -o main -L 库的路径 -l 库名    

                gcc main.c -o main -L . -l func            (点代表当前路径)

              

         7、执行:./main          (不需要将静态库拷贝到/usr/lib/)

              

       四、静态编译

            我们通常用的是动态编译,比如说调用标准库的printf()函数,printf()的代码不会直接全部的编译到可执行文件,而是相当于在可执行程序中链接调用printf()函数。这样可执行文件的大小就不会很大,但是可执行程序的运行环境必需要含有其所需要的库文件等。静态编译,就是将程序所调用到的代码全部编译到可执行文件,所以编译出来的可执行文件比较大,但是它无需过多依赖运行环境。

            比如在桌面创建hello.c;命令:vi hello.c 。编辑内容如图

            

            动态编译:gcc hello.c -o hello_dynamic          静态编译:gcc hello.c -o hello_static -static

           

     

    =====================以下回复 star火 =================

    在CentOS6.9测试的效果。尝试设置export LD_LIBRARY_PATH=/yourlibpath/:$LD_LIBRARY_PATH

    其中yourlibpath是libfunc.so的存放路径。

    展开全文
  • Linux基础——gcc编译静态库与动态库(共享库)

    万次阅读 多人点赞 2018-07-03 17:44:34
    gcc编译器 1、gcc工作流程 2、gcc常用参数 参数 ... 编译时定义宏 -00/-01/-03 没有优化/缺省值/优化级别最高 -Wall 提示更多警告信息 -c 只编译子程序 -E 生成预处理文件 ...

    gcc编译器

    1、gcc工作流程
    这里写图片描述
    2、gcc常用参数

    参数 用途
    -v 查看版本
    -o 产生目标文件
    -I+目录 指定头文件目录
    -D 编译时定义宏
    -00/-01/-03 没有优化/缺省值/优化级别最高
    -Wall 提示更多警告信息
    -c 只编译子程序
    -E 生成预处理文件
    -g 包含调试信息

    静态库

    1、静态库的命名格式
    lib + 库的名字 + .a
    例:libMyTest.a (MyTest为静态库的名字)

    2、静态库作用分析
    在项目开发过程中,经常出现优秀代码重用现象,又或者提供给第三方功能模块却又不想让其看到源代码,这些时候,通常的做法是将代码封装成库或者框架,生成的静态库要和头文件同时发布。

    优点:

    • 寻址方便,速度快
    • 库在链接时被打包到可执行文件中,直接发布可执行程序即可以使用

    缺点:

    • 静态库的代码被加载到可执行程序中,因此体积过大
    • 如果静态库的函数发生改变,必须重新编译可执行程序

    3、静态库的制作与使用
    这里写图片描述

    测试代码的目录结构如上图所示,include中存放的是头文件,lib中存放的是静态(动态)库,src中存放的是源代码,main.c是发布代码。

    第一步:得到*.o文件

    gcc *.c -c -I../include

    这里写图片描述

    第二步:创建静态库

    ar rcs libMyTest.a *.o        将所有.o文件打包为静态库,r将文件插入静态库中,c创建静态库,不管库是否存在,s写入一个目标文件索引到库中,或者更新一个存在的目标文件索引。
    mv libMyTest.a ../lib         将静态库文件放置lib文件夹下
    nm libMyTest.a                查看库中包含的函数等信息

    这里写图片描述

    第三步:使用静态库

    第一种方法:
    gcc + 源文件 + -L 静态库路径 + -l静态库名 + -I头文件目录 + -o 可执行文件名
    gcc main.c -L lib -l MyTest -I include -o app
    ./app
    
    第二种方法:
    gcc + 源文件 + -I头文件 + libxxx.a + -o 可执行文件名
    gcc main.c -I include lib/libMyTest.a -o app

    动态库(共享库)

    1、动态库的命名格式
    lib + 库的名字 + .so
    例:libMyTest.so (MyTest为动态库的名字)

    2、动态库作用分析
    共享库的代码是在可执行程序运行时才载入内存的,在编译过程中仅简单的引用,因此代码体积较小。

    优点:

    • 节省内存
    • 易于更新,不用重新编译可执行程序,运行时自动加载

    缺点:

    • 延时绑定,速度略慢

    3、动态库的制作与使用

    测试代码的目录结构与静态库相同。

    第一步:生成与位置无关的.o文件

    gcc -fPIC *.c -I ../include -c   参数-fPIC表示生成与位置无关代码

    这里写图片描述

    第二步:创建动态库

    gcc -shared -o libMyTest.so *.o        参数:-shared 制作动态库 -o:重命名生成的新文件
    mv libMyTest.so ../lib
    

    这里写图片描述

    第三步:使用动态库

    第一种方法:
    gcc + 源文件 + -L 动态库路径 + -l动态库名 + -I头文件目录 + -o 可执行文件名
    gcc main.c -L lib -l MyTest -I include -o app
    ./app
    (执行失败,找不到链接库,没有给动态链接器(ld-linux.so.2)指定好动态库 libmytest.so 的路径)
    
    第二种方法:
    gcc + 源文件 + -I头文件 + libxxx.so + -o 可执行文件名
    gcc main.c -I include lib/libMyTest.so -o app
    (执行成功,已经指明了动态库的路径)

    如何解决第一种方法中找不到链接库的问题

    使用命令ldd app可以查看当前的链接库情况
    
    第一种方法:
    export LD_LIBRARY_PATH=自定义动态库的路径
    (只能起到临时作用,关闭终端后失效)
    LD_LIBRARY_PATH : 指定查找共享库(动态链接库)时除了默认路径之外的其他路径,该路径在默认路径之前查找
    
    第二种方法:
    将上述命令写入home目录下的.bashrc文件中,保存后重启终端生效(永久)
    
    第三种方法:
    直接将动态库拷贝到user/lib的系统目录下(强烈不推荐!!)
    
    第四种方法:
    将libmytest.so所在绝对路径追加入到/etc/ld.so.conf文件,使用sudo ldconfig -v 更新
    展开全文
  • 静态库编译连接实例

    千次阅读 2017-10-30 16:59:48
    那么此时可以将B源码编译成指定的lib的方式,这里指的的 xxx.a的方式,而不是xxx.so的方式。那么在A调用B接口的时候,直接在编译选项中增加 -L参数指定需要的.a文件即可。那么在A中就能直接通过包含的B的头文件...
  • 编译.a静态库

    千次阅读 2015-11-09 15:07:39
    1.什么是?  是程序代码的集合,是共享程序代码的一种方式   2.的分类  根据源代码的公开情况,可以分为2种类型  (1)开源  公开源代码,能看到具体实现  比如SDWebImage、...
  • so动态库和a静态库编译

    千次阅读 2018-06-09 11:32:39
    一般linux环境下的链接分为a和so,分别表示静态链接和动态链接,其作用是把C程序编译好做成一种可执行链接文件,c主程序文件调用这些程序的函数接口是可以使用a或so,在主程序中只需要include含有中...
  • linux 下静态库编译与使用

    千次阅读 2018-01-25 11:23:07
    静态库的后缀是.a,它的产生分两步 : 1、由源文件编译生成一堆.o,每个.o里都包含这个编译单元的符号表 2、ar命令将很多.o转换成.a,成为静态库 编译 进入源码lib目录 (蓝色为链接文件) 步骤: 1、...
  • 使用JNI技术时,需要将第三方提供的静态库编译成动态库,在编译过程中遇到问题,使用gcc进行编译链接: gcc -I/home/jichenxiao/java/jdk1.8.0_11/include -I/home/jichenxiao/java/jdk1.8.0_11/include/linux -...
  • 静态库编译到动态库中

    千次阅读 2019-07-12 13:42:12
    最近做一个东西,需要采集硬件设备的音视频数据,然后做编码。以前做过编码部分直接拽过来使用,只写硬件采集部分即可。...编码部分使用ffmpeg4的动态,链接位置自己指定 将硬件采集代码设计为...
  • 将代码及依赖的静态库编译为新静态库最近需要在一个开源库上实现一个新功能并封成新的lib。方法: 将代码编译为.o 使用ar -x 将依赖的静态库拆成.o 使用ar -rcs 将.o编译生成新的.a 一些参数设置AR:=...
  • boost静态库编译方法

    千次阅读 2018-05-04 09:06:22
    1. 解压最新的boost代码2. 在命令行窗口中执行bootstrap.bat等待生成b2.exe3. 运行b2.exe stage --toolset=msvc --stagedir="D:\boost\out\bin" link=static threading=multi runtime-link=static --...
  • protobuf静态库编译

    千次阅读 2018-08-28 09:56:43
    1.解压protobuf包 tar -zxvf protobuf-2.4.1.tar.gz 2.进入解压目录,开始编译  (1)./configure --disable-shared --prefix=/usr ... 备注:64位的so使用protobuf-lite.a必须加-fPIC编译选项,否则编译报错 ...
  • Linux中C/C++动态库、静态库编译

    千次阅读 2017-06-11 10:51:38
    gcc helloworld.cpp -lstdc++ 或 g++ helloworld.cpp http://blog.csdn.net/dumgeewang/article/details/7403084/ http://www.cnblogs.com/dadawei/p/5368380.html http://www.jb51.net/article/37409.ht
  • Linux下静态库编译

    千次阅读 2013-10-11 12:04:41
    Linux下动态库文件的扩展名为".so"(Shared Object...静态库的文件名形式是libname.a。共享archive的文件名形式是libname.sa。共享archive只是一种过渡形式,帮助人们从静态库转变到动态库。  本文仅以简单的例子介
  • 使用ar命令合并两个静态库 ar.mac内容 CREATE libcombine.a ADDLIB libone.a ADDLIB libtwo.a SAVE END 执行如下命令 $ ar -M &lt; ar.mac 或者使用 如下脚本 $ printf \"create libcombine.a\\...
  • linux静态库 .a 注意命名必须为libXXX.a,不能随便起名字 其编译方法为: 静态库:  g++ -c 2.cpp  ar -cr libmy2.a 2.o  g++ -o main 1.cpp -L. -lmy2 (与动态链接方法一样) 动态库:  
  •  按AIT+F7,在打开界面里选静态库就可以(我在VC6常用的方法)
  • 静态库编译和连接遇到的奇怪问题

    千次阅读 2014-11-01 17:18:06
    编译静态库(lib)时,遇到过的三种问题: 1, 如果没有正确包含lib文件的路径,会提示无法打开静态库。 2, error LNK 2001: 有可能是路径问题,或者是头文件与lib库不对应,或者是lib文件有问题。 3, error...
  • 如果有源码的话,可以直接跟你自己的代码一去编译成动态库so,但是如果没有源码的话,你就必须在自己的动态库so里面将别人生成好的静态库导入进来一起编译了。我在编译的时候遇到了不少问题,我觉得有必要进行总结...

空空如也

1 2 3 4 5 ... 20
收藏数 293,949
精华内容 117,579
关键字:

静态库编译