Подтвердить что ты не робот

Как использовать CMake ExternalProject_Add или альтернативы кроссплатформенным способом?

Я хотел бы создать сторонний проект, в котором уже есть CMake, как часть моего проекта CMake strips. ExternalProject_Add предназначен для этой цели, но я обнаружил, что его можно настроить только для работы с определенным генератором, и я хотел, чтобы он легко работал на многих платформах.

Например, вот мой внешний проект с добавленным скриптом для zlib, который имеет свой собственный CMakeLists.txt:

set(USE_PROJECT_CMAKE_MODULE_PATH "-DCMAKE_MODULE_PATH=${MAKE_MODULE_PATH}")
ExternalProject_Add(ZLIB
                    SOURCE_DIR ${CMAKE_SOURCE_DIR}/external/zlib
                    DOWNLOAD_COMMAND ""
                    UPDATE_COMMAND ""
                    CMAKE_ARGS
                       -DCMAKE_INSTALL_PREFIX=<INSTALL_DIR>
                       -DCMAKE_CXX_FLAGS=${CMAKE_CXX_FLAGS}
                       -DCMAKE_C_FLAGS=${CMAKE_C_FLAGS}
                       -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}
                       ${USE_PROJECT_CMAKE_MODULE_PATH}
                    INSTALL_COMMAND "")

ExternalProject_Add_Step(ZLIB installInternally
                         COMMAND cd <BINARY_DIR> && make install
                         DEPENDEES install
                         ALWAYS 1)
ExternalProject_Get_Property(ZLIB install_dir)

if(UNIX)
    set(ZLIB_NAME libz)
else(UNIX)
    set(ZLIB_NAME zlib)
endif(UNIX)

add_library(zlib UNKNOWN IMPORTED)
set_property(TARGET zlib PROPERTY IMPORTED_LOCATION ${install_dir}/lib/${ZLIB_NAME}.a)
set(ZLIB_LIBRARIES zlib)
set(ZLIB_LIBRARIES_OPTIONAL ${ZLIB_LIBRARIES})
set(ZLIB_DIR ${install_dir} CACHE INTERNAL "zlib ROOT dir")
set(ZLIB_INCLUDE_DIRS ${install_dir}/include CACHE INTERNAL "zlib include dirs")
set(ZLIB_DEFINES "-msse2 -mfpmath=sse" CACHE INTERNAL "zlib defines")

Проблема в том, что он работает с make, но не с Xcode или Visual Studio. Возможно, есть какой-то способ взять команды сборки CMake, переданные в мой проект, и переслать их в ExternalProject_Add.

Как я могу писать вызовы ExternalProject_Add кросс-платформенным способом с минимальной сложностью кода, или есть лучшая альтернатива?

4b9b3361

Ответ 1

Проблемы

-DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}

Этого достаточно для проектов с одной конфигурацией. Но для Xcode и Visual Studio вам нужно установить CMAKE_CONFIGURATION_TYPES плюс вызов build . --config на этапе сборки. Смотрите мой ответ.

COMMAND cd <BINARY_DIR> && make install

Конечно, это будет работать только для генераторов Makefile. Чтобы быть кроссплатформенным, вы можете использовать:

--build . --target install --config внутри INSTALL_COMMAND из ExternalProject_Add.

Посмотрите этот файл шаблона и, в частности, следующие строки:

ExternalProject_Add(
    "${current_project}"
    URL
    @[email protected]
    URL_HASH
    [email protected][email protected]
    DOWNLOAD_DIR
    "@[email protected]"
    SOURCE_DIR
    "@[email protected]"
    INSTALL_DIR
    "@[email protected]"
        # Not used, just avoid creating Install/<name> empty directory
    BUILD_COMMAND ""
        # This command is empty because all necessary targets will
        # be built on install stage
    CMAKE_ARGS
    "[email protected][email protected]"
    "[email protected][email protected]"
    "[email protected][email protected]"
    "-D${postfix_name}=${${postfix_name}}"
    "-DCMAKE_BUILD_TYPE=${configuration}"
    "-DCMAKE_CONFIGURATION_TYPES=${configuration}"
    "[email protected][email protected]"
    "-DCMAKE_TOOLCHAIN_FILE=${CMAKE_TOOLCHAIN_FILE}"
    INSTALL_COMMAND
        "@[email protected]"
        --build .
        --target install
        --config ${configuration}
        --
        ${jobs_option}
)

