I’ve recently written a minesweeper implementation in C using ncurses on linux; everything works fine on my pc, but if I try to give the compiled binaries to someone else they often get the error:
error while loading shared libraries: libtinfo.so.5: cannot open shared object file: No such file or directory
If I have them recompile the code everything’s fine. By looking around I discovered it’s an issue with the separation between libtinfo and libncurses. It can be solved by making a few simlinks, but it’s a solution only viable when the user has root privileges.
As of here (and other sources), http://www.cyberspice.org.uk/blog/2009/12/24/tinfo-about-dash/ , it seems that it’s an issue that can be solved by writing the code in a different way or maybe compiling differently. I’d rather be able to solve the problem that way than forcing people to make simlinks.
Any pointers in the right direction to understand how to solve my issue? I can add any code or details, if needed, but it seems an overkill to post everything, so please tell me what can be added (if needed) to better understand the problem.
The only thing I’m posting for now is the makefile:
CC=gcc -std=gnu89 -pedantic -Wall -Wno-unused-but-set-variable CFLAGS=-c -g LDFLAGS=-lncurses NAME=campo_ex OBJECTS=error.o interface.o utilities.o main.o grid.o DEBUG_NAME=debug DEBUG_OBJECTS=error.o interface.o utilities.o debug.o $(NAME): $(OBJECTS) $(CC) -o $(NAME) $(OBJECTS) $(LDFLAGS) main.o: main.c interface.h grid.h $(CC) $(CFLAGS) main.c debug.o: debug.c interface.h $(CC) $(CFLAGS) debug.c error.o: error.c error.h $(CC) $(CFLAGS) error.c utilities.o: utilities.c utilities.h $(CC) $(CFLAGS) utilities.c interface.o: interface.c interface.h error.h utilities.h $(CC) $(CFLAGS) interface.c grid.o: grid.c grid.h error.h $(CC) $(CFLAGS) grid.c .PHONY: clean clean: @-rm -f $(OBJECTS) $(NAME) $(DEBUG_NAME) $(DEBUG_OBJECTS) .PHONY: debug debug: $(DEBUG_OBJECTS) $(CC) -o $(DEBUG_NAME) $(DEBUG_OBJECTS) $(LDFLAGS)
Advertisement
Answer
Executing readelf -d
on your compiled program will probably show the connection to libtinfo.so.5
$ readelf -d /path/to/your/program | grep NEEDED [...] 0x0000000000000001 (NEEDED) Shared library: [libtinfo.so.5] [...]
This may be pulled in because your libncurses.so
pulls it in somehow, e.g. by containing something like:
INPUT(... -ltinfo)
(Or something similar. I can just guess here..)
You can try adding -Wl,--as-needed
to your LDFLAGS
and hope that your program is not referencing any symbols from libtinfo
directly so that the linker does not need to add a dependency for libtinfo
to your program.
LDFLAGS=-Wl,--as-needed -lncurses
Recompile with new LDFLAGS
and check again with readelf -d
if it got compiled and linked without errors.
Using --as-needed
can be problematic if libncurses
uses symbols from libtinfo
but does not include a dependency to libtinfo
itself. If this happens your build will fail and complain about unreferenced symbols
or similar..
So if this does not work you may want to fix your curses installation or use the (in my opinion very dirty) symlink hack you already mentioned. Or let users compile the code on their systems – If you do not want to share code you can also just do the linking on the target system.
To fix the symlink-need-root-privileges issue you can also add a -Wl,-rpath,'$ORIGIN/../lib'
to your linker flags and expand the library search path of your program. This enables users to install your binary to /home/user/bin/program
and search libraries in /home/user/bin/../lib
. So they can do “dirty” symlink hacks in /home/user/lib
.
It is always problematic when distributing binaries only.