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, some of them crufty, but at least they 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 a much better option is to
make use of the build infrastructure provided by the mm-common module. To
get started, it helps a lot to pick an existing binding module as an example
to look at.
For instance, let's pretend that we are wrapping a C library called
libsomething. It provides a GObject
-based API with
types named, for instance, SomeWidget
and
SomeStuff
.
Typically our wrapper library would be called libsomethingmm. We can start by copying the skeleton source tree from the mm-common module.
$ git clone https://gitlab.gnome.org/GNOME/mm-common.git $ cp -a mm-common/skeletonmm libsomethingmm
This provides a directory structure for the source .hg and .ccg files and the generated .h
and .cc files, with filelist.am
Automake include files that can specify the
various files in use, in terms of generic Automake 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:
$ for f in $(find libsomethingmm -depth -name '*skeleton*'); do \ d="${f%/*}"; b="${f##*/}"; mv "$f" "$d/${b//skeleton/libsomething}"; \ done
A number of the skeleton files must still be filled in with project-specific content later.
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 our needs. You might prefer to use a multiple-file search-replace utility for this, such as regexxer. Note that nearly all of the files provided with the skeleton source tree contain placeholder text. Thus, the substitutions should be performed globally, and not be limited to the Automake and Autoconf files.
All mentions of skeleton
should be replaced by the correct name of the C
library you are wrapping, such as "something" or "libsomething". In the same manner, all
instances of SKELETON
should be replaced by "SOMETHING" or "LIBSOMETHING", and
all occurrences of Skeleton
changed to "Something".
Likewise, replace all instances of Joe Hacker
by the name of the intended
copyright holder, which is probably you. Do the same for the joe@example.com
email address.
In configure.ac
,
The AC_CONFIG_SRCDIR()
line must mention a file
in our source tree. We can edit this later if we don't yet know the
names of any of the files that we will create.
It is common for binding modules to track the version number of the library they are wrapping. So, for instance, if the C library is at version 1.23.4, then the initial version of the binding module would be 1.23.0. However, avoid starting with an even minor version number as that usually indicates a stable release.
The AC_CONFIG_HEADERS()
line is used to
generate two or more configuration header files. The first header file
in the list contains all configuration macros which are set during the
configure run. The remaining headers in the list contain only a subset
of configuration macros and their corresponding config.h.in
file will not be autogenerated. The reason for this separation is that
the namespaced configuration headers are installed with your library and
define publically visible macros.
The AC_SUBST([SOMETHINGMM_MODULES], ['...'])
line may need to be modified to check for the correct dependencies.
The AC_CONFIG_FILES()
block must mention
the correct directory names, as described above.
Next we must adapt the various Makefile.am
files:
In skeleton/src/Makefile.am
we
must mention the correct values for the generic variables that are used
elsewhere in the build system:
binding_name
The name of the library, such as libsomethingmm.
wrap_init_flags
Additional command-line flags passed to the
generate_wrap_init.pl
script, such
as the C++ namespace and the parent directory prefix of
include files.
In skeleton/skeletonmm/Makefile.am
we
must mention the correct values for the generic variables that are used
elsewhere in the build system:
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. It is permissible to
use variables substituted by configure
like
@SOMETHINGMM_API_VERSION@
as part of the
variable names.
AM_CPPFLAGS
The command line options passed to the C preprocessor.
AM_CXXFLAGS
The command line options passed to the C++ compiler.
We should now create our first .hg
and .ccg
files,
to wrap one of the objects in the C library. One pair of example source files already exists:
skeleton.ccg
and skeleton.hg
. Create copies of these
files as necessary.
We must mention all of our .hg
and
.ccg
files in the
skeleton/src/filelist.am
file, typically in the
files_hg
variable.
Any additional non-generated .h
and
.cc
source files may be placed in
skeleton/skeletonmm/
and listed in
skeleton/skeletonmm/filelist.am
, typically 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.