|
| 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