-
Notifications
You must be signed in to change notification settings - Fork 61
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
chore: android support #2554
chore: android support #2554
Conversation
You can find the image built from this PR at
Built from f46c028 |
I ended up disabling linking against libbacktrace when building for android. |
While attempting to compile for i386, I ran into this error:
Probably because we're linking against a |
I've run into this before - the solution is to add A static library ( Currently, both natpmp and miniupnp are built using their native build systems (cmake/make) - we've considered switching both so that nim builds them instead which "automatically" would take care of this problem and get rid of the need for cmake / make / etc in the build process significantly simplifying the whole setup - both for android and everyone else. This is something we do for practically all other libraries, ie secp, bearssl and so on. |
I think this is interesting for debugging purposes. Maybe we could check what happens (which error appears) by forcing an unmanaged exception somewhere in the code |
95700de
to
fd380ad
Compare
Just tested this in the example mobile app i created the other day, and was able to link succesfully against libwaku + librln in android! :) , I just had to do some minimal changes in the example to remove calls to libhello, and use instead
Originally It failed to load the libraries because i forgot to link against Now the next steps would be to figure out how to call functions from these libraries, probably by using the work @Ivansete-status has done for the go bindings, by adding a gomobile step, since it would be similar to what we would do in status-go... or perhaps we should use jni? 🤔. |
8d32e3e
to
786b4e3
Compare
library/libwaku.nim
Outdated
@@ -2,7 +2,10 @@ | |||
{.pragma: callback, cdecl, raises: [], gcsafe.} | |||
{.passc: "-fPIC".} | |||
|
|||
import std/[json, sequtils, times, strformat, options, atomics, strutils] | |||
if defined(linux): | |||
{.passl: "-Wl,-soname,libwaku.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.
Required so the dynamic linker/loader can resolve symbols at runtime.
@@ -39,6 +42,17 @@ const RET_MISSING_CALLBACK: cint = 2 | |||
################################################################################ | |||
### Not-exported components | |||
|
|||
|
|||
template foreignThreadGc(body: untyped) = |
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 use this template when executing the callbacks instead of having a single call. We need to ensure that Nim's GC can properly manage memory allocated by Nim code that might be running in other language threads.
library/libwaku.nim
Outdated
if defined(android): | ||
# Redirect chronicles to Android System logs | ||
when compiles(defaultChroniclesStream.outputs[0].writer): | ||
defaultChroniclesStream.outputs[0].writer = | ||
proc (logLevel: LogLevel, msg: LogOutputStr) {.raises: [].} = | ||
echo logLevel, msg |
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.
Without this, the logs for nwaku can't be seen unless we redirect somehow stdio to adb logcat
proc getNanosecondTime*(timeInSeconds: int64): Timestamp = | ||
let ns = Timestamp(timeInSeconds * int64(1_000_000_000)) | ||
return ns | ||
|
||
proc getNanosecondTime*(timeInSeconds: float64): Timestamp = | ||
let ns = Timestamp(timeInSeconds * float64(1_000_000_000)) | ||
return ns |
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 some reason proc getNanosecondTime*(timeInSeconds: int64 | float64): Timestamp
didn't work in Android x86. I think in practice these two functions I defined here have the same behavior 🤷
library/libwaku.nim
Outdated
proc waku_setup() {.dynlib, exportc.} = | ||
NimMain() | ||
if not initialized.load: | ||
initialized.store(true) | ||
|
||
# TODO: ask Ivan what is nimGC_setStackBottom for | ||
when declared(nimGC_setStackBottom): | ||
var locals {.volatile, noinit.}: pointer | ||
locals = addr(locals) | ||
nimGC_setStackBottom(locals) |
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 had to introduce this function waku_setup
in the bindings.
When I tried to use the original waku_init
function, Android crashed. Looks like NimMain() (at least on android) needs to be called before any nim logic is executed, because the code if not initialized.exchange(true):
that existed before did fail. I imagine it might be related to the initialized
atomic being setup by NimMain()
?
Anyway, I think I heard/read somewhere that NimMain()
function is not required in Nim 2.0? so perhaps on that version we can get rid of the existence of waku_setup
then.
Also, I couldn't find docs for nimGC_setStackBottom
. Is it really necessary?
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 imagine it might be related to the initialized atomic being setup by NimMain()?
I think you are right
Also, I couldn't find docs for nimGC_setStackBottom. Is it really necessary?
I could get some interesting explanations from ChatGPT about nimGC_setStackBottom
.
It should ideally be called at the beginning and is interesting to prevent stack issues, in async or multithreaded apps. By calling this function, we inform the GC about the stack boundaries.
I think this is ready for review. (The PR is big enough as it is right now).
|
this is really nice - does it make sense for any of it be ported back to nimbus-build-system or included in https://status-im.github.io/nim-style-guide/tooling.html ? |
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.
Went over it again and looks amazing :))
Thanks so much!
In tooling.html might be a good idea to document the process followed to cross compile android using the ndk toolchain. For porting back to nimbus-build-system, this part I'm not sure and would likely need your review to understand what can be extracted from waku repo to nimbus-build-system. The changes required for getting nwaku to run in android were few and limited to the Makefile and a config.nims file, as well as having a separate script for cross compiling RLN I think a good candidate could be to improve the build process for the nat-libs, to not have to require this target:
Which i had to add to delete the nat libs before building nwaku for android in the diff architectures, I'm thinking it should be possible to be able to specify the output dir of the libs somehow? |
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.
This is amazing ❤️ !
I just added some comments that I hope you find useful.
Not approving yet because few points to clarify:
- is it needed the change in
nim-chronos
andnimbus-build-system
? - We need to adapt the other examples so that the
waku_setup
is called at first. Or instead, try to avoidwaku_setup
. I will double-check if it is feasible to do so.
Congrats again for such wonderful PR 🥳
library/libwaku.nim
Outdated
proc waku_setup() {.dynlib, exportc.} = | ||
NimMain() | ||
if not initialized.load: | ||
initialized.store(true) | ||
|
||
# TODO: ask Ivan what is nimGC_setStackBottom for | ||
when declared(nimGC_setStackBottom): | ||
var locals {.volatile, noinit.}: pointer | ||
locals = addr(locals) | ||
nimGC_setStackBottom(locals) |
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 imagine it might be related to the initialized atomic being setup by NimMain()?
I think you are right
Also, I couldn't find docs for nimGC_setStackBottom. Is it really necessary?
I could get some interesting explanations from ChatGPT about nimGC_setStackBottom
.
It should ideally be called at the beginning and is interesting to prevent stack issues, in async or multithreaded apps. By calling this function, we inform the GC about the stack boundaries.
Yes, it's because of some issues I ran into that were fixed in specific PRs (merged already) |
33f2688
to
d4777b8
Compare
You can find the image built from this PR at
Built from 79d6465 |
You can find the image built from this PR at
Built from 79d6465 |
@Ivansete-status I implemented all the suggested changes except by calling the |
Hey @richard-ramos ! I've been playing and learning from what you've done :) I haven't found a way to avoid having the Nevertheless, I think is fine to have the Let me know if I can help to adapt the examples and include that new Besides, it would be useful to define the following macros at the top of
Then, the following can be added somewhere: |
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.
LGTM! Thanks for it! 💯 🥳
Congrats for such a great milestone that you've achieved!
Missing points:
- We need to adapt the examples to use
waku_setup
- Make sure the CI pass correctly. Your changes shouldn't impact the CI but we are having some flaky tests on mac-os
chore: disable backtrace for android feat: crosscompile rln for android refactor: properly build amd64 and arm64 targets refactor: makefile and build for all android architectures in a single step
fix: link against llog, lm, and lrln fix: remove additional instances of waitFor and attempt to get signal to fire refactor: bindings
@Ivansete-status I updated all the examples except the nodejs and python. Maybe later during the week we can pair program to add the waku_setup call? in the meantime, as soon as i get green lights i'll merge this PR since it's been open for a while and it's mostly complete :) |
Yes go ahead thanks! Cheers |
Description
Adds android support
To test this:
Architecures
Changes
unhandled exception: value out of range
ingetNanosecondTime
for 32b architecures(arm and x86)Use static linking for zerokit RLN (might not be a good idea since the resulting lib might be too large?). Decided against it. Resulting libraries are smalller this way and in the case of Android it's suggested that the app size should be < 100MB