2015-05-04 4 views
7

Кажется, что CMake ExternalProject всегда предполагает, что корневой каталог внешнего проекта является исходным каталогом. Но что, если это не случай?CMake ExternalProject: как указать относительный путь к корню CMakeLists.txt?

Рассмотрим следующий пример:

Внешний проект использует эту структуру директорий:

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

В зависимости проекта libfoo настроен так:

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

Билд затем терпит неудачу с следующее сообщение об ошибке:

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

Так что, как указано в приведенной выше схеме директорий, CMake считает, что корень внешнего проекта

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

, когда, на самом деле, это

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

Мои попытки решить эту проблему:

  1. К сожалению, изменение аргумента SOURCE_DIR из ExternalProject сделал не работает, потому что значение этой переменной используется как место для , к которому клонирован git-репозиторий libfoo. Это приводит к рекурсивному иждивенцу, который нельзя сломать.

  2. Изменение формата каталога libfoo соответствует ExternalProject. Очевидно, что это сработает, но оно может не работать для других (только для чтения) сторонних библиотек.

  3. Нарушение этапа обновления/исправления ExternalProject, например. с указанием

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

    Это работает, но это хаки и очень подвержено неудаче с другими внешними проектами.

  4. Здание на solution to another problem: добавьте временное CMakeLists.txt в том месте, где его принимает CMake. Этот временный файл затем включает фактическую 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 
    ) 
    

    Это работает, как хорошо и чувствует себя лучше, чем предыдущее решение.

Однако делает более изящным существуют, чтобы сделать то же самое?

ответ

9

Я подал a merge request, чтобы добавить SOURCE_SUBDIR вариант ExternalProject_Add, который решит этот прецедент. Надеюсь, он будет доступен в CMake 3.7. (Вы также можете скопировать ExternalProject*.cmake локально в свой собственный проект, чтобы сразу же воспользоваться функцией.)

+1

Функция была принята и доступна с CMake 3.7: https://cmake.org/cmake/help/v3.7/module/ExternalProject.html – Matthew

1

Вы можете использовать

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

ExternalProject_Add вызов.Это обозначает фактический каталог источника.

+0

К сожалению, это невозможно, и это было первое, что я попробовал (см. Вопрос 1.). В вашем примере репозиторий git клонируется в '/ path/to/build-dir/EP_libfoo/src/libfoo/libfoo'. И теперь я хотел бы, чтобы CMake использовал '/ path/to/build-dir/EP_libfoo/src/libfoo/libfoo/libfoo' (3x libfoo) как путь к корневому CMakeLists.txt (это своего рода циклическая зависимость) – nils

+0

Просто быстрое обновление: при условии, что я клонировал репозиторий 'libfoo' * вручную *, я мог бы использовать ваше предлагаемое решение (вместо указания' GIT_REPOSITORY'). Возможно, это то, что вы имели в виду. Однако, загрузка вручную зависимостей на самом деле не является вариантом, поскольку она слишком подвержена ошибкам. – nils

0

Я боролся с той же проблемой в проекте, над которым я работаю, и это решение, с которым я смог придумать. Это приводит к тому, что ExternalProject не используется для обработки git, но приводит к тому же поведению, насколько я мог рассказать.

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

Вот простое решение

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

В принципе вы разбить его на две части. Первый, чтобы получить источник, а второй - увеличить объем программного обеспечения. Я вручную создаю ссылки на заголовки, поэтому парсер kdevelop не должен разбирать весь проект.

0

Для тех, кто все еще ищет ответ: попробуйте указать 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

Вы можете просто переписать cmake команда муравья установила путь к CMakeLists.txt вручную. Например

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") 
Смежные вопросы