Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C code with ncurses compiled with libtinfo dependency

Tags:

c

linux

ncurses

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)
like image 922
gcali Avatar asked Feb 16 '23 22:02

gcali


1 Answers

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.

like image 178
mariux Avatar answered Mar 03 '23 22:03

mariux