Decimal-arithmetic support in gcc compilers

Original version: Fri Oct 27 17:12:17 2017.
Last update: Sat Mar 2 14:56:25 2024.

Nelson H. F. Beebe
University of Utah
Department of Mathematics, 110 LCB
155 S 1400 E RM 233
Salt Lake City, UT 84112-0090
USA

Email: beebe@math.utah.edu, beebe@acm.org, beebe@computer.org
WWW URL: http://www.math.utah.edu/~beebe
Telephone: +1 801 581 5254
FAX: +1 801 581 4148

PGP public key ID 0xA93C57C2 (fingerprint = 7C18 7199 BC82 5EAB 06EB 9B96 FD9E 0E97 A93C 57C2),
MCW public key ID 0xFE0A1F46 (fingerprint = B574 BCC7 210E 9A29 E810 C85B 6ADE 786E FE0A 1F46),
and notes for their use.

Table of contents

Overview

In early 2024, almost no operating-system distribution that includes gcc-family compilers has support for decimal arithmetic in C. The sole exceptions known to this author are some Linux distributions for the IBM PowerPC CPU, and the IBM z-Series mainframes (System-360 family descendants), which have hardware instructions for decimal arithmetic. Thus, users cannot yet expect to get decimal arithmetic support from most vendor software distribution channels for common departmental, desktop, and laptop computers. One of the goals of the MathCW project is to improve that situation, and this Web site documents that work.

Compilers at this site

This site provides pre-built gcc-family compilers for several platforms with compiler support for decimal arithmetic in the C language. In most cases, compilers are also provided for other languages, including Ada, Brig, C++, Fortran, Go, Java, LTO, Objective-C, and Objective-C++; none of them has support for decimal arithmetic. Release 9 and later of gcc supply a compiler for D (gdc), and releases 13 and later have compilers for Modula-2 (gm2) and Rust (gccrs).

The gcc compiler team has removed all support for Java from gcc version 7 onward, on the grounds that it was receiving little developer support, took about a quarter of the compiler build time, and some projects were switching from Java to newer languages, such as Go, Julia, and Rust. The team observed that the OpenJDK project has become a more popular source of Java compilers, so they felt that they could drop the gcj compiler entirely.

Building the Ada compiler tools (gnat, gnatbind, and gnatmake) requires a gcc that already supports Ada, because part of those tools are themselves written in Ada. Regrettably, that requires a bootstrap process, possibly back to an old gcc 2.x version that did not use Ada, but could build compiler tools for it. On some operating system distributions, it is sufficient to install packages named gnat* to get the needed gcc compiler. All of the compilers at this site fully support Ada, and can be used for the bootstrap process.

As with Ada, in recent gcc releases, part of the compiler for D is written in that language, and a bootstrap process is again required. The compilers at this site include D support, and can be used for the bootstrap.

The other languages supported by gcc require only compilers for C and C++, and can generally be built and installed without problems using the scripts at this site.

Languages supported by gcc

The top-level configure script in each gcc release that is run from the build-dgcc.sh accepts a --enable-languages option that lists the programming languages for which compilers are to be built. That list is supplied to build-dgcc.sh by the LANGS environment variable. However, the language list varies with major gcc releases, and sometimes, also with minor releases. Here is a summary of languages by compiler release:

Cryptographic verification of software downloads

Our machines in the math.utah.edu domain are managed by computer professionals with decades of experience, and we monitor them closely to guard against attacks. Nevertheless, because computer break-ins are a widespread problem in the computing industry, affecting even large corporations and national governments, we must introduce further guards that software that we have written, or built, remains unmodified after its packaging and public release.

All of the gcc distributions at this site are cryptographically signed by the builder, who is also the author of this Web site. After you have downloaded one or more distributions, we encourage you to also download the associated detached signature files that have the additional suffix .sig. You can then verify that the distribution has not been modified since it was signed, using either the venerable pgp (Pretty Good Privacy) system, or its GNU equivalents in the gnupg1 and gnupg2 packages.

Here are examples of such verification by a user who has never previously downloaded the signer's public key:

    % time pgp x86_64-unknown-linux-gnu-gcc-7.2.0.tar.gz.sig
    Pretty Good Privacy(tm) Version 6.5.8
    (c) 1999 Network Associates Inc.
    Uses the RSAREF(tm) Toolkit, which is copyright RSA Data Security, Inc.
    Export of this software may be restricted by the U.S. government.

    File 'x86_64-unknown-linux-gnu-gcc-7.2.0.tar.gz.sig' has signature, but with no text.
    Text is assumed to be in file 'x86_64-unknown-linux-gnu-gcc-7.2.0.tar.gz'.
    signature not checked.
    Signature made 2017/10/26 00:24 GMT
    key does not meet validity threshold.

    WARNING:  Because this public key is not certified with a trusted
    signature, it is not known with high confidence that this public key
    actually belongs to: "(KeyID: 0xFE0A1F46)".

    6.523u 0.267s 0:06.84 99.1%     0+0k 24+24io 0pf+0w

    % gpg --version | head -n1
    gpg (GnuPG) 1.4.20

    % time gpg x86_64-unknown-linux-gnu-gcc-7.2.0.tar.gz.sig
    gpg: directory `/home/jones/.gnupg' created
    gpg: new configuration file `/home/jones/.gnupg/gpg.conf' created
    gpg: WARNING: options in `/home/jones/.gnupg/gpg.conf' are not yet active during this run
    gpg: keyring `/home/jones/.gnupg/secring.gpg' created
    gpg: keyring `/home/jones/.gnupg/pubring.gpg' created
    gpg: assuming signed data in `x86_64-unknown-linux-gnu-gcc-7.2.0.tar.gz'
    gpg: Signature made Wed 25 Oct 2017 06:24:00 PM MDT using RSA key ID FE0A1F46
    gpg: Can't check signature: public key not found

    4.347u 0.171s 0:04.84 93.1%     0+0k 264+40io 1pf+0w

    % gpg2 --version | head -n1
    gpg (GnuPG) 2.1.9

    % time gpg2 x86_64-unknown-linux-gnu-gcc-7.2.0.tar.gz.sig
    gpg: assuming signed data in 'x86_64-unknown-linux-gnu-gcc-7.2.0.tar.gz'
    gpg: Signature made Wed 25 Oct 2017 06:24:00 PM MDT using RSA key ID FE0A1F46
    gpg: Can't check signature: No public key

    6.052u 0.170s 0:06.23 99.8%     0+0k 0+0io 0pf+0w

There are no complaints about compromised data, but each utility reports that it has no record of the public key belonging to the identifier 0xFE0A1F46.

That problem can be solved by going to any of several public key servers, such as

http://keys.gnupg.net
http://keyserver.oeg.com.au
http://keyserver.stack.nl
http://keyserver.ubuntu.com
http://pgp.mit.edu
http://pool.sks-keyservers.net ,

entering the key identifier, and then following the links to the public key that appears as a large text block that looks like this:

    Public Key Server -- Get "0x6ade786efe0a1f46 "

    -----BEGIN PGP PUBLIC KEY BLOCK-----
    Version: SKS 1.1.6
    Comment: Hostname: keyserver.ubuntu.com

    mQGNBFnufgsBDADblAgxb/kdWZgL1Kpos4AlYW5auzKFlEiCLMhFFDDT9n4LKnmqjtjWNGZc
    bcxi3JAoutV46/UnanCg1v0LP0LO+bbejMPNZxDD47c+DfEhrvcssL3BDssIXNr8q5YV3KgP
    ... many lines omitted ...
    d7USjbJfkZoPqtzrwp/iTfYVL5wS2xueMKtZUoLDhzf0PjZ9JBKaqz2fy7aTDZaFvsS264mc
    EwN/Bg==
    =FCid
    -----END PGP PUBLIC KEY BLOCK-----

