How to organize debug-channel namespaces, especially for libraries.
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.
This custom debug.h normally lives in the root of your project; what really matters is that its include directory is searched before the cwds directory, so that a plain #include "debug.h" from any source file picks up your version, if it exists, and only includes cwds/debug.h if your project doesn't define its own debug.h.
The custom debug.h should include cwds/debug.h which sets up the surrounding machinery (the Debug, Dout and ASSERT macros, the dc namespace) for both the CWDEBUG and non-CWDEBUG case: turning most macros into no-ops. Furthermore, your debug.h is the place where you get to influence that setup before it happens.
Having your own debug.h is handy because it is the natural, single point where you can:
A recommended skeleton defines NAMESPACE_DEBUG, includes cwds/debug.h to piggy-back on its boilerplate, and then declares the project-wide debug channels. Note that each declared channel still has to be defined in exactly one .cpp file:
«download»
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:
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 Debug(/*STATEMENTS*/...)
#define Dout(cntrl, ...)
#define DoutFatal(cntrl, ...) LibcwDoutFatal(, , cntrl, __VA_ARGS__)
#define ForAllDebugChannels(/*STATEMENT*/...)
#define ForAllDebugObjects(/*STATEMENT*/...)
#define LibcwDebug(dc_namespace, /*STATEMENTS*/...)
#define LibcwDout(dc_namespace, d, cntrl, ...)
#define LibcwDoutFatal(dc_namespace, d, cntrl, ...) \
do \
{ \
::std::cerr << __VA_ARGS__ << ::std::endl; \
::std::exit(EXIT_FAILURE); \
} while (1)
#define LibcwdForAllDebugChannels(dc_namespace, /*STATEMENT*/...)
#define LibcwdForAllDebugObjects(dc_namespace, /*STATEMENT*/...)
#define CWDEBUG_LOCATION 0
#define CWDEBUG_DEBUG 0
#define CWDEBUG_DEBUGOUTPUT 0
#define CWDEBUG_DEBUGT 0
#endif // CWDEBUG
#define LIBEXAMPLE_INTERNAL // See above.
#include <libexample/debug.h> // The debug.h shown above.
#define LIBCWD_DEBUG_CHANNELS 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: