[erlang-questions] tiny erlang
Matthias Lang
matthias@REDACTED
Wed Feb 24 11:21:40 CET 2016
Hi,
On 18. February 2016, Joe Armstrong wrote:
> I want to make a small erlang distribution for an embedded device -
> the process is rather simple:
> 1) strip the beam executable
> 2) for each library in {stdlib, kernerl, compiler, sasl} do
> Compress all the beam code and remove debug symbols
> squash everthing into a single packed file
> 3) Hack the code loader to read from the single packed beam file
> 4) Tweak the shell scripts to start Erlang
>
> At a guess we're down to c. 6 MB
>
> I have done this on *several* occassions - and am getting a bit fed up
> doing it over and over again.
>
> Has anybody done this recently - and should not something like this be
> in the standard distribution?
I do this every few years, using a Makefile. I've handed that file out
a few times. It's a get-stuff-done solution, not a masterpiece. Also,
I'm not on the bleeding edge of Erlang; on some hardware I use R14B03,
on other hardware 17.4.
Some things I do slightly differently to your steps:
2. I don't think you need to compress the beam code; Erlang's build
system does it for you by default when cross compiling, since at
least R14B03.
2. I don't ship the compiler library.
2. I strip some .beams within libraries,
e.g. 'stdlib/win32reg.beam' is useless on my hardware.
3. I don't think you need to hack the code loader; I don't. .ez files
files work as-is since at least R14B03
For R14B03, that gets me down to 2.5M. For 17.4, it's 3M.
---
Over the years, I've tried a number of different solutions to "which
library .beam files do I ship?".
Whitelist: the script only grabs the libraries I list. That's
what you suggest above.
Blacklist: the script deletes a list of libraries. That's what I do
now. This 'fails' more gracefully when OTP gets a new
library; I have to actively decide I don't need it.
test suite driven: I make a release with all the .beams in it, run
our (comprehensive!) test suite and delete all .beams
which didn't get loaded, using information from
code:all_loaded/0. This makes the smallest releases.
I've settled on the 'blacklist' approach. It's robust and
release size doesn't matter as much as it did in 2001 when I
started doing this, mainly because flash memory has gotten far cheaper.
Matt
----------------------------------------------------------------------
Here's the 'Makefile' I use:
# Build and slim Erlang
# Change the line below if you want to use a different version of Erlang
# (Keep in mind that patches may not apply cleanly)
erlang_version=otp_src_R14B03
erlang_source_file:=$(PACKAGE_SOURCES)/$(erlang_version)/$(erlang_version).tar.gz
erlang_root=$(GTH_ERLANG_ROOT)/$(erlang_version)
target_prefix=/opt/erlang
ifneq ($(COR_TARGET), GTH3)
ifneq ($(COR_TARGET), STH3)
ifneq ($(COR_TARGET), GTH2D)
$(error no COR_TARGET set, or set to an unknown target, giving up)
endif
endif
endif
xconf_file=erl-xcomp-armle-linux-gnu.conf
install_prefix=$($(COR_TARGET)_INSTALL_BASE)
prefix=$(install_prefix)$(target_prefix)
ifeq (,$(findstring $(erlang_version),$(erlang_root)))
default:
@echo "Aborting because Erlang versions do not match"
@echo "erlang_root=$(erlang_root)"
@echo "erlang_version=$(erlang_version)"
@/bin/false
endif
# Build the actual code
# The 'unset' commands are needed because otp_build misbehaves if it realises
# it's being run by a makefile. See mail to erlang-bugs 2010-06-22/23
build: $(erlang_version)
@if test -d $(prefix); then \
echo "$(prefix) already contains a (partial?) Erlang dist. Aborting, because building over the top of a dist is known to break. Use 'make clean_target' to wipe $(prefix)" ; \
exit 1 ; \
fi
sh -c "unset MAKELEVEL; unset MAKEFLAGS; cd $(erlang_version); ./otp_build boot -a"
sh -c "cd $(erlang_version); make release RELEASE_ROOT=$(prefix)"
# untar, patch, run configure
$(erlang_version): $(erlang_source_file)
tar -xzf $(erlang_source_file)
sh -c "cd $(erlang_version); patch -p 1 < ../patches/better_to_erl_messages"
sh -c "cd $(erlang_version); patch -p 1 < ../patches/extern_inline_c99"
sh -c "cd $(erlang_version); patch -p 1 < ../patches/perl_5_22_defined_fix"
sh -c "cd $(erlang_version); ./otp_build configure --xcomp-conf=../$(xconf_file)"
install: run_otp_install slim strip
make zip_libraries # run in sub-make; dependencies appeared just now
.PHONY run_otp_install:
sh -c "cd $(prefix); umask 022; ./Install -cross -minimal /opt/erlang"
slim_binaries =$(addprefix $(prefix)/bin/, beam.smp dialyzer epmd erlc heart typer escript ct_run)
slim_binaries+=$(addprefix $(prefix)/erts*/bin/, \
beam.smp dialyzer dyn_erl epmd erlc heart start typer escript ct_run *.src)
slim_sources +=$(prefix)/erts*/src/
slim_sources +=$(prefix)/erts*/include/
slim_sources +=$(prefix)/erts*/doc/
slim_sources +=$(prefix)/erts*/man/
slim_sources +=$(prefix)/erts*/lib/internal/README
slim_sources +=$(prefix)/lib/*/src/
slim_sources +=$(prefix)/lib/*/examples/
slim_sources +=$(prefix)/lib/*/include/
slim_sources +=$(prefix)/lib/*/man/
slim_sources +=$(prefix)/usr/
slim_sources +=$(prefix)/misc/
slim_applications +=$(prefix)/lib/appmon*/
slim_applications +=$(prefix)/lib/asn1*/
slim_applications +=$(prefix)/lib/common_test*/
slim_applications +=$(prefix)/lib/compiler*/
slim_applications +=$(prefix)/lib/cos*/
slim_applications +=$(prefix)/lib/debugger*/
slim_applications +=$(prefix)/lib/dialyzer*/
slim_applications +=$(prefix)/lib/diameter*/
slim_applications +=$(prefix)/lib/docbuilder*/
slim_applications +=$(prefix)/lib/edoc*/
slim_applications +=$(prefix)/lib/erl_docgen*/
slim_applications +=$(prefix)/lib/erl_interface*/
slim_applications +=$(prefix)/lib/et*/
slim_applications +=$(prefix)/lib/eunit*/
slim_applications +=$(prefix)/lib/gs*/
slim_applications +=$(prefix)/lib/hipe*/
slim_applications +=$(prefix)/lib/ic*/
slim_applications +=$(prefix)/lib/inets*/
slim_applications +=$(prefix)/lib/inviso*/
slim_applications +=$(prefix)/lib/jinterface*/
slim_applications +=$(prefix)/lib/megaco*/
slim_applications +=$(prefix)/lib/mnesia*/
slim_applications +=$(prefix)/lib/observer*/
slim_applications +=$(prefix)/lib/orber*/
slim_applications +=$(prefix)/lib/os_mon*/
slim_applications +=$(prefix)/lib/otp_mibs*/
slim_applications +=$(prefix)/lib/parsetools*/
slim_applications +=$(prefix)/lib/percept*/
slim_applications +=$(prefix)/lib/pman*/
slim_applications +=$(prefix)/lib/public_key*/
slim_applications +=$(prefix)/lib/reltool*/
slim_applications +=$(prefix)/lib/runtime_tools*/
slim_applications +=$(prefix)/lib/snmp*/
slim_applications +=$(prefix)/lib/syntax_tools*/
slim_applications +=$(prefix)/lib/test_server*/
slim_applications +=$(prefix)/lib/toolbar*/
slim_applications +=$(prefix)/lib/tools*/
slim_applications +=$(prefix)/lib/typer*/
slim_applications +=$(prefix)/lib/tv*/
slim_applications +=$(prefix)/lib/webtool*/
slim_applications +=$(prefix)/lib/wx*/
slim_applications +=$(prefix)/lib/xmerl*/
slim_applications +=$(prefix)/lib/stdlib*/ebin/win32reg.beam
slim_applications +=$(prefix)/lib/sasl*/ebin/systools*.beam
slim_applications +=$(prefix)/lib/sasl*/ebin/rb.beam
slim_applications +=$(prefix)/lib/sasl*/ebin/rb_format_supp.beam
slim_applications +=$(prefix)/lib/sasl*/ebin/erlsrv.beam
slim_applications +=$(prefix)/lib/kernel*/ebin/inet6_sctp.beam
slim_applications +=$(prefix)/lib/kernel*/ebin/array.beam
slim_other_junk +=$(prefix)/erts*/lib/
slim_other_junk +=$(prefix)/Install
slim_other_junk +=$(prefix)/releases/
slim_other_junk +=$(prefix)/bin/start_clean.boot
slim:
rm -f $(slim_binaries)
rm -rf $(slim_sources)
rm -rf $(slim_applications)
rm -rf $(slim_other_junk)
$(erlang_version)/bootstrap/bin/erl -noshell -noinput -eval "beam_lib:strip_release(\"$(prefix)\"),init:stop()"
rm -rf $(prefix)/bin/run_erl
rm -rf $(prefix)/bin/to_erl
sh -c "cd $(prefix)/bin; ln -s ../erts*/bin/run_erl ."
sh -c "cd $(prefix)/bin; ln -s ../erts*/bin/to_erl ."
zip_libraries: $(addsuffix .ez, $(wildcard $(prefix)/lib/*))
%.ez: %
sh -c "cd `dirname $@`; zip -n .beam -mr $@ `basename $^`"
STRIP=$(CROSS_COMPILE)strip
strip:
$(STRIP) $(prefix)/erts*/bin/run_erl
$(STRIP) $(prefix)/erts*/bin/to_erl
$(STRIP) $(prefix)/erts*/bin/beam
$(STRIP) $(prefix)/erts*/bin/inet_gethost
$(STRIP) $(prefix)/erts*/bin/erlexec
$(STRIP) $(prefix)/erts*/bin/child_setup
$(STRIP) $(prefix)/bin/run_erl
$(STRIP) $(prefix)/bin/to_erl
clean:
rm -rf $(erlang_version)
# removes Erlang from the GTH/STH/GMH target directory
clean_target:
rm -rf $(prefix)
# even deletes downloaded source code
dist_clean: clean
rm $(erlang_source_file)
More information about the erlang-questions
mailing list