Lua中文语言编程源码-第八节,更改loadlib.c 动态库加载器函数, 使Lua加载中文库关键词(加载库,搜索路径,引入)

文章讲述了对CLua库的源码进行更新,增加了中文版的函数名(如loadlib,searchpath),同时保持英文版本以支持双语调用。此外,还提到在Windows系统编译时需注意文件编码格式以避免中文乱码问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

源码已经更新在优快云的码库里:

git clone https://gitcode.com/funsion/CLua.git

在src文件夹下的loadlib.c  动态库加载器函数,此模块包含适用于具有dlfcn的Unix系统的loadlib实现,适用于Windows系统的实现,以及适用于其他系统的占位符实现。

增加中文版luaL_Reg pk_funcs 包的使用列表,保留英文版luaL_Reg pk_funcs 包的使用列表。

原始的代码为:
static const luaL_Reg pk_funcs[] = {
  {"loadlib", ll_loadlib},
  {"searchpath", ll_searchpath},
  /* placeholders */
  {"preload", NULL},
  {"cpath", NULL},
  {"path", NULL},
  {"searchers", NULL},
  {"loaded", NULL},
  {NULL, NULL}
};


static const luaL_Reg ll_funcs[] = {
  {"require", ll_require},
  {NULL, NULL}
};
 更改成以下代码: 
static const luaL_Reg pk_funcs[] = {
  {"loadlib", ll_loadlib}, {"加载库", ll_loadlib},        // 中文别名
  {"searchpath", ll_searchpath}, {"搜索路径", ll_searchpath},   // 中文别名
   {"preload", NULL}, {"预加载", NULL},             // 中文别名
  {"cpath", NULL}, {"C路径", NULL},              // 中文别名
  {"path", NULL}, {"路径", NULL},               // 中文别名
  {"searchers", NULL}, {"搜索器", NULL},             // 中文别名
  {"loaded", NULL}, {"已加载", NULL},             // 中文别名
  {NULL, NULL}
};
 更改搜索器的逻辑,以便支持中英文。
static void createsearcherstable (lua_State *L) {
  static const lua_CFunction searchers[] = {
    searcher_preload,
    searcher_Lua,
    searcher_C,
    searcher_Croot,
    NULL
  };
  int i;
  /* create 'searchers' table */
  lua_createtable(L, sizeof(searchers)/sizeof(searchers[0]) - 1, 0);
  /* fill it with predefined searchers */
  for (i=0; searchers[i] != NULL; i++) {
    lua_pushvalue(L, -2);  /* set 'package' as upvalue for all searchers */
    lua_pushcclosure(L, searchers[i], 1);
    lua_rawseti(L, -2, i+1);
  }
  lua_setfield(L, -2, "searchers");  /* put it in field 'searchers' */
}
static void createsearcherstable (lua_State *L) {
  static const lua_CFunction searchers[] = {
    searcher_preload,
    searcher_Lua,
    searcher_C,
    searcher_Croot,
    NULL
  };
  int i;

  /* 创建搜索器表 */
  lua_createtable(L, sizeof(searchers)/sizeof(searchers[0]) - 1, 0);  // 表在栈顶(位置 -1)
  
  /* 填充搜索器 */
  for (i = 0; searchers[i] != NULL; i++) {
    lua_pushvalue(L, -2);  // 上值:package 表(位置 -2)
    lua_pushcclosure(L, searchers[i], 1);
    lua_rawseti(L, -2, i + 1);  // 设置到搜索器表(位置 -2)
  }

  /* 关键修复:复制表的引用并绑定字段 */
  lua_pushvalue(L, -1);          // 复制搜索器表到栈顶(位置 -1)
  lua_setfield(L, -3, "searchers");  // package.searchers = 搜索器表(父表在 -3)
  
  lua_pushvalue(L, -1);          // 再次复制搜索器表到栈顶(位置 -1)
  lua_setfield(L, -3, "搜索器");      // package.搜索器 = 搜索器表(父表在 -3)
  
  lua_pop(L, 1);  // 弹出原始搜索器表(位置 -1)
}

 增加路径的映射,以便支持中英文。