Save that text page in a temporary file, say, /tmp/key.tmp, then load it into your personal keyrings like this:

    % pgp -ka /tmp/key.tmp
    Pretty Good Privacy(tm) Version 6.5.8
    (c) 1999 Network Associates Inc.
    Uses the RSAREF(tm) Toolkit, which is copyright RSA Data Security, Inc.
    Export of this software may be restricted by the U.S. government.

    Looking for new keys...
    RSA  3072/3072 0xFE0A1F46 2017/10/23 Nelson H. F. Beebe (MathCW 2016.10) <beebe@math.utah.edu>
    sig?           0xFE0A1F46             (Unknown signator, can't be checked)

    keyfile contains 1 new keys. Add these keys to keyring ? (Y/n) Y

    New userid: "Nelson H. F. Beebe (MathCW 2016.10) <beebe@math.utah.edu>".
    New signature from keyID 0xFE0A1F46 on userid Nelson H. F. Beebe (MathCW 2016.10) <beebe@math.utah.edu>

    Keyfile contains:
       1 new key(s)
       1 new signatures(s)
       1 new user ID(s)

    Summary of changes :

    New userid: "Nelson H. F. Beebe (MathCW 2016.10) <beebe@math.utah.edu>".
    New signature from keyID 0xFE0A1F46 on userid Nelson H. F. Beebe (MathCW 2016.10) <beebe@math.utah.edu>

    Added :
       1 new key(s)
       1 new signatures(s)
       1 new user ID(s)

    % gpg --import /tmp/key.tmp
    gpg: /home/jones/.gnupg/trustdb.gpg: trustdb created
    gpg: key FE0A1F46: public key "Nelson H. F. Beebe (MathCW 2016.10) <beebe@math.utah.edu>" imported
    gpg: Total number processed: 1
    gpg:               imported: 1  (RSA: 1)

    % gpg2 --import /tmp/key.tmp
    gpg: directory '/home/jones/.gnupg' created
    gpg: new configuration file '/home/jones/.gnupg/dirmngr.conf' created
    gpg: new configuration file '/home/jones/.gnupg/gpg.conf' created
    gpg: WARNING: options in '/home/jones/.gnupg' are not yet active during this run
    gpg: keybox '/home/jones/.gnupg/pubring.kbx' created
    gpg: /home/jones/.gnupg/trustdb.gpg: trustdb created
    gpg: key FE0A1F46: public key "Nelson H. F. Beebe (MathCW 2016.10) <beebe@math.utah.edu>" imported
    gpg: can't connect to the agent: IPC connect call failed
    gpg: Total number processed: 1
    gpg:               imported: 1

Now retry the signature verification, here using just the last one:

    % gpg2 x86_64-unknown-linux-gnu-gcc-7.2.0.tar.gz.sig
    gpg: assuming signed data in 'x86_64-unknown-linux-gnu-gcc-7.2.0.tar.gz'
    gpg: Signature made Wed 25 Oct 2017 06:24:00 PM MDT using RSA key ID FE0A1F46
    gpg: Good signature from "Nelson H. F. Beebe (MathCW 2016.10) <beebe@math.utah.edu>" [unknown]
    gpg: WARNING: This key is not certified with a trusted signature!
    gpg:          There is no indication that the signature belongs to the owner.
    Primary key fingerprint: B574 BCC7 210E 9A29 E810  C85B 6ADE 786E FE0A 1F46

The remaining warning reflects the problem of trusting trust (part of the title of Unix architect Ken Thompson's famous 1984 ACM Turing Award lecture): how does Shirley Jones know that Nelson Beebe's public key actually came from him? That problem is usually solved by meeting in person and exchanging public keys, or by getting keys from a certificate agency, as is commonly done for Web site signing keys. Here, we are likely to be satisfied with the Good signature … report.

If you have previously configured the GNU tools to know about one or more key servers (the keyserver lines in $HOME/.gnupg/gpg.conf), then you can avoid the Web browser step and intermediate file with a one-line retrieval command:

    % gpg --recv-keys 0xFE0A1F46
    gpg: requesting key FE0A1F46 from hkp server keys.gnupg.net
    gpg: /home/jones/.gnupg/trustdb.gpg: trustdb created
    gpg: key FE0A1F46: public key "Nelson H. F. Beebe (MathCW 2016.10) <beebe@math.utah.edu>" imported
    gpg: Total number processed: 1
    gpg:               imported: 1  (RSA: 1)

One of the commonest causes of signature-verification failure is corruption, or truncation, of downloaded files. Here is what happens when we have an intentionally truncated copy of the compiler distribution archive:

    % gpg2 /tmp/bad-x86_64-unknown-linux-gnu-gcc-7.2.0.tar.gz.sig
    gpg: assuming signed data in '/tmp/bad-x86_64-unknown-linux-gnu-gcc-7.2.0.tar.gz'
    gpg: Signature made Wed 25 Oct 2017 06:24:00 PM MDT using RSA key ID FE0A1F46
    gpg: BAD signature from "Nelson H. F. Beebe (MathCW 2016.10) <beebe@math.utah.edu>" [unknown]

Installing a compiler distribution on your system

Suppose that you have downloaded one compiler distribution from this Web site to a machine at your site. Here is how to install and use it:

That is all there is to it! The simple dgcc wrapper script makes it easy to compile and link programs in both binary and decimal floating-point arithmetic, and ensures that none of the installation details need be known anywhere else on your system. The fact that loader flags and a link-time library are specified is harmless when you are just doing test compilations with commands like dgcc -c myfile.c.

Compiler-build difficulties

Building the large gcc compiler family is a nontrivial exercise that this author has done several thousand times. A build on a single-core or single-CPU system can take many hours, and most builds eventually fail. On a 2016-vintage 16-core Intel or AMD processor, build time is about 45 minutes with a parallel make run. The Java component of gcc has frequently been a source of build failure on 64-bit systems, because Java is a 32-bit world, and there is often build confusion over which run-time libraries are needed.

Build failures are often traced to use of gcc-specific extensions in compiler source code, or use of newer language features introduced by national and international standards, notably ANSI, BSI, IEEE POSIX, and ISO. Consequently, a bootstrapping process is needed to move forward. The use of gcc extensions means that it is often impossible to use a non-gcc compiler, such as clang, opencc, pcc, IBM xlc, or Sun cc for the bootstrap. For example, in recent builds, vendor-provided gcc-4.1.2 compilers were able to build gcc-4.9.4, gcc-5.5.0, and gcc-6.4.0 compilers, but the newly created gcc-6.4.0 compilers were needed to build the gcc-7-*, gcc-8-*, and gcc-9-* compilers.

This author finds that limitation extremely frustrating: a compiler is, after all, just a filter that takes an input text file (source code), and produces an output text file (assembler-language code) that is translated by a separate program, the assembler, to a binary object file containing host machine instructions and data. A linker later combines object files and library code to create binary executable programs. There can be many different compilers on a given system, but only one assembler, and one linker, are needed. Thus, compilers should be written for extreme portability, such as defined by the 1990 ISO C Standard that all systems have supported for more than 35 years.

With the llvm and clang compiler family, the situation is much worse, because their code is written in bleeding-edge C++ that can only be compiled by rather recent C++ compilers. See this link for more on the build problems with that compiler family.

For compilation of software written in the Ada language, the situation is even worse, because from gcc-3.x (2002–) or gcc-4.x (2004–), part of the GNU Ada compiler is foolishly written in Ada itself, so there must already be an Ada compiler available. In the gcc-2.x (1993–) family, the Ada portion was entirely in C. Vendors with long experience have therefore been able to bootstrap forward to get Ada compilers for current gcc releases, but newer distributions would find that difficult, or impossible, because the old compilers are unlikely to be buildable on modern systems.

gcc package dependencies

Apart from required pre-installed C/C++ compilers and their standard header files, here are the main packages on which gcc builds often depend:

Package-naming conventions differ across operating systems and distribution channels. A developer package for a library includes both the library files, and the C header files that are needed to compile code that uses the library. Often, the suffix -devel is shorted to -dev.

In addition, the gcc build procedure often makes version-number checks for needed packages, and quits if packages are missing, or do not have the expected version numbers. In such cases, it is necessary to build local versions of the problem packages, and install them somewhere that a later build can find them, usually with the help of additional build options.

Here is how to find out what shared libraries are needed by all of the compilers:

    % find $L/ashare/gcc -type f -a -perm -111 | \
           xargs ldd | awk '{print $1}' | sort | uniq -c
    ...
    219 libc.so.7
     30 libgcc_s.so.1
     35 libgmp.so.10
      1 libgomp.so.1
    153 libiconv.so.2
     27 libisl.so.15
    183 libm.so.5
     35 libmpc.so.3
     35 libmpfr.so.4
      5 libquadmath.so.0
     15 libstdc++.so.6
     21 libthr.so.3
     30 libz.so.1
      1 libz.so.6

That example was from FreeBSD 11.1, but the same commands work on most systems. Apple Mac OS X (recently renamed macOS) lacks the ldd (list dynamic dependencies) utility to report the shared libraries used by an executable program, but we provide a local script of that name that runs the functionally similar command otool -L. The command pipeline finds all of the executables, sends that list to the xargs command that invokes ldd on that list, extracts the first word on each line, sorts the lines, and then reduces the list to just the unique lines, preceded by the number of times that each appeared.

Platform and filesystem-position-independence

For many years, gcc compilers have been able to run from any location in the filesystem, so they can be built at one site, and then transferred to another site and copied into any desired directory tree.

However, the newly compiled executable code and library code often contain symbols that identify the host environment, and the C library version. That means that it is frequently possible to use the compiler on other distributions, as long as they are at least as new as the build system. For example, the MathCW libmcw.so.0.0.0 library file built on a GNU/Linux system in late 2015 contains references to symbols GLIBC_2.14, GLIBC_2.2.5, and GLIBC_2.3, and further symbols identify the build compiler as GNU C 4.8.3 20140911.

Ideally, compilers should be built on the oldest available local system, because they are then likely to be usable on most newer operating-system releases.

One of the better known GNU/Linux distributions is that from Red Hat, which includes vendor support in return for an annual license fee. However, subsets of the commercial Red Hat distributions are also available in free distributions named CentOS, Oracle Linux, Scientific Linux, and others. Red Hat's bleeding-edge development channel is called Fedora. A disadvantage of many GNU/Linux distributions is that they evolve rapidly, and updates may be available only for a year or two. Red Hat's business model is to provide longer-term support for 10 to 14 years, as documented in an online encyclopedia article.

We therefore created 32-bit and 64-bit CentOS 5 systems to serve as gcc compiler build hosts, and the builds at this site for Fall 2017 and later were done on those systems, and have been demonstrated to run on many other GNU/Linux distributions. The CentOS 5 release is now past end-of-life, and no longer supported, and some of its libraries are too old for current compiler builds, so we have to provide our own replacements. We supply only static libraries (libgmp.a and so on), to avoid introducing dependencies on particular versions of shared libraries outside the compiler installation tree.

A sample build of decimal-enabled gcc

At our site, gcc builds are managed by a complex large script that takes care of unpacking a compiler distribution file, then creates and changes to a separate build directory, runs the top-level configure script with local platform-dependent options, and finally, runs make, usually in parallel mode. On completion, it examines and reports the compilers that were built, and whether the newly built libraries contain support for decimal arithmetic. It also gives commands needed to install the compilers on the local system. The script reports the commands that it executes, so there is a capturable log of how the job was done.

Here is a fragment from a build log of compilers on one of the CentOS 5 systems:

    # For C-shell family (csh and tcsh):
    set path=( /bin /usr/bin /sbin /usr/sbin )
    unsetenv CONFIG_SITE

    # For Bourne-shell family (sh, bash, ksh, mksh, zsh, ...):
    PATH=/bin:/usr/bin:/sbin:/usr/sbin ; export PATH
    unset CONFIG_SITE

    tar xf $G/gcc/gcc-7.2.0.tar.xz
    mkdir gcc-7.2.0-objdir
    cd gcc-7.2.0-objdir

    nice time env CC="$L/bin/gcc-6.4.0"                                             \
                  CXX="$L/bin/g++-6.4.0"                                            \
                  CFLAGS=""                                                         \
                  CPPFLAGS=""                                                       \
                  CXXFLAGS=""                                                       \
                  LDFLAGS="-L$L/lib64 -Wl,-rpath,$L/lib64"                          \
            ../gcc-7.2.0/configure                                                  \
                    --disable-nls                                                   \
                    --enable-decimal-float=dpd                                      \
                    --enable-languages=ada,brig,c,c++,fortran,go,lto,objc,obj-c++   \
                    --enable-multilib                                               \
                    --libdir=$L/ashare/gcc/gcc-7.2.0/lib64                          \
                    --prefix=$L/ashare/gcc/gcc-7.2.0                                \
                    --with-gmp-lib=$L/lib64                                         \
                    --with-gmp=$L                                                   \
                    --with-mpc-lib=$L/lib64                                         \
                    --with-mpc=$L                                                   \
                    --with-mpfr-lib=$L/lib64                                        \
                    --with-mpfr=$L                                              &&  \
            nice time $L/bin/gmake -j64

We first set the PATH variable to the minimal list of vendor-supplied directories, so as to eliminate dependence of the built compilers on other software at our site.

Our local configuration customizations for the GNU autoconf system are supplied in a file named by the value of the CONFIG_SITE variable. We hide those local settings by undefining that variable.

We unpack the compiler distribution archive, which was previously downloaded either from ftp://ftp.gnu.org/gnu/gcc/ for stable released versions, or ftp://gcc.gnu.org/pub/gcc/snapshots/ for current development versions. Then we create a separate build directory so that build attempts do not contaminate the just-unpacked source directory, and change to it.

The macro expansion $L shortens the input, and supplies our local convention for the installation tree prefix: the GNU convention for that prefix is /usr/local, but we no longer use that value, for reasons discussed elsewhere at this site. Similarly, $G is the root of the local GNU software package tree, under which there is a directory for each major GNU package.

The build compilers and their flags, and the linker flags, are set in the assignments of the variables CC through LDFLAGS. Here, in order to build this recent version, we need newer C and C++ compilers than the vendor-supplied ones, so we use those from the most recent of the next lower major versions in the assignments to CC and CXX.

The LDFLAGS variable supplies linker flags, and it often causes user confusion: the -L option gives the directory in which the linker should look for libraries at link time, when executables are created. The -Wl,-rpath, option usually supplies the same directory name, but that location is recorded inside the executable program for use by the program loader when the program is later run.

We turn off error-message translation ability with the --disable-nls option, because the default often fails due to confusion between locally installed libiconv packages, and recent C libraries that have absorbed the -liconv routines into -lc.

We choose the -enable-decimal-float=dpd option to get the decimal arithmetic flavor currently expected by the MathCW software. Please note that, although it should apply to all hardware and operating systems platforms for which gcc compilers can be built, that is not currently the case: the request is still ignored on far too many platforms. The wide availability of the MathCW library, and its associated book, should encourage all compiler teams to take up the challenge and make decimal floating-point arithmetic universally available in all C compilers, and eventually, in compilers for C++, Fortran, Go, Rust, and other languages as well.

Only a subset of compilers is chosen by default, but we want all of them, so we list them in the --enable-languages option.

Some 64-bit distributions have abandoned the 32-bit world, while others continue to support both. The --enable-multilib option selects the more general latter choice, and is of little consequence, except for some extra filesystem space, on 64-bit-only systems. Whenever possible, we build gcc with multilib support, so that user code can be compiled with either -m32 or -m64 options. The one effect that this has on end-user sites is that for 32-bit compilations, it is necessary to have the 32-bit C library and header files installed. Those packages have names like glibc.i686, glibc-devel.i686, and glibc-headers.i686 on Red Hat family systems. On OpenSUSE systems, they are called glibc-devel-32bit and glibc-utils-32bit. On Debian-family systems, including Ubuntu, libc6-dev:i386 suffices.

A typical build of one version of the full gcc compiler suite produces lots of things to be installed on the system: from 1500 to almost 6000 files, distributed in up to 175 subdirectories. They include version-specific header files and, especially for C++, shared libraries. It would produce calamitous clutter, and likely damage other packages, if the software were to be installed in the normal shared software directories. Thus, it is imperative to install it in its own unique directory tree, as selected by the --prefix option. The directory-path component ashare may be unique to our site: we use it to mean software that is dependent on a particular architecture and operating-system environment, but can nevertheless be shared via filesystem mounts, or filesystem replication, with other machines with the same environment. By contrast, the $L/share tree is used only for packages whose installed software is platform independent, such as the emacs text editor, and many scripting languages. Such trees can be shared across different operating systems and hardware.

Once the compiler has been installed, it is the directory tree specified by the --prefix variable that we bundle up into a single compressed archive with the GNU tar utility, and make those archives available in the directories listed at the top of this Web site.

We reported earlier that the multiple-precision libraries on CentOS 5 are too old for current gcc versions, so we supply the paths to our local installations of the latest static libraries in the --with-gmp-lib through --with-mpfr options.

That completes our documentation of the configure-time options for a build of gcc-7.2.0 on this 64-bit CentOS 5 system. That system has intentionally been kept a minimal one: it has no desktop environment, no X11 Window System, and no locally installed software, except for the multiple-precision libraries. The only vendor packages installed beyond the full GNU compiler suite are those needed by gcc builds.

The last step of the build job is the time-consuming one: && make -j64 says that, if the configure script succeeds, then the compilers should be built in parallel with up to 64 simultaneous compilation threads. That parallelism is critical, but each build experiment still takes nearly an hour of wall-clock time, and given the high failure rate on most platforms, many hours of human time are wasted by failing gcc builds.

About 14 to 17 million lines of text in from 75,000 to 100,000 source files are compiled, or read, in each build. For example, in gcc-6.4.0, the most recent release to still include Java, there are about 4.8 million lines of C code, 1.5 million lines of Java code, 1.4 million lines of Ada code, 1.1 million lines of C++ code, 520,000 lines of Go code, and almost 200,000 lines of Fortran code. Thus, most users are happy to be able to install compilers from their normal package distribution channels, or from a site like this, instead of having to build them directly from source code.

The filesystem space needed for builds is substantial, roughly 10GB for each gcc compiler release, as shown by these recent reports from the build directories:

    # 32-bit CentOS 5                       # 64-bit CentOS 5
    % du -sh gcc*                           % du -sh gcc*
    751M    gcc-4.9.4                       751M    gcc-4.9.4
    4.7G    gcc-4.9.4-objdir                3.4G    gcc-4.9.4-objdir

    804M    gcc-5.5.0                       804M    gcc-5.5.0
    6.5G    gcc-5.5.0-objdir                4.5G    gcc-5.5.0-objdir

    844M    gcc-6.4.0                       844M    gcc-6.4.0
    8.2G    gcc-6.4.0-objdir                5.5G    gcc-6.4.0-objdir

    695M    gcc-7.2.0                       695M    gcc-7.2.0
    8.9G    gcc-7.2.0-objdir                5.1G    gcc-7.2.0-objdir

    694M    gcc-8-20171022                  694M    gcc-8-20171022
    8.2G    gcc-8-20171022-objdir           6.1G    gcc-8-20171022-objdir

Installation space requirements are smaller:

# 64-bit CentOS 7
    631M    gcc-4.9.3       1.2G    gcc-7.4.0       1.8G    gcc-10.3.0
    494M    gcc-4.9.4       1.2G    gcc-7.5.0       1.8G    gcc-10.4.0
    1.1G    gcc-5.1.0       1.5G    gcc-8.1.0       3.5G    gcc-10.5.0
    1.0G    gcc-5.2.0       1.5G    gcc-8.2.0       1.9G    gcc-11.1.0
    1.0G    gcc-5.3.0       1.5G    gcc-8.3.0       1.8G    gcc-11.2.0
    793M    gcc-5.4.0       1.5G    gcc-8.4.0       1.8G    gcc-11.3.0
    861M    gcc-5.5.0       2.6G    gcc-8.5.0       1.8G    gcc-11.4.0
    1.1G    gcc-6.1.0       1.5G    gcc-9.1.0       1.9G    gcc-12.1.0
    1.1G    gcc-6.3.0       1.5G    gcc-9.2.0       2.0G    gcc-12.2.0
    1.2G    gcc-6.4.0       1.7G    gcc-9.3.0       2.0G    gcc-12.3.0
    1.0G    gcc-6.5.0       1.7G    gcc-9.4.0       2.3G    gcc-13.1.0
    1.2G    gcc-7.1.0       3.1G    gcc-9.5.0       2.3G    gcc-13.2.0
    1.2G    gcc-7.2.0       1.8G    gcc-10.1.0      5.3G    gcc-14-20240225
    1.2G    gcc-7.3.0       1.8G    gcc-10.2.0

Patching gcc for decimal-arithmetic support

The preceding section commented on the large size of the gcc compiler source trees, and you might wonder whether it is possible to modify the compiler source code to provide support for decimal floating-point arithmetic on your system, if the configure-time option --enable-decimal-float=dpd does not already do that.

The answer is perhaps, and you can do so with changes to only two lines of code!

The needed modifications are limited to one line each in just two files inside the gcc-x.y.z source tree: config/dfp.m4 and libgcc/config.host.

For Solaris systems, we need to patch a third file, gcc/config/sparc/sol2.h; however, it appears to be impossible to build any recent gcc compiler versions with decimal arithmetic on Solaris, so that patch location can be ignored for now.

The dfp.m4 file is an M4 macro file used by the configure script, and the relevant fragment from the roughly 60-line file looks like this:

    case $1 in
      powerpc*-*-linux* | i?86*-*-linux* | x86_64*-*-linux* | s390*-*-linux* | \
      i?86*-*-gnu* | \
      i?86*-*-mingw* | x86_64*-*-mingw* | \
      i?86*-*-cygwin* | x86_64*-*-cygwin*)
        enable_decimal_float=yes
        ;;

The selectors match the output of the config.guess script found in the top-level directory. On a FreeBSD 11.1 system, it reports x86_64-unknown-freebsd11.1. That value does not match any of the patterns in the case statement, so we just need to insert a new pattern line that looks like this:

      x86_64*-*-freebsd* | \

The config.host file is much larger — about 1300 lines — and thus seems more daunting to patch. It is a shell script that also has case statement selectors, and we need to find the pattern that matches our FreeBSD 11.1 build host. The fragment that needs modification looks like this:

    x86_64-*-freebsd*)
            tmake_file="${tmake_file} i386/t-freebsd i386/t-crtstuff"

