The component main file is a source file that :
The name of this file is usually main.c
(or main.cpp
if your component is written in C++), and the name of its header file is main.h
.
To access the Gambas Programming Interface, you need :
gambas.h
in each component source file.
GB
that will receive the interface.
GB
symbol.
The global structure must be declared this way :
GB_INTERFACE GB;
The source file must reference this structure this way :
extern GB_INTERFACE GB;
As every source file must reference the GB
interface and include the gambas.h
file, the easiest way is to put them in the main.h
file, to declare GB
in main.c
, and to include main.h
everywhere.
So main.h
will look like this :
/* main.h */ #ifndef __MAIN_H #define __MAIN_H #include "gambas.h" #ifndef __MAIN_C extern GB_INTERFACE GB; #endif ... #endif
And main.c
will look like this :
/* main.c */ #define __MAIN_C #include "main.h" ... GB_INTERFACE GB; ...
Each class you implement in your component has its own description structure declared in its own source file. This structure is declared in the header file of the class source file.
So, you must include every class header file in main.c
:
/* main.c */ #define __MAIN_C #include "main.h" #include "FirstClassSourceFile.h" #include "SecondClassSourceFile.h" ... GB_INTERFACE GB; ...
Then, you must declare a global null-terminated array that will contain a pointer to each class structure declared in the included header files. The name of this array must be GB_CLASSES
.
Note : a class source file can declare and implement more than one class.
See Writing a class for more information about class source files.
/* main.c */ ... GB_INTERFACE GB; GB_DESC *GB_CLASSES[] = { FirstClassDescription, SecondClassDescription, ThirdClassDescription, ..., NULL };
The component must export two global functions : the first is called when the interpreter loads the component, and the second is called when the interpreter unloads it.
The name of the function called at loading must be GB_INIT
.
/* main.c */ ... int GB_INIT(void) { ... }
This function receives no argument, and must return a non-zero integer value to tell the interpreter that he must keep the component shared libraries in memory after unloading.
Note : Some shared libraries, like the X-Window library, can crash a process if they are unloaded before its end. As the QT library uses the X-Window library, the QT component must be kept in memory at unloading.
The main job of GB_INIT()
is to declare interpreter hooks.
As for the function called at component unloading, its name must be GB_EXIT
.
/* main.c */ ... void GB_EXIT(void) { } ...
This function takes no argument and returns nothing. It usually does nothing, but you can use it to provide specific uninitializations.
Interpreter hooks must be declared during the GB_INIT()
function execution. Consequently, hooks functions are usually implemented in the main.c
file.
For example, here is the QT component GB_INIT()
function :
/* main.cpp of QT component */ int GB_INIT(void) { GB.Hook(GB_HOOK_MAIN, (void *)my_main); GB.Hook(GB_HOOK_LOOP, (void *)my_loop); GB.Hook(GB_HOOK_WAIT, (void *)my_wait); GB.Hook(GB_HOOK_WATCH, (void *)my_watch); GB.Hook(GB_HOOK_POST, (void *)my_post); return 1; }
To get more information about hooks, go to The interpreter hooks
In short, a component must export four symbols to the interpreter : GB
, GB_CLASSES
, GB_INIT
and GB_EXIT
.
If you program a component in C++, you must enclose the declaration of these symbols between extern "C" {
and }
so that the C++ linker does not transform their names.
Here is an extract of the main.cpp
file of the QT component :
extern "C" { GB_DESC *GB_CLASSES[] = { ... }; ... int GB_INIT(void) { GB.Hook(GB_HOOK_MAIN, (void *)my_main); GB.Hook(GB_HOOK_LOOP, (void *)my_loop); GB.Hook(GB_HOOK_WAIT, (void *)my_wait); GB.Hook(GB_HOOK_WATCH, (void *)my_watch); GB.Hook(GB_HOOK_POST, (void *)my_post); return 1; } void GB_EXIT() { ... } } /* extern "C" */
/* example of main.c */ #define __MAIN_C #include "main.h" #include "FirstClassSourceFile.h" #include "SecondClassSourceFile.h" #include "ThirdClassSourceFile.h" GB_INTERFACE GB; GB_DESC *GB_CLASSES[] = { FirstClassDescription, SecondClassDescription, ThirdClassDescription NULL }; static void my_error(int code, char *error, char *where) { ... } int GB_INIT(void) { GB.Hook(GB_HOOK_ERROR, (void *)my_error); return 0; }