Как начать работу с GTest и CMake
недавно я был продан с помощью CMake для компиляции моих проектов на C++, и теперь хотел бы начать писать некоторые модульные тесты для моего кода. Я решил использовать утилиту Google Test, чтобы помочь с этим, но требуется некоторая помощь в начале работы.
весь день я читал различные руководства и примеры включают в себя букварь, an введение в IBM и некоторые вопросы по SO (здесь и здесь), а также другие источники я потерял из виду. Я понимаю, что есть много там, но почему-то у меня все еще возникают трудности.
в настоящее время я пытаюсь реализовать самый простой тест, чтобы подтвердить, что я скомпилировал/установил gtest правильно, и он не работает. Единственный исходный файл (testgtest.cpp) берется почти точно из этой предыдущий ответ:
#include <iostream>
#include "gtest/gtest.h"
TEST(sample_test_case, sample_test)
{
EXPECT_EQ(1, 1);
}
и мои связанные CMakeLists.текст выглядит следующим образом:
cmake_minimum_required(VERSION 2.6)
project(basic_test)
# Setup testing
enable_testing()
find_package(GTest REQUIRED)
include_directories(${GTEST_INCLUDE_DIR})
# Add test cpp file
add_executable(runUnitTests
testgtest.cpp
)
# Link test executable against gtest & gtest_main
target_link_libraries(runUnitTests ${GTEST_LIBRARY_DEBUG} ${GTEST_MAIN_LIBRARY_DEBUG})
add_test(
NAME runUnitTests
COMMAND runUnitTests
)
обратите внимание, что я выбрал ссылку против gtest_main вместо предоставления основного в конце файла cpp, поскольку я считаю, что это позволит мне легче масштабировать тестирование до нескольких файлов.
при создании генерируется .sln файл (в Visual C++ 2010 Express) я к сожалению получаю длинный список ошибок вида
2>msvcprtd.lib(MSVCP100D.dll) : error LNK2005: "public: virtual __thiscall std::basic_iostream<char,struct std::char_traits<char> >::~basic_iostream<char,struct std::char_traits<char> >(void)" (??1?$basic_iostream@DU?$char_traits@D@std@@@std@@UAE@XZ) already defined in gtestd.lib(gtest-all.obj)
что, я думаю, означает, что я не успешно связываюсь с библиотеками gtest. Я убедился, что при связывании с библиотеками отладки я попытался построить режим отладки.
EDIT
сделав еще несколько раскопок, я думаю, что моя проблема связана с типом библиотеки, в которую я создаю gtest. При построении gtest с CMake, если BUILD_SHARED_LIBS
не проверяется, и я связываю свою программу с ними .lib файлы я получаю ошибки, упомянутые выше. Однако, если BUILD_SHARED_LIBS
проверяется, то я произвожу набор .lib и .DLL-файл. Когда теперь связывание против них .lib файлы программа компилирует, но при запуске жалуется, что она не могу найти gtest.файл DLL.
в чем разница между a SHARED
и SHARED
библиотека, и если я выбираю не общий, почему это не работает? Есть ли вариант в CMakeLists.txt для моего проекта, который мне не хватает?
7 ответов:
решение включало в себя размещение исходного каталога gtest в качестве подкаталога вашего проекта. Я включил рабочие CMakeLists.txt ниже, если это кому-то полезно.
cmake_minimum_required(VERSION 2.6) project(basic_test) ################################ # GTest ################################ ADD_SUBDIRECTORY (gtest-1.6.0) enable_testing() include_directories(${gtest_SOURCE_DIR}/include ${gtest_SOURCE_DIR}) ################################ # Unit Tests ################################ # Add test cpp file add_executable( runUnitTests testgtest.cpp ) # Link test executable against gtest & gtest_main target_link_libraries(runUnitTests gtest gtest_main) add_test( runUnitTests runUnitTests )
вот полный рабочий пример, который я только что протестировал. Он загружает непосредственно из интернета, либо фиксированный тарбол, либо последний каталог subversion.
cmake_minimum_required (VERSION 3.1) project (registerer) ################################## # Download and install GoogleTest include(ExternalProject) ExternalProject_Add(gtest URL https://googletest.googlecode.com/files/gtest-1.7.0.zip # Comment above line, and uncomment line below to use subversion. # SVN_REPOSITORY http://googletest.googlecode.com/svn/trunk/ # Uncomment line below to freeze a revision (here the one for 1.7.0) # SVN_REVISION -r700 PREFIX ${CMAKE_CURRENT_BINARY_DIR}/gtest INSTALL_COMMAND "" ) ExternalProject_Get_Property(gtest source_dir binary_dir) ################ # Define a test add_executable(registerer_test registerer_test.cc) ###################################### # Configure the test to use GoogleTest # # If used often, could be made a macro. add_dependencies(registerer_test gtest) include_directories(${source_dir}/include) target_link_libraries(registerer_test ${binary_dir}/libgtest.a) target_link_libraries(registerer_test ${binary_dir}/libgtest_main.a) ################################## # Just make the test runnable with # $ make test enable_testing() add_test(NAME registerer_test COMMAND registerer_test)
скорее всего, в таких ошибках виновата разница в параметрах компилятора между вашим тестовым двоичным файлом и тестовой библиотекой Google. Вот почему рекомендуется ввести Google Test в исходную форму и построить его вместе с вашими тестами. Это очень легко сделать в CMake. Вы просто вызываете
ADD_SUBDIRECTORY
с путем к корню gtest, а затем вы можете использовать цели публичной библиотеки (gtest
иgtest_main
) определено есть. Существует больше справочной информации в этом CMake thread в группа googletestframework.[редактирование] Элемент
BUILD_SHARED_LIBS
опция действует только на Windows на данный момент. Он определяет тип библиотек, которые вы хотите построить CMake. Если вы установите его вON
, CMake будет строить их как DLL, а не статические библиотеки. В этом случае вы должны построить свои тесты с-DGTEST_LINKED_AS_SHARED_LIBRARY=1 и скопировать DLL-файлы, созданные CMake, в каталог с вашим тестовым двоичным файлом (CMake помещает их в отдельный выходной каталог по умолчанию). Если gtest в статической lib не работает для вас, проще не устанавливать эту опцию.
Вы можете получить лучшее из обоих миров. Можно использовать
ExternalProject
чтобы загрузить источник gtest, а затем использоватьadd_subdirectory()
, чтобы добавить его в сборку. Это имеет следующие преимущества:
- gtest построен как часть вашей основной сборки, поэтому он использует те же флаги компилятора и т. д. и, следовательно, избегает проблем, подобных тем, которые описаны в вопросе.
- нет необходимости добавлять источники gtest в свое собственное дерево источников.
используется в обычном режиме, ExternalProject не будет выполнять загрузку и распаковку во время настройки (т. е. при запуске CMake), но вы можете заставить его сделать это с помощью всего лишь небольшой работы. Я написал сообщение в блоге о том, как это сделать, которое также включает обобщенную реализацию, которая работает для любого внешнего проекта, который использует CMake в качестве своей системы сборки, а не только gtest. Вы можете найти их здесь:
обновление: этот подход теперь тоже часть документации googletest.
сделав еще несколько раскопок, я думаю, что моя проблема связана с типом библиотеки, в которую я создаю gtest. При построении gtest с CMake, если BUILD_SHARED_LIBS не проверяется, и я связываю свою программу с ними .lib файлы я получаю ошибки, упомянутые выше. Однако, если BUILD_SHARED_LIBS проверяется, то я создаю набор .lib и .DLL-файл. Когда теперь связывание против них .lib-файлы программа компилируется, но при запуске жалуется, что не может найти gtest.файл DLL.
это потому, что вы должны добавить-DGTEST_LINKED_AS_SHARED_LIBRARY=1 к определениям компилятора в вашем проекте, если вы хотите использовать gtest в качестве общей библиотеки.
вы также можете использовать статические библиотеки, если вы скомпилировали его с опцией gtest_force_shared_crt для устранения ошибок, которые вы видели.
Мне нравится библиотека, но добавление ее в проект-это настоящая боль. И у вас нет никаких шансов сделать это правильно, если вы не копать (и взломать) в файлы gtest cmake. Стыд. В частности, мне не нравится идея добавления gtest в качестве источника. :)
ваши и Владлосевских решения, вероятно, лучше, чем мои. Если вы хотите решение грубой силы, однако, попробуйте это:
SET(CMAKE_EXE_LINKER_FLAGS /NODEFAULTLIB:\"msvcprtd.lib;MSVCRTD.lib\") FOREACH(flag_var CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE CMAKE_CXX_FLAGS_MINSIZEREL CMAKE_CXX_FLAGS_RELWITHDEBINFO) if(${flag_var} MATCHES "/MD") string(REGEX REPLACE "/MD" "/MT" ${flag_var} "${${flag_var}}") endif(${flag_var} MATCHES "/MD") ENDFOREACH(flag_var)
самые простые CMakeLists.txt я дистиллировал из ответов в этой теме и некоторые проб и ошибок:
project(test CXX C) cmake_minimum_required(VERSION 2.6.2) #include folder contains current project's header filed include_directories("include") #test folder contains test files set (PROJECT_SOURCE_DIR test) add_executable(hex2base64 ${PROJECT_SOURCE_DIR}/hex2base64.cpp) # Link test executable against gtest nothing else required target_link_libraries(hex2base64 gtest pthread)
Gtest уже должен быть установлен в вашей системе.