LUAMOD_API int luaopen_package (lua_State *L) {
  createclibstable(L);
  luaL_newlib(L, pk_funcs);  /* create 'package' table */
  createsearcherstable(L);
  /* set paths */
  setpath(L, "path", LUA_PATH_VAR, LUA_PATH_DEFAULT);
  setpath(L, "cpath", LUA_CPATH_VAR, LUA_CPATH_DEFAULT);
  /* store config information */
  lua_pushliteral(L, LUA_DIRSEP "\n" LUA_PATH_SEP "\n" LUA_PATH_MARK "\n"
                     LUA_EXEC_DIR "\n" LUA_IGMARK "\n");
  lua_setfield(L, -2, "config");
  /* set field 'loaded' */
  luaL_getsubtable(L, LUA_REGISTRYINDEX, LUA_LOADED_TABLE);
  lua_setfield(L, -2, "loaded");
  /* set field 'preload' */
  luaL_getsubtable(L, LUA_REGISTRYINDEX, LUA_PRELOAD_TABLE);
  lua_setfield(L, -2, "preload");
  lua_pushglobaltable(L);
  lua_pushvalue(L, -2);  /* set 'package' as upvalue for next lib */
  luaL_setfuncs(L, ll_funcs, 1);  /* open lib into global table */
  lua_pop(L, 1);  /* pop global table */
  return 1;  /* return 'package' table */
}
LUAMOD_API int luaopen_package (lua_State *L) {
  createclibstable(L);
  luaL_newlib(L, pk_funcs);  /* create 'package' table */
  createsearcherstable(L);
  /* set paths */
  setpath(L, "path", LUA_PATH_VAR, LUA_PATH_DEFAULT);
  setpath(L, "路径", LUA_PATH_VAR, LUA_PATH_DEFAULT);
  setpath(L, "cpath", LUA_CPATH_VAR, LUA_CPATH_DEFAULT);
  setpath(L, "c路径", LUA_CPATH_VAR, LUA_CPATH_DEFAULT);
  /* store config information */
  lua_pushliteral(L, LUA_DIRSEP "\n" LUA_PATH_SEP "\n" LUA_PATH_MARK "\n"
                     LUA_EXEC_DIR "\n" LUA_IGMARK "\n");
  lua_setfield(L, -2, "config");
  /* set field 'loaded' */
  luaL_getsubtable(L, LUA_REGISTRYINDEX, LUA_LOADED_TABLE);
  lua_setfield(L, -2, "loaded");
  luaL_getsubtable(L, LUA_REGISTRYINDEX, LUA_LOADED_TABLE);
  lua_setfield(L, -2, "已加载");
  /* set field 'preload' */
  luaL_getsubtable(L, LUA_REGISTRYINDEX, LUA_PRELOAD_TABLE);
  lua_setfield(L, -2, "preload");
  luaL_getsubtable(L, LUA_REGISTRYINDEX, LUA_PRELOAD_TABLE);
  lua_setfield(L, -2, "预加载");
  lua_pushglobaltable(L);
  lua_pushvalue(L, -2);  /* set 'package' as upvalue for next lib */
  luaL_setfuncs(L, ll_funcs, 1);  /* open lib into global table */
  lua_pop(L, 1);  /* pop global table */
  return 1;  /* return 'package' table */
}

为了保证中英文 函数都可以加载,以便你可以复制英文原码来进行更改。所以保留了英文版 函数名列表,这样就能使用两种文的函数。
  {"require", ll_require},    // 引入
  {"引入", ll_require},   // 和require相同,但是使用中文名称

其实它们都是加载同样的库名,算是加载了2次,以Lua内部算法,应该只会加载一次。

