[Toybox] Fw: Building Linux with Toybox

Rob Landley rob at landley.net
Wed Sep 2 22:18:56 PDT 2020


On 9/2/20 8:20 AM, Porter, Jeremy wrote:
> 
> On 8/28/20 11:56 AM, Porter, Jeremy wrote:
>>> I have RISC-V based cross compiled Linux running busybox. I have a very simple
>>> /etc/inittab file like this:
>>> 
>>>   1 ::sysinit:/bin/busybox mount -t proc proc /proc
>>>   2 ::sysinit:/bin/busybox mount -t tmpfs tmpfs /tmp
>>>   3 ::sysinit:/bin/busybox mount -o remount,rw /dev/htifbd0 /
>>>   4 ::sysinit:/bin/busybox --install -s
>>>   5 /dev/console::sysinit:-/bin/ash

That's trying to run busybox on a system that hasn't got busybox installed. Have
you tried replacing that with /bin/toybox?

>>> How can I translate this to something toybox can use? I've tried this:
>>> 
>>>   1 mount -t proc proc /proc
>>   2 mount -t tmpfs tmpfs /tmp
>>   3 mount -o remount,rw /dev/htifbd0 /
>>   4 #::sysinit:/bin/toybox --install -s
>>   5 #/dev/console::sysinit:-/bin/sh
>>   6 exec toybox init
> 
> And when you tried it, you saw what output?
> 
> ###Output below###
...
> Freeing unused kernel memory: 372K
> Run /init as init process
> Started init

Hmmm...

$ grep Started toys/pending/init.c
  printf("Started init\n");

Yeah, looks like it ran the init program. Not sure what the init program is
doing, it's been about 5 years since I last looked at it. To be honest, I'd
stick printf()s into the thing to debug it at this point. (I didn't write that
one, and haven't properly reviewed it. Hence "pending".)
> ###End Output###
> 
>>Toybox init is still in pending, and thus isn't in the defconfig build. It
>>hasn't undergone the full https://urldefense.com/v3/__https://landley.net/toybox/cleanup.html__;!!KGKeukY!l7f45aEjunFct2lAgh4PDXhjANSCxgr8ttibt-bfdygS30JJiBTR4QnjWXtLgD9rdq9bWHVPI8jHzw$ 

urldefense? Why is your mail client inserting gratuitous tracking wrappers into
your replies?

> review yet, so
>>I couldn't tell you what it does. (I'm told it worked for the people who
>>submitted it...)
>>
>>Toybox has a built-in system builder:
>>
>  
> https://urldefense.com/v3/__https://landley.net/toybox/faq.html*mkroot__;Iw!!KGKeukY!l7f45aEjunFct2lAgh4PDXhjANSCxgr8ttibt-bfdygS30JJiBTR4QnjWXtLgD9rdq9bWHWy5UZWrw$
> 
>>
> 
> I've been trying to get this working but I get:
> 
> ./scripts/mkroot.sh
> Building natively
> /usr/bin/ld: cannot find -lc
> collect2: error: ld returned 1 exit status
> Warning: host compiler can't create static binaries.

As that warning says, your host compiler hasn't got the static version of the C
library installed, ala /usr/lib/x86_64-linux-gnu/libc.a

I'm guessing you're using Red Hat? It's a uniquely crippled distro that removed
support for static linking because Ulrich Drepper was insane, and even after he
left they refused to admit they'd made a mistake. You need to either track down
the glibc-static package (which they moved out of their main repo for some
reason) or install a real compiler toolchain. (You can use musl-cross-make, or
llvm, or the android ndk, or install a debian chroot and build in there, or...)

