move libc related stuff out of platform.h

Rob Landley rob at landley.net
Sat Jul 11 03:37:39 UTC 2009


On Friday 10 July 2009 05:12:53 Denys Vlasenko wrote:
> On Fri, Jul 10, 2009 at 10:46 AM, Rob Landley<rob at landley.net> wrote:
> > How is the MS_BIND stuff a good idea?  Duplicating a long #ifdef
> > staircase in two places doesn't really sound like an improvement.
>
> I agree that duplicating is bad.
>
> I don't want to handle _libc_ compat issues in platform.h,
> because in order to do
>
> #ifdnef FOO
> # define FOO good_foo
> #endif
>
> one needs to #include <relevant_file.h> first. And if we do that
> in platform.h, it will grow big.
>
> I decided to do such things in libbb.h instead, directly after each
> #include <relevant_file.h> which needs such treatment.

The problem is that this mixes busybox knowledge with platform knowledge.

Essentially, a different platform is a different build environment.  Linux on 
powerpc is a different build environment from x86-64 glibc Linux, you need a 
special compiler and libraries to build it, and a special runtime environment 
(hardware or emulator) to test the result.  Linux on uClibc is also a different 
build environment, one which most people don't have lying around, so they 
can't easily test their changes against it.

Linux developers have to modify libbb.h to add functionality all the time.  If 
they screw up platform stuff, they can't regression test it.  This means that 
if libbb.h contains a lot of magic that most people aren't expected to 
understand, and thus shouldn't touch under any circumstances, then they're 
expected to add stuff around it and never remove anything they didn't put 
there...  That's a recipe for accumulating cruft.

I can see splitting platform.h into a "platform" directory and a bunch of 
#includes of platform/macos.h, platform/linux.h, platform/libgloss.h, and so 
on.  (That was always a possibility when platform.h was introduced, we just 
didn't have enough stuff to justify it back then.)  But segregating "only 
practicioners of this particular dark art should ever need to look at this 
bit" code from "everybody should be able to understand/test this and change it 
as needed" code was about half the reason for platform.h.  (The rest was to 
try to make everything work the same way as much as possible, so you didn't 
have to worry about platform idiosyncrasies when trying to wrap your head 
around things like "sed".)

> And if some headers aren't included into libbb.h because they are
> specialized (like sys/mount.h), then I decided to do it whereever they
> are included.

If a standard header always needs fixups, that sounds like that's more of an 
argument for centralizing those fixups somewhere.  Perhaps doing a "mount_.h" 
wrapper the way there's grp_.h, pwd_.h, rtc_.h, and shadow_.h today?  (Why 
there's header_.h style for those and xregex.c style for xregcomp() is 
something I don't remember the reasoning behind...)  But I'd like to make sure 
that doing without the fixups isn't a viable option first...

What platforms does busybox currently support, anyway?  (I vaguely recall 
somebody was seriously defending Dec Ultrix compatability, or some such.  And 
somebody was trying to port the thing to MacOSX but went away again.  And the 
guy who was getting some subset of the applets running on newlib/libgloss...)

