Wednesday, October 16, 2024

Building GCC compilers for SPARC Solaris

In this article I would like to share some ideas on how to build C, C++ and Ada compilers for SPARC Solaris.

To build GCC compilers we need a bootstrap compiler with which to build. It may be possible to use for example, x86 Linux GCC host and then cross compile for SPARC Solaris target. However, this article assumes there is a native SPARC Solaris GCC compiler, which is then used to build a new version of a native GCC compiler. If the bootstrap GCC compiler does not support Ada programming language, then exclude it from GCC configure --enable-languages list.

GCC needs binutils (assembler, linker, loader, etc) programs in order to work correctly. There are two types of binutils for Solaris: Sun original binutils and GNU binutils. GCC can use either of them, however it is not able to switch between them dynamically, hence GCC needs to be configured and built separately for each type of binutils. This article describes both versions, just in case.


1. Create build directories

First we create build directories for downloaded packages, source files and object files.

BUILD_ROOT="/opt/gcc_build" &&
TAR_DIR="${BUILD_ROOT:?}/tar" &&
SRC_DIR="${BUILD_ROOT:?}/src" &&
OBJ_DIR="${BUILD_ROOT:?}/obj"
mkdir -p ${TAR_DIR:?} ${SRC_DIR:?} ${OBJ_DIR:?}

BUILD_ROOT is set to /opt/gcc_build.
TAR_DIR
is set to /opt/gcc_build/tar, downloaded packages are stored here.
SRC_DIR is set to /opt/gcc_build/src, source files are unpacked here.
OBJ_DIR is set to /opt/gcc_build/obj, object files are stored here.


2. Download and unpack packages

These versions of packages are known to build on Solaris. Later versions may introduce various Linuxisms, thus causing breakage.

DEVUTILS_PREFIX=/opt/gcc_build_tools &&
PATH="${DEVUTILS_PREFIX:?}/bin:/usr/bin:/usr/sbin" &&
export PATH &&
\
GCC_VER="13.3.0" &&
MAKE_VER="4.4" &&
TAR_VER="1.35" &&
PATCH_VER="2.7.6" &&
COREUTILS_VER="9.4" &&
BINUTILS_VER="2.43" &&
OPENSSL_VER="3.3.1" &&
WGET_VER="1.24.5" &&
cd ${TAR_DIR:?} && WGET_OPT="--no-check-certificate" &&
\
# These packages are needed for building GCC. Stock binaries may be too old on some versions of Solaris \
wget ${WGET_OPT:?} https://ftp.gnu.org/gnu/gcc/gcc-${GCC_VER:?}/gcc-${GCC_VER:?}.tar.gz &&
wget ${WGET_OPT:?} https://ftp.gnu.org/gnu/make/make-${MAKE_VER:?}.tar.gz &&
wget ${WGET_OPT:?} https://ftp.gnu.org/gnu/tar/tar-${TAR_VER:?}.tar.gz &&
wget ${WGET_OPT:?} https://ftp.gnu.org/gnu/patch/patch-${PATCH_VER}.tar.gz &&
wget ${WGET_OPT:?} https://ftp.gnu.org/gnu/coreutils/coreutils-${COREUTILS_VER}.tar.gz &&
wget ${WGET_OPT:?} https://ftp.gnu.org/gnu/binutils/binutils-${BINUTILS_VER:?}.tar.gz &&
wget ${WGET_OPT:?} https://www.openssl.org/source/openssl-${OPENSSL_VER:?}.tar.gz &&
wget ${WGET_OPT:?} https://ftp.gnu.org/gnu/wget/wget-${WGET_VER:?}.tar.gz &&
\
# These packages are optional and only needed for testing GCC \
DEJAGNU_VER="1.6.3" &&
TCL_VER="8.6.14" &&
EXPECT_VER="5.45.4" &&
WGET_OPT="--no-check-certificate" &&
wget ${WGET_OPT:?} https://ftp.gnu.org/gnu/dejagnu/dejagnu-${DEJAGNU_VER:?}.tar.gz &&
wget ${WGET_OPT:?} https://prdownloads.sourceforge.net/tcl/tcl${TCL_VER:?}-src.tar.gz &&
wget ${WGET_OPT:?} https://sourceforge.net/projects/expect/files/Expect/${EXPECT_VER:?}/expect${EXPECT_VER:?}.tar.gz
\
# Unpack all packages \
cd ${SRC_DIR:?} &&
for i in $(ls ${TAR_DIR:?}); do gtar -xf ${TAR_DIR:?}/$i & done; wait


