The libdesc program


Contents


Overview


HBasic may load and use methods and components which have been defined in shared libraries. A shared library compiled from C or C++ code normally only declares symbols and code to be executed for a method call. When HBasic wants to call a method in a library it also needs some information about the parameters or return type of the method and which symbol should be called. This additional information will be stored in an appropriate description file which is needed for each shared object library.

The libdesc program is a GUI based program to create and edit this description files. You can find a special libdesc folder in your HBasic distribution with the sourcecode for the hbasic program. This document should describe how to use libdesc. You do not need to read this if you don't want to create new or extend existing shared libraries. The following image should give you an overview which files will be used and how HBasic manages the handling of shared libraries and it's descriptions.



1) Before you start libdesc you should already have created a shared object library with a C or C++ compiler and compiled it to a shared object library *.so. The library contains the machine code for all methods that may be called from a HBasic program later. You may find some information how to create this libraries in creating shared libraries. You can find some examples of shared libraries for HBasic in the packages folder of the HBasic distribution.

2) Start the libdesc program and create the method and component description for each library entry that should be used within HBasic. Have a look at the rest of this document to understand which description should be set up.

3) Start hbasic and include a reference to the *.dso description file into your HBasic project with the package manager. The HBasic source code editor will use this information to handle code completion and display help popups for classes and methods referenced in your source code.

4) Whenever you start the interpreter (parser) or compiler for your sourcecode HBasic will use the library description to create the correct runtime code to access symbold within the shared libraries.

5) Executing the runtime code the execution environment (interpreter or compiler runtime library) knows which symbols should be called within the *.so library  because  the parser has saved this information in the generated code. Therefore the library description will only be needed during parser execution and the library itself (*.so file) will mainly be used at runtime. The parser will only load the *.so file to check that the referenced symbols really exist in the library.


Libdesc edit dialog


After starting libdesc you can see the following main window. Libdesc may be used to handle constant, method and component descriptions. The image displayes the libdesc main window with parts of the hbasic_stdgui library. If you haven't loaded a library description yet the three folders for components, methods and constants will be empty.

 
Image: Libdesc main window displaying parts of hbasic_stdgui package description

You may add new subitems with a mouseclick of the right mousebutton on the component, method and constant folder. You may also click on the menu entry Entry/Add method, Entry/Add component or Entry/Add constant or click on the toolbar buttons with the same name to create new entries. To edit an existing entry doubleclick on the list viv item describing the entry and the appropriate editor dialog will pop up.


Create library description in libdesc


Before you create descriptions for methods or components exported by a library you should set up the reference to the shared object library file. Since HBasic only references the library description in the package manager the library description must contain a link to the shared library file wich contains the binary code to be executed. To insert this description click on the Edit libdesc button in the main window and insert at least the path to the shared object library file for your library. Without this entry HBasic cannot find and load the library at runtime.




Create global method entry in libdesc


The first entry type that may be exported by a library description is a global method definition. For a working method description you have to fill in the following information:

This entries passes two types of information to HBasic. The first is a description of the method call used in HBasic when starting the method and the second is the symbol used in the shared object library to define the method body. The method call description includes the name of the method used in the call, the parameter types and the returntype of the method. If the HBasic parser finds a call to a SO-method it will compare the actual parameter types used with the types of the method definition and send an error message if the parameter types don't match. If the parameter types are correct it will create code to change the HBasic style parameters to C++ calling conventions and create a jsr machine language call to the shared object symbol metioned in the method description. I would call this method definitions global because they may be referenced from every code position in yout HBasic program like a global variable.

 

To create a new description for a method in libdesc click with the right mouse button on the folder methods. To edit an existing description double click on the method entry in the main window with the left button. A new dialog pop's up where you can edit the description of the method call and the shared object symbol for the method. In the method editor dialog insert the following information:


To find the shared object symbol that should be called you may use the objdump program if it's installed on your system. Type

objdump -T <libraryname> | grep <method name>

to find the symbol for your method call. If you have for example created a method add_two in a library called testlib.so the correct call would be

objdump -T testlib.so | grep add_two. The result will show the shared symbols exported by the library which might be like

