2015-05-04 29 views
7

Sembra che CMake ExternalProject assuma sempre la directory radice del progetto esterno come directory di origine. Ma cosa succede se questo non è il caso ?CMake ExternalProject: come specificare il percorso relativo alla radice CMakeLists.txt?

consideri il seguente esempio:

Il progetto esterno utilizza questo layout directory:

libfoo.git     <--- ExternalProject assumes this as source dir. 
├── ... 
└── libfoo     <--- However, the actual source directory is this! 
   ├── CMakeLists.txt 
   └── ... 

Nel progetto a seconda libfoo è configurato in questo modo:

ExternalProject_Add(libfoo 
    PREFIX   "${CMAKE_CURRENT_BINARY_DIR}/EP_libfoo" 
    GIT_REPOSITORY "<link to remote which hosts libfoo.git>" 
    GIT_TAG   "<some hash>" 
) 

La compilazione fallisce poi con il seguente messaggio di errore:

$ cmake -H/path/to/source-dir -B/path/to/build-dir 
... 
$ cmake --build /path/to/build-dir/ --target all 
... 
CMake Error: The source directory "/path/to/build-dir/EP_libfoo/src/libfoo" does not appear to contain CMakeLists.txt. 
... 
$ 

Così, come sottolineato nella struttura delle directory di cui sopra, CMake pensa che la radice del progetto esterno è

/path/to/build-dir/EP_libfoo/src/libfoo 

quando, in realtà, è

/path/to/build-dir/EP_libfoo/src/libfoo/libfoo 

i miei tentativi di risolvere questo problema:

  1. Purtroppo, cambiando l'argomento SOURCE_DIR del ExternalProject ha funzionato con , poiché il valore di questa variabile viene utilizzato come posizione su in cui è clonato il repository git di libfoo. Ciò si traduce in un inferno ricorsivo di dipendenza che non può essere rotto.

  2. Modifica del layout di directory di libfoo in conformità con ExternalProject. Ovviamente, questo potrebbe funzionare ma potrebbe non funzionare per altre librerie di terze parti (di sola lettura) .

  3. Abuso della fase di aggiornamento/patch di ExternalProject, ad es. specificando

    set(EP_LIBFOO_DIR "${CMAKE_CURRENT_BINARY_DIR}/EP_libfoo") 
    
    ExternalProject_Add(libfoo 
        PREFIX   "${EP_LIBFOO_DIR}" 
        GIT_REPOSITORY "<link to remote which hosts libfoo.git>" 
        GIT_TAG   "<some hash>" 
    
        # Copy the content of `<...>/libfoo/libfoo` into `<...>/libfoo`. 
        # Note to self: using symlinks instead copying is too platform-specific. 
        PATCH_COMMAND  ${CMAKE_COMMAND} -E copy_directory "${EP_LIBFOO_DIR}/src/libfoo/libfoo" "${EP_LIBFOO_DIR}/src/libfoo" 
    ) 
    

    Questo funziona ma è maniacale e molto incline a fallire con altri progetti esterni.

  4. Edificio su solution to another problem: aggiungere uno temporaneo CMakeLists.txt nella posizione in cui CMake lo assume. Questo file temporaneo include poi la CMakeLists.txt attuale:

    set(EP_LIBFOO_DIR "${CMAKE_CURRENT_BINARY_DIR}/EP_libfoo") 
    set(GENERATED_DIR "${CMAKE_BINARY_DIR}/generated") 
    
    file(MAKE_DIRECTORY ${GENERATED_DIR}) 
    file(WRITE ${GENERATED_DIR}/CMakeLists.txt 
        "cmake_minimum_required(VERSION 3.0)\n" 
        "add_subdirectory(libfoo)\n" 
    ) 
    
    ExternalProject_Add(libfoo 
        PREFIX   "${EP_LIBFOO_DIR}" 
        GIT_REPOSITORY "<link to remote which hosts libfoo.git>" 
        GIT_TAG   "<some hash>" 
    
        # Copy the 
        UPDATE_COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_BINARY_DIR}/generated/CMakeLists.txt ${EP_LIBFOO_DIR}/src/libfoo 
    ) 
    

    Questo funziona come bene e si sente meglio rispetto alla soluzione precedente.

Tuttavia, fa un più elegante esistono per fare lo stesso?

risposta

9

Ho inviato a merge request per aggiungere un'opzione SOURCE_SUBDIR a ExternalProject_Add che risolverà questo caso d'uso. Spero che sarà disponibile in CMake 3.7. (È possibile anche copiare ExternalProject*.cmake localmente nel proprio progetto di prendere subito il vantaggio della funzionalità.)

+1

La funzione è stata accettata ed è disponibile a partire da CMake 3.7: https://cmake.org/cmake/help/v3.7/module/ExternalProject.html – Matthew

