Сравнение номера версии внутри make-файла - PullRequest
13 голосов
/ 16 сентября 2010

В make-файле я хотел бы определить переменную, указывающую, является ли текущий redhat-релиз больше, чем 5.3. (Эта переменная будет передана в gcc как #define)

До сих пор я придумал:

# Find out which version of Red-Hat we're running
RH_VER_NUM = $(shell /bin/grep -o [0-9].[0-9] /etc/redhat-release)
RH_GT_5_3 = $RH_VER_NUM > '5.3'

Как правильно определить RH_GT_5_3?

Ответы [ 7 ]

17 голосов
/ 17 сентября 2010

GNU Make не содержит никаких строковых сравнений, кроме равенства, а test может выполнять только проверки на целые числа меньше / больше, чем. Разбейте номер версии на его составные части и сделайте сравнение таким образом. Попробуйте это (обратите внимание также, что := лучше, чем = здесь, так как ленивая оценка make будет вызывать ваши $(shell) команды намного больше, чем требуется:

RH_VER_MAJOR := $(shell echo $(RH_VER_NUM) | cut -f1 -d.)
RH_VER_MINOR := $(shell echo $(RH_VER_NUM) | cut -f2 -d.)
RH_GT_5_3 := $(shell [ $(RH_VER_MAJOR) -gt 5 -o \( $(RH_VER_MAJOR) -eq 5 -a $(RH_VER_MINOR) -ge 3 \) ] && echo true)

ifeq ($(RH_GT_5_3),true)
CPPFLAGS += -DRH_GT_5_3=1
endif
3 голосов
/ 30 декабря 2015

Самое простое решение, о котором я думаю, это использование bc:

# Find out which version of Red-Hat we're running
RH_VER_NUM = $(shell /bin/grep -o [0-9].[0-9] /etc/redhat-release)
RH_GT_5_3 = $(shell echo $(RH_VER_NUM)\>=5.3 | bc )

ifeq ($(RH_GT_5_3),1)
CPPFLAGS += -DRH_GT_5_3=1
endif

Это будет равно 1 , если оно больше 5,3, и 0 в противном случае.

3 голосов
/ 26 марта 2013

Немного более короткое решение:

RH_GT_5_3 := $(shell echo -e "5.4\n$(RH_VER_NUM)"|sort -ct. -k1,1n -k2,2n && echo YES)

Это установит RH_GT_5_3 на "ДА", если RH_VER_NUM больше или равно 5,4 (то есть больше, чем 5,3).В противном случае RH_GT_5_3 будет пустым.

Если нужно проверить несколько номеров версий, мы можем определить функцию:

IF_VER_GE = $(shell echo -e "$2\n$1"|sort -ct. -k1,1n -k2,2n && echo YES)
GLIBC := $(word 2,$(shell getconf GNU_LIBC_VERSION))
...
all:
ifeq "$(call IF_VER_GE, $(GLIBC), 2.5)" "YES"
    echo "GE"
else
    echo "LT"
endif

Я использовал «$ (слово 2, ...»).вместо "$ (lastword, ...", потому что последний не работает в make 3.8. И короче ...

... через несколько эонов

Я попытался решить сравнение версий с внутренними функциями make-файла. Я нашел проект ( GNU Make Standard Library (GMSL) ), который добавляет в make-файл включение, которое реализует целочисленную арифметику. К сожалению, с общим унарная система счисления . Но сравнение номеров версий более сложное. Поскольку я работал с версиями, числа которых превышают 100_000, я решил реализовать более общее решение: оно работает с произвольным числом чисел подрывной деятельности, каждое с произвольными цифрами. Некоторые идеибыли заимствованы из проекта GMSL

Он реализует функцию ver.lt. Возвращает 'T', если первый номер версии меньше второго.в противном случае возвращает пустую строку.Конечно, числа подрывной деятельности сравниваются численно, а не лексикографически.Таким образом, 1,20 больше, чем 1,3.Есть некоторые проблемы.1.2 <1.2.0, 1.0.1 <1.00.1, 1.9.1 <1.01.1 (так как ожидается, что число начинается с ненулевой цифры. За исключением самого 0).Я не хочу их решать сейчас. </p>

Решение

Это тестирование под GNU make 3.82.90.Есть несколько очень длинных строк, так как makefile добавляет пробелы, если используется '\'.Я оставил некоторые реализованные, но не используемые функции в коде.Может быть, я бы лучше использовал временные имена переменных (например, GMSL использует _ gmsl ).Иногда временные переменные могут быть пропущены, но код будет более загадочным.

.SILENT:
S :=
SP := $S $S

# For non empty strings
#not = $(if $1,$S,T)
#str.ne = $(if $(subst $1,,$2),T,$S)
str.eq = $(if $(subst $1,,$2),$S,T)
str.le = $(call str.eq,$(word 1,$(sort $1 $2)),$1)
#str.ge = $(call str.eq,$(word 1,$(sort $1 $2)),$2)

# Creates a list of digits from a number
mklist = $(eval __tmp := $1)$(foreach i,0 1 2 3 4 5 6 7 8 9,$(eval __tmp := $$(subst $$i,$$i ,$(__tmp))))$(__tmp)
# reverse: $(subst $(SP),,$(list))

#pop = $(wordlist 2, $(words $1), x $1)
#push = $1 $2
shift = $(wordlist 2, $(words $1), $1)
#unshift = $2 $1

num.le = $(eval __tmp1 := $(call mklist,$1))$(eval __tmp2 := $(call mklist,$2))$(if $(call str.eq,$(words $(__tmp1)),$(words $(__tmp2))),$(call str.le,$1,$2),$(call str.le,$(words $(__tmp1)),$(words $(__tmp2))))

#num.ge = $(eval __tmp1 := $(call mklist,$1))$(eval __tmp2 := $(call mklist,$2))$(if $(call str.eq,$(words $(__tmp1)),$(words $(__tmp2))),$(call str.ge,$1,$2),$(call str.ge,$(words $(__tmp1)),$(words $(__tmp2))))

#Strip zeroes from the beginning of a list
list.strip = $(eval __flag := 1)$(foreach d,$1,$(if $(__flag),$(if $(subst 0,,$d),$(eval __flag :=)$d,$S),$d))
#Strip zeroes from the beginning of a number
#num.strip = $(subst $(SP),,$(call list.strip,$(call mklist,$1)))

# temp string: 0 - two number equals, L first LT, G first GT or second is short,
gen.cmpstr = $(eval __Tmp1 := $(subst ., ,$1))$(eval __Tmp2 := $(subst ., ,$2))$(foreach i,$(__Tmp1),$(eval j := $(word 1,$(__Tmp2)))$(if $j,$(if $(call str.eq,$i,$j),0,$(if $(call num.le,$i,$j),L,G)),G)$(eval __Tmp2 := $$(call shift,$(__Tmp2))))$(if $(__Tmp2), L)

ver.lt = $(call str.eq,$(word 1,$(call list.strip,$(call gen.cmpstr,$1,$2))),L)

all:
    echo ver.lt,1.20,1.3:$(call ver.lt,1.20,1.3)%
    echo ver.lt,1.5.9,1.5:$(call ver.lt,1.5.9,1.5)%
    echo ver.lt,1.4.9,1.5:$(call ver.lt,1.4.9,1.5)%
    echo ver.lt,1.2,1.2.0:$(call ver.lt,1.2,1.2.0)%
    echo ver.lt,1.20.3.4.5,1.10.5:$(call ver.lt,1.20.3.4.5,1.10.5)%
    echo ver.lt,1.20.3.4.5,1.0.5:$(call ver.lt,1.20.3.4.5,1.0.5)%
    echo ver.lt,1.0,1.0.5:$(call ver.lt,1.0,1.0.5)%
    echo ver.lt,1.20,1.10.3:$(call ver.lt,1.20,1.10.3)%
    echo ver.lt,1.20,1.30.3::$(call ver.lt,1.20,1.30.3)%
    echo ver.lt,1.10.3,1.10.3:$(call ver.lt,1.10.3,1.10.3)%

И вывод

ver.lt,1.20,1.3:%
ver.lt,1.5.9,1.5:%
ver.lt,1.4.9,1.5:T%
ver.lt,1.2,1.2.0:T%
ver.lt,1.20.3.4.5,1.10.5:%
ver.lt,1.20.3.4.5,1.0.5:%
ver.lt,1.0,1.0.5:T%
ver.lt,1.20,1.10.3:%
ver.lt,1.20,1.30.3::T%
ver.lt,1.10.3,1.10.3:%

Больше музыки

Я нашел еще один интересный проект под названием makepp (makepp.sourceforge.net).Это позволяет реализовывать новые функции в perl внутри make-файла.

2 голосов
/ 06 марта 2018

Благодарность TrueY за разработку версии, в которой не используются дорогостоящие команды оболочки. У меня есть более простая версия, которая сравнивает только 2 маленьких целых числа (часто вас интересует только основная версия).

Идея просто

x> y

= y является членом {0,1,2,3,4 ..., x - 1)

Член оператора может быть реализован с помощью GNU make $ (filter), а генерация набора может быть сделана с помощью $ (wordlist)

# returns all integers less than x
LessThanSubset=$(wordlist 1,$(1),0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20)

# if x > y, return 1, empty otherwise
GreaterThan=$(if $(filter $(2),$(call LessThanSubset,$(1))),1)
GreaterOrEqual=$(if $(filter $(2),$(call LessThanSubset,$(1)) $(1)),1)

# example
$(error 5 > 4 = $(call GreaterThan,5,4))
2 голосов
/ 04 марта 2016

Как насчет использования функции сортировки:

ifeq "$ (firstword $ (sort $ (RH_VER_NUM), 5.3))" "5.3"

RH_GT_5_3 = 1

endif

(ну, на самом деле это будет проверка на большее или равное, но вы поняли)

2 голосов
/ 09 августа 2012

Я понимаю, что это старый вопрос, но все же.На самом деле вы можете прибегнуть к lsb_release, который, как я обнаружил, установлен в каждой последней системе RedHat.

Если быть точным, вы бы использовали

lsb_release -sr

внутри $(shell ...)а затем разделить на . следующим образом:

RH_VER:=$(shell lsb_release -sr)
RH_MAJVER:=$(word 1, $(subst ., ,$(RH_VER)))
RH_MINVER:=$(word 2, $(subst ., ,$(RH_VER)))

Теперь у вас есть основные / второстепенные части версии выпуска и вы можете проверить это по своему вкусу.

Классический случайбудет $(filter ...), а другие текстовые функции, которые делает GNU, предоставляют .

Тем не менее я согласен, что разновидность config.h будет иметь больше смысла, хотя Autotools отнюдь не идеалендля всех сценариев (хотя есть и другие инструменты сборки, которые делают то же самое).

1 голос
/ 23 сентября 2014

Современным способом было бы получить версию в make (используя один вызов оболочки), например:

SHELL := /bin/bash
# Define redhat_release as major_version * 100 + minor_version
redhat_release := $(shell [[ "$$(cat /etc/redhat-release)" =~ ([0-9]+)\.([0-9]+) ]] && echo $$(( $${BASH_REMATCH[1]} * 100 + $${BASH_REMATCH[2]} )))

И затем иметь специфичные для версии флаги:

# Flags for different redhat versions
redhat_flags.604 := abc
redhat_flags.605 := ${redhat_flags.604} def 
redhat_flags := ${redhat_flags.${redhat_release}}

И печататьих выход:

$(info redhat_release=${redhat_release})
$(info redhat_flags=${redhat_flags})

Вывод:

$ make
redhat_release=605
redhat_flags=abc def
...