Building Bash 1.14.7 on a modern system ======================================= --- date: "2015-03-18" --- In a previous revision of my [Bash arrays post](./bash-arrays.html), I wrote: > Bash 1.x won't compile with modern GCC, so I couldn't verify how it > behaves. I recall spending a little time fighting with it, but apparently I didn't try very hard: getting Bash 1.14.7 to build on a modern box is mostly just adjusting it to use `stdarg` instead of the no-longer-implemented `varargs`. There's also a little fiddling with the pre-autoconf automatic configuration. ## stdarg Converting to `stdarg` is pretty simple: For each variadic function (functions that take a variable number of arguments), follow these steps: 1. Replace `#include ` with `#include ` 2. Replace `function_name (va_alist) va_dcl` with `function_name (char *format, ...)`. 3. Removing the declaration and assignment for `format` from the function body. 4. Replace `va_start (args);` with `va_start (args, format);` in the function bodies. 5. Replace `function_name ();` with `function_name (char *, ...)` in header files and/or at the top of C files. There's one function that uses the variable name `control` instead of `format`. I've prepared [a patch](./bash-1.14.7-gcc4-stdarg.patch) that does this. ## Configuration Instead of using autoconf-style tests to test for compiler and platform features, Bash 1 used the file `machines.h` that had `#ifdefs` and a huge database of of different operating systems for different platforms. It's gross. And quite likely won't handle your modern operating system. I made these two small changes to `machines.h` to get it to work correctly on my box: 1. Replace `#if defined (i386)` with `#if defined (i386) || defined (__x86_64__)`. The purpose of this is obvious. 2. Add `#define USE_TERMCAP_EMULATION` to the section for Linux [sic] on i386 (`# if !defined (done386) && (defined (__linux__) || defined (linux))`). What this does is tell it to link against libcurses to use curses termcap emulation, instead of linking against libtermcap (which doesn't exist on modern GNU/Linux systems). Again, I've prepared [a patch](./bash-1.14.7-machines-config.patch) that does this. ## Building With those adjustments, it should build, but with quite a few warnings. Making a couple of changes to `CFLAGS` should fix that: make CFLAGS='-O -g -Werror -Wno-int-to-pointer-cast -Wno-pointer-to-int-cast -Wno-deprecated-declarations -include stdio.h -include stdlib.h -include string.h -Dexp2=bash_exp2' That's a doozy! Let's break it down: - `-O -g` The default value for CFLAGS (defined in `cpp-Makefile`) - `-Werror` Treat warnings as errors; force us to deal with any issues. - `-Wno-int-to-pointer-cast -Wno-pointer-to-int-cast` Allow casting between integers and pointers. Unfortunately, the way this version of Bash was designed requires this. - `-Wno-deprecated-declarations` The `getwd` function in `unistd.h` is considered deprecated (use `getcwd` instead). However, if `getcwd` is available, Bash uses it's own `getwd` wrapper around `getcwd` (implemented in `general.c`), and only uses the signature from `unistd.h`, not the actuall implementation from libc. - `-include stdio.h -include stdlib.h -include string.h` Several files are missing these header file includes. If not for `-Werror`, the default function signature fallbacks would work. - `-Dexp2=bash_exp2` Avoid a conflict between the parser's `exp2` helper function and `math.h`'s base-2 exponential function. Have fun, software archaeologists!