CMakeLists: добавление исходных файлов из Github с помощью ExternalProject

Я пишу небольшую обёртку для библиотеки Beckhoff ADS. Я хотел бы установить файлы из папки AdsLib, но без использования файла CMake от Beckhoff.

Я просто хочу скопировать файлы, чтобы добавить их в свою библиотеку в свои собственные CMakeLists. Это отлично работает, если я копирую файлы вручную. Но я хотел бы построить напрямую, используя последние файлы из исходного кода Github.

Я перепробовал все возможные комбинации, которые смог найти здесь, в stackoverflow, но почему-то не смог заставить их работать.

cmake_minimum_required(VERSION 2.8.3)
project(ads_catkin)

find_package(catkin_simple REQUIRED)
catkin_simple()

include(ExternalProject)


ExternalProject_Add(ads
    PREFIX ${CMAKE_BINARY_DIR}/ads
    GIT_REPOSITORY https://github.com/Beckhoff/ADS.git
    GIT_TAG master
    CONFIGURE_COMMAND ""
    #GIT_TAG 6b3a03009a757cf651fe44d8be7b6df698028f0e
    UPDATE_COMMAND ""
    BUILD_COMMAND ""
    INSTALL_COMMAND ""
)

ExternalProject_Get_Property(ads source_dir)

cs_add_library(${PROJECT_NAME}
    ${source_dir}/AdsLib/AdsDef.cpp
)
cs_install()
cs_export()

В первый раз, когда я строю с помощью catkin_tools, это дает мне:

Errors     << ads_catkin:cmake /home/xxx/xxx_ws/logs/ads_catkin/build.cmake.000.log                                 
CMake Error at /home/xxx/xxx_ws/devel/share/catkin_simple/cmake/catkin_simple-extras.cmake:150 (add_library):
  Cannot find source file:

    /home/xxx/xxx/build/ads_catkin/ads/src/ads/AdsLib/AdsDef.cpp

  Tried extensions .c .C .c++ .cc .cpp .cxx .m .M .mm .h .hh .h++ .hm .hpp
  .hxx .in .txx
Call Stack (most recent call first):
  CMakeLists.txt:23 (cs_add_library)


CMake Error: CMake can not determine linker language for target: ads_catkin
CMake Error: Cannot determine link language for target "ads_catkin".

Затем, во второй раз, когда я запускаю инструмент сборки с тем же кодом, файлы фактически клонируются, но в итоге я получаю эту ошибку:

Errors     << ads_catkin:make /home/xxx/xxx_ws/logs/ads_catkin/build.make.000.log                                   
make[2]: *** No rule to make target 'CMakeFiles/ads_catkin.dir/build'.  Stop.
make[1]: *** [CMakeFiles/ads_catkin.dir/all] Error 2
make[1]: *** Waiting for unfinished jobs....
Cloning into 'ads'...
Already on 'master'
make: *** [all] Error 2

Кстати: cs_add_library — это форма catkin_simple для add_library и target_link_libraries.

Обновление: приближаемся... адаптируем решение от @Tsyvarev к моему файлу:

cmake_minimum_required(VERSION 2.8.3)
project(ads_catkin)

find_package(catkin_simple REQUIRED)
catkin_simple()

include(ExternalProject)


ExternalProject_Add(ads
    PREFIX ${CATKIN_DEVEL_PREFIX}/ads
    GIT_REPOSITORY https://github.com/Beckhoff/ADS.git
    GIT_TAG 6b3a03009a757cf651fe44d8be7b6df698028f0e
    #GIT_TAG master
    CONFIGURE_COMMAND ""
    UPDATE_COMMAND ""
    BUILD_COMMAND ""
    INSTALL_COMMAND ""
    BUILD_BYPRODUCTS 
        <SOURCE_DIR>/AdsLib/AdsDef.cpp
        <SOURCE_DIR>/AdsLib/AdsLib.cpp
        <SOURCE_DIR>/AdsLib/AmsConnection.cpp
        <SOURCE_DIR>/AdsLib/AmsPort.cpp
        <SOURCE_DIR>/AdsLib/AmsRouter.cpp
        <SOURCE_DIR>/AdsLib/Frame.cpp
        <SOURCE_DIR>/AdsLib/Log.cpp
        <SOURCE_DIR>/AdsLib/NotificationDispatcher.cpp
        <SOURCE_DIR>/AdsLib/Sockets.cpp
        <SOURCE_DIR>/AdsLib/AdsDef.h
        <SOURCE_DIR>/AdsLib/AdsLib.h
        <SOURCE_DIR>/AdsLib/AdsNotification.h
        <SOURCE_DIR>/AdsLib/AmsConnection.h
        <SOURCE_DIR>/AdsLib/AmsHeader.h
        <SOURCE_DIR>/AdsLib/AmsPort.h
        <SOURCE_DIR>/AdsLib/AmsRouter.h
        <SOURCE_DIR>/AdsLib/Frame.h
        <SOURCE_DIR>/AdsLib/Log.h
        <SOURCE_DIR>/AdsLib/NotificationDispatcher.h
        <SOURCE_DIR>/AdsLib/RingBuffer.h
        <SOURCE_DIR>/AdsLib/Router.h
        <SOURCE_DIR>/AdsLib/Semaphore.h
        <SOURCE_DIR>/AdsLib/Sockets.h
        <SOURCE_DIR>/AdsLib/wrap_endian.h
        <SOURCE_DIR>/AdsLib/wrap_socket.h
)

