Browse Source

[trac558] Update message compiler

Change of the message compiler to avoid a possible clash of names
in generated symbols.  Also update documentation.
Stephen Morris 14 years ago
parent
commit
2ebf994dfc
4 changed files with 111 additions and 64 deletions
  1. 45 16
      src/lib/log/compiler/message.cc
  2. 60 43
      src/lib/log/documentation.txt
  3. 2 2
      src/lib/log/messagedef.cc
  4. 4 3
      src/lib/log/messagedef.h

+ 45 - 16
src/lib/log/compiler/message.cc

@@ -195,24 +195,37 @@ sortedIdentifiers(MessageDictionary* dictionary) {
 /// for "namspace a" and the other for "namespace b".
 ///
 /// This function returns the set of namespace components as a vector of
-/// strings.
+/// strings.  A vector of one element, containing the empty string, is returned
+/// if the anonymous namespace is specified.
 ///
-/// \param ns Argument to $NAMESPACE (passed by valid, as we will be modifying
+/// \param ns Argument to $NAMESPACE (passed by value, as we will be modifying
 /// it.)
 
 vector<string>
 splitNamespace(string ns) {
 
-    // Namespaces components are separated by double colon characters - convert
-    // to single colons.
-    size_t dcolon;
-    while ((dcolon = ns.find("::")) != string::npos) {
-        ns.replace(dcolon, 2, ":");
+    vector<string>  components;
+
+    if (ns == "::") {
+
+        // Unnamed namespace
+        components.push_back("");
+        
+    } else {
+
+        // Namespaces components are separated by double colon characters -
+         //convert to single colons.
+        size_t dcolon;
+        while ((dcolon = ns.find("::")) != string::npos) {
+            ns.replace(dcolon, 2, ":");
+        }
+
+        // ... and return the vector of namespace components split on the single
+        // colon.
+        components = isc::strutil::tokens(ns, ":");
     }
 
-    // ... and return the vector of namespace components split on the single
-    // colon.
-    return isc::strutil::tokens(ns, ":");
+    return components;
 }
 
 
@@ -222,8 +235,16 @@ splitNamespace(string ns) {
 void
 writeOpeningNamespace(ostream& output, vector<string>& ns) {
     if (!ns.empty()) {
-        for (int i = 0; i < ns.size(); ++i) {
-            output << "namespace " << ns[i] << " {\n";
+        if (ns[0].empty()) {
+
+            // Empty namespace
+            output << "namespace {\n";
+        } else {
+
+            // Output namespaces in correct order
+            for (int i = 0; i < ns.size(); ++i) {
+                output << "namespace " << ns[i] << " {\n";
+            }
         }
         output << "\n";
     }
@@ -236,8 +257,12 @@ writeOpeningNamespace(ostream& output, vector<string>& ns) {
 void
 writeClosingNamespace(ostream& output, vector<string>& ns) {
     if (!ns.empty()) {
-        for (int i = ns.size() - 1; i >= 0; --i) {
-            output << "} // namespace " << ns[i] << "\n";
+        if (ns[0].empty()) {
+            output << "} // Unnamed namespace\n";
+        } else {
+            for (int i = ns.size() - 1; i >= 0; --i) {
+                output << "} // namespace " << ns[i] << "\n";
+            }
         }
         output << "\n";
     }
@@ -305,13 +330,17 @@ writeHeaderFile(const string& file, const string& prefix, const string& ns,
         writeClosingNamespace(hfile, ns_components);
 
         // Now create the reference to the message initializer to ensure that
-        // it gets run at program startup.
+        // it gets run at program startup.  Note that even the instantiator
+        // object is given its own unique name - multiple message header files
+        // might be included in the file, and identical multiple static names
+        // would clash.
 
         hfile << "namespace isc {\n" <<
             "namespace log {\n" <<
             "\n" <<
             "extern MessageInitializer " << mi_name << ";\n" <<
-            "static MessageInstantiator m(&" << mi_name << ");\n" <<
+            "static MessageInstantiator instantiate_" << mi_name << "(\n" <<
+            "   &" << mi_name << ");\n" <<
             "\n" <<
             "} // namespace log\n" <<
             "} // namespace isc\n" <<

+ 60 - 43
src/lib/log/documentation.txt

@@ -13,19 +13,19 @@ Hierarchical Logging System
 When a program writes a message to the logging system, it does so using an
 instance of the Logger class.  As well as performing the write of the message,
 the logger identifies the source of the message: different sources can write
-to different destinations and can log different severities of messages.  For
-example, the "cache" logger could write messages of DEBUG severity or above
-to a file while all other components write messages of "INFO" severity or above
-to the Syslog file.
+to different destinations and can log different severities of messages.
+For example, the "cache" logger could write messages of DEBUG severity or
+above to a file while all other components write messages of "INFO" severity
+or above to the Syslog file.
 
-The loggers are hierarchical in that each logger is the child of another logger.
-The top of the hierarchy is the root logger, which does not have a parent.  The
-point of the hierarchy is that unless a logger is explicitly assigned an
-attribute (such as severity of message being logger), it picks it up from the
-parent.  (In BIND-10, there is the root logger (named after the program) and
-every other logger is a child of that.)  So in the example above, the
-INFO/Syslog attributes could be associated with the root logger while the
-DEBUG/file attributes are associated with the "cache" logger.
+The loggers are hierarchical in that each logger is the child of another
+logger.  The top of the hierarchy is the root logger, which does not have
+a parent.  The point of the hierarchy is that unless a logger is explicitly
+assigned an attribute (such as severity of message being logger), it picks
+it up from the parent.  (In BIND-10, there is the root logger (named after
+the program) and every other logger is a child of that.)  So in the example
+above, the INFO/Syslog attributes could be associated with the root logger
+while the DEBUG/file attributes are associated with the "cache" logger.
 
 
 Separation of Messages Definitions And Text
@@ -38,10 +38,11 @@ retrieve the message associated with it (e.g. "unable to open %s for input").
 substitutes any message parameters (in this example, the string that is an
 invalid filename) and logs it to the destination.
 
-In the BIND-10 system, a set of default messages are linked into the program.
-At run-time. each program reads a message file, updating the stored definitions;
-this updated text is logged.  However, to aid support, the message identifier
-so in the example above, the message finally logged would be something like:
+In the BIND-10 system, a set of default messages are linked into the
+program.  At run-time. each program reads a message file, updating the
+stored definitions; this updated text is logged.  However, to aid support,
+the message identifier so in the example above, the message finally logged
+would be something like:
 
     OPENIN, unable to open a.txt for input
 
@@ -57,11 +58,11 @@ The steps in using the system are:
    Ideally the file should have a file type of ".msg".
 
 2. Run it through the message compiler to produce the .h and .cc files.  It
-   is intended that this step be included in the build process.  However, for
-   not run the compiler (found in the "compiler" subdirectory) manually.  The
-   only argument is the name of the message file: it will produce as output
-   two files, having the same name as the input file but with file types of
-   ".h" and ".cc".
+   is intended that this step be included in the build process.  However,
+   for not run the compiler (found in the "compiler" subdirectory) manually.
+   The only argument is the name of the message file: it will produce as
+   output two files, having the same name as the input file but with file
+   types of ".h" and ".cc".
 
    The compiler is built in the "compiler" subdirectory of the "src/lib/log"
    directory.
@@ -70,13 +71,13 @@ The steps in using the system are:
    make sure that the .cc file is compiled and linked into your program -
    static initialization will add the symbols to the global dictionary.
 
-4. Declare loggers in your code and use them to log messages.  This is described
-   in more detail below.
+4. Declare loggers in your code and use them to log messages.  This is
+   described in more detail below.
 
 5. To set the debug level and run-time message file, call runTimeInit (declared
    in logger_support.h) in the main program unit.  This is a temporary solution
-   for Year 2, and will be replaced at a later date, the information coming from
-   the configuration database.
+   for Year 2, and will be replaced at a later date, the information coming
+   from the configuration database.
 
 
 Message Files
@@ -84,9 +85,9 @@ Message Files
 
 File Contents and Format
 ------------------------
-A message file is a file containing message definitions.  Typically there will
-be one message file for each component that declares message symbols.  An
-example file could be:
+A message file is a file containing message definitions.  Typically there
+will be one message file for each component that declares message symbols.
+An example file could be:
 
 -- BEGIN --
 
@@ -94,6 +95,7 @@ example file could be:
 # $ID:$
 
 $PREFIX TEST_
+$NAMESPACE isc::log
 TEST1       message %s is much too large
 + This message is a test for the general message code
 
@@ -104,8 +106,8 @@ UNKNOWN     unknown message
 
 Points to note:
 * Leading and trailing space are trimmed from the line.  Although the above
-  exampl,e has every line starting at column 1, the lines could be indented if
-  desired.
+  exampl,e has every line starting at column 1, the lines could be indented
+  if desired.
 
 * Blank lines are ignored.
 
@@ -113,16 +115,22 @@ Points to note:
   a line by themselves - inline comments will be interpreted as part of the
   text of the line.
 
-* Lines starting $ are directives.  At present, the only directive recognised
-  is $PREFIX, which has one argument: the string used to prefix symbols.  If
-  there is no facility directive, there is no prefix to the symbols. (Prefixes
-  are explained below.)
+* Lines starting $ are directives.  At present, two directives are recognised:
+
+  * $PREFIX, which has one argument: the string used to prefix symbols.  If
+    absent, there is no prefix to the symbols. (Prefixes are explained below.)
+  * $NAMESPACE, which has one argument: the namespace in which the symbols are
+    created.  (Specifying the argument as a double colon - i.e. "$NAMESPACE
+    ::" puts the symbol definitions in the unnamed namespace.  And not
+    including a $NAMESPACE directive will result in the symbols note being
+    put in any namespace.
 
 * Lines starting + indicate an explanation for the preceding message.  These
-  are intended to be processed by a separate program and used to generate an
-  error messages manual.  However they are treated like comments by the message
-  compiler.  As with comments, these must be on a line by themselves; if inline,
-  the text (including the leading "+") will be interpreted as part of the line.
+  are intended to be processed by a separate program and used to generate
+  an error messages manual.  However they are treated like comments by the
+  message compiler.  As with comments, these must be on a line by themselves;
+  if inline, the text (including the leading "+") will be interpreted as
+  part of the line.
 
 * Message lines.  These comprise a symbol name and a message, which may
   include zero or more printf-style tokens.  Symbol names will be upper-cased
@@ -132,12 +140,17 @@ Points to note:
 Message Compiler
 ----------------
 The message compiler is a program built in the src/log/compiler directory.
-It processes the message file to produce two files:
+It is invoked by the command:
+
+    message [-h] [-v] <message-file>
+
+("-v" prints the version number and exits; "-h" prints brief help text.)
+The message compiler processes the message file to produce two files:
 
 1) A C++ header file (called <message-file-name>.h) that holds lines of
 the form:
 
-   namespace {
+   namespace <namespace> {
    isc::log::MessageID PREFIX_IDENTIFIER = "IDENTIFIER";
       :
    }
@@ -146,12 +159,17 @@ The symbols define the keys in the global message dictionary.  At present
 they are defined as std::strings, but a future implementation could redefine
 them as numeric values.
 
+The namespace enclosing the symbols is set by the $NAMESPACE directive.
+
 The "PREFIX_" part of the symbol name is the string defined in the $PREFIX
 the argument to the directive.  So "$PREFIX MSG_" would prefix the identifer
 ABC with "MSG_" to give the symbol MSG_ABC.  Similarly "$PREFIX E" would
 prefix it with "E" to give the symbol EABC.  If no $PREFIX is given, no
 prefix appears (so the symbol in this example would be ABC).
 
+The header file also includes a couple of lines to ensure that the message
+text is included in the final program image.
+
 
 2) A C++ source file (called <message-file-name>.cc) that holds the code to
 insert the symbols and messages into the map.
@@ -201,8 +219,7 @@ To use the current version of the logging:
 
        isc::log::RootLoggerName("b10-auth");
 
-   It should be declared outside an execution unit to allow other statically-
-   declared loggers to pick it up.
+   This can be declared inside or outside an execution unit.
 
 2. In the code that needs to do logging, declare a logger with a given name,
    e.g.
@@ -281,7 +298,7 @@ the program started but attempts to open one or more network interfaces failed.
 WARN
 ----
 An unusual event  happened.  Although the program will continue working
-normally, the event was sufficiently out of the ordinary to warrant drawings
+normally, the event was sufficiently out of the ordinary to warrant drawing
 attention to it.  For example, at program start-up a zone was loaded that
 contained no resource records,
 

+ 2 - 2
src/lib/log/messagedef.cc

@@ -1,4 +1,4 @@
-// File created from messagedef.mes on Mon Feb  7 11:18:04 2011
+// File created from messagedef.mes on Mon Feb  7 11:47:45 2011
 
 #include <cstddef>
 #include <log/message_initializer.h>
@@ -29,7 +29,7 @@ const char* values[] = {
 namespace isc {
 namespace log {
 
-MessageInitializer messagedef_cc_Mon_Feb__7_11_18_04_2011(values);
+MessageInitializer messagedef_cc_Mon_Feb__7_11_47_45_2011(values);
 
 } // namespace log
 } // namespace isc

+ 4 - 3
src/lib/log/messagedef.h

@@ -1,4 +1,4 @@
-// File created from messagedef.mes on Mon Feb  7 11:18:04 2011
+// File created from messagedef.mes on Mon Feb  7 11:47:45 2011
 
 #ifndef __MESSAGEDEF_H
 #define __MESSAGEDEF_H
@@ -31,8 +31,9 @@ static const isc::log::MessageID MSG_WRITERR = "WRITERR";
 namespace isc {
 namespace log {
 
-extern MessageInitializer messagedef_cc_Mon_Feb__7_11_18_04_2011;
-static MessageInstantiator m(&messagedef_cc_Mon_Feb__7_11_18_04_2011);
+extern MessageInitializer messagedef_cc_Mon_Feb__7_11_47_45_2011;
+static MessageInstantiator instantiate_messagedef_cc_Mon_Feb__7_11_47_45_2011(
+   &messagedef_cc_Mon_Feb__7_11_47_45_2011);
 
 } // namespace log
 } // namespace isc