2015-05-04 4 views
7

Es scheint, dass CMake ExternalProject immer das Stammverzeichnis des externen Projekts als Quellverzeichnis annimmt. Aber was, wenn das nicht der Fall ist?CMake ExternalProject: Wie wird der relative Pfad zur Wurzel CMakeLists.txt angegeben?

Betrachten Sie das folgende Beispiel:

Das externe Projekt diese Verzeichnisstruktur verwendet:

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

Im abhängig Projekt libfoo wie folgt konfiguriert ist:

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

Der Build dann nicht mit die folgende Fehlermeldung:

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

So, wie in der obigen Verzeichnisstruktur wies darauf hin, denkt CMake, dass die Wurzel des externen Projekt

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

ist, wenn in der Tat, es

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

Meine Versuche ist zu dieses Problem lösen:

  1. Leider SOURCE_DIR vondas Argument zu ändernhat nicht funktioniert, weil der Wert dieser Variablen als Speicherort verwendet wird, die das Git-Repository von libfoo geklont ist. Dies führt zu einer rekursiven Abhängigkeitshölle, die nicht gebrochen werden kann.

  2. Ändern des Verzeichnislayouts von libfoo, um zu entsprechen. Offensichtlich würde dies funktionieren, aber es funktioniert möglicherweise nicht für andere (schreibgeschützte) Third-Party-Bibliotheken.

  3. Missbrauch des Aktualisierungs/Patch-Schritts von , z.B. durch Angabe

    Das funktioniert, aber es ist hackish und sehr anfällig für andere externe Projekte.

  4. Aufbauend auf der solution to another problem: fügen Sie eine temporäre CMakeLists.txt an der Stelle, wo CMake es annimmt. Diese temporäre Datei beinhaltet dann die eigentliche CMakeLists.txt:

    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 
    ) 
    

    Dies funktioniert auch und fühlt sich besser als die bisherige Lösung.

Allerdings ist ein elegantere bestehen, das gleiche zu tun?

Antwort

9

Ich habe a merge request reichte eine SOURCE_SUBDIR Option ExternalProject_Add hinzuzufügen, die diesen Anwendungsfall lösen. Hoffentlich wird es in CMake 3.7 verfügbar sein. (Sie können auch ExternalProject*.cmake lokal in das eigene Projekt kopieren Vorteil der Funktion sofort zu übernehmen.)

+1

Die Funktion wurde akzeptiert und ist ab CMake 3.7 verfügbar: https://cmake.org/cmake/help/v3.7/module/ExternalProject.html – Matthew

1

können Sie

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

ExternalProject_Add Aufruf verwenden.Dies bezeichnet das eigentliche Quellverzeichnis.

+0

Leider ist das nicht möglich und es war das erste, was ich versuchte (siehe 1. in der Frage). In Ihrem Beispiel ist das Git-Repository in '/ path/to/build-dir/EP_libfoo/src/libfoo/libfoo' geklont. Und nun möchte Ich mag CMake verwenden '/ path/to/build-dir/EP_libfoo/src/libfoo/libfoo/libfoo' (3x libfoo) als Pfad zum Stamm CMakeLists.txt (es ist eine Art zyklischer Abhängigkeit) – nils

+0

Nur ein kurzes Update: vorausgesetzt, dass ich das Repository von 'libfoo' * manuell geklont habe * könnte ich Ihre vorgeschlagene Lösung verwenden (anstatt' GIT_REPOSITORY' zu spezifizieren). Vielleicht hast du das gemeint. Das manuelle Herunterladen von Abhängigkeiten ist jedoch keine echte Option, da es zu fehleranfällig ist. – nils

0

Ich habe in einem Projekt mit dem gleichen Problem zu kämpfen, dass ich arbeite und das ist die Lösung, die ich die Lage gewesen, mit zu kommen. Es führt dazu, dass ich ExternalProject nicht für die Git-Behandlung verwende, aber das gleiche Verhalten, soweit ich es feststellen konnte.

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

Hier ist eine einfache Lösung

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

Grundsätzlich Sie es in zwei Teile brechen. Das erste, um die Quelle zu bekommen, und das zweite, um die Software zu erweitern. Ich erstelle manuell Links zu den Headern, so dass der Parser von kdevelop nicht das gesamte Projekt analysieren muss.

0

Für diejenigen, die immer noch nach einer Antwort suchen: versuchen CONFIGURE_COMMAND angeben:

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

Sie können einfach überschreiben Cmake Befehl ant set Pfad zum CMakeLists.txt manuell. Zum Beispiel

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") 
Verwandte Themen