dec1/Boost-for-Android

How do you force the build to set __ANDROID_API__ to something like 19. It defaults to 10000

Closed this issue · 19 comments

How do you force the build to set __ANDROID_API__ to something like 19. It defaults to 10000

libboost_thread has some posix calls that are not defined before api 21 e.g.:
cannot locate symbol "pthread_condattr_setclock" referenced by "libboost_thread.so"...
on a kitkat (4.4) system. How do I force the build to target a very old api? Using defaults, I see that in boost/thread/detail/config.hpp that my ANDROID_API is set to 10000 (which means android future api).

dec1 commented

I presume you mean the ndk platform (api) version as in
$NDK_DIR/platforms/android-$APILEVEL ?

Boost-for-Android builds boost with (ndk) api level 16 (by default). Which is the lowest version currently shipped with googles ndk.

See LOWEST_NDK_API_LEVEL=16 in build_tools/build-boost.sh

You can change this if you want but it has the lowest possible value because (in contrast to the java api) binaries compiled with a lower version are forward compatible with those compiled with a later version

I see that in boost/thread/detail/config.hpp that my ANDROID_API is set to 10000 (which means android future api).

I can't confirm. This file just seems to have some checks as to whether the API_LEVEL is greater than 21

Not quite.

This is not about the platforms, it's about controlling boost so that the code that calls posix pthreads doesn't get compiled in so the boost libs will work on the older OS's. The LOWEST_ND_API_LEVEL doesn't change the default ANDROID_API setting which is what the boost libs and the code in the ndk sysroots are basing their behavior off of.

This is a pointer to the pull request in boost that fixed it as well as the boost issue:
boostorg/thread#216
boostorg/thread#215
These are why the thread config.hpp is checking for api >= 21. Sadly my target api is 19...

So, What I need is to set the ANDROID_API define. I could probably just pass it in as a cxxflag -D__ANDROID_API__=19 if I could get jam to do so, but I am not conversant enough with jam to know how to yet.

I think I used to be able to set this in the .mk files.

dec1 commented

