CMake + GoogleTest - PullRequest
       17

CMake + GoogleTest

47 голосов
/ 13 марта 2012

Я только что скачал googletest, сгенерировал его make-файл с помощью CMake и собрал его. Теперь мне нужно использовать его в моем тестовом проекте.

С CMake мне посоветовали не указывать напрямую на библиотеки gtest (используя include _directories или link_directories), а вместо этого использовать find_package().

Проблема в том, что для сгенерированного gtest makefile нет цели установки. Я не могу понять, как find_package(GTest REQUIRED) может работать без какой-либо установки. Кроме того, размещение папки gtest в качестве подпапки в моем проекте невозможно.

Спасибо за любую помощь.

Ответы [ 5 ]

64 голосов
/ 14 марта 2012

Это необычный случай;большинство проектов определяют правила установки.

Модуль CMake ExternalProject_Add, возможно, является лучшим инструментом для этой работы.Это позволяет вам загружать, настраивать и создавать gtest из своего проекта, а затем связываться с библиотеками gtest.

Я протестировал следующий файл CMakeLists.txt в Windows с Visual Studio 10 и 11 и в Ubuntuиспользуя GCC 4.8 и Clang 3.2 - возможно, потребуется настроить его для других платформ / компиляторов:

cmake_minimum_required(VERSION 2.8.7 FATAL_ERROR)
project(Test)

# Create main.cpp which uses gtest
file(WRITE src/main.cpp "#include \"gtest/gtest.h\"\n\n")
file(APPEND src/main.cpp "TEST(A, B) { SUCCEED(); }\n")
file(APPEND src/main.cpp "int main(int argc, char **argv) {\n")
file(APPEND src/main.cpp "  testing::InitGoogleTest(&argc, argv);\n")
file(APPEND src/main.cpp "  return RUN_ALL_TESTS();\n")
file(APPEND src/main.cpp "}\n")

# Create patch file for gtest with MSVC 2012
if(MSVC_VERSION EQUAL 1700)
  file(WRITE gtest.patch "Index: cmake/internal_utils.cmake\n")
  file(APPEND gtest.patch "===================================================================\n")
  file(APPEND gtest.patch "--- cmake/internal_utils.cmake   (revision 660)\n")
  file(APPEND gtest.patch "+++ cmake/internal_utils.cmake   (working copy)\n")
  file(APPEND gtest.patch "@@ -66,6 +66,9 @@\n")
  file(APPEND gtest.patch "       # Resolved overload was found by argument-dependent lookup.\n")
  file(APPEND gtest.patch "       set(cxx_base_flags \"\${cxx_base_flags} -wd4675\")\n")
  file(APPEND gtest.patch "     endif()\n")
  file(APPEND gtest.patch "+    if (MSVC_VERSION EQUAL 1700)\n")
  file(APPEND gtest.patch "+      set(cxx_base_flags \"\${cxx_base_flags} -D_VARIADIC_MAX=10\")\n")
  file(APPEND gtest.patch "+    endif ()\n")
  file(APPEND gtest.patch "     set(cxx_base_flags \"\${cxx_base_flags} -D_UNICODE -DUNICODE -DWIN32 -D_WIN32\")\n")
  file(APPEND gtest.patch "     set(cxx_base_flags \"\${cxx_base_flags} -DSTRICT -DWIN32_LEAN_AND_MEAN\")\n")
  file(APPEND gtest.patch "     set(cxx_exception_flags \"-EHsc -D_HAS_EXCEPTIONS=1\")\n")
else()
  file(WRITE gtest.patch "")
endif()

# Enable ExternalProject CMake module
include(ExternalProject)

# Set the build type if it isn't already
if(NOT CMAKE_BUILD_TYPE)
  set(CMAKE_BUILD_TYPE Release)
endif()

# Set default ExternalProject root directory
set_directory_properties(PROPERTIES EP_PREFIX ${CMAKE_BINARY_DIR}/ThirdParty)

