|
From: | Graham Asher |
Subject: | [ft-devel] enclosing FreeType in a C++ namespace |
Date: | Thu, 09 Jul 2015 09:58:05 +0100 |
User-agent: | Mozilla/5.0 (Windows NT 6.1; WOW64; rv:31.0) Gecko/20100101 Thunderbird/31.7.0 |
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 |
[Prev in Thread] | Current Thread | [Next in Thread] |