Main Page   Reference Manual   Namespace List   Compound List   Namespace Members   Compound Members   File Members  

Collaboration diagram for The Custom debug.h File:

Debug channels and namespace

Applications

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).

See Also
Preparation

Libraries

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:

// This is for example <libexample/debug.h>
#ifndef LIBEXAMPLE_DEBUG_H
#define LIBEXAMPLE_DEBUG_H
#ifdef CWDEBUG
namespace libexample {
namespace channels {
namespace dc {
using namespace libcwd::channels::dc;
extern libcwd::channel_ct warp;
// Add new channels here...
}
}
}
// Define private debug output macros for use in header files of the library,
// there is no reason to do this for normal applications.
// We use a literal libexample::channels here and not LIBCWD_DEBUGCHANNELS!
#define LibexampleDebug(STATEMENT...) LibcwDebug(libexample::channels, STATEMENT)
#define LibexampleDout(cntrl, data) LibcwDout(libexample::channels, libcwd::libcw_do, cntrl, data)
#define LibexampleDoutFatal(cntrl, data) LibcwDoutFatal(libexample::channels, libcwd::libcw_do, cntrl, data)
#define LibexampleForAllDebugChannels(STATEMENT...) LibcwdForAllDebugChannels(libexample::channels, STATEMENT)
#define LibexampleForAllDebugObjects(STATEMENT...) LibcwdForAllDebugObjects(libexample::channels, STATEMENT)
// All other macros might be used in header files of libexample, but need to be
// defined by the debug.h of the application that uses it.
// LIBEXAMPLE_INTERNAL is defined when the library itself is being compiled (see below).
#if !defined(Debug) && !defined(LIBEXAMPLE_INTERNAL)
#error The application source file (.cc or .cpp) must use '#include "debug.h"' _before_ including the header file that it includes now, that led to this error.
#endif
#else
#define LibexampleDebug(STATEMENT...) do { } while(0)
#define LibexampleDout(cntrl, data) do { } while(0)
#define LibexampleDoutFatal(cntrl, data) do { ::std::cerr << data << ::std::endl; ::std::exit(EXIT_FAILURE); } while(1)
#define LibexampleForAllDebugChannels(STATEMENT...) do { } while(0)
#define LibexampleForAllDebugObjects(STATEMENT...) do { } while(0)
#endif // CWDEBUG
#endif // LIBEXAMPLE_DEBUG_H

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

Header files of libraries

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.

Debug channel name collisions

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:

#define DEBUGCHANNELS ::application::channels
#include <lib1/debug.h>
#include <lib2/debug.h>
namespace application {
namespace channels {
namespace dc {
using namespace lib1::channels::dc;
using namespace lib2::channels::dc;
static libcwd::channel_ct& foobar1(lib1::channels::dc::foobar);
static libcwd::channel_ct& foobar2(lib2::channels::dc::foobar);
}
}
}
The hiding mechanism of the above `cascading' of debug channel declarations of libraries works as follows.  The debug macros use a using-directive to include the scope LIBCWD_DEBUGCHANNELS, which is set to DEBUGCHANNELS if you defined that and to libcwd::channels otherwise.  All debug channels are specified as 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.
Copyright © 2001 - 2004 Carlo Wood.  All rights reserved.