# Add gtest
ExternalProject_Add(
    googletest
    SVN_REPOSITORY http://googletest.googlecode.com/svn/trunk/
    SVN_REVISION -r 660
    TIMEOUT 10
    PATCH_COMMAND svn patch ${CMAKE_SOURCE_DIR}/gtest.patch ${CMAKE_BINARY_DIR}/ThirdParty/src/googletest
    # Force separate output paths for debug and release builds to allow easy
    # identification of correct lib in subsequent TARGET_LINK_LIBRARIES commands
    CMAKE_ARGS -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}
               -DCMAKE_ARCHIVE_OUTPUT_DIRECTORY_DEBUG:PATH=DebugLibs
               -DCMAKE_ARCHIVE_OUTPUT_DIRECTORY_RELEASE:PATH=ReleaseLibs
               -Dgtest_force_shared_crt=ON
    # Disable install step
    INSTALL_COMMAND ""
    # Wrap download, configure and build steps in a script to log output
    LOG_DOWNLOAD ON
    LOG_CONFIGURE ON
    LOG_BUILD ON)

# Specify include dir
ExternalProject_Get_Property(googletest source_dir)
include_directories(${source_dir}/include)

# Add compiler flag for MSVC 2012
if(MSVC_VERSION EQUAL 1700)
  add_definitions(-D_VARIADIC_MAX=10)
endif()

# Add test executable target
add_executable(MainTest ${PROJECT_SOURCE_DIR}/src/main.cpp)

# Create dependency of MainTest on googletest
add_dependencies(MainTest googletest)

# Specify MainTest's link libraries
ExternalProject_Get_Property(googletest binary_dir)
if(MSVC)
  set(Suffix ".lib")
else()
  set(Suffix ".a")
  set(Pthread "-pthread")
endif()
target_link_libraries(
    MainTest
    debug ${binary_dir}/DebugLibs/${CMAKE_FIND_LIBRARY_PREFIXES}gtest${Suffix}
    optimized ${binary_dir}/ReleaseLibs/${CMAKE_FIND_LIBRARY_PREFIXES}gtest${Suffix}
    ${Pthread})

Если вы создадите его как CMakeLists.txt в пустой директории (скажем, MyTest), то:

cd MyTest
mkdir build
cd build
cmake ..

Это должно создать основной файл main.cpp в MyTest/src и создать файл проекта (MyTest/build/Test.sln в Windows)

Когда вы собираете проект, он должен загрузить исходные коды gtest в MyTest/build/ThirdParty/src/googletest, и построить их в MyTest/build/ThirdParty/src/googletest-build.После этого вы сможете успешно запустить цель MainTest.

27 голосов
/ 25 июля 2015

Прошло много времени, когда задавался исходный вопрос, но для блага других можно использовать ExternalProject для загрузки исходного кода gtest и затем использовать add_subdirectory() для добавления его в вашу сборку.Это имеет следующие преимущества:

  • gtest построен как часть вашей основной сборки, поэтому он использует те же флаги компилятора и т. Д. И его не нужно нигде устанавливать.
  • Нет необходимости добавлять источники gtest в ваше собственное дерево исходников.

При обычном использовании ExternalProject не выполняет загрузку и распаковку во время настройки (т. Е. При запуске CMake),но вы можете сделать это.Я написал сообщение в блоге о том, как это сделать, которое также включает обобщенную реализацию, которая работает для любого внешнего проекта, который использует CMake в качестве своей системы сборки, а не только gtest.Вы можете найти его здесь:

https://crascit.com/2015/07/25/cmake-gtest/

Обновление: Описанный выше подход теперь также является частью документации googletest .

8 голосов
/ 29 июня 2015

