上午好☀️☀️☀️️
本答案参考通义千问
在使用 Visual Studio 2019 编译 Lua 动态链接库(DLL)时,如果你定义了 LUA_BUILD_AS_DLL 宏,并且希望明确知道哪些函数被导出,而不是默认导出所有的符号,你需要仔细检查和配置你的项目设置。以下是对问题的分析以及解决方案:
问题分析
-
默认导出行为:
- 在你的代码中,
LUA_API 的定义使用了 __declspec(dllexport) 和 __declspec(dllimport)。当定义了 LUA_BUILD_AS_DLL 宏时,所有标记为 LUA_API 的函数都会被自动导出。 - 如果没有显式地指定哪些函数需要导出,那么默认情况下,所有的
LUA_API 函数都会被导出。
-
DEF 文件缺失:
- DEF 文件(Definition File)是一种用于显式控制 DLL 导出符号的文件。如果未手动创建 DEF 文件,编译器会基于
LUA_API 宏自动推断需要导出的符号。 - 默认情况下,如果没有显式配置,所有标记为
LUA_API 的函数都会被包含在导出表中。
-
是否需要所有函数导出:
- 如果你只希望导出特定的函数(例如 Lua 核心 API),而隐藏其他内部实现细节,则需要通过 DEF 文件或显式配置来限制导出范围。
解决方案
1. 使用 DEF 文件明确导出符号
DEF 文件可以显式列出需要导出的函数和变量。以下是步骤:
-
创建一个 DEF 文件(例如 lua.def),内容如下:
EXPORTS
luaopen_core
luaL_newstate
luaL_loadstring
lua_pcall
lua_pushnumber
lua_gettop
lua_close
...
- 替换上述示例中的函数名为你实际需要导出的函数。
- 可以通过查看 Lua 源码中的头文件(如
lualib.h 和 lauxlib.h)来确认需要导出的函数。
-
在项目属性中启用 DEF 文件:
- 打开 Visual Studio 的项目属性窗口。
- 导航到
Configuration Properties -> Linker -> Input。 - 在
Module Definition File 中填写你的 DEF 文件路径,例如:
$(ProjectDir)\lua.def
-
编译项目,此时只有 DEF 文件中列出的符号会被导出。
2. 修改 Lua 源码,限制导出范围
如果你不想使用 DEF 文件,可以通过修改 Lua 源码来限制导出的函数范围。具体方法如下:
-
移除全局导出符号:
-
手动标记需要导出的函数:
- 在源码中,将需要导出的函数显式标记为
LUA_API,而其他函数保持为 extern 或不标记。
3. 使用工具检查导出符号
如果你已经编译了 DLL,但不确定导出了哪些符号,可以使用工具来检查导出表:
-
使用 dumpbin 工具:
-
使用第三方工具(如 Dependency Walker):
- 下载并安装 Dependency Walker。
- 打开你的 DLL 文件,查看导出的符号。
4. 示例代码调整
以下是修改后的代码示例,确保只导出核心 API:
#if defined(LUA_BUILD_AS_DLL) && defined(LUA_CORE)
#define LUA_API __declspec(dllexport)
#else
#define LUA_API extern
#endif
在头文件中,仅对核心 API 显式标记为 LUA_API,例如:
LUA_API int luaopen_core(lua_State *L);
LUA_API int luaL_dostring(lua_State *L, const char *str);
LUA_API void lua_close(lua_State *L);
其他非核心函数保持为 extern 或不标记。
总结
- 默认情况下,所有标记为
LUA_API 的函数都会被导出。 - 推荐使用 DEF 文件明确控制导出符号。
- 如果不需要 DEF 文件,可以通过修改代码或宏定义来限制导出范围。
- 使用工具检查导出符号,确保符合预期。
希望以上解决方案能帮助你解决问题!如果有进一步疑问,请随时补充说明。