makefile中的版本号比较

tso*_*tso 14 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'
Run Code Online (Sandbox Code Playgroud)

定义RH_GT_5_3的正确方法是什么?

Jac*_*lly 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
Run Code Online (Sandbox Code Playgroud)

  • PS这不仅是丑陋的,而且每次运行`make`时都会重新进行版本检查.一个更干净的解决方案是使用`autoconf`生成`Makefile`和/或像`config.h`这样的标题. (5认同)

Tru*_*ueY 7

更短的解决方案是:

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

如果 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
Run Code Online (Sandbox Code Playgroud)

我使用了“$(word 2,...”而不是“$(lastword,...”) 因为后者在 make 3.8 中不起作用。而且更短...

... 数亿年后

我试图解决与内部makefile函数的版本比较。我找到了一个项目(GNU Make Standard Library (GMSL)),它向实现整数运算的 makefile 添加了一个包含。不幸的是,使用常见的一元数字系统。但是比较版本号更复杂。当我使用数字大于 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 本身。)。我现在不想解决它们。

解决方案

它是在 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)%
Run Code Online (Sandbox Code Playgroud)

和输出

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:%
Run Code Online (Sandbox Code Playgroud)

更多音乐

我发现了另一个有趣的项目,叫做 makepp (makepp.sourceforge.net)。它允许在 makefile 中的 perl 中实现新功能。


Jea*_* T. 5

我想到的最简单的解决方案是使用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
Run Code Online (Sandbox Code Playgroud)

如果大于 5.3,则等于1,否则等于0