Question

I am trying to understand how libraries and linking in gcc work. I'm trying to compile an example ncurses "Hello World" program from a file test.c:

#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;
}

I first compiled it (without a makefile) using this command:

gcc test.c -o test.exe -lncurses

This produced a 9kb file. After not understanding what the -lncurses switch did, I read a bit about linking, then about static and dynamic, and decided I wanted to try compiling statically à la here:

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

However, for some reason, that didn't work, and produced tons of ld 'undefined reference to x' errors. Example:

/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'

From somewhere else, I added in an -L/usr/lib option:

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

This created a larger file, 1103kb.
I can understand why that should be bigger. What I don't understand is why removing just the -static option:

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

... produces a file 184kb in size, even though it isn't statically linked to the ncurses library.

What is the -L/usr/lib option doing here? According to the online docs, it adds the directory "to the list of directories to be searched for -l". The /usr/lib directory has a libncurses.a file (amongst others) while the /usr/include contains a an ncurses.h symlinked to curses.h and an ncurses_dll.h. Is perhaps the libncurses.a file not a dynamic library? What is ncurses.h then?

Was it helpful?

Solution

This is most likely the way you want to build it:

gcc test.c -o test -lncurses

This says: "compile test.c, name the output file test and dynamically link the library (or shared object) called libncurses.so (the lib prefix is automatically added).

Note that the .exe suffix is not used on Linux, just Windows (your question is tagged with linux so I assume that is the platform you are using here).

If you statically link like this:

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

then the linker will look for a static version of the library (ie. libncurses.a). You get a whole bunch of linker errors, as it cannot resolve the references to the library functions, which suggests you don't have a static version of the library. Unless you have a really good reason to link statically, the norm is to use dynamic linking.

The next command just specifies some additional (but redundant) library paths:

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

This is simply telling the linker to search in /usr/lib when looking for libraries. However, /usr/lib is already in the default path, so this shouldn't ordinarily make a difference. If you run gcc -dumpspecs it will print all the paths and definitions that have been 'baked in' to the tool, and thus what the default search paths are for include files, libraries and so on.

The /usr/lib directory has a libncurses.a file (amongst others) while the /usr/include contains a an ncurses.h symlinked to curses.h and an ncurses_dll.h. Is perhaps the libncurses.a file not a dynamic library? What is ncurses.h then?

The symlinks are present for backwards compatibility. The ncurses library (for "new curses") supersedes the original curses, but provides curses.h so old code can still build and run. The ncurses_dll.h header provides some definitions only used for compiling on cygwin or MSVC under Windows, so you can ignore it. The ncurses.h is the real primary header for the library, and should be used for new code.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top