1

I have a precompiled version of gtest (I know Google advises against it, but that's how our project will use it), and I want to write a very simple test and build it using scons. Assume I have super simple test called test.cpp, and gtest is installed in /opt/gtest . I am not that great using Scons, and would like to know how my SConstruct should look like.

//test.cpp
#include "gtest/gtest.h"

TEST(MyTest, Test) {
   ASSERT_TRUE(true);
}

int main(int argc, char** argv) {
 ::testing::InitGoogleTest(&argc, argv);
  return RUN_ALL_TESTS();
}

My current SConstruct looks like this (but does not work)

env = Environment()

LIBS =''

common_libs = ['pthread', 'gtest']
env.Append( LIBS = common_libs )

Program('test.cpp', LIBS, LIBPATH='/opt/gtest/lib')

I get the following message when I run scons

scons: Reading SConscript files ...
IndexError: list index out of range:
  File "/home/user/testing/SConstruct", line 8:
    Program('test.cpp', LIBS, LIBPATH='/opt/gtest/lib')
  File "/usr/lib/scons/SCons/Script/SConscript.py", line 614:
    return method(*args, **kw)
  File "/usr/lib/scons/SCons/Environment.py", line 258:
    return MethodWrapper.__call__(self, target, source, *args, **kw)
  File "/usr/lib/scons/SCons/Environment.py", line 222:
    return self.method(*nargs, **kwargs)
  File "/usr/lib/scons/SCons/Builder.py", line 632:
    return self._execute(env, target, source, OverrideWarner(kw), ekw)
  File "/usr/lib/scons/SCons/Builder.py", line 540:
    source = self.src_builder_sources(env, source, overwarn)
  File "/usr/lib/scons/SCons/Builder.py", line 736:
    s = self._adjustixes(s, None, src_suf)[0]

Thank you!

EDIT:

After changing

Program('test.cpp', LIBS, LIBPATH='/opt/gtest/lib')

to

Program('test', 'test.cpp', LIBS, LIBPATH='/opt/gtest/lib')

I get the following errors

scons: Reading SConscript files ...
scons: done reading SConscript files.
scons: Building targets ...
g++ -o test test.o -L/opt/gtest/lib
test.o: In function `MyTest_Test_Test::TestBody()':
test.cpp:(.text+0x5f): undefined reference to `testing::internal::GetBoolAssertionFailureMessage(testing::AssertionResult const&, char const*, char const*, char const*)'
test.cpp:(.text+0x8c): undefined reference to `testing::internal::AssertHelper::AssertHelper(testing::TestPartResult::Type, char const*, int, char const*)'
test.cpp:(.text+0x9f): undefined reference to `testing::internal::AssertHelper::operator=(testing::Message const&) const'
test.cpp:(.text+0xb2): undefined reference to `testing::internal::AssertHelper::~AssertHelper()'
test.cpp:(.text+0xc6): undefined reference to `testing::internal::AssertHelper::~AssertHelper()'
test.o: In function `main':
test.cpp:(.text+0x16a): undefined reference to `testing::InitGoogleTest(int*, char**)'
test.cpp:(.text+0x16f): undefined reference to `testing::UnitTest::GetInstance()'
test.cpp:(.text+0x177): undefined reference to `testing::UnitTest::Run()'
test.o: In function `__static_initialization_and_destruction_0(int, int)':
test.cpp:(.text+0x1df): undefined reference to `testing::internal::GetTestTypeId()'
test.cpp:(.text+0x20e): undefined reference to `testing::internal::MakeAndRegisterTestInfo(char const*, char const*, char const*, char const*, void const*, void (*)(), void (*)(), testing::internal::TestFactoryBase*)'
test.o: In function `MyTest_Test_Test::MyTest_Test_Test()':
test.cpp:(.text._ZN16MyTest_Test_TestC2Ev[_ZN16MyTest_Test_TestC5Ev]+0x14): undefined reference to `testing::Test::Test()'
test.o: In function `testing::internal::scoped_ptr<std::basic_string<char, std::char_traits<char>, std::allocator<char> > >::reset(std::basic_string<char, std::char_traits<char>, std::allocator<char> >*)':
test.cpp:(.text._ZN7testing8internal10scoped_ptrISsE5resetEPSs[testing::internal::scoped_ptr<std::basic_string<char, std::char_traits<char>, std::allocator<char> > >::reset(std::basic_string<char, std::char_traits<char>, std::allocator<char> >*)]+0x24): undefined reference to `testing::internal::IsTrue(bool)'
test.o: In function `testing::internal::scoped_ptr<std::basic_stringstream<char, std::char_traits<char>, std::allocator<char> > >::reset(std::basic_stringstream<char, std::char_traits<char>, std::allocator<char> >*)':
test.cpp:(.text._ZN7testing8internal10scoped_ptrISt18basic_stringstreamIcSt11char_traitsIcESaIcEEE5resetEPS6_[testing::internal::scoped_ptr<std::basic_stringstream<char, std::char_traits<char>, std::allocator<char> > >::reset(std::basic_stringstream<char, std::char_traits<char>, std::allocator<char> >*)]+0x23): undefined reference to `testing::internal::IsTrue(bool)'
test.o:(.rodata._ZTV16MyTest_Test_Test[vtable for MyTest_Test_Test]+0x20): undefined reference to `testing::Test::SetUp()'
test.o:(.rodata._ZTV16MyTest_Test_Test[vtable for MyTest_Test_Test]+0x28): undefined reference to `testing::Test::TearDown()'
test.o:(.rodata._ZTI16MyTest_Test_Test[typeinfo for MyTest_Test_Test]+0x10): undefined reference to `typeinfo for testing::Test'
test.o: In function `MyTest_Test_Test::~MyTest_Test_Test()':
test.cpp:(.text._ZN16MyTest_Test_TestD2Ev[_ZN16MyTest_Test_TestD5Ev]+0x1f): undefined reference to `testing::Test::~Test()'
collect2: ld returned 1 exit status
scons: *** [test] Error 1
scons: building terminated because of errors.
dead_jake
  • 523
  • 2
  • 12
  • 30
  • is it able to compile? It seems that it may have trouble finding the header files. – bikram990 May 06 '13 at 12:12
  • I added the output of running scons to my post. Thanks. – dead_jake May 06 '13 at 16:05
  • Its the linking problem. The linker is not able to find libraries for gtest. As you can see the command line for the build(just after scons building targets) the library path is mentioned but its not linking to any library. – bikram990 May 08 '13 at 04:33

3 Answers3

2

Please change the line:

Program('test.cpp', LIBS, LIBPATH='/opt/gtest/lib')

to

Program('test', 'test.cpp', LIBS, LIBPATH='/opt/gtest/lib')

You will get a binary named test.

bikram990
  • 1,085
  • 1
  • 14
  • 36
  • Thank you for your response, but now I am getting some new errors. I have added the error messages to my question above. – dead_jake May 07 '13 at 17:32
  • 4
    Add **env.Program** instead of **Program** for using that environment which you created otherwise it will be using the environment which was used to call the scons! – bikram990 May 08 '13 at 10:07
1

Example code

Let's say I have this C++ code:

#include "sample1.h"

// Returns n! (the factorial of n).  For negative n, n! is defined to be 1.
int Factorial(int n) {
    int result = 1;
    for (int i = 1; i <= n; i++) {
        result *= i;
    }

    return result;
}

The header file simple1.h is:

#ifndef GTEST_SAMPLES_SAMPLE1_H_
#define GTEST_SAMPLES_SAMPLE1_H_

// Returns n! (the factorial of n).  For negative n, n! is defined to be 1.
int Factorial(int n);

#endif  // GTEST_SAMPLES_SAMPLE1_H_

Test code

The test code is as follows:

#include <limits.h>
#include "sample1.h"
#include "gtest/gtest.h"

TEST(FactorialTest, Negative) {
    // This test is named "Negative", and belongs to the "FactorialTest"
    // test case.
    EXPECT_EQ(1, Factorial(0));
    EXPECT_EQ(2, Factorial(2));
    EXPECT_GT(Factorial(-10), 0);
}

Google test library and header file.

I copied all the header files in /usr/gtest/include, I also copied the two library files libgtest_main.a and libgtest.a in /usr/gtest directory. I don't need the test main file as I'll use the libgtest_main.a.

The sons configuration file.

This is the file:

env = Environment(CPPPATH=['/usr/gtest/include'])
common_libs = ['gtest_main', 'gtest']
env.Append( LIBS = common_libs )

env.Program(source=['sample1.cpp', 'test_sample1.cpp'], LIBPATH=['/usr/gtest'])

Run the sons scons -Q to get:

g++ -o sample1.o -c -I/Users/smcho/Dropbox/smcho/bin/lib/gtest/include sample1.cpp
g++ -o test_sample1.o -c -I/Users/smcho/Dropbox/smcho/bin/lib/gtest/include test_sample1.cpp
g++ -o sample1 sample1.o test_sample1.o -L/Users/smcho/Dropbox/smcho/bin/lib/gtest -lgtest_main -lgtest

Run the sample1 to get:

Running main() from gtest_main.cc
[==========] Running 1 test from 1 test case.
[----------] Global test environment set-up.
[----------] 1 test from FactorialTest
[ RUN      ] FactorialTest.Negative
[       OK ] FactorialTest.Negative (0 ms)
[----------] 1 test from FactorialTest (0 ms total)

[----------] Global test environment tear-down
[==========] 1 test from 1 test case ran. (0 ms total)
[  PASSED  ] 1 test.
prosseek
  • 182,215
  • 215
  • 566
  • 871
1

After making the correction that bikram990 suggested. Also make sure to change the order of the libraries. The gtest library should come first; see this comment! from a related post.

This line:

common_libs = ['pthread', 'gtest']

should be:

common_libs = ['gtest', 'pthread']

Community
  • 1
  • 1