2013-11-25

Legacy Jails on a FreeBSD 10 Tinderbox

This unfinished article has been sitting here for some time and was an attempt to keep track of my efforts to fix building legacy Tinderbox jails on FreeBSD 10. I have not made any progress for some time. So I decided to publish this article, maybe it is of use to someone else working on the same problems.

It has become customary to me to build libreoffice packages, whenever an update is available in the ports tree. The packages are published on the BSDForen.de Wiki. Recently I updated the Tinderbox host system to FreeBSD 10.

The Error

I use the oldest supported release for each branch to maximize the number of people who can use the packages. I use apply to update the whole batch of jails:

# /usr/local/tinderbox/jails
# apply 'tc makeJail -j' *
8.3-amd64: updating jail with SVN
8.3-amd64: cleaning out /usr/local/portstools/tinderbox/jails/8.3-amd64/obj
8.3-amd64: cleaning out /usr/local/portstools/tinderbox/jails/8.3-amd64/tmp
8.3-amd64: making world
ERROR: world failed - see /usr/local/portstools/tinderbox/jails/8.3-amd64/world.tmp
Cleaning up after Jail creation.  Please be patient.
8.3-i386: updating jail with SVN
8.3-i386: cleaning out /usr/local/portstools/tinderbox/jails/8.3-i386/obj
8.3-i386: cleaning out /usr/local/portstools/tinderbox/jails/8.3-i386/tmp
8.3-i386: making world
ERROR: world failed - see /usr/local/portstools/tinderbox/jails/8.3-i386/world.tmp
Cleaning up after Jail creation.  Please be patient.
...

So I checked the first log file 8.3-amd64/world.tmp:

--- upgrade_checks ---
A failure has been detected in another branch of the parallel make

make[1]: stopped in /usr/local/portstools/tinderbox/jails/8.3-amd64/src
*** [upgrade_checks] Error code 2

make: stopped in /usr/local/portstools/tinderbox/jails/8.3-amd64/src
1 error

make: stopped in /usr/local/portstools/tinderbox/jails/8.3-amd64/src

Diagnostics

That previous error message, wasn't really useful, apparently make had some issues. So I hacked the Tinderbox a bit:

--- lib/tc_command.sh   19 Oct 2013 20:13:08 -0000      1.179
+++ lib/tc_command.sh   30 Oct 2013 08:06:26 -0000
@@ -889,7 +889,7 @@
         fi
 
         cd ${SRCBASE} && env DESTDIR=${J_TMPDIR} ${crossEnv} \
-           make -j${factor} -DNO_CLEAN world > ${jailBase}/world.tmp 2>&1
+           make -B -j${factor} -DNO_CLEAN world > ${jailBase}/world.tmp 2>&1
         rc=$?
         execute_hook "postJailBuild" "JAIL=${jailName} DESTDIR=${J_TMPDIR} JAIL_ARCH=${jailArch} MY_ARCH=${myArch} JAIL_OBJDIR=${JAIL_OBJDIR} SRCBASE=${SRCBASE} PB=${pb} RC=${rc}"
         if [ ${rc} -ne 0 ]; then

FreeBSD 10 comes with a new version of make that has some incompatibilities. The -B flag causes make to behave old-fashioned.

The next log turned out to be a lot more telling:

...
c++ -O2 -pipe -I/usr/local/portstools/tinderbox/jails/8.3-amd64/obj/usr/local/portstools/tinderbox/jails/8.3-amd64/src/tmp/legacy/usr/include -I/usr/local/portstools/tinderbox/jails/8.3-amd64/src/gnu/usr.bin/gperf/../../../contrib/gperf/lib -I/usr/local/portstools/tinderbox/jails/8.3-amd64/src/gnu/usr.bin/gperf -c /usr/local/portstools/tinderbox/jails/8.3-amd64/src/gnu/usr.bin/gperf/../../../contrib/gperf/src/version.cc
c++ -O2 -pipe -I/usr/local/portstools/tinderbox/jails/8.3-amd64/obj/usr/local/portstools/tinderbox/jails/8.3-amd64/src/tmp/legacy/usr/include -I/usr/local/portstools/tinderbox/jails/8.3-amd64/src/gnu/usr.bin/gperf/../../../contrib/gperf/lib -I/usr/local/portstools/tinderbox/jails/8.3-amd64/src/gnu/usr.bin/gperf -c /usr/local/portstools/tinderbox/jails/8.3-amd64/src/gnu/usr.bin/gperf/../../../contrib/gperf/lib/getline.cc
c++ -O2 -pipe -I/usr/local/portstools/tinderbox/jails/8.3-amd64/obj/usr/local/portstools/tinderbox/jails/8.3-amd64/src/tmp/legacy/usr/include -I/usr/local/portstools/tinderbox/jails/8.3-amd64/src/gnu/usr.bin/gperf/../../../contrib/gperf/lib -I/usr/local/portstools/tinderbox/jails/8.3-amd64/src/gnu/usr.bin/gperf -c /usr/local/portstools/tinderbox/jails/8.3-amd64/src/gnu/usr.bin/gperf/../../../contrib/gperf/lib/hash.cc
make: don't know how to make /usr/lib/libstdc++.a. Stop
*** Error code 2

