您的位置:首页 > 编程语言 > C语言/C++

C++编译工作原理和编译时的动态库静态库

2014-03-15 18:23 645 查看

摘要

写这篇文章,主要是因为程序编译的时候遇到的两个问题,花费了半天功夫,其实了解Unix下C、C++程序编译运行原理,这两个问题自然迎刃而解。

内容

1. 问题描述
2. C、C++程序编译原理
3. C++动态库与静态库

1. 问题描述

/usr/bin/ld: warning: libdb2dascmn.so.1, needed by ./lib_third/linux/lib64/libdb2.so, not found (try using -rpath or -rpath-link)
/usr/bin/ld: warning: libdb2g11n.so.1, needed by ./lib_third/linux/lib64/libdb2.so, not found (try using -rpath or -rpath-link)
/usr/bin/ld: warning: libdb2genreg.so.1, needed by ./lib_third/linux/lib64/libdb2.so, not found (try using -rpath or -rpath-link)
/usr/bin/ld: warning: libdb2install.so.1, needed by ./lib_third/linux/lib64/libdb2.so, not found (try using -rpath or -rpath-link)
/usr/bin/ld: warning: libdb2locale.so.1, needed by ./lib_third/linux/lib64/libdb2.so, not found (try using -rpath or -rpath-link)
/usr/bin/ld: warning: libdb2osse.so.1, needed by ./lib_third/linux/lib64/libdb2.so, not found (try using -rpath or -rpath-link)
/usr/bin/ld: warning: libdb2osse_db2.so.1, needed by ./lib_third/linux/lib64/libdb2.so, not found (try using -rpath or -rpath-link)
/usr/bin/ld: warning: libdb2trcapi.so.1, needed by ./lib_third/linux/lib64/libdb2.so, not found (try using -rpath or -rpath-link)
/usr/bin/ld: warning: libstdc++.so.5, needed by ./lib_third/linux/lib64/libdb2.so, may conflict with libstdc++.so.6
./lib_third/linux/lib64/libdb2.so: undefined reference to `OSSDecimal64FromString(char const*)'
./lib_third/linux/lib64/libdb2.so: undefined reference to `OSSHLibrary::isLoaded()'
./lib_third/linux/lib64/libdb2.so: undefined reference to `OSS_DECIMAL64_NEG_SNAN'
./lib_third/linux/lib64/libdb2.so: undefined reference to `ossLogRC'
./lib_third/linux/lib64/libdb2.so: undefined reference to `sqlnlssplitcp2'
./lib_third/linux/lib64/libdb2.so: undefined reference to `sqlnlsFormatDate'
./lib_third/linux/lib64/libdb2.so: undefined reference to `OSSDecfloat::fromString(char const*, rounding)'
./lib_third/linux/lib64/libdb2.so: undefined reference to `dfpalInit(void*)'
./lib_third/linux/lib64/libdb2.so: undefined reference to `g_pGTCB'
./lib_third/linux/lib64/libdb2.so: undefined reference to `decimal64Minus(decimal64)'
./lib_third/linux/lib64/libdb2.so: undefined reference to `OSSHFile::read(OSSFileReadParam const*, void*, unsigned long*)'
./lib_third/linux/lib64/libdb2.so: undefined reference to `ossComputeMontgomeryInverse32'
./lib_third/linux/lib64/libdb2.so: undefined reference to `sqlnlsschr'
./lib_third/linux/lib64/libdb2.so: undefined reference to `sqloGetEnvLocale'
./lib_third/linux/lib64/libdb2.so: undefined reference to `decimal128FromNumber(decimal128*, decNumber const*, decContext*)'
./lib_third/linux/lib64/libdb2.so: undefined reference to `gtraceEnable'
./lib_third/linux/lib64/libdb2.so: undefined reference to `sqlnlsgetctryinfo'
./lib_third/linux/lib64/libdb2.so: undefined reference to `OSSHFile::sync()'
./lib_third/linux/lib64/libdb2.so: undefined reference to `OSSTrapFile::OSSTrapFile()'
./lib_third/linux/lib64/libdb2.so: undefined reference to `OSS_DECIMAL64_NAN'


其实这是一个很明显的错误,主要是因为我在有台服务器上编译没有报错,在另外一台服务器上拉下源码编译的时候就报错,两个环境的依赖的第三方库完全相同,Google 一下设置一下LD_LIBRARY_PATH就好了,当时觉得很奇怪,LD_LIBRARY_PATH不是代码运行时候调用动态库的时候需要设置的,为啥编译的也需要设置?还是自己对这个编译器工作原理的理解有偏差。
下面简单介绍下我对编译器工作原理的理解,有什么不对的地方,还希望大家指正。

2. C++编译器工作原理

