interfacing to the amiga system with the v39 modules
To use any other library than the five in the previous section, you'll
need to resort to modules. Also, if you wish to use some OBJECT or CONST
definition from the Amiga includes as is usual in C or assembler,
you'll need modules. Mod()ules are binary files which may include constant,
object, library and function (code) definitions. The fact that they're
binary has the advantage over ascii (as in C and assembly), that they
need not be compiled over and over again, each time your program is
compiled. The disadvantage is that they cannot simply be viewed; they
need a utility like ShowMod()ule to make their contents visible. The modules
that contain the library definitions (i.e the calls) are in the root of
emodules: (the modules dir in the distribution), the constant/object
definitions are in the subdirectories, structured just like the originals
syntax: MODULE ,...
Loads a module. A module is a binary file containing information on libraries,
constants, and sometimes functions. Using modules enables you to use
libraries and functions previously unknown to the compiler.
Now for an example, below is a short version of the source/examples/asldemo.e
source that uses modules to put up a filerequester from the 2.0 Asl.library.
MODULE 'Asl', 'libraries/Asl'
DEF req:PTR TO filerequester
IF RequestFile(req) THEN WriteF()('File: "\s" in
From the modules 'asl', the compiler takes asl-function definitions like
RequestFile(), and the global variable 'aslbase', which only needs to
be initialised by the programmer. From 'libraries/Asl', it takes
the definition of the filerequester object, which we use to read the
file the user picked. Well, that wasn't all that hard: did you think
it was that easy to program a filerequester in E?
compiling own modules
with v3, you can gather all PROCs, CONSTs, OBJECTs and to
some extent also global variables that you feel somehow belong
together in one source, write "OPT MODULE" to signal EC that
this is supposed to be a module, and then compile all to a
.m file to be used in the main program, just like you used to
do with the old modules.
by default, all elements in a module are PRIVATE, i.e. not accessable
to the code that imports the .m file. to show which elememts
you wish to be visible in the module, simply write EXPORT
EXPORT ENUM TESTING,ONE,TWO,THREE,FOUR
EXPORT DEF important_glob_var, bla:PTR TO x
EXPORT OBJECT x
next, index, term
EXPORT PROC burp()
/* whatever */
"EXPORT" is useful in making a distinction between private and
public, especially when all functions of an OBJECT can be accessed
via PROCs, you may wish to keep OBJECT private as an effective
method of data hiding.
[EXPORT can be written on any line, doesn't affect everything though.]
If in a module _all_ elememts need to be exported (for example
one with only constants), a 'OPT EXPORT' will export all, without
the need for individual EXPORT keywords.
global variables require extra attention:
- try to avoid lots of global variables. having lot of globals
in modules makes projects messy and error-prone
- globs in a module cannot have initialisations directly
in the DEF statement (reason for this will become clear
below). for example:
DEF a not DEF a=1
DEF a:PTR TO x not DEF a:ARRAY OF x
- globals in a module which are not exported function as
local for the module, i.e. they'll never clash with globals
in other modules. those who _are_ exported though, are
combined with the others, i.e. if in both the main program
and in a module a variable with the same name are used,
this will be one and the same variable. that's why
one can write DEF a:ARRAY OF x in the main program,
and EXPORT DEF a:PTR TO x in the module, to share the
array. Also, if both use for example 'gadtools.m',
only one of the two needs to initialise 'gadtoolsbase'
for both to be able to make calls to the library.
If you do not want librarybases to be shared (i.e. you
want to have a local, private library base), simply
redeclare it in a DEF in the module that is not EXPORTed.
If you export a variable in a general purpose
module, make sure to give it a pretty unique name.
- using globals in modules which provide general purpose
datatypes needs special attention, as the module may be
in use from more than one other module, in which case
it may be unclear who is responsable for resources.
take good care of this.
Using modules in modules
This requires little extra attention. If the module (B) you include
in your own module (A) is one that only declares CONSTs, LIBRARYs and
OBJECTs (without code) nothing special happens, however if B includes
PROCs, then it's obvious this code needs to be linked later to the
main program when A is linked. Therefore if a main program uses A,
B will need to be present for compilation. The fact that A needs
B is stored in A, and can be viewed with ShowMod()ule. This chain
of uses may grow out to a tree of dependencies, which has the result
that if you use just one module in your program, a lot of others
are automatically linked to it. Thus, E's module system automatically
keeps track of dependancies that other languages need makefiles for.
EC also allows for circular inclusions, and loads/links modules at most
once (i.e. doesn't link unused modules). One thing E's module system
doesn't automatically do for you is recompile dependant modules. If
you change B, it is often necessary to recompile A too, since it
might be referring to offsets etc. in the old version of B, which
might cause code to crash. If this gets too complex in your project,
use a utility such as E-Build.
Try out the new ShowMod()ule to see what EC puts in modules.
Including modules from other directories.
By default, a module name is prefixed by 'emodules:' to obtain
the actual file. Now you can prefix the name with a '*' to
denote the directory the source is in, so:
MODULE 'bla', '*bla'
if this statement would be in source 'WORK:E/burp.e', these two
modules would be 'emodules:bla.m' and 'WORK:E/bla.m'.
This is naturally the way to include components of your app into
other parts. If you write modules that you use in many of your programs
it would be handy to store them in the emodules hierarchy, and the
place for this is the 'emodules:other/' dir.