Stop in /usr/local/portstools/tinderbox/jails/8.3-amd64/src.
*** Error code 1

Stop in /usr/local/portstools/tinderbox/jails/8.3-amd64/src.
*** Error code 1

Stop.
make: stopped in /usr/local/portstools/tinderbox/jails/8.3-amd64/src

Fix C++

The meaning of the error should be clear to experienced FreeBSD admins. FreeBSD 10 introduces a new C++11 capable C++ stack and the legacy jails required the old stack to bootstrap the build process.

The solution was to add a line to /etc/src.conf:

WITH_GNUCXX=1

And updating world:

# cd /usr/src
# make -DNO_CLEAN buildworld
...
--------------------------------------------------------------
>>> World build completed on Wed Oct 30 10:28:06 CET 2013
--------------------------------------------------------------
# make installworld
...

That didn't take long, because instead of rebuilding the entire world, only the missing parts were added to the build due to the NO_CLEAN flag.

Note, the tc_command.sh hack should stay in place to ensure make compatibility. Unfortunately that seriously slows down the makeJail, because it prevents parallel make. A workaround that does not require meddling with the bootstrapping process would be to update several jails at the same time.

So once again it was time to kick off the builds:

# cd /usr/local/tinderbox/jails
# apply 'tc makeJail -j' *
8.3-amd64: updating jail with SVN
8.3-amd64: cleaning out /usr/local/portstools/tinderbox/jails/8.3-amd64/obj
8.3-amd64: cleaning out /usr/local/portstools/tinderbox/jails/8.3-amd64/tmp
8.3-amd64: making world
ERROR: world failed - see /usr/local/portstools/tinderbox/jails/8.3-amd64/world.tmp
Cleaning up after Jail creation.  Please be patient.
8.3-i386: updating jail with SVN
8.3-i386: cleaning out /usr/local/portstools/tinderbox/jails/8.3-i386/obj
8.3-i386: cleaning out /usr/local/portstools/tinderbox/jails/8.3-i386/tmp
8.3-i386: making world
ERROR: world failed - see /usr/local/portstools/tinderbox/jails/8.3-i386/world.tmp
Cleaning up after Jail creation.  Please be patient.
...

Fix cc != gcc

So basically the builds got a lot further, but still didn't complete. It was time to look at 8.3-amd64/world.tmp again:

...
cc -O2 -pipe -DIN_GCC -DHAVE_CONFIG_H -DPREFIX=\"/usr/local/portstools/tinderbox/jails/8.3-amd64/obj/usr/local/portstools/tinderbox/jails/8.3-amd64/src/tmp/usr\" -I/usr/local/portstools/tinderbox/jails/8.3-amd64/obj/usr/local/portstools/tinderbox/jails/8.3-amd64/src/tmp/usr/local/portstools/tinderbox/jails/8.3-amd64/src/gnu/usr.bin/cc/cc_int/../cc_tools -I/usr/local/portstools/tinderbox/jails/8.3-amd64/src/gnu/usr.bin/cc/cc_int/../cc_tools -I/usr/local/portstools/tinderbox/jails/8.3-amd64/src/gnu/usr.bin/cc/cc_int/../../../../contrib/gcc -I/usr/local/portstools/tinderbox/jails/8.3-amd64/src/gnu/usr.bin/cc/cc_int/../../../../contrib/gcc/config -I/usr/local/portstools/tinderbox/jails/8.3-amd64/src/gnu/usr.bin/cc/cc_int/../../../../contrib/gcclibs/include -I/usr/local/portstools/tinderbox/jails/8.3-amd64/src/gnu/usr.bin/cc/cc_int/../../../../contrib/gcclibs/libcpp/include -I/usr/local/portstools/tinderbox/jails/8.3-amd64/src/gnu/usr.bin/cc/cc_int/../../../../contrib/gcclibs/libdecnumber   -I/usr/local/portstools/tinderbox/jails/8.3-amd64/obj/usr/local/portstools/tinderbox/jails/8.3-amd64/src/tmp/legacy/usr/include -c /usr/local/portstools/tinderbox/jails/8.3-amd64/src/gnu/usr.bin/cc/cc_int/../../../../contrib/gcc/timevar.c
cc -O2 -pipe -DIN_GCC -DHAVE_CONFIG_H -DPREFIX=\"/usr/local/portstools/tinderbox/jails/8.3-amd64/obj/usr/local/portstools/tinderbox/jails/8.3-amd64/src/tmp/usr\" -I/usr/local/portstools/tinderbox/jails/8.3-amd64/obj/usr/local/portstools/tinderbox/jails/8.3-amd64/src/tmp/usr/local/portstools/tinderbox/jails/8.3-amd64/src/gnu/usr.bin/cc/cc_int/../cc_tools -I/usr/local/portstools/tinderbox/jails/8.3-amd64/src/gnu/usr.bin/cc/cc_int/../cc_tools -I/usr/local/portstools/tinderbox/jails/8.3-amd64/src/gnu/usr.bin/cc/cc_int/../../../../contrib/gcc -I/usr/local/portstools/tinderbox/jails/8.3-amd64/src/gnu/usr.bin/cc/cc_int/../../../../contrib/gcc/config -I/usr/local/portstools/tinderbox/jails/8.3-amd64/src/gnu/usr.bin/cc/cc_int/../../../../contrib/gcclibs/include -I/usr/local/portstools/tinderbox/jails/8.3-amd64/src/gnu/usr.bin/cc/cc_int/../../../../contrib/gcclibs/libcpp/include -I/usr/local/portstools/tinderbox/jails/8.3-amd64/src/gnu/usr.bin/cc/cc_int/../../../../contrib/gcclibs/libdecnumber   -I/usr/local/portstools/tinderbox/jails/8.3-amd64/obj/usr/local/portstools/tinderbox/jails/8.3-amd64/src/tmp/legacy/usr/include -DTARGET_NAME=\"amd64-undermydesk-freebsd\" -c /usr/local/portstools/tinderbox/jails/8.3-amd64/src/gnu/usr.bin/cc/cc_int/../../../../contrib/gcc/toplev.c
In file included from /usr/local/portstools/tinderbox/jails/8.3-amd64/src/gnu/usr.bin/cc/cc_int/../../../../contrib/gcc/toplev.c:58:
/usr/local/portstools/tinderbox/jails/8.3-amd64/src/gnu/usr.bin/cc/cc_int/../../../../contrib/gcc/output.h:123:6: warning: 'format' attribute argument not supported: __asm_fprintf__ [-Wignored-attributes]
     ATTRIBUTE_ASM_FPRINTF(2, 3);
     ^