Alternative

или есть лучшая альтернатива?

Вы видели Охотника?

Вы можете добавить zlib так же, как этот:

hunter_add_package(ZLIB)
find_package(ZLIB CONFIG REQUIRED)
target_link_libraries(... ZLIB::zlib)

Этот код работает везде. Сторонние зависимости будут загружены автоматически на этапе настройки. Пример сборки с разными генераторами/цепочками инструментов (build.py - это просто оболочка CMake, которая устанавливает CMAKE_TOOLCHAIN_FILE и -G/-B):

build.py --toolchain mingw --config Release # MinGW Makefiles
build.py --toolchain vs-12-2013 --config Debug # Visual Studio 12 2013
build.py --toolchain xcode --config Release # Xcode
build.py --toolchain libcxx --config Release # Makefile with -stdlib=libc++ toolchain
build.py --toolchain ios-8-2 --config Release # Xcode with iOS SDK 8.2 toolchain

Вы получаете полный контроль над тем, какие параметры, типы сборки или количество заданий вы хотите иметь при создании сторонних пакетов. Например, вот как вы можете построить четыре типа: Debug, Release, MinSizeRel и RelWithDebInfo для zlib и связать MinSizeRel с текущим проектом:

> build.py --toolchain xcode --verbose --config MinSizeRel --fwd "HUNTER_CONFIGURATION_TYPES=Release;Debug;MinSizeRel;RelWithDebInfo"
/.../clang  /.../lib/libz-MinSizeRel.a ... -o /.../_builds/xcode/MinSizeRel/foo

> ls -la /.../.hunter/_Base/d1232c0/326318e/37e4682/Install/lib/libz*
   99056 /.../.hunter/_Base/d1232c0/326318e/37e4682/Install/lib/libz-MinSizeRel.a
  307872 /.../.hunter/_Base/d1232c0/326318e/37e4682/Install/lib/libz-RelWithDebInfo.a
  109536 /.../.hunter/_Base/d1232c0/326318e/37e4682/Install/lib/libz.a
  258904 /.../.hunter/_Base/d1232c0/326318e/37e4682/Install/lib/libzd.a

Ответ 2

CMake ExternalProject_Add вызывает кроссплатформенную работу по умолчанию и не сможет этого сделать, только если используются конкретные команды, доступные только в подмножестве операционных систем.

Как правило, CMAKE_ARGS используется для передачи информации каждому суперкомпилированному модулю в рамках внешней сборки проекта. Файлы CMakeLists.txt, которые управляют каждой миниатюрной частью общей сборки, используют декларативный синтаксис CMake (например, "add_library (имя_библиотеки SHARED filename1.hpp filename1.cpp)". CMake преобразует такой синтаксис в команды, специфичные для конкретной системы сборки. вы хотите использовать (например, make и Ninja).

В приведенном выше примере re: zlib не может быть кроссплатформенным частично потому, что ExternalProject_Add_Step содержит "COMMAND cd & make install", который обязательно работает только в ситуациях, когда вызов "cd" фактически является правильным способом изменения каталогов, и где вызов "make" на самом деле является правильным способом создания программного обеспечения.

Опция CMake -E предоставляет способ вызывать основные операции, такие как изменение/копирование/создание/удаление каталогов, не делая таких предположений.

(Кстати, если вы используете IDE, такие как Visual Studio или Xcode, вы, вероятно, захотите вызвать один или несколько генераторов IDE при использовании CMake. Например, установка

-G "Eclipse CDT4 - Unix Makefiles" -DCMAKE_ECLIPSE_GENERATE_SOURCE_PROJECT=TRUE

приведет к тому, что проекты Eclipse будут создаваться в каждой области сборки, а также в области исходного кода, которая является общей для всех сборок. Конечно, если вы используете Xcode или Visual Studio, вам придется заменить соответствующий флаг для этих IDE. В качестве альтернативы, вы могли бы рассмотреть возможность использования Eclipse с Ninja на всех платформах, хотя на момент написания статьи я не был полностью уверен, что Ninja готов к прайм-тайм в операционных системах, отличных от Linux и не Windows.)