1

I'm a beginner to CMake and have been modifying a CMake script (see below) and it was compiling fine. However, I am now following this article to add Google Test:

https://raymii.org/s/tutorials/Cpp_project_setup_with_cmake_and_unit_tests.html

but I have a lot of problems. I don't think i've done this properly.

I'm currently getting undefined references to Boost source code when linking the unit test:

[ 98%] Linking CXX executable helloworld_test
cd /bla/bla/HelloWorld/build/test && /usr/bin/cmake -E cmake_link_script CMakeFiles/helloworld_test.dir/link.txt --verbose=1
/usr/bin/c++  -Wall -Wextra -pedantic -march=native -O2 -g -DNDEBUG -fsanitize=address CMakeFiles/helloworld_test.dir/AComponentTest.cpp.o CMakeFiles/helloworld_test.dir/main.cpp.o -o helloworld_test  ../libhelloworld.a ../lib/libgtest.a /usr/lib/x86_64-linux-gnu/libssl.a /usr/lib/x86_64-linux-gnu/libcrypto.a -ldl 
/usr/bin/ld: ../libhelloworld.a(AComponent.cpp.o): in function `ix::AComponent::onConnected()':
/bla/bla/HelloWorld/src/AComponent.cpp:152: undefined reference to `boost::json::serialize[abi:cxx11](boost::json::value const&)'
/usr/bin/ld: /bla/bla/HelloWorld/src/AComponent.cpp:153: undefined reference to `boost::json::value::~value()'
/usr/bin/ld: /bla/bla/HelloWorld/src/AComponent.cpp:144: undefined reference to `boost::json::value::value(std::initializer_list<boost::json::value_ref>, boost::json::storage_ptr)'
/usr/bin/ld: /bla/bla/HelloWorld/src/AComponent.cpp:146: undefined reference to `boost::json::operator<<(std::ostream&, boost::json::value const&)'
/usr/bin/ld: /bla/bla/HelloWorld/src/AComponent.cpp:153: undefined reference to `boost::json::value::~value()'

However, weirdly I didn't need to reference Boost in the CMake before adding the unit tests, so I'm not sure why that worked but fails now i'm building the tests? I'm really confused.

This is my CMake:

cmake_minimum_required(VERSION 3.20)
set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/CMake;${CMAKE_MODULE_PATH}")

project(helloworld C CXX)

set (CMAKE_CXX_STANDARD 20)
set (CMAKE_BUILD_TYPE Release)

set (BUILD_MAIN TRUE)
set (BUILD_SHARED_LIBS FALSE)
set (OPENSSL_USE_STATIC_LIBS TRUE)

set(CMAKE_POSITION_INDEPENDENT_CODE ON)

set( HELLOWORLD_HEADERS    helloworld/File1.h       helloworld/File2.h    )
set( HELLOWORLD_SOURCES    helloworld/File1.cpp     helloworld/File2.cpp  )

# Static library
add_library( helloworld  ${HELLOWORLD_SOURCES}    ${HELLOWORLD_HEADERS}   )

# OpenSSL
if (NOT OPENSSL_FOUND)
  find_package(OpenSSL REQUIRED)
endif()

add_definitions(${OPENSSL_DEFINITIONS})

target_include_directories(helloworld PUBLIC $<BUILD_INTERFACE:${OPENSSL_INCLUDE_DIR}>)
target_link_libraries(helloworld PRIVATE ${OPENSSL_LIBRARIES})

set( HELLOWORLD_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR})

include(GNUInstallDirs)

target_include_directories(helloworld PUBLIC
  $<BUILD_INTERFACE:${HELLOWORLD_INCLUDE_DIRS}/>
  $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}/helloworld>
)

set_target_properties(helloworld PROPERTIES PUBLIC_HEADER "${HELLOWORLD_HEADERS}")

add_library(helloworld::helloworld ALIAS helloworld)

include_directories(/bla/bla/helloworld/lib/googletest/googletest/include/)
add_subdirectory(test)
add_subdirectory(lib/googletest)

add_executable(main main.cpp)
target_link_libraries(main helloworld) 

My folder structure looks like this:

HelloWorld
|---CMakeList.txt
|---main.cpp
|---build
|---lib
|   |---googletest
|       |---googletest
|           |---include
|               |---gtest
|                   | <all the google test code>
|---src
|   |---CMakeList.txt
|    <lots of code>
|---tst
|   |---CMakeList.txt
|   |---main.cpp
|   |---AComponentTest.cpp

As per the article, my tst/CMakeList.txt is this:

set(BINARY ${CMAKE_PROJECT_NAME}_test)
file(GLOB_RECURSE TEST_SOURCES LIST_DIRECTORIES false *.h *.cpp)
set(SOURCES ${TEST_SOURCES})
add_executable(${BINARY} ${TEST_SOURCES})
add_test(NAME ${BINARY} COMMAND ${BINARY})
target_link_libraries(${BINARY} PUBLIC ${CMAKE_PROJECT_NAME} gtest)

and these are the only additional lines I added to helloworld/CMakeList.txt:

include_directories(/bla/bla/helloworld/lib/googletest/googletest/include/)
add_subdirectory(test)
add_subdirectory(lib/googletest)

(if I comment-out these lines, it builds fine)

My test is very simple:

#include "gtest/gtest.h"
#include <src/AComponent.h>

TEST(blaTest, test1) 
{
    const char* config_path = "";
    AComponent a(config_path, true);
    EXPECT_EQ(false, false);
}
intrigued_66
  • 16,082
  • 51
  • 118
  • 189
  • It's the library, specifically `AComponent.cpp` that uses undefined symbols from `Boost::json`. You probably should link `Boost::json` with `PUBLIC` visibility to the `helloworld` target... – fabian Jul 21 '22 at 19:36
  • If `AComponent.cpp` uses boost json, you'll need to link against the boost json libraries. – Stephen Newell Jul 21 '22 at 19:48
  • @fabian What I don't understand is how does the original (without the unit test) code link fine without any reference to Boost? – intrigued_66 Jul 21 '22 at 21:16
  • "by original" do you mean `helloworld` library? It is a **static** library, it is never linked actually. – Tsyvarev Jul 21 '22 at 21:34

0 Answers0