更改完之后,同样需要重新编译Lua的源码,实现以上列出的关键词的中文化。

注意,在Window系统下编译Lua, 最好将所有Lua的源码,重新保存成ANSI格式的文件,刚下载的默认的源码会是UTF-8格式的。

这个事情说三遍,

1,不然就会出现,Window下的UTF-8源码可编译,但Shell里的中文输出会乱码。
2,要不然就是Window的ANSI源码不可编译(假如你没做以上步骤),
3,如果是用ANSI格式的源码编译的Lua.exe,对应的,你在Window下写的Lua程序也是需要保存成ANSI格式的。这样就可以在Shell里输出正确的中文显示。

 测试代码:

-- 验证字段是否存在且为表
print("package.searchers 类型:", type(package.searchers))  --> table
print("package.搜索器 类型:", type(package.搜索器))        --> table

-- 验证两个字段指向同一个表
print("是否同一表:", package.searchers == package.搜索器)  --> true

-- 遍历中文搜索器列表
print("\n中文搜索器列表:")
for _, searcher in ipairs(package.搜索器) do
  print(searcher)
end

-- 验证 path 和 路径 是否同步
print("package.path 原始值:", package.path)
print("package.路径 原始值:", package.路径)

-- 修改英文路径,检查中文路径是否同步
package.path = package.path .. ";./mylua/?.lua"
print("\n修改后 package.path:", package.path)
print("修改后 package.路径:", package.路径)

-- 修改中文路径,检查英文路径是否同步
package.路径 = "/usr/local/lua/?.lua"
print("\n再次修改后 package.path:", package.path)
print("再次修改后 package.路径:", package.路径)

-- 验证 cpath 和 C路径 是否同步
print("\npackage.cpath 原始值:", package.cpath)
print("package.C路径 原始值:", package.C路径)

-- 修改英文C路径,检查中文C路径
package.cpath = package.cpath .. ";./myclib/?.so"
print("\n修改后 package.cpath:", package.cpath)
print("修改后 package.C路径:", package.C路径)

-- 修改中文C路径,检查英文C路径
package.C路径 = "/usr/local/lua/?.so"
print("\n再次修改后 package.cpath:", package.cpath)
print("再次修改后 package.C路径:", package.C路径)

-- 验证 loaded 和 已加载 是否指向同一个表
print("\npackage.loaded 类型:", type(package.loaded))
print("package.已加载 类型:", type(package.已加载))

-- 加载一个模块(例如 math)
require "math"
print("\npackage.loaded.math 是否存在:", package.loaded.math ~= nil)
print("package.已加载.math 是否存在:", package.已加载.math ~= nil)

-- 通过中文名删除模块
package.已加载.math = nil
print("\n删除后 package.loaded.math:", package.loaded.math)

-- 验证 preload 和 预加载 是否同步
local function mymodule() return "Hello" end

-- 通过英文名添加预加载模块
package.preload.mymodule = mymodule
print("\npackage.preload.mymodule 类型:", type(package.preload.mymodule))
print("package.预加载.mymodule 类型:", type(package.预加载.mymodule))

-- 通过中文名调用预加载模块
local ok, msg = pcall(require, "mymodule")
print("\n通过 require 'mymodule' 调用结果:", ok, msg)

-- 验证 loadlib 和 加载库 是否为同一函数
print("\npackage.loadlib 类型:", type(package.loadlib))
print("package.加载库 类型:", type(package.加载库))

-- 尝试加载一个不存在的库(预期失败)
local f, err = package.加载库("nonexistent.dll", "init")
print("\n加载不存在的库:", f, err)

-- 验证访问未定义的中文字段(预期返回 nil)
print("\n访问无效字段 package.不存在字段:", package.不存在字段)

-- 验证非字符串字段赋值(预期报错)
local ok, msg = pcall(function()
  package.路径 = 123  -- 错误:路径必须是字符串
end)
print("\n非法赋值测试:", ok, msg)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值