gtest - CMake+GoogleTest
github gtest (4)
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 / compiladores:
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 compilarlos en MyTest/build/ThirdParty/src/googletest-build
. Entonces debería poder ejecutar el objetivo MainTest con éxito.
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.
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 repositorio, 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
objetivos 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:
- Se agregó
CMAKE_ARGS
a la llamadaExternalProject_Add
para que funcione con msvc. - obtiene la fuente de Gtest desde una ubicación de archivo en lugar de descargar
- definición y uso agregado de portable (para MSVC y no MSVC) de IMPORTED_LOCATION
- 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 compilación especial que necesite mi código y que también deba usarse al compilar 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)
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 compilación. Esto tiene las siguientes ventajas:
- gtest está construido como parte de tu compilación principal, por lo que usa los mismos indicadores de compilación, etc. y no necesita instalarse en ningún lugar.
- No es necesario agregar las fuentes 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 compilació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 .