¿Cómo usar CMake ExternalProject_Add o alternativas de forma cruzada?
cross-platform (2)
Las llamadas CMake ExternalProject_Add funcionan de forma multiplataforma de forma predeterminada, y solo fallarán si se utilizan comandos particulares que solo están disponibles en un subconjunto de sistemas operativos. Normalmente, CMAKE_ARGS se utiliza para pasar información a cada unidad de superconstrucción dentro de una compilación de proyecto externa. Los archivos CMakeLists.txt que controlan cada parte en miniatura de la creación general utilizan la sintaxis declarativa de CMake (por ejemplo, "add_library (library_name SHARED filename1.hpp filename1.cpp). CMake convertirá dicha sintaxis a los comandos que son específicos del sistema de compilación en particular que desea usar (por ejemplo, make, ninja).
El ejemplo anterior re: zlib no puede ser multiplataforma en parte porque ExternalProject_Add_Step contiene "COMMAND cd && make install", que necesariamente solo funciona en situaciones donde invocar "cd" es en realidad la forma correcta de cambiar directorios, y donde se invoca " make "es en realidad la forma correcta de crear software. La opción -E de CMake proporciona una forma de invocar operaciones básicas como cambiar / copiar / hacer / eliminar directorios sin hacer tales suposiciones.
(Por cierto, si está utilizando IDEs como Visual Studio o XCode, probablemente quiera invocar uno o más generadores IDE cuando use CMake. Por ejemplo, establecer
-G "Eclipse CDT4 - Unix Makefiles" -DCMAKE_ECLIPSE_GENERATE_SOURCE_PROJECT=TRUE
hará que se generen proyectos de Eclipse en cada área de construcción, y también en el área del código fuente que se comparte para todas las construcciones. Por supuesto, si está utilizando XCode o Visual Studio, tendrá que sustituir la bandera apropiada para esos IDEs. Alternativamente, podrías considerar usar Eclipse con Ninja en todas las plataformas, aunque al momento de escribir estas líneas, no estoy completamente seguro de que Ninja esté preparado para el horario de máxima audiencia en sistemas operativos que no sean de Linux y que no sean de Windows).
Me gustaría crear un proyecto de terceros que ya tenga CMake como parte de las tiras CMake de mi proyecto. ExternalProject_Add es para este propósito, pero he descubierto que solo se puede hacer para que funcione con un generador específico, y quería trabajar en muchas plataformas fácilmente.
Por ejemplo, aquí está mi script de agregar proyecto externo para zlib, que tiene su propio 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")
El problema con esto es que funciona con make, pero no con Xcode o Visual Studio. Quizás haya alguna forma de llevar los comandos de compilación de cmake a mi proyecto y reenviarlos a ExternalProject_Add.
¿Cómo puedo escribir llamadas ExternalProject_Add de forma multiplataforma con una complejidad de código mínima o existe una alternativa mejor?
Problemas
-DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}
Esto es suficiente para proyectos de configuración única. Pero para Xcode y Visual Studio necesita establecer CMAKE_CONFIGURATION_TYPES
más la build . --config
llamadas build . --config
build . --config
en la etapa de compilación. Ver mi respuesta
COMMAND cd <BINARY_DIR> && make install
Esto funcionará solo para los generadores de Makefile, por supuesto. Para ser multiplataforma, puede usar: --build . --target install --config
--build . --target install --config
dentro de INSTALL_COMMAND
de ExternalProject_Add
.
Eche un vistazo a este archivo de plantilla y, en particular, a las siguientes líneas :
ExternalProject_Add(
"${current_project}"
URL
@HUNTER_PACKAGE_URL@
URL_HASH
SHA1=@HUNTER_PACKAGE_SHA1@
DOWNLOAD_DIR
"@HUNTER_PACKAGE_DOWNLOAD_DIR@"
SOURCE_DIR
"@HUNTER_PACKAGE_SOURCE_DIR@"
INSTALL_DIR
"@HUNTER_PACKAGE_INSTALL_PREFIX@"
# 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
"-G@CMAKE_GENERATOR@"
"-C@HUNTER_CACHE_FILE@"
"-C@HUNTER_ARGS_FILE@"
"-D${postfix_name}=${${postfix_name}}"
"-DCMAKE_BUILD_TYPE=${configuration}"
"-DCMAKE_CONFIGURATION_TYPES=${configuration}"
"-DCMAKE_INSTALL_PREFIX=@HUNTER_PACKAGE_INSTALL_PREFIX@"
"-DCMAKE_TOOLCHAIN_FILE=${CMAKE_TOOLCHAIN_FILE}"
INSTALL_COMMAND
"@CMAKE_COMMAND@"
--build .
--target install
--config ${configuration}
--
${jobs_option}
)
Alternativa
o hay una mejor alternativa?
¿Has visto a Hunter ?
Puedes agregar zlib así:
hunter_add_package(ZLIB)
find_package(ZLIB CONFIG REQUIRED)
target_link_libraries(... ZLIB::zlib)
Este código funciona en todas partes. El tercero se descargará automáticamente en el paso de configuración. Ejemplo de compilación con diferentes generadores / cadenas de herramientas ( build.py es simplemente CMake wrapper que establece CMAKE_TOOLCHAIN_FILE
y -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
Obtuviste el control total de las opciones , los tipos de compilación o la cantidad de trabajos que quieres tener mientras creas paquetes de terceros. Por ejemplo, así es como puedes construir 4 tipos Debug, Release, MinSizeRel, RelWithDebInfo para zlib y vincular MinSizeRel al proyecto actual:
> 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