makefile中的版本号比较

时间:2010-09-16 15:49:34

标签: makefile gnu-make

在makefile中,我想定义一个变量,指定当前的redhat-release是否大于5.3。 (此变量将作为#define传递给gcc)

到目前为止,我已经提出:

# 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的正确方法是什么?

9 个答案:

答案 0 :(得分:17)

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

答案 1 :(得分:3)

稍微简短的解决方案是:

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

如果RH_VER_NUM大于或等于5.4(那么大于5.3),这将RH_GT_5_3设置为“YES”。否则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中不起作用。而且更短...

......以后有些人

我尝试用内部makefile函数解决版本比较。我找到了一个项目(GNU Make Standard Library (GMSL)),它在makefile中添加了一个include,它实现了整数运算。不幸的是,常见的unary numeral system。但比较版本号更复杂。当我使用数字大于100_000的版本时,我决定实施更通用的解决方案。它适用于任意数量的subversion数字,每个数字都有任意数字。一些想法来自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本身。)。我现在不想解决它们。

解决方案

在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)的有趣项目。它允许在makefile中的perl中实现新函数。

答案 2 :(得分:3)

我想到的最简单的解决方案是使用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 ,否则等于 0

答案 3 :(得分:2)

我意识到这是一个老问题,但仍然存在。实际上你可以使用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对所有场景都不是完美的(尽管还有其他构建工具尝试相同)。

答案 4 :(得分:2)

使用sort函数怎么样:

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

RH_GT_5_3 = 1

ENDIF

(实际上,它会测试更大或相等,但你明白了)

答案 5 :(得分:2)

推荐使用不使用任何昂贵的shell命令的版本来推荐TrueY。我有一个更简单的版本,只比较2个小整数(通常你只关心主要版本)。

这个想法很简单

x> ÿ

= y是{0,1,2,3,4 ...,x - 1)的成员

运算符的成员可以用GNU make的$(过滤器)实现,生成集可以用$(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))

答案 6 :(得分:1)

现代的方法是将版本转换为make(使用一个shell调用),例如:

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

答案 7 :(得分:0)

在TrueY对# Select Questions without related Choices >>> Question.objects.filter(choice=None) # Select only Questions with related Choices >>> Question.objects.exclude(choice=None) # Select Questions related to Choice with id 1 >>> Question.objects.filter(choice__id=1) 的聪明使用的基础上,使其成为可重用的Make函数:

sort

答案 8 :(得分:0)

借助GNUmake table toolkit的算术功能,您可以编写一个相当通用的测试-您需要适应的一件事就是类似Lisp的函数样式(“函数op1,op2,opN”):

include gmtt/gmtt.mk

# Simulate some nasty versioning style:
# X.Y.Z.rN for release versions,
# X.rN-beta.Y.Z for beta versions towards a release
VERSION_NR_REL := $(call glob-match,$(VERSION_NR),*.*.*.r*)
VERSION_NR_BETA := $(call glob-match,$(VERSION_NR),*.r*-beta.*.*)

# glob-match only produces a non-empty result if the match succeeds,
# thus one of the following will be an empty string
$(info Release version: $(VERSION_NR_REL))
$(info Beta version: $(VERSION_NR_BETA))

# we use makes "if" function which sees empty strings as false and everything else as true
BETA_OR_RELEASE := $(if $(VERSION_NR_REL),release,beta)

# react to version numbers on different positions in release and beta
ifeq ($(BETA_OR_RELEASE),beta)
MAJOR_V := $(word 1,$(VERSION_NR_BETA))
MINOR_V := $(word 5,$(VERSION_NR_BETA))
BUGFIX_V := $(word 7,$(VERSION_NR_BETA))
REL_NR := $(word 3,$(VERSION_NR_BETA))
else
MAJOR_V := $(word 1,$(VERSION_NR_REL))
MINOR_V := $(word 3,$(VERSION_NR_REL))
BUGFIX_V := $(word 5,$(VERSION_NR_REL))
REL_NR := $(word 7,$(VERSION_NR_REL))
endif

GT_5_3 := $(if $(or $(call int-gt,$(MAJOR_V),5),\
                    $(and $(call int-eq,$(MAJOR_V),5),\
                          $(call int-gt,$(MINOR_V),3))),\
            yes,no)
$(info Major: $(MAJOR_V), Minor: $(MINOR_V), Bugfix: $(BUGFIX_V), Release: $(REL_NR), greater than 5.3: $(GT_5_3))

使用更大的版本号进行测试:

make VERSION_NR=18.r01-beta.3.5

输出:

Release version:
Beta version:  18 .r 01 -beta. 3 . 5
Major: 18, Minor: 3, Bugfix: 5, Release: 01, greater than 5.3:  yes

使用等于5.3的版本进行测试:

make VERSION_NR=5.3.12.r3

输出:

Release version:  5 . 3 . 12 .r 3
Beta version:
Major: 5, Minor: 3, Bugfix: 12, Release: 3, greater than 5.3: no
相关问题