Table of Contents
gtkmm uses the gmmproc tool to generate most of its
source code, using .defs files that define the APIs of
GObject
-based libraries. So it's quite easy to create
additional gtkmm-style wrappers of other glib/GObject-based
libraries.
This involves a variety of tools and some copying of existing build files, but it does at least work, and has been used successfully by several projects.
Generation of the source code for a gtkmm-style wrapper API requires use
of tools such as gmmproc and
generate_wrap_init.pl
. In theory you could write your
own build files to use these appropriately, but in practice it's usually
easier to simply copy an existing project and modify it for your needs. Note
however, that there is plenty of scope for improvement in the build
structure that we use, so try to copy the latest version, and feel free to
suggest improvements to make it more generic.
For instance, let's pretend that we are wrapping a C library called
libexample. It provides a GObject
-based API with
types named, for instance, ExampleThing
and
ExampleStuff
.
Typically our wrapper library would be called libexamplemm. We can start by copying an existing *mm library, such as libgdamm, after checking it out from svn.
$ svn co svn.gnome.org/svn/gnomemm/libgdamm/trunk libsomethingmm
This provides a directory structure for the source .hg and .ccg files and
the generated .h and .cc files, with Makefile.am
fragments that can specify the various files in use, in terms of generic
Makefile.am
variables. The directory structure usually
looks like this, after we have renamed the directories appropriately:
libsomethingmm
: The top-level directory.
libsomething
: Contains the main include file and the pkg-config .pc file.
src
: Contains .hg and .ccg source files.
libsomethingmm
: Contains generated and hand-written .h and .cc files.
private
: Contains generated *_p.h
files.
As well as renaming the directories, we should rename some of the source files. For instance:
$ mv libsomething/libgdamm-2.0.pc.in libsomething/libsomethingmm-1.0.pc.in $ mv libsomething/libgdammconfig.h.in libsomething/libsomethingmmconfig.h.in $ mv libsomething/libgdamm.h libsomething/libsomethingmm.h $ $ mv libsomething/src/libgda.defs libsomething/src/libsomething.defs $ mv libsomething/src/libgda_enums.defs libsomething/src/libsomething_enums.defs $ mv libsomething/src/libgda_methods.defs libsomething/src/libsomething_methods.defs $ mv libsomething/src/libgda_others.defs libsomething/src/libsomething_others.defs $ mv libsomething/src/libgda_signals.defs libsomething/src/libsomething_signals.defs $ mv libsomething/src/libgda_vfuncs.defs libsomething/src/libsomething_vfuncs.defs $ mv libsomething/src/libgda_docs.xml libsomething/src/libsomething_docs.xml $ mv libsomething/src/libgda_docs_override.xml libsomething/src/libsomething_docs_override.xml
A multiple-file renaming tool, such as prefixsuffix might
help with this. We will provide the contents of these files later. In addition,
if you started from an svn checkout, you'll probably want to get rid of all of
the extra .svn
directories in the source tree.
Note that files ending in .in
will be used to generate
files with the same name but without the .in
suffix, by
replacing some variables with actual values during the configure stage.
Now we edit the files to adapt them to to our needs. You might prefer to use a multiple-file search-replace too for this, such as regexxer.
For instance, in autogen.sh
:
PKG_NAME
must contain the new package
name, such as libexamplemm.
The test script lines must check for appropriate directory
names, such as $srcdir/libsomething/src
.
In configure.in
(or configure.ac
in newer projects),
The AC_INIT()
line must mention a file
in our library. We can edit this later if we don't yet know the
names of any of the files that we will create.
The PACKAGE
variable must be changed to
the correct name of the project, such as
libsomethingmm.
The version numbers should be reset to something small, such
as 0.0.1. You may want to rename the version variables if they are not
something generic. For instance, we would rename
LIBGDAMM_MAJOR_VERSION
to
LIBSOMETHINGMM_MAJOR_VERSION
or
LIBGENERICMM_MAJOR_VERSION
.
The AM_CONFIG_HEADER()
line must mention
the correctly named config header file.
The PKG_CHECK_MODULES()
line must be modified to check for the
correct dependencies. For instance, it might be changed to
PKG_CHECK_MODULES(LIBGENERICMM, gtkmm-2.4 >= 2.6.0 libsomething-1.0
>= 1.0.0).
The AC_OUTPUT()
block must mention the correct directory
names, as described above.
The m4 script to generate doxygen input directory paths must mention the correct directory.
Next we must adapt the various Makefile.am
files:
The top-level Makefile.am
must mention
the correct child directory in the SUBDIRS
variable.
The libexample/Makefile.am
must mention:
The correct child directories in the SUBDIRS
variable.
The correct filenames in EXTRA_DIST
.
The correct filenames in
*_includedir
,
*_include_HEADERS
,
*_configdir
, and
*_config_DATA
.
In libexample/libexamplemm/Makefile.am
we
must mention the correct names in the generic variables that are used
elsewhere in the build system:
sublib_name
The name of the library, such as libsomethingmm.
sublib_libname
The versioned name of the library, such as libsomethingmm-1.0
sublib_namespace
The name of the C++ namespace to use for this library, such as Something.
files_defs
The list of .defs and
*docs*.xml
files.
lib_LTLIBRARIES
This variable must mention the correct library
name, and this library name must be used to form the
_SOURCES
, _LDFLAGS
,
and _LIBADD
variable
names.
In libexample/libexamplemm/private/Makefile.am
, private_includedir
must contain the correct path.
In examples/Makefile.am_fragment
,
local_libgenericmm_lib
and
all_includes
must contain the correct
paths.
In libexample/src/Makefile.am
we must set
some more generic variables:
sublib_name
The name of the library, as in libexample/libexamplemm/Makefile.am
.
sublib_namespace
The name of the C++ namespace, as in libexample/libexamplemm/Makefile.am
sublib_parentdir
The name of the directory containing the generated files, such as libexamplemm.
files_defs
The list of .defs and *docs*.xml
files.
In
build_shared/Makefile_gensrc.am_fragment
, you
should remove the --namespace=Gnome option from the
gen_wrap_init_args
variable if your namespace will
not be under the Gnome namespace. This should be the only place that
you need to edit the generic build_shared/
files.
We should now create our first .hg and .ccg files, to wrap one of the objects in the C library. We will delete any existing .hg and .ccg files:
$ rm -rf libexample/src/*.hg $ rm -rf libexample/src/*.ccg
and create new files:
$ touch libexample/src/thing.hg $ touch libexample/src/thing.ccg
We must mention all of our .hg and .ccg files in the
libexample/src/Makefile_list_of_hg.am_fragment
file, in
the files_hg
variable.
Any extra non-generated .h and .cc source files may be placed in
libexample/libexamplemm/
and mentioned in
libexample/libexamplemm/Makefile.am
, in the
files_extra_h
and files_extra_cc
variables.
In the .hg and .ccg files section you can learn about the syntax used in these files.