[ft-devel] enclosing FreeType in a C++ namespace

2015-07-09 Thread Graham Asher
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


Re: [ft-devel] enclosing FreeType in a C++ namespace

2015-07-09 Thread Werner LEMBERG

Hello Graham!


 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.

Are you really meaning `pshalgo.h'?  In this file there isn't an
#include statement after FT_BEGIN_HEADER...  Anyways, this should be
easier now with my latest commit: I've moved around
FT_{BEGIN,END}_HEADER to not #include header files that contain
FT_{BEGIN,END}_HEADER files by themselves.

 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.

I guess this is too special to get upstream support ...

 [...] 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, [...]

In FreeType?  Theoretically, this shouldn't be necessary.


Werner

___
Freetype-devel mailing list
Freetype-devel@nongnu.org
https://lists.nongnu.org/mailman/listinfo/freetype-devel