ExternalProject_Get_Property(ads SOURCE_DIR)


include_directories(
    ${SOURCE_DIR}/AdsLib
)

cs_add_library(AdsLib
    ${SOURCE_DIR}/AdsLib/AdsDef.cpp
    ${SOURCE_DIR}/AdsLib/AdsLib.cpp
    ${SOURCE_DIR}/AdsLib/AmsConnection.cpp
    ${SOURCE_DIR}/AdsLib/AmsPort.cpp
    ${SOURCE_DIR}/AdsLib/AmsRouter.cpp
    ${SOURCE_DIR}/AdsLib/Frame.cpp
    ${SOURCE_DIR}/AdsLib/Log.cpp
    ${SOURCE_DIR}/AdsLib/NotificationDispatcher.cpp
    ${SOURCE_DIR}/AdsLib/Sockets.cpp
)
add_dependencies(AdsLib ads)


cs_install()

install(DIRECTORY ${SOURCE_DIR}/AdsLib/
        DESTINATION ${CATKIN_PACKAGE_INCLUDE_DESTINATION}
        PATTERN ".cpp" EXCLUDE   
)

cs_export()

Я попытался включить файлы заголовков в свою библиотеку AdsLib. Но я все еще получаю сообщение об ошибке:

In file included from /home/xxx/xxx_ws/src/xxx/nav_controller/src/controller.cpp:19:0:
/home/xxx/xxx_ws/src/xxx/nav_controller/include/nav_controller/controller.h:27:10: fatal error: AdsLib.h: No such file or directory
 #include "AdsLib.h"
          ^~~~~~~~~~~~~~~~~
compilation terminated.
make[2]: *** [CMakeFiles/nav_controller.dir/src/controller.cpp.o] Error 1
make[2]: *** Waiting for unfinished jobs....
In file included from /home/xxx/xxx_ws/src/xxx/nav_controller/src/test.cpp:22:0:
/home/xxx/xxx_ws/src/xxx/nav_controller/include/nav_controller/controller.h:27:10: fatal error: AdsLib.h: No such file or directory
 #include "AdsLib.h"
          ^~~~~~~~~~~~~~~~~
compilation terminated.
make[2]: *** [CMakeFiles/nav_controller.dir/src/test.cpp.o] Error 1
make[1]: *** [CMakeFiles/nav_controller.dir/all] Error 2
make: *** [all] Error 2

person pixelpress    schedule 17.01.2020    source источник
comment
Не ясно, что может быть причиной проблемы. Предоставьте полный журнал CMake, включая сообщение об ошибке, в сообщении с вопросом. Было бы полезно, если бы вы включили в свой пост минимально воспроизводимый пример, так как опубликованный вами CMake не выглядит полным. ...   -  person squareskittles    schedule 17.01.2020
comment
Связано, если не дубликат: "> https://stackoverflow.com/questions/21223163/how-to-tell-cmake-to-download-some-necessary-header-files-more-precisely-glm-ma   -  person drescherjm    schedule 17.01.2020
comment
@squarekittles Я расширил пример, который теперь представляет собой полный CMakeLists.txt. Я использую инструменты сережки для сборки.   -  person pixelpress    schedule 17.01.2020
comment
@drescherjm Я видел это. Второй пример, кажется, соответствует тому, что я делаю...   -  person pixelpress    schedule 17.01.2020
comment
У вас нет BUILD_COMMAND "" или CONFIGURE_COMMAND ""   -  person drescherjm    schedule 17.01.2020
comment
Предоставьте полный журнал ошибок CMake. Описывать ошибку не очень полезно.   -  person squareskittles    schedule 17.01.2020
comment
Прошу прощения за неопределенность. Я обновил свой примерный код и ошибки, которые я получаю.   -  person pixelpress    schedule 17.01.2020
comment
Спасибо, теперь проблема более ясна. Я думаю, что ответы в этом сообщении помогут решить вашу проблему. По сути, ExternalProject_Add запускает время сборки, поэтому при запуске CMake еще не имеет доступа к артефактам внешнего проекта.   -  person squareskittles    schedule 17.01.2020
comment
Действительно, с удалением cs_add_library работает без ошибок. Попытка выяснить, как включить его раньше.   -  person pixelpress    schedule 17.01.2020
comment
Я до сих пор не понимаю, как решить эту проблему в соответствии с другой темой.   -  person pixelpress    schedule 17.01.2020
comment
Как было предложено в одном ответе, вы можете использовать execute_process(), чтобы получить исходный файл, который вам нужно загрузить и сделать доступным для использования во время настройки. Более современным подходом было бы использовать FetchContent, который загружает внешний контент во время настройки, а не во время сборки.   -  person squareskittles    schedule 17.01.2020
comment
FetchContent не подходит для CMake 3.10. Разве нет лучшего решения, чем с execute_process()? Я пробовал include_directories(${source_dir}) и add_library(${PROJECT_NAME} ${source_dir}/AdsLib/AdsDef.cpp) безуспешно.   -  person pixelpress    schedule 17.01.2020
comment
У вас есть ${SOURCE_DIR}/AdsLib/AdsDef.h файл. Таким образом, для включения этого файла в код с помощью #include <AdsLib/AdsDef.h> вам нужно настроить ${SOURCE_DIR} как включаемый каталог, а не ${SOURCE_DIR}/AdsLib, как вы это делаете.   -  person Tsyvarev    schedule 18.01.2020
comment
Даже после перехода на install(DIRECTORY ${SOURCE_DIR}/ DESTINATION ${CATKIN_GLOBAL_INCLUDE_DESTINATION} ) я получаю ту же ошибку.   -  person pixelpress    schedule 18.01.2020
comment
Включаемый каталог задается командой include_directories, а не командой install(DIRECTORY)... Так что вам нужно исправить первую команду, а не вторую.   -  person Tsyvarev    schedule 20.01.2020
comment
Я изменил включение на #include <AdsLib.h>, так как они делают это в исходном коде github. Но проблема не в этом.   -  person pixelpress    schedule 20.01.2020


