5
votes

I'm trying to create a minimal example of gtest with CMake, but I'm not sure how I have to link the test.

I have read the README of the gtest. But, instead of creating CMakeLists.txt.in, I'd like to learn how to manually add the gtest to my project that uses CMake.

Problem

  • I can't compile my test files by make tests
  • It seems my test cannot link gtest

Error Message

Scanning dependencies of target tests
[ 25%] Building CXX object CMakeFiles/tests.dir/tests/main_test.cc.o
/Users/kkweon/temp/gtest_tutorial/tests/main_test.cc:5:1: warning: treating Unicode character as whitespace [-Wunicode-whitespace]
  ::testing::InitGoogleTest(&argc, argv);
^
/Users/kkweon/temp/gtest_tutorial/tests/main_test.cc:5:3: warning: treating Unicode character as whitespace [-Wunicode-whitespace]
  ::testing::InitGoogleTest(&argc, argv);
 ^
/Users/kkweon/temp/gtest_tutorial/tests/main_test.cc:6:1: warning: treating Unicode character as whitespace [-Wunicode-whitespace]
  return RUN_ALL_TESTS();
^
/Users/kkweon/temp/gtest_tutorial/tests/main_test.cc:6:3: warning: treating Unicode character as whitespace [-Wunicode-whitespace]
  return RUN_ALL_TESTS();
 ^
4 warnings generated.
[ 50%] Building CXX object CMakeFiles/tests.dir/tests/add_test.cc.o
[ 75%] Building CXX object CMakeFiles/tests.dir/src/add.cc.o
[100%] Linking CXX executable tests
Undefined symbols for architecture x86_64:
  "testing::InitGoogleTest(int*, char**)", referenced from:
      _main in main_test.cc.o
  "testing::Test::SetUp()", referenced from:
      vtable for AddTest_AddIntegers_Test in add_test.cc.o
  "testing::Test::TearDown()", referenced from:
      vtable for AddTest_AddIntegers_Test in add_test.cc.o
  "testing::Test::Test()", referenced from:
      AddTest_AddIntegers_Test::AddTest_AddIntegers_Test() in add_test.cc.o
  "testing::Test::~Test()", referenced from:
      AddTest_AddIntegers_Test::~AddTest_AddIntegers_Test() in add_test.cc.o
  "testing::Message::Message()", referenced from:
      AddTest_AddIntegers_Test::TestBody() in add_test.cc.o
  "testing::UnitTest::GetInstance()", referenced from:
      RUN_ALL_TESTS() in main_test.cc.o
  "testing::UnitTest::Run()", referenced from:
      RUN_ALL_TESTS() in main_test.cc.o
  "testing::internal::AssertHelper::AssertHelper(testing::TestPartResult::Type, char const*, int, char const*)", referenced from:
      AddTest_AddIntegers_Test::TestBody() in add_test.cc.o
  "testing::internal::AssertHelper::~AssertHelper()", referenced from:
      AddTest_AddIntegers_Test::TestBody() in add_test.cc.o
  "testing::internal::GetTestTypeId()", referenced from:
      ___cxx_global_var_init in add_test.cc.o
  "testing::internal::MakeAndRegisterTestInfo(char const*, char const*, char const*, char const*, testing::internal::CodeLocation, void const*, void (*)(), void (*)(), testing::internal::TestFactoryBase*)", referenced from:
      ___cxx_global_var_init in add_test.cc.o
  "testing::internal::GetBoolAssertionFailureMessage(testing::AssertionResult const&, char const*, char const*, char const*)", referenced from:
      AddTest_AddIntegers_Test::TestBody() in add_test.cc.o
  "testing::internal::IsTrue(bool)", referenced from:
      testing::internal::scoped_ptr<std::__1::basic_stringstream<char, std::__1::char_traits<char>, std::__1::allocator<char> > >::reset(std::__1::basic_stringstream<char, std::__1::char_traits<char>, std::__1::allocator<char> >*) in add_test.cc.o
      testing::internal::scoped_ptr<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >::reset(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >*) in add_test.cc.o
  "testing::internal::AssertHelper::operator=(testing::Message const&) const", referenced from:
      AddTest_AddIntegers_Test::TestBody() in add_test.cc.o
  "typeinfo for testing::Test", referenced from:
      typeinfo for AddTest_AddIntegers_Test in add_test.cc.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
make[3]: *** [tests] Error 1
make[2]: *** [CMakeFiles/tests.dir/all] Error 2
make[1]: *** [CMakeFiles/tests.dir/rule] Error 2
make: *** [tests] Error 2

Information

I have downloaded the googletest repository to /Users/kkweon/github/googletest

and "gtest.h" is located in /Users/kkweon/github/googletest/googletest/include/gtest/gtest.h

My project structure:

.
├── CMakeLists.txt
├── src
│   ├── add.cc
│   ├── add.h
│   └── main.cc
└── tests
    ├── add_test.cc
    └── main_test.cc

and CMakeLists.txt file

cmake_minimum_required(VERSION 3.0)

set(EXTRA_BINCFLAGS "-Wall -Wextra")
set(CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS} ${EXTRA_BINCFLAGS})

include_directories(/Users/kkweon/github/googletest/googletest/include)
include_directories(src)

set(SOURCES src/add.cc)
set(TEST_SOURCES tests/main_test.cc tests/add_test.cc)

add_executable(main src/main.cc ${SOURCES})
add_executable(tests ${TEST_SOURCES} ${SOURCES})

Entire Sourcecode: github

Thank you in advance!

1

1 Answers

7
votes

It is not enough to just include_directories with googletest. You have to also add its sources to be compiled.

This is what we do:

We create a separate CMake target google-test compile it as a library. We include googletest folder to our source tree so that our project and Google Test stay together.

In your main CMakeLists you do add_subdirectory(googletest)

googletest folder has its own CMakeLists.txt file and include/ and src/ folders (no need to store full googletest repo!).

tree googletest/

googletest/
├── CMakeLists.txt
├── include
│   └── gtest
│       ├── gtest-death-test.h
        ...
└── src
    ├── gtest-all.cc
    ├── gtest.cc
    └── gtest_main.cc
    ...

In your googletest/CMakeLists.txt you do:

set(google_test_include_dirs
  "${CMAKE_CURRENT_SOURCE_DIR}"
  "${CMAKE_CURRENT_SOURCE_DIR}/include")
include_directories(${google_test_include_dirs})
file(GLOB_RECURSE google_test_headers ${CMAKE_CURRENT_SOURCE_DIR}/*.h)
set(google_test_sources src/gtest-all.cc src/gtest_main.cc)
add_library(google-test STATIC ${google_test_sources} ${google_test_headers})

Then for your target with tests you do something like:

add_executable(MyTests ${my_unittests_sources})
include_directories("${CMAKE_CURRENT_SOURCE_DIR}")
include_directories("${CMAKE_SOURCE_DIR}/googletest/include")

target_link_libraries(MyTests google-test)

See CMakeLists.txt, googletest/CMakeLists.txt and unittests/CMakeLists.txt in the project I have linked above.