Is it possible to run the BEAM from C without compiling it first?
I’m trying to get Erlang and Elixir working in a mobile app. I am currently exploring Android NDK which has good support for C/C++ so it seems entirely possible that I should be able to use the BEAM source code here and essentially ‘extend the BEAM’ so when it compiles it wraps the whole app and the BEAM together into an Android APK. At the moment I’m trying Android but I’d like to get it working in iOS as well. I think it should work with a similar strategy.
I wouldn’t expect to have ‘command line’ access on the mobile device especially since I’m trying to build a proper app not for a rooted device so I wouldn’t be able to ‘install’ Erlang (or Elixir) for that matter.
I’ve already downloaded the Erlang source and am looking through the Makefile, etc for clues but I thought I might as well ask to see if someone else has some better knowledge.
My intent is to run the BEAM from C then somehow feed it
.erl files and eventually get Elixir working on it as well.
This is to this end.
Any tips or direction would be helpful.
Edit: I found this alternative which would enable including the binary on Android but I don’t think it would work for iOS as Apple is… well Apple.
Calling @rvirding if you’re around…
you might want to consider playing around alternative BEAMs, lumen is of course rust, so that’s a no-go, but there’s also atomvm, which is in https://github.com/bettio/AtomVM, which is much simpler (but also only 32-bit)
I’m here but not every day.
Do you have an idea of how I could package the BEAM code and essentially call it from C from within a mobile app? Any other pointers?
If you were hoping to ever make an app for iOS then trying to package the BEAM into an app probably wouldn’t pass Apple’s App Store guidelines; there’s a reason nobody has just ported an Android app written in Java to iOS by simply moving a Java runtime to iOS and translating Android system calls to iOS ones. (Although that may just be that Apple wouldn’t let apps that look like Android ones onto the App Store.)
However, that does not mean you shouldn’t try to do this. What I would do is look into the arguments used to launch a program and examine the source code of the main executable at the point when it takes those arguments. Now, I don’t know at which point the BEAM loads the first files before a hot reload, but if that happens in the same function or if you can track down to where that happens you could rewrite it so that all the data returned is just your BEAM files hard coded as the output. After removing the need to read the filesystem after starting the program, you could examine all the other arguments to the BEAM and hard code those as well. Finally, I would probably rename function from what I assume is called “main,” and then call it from what ever C code I need.
Do note that I am not an avid C programmer nor have I gone further beyond just slightly tinkering with the BEAM source code. Also, due to the hot reloading feature of the BEAM I really do doubt that Apple would let it onto their App Store.
FWIW, there’s this project from 2011:
@LTheGreats @al2o3cr There are several cross platform tools using C++ to generate apps for Android and iOS so I’m loosely assuming it will be possible to compile the BEAM source code for both platforms.
My plan is to have the BEAM running and then feed it Erlang and Elixir code. If it doesn’t have hot reloading it’s going to miss the target of hot reload for app development which is a major priority for me. I’m trying to mimic what is already standard in React Native and Flutter which both have hot reloading. Without it app development will be quite slow.
I don’t see this as a blocker for Apple. It’s not actually recompiling, it will just be interpreting the code sent to it. The hot reloading behaviour of the BEAM is not restarting it just swapping out the old version of code for the new one.
And that is precisely what would block Apple from allowing it. Apple does not allow apps written like that on the App Store. Flutter apps are compiled once they reach the app store and don’t have code reloading at that point, but in for that to work with the BEAM you’d need to rewrite it to load code differently. This isn’t a technical problem of Apple’s operating system being unable to do it, but rather a problem of Apple being unwilling to ship stuff like that on their distribution platforms.
CodePush seems to be pulling it off somehow. I guess I’ll cross that bridge when I get there. Maybe we’ll have to bundle the code for release or something.
The BEAM is not designed to be called, it is a central loop, or a number of them to be exact, which are continually running or waiting for signals from the “outside world”. So calling it is not really what it is about.
Would it be possible to run it on a background thread and send messages to that thread in order to execute Erlang and Elixir code?
That sounds like a similar concept to using the BEAM’s ports to call C code, however I don’t believe iOS supports having apps call foreign executables, and I’m pretty sure Android doesn’t aswell, but it might.
It wouldn’t be foreign, just two threads of the same program. Start the BEAM in a background thread and send Erlang and Elixir code to it in the foreground thread. I’m not sure if this would have to be a C port or what exactly. I also found this BEAM node implementation in C++ that might work for simulating another node.
As long as I can send code in either through a C port or another node I think I can get it to work.
Currently it is possible to compile (working for arm64) and start OTP either using NDK or directly from java. The example of starting the OTP is on my fork and JeromeDeBretagne’s, these examples have OTP-23 compiled binaries, in theory it should work on IOS also, you will have to try for yourself since I don’t plan on supporting IOS.
Now there is a new problem, starting android11 (api 30) you can no longer execute binaries from unsafe places, this means that the example provided will not work if you target API-30.
There are 2 ways you can solve this problem:
- Linking the binaries at runtime, the problem is that this is not possible currently in OTP, refer to this issue for more information.
- Build OTP as a .so library. This solution is the way to go in the long run. Platforms like xamarin adopted this long ago and it works without any problems in android 11. The problem is that this is a very hard task, taking in consideration the sparse documentation available for creating build scripts.
For more information about all of this you can read here.
@D4no0 Thank you so much. This gets me further down the road. I’ll give it shot soon and report.
Really? How does termux handle this? For that matter will F-droid work down the road?
Not directly related to this but I think BEAM by default uses busy wait for schedulers. You should probably disable that on Android so you don’t drain battery fast.
Background services get killed very fast on Android once the user leaves the app. Battery usage should therefore not be a problem.
But it will take more battery when app is running because of the busy wait