We just need to add t-dfprules to the assignment, like this:

    x86_64-*-freebsd*)
            tmake_file="${tmake_file} i386/t-freebsd i386/t-crtstuff t-dfprules"

It is expected that similar changes can be made in other gcc compiler releases, although the precise appearance of the changed sections may differ slightly. The best way to deal with that is to preserve the original files to be changed, by making a copy with an additional suffix .org, and then using the diff utility to produce context differences between the original and modified files:

    % diff -c3 config/dfp.m4.org           config/dfp.m4               > $G/gcc/gcc-4.9.4.patch.1
    % diff -c3 libgcc/config.host.org      libgcc/config.host          > $G/gcc/gcc-4.9.4.patch.2
    % diff -c3 gcc/config/sparc/sol2.h.org gcc/config/sparc/sol2.h.org > $G/gcc/gcc-4.9.4.patch.3

We saved the difference listings in our global distribution source tree for gcc. On another system, we can unbundle the original compiler distribution, and apply our patches, like this:

    % tar xf $G/gcc/gcc-4.9.4.tar.gz
    % cd gcc-4.9.4
    % patch -p0 < $G/gcc/gcc-4.9.4.patch.1
    % patch -p0 < $G/gcc/gcc-4.9.4.patch.2
    % patch -p0 < $G/gcc/gcc-4.9.4.patch.3

