freebasic / fbc

FreeBASIC is a completely free, open-source, multi-platform BASIC compiler, with syntax similar to MS-QuickBASIC, that adds new features such as pointers, object orientation, unsigned data types, inline assembly, and many others.
https://www.freebasic.net
877 stars 137 forks source link

undefined reference to symbol 'tgoto' #170

Open vilhelmgray opened 5 years ago

vilhelmgray commented 5 years ago

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.

vilhelmgray commented 5 years ago

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.

rversteegen commented 5 years ago

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.

vilhelmgray commented 5 years ago

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.

dkl commented 5 years ago

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.

rversteegen commented 5 years ago

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.

vilhelmgray commented 5 years ago

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.

vilhelmgray commented 5 years ago

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.

vilhelmgray commented 5 years ago

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:

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.