CMake + GoogleTest
我刚刚下载了googletest,用CMake生成了它的makefile并构build了它。 现在,我需要在我的testing项目中使用它。
对于CMake,我build议不要直接指向gtest库(使用include _directories
或link_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.a
和libgtest_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_CONFIGURE
和LOG_BUILD
选项。 在GTest
和GTestMain
目标被创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的答案。 我通过以下方式对其进行了修改:
- 添加
CMAKE_ARGS
到ExternalProject_Add
调用,所以它与msvc。 - 从文件位置获取gtest源代码而不是下载
- 添加便携式(用于MSVC和非MSVC)定义和使用IMPORTED_LOCATION
- 解决了调用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)