Module system and source tree reorg
Bill Gribble
grib@billgribble.com
Wed, 25 Jul 2001 10:46:30 -0500
I have been working on a module/plugin system for gnucash. It's
pretty much finished; I've posted a couple of messages here about the
way it works, and I'll start another thread for discussion of its
design and how it might need to change before a first release. In
general, it's a wrapper around 'dlopen' with explicit support for
versioning, load/unload/init hooks, and a path-scanning approach to
building a database of available modules.
What I want to address in this thread is how the gnucash source tree
can be restructured to take advantage of the module system. I have
an approach I've been following in my source tree, but I'm not
convinced it's the best.
Here are the general principles I'm trying to go for in my
reorganization and a stab at a source tree structure. Please
let me know what you think.
Thanks,
b.g.
---------------------------------------------------------------------
General principles:
1. Modules are the basic organizing unit for the code. All the code
needed for a module goes in one place, separate from the code for
other modules. In my source tree, this is in subdirectories of
src/modules/ but eventually it's my goal that *all* of gnucash should
be in modules, so maybe we should just put modules in top-level
subdirs of src/
2. A module should be self-contained. All the stuff needed to build
the module, including C code, Scheme code, g-wrap specs, g-wrap helper
files, tests, and documentation should all go in one place. For example,
the "engine" module looks like this:
src/modules/engine
Makefile.am
gw-engine-spec.scm - g-wrap spec file for just the engine API
engine-helpers.{c,h} - g-wrap helper functions for engine types,
from gnc-helpers.{c,h}
gncmod-engine.c - the actual module definition stub file
gnucash/ - subdir for Scheme module files
engine.scm - (gnucash engine) Scheme module
engine-init.scm - files from old src/scm (loaded by engine.scm)
gnc-numeric.scm
commodity-table.scm
iso-4217-currencies.scm
engine/ - subdir for 'libgncengine.la' source
test/ - tests for libgncengine.la
test/ - tests for the "engine" module (libgncmod-engine.la)
What's nice about this is that for the first time all the code needed
to use the engine in an app is in one place, and I can load it up from
a Scheme script like so:
(use-modules (gnucash gnc-module))
(gnc:module-system-init)
(gnc:module-load "gnucash/engine" 0)
(let ((acc (gnc:malloc-account)))
...)
Everything else can depend on the engine module by putting a similar
module-load in their own module init functions. Right now, in my
testing of the new QIF importer, I have a 20-line Scheme program that
can read a QIF file and save it as a Gnucash XML file from the command
line. I would love to be able to really script all the gnucash
components that way: run reports from the command line, run a headless
Gnucash server, etc.
3. Modules should be separately compilable and distributable. ATM my
source tree depends on a top-level configure script, but I think that
should possibly change (at least for non-core modules). It would be
really nice to get a bunch of contributed "plugins" a la Gimp. Right
now it would be a little awkward to write a C-only plugin that did
anything useful without linking against the engine library, but it
could be done, and it's easy to write a Scheme-only plugin that does
useful stuff without any gnucash libraries available at compile time.
In the future we will probably want to have a gnucash-devel package
that allows third parties to write and build C plugins outside the
gnucash source tree.
---------------------------------------------------------------------
And here's the start of a proposal for a set of modules and where they
would live in the source tree. I'd like people to look at it, add to
it, restructure it, and so on. The idea is that "gnucash" will just
be a little Scheme script that does a lot of "gnc:module-load"s and
starts the gui.
I'm a little unclear about how to use the naming conventions; at the
moment, each module registers itself with an arbitrary string for a
name, and that's what clients ask for with module-load. I've been
using "/" as a path-component separator in names with the idea that a
GUI would display available modules in a tree using these path
components, but I sort of like a flat structure in the actual source
tree.
I have not yet addressed the structure of most of the GUI components.
I don't think they should all go together; for example, having a
"gnome-gui-splashscreen" that just depends on a very minimal
"gnome-gui-core" would be nice because it would allow us to load just
enough to get a splash screen up before doing much of anything else.
Also we want to break out the dependencies a little; for example, the
QIF i/o gui probably shouldn't be part of an omnibus GUI module,
because the QIF gui will depend on the non-gui parts of QIF i/o, and
it's silly for the basic GUI to depend on QIF i/o being loaded. That
would argue for a separate gnome-gui-qif-io module. Opinions?
The following is a list of what I think should be subdirs of "src".
The format is
subdir-name gnc-module-name
description
gnc-module n/a
the gnc-module library source. it's not a module itself. You
can either link with libgnc-module.la and call gnc_module_system_init
from C, or (use-modules (gnucash gnc-module)) (gnc:module-system-init)
from Scheme, which dynamic-links the library and calls the init function.
gnc-app n/a
this would be where the actual gnucash application and utilities
live. It may be useful to have a module called 'gnc-util' or something
for non-gui utility code.
gnc-component gnucash/component
the gnc-component events-and-callbacks interface
gnc-engine gnucash/engine
the engine itself, with no backends. Where backends are now directly
'dlopen'-ed, dlopen calls would be replaced with gnc_module_loads;
'dlsym' can be replaced with gnc_module_lookup
backend-file gnucash/engine/backend/file
backend-postgres gnucash/engine/backend/postgres
backend-rpc gnucash/engine/backend/rpc
the backends. A kernel-config-like thing at the top level, or just more
args to top-level configure, can switch compilation on and off.
report-core gnucash/report/core
non-gui code for representing and running reports. This would be
mostly report.scm plus html-*.scm. Should be useful on its own
without GUI.
report-guppi gnucash/report/guppi
support for guppi graphs in reports
reports-text gnucash/reports/basic
most of the non-graphing reports we have now
reports-guppi gucash/reports/guppi
reports that use guppi
qif-io-core gnucash/qif-io/core
non-gui code for importing and exporting QIF files. Should be useful
without GUI.
register-core gnucash/register/core
the toolkit-independent parts of the register code
register-gnome gnucash/register/gnome
the gnome-dependent parts