The prefix gcc-x.y.z/ is omitted from the patch files, because it is likely that the same patch files can be applied without change to future gcc-4.9.5, gcc-4.9.6, gcc-4.9.7, … releases. They can also be a guide for patching other major releases of the gcc compiler family.

In practice, for large sites like ours, there may be similar changes made for other platforms, and we can then either make additional patch files for each system, or else copy the patched tree from one system to another, patch again (being careful to preserve the original *.org files), and make new combined patch files.

To allow you to apply our patches and attempt to rebuild compilers at your site, our distribution directories in the links at the top of this Web site contain both installation trees, and patch files, such as *-gcc-x.y.z.tar.gz and gcc-x.y.z.patch.*. There may also be gcc-x.y.z.recipes files that record the commands issued to do the build on patched source trees.

Managing multiple compiler versions

Casual users of a programming language are often content to have just a single compiler, but serious software developers know that is far from adequate.

As we reported earlier, modern multi-language, multi-platform, compilers are extraordinarily complex, and large, software projects. Thus, if you find that your own code does not compile, link, and run properly, there is a reasonable chance that your compiler may be at fault, because it is probably far larger than your programs.

The quickest check that you can make is to test your code with a different compiler. If the behavior does not change, the fault is likely in your code. However, if your code works properly with a second compiler, then the fault might lie with the first compiler. You should therefore try yet another compiler, so as to get a ‘majority opinion’ that suggests where the problem lies.

