architecture cmake build-process qmake

architecture - ¿Cómo detectar la arquitectura de destino usando CMake?



build-process qmake (8)

Así que ideé una solución bastante creativa para mi problema ... parece que CMake no tiene ninguna funcionalidad para detectar la arquitectura de destino en absoluto.

Ahora, sabemos que podemos hacer esto fácilmente en C porque se __i386__ símbolos como __i386__ , __x86_64__ , etc., dependiendo de su entorno. Afortunadamente CMake tiene una función try_run que compilará y ejecutará un archivo de código fuente C arbitrario durante la etapa de configuración.

Luego podríamos escribir un pequeño programa que use un montón de ifdefs y escriba el nombre de la arquitectura en la consola como una cadena. El único problema es que esto solo funciona si el host y el sistema de destino son los mismos ... no puede funcionar durante la compilación cruzada porque aunque puede compilar el binario, no puede ejecutarlo para ver su resultado.

Aquí es donde las cosas se ponen interesantes. Podemos explotar el preprocesador C para obtener la información necesaria escribiendo deliberadamente un programa C roto ... usamos el concepto original de escribir el nombre de la arquitectura en la consola en función de ifdefs, pero en lugar de hacerlo, simplemente colocaremos un # directiva de preprocesador de errores en lugar de una llamada printf.

Cuando la función try_run de CMake compila el archivo C, la compilación siempre fallará, pero cualquier mensaje que coloquemos en la directiva #error aparecerá en la salida de error del compilador, que try_run nos devolverá.

Por lo tanto, todo lo que tenemos que hacer es analizar el nombre de la arquitectura desde la salida de error del compilador utilizando algunos comandos de cadena CMake, y podemos recuperar la arquitectura de destino ... incluso cuando se realiza una compilación cruzada.

La parte específica del código OS X utiliza principalmente CMAKE_OSX_ARCHITECTURES para determinar la arquitectura de destino, pero en el caso de que no esté especificada utilizará el mismo código que otros sistemas y devolverá x86_64 (para sistemas modernos en los que ese es el valor predeterminado del compilador) o i386 (para sistemas OS X más antiguos como Leopard).

He probado y verificado que esto funciona en Windows, OS X y Linux usando los generadores de Visual Studio 9 y 10 (x86, x86_64, ia64), Xcode, NMake, MSYS Makefiles y Unix Makefiles. El resultado correcto se devuelve todo el tiempo.

Aviso: esta solución puede fallar si deliberadamente hace cosas como pasar -m32 o -m64 a su compilador u otras banderas que puedan afectar la arquitectura de destino (¿hay alguna manera de pasar todas las configuraciones de entorno a try_run?); esto no es algo que haya probado. Siempre que esté utilizando la configuración predeterminada para su generador y todos los objetivos se compilan para la misma arquitectura, debería estar bien.

El código fuente completo para mi solución se puede encontrar en GitHub: https://github.com/petroules/solar-cmake/blob/master/TargetArch.cmake

He investigado mucho y no he podido encontrar una respuesta a esto ... ¿cómo puedo encontrar de manera confiable la arquitectura de destino para la que estoy compilando, usando CMake? Básicamente, el equivalente a QMAKE_TARGET.arch en qmake.

La mayoría de las fuentes parecen sugerir CMAKE_SYSTEM_PROCESSOR, pero esa es una mala solución porque siempre devolverá i386 en OS X, por ejemplo, sin importar si está compilando para i386, x86_64, ppc o ppc64.

Del mismo modo, CMAKE_SIZEOF_VOID_P proporciona el tamaño del puntero del sistema , no el objetivo.

Entiendo que hay CMAKE_OSX_ARCHITECTURES, pero puede estar vacío si no está configurado, en cuyo caso parece predeterminado para lo que sea capaz el sistema. Entonces, ¿cómo puedo encontrar la información de la arquitectura de destino?

Y específicamente para OS X, ¿cómo puedo diferenciar entre 32, 64 e Intel Universal?


Creo que la solución más fácil y confiable es especificar la arquitectura de alguna manera a mano, para la plataforma en la que está construyendo (puede usar cmake . -DMY_ARCHITECTURE=x86 o algo similar). Al menos eso es lo que estamos haciendo en nuestros proyectos, debido a los mismos problemas que describió anteriormente


En caso de que su proceso de compilación implique más de 1 objetivo, si esto es mejor para que CMake sepa sobre qué ARCH / toolchain está construyendo. Puede seguir las instructions para la compilación cruzada de CMake, que lo alienta a crear un archivo CMake de cadena de herramientas, que le permite elegir la cadena de herramientas / compilador que se está utilizando.

