在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的正确方法是什么?
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
一点点解决方案是:
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中实现新函数。
我想到的最简单的解决方案是使用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。
我意识到这是一个古老的问题,但仍然存在。实际上你可以使用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对所有场景都不是完美的(尽管还有其他构建工具尝试相同)。
那么使用sort函数呢:
ifeq“$(firstword $(sort $(RH_VER_NUM),5.3))”“5.3”
RH_GT_5_3 = 1
ENDIF
(实际上,它会测试更大或相等,但你明白了)
感谢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))
一种现代的方法是将版本转换为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