链接到 Lua 5.2.4 的问题,即使在内联编译源代码时也是如此
Problems linking to Lua 5.2.4, even when compiling sources inline
我有一个文件configuration.cpp:
#include "configuration.hpp"
struct game_config* get_game_config(lua_State *L, char* script)
{
debug("Attempting to load configuration from %s", script);
// Execute the script
luaL_dofile(L, script);
// The environment should now be prepped, we can get the config variables
struct game_config* game_config;
lua_getglobal(L, "WINDOW_WIDTH");
game_config->screen_width = lua_tointeger(L, -1);
lua_getglobal(L, "WINDOW_HEIGHT");
game_config->screen_height = lua_tointeger(L, -1);
lua_getglobal(L, "GAME_TITLE");
game_config->game_title = lua_tostring(L, -1);
debug("Loaded config for %s, at %dx%d", game_config->game_title, game_config->screen_width, game_config->screen_height);
return game_config;
};
其中包括 configuration.hpp:
#ifndef CONFIGURATION_HPP_INCLUDED
#define CONFIGURATION_HPP_INCLUDED
#include "common.hpp"
#include "scripting.hpp"
// Data structures
struct game_config {
int screen_width;
int screen_height;
const char *game_title;
};
/*
* get_config
* run a script and retrieve configuration data from it
*/
struct game_config *get_game_config(lua_State*, char *);
#endif // CONFIGURATION_HPP_INCLUDED
其中包括 scripting.hpp
,其中以下行导入 Lua5.2:
#include "lua.h"
#include "lauxlib.h"
#include "lualib.h"
当我将这些行添加到 configuration.cpp 时,程序编译并运行。但是,当它们在任何其他文件中时(configuration.hpp、scripting.hpp),它不会:
||=== Build: debug in rpfreedom (compiler: GNU GCC Compiler) ===|
src/configuration.cpp||In function ‘game_config* get_game_config(lua_State*, char*)’:|
src/configuration.cpp|13|warning: ‘game_config’ is used uninitialized in this function [-Wuninitialized]|
src/main.cpp||In function ‘int main()’:|
src/main.cpp|13|warning: deprecated conversion from string constant to ‘char*’ [-Wwrite-strings]|
build/debug/configuration.o||In function `get_game_config(lua_State*, char*)':|
/home/leo/projects/rpfreedom/src/configuration.cpp|7|undefined reference to `luaL_loadfilex(lua_State*, char const*, char const*)'|
/home/leo/projects/rpfreedom/src/configuration.cpp|7|undefined reference to `lua_pcallk(lua_State*, int, int, int, int, int (*)(lua_State*))'|
/home/leo/projects/rpfreedom/src/configuration.cpp|12|undefined reference to `lua_getglobal(lua_State*, char const*)'|
/home/leo/projects/rpfreedom/src/configuration.cpp|13|undefined reference to `lua_tointegerx(lua_State*, int, int*)'|
/home/leo/projects/rpfreedom/src/configuration.cpp|14|undefined reference to `lua_getglobal(lua_State*, char const*)'|
/home/leo/projects/rpfreedom/src/configuration.cpp|15|undefined reference to `lua_tointegerx(lua_State*, int, int*)'|
/home/leo/projects/rpfreedom/src/configuration.cpp|16|undefined reference to `lua_getglobal(lua_State*, char const*)'|
/home/leo/projects/rpfreedom/src/configuration.cpp|17|undefined reference to `lua_tolstring(lua_State*, int, unsigned long*)'|
build/debug/scripting.o||In function `scripting_init()':|
/home/leo/projects/rpfreedom/src/scripting.cpp|7|undefined reference to `luaL_newstate()'|
/home/leo/projects/rpfreedom/src/scripting.cpp|20|undefined reference to `lua_settop(lua_State*, int)'|
build/debug/scripting.o||In function `scripting_report_errors(lua_State*, int)':|
/home/leo/projects/rpfreedom/src/scripting.cpp|30|undefined reference to `lua_tolstring(lua_State*, int, unsigned long*)'|
/home/leo/projects/rpfreedom/src/scripting.cpp|31|undefined reference to `lua_settop(lua_State*, int)'|
build/debug/scripting.o:(.rodata+0x88)||undefined reference to `luaopen_base(lua_State*)'|
Makefile|203|recipe for target 'bin/debug/rpfreedom' failed|
Makefile|160|recipe for target 'debug' failed|
||=== Build failed: 15 error(s), 2 warning(s) (0 minute(s), 1 second(s)) ===|
显然,包含 configuration.hpp 是有效的,因为没有关于 game_config 结构的错误,它在那里定义;递归包含也是如此,因为 debug() 宏遵循路径 debug.hpp -> common.hpp -> configuration.hpp -> configuration.cpp
。那么,为什么 Lua header 文件的 #includes 不能以类似的方式工作?
我决定调查;我运行g++ -Iinclude -I/usr/include/lua5.2 -E src/configuration.cpp| grep lua_getglobal
查看预处理器输出,结果发现……是的。连同它在源代码中的使用,该命令 returns:
extern void (lua_getglobal) (lua_State *L, const char *var);
所以,我不知道发生了什么。
编辑:原来我必须在我的 #include
周围为 Lua 做 extern C {}
。但是,现在,仅在 configuration.hpp 中(不在 scripting.hpp 中,其中包含 Lua header)我收到另一个错误:
include/configuration.hpp:21:37: error: ‘lua_State’ was not declared in this scope
struct game_config *get_game_config(lua_State*, char *);
但是,lua_State在scripting.cpp和scripting.hpp中的使用不受影响。
编辑 2:显然,推荐的嵌入 Lua 5.2 的方法是将其与您的项目一起编译,因为它非常小,所以我这样做了。然而,即使我的 Makefile 生成的 link 命令清楚地 links 我的所有 object 文件和 Lua object 文件:
g++ build/release/configuration.o build/release/lua5.2.4/lparser.c.o build/release/lua5.2.4/lcode.c.o build/release/lua5.2.4/lundump.c.o build/release/lua5.2.4/lzio.c.o build/release/lua5.2.4/ldo.c.o build/release/lua5.2.4/lapi.c.o build/release/lua5.2.4/lgc.c.o build/release/lua5.2.4/lfunc.c.o build/release/lua5.2.4/ldump.c.o build/release/lua5.2.4/ltable.c.o build/release/lua5.2.4/lcorolib.c.o build/release/lua5.2.4/loslib.c.o build/release/lua5.2.4/liolib.c.o build/release/lua5.2.4/ltm.c.o build/release/lua5.2.4/lmem.c.o build/release/lua5.2.4/lctype.c.o build/release/lua5.2.4/lauxlib.c.o build/release/lua5.2.4/ldebug.c.o build/release/lua5.2.4/lobject.c.o build/release/lua5.2.4/loadlib.c.o build/release/lua5.2.4/linit.c.o build/release/lua5.2.4/lmathlib.c.o build/release/lua5.2.4/llex.c.o build/release/lua5.2.4/lstate.c.o build/release/lua5.2.4/lopcodes.c.o build/release/lua5.2.4/lstrlib.c.o build/release/lua5.2.4/lbaselib.c.o build/release/lua5.2.4/ltablib.c.o build/release/lua5.2.4/ldblib.c.o build/release/lua5.2.4/lbitlib.c.o build/release/lua5.2.4/lvm.c.o build/release/lua5.2.4/lstring.c.o build/release/scripting.o build/release/main.o -L/usr/lib/x86_64-linux-gnu -Lm -Ldl -lsfml-graphics -lsfml-window -lsfml-audio -lsfml-network -lsfml-system -o bin/release/rpfreedom
我遇到了和之前一样的 linker 错误。
linker 的参数顺序重要吗?
您显示的错误消息似乎来自您的 linker,而不是编译器。
一切都已成功包含。一切都已成功编译。但是 link 失败了,因为某些必需的库没有 link 编辑。
注意错误信息参考:
build/debug/configuration.o
...
build/debug/scripting.o
...
... 而不是您的源代码(错误中提到的 cpp 具有误导性,它们实际上是从您的 .o 文件中的调试信息中提取的)。并且错误消息通常是来自 linker.
的错误消息
你的源代码没问题。您需要修复您的 makefile。
好吧,你的第一个警告正是编译器告诉你的。你的代码是这样的:
// The environment should now be prepped, we can get the config variables
struct game_config* game_config;
lua_getglobal(L, "WINDOW_WIDTH");
game_config->screen_width = lua_tointeger(L, -1);
警告是:
‘game_config’ is used uninitialized in this function.
在访问 screen_width
之前,您尚未将指针 game_config
设置为指向任何内容。也许您需要将其设置为 new game_config()
。我更愿意在堆栈上创建一个并按值return它:
game_config config;
lua_getglobal(L, "WINDOW_WIDTH");
config.screen_width = lua_tointeger(L, -1);
...
return config;
无论哪种方式,将 game_title 设为 std::string
可能比 const char *
更好。
我最终通过自己编译一个静态 Lua (liblua.a
)、创建一个 lib/ 目录并将 -Llib -llua
添加到我的链接器行来纠正这个问题。这将需要额外的努力来实现跨平台,但就目前而言,没问题。
我有一个文件configuration.cpp:
#include "configuration.hpp"
struct game_config* get_game_config(lua_State *L, char* script)
{
debug("Attempting to load configuration from %s", script);
// Execute the script
luaL_dofile(L, script);
// The environment should now be prepped, we can get the config variables
struct game_config* game_config;
lua_getglobal(L, "WINDOW_WIDTH");
game_config->screen_width = lua_tointeger(L, -1);
lua_getglobal(L, "WINDOW_HEIGHT");
game_config->screen_height = lua_tointeger(L, -1);
lua_getglobal(L, "GAME_TITLE");
game_config->game_title = lua_tostring(L, -1);
debug("Loaded config for %s, at %dx%d", game_config->game_title, game_config->screen_width, game_config->screen_height);
return game_config;
};
其中包括 configuration.hpp:
#ifndef CONFIGURATION_HPP_INCLUDED
#define CONFIGURATION_HPP_INCLUDED
#include "common.hpp"
#include "scripting.hpp"
// Data structures
struct game_config {
int screen_width;
int screen_height;
const char *game_title;
};
/*
* get_config
* run a script and retrieve configuration data from it
*/
struct game_config *get_game_config(lua_State*, char *);
#endif // CONFIGURATION_HPP_INCLUDED
其中包括 scripting.hpp
,其中以下行导入 Lua5.2:
#include "lua.h"
#include "lauxlib.h"
#include "lualib.h"
当我将这些行添加到 configuration.cpp 时,程序编译并运行。但是,当它们在任何其他文件中时(configuration.hpp、scripting.hpp),它不会:
||=== Build: debug in rpfreedom (compiler: GNU GCC Compiler) ===|
src/configuration.cpp||In function ‘game_config* get_game_config(lua_State*, char*)’:|
src/configuration.cpp|13|warning: ‘game_config’ is used uninitialized in this function [-Wuninitialized]|
src/main.cpp||In function ‘int main()’:|
src/main.cpp|13|warning: deprecated conversion from string constant to ‘char*’ [-Wwrite-strings]|
build/debug/configuration.o||In function `get_game_config(lua_State*, char*)':|
/home/leo/projects/rpfreedom/src/configuration.cpp|7|undefined reference to `luaL_loadfilex(lua_State*, char const*, char const*)'|
/home/leo/projects/rpfreedom/src/configuration.cpp|7|undefined reference to `lua_pcallk(lua_State*, int, int, int, int, int (*)(lua_State*))'|
/home/leo/projects/rpfreedom/src/configuration.cpp|12|undefined reference to `lua_getglobal(lua_State*, char const*)'|
/home/leo/projects/rpfreedom/src/configuration.cpp|13|undefined reference to `lua_tointegerx(lua_State*, int, int*)'|
/home/leo/projects/rpfreedom/src/configuration.cpp|14|undefined reference to `lua_getglobal(lua_State*, char const*)'|
/home/leo/projects/rpfreedom/src/configuration.cpp|15|undefined reference to `lua_tointegerx(lua_State*, int, int*)'|
/home/leo/projects/rpfreedom/src/configuration.cpp|16|undefined reference to `lua_getglobal(lua_State*, char const*)'|
/home/leo/projects/rpfreedom/src/configuration.cpp|17|undefined reference to `lua_tolstring(lua_State*, int, unsigned long*)'|
build/debug/scripting.o||In function `scripting_init()':|
/home/leo/projects/rpfreedom/src/scripting.cpp|7|undefined reference to `luaL_newstate()'|
/home/leo/projects/rpfreedom/src/scripting.cpp|20|undefined reference to `lua_settop(lua_State*, int)'|
build/debug/scripting.o||In function `scripting_report_errors(lua_State*, int)':|
/home/leo/projects/rpfreedom/src/scripting.cpp|30|undefined reference to `lua_tolstring(lua_State*, int, unsigned long*)'|
/home/leo/projects/rpfreedom/src/scripting.cpp|31|undefined reference to `lua_settop(lua_State*, int)'|
build/debug/scripting.o:(.rodata+0x88)||undefined reference to `luaopen_base(lua_State*)'|
Makefile|203|recipe for target 'bin/debug/rpfreedom' failed|
Makefile|160|recipe for target 'debug' failed|
||=== Build failed: 15 error(s), 2 warning(s) (0 minute(s), 1 second(s)) ===|
显然,包含 configuration.hpp 是有效的,因为没有关于 game_config 结构的错误,它在那里定义;递归包含也是如此,因为 debug() 宏遵循路径 debug.hpp -> common.hpp -> configuration.hpp -> configuration.cpp
。那么,为什么 Lua header 文件的 #includes 不能以类似的方式工作?
我决定调查;我运行g++ -Iinclude -I/usr/include/lua5.2 -E src/configuration.cpp| grep lua_getglobal
查看预处理器输出,结果发现……是的。连同它在源代码中的使用,该命令 returns:
extern void (lua_getglobal) (lua_State *L, const char *var);
所以,我不知道发生了什么。
编辑:原来我必须在我的 #include
周围为 Lua 做 extern C {}
。但是,现在,仅在 configuration.hpp 中(不在 scripting.hpp 中,其中包含 Lua header)我收到另一个错误:
include/configuration.hpp:21:37: error: ‘lua_State’ was not declared in this scope
struct game_config *get_game_config(lua_State*, char *);
但是,lua_State在scripting.cpp和scripting.hpp中的使用不受影响。
编辑 2:显然,推荐的嵌入 Lua 5.2 的方法是将其与您的项目一起编译,因为它非常小,所以我这样做了。然而,即使我的 Makefile 生成的 link 命令清楚地 links 我的所有 object 文件和 Lua object 文件:
g++ build/release/configuration.o build/release/lua5.2.4/lparser.c.o build/release/lua5.2.4/lcode.c.o build/release/lua5.2.4/lundump.c.o build/release/lua5.2.4/lzio.c.o build/release/lua5.2.4/ldo.c.o build/release/lua5.2.4/lapi.c.o build/release/lua5.2.4/lgc.c.o build/release/lua5.2.4/lfunc.c.o build/release/lua5.2.4/ldump.c.o build/release/lua5.2.4/ltable.c.o build/release/lua5.2.4/lcorolib.c.o build/release/lua5.2.4/loslib.c.o build/release/lua5.2.4/liolib.c.o build/release/lua5.2.4/ltm.c.o build/release/lua5.2.4/lmem.c.o build/release/lua5.2.4/lctype.c.o build/release/lua5.2.4/lauxlib.c.o build/release/lua5.2.4/ldebug.c.o build/release/lua5.2.4/lobject.c.o build/release/lua5.2.4/loadlib.c.o build/release/lua5.2.4/linit.c.o build/release/lua5.2.4/lmathlib.c.o build/release/lua5.2.4/llex.c.o build/release/lua5.2.4/lstate.c.o build/release/lua5.2.4/lopcodes.c.o build/release/lua5.2.4/lstrlib.c.o build/release/lua5.2.4/lbaselib.c.o build/release/lua5.2.4/ltablib.c.o build/release/lua5.2.4/ldblib.c.o build/release/lua5.2.4/lbitlib.c.o build/release/lua5.2.4/lvm.c.o build/release/lua5.2.4/lstring.c.o build/release/scripting.o build/release/main.o -L/usr/lib/x86_64-linux-gnu -Lm -Ldl -lsfml-graphics -lsfml-window -lsfml-audio -lsfml-network -lsfml-system -o bin/release/rpfreedom
我遇到了和之前一样的 linker 错误。
linker 的参数顺序重要吗?
您显示的错误消息似乎来自您的 linker,而不是编译器。
一切都已成功包含。一切都已成功编译。但是 link 失败了,因为某些必需的库没有 link 编辑。
注意错误信息参考:
build/debug/configuration.o
...
build/debug/scripting.o
...
... 而不是您的源代码(错误中提到的 cpp 具有误导性,它们实际上是从您的 .o 文件中的调试信息中提取的)。并且错误消息通常是来自 linker.
的错误消息你的源代码没问题。您需要修复您的 makefile。
好吧,你的第一个警告正是编译器告诉你的。你的代码是这样的:
// The environment should now be prepped, we can get the config variables
struct game_config* game_config;
lua_getglobal(L, "WINDOW_WIDTH");
game_config->screen_width = lua_tointeger(L, -1);
警告是:
‘game_config’ is used uninitialized in this function.
在访问 screen_width
之前,您尚未将指针 game_config
设置为指向任何内容。也许您需要将其设置为 new game_config()
。我更愿意在堆栈上创建一个并按值return它:
game_config config;
lua_getglobal(L, "WINDOW_WIDTH");
config.screen_width = lua_tointeger(L, -1);
...
return config;
无论哪种方式,将 game_title 设为 std::string
可能比 const char *
更好。
我最终通过自己编译一个静态 Lua (liblua.a
)、创建一个 lib/ 目录并将 -Llib -llua
添加到我的链接器行来纠正这个问题。这将需要额外的努力来实现跨平台,但就目前而言,没问题。