makefile中的版本号比较

问题描述 投票:13回答:7

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

makefile gnu-make
7个回答
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

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

我使用了“$(word 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中实现新函数。


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。


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对所有场景都不是完美的(尽管还有其他构建工具尝试相同)。


2
投票

那么使用sort函数呢:

ifeq“$(firstword $(sort $(RH_VER_NUM),5.3))”“5.3”

RH_GT_5_3 = 1

ENDIF

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


2
投票

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

这个想法很简单

x> y

= 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))

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
最新问题
© www.soinside.com 2019 - 2024. All rights reserved.