fbc
fbc copied to clipboard
undefined reference to symbol 'tgoto'
The following build error occurs after executing make bootstrap-minimal
in the FreeBASIC 1.07.0 bootstrap source release:
LINK bootstrap/fbc
/usr/lib/gcc/x86_64-pc-linux-gnu/9.2.0/../../../../x86_64-pc-linux-gnu/bin/ld: lib/freebasic/linux-x86_64/libfb.a(hinit.o): undefined reference to symbol 'tgoto'
/usr/lib/gcc/x86_64-pc-linux-gnu/9.2.0/../../../../x86_64-pc-linux-gnu/bin/ld: /lib64/libtinfo.so.6: error adding symbols: DSO missing from command line
collect2: error: ld returned 1 exit status
make: *** [makefile:1115: bootstrap/fbc] Error 1
However, this error is not related to the FreeBASIC 1.07.0 release: my ncurses library lacks the tgoto
symbol.
On my system (Gentoo x86-64), the curses library (libncurses) sep is built from the low-level terminfo library (libtinfo). This effectively means that the tgoto
symbol is provided by libtinfo instead of libncurses on my system.
Adding -ltinfo
to line 1112 in the FreeBASIC makefile resolves the issue, but this may cause missing file errors for users who do not have libtinfo on their system. So this flag should instead be conditionally added in order to properly resolve this issue.
I've been considering adding Autotools support to the FreeBASIC repository in order to get the canonical ./configure && make
support many users expect. Is there any objection if I submit a pull request implementing such?
One key benefit of utilizing Autoconf is that it'll help us avoid issues like this one by taking care of configuring the compiler and linker flags in a portable way. In addition, Automake would simplify the existing FreeBASIC makefile
into just a small number of lines representing the make dependencies of the source components.
The libncurses/libtinfo separation being distro-dependent really is a pain. Aside from getting autoconf to detect and handle that, what would the alternative be? A makefile rule to compile a small test program? Detecting whether libtinfo.so exists (eg using gcc -print-file-name
)?
I don't have much of a say in this, but I'm skeptical that switching to autotools would simplify the makefile much. There's some cruft in there, but I think most of makefile would have to remain. It is true that I had to read and study the makefile to learn how to do things like do multilib builds or cross-compile, since it is its own system.
The libncurses/libtinfo separation being distro-dependent really is a pain. Aside from getting autoconf to detect and handle that, what would the alternative be? A makefile rule to compile a small test program? Detecting whether libtinfo.so exists (eg using
gcc -print-file-name
)?
If we don't use Autoconf, then we essentially have to create some system tests to detect whether tgoto
is provided by libncurses.so or libtinfo.so -- effectively we have to recreate the same tests that Autoconf would do.
I don't have much of a say in this, but I'm skeptical that switching to autotools would simplify the makefile much. There's some cruft in there, but I think most of makefile would have to remain. It is true that I had to read and study the makefile to learn how to do things like do multilib builds or cross-compile, since it is its own system.
Fortunately Autoconf is independent from Automake, so we don't need to recreate the existing FreeBASIC makefile
file -- we can use it as it is now. We would just implement a configure.ac
file that generates a configure
script, and use that configuration (i.e. CFLAGS, LDFLAGS, etc.) directly in the existing FreeBASIC makefile
file.
So we can postpone utilizing Automake until a later point, and focus just on system checks and configuration for now.
Yea, looks like this issue with "make bootstrap" was overlooked. Normally (from my point of view) fbc is built using an existing fbc, which itself checks for libtinfo when linking (gcc -print-file-name=libtinfo.so, https://github.com/freebasic/fbc/blob/1.07.0/src/compiler/fbc.bas#L3360, https://github.com/freebasic/fbc/blob/1.07.0/src/compiler/fbc.bas#L291). So "make bootstrap" could do the same.
By the way, that's needed for all FB programs, not just fbc, so fbc's build system is usually not responsible for that, except in the bootstrap case of course. So chances are that even with autoconf the check for working -ltinfo would be missing.
For your information, fbc used autoconf in the past too. So it might well be accepted again, as long as it's not more complex and still does mostly the same :). But keep in mind, there are use cases like cross-compiling and the need to support MinGW/MSYS and DJGPP, plus some boilerplate is needed to integrate fbc and FB code into the gcc build system world (CFLAGS and LDFLAGS don't just magically work, unfortunately). To get an idea of what it looked like, see: 435d901a, b8fe3cd3, 2f6dc39b. Of course those configure.ac scripts won't work anymore since the build process and dependencies changed since then.
I had thought that linking to just ncurses would result in a binary that works on both distros with and without libtinfo.so, since libncurses.so would depend on libtinfo.so if it exists. Now that I know that doesn't actually compile for you, I'm not so sure...
ncurses/tinfo is one of the roadblocks to creating portable linux binaries that will run on any distro. Another problem is that newer distros have ncurses abi 6 while older ones have 5, and unlike glibc, don't provide multiple versions. This reminds me that I've been meaning to submit a rtlib patch I have to make ncurses/terminfo optional.
I had thought that linking to just ncurses would result in a binary that works on both distros with and without libtinfo.so, since libncurses.so would depend on libtinfo.so if it exists. Now that I know that doesn't actually compile for you, I'm not so sure...
ncurses/tinfo is one of the roadblocks to creating portable linux binaries that will run on any distro. Another problem is that newer distros have ncurses abi 6 while older ones have 5, and unlike glibc, don't provide multiple versions. This reminds me that I've been meaning to submit a rtlib patch I have to make ncurses/terminfo optional.
The reason libtinfo is required despite libncurses is because of the use of termcap compatibility functions used in src/rtlib/unix/hinit.c.
In fact, these functions should not even be used since they are marked TO BE WITHDRAWN in future versions of the XSI curses standard.
These routines are included as a conversion aid for programs that use the termcap library.
Since we are already using libncurses in FreeBASIC, these termcap functions should be replaced with their equivalent functionality in ncurses. Once that is done, we no longer need to worry about libtinfo.
Yea, looks like this issue with "make bootstrap" was overlooked. Normally (from my point of view) fbc is built using an existing fbc, which itself checks for libtinfo when linking (gcc -print-file-name=libtinfo.so, https://github.com/freebasic/fbc/blob/1.07.0/src/compiler/fbc.bas#L3360, https://github.com/freebasic/fbc/blob/1.07.0/src/compiler/fbc.bas#L291). So "make bootstrap" could do the same.
Ah, I understand now, FBC executes gcc -print-file-name=libtinfo.so
within, so that's how it links to libtinfo for native FreeBASIC programs.
I don't think the GCC -print-file-name
flag is the best way to determine this library -- there's no guarantee that the library it finds is actually the one with the symbol we need. The way tools like Autoconf deals with this is to create a simple C program with the symbol, compile it, and try to link with the desired library (e.g. libncurses.so); if it succeeds, then we know that library is the one we need, otherwise it does the same test with another library (e.g. libtinfo.so) until it finds one that works.
However, since FBC is already using that GCC flag within, we may as well use it in the FreeBASIC makefile
file. It may not be the absolute best solution, but it should be simple and good enough to resolve this issue for most users. Thus, the makefile
file should be updated to execute gcc -print-file-name=libtinfo.so
in order to determine if libtinfo.so is present -- if so, then add -ltinfo
to the library link list.
By the way, that's needed for all FB programs, not just fbc, so fbc's build system is usually not responsible for that, except in the bootstrap case of course. So chances are that even with autoconf the check for working -ltinfo would be missing.
For your information, fbc used autoconf in the past too. So it might well be accepted again, as long as it's not more complex and still does mostly the same :). But keep in mind, there are use cases like cross-compiling and the need to support MinGW/MSYS and DJGPP, plus some boilerplate is needed to integrate fbc and FB code into the gcc build system world (CFLAGS and LDFLAGS don't just magically work, unfortunately). To get an idea of what it looked like, see: 435d901, b8fe3cd, 2f6dc39. Of course those configure.ac scripts won't work anymore since the build process and dependencies changed since then.
Thank you for linking this, I wasn't aware the FreeBASIC repository had a configure.ac
file in the past. Was the reason for removal that the Autoconf files were becoming too cumbersome to maintain?
I might try to implement a simple new configure.ac
in the future, but for now it's just a consideration. If I do, I'll submit a pull request and we can further discuss it there.
Since we are already using libncurses in FreeBASIC, these termcap functions should be replaced with their equivalent functionality in ncurses. Once that is done, we no longer need to worry about libtinfo.
I'm not very familiar with ncurses or termcap, but I decided to take a look through the FreeBASIC repository and search for where these libtinfo functions are used:
- https://github.com/freebasic/fbc/blob/d8f11f42ff02d21b6a5b0bfd1e156e851331d1c1/src/rtlib/unix/hinit.c#L481 This just saves a description of the terminal type in use for reference later.
- https://github.com/freebasic/fbc/blob/d8f11f42ff02d21b6a5b0bfd1e156e851331d1c1/src/rtlib/unix/hinit.c#L484 This gets the padding commands.
- https://github.com/freebasic/fbc/blob/d8f11f42ff02d21b6a5b0bfd1e156e851331d1c1/src/rtlib/unix/hinit.c#L489 This checks if the terminal is set for automatic wrap at margin.
- https://github.com/freebasic/fbc/blob/d8f11f42ff02d21b6a5b0bfd1e156e851331d1c1/src/rtlib/unix/hinit.c#L492
This gets the string of commands necessary for the terminal capabilities requested by
seq
: https://github.com/freebasic/fbc/blob/d8f11f42ff02d21b6a5b0bfd1e156e851331d1c1/src/rtlib/unix/hinit.c#L34 - https://github.com/freebasic/fbc/blob/d8f11f42ff02d21b6a5b0bfd1e156e851331d1c1/src/rtlib/unix/hinit.c#L290 This encodes numeric parameters such as cursor positions into the terminal-specific form required for display commands.
- https://github.com/freebasic/fbc/blob/d8f11f42ff02d21b6a5b0bfd1e156e851331d1c1/src/rtlib/unix/hinit.c#L293 This puts out the prepared string to the terminal.
- https://github.com/freebasic/fbc/blob/d8f11f42ff02d21b6a5b0bfd1e156e851331d1c1/src/rtlib/unix/io_inkey.c#L120 This defines the terminal escape sequences for certain keyboard key presses.
Relatively, these aren't many calls so it may be simple to replace them with the ncurses equivalents. For example the ncurses mvprintw
and printw
functions could replace the tgoto
and tputs
functions.