3. Download GCC prerequisites

GCC needs several prerequisites packages in order to build correctly. These include: GMP, MPFR, MPC, etc. We patch the download_prerequisites script to avoid errors on systems which cannot verify SSL certificates.

cd ${SRC_DIR:?}/gcc-${GCC_VER:?} &&
cp contrib/download_prerequisites contrib/download_prerequisites.orig &&
sed "s/fetch='wget'/fetch='wget --no-check-certificate'/g" contrib/download_prerequisites.orig > contrib/download_prerequisites &&
/bin/sh contrib/download_prerequisites


4.A Build GCC with Sun binutils

The script below configures and builds GCC with Sun binutils and installs new compilers under /opt/gcc-<version>_sun_binutils.

PREFIX specifies GCC installation prefix.
DEVUTILS_PREFIX contains various build tools needed for downloading, patching, configuring and building GCC.
BUILD_CC contains the bootstrap build compiler.

MAKE_JOBS=64 &&
MARCH="sparc64-sun-solaris2.11" &&
PREFIX="/opt/gcc-${GCC_VER:?}_sun_binutils" &&
DEVUTILS_PREFIX=/opt/gcc_build_tools &&
BUILD_CC="/opt/gcc" &&
PATH="${DEVUTILS_PREFIX:?}/bin:${BUILD_CC:?}/bin:/usr/bin:/usr/sbin" &&
CC="gcc" &&
CXX="g++" &&
unset LDFLAGS &&
export PATH CC CXX \
\
# Build and install GCC \
pkg="gcc-${GCC_VER:?}"; cd ${OBJ_DIR:?} &&
test ! -d ${pkg:?} && mkdir ${pkg:?}; cd ${pkg:?} &&
${SRC_DIR:?}/${pkg:?}/configure --prefix="${PREFIX:?}" \
--build="${MARCH:?}" --host="${MARCH:?}" --target="${MARCH:?}" --with-cpu=v9 \
--enable-languages=c,c++,ada --enable-shared --enable-threads=posix \
--enable-bootstrap --enable-multilib --enable-obsolete --disable-nls \
--with-as="/usr/bin/as" --with-ld="/usr/bin/ld" &&
gmake --output-sync=target -j "${MAKE_JOBS:?}" && gmake install &&
\
# Perform final cleanup: \
rm -rf ${PREFIX:?}/share/info

# Run GCC tests (requires tcl, expect and dejagnu) \
# See https://gcc.gnu.org/install/test.html \
MAKE_JOBS=64 &&
PREFIX="/opt/gcc-${GCC_VER:?}_sun_binutils" &&
DEVUTILS_PREFIX=/opt/gcc_build_tools &&
PATH="${DEVUTILS_PREFIX:?}/bin:${PREFIX:?}/bin:/usr/bin:/usr/sbin" &&
CC="gcc" &&
CXX="g++" &&
LDFLAGS="" &&
export PATH CC CXX LDFLAGS &&
pkg="gcc-${GCC_VER:?}"; cd ${OBJ_DIR:?}/${pkg:?} &&
ulimit -s 32768 && gmake -j ${MAKE_JOBS:?} -k check

# Test results are in the following files
$ find . -name "*.sum"


4.B Build GCC with GNU binutils

