1

I'm trying to understand targets and properties in CMake. When using GTest in a C++ project, one needs to link to the GTest static libraries, which in my case have the default paths /usr/lib/libgtest.a and /usr/lib/libgtest_main.a. These paths are contained in variables (or macros?) GTEST_LIBRARIES and GTEST_MAIN_LIBRARIES, which are set when you run find_package(GTest REQUIRED).

Another way (seemingly more "modern CMake"?) is to use GTest::Main as a target in target_link_libraries. This also works but I don't understand why. Where are the library paths in terms of properties of this target?

To find out, I tried to list all the target properties using code from 1. Below code shows how these properties are listed and the output.

// tests_main.cpp // Google Test framework #include <gtest/gtest.h> int main(int argc, char **argv) { ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); } TEST(ExampleTests, example1) { EXPECT_EQ(1, 1); } 
# list_target_properties.cmake # Taken from https://stackoverflow.com/q/32183975/9988487 # Defines function `print_target_properties` that lists all properties of a target. # Get all propreties that cmake supports execute_process(COMMAND cmake --help-property-list OUTPUT_VARIABLE CMAKE_PROPERTY_LIST) # Convert command output into a CMake list STRING(REGEX REPLACE ";" "\\\\;" CMAKE_PROPERTY_LIST "${CMAKE_PROPERTY_LIST}") STRING(REGEX REPLACE "\n" ";" CMAKE_PROPERTY_LIST "${CMAKE_PROPERTY_LIST}") function(print_properties) message ("CMAKE_PROPERTY_LIST = ${CMAKE_PROPERTY_LIST}") endfunction(print_properties) function(print_target_properties tgt) if(NOT TARGET ${tgt}) message("There is no target named '${tgt}'") return() endif() foreach (prop ${CMAKE_PROPERTY_LIST}) string(REPLACE "<CONFIG>" "${CMAKE_BUILD_TYPE}" prop ${prop}) # Fix https://stackoverflow.com/questions/32197663/how-can-i-remove-the-the-location-property-may-not-be-read-from-target-error-i if(prop STREQUAL "LOCATION" OR prop MATCHES "^LOCATION_" OR prop MATCHES "_LOCATION$") continue() endif() # message ("Checking ${prop}") get_property(propval TARGET ${tgt} PROPERTY ${prop} SET) if (propval) get_target_property(propval ${tgt} ${prop}) message ("${tgt} ${prop} = ${propval}") endif() endforeach(prop) endfunction(print_target_properties) 
# CMakeLists.txt cmake_minimum_required(VERSION 3.12) find_package(GTest REQUIRED) add_executable(unit_tests tests_main.cpp ) target_compile_features(unit_tests PUBLIC cxx_std_17 ) target_include_directories(unit_tests PUBLIC ) if(USE_GTEST_MACROS_TO_FIND_LIBRARY_PATHS) # I was originally using this way to link to GTest target_link_libraries(unit_tests ${GTEST_LIBRARIES} # macro provided by find_package(GTest REQUIRED) earlier ${GTEST_MAIN_LIBRARIES} # macro provided by find_package(GTest REQUIRED) earlier pthread ) else() # Then I started using this way target_link_libraries(unit_tests GTest::Main pthread ) endif(USE_GTEST_MACROS_TO_FIND_LIBRARY_PATHS) # Both ways work but I don't understand why the second way works. What property of `GTest::Main` contains the library # paths that are contained in ${GTEST_LIBRARIES} and ${GTEST_MAIN_LIBRARIES}? # Code to print the static library paths for GTest message(STATUS "Value of GTEST_LIBRARIES: ${GTEST_LIBRARIES}") message(STATUS "Value of GTEST_MAIN_LIBRARIES: ${GTEST_MAIN_LIBRARIES}") # Code that (I hope) prints all properties of the GTest::Main target and the GTest::GTest target, which is specified as # a dependency of GTest::GTest. include(list_target_properties.cmake) # provides function `print_target_properties` print_target_properties(GTest::Main) message(STATUS "---------------------") print_target_properties(GTest::GTest) 

CMake Output:

