4 ms·
Some folks might wonder why GNU Make would require ongoing OS-specific maintenance at all. The answer lies with GNU coding standards, which are broadly unchange
by jmillikin 4y ago
Some folks might wonder why GNU Make would require ongoing OS-specific maintenance at all. The answer lies with GNU coding standards, which are broadly unchanged since the 1980s and are extremely hostile to portability in the modern sense.
--
First, if you look through the Make code, you'll see it's riddled with #ifdef lines for each supported OS. In modern code you'd separate these out into per-OS sub-libraries with a common API, but in GNU code it all gets mashed together.
Here's a good example I found from a quick search -- it's trying to find a default value for the user's home directory, which could easily be a per-OS function, except that that's not how it worked in the '80s so instead they embedded environment variable lookup into a SEVEN HUNDRED LINE glob() FUNCTION IN lib/glob.c.
#ifndef VMS
if ((flags & (GLOB_TILDE|GLOB_TILDE_CHECK)) && dirname[0] == '~')
{
if (dirname[1] == '\0' || dirname[1] == '/')
{
/* Look up home directory. */
#ifdef VMS
/* This isn't obvious, RTLs of DECC and VAXC know about "HOME" */
const char *home_dir = getenv ("SYS$LOGIN");
#else
const char *home_dir = getenv ("HOME");
#endif
# ifdef _AMIGA
if (home_dir == NULL || home_dir[0] == '\0')
home_dir = "SYS:";
# else
# ifdef WINDOWS32
if (home_dir == NULL || home_dir[0] == '\0')
home_dir = "c:/users/default"; /* poor default */
# else
# ifdef VMS
How do you test that? In modern code you'd have an OS-independent unit test for glob expansion, and a separate test for "get homedir on AmigaOS", and the AmigaOS code would never change because why would it?
Plus, the code itself is horrible, like if you read this and think "wait, they're nesting `#ifdef VMS` inside `#ifndef VMS`, what is their intention" then buckle the fuck up because the entire project looks like that.
--
Second, many GNU projects use a library named gnulib, which is a sort of anti-portability library developed to make every system look like GNU libc. To achieve this goal the gnulib code digs deep into opaque implementation details of the underlying system libraries, stuff like the layout of `struct FILE` or whether particular symbols are constants or macros. As you might expect this shit breaks constantly, even the most dirt-common gcc+glibc+Linux system might fail to build a GNU project from a year ago because the glibc folks changed something that gnulib implicitly depended on.
Things get even worse from there, like if you try to build with musl or Clang then you're in for potentially days of reading mailing lists and digging up old CVS checkouts to figure out how to get the damn thing to compile. And we haven't even talked about OS portability yet! It took me weeks to get a working GNU Bison build on Windows because I had to hunt down dozens of places where they assumed that sizeof(int) == sizeof(long) == sizeof(void*). That's on the world's most popular workstation OS, good fucking luck getting any sort of confidence that the code works as expected on an Amiga.
--
In summary, the GNU folks have intentionally structured their code such that it's difficult to maintain across platforms, and this email list is merely one of the observable outcomes of their decision.
- ahefner 4y agoI agree your example is a Lovecraftian horror, but you test it by running it on every platform. How else would you test it?
- jmillikin 4y agoYou separate out the core logic so it can be tested on any platform, and only the truly OS-dependent code needs to be target-specific. I should be able to run the test "expand this glob as if on AmigaOS, with given homedir path" on a Linux desktop.
- hamandcheese 4y agoAre things like this because someone thinks this is the way things should be, or are things like this because nobody has contributed to the cleanup?