CMake + GoogleTest

Acabo de descargar googletest, generé su archivo MAKE y lo construí. Ahora, necesito usarlo en mi proyecto de prueba.

Con CMake, se me ha aconsejado que no apunte directamente a las librerías gtest (usando include _directories o link_directories ) sino que use find_package() lugar.

El problema es que no existe un destino de instalación para el archivo MFP Gtest generado. No puedo entender cómo find_package(GTest REQUIRED) podría funcionar sin algún tipo de instalación. Además, no es posible colocar la carpeta gtest como una subcarpeta en mi proyecto.

Gracias por cualquier ayuda.

Este es un caso inusual; la mayoría de los proyectos especifican reglas de instalación.

El módulo ExternalProject_Add de CMake es quizás la mejor herramienta para este trabajo. Esto le permite descargar, configurar y crear gtest desde dentro de su proyecto, y luego vincularlo a las bibliotecas de gtest.

Probé el siguiente CMakeLists.txt en Windows con Visual Studio 10 y 11, y en Ubuntu usando GCC 4.8 y Clang 3.2, podría necesitar ajustar para otras plataformas / comstackdores:

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

Si crea esto como CMakeLists.txt en un directorio vacío (digamos MyTest ), entonces:

 cd MyTest mkdir build cd build cmake .. 

Esto debería crear un main.cpp básico en MyTest/src y crear un archivo de proyecto ( MyTest/build/Test.sln en Windows)

Cuando construya el proyecto, debe descargar los orígenes de prueba en MyTest/build/ThirdParty/src/googletest y comstackrlos en MyTest/build/ThirdParty/src/googletest-build . Entonces debería poder ejecutar el objective MainTest con éxito.

Ya pasó la pregunta original, pero para beneficio de los demás, es posible usar ExternalProject para descargar la fuente gtest y luego usar add_subdirectory() para agregarla a su comstackción. Esto tiene las siguientes ventajas:

  • gtest está construido como parte de tu comstackción principal, por lo que usa los mismos indicadores de comstackción, etc. y no necesita instalarse en ningún lugar.
  • No es necesario agregar las fonts de Gtest a su propio árbol fuente.

Si se usa de la forma habitual, ExternalProject no realizará la descarga ni el desempaquetado en el momento de la configuración (es decir, cuando se ejecuta CMake), pero puede hacerlo. He escrito una publicación de blog sobre cómo hacer esto que también incluye una implementación generalizada que funciona para cualquier proyecto externo que utilice CMake como su sistema de comstackción, no solo Gtest. Lo puedes encontrar aquí:

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

Actualización: el enfoque descrito anteriormente ahora también forma parte de la documentación de googletest .

Hay una solución un poco menos compleja que utiliza el módulo ExternalProject y la característica de bibliotecas importadas de cmake . Comprueba el código del repository, lo construye y crea el destino desde las bibliotecas estáticas construidas (son libgtest.a y libgtest_main.a en mi sistema).

 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) 

Es posible que desee reemplazar SVN_REVISION o agregar las opciones LOG_CONFIGURE y LOG_BUILD aquí. Después de GTest objectives GTest y GTestMain , se pueden usar así:

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

o, si tiene su propia función main() :

 add_executable(Test main.cc test1.cc test2.cc) target_link_libraries(Test GTest) 

Mi respuesta se basa en la respuesta de firegurafiku . Lo modifiqué de las siguientes maneras:

  1. Se agregó CMAKE_ARGS a la llamada ExternalProject_Add para que funcione con msvc.
  2. obtiene la fuente de Gtest desde una ubicación de archivo en lugar de descargar
  3. definición y uso agregado de portable (para MSVC y no MSVC) de IMPORTED_LOCATION
  4. Se solucionó el problema con la llamada a set_target_properties que no funcionaba en la hora de configuración cuando INTERFACE_INCLUDE_DIRECTORIES aún no existe porque el proyecto externo aún no se ha creado.

Prefiero mantener gtest como un proyecto externo en lugar de agregar su fuente directamente a mi proyecto. Una razón es porque no me gusta tener el código fuente Gtest incluido cuando estoy buscando mi código. Cualquier indicador de comstackción especial que necesite mi código y que también deba usarse al comstackr gtest se puede agregar a la definición de CMAKE_ARGS en la llamada a ExternalProject_Add

Aquí está mi enfoque modificado:

 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)