Multiple problems using Xcode 5.0.1 with GTest 1.7

1,497 views
Skip to first unread message

whem...@qiggroup.com

unread,
Nov 8, 2013, 2:55:45 PM11/8/13
to googletes...@googlegroups.com
Xcode 5.0.1 with gtest 1.7 has at least a couple of problems, which block more complete evaluation of it in our environment. Here's what I've found so far, as our group tries to move from Xcode 4.6.3 to Xcode 5.0.1 :
  1. Linker errors
  2. A failed EXPECT_foo or ASSERT_foo macro causes the test application to crash.
Our environment:
  • Xcode 5.0.1
  • gtest 1.7 (the September release from Downloads)
  • Mac OS 10.8.5
  • An existing Xcode project that works with gtest 1.6 and Xcode 4.6.3
  • gtest.framework built from version 1.7 source above, built using Xcode 5.0.1 and the unmodified Xcode project file included in the release (yes, I know that the Xcode project is not well maintained, but the generated Makefile does not build a framework, just the static libraries)
Linker results:

Ld Binaries/Debug/UnitTest.app/Contents/MacOS/UnitTest normal x86_64

    cd /Users/billhembree/Documents/workspace/Platforms/UnitTest

    setenv MACOSX_DEPLOYMENT_TARGET 10.9

    /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang++ -arch x86_64 -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk -L/Users/billhembree/Documents/workspace/Platforms/UnitTest/Binaries/Debug -F/Users/billhembree/Documents/workspace/Platforms/UnitTest/Binaries/Debug -F/Users/billhembree/Documents/workspace/Platforms/UnitTest/Frameworks -filelist /Users/billhembree/Documents/workspace/Platforms/UnitTest/Build/Debug/UnitTest.build/Objects-normal/x86_64/UnitTest.LinkFileList -mmacosx-version-min=10.9 -Wl,-search_paths_first -Wl,-headerpad_max_install_names -framework gtest -fprofile-arcs -ftest-coverage -Xlinker -dependency_info -Xlinker /Users/billhembree/Documents/workspace/Platforms/UnitTest/Build/Debug/UnitTest.build/Objects-normal/x86_64/UnitTest_dependency_info.dat -o /Users/billhembree/Documents/workspace/Platforms/UnitTest/Binaries/Debug/UnitTest.app/Contents/MacOS/UnitTest


Undefined symbols for architecture x86_64:

  "testing::internal::PrintStringTo(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::basic_ostream<char, std::__1::char_traits<char> >*)", referenced from:

      testing::internal::PrintTo(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::basic_ostream<char, std::__1::char_traits<char> >*) in QgMutexTest.o

      testing::internal::PrintTo(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::basic_ostream<char, std::__1::char_traits<char> >*) in CrossPlatformTests.o

  "testing::internal::EqFailure(char const*, char const*, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, bool)", referenced from:

      testing::AssertionResult testing::internal::CmpHelperEQ<int, long>(char const*, char const*, int const&, long const&) in EventTest.o

      testing::AssertionResult testing::internal::CmpHelperEQ<int, int>(char const*, char const*, int const&, int const&) in EventTest.o

      testing::AssertionResult testing::internal::CmpHelperEQ<bool, bool>(char const*, char const*, bool const&, bool const&) in EventDispatcherTest.o

      testing::AssertionResult testing::internal::CmpHelperEQ<int, int>(char const*, char const*, int const&, int const&) in EventDispatcherTest.o

      testing::AssertionResult testing::internal::CmpHelperEQ<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >(char const*, char const*, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&) in QgMutexTest.o

      testing::AssertionResult testing::internal::CmpHelperEQ<int, int>(char const*, char const*, int const&, int const&) in QgMutexTest.o

      testing::AssertionResult testing::internal::CmpHelperEQ<int, int>(char const*, char const*, int const&, int const&) in QgSignalTest.o

      ...

ld: symbol(s) not found for architecture x86_64

clang: error: linker command failed with exit code 1 (use -v to see invocation)


1) I examined the framework's gtest dylib using nm, grep and c++filt (to find, then unmangle the names). Both of the "missing" symbols are present and of type T (public text symbols, i.e., callable methods) and the method parameters match as well.

My team's next test was to set up a very tiny test project, with the following as the test file, using Xcode's default settings for a C++ :

#include <stdio.h>

using namespace std;


#include "gtest/gtest.h"


TEST(FirstTest, TestNumberOne)

{

  EXPECT_NE(2, 1);


  EXPECT_LE(2, 3) << "Oops, greater than";

}


The above compiles and links with the framework and runs, passing the single test case. When EXPECT_LE is changed to EXPECT_EQ, the linker flags an error. So the link error is triggered by the addition of the stream operator. 

2) Again in the above code, it is possible to change the EXPECT_NE to an EXPECT_EQ and still link, but the app crashes. In fact, the app crashes when any test fails.

Does gtest no longer support Mac OS frameworks?

whem...@qiggroup.com

