GCC toolchain choice

FreeBASIC

GCC toolchain choice
 
FB is based on GCC toolchains and corresponding libraries. However, there is not a single GCC toolchain per platform, but often multiple slightly different ones. FB can generally work with all of them, but still there can be differences depending on the toolchain chosen to build and use FB. Here we document some of the issues to consider when building FB and/or making FB releases.

Windows (MinGW)

MinGW toolchains:

  • MinGW.org - also provides MSYS, besides a MinGW GCC toolchain. No Win64 support (yet).
  • MinGW-w64 - 32bit and 64bit. Different runtime libraries than MinGW.org.
  • TDM-GCC - 32bit based on MinGW.org, 64bit based on MinGW-w64, with modifications.
  • MinGW cross-compilers on various GNU/Linux distributions - for example MinGW-w64 on Debian/Ubuntu and Fedora (i686-w64-mingw32, x86_64-w64-mingw32)

Notes:

  • GCC exception handling mechanism: SJLJ setjump/longjump (slow but safe), DWARF-2 (fast but does not always work). The MinGW.org toolchain uses DWARF2, while for MinGW-w64, both types are available.
FB does not support exceptions anyways, so in theory the exception handling mechanism used by the underlying GCC toolchain does not matter.

In practice though, DWARF-2 GCC generates static data for stack unwinding which is put into .eh_frame sections. The problem is that .eh_frame data is generated also for C code (not just C++ code) like all the FB/GCC/MinGW runtime libraries, and it increases .exe size noticably. This can be avoided in multiple ways:

      • Use gcc flags to disable the generation of the .eh_frame data. FB is using this in its makefile and for -gen gcc, however obviously it does not affect the prebuilt MinGW/GCC libraries (unless the entire toolchain is rebuilt).
-fno-exceptions -fno-unwind-tables -fno-asynchronous-unwind-tables
      • Discard/strip the .eh_frame section when linking (by using a custom ldscript)
      • Use an SJLJ toolchain (i.e. MinGW-w64 built for SJLJ, instead of MinGW.org)
Furthermore, the exception handling method may be an important detail afterall (even if you do not care about .exe size) if you want to use C++ libraries from FB, in case the C++ library uses exceptions.

  • GCC threading model: Win32 threads (native), POSIX threads (based on winpthreads library). The MinGW.org toolchain uses Win32 threads, while for MinGW-w64, both types are available.
GCC needs POSIX threads to implement certain new C++ features, which is not possible with native Win32 threading functions. Thus, MinGW-w64 uses the winpthreads library which provides POSIX threading functions for Windows. However, winpthreads is not part of the main MinGW-w64 runtime, and it has a different license, which may have to be considered.

Since FB does not care about these C++ features, we can just use MinGW toolchains with Win32 threads, and avoid winpthreads.
  • Globbing (command line wildcard expansion etc.) behaviour is different between MinGW.org and MinGW-w64 because they have different runtime libraries/startup code impementations.
    • Globbing is enabled by default in the MinGW.org runtime, but the MinGW-w64 runtime turns globbing off by default and has a --enable-wildcard configure option. Thus, whether globbing is on or off by default, depends on how MinGW-w64 was built.
    • The way to disable globbing is different:
      • MinGW.org:
Extern _CRT_glob Alias "_CRT_glob" As Long
Dim Shared _CRT_glob As Long = 0

      • MinGW-w64:
Extern _dowildcard Alias "_dowildcard" As Long
Dim Shared _dowildcard As Long = 0

  • MinGW-w64 includes DirectX headers needed to compile FB's graphics library. MinGW.org does not contain them; they have to be added manually.
  • MinGW.org provides a common installer for their MinGW toolchain and the MSYS shell environment. This makes installing easier than with other toolchains, if MSYS is needed too.

DOS (DJGPP)

FB needs the DJGPP 2.04 beta runtime (does DJGPP 2.03 not work?). Either way, this version of DJGPP is extremely old. On the other hand, there have not been any more recent DJGPP releases, and updates can only be found in DJGPP's CVS. The recommendation is to only use DJGPP CVS if really needed though.

Linux

GNU/Linux distros usually provide native gcc + glibc toolchains out-of-the-box, and FB is intended to work with them out-of-the-box.

Executables (such as fbc itself) produced on one GNU/Linux distro are not necessarily portable to other GNU/Linux distros, due to differences in system libraries and/or versions, such as glibc version differences, or ncurses/libtinfo differences. The most common problem with fbc is mismatching glibc versions, i.e. the fbc binary is run on a system with older glibc than the one it was built on, and some form of "glibc too old" error is encountered. The ncurses library is not always exactly the same either, as shown by the "`ospeed' has different size, consider re-linking" warnings when running fbc. Also, some distros have separated libncurses and libtinfo, some just have libncurses, which can cause errors due to the libtinfo shared library not being found.

In theory, it is possible to use static linking to avoid the problems with shared libraries:

  • The fbc -static command line option tells the linker to prefer static libraries instead of shared ones. This can (in theory) also be used when building fbc itself. It relies on the Linux distro to provide static versions of the system libraries. Linking statically on GNU/Linux is typically discouraged though, in particular with glibc (some of its components are not designed for static linking), but also in general (shared libraries are preferred to avoid redundancy.
  • FB can (in theory) also be used with a different libc (instead of glibc), one that explicitly supports static linking, for example musl-libc.
In this context, you will typically use a custom gcc toolchain, which also requires FB to be built specifically for that toolchain. This approach in general works quite well, but it can be a lot of work.

Besides that, other libc's may not be ABI-compatible with glibc, which can cause problems for FB programs if they are written for glibc. Most noticably, the FB Linux CRT headers are based on glibc. An example of an ABI difference between musl-libc (0.9) and glibc was the jmp_buf structure size (used with the setjmp()/longjmp() functions). As the FB CRT headers defined the glibc jmp_buf, they were incompatible to musl-libc which used a smaller jmp_buf structure.

Another headache when using a different libc than the Linux distro default is that you also need to build a lot of libraries such as ncurses, X11 and Mesa/OpenGL in order to satisfy FB's dependencies, not to mention any other third-party libraries you want to use in your program. Existing libraries precompiled for glibc can probably not be used (at least not safely) due to the two libc's being ABI-incompatible.

See also