0

我试图了解 gcc 中的库和链接是如何工作的。我正在尝试从文件 test.c编译示例“Hello World”程序: ncurses

#include <ncurses.h>

int main()
{
    initscr();                      /* Start curses mode              */
    printw("Hello World !!!");      /* Print Hello World              */
    refresh();                      /* Print it on to the real screen */
    getch();                        /* Wait for user input */
    endwin();                       /* End curses mode                */

    return 0;
}

我首先使用以下命令编译它(没有生成文件):

gcc test.c -o test.exe -lncurses

这产生了一个 9kb 的文件。在不了解开关的作用之后,我阅读了一些关于链接的内容,然后是关于静态和动态的,并决定我想尝试在这里-lncurses静态编译:

gcc -static test.c -o test.exe -lncurses

但是,由于某种原因,这不起作用,并产生了大量的ld“未定义对 x 的引用”错误。例子:

/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../x86_64-linux-gnu/libncurses.a(lib_echo.o): In function `echo':
(.text+0x3): undefined reference to `SP'

从其他地方,我添加了一个-L/usr/lib选项:

gcc -static test.c -o test.exe -L/usr/lib -lncurses

这创建了一个更大的文件,1103kb。
我可以理解为什么应该更大。我不明白为什么只删除-static选项:

gcc test.c -o test.exe -L/usr/lib -lncurses

... 生成大小为 184kb 的文件,即使它没有静态链接到ncurses库。

-L/usr/lib 选项在这里做什么?根据在线文档,它将目录“添加到要搜索的目录列表中 -l ”。/usr/lib 目录有一个libncurses.a文件(以及其他文件),而 /usr/include 包含一个ncurses.h符号链接到curses.h和一个ncurses_dll.h. 也许该libncurses.a文件不是动态库?那是什么ncurses.h

4

1 回答 1

3

这很可能是您想要构建它的方式:

gcc test.c -o test -lncurses

这说:“编译test.c,命名输出文件test并动态链接调用的库(或共享对象)libncurses.solib自动添加前缀)。

请注意,.exe后缀不在 Linux 上使用,仅在 Windows 上使用(您的问题被标记,linux所以我假设这是您在此处使用的平台)。

如果你像这样静态链接:

gcc -static test.c -o test.exe -lncurses

然后链接器将寻找库的静态版本(即。libncurses.a)。您会收到一大堆链接器错误,因为它无法解析对库函数的引用,这表明您没有库的静态版本。除非您有充分的理由进行静态链接,否则规范是使用动态链接。

下一个命令只是指定了一些额外的(但冗余的)库路径:

gcc -static test.c -o test.exe -L/usr/lib -lncurses

这只是告诉链接器在/usr/lib查找库时进行搜索。但是,/usr/lib它已经在默认路径中,所以这通常不会产生影响。如果你运行gcc -dumpspecs它,它会打印所有已经被“烘焙”到工具中的路径和定义,以及包含文件、库等的默认搜索路径。

/usr/lib 目录有一个 libncurses.a 文件(以及其他文件),而 /usr/include 包含一个 ncurses.h 符号链接到 curses.h 和一个 ncurses_dll.h。也许 libncurses.a 文件不是动态库?那么 ncurses.h 是什么?

存在符号链接是为了向后兼容。该ncurses库(用于“新诅咒”)取代了原来的curses,但提供的curses.h旧代码仍然可以构建和运行。头ncurses_dll.h文件提供了一些仅用于在 Windows 下的 cygwin 或 MSVC 上编译的定义,因此您可以忽略它。这ncurses.h是库的真正主要头文件,应该用于新代码。

于 2013-10-28T21:47:11.583 回答