2014-09-11 108 views
4

Google test documentation解释了gtest必须与项目一起编译,而不是使用标准的lib和headers方法。他们解释说使用lib可能会与“一个定义规则”相冲突。我发现这个解释奇怪,因为这是你如何使用任何其他库,它们不会与“一个定义规则”冲突。为什么使用项目编译gtest而不是使用lib

+0

你需要澄清你的意思是“项目”,因为这不是C++术语。 – juanchopanza 2014-09-11 07:53:53

回答

0

C++编译器生成的二进制代码可能因标志,OS位的不同而不同,不同的编译器可以用相同的标志产生不同的输出(例如g ++ vs clang ++)。该标准规定了结果行为,但没有详细说明每个装配细节。

但这不是最坏的情况。寻找一个例子:

SomeHeader.h

#ifdef MY_W_CHAR_T 
#define my_char_t unsigned long 
#else 
#define my_char_t char 
#endif 

struct letter 
{ 
my_char_t msg[255]; 
} 

现在,你可以有多个“项目”(也可能是像VS项目),并在每个可SomeHeader.h。并且说,除了一个定义MY_W_CHAR_T。在每个项目中,您都有字母的定义,但在一个项目中它有所不同。编译器不会将有关结构大小的信息添加到其ID中。它可能会编译,但在大多数情况下行为是不确定的。如果您将在一个项目中分配内存(letter * pLetter =新字母)并在另一个项目中释放内存(其定义不同),则会发生堆损坏错误。

这当然是可能发生的一种可能性。

你提到了其他图书馆。 VS可能是windows的dll/lib? (在linux上你可以在大多数时候编译源码)。请注意,它们始终是为特定的工具集实例提供的。这是因为这个原因。同样在Windows上,分享二进制代码就不像linux那么复杂。

+1

在Linux上,我不编译所有源码。当我使用standartd C++库Qt构建项目时,无论我使用/ usr/lib中的lib还是/ usr/include中的头文件。 – Trismegistos 2014-09-11 08:46:03

+0

问题依然存在,为什么其他图书馆在谷歌测试工程师的工作中不注意这些事情? – Trismegistos 2014-09-11 09:02:01

0

我认为谷歌的文档很好地解释了:

每个用户需要编译使用用于编译安装的谷歌测试库相同的编译器标志 他的测试;否则他可能会 遇到未定义的行为 为什么?因为C++有这个东西,所谓的一个定义规则:如果两个C++源文件包含相同的 class/function/variable的不同定义,并且将它们链接在一起,则违反了 规则。

一个简单的(但不准确)例如:

// Dynamic1.h

int GetInt(); 

// Dynamic1.cpp

static int i = 1; 
int GetInt() 
{ 
    return i; 
} 

// Dynamic2.h

int GetInt(); 

// Dynamic2。CPP

static int i = 2; 
int GetInt() 
{ 
    return i; 
} 

// main.cpp中

#include "dynamic1.h" 
#include "dynamic2.h" 
#include <cstdio> 
int main() 
{ 
    ::printf("GetInt returns %d\n", GetInt()); 
    return 0; 
} 

什么是GetInt()预期的结果?这取决于你如何编译和链接代码或链接顺序。

//编译所以

g++ -g -Wall -Wextra -fPIC -shared -o libdynamic1.so dynamic1.cpp 
g++ -g -Wall -Wextra -fPIC -shared -o libdynamic2.so dynamic2.cpp 

//生成主

g++ -o main main.cpp -L. -ldynamic1 -ldynamic2 
// GetInt returns 1 

g++ -o main main.cpp -L. -ldynamic2 -ldynamic1 
// GetInt returns 2 

g++ -o main main.cpp dynamic1.cpp dynamic2.cpp 
// multiple definition of `GetInt()' 

注的主要输出是由不同的链接命令不同。如果您将所有文件一起编译,链接器可以捕获错误。

如果您只是将Gtest作为库链接,您可能会得到相同的意外行为。

+0

所以我理解这个问题,但为什么没有其他人在谷歌测试工程师认为这是一个真正的问题? – Trismegistos 2014-09-11 09:45:06

+1

此外,我会在谷歌测试已经编译了一些版本。只有东西可以改变已经编译的gtest库的链接,这些链接是gtest * .h文件或链接器标志中的ifdefs,但Google工程师旁边的任何人都没有注意到这种可能性。 – Trismegistos 2014-09-11 10:14:21

1

谷歌测试有很多设置来控制它的行为,超出了通常的调试/发布和32位/ 64位的行为。例如,它可以在C++ 11标准(<tuple>),早期TR1(<tr1/tuple>)中指定的位置使用tuple,或者根据平台(即操作系统,编译器和标准库)支持。如果在二进制文件中编译的库的一部分被配置为使用它自己的tuple,但是#include到代码中的部分尝试使用标准<tuple>头文件,则会遇到问题。 Google Test的特点在于其非常广泛的平台兼容性,因此具有大量的这些设置,为冲突创造了充足的机会。事实上,这个规则是在开发人员被那些犯了这个错误的人的大量支持电话淹没之后才被调用的。

相关问题