How exactly does Elixir start your code?

Something I found myself wondering about recently, is how exactly a bunch of .ex files is actually executed.

I know that, if you have created a Mix project, you can run your files using Mix, which will compile your files and its dependencies, and finally run YourAppName.Application.start/2 (How does Mix know where to find this? I presume the application section of the mix.exs file, is that correct?).

But what if I wanted to, for the sake of education, try to run a project without Mix, how would this be done? I guess we first use elixirc to compile the .ex files, but what then? Where exactly does something become an OTP application?

I am very interested to learn how this actually works under the hood! :smiley:

2 Likes

@Qqwy: Have you looked at a build utility that allows you to to use mix packages in an elixir script? I think that should be better than plain scripts without mix. For example if you have test.ex in your current directory then you can run mix_script compile test.ex and finally you will have test binary that you can execute anytime you want. mix_script will automatically generate and compile your project into binary, so you do not need to create whole project for simple learning 5-minute code.
Hope that it will help you :slight_smile:

2 Likes

Yes, exactly. It points at your app module, which is expected to comply with the Application protocol.

2 Likes

Which uses elixirc to compile them to beam files in the _build directory.

Exactly, erlang has a standard of how/where to find the applications (so it knows how to launch them) and those settings in mix create the file _build/dev/my_server/ebin/my_server.app, which is the standard erlang method of ‘describing’ an application. In this file it is a single erlang term (documented in the erlang reference manual if curious about details) of the form (in erlang syntax since that is what it is, so lowercase-starting identifiers are atoms) {application, my_server, Opts} where Opts is an erlang property-list of settings, the usual ones are {description, "The string description of it"} (that is an erlang string, so a char-list), and {modules, Modules} where Modules is a list of atoms that the application ‘contains’ and supplies to the system, as well as other Opts like {vsn, "0.2.0"} and others. The 2 important ones to make sure your thing actually starts up right (technically modules could be left empty, you will just have issues with upgrading/downgrading/hotswapping and such) are the mod option and the applications option. The {applications, Applications} is an list of Application atoms that should be started before this application, and the mod option is of the form {mod, {ApplicationModuleAtom, Args}} where ApplicationModuleAtom will be something like 'Elixir.MyServer', which is your use Application module where start is called. The Args here is passed as the second argument to your application’s start/2 function, it’s usually just nil (Erlang’s nil, the empty list []) traditionally, but can be quite useful for loading the same application multiple times in to a system with different options in each (this takes more finagling that mix does not support).

The BEAM will read that file for each application and load the applications in order so dependencies are properly resolved. :slight_smile:

But yeah, Mix generates this file for you based on what it scans of your modules (auto-filled in modules section is awesome!) and so forth. :slight_smile:

It becomes an OTP Application via the *.app file above, we had to define that file ourselves ‘in the old days’. :wink:

4 Likes

Of course there is nothing stopping you from doing it the erlang way. Except a small little thing… You need to resolve dependencies because of macros.

Then just compile your sources in correct order, moving the BEAM files into their correct location such that elixirc can pick them up to execute macros.

Of course you’ll need to install dependencies manually as well, and you will be able to write your *.app file manually as you did back in those days.

1 Like

I think one that is useful here is to understand what is going on at a lower level when you create applications and releases. While you will generally use tools like mix, or rebar3 in the erlang world, to do this, knowing what is going on will definitely help you in the long run, especially if you need to do something the tools don’t do.

Some interesting links are into the Erlang documentation about Applications and Releases. These are at the low level but they do show what is going on. A good book is of course Learn You Some Erlang which has chapters on Applications and Releases. The whole book is very good, even if it is about erlang :wink:, as it goes through the whole functional/concurrent/fault-tolerant bits in a very good way. There are deeper books if you want more about systems.

Yes, these books are all in Erlang but at this level the mapping erlang<->elixir is pretty straight-forward.

IMAO going from erlang to elixir is easier than going the other way as the erlang language is simpler doesn’t contain so many features as elixir. And no, I have no intention into getting into a pointless argument about this, people get so worked up and lose their sense of humour.

7 Likes

Could you please list the titles? I know only about “Erlang and OTP in Action” and “Designing for Scalability with Erlang/OTP.”

They are the ones I mean, especially the 2nd. I can’t help you with the elixir books here I’m afraid.

1 Like