Кажется, что 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
Мои попытки решить эту проблему:
К сожалению, изменение аргумента
SOURCE_DIR
изExternalProject
сделал не работает, потому что значение этой переменной используется как место для , к которому клонирован git-репозиторийlibfoo
. Это приводит к рекурсивному иждивенцу, который нельзя сломать.Изменение формата каталога
libfoo
соответствуетExternalProject
. Очевидно, что это сработает, но оно может не работать для других (только для чтения) сторонних библиотек.Нарушение этапа обновления/исправления
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" )
Это работает, но это хаки и очень подвержено неудаче с другими внешними проектами.
Здание на 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 )
Это работает, как хорошо и чувствует себя лучше, чем предыдущее решение.
Однако делает более изящным существуют, чтобы сделать то же самое?
Функция была принята и доступна с CMake 3.7: https://cmake.org/cmake/help/v3.7/module/ExternalProject.html – Matthew