FreeBASIC in Antergos Linux (and possibly Arch and derivatives)

General discussion for topics related to the FreeBASIC project or its community.
Post Reply
xlucas
Posts: 334
Joined: May 09, 2014 21:19
Location: Argentina

FreeBASIC in Antergos Linux (and possibly Arch and derivatives)

Post by xlucas »

Hi, guys. I'm trying an Antergos Linux distribution. As I expect fewer people use it than those using Ubuntu and similar, I wanted to share my experience installing and running FreeBASIC on it. Antergos is based on Arch, so I expect this to also be applicable to Arch and its derivatives.

Programs having been complied with FreeBASIC do not run out of the box in Antergos, but just because of a tiny thing. They will report not finding libtinfo.so.5. This shared file, as I learnt, is only a link to ncurses, which is already installed, so all you have to do is create this link. Go to the /lib directory, locate your ncurses lib and create a link to it. In my case, it was like so:

Code: Select all

sudo link libncursesw.so.6.0 libtinfo.so.5
And voilà! Programs run normally.

About the FreeBASIC compiler itself, I am used to installing the development X libs and ncurses to get it working in Xubuntu. This was not necessary in Antergos. With just the same link given above, you can link both console and GUI based programs upon installation. So, surprisingly for me, setting up FB in Antergos was a lot easier than in Xubuntu. I expected quite the contrary.

Hope this helps somebody :)

EDIT: Oh! By the way, I'm going to now turn this into a question: Why is it that FB compiled programs require both ncurses AND tinfo if these two libraries are actually the same? Why does this happen?
TeeEmCee
Posts: 375
Joined: Jul 22, 2006 0:54
Location: Auckland

Re: FreeBASIC in Antergos Linux (and possibly Arch and derivatives)

Post by TeeEmCee »

Requiring both ncurses and tinfo sounds wrong. Maybe it happens only if libtinfo.so is a symlink, and ld adds both? I'm not sure. FB only requires the terminfo subset of ncurses. If libtinfo exists on the system then that is linked, otherwise libncurses is:

Code: Select all

'(From fbc.bas)
		'' libncurses and libtinfo: FB's rtlib depends on the libtinfo
		'' part of ncurses, which sometimes is included in libncurses
		'' and sometimes separate (depending on how ncurses was built).

		'' Prefer libtinfo over libncurses
		if( (len( fbcFindLibFile( "libtinfo.a"  ) ) > 0) or _
		    (len( fbcFindLibFile( "libtinfo.so" ) ) > 0) ) then
			fbcAddDefLib( "tinfo" )
		else
			fbcAddDefLib( "ncurses" )
		end if
Yes, the libtinfo thing is very annoying and should be fixed. I propose to always link to ncurses, not libtinfo, so that binaries will be portable. I don't see any other solution. In the bizarre event that ncurses isn't installed, then fbc can still fallback to libtinfo, and you'll be no worse off than before (you can compile, but your binaries aren't portable).
counting_pine
Site Admin
Posts: 6323
Joined: Jul 05, 2005 17:32
Location: Manchester, Lancs

Re: FreeBASIC in Antergos Linux (and possibly Arch and derivatives)

Post by counting_pine »

I'm not an expert, but wouldn't it break things, always linking to ncurses when tinfo contains what is needed?
What would a fallback look like?
marcov
Posts: 3462
Joined: Jun 16, 2005 9:45
Location: Netherlands
Contact:

Re: FreeBASIC in Antergos Linux (and possibly Arch and derivatives)

Post by marcov »

I think the symlink only adds the ncurses lib twice to the linker commandline. This is allowed on ELF systems, (to workaround circular references) so doesn't lead to problems.

