CMake + GoogleTest

我刚刚下载了googletest,用CMake生成了它的makefile并构build了它。 现在,我需要在我的testing项目中使用它。

对于CMake,我build议不要直接指向gtest库(使用include _directorieslink_directories ),而是使用find_package()来代替。

问题是,gtest makefile没有生成安装目标。 我无法理解find_package(GTest REQUIRED)如何在没有某种安装的情况下工作。 另外,将gtest文件夹作为子文件夹放在我的项目中是不可能的。

感谢您的帮助。

这是一个不寻常的案例。 大多数项目指定安装规则。

CMake的ExternalProject_Add模块可能是这项工作的最佳工具。 这使您可以从您的项目中下载,configuration和构buildgtest,然后链接到gtest库。

我使用Visual Studio 10和11在Windows上testing了以下CMakeLists.txt,并且在Ubuntu上使用GCC 4.8和Clang 3.2testing了它 – 可能需要为其他平台/编译器进行调整:

 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}) 

如果你在一个空目录(比如MyTest )中创buildCMakeLists.txt,那么:

 cd MyTest mkdir build cd build cmake .. 

这应该在MyTest/src创build一个基本的main.cpp,并创build一个项目文件(Windows上的MyTest/build/Test.sln

在构build项目时,应该将gtest源代码下载到MyTest/build/ThirdParty/src/googletest ,并在MyTest/build/ThirdParty/src/googletest-build 。 然后,您应该能够成功运行MainTest目标。

当被问及的原始问题早已过去,但为了别人的利益,可以使用ExternalProject下载gtest源代码,然后使用add_subdirectory()将其添加到您的构build中。 这具有以下优点:

  • gtest是作为主构build的一部分构build的,所以它使用相同的编译器标志等,不需要在任何地方安装。
  • 不需要将gtest源添加到您自己的源代码树中。

以正常的方式使用,ExternalProject不会在configuration时(即运行CMake的时候)下载和解包,但你可以这样做。 我写了一篇关于如何做到这一点的博客文章,其中还包括一个通用的实现,它适用于任何使用CMake作为构build系统的外部项目,而不仅仅是gtest。 你可以在这里find它:

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

更新:上述方法现在也是googletest文档的一部分 。

使用ExternalProject模块和cmake导入库特性有一点不太复杂的解决scheme。 它从存储库检出代码,构build它并从构build的静态库(在我的系统上是libgtest.alibgtest_main.a )创build目标。

 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) 

您可能想要replaceSVN_REVISION或在这里添加LOG_CONFIGURELOG_BUILD选项。 在GTestGTestMain目标被创build之后,可以像这样使用它们:

 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) 

我的答案是基于firegurafiku的答案。 我通过以下方式对其进行了修改:

  1. 添加CMAKE_ARGSExternalProject_Add调用,所以它与msvc。
  2. 从文件位置获取gtest源代码而不是下载
  3. 添加便携式(用于MSVC和非MSVC)定义和使用IMPORTED_LOCATION
  4. 解决了调用set_target_properties的问题,在INTERFACE_INCLUDE_DIRECTORIES尚不存在的configuration时间不起作用,因为外部项目尚未build立。

我更喜欢把gtest作为一个外部项目,而不是直接将其源代码添加到我的项目中。 其中一个原因是因为当我search我的代码时,我不喜欢包含gtest源代码。 任何我的代码所需的特殊构build标志,也应该在构buildgtest时使用,可以在调用ExternalProject_Add添加到CMAKE_ARGS的定义中

这是我修改的方法:

 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)