The script below configures and builds GCC with GNU binutils and installs new compilers under /opt/gcc-<version>_gnu_binutils.

PREFIX specifies GCC installation prefix.
DEVUTILS_PREFIX contains various build tools needed for downloading, patching, configuring and building GCC.
BUILD_CC contains the bootstrap build compiler.

First, we build GNU binutils with bootstrap compiler. We use option --with-static-standard-libraries so that binutils do not depend on any bootstrap compiler's shared libraries.

Second, we build new version of GCC compilers. It is important that the directory with GNU binutils is located first in our PATH so that GCC configure script can correctly locate GNU as (assembler) and ld (linker) tools.

Third, we rebuild GNU binutils with shared standard libraries. We set LDFLAGS to hardcode the paths to new GCC compilers shared libraries.

🖙 Don't try to use binutils --enable-gold=default linker config option, this linker doesn't seem to work properly on SPARC Solaris when building GCC.

MAKE_JOBS=64 &&
MARCH="sparc64-sun-solaris2.11" &&
PREFIX="/opt/gcc-${GCC_VER:?}_gnu_binutils" &&
DEVUTILS_PREFIX=/opt/gcc_build_tools &&
BUILD_CC="/opt/gcc" &&
PATH="${PREFIX:?}/bin:${DEVUTILS_PREFIX:?}/bin:${BUILD_CC:?}/bin:/usr/bin:/usr/sbin" &&
CC="gcc" &&
CXX="g++" &&
unset LDFLAGS &&
export PATH CC CXX \
\
# Build and install temporary binutils with static standard libs \
pkg="binutils-${BINUTILS_VER:?}"; cd ${OBJ_DIR:?} &&
test ! -d ${pkg:?} && mkdir ${pkg:?}; cd ${pkg:?} &&
${SRC_DIR:?}/${pkg:?}/configure --prefix=${PREFIX:?} \
--build="${MARCH:?}" --host="${MARCH:?}" --target="${MARCH:?}" \
--with-static-standard-libraries \
--enable-shared --enable-ld=default --enable-64-bit-bfd --disable-nls &&
gmake MAKEINFO=true -j "${MAKE_JOBS:?}" &&
gmake MAKEINFO=true -j "${MAKE_JOBS:?}" install &&
cd ../ && rm -rf ${pkg:?} &&
\
# Build and install GCC \
pkg="gcc-${GCC_VER:?}"; cd ${OBJ_DIR:?} &&
test ! -d ${pkg:?} && mkdir ${pkg:?}; cd ${pkg:?} &&
${SRC_DIR:?}/${pkg:?}/configure --prefix="${PREFIX:?}" \
--build="${MARCH:?}" --host="${MARCH:?}" --target="${MARCH:?}" --with-cpu=v9 \
--enable-languages=c,c++,ada --enable-shared --enable-threads=posix \
--enable-bootstrap --enable-multilib --enable-obsolete --disable-nls \
--with-gnu-as --with-gnu-ld &&
gmake --output-sync=target -j "${MAKE_JOBS:?}" && gmake install &&
\
# Build and install final binutils with dynamic standard libs \
PATH="${DEVUTILS_PREFIX:?}/bin:${PREFIX:?}/bin:/usr/bin:/usr/sbin" &&
CC="gcc" &&
CXX="g++" &&
LDFLAGS="-Wl,--library-path=${PREFIX:?}/lib -Wl,-rpath=${PREFIX:?}/lib" &&
export PATH CC CXX LDFLAGS &&
\
pkg="binutils-${BINUTILS_VER:?}"; cd ${OBJ_DIR:?} &&
test ! -d ${pkg:?} && mkdir ${pkg:?}; cd ${pkg:?} &&
${SRC_DIR:?}/${pkg:?}/configure --prefix=${PREFIX:?} --disable-nls \
--build="${MARCH:?}" --host="${MARCH:?}" --target="${MARCH:?}" \
--enable-shared --enable-ld=default --enable-64-bit-bfd --disable-nls &&
gmake MAKEINFO=true -j "${MAKE_JOBS:?}" &&
gmake MAKEINFO=true -j "${MAKE_JOBS:?}" install &&
\
# Perform final cleanup \
unset LDFLAGS &&
rm -rf ${PREFIX:?}/share/info