/usr/local/portstools/tinderbox/jails/8.3-amd64/src/gnu/usr.bin/cc/cc_int/../../../../contrib/gcc/output.h:113:53: note: expanded from macro 'ATTRIBUTE_ASM_FPRINTF'
#define ATTRIBUTE_ASM_FPRINTF(m, n) __attribute__ ((__format__ (__asm_fprintf__, m, n))) ATTRIBUTE_NONNULL(m)
                                                    ^
/usr/local/portstools/tinderbox/jails/8.3-amd64/src/gnu/usr.bin/cc/cc_int/../../../../contrib/gcc/toplev.c:542:1: error: redefinition of a 'extern inline' function 'floor_log2' is not supported in C99 mode
floor_log2 (unsigned HOST_WIDE_INT x)
^
/usr/local/portstools/tinderbox/jails/8.3-amd64/src/gnu/usr.bin/cc/cc_int/../../../../contrib/gcc/toplev.h:174:1: note: previous definition is here
floor_log2 (unsigned HOST_WIDE_INT x)
^
/usr/local/portstools/tinderbox/jails/8.3-amd64/src/gnu/usr.bin/cc/cc_int/../../../../contrib/gcc/toplev.c:577:1: error: redefinition of a 'extern inline' function 'exact_log2' is not supported in C99 mode
exact_log2 (unsigned HOST_WIDE_INT x)
^
/usr/local/portstools/tinderbox/jails/8.3-amd64/src/gnu/usr.bin/cc/cc_int/../../../../contrib/gcc/toplev.h:180:1: note: previous definition is here
exact_log2 (unsigned HOST_WIDE_INT x)
^
1 warning and 2 errors generated.
*** Error code 1

Stop in /usr/local/portstools/tinderbox/jails/8.3-amd64/src/gnu/usr.bin/cc/cc_int.
*** Error code 1

Stop in /usr/local/portstools/tinderbox/jails/8.3-amd64/src/gnu/usr.bin/cc.
*** Error code 1

Stop in /usr/local/portstools/tinderbox/jails/8.3-amd64/src.
*** Error code 1

Stop in /usr/local/portstools/tinderbox/jails/8.3-amd64/src.
*** Error code 1

Stop.
make: stopped in /usr/local/portstools/tinderbox/jails/8.3-amd64/src

In retrospect the cause is obvious, pre-10 releases of FreeBSD expect cc to be gcc. So it was time to update the /etc/src.conf again:

WITH_GCC=1
WITH_GNUCXX=1

And of course to update world like before.

So it was time for another try building a jail using gcc. To save time I opened multiple terminals (I use tmux) and built one jail in each:

# /usr/local/tinderbox/jails
# env CC=gcc CXX=g++ apply 'tc makeJail -j' 8.3-amd64
TODO: Insert output