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

Как определить целевую архитектуру с помощью CMake?

Я провел много исследований и не смог найти ответ на этот вопрос... как я могу надежно найти целевую архитектуру, которую я компилирую, используя CMake? В принципе, эквивалент QMAKE_TARGET.arch в qmake.

Большинство источников, похоже, предлагают CMAKE_SYSTEM_PROCESSOR, но это плохое решение, потому что оно всегда будет возвращать i386 на OS X, например, независимо от того, компилируете ли вы для i386, x86_64, ppc или ppc64.

Аналогично, CMAKE_SIZEOF_VOID_P дает размер указателя системы, а не цель.

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

И специально для OS X, как я могу различать 32, 64 и Intel Universal?

4b9b3361

Ответ 1

Итак, я разработал довольно творческое решение моей проблемы... похоже, что у CMake нет функциональности для обнаружения целевой архитектуры вообще.

Теперь мы знаем, что мы можем легко сделать это в C, потому что символы, такие как __i386__, __x86_64__ и т.д., будут определены в зависимости от вашей среды. К счастью, у CMake есть функция try_run, которая будет компилировать и запускать произвольный файл исходного кода на этапе конфигурации.

Затем мы могли бы написать небольшую программу, которая использует кучу ifdefs и записывает имя архитектуры в консоль в виде строки. Единственная проблема заключается в том, что это работает только в том случае, если хост и целевая система одинаковы... он не может работать во время кросс-компиляции, потому что, хотя вы можете скомпилировать двоичный файл, вы не можете запустить его, чтобы увидеть его вывод.

Здесь, где вещи становятся интересными. Мы можем использовать препроцессор C для получения необходимой информации путем преднамеренной записи разбитой программы на C... мы используем оригинальную концепцию написания имени архитектуры в консоли на основе ifdefs, но вместо этого мы просто разместим # вместо препроцессора printf.

Когда функция CMake try_run компилирует файл C, компиляция всегда терпит неудачу, но любое сообщение, которое мы помещаем в директиве #error, будет отображаться в выводе ошибки компилятора, который try_run возвращает нам.

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

Отдельная часть кода OS X в основном использует CMAKE_OSX_ARCHITECTURES для определения целевой архитектуры, но в случае, если она не указана, она будет использовать тот же код, что и другие системы, и правильно вернуть x86_64 (для современных систем, на которых это является стандартом компилятора ) или i386 (для более старых систем OS X, таких как Leopard).

Я тестировал и проверял, что это работает в Windows, OS X и Linux с использованием генераторов Visual Studio 9 и 10 (x86, x86_64, ia64), Xcode, NMake, MSYS Makefile и Unix Make файлов. Правильный результат возвращается каждый раз.

Примечание.. Это решение может выйти из строя, если вы намеренно делаете что-то вроде pass -m32 или -m64 для своего компилятора или других флагов, которые могут повлиять на целевую архитектуру (есть ли способ передать всю среду настройки до try_run?); это не то, что я тестировал. Пока вы используете настройки по умолчанию для своего генератора, и все цели компилируются для одной и той же архитектуры, вы должны быть в порядке.

Полный исходный код для моего решения можно найти в GitHub: https://github.com/petroules/solar-cmake/blob/master/TargetArch.cmake

Ответ 2

У меня есть решение для случая, когда хост и целевая система одинаковы.

Сначала вам нужно вызвать "uname -m", чтобы получить "имя аппаратного оборудования". После этого вам нужно отключить конечное "Возврат каретки", чтобы вернуть фактическое значение в предоставленную переменную.

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

Теперь вы можете распечатать переменную ${ARCHITECTURE}:

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

или сделать некоторые канонизации для отображения, например. "x86_64", "amd64",... к примеру. "64Bit". То же самое касается 32Bit. С помощью этого вы можете выполнить компиляцию зависимости archtecture, например:

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

Ответ 3

В случае, если в вашем процессе сборки задействовано более 1 цель, я должен дать CMake знать, что ARCH/toolchain, с которым он строится. Вы можете следовать инструкциям для кросс-компиляции CMake, что побуждает вас создать файл CMake файла toolchain, который позволяет вам выбрать используемую toolchain/компилятор.

Я создал один для создания моего приложения на С++ Linux для процессора arm и назвал его toolchain-arm.cmake.

Он включает set(CMAKE_SYSTEM_PROCESSOR arm).

Затем я выполнил CMake следующим образом:

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

в моем проекте CMakeList.txt Я могу ссылаться на CMAKE_SYSTEM_PROCESSOR любым желаемым способом.

При создании для X86 я не включаю ссылку на -DCMAKE_TOOLCHAIN_FILE, оставляя CMAKE_SYSTEM_PROCESSOR undefined или по крайней мере не определен как arm.

Здесь моя 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)

Ответ 4

Android ${ANDROID_ABI}

Переменная ${ANDROID_ABI} - это способ выхода на Android, где он принимает значения, такие как arm64-v8a, x86_64 и т.д.

Он используется в официальном примере библиотеки NDK: https://github.com/googlesamples/android-ndk/blob/840858984e1bb8a7fab37c1b7c571efbe7d6eb75/hello-libs/app/src/main/cpp/CMakeLists.txt#L25

Я еще раз прокомментировал этот пример: NDK: Как включить сборную общую библиотеку независимо от архитектуры

Ответ 5

Я думаю, что самым простым и надежным решением является определение архитектуры как-то вручную, для платформы, на которой вы строите (вы можете использовать cmake . -DMY_ARCHITECTURE=x86 или что-то подобное). По крайней мере, то, что мы делаем в наших проектах, из-за тех же проблем, которые вы описали выше.

Ответ 6

На данный момент вам не нужны хаки для определения целевой архитектуры: переменная-переменная OSX_ARCHITECTURES была добавлена ​​в cmake и может использоваться для вашей цели: http://public.kitware.com/Bug/view.php?id=8725

Ответ 7

Это хорошо проверенный способ знать архитектуру хоста:

# 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
)

И используйте эту информацию позже в CMakeLists, как вам нужно

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

Ответ 8

Этот пост старый, извините, если воскресить мертвых здесь, но я просто подумал, что поделюсь решением, которое я сделал.

Я не хотел использовать какое-либо внешнее приложение, и, к сожалению, файл toolchain.cmake, который мы используем, не имеет набора арки в другой переменной, поэтому я обнаруживаю его, просматривая переменные CMAKE_C_FLAGS и CMAKE_CXX_FLAGS ищет аргумент -march для GCC. Если его нет, он возвращается к CMAKE_HOST_SYSTEM_PROCESSOR.

Быстрый взгляд на документацию Clang, похоже, указывает на то, что это не сработает для этого, но для соответствия его ожидаемому аргументу просто потребуется второй шаг регулярного выражения.

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()