# Run GCC tests (requires tcl, expect and dejagnu) \
# See https://gcc.gnu.org/install/test.html \
MAKE_JOBS=64 &&
PREFIX="/opt/gcc-${GCC_VER:?}_gnu_binutils" &&
DEVUTILS_PREFIX=/opt/gcc_build_tools &&
PATH="${DEVUTILS_PREFIX:?}/bin:${PREFIX:?}/bin:/usr/bin:/usr/sbin" &&
CC="gcc" &&
CXX="g++" &&
LDFLAGS="" &&
export PATH CC CXX LDFLAGS &&
pkg="gcc-${GCC_VER:?}"; cd ${OBJ_DIR:?}/${pkg:?} &&
ulimit -s 32768 && gmake -j ${MAKE_JOBS:?} -k check

# Test results are in the following files
$ find . -name "*.sum"


5. Build GCC tools

It is useful to have a small set of self-contained build tools, with which new versions of GCC can be built. Many of these tools can be installed with Solaris native package management commands. This may not be an option with older and unsupported versions of Solaris, hence a process for building these tools manually is described below.

DEVUTILS_PREFIX is set to where build tools will be installed.
BUILD_CC is set to the base directory where current build compiler is located. There could be multiple compilers, hence set up /opt/gcc to be a symlink to the working compiler.

Note that CFLAGS and CXXFLAGS contain -static-libgcc -static-libstdc++ flags. This builds standalone tools which do not depend on GCC shared libraries. The build compiler can later be removed from the system and the tools should continue to work.

