如何在C++中获得预加载的模块名称

How to get preloaded module name in C++

本文关键字:加载 模块 C++      更新时间:2023-10-16

我想知道是否可以创建一个C++函数来返回(或打印(当前脚本的预加载模块名称。

例如,我想在下面的代码中创建getModuleName()函数,这样运行代码就可以打印A

#include "lua.hpp"
void main()
{
lua_State *L = luaL_newstate();
luaL_openlibs(L);
lua_settop(L, 0);
luaL_dostring(L, "package.preload['A'] = function ()n"
"local a = {}n"
"a.name = my.getModuleName()n"
"print(a.name)n"
"return a end");
luaL_dostring(L, "require 'A'n");
lua_close(L);
}

如何在C++中创建getModuleName()函数?

如果用C++做不到,我想知道用Lua做是否可能。

p.S:我正在使用SWIG绑定C++代码。。

require使用作为第一个参数的名称调用预加载函数。

#include "lua.hpp"
int main() {
lua_State *L = luaL_newstate();
luaL_openlibs(L);
lua_settop(L, 0);
luaL_dostring(L, "package.preload['A'] = function(this)n"
"local a = {}n"
"a.name = thisn"
"print(a.name)n"
"return a end");
luaL_dostring(L, "require 'A'n");
lua_close(L);
}
$ clang++ -Wall -Wextra -Wpedantic -I /usr/include/lua5.2 test.cpp -llua5.2
$ ./a.out 
A

避免传递和争论

我不明白你为什么要这样做,但通过用你自己的版本覆盖require函数,这很容易实现。为了简单起见,我只显示Lua代码:

local require_original = require
function require(name, ...)
current_module = name
local val = table.pack(require_original(name, ...))
current_module = nil
return table.unpack(val,1,val.n)
end
package.preload["test"] = function()
print("While loading:", current_module)
return {}
end
print("Before loading:", current_module)
require("test")
print("After loading:", current_module)
$ lua5.2 test.lua
Before loading: nil
While loading:  test
After loading:  nil

误解问题的答案

package.preload只是一个常规的Lua表,您可以像C-API中的任何其他Lua表一样遍历它。在这种情况下,您将不得不遍历它两次,一次是在添加新的预加载之前确定哪些预加载已经存在,然后在添加预加载之后再次遍历。

#include <iostream>
#include <string>
#include <unordered_set>
#include "lua.hpp"
int main() {
lua_State *L = luaL_newstate();
luaL_openlibs(L);
lua_settop(L, 0);
// Determine all existing preloads
std::unordered_set<std::string> known_preloads;
lua_getglobal(L, "package");
lua_getfield(L, -1, "preload");
lua_pushnil(L);
while (lua_next(L, -2) != 0) {
known_preloads.emplace(lua_tostring(L, -2)); // pops key
lua_pop(L, 1); // pops value
}
lua_pop(L, 2); // pop preload and package
// Add a new preload
luaL_dostring(L, "package.preload['A'] = function ()n"
"local a = {}n"
"a.name = my.getModuleName()n"
"print(a.name)n"
"return a end");
luaL_dostring(L, "require 'A'n");
// Determine which preloads are new
std::unordered_set<std::string> new_preloads;
lua_getglobal(L, "package");
lua_getfield(L, -1, "preload");
lua_pushnil(L);
while (lua_next(L, -2) != 0) {
std::string current = lua_tostring(L, -2); // pops key
if (known_preloads.find(current) == known_preloads.end()) {
new_preloads.emplace(current);
}
lua_pop(L, 1); // pops value
}
lua_pop(L, 2); // pop preload and package
// Print the new preloads
for (auto const & preload : new_preloads) {
std::cout << preload << 'n';
}
lua_close(L);
}

您可能需要考虑使用Sol2。它是目前存在的围绕C++的Lua-C-API最快的包装器。它需要C++14,这完全值得。看看我一次都不担心堆栈!

#include <iostream>
#include <string>
#include <unordered_set>
#define SOL_CHECK_ARGUMENTS 1
#include "sol.hpp"
int main() {
sol::state L;
L.open_libraries();
// Determine all existing preloads
std::unordered_set<std::string> known_preloads;
L.get<sol::table>("package").get<sol::table>("preload").for_each(
[&](sol::object &key, sol::object &) {
known_preloads.emplace(key.as<std::string>());
});
// Add a new preload
L.script("package.preload['A'] = function ()n"
"local a = {}n"
"a.name = my.getModuleName()n"
"print(a.name)n"
"return a end");
L.script("require 'A'n");
// Determine which preloads are new
std::unordered_set<std::string> new_preloads;
L.get<sol::table>("package").get<sol::table>("preload").for_each(
[&](sol::object &key_, sol::object &) {
std::string key = key_.as<std::string>();
if (known_preloads.find(key) == known_preloads.end()) {
new_preloads.emplace(key);
}
});
// Print the new preloads
for (auto const & preload : new_preloads) {
std::cout << preload << 'n';
}
}