简体   繁体   English

Lua 5.4 替换 luaL_openlib 给出零值错误

[英]Lua 5.4 replacement for luaL_openlib gives nil value error

I am currently working on trying to update the version of Lua used in Dungeon Crawl: Stone Soup, and I am running into issue since the luaL_openlib function is used heavily and has since been depricated.我目前正在尝试更新 Dungeon Crawl: Stone Soup 中使用的 Lua 的版本,并且由于 luaL_openlib function 被大量使用并因此被贬低,因此我遇到了问题。 Currently, I have it replaced with the following code (using different paramaters depending on the place):目前,我将其替换为以下代码(根据位置使用不同的参数):

//luaL_openlib(ls, nullptr, lr, 0); //OLD CALL

//New call
lua_getglobal(ls, "NULL");
if (lua_isnil(ls, -1)) {
   lua_pop(ls, 1);
   lua_newtable(ls);
}
luaL_setfuncs(ls, lr, 0);
lua_setglobal(ls, "NULL");

The code all compiles but when I try to run the game, I get the following error:代码全部编译,但是当我尝试运行游戏时,出现以下错误:

./crawl
/mnt/d/Google Drive/Jon/UK/Spring 2021/CS 498/Crawl/crawl/crawl-ref/source/dat/des/00init.des:18: ...CS 498/Crawl/crawl/crawl-ref/source/dat/dlua/dungeon.lua:255: global 'setfenv' is not callable (a nil value)

Can anyone give any advice on why this may be happening, or can anyone give a suggestion on a better way to replace all of the calls to luaL_openlib?任何人都可以就为什么会发生这种情况提供任何建议,或者任何人都可以就替换所有对 luaL_openlib 的调用的更好方法提供建议吗? The code I am working on can be found here , and in the commits it shows all the recent changes I made to update the references to luaL_openlib.我正在处理的代码可以在这里找到,并且在提交中它显示了我为更新对 luaL_openlib 的引用所做的所有最新更改。

Edit: As mentioned in a comment, here is the code in dungeon.lua that actually throws the error:编辑:正如评论中提到的,这里是地牢中的代码。lua 实际上引发了错误:

-- Given a list of map chunk functions, runs each one in order in that
-- map's environment (wrapped with setfenv) and returns the return
-- value of the last chunk. If the caller is interested in the return
-- values of all the chunks, this function may be called multiple
-- times, once for each chunk.
function dgn_run_map(...)
  local map_chunk_functions = { ... }
  if #map_chunk_functions > 0 then
    local ret
    if not g_dgn_curr_map then
      error("No current map?")
    end
    local env = dgn_map_meta_wrap(g_dgn_curr_map, dgn)
    for _, map_chunk_function in ipairs(map_chunk_functions) do
      if map_chunk_function then
        ret = setfenv(map_chunk_function, env)()
      end
    end
    return ret
  end
end

As mentioned in the comments, setfenv is not available in Lua 5.2 and up.如评论中所述, setfenv在 Lua 5.2 及更高版本中不可用。 Function environments work differently now. Function 环境现在的工作方式有所不同。 In Lua 5.1 they are mutable, which can cause issues when you somehow have concurrent function calls (recursive calls or using coroutines) with different environments.在 Lua 5.1 中,它们是可变的,当您以某种方式在不同环境中同时进行 function 调用(递归调用或使用协程)时,这可能会导致问题。 In Lua 5.2 and up environments are immutable, and a function keeps the environment it was defined with.在 Lua 5.2 及更高版本中,环境是不可变的,而 function 保持其定义的环境。 However, a piece of code (eg a function) can voluntarily and temporarily switch to a different environment during execution by using a local variable _ENV .但是,一段代码(例如一个函数)可以在执行期间通过使用局部变量_ENV自愿和临时切换到不同的环境。

So I suggest the following changes to your code to make it work on Lua 5.2+ as well.因此,我建议对您的代码进行以下更改,以使其也适用于 Lua 5.2+。

When you loop over your map chunk functions, you should conditionally call setfenv (only when it's available, ie Lua 5.1) and pass the environment as an extra argument to the function calls.当您循环遍历 map 块函数时,您应该有条件地调用setfenv (仅当它可用时,即 Lua 5.1)并将环境作为额外参数传递给 ZC1C425268E68385D1AB507F74Z 调用。

Instead of代替

if map_chunk_function then
  ret = setfenv(map_chunk_function, env)()
end

use利用

if map_chunk_function then
  if setfenv then setfenv(map_chunk_function, env) end
  ret = map_chunk_function(env)
end

(Btw., you will lose all return values except the one for the last call -- not sure that is intended.) (顺便说一句,除了最后一次调用的返回值之外,您将丢失所有返回值——不确定这是有意的。)

Now each individual map chunk function can decide whether and when to use the argument as environment.现在每个单独的 map 块 function 可以决定是否以及何时使用参数作为环境。 If the whole function should use the passed environment, define it like this:如果整个 function 应该使用传递的环境,定义如下:

local function a_map_chunk_function(_ENV)
  -- code uses value passed in _ENV as environment and ignores original
  -- environment
end

If only part of the map chunk function should use the passed environment, use the following pattern:如果 map 块 function 只有一部分应该使用传递的环境,请使用以下模式:

local function another_map_chunk_function(env)
  -- code using original function environment it was defined with
  do
    local _ENV = env
    -- code uses env as environment
  end
  -- code uses original function environment again
end

Of course, a map chunk function can also ignore the passed environment altogether and just use the original environment it got when it was defined:当然,一个 map 块 function 也可以完全忽略传递的环境,只使用它定义时得到的原始环境:

local function yet_another_map_chunk_function()
  -- code ignores passed value completely and uses environment is was
  -- defined with
end

Obviously, the last two options are not compatible with the Lua 5.1 way of doing things.显然,最后两个选项与 Lua 5.1 处事方式不兼容。 If you still want to modify the original functions environments instead of passing them in, you will have to use the debug module for that.如果您仍想修改原始函数环境而不是传递它们,则必须为此使用debug模块。 You can probably find some reimplementations of setfenv for Lua 5.2+ using your preferred search engine.您可能可以使用您喜欢的搜索引擎找到 Lua 5.2+ 的setfenv的一些重新实现。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM