Как найти базовую архитектуру внутри Makefile?

Я хочу найти внутри Makefile, независимо от того, работаю ли я на 32-битной или 64-битной машине.

Есть ли какие-либо макросы или переменные среды, к которым можно просто получить доступ из Makefile?

Я нашел этот ответ в Интернете:

LBITS := $(shell getconf LONG_BIT)
ifeq ($(LBITS),64)
   # do 64 bit stuff here, like set some CFLAGS
else
   # do 32 bit stuff here
endif

Однако я сомневаюсь, что во всей системе getconf инструмент будет доступен или нет.


person Vicky    schedule 20.07.2016    source источник
comment
Возможный дубликат: GNU Makefile, определение архитектуры   -  person frist    schedule 20.07.2016
comment
@frist, нет. Я только что перепроверил - ответ специфичный для BSD. Я добавил более портативный uname -m к своему собственному ответу.   -  person Dummy00001    schedule 20.07.2016


Ответы (2)


tl; dr;

Если все, что вам нужно, это получить количество бит в типе long в C переносимым способом, можно использовать getconf LONG_BIT.

Иначе:

  • для определения архитектуры хоста используйте config.guess сценарий оболочки
  • для определения целевой архитектуры используйте gcc -dumpmachine или gcc --help=target

Определение архитектуры хоста

1) getconf

Как упоминал @ Dummy00001, getconf является частью POSIX и широко доступен, но не предоставляет достаточно информации.

Обратите внимание, что getconf LONG_BIT - это просто количество бит в типе long в C. Например, это может быть 32 на 16-битных или 64-битных машинах. Это совершенно бесполезно для определения архитектуры хоста.

2) uname

uname также является частью POSIX и тоже не предоставляет достаточно информации.

Например, он не делает различий между жестким и мягким ARM в Linux. Кроме того, его архитектура именования не совсем переносима.

3) /proc

Вы можете использовать /proc для сбора информации об архитектуре, например /proc/cpuinfo в Linux. Однако он не переносится и его сложно разбирать.

4) config.guess

Наконец, я рекомендую сценарий GNU config.guess (исходный код). Это автономный скрипт, который вы можете скопировать в свой проект. Он написан в переносимой оболочке и должен работать в любой UNIX.

$ sh config.guess
x86_64-pc-linux-gnu

Этот сценарий используется в автоинструментах, но вы можете использовать его и без автоинструментов.


Определение целевой архитектуры по умолчанию вашей инструментальной цепочки

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

1) gcc -E

Вы можете проанализировать gcc -E вывод, чтобы получить кортеж инструментальной цепочки для целевой архитектуры gcc:

$ gcc -v -E - </dev/null |& grep Target:
Target: x86_64-linux-gnu

Это должно работать в любой UNIX, если вы используете GCC или clang.

Примечания:

  • Он печатает значение параметра --target, переданное configure скрипту при построении GCC. На него не влияют текущие флаги компиляции, переданные в GCC, такие как -m32 или -march.
  • В отличие от config.guess, этот кортеж инструментальной цепочки зависит от дистрибутива. Например, разные схемы используются в готовых наборах инструментов в Debian и Gentoo.

2) gcc -dumpmachine

Похоже, что gcc -dumpmachine печатает то же значение, что и в предыдущем рецепте:

$ gcc -dumpmachine
x86_64-linux-gnu

Работает с GCC и clang.

3) gcc -print-multiarch

Другой способ получить кортеж инструментальной цепочки:

$ gcc -print-multiarch
x86_64-linux-gnu

Работает с GCC, но не лязгает. Также известно, что этот вариант не работает в различных случаях:

  • в Debian пусто, если Multilib отключен
  • на Gentoo всегда пусто
  • как упоминалось @ Dummy00001, он может быть пустым для инструментальных цепочек кросс-компиляции (я думаю, это зависит от того, как был построен инструментальный цепочки)

Определение целевой архитектуры в зависимости от текущих флагов

Некоторые параметры GCC, такие как -m32 или -march, могут влиять на целевую архитектуру.

1) gcc --help=target

Это напечатает значение параметра -march, выведенное из целевой архитектуры по умолчанию (настроенной при сборке GCC) и текущих параметров компиляции.

$ gcc -Q --help=target |& grep -e -march | awk '{print $2}'
x86-64

$ gcc -m32 -Q --help=target |& grep -e -march | awk '{print $2}'
i686

$ gcc -march=i386 -Q --help=target |& grep -e -march | awk '{print $2}'
i386

Не работает с лязгом.

person gavv    schedule 20.07.2016
comment
К сожалению, gcc -print-multiarch не работает для ARM (работает для Intel i386 / x64 - но выводит пустую строку в цепочке инструментов кросс-компиляции ARM). Не поддерживается и clang. Точно так же ваш gcc -v -E - показывает цель GCC по умолчанию, но не реагирует на флаги -m32 / -m64. Другими словами, оба ваших предложения по цепочке инструментов плохи. - person Dummy00001; 22.07.2016
comment
@ Dummy00001, спасибо. Я добавил ваши примечания к ответу. Кстати, -print-multiarch работал у меня с наборами инструментов ARM, так что я предполагаю, что это зависит от того, как был построен набор инструментов. Я также добавил gcc --help=target рецепт, соответствующий текущим CFLAGS, например -m32. - person gavv; 22.07.2016

getconf - это инструмент POSIX, он должен быть доступен на всех unix- подобные системы. Но uname -m был бы более портативным и более традиционным способом определения типа системы.

В противном случае, с большой вероятностью, вы смотрите в неправильном направлении: разрядность хост-системы не обязательно совпадает с разрядностью цепочки инструментов. Цепочка инструментов (компилятор, компоновщик) определяет, какой разрядностью будет результат. И инструментальная цепочка может быть настроена пользователем для соответствия локальным потребностям (например, компиляция как 32-битная в 64-битной ОС) или даже кросс-компиляции.

Чтобы найти разрядность GCC (или clang) в вашей цепочке инструментов, вы можете использовать это:

LBITS := $(shell $(CC) $(CFLAGS) -dM -E - </dev/null | grep -q "__LP64__" && echo 64 || echo 32)

Фактически, он запрашивает, с какой разрядностью будет скомпилировано приложение, не выполняя фактическую компиляцию, но глядя на компилятор, определяющий для LP параметр, который обозначает" модель данных "архитектуры (LP64 означает" длинный и указатель 64-битный "(и, по пропуску, int - 32-битный ); ILP32 означает "int, long и указатель 32-битные").

Пока вы используете Linux, это будет работать. (Вам необходимо использовать CFLAGS в вызове компилятора, поскольку CFLAGS, переопределенный пользователем, может использовать параметры -m32 или -m64 для изменения разрядности выходного кода.)

person Dummy00001    schedule 20.07.2016
comment
Я не ищу разрядности инструментальной цепочки, просто хотел увидеть разрядность моей текущей системы. Однако вы дали отличную информацию. Спасибо. - person Vicky; 22.07.2016
comment
@Vicky, Rants: В последнее время количество программного обеспечения с ошибками увеличилось: он ошибочно предполагает, что разрядность OS / HW - это разрядность, для которой мне нужно компилировать. Например. В моем случае я использую много 32-битного программного обеспечения, чтобы быть максимально совместимым со встроенным 32-битным ARM. Тем не менее, некоторые библиотеки и приложения я могу скомпилировать только в виртуальной машине, потому что все их сценарии настройки тупо смотрят на uname -m, а затем выходят из строя, когда GCC в 32-битном режиме отказывается компилировать 64-битные оптимизированные части. - person Dummy00001; 22.07.2016