Hi folks! I spent a bit of time over the weekend trying to get AtomVM to compile for Android using NDK, and I’m proud to say I was able to make it work! It’s a bit hacky, and I’d definitely need some help turning it into a PR for more robust support, but I wanted to share my experience here in case it was helpful to anyone.
The full steps I took is in this GitHub issue on the AtomVM repo:
opened 05:43PM - 19 May 25 UTC
Hi there! Over the weekend I experimented with compiling AtomVM for Android, and… wanted to share the steps I took to get things working. I'm not particularly experienced in C programming, so I don't think my hacky approach is ready to be a PR, but I wanted to share the rough steps in case someone comes along later and wants to add more robust Android support.
1. First, I cloned AtomVM and followed the instructions to build on my MacOS machine.
2. Next, I installed ["NDK (Side by Side)"](https://developer.android.com/studio/projects/install-ndk#default-version) thru Android Studio's SDK Manager.
3. Then, I modified the `CMakeLists.txt` files as described below.
4. Then I built and copied the executable to an Android device via ADB and ran it as normal.
## CMake Changes
Some of these are necessary and make sense, but some are very hacky and would need a more robust solution. I based my Android build off of the `generic-unix` target.
- I modified `CMakeLists.txt` in the root, `src/libAtomVM`, `tests`, and `tools/packbeam` to add "Android" to the `CMAKE_SYSTEM_NAME` check.
- I configured the entire project to build with NDK by adding the following lines at the top of the root `CMakeLists.txt` file:
```cmake
set(CMAKE_TOOLCHAIN_FILE "/Users/<username>/Library/Android/sdk/ndk/29.0.13113456/build/cmake/android.toolchain.cmake")
set(ANDROID_ABI arm64-v8a)
set(ANDROID_PLATFORM 33)
```
- The above changes had the side effect of compiling `packbeam` under NDK as well, which caused issues later in the build when the `pack_archive`, `pack_runnable`, `pack_test`, `pack_eunit`, and `pack_uf2` macros tried to use the `PackBEAM` executable, which wouldn't run on my mac since it was compiled for Android :grin:
- I worked around this by hardcoding a path to a valid `PackBEAM` executable, but the proper solution would probably involve configuring CMake to ignore the NDK toolchain file, which I didn't spend a ton of time doing.
- The `define_if_function_exists` and `define_if_symbol_exists` macros were failing for some functions/symbols. It appears that NDK overloads these functions and that confuses the compiler somehow... Here's an example of the macro failing to compile for the `open` function from `fcntl.h`:
```
Change Dir: '/Users/<username>/Git/AtomVM/build_android/CMakeFiles/CMakeScratch/TryCompile-t7oowe'
Run Build Command(s): /opt/homebrew/bin/cmake -E env VERBOSE=1 /usr/bin/make -f Makefile cmTC_efb5e/fast
/Library/Developer/CommandLineTools/usr/bin/make -f CMakeFiles/cmTC_efb5e.dir/build.make CMakeFiles/cmTC_efb5e.dir/build
Building C object CMakeFiles/cmTC_efb5e.dir/CheckSymbolExists.c.o
/Users/<username>/Library/Android/sdk/ndk/29.0.13113456/toolchains/llvm/prebuilt/darwin-x86_64/bin/clang --target=aarch64-none-linux-android33 --sysroot=/Users/<username>/Library/Android/sdk/ndk/29.0.13113456/toolchains/llvm/prebuilt/darwin-x86_64/sysroot -g -DANDROID -fdata-sections -ffunction-sections -funwind-tables -fstack-protector-strong -no-canonical-prefixes -D_FORTIFY_SOURCE=2 -Wformat -Werror=unknown-pragmas -fPIE -MD -MT CMakeFiles/cmTC_efb5e.dir/CheckSymbolExists.c.o -MF CMakeFiles/cmTC_efb5e.dir/CheckSymbolExists.c.o.d -o CMakeFiles/cmTC_efb5e.dir/CheckSymbolExists.c.o -c /Users/<username>/Git/AtomVM/build_android/CMakeFiles/CMakeScratch/TryCompile-t7oowe/CheckSymbolExists.c
/Users/<username>/Git/AtomVM/build_android/CMakeFiles/CMakeScratch/TryCompile-t7oowe/CheckSymbolExists.c:8:19: error: address of overloaded function 'open' is ambiguous
8 | return ((int*)(&open))[argc];
| ^~~~
/Users/<username>/Library/Android/sdk/ndk/29.0.13113456/toolchains/llvm/prebuilt/darwin-x86_64/sysroot/usr/include/bits/fortify/fcntl.h:70:5: note: candidate address cannot be taken because parameter 1 has pass_object_size attribute
70 | int open(const char* _Nonnull const __pass_object_size pathname, int flags, mode_t modes)
| ^
/Users/<username>/Library/Android/sdk/ndk/29.0.13113456/toolchains/llvm/prebuilt/darwin-x86_64/sysroot/usr/include/bits/fortify/fcntl.h:59:5: note: candidate address cannot be taken because parameter 1 has pass_object_size attribute
59 | int open(const char* _Nonnull const __pass_object_size pathname, int flags)
| ^
/Users/<username>/Library/Android/sdk/ndk/29.0.13113456/toolchains/llvm/prebuilt/darwin-x86_64/sysroot/usr/include/bits/fortify/fcntl.h:49:5: note: candidate function
49 | int open(const char* _Nonnull pathname, int flags, mode_t modes, ...) __overloadable
| ^
/Users/<username>/Library/Android/sdk/ndk/29.0.13113456/toolchains/llvm/prebuilt/darwin-x86_64/sysroot/usr/include/fcntl.h:132:5: note: candidate function
132 | int open(const char* _Nonnull __path, int __flags, ...);
| ^
1 error generated.
make[1]: *** [CMakeFiles/cmTC_efb5e.dir/CheckSymbolExists.c.o] Error 1
make: *** [cmTC_efb5e/fast] Error 2
```
- The full list of missing functions/symbols were:
- `open` from `fcntl.h`
- `O_EXEC` from `fcntl.h`
- `O_SEARCH` from `fcntl.h`
- `O_TTY_INIT` from `fcntl.h`
- I'm not sure the correct solution to this problem - but I worked around it by manually hardcoding the macros for the missing functions, like this:
```cmake
target_compile_definitions(libAtomVM PUBLIC HAVE_OPEN=1)
```
- The above workaround worked for `open` but did not work for the other symbols in `fcntl.h`. AtomVM appeared to compile fine without those other symbols, but I'm guessing it's something we'd need to fix eventually. Interestingly, the missing `open` appeared to be that overload issue, but the missing `O_EXEC` and others seemed to actually be missing from NDK based on my CMake logs.
## Conclusion
Overall, aside from the few workarounds, AtomVM seemed to run on Android just fine! I'd definitely be interested in making Android more of a first class target, but I'm not an expert enough in the C ecosystem to do it myself - would love to pair with someone if that's something anyone is interested in! And if not, at least this issue should exist to help others find a good starting point.
4 Likes
This is really cool! I hope someone can pick this up. I would try, but I don’t have any Android devices. If we can get a workflow together to build and test this on the GitHub CI then we should be able to add Android to our supported platforms.
1 Like