MALOUDA-PSA 2025-05-17 11:51 采纳率: 85.6%
浏览 7
已结题

vs2019编译LUA动态链接库的问题

LUA5.4代码:

#if defined(LUA_BUILD_AS_DLL)    /* { */

#if defined(LUA_CORE) || defined(LUA_LIB)    /* { */
#define LUA_API __declspec(dllexport)
#else                        /* }{ */
#define LUA_API __declspec(dllimport)
#endif                        /* } */

#else                /* }{ */

#define LUA_API        extern

#endif                /* } */

当定义LUA_BUILD_AS_DLL宏, 编译dll 后可以看到 lib 文件,可是没看到DEF 文件, 具体导出的函数有哪些不知道,是不是所有 .h 头文件的函数都被导出?

  • 写回答

4条回答 默认 最新

  • 檀越@新空间 2025-05-17 11:52
    关注

    上午好☀️☀️☀️️
    本答案参考通义千问

    在使用 Visual Studio 2019 编译 Lua 动态链接库(DLL)时,如果你定义了 LUA_BUILD_AS_DLL 宏,并且希望明确知道哪些函数被导出,而不是默认导出所有的符号,你需要仔细检查和配置你的项目设置。以下是对问题的分析以及解决方案:


    问题分析

    1. 默认导出行为

      • 在你的代码中,LUA_API 的定义使用了 __declspec(dllexport)__declspec(dllimport)。当定义了 LUA_BUILD_AS_DLL 宏时,所有标记为 LUA_API 的函数都会被自动导出。
      • 如果没有显式地指定哪些函数需要导出,那么默认情况下,所有的 LUA_API 函数都会被导出。
    2. DEF 文件缺失

      • DEF 文件(Definition File)是一种用于显式控制 DLL 导出符号的文件。如果未手动创建 DEF 文件,编译器会基于 LUA_API 宏自动推断需要导出的符号。
      • 默认情况下,如果没有显式配置,所有标记为 LUA_API 的函数都会被包含在导出表中。
    3. 是否需要所有函数导出

      • 如果你只希望导出特定的函数(例如 Lua 核心 API),而隐藏其他内部实现细节,则需要通过 DEF 文件或显式配置来限制导出范围。

    解决方案

    1. 使用 DEF 文件明确导出符号

    DEF 文件可以显式列出需要导出的函数和变量。以下是步骤:

    1. 创建一个 DEF 文件(例如 lua.def),内容如下:

      EXPORTS
          luaopen_core
          luaL_newstate
          luaL_loadstring
          lua_pcall
          lua_pushnumber
          lua_gettop
          lua_close
          ...
      
      • 替换上述示例中的函数名为你实际需要导出的函数。
      • 可以通过查看 Lua 源码中的头文件(如 lualib.hlauxlib.h)来确认需要导出的函数。
    2. 在项目属性中启用 DEF 文件:

      • 打开 Visual Studio 的项目属性窗口。
      • 导航到 Configuration Properties -> Linker -> Input
      • Module Definition File 中填写你的 DEF 文件路径,例如:
        $(ProjectDir)\lua.def
        
    3. 编译项目,此时只有 DEF 文件中列出的符号会被导出。


    2. 修改 Lua 源码,限制导出范围

    如果你不想使用 DEF 文件,可以通过修改 Lua 源码来限制导出的函数范围。具体方法如下:

    1. 移除全局导出符号

      • LUA_API 定义改为仅导出特定的符号。例如:
        #if defined(LUA_BUILD_AS_DLL) && defined(LUA_CORE)
        #define LUA_API __declspec(dllexport)
        #else
        #define LUA_API extern
        #endif
        
      • 这样只有标记为 LUA_API 的函数才会被导出。
    2. 手动标记需要导出的函数

      • 在源码中,将需要导出的函数显式标记为 LUA_API,而其他函数保持为 extern 或不标记。

    3. 使用工具检查导出符号

    如果你已经编译了 DLL,但不确定导出了哪些符号,可以使用工具来检查导出表:

    1. 使用 dumpbin 工具:

      • 打开命令行,运行以下命令:
        dumpbin /EXPORTS your_lua_dll.dll
        
      • 查看输出结果,确认导出的符号。
    2. 使用第三方工具(如 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 文件,可以通过修改代码或宏定义来限制导出范围。
    • 使用工具检查导出符号,确保符合预期。

    希望以上解决方案能帮助你解决问题!如果有进一步疑问,请随时补充说明。

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(3条)

报告相同问题?

问题事件

  • 系统已结题 5月25日
  • 已采纳回答 5月17日
  • 创建了问题 5月17日