为什么重新加载动态库时 ncurses 会失败?
Why does ncurses fail when I reload a dynamic library?
我一直在关注“Interactive Programming in C”上的博客 post。它背后的总体理想是它在 ncurses
中显示 Conway 的生命游戏的实现,但游戏逻辑是作为动态库加载的。 main()
循环监视游戏的 .so
并在发现更新版本时以交互方式重新加载它。
我已经在 LinuxMint 17 中尝试过,但是 ncurses
在动态重新加载共享库时挂起。我已经进行了一些调试 fprintf
s 并跟踪了 GDB 中的程序执行,程序似乎正确地重新加载了库并像往常一样继续主循环。
看来问题出在ncurses
,但我不知道如何调试它。一旦重新加载动态库,game.c:draw()
中的 ncurses
函数 refresh()
开始返回 -1。谁能帮忙?代码可以在博客 post.
中链接的 github repo 中找到
更新
看起来 ncurses
库中的变量 stdscr
在调用 dlclose()
之后就消失了。这不会发生在我工作的 RedHat 机器上。
ncurses 是 libgame.so
的依赖项,而不是 main
可执行文件的依赖项。所以如果你卸载动态库并加载更改后的版本,你也会卸载 ncurses 然后再次加载它。但是您随后无法重新初始化它。这就是你的程序失败的原因。
正确的解决方法是在game_unload
中调用endwin()
来清理ncurses的状态,然后在game_reload
中重新初始化它:
static void game_reload(struct game_state *state)
{
initscr();
raw();
timeout(0);
noecho();
curs_set(0);
keypad(stdscr, TRUE);
}
static void game_unload(struct game_state *state)
{
endwin();
}
另一种解决方案是强制 linker 对主要可执行文件执行 link ncurses。这将防止动态 linker 在您卸载游戏库时卸载它。您可以通过在编译 main
可执行文件时在 $(LDLIBS)
变量之前添加 -Wl,--no-as-needed
标志来做到这一点:
main : main.c game.h
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< -Wl,--no-as-needed $(LDLIBS)
如果您更喜欢此解决方案,请考虑将 ncurses initialization/cleanup 也移动到 main.c
文件中。这没有技术原因,这只是一个干净的编码风格问题。
我一直在关注“Interactive Programming in C”上的博客 post。它背后的总体理想是它在 ncurses
中显示 Conway 的生命游戏的实现,但游戏逻辑是作为动态库加载的。 main()
循环监视游戏的 .so
并在发现更新版本时以交互方式重新加载它。
我已经在 LinuxMint 17 中尝试过,但是 ncurses
在动态重新加载共享库时挂起。我已经进行了一些调试 fprintf
s 并跟踪了 GDB 中的程序执行,程序似乎正确地重新加载了库并像往常一样继续主循环。
看来问题出在ncurses
,但我不知道如何调试它。一旦重新加载动态库,game.c:draw()
中的 ncurses
函数 refresh()
开始返回 -1。谁能帮忙?代码可以在博客 post.
更新
看起来 ncurses
库中的变量 stdscr
在调用 dlclose()
之后就消失了。这不会发生在我工作的 RedHat 机器上。
ncurses 是 libgame.so
的依赖项,而不是 main
可执行文件的依赖项。所以如果你卸载动态库并加载更改后的版本,你也会卸载 ncurses 然后再次加载它。但是您随后无法重新初始化它。这就是你的程序失败的原因。
正确的解决方法是在game_unload
中调用endwin()
来清理ncurses的状态,然后在game_reload
中重新初始化它:
static void game_reload(struct game_state *state)
{
initscr();
raw();
timeout(0);
noecho();
curs_set(0);
keypad(stdscr, TRUE);
}
static void game_unload(struct game_state *state)
{
endwin();
}
另一种解决方案是强制 linker 对主要可执行文件执行 link ncurses。这将防止动态 linker 在您卸载游戏库时卸载它。您可以通过在编译 main
可执行文件时在 $(LDLIBS)
变量之前添加 -Wl,--no-as-needed
标志来做到这一点:
main : main.c game.h
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< -Wl,--no-as-needed $(LDLIBS)
如果您更喜欢此解决方案,请考虑将 ncurses initialization/cleanup 也移动到 main.c
文件中。这没有技术原因,这只是一个干净的编码风格问题。