Applications depending on gpmi packages
1. Introduction
Usually an application uses gpmi to have modules that will later
call application functions back trough application-specific packages.
However some packages are not application-specific, but general ones
to provide a way to access console, network or other resources for
any module. Sometimes it's useful to utilize these applications from the
host application as well. However, it's not as easy as it is from modules
or other applications.
2. Problem: resolving references
When you link a module to form dynamic library, it is expected by the
compiler that there will be (external) references that can't be resolved
at the time of compiling or linking. For an application, it's different:
the linker needs to resolve every reference, even those that are external,
for example using the -l options. However, packages are handled by gpmi,
and the linker won't see them, linking will fail.
3. Solution: static packages
A gpmi package is compiled in two versions, a NAME.so for dynamic linking
and a NAME-static.o for static linking. The default (and recommended) way
is to use dynamic packages - most document assumes you did so. However,
you can use static packages as well.
A static package is not loaded runtime, but is linked in the application
binary. There is no way to replace a static package while the application
is running, on the other hand, the application may access any of the
symbols directly.
For applications depending on gpmi packages, it is recommended to use
those packages as static packages. It is possible to use static and
dynamic packages together (and this is the default).
4. Alternative solutions
Here I list some alternatives, each with different advantages. No example
codes for these.
4.1. Function pointers
A relatively clean solution, that doesn't need a wrapper around the
whole application, is not to call package routines directly. Instead,
have a definitions for all referenced package routines as pointers
(pointing to NULL by default). After the application initializes gpmi,
it should load the packages it depends on, passing a special routine
as the command registration callback. This special routine would load
all the function pointers we defined earlier.
However this solution is clear and structured, it has several drawbacks:
- you need to define pointers for all the package routines you plan to use
- you need to write a command registration routine that knows about all these
- later if you want to use another package call, you will need to add it at least two places (as above)
- each call is indirect, you waste some cpu cycles on them
- you also waste a small amount of memory storing these pointers
This solution still could be usable in a situation where the host
application uses only a very small number of package routines.
4.2. Writing modules instead of applications
This is another clean solution. You export all the package-dependent code
of your application into a module (or modules). The host application itself doesn't do
much more than loading gpmi and these modules. It's still more than the
loader of section 4.3, since the application may do all the init/uninit
tasks, provide a framework or anything else that does not need packages.
This solution is better than 4.1. since this more of the code becomes
replaceable, even runtime. However, this forces more of the gpmi design
(with RunTick and RunData) on your application's design.
4.3. Using a loader
Before implementing sttaic packages, this was the recommended way.
All the code of the application is compiled in a .so file, while
a thin wrapper (loader application) is provided which loads the
.so file. The only advantage this method has is that the .so file
can directly access any symbol in any package without compile-time
problems and without static package linking.