LOWEST_NDK_API_LEVEL=16 in Boost-for-Android should cause boost to get built with $NDK_DIR/platforms/android-16.
As far as I can tell this where __ANDROID_API__ gets its value (10000 is an initial value that gets 'overwritten' later - try outputting the value eg with #pragma message).

For the NDK, this is set by the compiler/build system based on the API level you claimed to target

So you are targeting api 16. (The boost binaries thus built should work on any device with api >= 16).

The patch should fix the issue with pthread_condattr_setclock, so Im not sure what is not working for you.

Is something actually not working for you?

Yes, something is broken. Namely if I try to load libbosst_thread.so on a KitKat 4.4 system I get an exception because it still has pthread_condattr_setclock in the library and the OS (4.4) does not provide it.

If I force the boost/thread/detail/config.hpp header file to dump the value of ANDROID_API using a stringify approach
#define STRINGIFY(s) XSTRINGIFY(s)
#define XSTRINGIFY(s) #s
#pragma message ("ANDROID_API=" STRINGIFY(ANDROID_API))

it shows ANDROID_API is set to 10000 (ANDROID_API_FUTURE) when this file gets preprocessed. I'm assuming this is due to the android unified headers change which means that the platform/android-16 isn't setting the ANDROID_API level as far as I can tell. see https://android-review.googlesource.com/c/platform/ndk/+/239934

If I call b2 in build-boost.sh with the additional line”

   define="__ANDROID_API__=19"  \

then my ANDROID_API stringify message comes out as 19 and libbosst_thread.so loads. I’m still in the process of determining if I’ve got full functionality.

I tried modifying the project-config.jam but that didn’t work well for me given my very limited understanding of jam.

This pre api 21 issue also applies to boost::filesystem, see:
boostorg/filesystem#65

I was hoping there was a clean way to force api 19 on the 32 bit libraries and leave the 64 bit libraries as is. This is because the support for 64 bit cpu’s came in in 5.0

dec1 commented

Seems like the build should define __ANDROID_API__ to something other than 10000
See here.
A standard android studio project (like the test app) has __ANDROID_API__ set correctly. Presumably cmake sets it automatically based on the minSdkVersion in the gradle build file. But as you say when building boost with Boost-for-Android its (still) 10000, set initially here.

I’m still in the process of determining if I’ve got full functionality.

I take it everything is working fine since you defined it manually?

I just managed to do a full test on a 4.4.4 device and all seems well if I define the ANDROID_API=19. I have a commit in progress that allows you to set defines in doIt.sh and I have build_boost.sh takes in the list of defines as a command line argument. Similar to how you deal with ABIs. I'll try to submit the PR tomoro for comments.

dec1 commented

OK. Thanks. Please use the "dev" branch

PR done.

bump?

dec1 commented

Sorry for the late reply.

Thanks for the pull request which has been merged.
Im not sure however if I want this in the main branch.

Even though its nice to be able to add defines like this, it does come at the cost of adding complexity to the interface, and I don't really see an application apart from defining ANDROID_API.

And for ANDROID_API I think its not an ideal solution.
Ideally ANDROID_API should be set automatically based on LOWEST_NDK_API_LEVEL, which in turn sets the android platform level used. Im however not fully sure how/why this is handled (for 64 bit builds) where you should need a platform version higher than the current value of 16.
Strictly speaking, trying to build a 64 bit target with a platform (eg 16) lower than when 64 bit support was added (ie 21) to android shouldn't work. But it seems it does.
Does it always get automatically get increased to the next highest platform level that supports 64 bit builds? This needs to be clarified (independently of the ANDROID_API).

Hmm, I see your point.
Here's some information and a suggestion for a different approach:
info ->
Why does this work with LOWEST_NDK_API_LEVEL set to 16 for 64 bit doodads?
Because in build_tools/build-boost.sh it checks the ABI and does:
local APILEVEL=$LOWEST_NDK_API_LEVEL
if [ ${ABI%%64*} != ${ABI} ]; then
APILEVEL=21
fi
so it corrects you if you are too low.
Right now this is ONLY used to set the sysroot for the boost build.

Looking into the boost code there are only 2 breakpoints for the ANDROID_API:
< 21 - this is for workarounds for old bionic stuff
< 24 for 64 bit filesystems:
boost/libs filesystems/src/operations.cpp -> // Android fully supports 64-bit file offsets only for API 24 and above.
Suggestion:
Rather than complicating the interface (you are right) what if we set
ANDROID_API= LOWEST_NDK_API_LEVEL and where it checks to see if the ABI is 64 bit, we set

ANDROID_API= MAX(LOWEST_NDK_API_LEVEL,21 ) (right now it just sets it to 21.

This would make the LOWEST_NDK_API_LEVEL actually work for lower levels and you could actually force boost filesystems to be 64 bit compatible as well if you want to.
We would then pass the ANDROID_API define into the boost build so it had an effect.

This seems cleaner to me and I'd be happy to do another PR if you agree with this approach. Please let me know if you like it or have a better suggestion :).

dec1 commented

Thanks for looking into that and well spotted.
Then Id say the way to go would be as you suggested:

set __ANDROID_API__ to LOWEST_NDK_API_LEVEL at the beginning of build-boost.sh
and here

if [ ${ABI%%64*} != ${ABI} ]; then
APILEVEL=21

where APILEVEL gets set to 21 then instead set APILEVEL to MAX(LOWEST_NDK_API_LEVEL,21 )

and

pass the __ANDROID_API__ with the value of APILEVEL as a define into the boost build

Also test everything to see that the resulting boost binaries are working as expected

If you want to do this and create a pull request to the dev branch that would be great.
Thanks in Advance.

dec1 commented

< 24 for 64 bit filesystems:

Do you mean '>24' ?

dec1 commented

You seem to not have read my messages above?

You are correct, I missed some messages since I was reading the responses on my phone email... which worked poorly.

I will go ahead and make a PR against dev sometime over the next few days doing what we outlined above.

The "< 24 " part is just how the boost code is set up. It's not something we would need to deal with. Basically, if you set the ANDROID_API to 24 or more you get some additional 64 bit filesystem capabilities. Otherwise, they are not supported. I'll add a comment next to where you set the LOWEST_NDK_API_LEVEL so people know what they are picking between.

dec1 commented
dec1 commented

Hello.

Ive implemented this (defined __ANDROID_API__ during the boost build) now in the branch
__ANDROID_API__.
Can you perhaps take a looks and see if this works for you?

Thanks in Advance