Search code examples
c++cmakestaticlibraries

How to use libraries (*.a files) in C++ when using cmake


So recently I started programming C++ again. I want to learn how to use Cmake properly and also start writing proper tests for my hobby projects from now on.

I basically just want to integrate GTest in my Project. I set up a TestProject directory and did the following:

  1. cloned the GTest repository
  2. build the code in the googletest repositroy with cmake
  3. copied the googletest/build/lib directory to TestProject/
  4. copied the googletest/include directory to TestProject/

Now when I try to use cmake, I get the following error when linking:

/usr/bin/ld: ./libgtest.a(gtest-all.cc.o): in function `testing::internal::ThreadLocal<testing::TestPartResultReporterInterface*>::~ThreadLocal()':
gtest-all.cc:(.text._ZN7testing8internal11ThreadLocalIPNS_31TestPartResultReporterInterfaceEED2Ev[_ZN7testing8internal11ThreadLocalIPNS_31TestPartResultReporterInterfaceEED5Ev]+0x24): undefined reference to `pthread_getspecific'
/usr/bin/ld: gtest-all.cc:(.text._ZN7testing8internal11ThreadLocalIPNS_31TestPartResultReporterInterfaceEED2Ev[_ZN7testing8internal11ThreadLocalIPNS_31TestPartResultReporterInterfaceEED5Ev]+0x39): undefined reference to `pthread_key_delete'
/usr/bin/ld: ./libgtest.a(gtest-all.cc.o): in function `testing::internal::ThreadLocal<std::vector<testing::internal::TraceInfo, std::allocator<testing::internal::TraceInfo> > >::~ThreadLocal()':
gtest-all.cc:(.text._ZN7testing8internal11ThreadLocalISt6vectorINS0_9TraceInfoESaIS3_EEED2Ev[_ZN7testing8internal11ThreadLocalISt6vectorINS0_9TraceInfoESaIS3_EEED5Ev]+0x24): undefined reference to `pthread_getspecific'
/usr/bin/ld: gtest-all.cc:(.text._ZN7testing8internal11ThreadLocalISt6vectorINS0_9TraceInfoESaIS3_EEED2Ev[_ZN7testing8internal11ThreadLocalISt6vectorINS0_9TraceInfoESaIS3_EEED5Ev]+0x39): undefined reference to `pthread_key_delete'
/usr/bin/ld: ./libgtest.a(gtest-all.cc.o): in function `testing::internal::ThreadLocal<std::vector<testing::internal::TraceInfo, std::allocator<testing::internal::TraceInfo> > >::GetOrCreateValue() const':
gtest-all.cc:(.text._ZNK7testing8internal11ThreadLocalISt6vectorINS0_9TraceInfoESaIS3_EEE16GetOrCreateValueEv[_ZNK7testing8internal11ThreadLocalISt6vectorINS0_9TraceInfoESaIS3_EEE16GetOrCreateValueEv]+0x25): undefined reference to `pthread_getspecific'
/usr/bin/ld: gtest-all.cc:(.text._ZNK7testing8internal11ThreadLocalISt6vectorINS0_9TraceInfoESaIS3_EEE16GetOrCreateValueEv[_ZNK7testing8internal11ThreadLocalISt6vectorINS0_9TraceInfoESaIS3_EEE16GetOrCreateValueEv]+0x88): undefined reference to `pthread_setspecific'
/usr/bin/ld: ./libgtest.a(gtest-all.cc.o): in function `testing::internal::ThreadLocal<testing::TestPartResultReporterInterface*>::CreateKey()':
gtest-all.cc:(.text._ZN7testing8internal11ThreadLocalIPNS_31TestPartResultReporterInterfaceEE9CreateKeyEv[_ZN7testing8internal11ThreadLocalIPNS_31TestPartResultReporterInterfaceEE9CreateKeyEv]+0x27): undefined reference to `pthread_key_create'
/usr/bin/ld: ./libgtest.a(gtest-all.cc.o): in function `testing::internal::ThreadLocal<std::vector<testing::internal::TraceInfo, std::allocator<testing::internal::TraceInfo> > >::CreateKey()':
gtest-all.cc:(.text._ZN7testing8internal11ThreadLocalISt6vectorINS0_9TraceInfoESaIS3_EEE9CreateKeyEv[_ZN7testing8internal11ThreadLocalISt6vectorINS0_9TraceInfoESaIS3_EEE9CreateKeyEv]+0x27): undefined reference to `pthread_key_create'
/usr/bin/ld: ./libgtest.a(gtest-all.cc.o): in function `testing::internal::ThreadLocal<testing::TestPartResultReporterInterface*>::GetOrCreateValue() const':
gtest-all.cc:(.text._ZNK7testing8internal11ThreadLocalIPNS_31TestPartResultReporterInterfaceEE16GetOrCreateValueEv[_ZNK7testing8internal11ThreadLocalIPNS_31TestPartResultReporterInterfaceEE16GetOrCreateValueEv]+0x25): undefined reference to `pthread_getspecific'
/usr/bin/ld: gtest-all.cc:(.text._ZNK7testing8internal11ThreadLocalIPNS_31TestPartResultReporterInterfaceEE16GetOrCreateValueEv[_ZNK7testing8internal11ThreadLocalIPNS_31TestPartResultReporterInterfaceEE16GetOrCreateValueEv]+0x88): undefined reference to `pthread_setspecific'

The files in my project directory are:

TestProject/CMakeLists.txt

cmake_minimum_required(VERSION 3.16)

project(TestGoogleTest)

set(ROOT_DIR "${PROJECT_SOURCE_DIR}")
set(SRC "${ROOT_DIR}/src")
set(LIB "${ROOT_DIR}/lib")
set(INCLUDE "${ROOT_DIR}/include")

link_directories("${LIB}")
include_directories("${INCLUDE}")

message("INCLUDE PATH: ${INCLUDE}")

set(SOURCES "${SRC}/main.cpp" "${INCLUDE}/gtest/gtest.h")

add_executable(main "${SOURCES}")
target_link_libraries(main libgtest.a)

TestProject/src/main.cpp:

#include "gtest/gtest.h"
#include <iostream>

int main(int argc, char **argv) 
{
  testing::InitGoogleTest(&argc, argv);
  std::cout << "Hello world!" << std::endl;
  return RUN_ALL_TESTS();
}

It works fine if I compile it manually with the systems gtest with the command

g++ src/main.cpp -o main -lgtest

I would be very happy to understand what causes the problem :)


Solution

  • I solved my problem by using the answer @squareskittles proposed. My CMakeLists.txt is now also way cleaner and looks like this

    CMakeLists.txt

    cmake_minimum_required(VERSION 3.16)
    
    project(TestGoogleTest)
    
    enable_testing()
    find_package(GTest REQUIRED)
    
    set(ROOT_DIR "${PROJECT_SOURCE_DIR}")
    set(SRC "${ROOT_DIR}/src")
    
    set(SOURCES "${SRC}/main.cpp")
    
    add_executable(test "${SOURCES}")
    target_link_libraries(test GTest::GTest GTest::Main)
    

    I'm sure the answer provided by @SALEH is solving the problem the way I wanted to solve it first. I haven't tried it out though.

    Thanks everyone!!!