Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/visual-studio-2010/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
makefile内的版本号比较_Makefile_Gnu Make - Fatal编程技术网

makefile内的版本号比较

makefile内的版本号比较,makefile,gnu-make,Makefile,Gnu Make,在makefile中,我想定义一个变量,指定当前redhat版本是否大于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的正确方法是什么?GN

在makefile中,我想定义一个变量,指定当前redhat版本是否大于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

我意识到这是一个老问题,但仍然是。实际上,你可以求助于
lsb_发行版
,我发现它安装在每一个最新的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…
)和其他情况


尽管如此,我还是同意使用一种
config.h
会更有意义,尽管Autotools并不是所有场景的完美工具(尽管还有其他构建工具尝试使用相同的工具)。

稍微短一点的解决方案是:

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设置为“是”。否则,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
ifeq "$(firstword $(sort $(RH_VER_NUM),5.3))" "5.3"

RH_GT_5_3 = 1

endif
version_greater_equal = $(shell if printf '%s\n%s\n' '$(2)' '$(1)' | \
    sort -Ct. -k1,1n -k2,2n ; then echo YES; else echo NO; fi )

ifeq (YES,$(call version_greater_equal,${SOME_VERSION},8.2))
...
我用“$(word 2,…”代替“$(lastword,…”,因为后者在make 3.8中不起作用。而且更短

…有些年代以后

我试图用内部makefile函数解决版本比较问题。我找到了一个项目(),它在实现整数运算的makefile中添加了一个include。很遗憾,这是一个常见的问题。但是比较版本号更复杂。当我处理的版本号大于100_000时,我决定实现一个更通用的解决方案。它可以处理任意数量的subversion编号,每个编号都有任意数字。S从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使用“U 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实现新功能。

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

然后具有特定于版本的标志:

# 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
Release version:
Beta version:  18 .r 01 -beta. 3 . 5
Major: 18, Minor: 3, Bugfix: 5, Release: 01, greater than 5.3:  yes
Release version:  5 . 3 . 12 .r 3
Beta version:
Major: 5, Minor: 3, Bugfix: 12, Release: 3, greater than 5.3: no

我想到的最简单的解决方案是使用
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

使用排序功能如何:

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
ifeq "$(firstword $(sort $(RH_VER_NUM),5.3))" "5.3"

RH_GT_5_3 = 1

endif
version_greater_equal = $(shell if printf '%s\n%s\n' '$(2)' '$(1)' | \
    sort -Ct. -k1,1n -k2,2n ; then echo YES; else echo NO; fi )

ifeq (YES,$(call version_greater_equal,${SOME_VERSION},8.2))
...

(实际上,它可以测试大于或等于,但你明白了)

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

这个想法很简单

x>y

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

操作符的成员可以用GNU make的$(filter)实现,生成集合可以用$(wordlist)完成


基于TrueY对
sort
的巧妙使用,使其成为可重用的Make功能:

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
ifeq "$(firstword $(sort $(RH_VER_NUM),5.3))" "5.3"

RH_GT_5_3 = 1

endif
version_greater_equal = $(shell if printf '%s\n%s\n' '$(2)' '$(1)' | \
    sort -Ct. -k1,1n -k2,2n ; then echo YES; else echo NO; fi )

ifeq (YES,$(call version_greater_equal,${SOME_VERSION},8.2))
...

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

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

make VERSION_NR=18.r01-beta.3.5
输出:

$ make
redhat_release=605
redhat_flags=abc def
Release version:
Beta version:  18 .r 01 -beta. 3 . 5
Major: 18, Minor: 3, Bugfix: 5, Release: 01, greater than 5.3:  yes
Release version:  5 . 3 . 12 .r 3
Beta version:
Major: 5, Minor: 3, Bugfix: 12, Release: 3, greater than 5.3: no
使用等于5.3的版本进行测试:

make VERSION_NR=5.3.12.r3
输出:

$ make
redhat_release=605
redhat_flags=abc def
Release version:
Beta version:  18 .r 01 -beta. 3 . 5
Major: 18, Minor: 3, Bugfix: 5, Release: 01, greater than 5.3:  yes
Release version:  5 . 3 . 12 .r 3
Beta version:
Major: 5, Minor: 3, Bugfix: 12, Release: 3, greater than 5.3: no

另外,这不仅很难看,而且每次运行
make
时它都会重新进行版本检查。一个更干净的解决方案是使用
autoconf
生成
Makefile
和/或类似
config.h
的头文件。实际上,我用它来检查glibc的版本号。我使用以下命令来获取version编号:
GLIBC:=$(lastword$(shell getconf GNU_LIBC_版本))
这不是故意的,但是如果
RH\u VER\u NUM
是5.4.3.2,它也可以工作。如果选中的版本也有多个点,那么应该扩展排序。如果有三个点,可以将a
-k3,3n-k4,4n
添加到
排序的末尾。您可能想看看哪个支持八进制、十进制和十六进制ecimal数字,正数和负数。此代码认为5.10小于5.2。排序版本号并不那么容易。例如,它不适用于5.3.1。不幸的是,它在Android 10 build中不起作用,而在主机env:/。使用的排序函数没有选项C和t。这是一个非常特殊的情况…Android使用busybox或类似工具。我指的不是运行Android的目标机器上的sort命令。我指的是主机(构建的计算机)上使用的sort命令。这是两个不同的