asdf-vm/asdf-erlang

Support for precompiled binaries?

Opened this issue Β· 22 comments

thbar commented

When working on projects using asdf, I typically use Erlang in addition to Elixir and NodeJS, for instance.

Both Elixir and NodeJS are very quick to install, while Erlang is much, much longer (a typical install on a modern Mac machine takes around 5 minutes).

This also impacts Docker builds, even in harder ways depending on your configuration (could take 10 minutes), and are more ephemeral (so more likely to be rebuilt). It was so slow that on one project using the 3 asdf plugins mentioned above for local development, I had to skip asdf-erlang in the Docker build and instead install the binaries for Erlang manually.

I wonder if we could evolve this plugin in order to optionally support using the binaries now available at https://www.erlang-solutions.com/resources/download.html (at least for Linux/Mac OS X)?

Just a thought, I wonder what your position is on that.

Thanks for your work on asdf-erlang btw!

https://www.erlang-solutions.com/resources/download.html does not provide easy-to-use prebuilt package for macOS.

This also impacts Docker builds, even in harder ways depending on your configuration (could take 10 minutes), and are more ephemeral (so more likely to be rebuilt)

Could you explain why your docker build does not leverage cache? For example, you can even use multi-stage docker build and copy erlang to maximize caching.

Hi, @chulkilee. Can you give an example of such a multi-stage docker build with copying erlang to maximize caching? I have no clue which directories I need to copy.

Can it also support multiple Erlang versions?

FYI I'm working on adding binary releases upstream so if that lands you could use it here, see: erlang/otp#2936

thbar commented

@chulkilee

Could you explain why your docker build does not leverage cache? For example, you can even use multi-stage docker build and copy erlang to maximize caching.

Because I bump the version of OTP on a regular basis, for instance, causing the layer to be invalidated (it cannot be cached).

@archan937 check out configure option - you can install all files at own directory (e.g. /opt/erlang) instead of default (e.g. /usr/local) - just don't forget to add the bin path there.

@thbar I also update erlang regularly (as soon as new version is released), but it only takes 15 minutes one time for all projects, not 15 minutes for all projects, since I share one base docker image, and all projects just using the base image. BTW my base image does not use asdf-erlang though...

thbar commented