Personally I think it is a great trick to avoid having to have two FBs (or -configurations), one that default links only to ncurses (for the targets that don't split out t(erm)info, and one for the ones that do.
dkl
Site Admin
Posts: 3235
Joined: Jul 28, 2005 14:45
Location: Germany

Re: FreeBASIC in Antergos Linux (and possibly Arch and derivatives)

Post by dkl »

Hm, I don't remember fbc ever linking FB programs against both libncurses and libtinfo at the same time. I think originally fbc only linked FB programs to ncurses, and it could be reverted back to it (partially revert 2a110bee). I don't remember any reason for using libtinfo only, besides trying to clean up.

The main problem that I remember is that FB programs (including the fbc binary itself) couldn't be run because libtinfo was missing. Now that I think about it, the change to link against libtinfo could have caused that. I used to check via ldd, but maybe readelf -d is better, because apparently ldd includes the recursive dependencies, while readelf -d doesn't; maybe that's why I missed it.
xlucas
Posts: 334
Joined: May 09, 2014 21:19
Location: Argentina

Re: FreeBASIC in Antergos Linux (and possibly Arch and derivatives)

Post by xlucas »

Sorry, I didn't realise I had a reply here till now. Well, as I said, ncurses was indeed present in my system and still FB was asking for libtinfo. FB was not saying anything about ncurses, so I don't know if it was really detecting it. Maybe ncurses had a name FB was not expecting and would've required a link named something with "ncurses" to get to it. I don't know. What I know is that, in Ubuntu, FB usually complains about ncurses missing instead (which points against my theory that it may be present with a different name). This gets me quite confused :S If others can test on their systems and check...
TeeEmCee
Posts: 375
Joined: Jul 22, 2006 0:54
Location: Auckland

Re: FreeBASIC in Antergos Linux (and possibly Arch and derivatives)

Post by TeeEmCee »

I also missed these replies.
marcov wrote:Personally I think it is a great trick to avoid having to have two FBs (or -configurations), one that default links only to ncurses (for the targets that don't split out t(erm)info, and one for the ones that do.
Doesn't linking to just libncurses work on systems that split out libtinfo from ncurses, since ncurses depends on libtinfo?
xlucas wrote:Sorry, I didn't realise I had a reply here till now. Well, as I said, ncurses was indeed present in my system and still FB was asking for libtinfo. FB was not saying anything about ncurses, so I don't know if it was really detecting it.
Originally you complained that binaries compiled elsewhere didn't run on Antergos, but now you are talking about "FB asking for...", which sounds like you're saying that you get an error message about a missing library when trying to compile with fbc. (Although I don't think fbc itself would show an error; it invokes a linker which shows an error message if a library is missing). That would be a completely different problem. I assume you misspoke, and you're still referring to the original problem?
xlucas
Posts: 334
Joined: May 09, 2014 21:19
Location: Argentina

Re: FreeBASIC in Antergos Linux (and possibly Arch and derivatives)

Post by xlucas »

TeeEmCee: You're right, sorry. The thing is like I described it on the first message. And maybe that's precisely the thing. I wonder what would have happened if I had compiled the program in Antergos with FBC without libtinfo. Would it have let me compile? And would programs later have different requirements? Now I have already created the link, so I would have to delete it to test that.
TeeEmCee
Posts: 375
Joined: Jul 22, 2006 0:54
Location: Auckland

Re: FreeBASIC in Antergos Linux (and possibly Arch and derivatives)

Post by TeeEmCee »

If Antergos has libncurses but not libtinfo, then compiling a FB program on it would work, and the program would work on other distributions too. fbc creates a nonportable dependency on libtinfo if it's present on the compiling machine.

Also, I realise now that we (mostly I) misinterpreted your original post. When you asked "Why is it that FB compiled programs require both ncurses AND tinfo if these two libraries are actually the same?", you were confused. They are not the same library. On machines where libtinfo does not exist, libncurses is the combination of ncurses and the terminfo library. If it does exist, then libtinfo is terminfo and libncurses is just ncurses. That's why (sym)linking libtinfo to libncurses works.

fbc won't directly link to both, but if libfb.a is compiled on one machine and then used by fbc on another I think the resulting binary could depend on both? Or if you link to other libraries which depend on libncurses, not just libtinfo.
xlucas
Posts: 334
Joined: May 09, 2014 21:19
Location: Argentina

Re: FreeBASIC in Antergos Linux (and possibly Arch and derivatives)

Post by xlucas »

Ah! Now I understand! So, in general, FB does not really use the other part of the library. Yeah, I asked the wrong question, like it tends to happen when one has no idea what the answer will be, but you managed to answer it anyway. Thanks.

Is it possible for me to somehow control the dynamic linking of these libraries within my program (as if I were linking a custom library), to ensure that, if one is not found, the other one is loaded in its place? Or would it be better to just try to link one of these libraries statically? What I'm trying to do is to make sure my programs are as portable as possible.
MrSwiss
Posts: 3910
Joined: Jun 02, 2013 9:27
Location: Switzerland

Re: FreeBASIC in Antergos Linux (and possibly Arch and derivatives)

Post by MrSwiss »

xlucas wrote:What I'm trying to do is to make sure my programs are as portable as possible.
Static linking is a good method, to achieve that since, it makes
the executable, independent of: "what's on the target system".

With dynamic lib's, you'd have to supply them, with the exec. ...
TeeEmCee
Posts: 375
Joined: Jul 22, 2006 0:54
Location: Auckland

Re: FreeBASIC in Antergos Linux (and possibly Arch and derivatives)

Post by TeeEmCee »

Well, you have a range of options including:
-make sure libtinfo isn't present, then fbc won't use it
-patch fbc not to use libtinfo (which is trivial), or I or someone else should do that, and then you use a git build
-statically link the entire binary (problematic; see below)
-pass -nodeflibs to fbc, as well as the necessary libraries. You can compile with -v to find out libraries get linked, and then specify those.
-don't use fbc to link, instead link yourself for more control over what gets linked (more or less the same as the above. This sounds odd, but it's actually what I do, for a number of reasons)
-many other routes which are more work, not seriously worth considering

I tried (on a ubuntu machine) statically linking just libtinfo with "-Wl -Bstatic,-ltinfo", but it didn't work. It seems ld ignored my request, because fbc puts -ltinfo first on 'ld's commandline, so ld gives it preference to the later static -ltinfo (ld effectively processes commandline flags in order). I don't know how to work around this problem without using -nodeflibs

Sadly, creating portable libraries on Linux is a big pain. Not because of libtinfo, that's easy to solve. The biggest problem is glibc.

Beware if you statically link everything, as there are various problems with statically linking glibc. Firstly, glibc is licensed under the LGPL, so you have to jump through hoops to distribute your program statically if it's not open source. Secondly, it will cause problems if you try to dynamically open other libraries (which e.g. SDL_mixer does). Thirdly, glibc will break if you use any network functions or some other CRT functions related to users or groups.
See https://stackoverflow.com/a/11693411/1185152 and http://micro.nicholaswilson.me.uk/post/ ... ibc-libgcc
Also, some libraries, like opengl, can never be statically linked.

Still, statically linking glibc is definitely the easiest 'solution', portably dynamically linking it is painful.
xlucas
Posts: 334
Joined: May 09, 2014 21:19
Location: Argentina

Re: FreeBASIC in Antergos Linux (and possibly Arch and derivatives)

Post by xlucas »

Cheers, guys. I am with free and open source software, but the dynamic-linking and the dependency hell that results from it, is definitely the part of the philosophy that I don't share. Before I found out this particular issue (about libtinfo and ncurses), the more-or-less comfortable position I had found was: let FBC create its default dynamic links, as the library it uses are almost guaranteed to be found on any GNU (not on any Linux-based OS, though), but if using any extra libraries, always link statically. It seemed to work fine. Most libraries linked by FBC have to do with X, but if X is unavailable, FBC compiled programs will use the framebuffer device, if I'm not mistaken and anyway, if my program is graphical, I can expect the system to have X.

TeeEmCee: I thought that glibc was not a problem because is the single one that's most guaranteed to be found, but now you make me doubt :S When would one have a problem because of linking glibc dynamically? In those cases, can I replace glibc with another library? (I've read there exist others that are compatible to it to some level and probably use a different, more permissive, license).
It's very interesting, the option of compiling only and then linking out of FBC. I'm going to try to learn to do it and see what results I get.
Oh, just saw you're from New Zealand. I've been there. Nice place and nice people. Hope to visit Kiwiland again some time in the future.
TeeEmCee
Posts: 375
Joined: Jul 22, 2006 0:54
Location: Auckland

Re: FreeBASIC in Antergos Linux (and possibly Arch and derivatives)

Post by TeeEmCee »

Yes there are various other libc's that you can use instead of glibc which are friendlier to static linking.

The problem is that if you link against a newer version of glibc than is present on the machine where your program will run, then it might make use of newer functions not present in that version.
You have the same problem with the version of GCC used: they may have dependencies on libgcc*.so libraries

The general advice is to not link glibc or other system libraries (like libgcc) statically, but instead ensure that you only require old versions of them.

When I was working on making my own programs portable, I wrote a program to check what versions of glibc and gcc are actually required, based on versioned symbols in the elf file:

Code: Select all

#!/usr/bin/env python

"""
A tool for testing portability.
Check which versions of the glibc, libgcc, and libstdc++ shared libraries
a GNU/Linux ELF binary depends upon.
Note that libstdc++ version requirements are reported as GCC requirements,
because each libstdc++ version is tied to a specific GCC version.
Old versions before ~2010 are lumped together, and GCC versions newer than 6.1
aren't supported yet.

Written 2017, Ralph Versteegen. Released into the Public Domain.
(Part of the OHRRPGCE build system.)
"""

import sys
import subprocess
import re

def get_command_output(cmd, args, shell = True):
    """Runs a shell command and returns stdout as a string"""
    if shell:
        # Argument must be a single string (additional arguments get passed as extra /bin/sh args)
        if isinstance(args, (list, tuple)):
            args = ' '.join(args)
        cmdargs = '"' + cmd + '" ' + args
    else:
        assert isinstance(args, (list, tuple))
        cmdargs = [cmd] + args
    proc = subprocess.Popen(cmdargs, shell=shell, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    errtext = proc.stderr.read()
    outtext = proc.stdout.read()
    # Annoyingly fbc prints (at least some) error messages to stdout instead of stderr
    if len(errtext) > 0 or proc.returncode:
        raise Exception("subprocess.Popen(%s) failed;\n%s\n%s" % (cmdargs, outtext, errtext))
    return outtext.strip()


def check_lib_requirements(binary):
    """Check and print which versions of glibc and gcc dependency libraries (including libstdc++.so)
    that an ELF binary requires"""

    libraries = []
    current_lib = None
    req = {'CXXABI': (), 'GLIBC': (), 'GLIBCXX': (), 'GCC': ()}
    for line in get_command_output("objdump", ["-p", binary]).split('\n'):
        match = re.search("required from (.*):", line)
        if match:
            current_lib = match.group(1)
            libraries.append(current_lib)
        match = re.search("(CXXABI|GCC|GLIBC|GLIBCXX)_([0-9.]*)", line)
        if match:
            symbol = match.group(1)
            version = tuple(map(int, match.group(2).split('.')))
            #print symbol, version
            req[symbol] = max(req[symbol], version)

    # Tables giving the required version of GCC corresponding to each GLIBCXX symbol versioning tag
    GLIBCXX_to_gcc = {
        (3,4,10): (4,3,0),
        (3,4,11): (4,4,0),
        (3,4,12): (4,4,1),
        (3,4,13): (4,4,2),
        (3,4,14): (4,5,0),
        (3,4,15): (4,6,0),
        (3,4,16): (4,6,1),
        (3,4,17): (4,7,0),
        (3,4,18): (4,8,0),
        (3,4,19): (4,8,3),
        (3,4,20): (4,9,0),
        (3,4,21): (5,1,0),
        (3,4,22): (6,1,0),
    }

    # Ditto for CXXABI
    CXXABI_to_gcc = {
        (1,3,2): (4,3,0),
        (1,3,3): (4,4,0),
        (1,3,3): (4,4,1),
        (1,3,3): (4,4,2),
        (1,3,4): (4,5,0),
        (1,3,5): (4,6,0),
        (1,3,5): (4,6,1),
        (1,3,6): (4,7,0),
        (1,3,7): (4,8,0),
        (1,3,7): (4,8,3),
        (1,3,8): (4,9,0),
        (1,3,9): (5,1,0),
        (1,3,10): (6,1,0),
    }

    gcc_release_dates = {
        (4,3,0): 'March 5, 2008',
        (4,4,0): 'April 21, 2009',
        (4,4,1): 'July 22, 2009',
        (4,4,2): 'October 15, 2009',
        (4,5,0): 'April 14, 2010',
        (4,6,0): 'March 25, 2011',
        (4,6,1): 'June 27, 2011',
        (4,7,0): 'March 22, 2012',
        (4,8,0): 'March 22, 2013',
        (4,8,3): 'May 22, 2014',
        (4,9,0): 'April 22, 2014',
        (5,1,0): 'April 22, 2015',
        (6,1,0): 'April 27, 2016',
    }

    glibc_release_dates = {
        (2,26): '2017-08-01',
        (2,25): '2017-02-01',
        (2,24): '2016-08-04',
        (2,23): '2016-02-19',
        (2,22): '2015-08-14',
        (2,21): '2015-02-06',
        (2,20): '2014-09-08',
        (2,19): '2014-02-07',
        (2,18): '2013-08-12',
        (2,17): '2012-12-25',
        (2,16): '2012-06-30',
        (2,15): '2012-03-21',
        (2,14,1): '2011-10-07',
        (2,14): '2011-06-01',
        (2,13): '2011-02-01',
        (2,12,2): '2010-12-13',
        (2,12,1): '2010-08-03',
        (2,12): '2010-05-03',
    }
    #print req

    def verstring(version_tuple):
        return '.'.join(map(str, version_tuple))

    def lookup_version(version_tuple, table):
        if version_tuple < min(table):
            return "before " + table[min(table)]
        elif version_tuple > max(table):
            return "after " + table[max(table)]
        elif version_tuple in table:
            return table[version_tuple]
        return "unknown"

    gcc_ver_reqs = []
    gcc_req = ''

    if 'libstdc++.so.6' in libraries:
        gcc_ver_reqs.append((3,4,0))

    if req['GLIBCXX'] > (3,4,22) or req['CXXABI'] > (1,3,10):
        gcc_req = '>6.1.0'
    else:
        if req['GCC']:
            gcc_ver_reqs.append(req['GCC'])
        # fixme: this isn't very good
        if req['CXXABI'] < (1,3,2):
            pass
        else: #if req['CXXABI'] in GLIBCXX_to_gcc:
            gcc_ver_reqs.append(CXXABI_to_gcc.get(req['CXXABI'], (9, 'unknown')))
        if req['GLIBCXX'] < (3,4,10):
            pass
        else: #if req['GLIBCXX'] in GLIBCXX_to_gcc:
            gcc_ver_reqs.append(GLIBCXX_to_gcc.get(req['GLIBCXX'], (9, 'unknown')))
        if gcc_ver_reqs:
            max_version = max(gcc_ver_reqs)
            gcc_req = verstring(max_version) + ' (released %s)' % lookup_version(max_version, gcc_release_dates)
    if gcc_req:
        gcc_req = 'and libs for gcc ' + gcc_req

    glibc_release = lookup_version(req['GLIBC'], glibc_release_dates)
    print ">>  %s requires glibc %s (released %s) %s" % (
        binary, verstring(req['GLIBC']), glibc_release, gcc_req)

if len(sys.argv) < 2:
    print("Usage: %s binaryfile" % sys.argv[0])
else:
    check_lib_requirements(sys.argv[1])
Example output (produced by running "for fil in /usr/local/bin/*; do if file $fil | grep -qi elf; then ./check_lib_reqs.py $fil; fi; done"):

Code: Select all

>>  /usr/local/bin/ipfs requires glibc 2.3.2 (released before 2010-05-03) 
>>  /usr/local/bin/jpg2ff requires glibc 2.7 (released before 2010-05-03) 
>>  /usr/local/bin/keyboardcast requires glibc 2.2.5 (released before 2010-05-03) 
>>  /usr/local/bin/opam requires glibc 2.7 (released before 2010-05-03) 
>>  /usr/local/bin/synergys requires glibc 2.14 (released 2011-06-01) and libs for gcc 4.6.0 (released March 25, 2011)
>>  /usr/local/bin/x128 requires glibc 2.15 (released 2012-03-21) and libs for gcc 3.4.0 (released before March 5, 2008)
On my system, binaries produced by fbc generally are reported as: "requires glibc 2.7 (released before 2010-05-03)" but this is completely system-dependent. Use an old distro in a virtual machine if you find the requirements too high.

As for linking X11 libraries statically, I don't know if that's safe but I would assume it is, since it's a well defined protocol, and those libraries are just for speaking the protocol.
xlucas
Posts: 334
Joined: May 09, 2014 21:19
Location: Argentina

Re: FreeBASIC in Antergos Linux (and possibly Arch and derivatives)

Post by xlucas »

The Antergos I installed on the other partition probably uses newest versions, because that's the style of Arch. But most of the time, I'm doing my work on a Xubuntu LTS, so I expect the glibc and GCC will be a little behind, for stability. I think this is a better environment to compile my programs on... although I have to watch out for the libtinfo matter. I've been checking the versions on my system now:

gcc (Ubuntu 5.4.0-6ubuntu1~16.04.4) 5.4.0 20160609 (one year ago)
ldd (Ubuntu GLIBC 2.23-0ubuntu7) 2.23 (latest stable release is 2.25, from February 5, 2017)

Looks like they're old enough :)
Post Reply