diff options
Diffstat (limited to 'system/doc/system_principles/create_target.xml')
-rw-r--r-- | system/doc/system_principles/create_target.xml | 497 |
1 files changed, 0 insertions, 497 deletions
diff --git a/system/doc/system_principles/create_target.xml b/system/doc/system_principles/create_target.xml deleted file mode 100644 index 7d9f4681b9..0000000000 --- a/system/doc/system_principles/create_target.xml +++ /dev/null @@ -1,497 +0,0 @@ -<?xml version="1.0" encoding="latin1" ?> -<!DOCTYPE chapter SYSTEM "chapter.dtd"> - -<chapter> - <header> - <copyright> - <year>2002</year><year>2009</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>Creating a First Target System</title> - <prepared>Peter Högfeldt</prepared> - <responsible></responsible> - <docno></docno> - <approved></approved> - <checked></checked> - <date>2002-09-17</date> - <rev>A</rev> - <file>create_target.xml</file> - </header> - - <section> - <title>Introduction</title> - <p>When creating a system using Erlang/OTP, the most simple way is - to install Erlang/OTP somewhere, install the application specific - code somewhere else, and then start the Erlang runtime system, - making sure the code path includes the application specific code.</p> - <p>Often it is not desirable to use an Erlang/OTP system as is. A - developer may create new Erlang/OTP compliant applications for a - particular purpose, and several original Erlang/OTP applications - may be irrelevant for the purpose in question. Thus, there is a - need to be able to create a new system based on a given - Erlang/OTP system, where dispensable applications are removed, - and a set of new applications that are included in the new - system. Documentation and source code is irrelevant and is - therefore not included in the new system.</p> - <p>This chapter is about creating such a system, which we call a - <em>target system</em>.</p> - <p>In the following sections we consider creating target systems with - different requirements of functionality:</p> - <list type="bulleted"> - <item>a <em>basic target system</em> that can be started by - calling the ordinary <c>erl</c> script, </item> - <item>a <em>simple target system</em> where also code - replacement in run-time can be performed, and</item> - <item>an <em>embedded target system</em> where there is also - support for logging output from the system to file for later - inspection, and where the system can be started automatically - at boot time. </item> - </list> - <p>We only consider the case when Erlang/OTP is running on a UNIX - system.</p> - <p>There is an example Erlang module <c>target_system.erl</c> that - contains functions for creating and installing a target system. - That module is used in the examples below. The source code of - the module is listed at the end of this chapter.</p> - </section> - - <section> - <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 - <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> - <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 - <c>pea</c>). </p> - <p><em>Step 2.</em> From the directory where the <c>mysystem.rel</c> - file reside, start the Erlang/OTP system:</p> - <pre> -os> <input>erl -pa /home/user/target_system/myapps/pea-1.0/ebin</input></pre> - <p>where also the path to the <c>pea-1.0</c> ebin directory is - provided. </p> - <p><em>Step 3.</em> Now create the target system: </p> - <pre> -1> <input>target_system:create("mysystem").</input></pre> - <p>The <c>target_system:create/1</c> function does the following:</p> - <list type="ordered"> - <item>Reads the <c>mysystem.rel</c> file, and creates a new file - <c>plain.rel</c> which is identical to former, except that it - only lists the <c>kernel</c> and <c>stdlib</c> applications. </item> - <item>From the <c>mysystem.rel</c> and <c>plain.rel</c> files - creates the files <c>mysystem.script</c>, - <c>mysystem.boot</c>, <c>plain.script</c>, and - <c>plain.boot</c> through a call to - <c>systools:make_script/2</c>.</item> - <item> - <p>Creates the file <c>mysystem.tar.gz</c> by a call to - <c>systools:make_tar/2</c>. That file has the following - contents:</p> - <code type="none"> -erts-5.1/bin/ -releases/FIRST/start.boot -releases/mysystem.rel -lib/kernel-2.7/ -lib/stdlib-1.10/ -lib/sasl-1.9.3/ -lib/pea-1.0/ </code> - <p>The file <c>releases/FIRST/start.boot</c> is a copy of our - <c>mysystem.boot</c>, and a copy of the original - <c>mysystem.rel</c> has been put in the <c>releases</c> - directory.</p> - </item> - <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>. XXX Why.</item> - <item>Creates the directory <c>tmp/bin</c>.</item> - <item>Copies the previously creates 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 - the directory <c>tmp/bin</c>.</item> - <item>Creates the file <c>tmp/releases/start_erl.data</c> with the - contents "5.1 FIRST". - </item> - <item>Recreates the file <c>mysystem.tar.gz</c> from the directories - in the directory <c>tmp</c>, and removes <c>tmp</c>.</item> - </list> - </section> - - <section> - <title>Installing a Target System</title> - <p><em>Step 4.</em> Install the created target system in a - suitable directory. </p> - <pre> -2> <input>target_system:install("mysystem", "/usr/local/erl-target").</input></pre> - <p>The function <c>target_system:install/2</c> does the following: - </p> - <list type="ordered"> - <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> - <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> - 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> - <item>Finally the target <c>releases/RELEASES</c> file is created - from data in the <c>releases/mysystem.rel</c> file.</item> - </list> - </section> - - <section> - <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> - <pre> -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>) - 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 - <c>mysystem.rel</c> file, use the <c>-boot</c> flag as follows:</p> - <pre> -os> <input>/usr/local/erl-target/bin/erl -boot /usr/local/erl-target/releases/FIRST/start</input></pre> - <p>We start a <em>simple target system</em> as above. The only difference - is that also the file <c>releases/RELEASES</c> is present for - code replacement in run-time to work.</p> - <p>To start an <em>embedded target system</em> the shell script - <c>bin/start</c> is used. That shell script calls - <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><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> - <p><c>start_erl</c> requires the root directory - (<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 - 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 - (<c>"releases/FIRST/start.boot"</c>).</p> - <p><c>start_erl</c> also assumes that there is <c>sys.config</c> in - release version directory (<c>"releases/FIRST/sys.config</c>). That - is the topic of the next section (see below).</p> - <p>The <c>start_erl</c> shell script should normally not be - altered by the user.</p> - </section> - - <section> - <title>System Configuration Parameters</title> - <p>As was pointed out above <c>start_erl</c> requires a - <c>sys.config</c> in the release version directory - (<c>"releases/FIRST/sys.config"</c>). If there is no such a - file, the system start will fail. Hence such a file has to - added as well.</p> - <p></p> - <p>If you have system configuration data that are neither file - location dependent nor site dependent, it may be convenient to - create the <c>sys.config</c> early, so that it becomes a part of - the target system tar file created by - <c>target_system:create/1</c>. In fact, if you create, in the - current directory, not only the <c>mysystem.rel</c> file, but - also a <c>sys.config</c> file, that latter file will be tacitly - put in the apropriate directory.</p> - </section> - - <section> - <title>Differences from the Install Script</title> - <p>The above <c>install/2</c> procedure differs somewhat from that - of the ordinary <c>Install</c> shell script. In fact, <c>create/1</c> - makes the release package as complete as possible, and leave to the - <c>install/2</c> procedure to finish by only considering location - dependent files.</p> - </section> - - <section> - <title>Listing of target_system.erl</title> - <code type="none"><![CDATA[ --module(target_system). --include_lib("kernel/include/file.hrl"). --export([create/1, install/2]). --define(BUFSIZE, 8192). - -%% Note: RelFileName below is the *stem* without trailing .rel, -%% .script etc. -%% - -%% create(RelFileName) -%% -create(RelFileName) -> - RelFile = RelFileName ++ ".rel", - io:fwrite("Reading file: \"~s\" ...~n", [RelFile]), - {ok, [RelSpec]} = file:consult(RelFile), - io:fwrite("Creating file: \"~s\" from \"~s\" ...~n", - ["plain.rel", RelFile]), - {release, - {RelName, RelVsn}, - {erts, ErtsVsn}, - AppVsns} = RelSpec, - PlainRelSpec = {release, - {RelName, RelVsn}, - {erts, ErtsVsn}, - lists:filter(fun({kernel, _}) -> - true; - ({stdlib, _}) -> - true; - (_) -> - false - end, AppVsns) - }, - {ok, Fd} = file:open("plain.rel", [write]), - io:fwrite(Fd, "~p.~n", [PlainRelSpec]), - file:close(Fd), - - io:fwrite("Making \"plain.script\" and \"plain.boot\" files ...~n"), - make_script("plain"), - - io:fwrite("Making \"~s.script\" and \"~s.boot\" files ...~n", - [RelFileName, RelFileName]), - make_script(RelFileName), - - TarFileName = io_lib:fwrite("~s.tar.gz", [RelFileName]), - io:fwrite("Creating tar file \"~s\" ...~n", [TarFileName]), - make_tar(RelFileName), - - io:fwrite("Creating directory \"tmp\" ...~n"), - file:make_dir("tmp"), - - io:fwrite("Extracting \"~s\" into directory \"tmp\" ...~n", [TarFileName]), - extract_tar(TarFileName, "tmp"), - - TmpBinDir = filename:join(["tmp", "bin"]), - ErtsBinDir = filename:join(["tmp", "erts-" ++ ErtsVsn, "bin"]), - io:fwrite("Deleting \"erl\" and \"start\" in directory \"~s\" ...~n", - [ErtsBinDir]), - file:delete(filename:join([ErtsBinDir, "erl"])), - file:delete(filename:join([ErtsBinDir, "start"])), - - io:fwrite("Creating temporary directory \"~s\" ...~n", [TmpBinDir]), - file:make_dir(TmpBinDir), - - io:fwrite("Copying file \"plain.boot\" to \"~s\" ...~n", - [filename:join([TmpBinDir, "start.boot"])]), - copy_file("plain.boot", filename:join([TmpBinDir, "start.boot"])), - - io:fwrite("Copying files \"epmd\", \"run_erl\" and \"to_erl\" from \n" - "\"~s\" to \"~s\" ...~n", - [ErtsBinDir, TmpBinDir]), - copy_file(filename:join([ErtsBinDir, "epmd"]), - filename:join([TmpBinDir, "epmd"]), [preserve]), - copy_file(filename:join([ErtsBinDir, "run_erl"]), - filename:join([TmpBinDir, "run_erl"]), [preserve]), - copy_file(filename:join([ErtsBinDir, "to_erl"]), - filename:join([TmpBinDir, "to_erl"]), [preserve]), - - StartErlDataFile = filename:join(["tmp", "releases", "start_erl.data"]), - io:fwrite("Creating \"~s\" ...~n", [StartErlDataFile]), - StartErlData = io_lib:fwrite("~s ~s~n", [ErtsVsn, RelVsn]), - write_file(StartErlDataFile, StartErlData), - - io:fwrite("Recreating tar file \"~s\" from contents in directory " - "\"tmp\" ...~n", [TarFileName]), - {ok, Tar} = erl_tar:open(TarFileName, [write, compressed]), - {ok, Cwd} = file:get_cwd(), - file:set_cwd("tmp"), - erl_tar:add(Tar, "bin", []), - erl_tar:add(Tar, "erts-" ++ ErtsVsn, []), - erl_tar:add(Tar, "releases", []), - erl_tar:add(Tar, "lib", []), - erl_tar:close(Tar), - file:set_cwd(Cwd), - io:fwrite("Removing directory \"tmp\" ...~n"), - remove_dir_tree("tmp"), - ok. - - -install(RelFileName, RootDir) -> - TarFile = RelFileName ++ ".tar.gz", - io:fwrite("Extracting ~s ...~n", [TarFile]), - extract_tar(TarFile, RootDir), - StartErlDataFile = filename:join([RootDir, "releases", "start_erl.data"]), - {ok, StartErlData} = read_txt_file(StartErlDataFile), - [ErlVsn, RelVsn| _] = string:tokens(StartErlData, " \n"), - ErtsBinDir = filename:join([RootDir, "erts-" ++ ErlVsn, "bin"]), - BinDir = filename:join([RootDir, "bin"]), - io:fwrite("Substituting in erl.src, start.src and start_erl.src to\n" - "form erl, start and start_erl ...\n"), - subst_src_scripts(["erl", "start", "start_erl"], ErtsBinDir, BinDir, - [{"FINAL_ROOTDIR", RootDir}, {"EMU", "beam"}], - [preserve]), - io:fwrite("Creating the RELEASES file ...\n"), - create_RELEASES(RootDir, - filename:join([RootDir, "releases", RelFileName])). - -%% LOCALS - -%% make_script(RelFileName) -%% -make_script(RelFileName) -> - Opts = [no_module_tests], - systools:make_script(RelFileName, Opts). - -%% make_tar(RelFileName) -%% -make_tar(RelFileName) -> - RootDir = code:root_dir(), - systools:make_tar(RelFileName, [{erts, RootDir}]). - -%% extract_tar(TarFile, DestDir) -%% -extract_tar(TarFile, DestDir) -> - erl_tar:extract(TarFile, [{cwd, DestDir}, compressed]). - -create_RELEASES(DestDir, RelFileName) -> - release_handler:create_RELEASES(DestDir, RelFileName ++ ".rel"). - -subst_src_scripts(Scripts, SrcDir, DestDir, Vars, Opts) -> - lists:foreach(fun(Script) -> - subst_src_script(Script, SrcDir, DestDir, - Vars, Opts) - end, Scripts). - -subst_src_script(Script, SrcDir, DestDir, Vars, Opts) -> - subst_file(filename:join([SrcDir, Script ++ ".src"]), - filename:join([DestDir, Script]), - Vars, Opts). - -subst_file(Src, Dest, Vars, Opts) -> - {ok, Conts} = read_txt_file(Src), - NConts = subst(Conts, Vars), - write_file(Dest, NConts), - case lists:member(preserve, Opts) of - true -> - {ok, FileInfo} = file:read_file_info(Src), - file:write_file_info(Dest, FileInfo); - false -> - ok - end. - -%% subst(Str, Vars) -%% Vars = [{Var, Val}] -%% Var = Val = string() -%% Substitute all occurrences of %Var% for Val in Str, using the list -%% of variables in Vars. -%% -subst(Str, Vars) -> - subst(Str, Vars, []). - -subst([$%, C| Rest], Vars, Result) when $A =< C, C =< $Z -> - subst_var([C| Rest], Vars, Result, []); -subst([$%, C| Rest], Vars, Result) when $a =< C, C =< $z -> - subst_var([C| Rest], Vars, Result, []); -subst([$%, C| Rest], Vars, Result) when C == $_ -> - subst_var([C| Rest], Vars, Result, []); -subst([C| Rest], Vars, Result) -> - subst(Rest, Vars, [C| Result]); -subst([], _Vars, Result) -> - lists:reverse(Result). - -subst_var([$%| Rest], Vars, Result, VarAcc) -> - Key = lists:reverse(VarAcc), - case lists:keysearch(Key, 1, Vars) of - {value, {Key, Value}} -> - subst(Rest, Vars, lists:reverse(Value, Result)); - false -> - subst(Rest, Vars, [$%| VarAcc ++ [$%| Result]]) - end; -subst_var([C| Rest], Vars, Result, VarAcc) -> - subst_var(Rest, Vars, Result, [C| VarAcc]); -subst_var([], Vars, Result, VarAcc) -> - subst([], Vars, [VarAcc ++ [$%| Result]]). - -copy_file(Src, Dest) -> - copy_file(Src, Dest, []). - -copy_file(Src, Dest, Opts) -> - {ok, InFd} = file:open(Src, [raw, binary, read]), - {ok, OutFd} = file:open(Dest, [raw, binary, write]), - do_copy_file(InFd, OutFd), - file:close(InFd), - file:close(OutFd), - case lists:member(preserve, Opts) of - true -> - {ok, FileInfo} = file:read_file_info(Src), - file:write_file_info(Dest, FileInfo); - false -> - ok - end. - -do_copy_file(InFd, OutFd) -> - case file:read(InFd, ?BUFSIZE) of - {ok, Bin} -> - file:write(OutFd, Bin), - do_copy_file(InFd, OutFd); - eof -> - ok - end. - -write_file(FName, Conts) -> - {ok, Fd} = file:open(FName, [write]), - file:write(Fd, Conts), - file:close(Fd). - -read_txt_file(File) -> - {ok, Bin} = file:read_file(File), - {ok, binary_to_list(Bin)}. - -remove_dir_tree(Dir) -> - remove_all_files(".", [Dir]). - -remove_all_files(Dir, Files) -> - lists:foreach(fun(File) -> - FilePath = filename:join([Dir, File]), - {ok, FileInfo} = file:read_file_info(FilePath), - case FileInfo#file_info.type of - directory -> - {ok, DirFiles} = file:list_dir(FilePath), - remove_all_files(FilePath, DirFiles), - file:del_dir(FilePath); - _ -> - file:delete(FilePath) - end - end, Files). - ]]></code> - </section> -</chapter> - |