add_two if you have compiled a C coded file
add_two__Fi if your library is a C++ file and has been compiled with GCC version <= 3.1
_Z7add_two__Fi if your library is a C++ file and has been compiled with GCC version >=3.2

Insert this symbol in the second line of the method description, close the method editor dialog and save the library description.

If all the entries have been set up correctly you can call the method from your HBasic program after you have inserted the library description file with the package manager.
 

Create constant entry in libdesc


For some libraries it may be helpfull to define some constants that may be used with the library methods. Like method definitions this constants may be used in the whole program and will therefore be called global constants. To create a new description for a constant in libdesc click with the right mouse button on the folder constants. To edit an existing description double click on the constant description entry in the main window with the left button. A new dialog pop's up where you can edit the description of the constant. You have to set the name, type and value of a constant.



If for example you want to define a constant Pi you should insert the name Pi, Type double and a value like 3.1415926535 in the field of the constant editor. You can now type Print Pi in your HBasic program and the value 3.1415926535 will be displayed on the screen.


Create component description for class example


Before you can use the component definition within HBasic you have to set up a description of the component in the libdesc program. Start libdesc and click on the component_list folder with the right mouse button. You will see a new dialog where you can insert or edit the description of a component. For HBasic to work correctly you should at least insert a component name and the name of the init method. This is the symbol of the method that creates an instance of the component. As for global methods you have to insert the symbol that has been generated by the compiler for this method. You may for example use objdump -T soname to get the list of exported symbols.



Beside this information you may insert a component description which may be used as an information in the package manager, an exit method which will be called when a component will be destroyed, a matching Qt class if the class init method just returns a pointer to a Qt class instance and a class icon which will be used in the formdesigner with the class.


Component numbers


Whenever the HBasic formdesigner creates a component exported by a package it needs something to reference this component within the package to store the selected component in a project file or to recreate the component at runtime. HBasic takes the position of the component within the package to reference it later on. If you add new components later into the package description the position of a component which has been referenced may change and HBasic will get into trouble. It's therefore useful that libdesc always sorts the components of a package in the same way. Since a component who's name starts with the letter A should not always be the first in the list of components displayed in the select window I decided to sort them by a number prefix in the component name. This number prefix doesn't belong to the component name and will be deleted when loading the component into HBasic. A component which will be named 04_MultiEdit will be displayed with name MultiEdit in HBasic and if you alocate components with a Dim statement it must be

Dim varname As MultiEdit

and not Dim varname As 04_MultiEdit. With this numbers you can exactly define the order of the components within the seelct window of HBasic.


Additional component init methods


The default component init method allows only the parent widget to be passed as a parameter. There are some examples where it makes sence to create a component with other parameter definitions. In the hbasic_stdgui package you can find some components that may be created with more parameters. Examples are the point and size classes where you can create an instance with 2 integer parameters (xpos, ypos ) or (width, height ). To create additional init method descriptions in the libdesc program just add more lines in the parameter listview with the add button. The callsymbol mentioned in this additional init methods must be available in the C++ library file that you have created before.

Within HBasic you can create an instance of this component with a statement like

Dim varname As Point
varname = Point( xpos, ypos )



libdesc - old version - Editing library descriptions


Most scripting languages used with LINUX use some kind of modules that may be loaded at runtime to extend the functionality of the base program. This modules are normally shared object libraries set up with C or C++ code. The binary code may be loaded at runtime and the functions implemented may be called from the scripting language. Currently there are different formats for shared object libraries in HBasic. This mainly depends on the description of the methods and classes that have been implemented in the (shared object) SO-library. HBasic uses this description to check the correct syntax of a method call prior to executing the code, to display the methods in the package manager or to implement code completion in the source code editor. This library descriptions were different for HBasic packages, Qt-C support and the access to common shared object libraries described in xxxx. Starting with version 0.8.8 I have implemented one common format of descriptions for shared libraries.

There is a separate program to edit this shared library descriptions which is called libdesc. You can find a special libdesc folder in your HBasic distribution with the sourcecode for the libdesc program. If you want to use this program to set up you own libraries you first have to compile this program by typing make in this directory. This document should describe how to use libdesc and how you may set up your own components to extend HBasic functions with C++ code. You do not need to read this if you don't want to extend or create your own libraries. You can find some examples of shared libraries for HBasic in the packages folder of the HBasic distribution.