1

È possibile utilizzare

SOURCE_DIR /path/to/build-dir/EP_libfoo/src/libfoo/libfoo 

ExternalProject_Add chiamata.Questo indica la vera directory dei sorgenti.

+0

Sfortunatamente, non è possibile ed è stata la prima cosa che ho provato (vedere 1. nella domanda). Nel tuo esempio il repository git è clonato in '/ path/to/build-dir/EP_libfoo/src/libfoo/libfoo'. E ora vorrei che CMake usasse '/ path/to/build-dir/EP_libfoo/src/libfoo/libfoo/libfoo' (3x libfoo) come percorso della radice CMakeLists.txt (è una sorta di dipendenza ciclica) – nils

+0

Solo un rapido aggiornamento: ammesso che io abbia clonato manualmente il repository di 'libfoo' * * Potrei usare la soluzione suggerita (invece di specificare' GIT_REPOSITORY'). Forse è quello che intendevi. Tuttavia, il download manuale delle dipendenze non è realmente un'opzione poiché è troppo soggetto a errori. – nils

0

Ho lottato con lo stesso problema in un progetto a cui sto lavorando e questa è la soluzione che sono riuscito a trovare. Il risultato è di non usare ExternalProject per la gestione di git, ma comporta lo stesso comportamento per quanto ho potuto dire.

CMakeLists.txt

include(ExternalProject) 
set(libfoo_prefix ${CMAKE_HOME_DIRECTORY}/libfoo) 

# during generation remove any previous repo and clone. 
file(REMOVE_RECURSE ${libfoo_prefix}) 
execute_process(
    COMMAND git clone <link to remote which hosts libfoo.git> 
    WORKING_DIRECTORY ${CMAKE_HOME_DIRECTORY}) 

# Add the external project. 
ExternalProject_Add(libfoo 
    PREFIX ${libfoo_prefix} 
    SOURCE_DIR ${libfoo_prefix}/libfoo) 
# As part of the pre-build step update the git repo. 
add_custom_command(
    TARGET libfoo 
    PRE_BUILD 
    COMMAND ${CMAKE_COMMAND} -P GitPull.cmake) 

GitPull.cmake

execute_process(
    COMMAND git pull origin master 
    WORKING_DIRECTORY ${CMAKE_SOURCE_DIRECTORY}/libfoo) 
0

Ecco una soluzione semplice

set(EXTERNAL_PROJECTS "") 
set(EXTERNAL_LIBS "") 
include(ExternalProject) 

# Set compiler(s) per project as required to CMAKE_ARGS in ExternalProject_Add(..). 
#  -DCMAKE_C_COMPILER=${CMAKE_C_COMPILER} 
#  -DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER} 
set(EXTERNAL_CMAKE_ARGS -D CMAKE_SYSROOT=${CMAKE_SYSROOT} 
    -DCMAKE_FIND_ROOT_PATH_MODE_PROGRAM=${CMAKE_FIND_ROOT_PATH_MODE_PROGRAM} 
    -DCMAKE_FIND_ROOT_PATH_MODE_LIBRARY=${CMAKE_FIND_ROOT_PATH_MODE_LIBRARY} 
    -DCMAKE_FIND_ROOT_PATH_MODE_INCLUDE=${CMAKE_FIND_ROOT_PATH_MODE_INCLUDE} 
    -DCMAKE_FIND_ROOT_PATH_MODE_PACKAGE=${CMAKE_FIND_ROOT_PATH_MODE_PACKAGE} 
) 

set(AIOUSB aiousb) 
set(AIOUSB_SRC aiousb_src) 
set(EXTERNAL_PROJECTS ${EXTERNAL_PROJECTS} ${AIOUSB_SRC} ${AIOUSB}) 
set(AIOUSB_SRC_GIT_BRANCH "master") 

ExternalProject_Add(${AIOUSB_SRC} 
    PREFIX ${AIOUSB_SRC} 
    GIT_REPOSITORY "https://github.com/accesio/AIOUSB.git" 
    GIT_TAG ${AIOUSB_SRC_GIT_BRANCH} 
    UPDATE_COMMAND "" 
    CONFIGURE_COMMAND "" 
    BUILD_COMMAND "" 
    BUILD_BYPRODUCTS ${CMAKE_BINARY_DIR}/${AIOUSB_SRC}/src/${AIOUSB_SRC}/AIOUSB/CMakeLists.txt 
    INSTALL_COMMAND "" 
) 

