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

Mar*_*rty 5 c ncurses linux-mint

我一直关注这篇关于" C语言交互式编程 "的博客文章.它背后的一般理想是它显示了Conway的生命游戏的实现ncurses,但游戏逻辑被加载为动态库.该main()回路监控.so的游戏,如果它发现一个新的版本重新加载交互.

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

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

更新

看起来库中的变量stdscrncurses调用之后就消失了dlclose().在我的RedHat机器上工作时不会发生这种情况.

Phi*_*lip 3

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

正确的解决方案是调用endwin()清理game_unloadncurses 的状态,然后重新初始化它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();
}
Run Code Online (Sandbox Code Playgroud)

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

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

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

  • 除此之外,Red Hat 安装的 OP 可能已经足够老了,以至于“--no-as-needed”链接器标志是默认值,这与较新的工具链不同,其中“--as-needed”是默认值。 (2认同)