[GRASSLIST:1261] readline problem and fix

Sharing a quick fix to a configuration error due to a problem with readline. Not sure if it's been documented (or how many find readline useful), but if so, it is not yet reflected in configure. This problem exists primarily on linux for reasons not entirely clear, (although it appears there is a link failure between the shared readline (libreadline.so) and ncurses libraries (libncurses.so) in multiple distributions. I'm running Mandrake 9.1)...

Symptom:

./configure --with-readline
<chop>
checking for readline in -lreadline... no
configure: error: *** Unable to locate Readline library.

From config.log...

configure:5276: checking for readline in -lreadline
configure:5293: gcc -o conftest -g -O2 conftest.c -lreadline 1>&5
/usr/lib/gcc-lib/i586-mandrake-linux-gnu/3.2.2/../../../libreadline.so: undefined reference to `tgetnum'
/usr/lib/gcc-lib/i586-mandrake-linux-gnu/3.2.2/../../../libreadline.so: undefined reference to `tgoto'
/usr/lib/gcc-lib/i586-mandrake-linux-gnu/3.2.2/../../../libreadline.so: undefined reference to `tgetflag'
/usr/lib/gcc-lib/i586-mandrake-linux-gnu/3.2.2/../../../libreadline.so: undefined reference to `BC'
/usr/lib/gcc-lib/i586-mandrake-linux-gnu/3.2.2/../../../libreadline.so: undefined reference to `tputs'
/usr/lib/gcc-lib/i586-mandrake-linux-gnu/3.2.2/../../../libreadline.so: undefined reference to `PC'
/usr/lib/gcc-lib/i586-mandrake-linux-gnu/3.2.2/../../../libreadline.so: undefined reference to `tgetent'
/usr/lib/gcc-lib/i586-mandrake-linux-gnu/3.2.2/../../../libreadline.so: undefined reference to `UP'
/usr/lib/gcc-lib/i586-mandrake-linux-gnu/3.2.2/../../../libreadline.so: undefined reference to `tgetstr'
collect2: ld returned 1 exit status
configure: failed program was:
#line 5282 "configure"
#include "confdefs.h"
/* Override any gcc2 internal prototype to avoid an error. */
/* We use char because int might match the return type of a gcc2
    builtin and then its argument prototype would still apply. */
char readline();

int main() {
readline()
; return 0; }

Using linker to test readline...

$ ld /usr/lib/libreadline.so
ld: warning: cannot find entry symbol _start; not setting start address
/usr/lib/libreadline.so: undefined reference to `tgetnum'
/usr/lib/libreadline.so: undefined reference to `tgoto'
/usr/lib/libreadline.so: undefined reference to `tgetflag'
/usr/lib/libreadline.so: undefined reference to `BC'
/usr/lib/libreadline.so: undefined reference to `tputs'
/usr/lib/libreadline.so: undefined reference to `PC'
/usr/lib/libreadline.so: undefined reference to `tgetent'
/usr/lib/libreadline.so: undefined reference to `UP'
/usr/lib/libreadline.so: undefined reference to `tgetstr'

...all of which are references supplied by ncurses.

The quick fix for me was to add '-lncurses' whenever there was a link to readline and re-run configure.

$ sed 's/\-lreadline/\-lreadline \-lncurses/g' configure > newconfigure

$ mv configure configure.bak ; mv newconfigure configure

$ ./configure --with-readline

Jack Varga
Boulder, CO

Jack Varga wrote:

