aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--HOWTO/INSTALL-CROSS.md8
-rw-r--r--HOWTO/INSTALL-WIN32.md10
-rw-r--r--HOWTO/INSTALL.md887
-rw-r--r--README.md11
-rw-r--r--erts/doc/src/erlang.xml20
-rw-r--r--erts/emulator/beam/erl_process.c15
-rw-r--r--erts/emulator/test/binary_SUITE.erl4
-rw-r--r--erts/emulator/test/match_spec_SUITE.erl2
-rw-r--r--erts/emulator/test/port_SUITE.erl9
-rw-r--r--erts/preloaded/ebin/erl_prim_loader.beambin54792 -> 54768 bytes
-rw-r--r--erts/preloaded/ebin/erlang.beambin98276 -> 98240 bytes
-rw-r--r--erts/preloaded/ebin/erts_internal.beambin4296 -> 4276 bytes
-rw-r--r--erts/preloaded/ebin/init.beambin48816 -> 48796 bytes
-rw-r--r--erts/preloaded/ebin/otp_ring0.beambin1480 -> 1460 bytes
-rw-r--r--erts/preloaded/ebin/prim_eval.beambin1360 -> 1340 bytes
-rw-r--r--erts/preloaded/ebin/prim_file.beambin44916 -> 44892 bytes
-rw-r--r--erts/preloaded/ebin/prim_inet.beambin72932 -> 72912 bytes
-rw-r--r--erts/preloaded/ebin/prim_zip.beambin23448 -> 23424 bytes
-rw-r--r--erts/preloaded/ebin/zlib.beambin13196 -> 13176 bytes
-rw-r--r--erts/preloaded/src/erlang.erl6
-rw-r--r--erts/test/otp_SUITE.erl80
-rw-r--r--lib/common_test/doc/src/ct_hooks.xml50
-rw-r--r--lib/common_test/doc/src/ct_run.xml3
-rw-r--r--lib/common_test/doc/src/event_handler_chapter.xml29
-rw-r--r--lib/common_test/doc/src/run_test_chapter.xml14
-rw-r--r--lib/common_test/src/ct.erl3
-rw-r--r--lib/common_test/src/ct_framework.erl2
-rw-r--r--lib/common_test/src/ct_netconfc.erl10
-rw-r--r--lib/common_test/src/ct_telnet.erl128
-rw-r--r--lib/common_test/src/cth_conn_log.erl11
-rw-r--r--lib/common_test/src/unix_telnet.erl23
-rw-r--r--lib/common_test/test/ct_telnet_SUITE.erl26
-rw-r--r--lib/diameter/src/Makefile5
-rw-r--r--lib/diameter/src/app.sed40
-rw-r--r--lib/diameter/src/diameter.app.src19
-rw-r--r--lib/diameter/src/info/diameter_dbg.erl150
-rw-r--r--lib/diameter/test/diameter_app_SUITE.erl66
-rw-r--r--lib/edoc/src/edoc_types.erl1
-rw-r--r--lib/hipe/llvm/hipe_llvm_main.erl30
-rw-r--r--lib/hipe/llvm/hipe_rtl_to_llvm.erl9
-rw-r--r--lib/hipe/main/hipe.erl32
-rw-r--r--lib/inets/src/http_server/httpd_util.erl9
-rw-r--r--lib/observer/test/crashdump_viewer_SUITE.erl19
-rw-r--r--lib/public_key/doc/src/cert_records.xml4
-rw-r--r--lib/public_key/doc/src/part.xml4
-rw-r--r--lib/public_key/doc/src/public_key.xml41
-rw-r--r--lib/sasl/doc/src/appup.xml23
-rw-r--r--lib/sasl/examples/src/target_system.erl16
-rw-r--r--lib/sasl/test/release_handler_SUITE.erl27
-rw-r--r--lib/ssl/doc/src/ssl.xml69
-rw-r--r--lib/ssl/src/ssl.erl12
-rw-r--r--lib/ssl/src/ssl_connection.erl31
-rw-r--r--lib/ssl/src/ssl_internal.hrl1
-rw-r--r--lib/ssl/test/ssl_basic_SUITE.erl34
-rw-r--r--lib/ssl/test/ssl_test_lib.erl25
-rw-r--r--lib/stdlib/doc/src/pg.xml5
-rw-r--r--lib/stdlib/src/otp_internal.erl4
-rw-r--r--lib/stdlib/src/pg.erl3
-rw-r--r--lib/test_server/doc/src/test_server_ctrl.xml11
-rw-r--r--lib/tools/test/eprof_SUITE.erl10
-rw-r--r--system/doc/design_principles/applications.xml7
-rw-r--r--system/doc/design_principles/release_handling.xml17
-rw-r--r--system/doc/getting_started/seq_prog.xml123
-rw-r--r--system/doc/installation_guide/Makefile8
-rw-r--r--system/doc/installation_guide/install-binary.xml127
-rw-r--r--system/doc/installation_guide/part.xml4
-rw-r--r--system/doc/installation_guide/verification.xml102
-rw-r--r--system/doc/installation_guide/xmlfiles.mk6
-rw-r--r--system/doc/reference_manual/data_types.xml32
-rw-r--r--system/doc/reference_manual/expressions.xml8
-rw-r--r--system/doc/reference_manual/maps.xml274
-rw-r--r--system/doc/reference_manual/modules.xml8
-rw-r--r--system/doc/reference_manual/part.xml1
-rw-r--r--system/doc/reference_manual/typespec.xml12
-rw-r--r--system/doc/reference_manual/xmlfiles.mk1
-rw-r--r--system/doc/system_principles/create_target.xmlsrc248
-rw-r--r--system/doc/system_principles/part.xml4
-rw-r--r--system/doc/system_principles/system_principles.xml9
-rw-r--r--system/doc/system_principles/upgrade.xml118
-rw-r--r--system/doc/system_principles/xmlfiles.mk3
80 files changed, 2093 insertions, 1070 deletions
diff --git a/HOWTO/INSTALL-CROSS.md b/HOWTO/INSTALL-CROSS.md
index 10f463c06d..af4b38f292 100644
--- a/HOWTO/INSTALL-CROSS.md
+++ b/HOWTO/INSTALL-CROSS.md
@@ -563,12 +563,6 @@ under the License.
%CopyrightEnd%
-Modifying This Document
------------------------
-
-Before modifying this document you need to have a look at the
-[$ERL_TOP/HOWTO/MARKDOWN.md][] document.
-
[$ERL_TOP/HOWTO/INSTALL.md]: INSTALL.md
@@ -576,6 +570,4 @@ Before modifying this document you need to have a look at the
[How to Build the Documentation]: INSTALL.md#The-ErlangOTP-Documentation_How-to-Build-the-Documentation
[cross configuration variables]: #Currently-Used-Configuration-Variables
[DESTDIR]: http://www.gnu.org/prep/standards/html_node/DESTDIR.html
- [$ERL_TOP/HOWTO/MARKDOWN.md]: MARKDOWN.md
-
[?TOC]: true
diff --git a/HOWTO/INSTALL-WIN32.md b/HOWTO/INSTALL-WIN32.md
index 94d3688f23..0387572dd3 100644
--- a/HOWTO/INSTALL-WIN32.md
+++ b/HOWTO/INSTALL-WIN32.md
@@ -1018,7 +1018,7 @@ Copyright and License
%CopyrightBegin%
-Copyright Ericsson AB 2003-2012. All Rights Reserved.
+Copyright Ericsson AB 2003-2014. All Rights Reserved.
The contents of this file are subject to the Erlang Public License,
Version 1.1, (the "License"); you may not use this file except in
@@ -1033,15 +1033,7 @@ under the License.
%CopyrightEnd%
-Modifying This Document
------------------------
-
-Before modifying this document you need to have a look at the
-[$ERL_TOP/HOWTO/MARKDOWN.md][] document.
-
-
[1]: http://www.erlang.org/faq.html "mailing lists"
- [$ERL_TOP/HOWTO/MARKDOWN.md]: MARKDOWN.md
[?TOC]: true
diff --git a/HOWTO/INSTALL.md b/HOWTO/INSTALL.md
index 368947b36c..f1bb8ec853 100644
--- a/HOWTO/INSTALL.md
+++ b/HOWTO/INSTALL.md
@@ -4,174 +4,109 @@ Building and Installing Erlang/OTP
Introduction
------------
-This document describes how to build and install Erlang/OTP-%OTP-REL%. You
-are advised to read the whole document before attempting to build and install
-Erlang/OTP. You can find more information about Open Source Erlang/OTP at:
+This document describes how to build and install Erlang/OTP-%OTP-REL%.
+Erlang/OTP should be possible to build from source on any Unix/Linux system,
+including OS X. You are advised to read the whole document
+before attempting to build and install Erlang/OTP.
- <http://www.erlang.org/>
+The source code can be downloaded from the official site of Erlang/OTP or GitHub.
+* <http://www.erlang.org>
+* <https://github.com/erlang/otp>
-The source code for Erlang/OTP can also be found in a Git repository:
-
- <http://github.com/erlang/otp>
-
-Erlang/OTP should be possible to build from source on any Unix system,
-including Mac OS X. This document describes how to native compile Erlang/OTP
-on Unix. For detailed instructions on how to
-
-* cross compile Erlang/OTP, see the [$ERL_TOP/HOWTO/INSTALL-CROSS.md][]
- document.
-
-* build Erlang/OTP on Windows, see the [$ERL_TOP/HOWTO/INSTALL-WIN32.md][]
- document.
+Required Utilities
+------------------
- Binary releases for Windows can be found at
- <http://www.erlang.org/download.html>.
+These are the tools you need in order to unpack and build Erlang/OTP.
-Before reading the above mentioned documents you are in any case advised to
-read this document first, since it covers building Erlang/OTP in general as
-well as other important information.
+> *WARNING*: Please have a look at the [Known platform issues][] chapter
+> before you start.
-Daily Build and Test
---------------------
-At Ericsson we have a "Daily Build and Test" that runs on:
-
-* Solaris 8, 9
- * Sparc32
- * Sparc64
-* Solaris 10
- * Sparc32
- * Sparc64
- * x86
-* SuSE Linux/GNU 9.4, 10.1
- * x86
-* SuSE Linux/GNU 10.0, 10.1, 11.0
- * x86
- * x86\_64
-* openSuSE 11.4 (Celadon)
- * x86\_64 (valgrind)
-* Fedora 7
- * PowerPC
-* Fedora 14
- * x86\_64
-* Gentoo Linux/GNU 1.12.11.1
- * x86
-* Ubuntu Linux/GNU 7.04, 10.04, 10.10, 11.0
- * x86\_64
-* MontaVista Linux/GNU 4.0.1
- * PowerPC
-* FreeBSD 8.2
- * x86
-* OpenBSD 5.0
- * x86\_64
-* Mac OS X 10.5.8 (Leopard), 10.7.3 (Lion), 10.9 (Mavericks)
- * x86
-* Windows XP SP3, 2003, Vista, 7
- * x86
-* Windows 7
- * x86\_64
+### Unpacking ###
-We also have the following "Daily Cross Builds":
+* GNU unzip, or a modern uncompress.
+* A TAR program that understands the GNU TAR format for long filenames.
-* SuSE Linux/GNU 10.1 x86 -> SuSE Linux/GNU 10.1 x86\_64
-* SuSE Linux/GNU 10.1 x86\_64 -> Linux/GNU TILEPro64
+### Building ###
-and the following "Daily Cross Build Tests":
+* GNU `make`
+* Compiler -- GNU C Compiler, `gcc` or the C compiler frontend for LLVM, `clang`.
+* Perl 5
+* GNU `m4` -- If HiPE (native code) support is enabled. HiPE can be
+ disabled using `--disable-hipe`
+* `ncurses`, `termcap`, or `termlib` -- The development headers and
+ libraries are needed, often known as `ncurses-devel`. Use
+ `--without-termcap` to build without any of these libraries. Note that
+ in this case only the old shell (without any line editing) can be used.
+* `sed` -- Stream Editor for basic text transformation.
-* SuSE Linux/GNU 10.1 x86\_64
+#### Building in Git ####
-Versions Known NOT to Work
---------------------------
+* GNU `autoconf` of at least version 2.59. Note that `autoconf` is not
+ needed when building an unmodified version of the released source.
-* Suse linux 9.1 is shipped with a patched GCC version 3.3.3, having the
- rpm named `gcc-3.3.3-41`. That version has a serious optimization bug
- that makes it unusable for building the Erlang emulator. Please
- upgrade GCC to a newer version before building on Suse 9.1. Suse Linux
- Enterprise edition 9 (SLES9) has `gcc-3.3.3-43` and is not affected.
+#### Building on OS X ####
-* `gcc-4.3.0` has a serious optimizer bug. It produces an Erlang emulator
- that will crash immediately. The bug is supposed to be fixed in
- `gcc-4.3.1`.
+* Xcode -- Download and install via the Mac App Store.
+ Read about [Building on a Mac][] before proceeding.
-* FreeBSD had a bug which caused `kqueue`/`poll`/`select` to fail to detect
- that a `writev()` on a pipe has been made. This bug should have been fixed
- in FreeBSD 6.3 and FreeBSD 7.0. NetBSD and DragonFlyBSD probably have or
- have had the same bug. More information can be found at:
+### Installing ###
- * <http://www.freebsd.org/cgi/cvsweb.cgi/src/sys/kern/sys_pipe.c>
- * <http://lists.freebsd.org/pipermail/freebsd-arch/2007-September/006790.html>
+* An `install` program that can take multiple file names.
-* `getcwd()` on Solaris 9 can cause an emulator crash. If you have
- async-threads enabled you can increase the stack size of the
- async-threads as a temporary workaround. See the `+a` command-line
- argument in the documentation of `erl(1)`. Without async-threads the
- emulator is not as vulnerable to this bug, but if you hit it without
- async-threads the only workaround available is to enable async-threads
- and increase the stack size of the async-threads. Sun has however
- released patches that fixes the issue:
- > Problem Description: 6448300 large mnttab can cause stack overrun
- > during Solaris 9 getcwd
+Optional Utilities
+------------------
- More information can be found at:
+Some applications are automatically skipped if the dependencies aren't met.
+Here is a list of utilities needed for those applications. You will
+also find the utilities needed for building the documentation.
- * <http://sunsolve.sun.com/search/document.do?assetkey=1-21-112874-40-1&searchclause=6448300>
- * <http://sunsolve.sun.com/search/document.do?assetkey=1-21-114432-29-1&searchclause=6448300>
+### Building ###
-Required Utilities
-------------------
+* OpenSSL -- The opensource toolkit for Secure Socket Layer
+ and Transport Layer Security.
+ Required for building the application `crypto`.
+ Further, `ssl` and `ssh` require a working crypto application and
+ will also be skipped if OpenSSL is missing. The `public_key`
+ application will available without `crypto`, but the functionality
+ will be very limited.
+
+ The development package of OpenSSL including the header files are needed as well
+ as the binary command program `openssl`. At least version 0.9.8 of OpenSSL is required.
+ Read more and download from <http://www.openssl.org>.
+* Oracle Java SE JDK -- The Java Development Kit (Standard Edition).
+ Required for building the application `jinterface` and parts of `ic` and `orber`.
+ At least version 1.5.0 of the JDK is required.
+
+ Download from <http://www.oracle.com/technetwork/java/javase/downloads>.
+ We have also tested with IBM's JDK 1.5.0.
+* X Windows -- Development headers and libraries are needed
+ to build the Erlang/OTP application `gs` on Unix/Linux.
+* `flex` -- Headers and libraries are needed to build the flex
+ scanner for the `megaco` application on Unix/Linux.
+* wxWidgets -- Toolkit for GUI applications.
+ Required for building the `wx` application. At least
+ version 3.0 of wxWidgets is required.
-These are the tools you will need in order to unpack and build Erlang/OTP.
+ Download from <http://sourceforge.net/projects/wxwindows/files/3.0.0/>
+ or get it from GitHub: <https://github.com/wxWidgets/wxWidgets>
-### Unpacking ###
+ Further instructions on wxWidgets, read [Building with wxErlang][].
-* GNU unzip, or a modern uncompress.
-* A TAR program that understands the GNU TAR format for long filenames
- (such as GNU TAR).
-### Building ###
-* GNU `make`
-* `gcc` -- GNU C compiler
-* Perl 5
-* GNU `m4` -- If HiPE (native code) support is enabled. HiPE can be
- disabled using `--disable-hipe`
-* `ncurses`, `termcap`, or `termlib` -- The development headers and
- libraries are needed, often known as `ncurses-devel`. Use
- `--without-termcap` to build without any of these libraries. Note that
- in this case only the old shell (without any line editing) can be used.
-* OpenSSL -- Optional, but needed for building the Erlang/OTP applications
- `ssl` and `crypto`. You need the "development package" of OpenSSL, i.e.
- including the header files. For building the application `ssl` the OpenSSL
- binary command program `openssl` is also needed. At least version 0.9.8
- of OpenSSL is required. Can be downloaded from <http://www.openssl.org>.
-* Sun Java jdk-1.5.0 or higher -- Optional but needed for building the
- Erlang/OTP application `jinterface` and parts of `ic` and `orber`. Can
- be downloaded from <http://java.sun.com>. We have also tested IBM's
- JDK 1.5.0.
-* X Windows -- Optional, but development headers and libraries are needed
- to build the Erlang/OTP application `gs` on Unix/Linux.
-* `sed` -- There seem to be some problems with some of the `sed` version on
- Solaris. Make sure `/bin/sed` or `/usr/bin/sed` is used on the Solaris
- platform.
-* `flex` -- Optional, headers and libraries are needed to build the `flex`
- scanner for the `megaco` application on Unix/Linux.
+### Building Documentation ###
-#### Building Documentation ####
+* `xsltproc` -- A command line XSLT processor.
-* `xsltproc` -- XSLT processor. A tool for applying XSLT stylesheets
- to XML documents. Can be downloaded from
+ A tool for applying XSLT stylesheets
+ to XML documents. Download xsltproc from
<http://xmlsoft.org/XSLT/xsltproc2.html>.
+
* `fop` -- Apache FOP print formatter (requires Java). Can be downloaded
from <http://xmlgraphics.apache.org/fop>.
-#### Building in Git ####
-* GNU `autoconf` of at least version 2.59. Note that `autoconf` is not
- needed when building an unmodified version of the released source.
-
-### Installing ###
-
-* An `install` program that can take multiple file names.
How to Build and Install Erlang/OTP
-----------------------------------
@@ -186,65 +121,205 @@ section below before proceeding.
### Unpacking ###
-Step 1: Start by unpacking the Erlang/OTP distribution file with your GNU
+Start by unpacking the Erlang/OTP distribution file with your GNU
compatible TAR program.
- $ gunzip -c otp_src_%OTP-VSN%.tar.gz | tar xf -
+ $ tar -zxf otp_src_%OTP-VSN%.tar.gz # Assuming bash/sh
-alternatively:
-
- $ zcat otp_src_%OTP-VSN%.tar.gz | tar xf -
-
-
-Step 2: Now cd into the base directory (`$ERL_TOP`).
+Now change directory into the base directory and set the `$ERL_TOP` variable.
$ cd otp_src_%OTP-VSN%
+ $ export ERL_TOP=`pwd` # Assuming bash/sh
### Configuring ###
-Step 3: On some platforms Perl may behave strangely if certain locales are
-set, so optionally you may need to set the LANG variable:
-
- # Bourne shell
- $ LANG=C; export LANG
+Run the following commands to configure the build:
-or
+ $ ./configure [ options ]
- # C-Shell
- $ setenv LANG C
+> *NOTE*: If you are building Erlang/OTP from git you will need to run `./otp_build autoconf` to generate
+> the configure scripts.
-Step 4: Run the following commands to configure the build:
+By default, Erlang/OTP release will be installed in `/usr/local/{bin,lib/erlang}`.
+If you for instance don't have the permission to install in the standard location,
+ you can install Erlang/OTP somewhere else. For example, to install in
+`/opt/erlang/%OTP-VSN%/{bin,lib/erlang}`, use the `--prefix=/opt/erlang/%OTP-VSN%` option.
- $ ./configure [ options ]
+On some platforms Perl may behave strangely if certain locales are
+set. If you get errors when building, try setting the LANG variable:
-If you are building it from git you will need to run `./otp_build autoconf` to generate configure file.
-By default, Erlang/OTP will be installed in `/usr/local/{bin,lib/erlang}`.
-To instead install in `<BaseDir>/{bin,lib/erlang}`, use the
-`--prefix=<BaseDir>` option.
+ $ export LANG=C # Assuming bash/sh
-If you upgraded the source with some patch you may need to clean up
-from previous builds before the new build. Before doing a `make clean`,
-be sure to read the [Pre-built Source Release][] section below.
### Building ###
-Step 5: Build the Erlang/OTP package.
+Build the Erlang/OTP release.
$ make
+
+### Testing ###
+
+Before installation you should test whether your build is working properly
+by running our smoke test. The smoke test is a subset of the complete Erlang/OTP test suites.
+First you will need to build and release the test suites.
+
+ $ make release_tests
+
+This creates an additional folder in `$ERL_TOP/release` called `tests`.
+Now, it's time to start the smoke test.
+
+ $ cd release/tests/test_server
+ $ $ERL_TOP/bin/erl -s ts install -s ts smoke_test batch -s init stop
+
+To verify that everything is ok you should open `$ERL_TOP/release/tests/test_server/index.html`
+in your web browser and make sure that there are zero failed test cases.
+
+> *NOTE*: On builds without `crypto`, `ssl` and `ssh` there is a failed test case
+> for undefined functions. Verify that the failed test case log only shows calls
+> to skipped applications.
+
### Installing ###
-Step 6: Install then Erlang/OTP package
+You are now ready to install the Erlang/OTP release!
+The following command will install the release on your system.
$ make install
-### A Closer Look at the individual Steps ###
-Let us go through them in some detail.
+### Running ###
+
+You should now have a working release of Erlang/OTP!
+Jump to [System Principles][] for instructions on running Erlang/OTP.
+
+
+### How to Build the Documentation ###
+
+Make sure you're in the top directory in the source tree.
+
+ $ cd $ERL_TOP
+
+If you have just built Erlang/OTP in the current source tree, you have
+already ran `configure` and do not need to do this again; otherwise, run
+`configure`.
+
+ $ ./configure [Configure Args]
+
+When building the documentation you need a full Erlang/OTP-%OTP-VSN% system in
+the `$PATH`.
+
+ $ export PATH=$ERL_TOP/bin:$PATH # Assuming bash/sh
+
+Build the documentation.
-#### Configuring ####
+ $ make docs
+
+#### Build Issues ####
+
+We have sometimes experienced problems with Oracle's `java` running out of
+memory when running `fop`. Increasing the amount of memory available
+as follows has in our case solved the problem.
+
+ $ export FOP_OPTS="-Xmx<Installed amount of RAM in MB>m"
+
+More information can be found at
+* <http://xmlgraphics.apache.org/fop/0.95/running.html#memory>.
+
+
+### How to Install the Documentation ###
+
+The documentation can be installed either using the `install-docs` target,
+or using the `release_docs` target.
+
+* If you have installed Erlang/OTP using the `install` target, install
+ the documentation using the `install-docs` target. Install locations
+ determined by `configure` will be used. `$DESTDIR` can be used the
+ same way as when doing `make install`.
+
+ $ make install-docs
+
+* If you have installed Erlang/OTP using the `release` target, install
+ the documentation using the `release_docs` target. You typically want
+ to use the same `RELEASE_ROOT` as when invoking `make release`.
+
+ $ make release_docs RELEASE_ROOT=<release dir>
+
+
+### Accessing the Documentation ###
+
+After installation you can access the documentation by
+
+* Reading man pages. Make sure that `erl` is referring to the
+ installed version. For example `/usr/local/bin/erl`.
+ Try viewing at the man page for Mnesia
+
+ $ erl -man mnesia
+
+* Browsing the html pages by loading the page `/usr/local/lib/erlang/doc/erlang/index.html`
+ or `<BaseDir>/lib/erlang/doc/erlang/index.html` if the prefix option has been used.
+
+
+### How to Install the Pre-formatted Documentation ###
+
+Pre-formatted [html documentation][] and [man pages][] can be downloaded from
+* <http://www.erlang.org/download.html>.
+
+Extract the html archive in the installation directory.
+
+ $ cd <ReleaseDir>
+ $ tar -zxf otp_html_%OTP-VSN%.tar.gz
+
+For `erl -man <page>` to work the Unix manual pages have to be
+installed in the same way, i.e.
+
+ $ cd <ReleaseDir>
+ $ tar -zxf otp_man_%OTP-VSN%.tar.gz
+
+Where `<ReleaseDir>` is
+
+* `<PrefixDir>/lib/erlang` if you have installed Erlang/OTP using
+ `make install`.
+* `$DESTDIR<PrefixDir>/lib/erlang` if you have installed Erlang/OTP
+ using `make install DESTDIR=<TmpInstallDir>`.
+* `RELEASE_ROOT` if you have installed using
+ `make release RELEASE_ROOT=<ReleaseDir>`.
+
+
+Advanced configuration and build of Erlang/OTP
+----------------------------------------------
+
+If you want to tailor your Erlang/OTP build and installation, please read
+on for detailed information about the individual steps.
+
+### make and $ERL\_TOP ###
+
+All the makefiles in the entire directory tree use the environment
+variable `ERL_TOP` to find the absolute path of the installation. The
+`configure` script will figure this out and set it in the top level
+Makefile (which, when building, it will pass on). However, when
+developing it is sometimes convenient to be able to run make in a
+subdirectory. To do this you must set the `ERL_TOP` variable
+before you run make.
-Step 4 runs a configuration script created by the GNU autoconf utility, which
+For example, assume your GNU make program is called `make` and you
+want to rebuild the application `STDLIB`, then you could do:
+
+ $ cd lib/stdlib; env ERL_TOP=<Dir> make
+
+where `<Dir>` would be what you find `ERL_TOP` is set to in the top level
+Makefile.
+
+### otp\_build vs configure/make ###
+
+Building Erlang/OTP can be done either by using the `$ERL_TOP/otp_build`
+script, or by invoking `$ERL_TOP/configure` and `make` directly. Building using
+`otp_build` is easier since it involves fewer steps, but the `otp_build` build
+procedure is not as flexible as the `configure`/`make` build procedure. The binary
+releases for Windows that we deliver are built using `otp_build`.
+
+### Configuring ###
+
+The configure script is created by the GNU autoconf utility, which
checks for system specific features and then creates a number of makefiles.
The configure script allows you to customize a number of parameters;
@@ -260,10 +335,10 @@ use the `--prefix` argument like this: `./configure --prefix=<Dir>`.
Some of the available `configure` options are:
* `--prefix=PATH` - Specify installation prefix.
-* `--{enable,disable}-threads` - Thread support (enabled by default if
- possible)
+
+* `--{enable,disable}-threads` - Thread support. This is enabled by default if possible.
* `--{enable,disable}-smp-support` - SMP support (enabled by default if
- possible)
+ a usable POSIX thread library or native Windows threads is found)
* `--{enable,disable}-kernel-poll` - Kernel poll support (enabled by
default if possible)
* `--{enable,disable}-hipe` - HiPE support (enabled by default on supported
@@ -321,9 +396,9 @@ Some of the available `configure` options are:
to configure.
* `--without-$app` - By default all applications in Erlang/OTP will be included
in a release. If this is not wanted it is possible to specify that Erlang/OTP
- should be compiled without that applications, i.e. `--without-wx`. There is
- no automatic dependency handling inbetween applications. So if you disable
- an application that another depends on, you also have to disable the
+ should be compiled without one or more applications, i.e. `--without-wx`. There is
+ no automatic dependency handling between applications. If you disable
+ an application that another application depends on, you also have to disable the
dependant application.
* `--enable-dirty-schedulers` - Enable the **experimental** dirty schedulers
functionality. Note that the dirty schedulers functionality is experimental,
@@ -334,26 +409,133 @@ Some of the available `configure` options are:
If you or your system has special requirements please read the `Makefile` for
additional configuration information.
-#### Building ####
-Step 5 builds the Erlang/OTP system. On a fast computer, this will take about
-5 minutes. After completion of this step, you should have a working
-Erlang/OTP system which you can try by typing `bin/erl`. This should start
-up Erlang/OTP and give you a prompt:
+### Building ###
+
+Building Erlang/OTP on a relatively fast computer takes approximately
+5 minutes. To speed it up, you can utilize parallel make with the `-j<num_jobs>` option.
+
+ $ export MAKEFLAGS=-j8 # Assuming bash/sh
+ $ make
+
+If you've upgraded the source with a patch you may need to clean up from previous
+builds before the new build.
+Make sure to read the [Pre-built Source Release][] section below before doing a `make clean`.
+
+#### Within Git ####
+
+When building in a Git working directory you also have to have a GNU `autoconf`
+of at least version 2.59 on your system, because you need to generate the
+`configure` scripts before you can start building.
+
+The `configure` scripts are generated by invoking `./otp_build autoconf` in
+the `$ERL_TOP` directory. The `configure` scripts also have to be regenerated
+when a `configure.in` or `aclocal.m4` file has been modified. Note that when
+checking out a branch a `configure.in` or `aclocal.m4` file may change
+content, and you may therefore have to regenerate the `configure` scripts
+when checking out a branch. Regenerated `configure` scripts imply that you
+have to run `configure` and build again.
+
+> *NOTE*: Running `./otp_build autoconf` is **not** needed when building
+> an unmodified version of the released source.
+
+Other useful information can be found at our GitHub wiki:
+* <http://wiki.github.com/erlang/otp>
+
+#### OS X (Darwin) ####
+
+Make sure that the command `hostname` returns a valid fully qualified host
+name (this is configured in `/etc/hostconfig`). Otherwise you might experience
+problems when running distributed systems.
+
+If you develop linked-in drivers (shared library) you need to link using
+`gcc` and the flags `-bundle -flat_namespace -undefined suppress`. You also
+include `-fno-common` in `CFLAGS` when compiling. Use `.so` as the library
+suffix.
+
+If you have Xcode 4.3, or later, you will also need to download
+"Command Line Tools" via the Downloads preference pane in Xcode.
+
+#### Building with wxErlang ####
+
+Be aware that the wxWidgets-3.0 is a new release of wxWidgets, it is not as matured
+as the old releases and the OS X port still lags behind the other ports.
+
+Configure and build wxWidgets (on Mavericks - 10.9):
+
+ $ ./configure --with-cocoa --prefix=/usr/local
+ or without support for old versions and with static libs
+ $ ./configure --with-cocoa --prefix=/usr/local --with-macosx-version-min=10.9 --disable-shared
+ $ make
+ $ sudo make install
+ $ export PATH=/usr/local/bin:$PATH
+
+Check that you got the correct wx-config
+
+ $ which wx-config && wx-config --version-full
+
+Build Erlang/OTP
+
+ $ export PATH=/usr/local/bin:$PATH
+ $ cd $ERL_TOP
+ $ ./configure --enable-shared-zlib
+ $ make
+ $ sudo make install
+
+
+#### Pre-built Source Release ####
+
+The source release is delivered with a lot of platform independent
+build results already pre-built. If you want to remove these pre-built
+files, invoke `./otp_build remove_prebuilt_files` from the `$ERL_TOP`
+directory. After you have done this, you can build exactly the same way
+as before, but the build process will take a much longer time.
+
+> *WARNING*: Doing `make clean` in an arbitrary directory of the source
+> tree, may remove files needed for bootstrapping the build.
+>
+> Doing `./otp_build save_bootstrap` from the `$ERL_TOP` directory before
+> doing `make clean` will ensure that it will be possible to build after
+> doing `make clean`. `./otp_build save_bootstrap` will be invoked
+> automatically when `make` is invoked from `$ERL_TOP` with either the
+> `clean` target, or the default target. It is also automatically invoked
+> if `./otp_build remove_prebuilt_files` is invoked.
+
+#### How to Build a Debug Enabled Erlang RunTime System ####
+
+After completing all the normal building steps described above a debug
+enabled runtime system can be built. To do this you have to change
+directory to `$ERL_TOP/erts/emulator`.
+
+In this directory execute:
+
+ $ make debug FLAVOR=$FLAVOR
+
+where `$FLAVOR` is either `plain` or `smp`. The flavor options will
+produce a beam.debug and beam.smp.debug executable respectively. The
+files are installed along side with the normal (opt) versions `beam.smp`
+and `beam`.
+
+To start the debug enabled runtime system execute:
+
+ $ $ERL_TOP/bin/cerl -debug
- $ bin/erl
- Erlang/OTP %OTP-REL% [erts-%ERTS-VSN%] [source] [smp:4:4] [async-threads:0] [kernel-poll:false]
+The debug enabled runtime system features lock violation checking,
+assert checking and various sanity checks to help a developer ensure
+correctness. Some of these features can be enabled on a normal beam
+using appropriate configure options.
- Eshell V%ERTS-VSN% (abort with ^G)
- 1> _
+There are other types of runtime systems that can be built as well
+using the similar steps just described.
-#### Installing ####
+ $ make $TYPE FLAVOR=$FLAVOR
+
+where `$TYPE` is `opt`, `gcov`, `gprof`, `debug`, `valgrind`, or `lcnt`.
+These different beam types are useful for debugging and profiling
+purposes.
-Step 6 is optional. It installs Erlang/OTP at a standardized location (if you
-change your mind about where you wish to install you can rerun step 4,
-without having to do step 5 again).
-##### Alternative Installation Procedures #####
+### Installing ###
* Staged install using [DESTDIR][]. You can perform the install
phase in a temporary directory and later move the installation into
@@ -435,7 +617,7 @@ without having to do step 5 again).
if you want to try the system out, running test suites, etc, before doing
the real install without `EXTRA_PREFIX`.
-### Symbolic Links in --bindir ###
+#### Symbolic Links in --bindir ####
When doing `make install` and the default installation prefix is used,
relative symbolic links will be created from `/usr/local/bin` to all public
@@ -449,156 +631,10 @@ passed to `configure`. One can force relative, or absolute links by passing
phase. Note that such a request might cause a failure if the request cannot
be satisfied.
-### Pre-built Source Release ###
-
-The source release is delivered with a lot of platform independent
-build results already pre-built. If you want to remove these pre-built
-files, invoke `./otp_build remove_prebuilt_files` from the `$ERL_TOP`
-directory. After you have done this, you can build exactly the same way
-as before, but the build process will take a much longer time.
-
-> *WARNING*: Doing `make clean` in an arbitrary directory of the source
-> tree, may remove files needed for bootstrapping the build.
->
-> Doing `./otp_build save_bootstrap` from the `$ERL_TOP` directory before
-> doing `make clean` will ensure that it will be possible to build after
-> doing `make clean`. `./otp_build save_bootstrap` will be invoked
-> automatically when `make` is invoked from `$ERL_TOP` with either the
-> `clean` target, or the default target. It is also automatically invoked
-> if `./otp_build remove_prebuilt_files` is invoked.
-
-### Building in Git ###
-
-When building in a Git working directory you also have to have a GNU `autoconf`
-of at least version 2.59 on your system, because you need to generate the
-`configure` scripts before you can start building.
-
-The `configure` scripts are generated by invoking `./otp_build autoconf` in
-the `$ERL_TOP` directory. The `configure` scripts also have to be regenerated
-when a `configure.in` or `aclocal.m4` file has been modified. Note that when
-checking out a branch a `configure.in` or `aclocal.m4` file may change
-content, and you may therefore have to regenerate the `configure` scripts
-when checking out a branch. Regenerated `configure` scripts imply that you
-have to run `configure` and build again.
-
-> *NOTE*: Running `./otp_build autoconf` is **not** needed when building
-> an unmodified version of the released source.
-
-Other useful information can be found at our github wiki:
-<http://wiki.github.com/erlang/otp>
-
-### make and $ERL\_TOP ###
-
-All the makefiles in the entire directory tree use the environment
-variable `ERL_TOP` to find the absolute path of the installation. The
-`configure` script will figure this out and set it in the top level
-Makefile (which, when building, it will pass on). However, when
-developing it is sometimes convenient to be able to run make in a
-subdirectory. To do this you must set the `ERL_TOP` variable
-before you run make.
-
-For example, assume your GNU make program is called `make` and you
-want to rebuild the application `STDLIB`, then you could do:
-
- $ cd lib/stdlib; env ERL_TOP=<Dir> make
-
-where `<Dir>` would be what you find `ERL_TOP` is set to in the top level
-Makefile.
-
-The Erlang/OTP Documentation
-----------------------------
-
-### How to Build the Documentation ###
-
-Before you can build the documentation you need to either [native build][]
-or [cross build][] the Erlang/OTP system. After this you can build the
-documentation as follows.
-
- $ cd $ERL_TOP
- $ make docs
-
-The documentation can be installed either using the `install-docs` target,
-or using the `release_docs` target.
-
-* If you have installed Erlang/OTP using the `install` target, install
- the documentation using the `install-docs` target. Install locations
- determined by `configure` will be used. `$DESTDIR` can be used the
- same way as when doing `make install`.
-
- $ make install-docs
-
-* If you have installed Erlang/OTP using the `release` target, install
- the documentation using the `release_docs` target. You typically want
- to use the same `RELEASE_ROOT` as when invoking `make release`.
-
- $ make release_docs RELEASE_ROOT=<release dir>
-
-#### Build Issues ####
-
-We have sometimes experienced problems with Sun's `java` running out of
-memory when running `fop`. Increasing the amount of memory available
-as follows has in our case solved the problem.
-
- $ export FOP_OPTS="-Xmx<Installed amount of RAM in MB>m"
-
-More information can be found at
-<http://xmlgraphics.apache.org/fop/0.95/running.html#memory>.
-
-### How to Install the Pre-formatted Documentation ###
-
-Pre-formatted [html documentation][] and [man pages][] can be downloaded at
-<http://www.erlang.org/download.html>.
-
-For some graphical tools to find the on-line help you have to install
-the HTML documentation on top of the installed OTP applications, i.e.
-
- $ cd <ReleaseDir>
- $ gunzip -c otp_html_%OTP-VSN%.tar.gz | tar xf -
-
-For `erl -man <page>` to work the Unix manual pages have to be
-installed in the same way, i.e.
-
- $ cd <ReleaseDir>
- $ gunzip -c otp_man_%OTP-VSN%.tar.gz | tar xf -
-
-Where `<ReleaseDir>` is
-
-* `<PrefixDir>/lib/erlang` if you have installed Erlang/OTP using
- `make install`.
-* `$DESTDIR<PrefixDir>/lib/erlang` if you have installed Erlang/OTP
- using `make install DESTDIR=<TmpInstallDir>`.
-* `RELEASE_ROOT` if you have installed using
- `make release RELEASE_ROOT=<ReleaseDir>`.
-
-Support for SMP (Symmetric Multi Processing)
---------------------------------------------
-
-An emulator with SMP support will be built by default on most platforms
-if a usable POSIX thread library or native Windows threads is found.
-You can force building of an SMP emulator, by using
-`./configure --enable-smp-support`. However, if configure does not
-automatically enable SMP support, the build is very likely to fail.
+### Running ###
-Use `./configure --disable-smp-support` if you for some reason do not
-want to have the emulator with SMP support built.
-
-If SMP support is enabled, support for threaded I/O will also be turned on
-(also in the emulator without SMP support).
-
-The `erl` command will automatically start the SMP emulator if the
-computer has more than one logical processor. You can force a start
-of the emulator with SMP support by passing `-smp enable` as
-command line arguments to erl, and you can force a start of the
-emulator without SMP support by passing `-smp disable`.
-
-GS (Graphic System)
--------------------
-
-GS now Tcl/Tk 8.4. It will be searched for when starting GS.
-
-Using HiPE
-----------
+#### Using HiPE ####
HiPE supports the following system configurations:
@@ -619,12 +655,12 @@ HiPE supports the following system configurations:
* FreeBSD: FreeBSD 6.1 and 6.2 in 32-bit and 64-bit modes should work.
- * MacOSX/Darwin: Darwin 9.8.0 in 32-bit mode should work.
+ * OS X/Darwin: Darwin 9.8.0 in 32-bit mode should work.
* PowerPC: All 32-bit 6xx/7xx(G3)/74xx(G4) processors should work. 32-bit
mode on 970 (G5) and POWER5 processors should work.
- * Linux (Yellow Dog) and Mac OSX 10.4 are supported.
+ * Linux (Yellow Dog) and OS X 10.4 are supported.
* SPARC: All UltraSPARC processors running 32-bit user code should work.
@@ -643,11 +679,11 @@ HiPE is automatically enabled on the following systems:
* x86 in 32-bit mode: Linux, Solaris, FreeBSD
* x86 in 64-bit mode: Linux, Solaris, FreeBSD
-* PowerPC: Linux, MacOSX
+* PowerPC: Linux, Mac OSX
* SPARC: Linux
* ARM: Linux
-On other supported systems you need to `./configure --enable-hipe`.
+On other supported systems, see [Advanced Configure][] on how to enable HiPE.
If you are running on a platform supporting HiPE and if you have not disabled
HiPE, you can compile a module into native code like this from the Erlang
@@ -659,7 +695,7 @@ or
1> c(Module, [native|OtherOptions]).
-Using the erlc program, write like this:
+Using the erlc program, write like this
$ erlc +native Module.erl
@@ -674,88 +710,103 @@ Use `hipe:help_options/0` to print out the available options.
1> hipe:help_options().
-Mac OS X (Darwin)
------------------
-
-Make sure that the command `hostname` returns a valid fully qualified host
-name (this is configured in `/etc/hostconfig`).
-
-If you develop linked-in drivers (shared library) you need to link using
-`gcc` and the flags `-bundle -flat_namespace -undefined suppress`. You also
-include `-fno-common` in `CFLAGS` when compiling. Use `.so` as the library
-suffix.
-
-Install `Xcode` from the `AppStore` if it is not already installed.
-
-If you have Xcode 4.3, or later, you will also need to download
-"Command Line Tools" via the Downloads preference pane in Xcode.
-
-### Building with wxErlang ###
+#### Running with GS ####
-If you want to build the `wx` application, you will need to get wxWidgets-3.0 (or later)
-(`wxWidgets-3.0.0.tar.bz2` from <http://sourceforge.net/projects/wxwindows/files/3.0.0/>)
-or get it from github:
- $ git clone [email protected]:wxWidgets/wxWidgets.git
+The `gs` application requires the GUI toolkit Tcl/Tk to run. At least
+version 8.4 is required.
-Be aware that the wxWidgets-3.0 is a new release of wxWidgets, it is not as matured
-as the old releases and the MacOsX port still lags behind the other ports.
-
-Configure and build wxWidgets (on Mavericks - 10.9):
- $ ./configure --with-cocoa --prefix=/usr/local
- or without support for old versions and with static libs
- $ ./configure --with-cocoa --prefix=/usr/local --with-macosx-version-min=10.9 --disable-shared
- $ make
- $ sudo make install
- $ export PATH=/usr/local/bin:$PATH
+Known platform issues
+---------------------
-Check that you got the correct wx-config
+* Suse linux 9.1 is shipped with a patched GCC version 3.3.3, having the
+ rpm named `gcc-3.3.3-41`. That version has a serious optimization bug
+ that makes it unusable for building the Erlang emulator. Please
+ upgrade GCC to a newer version before building on Suse 9.1. Suse Linux
+ Enterprise edition 9 (SLES9) has `gcc-3.3.3-43` and is not affected.
- $ which wx-config
+* `gcc-4.3.0` has a serious optimizer bug. It produces an Erlang emulator
+ that will crash immediately. The bug is supposed to be fixed in
+ `gcc-4.3.1`.
-### Finish up ###
+* FreeBSD had a bug which caused `kqueue`/`poll`/`select` to fail to detect
+ that a `writev()` on a pipe has been made. This bug should have been fixed
+ in FreeBSD 6.3 and FreeBSD 7.0. NetBSD and DragonFlyBSD probably have or
+ have had the same bug. More information can be found at:
-Build Erlang
+ * <http://www.freebsd.org/cgi/cvsweb.cgi/src/sys/kern/sys_pipe.c>
+ * <http://lists.freebsd.org/pipermail/freebsd-arch/2007-September/006790.html>
- $ export PATH=/usr/local/bin:$PATH
- $ cd $ERL_TOP
- $ ./configure --enable-shared-zlib
- $ make
- $ sudo make install
+* `getcwd()` on Solaris 9 can cause an emulator crash. If you have
+ async-threads enabled you can increase the stack size of the
+ async-threads as a temporary workaround. See the `+a` command-line
+ argument in the documentation of `erl(1)`. Without async-threads the
+ emulator is not as vulnerable to this bug, but if you hit it without
+ async-threads the only workaround available is to enable async-threads
+ and increase the stack size of the async-threads. Oracle has however
+ released patches that fixes the issue:
-How to Build a Debug Enabled Erlang RunTime System
---------------------------------------------------
+ > Problem Description: 6448300 large mnttab can cause stack overrun
+ > during Solaris 9 getcwd
-After completing all the normal building steps described above a debug
-enabled runtime system can be built. To do this you have to change
-directory to `$ERL_TOP/erts/emulator`.
+ More information can be found at:
+ * <https://getupdates.oracle.com/readme/112874-40>
+ * <https://getupdates.oracle.com/readme/114432-29>
-In this directory execute:
+* `sed` on Solaris seem to have some problems. For example on
+ Solaris 8, the BSD `sed` and XPG4 `sed` should be avoided.
+ Make sure `/bin/sed` or `/usr/bin/sed` is used on the Solaris
+ platform.
- $ make debug FLAVOR=$FLAVOR
-where `$FLAVOR` is either `plain` or `smp`. The flavor options will
-produce a beam.debug and beam.smp.debug executable respectively. The
-files are installed along side with the normal (opt) versions `beam.smp`
-and `beam`.
+Daily Build and Test
+--------------------
+At Ericsson we have a "Daily Build and Test" that runs on:
-To start the debug enabled runtime system execute:
+* Solaris 8, 9
+ * Sparc32
+ * Sparc64
+* Solaris 10
+ * Sparc32
+ * Sparc64
+ * x86
+* SuSE Linux/GNU 9.4, 10.1
+ * x86
+* SuSE Linux/GNU 10.0, 10.1, 11.0
+ * x86
+ * x86\_64
+* openSuSE 11.4 (Celadon)
+ * x86\_64 (valgrind)
+* Fedora 7
+ * PowerPC
+* Fedora 16
+ * x86\_64
+* Gentoo Linux/GNU 1.12.11.1
+ * x86
+* Ubuntu Linux/GNU 7.04, 10.04, 10.10, 11.04, 12.04
+ * x86\_64
+* MontaVista Linux/GNU 4.0.1
+ * PowerPC
+* FreeBSD 10.0
+ * x86
+* OpenBSD 5.4
+ * x86\_64
+* OS X 10.5.8 (Leopard), 10.7.5 (Lion), 10.9.1 (Mavericks)
+ * x86
+* Windows XP SP3, 2003, Vista, 7
+ * x86
+* Windows 7
+ * x86\_64
- $ $ERL_TOP/bin/cerl -debug
+We also have the following "Daily Cross Builds":
-The debug enabled runtime system features lock violation checking,
-assert checking and various sanity checks to help a developer ensure
-correctness. Some of these features can be enabled on a normal beam
-using appropriate configure options.
+* SuSE Linux/GNU 10.1 x86 -> SuSE Linux/GNU 10.1 x86\_64
+* SuSE Linux/GNU 10.1 x86\_64 -> Linux/GNU TILEPro64
-There are other types of runtime systems that can be built as well
-using the similar steps just described.
+and the following "Daily Cross Build Tests":
- $ make $TYPE FLAVOR=$FLAVOR
+* SuSE Linux/GNU 10.1 x86\_64
-where `$TYPE` is `opt`, `gcov`, `gprof`, `debug`, `valgrind`, or `lcnt`.
-These different beam types are useful for debugging and profiling
-purposes.
Authors
-------
@@ -764,6 +815,7 @@ Authors are mostly listed in the application's `AUTHORS` files,
that is `$ERL_TOP/lib/*/AUTHORS` and `$ERL_TOP/erts/AUTHORS`,
not in the individual source files.
+
Copyright and License
---------------------
@@ -784,30 +836,25 @@ under the License.
%CopyrightEnd%
-More Information
-----------------
-
-More information can be found at <http://www.erlang.org>.
-Modifying This Document
------------------------
-
-Before modifying this document you need to have a look at the
-[$ERL_TOP/HOWTO/MARKDOWN.md][] document.
[$ERL_TOP/HOWTO/INSTALL-CROSS.md]: INSTALL-CROSS.md
[$ERL_TOP/HOWTO/INSTALL-WIN32.md]: INSTALL-WIN32.md
[DESTDIR]: http://www.gnu.org/prep/standards/html_node/DESTDIR.html
- [Building in Git]: #How-to-Build-and-Install-ErlangOTP_Building-in-Git
- [Pre-built Source Release]: #How-to-Build-and-Install-ErlangOTP_Prebuilt-Source-Release
- [make and $ERL_TOP]: #How-to-Build-and-Install-ErlangOTP_make-and-ERLTOP
+ [Building in Git]: #Advanced-configuration-and-build-of-ErlangOTP_Building_Within-Git
+ [Advanced Configure]: #Advanced-configuration-and-build-of-ErlangOTP_Configuring
+ [Pre-built Source Release]: #Advanced-configuration-and-build-of-ErlangOTP_Building_Prebuilt-Source-Release
+ [make and $ERL_TOP]: #Advanced-configuration-and-build-of-ErlangOTP_make-and-ERLTOP
[html documentation]: http://www.erlang.org/download/otp_doc_html_%OTP-VSN%.tar.gz
[man pages]: http://www.erlang.org/download/otp_doc_man_%OTP-VSN%.tar.gz
[the released source tar ball]: http://www.erlang.org/download/otp_src_%OTP-VSN%.tar.gz
+ [System Principles]: ../system_principles/system_principles
+ [Known platform issues]: #Known-platform-issues
[native build]: #How-to-Build-and-Install-ErlangOTP
[cross build]: INSTALL-CROSS.md
- [$ERL_TOP/HOWTO/MARKDOWN.md]: MARKDOWN.md
-
- [?TOC]: true
+ [Required Utilities]: #Required-Utilities
+ [Optional Utilities]: #Optional-Utilities
+ [Building on a Mac]: #Advanced-configuration-and-build-of-ErlangOTP_Building_OS-X-Darwin
+ [Building with wxErlang]: #Advanced-configuration-and-build-of-ErlangOTP_Building_Building-with-wxErlang
diff --git a/README.md b/README.md
index a6a4f11be8..bf80b6391b 100644
--- a/README.md
+++ b/README.md
@@ -12,6 +12,15 @@ middle-ware to develop these systems. It includes its own distributed
database, applications to interface towards other languages, debugging
and release handling tools.
+ERTS and BEAM
+-------------
+**BEAM** is the name of the virtual machine where all Erlang code is executed.
+Every compiled Erlang file has the suffix .beam. The virtual machine
+is sometimes referred to as the emulator.
+
+**ERTS** is the Erlang Runtime System where the BEAM, kernel and
+standard libraries amongst others are included.
+
More information can be found at [erlang.org] [1].
Building and Installing
@@ -57,7 +66,7 @@ Copyright and License
> %CopyrightBegin%
>
-> Copyright Ericsson AB 2010-2012. All Rights Reserved.
+> Copyright Ericsson AB 2010-2014. All Rights Reserved.
>
> The contents of this file are subject to the Erlang Public License,
> Version 1.1, (the "License"); you may not use this file except in
diff --git a/erts/doc/src/erlang.xml b/erts/doc/src/erlang.xml
index 7aaded200c..e7e9b218f2 100644
--- a/erts/doc/src/erlang.xml
+++ b/erts/doc/src/erlang.xml
@@ -1784,6 +1784,15 @@ os_prompt% </pre>
</desc>
</func>
<func>
+ <name name="is_map" arity="1"/>
+ <fsummary>Check whether a term is a map</fsummary>
+ <desc>
+ <p>Returns <c>true</c> if <c><anno>Term</anno></c> is a map;
+ otherwise returns <c>false</c>.</p>
+ <p>Allowed in guard tests.</p>
+ </desc>
+ </func>
+ <func>
<name name="is_number" arity="1"/>
<fsummary>Check whether a term is a number</fsummary>
<desc>
@@ -2220,6 +2229,17 @@ os_prompt% </pre>
</desc>
</func>
<func>
+ <name name="map_size" arity="1"/>
+ <fsummary>Return the size of a map</fsummary>
+ <desc>
+ <p>Returns an integer which is the number of key-value pairs in <c><anno>Map</anno></c>.</p>
+ <pre>
+> <input>map_size(#{a=>1, b=>2, c=>3}).</input>
+3</pre>
+ <p>Allowed in guard tests.</p>
+ </desc>
+ </func>
+ <func>
<name name="max" arity="2"/>
<fsummary>Return the largest of two term</fsummary>
<desc>
diff --git a/erts/emulator/beam/erl_process.c b/erts/emulator/beam/erl_process.c
index 8bf0cc9491..b4b97d7df1 100644
--- a/erts/emulator/beam/erl_process.c
+++ b/erts/emulator/beam/erl_process.c
@@ -9207,7 +9207,6 @@ Process *schedule(Process *p, int calls)
*/
pick_next_process: {
erts_aint32_t psflg_band_mask;
- erts_aint32_t running_flag;
int prio_q;
int qmask;
@@ -9269,12 +9268,6 @@ Process *schedule(Process *p, int calls)
state = erts_smp_atomic32_read_nob(&p->state);
}
-
- if (state & ERTS_PSFLG_ACTIVE_SYS)
- running_flag = ERTS_PSFLG_RUNNING_SYS;
- else
- running_flag = ERTS_PSFLG_RUNNING;
-
while (1) {
erts_aint32_t exp, new, tmp;
tmp = new = exp = state;
@@ -9284,8 +9277,12 @@ Process *schedule(Process *p, int calls)
tmp = state & (ERTS_PSFLG_SUSPENDED
| ERTS_PSFLG_PENDING_EXIT
| ERTS_PSFLG_ACTIVE_SYS);
- if (tmp != ERTS_PSFLG_SUSPENDED)
- new |= running_flag;
+ if (tmp != ERTS_PSFLG_SUSPENDED) {
+ if (state & ERTS_PSFLG_ACTIVE_SYS)
+ new |= ERTS_PSFLG_RUNNING_SYS;
+ else
+ new |= ERTS_PSFLG_RUNNING;
+ }
}
state = erts_smp_atomic32_cmpxchg_relb(&p->state, new, exp);
if (state == exp) {
diff --git a/erts/emulator/test/binary_SUITE.erl b/erts/emulator/test/binary_SUITE.erl
index 938aac6a0e..7aba367e33 100644
--- a/erts/emulator/test/binary_SUITE.erl
+++ b/erts/emulator/test/binary_SUITE.erl
@@ -64,7 +64,7 @@
-export([sleeper/0,trapping_loop/4]).
suite() -> [{ct_hooks,[ts_install_cth]},
- {timetrap,{minutes,2}}].
+ {timetrap,{minutes,4}}].
all() ->
[copy_terms, conversions, deep_lists, deep_bitstr_lists,
@@ -1266,7 +1266,7 @@ deep(Config) when is_list(Config) ->
deep_roundtrip(T) ->
B = term_to_binary(T),
- T = binary_to_term_stress(B).
+ T = binary_to_term(B).
obsolete_funs(Config) when is_list(Config) ->
erts_debug:set_internal_state(available_internal_state, true),
diff --git a/erts/emulator/test/match_spec_SUITE.erl b/erts/emulator/test/match_spec_SUITE.erl
index 330bef7104..8038888796 100644
--- a/erts/emulator/test/match_spec_SUITE.erl
+++ b/erts/emulator/test/match_spec_SUITE.erl
@@ -42,7 +42,7 @@
-export([init_per_testcase/2, end_per_testcase/2]).
init_per_testcase(Func, Config) when is_atom(Func), is_list(Config) ->
- Dog=?t:timetrap(?t:seconds(10)),
+ Dog=?t:timetrap(?t:seconds(30)),
[{watchdog, Dog}|Config].
end_per_testcase(_Func, Config) ->
diff --git a/erts/emulator/test/port_SUITE.erl b/erts/emulator/test/port_SUITE.erl
index 202a8b7537..e01b2f253b 100644
--- a/erts/emulator/test/port_SUITE.erl
+++ b/erts/emulator/test/port_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2013. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2014. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -1698,12 +1698,13 @@ otp_5119(Config) when is_list(Config) ->
Path = ?config(data_dir, Config),
ok = load_driver(Path, "exit_drv"),
PI1 = port_ix(otp_5119_fill_empty_port_tab([])),
- PI2 = port_ix(erlang:open_port({spawn, "exit_drv"}, [])),
+ Port2 = erlang:open_port({spawn, "exit_drv"}, []),
+ PI2 = port_ix(Port2),
{PortIx1, PortIx2} = case PI2 > PI1 of
true ->
{PI1, PI2};
false ->
- {port_ix(otp_5119_fill_empty_port_tab([PI2])),
+ {port_ix(otp_5119_fill_empty_port_tab([Port2])),
port_ix(erlang:open_port({spawn, "exit_drv"}, []))}
end,
MaxPorts = max_ports(),
@@ -2318,7 +2319,7 @@ close_deaf_port(Config) when is_list(Config) ->
test_server:timetrap_cancel(Dog),
Res.
-close_deaf_port_1(1000, _) ->
+close_deaf_port_1(200, _) ->
ok;
close_deaf_port_1(N, Cmd) ->
Timeout = integer_to_list(random:uniform(5*1000)),
diff --git a/erts/preloaded/ebin/erl_prim_loader.beam b/erts/preloaded/ebin/erl_prim_loader.beam
index 26f851fd7a..f1e588320b 100644
--- a/erts/preloaded/ebin/erl_prim_loader.beam
+++ b/erts/preloaded/ebin/erl_prim_loader.beam
Binary files differ
diff --git a/erts/preloaded/ebin/erlang.beam b/erts/preloaded/ebin/erlang.beam
index 344176b71b..b4e22f6d74 100644
--- a/erts/preloaded/ebin/erlang.beam
+++ b/erts/preloaded/ebin/erlang.beam
Binary files differ
diff --git a/erts/preloaded/ebin/erts_internal.beam b/erts/preloaded/ebin/erts_internal.beam
index bd402f9a98..d41c833e05 100644
--- a/erts/preloaded/ebin/erts_internal.beam
+++ b/erts/preloaded/ebin/erts_internal.beam
Binary files differ
diff --git a/erts/preloaded/ebin/init.beam b/erts/preloaded/ebin/init.beam
index 5d49eed469..7f2d2740e1 100644
--- a/erts/preloaded/ebin/init.beam
+++ b/erts/preloaded/ebin/init.beam
Binary files differ
diff --git a/erts/preloaded/ebin/otp_ring0.beam b/erts/preloaded/ebin/otp_ring0.beam
index 2607739d12..4d22d8bace 100644
--- a/erts/preloaded/ebin/otp_ring0.beam
+++ b/erts/preloaded/ebin/otp_ring0.beam
Binary files differ
diff --git a/erts/preloaded/ebin/prim_eval.beam b/erts/preloaded/ebin/prim_eval.beam
index d665d35ab1..efc8347b6e 100644
--- a/erts/preloaded/ebin/prim_eval.beam
+++ b/erts/preloaded/ebin/prim_eval.beam
Binary files differ
diff --git a/erts/preloaded/ebin/prim_file.beam b/erts/preloaded/ebin/prim_file.beam
index 201252de34..6c49b5185e 100644
--- a/erts/preloaded/ebin/prim_file.beam
+++ b/erts/preloaded/ebin/prim_file.beam
Binary files differ
diff --git a/erts/preloaded/ebin/prim_inet.beam b/erts/preloaded/ebin/prim_inet.beam
index ff8265414e..fe5431c5ff 100644
--- a/erts/preloaded/ebin/prim_inet.beam
+++ b/erts/preloaded/ebin/prim_inet.beam
Binary files differ
diff --git a/erts/preloaded/ebin/prim_zip.beam b/erts/preloaded/ebin/prim_zip.beam
index f80d4a96e5..73be297bbb 100644
--- a/erts/preloaded/ebin/prim_zip.beam
+++ b/erts/preloaded/ebin/prim_zip.beam
Binary files differ
diff --git a/erts/preloaded/ebin/zlib.beam b/erts/preloaded/ebin/zlib.beam
index dba3ec9546..193cebdc31 100644
--- a/erts/preloaded/ebin/zlib.beam
+++ b/erts/preloaded/ebin/zlib.beam
Binary files differ
diff --git a/erts/preloaded/src/erlang.erl b/erts/preloaded/src/erlang.erl
index fbc37bd955..cabbbd191f 100644
--- a/erts/preloaded/src/erlang.erl
+++ b/erts/preloaded/src/erlang.erl
@@ -1745,9 +1745,9 @@ is_pid(_Term) ->
erlang:nif_error(undefined).
%% Shadowed by erl_bif_types: erlang:is_map/1
--spec is_map(Map) -> boolean() when
- Map :: map().
-is_map(_Map) ->
+-spec is_map(Term) -> boolean() when
+ Term :: term().
+is_map(_Term) ->
erlang:nif_error(undefined).
%% Shadowed by erl_bif_types: erlang:is_port/1
diff --git a/erts/test/otp_SUITE.erl b/erts/test/otp_SUITE.erl
index cd5cfcbab4..229d10ccee 100644
--- a/erts/test/otp_SUITE.erl
+++ b/erts/test/otp_SUITE.erl
@@ -392,12 +392,18 @@ is_bad_encoding(File) ->
end.
runtime_dependencies(Config) ->
+ %% Ignore applications intentionally not declaring dependencies
+ %% found by xref.
+ IgnoreApps = [diameter],
+
+
%% Verify that (at least) OTP application runtime dependencies found
%% by xref are listed in the runtime_dependencies field of the .app file
%% of each application.
Server = ?config(xref_server, Config),
{ok, AE} = xref:q(Server, "AE"),
SAE = lists:keysort(1, AE),
+ put(ignored_failures, []),
{AppDep, AppDeps} = lists:foldl(fun ({App, App}, Acc) ->
Acc;
({App, Dep}, {undefined, []}) ->
@@ -409,8 +415,45 @@ runtime_dependencies(Config) ->
end,
{undefined, []},
SAE),
- [] = check_apps_deps([AppDep|AppDeps]),
- ok.
+ [] = lists:filter(fun ({missing_runtime_dependency,
+ AppFile,
+ common_test}) ->
+ %% The test_server app is contaminated by
+ %% common_test when run in a source tree. It
+ %% should however *not* be contaminated
+ %% when run in an installation.
+ case {filename:basename(AppFile),
+ is_run_in_src_tree()} of
+ {"test_server.app", true} ->
+ false;
+ _ ->
+ true
+ end;
+ (_) ->
+ true
+ end,
+ check_apps_deps([AppDep|AppDeps], IgnoreApps)),
+ case IgnoreApps of
+ [] ->
+ ok;
+ _ ->
+ Comment = lists:flatten(io_lib:format("Ignored applications: ~p "
+ "Ignored failures: ~p",
+ [IgnoreApps,
+ get(ignored_failures)])),
+ {comment, Comment}
+ end.
+
+is_run_in_src_tree() ->
+ %% At least currently run_erl is not present in <code-root>/bin
+ %% in the source tree, but present in <code-root>/bin of an
+ %% ordinary installation.
+ case file:read_file_info(filename:join([code:root_dir(),
+ "bin",
+ "run_erl"])) of
+ {ok, _} -> false;
+ {error, _} -> true
+ end.
have_rdep(_App, [], _Dep) ->
false;
@@ -424,28 +467,43 @@ have_rdep(App, [RDep | RDeps], Dep) ->
have_rdep(App, RDeps, Dep)
end.
-check_app_deps(_App, _AppFile, _AFDeps, []) ->
+check_app_deps(_App, _AppFile, _AFDeps, [], _IgnoreApps) ->
[];
-check_app_deps(App, AppFile, AFDeps, [XRDep | XRDeps]) ->
- ResOtherDeps = check_app_deps(App, AppFile, AFDeps, XRDeps),
+check_app_deps(App, AppFile, AFDeps, [XRDep | XRDeps], IgnoreApps) ->
+ ResOtherDeps = check_app_deps(App, AppFile, AFDeps, XRDeps, IgnoreApps),
case have_rdep(App, AFDeps, XRDep) of
true ->
ResOtherDeps;
false ->
- [{missing_runtime_dependency, AppFile, XRDep} | ResOtherDeps]
+ Failure = {missing_runtime_dependency, AppFile, XRDep},
+ case lists:member(App, IgnoreApps) of
+ true ->
+ put(ignored_failures, [Failure | get(ignored_failures)]),
+ ResOtherDeps;
+ false ->
+ [Failure | ResOtherDeps]
+ end
end.
-check_apps_deps([]) ->
+check_apps_deps([], _IgnoreApps) ->
[];
-check_apps_deps([{App, Deps}|AppDeps]) ->
- ResOtherApps = check_apps_deps(AppDeps),
+check_apps_deps([{App, Deps}|AppDeps], IgnoreApps) ->
+ ResOtherApps = check_apps_deps(AppDeps, IgnoreApps),
AppFile = code:where_is_file(atom_to_list(App) ++ ".app"),
{ok,[{application, App, Info}]} = file:consult(AppFile),
case lists:keyfind(runtime_dependencies, 1, Info) of
{runtime_dependencies, RDeps} ->
- check_app_deps(App, AppFile, RDeps, Deps) ++ ResOtherApps;
+ check_app_deps(App, AppFile, RDeps, Deps, IgnoreApps)
+ ++ ResOtherApps;
false ->
- [{missing_runtime_dependencies_key, AppFile} | ResOtherApps]
+ Failure = {missing_runtime_dependencies_key, AppFile},
+ case lists:member(App, IgnoreApps) of
+ true ->
+ put(ignored_failures, [Failure | get(ignored_failures)]),
+ ResOtherApps;
+ false ->
+ [Failure | ResOtherApps]
+ end
end.
%%%
diff --git a/lib/common_test/doc/src/ct_hooks.xml b/lib/common_test/doc/src/ct_hooks.xml
index 859ff9df14..cab6dfea51 100644
--- a/lib/common_test/doc/src/ct_hooks.xml
+++ b/lib/common_test/doc/src/ct_hooks.xml
@@ -450,12 +450,15 @@
</func>
<func>
- <name>Module:on_tc_fail(TestcaseName, Reason, CTHState) -&gt;
+ <name>Module:on_tc_fail(TestName, Reason, CTHState) -&gt;
NewCTHState</name>
<fsummary>Called after the CTH scope ends</fsummary>
<type>
- <v>TestcaseName = init_per_suite | end_per_suite |
- init_per_group | end_per_group | atom()</v>
+ <v>TestName = init_per_suite | end_per_suite |
+ {init_per_group,GroupName} | {end_per_group,GroupName} |
+ {FuncName,GroupName} | FuncName</v>
+ <v>FuncName = atom()</v>
+ <v>GroupName = atom()</v>
<v>Reason = term()</v>
<v>CTHState = NewCTHState = term()</v>
</type>
@@ -463,14 +466,16 @@
<desc>
<p> OPTIONAL </p>
- <p>This function is called whenever a testcase fails.
- It is called after the post function has been called for
- the testcase which failed. i.e.
- if init_per_suite fails this function is called after
+ <p>This function is called whenever a test case (or config function)
+ fails. It is called after the post function has been called for
+ the failed test case. I.e. if init_per_suite fails, this function
+ is called after
<seealso marker="#Module:post_init_per_suite-4">
- post_init_per_suite</seealso>, and if a testcase fails it is called
+ post_init_per_suite</seealso>, and if a test case fails, it is called
after <seealso marker="#Module:post_end_per_testcase-4">
- post_end_per_testcase</seealso>.</p>
+ post_end_per_testcase</seealso>. If the failed test case belongs
+ to a test case group, the first argument is a tuple
+ <c>{FuncName,GroupName}</c>, otherwise simply the function name.</p>
<p>The data which comes with the Reason follows the same format as the
<seealso marker="event_handler_chapter#failreason">FailReason
@@ -481,12 +486,14 @@
</func>
<func>
- <name>Module:on_tc_skip(TestcaseName, Reason, CTHState) -&gt;
+ <name>Module:on_tc_skip(TestName, Reason, CTHState) -&gt;
NewCTHState</name>
<fsummary>Called after the CTH scope ends</fsummary>
<type>
- <v>TestcaseName = end_per_suite | {init_per_group,GroupName} |
- {end_per_group,GroupName} | atom()</v>
+ <v>TestName = init_per_suite | end_per_suite |
+ {init_per_group,GroupName} | {end_per_group,GroupName} |
+ {FuncName,GroupName} | FuncName</v>
+ <v>FuncName = atom()</v>
<v>GroupName = atom()</v>
<v>Reason = {tc_auto_skip | tc_user_skip, term()}</v>
<v>CTHState = NewCTHState = term()</v>
@@ -495,14 +502,17 @@
<desc>
<p> OPTIONAL </p>
- <p>This function is called whenever a testcase is skipped.
- It is called after the post function has been called for the
- testcase which was skipped.
- i.e. if init_per_group is skipped this function is called after
- <seealso marker="#Module:post_init_per_suite-4">post_init_per_group
- </seealso>, and if a testcase is skipped it is called after
- <seealso marker="#Module:post_end_per_testcase-4">post_end_per_testcase
- </seealso>.</p>
+ <p>This function is called whenever a test case (or config function)
+ is skipped. It is called after the post function has been called
+ for the skipped test case. I.e. if init_per_group is skipped, this
+ function is called after
+ <seealso marker="#Module:post_init_per_group-4">
+ post_init_per_group</seealso>, and if a test case is skipped,
+ it is called after
+ <seealso marker="#Module:post_end_per_testcase-4">
+ post_end_per_testcase</seealso>. If the skipped test case belongs to a
+ test case group, the first argument is a tuple <c>{FuncName,GroupName}</c>,
+ otherwise simply the function name.</p>
<p>The data which comes with the Reason follows the same format as
<seealso marker="event_handler_chapter#tc_auto_skip">tc_auto_skip
diff --git a/lib/common_test/doc/src/ct_run.xml b/lib/common_test/doc/src/ct_run.xml
index 39259b092a..d8e79ca80e 100644
--- a/lib/common_test/doc/src/ct_run.xml
+++ b/lib/common_test/doc/src/ct_run.xml
@@ -108,6 +108,7 @@
EvHandler2 InitArg2 and .. EvHandlerN InitArgN]
[-include InclDir1 InclDir2 .. InclDirN]
[-no_auto_compile]
+ [-abort_if_missing_suites]
[-muliply_timetraps Multiplier]
[-scale_timetraps]
[-create_priv_dir auto_per_run | auto_per_tc | manual_per_tc]
@@ -144,6 +145,7 @@
EvHandler2 InitArg2 and .. EvHandlerN InitArgN]
[-include InclDir1 InclDir2 .. InclDirN]
[-no_auto_compile]
+ [-abort_if_missing_suites]
[-muliply_timetraps Multiplier]
[-scale_timetraps]
[-create_priv_dir auto_per_run | auto_per_tc | manual_per_tc]
@@ -171,6 +173,7 @@
[-decrypt_key Key] | [-decrypt_file KeyFile]
[-include InclDir1 InclDir2 .. InclDirN]
[-no_auto_compile]
+ [-abort_if_missing_suites]
[-muliply_timetraps Multiplier]
[-scale_timetraps]
[-create_priv_dir auto_per_run | auto_per_tc | manual_per_tc]
diff --git a/lib/common_test/doc/src/event_handler_chapter.xml b/lib/common_test/doc/src/event_handler_chapter.xml
index 47d0ba59fb..45f01c12ec 100644
--- a/lib/common_test/doc/src/event_handler_chapter.xml
+++ b/lib/common_test/doc/src/event_handler_chapter.xml
@@ -227,11 +227,13 @@
<item>
<marker id="tc_auto_skip"></marker>
- <c>#event{name = tc_auto_skip, data = {Suite,Func,Reason}}</c>
+ <c>#event{name = tc_auto_skip, data = {Suite,TestName,Reason}}</c>
<p><c>Suite = atom()</c>, the name of the suite.</p>
- <p><c>Func = atom() | {end_per_group,GroupName}</c>, the name of the test case
- or configuration function.</p>
- <p><c>GroupName = atom()</c>, name of the group.</p>
+ <p><c>TestName = init_per_suite | end_per_suite |
+ {init_per_group,GroupName} | {end_per_group,GroupName} |
+ {FuncName,GroupName} | FuncName</c></p>
+ <p><c>FuncName = atom()</c>, the name of the test case or configuration function.</p>
+ <p><c>GroupName = atom()</c>, the name of the test case group.</p>
<p><c>Reason = {failed,FailReason} |
{require_failed_in_suite0,RequireInfo}</c>,
reason for auto skipping <c>Func</c>.</p>
@@ -252,21 +254,26 @@
<c>init_per_group</c>, a failed <c>require</c> in <c>suite/0</c>, or a failed test case
in a sequence. Note that this event is never received as a result of a test case getting
skipped because of <c>init_per_testcase</c> failing, since that information is carried with
- the <c>tc_done</c> event.
+ the <c>tc_done</c> event. If a failed test case belongs to a test case group, the second
+ data element is a tuple <c>{FuncName,GroupName}</c>, otherwise simply the function name.
</p></item>
-
+
<item>
<marker id="tc_user_skip"></marker>
- <c>#event{name = tc_user_skip, data = {Suite,Func,Comment}}</c>
+ <c>#event{name = tc_user_skip, data = {Suite,TestName,Comment}}</c>
<p><c>Suite = atom()</c>, the name of the suite.</p>
- <p><c>Func = atom() | {end_per_group,GroupName}</c>, the name of the test case
- or configuration function.</p>
- <p><c>GroupName = atom()</c>, name of the group.</p>
+ <p><c>TestName = init_per_suite | end_per_suite |
+ {init_per_group,GroupName} | {end_per_group,GroupName} |
+ {FuncName,GroupName} | FuncName</c></p>
+ <p><c>FuncName = atom()</c>, the name of the test case or configuration function.</p>
+ <p><c>GroupName = atom()</c>, the name of the test case group.</p>
<p><c>Comment = string()</c>, reason for skipping the test case.</p>
<p>This event specifies that a test case has been skipped by the user.
It is only ever received if the skip was declared in a test specification.
Otherwise, user skip information is received as a <c>{skipped,SkipReason}</c>
- result in the <c>tc_done</c> event for the test case.
+ result in the <c>tc_done</c> event for the test case. If a skipped test case belongs
+ to a test case group, the second data element is a tuple <c>{FuncName,GroupName}</c>,
+ otherwise simply the function name.
</p></item>
<item><c>#event{name = test_stats, data = {Ok,Failed,Skipped}}</c>
diff --git a/lib/common_test/doc/src/run_test_chapter.xml b/lib/common_test/doc/src/run_test_chapter.xml
index ef21948f89..864f82cb63 100644
--- a/lib/common_test/doc/src/run_test_chapter.xml
+++ b/lib/common_test/doc/src/run_test_chapter.xml
@@ -59,7 +59,15 @@
<p>If compilation should fail for one or more suites, the compilation errors
are printed to tty and the operator is asked if the test run should proceed
without the missing suites, or be aborted. If the operator chooses to proceed,
- it is noted in the HTML log which tests have missing suites.</p>
+ it is noted in the HTML log which tests have missing suites. If Common Test is
+ unable to prompt the user after compilation failure (if Common Test doesn't
+ control stdin), the test run will proceed automatically without the missing
+ suites. This behaviour can however be modified with the
+ <c><![CDATA[ct_run]]></c> flag <c><![CDATA[-abort_if_missing_suites]]></c>,
+ or the <c><![CDATA[ct:run_test/1]]></c> option
+ <c><![CDATA[{abort_if_missing_suites,TrueOrFalse}]]></c>. If
+ <c><![CDATA[abort_if_missing_suites]]></c> is set (to true), the test run
+ will stop immediately if some suites fail to compile.</p>
<p>Any help module (i.e. regular Erlang module with name not ending with
"_SUITE") that resides in the same test object directory as a suite
@@ -167,6 +175,7 @@
<seealso marker="ct_hooks_chapter#builtin_cths">Built-in Common Test Hooks</seealso>. Default is <c>true</c>.</item>
<item><c><![CDATA[-include]]></c>, specifies include directories (see above).</item>
<item><c><![CDATA[-no_auto_compile]]></c>, disables the automatic test suite compilation feature (see above).</item>
+ <item><c><![CDATA[-abort_if_missing_suites]]></c>, aborts the test run if one or more suites fail to compile (see above).</item>
<item><c><![CDATA[-multiply_timetraps <n>]]></c>, extends <seealso marker="write_test_chapter#timetraps">timetrap
timeout</seealso> values.</item>
<item><c><![CDATA[-scale_timetraps <bool>]]></c>, enables automatic <seealso marker="write_test_chapter#timetraps">timetrap
@@ -744,6 +753,9 @@
{auto_compile, Bool},
{auto_compile, NodeRefs, Bool},
+ {abort_if_missing_suites, Bool},
+ {abort_if_missing_suites, NodeRefs, Bool},
+
{config, ConfigFiles}.
{config, ConfigDir, ConfigBaseNames}.
{config, NodeRefs, ConfigFiles}.
diff --git a/lib/common_test/src/ct.erl b/lib/common_test/src/ct.erl
index e6732f7fc7..241cd928b7 100644
--- a/lib/common_test/src/ct.erl
+++ b/lib/common_test/src/ct.erl
@@ -150,7 +150,8 @@ run(TestDirs) ->
%%% {silent_connections,Conns} | {stylesheet,CSSFile} |
%%% {cover,CoverSpecFile} | {cover_stop,Bool} | {step,StepOpts} |
%%% {event_handler,EventHandlers} | {include,InclDirs} |
-%%% {auto_compile,Bool} | {create_priv_dir,CreatePrivDir} |
+%%% {auto_compile,Bool} | {abort_if_missing_suites,Bool} |
+%%% {create_priv_dir,CreatePrivDir} |
%%% {multiply_timetraps,M} | {scale_timetraps,Bool} |
%%% {repeat,N} | {duration,DurTime} | {until,StopTime} |
%%% {force_stop,ForceStop} | {decrypt,DecryptKeyOrFile} |
diff --git a/lib/common_test/src/ct_framework.erl b/lib/common_test/src/ct_framework.erl
index 7d577462b0..9ef917a507 100644
--- a/lib/common_test/src/ct_framework.erl
+++ b/lib/common_test/src/ct_framework.erl
@@ -1274,7 +1274,7 @@ report(What,Data) ->
ct_util:set_testdata({What,Data}),
ok;
tc_start ->
- %% Data = {Suite,{Func,GroupName}},LogFileName}
+ %% Data = {{Suite,{Func,GroupName}},LogFileName}
Data1 = case Data of
{{Suite,{Func,undefined}},LFN} -> {{Suite,Func},LFN};
_ -> Data
diff --git a/lib/common_test/src/ct_netconfc.erl b/lib/common_test/src/ct_netconfc.erl
index 6fc840745d..a3861dc745 100644
--- a/lib/common_test/src/ct_netconfc.erl
+++ b/lib/common_test/src/ct_netconfc.erl
@@ -536,7 +536,7 @@ send(Client, SimpleXml) ->
Client :: client(),
SimpleXml :: simple_xml(),
Timeout :: timeout(),
- Result :: ok | {error,error_reason()}.
+ Result :: simple_xml() | {error,error_reason()}.
%% @doc Send an XML document to the server.
%%
%% The given XML document is sent as is to the server. This function
@@ -556,7 +556,7 @@ send_rpc(Client, SimpleXml) ->
Client :: client(),
SimpleXml :: simple_xml(),
Timeout :: timeout(),
- Result :: ok | {error,error_reason()}.
+ Result :: [simple_xml()] | {error,error_reason()}.
%% @doc Send a Netconf <code>rpc</code> request to the server.
%%
%% The given XML document is wrapped in a valid Netconf
@@ -635,7 +635,7 @@ get(Client, Filter) ->
Client :: client(),
Filter :: simple_xml() | xpath(),
Timeout :: timeout(),
- Result :: {ok,simple_xml()} | {error,error_reason()}.
+ Result :: {ok,[simple_xml()]} | {error,error_reason()}.
%% @doc Get data.
%%
%% This operation returns both configuration and state data from the
@@ -661,7 +661,7 @@ get_config(Client, Source, Filter) ->
Source :: netconf_db(),
Filter :: simple_xml() | xpath(),
Timeout :: timeout(),
- Result :: {ok,simple_xml()} | {error,error_reason()}.
+ Result :: {ok,[simple_xml()]} | {error,error_reason()}.
%% @doc Get configuration data.
%%
%% To be able to access another source than `running', the server
@@ -759,7 +759,7 @@ action(Client,Action) ->
Client :: client(),
Action :: simple_xml(),
Timeout :: timeout(),
- Result :: {ok,simple_xml()} | {error,error_reason()}.
+ Result :: {ok,[simple_xml()]} | {error,error_reason()}.
%% @doc Execute an action.
%%
%% @end
diff --git a/lib/common_test/src/ct_telnet.erl b/lib/common_test/src/ct_telnet.erl
index bc22a99741..c9dc2338cd 100644
--- a/lib/common_test/src/ct_telnet.erl
+++ b/lib/common_test/src/ct_telnet.erl
@@ -46,100 +46,80 @@
%%
%% == Logging ==
%%
-%% `ct_telnet' can be configured to uses the `error_logger' for logging telnet
-%% traffic. A special purpose error handler is implemented in
-%% `ct_conn_log_h'. To use this error handler, add the `cth_conn_log'
-%% hook in your test suite, e.g:
-%%
+%% The default logging behaviour of `ct_telnet' is to print information
+%% to the test case HTML log about performed operations and commands
+%% and their corresponding results. What won't be printed to the HTML log
+%% are text strings sent from the telnet server that are not explicitly
+%% received by means of a `ct_telnet' function such as `expect/3'.
+%% `ct_telnet' may however be configured to use a special purpose event handler,
+%% implemented in `ct_conn_log_h', for logging <b>all</b> telnet traffic.
+%% To use this handler, you need to install a Common Test hook named
+%% `cth_conn_log'. Example (using the test suite info function):
%%
%% ```
%% suite() ->
-%% [{ct_hooks, [{cth_conn_log, [{conn_mod(),hook_options()}]}]}].
-%%'''
+%% [{ct_hooks, [{cth_conn_log, [{conn_mod(),hook_options()}]}]}].
+%% '''
%%
%% `conn_mod()' is the name of the common_test module implementing
%% the connection protocol, i.e. `ct_telnet'.
%%
-%% The hook option `log_type' specifies the type of logging:
-%%
-%% <dl>
-%% <dt>`raw'</dt>
-%% <dd>The sent and received telnet data is logged to a separate
-%% text file as is, without any formatting. A link to the file is
-%% added to the test case HTML log.</dd>
+%% The `cth_conn_log' hook performs unformatted logging of telnet data to
+%% a separate text file. All telnet communication is captured and printed,
+%% including arbitrary data sent from the server. The link to this text file
+%% can be found on the top of the test case HTML log.
%%
-%% <dt>`html (default)'</dt>
-%% <dd>The sent and received telnet traffic is pretty printed
-%% directly in the test case HTML log.</dd>
-%%
-%% <dt>`silent'</dt>
-%% <dd>Telnet traffic is not logged.</dd>
-%% </dl>
-%%
-%% By default, all telnet traffic is logged in one single log
-%% file. However, it is possible to have different connections logged
-%% in separate files. To do this, use the hook option `hosts' and
-%% list the names of the servers/connections that will be used in the
-%% suite. Note that the connections must be named for this to work
+%% By default, data for all telnet connections is logged in one common
+%% file (named `default'), which might get messy e.g. if multiple telnet
+%% sessions are running in parallel. It is therefore possible to create a
+%% separate log file for each connection. To configure this, use the hook
+%% option `hosts' and list the names of the servers/connections that will be
+%% used in the suite. Note that the connections must be named for this to work
%% (see the `open' function below).
%%
-%% The `hosts' option has no effect if `log_type' is set to `html' or
-%% `silent'.
+%% The hook option named `log_type' may be used to change the `cth_conn_log'
+%% behaviour. The default value of this option is `raw', which results in the
+%% behaviour described above. If the value is set to `html', all telnet
+%% communication is printed to the test case HTML log instead.
%%
-%% The hook options can also be specified in a configuration file with
-%% the configuration variable `ct_conn_log':
+%% All `cth_conn_log' hook options described above can also be specified in
+%% a configuration file with the configuration variable `ct_conn_log'. Example:
%%
%% ```
-%% {ct_conn_log,[{conn_mod(),hook_options()}]}.
-%% '''
-%%
-%% For example:
-%%
-%% ```
-%% {ct_conn_log,[{ct_telnet,[{log_type,raw},
-%% {hosts,[key_or_name()]}]}]}
+%% {ct_conn_log, [{ct_telnet,[{log_type,raw},
+%% {hosts,[key_or_name()]}]}]}
%% '''
%%
%% <b>Note</b> that hook options specified in a configuration file
-%% will overwrite any hardcoded hook options in the test suite.
+%% will overwrite any hardcoded hook options in the test suite!
%%
-%% === Logging example 1 ===
+%% === Logging example ===
%%
-%% The following `ct_hooks' statement will cause raw printing of
-%% telnet traffic to separate logs for the connections named
-%% `server1' and `server2'. Any other connections will be logged
-%% to default telnet log.
+%% The following `ct_hooks' statement will cause printing of telnet traffic
+%% to separate logs for the connections named `server1' and `server2'.
+%% Traffic for any other connections will be logged in the default telnet log.
%%
%% ```
%% suite() ->
-%% [{ct_hooks, [{cth_conn_log, [{ct_telnet,[{log_type,raw}},
-%% {hosts,[server1,server2]}]}
-%% ]}]}].
+%% [{ct_hooks,
+%% [{cth_conn_log, [{ct_telnet,[{hosts,[server1,server2]}]}]}]}].
%%'''
%%
-%% === Logging example 2 ===
-%%
-%% The following configuration file will cause raw logging of all
-%% telnet traffic into one single text file.
+%% As previously explained, the above specification could also be provided
+%% by means of an entry like this in a configuration file:
%%
%% ```
-%% {ct_conn_log,[{ct_telnet,[{log_type,raw}]}]}.
+%% {ct_conn_log, [{ct_telnet,[{hosts,[server1,server2]}]}]}.
%% '''
%%
-%% The `ct_hooks' statement must look like this:
+%% in which case the `ct_hooks' statement in the test suite may simply look
+%% like this:
%%
%% ```
%% suite() ->
-%% [{ct_hooks, [{cth_conn_log, []}]}].
+%% [{ct_hooks, [{cth_conn_log, []}]}].
%% '''
%%
-%% The same `ct_hooks' statement without the configuration file would
-%% cause HTML logging of all telnet connections into the test case
-%% HTML log.
-%%
-%% <b>Note</b> that if the `cth_conn_log' hook is not added, telnet
-%% traffic is still logged in the test case HTML log file (on the legacy
-%% `ct_telnet' format).
%% @end
%% @type connection_type() = telnet | ts1 | ts2
@@ -205,6 +185,7 @@ open(Name) ->
%%% Name = target_name()
%%% ConnType = ct_telnet:connection_type()
%%% Handle = ct_telnet:handle()
+%%% Reason = term()
%%%
%%% @doc Open a telnet connection to the specified target host.
open(Name,ConnType) ->
@@ -234,6 +215,7 @@ open(KeyOrName,ConnType,TargetMod) ->
%%% TargetMod = atom()
%%% Extra = term()
%%% Handle = handle()
+%%% Reason = term()
%%%
%%% @doc Open a telnet connection to the specified target host.
%%%
@@ -295,7 +277,8 @@ open(KeyOrName,ConnType,TargetMod,Extra) ->
%%%-----------------------------------------------------------------
%%% @spec close(Connection) -> ok | {error,Reason}
-%%% Connection = ct_telnet:connection()
+%%% Connection = ct_telnet:connection()
+%%% Reason = term()
%%%
%%% @doc Close the telnet connection and stop the process managing it.
%%%
@@ -330,6 +313,7 @@ cmd(Connection,Cmd) ->
%%% Cmd = string()
%%% Timeout = integer()
%%% Data = [string()]
+%%% Reason = term()
%%% @doc Send a command via telnet and wait for prompt.
cmd(Connection,Cmd,Timeout) ->
case get_handle(Connection) of
@@ -350,6 +334,7 @@ cmdf(Connection,CmdFormat,Args) ->
%%% Args = list()
%%% Timeout = integer()
%%% Data = [string()]
+%%% Reason = term()
%%% @doc Send a telnet command and wait for prompt
%%% (uses a format string and list of arguments to build the command).
cmdf(Connection,CmdFormat,Args,Timeout) when is_list(Args) ->
@@ -360,6 +345,7 @@ cmdf(Connection,CmdFormat,Args,Timeout) when is_list(Args) ->
%%% @spec get_data(Connection) -> {ok,Data} | {error,Reason}
%%% Connection = ct_telnet:connection()
%%% Data = [string()]
+%%% Reason = term()
%%% @doc Get all data which has been received by the telnet client
%%% since last command was sent.
get_data(Connection) ->
@@ -374,6 +360,7 @@ get_data(Connection) ->
%%% @spec send(Connection,Cmd) -> ok | {error,Reason}
%%% Connection = ct_telnet:connection()
%%% Cmd = string()
+%%% Reason = term()
%%% @doc Send a telnet command and return immediately.
%%%
%%% <p>The resulting output from the command can be read with
@@ -391,6 +378,7 @@ send(Connection,Cmd) ->
%%% Connection = ct_telnet:connection()
%%% CmdFormat = string()
%%% Args = list()
+%%% Reason = term()
%%% @doc Send a telnet command and return immediately (uses a format
%%% string and a list of arguments to build the command).
sendf(Connection,CmdFormat,Args) when is_list(Args) ->
@@ -765,8 +753,8 @@ check_if_prompt_was_reached(Data,_) when is_list(Data) ->
check_if_prompt_was_reached(_,_) ->
false.
-%%% @hidden
-%% Functions for logging ct_telnet reports and telnet data
+%%%-----------------------------------------------------------------
+%%% Functions for logging ct_telnet reports and telnet data
heading(Action,undefined) ->
io_lib:format("~w ~w",[?MODULE,Action]);
@@ -776,6 +764,8 @@ heading(Action,Name) ->
force_log(State,Action,String,Args) ->
log(State,Action,String,Args,true).
+%%%-----------------------------------------------------------------
+%%% @hidden
log(State,Action,String,Args) when is_record(State, state) ->
log(State,Action,String,Args,false);
log(Name,Action,String,Args) when is_atom(Name) ->
@@ -783,6 +773,8 @@ log(Name,Action,String,Args) when is_atom(Name) ->
log(TelnPid,Action,String,Args) when is_pid(TelnPid) ->
log(#state{teln_pid=TelnPid},Action,String,Args,false).
+%%%-----------------------------------------------------------------
+%%% @hidden
log(undefined,String,Args) ->
log(#state{},undefined,String,Args,false);
log(Name,String,Args) when is_atom(Name) ->
@@ -790,6 +782,8 @@ log(Name,String,Args) when is_atom(Name) ->
log(TelnPid,String,Args) when is_pid(TelnPid) ->
log(#state{teln_pid=TelnPid},undefined,String,Args).
+%%%-----------------------------------------------------------------
+%%% @hidden
log(#state{name=Name,teln_pid=TelnPid,host=Host,port=Port},
Action,String,Args,ForcePrint) ->
Name1 = if Name == undefined -> get({ct_telnet_pid2name,TelnPid});
@@ -839,6 +833,8 @@ log(#state{name=Name,teln_pid=TelnPid,host=Host,port=Port},
end
end.
+%%%-----------------------------------------------------------------
+%%% @hidden
start_gen_log(Heading) ->
%% check if output is suppressed
case ct_util:is_silenced(telnet) of
@@ -846,6 +842,8 @@ start_gen_log(Heading) ->
false -> ct_gen_conn:start_log(Heading)
end.
+%%%-----------------------------------------------------------------
+%%% @hidden
end_gen_log() ->
%% check if output is suppressed
case ct_util:is_silenced(telnet) of
diff --git a/lib/common_test/src/cth_conn_log.erl b/lib/common_test/src/cth_conn_log.erl
index 0e6c877c5d..1e60f2751e 100644
--- a/lib/common_test/src/cth_conn_log.erl
+++ b/lib/common_test/src/cth_conn_log.erl
@@ -91,12 +91,15 @@ merge_log_info([{Mod,ConfOpts}|ConfList],HookList) ->
{value,{_,HookOpts},HL1} ->
{ConfOpts ++ HookOpts, HL1} % ConfOpts overwrites HookOpts!
end,
- [{Mod,get_log_opts(Opts)} | merge_log_info(ConfList,HookList1)];
+ [{Mod,get_log_opts(Mod,Opts)} | merge_log_info(ConfList,HookList1)];
merge_log_info([],HookList) ->
- [{Mod,get_log_opts(Opts)} || {Mod,Opts} <- HookList].
+ [{Mod,get_log_opts(Mod,Opts)} || {Mod,Opts} <- HookList].
-get_log_opts(Opts) ->
- LogType = proplists:get_value(log_type,Opts,html),
+get_log_opts(Mod,Opts) ->
+ DefaultLogType = if Mod == ct_telnet -> raw;
+ true -> html
+ end,
+ LogType = proplists:get_value(log_type,Opts,DefaultLogType),
Hosts = proplists:get_value(hosts,Opts,[]),
{LogType,Hosts}.
diff --git a/lib/common_test/src/unix_telnet.erl b/lib/common_test/src/unix_telnet.erl
index b05386a5ab..10666b979d 100644
--- a/lib/common_test/src/unix_telnet.erl
+++ b/lib/common_test/src/unix_telnet.erl
@@ -17,8 +17,8 @@
%% %CopyrightEnd%
%%
-%%% @doc Callback module for ct_telnet for talking telnet
-%%% to a unix host.
+%%% @doc Callback module for ct_telnet, for connecting to a telnet
+%%% server on a unix host.
%%%
%%% <p>It requires the following entry in the config file:</p>
%%% <pre>
@@ -28,15 +28,15 @@
%%% {password,Password},
%%% {keep_alive,Bool}]}. % optional</pre>
%%%
-%%% <p>To talk telnet to the host specified by
+%%% <p>To communicate via telnet to the host specified by
%%% <code>HostNameOrIpAddress</code>, use the interface functions in
-%%% <code>ct</code>, e.g. <code>open(Name), cmd(Name,Cmd), ...</code>.</p>
+%%% <code>ct_telnet</code>, e.g. <code>open(Name), cmd(Name,Cmd), ...</code>.</p>
%%%
%%% <p><code>Name</code> is the name you allocated to the unix host in
%%% your <code>require</code> statement. E.g.</p>
-%%% <pre> suite() -> [{require,Name,{unix,[telnet,username,password]}}].</pre>
+%%% <pre> suite() -> [{require,Name,{unix,[telnet]}}].</pre>
%%% <p>or</p>
-%%% <pre> ct:require(Name,{unix,[telnet,username,password]}).</pre>
+%%% <pre> ct:require(Name,{unix,[telnet]}).</pre>
%%%
%%% <p>The "keep alive" activity (i.e. that Common Test sends NOP to the server
%%% every 10 seconds if the connection is idle) may be enabled or disabled for one
@@ -62,20 +62,18 @@
-define(prx,"login: |Password: |\\\$ |> ").
%%%-----------------------------------------------------------------
-%%% @hidden
%%% @spec get_prompt_regexp() -> PromptRegexp
%%% PromptRegexp = ct_telnet:prompt_regexp()
%%%
%%% @doc Callback for ct_telnet.erl.
%%%
-%%% <p>Return the prompt regexp for telnet connections to the
-%%% interwatch instrument.</p>
+%%% <p>Return a suitable regexp string that will match common
+%%% prompts for users on unix hosts.</p>
get_prompt_regexp() ->
?prx.
%%%-----------------------------------------------------------------
-%%% @hidden
%%% @spec connect(ConnName,Ip,Port,Timeout,KeepAlive,Extra) ->
%%% {ok,Handle} | {error,Reason}
%%% ConnName = ct:target_name()
@@ -83,14 +81,15 @@ get_prompt_regexp() ->
%%% Port = integer()
%%% Timeout = integer()
%%% KeepAlive = bool()
-%%% Extra = {Username,Password}
+%%% Extra = ct:target_name() | {Username,Password}
%%% Username = string()
%%% Password = string()
%%% Handle = ct_telnet:handle()
+%%% Reason = term()
%%%
%%% @doc Callback for ct_telnet.erl.
%%%
-%%% <p>Setup telnet connection to a UNIX host.</p>
+%%% <p>Setup telnet connection to a unix host.</p>
connect(ConnName,Ip,Port,Timeout,KeepAlive,Extra) ->
case Extra of
{Username,Password} ->
diff --git a/lib/common_test/test/ct_telnet_SUITE.erl b/lib/common_test/test/ct_telnet_SUITE.erl
index f5cff76fd1..84e69c2b54 100644
--- a/lib/common_test/test/ct_telnet_SUITE.erl
+++ b/lib/common_test/test/ct_telnet_SUITE.erl
@@ -180,14 +180,20 @@ telnet_config(unix_telnet, legacy) ->
{ct_conn_log,[]}];
%% LogType same as GroupName
telnet_config(unix_telnet, LogType) ->
+ LogTypeTerm = if LogType == raw -> [];
+ true -> [{log_type,LogType}]
+ end,
[{unix, ct:get_config(unix)},
{ct_conn_log,
- [{ct_telnet,[{log_type,LogType},
- {hosts,[telnet_server_conn1,
- telnet_server_conn2,
- telnet_server_conn3,
- telnet_server_conn4]}]}]}];
+ [{ct_telnet, LogTypeTerm ++
+ [{hosts,[telnet_server_conn1,
+ telnet_server_conn2,
+ telnet_server_conn3,
+ telnet_server_conn4]}]}]}];
telnet_config(_, LogType) ->
+ LogTypeTerm = if LogType == raw -> [];
+ true -> [{log_type,LogType}]
+ end,
[{unix,[{telnet,"localhost"},
{port, ?erl_telnet_server_port},
{username,?erl_telnet_server_user},
@@ -202,11 +208,11 @@ telnet_config(_, LogType) ->
[{ct_conn_log,[]}];
true ->
[{ct_conn_log,
- [{ct_telnet,[{log_type,LogType},
- {hosts,[telnet_server_conn1,
- telnet_server_conn2,
- telnet_server_conn3,
- telnet_server_conn4]}]}]}]
+ [{ct_telnet, LogTypeTerm ++
+ [{hosts,[telnet_server_conn1,
+ telnet_server_conn2,
+ telnet_server_conn3,
+ telnet_server_conn4]}]}]}]
end].
%%%-----------------------------------------------------------------
diff --git a/lib/diameter/src/Makefile b/lib/diameter/src/Makefile
index 127406ae23..9afccf298c 100644
--- a/lib/diameter/src/Makefile
+++ b/lib/diameter/src/Makefile
@@ -148,7 +148,7 @@ gen/$(DICT_YRL).erl: compiler/$(DICT_YRL).yrl
$(ERLC) -Werror -o $(@D) $<
# Generate the app file.
-$(APP_TARGET): $(APP_SRC) ../vsn.mk modules.mk
+$(APP_TARGET): $(APP_SRC) ../vsn.mk modules.mk app.sed
$(gen_verbose) \
M=`echo $(notdir $(APP_MODULES)) | tr ' ' ,`; \
C=`echo $(COMPILER_MODULES) | tr ' ' ,`; \
@@ -159,7 +159,8 @@ $(APP_TARGET): $(APP_SRC) ../vsn.mk modules.mk
-e "s;%COMPILER%;$$C;" \
-e "s;%INFO%;$$I;" \
-e "s;%REGISTERED%;$$R;" \
- $< > $@
+ $< \
+ | sed -f app.sed > $@
$(APPUP_TARGET): $(APPUP_SRC) ../vsn.mk
$(vsn_verbose) \
diff --git a/lib/diameter/src/app.sed b/lib/diameter/src/app.sed
new file mode 100644
index 0000000000..7916f65002
--- /dev/null
+++ b/lib/diameter/src/app.sed
@@ -0,0 +1,40 @@
+#
+# %CopyrightBegin%
+#
+# Copyright Ericsson AB 2014. All Rights Reserved.
+#
+# The contents of this file are subject to the Erlang Public License,
+# Version 1.1, (the "License"); you may not use this file except in
+# compliance with the License. You should have received a copy of the
+# Erlang Public License along with this software. If not, it can be
+# retrieved online at http://www.erlang.org/.
+#
+# Software distributed under the License is distributed on an "AS IS"
+# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+# the License for the specific language governing rights and limitations
+# under the License.
+#
+# %CopyrightEnd%
+
+#
+# Generate runtime_dependencies from applications to avoid having to
+# specify the same application more than once.
+#
+
+/{runtime_dependencies,/b v
+/{[-a-z]*, "[0-9.]*"}/!b
+/{vsn,/b
+
+/%%/!H
+s/{\([^,]*\)[^}]*}/\1/g
+s/%%/%,/
+b
+
+:v
+
+p
+x
+s/\n//
+s/%//g
+s/\n */ /g
+s/{\([^,]*\), "\([^"]*"\)}/"\1-\2/g
diff --git a/lib/diameter/src/diameter.app.src b/lib/diameter/src/diameter.app.src
index d2290aeccc..ac1d847753 100644
--- a/lib/diameter/src/diameter.app.src
+++ b/lib/diameter/src/diameter.app.src
@@ -27,13 +27,20 @@
]},
{registered, [%REGISTERED%]},
{applications, [
- stdlib, kernel
- %, syntax_tools
- %, runtime_tools
- %, ssl
+ {stdlib, "2.0"}, {kernel, "3.0"}%, {erts, "6.0"}
+ %% {syntax-tools, "1.6.14"}
+ %% {runtime-tools, "1.8.14"}
+ %, {ssl, "5.3.4"}
]},
{env, []},
{mod, {diameter_app, []}},
- {runtime_dependencies, ["syntax_tools-1.6.14","stdlib-2.0","ssl-5.3.4",
- "runtime_tools-1.8.14","kernel-3.0","erts-6.0"]}
+ {runtime_dependencies, [
+ ]}
+ %%
+ %% Note that ssl is only required if configured on TCP transports,
+ %% and syntax-tools and runtime-tools are only required if the
+ %% dictionary compiler and debug modules (respectively) are
+ %% needed/wanted at runtime, which they typically aren't. These
+ %% modules are the two commented lines in the 'modules' tuple.
+ %%
]}.
diff --git a/lib/diameter/src/info/diameter_dbg.erl b/lib/diameter/src/info/diameter_dbg.erl
index 1237007a75..b5b3983afa 100644
--- a/lib/diameter/src/info/diameter_dbg.erl
+++ b/lib/diameter/src/info/diameter_dbg.erl
@@ -26,7 +26,6 @@
-export([table/1,
tables/0,
fields/1,
- help/0,
modules/0,
versions/0,
version_info/0,
@@ -56,9 +55,8 @@
-include_lib("diameter/include/diameter.hrl").
--define(APPLICATION, diameter).
--define(INFO, diameter_info).
--define(SEP(), ?INFO:sep()).
+-define(APP, diameter).
+-define(I, diameter_info).
-define(LOCAL, [diameter_config,
diameter_peer,
@@ -70,24 +68,16 @@
-define(VALUES(Rec), tl(tuple_to_list(Rec))).
-%%% ----------------------------------------------------------
-%%% # help()
-%%% ----------------------------------------------------------
-
-help() ->
- not_yet_implemented.
-
-%%% ----------------------------------------------------------
-%%% # table(TableName)
-%%%
-%%% Input: TableName = diameter table containing record entries.
-%%%
-%%% Output: Count | undefined
-%%% ----------------------------------------------------------
+%% ----------------------------------------------------------
+%% # table(TableName)
+%%
+%% Pretty-print a diameter table. Returns the number of records
+%% printed, or undefined.
+%% ----------------------------------------------------------
table(T)
when (T == diameter_peer) orelse (T == diameter_reg) ->
- ?INFO:format(collect(T), fields(T), fun ?INFO:split/2);
+ ?I:format(collect(T), fields(T), fun ?I:split/2);
table(Table)
when is_atom(Table) ->
@@ -95,7 +85,7 @@ table(Table)
undefined = No ->
No;
Fields ->
- ?INFO:format(Table, Fields, fun split/2)
+ ?I:format(Table, Fields, fun split/2)
end.
split([started, name | Fs], [S, N | Vs]) ->
@@ -106,9 +96,9 @@ split([[F|FT]|Fs], [Rec|Vs]) ->
split([F|Fs], [V|Vs]) ->
{F, Fs, V, Vs}.
-%%% ----------------------------------------------------------
-%%% # TableName()
-%%% ----------------------------------------------------------
+%% ----------------------------------------------------------
+%% # TableName()
+%% ----------------------------------------------------------
-define(TABLE(Name), Name() -> table(Name)).
@@ -120,16 +110,15 @@ split([F|Fs], [V|Vs]) ->
?TABLE(diameter_service).
?TABLE(diameter_stats).
-%%% ----------------------------------------------------------
-%%% # tables()
-%%%
-%%% Output: Number of records output.
-%%%
-%%% Description: Pretty-print records in diameter tables from all nodes.
-%%% ----------------------------------------------------------
+%% ----------------------------------------------------------
+%% # tables()
+%%
+%% Pretty-print diameter tables from all nodes. Returns the number of
+%% records printed.
+%% ----------------------------------------------------------
tables() ->
- ?INFO:format(field(?LOCAL), fun split/3, fun collect/1).
+ ?I:format(field(?LOCAL), fun split/3, fun collect/1).
field(Tables) ->
lists:map(fun(T) -> {T, fields(T)} end, lists:sort(Tables)).
@@ -137,66 +126,66 @@ field(Tables) ->
split(_, Fs, Vs) ->
split(Fs, Vs).
-%%% ----------------------------------------------------------
-%%% # modules()
-%%% ----------------------------------------------------------
+%% ----------------------------------------------------------
+%% # modules()
+%% ----------------------------------------------------------
modules() ->
- Path = filename:join([appdir(), atom_to_list(?APPLICATION) ++ ".app"]),
- {ok, [{application, ?APPLICATION, Attrs}]} = file:consult(Path),
+ Path = filename:join([appdir(), atom_to_list(?APP) ++ ".app"]),
+ {ok, [{application, ?APP, Attrs}]} = file:consult(Path),
{modules, Mods} = lists:keyfind(modules, 1, Attrs),
Mods.
appdir() ->
- [_|_] = code:lib_dir(?APPLICATION, ebin).
+ [_|_] = code:lib_dir(?APP, ebin).
-%%% ----------------------------------------------------------
-%%% # versions()
-%%% ----------------------------------------------------------
+%% ----------------------------------------------------------
+%% # versions()
+%% ----------------------------------------------------------
versions() ->
- ?INFO:versions(modules()).
+ ?I:versions(modules()).
-%%% ----------------------------------------------------------
-%%% # versions()
-%%% ----------------------------------------------------------
+%% ----------------------------------------------------------
+%% # versions()
+%% ----------------------------------------------------------
version_info() ->
- ?INFO:version_info(modules()).
+ ?I:version_info(modules()).
-%%% ----------------------------------------------------------
-%%% # compiled()
-%%% ----------------------------------------------------------
+%% ----------------------------------------------------------
+%% # compiled()
+%% ----------------------------------------------------------
compiled() ->
- ?INFO:compiled(modules()).
+ ?I:compiled(modules()).
-%%% ----------------------------------------------------------
-%%% procs()
-%%% ----------------------------------------------------------
+%% ----------------------------------------------------------
+%% procs()
+%% ----------------------------------------------------------
procs() ->
- ?INFO:procs(?APPLICATION).
+ ?I:procs(?APP).
-%%% ----------------------------------------------------------
-%%% # latest()
-%%% ----------------------------------------------------------
+%% ----------------------------------------------------------
+%% # latest()
+%% ----------------------------------------------------------
latest() ->
- ?INFO:latest(modules()).
+ ?I:latest(modules()).
-%%% ----------------------------------------------------------
-%%% # nl()
-%%% ----------------------------------------------------------
+%% ----------------------------------------------------------
+%% # nl()
+%% ----------------------------------------------------------
nl() ->
lists:foreach(fun(M) -> abcast = c:nl(M) end, modules()).
-%%% ----------------------------------------------------------
-%%% # pp(Bin)
-%%%
-%%% Description: Pretty-print a message binary.
-%%% ----------------------------------------------------------
+%% ----------------------------------------------------------
+%% # pp(Bin)
+%%
+%% Description: Pretty-print a message binary.
+%% ----------------------------------------------------------
%% Network byte order = big endian.
@@ -206,7 +195,7 @@ pp(<<Version:8, MsgLength:24,
HbHid:32,
E2Eid:32,
AVPs/binary>>) ->
- ?SEP(),
+ ?I:sep(),
ppp(["Version",
"Message length",
"[Actual length]",
@@ -226,7 +215,7 @@ pp(<<Version:8, MsgLength:24,
HbHid,
E2Eid]),
N = avp_loop({AVPs, MsgLength - 20}, 0),
- ?SEP(),
+ ?I:sep(),
N;
pp(<<_Version:8, MsgLength:24, _/binary>> = Bin) ->
@@ -327,23 +316,23 @@ ppp(Fields, Values) ->
ppp({Field, Value}) ->
io:format(": ~-22s : ~p~n", [Field, Value]).
-%%% ----------------------------------------------------------
-%%% # subscriptions()
-%%%
-%%% Output: list of {SvcName, Pid}
-%%% ----------------------------------------------------------
+%% ----------------------------------------------------------
+%% # subscriptions()
+%%
+%% Returns a list of {SvcName, Pid}.
+%% ----------------------------------------------------------
subscriptions() ->
diameter_service:subscriptions().
-%%% ----------------------------------------------------------
-%%% # children()
-%%% ----------------------------------------------------------
+%% ----------------------------------------------------------
+%% # children()
+%% ----------------------------------------------------------
children() ->
diameter_sup:tree().
-%%% ----------------------------------------------------------
+%% ----------------------------------------------------------
%% tracer/[12]
@@ -429,7 +418,7 @@ peers(Name, Ts) ->
mk_peers(Name, [_, {type, connect} | _] = Ts) ->
[[Name | mk_peer(Ts)]];
-mk_peers(Name, [R, {type, listen}, O, {accept = A, As}]) ->
+mk_peers(Name, [R, {type, listen}, O, {accept = A, As} | _]) ->
[[Name | mk_peer([R, {type, A}, O | Ts])] || Ts <- As].
%% This is a bit lame: service_info works to build this list and out
%% of something like what we want here and then we take it apart.
@@ -484,13 +473,12 @@ fields(diameter_service) ->
[started,
name,
record_info(fields, diameter_service),
+ watchdogT,
peerT,
- connT,
- share_peers,
- use_shared_peers,
shared_peers,
local_peers,
- monitor];
+ monitor,
+ options];
?FIELDS(diameter_event);
?FIELDS(diameter_uri);
diff --git a/lib/diameter/test/diameter_app_SUITE.erl b/lib/diameter/test/diameter_app_SUITE.erl
index 1e262895a6..f68a18b5c2 100644
--- a/lib/diameter/test/diameter_app_SUITE.erl
+++ b/lib/diameter/test/diameter_app_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2013. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2014. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -50,7 +50,7 @@
diameter_exprecs,
diameter_make]).
--define(HELP_MODULES, [diameter_dbg,
+-define(INFO_MODULES, [diameter_dbg,
diameter_info]).
%% ===========================================================================
@@ -99,13 +99,13 @@ vsn(Config) ->
%% # modules/1
%%
%% Ensure that the app file modules and installed modules differ by
-%% compiler/help modules.
+%% compiler/info modules.
%% ===========================================================================
modules(Config) ->
Mods = fetch(modules, fetch(app, Config)),
Installed = code_mods(),
- Help = lists:sort(?HELP_MODULES ++ ?COMPILER_MODULES),
+ Help = lists:sort(?INFO_MODULES ++ ?COMPILER_MODULES),
{[], Help} = {Mods -- Installed, lists:sort(Installed -- Mods)}.
@@ -158,12 +158,15 @@ appvsn(Name) ->
%% # xref/1
%%
%% Ensure that no function in our application calls an undefined function
-%% or one in an application we haven't specified as a dependency. (Almost.)
+%% or one in an application we haven't declared as a dependency. (Almost.)
%% ===========================================================================
xref(Config) ->
App = fetch(app, Config),
- Mods = fetch(modules, App),
+ Mods = fetch(modules, App), %% modules listed in the app file
+
+ %% List of application names extracted from runtime_dependencies.
+ Deps = lists:map(fun unversion/1, fetch(runtime_dependencies, App)),
{ok, XRef} = xref:start(make_name(xref_test_name)),
ok = xref:set_default(XRef, [{verbose, false}, {warnings, false}]),
@@ -178,7 +181,9 @@ xref(Config) ->
[?APP, erts | fetch(applications, App)]),
{ok, Undefs} = xref:analyze(XRef, undefined_function_calls),
- {ok, Called} = xref:analyze(XRef, {module_call, ?COMPILER_MODULES}),
+ {ok, RTmods} = xref:analyze(XRef, {module_use, Mods}),
+ {ok, CTmods} = xref:analyze(XRef, {module_use, ?COMPILER_MODULES}),
+ {ok, RTdeps} = xref:analyze(XRef, {module_call, Mods}),
xref:stop(XRef),
@@ -190,18 +195,41 @@ xref(Config) ->
Undefs),
%% diameter_tcp does call ssl despite the latter not being listed
%% as a dependency in the app file since ssl is only required for
- %% TLS security: it's up to a client who wants TLS it to start
- %% ssl.
-
- [] = lists:filter(fun is_bad_dependency/1, Called).
-
-%% It's not strictly necessary that diameter compiler modules not
-%% depend on other diameter modules but it's a simple source of build
-%% errors if not encoded in the makefile (hence the test) so guard
-%% against it.
-is_bad_dependency(Mod) ->
- lists:prefix("diameter", atom_to_list(Mod))
- andalso not lists:member(Mod, ?COMPILER_MODULES).
+ %% TLS security: it's up to a client who wants TLS to start ssl.
+
+ %% Ensure that only runtime or info modules call runtime modules.
+ %% It's not strictly necessary that diameter compiler modules not
+ %% depend on other diameter modules but it's a simple source of
+ %% build errors if not properly encoded in the makefile so guard
+ %% against it.
+ [] = (RTmods -- Mods) -- ?INFO_MODULES,
+
+ %% Ensure that runtime modules don't call compiler modules.
+ CTmods = CTmods -- Mods,
+
+ %% Ensure that runtime modules only call other runtime modules, or
+ %% applications declared as in runtime_dependencies in the app
+ %% file. Note that the declared application versions are ignored
+ %% since we only know what we can see now.
+ [] = lists:filter(fun(M) -> not lists:member(app(M), Deps) end,
+ RTdeps -- Mods).
+
+unversion(App) ->
+ T = lists:dropwhile(fun is_vsn_ch/1, lists:reverse(App)),
+ lists:reverse(case T of [$-|TT] -> TT; _ -> T end).
+
+is_vsn_ch(C) ->
+ $0 =< C andalso C =< $9 orelse $. == C.
+
+app('$M_EXPR') -> %% could be anything but assume it's ok
+ "erts";
+app(Mod) ->
+ case code:which(Mod) of
+ preloaded ->
+ "erts";
+ Path ->
+ unversion(lists:nth(3, lists:reverse(filename:split(Path))))
+ end.
add_application(XRef, App) ->
add_application(XRef, App, code:lib_dir(App)).
diff --git a/lib/edoc/src/edoc_types.erl b/lib/edoc/src/edoc_types.erl
index af8f1230fb..d4e00d3ecd 100644
--- a/lib/edoc/src/edoc_types.erl
+++ b/lib/edoc/src/edoc_types.erl
@@ -66,6 +66,7 @@ is_new_predefined(boolean, 0) -> true;
is_new_predefined(byte, 0) -> true;
is_new_predefined(iodata, 0) -> true;
is_new_predefined(iolist, 0) -> true;
+is_new_predefined(map, 0) -> true;
is_new_predefined(maybe_improper_list, 0) -> true;
is_new_predefined(maybe_improper_list, 2) -> true;
is_new_predefined(mfa, 0) -> true;
diff --git a/lib/hipe/llvm/hipe_llvm_main.erl b/lib/hipe/llvm/hipe_llvm_main.erl
index e911fb89c9..0e50c9539b 100644
--- a/lib/hipe/llvm/hipe_llvm_main.erl
+++ b/lib/hipe/llvm/hipe_llvm_main.erl
@@ -342,8 +342,8 @@ create_sdesc_list([{ExnLbl, SPOff} | MoreExnAndSPOffs],
%% (thus, some of their arguments are passed to the stack). Because of the
%% Reserved Call Frame feature that the LLVM uses, the stack descriptors
%% are not correct since at the point of call the frame size is reduced
-%% proportionally to the number of arguments that are passed on the stack.
-%% Also the offsets of the roots need to be re-adjusted.
+%% by the number of arguments that are passed on the stack. Also, the
+%% offsets of the roots need to be re-adjusted.
fix_stack_descriptors(_, _, [], _) ->
[];
fix_stack_descriptors(RelocsDict, Relocs, SDescs, ExposedClosures) ->
@@ -427,30 +427,22 @@ find_offsets([{Off,Arity}|Rest], Offsets, Acc) ->
[I | RestOffsets] = lists:dropwhile(fun (Y) -> Y<Off end, Offsets),
find_offsets(Rest, RestOffsets, [{I, Arity}|Acc]).
-%% The functions below correct the arity of calls, that are identified
-%% by offset, in the stack descriptors.
+%% The function below corrects the stack descriptors of calls with arguments
+%% that are passed on the stack (more than NR_ARG_REGS) by subtracting the
+%% number of stacked arguments from the frame size and from the offset of the
+%% roots.
fix_sdescs([], SDescs) -> SDescs;
fix_sdescs([{Offset, Arity} | Rest], SDescs) ->
case lists:keyfind(Offset, 2, SDescs) of
false ->
fix_sdescs(Rest, SDescs);
- {?SDESC, Offset, SDesc} ->
- {ExnHandler, FrameSize, StkArity, Roots} = SDesc,
- DecRoot = fun(X) -> X-Arity end,
- NewRootsList = lists:map(DecRoot, tuple_to_list(Roots)),
- NewSDesc =
- case length(NewRootsList) > 0 andalso hd(NewRootsList) >= 0 of
- true ->
- {?SDESC, Offset, {ExnHandler, FrameSize-Arity, StkArity,
- list_to_tuple(NewRootsList)}};
- false ->
- {?SDESC, Offset, {ExnHandler, FrameSize, StkArity, Roots}}
- end,
- RestSDescs = lists:keydelete(Offset, 2, SDescs),
- fix_sdescs(Rest, [NewSDesc | RestSDescs])
+ {?SDESC, Offset, {ExnHandler, FrameSize, StkArity, Roots}} ->
+ FixedRoots = list_to_tuple([Ri - Arity || Ri <- tuple_to_list(Roots)]),
+ FixedSDesc =
+ {?SDESC, Offset, {ExnHandler, FrameSize - Arity, StkArity, FixedRoots}},
+ fix_sdescs(Rest, [FixedSDesc | lists:keydelete(Offset, 2, SDescs)])
end.
-
%%------------------------------------------------------------------------------
%% Miscellaneous functions
%%------------------------------------------------------------------------------
diff --git a/lib/hipe/llvm/hipe_rtl_to_llvm.erl b/lib/hipe/llvm/hipe_rtl_to_llvm.erl
index ba76e1d815..d7d8d1b049 100644
--- a/lib/hipe/llvm/hipe_rtl_to_llvm.erl
+++ b/lib/hipe/llvm/hipe_rtl_to_llvm.erl
@@ -430,12 +430,13 @@ trans_call_name(RtlCallName, Relocs, CallArgs, FinalArgs) ->
case RtlCallName of
PrimOp when is_atom(PrimOp) ->
LlvmName = trans_prim_op(PrimOp),
- Relocs1 = relocs_store(LlvmName, {call, {bif, PrimOp, length(CallArgs)}},
- Relocs),
+ Relocs1 =
+ relocs_store(LlvmName, {call, {bif, PrimOp, length(CallArgs)}}, Relocs),
{"@" ++ LlvmName, [], Relocs1};
{M, F, A} when is_atom(M), is_atom(F), is_integer(A) ->
- LlvmName = trans_mfa_name({M,F,A}),
- Relocs1 = relocs_store(LlvmName, {call, {M,F,A}}, Relocs),
+ LlvmName = trans_mfa_name({M, F, A}),
+ Relocs1 =
+ relocs_store(LlvmName, {call, {M, F, length(CallArgs)}}, Relocs),
{"@" ++ LlvmName, [], Relocs1};
Reg ->
case hipe_rtl:is_reg(Reg) of
diff --git a/lib/hipe/main/hipe.erl b/lib/hipe/main/hipe.erl
index d47eced6d8..539ce883c0 100644
--- a/lib/hipe/main/hipe.erl
+++ b/lib/hipe/main/hipe.erl
@@ -200,6 +200,7 @@
compile_core/4,
file/1,
file/2,
+ llvm_support_available/0,
load/1,
help/0,
help_hiper/0,
@@ -648,7 +649,18 @@ run_compiler_1(DisasmFun, IcodeFun, Options) ->
%% The full option expansion is not done
%% until the DisasmFun returns.
{Code, CompOpts} = DisasmFun(Options),
- Opts = expand_options(Options ++ CompOpts),
+ Opts0 = expand_options(Options ++ CompOpts),
+ Opts =
+ case proplists:get_bool(to_llvm, Opts0) andalso
+ not llvm_support_available() of
+ true ->
+ ?error_msg("No LLVM version 3.4 or greater "
+ "found in $PATH; aborting "
+ "native code compilation.\n", []),
+ ?EXIT(cant_find_required_llvm_version);
+ false ->
+ Opts0
+ end,
check_options(Opts),
?when_option(verbose, Options,
?debug_msg("Options: ~p.\n",[Opts])),
@@ -1537,4 +1549,22 @@ check_options(Opts) ->
ok
end.
+-spec llvm_support_available() -> boolean().
+
+llvm_support_available() ->
+ get_llvm_version() >= 3.4.
+
+get_llvm_version() ->
+ OptStr = os:cmd("opt -version"),
+ SubStr = "LLVM version ", N = length(SubStr),
+ case string:str(OptStr, SubStr) of
+ 0 -> % No opt available
+ 0.0;
+ S ->
+ case string:to_float(string:sub_string(OptStr, S + N)) of
+ {error, _} -> 0.0; %XXX: Assumes no revision numbers in versioning
+ {Float, _} -> Float
+ end
+ end.
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
diff --git a/lib/inets/src/http_server/httpd_util.erl b/lib/inets/src/http_server/httpd_util.erl
index b0b18b9c3d..0d04a75205 100644
--- a/lib/inets/src/http_server/httpd_util.erl
+++ b/lib/inets/src/http_server/httpd_util.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2011. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2014. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -206,9 +206,6 @@ message(413, Reason,_) ->
"Entity: " ++ html_encode(Reason);
message(414,ReasonPhrase,_) ->
"Message " ++ html_encode(ReasonPhrase) ++ ".";
-message(416,ReasonPhrase,_) ->
- html_encode(ReasonPhrase);
-
message(500,_,ConfigDB) ->
ServerAdmin=lookup(ConfigDB,server_admin,"unknown@unknown"),
"The server encountered an internal error or "
@@ -233,7 +230,9 @@ message(501,{Method, RequestURI, HTTPVersion}, _ConfigDB) ->
end;
message(503, String, _ConfigDB) ->
- "This service in unavailable due to: " ++ html_encode(String).
+ "This service in unavailable due to: " ++ html_encode(String);
+message(_, ReasonPhrase, _) ->
+ html_encode(ReasonPhrase).
maybe_encode(URI) ->
Decoded = try http_uri:decode(URI) of
diff --git a/lib/observer/test/crashdump_viewer_SUITE.erl b/lib/observer/test/crashdump_viewer_SUITE.erl
index f6e7d18f65..e9567c82cb 100644
--- a/lib/observer/test/crashdump_viewer_SUITE.erl
+++ b/lib/observer/test/crashdump_viewer_SUITE.erl
@@ -301,10 +301,12 @@ wait_for_progress_done() ->
%%%-----------------------------------------------------------------
%%% General check of what is displayed for a dump
browse_file(File) ->
- io:format("Browsing file: ~s~n",[File]),
+ io:format("~nBrowsing file: ~s",[File]),
ok = start_backend(File),
+ io:format(" backend started",[]),
+
{ok,_GI=#general_info{},_GenTW} = crashdump_viewer:general_info(),
{ok,Procs,_ProcsTW} = crashdump_viewer:processes(),
{ok,Ports,_PortsTW} = crashdump_viewer:ports(),
@@ -321,10 +323,16 @@ browse_file(File) ->
{ok,_HashTabs,_HashTabsTW} = crashdump_viewer:hash_tables(),
{ok,_IndexTabs,_IndexTabsTW} = crashdump_viewer:index_tables(),
+ io:format(" info read",[]),
+
lookat_all_pids(Procs),
+ io:format(" pids ok",[]),
lookat_all_ports(Ports),
+ io:format(" ports ok",[]),
lookat_all_mods(Mods),
+ io:format(" mods ok",[]),
lookat_all_nodes(Nodes),
+ io:format(" nodes ok",[]),
Procs. % used as second arg to special/2
@@ -339,6 +347,7 @@ special(File,Procs) ->
[#proc{pid=Pid0}|_Rest] = lists:keysort(#proc.name,Procs),
Pid = pid_to_list(Pid0),
{ok,ProcDetails=#proc{},[]} = crashdump_viewer:proc_details(Pid),
+ io:format(" process details ok",[]),
#proc{dict=Dict} = ProcDetails,
@@ -350,6 +359,7 @@ special(File,Procs) ->
['#CDVBin',SOffset,SSize,SPos] = proplists:get_value(sub_bin,Dict),
{ok,<<_:SSize/binary>>} =
crashdump_viewer:expand_binary({SOffset,SSize,SPos}),
+ io:format(" expand binary ok",[]),
['#CDVPid',X1,Y1,Z1] = proplists:get_value(ext_pid,Dict),
ChannelStr1 = integer_to_list(X1),
@@ -359,22 +369,28 @@ special(File,Procs) ->
integer_to_list(Z1) ++ ">",
{error,{other_node,ChannelStr1}} =
crashdump_viewer:proc_details(ExtPid),
+ io:format(" process details external ok",[]),
['#CDVPort',X2,Y2] = proplists:get_value(port,Dict),
ChannelStr2 = integer_to_list(X2),
Port = "#Port<"++ChannelStr2++"."++integer_to_list(Y2)++">",
{ok,_PortDetails=#port{},[]} = crashdump_viewer:port(Port),
+ io:format(" port details ok",[]),
['#CDVPort',X3,Y3] = proplists:get_value(ext_port,Dict),
ChannelStr3 = integer_to_list(X3),
ExtPort = "#Port<"++ChannelStr3++"."++integer_to_list(Y3)++">",
{error,{other_node,ChannelStr3}} = crashdump_viewer:port(ExtPort),
+ io:format(" port details external ok",[]),
{ok,[_Ets=#ets_table{}],[]} = crashdump_viewer:ets_tables(Pid),
+ io:format(" ets tables ok",[]),
{ok,[_Timer=#timer{}],[]} = crashdump_viewer:timers(Pid),
+ io:format(" timers ok",[]),
{ok,Mod1=#loaded_mod{},[]} =
crashdump_viewer:loaded_mod_details(atom_to_list(?helper_mod)),
+ io:format(" modules ok",[]),
#loaded_mod{current_size=CS, old_size=OS,
old_attrib=A,old_comp_info=C}=Mod1,
true = is_integer(CS),
@@ -383,6 +399,7 @@ special(File,Procs) ->
true = (C=/=undefined),
{ok,Mod2=#loaded_mod{},[]} =
crashdump_viewer:loaded_mod_details("application"),
+ io:format(" module details ok",[]),
#loaded_mod{old_size="No old code exists",
old_attrib=undefined,
old_comp_info=undefined}=Mod2,
diff --git a/lib/public_key/doc/src/cert_records.xml b/lib/public_key/doc/src/cert_records.xml
index 79e5cb219d..397c13b463 100644
--- a/lib/public_key/doc/src/cert_records.xml
+++ b/lib/public_key/doc/src/cert_records.xml
@@ -5,7 +5,7 @@
<header>
<copyright>
<year>2008</year>
- <year>2013</year>
+ <year>2014</year>
<holder>Ericsson AB, All Rights Reserved</holder>
</copyright>
<legalnotice>
@@ -39,7 +39,7 @@
The intent is to describe the data types and not to specify the meaning of each
component for this we refer you to <url
href="http://www.ietf.org/rfc/rfc5280.txt">RFC 5280</url> and
- <url href="http://www.rsa.com/rsalabs/node.asp?id=2124">PKCS-10</url>.
+ <url href="http://www.ietf.org/rfc/rfc5967.txt">PKCS-10</url>.
</p>
<p>Use the following include directive to get access to the
diff --git a/lib/public_key/doc/src/part.xml b/lib/public_key/doc/src/part.xml
index 51e628aa90..73146c8e2a 100644
--- a/lib/public_key/doc/src/part.xml
+++ b/lib/public_key/doc/src/part.xml
@@ -5,7 +5,7 @@
<header>
<copyright>
<year>2008</year>
- <year>2013</year>
+ <year>2014</year>
<holder>Ericsson AB, All Rights Reserved</holder>
</copyright>
<legalnotice>
@@ -34,7 +34,7 @@
<p> This application provides an API to public key infrastructure
from <url href="http://www.ietf.org/rfc/rfc5280.txt">RFC
5280</url> (X.509 certificates) and public key formats defined by
- the <url href="http://www.rsa.com/rsalabs/node.asp?id=2124">
+ the <url href="http://en.wikipedia.org/wiki/PKCS">
PKCS-standard</url></p>
</description>
<xi:include href="introduction.xml"/>
diff --git a/lib/public_key/doc/src/public_key.xml b/lib/public_key/doc/src/public_key.xml
index fc3479cb64..8e93f562d4 100644
--- a/lib/public_key/doc/src/public_key.xml
+++ b/lib/public_key/doc/src/public_key.xml
@@ -5,7 +5,7 @@
<header>
<copyright>
<year>2008</year>
- <year>2013</year>
+ <year>2014</year>
<holder>Ericsson AB, All Rights Reserved</holder>
</copyright>
<legalnotice>
@@ -48,12 +48,12 @@
<item>Supports <url href="http://www.ietf.org/rfc/rfc5280.txt">RFC 5280 </url> -
Internet X.509 Public Key Infrastructure Certificate and Certificate Revocation List (CRL) Profile </item>
- <item>Supports <url href="http://www.rsa.com/rsalabs/node.asp?id=2125"> PKCS-1 </url> - RSA Cryptography Standard </item>
+ <item>Supports <url href="http://www.ietf.org/rfc/rfc3447.txt"> PKCS-1 </url> - RSA Cryptography Standard </item>
<item>Supports <url href="http://csrc.nist.gov/publications/fips/fips186-3/fips_186-3.pdf"> DSS</url>- Digital Signature Standard (DSA - Digital Signature Algorithm)</item>
- <item>Supports <url href="http://www.rsa.com/rsalabs/node.asp?id=2126"> PKCS-3 </url> - Diffie-Hellman Key Agreement Standard </item>
- <item>Supports <url href="http://www.rsa.com/rsalabs/node.asp?id=2127"> PKCS-5</url> - Password-Based Cryptography Standard </item>
- <item>Supports <url href="http://www.rsa.com/rsalabs/node.asp?id=2130"> PKCS-8</url> - Private-Key Information Syntax Standard</item>
- <item>Supports <url href="http://www.rsa.com/rsalabs/node.asp?id=2132"> PKCS-10</url> - Certification Request Syntax Standard</item>
+ <item>Supports <url href="http://www.emc.com/emc-plus/rsa-labs/standards-initiatives/pkcs-3-diffie-hellman-key-agreement-standar.htm"> PKCS-3 </url> - Diffie-Hellman Key Agreement Standard </item>
+ <item>Supports <url href="http://www.ietf.org/rfc/rfc2898.txt"> PKCS-5</url> - Password-Based Cryptography Standard </item>
+ <item>Supports <url href="http://www.ietf.org/rfc/rfc5208.txt"> PKCS-8</url> - Private-Key Information Syntax Standard</item>
+ <item>Supports <url href="http://www.ietf.org/rfc/rfc5967.txt"> PKCS-10</url> - Certification Request Syntax Standard</item>
</list>
</section>
@@ -461,11 +461,14 @@
<p>The fun should be defined as:</p>
<code>
-fun(OtpCert :: #'OTPCertificate'{}, Event :: {bad_cert, Reason :: atom()} |
- {extension, #'Extension'{}},
+fun(OtpCert :: #'OTPCertificate'{},
+ Event :: {bad_cert, Reason :: atom()} |
+ {extension, #'Extension'{}},
InitialUserState :: term()) ->
- {valid, UserState :: term()} | {valid_peer, UserState :: term()} |
- {fail, Reason :: term()} | {unknown, UserState :: term()}.
+ {valid, UserState :: term()} |
+ {valid_peer, UserState :: term()} |
+ {fail, Reason :: term()} |
+ {unknown, UserState :: term()}.
</code>
<p>If the verify callback fun returns {fail, Reason}, the
@@ -511,7 +514,8 @@ fun(OtpCert :: #'OTPCertificate'{}, Event :: {bad_cert, Reason :: atom()} |
<item>
<p>The fun has the following type spec:</p>
- <code> fun(#'DistributionPoint'{}, #'CertificateList'{}) -> #'CertificateList'{}</code>
+ <code> fun(#'DistributionPoint'{}, #'CertificateList'{}) ->
+ #'CertificateList'{}</code>
<p>The fun should use the information in the distribution point to acesses
the lates possible version of the CRL. If this fun is not specified
@@ -519,6 +523,21 @@ fun(OtpCert :: #'OTPCertificate'{}, Event :: {bad_cert, Reason :: atom()} |
</p>
<code> fun(_DP, CRL) -> CRL end</code>
</item>
+
+ <tag>{issuer_fun, fun()}</tag>
+ <item>
+ <p>The fun has the following type spec:</p>
+
+ <code>
+fun(#'DistributionPoint'{}, #'CertificateList'{},
+ {rdnSequence,[#'AttributeTypeAndValue'{}]}, term()) ->
+ {ok, #'OTPCertificate'{}, [der_encoded]}</code>
+
+ <p>The fun should return the root certificate and certificate chain
+ that has signed the CRL.
+ </p>
+ <code> fun(DP, CRL, Issuer, UserState) -> {ok, RootCert, CertChain}</code>
+ </item>
</taglist>
</desc>
</func>
diff --git a/lib/sasl/doc/src/appup.xml b/lib/sasl/doc/src/appup.xml
index 85fcbed3ba..95f315d269 100644
--- a/lib/sasl/doc/src/appup.xml
+++ b/lib/sasl/doc/src/appup.xml
@@ -4,7 +4,7 @@
<fileref>
<header>
<copyright>
- <year>1997</year><year>2013</year>
+ <year>1997</year><year>2014</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -84,6 +84,9 @@
version identifier must be specified as a binary, e.g.</p>
<code type="none">&lt;&lt;"2\\.1\\.[0-9]+">></code>
<p>will match all versions <c>2.1.x</c>, where x is any number.</p>
+ <p>Note that the regular expression must match the complete
+ version string, so the above example will work for for
+ e.g. <c>2.1.1</c>, but not for <c>2.1.1.1</c></p>
</section>
<section>
@@ -339,7 +342,7 @@ restart_new_emulator
version of erts, kernel, stdlib and sasl are used when the
emulator restarts. Only one <c>restart_new_emulator</c>
instruction is allowed in the relup, and it shall be placed
- first. <seealso marker="systools#make_relup/3">systools:make_relup3,4</seealso>
+ first. <seealso marker="systools#make_relup/3">systools:make_relup/3,4</seealso>
will ensure this when the relup is generated. The rest of the
relup script is executed after the restart as a part of the boot
script.</p>
@@ -347,11 +350,25 @@ restart_new_emulator
completed. To programatically find out if the upgrade is
complete,
call <seealso marker="release_handler#which_releases/0">
- release_handler:which_releases</seealso> and check if the
+ release_handler:which_releases/0,1</seealso> and check if the
expected release has status <c>current</c>.</p>
<p>The new release must still be made permanent after the upgrade
is completed. Otherwise, the old emulator is started in case of
an emulator restart.</p>
+ <warning>
+ <p>As stated above, the <c>restart_new_emulator</c>
+ instruction causes the emulator to be restarted with new
+ versions of <c>erts</c>, <c>kernel</c>, <c>stdlib</c> and
+ <c>sasl</c>. All other applications, however, will at startup
+ be running their old versions in this new emulator. In most
+ cases this is no problem, but every now and then there will be
+ incompatible changes to the core applications which may cause
+ trouble in this setting. Such incompatible changes (when
+ functions are removed) are normally preceded by a deprecation
+ over two major releases. To make sure your application is not
+ crashed by an incompatible change, always remove any call to
+ deprecated functions as soon as possible.</p>
+ </warning>
<pre>
restart_emulator
</pre>
diff --git a/lib/sasl/examples/src/target_system.erl b/lib/sasl/examples/src/target_system.erl
index fb9e9aaaaf..a0ae016791 100644
--- a/lib/sasl/examples/src/target_system.erl
+++ b/lib/sasl/examples/src/target_system.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2011-2013. All Rights Reserved.
+%% Copyright Ericsson AB 2011-2014. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -65,7 +65,7 @@ create(RelFileName,SystoolsOpts) ->
[RelFileName, RelFileName]),
make_script(RelFileName,SystoolsOpts),
- TarFileName = filename:join(Dir,RelFileName ++ ".tar.gz"),
+ TarFileName = RelFileName ++ ".tar.gz",
io:fwrite("Creating tar file ~tp ...~n", [TarFileName]),
make_tar(RelFileName,SystoolsOpts),
@@ -100,6 +100,12 @@ create(RelFileName,SystoolsOpts) ->
copy_file(filename:join([ErtsBinDir, "to_erl"]),
filename:join([TmpBinDir, "to_erl"]), [preserve]),
+ %% This is needed if 'start' script created from 'start.src' shall
+ %% be used as it points out this directory as log dir for 'run_erl'
+ TmpLogDir = filename:join([TmpDir, "log"]),
+ io:fwrite("Creating temporary directory ~tp ...~n", [TmpLogDir]),
+ ok = file:make_dir(TmpLogDir),
+
StartErlDataFile = filename:join([TmpDir, "releases", "start_erl.data"]),
io:fwrite("Creating ~tp ...~n", [StartErlDataFile]),
StartErlData = io_lib:fwrite("~s ~s~n", [ErtsVsn, RelVsn]),
@@ -115,6 +121,7 @@ create(RelFileName,SystoolsOpts) ->
erl_tar:add(Tar, filename:join(TmpDir,ErtsDir), ErtsDir, []),
erl_tar:add(Tar, filename:join(TmpDir,"releases"), "releases", []),
erl_tar:add(Tar, filename:join(TmpDir,"lib"), "lib", []),
+ erl_tar:add(Tar, filename:join(TmpDir,"log"), "log", []),
erl_tar:close(Tar),
%% file:set_cwd(Cwd),
io:fwrite("Removing directory ~tp ...~n",[TmpDir]),
@@ -136,6 +143,11 @@ install(RelFileName, RootDir) ->
subst_src_scripts(["erl", "start", "start_erl"], ErtsBinDir, BinDir,
[{"FINAL_ROOTDIR", RootDir}, {"EMU", "beam"}],
[preserve]),
+ %%! Workaround for pre OTP 17.0: start.src and start_erl.src did
+ %%! not have correct permissions, so the above 'preserve' option did not help
+ ok = file:change_mode(filename:join(BinDir,"start"),8#0755),
+ ok = file:change_mode(filename:join(BinDir,"start_erl"),8#0755),
+
io:fwrite("Creating the RELEASES file ...\n"),
create_RELEASES(RootDir, filename:join([RootDir, "releases",
filename:basename(RelFileName)])).
diff --git a/lib/sasl/test/release_handler_SUITE.erl b/lib/sasl/test/release_handler_SUITE.erl
index ad2a8005b9..1d8bf45289 100644
--- a/lib/sasl/test/release_handler_SUITE.erl
+++ b/lib/sasl/test/release_handler_SUITE.erl
@@ -667,6 +667,9 @@ release_handler_which_releases(Conf) ->
ok.
+release_handler_which_releases(cleanup,_Conf) ->
+ stop_node(node_name(release_handler_which_releases)).
+
%%-----------------------------------------------------------------
%% Ticket: OTP-2740
%% Slogan: vsn not numeric doesn't work so good in release_handling
@@ -1365,6 +1368,9 @@ upgrade_supervisor(Conf) when is_list(Conf) ->
ok.
+upgrade_supervisor(cleanup,_Condf) ->
+ stop_node(node_name(upgrade_supervisor)).
+
%% Check that if the supervisor fails, then the upgrade is rolled back
%% and an ok error message is returned
upgrade_supervisor_fail(Conf) when is_list(Conf) ->
@@ -2417,9 +2423,28 @@ check_gg_info(Node,OtherAlive,OtherDead,Synced) ->
?t:format("~ncheck_gg_info failed for ~p: ~p~nwhen GGI was: ~p~n"
"and GI was: ~p~n",
[Node,E,GGI,GI]),
+ %% An attempt to find out if it is only a timing issue
+ %% that makes this fail every now and then:
+ try_again_check(Node,GGI,GI,1),
?t:fail("check_gg_info failed")
end.
+try_again_check(_Node,_GGI,_GI,6) ->
+ ok;
+try_again_check(Node,GGI,GI,N) ->
+ timer:sleep(1000),
+ case {rpc:call(Node,global_group,info,[]),
+ rpc:call(Node,global,info,[])} of
+ {GGI,GI} ->
+ ?t:format("~nAfter one more sek, GGI and GI are still the same"),
+ try_again_check(Node,GGI,GI,N+1);
+ {NewGGI,NewGI} ->
+ ?t:format("~nAfter one more sek:~nNew GGI: ~p~nNew GI: ~p~n",
+ [NewGGI,NewGI]),
+ try_again_check(Node,NewGGI,NewGI,N+1)
+ end.
+
+
do_check_gg_info(OtherAlive,OtherDead,Synced,GGI,GI) ->
{_,gg1} = lists:keyfind(own_group_name,1,GGI),
{_,synced} = lists:keyfind(state,1,GGI),
@@ -2563,7 +2588,7 @@ start_nodes(Conf,Snames,Tag) ->
start_node_unix(Sname,NodeDir) ->
Script = filename:join([NodeDir,"bin","start"]),
- ?t:format("Starting ~p: ~tp~n", [Sname,Script]),
+ ?t:format("Starting ~p: ~ts~n", [Sname,Script]),
case rh_test_lib:cmd(Script,[],[{"NODENAME",atom_to_list(Sname)}]) of
ok ->
{ok,node_name(Sname)};
diff --git a/lib/ssl/doc/src/ssl.xml b/lib/ssl/doc/src/ssl.xml
index 4bc1a9a644..ffee4bd1af 100644
--- a/lib/ssl/doc/src/ssl.xml
+++ b/lib/ssl/doc/src/ssl.xml
@@ -768,39 +768,45 @@ fun(srp, Username :: string(), UserState :: term()) ->
</func>
<func>
- <name>ssl_accept(ListenSocket) -> </name>
- <name>ssl_accept(ListenSocket, Timeout) -> ok | {error, Reason}</name>
- <fsummary>Perform server-side SSL handshake</fsummary>
+ <name>ssl_accept(Socket) -> </name>
+ <name>ssl_accept(Socket, Timeout) -> ok | {error, Reason}</name>
+ <fsummary>Perform server-side SSL/TLS handshake</fsummary>
<type>
- <v>ListenSocket = sslsocket()</v>
+ <v>Socket = sslsocket()</v>
<v>Timeout = integer()</v>
<v>Reason = term()</v>
</type>
<desc>
- <p>The <c>ssl_accept</c> function establish the SSL connection
- on the server side. It should be called directly after
- <c>transport_accept</c>, in the spawned server-loop.</p>
+ <p> Performs the SSL/TLS server-side handshake <c>Socket</c> is a socket as returned
+ by <seealso
+ marker="#transport_accept-2">ssl:transport_accept/[1,2]</seealso>
+ </p>
</desc>
</func>
<func>
- <name>ssl_accept(ListenSocket, SslOptions) -> </name>
- <name>ssl_accept(ListenSocket, SslOptions, Timeout) -> {ok, Socket} | {error, Reason}</name>
- <fsummary>Perform server-side SSL handshake</fsummary>
+ <name>ssl_accept(Socket, SslOptions) -> </name>
+ <name>ssl_accept(Socket, SslOptions, Timeout) -> {ok, Socket} | ok | {error, Reason}</name>
+ <fsummary>Perform server-side SSL/TLS handshake</fsummary>
<type>
- <v>ListenSocket = socket()</v>
+ <v>Socket = socket() | sslsocket() </v>
<v>SslOptions = ssloptions()</v>
<v>Timeout = integer()</v>
<v>Reason = term()</v>
</type>
<desc>
- <p> Upgrades a gen_tcp, or
- equivalent, socket to an ssl socket i.e. performs the
- ssl server-side handshake.</p>
+ <p> If <c>Socket</c> is a socket() - upgrades a gen_tcp, or equivalent, socket to an ssl socket
+ i.e. performs the SSL/TLS server-side handshake and returns the ssl socket.
+ </p>
+
<warning><p>Note that the listen socket should be in {active, false} mode
before telling the client that the server is ready to upgrade
- and calling this function, otherwise the upgrade may
+ by calling this function, otherwise the upgrade may
or may not succeed depending on timing.</p></warning>
+
+ <p> If <c>Socket</c> is an sslsocket() - provides additional SSL/TLS options to those specified in <seealso
+ marker="#listen-2">ssl:listen/2 </seealso> and then performs the SSL/TLS handshake.
+ </p>
</desc>
</func>
@@ -842,33 +848,38 @@ fun(srp, Username :: string(), UserState :: term()) ->
</func>
<func>
- <name>transport_accept(Socket) -></name>
- <name>transport_accept(Socket, Timeout) ->
+ <name>transport_accept(ListenSocket) -></name>
+ <name>transport_accept(ListenSocket, Timeout) ->
{ok, NewSocket} | {error, Reason}</name>
<fsummary>Accept an incoming connection and
prepare for <c>ssl_accept</c></fsummary>
<type>
- <v>Socket = NewSocket = sslsocket()</v>
+ <v>ListenSocket = NewSocket = sslsocket()</v>
<v>Timeout = integer()</v>
<v>Reason = reason()</v>
</type>
<desc>
<p>Accepts an incoming connection request on a listen socket.
- <c>ListenSocket</c> must be a socket returned from
- <c>listen/2</c>. The socket returned should be passed to
- <c>ssl_accept</c> to complete ssl handshaking and
- establishing the connection.</p>
+ <c>ListenSocket</c> must be a socket returned from
+ <seealso
+ marker="#listen-2"> ssl:listen/2</seealso>.
+ The socket returned should be passed to
+ <seealso marker="#ssl_accept-2"> ssl:ssl_accept[2,3]</seealso>
+ to complete handshaking i.e
+ establishing the SSL/TLS connection.</p>
<warning>
- <p>The socket returned can only be used with <c>ssl_accept</c>,
- no traffic can be sent or received before that call.</p>
+ <p>The socket returned can only be used with
+ <seealso marker="#ssl_accept-2"> ssl:ssl_accept[2,3]</seealso>
+ no traffic can be sent or received before that call.</p>
</warning>
<p>The accepted socket inherits the options set for
- <c>ListenSocket</c> in <c>listen/2</c>.</p>
+ <c>ListenSocket</c> in <seealso
+ marker="#listen-2"> ssl:listen/2</seealso>.</p>
<p>The default
- value for <c>Timeout</c> is <c>infinity</c>. If
- <c>Timeout</c> is specified, and no connection is accepted
- within the given time, <c>{error, timeout}</c> is
- returned.</p>
+ value for <c>Timeout</c> is <c>infinity</c>. If
+ <c>Timeout</c> is specified, and no connection is accepted
+ within the given time, <c>{error, timeout}</c> is
+ returned.</p>
</desc>
</func>
diff --git a/lib/ssl/src/ssl.erl b/lib/ssl/src/ssl.erl
index a88bf45293..743753bf7d 100644
--- a/lib/ssl/src/ssl.erl
+++ b/lib/ssl/src/ssl.erl
@@ -195,7 +195,8 @@ transport_accept(#sslsocket{pid = {ListenSocket,
-spec ssl_accept(#sslsocket{} | port(), timeout()| [ssl_option()
| transport_option()]) ->
ok | {ok, #sslsocket{}} | {error, reason()}.
--spec ssl_accept(port(), [ssl_option()| transport_option()], timeout()) ->
+
+-spec ssl_accept(#sslsocket{} | port(), [ssl_option()] | [ssl_option()| transport_option()], timeout()) ->
{ok, #sslsocket{}} | {error, reason()}.
%%
%% Description: Performs accept on an ssl listen socket. e.i. performs
@@ -210,6 +211,15 @@ ssl_accept(#sslsocket{} = Socket, Timeout) ->
ssl_accept(ListenSocket, SslOptions) when is_port(ListenSocket) ->
ssl_accept(ListenSocket, SslOptions, infinity).
+ssl_accept(#sslsocket{} = Socket, [], Timeout) ->
+ ssl_accept(#sslsocket{} = Socket, Timeout);
+ssl_accept(#sslsocket{} = Socket, SslOptions, Timeout) ->
+ try
+ {ok, #config{ssl = SSL}} = handle_options(SslOptions, server),
+ ssl_connection:handshake(Socket, SSL, Timeout)
+ catch
+ Error = {error, _Reason} -> Error
+ end;
ssl_accept(Socket, SslOptions, Timeout) when is_port(Socket) ->
{Transport,_,_,_} =
proplists:get_value(cb_info, SslOptions, {gen_tcp, tcp, tcp_closed, tcp_error}),
diff --git a/lib/ssl/src/ssl_connection.erl b/lib/ssl/src/ssl_connection.erl
index ed9e4d344f..c2810a199f 100644
--- a/lib/ssl/src/ssl_connection.erl
+++ b/lib/ssl/src/ssl_connection.erl
@@ -36,7 +36,7 @@
-include_lib("public_key/include/public_key.hrl").
%% Setup
--export([connect/8, ssl_accept/7, handshake/2,
+-export([connect/8, ssl_accept/7, handshake/2, handshake/3,
socket_control/4]).
%% User Events
@@ -100,6 +100,20 @@ handshake(#sslsocket{pid = Pid}, Timeout) ->
Error ->
Error
end.
+
+%%--------------------------------------------------------------------
+-spec handshake(#sslsocket{}, #ssl_options{}, timeout()) -> ok | {error, reason()}.
+%%
+%% Description: Starts ssl handshake with some new options
+%%--------------------------------------------------------------------
+handshake(#sslsocket{pid = Pid}, SslOptions, Timeout) ->
+ case sync_send_all_state_event(Pid, {start, SslOptions, Timeout}) of
+ connected ->
+ ok;
+ Error ->
+ Error
+ end.
+
%--------------------------------------------------------------------
-spec socket_control(tls_connection | dtls_connection, port(), pid(), atom()) ->
{ok, #sslsocket{}} | {error, reason()}.
@@ -650,6 +664,10 @@ handle_sync_event({start, Timeout}, StartFrom, StateName, State) ->
{next_state, StateName, State#state{start_or_recv_from = StartFrom,
timer = Timer}, get_timeout(State)};
+handle_sync_event({start, Opts, Timeout}, From, StateName, #state{ssl_options = SslOpts} = State) ->
+ NewOpts = new_ssl_options(Opts, SslOpts),
+ handle_sync_event({start, Timeout}, From, StateName, State#state{ssl_options = NewOpts});
+
handle_sync_event(close, _, StateName, #state{protocol_cb = Connection} = State) ->
%% Run terminate before returning
%% so that the reuseaddr inet-option will work
@@ -1855,3 +1873,14 @@ make_premaster_secret({MajVer, MinVer}, rsa) ->
<<?BYTE(MajVer), ?BYTE(MinVer), Rand/binary>>;
make_premaster_secret(_, _) ->
undefined.
+
+%% One day this can be maps instead, but we have to be backwards compatible for now
+new_ssl_options(New, Old) ->
+ new_ssl_options(tuple_to_list(New), tuple_to_list(Old), []).
+
+new_ssl_options([], [], Acc) ->
+ list_to_tuple(lists:reverse(Acc));
+new_ssl_options([undefined | Rest0], [Head1| Rest1], Acc) ->
+ new_ssl_options(Rest0, Rest1, [Head1 | Acc]);
+new_ssl_options([Head0 | Rest0], [_| Rest1], Acc) ->
+ new_ssl_options(Rest0, Rest1, [Head0 | Acc]).
diff --git a/lib/ssl/src/ssl_internal.hrl b/lib/ssl/src/ssl_internal.hrl
index cec5d8fbb1..8bf5b30a83 100644
--- a/lib/ssl/src/ssl_internal.hrl
+++ b/lib/ssl/src/ssl_internal.hrl
@@ -101,7 +101,6 @@
reuse_sessions :: boolean(),
renegotiate_at,
secure_renegotiate,
- debug,
%% undefined if not hibernating, or number of ms of
%% inactivity after which ssl_connection will go into
%% hibernation
diff --git a/lib/ssl/test/ssl_basic_SUITE.erl b/lib/ssl/test/ssl_basic_SUITE.erl
index 0148e1f5bc..8e3d2e4b80 100644
--- a/lib/ssl/test/ssl_basic_SUITE.erl
+++ b/lib/ssl/test/ssl_basic_SUITE.erl
@@ -119,7 +119,8 @@ options_tests() ->
].
api_tests() ->
- [connection_info,
+ [new_options_in_accept,
+ connection_info,
peername,
peercert,
peercert_with_client_cert,
@@ -325,6 +326,37 @@ alerts(Config) when is_list(Config) ->
end
end, Alerts).
%%--------------------------------------------------------------------
+new_options_in_accept() ->
+ [{doc,"Test that you can set ssl options in ssl_accept/3 and not tcp upgrade"}].
+new_options_in_accept(Config) when is_list(Config) ->
+ ClientOpts = ?config(client_opts, Config),
+ ServerOpts = ?config(server_opts, Config),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {ssl_opts, [{versions, [sslv3]},
+ {ciphers,[{rsa,rc4_128,sha}]}]}, %% To be set in ssl_accept/3
+ {mfa, {?MODULE, connection_info_result, []}},
+ {options, ServerOpts}]),
+
+ Port = ssl_test_lib:inet_port(Server),
+ Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {?MODULE, connection_info_result, []}},
+ {options, [{versions, [sslv3]} | ClientOpts]}]),
+
+ ct:log("Testcase ~p, Client ~p Server ~p ~n",
+ [self(), Client, Server]),
+
+ ServerMsg = ClientMsg = {ok, {sslv3, {rsa, rc4_128, sha}}},
+
+ ssl_test_lib:check_result(Server, ServerMsg, Client, ClientMsg),
+
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
+%%--------------------------------------------------------------------
+
connection_info() ->
[{doc,"Test the API function ssl:connection_info/1"}].
connection_info(Config) when is_list(Config) ->
diff --git a/lib/ssl/test/ssl_test_lib.erl b/lib/ssl/test/ssl_test_lib.erl
index 7d8ece8d19..59f10d53a6 100644
--- a/lib/ssl/test/ssl_test_lib.erl
+++ b/lib/ssl/test/ssl_test_lib.erl
@@ -106,7 +106,8 @@ connect(#sslsocket{} = ListenSocket, Opts) ->
Node = proplists:get_value(node, Opts),
ReconnectTimes = proplists:get_value(reconnect_times, Opts, 0),
Timeout = proplists:get_value(timeout, Opts, infinity),
- AcceptSocket = connect(ListenSocket, Node, 1 + ReconnectTimes, dummy, Timeout),
+ SslOpts = proplists:get_value(ssl_opts, Opts, []),
+ AcceptSocket = connect(ListenSocket, Node, 1 + ReconnectTimes, dummy, Timeout, SslOpts),
case ReconnectTimes of
0 ->
AcceptSocket;
@@ -121,24 +122,30 @@ connect(ListenSocket, Opts) ->
[ListenSocket]),
AcceptSocket.
-connect(_, _, 0, AcceptSocket, _) ->
+connect(_, _, 0, AcceptSocket, _, _) ->
AcceptSocket;
-connect(ListenSocket, Node, N, _, Timeout) ->
- ct:log("~p:~p~nssl:transport_accept(~p)~n", [?MODULE,?LINE, ListenSocket]),
+
+connect(ListenSocket, Node, N, _, Timeout, []) ->
+ ct:log("ssl:transport_accept(~p)~n", [ListenSocket]),
{ok, AcceptSocket} = rpc:call(Node, ssl, transport_accept,
[ListenSocket]),
ct:log("~p:~p~nssl:ssl_accept(~p, ~p)~n", [?MODULE,?LINE, AcceptSocket, Timeout]),
case rpc:call(Node, ssl, ssl_accept, [AcceptSocket, Timeout]) of
ok ->
-ct:log("~p:~p~nok from ssl:ssl_accept@~p",[?MODULE,?LINE, Node]),
- connect(ListenSocket, Node, N-1, AcceptSocket, Timeout);
+ connect(ListenSocket, Node, N-1, AcceptSocket, Timeout, []);
Result ->
-ct:log("~p:~p~nssl:ssl_accept@~p ret ~p",[?MODULE,?LINE, Node,Result]),
+ ct:log("~p:~p~nssl:ssl_accept@~p ret ~p",[?MODULE,?LINE, Node,Result]),
Result
- end.
+ end;
+connect(ListenSocket, Node, _, _, Timeout, Opts) ->
+ ct:log("ssl:transport_accept(~p)~n", [ListenSocket]),
+ {ok, AcceptSocket} = rpc:call(Node, ssl, transport_accept,
+ [ListenSocket]),
+ ct:log("ssl:ssl_accept(~p,~p, ~p)~n", [AcceptSocket, Opts, Timeout]),
+ rpc:call(Node, ssl, ssl_accept, [AcceptSocket, Opts, Timeout]),
+ AcceptSocket.
-
remove_close_msg(0) ->
ok;
remove_close_msg(ReconnectTimes) ->
diff --git a/lib/stdlib/doc/src/pg.xml b/lib/stdlib/doc/src/pg.xml
index 7cc1b805b4..a3b69884b6 100644
--- a/lib/stdlib/doc/src/pg.xml
+++ b/lib/stdlib/doc/src/pg.xml
@@ -5,7 +5,7 @@
<header>
<copyright>
<year>1996</year>
- <year>2013</year>
+ <year>2014</year>
<holder>Ericsson AB, All Rights Reserved</holder>
</copyright>
<legalnotice>
@@ -32,6 +32,9 @@
<module>pg</module>
<modulesummary>Distributed, Named Process Groups</modulesummary>
<description>
+ <warning>
+ <p>This module is deprecated and will be removed in Erlang/OTP 18.</p>
+ </warning>
<p>This (experimental) module implements process groups. A process
group is a group of processes that can be accessed by a common
name. For example, a group named <c>foobar</c> can include a set
diff --git a/lib/stdlib/src/otp_internal.erl b/lib/stdlib/src/otp_internal.erl
index 62d4b13e41..c0ee8799c8 100644
--- a/lib/stdlib/src/otp_internal.erl
+++ b/lib/stdlib/src/otp_internal.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2013. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2014. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -577,6 +577,8 @@ obsolete_1(asn1rt, utf8_binary_to_list, 1) ->
{deprecated,{unicode,characters_to_list,1}};
obsolete_1(asn1rt, utf8_list_to_binary, 1) ->
{deprecated,{unicode,characters_to_binary,1}};
+obsolete_1(pg, _, _) ->
+ {deprecated,"deprecated; will be removed in OTP 18"};
obsolete_1(_, _, _) ->
no.
diff --git a/lib/stdlib/src/pg.erl b/lib/stdlib/src/pg.erl
index ee177e4e0b..a41fd329c2 100644
--- a/lib/stdlib/src/pg.erl
+++ b/lib/stdlib/src/pg.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2011. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2014. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -17,6 +17,7 @@
%% %CopyrightEnd%
%%
-module(pg).
+-deprecated(module).
%% pg provides a process group facility. Messages
%% can be multicasted to all members in the group
diff --git a/lib/test_server/doc/src/test_server_ctrl.xml b/lib/test_server/doc/src/test_server_ctrl.xml
index f4aae724e0..0cda531716 100644
--- a/lib/test_server/doc/src/test_server_ctrl.xml
+++ b/lib/test_server/doc/src/test_server_ctrl.xml
@@ -773,11 +773,14 @@ test_server_ctrl:cross_cover_analyse(Level,[{s1,S1LogDir},{s2,S2LogDir}])
<p><c>What = tests_start, Data = {Name,NumCases}</c><br></br>
<c>What = loginfo, Data = [{topdir,TestRootDir},{rundir,CurrLogDir}]</c><br></br>
<c>What = tests_done, Data = {Ok,Failed,{UserSkipped,AutoSkipped}}</c><br></br>
- <c>What = tc_start, Data = {{Mod,Func},TCLogFile}</c><br></br>
- <c>What = tc_done, Data = {Mod,Func,Result}</c><br></br>
- <c>What = tc_user_skip, Data = {Mod,Func,Comment}</c><br></br>
- <c>What = tc_auto_skip, Data = {Mod,Func,Comment}</c><br></br>
+ <c>What = tc_start, Data = {{Mod,{Func,GroupName}},TCLogFile}</c><br></br>
+ <c>What = tc_done, Data = {Mod,{Func,GroupName},Result}</c><br></br>
+ <c>What = tc_user_skip, Data = {Mod,{Func,GroupName},Comment}</c><br></br>
+ <c>What = tc_auto_skip, Data = {Mod,{Func,GroupName},Comment}</c><br></br>
<c>What = framework_error, Data = {{FWMod,FWFunc},Error}</c></p>
+ <p>Note that for a test case function that doesn't belong to a group,
+ <c>GroupName</c> has value <c>undefined</c>, otherwise the name of the test
+ case group.</p>
</desc>
</func>
<func>
diff --git a/lib/tools/test/eprof_SUITE.erl b/lib/tools/test/eprof_SUITE.erl
index 1227d5b841..04b522de4a 100644
--- a/lib/tools/test/eprof_SUITE.erl
+++ b/lib/tools/test/eprof_SUITE.erl
@@ -104,7 +104,7 @@ basic(Config) when is_list(Config) ->
profiling = eprof:profile([A]),
true = exit(A, kill_it),
profiling_stopped = eprof:stop_profiling(),
- {error,_} = eprof:profile(fun() -> a = b end),
+ {error,_} = eprof:profile(fun() -> a = id(b) end),
%% with mfa
@@ -149,8 +149,7 @@ basic_option_1(Config) ->
% vanilla
{ok, _} = eprof:profile(fun() -> eprof_test:do(10) end, [{set_on_spawn, true}]),
- [{_, MfasDo1},{_, MfasLists1}] = eprof:dump(),
- Mfas1 = MfasDo1 ++ MfasLists1,
+ Mfas1 = lists:foldl(fun({_,Mfas},Out) -> Mfas ++ Out end, [], eprof:dump()),
{value, {_, {11, _}}} = lists:keysearch({eprof_test,dec,1}, 1, Mfas1),
{value, {_, { 1, _}}} = lists:keysearch({eprof_test, go,1}, 1, Mfas1),
@@ -159,8 +158,7 @@ basic_option_1(Config) ->
{ok, _} = eprof:profile(fun() -> eprof_test:do(10) end, [set_on_spawn]),
- [{_, MfasDo2},{_, MfasLists2}] = eprof:dump(),
- Mfas2 = MfasDo2 ++ MfasLists2,
+ Mfas2 = lists:foldl(fun({_,Mfas},Out) -> Mfas ++ Out end, [], eprof:dump()),
{value, {_, {11, _}}} = lists:keysearch({eprof_test,dec,1}, 1, Mfas2),
{value, {_, { 1, _}}} = lists:keysearch({eprof_test, go,1}, 1, Mfas2),
{value, {_, { 9, _}}} = lists:keysearch({lists, split_2,5}, 1, Mfas2),
@@ -255,3 +253,5 @@ ensure_eprof_stopped() ->
Pid ->
stopped=eprof:stop()
end.
+
+id(I) -> I.
diff --git a/system/doc/design_principles/applications.xml b/system/doc/design_principles/applications.xml
index 228ca1f2bf..7b030115df 100644
--- a/system/doc/design_principles/applications.xml
+++ b/system/doc/design_principles/applications.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>1997</year><year>2013</year>
+ <year>1997</year><year>2014</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -157,8 +157,9 @@ ch_app:stop([])</code>
all applications have dependencies to at least <c>kernel</c>
and <c>stdlib</c>.</item>
</taglist>
- <p>The syntax and contents of of the application resource file
- are described in detail in <c>app(4)</c>.</p>
+ <note><p>The syntax and contents of of the application resource file
+ are described in detail in the<seealso marker="kernel:app">
+ Application resource file reference</seealso>.</p></note>
</section>
<section>
diff --git a/system/doc/design_principles/release_handling.xml b/system/doc/design_principles/release_handling.xml
index 2a5831b89f..ba8a88d1c2 100644
--- a/system/doc/design_principles/release_handling.xml
+++ b/system/doc/design_principles/release_handling.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>2003</year><year>2013</year>
+ <year>2003</year><year>2014</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -329,13 +329,26 @@
automatically ensured.</p>
<p>When the release handler encounters the instruction, it first
generates a temporary boot file, which starts the new versions
- of the emulator and the core applications. Then it shuts down
+ of the emulator and the core applications, and the old version
+ of all other applications. Then it shuts down
the current emulator by calling <c>init:reboot()</c>, see
<c>init(3)</c>. All processes are terminated gracefully and
the system is rebooted by the heart program, using the
temporary boot file. After the reboot, the rest of the relup
instructions are executed. This is done as a part of the
temporary boot script.</p>
+ <warning>
+ <p>Since this mechanism causes the new versions of the
+ emulator and core applications to run with the old version of
+ other applications during startup, extra care must be taken to
+ avoid incompatibility. Incompatible changes in the core
+ applications may in some situations be necessary. If possible,
+ such changes are preceded by deprecation over two major
+ releases before the actual change. To make sure your
+ application is not crashed by an incompatible change, always
+ remove any call to deprecated functions as soon as
+ possible.</p>
+ </warning>
<p>An info report is written when the upgrade is completed. To
programatically find out if the upgrade is complete,
call <c>release_handler:which_releases(current)</c> and check
diff --git a/system/doc/getting_started/seq_prog.xml b/system/doc/getting_started/seq_prog.xml
index 3830a34e5a..fd49102263 100644
--- a/system/doc/getting_started/seq_prog.xml
+++ b/system/doc/getting_started/seq_prog.xml
@@ -419,6 +419,129 @@ list_length([First | Rest]) ->
</section>
<section>
+ <title>Maps</title>
+ <p>Maps are a set of key to value associations. These associations
+ are encapsulated with "#{" and "}". To create an association from
+ "key" to value 42, we write:</p>
+<code type="none">
+> #{ "key" => 42 }.
+#{"key" => 42}</code>
+ <p>We will jump straight into the deep end with an example using some
+ interesting features.</p>
+ <p>The following example shows how we calculate alpha blending using
+ maps to reference color and alpha channels:</p>
+ <code type="none">
+-module(color).
+
+-export([new/4, blend/2]).
+
+-define(is_channel(V), (is_float(V) andalso V &gt;= 0.0 andalso V =&lt; 1.0)).
+
+new(R,G,B,A) when ?is_channel(R), ?is_channel(G),
+ ?is_channel(B), ?is_channel(A) ->
+ #{red =&gt; R, green =&gt; G, blue =&gt; B, alpha =&gt; A}.
+
+blend(Src,Dst) ->
+ blend(Src,Dst,alpha(Src,Dst)).
+
+blend(Src,Dst,Alpha) when Alpha > 0.0 ->
+ Dst#{
+ red := red(Src,Dst) / Alpha,
+ green := green(Src,Dst) / Alpha,
+ blue := blue(Src,Dst) / Alpha,
+ alpha := Alpha
+ };
+blend(_,Dst,_) ->
+ Dst#{
+ red := 0.0,
+ green := 0.0,
+ blue := 0.0,
+ alpha := 0.0
+ }.
+
+alpha(#{alpha := SA}, #{alpha := DA}) ->
+ SA + DA*(1.0 - SA).
+
+red(#{red := SV, alpha := SA}, #{red := DV, alpha := DA}) ->
+ SV*SA + DV*DA*(1.0 - SA).
+green(#{green := SV, alpha := SA}, #{green := DV, alpha := DA}) ->
+ SV*SA + DV*DA*(1.0 - SA).
+blue(#{blue := SV, alpha := SA}, #{blue := DV, alpha := DA}) ->
+ SV*SA + DV*DA*(1.0 - SA).</code>
+ <p>Compile (file <c>color.erl</c>) and test:</p>
+ <pre>
+> <input>c(color).</input>
+{ok,color}
+> <input>C1 = color:new(0.3,0.4,0.5,1.0).</input>
+#{alpha => 1.0,blue => 0.5,green => 0.4,red => 0.3}
+> <input>C2 = color:new(1.0,0.8,0.1,0.3).</input>
+#{alpha => 0.3,blue => 0.1,green => 0.8,red => 1.0}
+> <input>color:blend(C1,C2).</input>
+#{alpha => 1.0,blue => 0.5,green => 0.4,red => 0.3}
+> <input>color:blend(C2,C1).</input>
+#{alpha => 1.0,blue => 0.38,green => 0.52,red => 0.51}
+</pre>
+ <p>This example warrant some explanation:</p>
+ <code type="none">
+-define(is_channel(V), (is_float(V) andalso V &gt;= 0.0 andalso V =&lt; 1.0)).</code>
+ <p>
+ First we define a macro <c>is_channel</c> to help with our guard tests.
+ This is only here for convenience and to reduce syntax cluttering.
+
+ You can read more about <seealso marker="doc/reference_manual:macros">Macros</seealso>
+ in the Erlang Reference Manual.
+ </p>
+ <code type="none">
+new(R,G,B,A) when ?is_channel(R), ?is_channel(G),
+ ?is_channel(B), ?is_channel(A) ->
+ #{red =&gt; R, green =&gt; G, blue =&gt; B, alpha =&gt; A}.</code>
+ <p>
+ The function <c>new/4</c> creates a new map term with and lets the keys
+ <c>red</c>, <c>green</c>, <c>blue</c> and <c>alpha</c> be associated
+ with an initial value. In this case we only allow for float
+ values between and including 0.0 and 1.0 as ensured by the <c>?is_channel/1</c> macro
+ for each argument. Only the <c>=></c> operator is allowed when creating a new map.
+ </p>
+ <p>
+ By calling <c>blend/2</c> on any color term created by <c>new/4</c> we can calculate
+ the resulting color as determined by the two maps terms.
+ </p>
+ <p>
+ The first thing <c>blend/2</c> does is to calculate the resulting alpha channel.
+ </p>
+ <code type="none">
+alpha(#{alpha := SA}, #{alpha := DA}) ->
+ SA + DA*(1.0 - SA).</code>
+ <p>
+ We fetch the value associated with key <c>alpha</c> for both arguments using
+ the <c>:=</c> operator. Any other keys
+ in the map are ignored, only the key <c>alpha</c> is required and checked for.
+ </p>
+ <p>This is also the case for functions <c>red/2</c>, <c>blue/2</c> and <c>green/2</c>.</p>
+ <code type="none">
+red(#{red := SV, alpha := SA}, #{red := DV, alpha := DA}) ->
+ SV*SA + DV*DA*(1.0 - SA).</code>
+ <p>
+ The difference here is that we check for two keys in each map argument. The other keys
+ are ignored.
+ </p>
+ <p>
+ Finally we return the resulting color in <c>blend/3</c>.
+ </p>
+ <code type="none">
+blend(Src,Dst,Alpha) when Alpha > 0.0 ->
+ Dst#{
+ red := red(Src,Dst) / Alpha,
+ green := green(Src,Dst) / Alpha,
+ blue := blue(Src,Dst) / Alpha,
+ alpha := Alpha
+ };</code>
+ <p>
+ We update the <c>Dst</c> map with new channel values. The syntax for updating an existing key with a new value is done with <c>:=</c> operator.
+ </p>
+ </section>
+
+ <section>
<title>Standard Modules and Manual Pages</title>
<p>Erlang has a lot of standard modules to help you do things. For
example, the module <c>io</c> contains a lot of functions to help
diff --git a/system/doc/installation_guide/Makefile b/system/doc/installation_guide/Makefile
index 6923f52d8a..83210bd21f 100644
--- a/system/doc/installation_guide/Makefile
+++ b/system/doc/installation_guide/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1996-2012. All Rights Reserved.
+# Copyright Ericsson AB 1996-2014. All Rights Reserved.
#
# The contents of this file are subject to the Erlang Public License,
# Version 1.1, (the "License"); you may not use this file except in
@@ -58,8 +58,7 @@ XML_FILES = \
GENERATED_XML_FILES = \
INSTALL.xml \
INSTALL-CROSS.xml \
- INSTALL-WIN32.xml \
- MARKDOWN.xml
+ INSTALL-WIN32.xml
# ----------------------------------------------------
@@ -74,8 +73,7 @@ REDIRECT_HTML_DIR = $(HTMLDIR)/source
REDIRECT_HTML_FILES = \
$(REDIRECT_HTML_DIR)/INSTALL.html \
$(REDIRECT_HTML_DIR)/INSTALL-CROSS.html \
- $(REDIRECT_HTML_DIR)/INSTALL-WIN32.html \
- $(REDIRECT_HTML_DIR)/MARKDOWN.html
+ $(REDIRECT_HTML_DIR)/INSTALL-WIN32.html
# ----------------------------------------------------
# FLAGS
diff --git a/system/doc/installation_guide/install-binary.xml b/system/doc/installation_guide/install-binary.xml
index 07027a39f6..af7dab6e44 100644
--- a/system/doc/installation_guide/install-binary.xml
+++ b/system/doc/installation_guide/install-binary.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>2000</year><year>2013</year>
+ <year>2000</year><year>2014</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -31,117 +31,40 @@
<rev>C</rev>
<file>install-binary.xml</file>
</header>
-
- <section>
- <title>UNIX</title>
-
- <section>
- <title>Introduction</title>
- <p>The system is delivered as a single compressed tar file.</p>
- <p>To browse the on-line HTML documentation, Netscape or an equivalent
- browser supporting frames is needed.</p>
- </section>
-
- <section>
- <title>Installation Procedure</title>
- <p>When installed, the entire system, except for a small start-up
- script, resides in a single directory tree. The location of this
- directory tree can be chosen arbitrarily by the installer, and it
- does not need to be in the user's <c>$PATH</c>. The only requirements
- are that the file system where it is placed has enough free space,
- and that the users who run Erlang/OTP have read access to it. In the
- example below, the directory tree is assumed to be located at
- <c>/usr/local/erlang</c>, which is here called the <em>top-level directory</em>.</p>
- <p>It is assumed that you have the compressed tar file, the name of
- which is <c><![CDATA[<PREFIX>.tar.gz]]></c>, where <c><![CDATA[<PREFIX>]]></c> is a string
- denoting the particular Erlang/OTP release, e.g.
- <c>otp_LXA_11930_sunos5_R9B</c>.</p>
- <p>Wherever the string <c><![CDATA[<PREFIX>]]></c> is used below, it should
- be replaced by the actual name prefix of the compressed tar file.</p>
- <p>The tape archive file does not have one single directory in which
- all other files are rooted. Therefore the tape archive file must be
- extracted into an empty (newly created) directory.</p>
- <list type="ordered">
- <item>
- <p>If the <em>top-level directory</em> does not already exist,
- create it:</p>
- <pre>
-mkdir /usr/local/erlang</pre>
- </item>
- <item>
- <p>Change the current directory to the <em>top level directory</em>:</p>
- <pre>
-cd /usr/local/erlang</pre>
- </item>
- <item>
- <p>Create the <em>installation directory</em> with an appropriate
- name. For example:</p>
- <pre>
-mkdir otp_r7b</pre>
- </item>
- <item>
- <p>Change to the <em>installation directory</em>, e.g.</p>
- <pre>
-cd otp_r7b</pre>
- </item>
- <item>
- <p>Assuming the compressed tar file resides in the directory
- <c><![CDATA[<SOME-DIR>]]></c>,. extract the compressed tar file into the
- current directory:</p>
- <pre>
-gunzip -c &lt;SOME-DIR&gt;/&lt;PREFIX&gt;.tar.gz | tar xfp -</pre>
- </item>
- <item>
- <p>Read the <c>README</c> file in the installation directory for
- last minute updates, before proceeding.</p>
- </item>
- <item>
- <p>Run the <c>Install</c> script in the installation directory,
- with the absolute path of the installation directory as argument,</p>
- <pre>
-./Install /usr/local/erlang/otp_r7b</pre>
- <p>and supply answers to the prompts.</p>
- <p>In most cases, there is a default answer in square brackets
- (<c>[]</c>). If the default is satisfactory, just press
- <c><![CDATA[<Return>]]></c>. In general you are only prompted for one thing:</p>
- <list type="bulleted">
- <item>
- <p>"Do you want to use a minimal system startup instead of the
- SASL startup?" <br></br>
-
- In a minimal system, only the Kernel and STDLIB applications
- are loaded and started. If the SASL startup is used, the SASL
- application is included as well. Normally, the minimal system
- is enough.</p>
- </item>
- </list>
- </item>
- <item>
- <p>Make Erlang/OTP available for users, either by putting the path
- <c>/usr/local/erlang/otp_r7b/bin</c> in users <c>$PATH</c>
- variable, or link the executable
- <c>/usr/local/erlang/otp_r7b/bin/erl</c> accordingly, e.g.:</p>
- <pre>
-ln -s /usr/local/erlang/otp_r7b/bin/erl /usr/local/bin/erl </pre>
- </item>
- </list>
- </section>
- </section>
-
<section>
<title>Windows</title>
<section>
<title>Introduction</title>
- <p>The system is delivered as a single <c>.exe</c> file.</p>
- <p>To browse the on-line HTML documentation, Netscape or an equivalent
- browser supporting frames is needed.</p>
+ <p>The system is delivered as a Windows Installer executable.
+ Get it from our <url href="http://www.erlang.org/download.html">download page</url>.</p>
</section>
<section>
- <title>Installation Procedure</title>
+ <title>Installation</title>
<p>The installation procedure is is automated. Double-click the
<c>.exe</c> file icon and follow the instructions.</p>
</section>
+ <section>
+ <title>Verification</title>
+ <list type="bulleted">
+ <item>
+ <p>Start Erlang/OTP by double-clicking on the Erlang shortcut icon on the
+ desktop.</p>
+ <p>Expect a command line window to pop up with an output looking something like this:</p>
+ <pre>
+ Erlang/OTP 17 [erts-6.0] [64-bit] [smp:2:2]
+
+ Eshell V6.0 (abort with ^G)
+ 1></pre>
+ </item>
+ <item>
+ <p>Exit by entering the command <c>halt()</c>,</p>
+ <pre>
+ 2> <input>halt().</input></pre>
+ <p>which will close the Erlang/OTP shell. </p>
+ </item>
+ </list>
+ </section>
</section>
</chapter>
diff --git a/system/doc/installation_guide/part.xml b/system/doc/installation_guide/part.xml
index 19808fd165..02bf98db7c 100644
--- a/system/doc/installation_guide/part.xml
+++ b/system/doc/installation_guide/part.xml
@@ -4,7 +4,7 @@
<part xmlns:xi="http://www.w3.org/2001/XInclude">
<header>
<copyright>
- <year>2000</year><year>2013</year>
+ <year>2000</year><year>2014</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -32,9 +32,7 @@
<p>How to install Erlang/OTP on UNIX or Windows.</p>
</description>
<xi:include href="install-binary.xml"/>
- <xi:include href="verification.xml"/>
<xi:include href="INSTALL.xml"/>
<xi:include href="INSTALL-CROSS.xml"/>
<xi:include href="INSTALL-WIN32.xml"/>
- <xi:include href="MARKDOWN.xml"/>
</part> \ No newline at end of file
diff --git a/system/doc/installation_guide/verification.xml b/system/doc/installation_guide/verification.xml
deleted file mode 100644
index 391ddfb7b8..0000000000
--- a/system/doc/installation_guide/verification.xml
+++ /dev/null
@@ -1,102 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE chapter SYSTEM "chapter.dtd">
-
-<chapter>
- <header>
- <copyright>
- <year>2000</year><year>2013</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- The contents of this file are subject to the Erlang Public License,
- Version 1.1, (the "License"); you may not use this file except in
- compliance with the License. You should have received a copy of the
- Erlang Public License along with this software. If not, it can be
- retrieved online at http://www.erlang.org/.
-
- Software distributed under the License is distributed on an "AS IS"
- basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
- the License for the specific language governing rights and limitations
- under the License.
-
- </legalnotice>
-
- <title>Installation Verification</title>
- <prepared>Peter H&ouml;gfeldt</prepared>
- <responsible>Peter H&ouml;gfeldt</responsible>
- <docno></docno>
- <approved>(Peter H&ouml;gfeldt</approved>
- <checked></checked>
- <date>1997-05-26</date>
- <rev>C</rev>
- <file>verification.xml</file>
- </header>
- <p>This chapter is about verifying your installation by performing
- a few simple tests to see that your system is properly installed.</p>
-
- <section>
- <title>UNIX</title>
- <list type="bulleted">
- <item>
- <p>Start Erlang/OTP from the command line,</p>
- <pre>
- unix> erl</pre>
- <p>Expect the following output:</p>
- <pre>
- Erlang (BEAM) emulator version 5.0.1 [threads]
-
- Eshell V5.0.1 (abort with ^G)
- 1></pre>
- </item>
- <item>
- <p>Start the GS-based toolbar from the Erlang shell, </p>
- <pre>
- 1> <input>toolbar:start().</input></pre>
- <p>and check that the toolbar window pops up.
- </p>
- <p><em>Note:</em> The trailing full stop (<c>"."</c>) is an end marker
- for all commands in the Erlang shell, and must be entered for a
- command to begin execution.</p>
- </item>
- <item>
- <p>Exit by entering the command <c>halt()</c>,</p>
- <pre>
- 2> <input>halt().</input></pre>
- <p>which should end both the toolbar window and the command line window. </p>
- </item>
- </list>
- </section>
-
- <section>
- <title>Windows</title>
- <list type="bulleted">
- <item>
- <p>Start Erlang/OTP by double-clicking on the Erlang shortcut icon on the
- desktop.</p>
- <p>Expect a command line window to pop up with the following output,</p>
- <pre>
- Erlang (BEAM) emulator version 5.0.1 [threads]
-
- Eshell V5.0.1 (abort with ^G)
- 1></pre>
- </item>
- <item>
- <p>Start the GS-based toolbar from the Erlang shell, </p>
- <pre>
- 1> <input>toolbar:start().</input></pre>
- <p>and check that the toolbar window pops up.
- </p>
- <p><em>Note:</em> The trailing full stop (<c>"."</c>) is an end marker
- for all commands in the Erlang shell, and must be entered for a
- command to begin execution.</p>
- </item>
- <item>
- <p>Exit by entering the command <c>halt()</c>,</p>
- <pre>
- 2> <input>halt().</input></pre>
- <p>which should end both the toolbar window and the command line window. </p>
- </item>
- </list>
- </section>
-</chapter>
-
diff --git a/system/doc/installation_guide/xmlfiles.mk b/system/doc/installation_guide/xmlfiles.mk
index 3995c607af..c443334cd7 100644
--- a/system/doc/installation_guide/xmlfiles.mk
+++ b/system/doc/installation_guide/xmlfiles.mk
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2009-2013. All Rights Reserved.
+# Copyright Ericsson AB 2009-2014. All Rights Reserved.
#
# The contents of this file are subject to the Erlang Public License,
# Version 1.1, (the "License"); you may not use this file except in
@@ -18,8 +18,6 @@
#
INST_GUIDE_CHAPTER_FILES = \
install-binary.xml \
- verification.xml \
INSTALL.xml \
INSTALL-CROSS.xml \
- INSTALL-WIN32.xml \
- MARKDOWN.xml
+ INSTALL-WIN32.xml
diff --git a/system/doc/reference_manual/data_types.xml b/system/doc/reference_manual/data_types.xml
index 8c690d6b86..0031664dfb 100644
--- a/system/doc/reference_manual/data_types.xml
+++ b/system/doc/reference_manual/data_types.xml
@@ -190,6 +190,38 @@ adam
</section>
<section>
+ <title>Map</title>
+ <p>Compound data type with a variable number of key-value associations:</p>
+ <pre>
+#{Key1=>Value1,...,KeyN=>ValueN}</pre>
+ <p>Each key-value association in the map is called an
+ <em>association pair</em>. The key and value parts of the pair are
+ called <em>elements</em>. The number of association pairs is said to be
+ the <em>size</em> of the map.</p>
+ <p>There exists a number of BIFs to manipulate maps.</p>
+ <p>Examples:</p>
+ <pre>
+1> <input>M1 = #{name=>adam,age=>24,date=>{july,29}}.</input>
+#{age => 24,date => {july,29},name => adam}
+2> <input>maps:get(name,M1).</input>
+adam
+3> <input>maps:get(date,M1).</input>
+{july,29}
+4> <input>M2 = maps:update(age,25,M1).</input>
+#{age => 25,date => {july,29},name => adam}
+5> <input>map_size(M).</input>
+3
+6> <input>map_size(#{}).</input>
+0</pre>
+ <p>A collection of maps processing functions can be found in
+ the STDLIB module <seealso marker="stdlib:maps"><c>maps</c></seealso>.</p>
+ <p>Read more about <seealso marker="maps">Maps</seealso>.</p>
+ <note>
+ <p>Maps are considered experimental during OTP 17.</p>
+ </note>
+ </section>
+
+ <section>
<title>List</title>
<p>Compound data type with a variable number of terms.</p>
<pre>
diff --git a/system/doc/reference_manual/expressions.xml b/system/doc/reference_manual/expressions.xml
index e9de3e006e..37208710fe 100644
--- a/system/doc/reference_manual/expressions.xml
+++ b/system/doc/reference_manual/expressions.xml
@@ -56,7 +56,7 @@ Expr1 + Expr2</code>
<marker id="term"></marker>
<title>Terms</title>
<p>The simplest form of expression is a term, that is an integer,
- float, atom, string, list or tuple.
+ float, atom, string, list, map or tuple.
The return value is the term itself.</p>
</section>
@@ -1348,6 +1348,9 @@ end</pre>
<cell align="left" valign="middle"><c>is_list/1</c></cell>
</row>
<row>
+ <cell align="left" valign="middle"><c>is_map/1</c></cell>
+ </row>
+ <row>
<cell align="left" valign="middle"><c>is_number/1</c></cell>
</row>
<row>
@@ -1398,6 +1401,9 @@ end</pre>
<cell align="left" valign="middle"><c>length(List)</c></cell>
</row>
<row>
+ <cell align="left" valign="middle"><c>map_size(Map)</c></cell>
+ </row>
+ <row>
<cell align="left" valign="middle"><c>node()</c></cell>
</row>
<row>
diff --git a/system/doc/reference_manual/maps.xml b/system/doc/reference_manual/maps.xml
new file mode 100644
index 0000000000..78808ce4a2
--- /dev/null
+++ b/system/doc/reference_manual/maps.xml
@@ -0,0 +1,274 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!DOCTYPE chapter SYSTEM "chapter.dtd">
+
+<chapter>
+ <header>
+ <copyright>
+ <year>2014</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ The contents of this file are subject to the Erlang Public License,
+ Version 1.1, (the "License"); you may not use this file except in
+ compliance with the License. You should have received a copy of the
+ Erlang Public License along with this software. If not, it can be
+ retrieved online at http://www.erlang.org/.
+
+ Software distributed under the License is distributed on an "AS IS"
+ basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ the License for the specific language governing rights and limitations
+ under the License.
+ </legalnotice>
+
+ <title>Maps</title>
+ <prepared></prepared>
+ <docno></docno>
+ <date></date>
+ <rev></rev>
+ <file>maps.xml</file>
+ </header>
+
+ <note>
+ <p>Maps are considered experimental during OTP 17 and may be subject to change.</p>
+ <p>The documentation below describes it being possible to use arbitrary
+ expressions or variables as keys, this is <em>NOT</em> implemented in the current
+ version of Erlang/OTP.</p>
+ <p>Exceptions returns <c>badarg</c> instead of <c>badmap</c>, this will change in
+ the future releases.</p>
+ </note>
+
+ <section>
+ <title>Creating Maps</title>
+ <p>
+ Constructing a new map is done by letting an expression <c>K</c> be associated with
+ another expression <c>V</c>:
+ </p>
+ <code>#{ K => V }</code>
+ <p>
+ New maps may include multiple associations at construction by listing every
+ association:
+ </p>
+ <code>#{ K1 => V1, .., Kn => Vn }</code>
+ <p>
+ An empty map is constructed by not associating any terms with each other:
+ </p>
+ <code>#{}</code>
+ <p>
+ All keys and values in the map are terms. Any expression is first evaluated and
+ then the resulting terms are used as <em>key</em> and <em>value</em> respectively.
+ </p>
+ <p>
+ Keys and values are separated by the <c>=></c> arrow and associations are
+ separated by <c>,</c>.
+ </p>
+
+ <p>
+ Examples:
+ </p>
+ <code>
+M0 = #{}, % empty map
+M1 = #{a => &lt;&lt;"hello"&gt;&gt;}, % single association with literals
+M2 = #{1 => 2, b => b}, % multiple associations with literals
+M3 = #{k => {A,B}}, % single association with variables
+M4 = #{{"w", 1} => f()}. % compound key associated with an evaluated expression</code>
+ <p>
+ where, <c>A</c> and <c>B</c> are any expressions and <c>M0</c> through <c>M4</c>
+ are the resulting map terms.
+ </p>
+ <p>
+ If two matching keys are declared, the latter key will take precedence.
+ </p>
+ <p>
+ Example:
+ </p>
+
+<pre>
+1> <input>#{1 => a, 1 => b}.</input>
+#{1 => b }
+2> <input>#{1.0 => a, 1 => b}.</input>
+#{1 => b, 1.0 => a}
+</pre>
+ <p>
+ The order in which the expressions constructing the keys and their
+ associated values are evaluated is not defined. The syntactic order of
+ the key-value pairs in the construction is of no relevance, except in
+ the above mentioned case of two matching keys.
+ </p>
+ </section>
+
+ <section>
+ <title>Updating Maps</title>
+ <p>
+ Updating a map has similar syntax as constructing it.
+ </p>
+ <p>
+ An expression defining the map to be updated is put in front of the expression
+ defining the keys to be updated and their respective values.
+ </p>
+ <code>M#{ K => V }</code>
+ <p>
+ where <c>M</c> is a term of type map and <c>K</c> and <c>V</c> are any expression.
+ </p>
+ <p>
+ If key <c>K</c> does not match any existing key in the map, a new association
+ will be created from key <c>K</c> to value <c>V</c>. If key <c>K</c> matches
+ an existing key in map <c>M</c> its associated value will be replaced by the
+ new value <c>V</c>. In both cases the evaluated map expression will return a new map.
+ </p>
+ <p>
+ If <c>M</c> is not of type map an exception of type <c>badmap</c> is thrown.
+ </p>
+ <p>
+ To only update an existing value, the following syntax is used,
+ </p>
+ <code>M#{ K := V } </code>
+ <p>
+ where <c>M</c> is an term of type map, <c>V</c> is an expression and <c>K</c>
+ is an expression which evaluates to an existing key in <c>M</c>.
+ </p>
+ <p>
+ If key <c>K</c> does not match any existing keys in map <c>M</c> an exception
+ of type <c>badarg</c> will be triggered at runtime. If a matching key <c>K</c>
+ is present in map <c>M</c> its associated value will be replaced by the new
+ value <c>V</c> and the evaluated map expression returns a new map.
+ </p>
+ <p>
+ If <c>M</c> is not of type map an exception of type <c>badmap</c> is thrown.
+ </p>
+ <p>
+ Examples:
+ </p>
+ <code>
+M0 = #{},
+M1 = M0#{a => 0},
+M2 = M1#{a => 1, b => 2},
+M3 = M2#{"function" => fun() -> f() end},
+M4 = M3#{a := 2, b := 3}. % 'a' and 'b' was added in `M1` and `M2`.</code>
+ <p>
+ where <c>M0</c> is any map. It follows that <c>M1 .. M4</c> are maps as well.
+ </p>
+ <p>
+ More Examples:
+ </p>
+<pre>
+1> <input>M = #{1 => a}.</input>
+#{1 => a }
+2> <input>M#{1.0 => b}.</input>
+#{1 => a, 1.0 => b}.
+3> <input>M#{1 := b}.</input>
+#{1 => b}
+4> <input>M#{1.0 := b}.</input>
+** exception error: bad argument
+</pre>
+ <p>
+ As in construction, the order in which the key and value expressions
+ are evaluated is not defined. The
+ syntactic order of the key-value pairs in the update is of no
+ relevance, except in the case where two keys match, in which
+ case the latter value is used.
+ </p>
+ </section>
+
+ <section>
+ <title>Maps in Patterns</title>
+ <p>
+ Matching of key-value associations from maps is done in the following way:
+ </p>
+
+ <code>#{ K := V } = M</code>
+ <p>
+ where <c>M</c> is any map. The key <c>K</c> has to be an expression with bound
+ variables or a literals, and <c>V</c> can be any pattern with either bound or
+ unbound variables.
+ </p>
+ <p>
+ If the variable <c>V</c> is unbound, it will be bound to the value associated
+ with the key <c>K</c>, which has to exist in the map <c>M</c>. If the variable
+ <c>V</c> is bound, it has to match the value associated with <c>K</c> in <c>M</c>.
+ </p>
+ <p> Example: </p>
+<code>
+1> <input>M = #{"tuple" => {1,2}}.</input>
+#{"tuple" => {1,2}}
+2> <input>#{"tuple" := {1,B}} = M.</input>
+#{"tuple" => {1,2}}
+3> <input>B.</input>
+2.</code>
+ <p>
+ This will bind variable <c>B</c> to integer <c>2</c>.
+ </p>
+ <p>
+ Similarly, multiple values from the map may be matched:
+ </p>
+ <code>#{ K1 := V1, .., Kn := Vn } = M</code>
+ <p>
+ where keys <c>K1 .. Kn</c> are any expressions with literals or bound variables. If all
+ keys exist in map <c>M</c> all variables in <c>V1 .. Vn</c> will be matched to the
+ associated values of their respective keys.
+ </p>
+ <p>
+ If the matching conditions are not met, the match will fail, either with
+ </p>
+ <list>
+ <item>
+ a <c>badmatch</c> exception, if used in the context of the matching operator
+ as in the example,
+ </item>
+ <item>
+ or resulting in the next clause being tested in function heads and
+ case expressions.
+ </item>
+ </list>
+ <p>
+ Matching in maps only allows for <c>:=</c> as delimiters of associations.
+ The order in which keys are declared in matching has no relevance.
+ </p>
+ <p>
+ Duplicate keys are allowed in matching and will match each pattern associated
+ to the keys.
+ </p>
+ <code>#{ K := V1, K := V2 } = M</code>
+ <p>
+ Matching an expression against an empty map literal will match its type but
+ no variables will be bound:
+ </p>
+ <code>#{} = Expr</code>
+ <p>
+ This expression will match if the expression <c>Expr</c> is of type map, otherwise
+ it will fail with an exception <c>badmatch</c>.
+ </p>
+ <section>
+ <title>Matching syntax: Example with literals in function heads</title>
+ <p>
+ Matching of literals as keys are allowed in function heads.
+ </p>
+ <code>
+%% only start if not_started
+handle_call(start, From, #{ state := not_started } = S) ->
+...
+ {reply, ok, S#{ state := start }};
+
+%% only change if started
+handle_call(change, From, #{ state := start } = S) ->
+...
+ {reply, ok, S#{ state := changed }};</code>
+ </section>
+ </section>
+ <section>
+ <title>Maps in Guards</title>
+ <p>
+ Maps are allowed in guards as long as all sub-expressions are valid guard expressions.
+ </p>
+ <p>
+ Two guard BIFs handles maps:
+ </p>
+ <list>
+ <item>
+ <seealso marker="erts:erlang#is_map/1">is_map/1</seealso>
+ </item>
+ <item>
+ <seealso marker="erts:erlang#map_size/1">map_size/1</seealso>
+ </item>
+ </list>
+ </section>
+</chapter>
diff --git a/system/doc/reference_manual/modules.xml b/system/doc/reference_manual/modules.xml
index cd4c3a1b1b..f0ec7ef165 100644
--- a/system/doc/reference_manual/modules.xml
+++ b/system/doc/reference_manual/modules.xml
@@ -53,10 +53,10 @@ fact(0) -> % |
<pre>
-Tag(Value).</pre>
<p><c>Tag</c> must be an atom, while <c>Value</c> must be a literal
- term. As a convenience in user-defined attributes, the literal term
- <c>Value</c> the syntax <c>Name/Arity</c>
- (where <c>Name</c> is an atom and <c>Arity</c> a positive integer)
- will be translated to <c>{Name,Arity}</c>.</p>
+ term. As a convenience in user-defined attributes, if the literal term
+ <c>Value</c> has the syntax <c>Name/Arity</c>
+ (where <c>Name</c> is an atom and <c>Arity</c> a positive integer),
+ the term <c>Name/Arity</c> will be translated to <c>{Name,Arity}</c>.</p>
<p>Any module attribute can be specified. The attributes are stored
in the compiled code and can be retrieved by calling
diff --git a/system/doc/reference_manual/part.xml b/system/doc/reference_manual/part.xml
index ee8f3dd7eb..36fb888748 100644
--- a/system/doc/reference_manual/part.xml
+++ b/system/doc/reference_manual/part.xml
@@ -36,6 +36,7 @@
<xi:include href="typespec.xml"/>
<xi:include href="expressions.xml"/>
<xi:include href="macros.xml"/>
+ <xi:include href="maps.xml"/>
<xi:include href="records.xml"/>
<xi:include href="errors.xml"/>
<xi:include href="processes.xml"/>
diff --git a/system/doc/reference_manual/typespec.xml b/system/doc/reference_manual/typespec.xml
index 71aec732cf..cc35c6eb21 100644
--- a/system/doc/reference_manual/typespec.xml
+++ b/system/doc/reference_manual/typespec.xml
@@ -100,6 +100,7 @@
| Fun
| Integer
| List
+ | Map
| Tuple
| Union
| UserDefined %% described in Section 6.3
@@ -126,10 +127,17 @@
| nonempty_improper_list(Type1, Type2) %% Type1 and Type2 as above
| nonempty_list(Type) %% Proper non-empty list
+ Map :: map() %% stands for a map of any size
+ | #{} %% stands for a map of any size
+ | #{PairList}
+
Tuple :: tuple() %% stands for a tuple of any size
| {}
| {TList}
+ PairList :: Type => Type
+ | Type => Type, PairList
+
TList :: Type
| Type, TList
@@ -275,6 +283,10 @@
Records have been extended to possibly contain type information.
This is described in the sub-section <seealso marker="#typeinrecords">"Type information in record declarations"</seealso> below.
</p>
+ <note>
+ <p>Map types, both <c>map()</c> and <c>#{ ... }</c>, are considered experimental during OTP 17.</p>
+ <p>No type information of maps pairs, only the containing map types, are used by Dialyzer in OTP 17.</p>
+ </note>
</section>
<section>
diff --git a/system/doc/reference_manual/xmlfiles.mk b/system/doc/reference_manual/xmlfiles.mk
index 6886c8c7cf..181e6f8042 100644
--- a/system/doc/reference_manual/xmlfiles.mk
+++ b/system/doc/reference_manual/xmlfiles.mk
@@ -24,6 +24,7 @@ REF_MAN_CHAPTER_FILES = \
functions.xml \
expressions.xml \
macros.xml \
+ maps.xml \
records.xml \
errors.xml \
processes.xml \
diff --git a/system/doc/system_principles/create_target.xmlsrc b/system/doc/system_principles/create_target.xmlsrc
index fbc935d708..b5f8d8ac4d 100644
--- a/system/doc/system_principles/create_target.xmlsrc
+++ b/system/doc/system_principles/create_target.xmlsrc
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>2002</year><year>2013</year>
+ <year>2002</year><year>2014</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -21,7 +21,7 @@
</legalnotice>
- <title>Creating a First Target System</title>
+ <title>Creating and Upgrading a Target System</title>
<prepared>Peter H&ouml;gfeldt</prepared>
<responsible></responsible>
<docno></docno>
@@ -71,23 +71,24 @@
</section>
<section>
+ <marker id="create"/>
<title>Creating a Target System</title>
<p>It is assumed that you have a working Erlang/OTP system structured
according to the OTP Design Principles.</p>
- <p><em>Step 1.</em> First create a <c>.rel</c> file (see
- <c>rel(4)</c>) that specifies the <c>erts</c> version
- and lists all applications that should be included in the new
- basic target system. An example is the following
+ <p><em>Step 1.</em> First create a <c>.rel</c> file (see <seealso
+ marker="sasl:rel">rel(4)</seealso>) that specifies the <c>erts</c>
+ version and lists all applications that should be included in the
+ new basic target system. An example is the following
<c>mysystem.rel</c> file:</p>
<code type="none">
%% mysystem.rel
{release,
{"MYSYSTEM", "FIRST"},
- {erts, "5.1"},
- [{kernel, "2.7"},
- {stdlib, "1.10"},
- {sasl, "1.9.3"},
- {pea, "1.0"}]}. </code>
+ {erts, "5.10.4"},
+ [{kernel, "2.16.4"},
+ {stdlib, "1.19.4"},
+ {sasl, "2.3.4"},
+ {pea, "1.0"}]}.</code>
<p>The listed applications are not only original Erlang/OTP
applications but possibly also new applications that you have
written yourself (here examplified by the application
@@ -116,13 +117,13 @@ os> <input>erl -pa /home/user/target_system/myapps/pea-1.0/ebin</input></pre>
<c>systools:make_tar/2</c>. That file has the following
contents:</p>
<code type="none">
-erts-5.1/bin/
+erts-5.10.4/bin/
releases/FIRST/start.boot
releases/FIRST/mysystem.rel
releases/mysystem.rel
-lib/kernel-2.7/
-lib/stdlib-1.10/
-lib/sasl-1.9.3/
+lib/kernel-2.16.4/
+lib/stdlib-1.19.4/
+lib/sasl-2.3.4/
lib/pea-1.0/ </code>
<p>The file <c>releases/FIRST/start.boot</c> is a copy of our
<c>mysystem.boot</c></p>
@@ -142,16 +143,19 @@ lib/pea-1.0/ </code>
<item>Creates the temporary directory <c>tmp</c> and extracts the tar file
<c>mysystem.tar.gz</c> into that directory. </item>
<item>Deletes the <c>erl</c> and <c>start</c> files from
- <c>tmp/erts-5.1/bin</c>. These files will be created again from
+ <c>tmp/erts-5.10.4/bin</c>. These files will be created again from
source when installing the release.</item>
<item>Creates the directory <c>tmp/bin</c>.</item>
<item>Copies the previously created file <c>plain.boot</c> to
<c>tmp/bin/start.boot</c>.</item>
<item>Copies the files <c>epmd</c>, <c>run_erl</c>, and
- <c>to_erl</c> from the directory <c>tmp/erts-5.1/bin</c> to
+ <c>to_erl</c> from the directory <c>tmp/erts-5.10.4/bin</c> to
the directory <c>tmp/bin</c>.</item>
+ <item>Creates the directory <c>tmp/log</c>, which will be used
+ if the system is started as embedded with the <c>bin/start</c>
+ script.</item>
<item>Creates the file <c>tmp/releases/start_erl.data</c> with
- the contents "5.1 FIRST". This file is to be passed as data
+ the contents "5.10.4 FIRST". This file is to be passed as data
file to the <c>start_erl</c> script.
</item>
<item>Recreates the file <c>mysystem.tar.gz</c> from the directories
@@ -171,11 +175,11 @@ lib/pea-1.0/ </code>
<item>Extracts the tar file <c>mysystem.tar.gz</c> into the target
directory <c>/usr/local/erl-target</c>.</item>
<item>In the target directory reads the file <c>releases/start_erl.data</c>
- in order to find the Erlang runtime system version ("5.1").</item>
+ in order to find the Erlang runtime system version ("5.10.4").</item>
<item>Substitutes <c>%FINAL_ROOTDIR%</c> and <c>%EMU%</c> for
<c>/usr/local/erl-target</c> and <c>beam</c>, respectively, in
the files <c>erl.src</c>, <c>start.src</c>, and
- <c>start_erl.src</c> of the target <c>erts-5.1/bin</c>
+ <c>start_erl.src</c> of the target <c>erts-5.10.4/bin</c>
directory, and puts the resulting files <c>erl</c>,
<c>start</c>, and <c>run_erl</c> in the target <c>bin</c>
directory.</item>
@@ -185,6 +189,7 @@ lib/pea-1.0/ </code>
</section>
<section>
+ <marker id="start"/>
<title>Starting a Target System</title>
<p>Now we have a target system that can be started in various ways.</p>
<p>We start it as a <em>basic target system</em> by invoking</p>
@@ -193,7 +198,7 @@ os> <input>/usr/local/erl-target/bin/erl</input></pre>
<p>where only the <c>kernel</c> and <c>stdlib</c> applications are
started, i.e. the system is started as an ordinary development
system. There are only two files needed for all this to work:
- <c>bin/erl</c> file (obtained from <c>erts-5.1/bin/erl.src</c>)
+ <c>bin/erl</c> file (obtained from <c>erts-5.10.4/bin/erl.src</c>)
and the <c>bin/start.boot</c> file (a copy of <c>plain.boot</c>).</p>
<p>We can also start a distributed system (requires <c>bin/epmd</c>).</p>
<p>To start all applications specified in the original
@@ -208,9 +213,10 @@ os> <input>/usr/local/erl-target/bin/erl -boot /usr/local/erl-target/releases/FI
<c>bin/run_erl</c>, which in turn calls <c>bin/start_erl</c>
(roughly, <c>start_erl</c> is an embedded variant of
<c>erl</c>). </p>
- <p>The shell script <c>start</c> is only an example. You should
- edit it to suite your needs. Typically it is executed when the
- UNIX system boots.</p>
+ <p>The shell script <c>start</c>, which is generated from
+ erts-5.10.4/bin/start.src during installation, is only an
+ example. You should edit it to suite your needs. Typically it is
+ executed when the UNIX system boots.</p>
<p><c>run_erl</c> is a wrapper that provides logging of output from
the run-time system to file. It also provides a simple mechanism
for attaching to the Erlang shell (<c>to_erl</c>).</p>
@@ -218,7 +224,7 @@ os> <input>/usr/local/erl-target/bin/erl -boot /usr/local/erl-target/releases/FI
(<c>"/usr/local/erl-target"</c>), the releases directory
(<c>"/usr/local/erl-target/releases"</c>), and the location of
the <c>start_erl.data</c> file. It reads the run-time system
- version (<c>"5.1"</c>) and release version (<c>"FIRST"</c>) from
+ version (<c>"5.10.4"</c>) and release version (<c>"FIRST"</c>) from
the <c>start_erl.data</c> file, starts the run-time system of the
version found, and provides <c>-boot</c> flag specifying the boot
file of the release version found
@@ -258,6 +264,198 @@ os> <input>/usr/local/erl-target/bin/erl -boot /usr/local/erl-target/releases/FI
</section>
<section>
+ <title>Creating the Next Version</title>
+
+ <p>
+ In this example the <c>pea</c> application has been changed, and
+ so are <c>erts</c>, <c>kernel</c>, <c>stdlib</c> and
+ <c>sasl</c>.
+ </p>
+
+ <p>
+ <em>Step 1.</em> Create the <c>.rel</c> file:
+ </p>
+ <code type="none">
+%% mysystem2.rel
+{release,
+ {"MYSYSTEM", "SECOND"},
+ {erts, "6.0"},
+ [{kernel, "3.0"},
+ {stdlib, "2.0"},
+ {sasl, "2.4"},
+ {pea, "2.0"}]}.</code>
+ <p>
+ <em>Step 2.</em> Create the application upgrade file (see
+ <seealso marker="sasl:appup">appup(4)</seealso>) for <c>pea</c>,
+ for example:
+ </p>
+ <code type="none">
+%% pea.appup
+{"2.0",
+ [{"1.0",[{load_module,pea_lib}]}],
+ [{"1.0",[{load_module,pea_lib}]}]}.</code>
+ <p>
+ <em>Step 3.</em> From the directory where the
+ <c>mysystem2.rel</c> file reside, start the Erlang/OTP system:
+ </p>
+ <pre>
+os> <input>erl -pa /home/user/target_system/myapps/pea-2.0/ebin</input></pre>
+ <p>giving the path to the new version of <c>pea</c>. </p>
+
+ <p>
+ <em>Step 4.</em> Create the release upgrade file (see <seealso
+ marker="sasl:relup">relup(4)</seealso>):
+ </p>
+ <pre>
+1> <input>systools:make_relup("mysystem2",["mysystem"],["mysystem"],[{path,["/home/user/target_system/myapps/pea-1.0/ebin","/my/old/erlang/lib/*/ebin"]}]).</input></pre>
+ <p>
+ where <c>"mysystem"</c> is the base release and
+ <c>"mysystem2"</c> is the release to upgrade to.
+ </p>
+ <p>
+ Note that the <c>path</c> option is used for pointing out the
+ old version of all applications. (The new versions are already
+ in the code path - assuming of course that the erlang node on
+ which this is executed is running the correct version of
+ Erlang/OTP.)
+ </p>
+ <p>
+ <em>Step 5.</em> Create the new release:
+ </p>
+ <pre>
+2> <input>target_system:create("mysystem2").</input></pre>
+ <p>
+ Given that the <c>relup</c> file generated in step 4 above is
+ now located in the current directory, it will automatically be
+ included in the release package.
+ </p>
+ </section>
+
+ <section>
+ <title>Upgrading the Target System</title>
+ <p>
+ This part is done on the target node, and for this example we
+ want the node to be running as an embedded system with the
+ <c>-heart</c> option, allowing automatic restart of the
+ node. See <seealso marker="#start">Starting a Target
+ System</seealso> above for more information.
+ </p>
+ <p>
+ We add <c>-heart</c> to <c>bin/start</c>:
+ </p>
+ <code type="none">
+#!/bin/sh
+ROOTDIR=/usr/local/erl-target/
+
+if [ -z "$RELDIR" ]
+then
+ RELDIR=$ROOTDIR/releases
+fi
+
+START_ERL_DATA=${1:-$RELDIR/start_erl.data}
+
+$ROOTDIR/bin/run_erl -daemon /tmp/ $ROOTDIR/log "exec $ROOTDIR/bin/start_erl $ROOTDIR $RELDIR $START_ERL_DATA -heart</code>
+ <p>
+ And we use the simplest possible <c>sys.config</c>, which we
+ store in <c>releases/FIRST</c>:
+ </p>
+ <code type="none">
+%% sys.config
+[].</code>
+ <p>
+ Finally, in order to prepare the upgrade, we need to put the new
+ release package in the <c>releases</c> directory of the first
+ target system:
+ </p>
+ <pre>
+os> <input>cp mysystem2.tar.gz /usr/local/erl-target/releases</input></pre>
+ <p>
+ And assuming that the node has been started like this:
+ </p>
+ <pre>
+os> <input>/usr/local/erl-target/bin/start</input></pre>
+ <p>
+ it can be accessed like this:
+ </p>
+ <pre>
+os> <input>/usr/local/erl-target/bin/to_erl /tmp/erlang.pipe.1</input></pre>
+ <p>
+ Also note that logs can be found in
+ <c>/usr/local/erl-target/log</c>. This directory is specified as
+ an argument to <c>run_erl</c>in the start script listed above.
+ </p>
+ <p>
+ <em>Step 1.</em> Unpack the release:
+ </p>
+ <pre>
+1> <input>{ok,Vsn} = release_handler:unpack_release("mysystem2").</input></pre>
+ <p>
+ <em>Step 2.</em> Install the release:
+ </p>
+ <pre>
+2> <input>release_handler:install_release(Vsn).</input>
+<output>{continue_after_restart,"FIRST",[]}
+heart: Tue Apr 1 12:15:10 2014: Erlang has closed.
+heart: Tue Apr 1 12:15:11 2014: Executed "/usr/local/erl-target/bin/start /usr/local/erl-target/releases/new_start_erl.data" -> 0. Terminating.
+[End]</output></pre>
+ <p>
+ The above return value and output after the call to
+ <c>release_handler:install_release/1</c> means that the
+ <c>release_handler</c> has restarted the node by using
+ <c>heart</c>. This will always be done when the upgrade involves
+ a change of <c>erts</c>, <c>kernel</c>, <c>stdlib</c> or
+ <c>sasl</c>. See <seealso marker="upgrade">Upgrade when
+ Erlang/OTP has Changed</seealso> for more infomation about this.
+ </p>
+ <p>
+ The node will be accessable via a new pipe:
+ </p>
+ <pre>
+os> <input>/usr/local/erl-target/bin/to_erl /tmp/erlang.pipe.2</input></pre>
+ <p>
+ Let's see which releases we have in our system:
+ </p>
+ <pre>
+1> <input>release_handler:which_releases().</input>
+<output>[{"MYSYSTEM","SECOND",
+ ["kernel-3.0","stdlib-2.0","sasl-2.4","pea-2.0"],
+ current},
+ {"MYSYSTEM","FIRST",
+ ["kernel-2.16.4","stdlib-1.19.4","sasl-2.3.4","pea-1.0"],
+ permanent}]</output></pre>
+ <p>
+ Our new release, "SECOND", is now the current release, but we
+ can also see that our "FIRST" release is still permanent. This
+ means that if the node would be restarted at this point, it
+ would come up running the "FIRST" release again.
+ </p>
+ <p>
+ <em>Step 3.</em> Make the new release permanent:
+ </p>
+ <pre>
+2> <input>release_handler:make_permanent("SECOND").</input></pre>
+
+ <p>
+ Now look at the releases again:
+ </p>
+
+ <pre>
+3> <input>release_handler:which_releases().</input>
+<output>[{"MYSYSTEM","SECOND",
+ ["kernel-3.0","stdlib-2.0","sasl-2.4","pea-2.0"],
+ permanent},
+ {"MYSYSTEM","FIRST",
+ ["kernel-2.16.4","stdlib-1.19.4","sasl-2.3.4","pea-1.0"],
+ old}]</output></pre>
+
+ <p>
+ Here we see that the new release version is <c>permanent</c>, so
+ it would be safe to restart the node.
+ </p>
+
+ </section>
+
+ <section>
<title>Listing of target_system.erl</title>
<p>This module can also be found in the <c>examples</c> directory
of the <c>sasl</c> application.</p>
diff --git a/system/doc/system_principles/part.xml b/system/doc/system_principles/part.xml
index 811428baae..d05c89fde8 100644
--- a/system/doc/system_principles/part.xml
+++ b/system/doc/system_principles/part.xml
@@ -4,7 +4,7 @@
<part xmlns:xi="http://www.w3.org/2001/XInclude">
<header>
<copyright>
- <year>1997</year><year>2013</year>
+ <year>1997</year><year>2014</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -31,6 +31,6 @@
<xi:include href="system_principles.xml"/>
<xi:include href="error_logging.xml"/>
<xi:include href="create_target.xml"/>
+ <xi:include href="upgrade.xml"/>
<xi:include href="versions.xml"/>
</part>
-
diff --git a/system/doc/system_principles/system_principles.xml b/system/doc/system_principles/system_principles.xml
index 4f2202fdd1..70c69b1dab 100644
--- a/system/doc/system_principles/system_principles.xml
+++ b/system/doc/system_principles/system_principles.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>1996</year><year>2013</year>
+ <year>1996</year><year>2014</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -34,13 +34,12 @@
<p>An Erlang runtime system is started with the command <c>erl</c>:</p>
<pre>
% <input>erl</input>
-Erlang (BEAM) emulator version 5.2.3.5 [hipe] [threads:0]
+Erlang/OTP 17 [erts-6.0] [hipe] [smp:8:8]
-Eshell V5.2.3.5 (abort with ^G)
+Eshell V6.0 (abort with ^G)
1> </pre>
<p><c>erl</c> understands a number of command line arguments, see
- <c>erl(1)</c>. A number of them are also described in this
- chapter.</p>
+ <c>erl(1)</c>. A number of them are also described in this chapter.</p>
<p>Application programs can access the values of the command line
arguments by calling one of the functions
<c>init:get_argument(Key)</c>, or <c>init:get_arguments()</c>.
diff --git a/system/doc/system_principles/upgrade.xml b/system/doc/system_principles/upgrade.xml
new file mode 100644
index 0000000000..68e48da0b8
--- /dev/null
+++ b/system/doc/system_principles/upgrade.xml
@@ -0,0 +1,118 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!DOCTYPE chapter SYSTEM "chapter.dtd">
+
+<chapter>
+ <header>
+ <copyright>
+ <year>2014</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ The contents of this file are subject to the Erlang Public License,
+ Version 1.1, (the "License"); you may not use this file except in
+ compliance with the License. You should have received a copy of the
+ Erlang Public License along with this software. If not, it can be
+ retrieved online at http://www.erlang.org/.
+
+ Software distributed under the License is distributed on an "AS IS"
+ basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ the License for the specific language governing rights and limitations
+ under the License.
+
+ </legalnotice>
+
+ <title>Upgrade when Erlang/OTP has Changed</title>
+ <prepared></prepared>
+ <responsible></responsible>
+ <docno></docno>
+ <approved></approved>
+ <checked></checked>
+ <date>2014-02-19</date>
+ <rev></rev>
+ <file>upgrade.xml</file>
+ </header>
+
+ <section>
+ <title>Introduction</title>
+ <p>
+ As of Erlang/OTP 17, most applications deliver a valid
+ application upgrade (<c>appup</c>) file. In earlier releases, a
+ majority of the applications in Erlang/OTP did not support
+ upgrade at all. Many of the applications use the
+ <c>restart_application</c> instruction. These are applications
+ for which it is not crucial to support real soft upgrade, for
+ instance tools and library applications. The
+ <c>restart_application</c> instruction
+ ensures that all modules in the application are reloaded and
+ thereby running the new code.
+ </p>
+ </section>
+
+ <section>
+ <title>Upgrade of core applications</title>
+ <p>
+ The core applications ERTS, Kernel, STDLIB
+ and SASL never allow real soft upgrade, but require the
+ Erlang emulator to be restarted. This is indicated to the
+ <c>release_handler</c> by the upgrade instruction
+ <c>restart_new_emulator</c>. This instruction will always be the
+ very first instruction executed, and it will restart the
+ emulator with the new versions of the above mentioned core
+ applications and the old versions of all other
+ applications. When the node is back up all other upgrade instructions are
+ executed, making sure each application is finally running its
+ new version.
+ </p>
+
+ <p>
+ It might seem strange to do a two-step upgrade instead of
+ just restarting the emulator with the new version of all
+ applications. The reason for this design decision is to allow
+ <c>code_change</c> functions to have side effects, for example changing
+ data on disk. It also makes sure that the upgrade mechanism for
+ non-core applications does not differ depending on whether or not
+ core applications are changed at the same time.
+ </p>
+
+ <p>
+ If, however, the more brutal variant is preferred, it is
+ possible to handwrite the release upgrade file using only the
+ single upgrade instruction <c>restart_emulator</c>. This
+ instruction, in contrast to <c>restart_new_emulator</c>, will
+ cause the emulator to restart with the new versions of
+ <em>all</em> applications.
+ </p>
+
+ <p>
+ <em>Note</em> that if other instructions are included before
+ <c>restart_emulator</c> in the handwritten <c>relup</c> file,
+ they will be executed in the old emulator. This is a big risk
+ since there is no guarantee that new beam code can be loaded
+ into the old emulator. Adding instructions after
+ <c>restart_emulator</c> has no effect as the
+ <c>release_handler</c> will not do any attempt at executing
+ them.
+ </p>
+
+ <p>
+ See <seealso marker="sasl:relup">relup(4)</seealso> for
+ information about the release upgrade file, and <seealso
+ marker="sasl:appup">appup(4)</seealso> for further information
+ about upgrade instructions.
+ </p>
+ </section>
+
+ <section>
+ <title>Applications that still do not allow code upgrade</title>
+ <p>
+ A few applications, for instance HiPE do not support
+ upgrade at all. This is indicated by an application upgrade file
+ containing only <c>{Vsn,[],[]}</c>. Any attempt at creating a release
+ upgrade file with such input will fail.
+ The only way to force an upgrade involving applications like this is to
+ handwrite the <c>relup</c> file, preferably as described above
+ with only the <c>restart_emulator</c> instruction.
+ </p>
+
+ </section>
+</chapter>
diff --git a/system/doc/system_principles/xmlfiles.mk b/system/doc/system_principles/xmlfiles.mk
index 9743949798..c60ffbad28 100644
--- a/system/doc/system_principles/xmlfiles.mk
+++ b/system/doc/system_principles/xmlfiles.mk
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2009. All Rights Reserved.
+# Copyright Ericsson AB 2009-2014. All Rights Reserved.
#
# The contents of this file are subject to the Erlang Public License,
# Version 1.1, (the "License"); you may not use this file except in
@@ -20,4 +20,5 @@ SYSTEM_PRINCIPLES_CHAPTER_FILES = \
system_principles.xml \
error_logging.xml \
create_target.xml \
+ upgrade.xml \
versions.xml