This document provides an overview of the C-Eiffel Call-In Library (CECIL) as defined in Eiffel: The Language (ETL). The first section adresses how to compile and run a CECIL program. The second part contains a more precise description of the Eiffel types, the protection mechanism as well as how to write and use C externals.
CECIL , designed by ISE, is the C library that permits C and C++ applications (as well as applications written in other languages) to take advantage of almost all Eiffel facilities: create Eiffel objects, apply features to them. The basics of CECIL are described in chapter 24 of the reference book on Eiffel, Eiffel: The Language, which covers interfaces between Eiffel and other languages. Important material can also be found in the ISE manual Eiffel: The Environment and on ISE's FTP server. In particular, the FTP server contains a complete example which you are strongly encouraged to download if you plan to make serious use of CECIL. You can find the examples in
The present document complement the descriptions of Eiffel: The Language. Note that CECIL has been revised and improved since that book was published, so the explanations below have precedence over those of the book.
This document is intended for both Windows and Unix users. Only a few of the sections, clearly marked, are platform-specific.
Once unzipped, the example directory cited above will yield (apart from a README containing the same material as the present document) two subdirectories: unix-examples and windows-examples. Each contains a full example, adapted to each platform and illustrating the use of CECIL. Please study it carefully and use it as a model.
This document is regularly completed. There are many remarks concerning the modifications made in the ISE Eiffel compiler 4.3. Particularly, some CECIL feature names have changed to match the naming conventions, this imply some changes in the C examples if you are using earlier versions (read carefully the comments for the modifications to make). However, the previous feature names are still valid in v4.3. Every eiffel feature is given with the include file from $EIFFEL4/bench/spec/$PLATFORM/include where it is declared. When compiling a CECIL example with one of these features, you do not need to include them, provided that you include `eif_eiffel.h' (for all the cecil features) and `eif_setup.h' (for the run-time initialization and reclaim).
For step 1, note that through CECIL you can use an Eiffel system
compiled in any of the Eiffel compilation modes:
$ applied to melted routineThe solution is simply to refreeze the system.
To do this, include the appropriate features and classes in the visible clause of the Ace file, as in
system system_name root ... default ... cluster ... your_cluster: "..." adapt ... visible CLASS1; CLASS2 creation "other_make" export "feat1", "feat2" end end ... Other clusters ... ... endHere all features of CLASS1 are available to the external software; for CLASS2, only other_make (for creation) and feat1 and feat2 (for normal call) are available. For the full set of visible options, see appendix D of Eiffel: The Language. If you omit the clause export , only the features with no export clause in the Eiffel code, will be available. The creation procedure of a visible class is always available in the version 4.3 of the compiler. It will not be with the version 4.2 if it is in an exporting clause. See also visible classes
To produce a CECIL library, you must: open a shell (unix) or the MS-DOS prompt (Windows), go to the subdirectory that contains the Makefile, and then type:
This generates a CECIL archive whose name derived from the name
<system nameof the Eiffel system, as follows:
You can build a CECIL archive with either the "finalized" C code or "frozen" C code. In the latter case you must copy the "melted.eif" file located in $/EIFGEN/W_code/<system name>.melted ($/EIFGEN/W_code/melted.eif with the ISE compiler 4.3 and later) to the directory from where you intend to execute your C application . Each time you melt the Eiffel system, the <system name>.melted (melted.eif) file updates. Note: Calling melted routines through the CECIL interface is not supported in the current version - calling a melted routine raises the exception "$ applied to melted routine".
cc [your C files object files and archives] lib<system name>.a -lm (on Unix)
Note:linking with "-lm" is required since the Eiffel 4 run-time uses the standard math libraries.You may need to link with other libraries (for example, on linux: with "-lbsd", in MT mode with "-lpthread" (posix threads) or "-lthread" (solaris)) .
On Windows, go to the appropriate directory (W_code or
F_code) and locate the file:
assuming that the main.obj object file is in the project
directory; update the above path if it is in another directory.
Then, link with:
Notes for compiling
CECIL C files:
Typically, you will compile your flags as below:
gcc -c -O -I$EIFFEL4/bench/spec/$PLATFORM/include -I<SOME_INCLUDE_PATH>
-D<SOME_FLAGS> your_file.c
or
cl -c -nologo -Ox -I<INSTALLATION_DIR>\bench\spec\windows\include
-I<SOME_INCLUDE_PATH> -D<SOME_FLAGS> your_file.c
For instance, if you want to use the multithreaded facilities of Eiffel,
you should define the EIFFEL MT flags.
gcc -c -O -I$EIFFEL4/bench/spec/$PLATFORM/include -DEIF_THREADS -DSOLARIS_THREADS
-D_REENTRANT your_file.c
or
cl -c -nologo -DEIF_THREADS -MT -Ox -I<INSTALLATION_DIR>\bench\spec\windows\include
your_file.c
Since v4.3, you can specify a Makefile in your Ace file, so that your
C files will be compiled automatically after the Eiffel compilation and
before the final linking. Just add at the end of your Ace file in the external
clause:
external:
This makefile will be run from the $/EIFGEN/W_code or $/EIFGEN/F_code
directory. You should not give to the CECIL executable the same name as
your system, because it will be replaced by the Eiffel executable when
you run another compilation.
<system_name>.lnk
To have a Cecilized version (that is to say, a
version usable from external software ) you should:
- Copy system_name.lnk into a new file cecil.lnk in the same directory.
- Edit the file cecil.lnk and replace the option:
-SUBSYSTEM:WINDOWS
by
-SUBSYSTEM:CONSOLE
To use the current MS-DOS shell as the default console. (On v4.3, this is done with ace option "console_application (yes)")
- and replace the line:
e1\emain.obj
by
..\..\main.obj
link @cecil.lnk
(in the appropriate directory W_code or F_code)
The CECIL library is built automatically, which is unfortunately not
the case of the corresponding object files of the cecil program you
wrote.
The C flags to use are usually the same as the ones needed during the
compilation of the generated C-code plus those, which are relevant to your
own C-code.
(if your are compiling with gcc on a Solaris).
(if you are using VC on Windows. <INSTALLATION_DIR> is the
installation directory of your Eiffel delivery: C:\Eiffel4, for
example).
make: "$PATH_TO_MAKEFILE/your_makefile";
Back to index
In the C file containing the "main" C function, you must add the following
line to include the header file "eif_setup.h" provided with this example:
#include "eif_setup.h" /* Macros EIF_INITIALIZE and EIF_DISPOSE_ALL
*/
#include "eif_eiffel.h" /* Exported functions of the Eiffel run-time
*/
Your "main" function must have the three standard arguments of the C
"main" function" "argc", "argv" and "envp" and include the following macros
that are defined in "eif_setup.h":
main(int argc, char **argv, char **envp)
EIF_INITIALIZE(failure)
/* ...
EIF_DISPOSE_ALL
/* Please, respect this
signature: `argc', `argv' and `envp' are used
* in EIF_INITIALIZE.
*/
{
/* declarations of variables */
/* Initialize the Eiffel run-time. */
* body of your "main" function
*
... */
/* Reclaim the memory allocated by the Eiffel
* run-time. */
}
See the cecil examples on ftp://ftp.eiffel.com/examples/cecil.
Note that the above mentioned macros must imperatively be in the body
of the "main" function for the Eiffel 4 exception handling mechanism to
work correctly.
You also need to add the Eiffel 4 run time directory to the list of
directories in which the C compiler searches for include files. You can
do so by using the "-I" option of your C compiler.
See also Linking the CECIL archive into a program.
An Eiffel INTEGER is an EIF_INTEGER,
An Eiffel CHARACTER is an EIF_CHARACTER,
An Eiffel REAL is an EIF_REAL,
An Eiffel DOUBLE is an EIF_DOUBLE,
Eiffel references (any Eiffel objects, which is not from a basic type)
are EIF_REFERENCE (not protected, and can be moved),
An Eiffel POINTER is an EIF_POINTER,
An Eiffel BOOLEAN is an EIF_BOOLEAN,
An Protected Eiffel objects is an EIF_OBJECT since v4.3 and an EIF_OBJ
until v4.2(do not move, and should be access through eif_access.).
EIF_OBJ
is
obsolete in v4.3, but still valid.
Generally, you need to use these types when implementing external C
functions bound to be used from Eiffel or when you want to manipulate Eiffel
objects from the C side. EIF_REFERENCE, EIF_OBJECT/EIF_OBJ, EIF_POINTER
all correspond in C to a (char *), but their semantic remains different
in Eiffel.
Example:
c_foo (ptr: POINTER; obj: OBJECT): INTEGER is
external
"C | %"your_file.h%""
alias
"foo"
end
In the C side, The C function `foo' is defined as below:
EIF_INTEGER foo (EIF_POINTER
ptr, EIF_OBJECT obj) /* replace EIF_OBJECT by EIF_OBJ
on v4.2 */
{
/* some code */
}
On the C side, foo is already defined as below:
int foo (void *arg1,
char c, FILE *file)
To match the signature, you must declare it in Eiffel as:
{
/* some code */
}
c_foo (arg1: POINTER; c: CHARACTER; file: POINTER): INTEGER is
To perform the conversion, here is the actual Eiffel types mapping to C types:
An EIF_REFERENCE is an Eiffel reference. It corresponds to an Eiffel object in the Eiffel side. eif_field, eif_reference_function/eif_fn_ref , RTMS and eif_make_string/makestr, eif_wean all return an EIF_REFERENCE. An EIF_REFERENCE can be used "as is" by the Eiffel run-time. eif_field, eif_xx_function/eif_fn_xx take EIF_REFERENCE as arguments, never EIF_OBJECT. The return value of a C external is to be an EIF_REFERENCE, if it is not a basic expanded type. To protect an EIF_REFERENCE, use eif_protect/henter.
An EIF_OBJECT is a safe and static indirection to an Eiffel reference. As the GC may move an Eiffel reference, this indirection is updated at every collection so that you do not need to know whether an Eiffel reference has moved or not. You must pass through this indirection to access to the Eiffel reference (see eif_access). Not doing it is completely unsafe since an Eiffel reference may be obsolete after a collection. eif_create, eif_adopt, and eif_protect/henter returns an EIF_OBJECT. The argument of a C external (on the C side) , which is not a basic expanded type, is also an EIF_OBJECT . The Eiffel run-time temporarily protects the Eiffel objects that are passed to a C external , that is why the signature of a C external has no EIF_REFERENCE in it, but EIF_OBJECT instead. After the C external call, the run-time unprotects the Eiffel object. If you intend to use in the C side an EIF_OBJECT given by a C external afterwards, you must protect it with eif_adopt. To unprotect an EIF_OBJECT , which is not a C external argument, use eif_wean.
The basic expanded types are INTEGER, REAL, DOUBLE, CHARACTER, BOOLEAN, POINTER. They are passed to C externals by values. There is no need to protect an INTEGER, REAL, DOUBLE, CHARACTER, or a BOOLEAN. When the POINTER is a pointer to an Eiffel object (ex: $my_object ), then the direct Eiffel reference is passed to C, with no protection and this reference may move. Use eif_protect/henter to manually protect it. To unprotect it, call eif_wean
The cecil library provides the user with numorous macros and functions, which relieves the programmer from these kinds of low-level considerations (most of them are declared in $EIFFEL4/bench/spec/$PLATFORM/include/eif_cecil.h).
EIF_REFERENCE eif_access
(EIF_OBJECT object) /* Macro */ (since
v4.3)
EIF_REFERENCE eif_access
(EIF_OBJ object) (until v4.2)
The GC moves the objects every time it runs a collection cycle. A collection cycle can only occur during Eiffel call. This includes: call to Eiffel routines, call to CECIL functions (other than eif_access). Thus, it may be unsafe to use a direct reference to an Eiffel object (EIF_REFERENCE) "as is", since it can be obsolete after each collection. To avoid this, you must access to a direct reference through a "protection", which is a safe, static pointer (EIF_OBJECT (EIF_OBJ in v4.2)). Call the macro eif_access as follows: eif_access (protection) , where protection is either a value returned by eif_create, eif_adopt, eif_protect/henter or an Eiffel object, which is an argument of a C external.
Use eif_access to pass an Eiffel object to an Eiffel routine or to return the value of a C external. It is also unsafe to pass a direct Eiffel reference (EIF_REFERENCE) to a C function, which is not an Eiffel routine. Pass a protected indirection instead (EIF_OBJECT). However, if you still intend to pass a direct reference, be very careful and make sure that you do not perform any Eiffel call after passing the reference to the C function and before reading it.
For example, in the following external:
c_foo (ptr: POINTER; obj: OBJECT): INTEGER is
external
"C | %"your_file.h%""
alias
"foo"
end
the Eiffel run-time will protect obj ,which can asynchronously move, and give a static and safe indirection to C.
Here is an example of how accessing obj: OBJECT:
EIF_INTEGER foo (EIF_POINTER ptr, EIF_OBJECT obj)
/* Replace EIF_OBJECT by EIF_OBJ in v4.2 */
EIF_PROCEDURE ep;
/* Replace EIF_PROCEDURE by EIF_PROC in v4.2 */
tid = eif_type_id ("GENERAL");
{
/* Print the Eiffel object
`obj', with the feature `print'
* from GENERAL.
(do not forget to put `visible' the class
* GENERAL in the
Ace.ace file.
*/
EIF_TYPE_ID tid;
ep = eif_procedure ("print",
tid); /* Call eif_proc in v4.2 instead */
(ep) (eif_access(obj),eif_access(obj));
}
NB: The first argument of (ep) is the target of the function (the eiffel object to which you want to apply the Eiffel feature (ep)) and the second argument corresponds to the first argument of `print'. Note that any Eiffel objects could have been the 1st argument of (ep) since all of them inherit from GENERAL.
Important rules when using eif_access:
EIF_REFERENCE e_ref = eif_access (obj);
...
(ep) (e_ref, e_ref);
because e_ref is the direct reference to the Eiffel object when calling
eif_access().
There
is not guarantee that it will still be valid when the call to
(ep)
is done: meanwhile, e_ref may have been moved by the GC.
(ep) (eif_access (a), RTMS ("Hello world"));
/* RTMS is a macro returning
a direct reference to an Eiffel string,
* which corresponds
to the C string passed as its argument.
*/
The correct code is
EIF_REFERENCE my_string;
/* some code */
my_string = RTMS
("Hello world");
(ep) (eif_access (a),
my_string);
In this case, you do not need to protect `my_string' since the GC is
not likely to be triggered after the call to RTMS
and before
`my_string' is given as argument in (ep) . A collection is triggered
only during Eiffel calls. If an Eiffel call had been performed, you
would have had to use `eif_protect/henter'
(see paragraph 3.2):
EIF_REFERENCE my_string;
/* some code */
EIF_OBJECT i_my_string; /*
EIF_OBJ in v4.2 */
my_string = RTMS ("Hello world");
i_my_string = eif_protect (my_string); /* Protect
`my_string'. Replace eif_protect by henter in v4.2 */
/* Some eiffel calls
*/
(ep) (eif_access (a), eif_access (i_my_string));
eif_wean (i_my_string); /* Release protection.
*/
See also eif_protect/henter.
EIF_OBJECT eif_adopt (EIF_OBJECT
object) (since v4.3)
EIF_OBJ eif_adopt (EIF_OBJ object)
(until
v4.2)
When passing Eiffel objects to C, you may need to keep a reference to them after the C external is called. Since the Eiffel run-time automatically unprotects the Eiffel objects references passed to a C external after execution. If one of the Eiffel objects is not referenced any longer from Eiffel, then the garbage collector will collect it because it is not aware that you may still need to reference this object from the C side.
Called within a C external, the function eif_adopt creates a user protection for the Eiffel object object passed to C (object is a C external argument). This way, the GC cannot collect the Eiffel reference returned by eif_access(object) when the C external returned. It tells the GC to keep artificially a reference to this Eiffel reference from C. It returns the new indirection pointer (say returned_value) that must be used afterwards to access to this direct Eiffel reference with eif_access (return_value). It is important to note that eif_adopt already takes an indirection pointer as unique argument . This is a temporary protection pointer: you can access the direct Eiffel reference with eif_access (object). only within the code of the C external. When the C external returned, eif_access (object) is NULL but eif_access (returned_value) remains valid until you release it with `eif_wean'.
See also eif_access, eif_protect/henter, eif_create, More about Eiffel types.
Example:
In Eiffel:
c_foo (ptr: POINTER; obj: OBJECT): INTEGER is
c_display_and_release_obj is
external
"C | %"your_file.h%""
alias
"foo"
end
external
"C | %"your_file.h%""
alias
"display_and_release_obj"
end
On the C side:
EIF_OBJECT my_obj; /* Protection
of the object of type OBJECT. Declare an EIF_OBJ in v4.2*/
EIF_INTEGER foo (EIF_POINTER ptr, EIF_OBJ obj)
my_obj = eif_adopt (obj); /* Keeping a reference on it for
/* some code */
EIF_PROCEDURE ep; /* EIF_PROC in v4.2 */
tid = eif_type_id ("OBJECT");
{
* for later use.
*/
}
void display_and_release_obj (void)
{
/* Display global object. */
EIF_TYPE_ID tid;
ep = eif_procedure ("print", tid); /* Call eif_proc in
v4.2 instead*/
(ep) (eif_access(my_obj),eif_access(my_obj)); /* Print global object.*/
eif_wean (my_obj); /* Remove the protection on global object.*/
}
Between the call of `c_foo' and `c_display_obj', the global object (eif_access (my_obj)) may not be referenced from Eiffel any longer. To prevent the GC from collecting it before the call to `c_display_and_release_obj', you must protect it with `eif_adopt' in the C function `foo'.
EIF_OBJECT eif_create ( EIF_TYPE_ID type_id)
All CECIL calls are not completed using C external. It is possible to create and manipulate Eiffel objects from a C program and still reap benefits from the garbage collector and design by contract methodology provided by Eiffel (see also How to run a CECIL program ). This function does not call any creation procedure.
The CECIL function eif_create takes a type identifier type_id as argument (generally returned by eif_type_id). It returns a static indirection pointer which is to be used afterwards to access to the newly created Eiffel object with eif_access (returned_value) where returned_value is the value returned by eif_create . This means that when creating an eiffel object from C, the eiffel object is automatically protected: there is no need to call eif_adopt or eif_protect/henter on it. This function does not call any creation procedure. To do so, you need to explicitly call it with eif_procedure/eif_proc. The garbage collector will not collect the newly created object until you call eif_wean on it.
See also More about Eiffel types.
Example:
Creating an object of type "OBJECT":
#include eif_setup.h" /* for EIF_INITIALIZE and EIF_DISPOSE_ALL */
main (int argc,char **argv,char **envp)
EIF_INITIALIZE(failure) /* Initialization of Eiffel run-time.
tid = eif_type_id ("OBJECT");
my_obj = eif_create (tid); /* Create eiffel object, returns an indirection.
*/
EIF_DISPOSE_ALL /* Reclaim memory allocated by Eiffel run-time. */
#include "eif_eiffel.h" /* for other exported routines from the
Eiffel run-time */
{
EIF_TYPE_ID tid;
EIF_OBJECT my_obj; /* Declare an EIF_OBJ in v4.2
instead */
* This is to be done before any CECIL call.
*/
if (tid == EIF_NO_TYPE)
eif_panic ("No type id.");
/* some code */
eif_wean (my_obj); /* We do not need it any more. */
}
Note: `eif_create' does not call any creation procedure. It just
allocates
memory and initializes an object.
EIF_OBJ henter (EIF_REFERENCE object)
(until
v4.2)
EIF_OBJECT eif_protect (EIF_REFERENCE
object) (since v4.3)
This function is used to tell explicitely the GC that you want to keep a reference to an eiffel object from the C. It returns a static indirection pointer which is to be used afterwards to access to the direct Eiffel reference object with eif_access (returned_value) where returned_value is the value returned by eif_protect (henter in v4.2) . With this call, the GC artificially references object, so that it cannot collect it. It is unsafe to access directly (i.e without using eif_access) to the Eiffel reference object, which may be obsolete after any collection cycle (the GC moves the objects). Ignore this rule, if you are sure that there is no Eiffel call after you pass the direct Eiffel reference to a C function and before you read it.
To release this articifial reference, call eif_wean (returned_value)
eif_protect/henter is to be called on an EIF_REFERENCE returned by eif_field, RTMS and eif_make_string/makestr, or the returned value of eif_reference_function.
See also eif_adopt, eif_create, eif_wean, eif_access. More about Eiffel types.
Example: Assume that you
want to access to an attribute `tab' of type ARRAY [INTEGER] in
the class OBJECT.
#include eif_setup.h"
main (int argc,char **argv,char **envp)
EIF_INITIALIZE(failure)
tid = eif_type_id ("OBJECT");
my_obj = eif_create (tid);
/* some code */
eif_wean (my_obj);
EIF_DISPOSE_ALL /* Reclaim memory allocated by Eiffel run-time. */
#include "eif_eiffel.h"
{
EIF_TYPE_ID tid;
EIF_OBJECT my_obj; /* Declare an EIF_OBJ in v4.2
*/
EIF_PROCEDURE emake; /* Creation procedure of "OBJECT". Declare
an EIF_PROC in v4.2 instead*/
EIF_REFERENCE tab; /* direct reference to `tab' from "OBJECT". */
EIF_OBJECT i_tab; /* Protected indirection to `tab'. Declare an
EIF_OBJ in v4.2 */
if (tid == EIF_NO_TYPE)
eif_panic ("No type Id.");
emake = eif_procedure ("make", tid); /* On the eiffel side: make
is do ... end.. Use eif_proc instead in v4.2*/
(emake) (eif_access (my_obj)); /* Call `make' on `eif_access(my_obj)'.*/
tab = eif_field( eif_access (my_obj), "tab", EIF_REFERENCE);
/* Return the attribute `tab' of type EIF_REFERENCE
* of the object `eif_access (my_obj)'.
*/
i_tab = eif_protect (tab); /* Here, protect `tab' . Use henter instead
in v4.2*/
eif_wean (i_tab); /* We do not need it any more. */
}
Note: Although you must protect Eiffel references returned by eif_field. You must not protect attributes of basic types - they are not Eiffel references and not supposed to move.
EIF_TYPE_ID eif_type_id (char *type_string)
Returns the type identifier corresponding to the type described in type_string. If the type does not exists , is not visible or an instance of it is not declared in the root class (see visible classes), it returns EIF_NO_TYPE.
Example: type_id of STD_FILES so
as to call 'put_string'.
EIF_PROCEDURE p_put_string;
/* 'put_string' from STD_FILES. Declare an EIF_PROC in v4.2 */
tid = eif_type_id ("STD_FILES");
EIF_TYPE_ID tid;
EIF_REFERENCE_FUNCTION fn_io;
/* once function `io' from GENERAL (and STD_FILES by inheritance). Declare
an EIF_FN_REF instead in v4.2 */
EIF_REFERENCE o_io; /* Eiffel
object `io' returned by once function*/
EIF_REFERENCE o_str;
/* Eiffel string */
EIF_OBJECT i_io, i_str; /*
safe indirection pointers to ``io' and Eiffel string. Declare an EIF_OBJ
in v4.2 */
if (tid == EIF_NO_TYPE)
eif_panic ("Type not
in system.");
fn_io = eif_fn_ref ("io", tid);
o_io = (fn_io) (root_obj);
/* `root_obj' is the root object of the CECIL system
* automatically initialized in EIF_INITIALIZED
* if it does not exists */
i_io = eif_protect (o_io);
/* Protect `io' . Replace eif_protect by henter in v4.2*/
o_str = RTMS ("Hello World");
/* Create Eiffel string */
i_str = eif_protect (o_str);
/* Protect Eiffel string. Replace eif_protect by henter in v4.2 */
p_put_string = eif_procedure ("put_string", tid);
/* replace eif_procedure by eif_proc in v4.2 */
if (p_put_string == (EIF_PROCEDURE) 0) /* No routine found. */
eif_panic ("put_string not visible"); /* Raised if "visible exception" disabled. */
(p_put_string) (eif_access (i_io), eif_access
(i_str));
On version 4.3 and higher, eif_type_id is also used for returning the type identifier of generic types but you need to specify the generic parameter, otherwise it returns EIF_NO_TYPE. On lower version use eif_generic_id for generic type identifier.
Example:
EIF_PROCEDURE p_make;
/* 'make' from ARRAY [INTEGER] . EIF_PROC in v4.2*/
tid = eif_type_id ("ARRAY[INTEGER]");
/* tid = eif_generic_id ("ARRAY", eif_type_if("INTEGER") in v4.2 */
EIF_TYPE_ID tid;
p_make = eif_procedure ("make", tid);
/* use eif_proc instead in v4.2 */
EIF_TYPE_ID eif_generic_id(char *class_name, EIF_TYPE_ID par_gen1, ...) (until v4.2, not valid in v4.3)
Returns the generic type identifer corresponding to classname and with generic_par1, generic_par2 and so on as generic parameters. Returns EIF_NO_TYPE if no type id is found. On version 4.3 and higher, use eif_type_id instead.
Example: get the type id of HASH_TABLE [STRING,
INTEGER]
EIF_TYPE_ID tid;
tid = eif_generic_id ("HASH_TABLE", eif_type_id
("STRING"), eif_type_id ("INTEGER"));
if (tid == EIF_NO_TYPE)
eif_panic ("Type not
in system.");
void eif_panic(char *msg)
#include "eif_threads.h"
void eif_thr_panic (char *msg)
Raise an Eiffel panic with Eiffel exception trace with message msg . In MT mode, use eif_thr_panic instead.
EIF_REFERENCE eif_wean(EIF_OBJECT
object) (since v4.3)
EIF_REFERENCE eif_wean(EIF_OBJ
object) (until v4.2)
Tells the GC to remove the artificial reference to the nested Eiffel reference eif_access (object), so that the GC can collect it, when it will not be reference from Eiffel any longer. This artificial reference has been previously created with eif_adopt, eif_protect/henter or eif_create. It returns the direct reference eif_access (object). After this call, eif_access (object) is NULL. The argument of eif_wean is a value returned by eif_adopt, eif_protect/henter or eif_create. It is useless to call eif_wean on an Eiffel object given by a C external since it is a temporary indirection pointer (see eif_access).
Example: C external returning an Eiffel string.
In Eiffel:
EIF_REFERENCE foo () {
foo : STRING is
external
"C
| %"a file.h%""
end
In C:
EIF_REFERENCE str;
EIF_OBJECT i_str;
/* EIF_OBJ in v4.2 */
str = RTMS ("Hello world");
i_str = eif_protect(str);
/* use henter in v4.2 */
/* Some operations on
`i_str' */
return eif_wean (i_str);
/* Returns direct reference to the Eiffel string.
* No need to keep an extra reference from the C. */
}
#define eif_field(object,name,type)
*(type *)(eifaddr(object,name))
EIF_REFERENCE eifaddr(EIF_REFERENCEobject,
char *name)
Returns the direct reference of the attribute described as name in the Eiffel object object. You must give the return Eiffel type type. (see Eiffel basic types). If type is an EIF_REFERENCE, you must protect it with eif_protect (or henter until v4.2). Returns (type) 0 , if the attribute is not found. A segmentation fault may be raised, if you try to access an attribute of basic expanded type, which does not exists.
You cannot access a constant attribute or the result of a once function using eif_field.
See also eif_procedure/eif_proc, eif_xx_function/eif_fn_ref.
(since v4.3)
EIF_PROCEDURE eif_procedure
(char *rout_name, EIF_TYPE_ID type_id)
EIF_REFERENCE_FUNCTION eif_reference_function
(char *rout_name, EIF_TYPE_ID type_id)
EIF_INTEGER_FUNCTION eif_integer_function
(char *rout_name, EIF_TYPE_ID type_id)
EIF_CHARACTER_FUNCTION eif_character_function
(char *rout_name, EIF_TYPE_ID type_id)
EIF_REAL_FUNCTION eif_real_function
(char *rout_name, EIF_TYPE_ID type_id)
EIF_DOUBLE_FUNCTION eif_double_function
(char *rput_name, EIF_TYPE_ID type_id)
EIF_BIT_FUNCTION eif_bit_function
(char *rout_name, EIF_TYPE_ID type_id)
EIF_BOOLEAN_FUNCTION eif_boolean_function
(char *rout_name, EIF_TYPE_ID type_id)
EIF_POINTER_FUNCTION eif_pointer_function
(char *rout_name, EIF_TYPE_ID type_id)
(until v4.2, obsolete
in v4.3 but still valid)
EIF_PROC eif_proc (char *rout_name,
EIF_TYPE_ID type_id)
EIF_FN_REF eif_fn_ref (char *rout_name,
EIF_TYPE_ID type_id)
EIF_FN_INT eif_fn_int (char *rout_name,
EIF_TYPE_ID type_id)
EIF_FN_CHAR eif_fn_char (char *rout_name,
EIF_TYPE_ID type_id)
EIF_FN_FLOAT eif_fn_float (char
*rout_name, EIF_TYPE_ID type_id)
EIF_FN_DOUBLE eif_fn_double (char
*rput_name, EIF_TYPE_ID type_id)
EIF_FN_BIT eif_fn_bit (char *rout_name,
EIF_TYPE_ID type_id)
EIF_FN_BOOL eif_fn_bool (char *rout_name,
EIF_TYPE_ID type_id)
EIF_FN_POINTER eif_fn_pointer (char
*rout_name, EIF_TYPE_ID type_id)
Returns the address of the Eiffel routine by giving its name rout_name and the type id type_id of the class, in which it is declared. Returns a NULL pointer or raises a visible exception (if enabled) when there is no corresponding routine with name rout_name or the routine is not visible. The first argument of an Eiffel routine has to be the target of the Eiffel routine.
The Eiffel object returned by an Eiffel function must be protected afterwards with 'eif_protect/henter' (this only applies for functions, which address is returned by `eif_reference_function/eif_fn_ref' since the other function types returns basic types, which are not Eiffel objects).
Note: the address returned by these functions must be called between parenthesis.
See also Declaring routines taking real as argument, Cast of the Eiffel routines in C, Bad macros in eif_cecil.h.
void eif_enable_visible_exception
() (since v4.3)
void eif_disable_visible_exception
() (since v4.3)
Respectively,
enables and disables the visible exception. See visible
exception
By default, the visible exception is enabled
(even on 4.2).
EIF_REFERENCE eif_make_string (char
*string, int len) /* Macro */ (since v4.3)
EIF_REFERENCE makestr (char *string,
int len) (until v4.2, still valid on v4.3)
#include "eif_macros.h"
#define RTMS(str) makestr(str,
strlen (str))
Returns the direct reference to an Eiffel string by giving the corresponding C string string and its length len (for eif_make_string or makestr). The result of RTMS or eif_make_string does not reference the C string passed as argument: these functions only use a copy of it to create the Eiffel string. The C string must be manually freed by the user, if it has been dynamically allocated.
int eif_attribute_type (char *attr_name, EIF_TYPE_ID tid) (since v4.3)
#define EIF_REFERENCE_TYPE
1
#define EIF_CHARACTER_TYPE
2
#define EIF_BOOLEAN_TYPE
3
#define EIF_INTEGER_TYPE
4
#define EIF_REAL_TYPE
5
#define EIF_DOUBLE_TYPE
6
#define EIF_EXPANDED_TYPE
7
#define EIF_BIT_TYPE
8
#define EIF_POINTER_TYPE
0
#define EIF_NO_TYPE
(-1)
Returns the type of the attribute described by its name attr_name and the type identifier of the class where it is defined tid. The return type is an int (see above for correspondances). In case of failure, EIF_NO_TYPE is returned - not such given attribute name, routine name instead of attribute name, or so on.
Example: Get the type of count
from STRING
int i;
i = eif_attribute_type ("count", eif_type_id ("STRING");
printf ("type is %d\n"); /*
char *eif_name (EIF_TYPE_ID tid)
Returns the corresponding name (C string) of the Eiffel class, given a type identifier type_id. If the type identifier is a generic type identifier, no generic parameter type is given. Returns NULL if an invalid type idientifer is given.
Example:
printf ("the class name with type id 1 is %s\n",
eif_name (1); /* Should print "PLATFORM" on most
compiler versions*/
See also eif_type, eif_type_id
EIF_TYPE_ID eif_type (EIF_OBJECT
object) (since v4.3)
EIF_TYPE_ID eif_type (EIF_OBJ object)
(until
v4.2)
Returns the type identifier, given an indirection pointer to an Eiffel object. See also eif_name, eif_type_id
Example: call to put (r: REAL ; index: INTEGER) from ARRAY
[REAL])
typedef void (*EIF_PROC_REAL_INTEGER)(EIF_REFERENCE, EIF_REAL, EIF_INTEGER);
/* some code */
EIF_PROC_REAL_INTEGER eput;
eput = (EIF_PROC_REAL_INTEGER) eif_proc ("put", eif_type_id ("ARRAY
[REAL]"));
(until v4.2, obsolete but still valid on v4.3)
EIF_PROC: Eiffel procedure
EIF_FN_INT: Eiffel functions returning an Eiffel Integer
EIF_FN_BOOL: Eiffel functions returning an Eiffel Boolean
EIF_FN_CHAR: Eiffel functions returning an Eiffel Character
EIF_FN_FLOAT: Eiffel functions returning an Eiffel real
EIF_FN_DOUBLE: Eiffel functions returning an Eiffel double
EIF_FN_REF: Eiffel functions returning an Eiffel references
(e.g an Eiffel object, which is not an instance of a basic type)
EIF_FN_POINTER: Eiffel functions returning an Eiffel pointer
EIF_FN_BIT: Eiffel functions returning an Eiffel bit.
These typedefs do not perform the type checking of the arguments. The typedefs only cast the result of the Eiffel routine (void if it is an Eiffel procedure). For more information on the previous definitions, see their definitions in $EIFFEL4/bench/spec/$PLATFORM/include/eif_cecil.h.
CECIL can not generate relevant typedefs for every type of routine that is exported to C through CECIL. Consequently, you must define manually the typedefs to properly cast the pointer type to the Eiffel routine. This way, during compilation, a warning or an error is raised if arguments with incorrect types are passed to the Eiffel routine.
Example:
Let the Eiffel function `foo' :
foo (c: CHARACTER; a: ARRAY [INTEGER]): POINTER is
typedef EIF_POINTER (*EIF_FOO_TYPE)(EIF_REFERENCE /* Current object */,
EIF_REFERENCE /* 2d argument */);
Note: Do not forget to call all the Eiffel routines from C within parenthesis. Otherwise, they will return the address of the Eiffel routine, rather than performing an action.
- Using a non-generic type, declare:
a_cluster: "A_PATH"
dummy: SIMPLE_TYPE
in your root class.
visible
SIMPLE_TYPE
end
end;
in your Ace file.
- Using Generic types , declare for example:
dummy1: GEN_TYPE [INTEGER]
dummy2: GEN_TYPE [OTHER_TYPE]
in the root class.
and
an_other_cluster: "AN_OTHER_PATH"
visible
GEN_TYPE
-- Do not specify any generic parameter.
end
end;
in your Ace file.
This is necessary to tell the compiler to generate the C code corresponding to GEN_TYPE[INTEGER] or GEN_TYPE[OTHER_TYPE] and make it available to CECIL. Otherwise, eif_type_id will returns EIF_NO_TYPE, and eif_procedure/eif_function_xx will return a NULL pointer or raise a visible exception.
You can disable this exception by calling eif_disable_visible_exception. You can also enable it with eif_enable_visible_exception.
If you try to call eif_proc/eif_procedure or eif_fn_xx/eif_xx_function to get the pointer on a non visible routine, they will return a NULL pointer.
Exporting features to CECIL, overriding the export clause in the Ace file:
Example: export the feature foo from class A which has an export clause.
In Eiffel:
feature {B,C} -- Only exported
to classes B and C
foo is
do
...
end
In the Ace file:
....
visible
A
export
"make", -- creation procedure
"foo"
end
end
...
In this case, only foo and make are exported to CECIL.
All other features from class A are no longer available. See also
ETL Part E, appendice D and bug in export clause.
The name of the features to export should be put between " " to avoid any confusion with Lace keywords.
By default, the creation procedure(s) of a visible class is/are exported and visible in CECIL. However, if the creation procedure is defined in a parent and has an export clause in the Eiffel code, you must explicitely export it to CECIL in the Ace file.
#define eif_double_function eifreal /* Get an Eiffel function returning an Eiffel Double */
#define eif_reference_function eifreal /* Get an Eiffel function returning an Eiffel Double */
#define eif_fn_pointer eifpointer /* Use `eif_pointer_function' instead */
#define eif_fn_pointer eifptr /* Use `eif_pointer_function' instead */
#define EIF_FN_INT EIF_INTEGER_PROCEDURE /* Use EIF_INTEGER_PROCEDURE instead */
by
#define EIF_FN_INT EIF_INTEGER_FUNCTION /* Use EIF_INTEGER_FUNCTION instead */
#define eif_fn_float eifreal /* Use `eif_double_function' instead */
by
#define eif_fn_double eifreal /* Use `eif_double_function' instead *