[Toybox] [landley/toybox] Help building toybox with the NDK/bionic (#43)

enh enh at google.com
Sat Dec 24 11:40:44 PST 2016

On Wed, Dec 21, 2016 at 2:29 PM, Rob Landley <rob at landley.net> wrote:
> On 12/18/2016 12:52 PM, enh wrote:
>> for configure-like usage you'll need to generate a standalone toolchain:
>>   https://developer.android.com/ndk/guides/standalone_toolchain.html
>> (you'll also want to use --unified-headers when you generate your
>> standalone toolchain to get headers new enough to have any chance of
>> being useful.)
> I did that and got further. Starting with:
> $ CROSS_COMPILE=/opt/android/x86_64/bin/x86_64-linux-android- \
>   LDFLAGS=--static make defconfig
> (Yes you have to run the config stage with the same CROSS_COMPILE and
> LDFLAGS you're going to build with, or else it'll make a
> generated/Config.probed that thinks TOYBOX_SHADOW should be switched on
> when your toolchain hasn't got it, and so on.)
> Then I did:
> $ CROSS_COMPILE=/opt/android/x86_64/bin/x86_64-linux-android- \
>   LDFLAGS=--static make
> And it went:
> In file included from ./toys.h:9:0,
>                  from lib/args.c:12:
> ./lib/portability.h:274:33: fatal error: cutils/sched_policy.h: No such
> file or directory
>  #include <cutils/sched_policy.h>
>                                  ^
> I can add another compile-time probe for this, but I'm wondering if
> there's a way to figure it out from the #defines? You added it in commit
> e0dbc6beaf37:
> +#ifdef __ANDROID__
> +#include <cutils/sched_policy.h>
> +#else
> +typedef int SchedPolicy;
> +int get_sched_policy(int tid, SchedPolicy *policy);
> +const char *get_sched_policy_name(SchedPolicy policy);
> +#endif
> So presumably you understand when it is/isn't there? Anyway, when I #if
> 0'd that out, it got further but then died with:

the problem here is that libcutils is part of the platform, but not
the NDK. i think the right fix here is to have a probe for libcutils
(like there already is for libselinux)? or -- since the platform build
doesn't use your build system at all -- you can just change
__ANDROID__ here to anything you like, and i'll set it in the Android
build system's build system for toybox.

> toys/android/getprop.c:20:31: fatal error: cutils/properties.h: No such
> file or directory
>  #include <cutils/properties.h>
> I'm guessing that was the libselinux thing you were talking about,
> maybe? Anyway, I can switch that app off.

yeah, i think for now just turning off the android apps makes the most
sense. (these ones are slightly different to the one above in that we
can rewrite these to just use bionic's lower-level primitives. i'll
send a patch for that when we get closer to being able to build with
the NDK.)

> Then it died with:
> In file included from ./toys.h:9:0,
>                  from toys/android/log.c:22:
> ./lib/portability.h:13:18: error: expected ')' before '__attribute__'
>  #define noreturn __attribute__((noreturn))
> In file included from toys/android/log.c:23:0:
> /opt/android/x86_64/sysroot/usr/include/android/log.h:119:30: error:
> expected ',' or ';' before ')' token
>      __attribute__ ((noreturn))
> Which is really _weird_ but it seems like android/log.h #defining
> noreturn reaches back in time and breaks the earlier #define of
> noreturn? Or something? (gcc is weird.) Anyway, switching off the "log"
> command as well... And in addition to getprop, I have to switch off
> setprop, start, and stop because they all #include <cutils/properties.h>
> which isn't there.

hah. that makes me feel more vindicated about being anal with the
double-underscores. i often wonder whether i'm just wasting time when
i clean stuff like that up. anyway, looks like i already cleaned this
up in the platform
but that hasn't made it to the NDK yet. filed

> Then it made it through several commands, but the "eject" command died
> because:
> toys/other/eject.c:25:21: fatal error: scsi/sg.h: No such file or directory
>  #include <scsi/sg.h>
> Which is a linux-kernel header, but I can't say I'm hugely surprised.
> Switch that off...

yeah, it's a slightly weird header in that it's probably meant to be
public API but it's not a uapi header. for the platform we have it
(and a couple of other scsi headers) as a special case, but they're
not copied into the NDK. filed

> And it's doing pretty well through the rest of the commands. Lots of
> warnings about implicit declarations (gethostid, crypt) wandering by. I
> wonder if I can -Werror just _that_ error? (That's going to come back
> and bite me at link time, I just know it...)


> Yes. Yes it is:
> generated/obj/lib_lib.o:lib.c:function verror_msg: error: undefined
> reference to 'stderr'
> generated/obj/lib_lib.o:lib.c:function help_exit: error: undefined
> reference to 'stderr'
> generated/obj/lib_lib.o:lib.c:function mkpathat: error: undefined
> reference to 'stderr'
> generated/obj/lib_lib.o:lib.c:function yesno: error: undefined reference
> to 'stderr'
> generated/obj/lib_lib.o:lib.c:function yesno: error: undefined reference
> to 'stdin'
> generated/obj/lib_lib.o:lib.c:function bufgetgrgid: error: undefined
> reference to 'getgrgid_r'
> generated/obj/lib_lib.o:lib.c:function do_lines: error: undefined
> reference to 'stdin'
> generated/obj/lib_linestack.o:linestack.c:function draw_trim_esc: error:
> undefined reference to 'stdout'
> generated/obj/lib_xwrap.o:xwrap.c:function xexit: error: undefined
> reference to 'stdout'
> generated/obj/lib_xwrap.o:xwrap.c:function xprintf: error: undefined
> reference to 'stdout'
> generated/obj/lib_xwrap.o:xwrap.c:function xputs: error: undefined
> reference to 'stdout'
> generated/obj/hostname.o:hostname.c:function hostname_main: error:
> undefined reference to 'sethostname'
> generated/obj/md5sum.o:md5sum.c:function looplines: error: undefined
> reference to 'stdin'
> generated/obj/md5sum.o:md5sum.c:function looplines: error: undefined
> reference to 'stdin'
> generated/obj/hostid.o:hostid.c:function hostid_main: error: undefined
> reference to 'gethostid'
> generated/obj/mkpasswd.o:mkpasswd.c:function mkpasswd_main: error:
> undefined reference to 'crypt'
> collect2: error: ld returned 1 exit status
> So it couldn't find stderr, stdin, stdout, getgrid_r, gethostid, and
> crypt. Well that's a _manageable_ list, but the stdin/stdout/stderr
> stuff I can't easily patch around, that's posix:
> http://pubs.opengroup.org/onlinepubs/9699919799/functions/stdout.html
> I'm assuming that AOSP had stdin/stdout/stderr.

the problem here seems to be with the .a files. and it's not just
x86-64 (which was a possibility, since no one has ever shipped an
x86-64 Android device to my knowledge); it's that Android doesn't
really use static executables. it looks like the .so files are fine,
but the .a files have never really been updated. everything <21 for a
given arch is identical, and everything >=21 for a given arch is
identical. filed https://github.com/android-ndk/ndk/issues/272 to at
least start updating the modern ones.

you can probably work around this by targeting API 21, but then you
really will be missing some functions used by toybox.

> You can't error_exit()
> without verror_msg(), it's in pretty much every command. (I think if you
> build "false" standalone, it might get omitted... "make false", "objdump
> -d generated/unstripped/false | less"... Nope, it's still there.
> Probably shouldn't be. I'll throw it on the todo heap.) *
> I don't see a strong reason _not_ to have a gethostid(), but I could
> stub it out (or just do the syscall, or read /proc/sys/kernel/hostname)
> if you have one.

have you read the man page :-)

