为什么在重新加载动态库时ncurses会失败?

时间:2015-01-10 20:54:03

标签: c ncurses linuxmint

我一直关注" Interactive Programming in C"上的这篇博客文章。它背后的一般理想是它在ncurses中显示了Conway的生命游戏的实现,但游戏逻辑被加载为动态库。 main()循环监视游戏的.so,如果找到更新版本,则以交互方式重新加载。

我已在LinuxMint 17中尝试过此操作,但ncurses在动态重新加载共享库时挂起。我已经输入了一些调试fprintf并跟随GDB中的程序执行,程序似乎正确地重新加载库并像往常一样继续主循环。

ncurses似乎是问题,但我不知道如何调试它。重新加载动态库后,ncurses中的refresh()函数game.c:draw()开始返回-1。有人可以帮忙吗?该代码可以在博文中链接的github repo中找到。

更新

看起来stdscr库中的变量ncurses在调用dlclose()后就消失了。这在我工作的RedHat机器上不会发生。

1 个答案:

答案 0 :(得分:3)

ncurses是libgame.so的依赖关系,而不是main可执行文件的依赖关系。因此,如果卸载动态库并加载更改后的版本,还可以卸载ncurses,然后再次加载它。但是你没有重新初始化它。这就是你的程序失败的原因。

正确的解决方案是调用endwin()中的game_unload来清理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();
}

另一种解决方案是强制链接器将ncurses链接到主可执行文件。这将阻止动态链接器在卸载游戏库时卸载它。您可以通过在编译-Wl,--no-as-needed可执行文件时在$(LDLIBS)变量之前添加main标志来实现此目的:

main : main.c game.h
    $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< -Wl,--no-as-needed $(LDLIBS)

如果您更喜欢此解决方案,请考虑将ncurses初始化/清除移至main.c文件。这没有技术上的原因,只是清晰的编码风格。