toolchain-arm.cmake uno para construir mi aplicación C ++ Linux para el procesador de brazo, y lo toolchain-arm.cmake .

Incluye set(CMAKE_SYSTEM_PROCESSOR arm) .

Luego ejecuté CMake así:

cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_TOOLCHAIN_FILE={my toolchain cmake path}/toolchain-arm.cmake {my source path}

dentro de CMakeList.txt de mi proyecto, puedo referirme a CMAKE_SYSTEM_PROCESSOR de la manera que desee.

Al compilar para X86, no incluyo la referencia a -DCMAKE_TOOLCHAIN_FILE, dejando CMAKE_SYSTEM_PROCESSOR indefinido, o al menos no definido como arm .

Aquí está mi toolchain-arm.cmake

SET(CMAKE_SYSTEM_NAME Linux) SET(CMAKE_SYSTEM_VERSION 1) set(CMAKE_SYSTEM_PROCESSOR arm) # specify the cross compiler SET(ENV{TOOLCHAIN_ROOT} /home/user/toolchain/tools-master/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian/bin ) SET(CMAKE_C_COMPILER $ENV{TOOLCHAIN_ROOT}/arm-linux-gnueabihf-gcc) SET(CMAKE_CXX_COMPILER $ENV{TOOLCHAIN_ROOT}/arm-linux-gnueabihf-gcc) # search for programs in the build host directories SET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) # for libraries and headers in the target directories SET(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) SET(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)


Esta es una forma bien probada de conocer la arquitectura del host:

# Store in CMAKE_DEB_HOST_ARCH var the current build architecture execute_process(COMMAND dpkg-architecture -qDEB_HOST_ARCH OUTPUT_VARIABLE CMAKE_DEB_HOST_ARCH OUTPUT_STRIP_TRAILING_WHITESPACE )

Y use esa información más tarde en CMakeLists como necesite

if(${CMAKE_DEB_HOST_ARCH} MATCHES "armhf") ... elseif(${CMAKE_DEB_HOST_ARCH} MATCHES "i386") ... else() ... endif()


Esta publicación es antigua, lo siento mucho si resucito a los muertos aquí, pero pensé que compartiría la solución que hice.

No quería utilizar ninguna aplicación externa y desafortunadamente el archivo toolchain.cmake que estamos utilizando no tiene el arco configurado en otra variable, así que lo detecto mirando las variables CMAKE_C_FLAGS y CMAKE_CXX_FLAGS buscando el argumento -march para GCC. Si no hay uno, vuelve a CMAKE_HOST_SYSTEM_PROCESSOR .

Un vistazo rápido a la documentación de Clang parece indicar que esto no funcionaría para eso, pero solo necesitaría un segundo paso de expresión regular para coincidir con su argumento esperado.

set(TARGET_ARCH_REGEX "^.*-march[= ]([^ ]+).*$") string(REGEX MATCH "${TARGET_ARCH_REGEX}" TARGET_ARCH_MATCH ${CMAKE_C_FLAGS} ${CMAKE_CXX_FLAGS}) if (TARGET_ARCH_MATCH) string(REGEX REPLACE "${TARGET_ARCH_REGEX}" "//1" TARGET_ARCH ${CMAKE_C_FLAGS} ${CMAKE_CXX_FLAGS}) else() set(TARGET_ARCH ${CMAKE_HOST_SYSTEM_PROCESSOR}) endif()



Tengo una solución para el caso donde el sistema de host y de destino es el mismo.

Primero debe llamar a "uname -m" para obtener el " nombre del hardware de la máquina ". Después, debe cortar el " Retorno de carro " posterior para volver a colocar el Valor real en la Variable proporcionada.

EXECUTE_PROCESS( COMMAND uname -m COMMAND tr -d ''/n'' OUTPUT_VARIABLE ARCHITECTURE )

Ahora puede imprimir la Variable $ {ARCHITECTURE}:

message( STATUS "Architecture: ${ARCHITECTURE}" )

o haga Canonización para mapear, por ejemplo, "x86_64", "amd64", ... a, por ejemplo, "64 bits". Lo mismo vale para 32 bits. Con esto puedes ejecutar la arquitectura de acuerdo y compilar como:

if( ${ARCHITECTURE} STREQUAL "64Bit" ) set( BLA_LIBRARY "/opt/lib/libBla.so" ) else() set( BLA_LIBRARY "/opt/lib32/libBla.so" ) endif()