the elj projectOpen Source Eiffel Libraries and Applications(SmartEiffel and ISE Eiffel) |
Building ELJIntroductionThis page describes how to build ELJ's systems. For the simple cases like a 'hello world' example it basically means to compile it. But ELJ's built system allows you as well to build more complex examples which involves more tasks than simply compiling the code. The build process cannot only be executed on the individual systems but on higher levels as well. This makes it possible for example to build all wxEiffel examples by starting the build process in the directory 'examples/ifs/ewxw' or even for everything in ELJ by starting the build process in the top level directories. ELJ's build process relies on the Gobo tools 'geant' and 'gexace'. Geant is a build tool similar to 'make' and more similar to Jakarta's 'ant' for Java. Gexace is a tool which makes it possible to write (x)ace files which are extended ace files suitable for all Eiffel compiler. Xace files make it also possible to modularize and reuse other xace files which is not possible with standard ace files. For more info see Gobo's project page which soon will have documentation about these new tools. Contact InfoIf you have questions regarding the build process contact the ELJ users list You can find the ELJ project page here. PrerequisitesYou can download the latest version of the ELJ library package here. Download and install the package of your choice and you should be ready to go. You must have:
For this description we assume you have a basic knowledge of 'geant' and 'gexace'. If this is not the case you might want to check out the examples for these tools coming with the Gobo package. TutorialI'll take the example based way to explain how to build systems within ELJ. As we have seen in the past (first when we had the 'elj.bat' files and even after that with the first eant files) most of the times those files looked very similar. But if something changed over time it had to be changed in all of the 'elj.bat' files respectively all eant file. Since geant provide an object oriented way to setup build scripts the new files will make use of inheritance if it makes sense. And it makes sense in almost any case. A simple build scriptLet's have a look at the simple example 'examples/base/gc/build.eant':
<?xml version="1.0"?> <project name="base_gc_example" default="help"> <description> description: "Eiffel Ant file for 'elj-2002'" system: "elj-2002" copyright: "Copyright (c) 2002, Sven Ehrke and others" license: "Eiffel Forum Freeware License v1 (see forum.txt)" date: "$Date: 2003/06/16 16:32:08 $" revision: "$Revision: 1.2 $" </description> <inherit> <parent location="${ELJ}/eant/elj-eiffel.eant"> <redefine target="init"/> </parent> </inherit> <!-- Implementation --> <target name="init"> <precursor/> <set name="system" value="example"/> </target> </project> As you can see there's not a lot in it. The first thing to remark is that it inherits from '${ELJ}/eant/elj-eiffel.eant'. The second thing is target 'init' which first calls it's precursor and then defines the name of the system. And in fact this example demonstrates quite well what we wanted to achieve: reuse the general things (provided through the inheritance from 'elj-eiffel.eant' and redefining the things which change: the name of the system to be built. To compile this program simply invoke the command 'geant compile' on the commandline and you will end up with a file 'example.exe'. Of course so far it is not clear how this all works but you will see how it works when we have a deeper look into 'elj-eiffel.eant'. So, what's remarkable here? Every wxEiffel application needs an instance of the WX_APP class created and initialized. The initialization routine must be passed as an agent to the WX_APP object and must return TRUE to let the message dispatcher loop start its task. If you let the routine return FALSE, the application control flow reaches the point after 'create app' immediately, otherwise the application runs until the top level frame is closed and then reaches the point after creating the application object.A standard WX_FRAME is not visible unless you show it with the 'show' routine of the WX_WINDOW class and no window is the top window unless you tell the application object which one is the chosen one. elj-eiffel.eantThis is the build script from which all build scripts for examples, tools and so on inherit from. It contains various targets for initialization, compilation, and generation of ace files. Don't be overwhelmed by it's size: the good new is that you just have to inherit from it and reproduce it for every system you are creating. <?xml version="1.0"?> <project name="elj-eiffel"> <description> description: "Eiffel Ant file for 'elj-2002'" system: "elj-2002" copyright: "Copyright (c) 2002, Sven Ehrke and others" license: "Eiffel Forum Freeware License v1 (see forum.txt)" date: "$Date: 2003/06/16 16:32:08 $" revision: "$Revision: 1.2 $" </description> <target name="help"> <echo message="usage:"/> <echo message=" geant compile -- default version as configured in target 'init'"/> <echo message=" geant compile_boost -- english 'boost' version"/> <echo message=" geant compile_assert -- english version, all assertions enabled"/> <echo message=" geant compile_trace -- debugger version"/> <echo message=" geant compile_boehm -- 'boost' version with BDW gc"/> <echo message=" geant clean -- remove intermediary generated files"/> <echo message=" geant clobber -- remove all generated files"/> </target> <target name="clean" depend="init"> <description> Remove intermediary generated files. </description> <se clean="${system}"/> <delete file="se.ace"/> </target> <target name="clobber" depend="init"> <description> Remove all generated files. </description> <geant target="clean"/> <delete file="se.ace"/> <delete file="${system}${exe}"/> <delete file="eiffel.out"/> <delete file="eiffel.err"/> </target> <target name="generate" depend="init"> <description> Compile '${system}' with SmallEiffel. Compile in debug mode if ${debug} is defined. </description> <set name="gexace_output" value="se.ace"/> <geant target="xace"/> <delete file="${system}${exe}"/> <se ace="se.ace"/> </target> <target name="compile" depend="init"> <description> Compile in default mode as configured in target 'init'. </description> <geant target="generate"/> </target> <target name="compile_boost" depend="init"> <description> Compile in boost mode. </description> <geant target="init_boost"/> <geant target="generate"/> </target> <target name="compile_trace" depend="init"> <description> Compile in trace mode. </description> <geant target="init_trace"/> <geant target="generate"/> </target> <target name="compile_assert" depend="init"> <description> Compile in assert mode. </description> <geant target="init_assert"/> <geant target="generate"/> </target> <target name="compile_boehm" depend="init"> <description> Compile in assert + boehm mode. </description> <geant target="init_boehm"/> <geant target="generate"/> </target> <!-- Implementation --> <target name="xace" depend="init"> <description> Build SmallEiffel Ace file. Generate file in ${gexace_output} if specified. Pass $DEBUG option to 'gexace' if ${debug} is defined. Pass $GOBO_OS value to 'gexace'. Pass $GOBO_CC value to 'gexace' if defined. To be redefined in descendant if additional options are necessary. </description> <set name="gexace_output" value="" unless="${gexace_output}"/> <gexace system="se" output="${gexace_output}" xace="${system_dir}/system.xace"> <define name="BOOST" value="${boost}" if="${boost}"/> <define name="ASSERT" value="${assert}" if="${assert}"/> <define name="TRACE" value="${trace}" if="${trace}"/> <define name="BETA" value="${beta}" if="${beta}"/> <define name="WINDOWS_FINAL" value="${final}" if="${final}"/> <define name="LANGUAGE" value="${language}"/> <define name="BOEHM" value="${boehm}" if="${boehm}"/> <define name="GOBO_OS" value="${GOBO_OS}"/> <define name="GOBO_CC" value="${GOBO_CC}" if="${GOBO_CC}"/> <define name="SYSTEM" value="${system}"/> </gexace> </target> <target name="init"> <description> Initialize variables and prepare system to start build. </description> <set name="language" value="en"/> <set name="system_dir" value="."/> <set name="system" value="system_name_to_be_defined_in_heir"/> <echo message="${cwd}"/> <geant target="init_boost"/> </target> <target name="init_trace"> <description> Initialize variables for 'trace' build (trace=true). </description> <set name="trace" value="true"/> <unset name="boost"/> </target> <target name="init_assert"> <description> Initialize variables for 'assert' build (assert=true). </description> <set name="assert" value="true"/> <unset name="boost"/> </target> <target name="init_boost"> <description> Initialize variables for 'boost' build (boost=true). </description> <unset name="assert"/> <set name="boost" value="true"/> </target> <target name="init_boehm"> <description> Initialize variables for 'boehm' build (assert=true, boehm=true). </description> <unset name="boost"/> <set name="assert" value="true"/> <set name="boehm" value="true"/> </target> </project>
'elj-eiffel.eant' consists of various targets to compile the system: compile, compile_boost,
compile_trace, compile_assert and compile_boehm. When we look at the code above it get's clear that when we invoked 'geant compile' the target 'compile' of 'elj-eiffel.eant' got invoked. That in turn invokes target 'init' (through the attribute 'depend') to set up some default variables and then calls target 'generate' to generate the SmallEiffel ace file from the provided xace file and finally invokes the SmallEiffel compiler. Now if you remember that our simple example redefines target 'init' you recognize now that instead of 'elj-eiffel.eant''s 'init' now target 'init' of our simple example is called by the attribute 'depend' of 'elj-eiffel.eant''s 'compile target. If you have the impression that this is complex simply think of eant files as if they were classes of an object oriented system and the targets are the individual routines of that class. Most of the OO concepts available in Eiffel apply to eant files as well, even multiple inheritance. The target 'init' of our simple example did call it's precursor first so that the default settings are applied and then sets the name of the system which usually is different from system to system. But in this target you can also change the default mode by simply invoking another 'init_*' target: <target name="init"> <precursor/> <geant target="init_assert"/> <set name="system" value="example"/> </target> The default mode is applied when we call 'geant compile'. This is also important to know since the build process spanning over several systems (or all of ELJ) later will invoke this target. elj-wxeiffel.eantTo build wxEiffel examples there exists a special eant script: 'elj-2000/eant/elj-wxweiffel.eant' which inherits from elj-eiffel.eant': <?xml version="1.0"?> <project name="elj-wxeiffel"> <description> description: "Eiffel Ant file for 'elj-2002'" system: "elj-2002" copyright: "Copyright (c) 2002, Sven Ehrke and others" license: "Eiffel Forum Freeware License v1 (see forum.txt)" date: "$Date: 2003/06/16 16:32:08 $" revision: "$Revision: 1.2 $" </description> <inherit> <parent location="${ELJ}/eant/elj-eiffel.eant"> <redefine target="help"/> <redefine target="init"/> </parent> </inherit> <target name="help"> <precursor/> <echo message=" geant compile_beta -- assertion level require, no optimizations"/> <echo message=" geant compile_final -- boost version, without console window"/> </target> <target name="compile_beta" depend="init"> <description> Compile in beta mode (beta=true, final=true). </description> <geant target="init_beta"/> <geant target="generate"/> </target> <target name="compile_final" depend="init"> <description> Compile in final mode (boost=true, final=true). </description> <geant target="init_final"/> <geant target="generate"/> </target> <!-- Implementation --> <target name="init"> <description> Initialize variables and prepare system to start build. </description> <precursor/> <geant target="init_beta"/> </target> <target name="init_beta"> <description> Initialize variables for 'beta' build (beta=true, final=true). </description> <set name="beta" value="true"/> <set name="final" value="true"/> <unset name="boost"/> </target> <target name="init_final"> <description> Initialize variables for 'final' build (boost=true, final=true). </description> <set name="boost" value="true"/> <set name="final" value="true"/> <unset name="beta"/> <unset name="assert"/> <unset name="trace"/> </target> </project> As you can see it simply adds the targets compile_beta and compile_final as these have a special meaning to wxEiffel systems. Of course the 'help' target reflects this and the according 'init_*' targets are provided as well. It's also worth to note that 'init' has been redefined and calls target 'init_beta' which is therefore the default mode for wxEiffel systems. wxEiffel systems' build file now simply inherit from 'elj-wxeiffel.eant'. Here is the example from 'examples/ifs/ewxw/dc': <?xml version="1.0"?> <project name="example" default="help"> <description> description: "Eiffel Ant file for 'elj-2002'" system: "elj-2002" copyright: "Copyright (c) 2002, Sven Ehrke and others" license: "Eiffel Forum Freeware License v1 (see forum.txt)" date: "$Date: 2003/06/16 16:32:08 $" revision: "$Revision: 1.2 $" </description> <inherit> <parent location="${ELJ}/eant/elj-wxeiffel.eant"> <redefine target="init"/> </parent> </inherit> <!-- Implementation --> <target name="init"> <precursor/> <set name="system" value="example"/> <!-- override default mode if desired: <geant target="init_final"/> --> </target> </project> Building Clustersmore too come... More InfoThis is the end of our description into ELJ's build system. For further informations, you should take a deep look into Gobo's eant/xace examples and into Gobo's build system itself. With release of Gobo 3.1 there will also be official documentation about these tools which still is missing. |
|
``.. in open source, software lives on if there are enough believers to keep it alive ..'' (WSJ - 20 Jul 2003) |
http://elj.sourceforge.net/docs/build
Dec 04, 2003, 00:26 UTC