2010-09-16 12 views
12

En un archivo MAKE, me gustaría definir una variable que especifique si el redhat-release actual es mayor que 5.3. (Esta variable se pasará a gcc como #define)Comparación del número de versión dentro del archivo MAKE

Hasta ahora hemos llegado con:

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

¿Cuál sería la forma correcta para definir RH_GT_5_3?

Respuesta

15

GNU Make no contiene comparaciones de cadenas distintas de la igualdad, y test solo puede realizar pruebas menores que/mayores en enteros. Dividir el número de versión en sus partes integrales y hacer la comparación de esa manera. Prueba esto (Tenga en cuenta también que := es mejor que = aquí, ya que la evaluación perezosa de maquillaje llamarían su $(shell) comandos muchas veces más de lo necesario:

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 No solo es feo, sino que volverá a hacer la verificación de la versión cada vez que ejecute 'make'. Una solución más limpia sería usar 'autoconf' para generar su' Makefile' y/o algún encabezado como 'config.h'. –

1

Comprendo que esto es una vieja pregunta, pero aún En realidad se puede recurrir. a lsb_release, que he encontrado para ser instalado en todos los sistemas RedHat reciente sencillo.

para ser más precisos que serías uso de

lsb_release -sr 

dentro $(shell ...) y luego dividir en el . así:

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

ahora tiene las partes principales/secundarias de la versión de lanzamiento y puede comprobar que en contra de lo que quiera.

El caso clásico sería $(filter ...) y el otro text functions that GNU make provides.

Sin embargo, estoy de acuerdo en que una especie de config.h tendría más sentido, aunque Autotools no es perfecto para todos los escenarios (aunque hay otras herramientas de compilación que intentan lo mismo).

solución
1

Un poco más corta es:

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

Esto establecerá RH_GT_5_3 a "SÍ" si RH_VER_NUM es mayor que o igual a 5,4 (de modo mayor que 5,3). De lo contrario, RH_GT_5_3 se configurará como vacío.

Si hay varios números de versión deben ser verificados podemos definir una función:

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 

he utilizado la palabra "($ 2, ..." en lugar de "$ (LastWord, ...", porque la tarde no funciona en hacer 3.8. Y más corto ...

... algunos eones más tarde

me trataron de resolver la comparación de versiones con funciones internas makefile. he encontrado un proyecto (GNU Make Standard Library (GMSL)), que agrega una inclusión a el archivo MAKE que implementa la aritmética de enteros. Desafortunadamente con el unary numeral system común. Pero comparar números de versión es más complejo. Como trabajé con versiones que tenían números mayores que 100_000, decidí implementar una solución más general. Funciona con un número arbitrario de números de subversión, cada uno con dígitos arbitrarios.Algunas ideas fueron tomadas del proyecto GMSL

Implementa la función ver.lt. Devuelve 'T' si el primer número de versión es menor que el segundo. Devuelve una cadena vacía de lo contrario. Por supuesto, los números de subversión se comparan numéricamente, no lexicográficamente. Entonces 1.20 es mayor que 1.3. Hay algunos problemas. 1.2 < 1.2.0, 1.0.1 < 1.00.1, 1.9.1 < 1.01.1 (ya que se espera que un número comience con un dígito distinto de cero. Excepto el 0 en sí). No quiero resolverlos ahora.

La solución

Se testAed bajo los términos de hacer 3.82.90. Hay algunas líneas muy largas como makefile add espacios si se usa '\'. Dejé algunas funciones implementadas, pero no usadas en el código. Tal vez usaría mejores nombres temporales de variables (como GMSL usa _ gmsl). A veces, las variables temporales pueden dejarse, pero el código sería más críptico.

.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)% 

Y la salida

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:% 

Más música

he encontrado otro interesante proyecto llamado makepp (makepp.sourceforge.net). Permite implementar nuevas funciones en perl dentro del archivo MAKE.

+0

En realidad lo he usado para verificar el número de versión de glibc. Utilicé el siguiente comando para obtener el número de versión: 'GLIBC: = $ (lastword $ (shell getconf GNU_LIBC_VERSION))' – TrueY

+0

No fue intencionado, pero también funciona si 'RH_VER_NUM' es 5.4.3.2. Si la versión comprobada también tiene múltiples puntos, entonces la clasificación debe extenderse. En el caso de tres puntos, se podría agregar '-k3,3n -k4,4n' al final del 'tipo'. – TrueY

0

Una manera moderna sería la de obtener la versión en make (usando una llamada al shell), por ejemplo:

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]}))) 

Y luego tener la versión de indicadores específicos:

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

e imprimirlos:

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

salida:

$ make 
redhat_release=605 
redhat_flags=abc def 
2

La solución más sencilla pienso es mediante el uso de 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 

Esta será igual a 1 si más grande que 5,3, y lo contrario.

1

¿Qué pasa con el uso de la función para ordenar:

ifeq "$ (FirstWord $ (tipo $ (RH_VER_NUM), 5,3))" "5.3"

RH_GT_5_3 = 1

endif

(Bueno, en realidad sería una prueba para mayor o igual, pero se entiende)

1

Felicitaciones a TrueY por encontrar una versión que no utiliza comandos de shell caros. Tengo una versión más simple que solo compara 2 enteros pequeños (a menudo solo te importa la versión principal).

La idea es simplemente

x> y

= y es miembro del {0,1,2,3,4 ..., x - 1)

El miembro del operador se puede implementar con GNU make's $ (filtro) y generar el conjunto se puede hacer con $ (lista de palabras)

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