CONTENTS | PREV | NEXT
10C. 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. more on this topic, (see 14C )
[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 global variables. having lots of globals
in modules makes projects messy and error-prone
- globals 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 that is not EXPORTed in the module.
If you export a variable in a general purpose
module, make sure to give it a pretty unique name.
variables are combined in the main program, if you want to
reference an exported variable from another module,
you will have to export it there too.
- 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 ShowModule. 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 (see 17I ).
Try out the new ShowModule (see 17A ) 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.
When writing sets of own modules, one should try to avoid
circular dependancies (EC does not enforce this), as in some
cases this can result in chicken and egg problems (you can't
recompile everything from scratch, you always need atleast
one readily compiled module).