百度百科上的解释:
编译器就是将“高级语言”翻译为“机器语言(低级语言)”的程序。一个现代编译器的主要工作流程:源代码(source
code) → 预处理器 (preprocessor)
→ 编译器 (compiler) → 汇编程序 (assembler)
→ 目标代码 (object
code) → 链接器 (Linker)
→ 可执行程序 (executables)。

源代码:
       这个就不解释了,就是自己写的程序,或者引用的其他库的头文件。
预处理器:
      C/C++提供的预处理功能主要有文件包含、宏替换、条件编译等。
编译器:
      编译器将源程序(Source program)作为输入,翻译产生使用目标语言(Target language)的等价程序。

汇编程序:
       把汇编语言书写的程序翻译成与之等价的机器语言程序的翻译程序。汇编程序输入的是用汇编语言书写的源程序,输出的是用机器语言表示的目标程序

目标代码

       指源代码经编译后,产生的能被 CPU直接识别的二进制代码
 链接器 :

 
      链接器(Linker)是一个程序,将一个或多个由编译器汇编器生成的目标文件外加库链接为一个可执行文件。这个要重点介绍下,链接又分静态链接和动态链接。
可执行程序:

 
     可执行程序就没啥好说的了,就是你在服务器或者自己点上可以直接执行的程序。

3.
UNIX 环境下C/C++动态库与静态库

 
     首先介绍下库的概念:

 
    什么是库?

 
    在我们的应用中,有一些公共代码是需要反复使用,就把这些代码编译为“库”文件;

 
    静态库

 
    在链接步骤中,连接器将从库文件取得所需的代码,复制到生成的可执行文件中。这种库称为静态库,其特点是可执行文件中包含了库代码的一份完整拷贝;缺点就是被多次使用就会有多份冗余拷贝。
 
    也就是说静态库其实已经复制了一份到我们程序中了,编译完成后程序就不需要依赖静态库了。如何生成静态库,一般是将目标文件.so文件通过ar工具打包,生成libxxx.a

 
  动态库

在Windows上是dynamic
link library (DLL),在UNIX或Linux上是Shared Library。

①链接阶段,即通过ld
创建执行程序时,链接编辑器会在指定的动态库中搜索、解析被主程序调用的函数及其他变量等,如引用被找到,则在执行程序的XCOFF 头结构的loader 区域,建立包含引用的动态库的影像,反之,如在指定的动态库中没有找到此引用的定义,编译器会给出类似未定义的符号引用错误。
---所以我编译的时候没有添加动态库路径导致报错。
②运行阶段,即执行程序运行时。程序运行时,系统相关模块将读取定义执行程序的XCOFF
头结构中的信息,查找并加载相关的动态库,假设,所有被应用的动态库都被定位且加载后,程序将开始运行。反之,如果,被应用的动态库丢失,则程序报错。这一个过程我们常称之为动态链接。

---所以,我们很多时候直接拷贝可执行程序,动态库有遗漏,或者丢失都会导致报错。
总之:动态库静态库各有优缺点。
静态库:编译的时候会将静态库复制到我们的程序中,程序运行的时候就不需要依赖静态库了,从而导致应用程序很大。
动态库:就比较灵活,编译的时候不需要将静态库代码复制到程序中,只是编译的时候建立一个动态库影像,程序运行的时候才将动态库加载到程序中。
动态库的好处就是,不同的程序可以依赖相同的动态库,只需要一个共享的动态库可以了。静态库链接时搜索路径顺序:
1.ld会去找GCC命令中的参数-L
2.再找gcc的环境变量LIBRARY_PATH
3.再找内定目录 /lib /usr/lib /usr/local/lib 这是当初compile gcc时写在程序内的
 
动态链接时、执行时搜索路径顺序:
1.编译目标代码时指定的动态库搜索路径;
2.环境变量LD_LIBRARY_PATH指定的动态库搜索路径,默认没有设置,需要自己手动设置;
3.配置文件/etc/ld.so.conf中指定的动态库搜索路径,需要执行 /sbin/ldconfig使之生效;
4.默认的动态库搜索路径/lib;
5.默认的动态库搜索路径/usr/lib。
Linux下,库文件一般放在/usr/lib /lib下,
如果安装在/lib或者/usr/lib下,那么ld默认能够找到,无需其他操作。
如果安装在其他目录,需要将其添加到/etc/ld.so.cache文件中,步骤如下
1.编辑/etc/ld.so.conf文件,加入库文件所在目录的路径
2.运行ldconfig,该命令会重建/etc/ld.so.cache文件

有关环境变量:

LIBRARY_PATH环境变量:指定程序静态链接库文件搜索路径

LD_LIBRARY_PATH环境变量:指定程序动态链接库文件搜索路径

参考文档:

百度百科

动态库与静态库的原理介绍
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: