如何有条件地为 Makefile (BSD + GNU) 中的变量赋值?
How to conditionally assign value to a variable in a Makefile (BSD + GNU)?
我有一个(从我的角度来看)相当复杂的 Makefile。
那主要是因为我想要那里的颜色和其他不必要的东西。
无论如何,我可以直接进入我的问题:
除了Linux我最近支持*BSD,因此我需要在几个地方检查正在使用的平台。 Makefile 中是否可以进行条件变量赋值?类似于:
platform := [ $$(uname) = Linux ] && echo Linux || echo BSD or other
当然这行不通,但希望你明白我的意思。
我需要一个同时适用于 BSD make
和 GNU make
的解决方案。
BSD 和 GNU make 显然都支持 !=
shell 赋值运算符:
platform_id != uname -s
platform != if [ $(platform_id) = Linux ] || \
[ $(platform_id) = FreeBSD ] || \
[ $(platform_id) = OpenBSD ] || \
[ $(platform_id) = NetBSD ]; then \
echo $(platform_id); \
else \
echo Unrecognized; \
fi
请注意,赋值实际上是由 shell 求值的:赋值给 make 变量的是求值结果,而不是 shell 命令。
需要 GNU make 的解决方案。它适用于 BSD 上的 GNU make,但不适用于 BSD make。
一种可能是使用 if
GNU make function:
platform := $(if $(patsubst Linux,,$(shell uname -s)),BSD or other,Linux)
另一种是仅依赖 shell 条件:
platform := $(shell [ $$(uname) = Linux ] && echo Linux || echo BSD or other)
ifeq ($(shell uname -s),Linux)
platform := Linux
else
platform := BSD or other
endif
使用此解决方案前请注意
对Renaud Pacalet的赞美:你分配给make变量的是shell命令,而不是shell执行它们的结果。这将严重限制您对它们的使用(主要是食谱)。您将无法将它们用作目标、先决条件、其他变量定义、make conditionals 的条件。
扩展 MadScientist 的评论
我引用:
Note !=
was added to GNU make in version 4.0. It won't work in older versions.
并且还简化了一堆不必要的 if
s,我们可以在 可能是所有 版本的 GNU 和 BSD make
上得到一个工作版本,比如下面的方法。
通过 shell
的替代方法
platform_id = $$( uname -s )
platform = $$( \
case $(platform_id) in \
( Linux | FreeBSD | OpenBSD | NetBSD ) echo $(platform_id) ;; \
( * ) echo Unrecognized ;; \
esac )
重要提示:
您需要在此处使用标准 =
惰性赋值。使用立即赋值运算符 :=
,它在 BSD make 中不起作用。
您需要在case
语句中使用( ... )
。否则,它将无法在 OpenBSD
上运行
成功测试:
我仍在努力让 NetBSD 8.0 在 VirtualBox 中工作,所以我还不能确认这一点。
需要对这些系统的旧版本进行进一步测试,因此如果您有其中一个明显较旧的系统,请进行测试,谢谢。
我有一个(从我的角度来看)相当复杂的 Makefile。
那主要是因为我想要那里的颜色和其他不必要的东西。
无论如何,我可以直接进入我的问题:
除了Linux我最近支持*BSD,因此我需要在几个地方检查正在使用的平台。 Makefile 中是否可以进行条件变量赋值?类似于:
platform := [ $$(uname) = Linux ] && echo Linux || echo BSD or other
当然这行不通,但希望你明白我的意思。
我需要一个同时适用于 BSD make
和 GNU make
的解决方案。
BSD 和 GNU make 显然都支持 !=
shell 赋值运算符:
platform_id != uname -s
platform != if [ $(platform_id) = Linux ] || \
[ $(platform_id) = FreeBSD ] || \
[ $(platform_id) = OpenBSD ] || \
[ $(platform_id) = NetBSD ]; then \
echo $(platform_id); \
else \
echo Unrecognized; \
fi
请注意,赋值实际上是由 shell 求值的:赋值给 make 变量的是求值结果,而不是 shell 命令。
需要 GNU make 的解决方案。它适用于 BSD 上的 GNU make,但不适用于 BSD make。
一种可能是使用 if
GNU make function:
platform := $(if $(patsubst Linux,,$(shell uname -s)),BSD or other,Linux)
另一种是仅依赖 shell 条件:
platform := $(shell [ $$(uname) = Linux ] && echo Linux || echo BSD or other)
ifeq ($(shell uname -s),Linux)
platform := Linux
else
platform := BSD or other
endif
使用此解决方案前请注意
对Renaud Pacalet的赞美:你分配给make变量的是shell命令,而不是shell执行它们的结果。这将严重限制您对它们的使用(主要是食谱)。您将无法将它们用作目标、先决条件、其他变量定义、make conditionals 的条件。
扩展 MadScientist 的评论
我引用:
Note
!=
was added to GNU make in version 4.0. It won't work in older versions.
并且还简化了一堆不必要的 if
s,我们可以在 可能是所有 版本的 GNU 和 BSD make
上得到一个工作版本,比如下面的方法。
通过 shell
的替代方法platform_id = $$( uname -s )
platform = $$( \
case $(platform_id) in \
( Linux | FreeBSD | OpenBSD | NetBSD ) echo $(platform_id) ;; \
( * ) echo Unrecognized ;; \
esac )
重要提示:
您需要在此处使用标准
=
惰性赋值。使用立即赋值运算符:=
,它在 BSD make 中不起作用。您需要在
case
语句中使用( ... )
。否则,它将无法在 OpenBSD 上运行
成功测试:
我仍在努力让 NetBSD 8.0 在 VirtualBox 中工作,所以我还不能确认这一点。
需要对这些系统的旧版本进行进一步测试,因此如果您有其中一个明显较旧的系统,请进行测试,谢谢。