There are many ways that software can fail, including outright coding blunders, use of uninitialized storage, errant pointers, out-of-bounds array indexes, byte-order storage dependence, and correctness and robustness of external libraries. Much software contains insidious assumptions and erroneous beliefs about the behavior of computer hardware, especially in number representation, precision, and range, as well as in exception handling. In addition, for any programming language suitable for large software projects, there are always dark corners of the language, where behavior is not clearly specified by language definitions or standards, or worse, behavior is declared to be implementation dependent.

Sadly, with the commercial success of Intel, Apple, and Microsoft, especially for desktop and laptop computers, the hardware world has become much more monolithic than it was in the past. We know from biology and human culture that diversity is a key to success and survival, and loss of diversity makes computers much more vulnerable to failure, as we saw with the infamous Intel Pentium CPU divide flaw in the 1990s, and we continue to see with the increasing number of attacks against computer systems, computer software, and communication networks. The Meltdown and Spectre flaws that were first reported to the public in early 2018 affect numerous CPU models and architectures produced over the last 25 years, and are difficult to completely protect against, although operating systems vendors are working hard to reduce the security risks.

Users at our large academic site develop a lot of software, and it has been important for us to offer them a large and growing selection of compilers and programming languages. If they are to be convenient to use, compiler names must usually carry version information, so that users do not need to modify shell search paths just to change compilers.

Our reasonable solution has been to preserve older versions of compilers, with symbolic links used to make shorter names available:

    % cd $L/bin

    % file gcc-5*
    ...
    gcc-5:                 symbolic link to gcc-5.5
    gcc-5.5:               symbolic link to gcc-5.5.0
    gcc-5.5.0:             POSIX shell script, ASCII text executable
    ...

    % file gcc-8*
    gcc-8:          symbolic link to gcc-8.0
    gcc-8-20171008: POSIX shell script, ASCII text executable
    gcc-8.0:        symbolic link to gcc-8.0.0
    gcc-8.0.0:      symbolic link to gcc-8-20171008

That particular system also has many earlier gcc-x.y.z and gcc-x-YYYYMMDD versions available, but the shortest name for any major version normally refers to the latest available one.

Maintaining those links manually for each programming language is tedious and error prone, so we hide the complexity in a shell script that is run like this:

    % cd $L/bin

    % env VER1=5 VER2=5.5 VER3=5.5.0 $G/gcc/make-gcc-links.sh gcc-5.5.0

Another local shell script creates symbolic links from the compiler installation tree to the single common $L/bin directory that everyone has in the shell search path:

    % cd $L/bin

    % $G/gcc/make-gcc-wrapper.sh gcc-5.5.0
    lrwxrwxrwx 1 sysmgr sysmgr  41 Oct 22 15:45 gcov-5.5.0 -> $L/ashare/gcc/gcc-5.5.0/bin/gcov
    -rwxrwxr-x 1 sysmgr sysmgr 138 Oct 28 13:56 gcc-5.5.0
    -rwxrwxr-x 1 sysmgr sysmgr 138 Oct 28 13:56 g++-5.5.0
    -rwxrwxr-x 1 sysmgr sysmgr 140 Oct 28 13:56 gccgo-5.5.0
    -rwxrwxr-x 1 sysmgr sysmgr 138 Oct 28 13:56 gcj-5.5.0
    -rwxrwxr-x 1 sysmgr sysmgr 143 Oct 28 13:56 gfortran-5.5.0
    -rwxrwxr-x 1 sysmgr sysmgr 139 Oct 28 13:56 gnat-5.5.0
    -rwxrwxr-x 1 sysmgr sysmgr 143 Oct 28 13:56 gnatbind-5.5.0
    -rwxrwxr-x 1 sysmgr sysmgr 143 Oct 28 13:56 gnatmake-5.5.0

The script creates links for every installed compiler from the specified version, skipping any that do not exist for that particular installation.

Having compilers hidden inside suitably named shell scripts is convenient for users, and allows managers to customize the scripts for local needs, such as we did with the suggested private dgcc script that supplied additional compiler and linker flags.

Both make-gcc-*.sh scripts are available from links in the directory at the top of this Web site. Please remember that they might well need small tweaks to customize them for your own site conventions.

Sharing compilers across similar systems

Our test laboratory contains a growing number of physical machines of diverse architectures, and numerous virtual machines (VMs) for the x86_64 architecture on VMware ESX, or on QEMU KVM. Because VMs are easy to create and need modest resources, we add new ones from time to time.

When a new major operating-system release is announced that we wish to add to our laboratory, we just create a new VM for it, add user accounts, configure it with a substantial set of desired packages, and then, to save software installation work, we copy over our local directory tree from the previous release of that operating system. In most cases, the copied software works as expected, but sometimes, notably in the OpenBSD family, we find that we have to rebuild most, or all, of it from scratch.

Because building compilers is difficult, and time consuming, we prefer to share builds across similar platforms, such as those in the list of GNU/Linux distributions given later in the section Portability of the pre-built compiler distributions. One way to do so is just to copy the $prefix/ashare/gcc tree to each compatible machine, and create symlinks for the compiler names in $prefix/bin. However, that requires about 2GB of extra filesystem space for each compiler version.

We therefore created a minimally configured Network File System (NFS) server machine whose sole job it is to export filesystems to clients. Before those filesystems are added to the server, the filesystem space requirements are, by modern standards, tiny: about 1GB!

On that CentOS 7 server, we installed the nfs-utils package that provides the NFS daemon and the exportfs tool that controls what filesystems are exported, and to which machines. Here is a sample control file for that program, and the command that updates the list of available filesystems:

    # cat /etc/exports
    /export/your-server-name-here/x86/linux/a         10.9.8.0/24(ro)
    /export/your-server-name-here/x86_64/linux/a      10.9.8.0/24(ro)
    /export/your-server-name-here/x86_64/dragonflybsd 10.9.8.0/24(ro)
    /export/your-server-name-here/x86_64/freebsd      10.9.8.0/24(ro)

    # exportfs -a

