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

The Custom debug.h File
[Configuration, Installation And Getting Started]

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

Libraries that use libcwd should not put their debug channels in libcwd::channels::dc.  The correct way to declare new debug channels is by putting them in a namespace of the library and providing new macros for writing debug output.  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:

namespace libexample {
  namespace channels {
    namespace dc {
      ::libcwd::channel_ct warp("WARP");
    }
  }
}

Then provide a debug header file (debug.h) with the following:

#ifndef LIBEXAMPLE_DEBUG_H
#define LIBEXAMPLE_DEBUG_H

#ifndef DEBUGCHANNELS
#define DEBUGCHANNELS ::libexample::channels
#endif
#include <libcwd/debug.h>

namespace libexample {
  namespace channels {
    namespace dc {
      using namespace libcwd::channels::dc;
      extern libcwd::channel_ct warp;
    }
  }
}

// Define private debug output macros for use in header files of the library,
// there is no reason to do this for normal applications.
#ifdef CWDEBUG
#define LibExampleDout(cntrl, data) \
    LibcwDout(libexample::channels, libcwd::libcw_do, cntrl, data)
#define LibExampleDoutFatal(cntrl, data) \
    LibcwDoutFatal(libexample::channels, libcwd::libcw_do, cntrl, data)
#else
#define LibExampleDout(cntrl, data)
#define LibExampleDoutFatal(cntrl, data) LibcwDoutFatal(::std, , cntrl, data)
#endif

#endif // LIBEXAMPLE_DEBUG_H

This will make your debug channels available in the usual way (by using Dout and friends.  LibExampleDout and friends are only for use in the header files of `libexample' itself) avoiding any linker name collisions.

Header files of libraries

Don't use Dout etc. in header files of libraries, instead use (for example) LibExampleDout etc., as shown above.  It is advisable not to include any debug.h in your headerfiles.  Instead, add the following lines to each header file that needs debugging:

#ifndef LIBEXAMPLE_DEBUG_H
#error "You need to include the appropriate debug.h in the source file, before including this header file."
#endif

Don't use "libexample/%debug.h" in this error message because someone else might write a library that is using your library and needs a different debug.h to be included in end applications.

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:

#ifndef DEBUGCHANNELS
#define DEBUGCHANNELS ::application::channels
#endif
#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 DEBUGCHANNELS.  Because all debug channels are specified as dc::channelname (and there is no using namespace someother::dc in name space DEBUGCHANNELS!), the namespace dc is 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 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.