i haven't seen a system return anything but 0x007f0101 in decades.
(because who's not using DHCP?)

and that's without getting into the privacy/security issues.

this is the kind of thing we tend to prefer to leave broken because
it's a signal that you need to rewrite the calling code for it to make
any sense on Android. in this case, hostid(1) is useless, so i'd just
disable it. POSIX will catch up with reality in another 20-30 years...

> I can also probe/stub out getgrid_r() and crypt() which both fall under
> "do we have /etc/passwd or similar on this system". It would be nice if
> there was some sort of plan for setting up a "posix container" under
> android that understood 2 users (root and not root) so we can run AOSP
> builds as "not root", but that's a todo item. In the meantime consistent
> stubs would be nice. :)

there are *many* users on an Android system, with "root" and "shell"
probably being the two you're looking for. we have <pwd.h> and <grp.h>
even if they're a little unusual (you certainly wouldn't want to loop
through all the users/groups on the system, for example!). getgrid_r
is just too new to be in any libc.a (i built a non-static toybox
binary just fine).

crypt(3) is another deliberate "please stop and thing about what
you're doing" omission. Android code that wants this kind of
functionality should probably be using BoringSSL. folks trying to
manually mess around with /etc/passwd or /etc/group are going to have
to completely rethink what they're doing. the mkpasswd toy should just
be disabled on Android. (build/tools/fs_config is the closest

> Rob
> * Ah, it's because everything except true and false has --help output, and:
>   ./echo --help > /dev/full
>   echo: write: No space left on device
> That's why error_exit doesn't drop out. But I should probably let it do
> so when you've disabled CONFIG_TOYBOX_HELP_DASHDASH.

Elliott Hughes - http://who/enh - http://jessies.org/~enh/
Android native code/tools questions? Mail me/drop by/add me as a reviewer.

More information about the Toybox mailing list