Skip to content

Commit d3cc365

Browse files
committed
Introduce beamruntime
1 parent 1cdba2d commit d3cc365

File tree

1 file changed

+221
-0
lines changed

1 file changed

+221
-0
lines changed

blog/2025-09-25/index.md

Lines changed: 221 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,221 @@
1+
---
2+
title: beamruntime
3+
authors: [joaohf]
4+
tags: [meta-erlang, beamruntime]
5+
---
6+
7+
One of the coolest features from the Yocto Project is the ability of creating toolchains and SDK for specific needs. There is a full
8+
session on Yocto's documentation about [Software Development Kits](https://docs.yoctoproject.org/sdk-manual/index.html). Also, many talks
9+
showing that feature in action, e.g.: [Building Bare Metal Toolchains, Crosstool-ng and Yocto Project - Mark Hatle, Xilinx](https://www.youtube.com/watch?v=b0yXASkIIv8&t=2496s).
10+
11+
While reading this discussion: [It is possible that this project may expand to also provide Linux builds?](https://github.com/erlef/otp_builds/issues/39#issuecomment-3265877959), I thought it would be interesting as a PoC to create a sort of _beamruntime_ Yocto based toolchain with only
12+
Erlang/OTP and Elixir installed plus base libraries like libc, termcap, openssl. Nothing more. As meta-erlang layer has all the components and infrastructure for that. See beamtools idea.
13+
14+
<!-- truncate -->
15+
16+
The target is for Linux boxes that does not have Erlang/OTP installed, then the user would install beamruntime and get access to a fresh
17+
and up to date Erlang/OTP and Elixir environment. As the SDK generated by Yocto is self-content, there is no need to install anything else into Operational System.
18+
19+
Moreover, beamruntime is linux distribution independent, it could run in any distribution for the target architecture.
20+
21+
In fact, this idea is not new in meta-erlang land, _beamtools_ uses exact the same approach. The difference is beamtools has development tools for
22+
building Erlang/OTP and Elixir application (like headers, rebar3, etc). While beamruntime is just for running application, that is BEAM VM plus and modules.
23+
24+
## beamruntime recipe
25+
26+
I've started with two architecture targets in mind: x86-64 and aarch64. And a new bitbake recipe called [beamruntime-tarball](https://github.com/meta-erlang/meta-erlang/blob/master/recipes-core/meta/beamruntime-tarball.bb).
27+
28+
After building it using `bitbake beamruntime-tarball` a sdk was made and available at _tmp/deploy/sdk_ ready for use.
29+
30+
I borrowed some ideas from the [OE-core recipe from here](https://git.yoctoproject.org/poky/tree/meta/recipes-core/meta/buildtools-tarball.bb). Because the purpose is very similar.
31+
32+
## Practical usage
33+
34+
Installing beamruntime is like running a selfextract shell script which install beamruntime in the target folder (-d option):
35+
36+
```
37+
$ x86_64-beamruntime-nativesdk-standalone-5.2.99+snapshot-musl-erlang-28.0.4-elixir-1.18.4.sh -d /tmp/test0
38+
BEAM runtime installer version 5.2.99+snapshot-erlang-28.0.4-elixir-1.18.4
39+
==========================================================================
40+
You are about to install the SDK to "/tmp/test0". Proceed [Y/n]?
41+
Extracting SDK......done
42+
Setting it up...done
43+
SDK has been successfully set up and is ready to be used.
44+
Each time you wish to use the SDK in a new shell session, you need to source the environment setup script e.g.
45+
$ . /tmp/test0/environment-setup-x86_64-pokysdk-linux
46+
```
47+
48+
After the installation, and for each shell, it's necessary to source a script that will fix some environment variables:
49+
50+
```
51+
$ source /tmp/test0/environment-setup-x86_64-pokysdk-linux
52+
53+
$ erl
54+
55+
Erlang/OTP 28 [erts-16.0.3] [source] [64-bit] [smp:12:12] [ds:12:12:10] [async-threads:1] [jit:ns]
56+
57+
Eshell V16.0.3 (press Ctrl+G to abort, type help(). for help)
58+
1> application:start(crypto).
59+
ok
60+
2>
61+
```
62+
63+
Erlang shell is working as expected. Let's take a look in the image process mapping to check from where the beam PID is getting libraries:
64+
65+
```
66+
$ cat /proc/142729/maps
67+
60245d000000-60245d018000 rw-p 00a00000 fc:00 26099460 /tmp/test0/sysroots/x86_64-pokysdk-linux/usr/lib/erlang/erts-16.0.3/bin/beam.smp
68+
...
69+
785f53fee000-785f53ff3000 rw-p 001de000 fc:00 26099940 /tmp/test0/sysroots/x86_64-pokysdk-linux/lib/libc.so.6
70+
...
71+
785f54272000-785f54275000 rw-p 00271000 fc:00 20982895 /tmp/test0/sysroots/x86_64-pokysdk-linux/usr/lib/libstdc++.so.6.0.34
72+
...
73+
785f542cf000-785f542d0000 rw-p 0002b000 fc:00 26099910 /tmp/test0/sysroots/x86_64-pokysdk-linux/lib/libgcc_s.so.1
74+
...
75+
785f543c1000-785f543c2000 rw-p 000f0000 fc:00 26099961 /tmp/test0/sysroots/x86_64-pokysdk-linux/lib/libm.so.6
76+
...
77+
785f543dc000-785f543dd000 rw-p 00019000 fc:00 20982885 /tmp/test0/sysroots/x86_64-pokysdk-linux/usr/lib/libz.so.1.3.1
78+
...
79+
785f5440f000-785f54410000 rw-p 00031000 fc:00 26099959 /tmp/test0/sysroots/x86_64-pokysdk-linux/lib/libtinfo.so.5.9
80+
...
81+
785f54451000-785f54452000 rw-p 00039000 fc:00 26099952 /tmp/test0/sysroots/x86_64-pokysdk-linux/lib/ld-linux-x86-64.so.2
82+
```
83+
84+
As expected every dependency is self-content from `/tmp/test0`. Even the openssl libs:
85+
86+
Get some crypto info:
87+
88+
```
89+
2> crypto:info().
90+
#{otp_crypto_version => "5.6",compile_type => normal,
91+
link_type => dynamic,
92+
cryptolib_version_compiled => "OpenSSL 3.5.2 5 Aug 2025",
93+
cryptolib_version_linked => "OpenSSL 3.5.2 5 Aug 2025",
94+
fips_provider_available => false}
95+
3> crypto:info_lib().
96+
[{<<"OpenSSL">>,810549280,<<"OpenSSL 3.5.2 5 Aug 2025">>}]
97+
```
98+
99+
My Ubuntu (24.04) host has OpenSSL 3.0.13, not _3.5.2_. That is a good sign for self-content approach.
100+
101+
So, beamruntime could be used as a generic Erlang/OTP and Elixir installation for Linux boxes.
102+
103+
## More details
104+
105+
The file _x86_64-beamruntime-nativesdk-standalone-5.2.99+snapshot-musl-erlang-28.0.4-elixir-1.18.4.sh_ has
106+
36291 KB and when installed it goes up to 78476 KB. The user can install it in any folder.
107+
108+
:::note
109+
110+
The size footprint is relative, as in this experience I was targeting a generic installation.
111+
112+
:::
113+
114+
beamruntime provides the following packages:
115+
116+
* libc
117+
* terminfo
118+
* zlib
119+
* openssl
120+
* Erlang/OTP
121+
* Elixir
122+
123+
A more detailed list with package size and theirs names:
124+
125+
```
126+
11825 KiB nativesdk-erlang-erts
127+
7018 KiB nativesdk-elixir
128+
6418 KiB nativesdk-erlang-stdlib
129+
5894 KiB nativesdk-libcrypto3
130+
4428 KiB nativesdk-libc6
131+
3248 KiB nativesdk-erlang-compiler
132+
3163 KiB nativesdk-erlang-snmp
133+
2890 KiB nativesdk-glibc-binary-localedata-en-us.utf-8
134+
2868 KiB nativesdk-erlang-kernel
135+
2681 KiB nativesdk-erlang-public-key
136+
2511 KiB nativesdk-libstdc++6
137+
2254 KiB nativesdk-erlang-ssl
138+
1971 KiB nativesdk-erlang-xmerl
139+
1893 KiB nativesdk-erlang-common-test
140+
1459 KiB nativesdk-erlang-dialyzer
141+
1267 KiB nativesdk-erlang-ssh
142+
1246 KiB nativesdk-erlang-asn1
143+
1158 KiB nativesdk-erlang-mnesia
144+
1137 KiB nativesdk-erlang-diameter
145+
848 KiB nativesdk-erlang-inets
146+
699 KiB nativesdk-erlang-tools
147+
594 KiB nativesdk-erlang-edoc
148+
472 KiB nativesdk-erlang-emacs
149+
467 KiB nativesdk-erlang-reltool
150+
449 KiB nativesdk-erlang-syntax-tools
151+
401 KiB nativesdk-erlang-sasl
152+
348 KiB nativesdk-erlang-crypto
153+
328 KiB nativesdk-erlang-runtime-tools
154+
261 KiB nativesdk-erlang-parsetools
155+
220 KiB nativesdk-erlang-eunit
156+
200 KiB nativesdk-libtinfo5
157+
177 KiB nativesdk-erlang-eldap
158+
175 KiB nativesdk-libgcc1
159+
159 KiB nativesdk-erlang-os-mon
160+
139 KiB nativesdk-openssl-ossl-module-legacy
161+
124 KiB nativesdk-erlang-erl-interface
162+
123 KiB nativesdk-erlang-tftp
163+
115 KiB nativesdk-erlang-ftp
164+
102 KiB nativesdk-libz1
165+
85 KiB nativesdk-erlang-typer
166+
66 KiB nativesdk-erlang-epmd
167+
26 KiB nativesdk-ncurses-terminfo-base
168+
24 KiB nativesdk-openssl-conf
169+
0 KiB nativesdk-sdk-provides-dummy
170+
0 KiB nativesdk-erlang-modules
171+
0 KiB nativesdk-erlang-erl-docgen
172+
0 KiB nativesdk-erlang
173+
```
174+
175+
On this Erlang/OTP installation, I did not enabled wx (wxwidget), odbc, lkscp options. And all Erlang/OTP modules have
176+
been installed. It's a pretty generic installation, though.
177+
178+
Some additional Yocto configuration for reducing size were applied. Like the following:
179+
180+
* Disable locales:
181+
182+
```
183+
ENABLE_BINARY_LOCALE_GENERATION = "1"
184+
LOCALE_GENERATION_WITH_CROSS_LOCALEDEF = "1"
185+
GLIBC_INTERNAL_USE_BINARY_LOCALE = "compile"
186+
187+
GLIBC_GENERATE_LOCALES = "en_US.UTF-8"
188+
IMAGE_LINGUAS = "en-us"
189+
190+
LOCALE_UTF8_ONLY = "1"
191+
LOCALE_UTF8_IS_DEFAULT = "1"
192+
```
193+
194+
* Use musl:
195+
196+
```
197+
TCLIBC = "musl"
198+
```
199+
200+
* Disable opengl support:
201+
202+
```
203+
DISTRO_FEATURES_FILTER_NATIVESDK:remove = "opengl"
204+
```
205+
206+
* Optional: disable termcap (reducing ~300KB)
207+
208+
```
209+
PACKAGECONFIG:remove:pn-nativesdk-erlang = "termcap"
210+
```
211+
212+
## Next steps and ideas
213+
214+
* Provide musl and glibc beamruntime packages for testing. Both versions of beamruntime work as expected.
215+
* Enable static build, what would be the final footprint ?
216+
* Make beamruntime a bit more generic like adding odbc, lksctp ?
217+
* Or make it less generic removing some erlang application that does not make sense for
218+
runtime. Like: dialyzer, edoc, emacs, typer
219+
* What does mean generic nowadays ? Providing a generic beamruntime is feasible and if a specific user
220+
wants to add or remove components it could be easily done building a beamruntime itself.
221+
* How beamruntime could be useful for tools that expect a Erlang/OTP installation on the target host ?

0 commit comments

Comments
 (0)