Мой ответ основан на ответе от firegurafiku .Я изменил его следующими способами:

  1. добавил CMAKE_ARGS к вызову ExternalProject_Add, чтобы он работал с msvc.
  2. получает источник gtest из местоположения файла вместо загрузки
  3. добавлено переносимое (для MSVC и не-MSVC) определение и использование IMPORTED_LOCATION
  4. Устранена проблема с вызовом set_target_properties, который не работает во время настройки, когда INTERFACE_INCLUDE_DIRECTORIES еще не существует, посколькувнешний проект еще не создан.

Я предпочитаю сохранять gtest как внешний проект, а не добавлять его источник непосредственно в мой проект.Одна из причин в том, что мне не нравится, когда при поиске кода включается исходный код gtest.Любые специальные флаги сборки, которые нужны моему коду, которые также должны использоваться при сборке gtest, могут быть добавлены к определению CMAKE_ARGS в вызове ExternalProject_Add

Вот мой модифицированный подход:

include(ExternalProject)

# variables to help keep track of gtest paths
set(GTEST_PREFIX "${CMAKE_CURRENT_BINARY_DIR}/gtest")
set(GTEST_LOCATION "${GTEST_PREFIX}/src/GTestExternal-build")
set(GTEST_INCLUDES "${GTEST_PREFIX}/src/GTestExternal/include")

# external project download and build (no install for gtest)
ExternalProject_Add(GTestExternal
    URL ${CMAKE_CURRENT_SOURCE_DIR}/../googletest
    PREFIX "${GTEST_PREFIX}"

    # cmake arguments
    CMAKE_ARGS -Dgtest_force_shared_crt=ON

    # Disable install step
    INSTALL_COMMAND ""

    # Wrap download, configure and build steps in a script to log output
    LOG_DOWNLOAD ON
    LOG_CONFIGURE ON
    LOG_BUILD ON
    )

# variables defining the import location properties for the generated gtest and
# gtestmain libraries
if (MSVC)
    set(GTEST_IMPORTED_LOCATION
        IMPORTED_LOCATION_DEBUG           "${GTEST_LOCATION}/Debug/${CMAKE_STATIC_LIBRARY_PREFIX}gtest${CMAKE_STATIC_LIBRARY_SUFFIX}"
        IMPORTED_LOCATION_RELEASE         "${GTEST_LOCATION}/Release/${CMAKE_STATIC_LIBRARY_PREFIX}gtest${CMAKE_STATIC_LIBRARY_SUFFIX}"
        )
    set(GTESTMAIN_IMPORTED_LOCATION
        IMPORTED_LOCATION_DEBUG           "${GTEST_LOCATION}/Debug/${CMAKE_STATIC_LIBRARY_PREFIX}gtest_main${CMAKE_STATIC_LIBRARY_SUFFIX}"
        IMPORTED_LOCATION_RELEASE         "${GTEST_LOCATION}/Release/${CMAKE_STATIC_LIBRARY_PREFIX}gtest_main${CMAKE_STATIC_LIBRARY_SUFFIX}"
        )
else()
    set(GTEST_IMPORTED_LOCATION
        IMPORTED_LOCATION                 "${GTEST_LOCATION}/${CMAKE_STATIC_LIBRARY_PREFIX}gtest${CMAKE_STATIC_LIBRARY_SUFFIX}")
    set(GTESTMAIN_IMPORTED_LOCATION
        IMPORTED_LOCATION                 "${GTEST_LOCATION}/${CMAKE_STATIC_LIBRARY_PREFIX}gtest_main${CMAKE_STATIC_LIBRARY_SUFFIX}")
endif()

# the gtest include directory exists only after it is build, but it is used/needed
# for the set_target_properties call below, so make it to avoid an error
file(MAKE_DIRECTORY ${GTEST_INCLUDES})

# define imported library GTest
add_library(GTest IMPORTED STATIC GLOBAL)
set_target_properties(GTest PROPERTIES
    INTERFACE_INCLUDE_DIRECTORIES     "${GTEST_INCLUDES}"
    IMPORTED_LINK_INTERFACE_LIBRARIES "${CMAKE_THREAD_LIBS_INIT}"
    ${GTEST_IMPORTED_LOCATION}
    )

