Как проверить версию Binutils в коде сборки GNU GAS во время компиляции?
В Crypto ++ возникла похожая проблема.Им нужно было знать версии AS и LD, чтобы обеспечить наличие инструкций ISA, таких как SSE4 (-msse4.1
), AES (-maes
) и SHA (-msha
) во время сборки (на примере Intel).
В GNUmakefile Crypto ++ используется для выполнения :
GCC_COMPILER := $(shell $(CXX) --version 2>/dev/null | $(GREP) -v -E '(llvm|clang)' | $(GREP) -i -c -E '(gcc|g\+\+)')
...
ifneq ($(GCC_COMPILER),0)
IS_GCC_29 := $(shell $(CXX) -v 2>&1 | $(GREP) -i -c -E gcc-9[0-9][0-9])
GCC42_OR_LATER := $(shell $(CXX) -v 2>&1 | $(GREP) -i -c -E "gcc version (4\.[2-9]|[5-9]\.)")
GCC46_OR_LATER := $(shell $(CXX) -v 2>&1 | $(GREP) -i -c -E "gcc version (4\.[6-9]|[5-9]\.)")
endif
ifneq ($(HAVE_GAS),0)
GAS210_OR_LATER := $(shell $(CXX) -xc -c /dev/null -Wa,-v -o/dev/null 2>&1 | $(GREP) -c -E "GNU assembler version (2\.[1-9][0-9]|[3-9])")
GAS217_OR_LATER := $(shell $(CXX) -xc -c /dev/null -Wa,-v -o/dev/null 2>&1 | $(GREP) -c -E "GNU assembler version (2\.1[7-9]|2\.[2-9]|[3-9])")
GAS218_OR_LATER := $(shell $(CXX) -xc -c /dev/null -Wa,-v -o/dev/null 2>&1 | $(GREP) -c -E "GNU assembler version (2\.1[8-9]|2\.[2-9]|[3-9])")
GAS219_OR_LATER := $(shell $(CXX) -xc -c /dev/null -Wa,-v -o/dev/null 2>&1 | $(GREP) -c -E "GNU assembler version (2\.19|2\.[2-9]|[3-9])")
GAS224_OR_LATER := $(shell $(CXX) -xc -c /dev/null -Wa,-v -o/dev/null 2>&1 | $(GREP) -c -E "GNU assembler version (2\.2[4-9]|2\.[3-9]|[3-9])")
endif
А позже Crypto ++ будет выполнять такие вещи, как:
ifeq ($(HAVE_GAS)$(GAS224_OR_LATER),10)
CXXFLAGS += -DCRYPTOPP_DISABLE_SHA
endif
Строка 10
в основном эквивалентно следующему.Это способ создания логических выражений в GNU Makefile:
if HAVE_GAS==true && GAS224_OR_LATER==false
CXXFLAGS += -DCRYPTOPP_DISABLE_SHA
fi
Кстати, проверка версии GAS не работает с Clang и Integrated Assembler.Clang не отвечает на -Wa,-v
, как AS.Ошибка LLVM 24200 была вызвана из-за этого: Не удалось получить строку версии ассемблера при использовании встроенного ассемблера .
То, что обнаружил Crypto ++, не очень хорошо масштабировалось.Это было нормально 10 или 20 лет назад (буквально, когда оно использовалось изначально).Однако это сломалось, когда (1) новые платформы используют древние цепочки инструментов, такие как современные BSD, прикрепляемые к цепям инструментов GPL2 (2) новые компиляторы были установлены на старые платформы, такие как Clang 7.0 на машине Power6, и (3) Clang и его интегрированный ассемблер,который не нуждался в AS для сборки более высоких ISA.
Платформы ARM также были очень хлопотными, потому что проект не мог надежно определить, когда включать <arm_neon.h>
и <arm_acle.h>
на основе платформ и компилятораверсии.Иногда заголовки были доступны для платформы и компилятора, иногда - нет (даже на одной и той же платформе с разными версиями одного и того же компилятора).Макросы препроцессора, такие как __ARM_ACLE__
, полностью отсутствовали (см. ARM C Language Extensions (ACLE) ).Android и iOS просто делают то, что хотят, ломаясь от того, что происходит с armhf и друзьями или с тем, что указано в документации.И Microsoft нашла новый способ сломать его с помощью своего заголовка <arm64_neon.h>
.
Теперь Crypto ++ выполняет тестовую компиляцию через Makefile GNU, чтобы посмотреть, можно ли скомпилировать, собрать и связать программу,Тем не менее, это не мозговой мертвец, как Autotools или Cmake.Crypto ++ ищет любую диагностику и не проходит тест на любую диагностику.Это обнаруживало случаи, когда Autotools и Cmake отсутствовали, например, SunCC излучал как "недопустимый параметр: -xarch = sha" .Autotools и Cmake сообщат об успехе, и позже сборка не удастся.(Очевидно, что Autotools и Cmake проверяют только коды возврата компилятора, а не диагностические сообщения, такие как «недопустимая опция»).
Тесты Crypto ++ теперь выглядят как :
SUN_COMPILER := $(shell $(CXX) -V 2>&1 | $(GREP) -i -c -E 'CC: (Sun|Studio)')
...
ifeq ($(SUN_COMPILER),1)
SSE2_FLAG = -xarch=sse2
else
SSE2_FLAG = -msse2
endif
...
TPROG = TestPrograms/test_x86_sse2.cxx
TOPT = $(SSE2_FLAG)
HAVE_OPT = $(shell $(CXX) $(TCXXFLAGS) $(ZOPT) $(TOPT) $(TPROG) -o $(TOUT) 2>&1 | tr ' ' '\n' | wc -l)
ifeq ($(strip $(HAVE_OPT)),0)
CHACHA_FLAG = $(SSE2_FLAG)
SUN_LDFLAGS += $(SSE2_FLAG)
else
SSE2_FLAG =
endif
И test_x86_sse2.cxx
, который компилируется в -O0
, поэтому оптимизатор не удаляет код:
$ cat TestPrograms/test_x86_sse2.cxx
#include <emmintrin.h>
int main(int argc, char* argv[])
{
__m128i x = _mm_setzero_si128();
x=_mm_add_epi64(x,x);
return 0;
}