My product, CartoType, is sometimes supplied as a static C++ library,
and lately I've had some problems reported by users who also link to
other libraries containing conflicting versions of open-source
components, including FreeType, Zlib, Libpng, Libjpeg, Expat, etc.
One possible fix would be to take these components out of CartoType, and
allow users to link to their own versions, but that would compromise
consistency and maintainability. Therefore my solution has been to move
everything into the CartoType namespace; which means compiling the code
as C++ and enclosing all declarations and definitions in "namespace
CartoType { ... }". Doing this has helped a number of my clients.
It may interest FreeType aficionados if I give a brief overview of how
to do this. My description is based on a somewhat older version of
FreeType, but I am sure it remains applicable.This is not the same as
creating a C++ wrapper for FreeType. It does not change the FreeType
API, but puts /everything/ into the C++ namespace, so that, for example
the full signature of FT_Init_FreeType becomes
CartoType::FT_Error CartoType::FT_Init_FreeType(CartoType::FT_Library*
alibrary)
Obviously any namespace would work here.
Here's the process I followed:
1. Rename all directly compiled .c files to .cpp. These are files that
are not #included, but are part of the main project. So ftbase.c,
ftinit.c, truetype.c, raster.c, etc., become ftbase.cpp, ftinit.cpp,
truetype.cpp, raster.cpp, etc. The renaming is not absolutely necessary
(you could just tell your compiler to compile everything as C++) but it
makes things a lot easier if you are working on five different
platforms, with many different project files and compilers; all the
compilers I use infer C or C++ from the file extension.
2. Change FT_LOCAL, etc, as follows:
#define FT_LOCAL( x ) x
#define FT_LOCAL_DEF( x ) x
#define FT_BASE( x ) x
#define FT_BASE_DEF( x ) x
#define FT_EXPORT( x ) x
#define FT_EXPORT_DEF( x ) x
#define FT_EXPORT_VAR( x ) extern x
#define FT_CALLBACK_DEF( x ) x
#define FT_CALLBACK_TABLE extern
#define FT_CALLBACK_TABLE_DEF extern
That is, various 'extern "C"' and 'static' qualifiers are removed.
3. Make FT_BEGIN_HEADER and FT_END_HEADER into the start and end of the
namespace:
#define FT_BEGIN_HEADER namespace CartoType {
#define FT_END_HEADER } // namespace CartoType
For this to work, I had to remove FT_BEGIN_HEADER and FT_END_HEADER from
pshalgo.h, because it #includes other headers; while 'extern "C"' can be
nested, a nested namespace is a different namespace.
4. Put all indirectly compiled .c files into the namespace. These are
the source files which were not renamed to .cpp files, and are #included
by them. They are compiled as C++ because they become part of the same
compilation unit when #included. For example, the file ttdriver.c
acquires 'namespace CartoType {' after all its #include statements, and
'} // namespace CartoType' at the end of the file. I had to do that to
about 40 files.
5. Fix up some annoyances in ftinit.cpp. The ordinary system for module
specification doesn't work, for reasons I am too bored to investigate
involving static object initialisation, 'extern' declarations and strict
type checking, so I have to declare the modules like this:
extern const FT_Module_Class psaux_module_class;
extern const FT_Module_Class psnames_module_class;
extern const FT_Module_Class pshinter_module_class;
extern const FT_Renderer_Class ft_raster1_renderer_class;
extern const FT_Module_Class sfnt_module_class;
extern const FT_Renderer_Class ft_smooth_renderer_class;
extern const FT_Driver_ClassRec tt_driver_class;
extern const FT_Driver_ClassRec t1_driver_class;
#define FT_USE_MODULE( x ) (const FT_Module_Class*)&x,
const FT_Module_Class* const ft_default_modules[] =
{
#include FT_CONFIG_MODULES_H
0
};
6. There were some other small problems - pretty obvious stuff - but I
won't go into them because they have almost certainly been made obsolete
by changes to FreeType.
I have used the same technique for libpng, zlib, expat and libjpeg. (I
had some trouble with sqlite, so (for the moment) I have left it in C
and avoided namespace conflicts by a massive global renaming, adding a
prefix to all symbols.) Yes, I am aware that C and C++ are not entirely
compatible, but this has not caused any difficulties, apart from trivial
matters like casting the return value of malloc from void* to the
desired pointer type in a couple of places, and (in zlib) changing
old-style C function declarations to the current C and C++ syntax.
I hope all this is of interest.
Best regards,
Graham
--
Graham Asher
founder and CTO
CartoType Ltd
graham.as...@cartotype.com
+44 (0) 7718 895191
_______________________________________________
Freetype-devel mailing list
Freetype-devel@nongnu.org
https://lists.nongnu.org/mailman/listinfo/freetype-devel