检查 Erlang OTP Release 以在 Elixir 上执行不同的功能
Checking Erlang OTP Release to execute different functions on Elixir
我正在创建一个新的 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 发布版本执行代码的正确方法吗?
- 有没有更明显的方法来解决这个问题?
谢谢。
宏是编译时的产物。编译后没有宏的踪迹;相反,它注入的 AST 发生在发布中。
也就是说,如果您希望它是一个编译时,这意味着您将需要许多环境来编译,并且每个版本都只能在编译时在同一平台上运行,这是正确的方法。
如果你想 assemble 一次发布并使其在不同的目标平台上工作,你最好使用 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 代码中发生。
Is this a correct way of execute code based in the OTP release version?
您不应检查 OTP 版本,而应检查应用程序(在本例中为 crypto
)版本。由于 OTP 版本可能与应用程序版本不同。
Any better obvious way to address this problem?
是的,检查给定函数是否导出,而不是检查 OTP/application.
的版本
在运行时有两种方法:
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
我正在创建一个新的 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 发布版本执行代码的正确方法吗?
- 有没有更明显的方法来解决这个问题?
谢谢。
宏是编译时的产物。编译后没有宏的踪迹;相反,它注入的 AST 发生在发布中。
也就是说,如果您希望它是一个编译时,这意味着您将需要许多环境来编译,并且每个版本都只能在编译时在同一平台上运行,这是正确的方法。
如果你想 assemble 一次发布并使其在不同的目标平台上工作,你最好使用 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 代码中发生。
Is this a correct way of execute code based in the OTP release version?
您不应检查 OTP 版本,而应检查应用程序(在本例中为 crypto
)版本。由于 OTP 版本可能与应用程序版本不同。
Any better obvious way to address this problem?
是的,检查给定函数是否导出,而不是检查 OTP/application.
的版本在运行时有两种方法:
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