unread,
Nov 8, 2013, 5:43:34 PM11/8/13
to googletes...@googlegroups.com
An update:

Linking is successful if I add the following to the project being tested:

void testing::internal::PrintStringTo(const ::std::string &s, ::std::ostream *os)

{

    if (os) {

        *os << s;

    }

}


testing::AssertionResult testing::internal::EqFailure(char const*, char const*, string const&, string const&, bool){

    return AssertionSuccess();

}


This is, obviously, a crude hack and will probably cause varying malfunctions. It does, however, demonstrate that the problem is in the linker

whem...@qiggroup.com

unread,
Nov 11, 2013, 6:13:57 PM11/11/13
to googletes...@googlegroups.com
I just installed Xcode 5.0.2 and the build-time linker errors are now resolved. In fact, if there are no failures, the tests run to completion.

However, I still get a runtime error when an ASSERT_foo or EXPECT_foo fails, with the message (for EXPECT_EQ):

dyld: lazy symbol binding failed: Symbol not found: __ZN7testing8internal9EqFailureEPKcS2_RKSsS4_b

  Referenced from: /Users/billhembree/Documents/workspace/Platforms/UnitTest/Binaries/Debug/UnitTest.app/Contents/MacOS/UnitTest

  Expected in: /Library/Frameworks/gtest.framework/Versions/A/gtest


dyld: Symbol not found: __ZN7testing8internal9EqFailureEPKcS2_RKSsS4_b

  Referenced from: /Users/billhembree/Documents/workspace/Platforms/UnitTest/Binaries/Debug/UnitTest.app/Contents/MacOS/UnitTest

  Expected in: /Library/Frameworks/gtest.framework/Versions/A/gtest


When I look for this symbol (__ZN7testing8internal9EqFailureEPKcS2_RKSsS4_b) in the gtest dylib, I find it thusly:

nm gtest | grep EqFailure | c++filt
0000000000005a10 T testing::internal::EqFailure(char const*, char const*, std::string const&, std::string const&, bool)

A grep of the entire gtest 1.7.0 source reveals that EqFailure is declared in gtest-internal.h and used (twice) only in gtest.h. So presumably the method is defined in a macro/template somewhere that doesn't present the method name in a simple, searchable form anywhere.

When I changed to an EXPECT_GT(1,2) for the test failure, the symbol changed and the nm result is

nm gtest | grep __ZN7testing7MessageC1Ev | c++filt
00000000000044d0 T testing::Message::Message()

The actual Message::Message() (the empty constructor for the Message class) is nowhere to be found in the gtest source. The Message constructor is declared in gtest-message.h but there is no corresponding gtest-message.cc (or other file anywhere in the source) that holds the actual empty constructor code for this class. 

So the question is now why the dynamic linker is not finding the (apparently defined) symbols, which must be found to avoid a crash when an ASSERT_foo or EXPECT_foo fails. Is it the linker (again) or is it the way that gtest creates EqFailure and Message::Message() ?

Vikas Putcha

unread,
Dec 16, 2013, 11:22:23 AM12/16/13
to googletes...@googlegroups.com

Have you tried the steps at the below section?  https://code.google.com/p/googletest/wiki/V1_5_XcodeGuide 

Set Up the Executable Run Environment

William Hembree

unread,
Dec 30, 2013, 1:10:23 PM12/30/13
to googletes...@googlegroups.com
I've done all of that and tried various code hacks in gtest. The code being tested has been using Xcode 4.5.x and 4.6.x with gtest 1.6.0 (with no problems) for about 16 months. In fact, we added an echo command in the Makefile we use to drive cmake to remind us to add the correct value for DYLD_FRAMEWORK_PATH.

The problems began when I attempted to move the existing, running tests to gtest 1.7.0 and Xcode 5 simultaneously.

A colleague has successfully used gtest 1.7.0 with Xcode 5.0 by including the gtest source files instead of a built framework (or static library). That is a less than satisfactory work-around of the linker issue but it works.

Chen-Hai Teng

unread,
Jan 13, 2014, 10:42:49 AM1/13/14
to googletes...@googlegroups.com
I have the same problem, and I've solve it by set up the unit test target link to libstdc++.
The gtest.framework use libstdc++, but the cmmand line tool target in Xcode 5 use libc++ as the default library. It causes this problem.

Sérgio Agostinho

unread,
Feb 10, 2014, 10:27:21 PM2/10/14
to googletes...@googlegroups.com
I can confirm that as Chen-Hai Teng has indicated, setting the unit test to use -stdlib=libstdc++ does solve the problem. In Xcode 5.0.2, search in the project's "Build Settings ->  Apple LLVM 5.0 - Language - C++  -> C++ Standard Library"

Check this topic for the full explanation. I arrived there hinted by this topic.

If somehow you're stuck on having to use libc++, compile google test framework with -stdlib=libc++. In order to do so you may be forced to remove support for older versions/architectures. 
Reply all
Reply to author
Forward
0 new messages