Adding GoogleTest to existing project give linker errors - c++

I have a project that uses CMake to get built. I wanted to test my program using GoogleTest.
So I followed the instructions of the ReadMe file of GoogleTest, and added the marked lines to my CMakeLists.txt (My OS is Ubuntu 20.04.3 LTS) :
cmake_minimum_required(VERSION 3.20)
project(replicatorProject)
set(CMAKE_CXX_STANDARD 14)
### I added the the following lines which I got from the ReadMe of GoogleTest
include(FetchContent)
FetchContent_Declare(
googletest
# Specify the commit you depend on and update it regularly.
URL https://github.com/google/googletest/archive/609281088cfefc76f9d0ce82e1ff6c30cc3591e5.zip
)
# Now simply link against gtest or gtest_main as needed. Eg
add_executable(example test/CrushMapperTest.cpp)
target_link_libraries(example gtest_main)
add_test(NAME example_test COMMAND example)
### until here (above)
find_library(CRUSH_LIBRARY libcrush.so /usr/local/lib/crush/ REQUIRED)
find_package(CppKafka REQUIRED)
add_executable(replicator src/main.cpp src/kafka/KafkaConsumer.cpp src/kafka/KafkaConsumer.h src/crush/CrushMapper.cpp src/crush/CrushMapper.h src/Replicator.cpp src/Replicator.h src/crush/Bucket.cpp src/crush/Bucket.h src/crush/Device.cpp src/crush/Device.h)
target_link_libraries(replicator LINK_PUBLIC ${CRUSH_LIBRARY} CppKafka::cppkafka)
target_include_directories(replicator PRIVATE /usr/local/include)
My Project structure looks like this:
CrushMapperTest.cpp looks like the following:
#include "gtest/gtest.h"
int main(int argc, char **argv){
testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
TEST(case1, name){
EXPECT_EQ(1,1);
}
However, if I run the test, I get a lot of undefined reference errors from my linker (here are some of them):
/usr/bin/ld: /home/lorik/Uni/Praktikum/Projekt/replicator/test/CrushMapperTest.cpp:13: undefined reference to `testing::internal::AssertHelper::~AssertHelper()'
/usr/bin/ld: /home/lorik/Uni/Praktikum/Projekt/replicator/test/CrushMapperTest.cpp:13: undefined reference to `testing::internal::AssertHelper::~AssertHelper()'
Now I am new to using CMake and I don't get what else I need to add to make the linker find the Google Test functions. I was looking through some other SO posts with similar problems ( like this one) a while ago , but so far no suggested solution helped while trying to dowload google test directly through CMake.
What am I doing wrong? Do I need another CMakeLists.txt for the test directory?
Solution
I had to add FetchContent_MakeAvailable(googletest) after the FetchContent_Declare(...) line

Related

gtest and libtorch undefined reference to `testing::internal::

I am trying to use gtest with libtorch. Currently, I have a basic test program:
#include <gtest/gtest.h>
TEST(WorldMapTests, FirstTest) {
ASSERT_TRUE(true);
}
And then I have a main make where I get torch in the third-party folder as follows:
set(TORCH_INSTALL_PREFIX "${CMAKE_CURRENT_SOURCE_DIR}/third-party/libtorch")
set(Torch_DIR "${TORCH_INSTALL_PREFIX}/share/cmake/Torch")
set(pybind11_INCLUDE_DIR "${TORCH_INSTALL_PREFIX}/include/pybind11")
And then my test make looks like:
cmake_minimum_required(VERSION 3.0)
set(CMAKE_CXX_STANDARD 14)
set(This ${PROJECT_NAME}_test)
set(Sources
cpp/WorldMapTests.cpp
)
############################################################## gtest
# Download and unpack googletest at configure time
configure_file(CMakeLists.txt.in googletest-download/CMakeLists.txt)
--- SNIP --- (test configure stuff from the github)
endif()
############################################################## gtest
add_executable(${This} ${Sources})
target_link_libraries(${This} PUBLIC
${TORCH_LIBRARIES}
gtest
gtest_main
${PROJECT_NAME}
)
target_include_directories(${This} PUBLIC ${TORCH_INCLUDE_DIRS} ${PYTHON_INCLUDE_DIRS})
target_compile_options(${This} PUBLIC ${TORCH_CXX_FLAGS})
add_test(
NAME ${This}
COMMAND ${This}
)
When I compile in release version it is fine. It is also fine if I don't include "${TORCH_LIBRARIES}" in my link directory. However, when I link to torch and test under debug I get the following:
.../test/cpp/WorldMapTests.cpp:5: undefined reference to `testing::internal::GetBoolAssertionFailureMessage(testing::AssertionResult const&, char const*, char const*, char const*)'
I think it's because torch makes use of test and is compiled under a release build. I manually found a gtest.so in the lib folder under torch and deleted it to see if it would solve it but it did not.
After quite a bit of research I was able to come right. Just wanted to post an update for anyone running into the same issue. The issue comes from libtorch being compiled in release mode rather than debug causing conflicts with the gtest library. On windows this is easy to solve as torch provides pre-compiled development libraries. However, on linux you will need to compile your own from source and then link it. I used the following guide to get torch compiled for c++ "https://kezunlin.me/post/54e7a3d8/".

Trying to add libraries with CMake results in error

I am trying to add an external .lib file to my project in Clion which uses CMake. My code is very simple and is simply to test whether the library gets included:
#include <iostream>
#include "header/test.h"
int main() {
test a; // returns error saying undefined reference to 'test::test()'
return 0;
}
When running this code I get the following error:
undefined reference to `test::test()'
This is because I am trying to make a test object however the library for test is not included.
The test.lib file and the test.h file are both in the "header" folder which is in the root of my project folder. The file path to this is F:\Project\header\
My Cmake text file is as follows:
cmake_minimum_required(VERSION 3.14)
project(Project)
set(CMAKE_CXX_STANDARD 14)
add_executable(Project main.cpp)
target_link_libraries(Project
F:\\Project\\header\\test.lib)
In the cmake text file i use the line:
target_link_libraries(Project F:\Project\header\test.lib)
This should include the library file, however it doesn't seem to because I get the "undefined reference to..." error as mentioned above. The Cmake compiler does not give me an error.
You are conceptually correct, however you are not doing it in the CMake fashion. Check out the following links on how to link an external library.
CMake link to external library
cmake doesn't support imported libraries?
https://gitlab.kitware.com/cmake/community/wikis/doc/tutorials/Exporting-and-Importing-Targets
For your case, it would be as follows):
cmake_minimum_required(VERSION 3.14)
project(Project)
set(CMAKE_CXX_STANDARD 14)
# Import the library into the CMake build system
ADD_LIBRARY(test SHARED IMPORTED)
# Specify the location of the library
SET_TARGET_PROPERTIES(TARGET test PROPERTIES IMPORTED_LOCATION “/path/to/lib/test.dll”)
# create the executable
add_executable(Project main.cpp)
# Link your exe to the library
target_link_libraries(Project test)
The CMake documentation is very good. I recommend checking it out when you run into issues.
https://cmake.org/cmake/help/latest/command/add_library.html#imported-libraries

BOOST_ROOT not respected at link stage after cmake config

Apologies for a lengthy title.
I am struggling linking boost with cmake due to existence of boost libraries in /usr/lib64 directory. My boost is compiled in a different place and I am pointing cmake with BOOST_ROOT. Aware of potential problems I am setting a minimal version and Boost_NO_SYSTEM_PATH. Configure stage works fine, but when linking I get an error:
test.cpp:(.text._ZN5boost15program_options25basic_command_line_parserIcEC2EiPKPKc[_ZN5boost15program_options25basic_command_line_parserIcEC5EiPKPKc]+0xa8): undefined reference to `boost::program_options::detail::cmdline::cmdline(std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>
>, std::allocator<std::__cxx11::basic_string<char,std::char_traits<char>, std::allocator<char> > > > const&)'
This is clearly a problem of picking up the wrong library and I can see with make VERBOSE=2 that the g++ line doesn't respect my previously found boost setting in BOOST_ROOT
g++ CMakeFiles/test.dir/test.cpp.o -o test -rdynamic -lboost_program_options-mt
But I would expect something along these lines:
g++ ... -L/path/to/my/own/boost/lib -lboost_program_options-mt
As a "debug" step I print out a message in cmake with Boost_LIBRARY_DIRS and I can see /path/to/my/own/boost/lib. When I "manually" add the -L flag the linking works, which is how I know that the system libs are still interfering. Also, my *LIBRARY_PATH are pointing only at /path/to/my/own/boost/lib.
Perhaps, it's not unlikely that this is a bug of FindBoost module, but I am finding it hard to believe. It seems to me that there's still something major in cmake I do not understand? Why is the -L flag not generated in this instance or a link to a specific file? Please advise.
Here is my CMakeLists.txt
cmake_minimum_required(VERSION 2.8)
set(Boost_NO_SYSTEM_PATHS ON)
find_package(Boost 1.67.0 REQUIRED COMPONENTS program_options)
include_directories(${Boost_INCLUDE_DIR})
add_executable(test test.cpp)
target_link_libraries(test LINK_PUBLIC ${Boost_PROGRAM_OPTIONS_LIBRARY})
And my program:
#include <iostream>
#include <string>
#include <boost/program_options.hpp>
namespace po=boost::program_options;
int main( int argc, char* argv[])
{
po::options_description options_description;
po::positional_options_description positional_options_description;
po::variables_map variables_map;
options_description.add_options()
("help,h", "print usage message");
po::store(po::command_line_parser(argc, argv).options(
options_description).positional(positional_options_description).run(),
variables_map);
return 0;
}
Other relevant output
I am using message to pull out varables from cmake config step after find_package:
${Boost_INCLUDE_DIR} /path/to/my/own/boost/include
${Boost_LIBRARY_DIRS} /path/to/my/own/boost/lib
${Boost_LIBRARIES} /path/to/my/own/boost/lib/libboost_program_options-mt.so
${Boost_PROGRAM_OPTIONS_LIBRARY} /path/to/my/own/boost/lib/libboost_program_options-mt.so
I don't know which CMake version you are using but did you try using Boost imported target instead of the old-fashioned CMake variable:
i.e.
replace:
target_link_libraries(test LINK_PUBLIC ${Boost_PROGRAM_OPTIONS_LIBRARY})
by
target_link_libraries(test LINK_PUBLIC Boost::program_options)
After calling in on cmake-developer mailing list and finally leaving a post on cmake gitlab issues I realised that the problem was not so much my cmake version, but rather my cmake_minimum_required which I inherited from an older project.
I was setting:
cmake_minium_required(VERSION 2.8)
After updating it to 3.12 that I got the correct behaviour:
/path/to/g++ -rdynamic CMakeFiles/test.dir/test.cpp.o -o test -lboost_program_options-mt
Reading cmake_minimum_required docs I understood that "command implicitly invokes" cmake_policy. I believe the latter wasn't playing well with FindBoost from my 3.12 `cmake.
I am not sure if this post is useful to SO, but I have certainly learnt my cmake lesson here.

cmake does not consider -pthread

I am trying to make a testbench to my program using gmock/gtest; Linux/Ubuntu; KDevelop/CMake. From the link error message I conclude that part of the gtest package is missing pthread support.
/home/projects/cpp/gmock/gtest/libgtest.a(gtest-all.cc.o): In function `testing::internal::ThreadLocal<testing::TestPartResultReporterInterface*>::~ThreadLocal()':
gtest-all.cc:(.text._ZN7testing8internal11ThreadLocalIPNS_31TestPartResultReporterInterfaceEED2Ev[_ZN7testing8internal11ThreadLocalIPNS_31TestPartResultReporterInterfaceEED5Ev]+0x16): undefined reference to `pthread_getspecific'
gtest-all.cc:(.text._ZN7testing8internal11ThreadLocalIPNS_31TestPartResultReporterInterfaceEED2Ev[_ZN7testing8internal11ThreadLocalIPNS_31TestPartResultReporterInterfaceEED5Ev]+0x2b): undefined reference to `pthread_key_delete'
I also read
googletest: how to setup?
Using g++ directly, everything works. So, since I am usinc KDevelop/CMake, I suspect either my code or CMake.
In my CMakeLists.txt I do use
add_definitions( -pthread -m64)
However, I do not see any effect in the Makefile.
Am I missing something from my CMakeLists.txt, or CMake does not consider the line above?
My CMakeLists.txt
cmake_minimum_required(VERSION 2.8)
add_definitions( -Dpthread )
project(ThreadTest)
INCLUDE_DIRECTORIES(gmock/gtest/include)
set ( GTEST_LIBS libgtest.a )
link_directories( ~/projects/cpp/gmock/gtest)
add_executable(ThreadTest main_test.cpp)
target_link_libraries(ThreadTest ${GTEST_LIBS})
Do I misunderstand, that add_definitions should work in this situation?
After reading
How do I force cmake to include "-pthread" option during compilation?
my question really looks like duplicate. However,
cmake_minimum_required(VERSION 2.8)
add_definitions( -Dpthread )
project(ThreadTest)
INCLUDE_DIRECTORIES(gmock/gtest/include)
find_package( Threads )
set ( GTEST_LIBS libgtest.a )
link_directories( ~/projects/cpp/gmock/gtest)
add_executable(ThreadTest main_test.cpp)
target_link_libraries(ThreadTest ${GTEST_LIBS} ${CMAKE_THREAD_LIBS_INIT})
still gives the warning 'Could NOT find Threads'. I tried to search Ubuntu software center for "threads", with no result. After that, I installed libghc-threads-dev. However, when using
set(CMAKE_THREAD_PREFER_PTHREAD TRUE)
find_package(Threads REQUIRED)
I keep receiving 'Could NOT find Threads', as error. What shall I do to satisfy find_package, and why do I have this problem, when the simple Makefile produces what I expect?
PS: my main file:
#include "gmock/gtest/include/gtest/gtest.h"
TEST(blahTest, blah1) {
EXPECT_EQ(1, 1);
}
int main (int argc, char** argv) {
::testing::InitGoogleTest(&argc, argv);
int returnValue;
returnValue = RUN_ALL_TESTS();
return returnValue;
}
After busy hours, I succeeded to compile my supercomplex test program, using KDevelop/CMake/gtest
#include "gtest-1.7.0/include/gtest/gtest.h"
TEST(blahTest, blah1) {
EXPECT_EQ(1, 1);
}
int main (int argc, char** argv) {
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
The CMakeLists.txt file that could do the task is
# http://stackoverflow.com/questions/13513905/how-to-properly-setup-googletest-on-linux/13513907#13513907
# http://stackoverflow.com/questions/15193785/how-to-get-cmake-to-recognize-pthread-on-ubuntu
# http://stackoverflow.com/questions/21116622/undefined-reference-to-pthread-key-create-linker-error
# http://stackoverflow.com/questions/1620918/cmake-and-libpthread
# https://meekrosoft.wordpress.com/2009/10/04/testing-c-code-with-the-googletest-framework/
# http://stackoverflow.com/questions/30106608/googletest-cmake-and-make-tests-not-running
# http://stackoverflow.com/questions/13521618/c-project-organisation-with-gtest-cmake-and-doxygen
# http://www.kaizou.org/2014/11/gtest-cmake/
cmake_minimum_required(VERSION 2.8)
project(ThreadTest C CXX)
ADD_SUBDIRECTORY (gtest-1.7.0)
enable_testing()
#set(THREADS_PREFER_PTHREAD_FLAG ON)
find_package(Threads REQUIRED)
find_package(GTest REQUIRED)
include_directories(${gtest_SOURCE_DIR}/include ${gtest_SOURCE_DIR})
if(NOT MSVC)
set(PThreadLib -pthread)
endif()
add_executable(ThreadTest main_test.cpp)
target_link_libraries(ThreadTest ${PThreadLib} ${GTEST_LIBRARIES})
#add_test(ThreadTest ThreadTest)
I want to highlight some things: a few valuable links and
project(ThreadTest C CXX) rather than project(ThreadTest)
and
set(PThreadLib -pthread) rather than set(PThreadLib pthread)
I guess the rest can be managed. It could be a good starting point.
I integrated Google Test framework in my own project and this CMake file is working.
# Google C++ Testing Framework
# https://code.google.com/p/googletest/
find_package(GTest REQUIRED)
include_directories(${GTEST_INCLUDE_DIRS})
if(WIN32)
# GTest is static compiled by default
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /MT")
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /MTd")
endif()
enable_testing()
add_executable(ThreadTest main_test.cpp)
target_link_libraries(ThreadTest ${GTEST_BOTH_LIBRARIES})
CMake warning "Could NOT find Threads" is related to a bug:
CMake failing to detect pthreads due to warnings
All you need to do is link with pthread:
target_link_libraries(BUILD_ARTIFACT pthread)
BUILD_ARTIFACT can be your project, or library name. You should add this line after defining your artifact.
For example, if your build artifact is ThreadTest:
add_executable(ThreadTest main_test.cpp)
target_link_libraries(ThreadTest pthread)

How do I make gtest work

So I'm getting undefined reference to testing::UnitTest::Run() along with some others with gtest. I've compiled the libraries (libgtest.a and libgtest_main.a) and placed them in my lib folder for MinGW and got no where.
Here is my CMakeList.txt:
cmake_minimum_required(VERSION 3.2)
project(proj_tests)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
set(SOURCE_FILES main.cpp)
include_directories("E:/Git/proj")
include_directories("D:/Development/Libraries/gtest-1.7.0/include")
find_package(gtest REQUIRED)
include_directories(${GTEST_INCLUDE_DIRS})
add_executable(proj_tests ${SOURCE_FILES} containers/proj_test.h)
target_link_libraries(proj_tests ${GTEST_LIBRARIES} pthread)
I have done make on the gtest sample and was able to run that without any issues.
I'm using CLion on Windows 7 for the project. How can I make this Google Test framework thing work properly?
When you build gtest, you should have the following three files:
include_fused/gtest/gtest.h
include_fused/gtest/gtest-all.cc
include_fused/gtest/gtest_main.cc
If you are providing your own main you just need the first two. If you want to use the gtest main, you need the third one too. The recommendation is to add these to each unit test project that you are building.
So after a lot of hurt I switched to Linux and tried it there by downloading and compiling the libgtest-dev and using the configuration from Erik Smistad's blog. It worked within the CLion project without issues meaning something weird was happening to my Windows compiled Google Test library.
For windows/MinGW: Here is the solution I reached for Windows..
I got pre-compiled libraries from Richard Pattis's UCI webpage on how to get the google test framework to work on eclipse.
the gtest folder in include was copied to the mingw32\include folder,
the gtest_main.a and libgtest.a files from the make folder files were copied to mingw32\lib folder.
The final working CMake configuration looks like this for me:
cmake_minimum_required(VERSION 3.2)
project(eadlib_tests)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
set(SOURCE_FILES main.cpp)
#path to project to test
include_directories("E:/Git/eadlib")
#Google test framework stuff
find_package(GTest REQUIRED)
include_directories(${GTEST_INCLUDE_DIRS})
add_executable(eadlib_tests ${SOURCE_FILES} containers/eadlib_test.h)
target_link_libraries(eadlib_tests ${GTEST_LIBRARIES} pthread)
like this (here's a snippet from one of my library projects)
find_package(GTest REQUIRED)
target_link_libraries(cpputil_test cpputil ${CMAKE_THREAD_LIBS_INIT} ${GTEST_BOTH_LIBRARIES} ${Boost_LIBRARIES} )
add_test(NAME cpputil_test COMMAND cpputil_test)
Of course in my case the project is called cpputil_test. You'll need to replace it with your own.
Note also the use of CMAKE_THREAD_LIBS_INIT which allows your code to be portable across all host systems. It hides the dependency on pthreads when building for linux (OSX, iOS and Windows for example, do not have this dependency).