Putting the server name in the mount path proves convenient for client-machine managers, and for error reporting. For example, if your domain is research.example.com, your first NFS server machine might be named nfs-1.research.example.com, The paths would then begin /export/nfs-1/, followed by a short CPU architecture name, an operating-system family name, and possibly, a version number or name. Because there are so many different GNU/Linux distributions, we anticipated the need for multiple incompatible versions, to be named a, b, c, ….

The second field on each line of the exports file can be a client hostname, or more usefully in a local environment, a range of allowed-client IP addresses. There are three blocks of IP space that are reserved for private use, and are thus not routed, or visible, across the Internet. The largest block contains 16,777,216 addresses of the form 10.x.y.z. Here, we permit clients with addresses from 10.9.8.0 to 10.9.8.255 to mount the specified filesystems. The trailing /24 says that the top 24 bits are fixed, leaving 8 bits for 256 private local addresses.

The first address, 10.9.8.0, is reserved for the network address, and the second, 10.9.8.1, is usually the address of the gateway machine to which the private network is attached. The last, 10.9.8.255, is reserved for broadcasts, leaving 253 assignable addresses, some of which are for machines that supply network services, such as NFS (Network File System), DNS (Domain Name System), and NTP (Network Time Protocol). The latter allows all machines on the private network to have consistent clocks, which is critical for tools like make that use file timestamps to influence their actions.

On a client machine, we may need to install packages named something like nfs-client and rpcbind in order to be able to mount remote NFS filesystems. We then create the needed local mount points, add a few lines to the system mount table, and mount all filesystems, as in this example for a FreeBSD family member:

    % mkdir our-prefix/{dec,gcc,hoc,mcw}

    % tail -n4 /etc/fstab
    remote-name:/export/remote-name/x86_64/freebsd/11/gcc our-prefix/gcc nfs bg,intr,ro,soft 0 0
    remote-name:/export/remote-name/x86_64/freebsd/11/mcw our-prefix/mcw nfs bg,intr,ro,soft 0 0
    remote-name:/export/remote-name/x86_64/freebsd/11/hoc our-prefix/hoc nfs bg,intr,ro,soft 0 0
    remote-name:/export/remote-name/x86_64/freebsd/11/dec our-prefix/dec nfs bg,intr,ro,soft 0 0

    % sudo mount -a

The comma-separated options in the fourth field of /etc/fstab provide resilience against remote server disappearance or sluggishness: the mount is done in the background (bg) to avoid boot-time delay, is interruptible (intr), is read-only (ro), and can fail to deliver data in the future (soft). The read-only choice is desirable both for security (clients cannot modify data on the server), and for performance (file access times need not be updated). On local networks, NFS data-delivery failures are rare, so permitting errors in mounts and reads is unlikely to ever be noticed by users. NFS provides many other options to improve robustness, but we do not need them at our site.

The corresponding /etc/fstab file entries on a modern GNU/Linux system are almost identical: only the remote path and options change, the latter to something like bg,nofail,ro.

On a 2014-vintage system running Ubuntu 14, we had to add one more option to the fourth-field list: vers=3; without it, mounts would fail with a cryptic log message RPC: AUTH_GSS upcall failed.

On Sun/Oracle Solaris systems, or any other member of the Solaris family (Dilos, Dyson, Hipster, illumian, OmniOS, OpenIndiana, Tribblix, XStreamOS, …), mount relations are stored instead in /etc/vfstab, and have a slightly different field layout:

    % mkdir our-prefix/{dec,gcc,hoc,mcw}

    % tail -n4 /etc/vfstab
    remote-name:/export/remote-name/x86_64/solaris/11/gcc - our-prefix/gcc nfs - yes bg,intr,ro,soft
    remote-name:/export/remote-name/x86_64/solaris/11/mcw - our-prefix/mcw nfs - yes bg,intr,ro,soft
    remote-name:/export/remote-name/x86_64/solaris/11/hoc - our-prefix/hoc nfs - yes bg,intr,ro,soft
    remote-name:/export/remote-name/x86_64/solaris/11/dec - our-prefix/dec nfs - yes bg,intr,ro,soft

    % sudo mount -a

To avoid exposing names of mounted directories to users on the client, we then create names for the compiler executables with the make-gcc-*.sh scripts described earlier.

We can do something similar for other executables in the remote directories:

    % cat our-prefix/bin/hoc.sh
    #! /bin/sh -
    LD_LIBRARY_PATH=our-prefix/mcw/lib
    export LD_LIBRARY_PATH
    our-prefix/hoc/bin/`basename $0` "$@"

    % cd our-prefix/bin
    % ln -s hoc.sh hoc32
    % ln -s hoc.sh hoc64
    ...
    % ln -s hoc.sh hocd128

When you have multiple client machines, it is a great convenience to provide locally installed software, and user home directories, via NFS mounts. We have done so for decades at our large academic site. However, as machines have grown in filesystem capacity, we have often replaced NFS mounts of software by nightly mirrors from master machines, reducing daily network traffic, and providing faster response for users. The only drawback of mirroring is that a software update made on a server may not be available to clients for several hours, but that delay is often unimportant, except for security patches, or some bug fixes. As I/O performance increases, the mirroring can be done more frequently.

Portability of the pre-built compiler distributions

Each compiler installation tree needs about 2GB of filesystem space, and we currently supply compilers for the latest releases of eleven major versions of the gcc family. Our test laboratory has about 800 different systems, of which about half are flavors of GNU/Linux. To avoid copying compiler trees into each machine, we have instead created a minimal fileserver whose sole job is to provide network-mountable filesystems that all of the machines can access.

We have found that gcc compilers built on CentOS 5 are usable on at least these GNU/Linux distributions:

However, there is currently a stumbling block with some of the latest GNU/Linux distributions, including ArchLinux (rolling release), Fedora (26, 27, and Rawhide), Kubuntu (17.10), Manjaro, OpenMandriva Lx (3.0), OpenSUSE Tumbleweed (rolling release), Ubuntu (17.10), and Xubuntu (17.10). Compilations with all five latest versions of gcc fail due to undefined symbols in system header files. The simple solution appears to be to do separate builds of the five compiler versions, but so far, despite multiple attempts on multiple platforms, we have been unable to build gcc from source code on those systems. Fortunately, the Devuan compiler builds can be used on those recent systems.

Note added later: After several system updates on Ubuntu 17.10, the problems appear to have been partially fixed, and gcc family versions 5, 6, 7, 8, and 9 now build successfully.

Similarly, on FreeBSD 11.1 on x86_64, a build of the MathCW library and multiple variants of hoc could be used on FreeBSD 10.3 and 10.4, and also on recent versions of FuryBSD, GhostBSD, HardenedBSD, MidnightBSD, NomadBSD, and PacBSD, although sometimes we needed to install additional libraries. They do not work on DesktopBSD, DragonFlyBSD, LibertyBSD, NetBSD, OpenBSD, PCBSD, or TrueOS.

On TrueOS, we have machines set to the bleeding-edge unstable software update channel, and others to the default master channel. At present, the two channels require separate NFS mount points on the distribution fileserver. In the future, we may just do builds on the more stable channel, provided that they work on both channels.

Simplifying builds of decimal-enabled gcc

The sample invocation of the configure script shown earlier is complex, and it makes sense to hide the complexity for most systems in a shell script that can often be invoked with one line. The script takes care of finding and unpacking a compiler distribution and applying any associated patches, provides a PATH value suited to the current system, invokes configure and make, the latter with a -jNN parallel-build option automatically adjusted for the build host, and finally, reports the status of the build, including counts of how many decimal functions are found in the created compiler libraries, -lgcc. In a successful build, there are currently 269 such functions. If the counts are reported as zero, then the patches to enable decimal arithmetic have either not been applied, or have not made all of the needed changes.