# define imported library GTestMain
add_library(GTestMain IMPORTED STATIC GLOBAL)
set_target_properties(GTestMain PROPERTIES
    IMPORTED_LINK_INTERFACE_LIBRARIES GTest
    ${GTESTMAIN_IMPORTED_LOCATION}
    )

# make GTest depend on GTestExternal
add_dependencies(GTest GTestExternal)

#
# My targets
#

project(test_pipeline)
add_executable(${PROJECT_NAME} test_pipeline.cpp)
set_target_properties(${PROJECT_NAME} PROPERTIES DEBUG_POSTFIX ${CMAKE_DEBUG_POSTFIX})
target_link_libraries(${PROJECT_NAME} ${TBB_LIBRARIES})
target_link_libraries(${PROJECT_NAME} GTest)
8 голосов
/ 15 июня 2014

Существует немного менее сложное решение, использующее модуль ExternalProject и функцию импортированных библиотек cmake.Он извлекает код из репозитория, создает его и создает цель из встроенных статических библиотек (в моей системе они libgtest.a и libgtest_main.a).

find_package(Threads REQUIRED)
include(ExternalProject)

set(GTEST_PREFIX "${CMAKE_CURRENT_BINARY_DIR}/gtest")
ExternalProject_Add(GTestExternal
    SVN_REPOSITORY http://googletest.googlecode.com/svn/trunk
    SVN_REVISION -r HEAD
    TIMEOUT 10
    PREFIX "${GTEST_PREFIX}"
    INSTALL_COMMAND "")

set(LIBPREFIX "${CMAKE_STATIC_LIBRARY_PREFIX}")
set(LIBSUFFIX "${CMAKE_STATIC_LIBRARY_SUFFIX}")
set(GTEST_LOCATION "${GTEST_PREFIX}/src/GTestExternal-build")
set(GTEST_INCLUDES "${GTEST_PREFIX}/src/GTestExternal/include")
set(GTEST_LIBRARY  "${GTEST_LOCATION}/${LIBPREFIX}gtest${LIBSUFFIX}")
set(GTEST_MAINLIB  "${GTEST_LOCATION}/${LIBPREFIX}gtest_main${LIBSUFFIX}")

add_library(GTest IMPORTED STATIC GLOBAL)
set_target_properties(GTest PROPERTIES
    IMPORTED_LOCATION                 "${GTEST_LIBRARY}"
    INTERFACE_INCLUDE_DIRECTORIES     "${GTEST_INCLUDES}"
    IMPORTED_LINK_INTERFACE_LIBRARIES "${CMAKE_THREAD_LIBS_INIT}")

add_library(GTestMain IMPORTED STATIC GLOBAL)
set_target_properties(GTestMain PROPERTIES
    IMPORTED_LOCATION "${GTEST_MAINLIB}"
    IMPORTED_LINK_INTERFACE_LIBRARIES
        "${GTEST_LIBRARY};${CMAKE_THREAD_LIBS_INIT}")

add_dependencies(GTest GTestExternal)

Возможно, вы захотите заменить SVN_REVISION илидобавьте сюда опции LOG_CONFIGURE и LOG_BUILD.После создания GTest и GTestMain целей их можно использовать следующим образом:

add_executable(Test
    test1.cc
    test2.cc)
target_link_libraries(Test GTestMain)

или, если у вас есть собственная функция main():

add_executable(Test
    main.cc
    test1.cc
    test2.cc)
target_link_libraries(Test GTest)
0 голосов
/ 28 июня 2019

Когда вы получаете пакет libgtest-dev через

sudo apt install libgtest-dev

Источник хранится в папке /usr/src/googletest

Вы можете просто указать CMakeLists.txt на этот каталог, чтобы онможно найти необходимые зависимости

Примерно так:

add_subdirectory(/usr/src/googletest gtest)
target_link_libraries(your_executable gtest)
...