Sharing a quick fix to a configuration error due to a problem with
readline. Not sure if it's been documented (or how many find readline
useful), but if so, it is not yet reflected in configure. This problem
exists primarily on linux for reasons not entirely clear, (although it
appears there is a link failure between the shared readline
(libreadline.so) and ncurses libraries (libncurses.so) in multiple
distributions. I'm running Mandrake 9.1)...

It's a known problem. FWIW, readline is only used by r.mapcalc.

Using linker to test readline...

$ ld /usr/lib/libreadline.so
ld: warning: cannot find entry symbol _start; not setting start address
/usr/lib/libreadline.so: undefined reference to `tgetnum'
/usr/lib/libreadline.so: undefined reference to `tgoto'
/usr/lib/libreadline.so: undefined reference to `tgetflag'
/usr/lib/libreadline.so: undefined reference to `BC'
/usr/lib/libreadline.so: undefined reference to `tputs'
/usr/lib/libreadline.so: undefined reference to `PC'
/usr/lib/libreadline.so: undefined reference to `tgetent'
/usr/lib/libreadline.so: undefined reference to `UP'
/usr/lib/libreadline.so: undefined reference to `tgetstr'

...all of which are references supplied by ncurses.

And also supplied by libtermcap and libtinfo:

$ nm -D /usr/lib/libncurses.so | fgrep tgetnum
000292a0 T tgetnum
$ nm -D /usr/lib/libtermcap.so | fgrep tgetnum
00001e60 T tgetnum
$ nm -D /usr/lib/libtinfo.so | fgrep tgetnum
00011e34 T tgetnum

And therein lies the problem. There may be multiple libraries which
could be used, and it may make a difference depending upon which one
is actually chosen (some libraries may use termcap, others terminfo).

I'm fairly sure that there is no practical way to autodetect which is
the correct library to use. We could add an addtional switch, e.g.
--with-readline-deps={curses,ncurses,termcap,tinfo} to allow the user
to select which additional library to try, although I'd rather they
just filed bug reports with their OS vendor until the vendor issues a
version of readline with the correct dependency information (as is the
case for e.g. RH6.2's readline).

--
Glynn Clements <glynn.clements@virgin.net>

Glynn,

Thanks for the explanation. I'm reposting to the list as I'm sure someone can benefit from this down the road.

Best regards,

Jack Varga

Glynn Clements wrote:

Jack Varga wrote:

I'd rather they just filed bug reports with their OS vendor until the vendor issues a version of readline with the correct dependency information (as is the case for e.g. RH6.2's readline).

Until they do, would it be advantageous to add links for each of these shared libraries?
   
We definitely don't want to link in more than one of them; on many
platforms, that in itself would cause an error. On platforms which
allow this, only one of them (typically either the first or last)
would actually be used. Also, if you specify a library which doesn't
exist, that will usually cause an error even if the library isn't
actually required.

Relatedly, don't termcap and terminfo libraries, for all practical purposes, provide the same functionality?
   
They provide the same essential functionality, i.e. they provide
functions which allow an application to determine whether the current
terminal type supports a particular feature and, if so, which codes
are used to activate it. However:

1. There are two different sets of functions: the original termcap API
(tgetstr etc) and the newer terminfo API (tigetstr etc).

2. There are two different database formats: the original termcap
format (a single text file, typically /etc/termcap) and the newer
terminfo format (a directory tree of binary files, with one file for
each terminal type).

To complicate matters, there is no guarantee that the choice of API
matches the choice of database; it's quite possible that a library
provides the termcap API but actually uses the terminfo database (a
common approach is to try terminfo first then termcap).

While the configure script can readily determine whether a library
provides the correct API, there is no practical way for it to
determine which database is used. Which is unfortunate, because the
choice of database may be important; it's quite possible that one
database is more complete and/or more accurate than the other.

For that matter, isn't curses decprecated by ncurses (new curses)?
   
Yes, although:

1. We make reasonable efforts to support legacy systems.

2. Of the libraries in question ([n]curses, termcap, tinfo), [n]curses
should be the last choice. The other two are much simpler, simply
providing an interface for querying the termcap/terminfo databases. Curses is a higher-level library, and significantly more complex (and
hence more likely to introduce additional problems) than the other
two.

In summary: configure can easily go through a list of combinations,
such as:

-lreadline -ltinfo
-lreadline -ltermcap
-lreadline -lncurses
-lreadline -lcurses

determining whether each combination succeeds. The problem is that, if
more than one of the combinations works (and that's highly likely),
how to choose which combination to actually use. Because it may well
make a difference.