检查 Erlang OTP Release 以在 Elixir 上执行不同的功能
Posted
技术标签:
【中文标题】检查 Erlang OTP Release 以在 Elixir 上执行不同的功能【英文标题】:Checking Erlang OTP Release to execute different functions on Elixir 【发布时间】:2021-12-31 14:35:40 【问题描述】:我正在创建一个新的 Elixir 库,需要使用不同版本的语言来执行。
这个库使用 Erlang :crypto.hmac
函数,但是这个函数在 Erlang OTP 的第 22 版上被 :crypto.mac
取代(具有相同的功能)。
我正在使用以下私有宏来执行较新或较旧的功能:
defmacrop hmac(key, data) do
if System.otp_release() >= "22" do
quote do: :crypto.mac(:hmac, :sha256, unquote(key), unquote(data))
else
quote do: :crypto.hmac(:sha256, unquote(key), unquote(data))
end
end
并以下列方式使用它:
hmac(key, data)
两个问题:
-
这是基于 OTP 发行版执行代码的正确方式吗?
有什么更好的方法来解决这个问题?
谢谢。
【问题讨论】:
【参考方案1】:宏是编译时的生物。编译后没有宏的踪迹;相反,它注入的 AST 发生在版本中。
也就是说,如果您希望它是编译时的,这意味着您将需要许多环境来编译,并且每个版本都可以在与仅编译时相同的平台上工作,这是正确的方法。
如果你想组装一个版本并让它在不同的目标平台上运行,你最好使用Kernel.apply/3
as
def hmac(key, data) do
if String.to_integer(System.otp_release) >= 22,
do: apply(:crypto, :mac, [:hmac, :sha256, key, data]),
else: apply(:crypto, :hmac, [:sha256, key, data])
end
旁注:即使你希望它是编译时的,声明不同的函数会比声明宏更简洁。
if String.to_integer(System.otp_release) >= 22 do
def hmac(key, data),
do: :crypto.mac(:hmac, :sha256, key, data)
else
def hmac(key, data),
do: :crypto.hmac(:sha256, key, data)
end
这将在编译时进行评估,相应的函数将在生成的 BEAM 代码中执行。
【讨论】:
也许使用String.to_integer(System.otp_release) >= 22
会更好
@Aetherus 确实,谢谢,我会更新答案。
正如@Hauleth 所评论的,没有必要检查 OTP 版本。使用function_exported?
检查:crypto
模块上的可用功能是一个更好的解决方案。【参考方案2】:
这是基于 OTP 发行版执行代码的正确方式吗?
您不应检查 OTP 版本,而应检查应用程序(在本例中为 crypto
)版本。因为 OTP 版本可能与应用程序版本不同。
有什么更好的方法来解决这个问题?
是的,检查给定函数是否被导出,而不是检查 OTP/应用程序的版本。
在运行时有两种方法:
def hmac(key, data) do
if Code.ensure_loaded?(:crypto) and function_exported?(:crypto, :mac, 4) do
:crypto.mac(:mac, :sha256, key, data)
else
:crypto.hmac(:sha256, key, data)
end
end
或者在编译期间:
if Code.ensure_loaded?(:crypto) and function_exported?(:crypto, :mac, 4) do
def hmac(key, data), do: :crypto.mac(:mac, :sha256, key, data)
else
def hmac(key, data), do: :crypto.hmac(:sha256, key, data)
end
【讨论】:
精彩的答案。我不知道function_exported?
功能。顺便说一句,为了正常工作,条件应该是:Code.ensure_loaded(:crypto) && function_exported?(:crypto, :mac, 4) do
如果:crypto
尚未加载,则对function_exported?
的调用将返回false。请问您能否对这两个版本进行更改,以便我可以将您的解决方案作为正确的解决方案?谢谢!以上是关于检查 Erlang OTP Release 以在 Elixir 上执行不同的功能的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 com.ericsson.otp.erlang 确定 erlang 术语是不是为空