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.
#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.
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); } } }
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.