... ... -- Found GTest: /usr/lib/libgtest.a -- Value of GTEST_LIBRARIES: /usr/lib/libgtest.a -- Value of GTEST_MAIN_LIBRARIES: /usr/lib/libgtest_main.a GTest::Main AUTOMOC_COMPILER_PREDEFINES = ON GTest::Main AUTOMOC_MACRO_NAMES = Q_OBJECT;Q_GADGET;Q_NAMESPACE;Q_NAMESPACE_EXPORT GTest::Main BINARY_DIR = /home/alice/CLionProjects/UnderstandCMakeTargets/cmake-build-debug GTest::Main BINARY_DIR = /home/alice/CLionProjects/UnderstandCMakeTargets/cmake-build-debug GTest::Main BUILD_WITH_INSTALL_RPATH = OFF GTest::Main IMPORTED = TRUE GTest::Main IMPORTED_LINK_INTERFACE_LANGUAGES = CXX GTest::Main INSTALL_RPATH = GTest::Main INSTALL_RPATH_USE_LINK_PATH = OFF GTest::Main INTERFACE_LINK_LIBRARIES = GTest::GTest GTest::Main NAME = GTest::Main GTest::Main SKIP_BUILD_RPATH = OFF GTest::Main SOURCE_DIR = /home/alice/CLionProjects/UnderstandCMakeTargets GTest::Main SOURCE_DIR = /home/alice/CLionProjects/UnderstandCMakeTargets GTest::Main TYPE = UNKNOWN_LIBRARY GTest::Main TYPE = UNKNOWN_LIBRARY -- --------------------- GTest::GTest AUTOMOC_COMPILER_PREDEFINES = ON GTest::GTest AUTOMOC_MACRO_NAMES = Q_OBJECT;Q_GADGET;Q_NAMESPACE;Q_NAMESPACE_EXPORT GTest::GTest BINARY_DIR = /home/alice/CLionProjects/UnderstandCMakeTargets/cmake-build-debug GTest::GTest BINARY_DIR = /home/alice/CLionProjects/UnderstandCMakeTargets/cmake-build-debug GTest::GTest BUILD_WITH_INSTALL_RPATH = OFF GTest::GTest IMPORTED = TRUE GTest::GTest IMPORTED_LINK_INTERFACE_LANGUAGES = CXX GTest::GTest INSTALL_RPATH = GTest::GTest INSTALL_RPATH_USE_LINK_PATH = OFF GTest::GTest INTERFACE_INCLUDE_DIRECTORIES = /usr/include GTest::GTest INTERFACE_LINK_LIBRARIES = Threads::Threads GTest::GTest NAME = GTest::GTest GTest::GTest SKIP_BUILD_RPATH = OFF GTest::GTest SOURCE_DIR = /home/alice/CLionProjects/UnderstandCMakeTargets GTest::GTest SOURCE_DIR = /home/alice/CLionProjects/UnderstandCMakeTargets GTest::GTest TYPE = UNKNOWN_LIBRARY GTest::GTest TYPE = UNKNOWN_LIBRARY -- Configuring done -- Generating done -- Build files have been written to: /home/alice/CLionProjects/UnderstandCMakeTargets/cmake-build-debug [Finished] 
6
  • 1
    According to the script FindGTest.cmake, path to the library is set in IMPORTED_LOCATION and IMPORTED_LOCATION_<CONFIG> properties. Not sure why your script doesn't list them. Commented Dec 10, 2020 at 14:42
  • 1
    Well, your script skips IMPORTED_LOCATION property because of prop MATCHES "_LOCATION$" check. As for IMPORTED_LOCATION_<CONFIG> properties, they are probably skipped because you don't specify build type (CMAKE_BUILD_TYPE) for your project. Commented Dec 10, 2020 at 14:47
  • @Tsyvarev Thanks for your comment. In my test I set the build type to DEBUG (default for CLion IDE, which I use). Should have mentioned that in the question. Commented Dec 10, 2020 at 14:55
  • BTW, for call cmake executable inside CMakeLists.txt it is better to use ${CMAKE_COMMAND}, so you will call exactly the same cmake which currently parses your script. It could be no system-wide cmake installation, so plain cmake won't work. Also, some IDE (and CLion too) could use their own versions of CMake, which differs from the system one. This all is about the line execute_process(COMMAND cmake --help-property-list ...) in your code. Commented Dec 10, 2020 at 16:01
  • @Tsyvarev I do not fully understand the script which defines the function listing the target properties. It is taken from the linked StackOverflow post, stackoverflow.com/q/32183975/9988487. If you have suggestions how to improve that function, please comment on the answer in that thread. Commented Dec 10, 2020 at 16:06

0

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.