User applications have less strict requirements than libraries, because nobody else will link with it. The developer of an application directly controls and checks and resolves name collisions when needed. If you are writing an end-application then you are still urged to create a header file called debug.h and use that in your source files, instead of including <libcwd/debug.h> directly. You will benefit greatly from this in terms on flexibility (trust me).
If you are developing a library that uses libcwd then do not put your debug channels in the libcwd::channels::dc namespace. The correct way to declare new debug channels is by putting them in a namespace of the library itself. Also end-applications will benefit by using this method (in terms of flexibility).
The following code would define a debug channel warp
in the namespace libexample:
// This is some .cpp file of your library. #include "debug.h" // ... #ifdef CWDEBUG namespace libexample { namespace channels { namespace dc { libcwd::channel_ct warp("WARP"); // Add new channels here... } } } #endif
The namespace channels in this example is not really necessary but it illustrates which namespace DEBUGCHANNELS will be set to. This is the namespace that needs to contain the dc namespace.
Next provide two debug header files (both named debug.h), one for installation with the library headers (ie libexample/debug.h) and one in an include directory that is only used while compiling your library itself - this one would not be installed.
The first one (the debug.h that will be installed) would look something like this:
The second "debug.h", which would not be installed but only be included when compiling the .cpp files (that #include "debug.h") of your library itself, then looks like this:
#ifndef DEBUG_H #define DEBUG_H #ifndef CWDEBUG #include <iostream> // std::cerr #include <cstdlib> // std::exit, EXIT_FAILURE#define AllocTag1(p)#define AllocTag2(p, desc)#define AllocTag_dynamic_description(p, data)#define AllocTag(p, data)#define Debug(STATEMENT...)#define Dout(cntrl, data)#define DoutFatal(cntrl, data) LibcwDoutFatal(, , cntrl, data)#define ForAllDebugChannels(STATEMENT...)#define ForAllDebugObjects(STATEMENT...)#define LibcwDebug(dc_namespace, STATEMENT...)#define LibcwDout(dc_namespace, d, cntrl, data)#define LibcwDoutFatal(dc_namespace, d, cntrl, data) do { ::std::cerr << data << ::std::endl; ::std::exit(EXIT_FAILURE); } while(1)#define LibcwdForAllDebugChannels(dc_namespace, STATEMENT...)#define LibcwdForAllDebugObjects(dc_namespace, STATEMENT...)#define NEW(x) new x#define CWDEBUG_ALLOC 0#define CWDEBUG_MAGIC 0#define CWDEBUG_LOCATION 0#define CWDEBUG_LIBBFD 0#define CWDEBUG_DEBUG 0#define CWDEBUG_DEBUGOUTPUT 0#define CWDEBUG_DEBUGM 0#define CWDEBUG_DEBUGT 0#define CWDEBUG_MARKER 0#endif // CWDEBUG #define LIBEXAMPLE_INTERNAL // See above. #include <libexample/debug.h> // The debug.h shown above. #define DEBUGCHANNELS libexample::channels #ifdef CWDEBUG #include <libcwd/debug.h> #endif #endif // DEBUG_H
Don't use Dout etc. in header files of libraries, instead use (for example) LibExampleDout etc., as shown above. If you want to use Dout etc. in your source files then you can do so after first including the "debug.h" as shown above.
The reason that libcwd uses the convention to put debug channels in the namespace dc is to avoid collisions between debug channel names of libraries. There are two types of name collisions possible: you upgrade or start to use a library which uses a debug channel that you had already defined, in that case you might need to change the name of your own channel, or you link with two or more libraries that both use libcwd and that defined the same debug channel, in that case you will have to make your own debug namespace as shown above and choose a new name for one of the channels.
For example, suppose you link with two libraries: lib1 and lib2 who use the above convention and defined their own namespaces called lib1 and lib2, but both defined a debug channel called foobar. Then you can rename these channels as follows. Make a debug header file that contains:
dc::channelname
in the source code and the namespace dc
will be uniquely defined. For instance, in the case of the above example, when writing dc::notice
the dc
will be unambiguously resolved to application::debug::channels::dc
, because it is the only dc
name space in LIBCWD_DEBUGCHANNELS (application::debug::channels
). The C++ standard states: "During the lookup of a name qualified by a namespace name, declarations that would otherwise be made
visible by a using-directive can be hidden by declarations with the same name in the namespace containing the using-directive;". This allows us to put a list of using-directives in application::debug::channels::dc
and then hide any collision by redefining it in application::debug::channels::dc
itself, either as new debug channel, or as reference to one of the debug channels of the library of choice.