A colleague at work came yesterday with an interesting problem:
We have a few long Erlang modules that we would like to use from other languages. Ideally, we would like to be able to call the functions in this module from C. The modules do some string parsing and based on input values, they return another string. The modules mainly use pattern matching, records and lists module but they don’t use processes or any other OTP features. We don’t expect the modules to change a lot and we would like to avoid rewriting them in C.Having two version can ended diverging if they are not properly maintained.
I had a quick look on the internet and I found this issue in the rebar3 project where they explain different ways to wrap the modules with ERTS so it can be run as an executable.
This solution might work for us since we can pack the executable and call it when we need it. However, I was wondering if there are other ways of achieving this. I know Erlang uses now BeamAsm but I know very little about it. Could be used BeamAsm to compile .beam file into some other format and call them from a C program (maybe using asmjit)?
The beam byte code and runtime are very heavily connected, even for seemingly simple things in a module. So while it could be possible, it would be a lot of work to disentangle them enough to be able to do what you want.
You can use erl_interface to act as an Erlang node and implement an RPC call to a server process on a real Erlang node. Or maybe even the RPC server process rex on the Erlang node.
If you do not need it to be super performant, you could add a port module on the erlang side and communicate with C via stdin- stdout.
I was thinking to wrap everything in an executable as explained here and communicate by stdin/stdout as you suggested. What is the advantage of adding a port module? Would it make the executable smaller or similar?
You can use erl_interface to act as an Erlang node and implement an RPC call to a server process on a real Erlang node. Or maybe even the RPC server process rex on the Erlang node.
That would be cool but we were looking to avoid depending on another node. I haven’t explained before but we currently have a webserver that does it for us so it wouldn’t be very different. I would have a look how to implement it with erl_interface though because it sounds interesting
On using a port (or some kind of stdin-stdout):
if your erlang modules are currently running in some release, you could minimize the effort
by just adding this new communication module.
No need to create a new executable with a deployment procedure…
But this of course very much depends on your situation.
If I remember correctly, Maurice Castro wrote an Erlang implementation
that compiled to C. I’ve seen a claim around that you can’t really
compile a language like Erlang to C, but it’s been done for Scheme,
for Prolog, for Mercury (think of it as industrial-strength Prolog with
strong static types and modes), and indeed for Erlang.
If you are concerned with a subset of Erlang not including processes
(which has me imagining a subset of Fortran without floating-point
numbers (:-)), this should be relatively straightforward, except that
you will still need library support for integers – typically GMP and
you will still need garbage collection.
How much code are you talking about?
What range of Erlang constructs does it use?