This document will describe using shared libraries in the following steps:


Creating a shared library for testing purposes


To test the connection to shared libraries I have created a small example of a shared library which you should find in the folder code_examples/solib. Start the command make in this directory and you will have a shared library called solib.so that exports 3 symbols.
  1. A method intvalue which when started will return a value of 1234.
  2. A method addthem which will return the sum of two integer parameters passed as parameter value
  3. A method addcpp which will also return the sum of two integers but is implemented as a cpp method
I will describe how to set up a description file solib.dso later in this document. For the first test you may find a library description in the example folder code_examples/solib. This description searches for the library /usr/lib/solib.so so you have to copy this library to the directory /usr/lib to start the examples. One main entry in the library description is the name of the assembler label that must be called when starting a function foo. When compiling C-code this is the same as the name of the method (The label for the method addthem will be addthem). Compiling the method addcpp in the example the assembler label will addcpp__Fii in older versions of gcc and something like _Z6addcppFii in newer versions. The reason is that parameters types will be included into the method name to separate distinct overloded methods from each other. The description for calls to cpp functions therefore has to be set up in another way which might be tested with the addcpp function.


Loading the library description in the package manager


If you have the shared library solib.so and the description file solib.dso you can tell HBasic projects to use this library in your current project. This will be done by adding the library description to the package list of your project. Saving the project will store this package list and reload it with the project file later. To add the shared library description to your project click on Add packageand select the solib.dso file in the file selector dialog.



You should now see a new red symbol for the library description solib.dso and the methods available in this shared library. Since there are no class definitions within this shared library descriptions (all symbols are defined global) the ListView classlist in the package manager will stay empty for this packages.


Calling methods in the shared library


After you have included the shared library description into your project with the package manager you can call methods of the library from the HBasic sourcecode. To use for example the method addthemto compute the sum of to integers 22 and 44 call the method like any other global defined symbol.


' Call a method from a shared object library

Sub button1_clicked()
Print addthem( 22, 44)
End Sub

Example test_c_add.bas: Call method in shared library.

Executing this program HBasic will transfer the parameter into the format needed, find the method start in the library file, call the method and transfer the return value back to a HBasis value. You can find some small example programs in the code_examples/solib folder of the HBasic distribution. This examples try to load solib.dso from /usr/local/hbasic/packages and call the methods defined in the shared library solib.so. In this examples you can see that there is no difference in HBasic between calling the C-function addthem and calling the cpp function add_cpp.


Binary format of library description


The description for a library <libname.so> will normally by called <libname.dso> and stored in the directory /usr/local/hbasic/packages. It contains the following parts:

<< New format will be described later >>



Create library description in libdesc


Before you can define any method or class descriptions in libdesc you should set up the reference to the shared object file. Since HBasic only references the library description in the package manager the library description must contain a link to the share library file. To insert this description click on the Edit libdesc button and insert at least the path to the shared object library filefor yout library. Without this entry HBasic cannot find and load the library at runtime.


Create global method entry in libdesc


The first entry type that may be exported by a library description is a global method definition. This entries passes two types of information to HBasic. The first is a description of the method call used in HBasic and the second is the symbol used in the shared object library to define the method body. The method call description includes the name of the method used in the call, the parameter types and the returntype of the method. If the HBasic parser finds a call to a SO-method it will compare the actual parameter types used with the types of the method definition and send an error message if the parameter types don't match. If the parameter types are correct it will create code to change the HBasic style parameters to C++ calling conventions and create a jsr machine language call to the shared object symbol metioned in the method description. I would call this method definitions global because they may be referenced from every code position in yout HBasic program like a global variable.

To create a new description for a method in libdesc click with the right mouse button on the folder methods. To edit an existing description double click on the method entry in the main window with the left button. A new dialog pop's up where you can edit the description of the method call and the shared object symbol for the method. Insert the method description in the format

<return type> <method name> ( <type of par1> , <type of par2> , ... )

