Я использую Google Mock для своего проекта, и в инструкциях говорится, что лучше собирать библиотеку вместе с проектом, потому что разные флаги компилятора могут привести к ошибкам. Я не хочу добавлять каталог gmock/ в свой репозиторий; Я бы предпочел, чтобы источники были внешней зависимостью и подключались к моему процессу сборки. Что подводит меня к моему вопросу: как я могу указать CMake вытащить внешний исходный каталог в сборку (т.е. построить его в каталоге сборки моего проекта)? Я нашел похожий вопрос здесь, но ответы требуют жесткого размещения каталога, и я бы предпочел, чтобы это настраивалось. Есть ли другой способ сделать это?
Добавить внешний исходный каталог в сборку CMake
Ответы (2)
Для этого можно использовать ExternalProject_Add
, поскольку он позволяет загружать, настраивать и собирать gmock из дерева сборки вашего проекта, а затем ссылаться на библиотеки gmock.
Однако ответ @arrowdodger, вероятно, является более обычным способом сделать это. Используя его метод, у вас обычно нет исходников gmock в дереве сборки. Это может быть хорошо или плохо, в зависимости от того, чего вы хотите.
Используя ExternalProject_Add
, исходники gmock извлекаются (обновление svn) каждый раз, когда вы создаете gmock или зависимую цель. Это делает сборку немного медленнее, но явно поддерживает актуальность исходных кодов и удобна (на одну зависимость меньше, чтобы разработчики устанавливали). Однако для такого проекта, как gmock, который меняется нечасто, накладные расходы на постоянное обновление могут быть для вас слишком большими.
Следующий файл CMakeLists.txt работает с Visual Studio 2010 и 2012 — возможно, его нужно настроить для других платформ. В частности, в настоящее время gtest не может создать коробку с помощью Visual Studio 2012 (см. этот отчет об ошибке), следовательно, файл исправления и PATCH_COMMAND
в вызове ExternalProject_Add
.
cmake_minimum_required(VERSION 2.8.8 FATAL_ERROR)
project(Test)
# Create main.cpp which uses gmock
file(WRITE src/main.cpp "#include \"gmock/gmock.h\"\n\n")
file(APPEND src/main.cpp "struct A {\n virtual void Do() {}\n};\n\n")
file(APPEND src/main.cpp "struct MockA : public A {\n MOCK_METHOD0(Do, void());\n};\n\n")
file(APPEND src/main.cpp "TEST(A, Do) {\n")
file(APPEND src/main.cpp " MockA mock_a;\n")
file(APPEND src/main.cpp " EXPECT_CALL(mock_a, Do()).Times(testing::AtLeast(1));\n")
file(APPEND src/main.cpp " mock_a.Do();\n}\n\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 643)\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")
file(APPEND gtest.patch "Index: include/gtest/internal/gtest-tuple.h\n")
file(APPEND gtest.patch "===================================================================\n")
file(APPEND gtest.patch "--- include/gtest/internal/gtest-tuple.h (revision 643)\n")
file(APPEND gtest.patch "+++ include/gtest/internal/gtest-tuple.h (working copy)\n")
file(APPEND gtest.patch "@@ -1,3 +1,4 @@\n")
file(APPEND gtest.patch "+#include <tuple> /*\n")
file(APPEND gtest.patch " // This file was GENERATED by command:\n")
file(APPEND gtest.patch " // pump.py gtest-tuple.h.pump\n")
file(APPEND gtest.patch " // DO NOT EDIT BY HAND!!!\n")
file(APPEND gtest.patch "@@ -197,8 +198,8 @@\n")
file(APPEND gtest.patch " class tuple<> {\n")
file(APPEND gtest.patch " public:\n")
file(APPEND gtest.patch " tuple() {}\n")
file(APPEND gtest.patch "- tuple(const tuple& /* t */) {}\n")
file(APPEND gtest.patch "- tuple& operator=(const tuple& /* t */) { return *this; }\n")
file(APPEND gtest.patch "+ tuple(const tuple& t) {}\n")
file(APPEND gtest.patch "+ tuple& operator=(const tuple&) { return *this; }\n")
file(APPEND gtest.patch " };\n")
file(APPEND gtest.patch " \n")
file(APPEND gtest.patch " template <GTEST_1_TYPENAMES_(T)>\n")
file(APPEND gtest.patch "@@ -946,7 +947,7 @@\n")
file(APPEND gtest.patch " template <>\n")
file(APPEND gtest.patch " struct SameSizeTuplePrefixComparator<0, 0> {\n")
file(APPEND gtest.patch " template <class Tuple1, class Tuple2>\n")
file(APPEND gtest.patch "- static bool Eq(const Tuple1& /* t1 */, const Tuple2& /* t2 */) {\n")
file(APPEND gtest.patch "+ static bool Eq(const Tuple1&, const Tuple2&) {\n")
file(APPEND gtest.patch " return true;\n")
file(APPEND gtest.patch " }\n")
file(APPEND gtest.patch " };\n")
else()
file(WRITE gtest.patch "")
endif()
# Enable ExternalProject CMake module
include(ExternalProject)
# Set default ExternalProject root directory
set_directory_properties(PROPERTIES EP_PREFIX ${CMAKE_BINARY_DIR}/ThirdParty)
# Add gmock
ExternalProject_Add(
googlemock
SVN_REPOSITORY http://googlemock.googlecode.com/svn/trunk/
TIMEOUT 30
PATCH_COMMAND svn patch ${CMAKE_SOURCE_DIR}/gtest.patch ${CMAKE_BINARY_DIR}/ThirdParty/src/googlemock/gtest
# 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_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 for googlemock and googletest
ExternalProject_Get_Property(googlemock source_dir)
include_directories(${source_dir}/include)
include_directories(${source_dir}/gtest/include)
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 googlemock
add_dependencies(MainTest googlemock)
# Specify MainTest's link libraries
ExternalProject_Get_Property(googlemock binary_dir)
target_link_libraries(MainTest
debug ${binary_dir}/DebugLibs/${CMAKE_FIND_LIBRARY_PREFIXES}gmock${CMAKE_FIND_LIBRARY_SUFFIXES}
optimized ${binary_dir}/ReleaseLibs/${CMAKE_FIND_LIBRARY_PREFIXES}gmock${CMAKE_FIND_LIBRARY_SUFFIXES})
Если вы создадите это как CMakeLists.txt в пустом каталоге (скажем, MyTest), то:
cd MyTest
mkdir build
cd build
cmake ..
Это должно создать базовый файл main.cpp в MyTest/src и создать файл проекта (MyTest/build/Test.sln в Windows).
Когда вы создаете проект, он должен загрузить исходники gmock в MyTest/build/ThirdParty/src/googlemock и собрать их в MyTest/build/ThirdParty/src/googlemock-build. После этого вы сможете успешно запустить цель MainTest.
Дополнительные сведения о команде ExternalProject_Add
см. в этой статье, озаглавленной Создание внешних проектов с помощью CMake 2.8.
Вот суть, содержащая этот CMakeLists.txt
CMAKE_ARCHIVE_OUTPUT_DIRECTORY_DEBUG
и CMAKE_ARCHIVE_OUTPUT_DIRECTORY_RELEASE
при сборке googlemock. Я попытался исправить CMakeLists.txt cmake_minimum_required
Googlemock до cmake_minimum_required(VERSION 2.8.10)
. Это все еще не имеет никакого эффекта. Я не думаю, что возможно иметь отдельные отладочные и выпускные/оптимизированные сборки googletest или googlemock. Удалите части debug
и DebugLibs
(и всю строку optimized
), и это будет построено.
- person gotgenes; 06.03.2013
...ARCHIVE_OUTPUT_DIRECTORY...
на ...LIBRARY_OUTPUT_DIRECTORY...
? Также можно использовать CMAKE_<CONFIG>_POSTFIX
, например -DCMAKE_DEBUG_POSTFIX=-d
- person Fraser; 08.03.2013
Я вижу, что Google Mock поддерживает CMake. В этом случае вы можете просто добавить эту строку
add_subdirectory(${GOOGLE_MOCK_SOURCE_DIR})
в корень CMakeLists.txt
и позволить пользователю установить переменную GOOGLE_MOCK_SOURCE_DIR
на этапе настройки:
set(GOOGLE_MOCK_SOURCE_DIR "" CACHE PATH "Path to the GMock source")
if(NOT ${GOOGLE_MOCK_SOURCE_DIR} OR NOT EXISTS "${GOOGLE_MOCK_SOURCE_DIR}/CMakeLists.txt")
message(FATAL_ERROR "GOOGLE_MOCK_SOURCE_DIR isn't set properly!")
endif()
include_directories
вызовов для ${GOOGLE_MOCK_SOURCE_DIR}/googlemock/include
и ${GOOGLE_MOCK_SOURCE_DIR}/googlemock/gtest/include
, я думаю.
- person Fraser; 12.08.2012