Building the Netrek Server – autofake

Building the Netrek server software on Solaris 2.6 is problematic – due to the all-too-common misuse and failings of automake/configure, combined with some loose programming.

Running the ./configure script does not initially report any errors, but (it turns out) also does not adapt the build/software for some platforms that other automake-based software does…

Not Quite a Dependancy Problem
The Netrek vanilla servers’ configure invokes a subsidiary configure script in the res-rsa subdirectory, which initially whinged about not being able to find the GNU Multiple-Precision Math library (generally used for programmable-sized fixed-point math instead of floating-point, including BIGINT math which is just a special-case of fixed-point). And not just “GMP”, but “GMP 2.x” in particular (current version is GMP 5.x). The README therein points out that the old “GMP 1.x” is not suitable, that being based on the archaic original BSD MP API. Strangely enough, that old archaic BSD MP API was replaced with a revised API in (BSD 4.4) 1992 when it was recognised that the original conflicted in an awkward way with the ANSI C89 standard math library. Given that the old API has completely different function-names, the point is moot anyway – the configure script would not accidentally find and accept an old one even it it was there… this is exactly the kind of automake nonsense that gets on my nerves!

Of course, Solaris includes a “new-MP” API library built-in, but with the “new-BSD-compatible” name libmp and header “mp.h” instead of the GNUised names libgmp and “gmp.h”.

If In Doubt, Use Brute Force
To use the Solaris built-in MP library in place of the (not installed) GNU MP library, a couple of manouvers are needed. We need to create a “gmp.h” header file that simply references the “mp.h” header, and also post-process the res-rsa Makefile produced by the configure script to tell it the compiler options to locate and link with the “libmp” library. We do this using brute force, by creating a wrapper script “myconfigure”:

./configure \
        --sysconfdir=/etc/netrek \
        --sharedstatedir=/var/netrek \
        --localstatedir=/var/spool/netrek || exit 1
# create a usable "gmp.h" header:
echo '#include "mp.h"' > ./gmp.h
# Adjust the generated res-rsa Makefile to use our "gmp.h" header and
# to and link with "libmp":
sed     -e 's/GMP_INC =.*/GMP_INC = -I../' \
        -e 's/GMP_LIB =.*-lgmp/GMP_LIB = -lmp/' \
        -e 's/^\(all:.*\)nogmp/\1/' \
         res-rsa/Makefile > /tmp/$$ && cp /tmp/$$ res-rsa/Makefile || exit 1
rm -f /tmp/$$

So far so good.

The Netrek vanilla server is currently exclusively IPv4, it is not IPv6 capable – it uses the classic BSD-style socket functions such as gethostbyname(), and not the newer IP version-agnostic functions such as getaddrinfo(). However, in a couple of places it uses one of the newer typenames – socklen_t, which is unfortunate for systems that are not IPv6 capable or POSIX.1-2001 conformant. It could be argued that this is a case of erroneously mixing APIs…

Running make spits an error:

rsa_key.c: In function `decryptRSAPacket':
rsa_key.c:56: error: `socklen_t' undeclared (first use in this function)
rsa_key.c:56: error: (Each undeclared identifier is reported only once
rsa_key.c:56: error: for each function it appears in.)
rsa_key.c:56: error: syntax error before "addrlen"
rsa_key.c:68: error: `addrlen' undeclared (first use in this function)
gmake[1]: *** [rsa_key.o] Error 1

For the classic BSD-style (IPv4-only) socket API, in all the places where socklen_t would be used for IPv6, the appropriate type is int. Thus I thought that the obvious way to handle this would be to define a suitable CFLAGS environment-variable (to tell the compiler to treat all ocurrences of socklen_t as if they were int) before running ./configure (the typical “approved” method of handling this kind of thing with automake-based software):

CFLAGS=-Dsocklen_t=int  ./configure

That should do it!

The Subsidiary res-rsa Configure Script
Well, unfortunately not:

config.status: creating tools/admin/Makefile
config.status: creating include/config.h
=== configuring in res-rsa (/var/home/spoof/nt-server/netrek-server-vanilla-2.14.0/res-rsa)

configure: running /bin/ksh ./configure '--prefix=/usr/local/games/netrek-server -vanilla'  
 '--sysconfdir=/etc/netrek' '--sharedstatedir=/var/netrek'
 '--localstatedir=/var/spool/netrek' 'CFLAGS=-Dsocklen_t=int'
 --cache-file=/dev/null --srcdir=.

configure: warning: CFLAGS=-Dsocklen_t=int: invalid host type
configure: error: can only configure for one host and one target at a time
configure: error: ./configure failed for res-rsa

This cryptic message indicates that the subsidiary configure script in the res-rsa subdirectory was generated by a much older version of automake which does not understand the mechanism that the top-level configure script uses to pass overridden CC, CFLAGS, etc settings. Darn!

An Old Trick: Use a Custom C Compiler
Not being able to pre-define CC or CFLAGS, but needing to always invoke the C compiler with an additional flag, it was time to write a custom C compiler – in a manner of speaking. The trick is to create an executable script that invokes the C compiler *with the additional flag required*:

exec /usr/local/bin/gcc -Dsocklen_t=int "$@" 

Due to not being able to specify the CC environment-variable, this script must be called gcc, and must invoke the real gcc by absolute pathname; we also set PATH so that it finds this script in preference to the real gcc:

PATH="$HOME/bin:$PATH" ./myconfigure && gmake

Are We There Yet?
Still not quite: there remains a couple of missing functions at link-time:

Undefined                       first referenced
 symbol                             in file
setenv                              libnetrek.a(getpath.o)
round                               libnetrek.a(ping.o)
ld: fatal: Symbol referencing errors. No output written to ntserv

These are POSIX.1-2001 functions that are not present on Solaris 2.6. However, I have a plan… stay tuned!


Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s