The current version of libdesc has a poor parser for this method description which may fail if you don't insert this description correctly. To find the shared object symbol that should be called you may use the objdump program if it's installed on your system. Type

objdump -T <libraryname> | grep <method name>

to find the symbol for your method call. If you have for example created a method add_two in a library called testlib.so the correct call would be

objdump -T testlib.so | grep add_two. The result will show the shared symbols exported by the library which might be like

add_two if you have compiled a C coded file
add_two__Fi if your library is a C++ file and has been compiled with GCC version <= 3.1
_Z7add_two__Fi if your library is a C++ file and has been compiled with GCC version >=3.2

Insert this symbol in the second line of the method description, close the method editor dialog and save the library description.

If all the entries have been set up correctly you can call the method from your HBasic program after you have inserted the library description file with the package manager.
 

Create constant entry in libdesc


For some libraries it may be helpfull to define some constants that may be used with the library methods. Like method definitions this constants may be used in the whole program and will therefore be called global constants. To create a new description for a constant in libdesc click with the right mouse button on the folder constants. To edit an existing description double click on the constant description entry in the main window with the left button. A new dialog pop's up where you can edit the description of the constant. You have to set the name, type and value of a constant.

If for example you want to define a constant Pi you should insert the name Pi, Type double and a value like 3.1415926535 in the field of the constant editor. You can now type Print Pi in your HBasic program and the value 3.1415926535 will be displayed on the screen.


Create class example in C++


If you want to use Qt objects and widgets or event handling within HBasic you need a little bit more complex code in your C++ library. Libdesc therefore allows you to define your own classes. The capabilities of a class definition are between user defined types and object oriented class definitions. To set up a class definition that may be used in a shared object library you will need three things.
  1. A c++ class definition which inherits QObject or QWidget.
  2. A global method which creates an instance of the class and returns a pointer to it
  3. A class description set up in the libdesc program
With this descriptions available you can create instances of the class in HBasic with the formdesigner or with a variable definition like

Dim varname As classtype

HBasic may than access the signal, slot and property definitions exported by the class. You may call every public slot of the class like a method in the form varname.methodname( parameter ). You can catch events triggered by the class as a signal definition with a function definition like Sub button1_clicked() which connects to the clicked event of the button widget and read or write values of property definitions.

You can find examples of this class definitions in the packages folder of your HBasic distribution. The example_package folder contains a simple class definition which exports one class derived from QObject and one class derived from QWidget.

The following code declares an example class derived from QObject and a global method to create an instance for this class. The class currently only exports a method definition.


class Nogui : public QObject
{
Q_OBJECT

public:
Nogui( void );

public slots:
int add( int p1, int p2 );
}

Nogui::Nogui( void ) : QObject()
{
}

int Nogui::add( int p1, int p2 )
{
return( p1 + p2 );
}

/* ----------------------------------- */

long new_nogui()
{
return( (long)new Nogui() );
}

Example: Class definition for shared object class.

Beside the normal class definitions you only need to set up some methods like add and define them as public slots. This is enough for HBasic to find the method description and create a method call for the runtime interpreter or compiler generated code.


Create class description for class example


Before you can use the class definition within HBasic you have to set up a description of the class in the libdesc program. Start libdesc and click on the classlist folder with the right mouse button. You will see a new dialog where you can insert or edit the description of a class. For HBasic to work correctly you should at least insert a class name and the name of the init method. This is the symbol of the method that creates a class instance in the library. As for global methods you have to insert the symbol that has been generated by the compiler for this method. You may for example use objdump -T soname to get the list of exported symbols.

Beside this information you may insert a class description which may be used as an information in the package manager, an exit method which will be called when a class instance will be destroyed a matching Qt class if the class init method just returns a pointer to a Qt class instance and a class icon which will be used in the formdesigner with the class.


Using class instances as components in HBasic


Create intance in formdesigner or define class instance with "Dim varname As classname". The following example calls a method which has been defined as a public slot like the Nogui class definition listed above.


Public
n As nogui

Sub button1_clicked()
Print n.add( 22, 44)
End Sub

Example: Call method in class definition defined in shared library.