2010-09-16 3 views
12

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

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

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

ответ

15

GNU Make не содержит никаких сравнений строк, отличных от равенства, и test может выполнять тесты на целых числах меньше или больше. Разделите номер версии на ее неотъемлемые части и сравните ее таким образом. Попробуйте (обратите внимание также, что := лучше = здесь, как ленивые оценки сделать было бы назвать вашу $(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 
+4

PS Мало того, что это некрасиво, но он будет повторять проверку версии каждый раз, когда вы запускаете 'make'. Более чистым решением будет использование 'autoconf' для создания вашего' Makefile' и/или некоторого заголовка, например 'config.h'. –

1

Я понимаю, что это старый вопрос, но все же На самом деле вы можете прибегнуть. к 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 ...), а другой text functions that GNU make provides.

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

1

немного короче раствор:

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, ...", потому что позже не работает сделать 3.8. И короче ...

... некоторые эр позже

Я попытался решить сравнение версий с внутренними функциями Makefile. Я нашел проект (GNU Make Standard Library (GMSL)), который добавляет к make-файл, который реализует целочисленную арифметику. К сожалению, с общим unary numeral system. Но сравнение номеров версий сложнее. Когда я работал с версиями с номерами больше 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). Сейчас я не хочу их решать.

Раствор

Он testAed под гну сделать 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-файла.

+0

На самом деле я использовал это, чтобы проверить номер версии glibc. Я использовал следующую команду для получения номера версии: 'GLIBC: = $ (lastword $ (shell getconf GNU_LIBC_VERSION))' – TrueY

+0

Это не было предназначено, но оно также работает, если 'RH_VER_NUM' - это 5.4.3.2. Если проверенная версия также имеет несколько точек, то сортировка должна быть расширена. В случае трех точек в конец 'sort' можно добавить' -k3,3n -k4,4n'. – TrueY

0

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

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 
2

Самое простое решение, я думаю, является с помощью 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 

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

1

Что об использовании функции сортировки:

ifeq "$ (firstword $ (вроде $ (RH_VER_NUM), 5,3))" "5,3"

RH_GT_5_3 = 1

ENDIF

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

1

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

Идея просто

х> у

= у члена {0,1,2,3,4 ..., х - 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)) 
Смежные вопросы