@chulkilee it is nice that it works nicely for you. You have "economies of scale" in your context, which is nice, and which is also not my case. I cannot share a base image in my context (that's how it is), and I cannot mutualise the build step between projects either efficiently (they belong to different clients), so for me this usually means 15 minutes (or more on occasions depending on the machine) per update, per project and also per developer.

I also think, having coached new Elixir programmers, that this quite hinders the newcomer experience to Elixir. The Elixir install is super fast, and Erlang takes ages. Having something precompiled would make for a better "try this" experience IMO.

I feel the pain! Yeah I'm also looking for precompiled binaries... πŸ˜‰ I believe @wojtekmach and Erlang Ecosystem Foundation are working on that matter...

Here are some notes (as far as you can run docker pull in your cases):

  • You don't need to share the base image with explicit tagging. You just need to use the exactly same steps after pulling the image using them. You may need to use --cache-from option of docker build as well. By doing so, you can leverage docker caching on dev laptops and CI as well.
  • Consider open-sourcing your "base" docker image, to reuse them freely across clients or projects. It allows making changes as needed, without waiting for official images. Here is my example for using Red Hat UBI - https://gitlab.com/chulkilee/docker-images - I have similar thing at work to push images to the internal repo.

One question to @wojtekmach

The compiled result by asdf-erlang on my mac - can it be freely copied to other mac under different path (e.g. different user name), as far as it has all the same packages (e.g. openssl from brew)?

The compiled result by asdf-erlang on my mac - can it be freely copied to other mac under different path (e.g. different user name), as far as it has all the same packages (e.g. openssl from brew)?

I haven't tried but I think it should be possible but it may require some manual steps. I believe part of the problem is some paths are hardcoded, e.g.:

$ cat ~/.asdf/installs/erlang/23.2/bin/erl | grep ROOTDIR=
ROOTDIR="/Users/wojtek/.asdf/installs/erlang/23.2"

There's ongoing work on making that easier: erlang/otp#2879.

I believe part of the problem is some paths are hardcoded, e.g.:

$ cat ~/.asdf/installs/erlang/23.2/bin/erl | grep ROOTDIR=
ROOTDIR="/Users/wojtek/.asdf/installs/erlang/23.2"

There's ongoing work on making that easier: erlang/otp#2879.

FYI a first solution is already available with erlang/otp#2863. The idea is to pass the different rootdir path in the ERL_ROOTDIR environment variable, as a way to override at runtime the hardcoded ROOTDIR in the script(s) from the compiled binaries. This was implemented mainly for a specific use case but it could be temporarily an option for your need.

The purpose of erlang/otp#2879 is exactly to answer such a need, once for all in a generic way and with no manual steps required anymore.

I added support for precompiled binaries here #190 but only for macOS as of today.

thbar commented

I have tested it today. Many thanks @seivan!

One caveat is that without upgrading asdf, things would continue compiling instead of using the binary version.

thbar commented

I spoke too soon, it is actually still grabbing the source version and compiling it. I will investigate.

One caveat is that without upgrading asdf, things would continue compiling instead of using the binary version.

@thbar I don't quite understand, you mean without upgrading asdf itself or the forked plugin?
Keep in mind if it can't find the version for your arch and major macOS marketing version it will fallback to source.
Do you happen to see it mentioning going the fallback route in the terminal?

thbar commented

@seivan sorry, as commented above, I'm not sure anymore of anything. I will investigate and will report back!

For linux precompiled binaries, since it doesn't look like the Erlang/OTP team will provide the binaries, would it make sense to use the builds packaged by the hex team? This is what the setup-beam action uses

edit: Here's a list of currently available builds for Ubuntu 20.04: https://repo.hex.pm/builds/otp/ubuntu-20.04/builds.txt

thbar commented

Heads-up: #190 has not been merged but closed, so if you try to understand why you do not get precompiled binaries, this is the reason.

Thanks to @seivan still, I'm pretty sure the whole ecosystem is going somewhere with this (see various efforts), and your branch has been a useful inspiration!

Regarding precompiled binaries for Ubuntu 18.04 and 20.04, I pursued my idea mentioned earlier, and I don't know if this is a correct approach (or if it's safe to use), but I forked asdf-elixir and made a few changes to it so that instead of downloading Elixir from repo.hex.pm, it downloads installs Erlang. Here are the repositories if someone wants to give it a try:
michallepicki/asdf-erlang-prebuilt-ubuntu-18.04
michallepicki/asdf-erlang-prebuilt-ubuntu-20.04

edit:
Now also 22.04 for Erlang 24.2 and newer (no openssl 3 support in earlier Erlang versions):
michallepicki/asdf-erlang-prebuilt-ubuntu-22.04

edit2:
And for 24.04+:
michallepicki/asdf-erlang-prebuilt-ubuntu-24.04

I opened a PR which would publish the macOS builds on OTP GitHub releases: erlang/otp#5723

What do you all think of this?

By default:

  • First try hex.pm for the version of Erlang (what the setup-beam action does, and what @michallepicki has done with his forks)
  • If version/OS combination not found, try https://www.erlang-solutions.com/downloads/ (I'm not yet sure how we'd programmatically determine whether they offered the correct version)
  • If version/OS combination not found, compile from source using kerl (as we currently do)

If the users specifies a flag indicating they want to force a compilation, then we only use kerl.

The above plan looks good to me

For Linux, to use the existing builds by Bob and The Hex Team (it could be a band name) I think the plugin needs to confirm x86-64 architecture, distribution and if it’s Ubuntu based then pick latest LTS version for user’s version (e.g. for 21.10 pick 20.04).

Also see a related discussion on erlef/build-and-packaging-wg#27

Is there any news on this?