> > Besides, all these
> > #defines are already in a standard header file if you're building on a
> > system that can actually use the result.  (If they're not in your header,
> > that means the kernel headers you're using don't know about that call,
> > and thus you probably shouldn't be using it.)
>
> And if you're building on an old(er) system, but run on a newer one?

If you have an older build environment, that limits the functionality binaries 
you build can access out of a newer system.  This issue isn't specific to 
busybox, this is in general.  Trying to provide every missing system call and 
longer ioctl structure and so on in your own code is not only a nightmare, but 
it's not our job.  The C library provides that stuff, that's its' job.  
Reproducing it in busybox, a project intended to be smaller and simpler than 
the alternative implementations it replaces, is probably not a good idea.  If 
busybox _isn't_ smaller and simpler, there's no point in reinventing the 
wheel.

The horrible, horrible, horrible history of loop.c is one example of where we 
couldn't quite avoid this, and had to settle for minimizing it.  Once upon a 
time I managed to localize the horribleness to an #else for the 2.4 kernel 
(look at the libbb/loop.c part of "git show 6a6798b8e47c7"), and I'd hoped it 
could go away entirely when the 2.4 kernel finally fell off of people's radars.  
(Keep in mind 2.6 had only been out for a couple years at the time, and it was 
so new some distros most recent releases were still using 2.4.)

Unfortunately, looking at it now, none of the old horribleness ever expired, 
and instead new #ifdefs grew up around it...

Um, I think this is wrong:

+
+/* For 2.6, use the cleaned up header to get the 64 bit API. */
+/* linux/loop.h relies on __u64. Make sure we have that as a proper type
+ * until userspace is widely fixed. */
+# if (defined __INTEL_COMPILER && !defined __GNUC__) \
+  || (defined __GNUC__ && defined __STRICT_ANSI__)

What does __INTEL_COMPILER or __STRICT_ANSI__ have to do with a linux kernel 
header?  The file "linux/loop.c" is exported by the kernel source via "make 
headers_install".  It has nothing to do with your compiler, it's a Linux 
kernel header.  It's supposed to match your Linux kernel version, not your 
compiler version.  (And technically it's your C library that the kernel 
headers are exported to, not your compiler at all.)

+__extension__ typedef long long __s64;
+__extension__ typedef unsigned long long __u64;
+# endif
+# include <linux/loop.h>

The linux/loop.h header #includes either asm/types.h or linux/types.h 
(depending on kernel version) to get the definition of __u64.  There's a 
comment to that effect in the kernel headers, which come from the Linux kernel.  
If somebody's build environment isn't getting that, then their kernel headers 
are broken.  (Most likely because they weren't exported properly.)

Busybox really shouldn't be working around obvious bugs in people's build 
environments, that way lies madness.

(By the way, the reason I didn't try to throw any of the loop.c setup in 
platform.h is precisely because it's so linux-specific, yet doesn't vary by 
target architecture.  The "losetup" command only existed on Linux, it's based 
around #including a header with "linux" in its name because that's the only 
place the ioctl structure for it was ever defined, and as far as I know other 
operating systems haven't got the loopback device association system call 
unless they're copying the Linux one.  Therefore, a "make this work on 
freebsd" checkin touching loop.c is WEIRD.)

> I suspect that was the original motivation for this.

Actually, the original motivation was to avoid build breaks in mount.c (which 
I rewrote three times trying to get it right).

The first #ifdef was pretty much me being lazy, if I added a proper config 
option for --bind and --move then I'd need to change the option parsing and 
help text, the quick and dirty way to make it build everywhere was just #define 
it if it wasn't there.  I expected old kernels that didn't support it to fall 
out of use anyway, so didn't put a whole lot of effort into supporting them.  I 
did a quick hack instead of a config option for it because I thought the 
problem was _going_away_, at which point the hack could be removed.

In general, older systems are yet more build environments most developers 
didn't tend to have lying around, which we couldn't easily test on, so we 
erred on the side of not build breaking on them.  That's why I put that Red 
Hat 9 image up in downloads/qemu, so we at least had the capability of 
regression testing against a common "old" system.  (The _interest_ in doing so 
is another matter; I just tried building 1.14.1 defconfig under that RH9 image 
and it died in miscutils/ionice.c.  Switching that off, it died in 
miscutils/watchdog.c.)

Even back in 2006 the majority opinion was already that Red hat 9 was probably 
too old to care about in new releases of busybox.  (If you want to use an 
older build environment, you can always download older busybox source to build 
under it.)  I was being a bit conservative at the time, largely because RH9 
was only about 3 years old then.  These days it's more like 7, and that's a 
very different threshold.

Beyond a certain point, newer busyboxes not working with older build 
environments (kernel, C library, compiler, make, command line utilities) is 
probably a subset of http://busybox.net/FAQ.html#backporting

It's a balancing act, but if you accept "simple" is one of the virtues of 
busybox, accumuluating cruft is bad.

> > What might be better is some kind of switch you can throw to trim this
> > functionality when it's not supported, to avoid a build break.  Either a
> > CONFIG option for "2.6 mount options", or a single "#ifndef MS_RELATIME"
> > to disable the lot of it, checking the most recent one.  (There's not
> > much point in adding extra granularity, special support for a 2.6.12
> > kernel as distinct from a 2.4 kernel doesn't really seem worth the effort
> > to me.)
>
> Feel free to send a patch for CONFIG option for "2.6 mount options".
>
> Another possible thing is to just wait a year and then declare that
> whoever still uses 2.6.12 instead of migrating to something
> less antiquated (less antiquated within 2.6.x world)
> is going to suffer, and delete the ifdefs.

I'd strongly lean towards the second.

On that note:

commit 4c5ad2fc90389bf1239f17d84967d07b82f31dd7
Author: Rob Landley <rob at landley.net>
Date:   Wed Jun 7 20:11:53 2006 +0000

    Consolidate devfs garbage and mark it as obsolete.

It's been over three years since then.  Can it go away yet?

Rob
-- 
Latency is more important than throughput. It's that simple. - Linus Torvalds


More information about the busybox mailing list