现在的位置: 首页 > 综合 > 正文

开始尝试google test单元测试工具(又是MTd/MDd搞的鬼!)附带VC运行库详解

2012年06月30日 ⁄ 综合 ⁄ 共 2581字 ⁄ 字号 评论关闭

 

今天试了一下google test,环境是VS2008.

下载gtest 1.30,分别在debugrelease模式下编译gtest-1.3.0\msvc下的项目文件。项目目录中debug文件夹下和release文件下分别生成debug版本的gtest静态库(gtestd.lib)和release版本的gtest静态库(gtest.lib).

 

接着新建测试demo项目。建立win32 console项目,在项目属性中设置附加include目录为gtest-1.3.0\include, 根据编译环境是debugrelease添加对应的附加依赖项gtestd.libgtest.lib。设置附加库路径为对应的lib路径。

 

写好测试程序后编译工程,结果出现了很多“无法解析的外部符号”类型的错误。但是lib都已经添加了呀?!

 

错误原因: 编译测试程序时,项目属性/C++/代码生成/选项中,C++的运行库设置与编译gtest库时的运行库设置不同。

 

在编译gtest库时项目设置中运行库设置成了“多线程调试(/MTd)”,而VS2008默认项目设置是“多线程调试 DLL (/MDd)”,导致很多函数符号无法解析。

 

解决:修改运行库设置,运行库必须与生成gtest.lib的运行库设置相同。

 

PS 之前编译毕设程序总是通不过 估计也是这个原因。。

 

//*********************************

使用第三方的库容易造成LNK2005错误――重复定义错误,一般是第三方库的链接方式与现工程不一致造成的,如第三方库采用静态链接,而现工程采用动态链接,或者第三方库用单线程,而现工程采用多线程都会引发此错误。

 

MSDN上的参考文章:

http://msdn.microsoft.com/en-us/library/aa278396(VS.60).aspx

 

//********************************

转载一篇文章:

http://tech.ccidnet.com/art/1081/20060310/474235_1.html

 

 

许多Visual C++的使用者都碰到过LNK2005:symbol already definedLNK1169:one or more multiply defined symbols found这样的链接错误,而且通常是在使用第三方库时遇到的。对于这个问题,有的朋友可能不知其然,而有的朋友可能知其然却不知其所以然,那么本文就试图为大家彻底解开关于它的种种疑惑。

 

    大家都知道,从C/C++源程序到可执行文件要经历两个阶段:(1)编译器将源文件编译成汇编代码,然后由汇编器(assembler)翻译成机器指令(再加上其它相关信息)后输出到一个个目标文件(object file,VC的编译器编译出的目标文件默认的后缀名是.obj)中;(2)链接器(linker)将一个个的目标文件(或许还会有若干程序库)链接在一起生成一个完整的可执行文件。

 

    编译器编译源文件时会把源文件的全局符号(global symbol)分成强(strong)和弱(weak)两类传给汇编器,而随后汇编器则将强弱信息编码并保存在目标文件的符号表中。那么何谓强弱呢?编译器认为函数与初始化了的全局变量都是强符号,而未初始化的全局变量则成了弱符号。比如有这么个源文件:

 

extern int errorno;

int buf[2] = {1,2};

int *p;

 

int main()

{

   return 0;

}

 

其中mainbuf是强符号,p是弱符号,而errorno则非强非弱,因为它只是个外部变量的使用声明。

 

    有了强弱符号的概念,我们就可以看看链接器是如何处理与选择被多次定义过的全局符号:

 

规则1: 不允许强符号被多次定义(即不同的目标文件中不能有同名的强符号)

 

 

规则2: 如果一个符号在某个目标文件中是强符号,在其它文件中都是弱符号,那么选择强符号;

 

 

规则3: 如果一个符号在所有目标文件中都是弱符号,那么选择其中任意一个;

 

 

由上可知多个目标文件不能重复定义同名的函数与初始化了的全局变量,否则必然导致LNK2005LNK1169两种链接错误。可是,有的时候我们并没有在自己的程序中发现这样的重定义现象,却也遇到了此种链接错误,这又是何解?嗯,问题稍微有点儿复杂,容我慢慢道来。

 

 

    众所周知,ANSI C/C++ 定义了相当多的标准函数,而它们又分布在许多不同的目标文件中,如果直接以目标文件的形式提供给程序员使用的话,就需要他们确切地知道哪个函数存在于哪个目标文件中,并且在链接时显式地指定目标文件名才能成功地生成可执行文件,显然这是一个巨大的负担。所以C语言提供了一种将多个目标文件打包成一个文件的机制,这就是静态程序库(static library)。开发者在链接时只需指定程序库的文件名,链接器就会自动到程序库中寻找那些应用程序确实用到的目标模块,并把(且只把)它们从库中拷贝出来参与构建可执行文件。几乎所有的C/C++开发系统都会把标准函数打包成标准库提供给开发者使用(有不这么做的吗?)

 

    程序库为开发者带来了方便,但同时也是某些混乱的根源。我们来看看链接器是如何解析(resolve)对程序库的引用的。

   

在符号解析(symbol resolution)阶段,链接器按照所有目标文件和库文件出现在命令行中的顺序从左至右依次扫描它们,在此期间它要维护若干个集合:(1)集合E是将被合并到一起组成可执行文件的所有目标文件集合;(2)集合U是未解析符号(unresolved symbols,比如已经被引用但是还未被定义的符号)的集合;(3)集合D是所有之前已被加入到E的目标文件定义的符号集合。一开始,EUD都是空的。

 

(1): 对命令行中的每一个输入文件f,链接器确定它是目标文件还是库文件,如果它是目标文件,就把f加入到E,并把f中未解析的符号和已定义的符号分别加入到UD集合中,然后处理下一个输入文件。

 

(2): 如果f是一个库文件,链接器会尝试把U中的所有未解析符号与f中各目标模块定义的符号进行匹配。如果某个目标模块m定义了一个U中的未解析符号,那么就把m加入到E中,并把m中未解析的符号和已定义的符号分别加入到U

抱歉!评论已关闭.