如何在C ++中获取预加载的模块名称 [英] How to get preloaded module name in C++
问题描述
我想知道是否有可能创建一个C ++函数来返回(或打印)当前脚本的预加载模块名称.
I wonder if it's possible to create a C++ function that returns(or prints) the preloaded module name of the current script.
例如,我想在以下代码中创建getModuleName()
函数,以便运行代码可以将A
打印为结果.
For example, I would like to create getModuleName()
function in the following code so running the code can print A
as a result.
#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()
函数?
How can I create a getModuleName()
function in C++?
如果C ++无法实现,我想知道是否可以在Lua中实现.
If it's not possible with C++, I would like to know if it's possible to do it in Lua.
P.S:我正在使用SWIG来绑定C ++代码.
P.S: I'm using SWIG for binding C++ code..
推荐答案
require
调用名称为第一个参数的预加载函数.
require
calls the preload function with the name it was given as the first argument.
#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 = this\n"
"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代码:
Avoiding to pass and argument
I don't see why you would want to do this but it is easily doable by overriding the require
function with your own version. For simplicity I only show the Lua code:
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表一样遍历该表.在这种情况下,您将不得不遍历两次,一次以确定添加新的预紧力之前已经存在的预紧力,然后再一次添加预紧力.
Answer to the misunderstood question
package.preload
is just a regular Lua table which you can traverse just as any other Lua table from the C-API. In this case you will have to traverse it twice, once to determine which preloads are already there before adding a new one, and then again after you added your preload.
#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,这是完全值得的.看看我如何一次都不必担心堆栈!
You might want to consider using Sol2. It's the fastest wrapper around the Lua C-API for C++ that exists. It requires C++14 and it's totally worth it. See how I didn't worry about the stack a single time!
#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';
}
}
这篇关于如何在C ++中获取预加载的模块名称的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!