MAKE_JOBS=64 &&
MARCH="sparc64-sun-solaris2.11" &&
DEVUTILS_PREFIX=/opt/gcc_build_tools &&
BUILD_CC="/opt/gcc" &&
PATH="${DEVUTILS_PREFIX:?}/bin:${BUILD_CC:?}/bin:/usr/bin:/usr/sbin" &&
CC="gcc" &&
CXX="g++" &&
CFLAGS="-O2 -mcpu=v9 -static-libgcc -static-libstdc++" &&
CXXFLAGS="-O2 -mcpu=v9 -static-libgcc -static-libstdc++" &&
LDFLAGS="-Wl,-L${DEVUTILS_PREFIX:?}/lib -Wl,-R${DEVUTILS_PREFIX:?}/lib" &&
export PATH CC CXX CFLAGS CXXFLAGS LDFLAGS &&
\
# Build and install GNU make \
pkg="make-${MAKE_VER:?}"; cd ${OBJ_DIR:?} &&
test ! -d ${pkg:?} && mkdir ${pkg:?}; cd ${pkg:?} &&
${SRC_DIR:?}/${pkg:?}/configure --prefix=${DEVUTILS_PREFIX:?} --disable-nls &&
./build.sh && ./make install && ln -sf make ${DEVUTILS_PREFIX:?}/bin/gmake &&
hash -r &&
\
# Build and install GNU tar \
pkg="tar-${TAR_VER:?}"; cd ${OBJ_DIR:?} &&
test ! -d ${pkg:?} && mkdir ${pkg:?}; cd ${pkg:?} &&
FORCE_UNSAFE_CONFIGURE=1 ${SRC_DIR:?}/${pkg:?}/configure --prefix=${DEVUTILS_PREFIX:?} --disable-nls &&
gmake -j ${MAKE_JOBS:?} && gmake install &&
ln -s tar ${DEVUTILS_PREFIX:?}/bin/gtar &&
\
# Build and install GNU patch \
pkg="patch-${PATCH_VER:?}"; cd ${OBJ_DIR:?} &&
test ! -d ${pkg:?} && mkdir ${pkg:?}; cd ${pkg:?} &&
${SRC_DIR:?}/${pkg:?}/configure --prefix=${DEVUTILS_PREFIX:?} --disable-nls &&
gmake -j ${MAKE_JOBS:?} && gmake install &&
\
# Build and Install subset of GNU coreutils (needed by GCC contrib/download_prerequisites script) \
pkg="coreutils-${COREUTILS_VER:?}"; cd ${OBJ_DIR:?} &&
test ! -d ${pkg:?} && mkdir ${pkg:?}; cd ${pkg:?} &&
FORCE_UNSAFE_CONFIGURE=1 ${SRC_DIR:?}/${pkg:?}/configure --prefix=${DEVUTILS_PREFIX:?} --disable-nls &&
gmake -j ${MAKE_JOBS:?} && mkdir -p ${DEVUTILS_PREFIX:?}/bin &&
src/ginstall -c src/md5sum src/sha1sum src/sha512sum ${DEVUTILS_PREFIX:?}/bin &&
\
# Build and install OpenSSL (needed by wget) \
pkg="openssl-${OPENSSL_VER:?}"; cd ${OBJ_DIR:?} &&
test ! -d ${pkg:?} && mkdir ${pkg:?}; cd ${pkg:?} &&
${SRC_DIR:?}/${pkg:?}/Configure --prefix=${DEVUTILS_PREFIX:?} --libdir=lib \
shared solaris64-sparcv9-gcc &&
gmake -j ${MAKE_JOBS:?} && gmake install_sw &&
\
# Build and install GNU wget (needed by GCC contrib/download_prerequisites script) \
pkg="wget-${WGET_VER:?}"; cd ${OBJ_DIR:?} &&
test ! -d ${pkg:?} && mkdir ${pkg:?}; cd ${pkg:?} &&
OPENSSL_CFLAGS="-I${DEVUTILS_PREFIX:?}/include" \
OPENSSL_LIBS="-L${DEVUTILS_PREFIX:?}/lib -lssl -lcrypto" \
${SRC_DIR:?}/${pkg:?}/configure --prefix=${DEVUTILS_PREFIX:?} --with-ssl=openssl --disable-nls &&
gmake -j ${MAKE_JOBS:?} && gmake install &&
\
# These are only needed for testing GCC \
\
# Build and install tcl \
pkg="tcl${TCL_VER:?}"; cd ${OBJ_DIR:?} &&
test ! -d ${pkg:?} && mkdir ${pkg:?}; cd ${pkg:?} &&
${SRC_DIR:?}/${pkg:?}/unix/configure --prefix=${DEVUTILS_PREFIX:?} &&
gmake -j ${MAKE_JOBS:?} && gmake install && gmake install-private-headers &&
ln -s tclsh* ${DEVUTILS_PREFIX:?}/bin/tclsh &&
\
# Build and install expect \
pkg="expect${EXPECT_VER:?}"; cd ${OBJ_DIR:?} &&
test ! -d ${pkg:?} && mkdir ${pkg:?}; cd ${pkg:?} &&
${SRC_DIR:?}/${pkg:?}/configure --prefix=${DEVUTILS_PREFIX:?} \
--with-tcl=${DEVUTILS_PREFIX:?}/lib --with-tclinclude=${DEVUTILS_PREFIX:?}/include &&
gmake -j ${MAKE_JOBS:?} && gmake install &&
\
# Build and install dejagnu \
pkg="dejagnu-${DEJAGNU_VER:?}"; cd ${OBJ_DIR:?} &&
test ! -d ${pkg:?} && mkdir ${pkg:?}; cd ${pkg:?} &&
${SRC_DIR:?}/${pkg:?}/configure --prefix=${DEVUTILS_PREFIX:?} &&
gmake -j ${MAKE_JOBS:?} && gmake install

No comments:

Post a Comment