检查 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 术语是不是为空

初学者的 Erlang/OTP 行为

为啥在 Erlang 中使用 OTP?

Erlang/OTP 升级丢失现有的 RabbitMQ 消息

Erlang/OTP 发布和 LTS 时间表是啥?

erlang驱动使用mysql-otp