2012-08-12 64 views
5

我正在使用Google Mock作为我的项目,并且说明指出最好与项目一起构建库,因为不同的编译器标志可能会引入错误。我不想将gmock /目录添加到我的存储库;我宁愿将源代码作为外部依赖项并将其插入到构建过程中。这使我想到了我的问题:我如何指示CMake将外部源目录拖放到构建中(即,将其构建在我的项目的构建目录中)?我在这里发现了一个similar question,但答案需要一个刚性目录放置,我宁愿有可配置。任何其他方式来做到这一点?将外部源代码目录添加到CMake内部

回答

6

我看到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() 
+0

+1虽然你还是会需要几个'include_directories'为'$ {} GOOGLE_MOCK_SOURCE_DIR电话/ googlemock/include'和'$ {GOOGLE_MOCK_SOURCE_DIR}/googlemock/gtest/include'我想。 – Fraser 2012-08-12 11:31:36

+0

另外,这并不真正“将外部源目录拖入内部版本”,但这可能并不重要。 – Fraser 2012-08-12 11:34:05

+0

它不起作用,除非源目录在我的树内(不是)。这是我尝试的第一件事。 :-) – 2012-08-12 12:38:09

7

您可以使用ExternalProject_Add对于这一点,因为它可以让您下载,从项目的构建树中配置和构建gmock,然后链接到gmock库。

@ arrowdodger的answer可能是更常见的方法去做这件事。使用他的方法,通常不会在构建树中使用gmock源代码。这可能是好的或坏的取决于你想要什么。

使用ExternalProject_Add时,每当您构建gmock或依赖目标时,gmock源将被拉动(svn update)。这使得构建稍微慢一点,但显然保持了源代码的最新性,并且方便(开发人员安装时,它的依赖性更小)。对于像gmock这样不经常更改的项目,尽管如此,更新所有时间的开销可能太多了。

以下CMakeLists.txt适用于Visual Studio 2010 & 2012 - 可能需要针对其他平台进行调整。特别是,gtest目前无法使用Visual Studio 2012(请参阅此bug report)构建该框,因此调用ExternalProject_Add调用中的修补程序文件和PATCH_COMMAND

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 .. 

这应该创造MyTest的/ src目录基本的main.cpp并创建一个项目文件(在Windows上为MyTest/build/Test.sln)

当您构建项目时,它应该将gmock源代码下载到MyTest/build/ThirdParty/src/googlemock,并在MyTest/build/ThirdParty/src/googlemock建造​​。然后,您应该能够成功运行MainTest目标。

有关ExternalProject_Add命令的进一步信息,请参阅this article entitled Building External Projects with CMake 2.8

下面是一个包含a gist此的CMakeLists.txt

+0

当它开始构建googlemock时,CMake忽略“CMAKE_ARCHIVE_OUTPUT_DIRECTORY_DEBUG”和“CMAKE_ARCHIVE_OUTPUT_DIRECTORY_RELEASE” 。我尝试将googlemock的CMakeLists.txt'cmake_minimum_required'修补为'cmake_minimum_required(VERSION 2.8.10)'。它仍然没有效果。我认为不可能对googletest或googlemock进行独特的调试和发布/优化构建。删除'debug'和'DebugLibs'部分(以及整个'优化'行),这将生成。 – gotgenes 2013-03-06 17:18:41

+0

什么平台?这与上面的工作方式一样,在Windows上使用单独的输出文件夹,使用VC++ 2010,VC++ 2012使用gtest添加一些小补丁。 – Fraser 2013-03-06 21:02:37

+0

我现在也添加了VC++ 2012的补丁代码。 – Fraser 2013-03-06 21:31:19

相关问题