-
-
Notifications
You must be signed in to change notification settings - Fork 37
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Use llvm-readelf
to detect and bundle needed dynamic libs for Android
#65
Conversation
xbuild/src/command/build.rs
Outdated
|
||
let ndk = env.android_ndk(); | ||
|
||
let search_paths = []; // TODO: deps dir and everything from `cargo:rustc-link-search=` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll implement this in a separate PR later when needing it; for now I only really care about libc++_shared.so
and would also like to bundle custom libs which are dlopen
ed at runtime, also for a separate PR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess it's probably easier to review the entire "dynamic library" handling at once? Also need some kind of test/example so we can check that it works for all platforms in ci.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I implemented the missing bits, will see about some CI action to test this functionality next.
@dvc94ch How should we implement this for MacOS and iOS and the other targets? |
not sure, will have to try. at least for ios we don't need to bother, since rust doesn't support building dynamic libraries for ios. and I really don't have the time to mess about with major change proposals. |
Thanks, as I'm not sure what you can do in terms of the other packaging targets x supports. Will probably need some additional refactoring though :/ |
d7284c6
to
be51030
Compare
@dvc94ch Turns out GH actions CI doesn't ship with |
should probably be llvm-readobj (llvm-readelf is just a symlink). you should setup ci like done by windows actions.
|
Can't solve all problems at the same time. The clang/lldb/java/javac binaries are going to have to be preinstalled for the foreseeable future. It's possible we could try using rust-lld and llvm tools from rustup. Although it looks like it could disappear at any time since it's still a preview feature |
Oh okay, I thought it was already there. Will double-check the script and setup. |
e49abb9
to
c09ada3
Compare
So it seems I've been reading the CI results for at least https://github.com/cloudpeers/xbuild/runs/6261865757?check_suite_focus=true all wrong.
|
Why are you symlinking llvm-readobj-12? Maybe you're trying to run a dangling symlink? |
Shall I add a comment for these? Ubuntu only provides |
Looks like the CI succeeds now, thanks to the symlinks 🥳 @dvc94ch I'll add a test for a small C++ file through the |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looking good, thanks for working on this!
pub fn list_needed_libs_recursively( | ||
lib: &Path, | ||
search_paths: &[&Path], | ||
provided_libs_paths: &[&Path], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
think we should change this logic. instead of a provided_libs_paths we should have a blacklist. this way we can maintain a text file of libraries not to include for each platform.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That sounds like a lot of work to update and maintain?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also if we don't update this with new libraries, the logic will just copy the new libraries even when they are already available on the phone, making an APK unnecessarily bigger than it needs to be.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note that none of the items in provided_libs_paths
is used to copy or blacklist anything at all. That only happens for search_paths
. The goal of provided_libs_paths
is to at least validate that a library is available (without copying it!) so that we can otherwise provide an error instead of having the app fail at runtime.
(Except the libc++_shared.so
edgecase - it's just that, a single edgecase)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
for linux we already have an excludelist [0]. for android we can compute the exclude list by finding all libraries in provided_libs_path - libc++_shared.so. if it's in the exclude list we skip it otherwise we use search_paths to locate it and include it. for macos/windows we can compute the exclude list similarly.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
well, it contains the library name not the path. the block list would be all file names with an so extension within provided paths. so something like filename(find provided_libs_paths | grep *.so)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
in a sense it's already an excludelist, was just suggesting how to generalize it. it requries a bit more work but should be more generic.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ah, this is good enough for now, let's just merge it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you have a fair point yes, but as pointed out below perhaps you weren't aware that provided_libs_paths
is not included in search_paths
currently.
Perhaps we can improve that as I quite like your suggestion. It is indeed already converted into an exclude list, with libc++_shared.so
removed from it:
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ah, this is good enough for now, let's just merge it.
Your call, we can also merge it now and improve in the future. I don't mind either way, I think we just misunderstood each others ideas in the beginning :)
provided_libs_paths | ||
} else { | ||
search_paths | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yep, this needs to go. you can compute the blocklist for android by searching the provided_libs and filtering for libc++_shared.so
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
And then I copypaste that to a list somewhere... And document the manual commands/steps someone needs to go through to regenerate that list? Please no :(
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note also that your change implies that we'll add all the Android library paths from provided_libs_paths
to search_paths
which pretty much defeat the purpose since there's exactly one library from there that we need to copy, the rest should not be copied but only used to validate that all dynamic-link dependencies are met.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
provided_libs_paths must already be included in search_paths. the search paths are anything added via -L
, otherwise there's a bug.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
They are not, and it should be by design?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
well, maybe it's just named confusingly. but if the search path is the same that is passed to the linker, then any library that was linked must be in the search path. So this means that libc++_shared.so
would be in both the search path and the provided path. So the provided path seems like it should be a subset of search path.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
libc++ is a poor example, since we actually want to remove it from the provided path.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah I think this does not match the search path passed to the linker. fn use_android_ndk()
adds it to the rustflags but that isn't propagated to here.
What do you think, should we also parse -L
from all the various rustflags sources (env var, .cargo/config.toml
, etc) and pass those paths into this code as well? Then we can rework it into a blocklist as well.
We can also do this in a followup PR to not enlarge this one even further, though. I prefer keeping changes small as long as they don't actively and obviously break someones workflow or have outstanding issues/smells.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that's too fragile. Wondering about taking a different approach. How about we get the linker to tell us which libraries it needs from where? It looks like ld.lld
supports a --Map=filepath
argument that looks like it would give us just that.
@MarijnS95 sorry for proposing all these last minute changes. Maybe if I'd have reviewed it earlier we could have been able to avoid it. To summarize my thoughs:
I think this is the most generic approach and should easily generalize to the other platforms. Sorry for making you jump through hoops. Once it's merged I'm commited to maintaining it, so we need to get the basic design right. |
@dvc94ch Apologies for pretty much dropping the ball on this, been running into many other things that had higher prio and so this notification slipped to the end of my queue. I totally understand where you're coming from and would love to do this differently too. The main pain-point being scanning various places for search paths and then perhaps not even maintaining the exact same order as Anyway, since you approved this PR: Do you want to get this initial implementation in first, and let me rework it in a future PR - potentially removing lots of code again - or rather get that done first in this PR or a new PR? I'm already using this branch in automated Android CI builds to not be blocked, but I don't like being a downstream :) |
xbuild is currently on hold, due to lack of funding and it not being a priority right now. I'm currently working on building the cloudpeer service. For this I started down the rabbit hole of building passwordless, an abstraction over roaming and platform authenticators. This in turn will require a lot of android apis for the android platform authenticator. android.security.identity and android.hardware.biometric, which is were I plan to fit in some experimentation with aidl. |
however for the time being if you fix the merge conflict I guess we can merge it. |
Ouch that's sad but very relatable. It works well enough for both our purposes (minus the few PRs I have open now) which I guess counts as "good enough" 😬. Thanks for bringing it this far though!
That'd be very nice to combine then :D
Will do, and will make a note to look into this because I'm curious to your |
Let's see if I resolved that correctly :) |
64e5ee2
to
c5addcc
Compare
Dynamic libraries that a Rust library links against while not being present on the target platform (`libc++_shared.so` and other custom libraries) need to be bundled in the APK specifically. This approach is adopted frm `android-ndk-rs` while switching from `readelf` to `llvm-readelf`.
Fixes #47
Dynamic libraries that a Rust library links against while not being present on the target platform (
libc++_shared.so
and other custom libraries) need to be bundled in the APK specifically. This approach is adopted frmandroid-ndk-rs
while switching fromreadelf
tollvm-readelf
.