> cleaned
> gcc -o kconfig/conf kconfig/conf.c kconfig/zconf.tab.c -DKBUILD_NO_NLS=1 \
>         -DPROJECT_NAME=\"ToyBox\"
> scripts/genconfig.sh
> yes '' | kconfig/conf -o Config.in > /dev/null
> scripts/make.sh
> Generate headers from toys/*/*.c...
> generated/newtoys.h Library probe...........
> Make generated/config.h from .config.
> generated/flags.h generated/globals.h generated/tags.h generated/help.h
> Compile toybox....................../usr/bin/ld: cannot find -lc
> collect2: error: ld returned 1 exit status
> make: *** [toybox] Error 1
> 
> I'm also using RISC-V so I'd have to add a target to the script. I don't mind
> doing that, but I want to get something simple working first.

Just set CROSS_COMPILE= to your compiler prefix (which usually needs a trailing
dash, easy to forget).

I.E. https://landley.net/toybox/faq.html#mkroot references
https://landley.net/toybox/faq.html#cross and you can either set "CROSS=" to a
simple name and have it expect to find stuff via a ccc symlink with standardized
names, or you can set CROSS_COMPILE=big-long-prefix- in a more traditional manner.

Assuming your cross compiler toolchain contains static libraries, that should
also solve the other problem. :)

>>And the init script it uses starts at:
> 
> https://github.com/landley/toybox/blob/master/scripts/mkroot.sh*L73

>>The downside of the project not being to 1.0 yet. :)
> 
> I actually don't need route or sh. My system is a very minimal.

You'd need sh to run the init script I referenced above. If you rdinit=/mybinary
then you don't need it.

> I suppose sh
> could be useful to get something happening in toybox init or oneit, but I don't
> have any specific requirements for it. I can put it in to get it working--it's
> still smaller than busybox.

toysh is, alas, also in pending. But it's under active development by me and is
something like 2/3 complete? The main rough edge you'll hit is it doesn't have
interactive comnad line editing (or shell function support) yet. I just added
support for switch/case statements, am about halfway through wildcard support,
and last night I did the first half of teaching brace expansion about {1..5..2}
ranges.

(Android's been using mksh so far. I'm trying to provide a better shell
implementation, but it's not quite there yet.)

>>> It's starting partially (I think) but I'm not quite sure how to troubleshoot
>>> this.
> 
>>Without seeing what it produced, I can't either.
> 
>> My goal is to have a very small Linux. It's around 3 MB file size right
>> now and takes about 5 MB of memory when booted. It looks like toybox might go a
>> little smaller if I can get it working.
> 
>>Try running /bin/sh as pid 1, and run your statements from the command line to
>> see what they do?
> 
> I don't have sh, but I can put it in to do this.

I note that init tends to wash things through /bin/sh because that's what
system() (I.E. "man 3 system") does. Checking the code, it looks like it only
does so if it finds shell metacharacters in the output:

  if (!strpbrk(command, "?<>'\";[]{}\\|=()*&^$!`~")) {
...
  } else {
    snprintf(toybuf, sizeof(toybuf), "exec %s", command);
    command = "-/bin/sh"+1;
    final_command[0] = ("-/bin/sh"+!hyphen);
    final_command[1] = "-c";
    final_command[2] = toybuf;

So _maybe_ you don't need /bin/sh installed? (Dunno, depends on your setup. The
example "translated" inittab you posted looks like a shell script and ends with
an exec command.)

>>You can also stick in "echo" statements to see what's being output, although if
>>your initramfs hasn't got a /dev/console entry you won't have a stdout until you
>>mount devtmpfs and redirect it yourself, but it looks like you're using
>>/dev/htifbd0 as your root so presumably you're using the root= fallback logic
>>which creates a temporary /dev/console node to attach PID 1's stdin/out/err to,
>>so this doesn't apply to that case...
> 
> Again, I don't have echo, but I can put it in and try this. I gave it a try, but
> I'm having some issues with the build (I suspect).

About 15 years ago when I maintained busybox, I wrote documentation on debugging
init failures, and what I wrote is still there and mostly still applies:

  https://busybox.net/FAQ.html#init

Query: If you're running a dedicated app, why do you need init? Why not just run
your app directly?

>>Rob

Rob


More information about the Toybox mailing list