set(AIOUSB_LIBRARY ${CMAKE_BINARY_DIR}/${AIOUSB}/src/${AIOUSB}-build/lib/${CMAKE_STATIC_LIBRARY_PREFIX}${AIOUSB}${CMAKE_STATIC_LIBRARY_SUFFIX}) 
set(AIOUSBCPP_LIBRARY ${CMAKE_BINARY_DIR}/${AIOUSB}/src/${AIOUSB}-build/lib/${CMAKE_STATIC_LIBRARY_PREFIX}${AIOUSB}cpp${CMAKE_STATIC_LIBRARY_SUFFIX}) 

ExternalProject_Add(${AIOUSB} 
    DEPENDS ${AIOUSB_SRC} 
    PREFIX ${AIOUSB} 
    DOWNLOAD_COMMAND "" 
    SOURCE_DIR ${CMAKE_BINARY_DIR}/${AIOUSB_SRC}/src/${AIOUSB_SRC}/AIOUSB 
    CMAKE_ARGS ${EXTERNAL_CMAKE_ARGS} -DCMAKE_C_COMPILER=${CMAKE_C_COMPILER} -DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER} 
     -DBUILD_SAMPLES:BOOL=OFF -DBUILD_AIOUSB_SHARED:BOOL=OFF -DBUILD_AIOUSBDBG_SHARED:BOOL=OFF -DBUILD_AIOUSBCPP_SHARED:BOOL=OFF 
     -DBUILD_AIOUSBCPPDBG_SHARED:BOOL=OFF 
    BUILD_BYPRODUCTS ${CMAKE_SOURCE_DIR}/src/lib/include/${AIOUSB} ${CMAKE_BINARY_DIR}/${AIOUSB}/src/${AIOUSB}-build/lib/libaiousb.a 
     ${CMAKE_BINARY_DIR}/${AIOUSB}/src/${AIOUSB}-build/lib/libaiousbcpp.a 
    INSTALL_COMMAND rm -rf ${CMAKE_SOURCE_DIR}/src/lib/include/${AIOUSB} && mkdir -p ${CMAKE_SOURCE_DIR}/src/lib/include/${AIOUSB} && 
     echo "ln -sr ${CMAKE_BINARY_DIR}/${AIOUSB_SRC}/src/${AIOUSB_SRC}/AIOUSB/lib/*.h ${CMAKE_SOURCE_DIR}/src/lib/include/${AIOUSB}" | bash 
) 

set(LIBAIOUSB libaiousb) 
add_library(${LIBAIOUSB} STATIC IMPORTED) 
set_property(TARGET ${LIBAIOUSB} PROPERTY IMPORTED_LOCATION ${AIOUSB_LIBRARY}) 
add_dependencies(${LIBAIOUSB} ${AIOUSB}) 
set(EXTERNAL_LIBS ${EXTERNAL_LIBS} ${LIBAIOUSB}) 

set(LIBAIOUSBCPP libaiousbcpp) 
add_library(${LIBAIOUSBCPP} STATIC IMPORTED) 
set_property(TARGET ${LIBAIOUSBCPP} PROPERTY IMPORTED_LOCATION ${AIOUSBCPP_LIBRARY}) 
add_dependencies(${LIBAIOUSBCPP} ${AIOUSB}) 
set(EXTERNAL_LIBS ${EXTERNAL_LIBS} ${LIBAIOUSBCPP}) 

... 
add_dependencies(${PROJECT_NAME} ${EXTERNAL_PROJECTS}) 
... 
also add 
target_link_libraries(${PROJECT_NAME} ${EXTERNAL_LIBS} ...) 

In pratica si rompe in due parti. Il primo solo per ottenere la fonte e il secondo per installare il software. Creo manualmente i collegamenti alle intestazioni in modo che il parser di kdevelop non debba analizzare l'intero progetto.

0

Per coloro che ancora alla ricerca di una risposta: tenta di specificare CONFIGURE_COMMAND:

ExternalProject_Add(libfoo 
    GIT_REPOSITORY "<link to remote which hosts libfoo.git>" 
    GIT_TAG "<some hash>" 
    SOURCE_DIR "where to put the source" 
    CONFIGURE_COMMAND 
     "${CMAKE_COMMAND}" 
     "-HPathToDirectoryWhereTheCMakeListsAre" 
     "-BWhereToBuild" 
    BUILD_COMMAND 
     "${CMAKE_COMMAND}" --build "Path to the directory where you are building (specified with -B flag in CONFIGURE_COMMAND)" 
) 
1

Si può semplicemente sovrascrivere cmake comando ant set percorso a CMakeLists.txt manualmente. Ad esempio

ExternalProject_Add(libfoo 
    PREFIX   "${EP_LIBFOO_DIR}" 
    GIT_REPOSITORY "<link to remote which hosts libfoo.git>" 
    GIT_TAG   "<some hash>" 
    CONFIGURE_COMMAND ${CMAKE_COMMAND} -G${CMAKE_GENERATOR} "${EP_LIBFOO_DIR}/src/libfoo/libfoo")