2012-08-12 14 views
5

Sto utilizzando Google Mock per il mio progetto e le istruzioni dicono che è meglio costruire la libreria insieme al progetto, perché i diversi flag del compilatore possono introdurre bug. Non voglio aggiungere la directory gmock/al mio repository; Preferisco avere le fonti come dipendenza esterna e collegarle al mio processo di compilazione. Il che mi porta alla mia domanda: come posso istruire CMake a inserire la directory sorgente esterna nella compilazione (ad esempio, compilarla nella directory di costruzione del mio progetto)? Ho trovato uno similar question qui, ma le risposte richiedono un posizionamento di directory rigido e preferirei che fosse configurabile. Qualche altro modo per farlo?Aggiungere una directory di origine esterna a una build di CMake

risposta

6

Vedo che Google Mock supporta CMake. In questo caso si può solo aggiungere questa riga

add_subdirectory(${GOOGLE_MOCK_SOURCE_DIR}) 

nella radice CMakeLists.txt e lasciare all'utente di impostare GOOGLE_MOCK_SOURCE_DIR variabile durante la fase di configurazione:

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 Anche se avresti ancora bisogno di un paio di 'include_directories' richiede' $ {} GOOGLE_MOCK_SOURCE_DIR/googlemock/include' e '$ {GOOGLE_MOCK_SOURCE_DIR}/googlemock/gtest/include' Penso. – Fraser

+0

Inoltre, questo in realtà non "tira la directory del sorgente esterno nella build", ma forse non è importante. – Fraser

+0

Non funzionerà, a meno che la directory di origine non si trovi all'interno del mio albero (non lo è). Questa è la prima cosa che ho provato. :-) –

7

si potrebbe usare ExternalProject_Add per questo, dal momento che consente di scaricare , configura e costruisci gmock dall'interno dell'albero del tuo progetto, quindi collega alle librerie gmock.

@ arrowdodger's answer è probabilmente il modo più comune per andare su questo tuttavia. Usando il suo metodo, normalmente non hai i sorgenti di gmock nella tua struttura di costruzione. Questo potrebbe essere buono o cattivo a seconda di ciò che desideri.

Utilizzando ExternalProject_Add, le origini di gmock vengono scaricate (svn update) ogni volta che si genera gmock o una destinazione dipendente. Ciò rende la build leggermente più lenta, ma mantiene le fonti aggiornate ed è conveniente (è una dipendenza in meno per l'installazione degli sviluppatori). Per un progetto come gmock che non cambia spesso, il sovraccarico di aggiornamento in ogni momento potrebbe essere troppo per te.

Il seguente CMakeLists.txt funziona utilizzando Visual Studio 2010 & 2012 - potrebbe essere necessario adattarlo per altre piattaforme. In particolare, gtest al momento non riesce a costruire la scatola usando Visual Studio 2012 (vedi questo bug report), quindi il file di patch e PATCH_COMMAND nella chiamata 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}) 

Se si crea questo come CMakeLists.txt in una directory vuota (diciamo MyTest), quindi:

cd MyTest 
mkdir build 
cd build 
cmake .. 

Questo dovrebbe creare una base in main.cpp Mytest/src e creare un file di progetto (MyTest/build/Test.sln su Windows)

Quando si genera il progetto, è necessario scaricare i sorgenti di gmock su MyTest/build/ThirdParty/src/googlemock e crearli in MyTest/build/ThirdParty/src/googlemock-build. Dovresti quindi essere in grado di eseguire correttamente l'obiettivo MainTest.

Per ulteriori informazioni sul comando ExternalProject_Add, vedere this article entitled Building External Projects with CMake 2.8

Ecco a gist contenente questo CMakeLists.txt

+0

CMake ignora 'CMAKE_ARCHIVE_OUTPUT_DIRECTORY_DEBUG' e' CMAKE_ARCHIVE_OUTPUT_DIRECTORY_RELEASE' quando va a costruire googlemock . Ho provato a applicare patch a googlemock CMakeLists.txt 'cmake_minimum_required' a' cmake_minimum_required (VERSION 2.8.10) '. Non ha ancora effetto. Non penso sia possibile avere debug distinti e versioni ottimizzate di googletest o googlemock. Rimuovi le parti 'debug' e' DebugLibs' (e l'intera riga 'ottimizzata') e questo verrà creato. – gotgenes

+0

Quale piattaforma? Funziona come sopra con cartelle di output separate su Windows con VC++ 2010 e con VC++ 2012 con un paio di patch minori aggiunte a gtest. – Fraser

+0

Ho aggiunto anche il codice patch per VC++ 2012. – Fraser