summaryrefslogtreecommitdiff
path: root/public/build-bash-1.md
blob: 8e8c847251d7a7f4319097c92c204b6d93fa7d8d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
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 <varargs.h>` with `#include <stdarg.h>`
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!