Because of the dependence of the build on many different software tools, some of which must be GNU versions, the script needs to be customizable through build-time setting of variables. The script tries to locate the tools on the local system, and reports its findings in the output log. However, the bootstrap compilers, and target languages, usually need to be under user control, and cannot always be determined correctly on every platform.

Here is a sample invocation on a TrueOS system:

    % set path=( /usr/local/bin /bin /usr/bin )

    % env BUILDPATH=$PATH                         \
          CC=gcc6                                 \
          CXX=g++6                                \
          GMPPREFIX=$L/gmp                        \
          LANGS=c,c++,fortran,go,lto,objc,obj-c++ \
          prefix=$L                               \
          $G/gcc/build-dgcc.sh gcc-7.2.0

The PATH begins with the target directory of the TrueOS package system.

The BUILDPATH variable supplies a search path that overrides the internal choice: as builds become more successful, that forced path should become the internal default, and then can be omitted.

We choose version 6 GNU compilers, which are needed to build versions 7 and 8. The native C compiler on TrueOS is /bin/cc, which is linked to clang version 5.0.0 in late 2017. That compiler is unable to build gcc-4.9.4 because of the use of GNU C language extensions. However, the native compiler is able to build gcc versions 5.5.0, 6.4.0, 7.2.0, and 8-20171105.

The prefix variable is mandatory, and names the default root of locally installed software.

In order to produce distributable compilers that do not depend on particular versions of shared libraries, the GMPPREFIX variable names a locally created tree with only header files and static libraries:

    % ( cd $L/gmp && ls -R )
    .:
    include  lib

    ./include:
    gmp.h  mpc.h  mpfr.h

    ./lib:
    libgmp.a  libmpc.a  libmpfr.a

On the sample system, the first directory in the PATH is the location of vendor-supplied packages, among them, the recent gcc-x.y.z and g++-x.y.z compilers needed to build the particular compiler release. Early output of the build reports the tool locations that were found automatically:

    INFO: GNU utilities found:
    INFO: DF        = /usr/local/bin/gdf
    INFO: DIFF      = /usr/local/bin/gdiff
    INFO: GREP      = /usr/local/bin/grep
    INFO: MAKE      = /usr/local/bin/gmake
    INFO: PATCH     = /usr/local/bin/gpatch
    INFO: SED       = /usr/local/bin/gsed
    INFO: TAR       = /usr/local/bin/gtar
    INFO: TIME      = /usr/bin/time

It is expected that, once a few more compiler versions have been successfully built on a particular platform, the build recipe can be shortened to just one of these:

    % env LANGS=c,c++,fortran,go,lto,objc,obj-c++ prefix=$L $G/gcc/build-dgcc.sh gcc-7.2.0
    % env prefix=$L $G/gcc/build-dgcc.sh gcc-7.2.0

Another modest shell script can then be written and run as a weekly cron job to fetch compiler development snapshots, attempt to build them automatically, install them if successful, and e-mail a status report to the local compiler maintainer.

The success rate for Go language compilers is mixed. On GNU/Linux systems, they usually build flawlessly. On some other operating systems, builds may report compilation errors in the Go portion of the compilers. We usually include go in the initial LANGS list, and then if there are errors, remove it from the list, delete the object directory, and redo the build.

Here is the build command for an early 2024 gcc-14 snapshot release that works on CentOS 7, and on Ubuntu 20, 22, and 24:

    % set path=( /usr/local/bin /bin /usr/bin )

    % set path=( /usr/local/bin /bin /usr/bin )

    % setenv LD_LIBRARY_PATH $L/ashare/gcc/gcc-13.2.0/lib64:

    % env                                                       \
        CC=$B/gcc-13                                            \
        CFLAGS=-I$L/gmp/include                                 \
        CXX=$B/g++-13                                           \
        CXXFLAGS=-I$L/gmp/include                               \
        GDC=$B/gdc-13                                           \
        GMPPREFIX=$L/gmp                                        \
        GNAT=$B/gnat-13                                         \
        GNATBIND=$B/gnatbind-13                                 \
        GNATMAKE=$B/gnatmake-13                                 \
        LANGS='ada,c,c++,d,fortran,go,lto,m2,objc,obj-c++,rust' \
        LDFLAGS="-Wl,-rpath,$L/gmp/lib -L$L/gmp/lib"            \
        MAKE=$L/bin/make                                        \
        prefix=$L                                               \
        $G/gcc/build-dgcc.sh                                    \
        gcc-14-20240225

Platform notes

This final section contains remarks about the platforms for which builds of gcc compilers with support for decimal arithmetic have been attempted at the developer's site at Utah.

Sun/Oracle Solaris

Solaris, and its predecessor, SunOS, was the operating system of most of our Sun computers from 1987 to 2010, when the sale of Sun Microsystems to Oracle Corporation was completed. The MathCW developer's Sun workstations included MC68020 and SPARC CPUs, and our central fileservers also used those CPUs until 2011, when we added servers with x86-64 processors.

Despite numerous attempts, it has so far proved impossible to compile gcc with support for decimal floating-point arithmetic on either SPARC or x86-64 Solaris systems. Compilation failures on SPARC processors suggest that the gcc decimal code does not support the SPARC big-endian architecture. However, in general, it has rarely been possible to build any gcc release on Solaris, because of system header file conflicts, or compiler code-generation errors, or passing invalid flags to assemblers and linkers. That situation has improved somewhat with the release of Oracle Solaris 11.3 in Fall 2017, but even on x86-64 CPUs, decimal gcc compiler builds have yet to succeed on any Solaris system.

GNU/Linux CentOS and Red Hat

Our site has used Red Hat and CentOS distributions of GNU/Linux on desktops and servers since about 2011 when competitive bidding forced us to leave behind 24 years of use of Sun/Oracle hardware and move to x86-64 CPUs on hardware from IBM, HP, Dell, Supermicro, and others.

Red Hat Enterprise Linux provides long-term support and stability, typically for 8 to 10 years. While that is important for production and service environments, it also means that the vendor's software offerings are several years behind current open-source development. Consequently, we have made substantial efforts to provide our users with thousands of additional programs in much more recent versions. Key to that work has been having recent compilers, because, sadly, too many developers seem to feel the need to exploit bleeding-edge features of programming languages and libraries, instead of emphasizing maximal portability of their code.

Despite the age of the base system software, we have routinely been able to build decimal-enabled gcc compilers for versions 4 through 14, and most of the development work of the MathCW library was done with those compilers. However, the nondecimal parts of the library have also been built and tested with numerous compilers on many other operating systems and CPU architectures.

GNU/Linux Devuan and GNUinos

These two systems are recent offshoots of the long-term Debian project (1993–date). They reject the huge complex systemd facility for startup and process management in favor of the simpler traditional approach of independent shell scripts for process startup and shutdown.

This author hoped that the CentOS 5 compiler builds would be usable on Devuan and GNUinos: they run, but fail to compile user code because of missing header files that do not appear to be in the package system. Consequently, several decimal-enabled gcc compilers are provided for them from links at the top of this Web site. The 64-bit Devuan build system is on the ascii/ceres development channel, and the 32-bit GNUinos system is on the jessie channel. Those are the latest versions available in Fall 2017.

The Devuan builds on x86_64 can be used on those recent GNU/Linux systems for which gcc builds currently fail (at least ArchLinux (rolling release), Fedora (26, 27, and Rawhide), Kubuntu (17.10), Manjaro, OpenMandriva Lx (3.0), OpenSUSE Tumbleweed (rolling release), Ubuntu (17.10), and Xubuntu (17.10)).

GNU Hurd

