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:
- Insert a method name. This is the name to be used to call the method
from HBasic source code.
- Insert the symbol that should be called when starting the method
at runtime. This is the symbol the C++ parser has generated from your C++
method declaration. If you click on the S button on the right side of
the callsymbol lineedit libdesc will display a popup dialog to select the
method symbol from all available symbols in the library.
- Insert the return type of the method (Currently there are only few
types available).
- Inserting a docid is optional
- Insert a parameter description for each parameter of the method.
For each parameter type a name and assign it a parameter type. Click on add
to insert into list of parameters or delete to drop a selected parameter from
the list of parameter definitions.
- Insert an optional method description which may for example be displayed
in the source code editor.
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.
- A method intvalue which
when started will return a value of 1234.
- A method addthem which
will return the sum of two integer parameters passed as parameter value
- 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.
- A c++ class definition which inherits QObject or QWidget.
- A global method which creates an instance of the class and returns
a pointer to it
- 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.