Ответы (2)


Ошибка CMake Cannot find source file означает простую вещь: ничто не сообщает CMake, что данный исходный файл сгенерирован, а сам файл отсутствует.

Поскольку файл создается в ExternalProject_Add, вам необходимо настроить соответствующую зависимость целевого уровня:

add_dependency(ads_catkin ads)

Эта команда должна быть запущена после вызовов add_library() и ExternalProject_Add, которые создают соответствующие цели. Эта команда сообщает CMake, что библиотеку следует собирать только после выполнения всех шагов для внешнего проекта.

Вам все еще нужно сообщить CMake, что исходный файл сгенерирован. Для этого есть два способа.

  1. Установите свойство GENERATED:

    set_source_files_properties(${source_dir}/AdsLib/AdsDef.cpp PROPERTIES GENERATED TRUE)
    

    Это не позволяет CMake искать файл на этапе настройки.

  2. Файл списка в опции BYPRODUCTS для цели, которая его генерирует. Для цели, созданной командой ExternalProject_Add, это достигается дополнительной опцией этой команды.

    BUILD_BYPRODUCTS <SOURCE_DIR>/AdsLib/AdsDef.cpp
    

    Это также устанавливает свойство GENERATED для исходного файла, как и в первом случае. Но BYPRODUCTS также делает ваш проект пригодным для использования пользователями Ninja.

    (В приведенном выше варианте выражение <SOURCE_DIR> — это особый способ ссылки на исходный каталог ExternalProject. Его можно использовать для некоторых параметров ExternalProject, и BUILD_BYPRODUCTS — один из них).


Технически CMake должен быть достаточно умен, чтобы добавлять зависимости целевого уровня (эффект add_dependency(ads_catkin ads)) автоматически, когда он видит соответствующую опцию BYPRODUCTS. Но эта функция описана только для версии 3.16, и я не знаю, работает ли она в более старых версиях.

person Tsyvarev    schedule 17.01.2020
comment
Спасибо! Я пробовал это, но теперь мне все еще не хватает файлов заголовков в моей библиотеке сережек. Я обновил пост своим новым файлом. - person pixelpress; 18.01.2020
comment
Вроде установка не проблема. Дело в том, что включаемые файлы не связаны должным образом. Я попытался добавить catkin_package(INCLUDE_DIRS ${SOURCE_DIR}/AdsLib), так как cs_export экспортирует только включаемую папку. Но даже если я добавлю это в конец файла Cmake, я получаю ошибку, что файлы из внешнего проекта недоступны. - person pixelpress; 20.01.2020
comment
Этот ответ полностью правильный. Я хотел бы отметить, что есть также менее известный FetchContent Модуль CMake, который извлекает внешние проекты или другое содержимое во время настройки, а не во время сборки. Если вы объявляете и предоставляете Контент перед использованием файлов из проекта, это должно работать прямо из коробки без управления зависимостями. - person d-karl; 20.01.2020
comment
@d-karl: использование модуля FetchContent обсуждалось в комментариях к вопросу. Спрашивающий комментирует, что этот модуль недоступен для более старых (‹3.10) версий CMake, и это правда. - person Tsyvarev; 20.01.2020

В конце концов, даже с хорошей помощью @Tsyvarev, я не смог заставить его работать с помощью ExternalProject_Add. Часть решения состоит в том, чтобы вручную экспортировать библиотеку с помощью cs_export(INCLUDE_DIRS ${ads}), что не сработало с ExternalProject_Add, поскольку в это время файлы были недоступны.

В конце концов я включил в свой пакет модуль DownloadProject, который является предшественником FetchContent. Это делает то, что должно.

person pixelpress    schedule 22.01.2020