Hurd is a long-running effort to develop a Mach-based kernel for GNU software. It is available only for the Intel x86 architecture, supports only IDE disks, and provides only the slow EXT2 filesystem. The latter has proved fragile and unreliable: almost every reboot of the system requires a filesystem consistency check before normal operations can resume. Several of those events have been unrecoverable, requiring a rollback to a previous stable version of the filesystem.

Attempts to install a minimal set of compilers with the commands

    % export PATH=$B:/bin:/usr/bin:/sbin:/usr/sbin
    % env CONFIGUREFLAGS=--disable-multilib LANGS=c,c++,fortran prefix=$L $G/gcc/build-dgcc.sh gcc-x.y.z

fail with a complaint The directory that should contain system headers does not exist: /include. It is unclear what directory that is, or what could be done to repair the problem. The same failure afflicts gcc versions 4, 5, and 7. Version 6.4.0 fails with an unterminated-comment error in gcc/auto-profile.c.

DragonFlyBSD

The DragonFlyBSD project forked from FreeBSD 4.8 in 2003 and continues as an independent, and no-longer binary compatible, system that is built on top of the Hammer-1 and Hammer-2 filesystems that provide high performance, advanced management, reliability, and file version history. The only supported CPU family in DragonFlyBSD is x86-64.

We have virtual machines running DragonFlyBSD version 3.8 through the latest version 6.4 but decimal-enabled gcc compilers have been built only on DragonFlyBSD 4.6 and later. As with the GNU/Linux and FreeBSD systems on x86-64, compiler builds have been reasonably straightforward for gcc versions 5 through 8. The gcc-4.9.4 compilers will not build at all on DragonFlyBSD, because that system is not recognized by the GNU autoconf files in that compiler release.

DragonFlyBSD development is rapid, and the master site generally offers software packages only for the most recent four even-numbered versions (5.8, 6.0, 6.2, and 6.4 at the time of writing this). There do not appear to be standard repositories for older versions, so DragonFlyBSD users have to live with frequent major O/S updates if they expect to install prebuilt packages in the future.

However, Web searches for strings like "dragonfly:3.8:x86:64" seem to be able to find still-existing mirrors of earlier, and now unsupported, DragonFlyBSD package repositories.

FreeBSD family

FreeBSD was the main development project that came out of the University of California, Berkeley, work on what was known during the 1980s as BSD (Berkeley Standard Distribution) Unix. That version was popular among academic sites because it supported virtual memory before the Bell Labs System III and System V alternatives did, and it ran on the DEC PDP-11 and VAX minicomputers that were affordable in research groups and university departments.

FreeBSD has many descendants, including the popular NetBSD and OpenBSD systems that have diverged enough from FreeBSD to have lost binary code portability. However, DesktopBSD, FreeNAS, GhostBSD, HardenedBSD, MidnightBSD, PacBSD, PC-BSD, and TrueOS are sufficiently similar that there is at least some portability of prebuilt software. We run systems with all of those, and the MathCW developer's home environment uses two GNU/Linux distributions (Fedora and Ubuntu) and TrueOS. The latter provides a rolling-release model of the latest FreeBSD work on top of the superb ZFS filesystem.

FreeBSD builds of decimal-enabled gcc compilers have been reasonably successful, and the links at the top of this Web site lead to both 32-bit and 64-bit distributions for compiler versions 4 through 8.

Because TrueOS is generally ahead of standard FreeBSD releases, we provide x86-64 distributions for compiler versions 4 through 8, in two different flavors: the stable master TrueOS development channel, and the more active unstable channel.

NetBSD

The NetBSD project began in 1993 as a fork of 386BSD at Berkeley, and is the BSD family member that supports the largest number of CPU types.

The native /usr/bin/gcc compiler is version 4.8.4, which is too old to compile versions 7 and 8, but the package system supplies a version 6.4.0 compiler in /usr/pkg/gcc6/bin/cc.

A few attempts to build decimal-enabled gcc compilers have been made on NetBSD 7.0 and 7.1 x86-64, but they all fail because of conflicts with system C++ header files, even with a reduced set of compilers set by LANGS=c,fortran. That happens with either gcc or clang as the bootstrap compiler.

On NetBSD 6.1.5, gcc-4.9.4 fails to build, complaining Unknown architecture.

OpenBSD

The OpenBSD project began in 1996 as a fork of NetBSD, and its primary design goal is maximal security of open-source software. One of its most widely used contributions is the OpenSSH package for secure inter-computer communication and file transfer. Like NetBSD, it supports a large number of CPU types.

While many operating systems support a certain degree of upward code portability, so that code compiled on major version n continues to run on version n + 1, this author's experience is that often does not hold on OpenBSD, even for minor releases. There, binary code from version m.n may not work on version m.(n + 1), but such software can usually be easily rebuilt from source code.

Version dependence on OpenBSD requires a larger effort to provide decimal-enabled gcc compilers.

On OpenBSD 6.2 (latest release in Fall 2017), compilations of gcc-8-20171119 fail with internal segment faults in the newly generated compiler components. For gcc-7.2.0, the stage1 compiler is unable to compile, and the build terminates.

Initial compilation attempts found the build complaining that compilation must be restarted with the position-independent code option, -fPIC. Subsequent builds therefore used CC='gcc -fPIC' and CXX='g++ -fPIC', after an initial attempt to supply that option in CFLAGS and CXXFLAGS failed.

With two different bootstrap compilers, the latest releases of gcc version 4 through 8 fail to build on OpenBSD 6.2. Efforts are now in progress on OpenBSD 6.1 … stay tuned!

Apple Mac OS X and macOS

Recent builds of decimal-enabled gcc compilers have been done on a server running Mac OS X 10.11.6 (code named El Capitan). Since then, Apple has released 10.12 (Sierra) and 10.13 (High Sierra), and changed the O/S name to macOS. Compilers and libraries from the Utah builds should work fine on later O/S releases.

About 2010, Apple made two significant changes that impact software development: the default compiler memory model went from -m32 to -m64, and the default C/C++ compilers were changed from gcc to clang. Regrettably, Apple chose to continue to supply /usr/bin/gcc, but it is only a wrapper that ultimately calls clang, after defining several preprocessor symbols that make it appear that the compiler is gcc. However, emulation of gcc is incomplete, and there are other preprocessor symbols, and numerous compiler options, that are known to a real gcc compiler, but not to clang. That serious misfeatures breaks some software builds.

The gcc compilers supplied via links from the top of this Web site have no clang content whatever, and are built from standard GNU releases. The older builds are for the 32-bit model, whereas the newer ones are for the 64-bit model. The bootstrap builds are with the native wrapped clang compilers.

Apple no longer even supplies C and C++ compilers in its standard O/S distributions: you have to first register as an “Apple developer” to get access to downloadable compilers and associated tools. That means that most Mac users probably do not have compilers, and their associated header files, on their personal systems.

During testing, we found that two available assemblers were incompatible:

    % /usr/bin/as -v
    Apple LLVM version 8.0.0 (clang-800.0.42.1)
    …

    % /opt/local/bin/as -v
    Apple Inc version cctools-895, GNU assembler version 1.38
    …

The second of those is from the popular MacPorts system that provides a lot of additional prebuilt software that is unavailable from Apple.

The incompatibility in the assemblers is that the MacPorts version does not recognize memory-model flags. Thus, if you have both on your system, you need to adjust your PATH variable to ensure that /usr/bin precedes /opt/local/bin. That infelicity could easily be hidden by setting PATH in the wrapper scripts created by make-gcc-wrapper.sh, and we may do so in the future.

Microsoft Windows 10

Not yet attempted. Either Cygwin or Ubuntu-on-Windows may provide a route to decimal-enabled gcc compilers. The gcc build procedure is far too complex to easily adapt to non-Unix systems, or systems that lack the GNU tool suite.