diff host/libcdl/build.cxx @ 103:95f3e12a6327 ecos-sw-2000-06-23

Merge from eCos master repository on 2000-06-23-16:41:10-BST
author jlarmour
date Fri, 23 Jun 2000 17:06:31 +0000
parents 6736c52df507
children 6ed91473a1cd
line wrap: on
line diff
--- a/host/libcdl/build.cxx
+++ b/host/libcdl/build.cxx
@@ -1114,6 +1114,143 @@ CdlBuildLoadableBody::update_all_build_i
 //}}}
 
 //}}}
+//{{{  Version number #define's         
+
+// ----------------------------------------------------------------------------
+// Given a package xxxPKG_A_B_C with a version V1_2_3, generate additional
+// #define's of the form:
+//
+//   #define xxxNUM_A_B_C_VERSION_MAJOR 1
+//   #define xxxNUM_A_B_C_VERSION_MINOR 2
+//   #define xxxNUM_A_B_C_VERSION_RELEASE 3
+//
+// The goal here is to allow application code to cope with API
+// changes (which of course should be a rare event but cannot be
+// eliminated completely). C preprocessor #if statements are
+// essentially limited to numerical values, so there is no easy
+// way of coping with V1_2_3 at the preprocessor level. However it
+// is possible to cope with VERSION_NUMBER #define's.
+//
+// Note that only application code and third party packages are
+// affected. 
+//
+// These #define's go into system.h, alongside the main definition of
+// the package. There seems to be little point in putting them in the
+// package's own configuration header.
+//
+// There are three problems. First, what should be done for packages
+// which do not follow the naming conventions? Given a completely
+// random package rather than something like xxxPKG_..., what symbol
+// names should be used? Basically, if the package does not follow the
+// naming convention then there is no safe way of generating new
+// symbols. Any names that are chosen might clash. Of course even for
+// packages that do follow the naming convention a clash is still
+// possible, just a lot less likely.
+//
+// Conclusion: if a package does not follow the naming convention, do
+// not generate version #define's for it.
+//
+// Second, what happens if a different version numbering scheme is
+// used? For example the release number might be absent. Version
+// numbering schemes might change between releases, but application
+// code may still check the #define's.
+//
+// Third and related, what should happen for "current" and anoncvs? Do
+// we want to look at what other versions are installed and bump one
+// of the numbers?
+//
+// Conclusion: the version #define's always have to be generated,
+// even if they are not present in the version string, to allow
+// application code to test these symbols anyway. A safe default is
+// necessary, and -1 is probably the best bet. For example, if
+// the version is bumped from 1.3.287 to 1.4 then the release number
+// for the latter is set to -1. Another possible default would be
+// 0, but that could cause problems for packages that start counting
+// from 0 (not a common practice, but...)
+//
+// This leaves the question of what to do about "current". Chances are
+// that "current" comes from anoncvs and is always more recent than
+// any official release, so when comparing versions "current" should
+// always be greater than anything else. This can be achieved by using
+// a sufficiently large number for the major version. In practice
+// it is cleaner to have another #define to indicate the current
+// version, and then define package versions to match, i.e.:
+//
+//   #define CYGNUM_VERSION_CURRENT 0x7fffff00
+//   ...
+//   #define xxxNUM_A_B_C_VERSION_MAJOR   CYGNUM_VERSION_CURRENT
+//   #define xxxNUM_A_B_C_VERSION_MINOR   -1
+//   #define xxxNUM_A_B_C_VERSION_RELEASE -1
+//
+// All comparisons should now work sensibly. Leaving a little bit
+// of slack for VERSION_CURRENT seems like a good precaution.
+
+static void
+system_h_add_version_header(Tcl_Channel system_h)
+{
+    CYG_REPORT_FUNCNAME("system_h_add_version_header");
+    Tcl_Write(system_h, "#define CYGNUM_VERSION_CURRENT 0x7fffff00\n", -1);
+    CYG_REPORT_RETURN();
+}
+
+static void
+system_h_add_package_versioning(Tcl_Channel system_h, std::string name, std::string value)
+{
+    CYG_REPORT_FUNCNAME("system_h_add_package_versioning");
+
+    char name_buf[256];
+    char line_buf[512];
+    
+    // The first thing to check is that the package name can be used
+    // as the basis for the version symbols.
+    bool ok = false;
+    unsigned int i;
+    for (i = 0; i < name.size(); i++) {
+        if ('_' == name[i]) {
+            if (3 < i) {
+                if ((name[i-3] == 'P') && (name[i-2] == 'K') && (name[i-1] == 'G')) {
+                    ok = true;
+                }
+            }
+            break;
+        }
+    }
+    if (name.size() >= 256) {
+        ok = false;
+    }
+    if (!ok) {
+        CYG_REPORT_RETURN();
+        return;
+    }
+
+    strcpy(name_buf, name.c_str());
+    
+    // Change from xxxPKG to xxxNUM
+    name_buf[i - 3] = 'N';
+    name_buf[i - 2] = 'U';
+    name_buf[i - 1] = 'M';
+
+    // Now determine the version strings.
+    std::string major   = "-1";
+    std::string minor   = "-1";
+    std::string release = "-1";
+    if ("current" == value) {
+        major   = "CYGNUM_VERSION_CURRENT";
+    } else {
+        Cdl::split_version_string(value, major, minor, release);
+    }
+
+    sprintf(line_buf, "#define %s_VERSION_MAJOR %s\n", name_buf, major.c_str());
+    Tcl_Write(system_h, line_buf, -1);
+    sprintf(line_buf, "#define %s_VERSION_MINOR %s\n", name_buf, minor.c_str());
+    Tcl_Write(system_h, line_buf, -1);
+    sprintf(line_buf, "#define %s_VERSION_RELEASE %s\n", name_buf, release.c_str());
+    Tcl_Write(system_h, line_buf, -1);
+    
+    CYG_REPORT_RETURN();
+}
+
+//}}}
 //{{{  CdlDefinableBody                 
 
 //{{{  Basics                                           
@@ -1468,6 +1605,11 @@ CdlDefinableBody::generate_config_header
                 tmp = "#define "+ tmp + "\n";
                 Tcl_Write(chan, const_cast<char*>(tmp.c_str()), -1);
             }
+            
+            // For loadables, add additional version information to system_h
+            if (dynamic_cast<CdlConstLoadable>((CdlConstNode)this) == loadable) {
+                system_h_add_package_versioning(system_h, name, value);
+            }
         }
     }
 
@@ -1956,11 +2098,14 @@ CdlToplevelBody::generate_config_headers
         sprintf(local_buf, banner_format, "SYSTEM_H", "SYSTEM_H", "system.h");
         Tcl_Write(system_h, local_buf, -1);
 
+        // Add generic version information
+        system_h_add_version_header(system_h);
+        
         // The rest of system.h will be filled in by the following loop.
         //
-        // Next, walk down the previously constructed headers vector,
-        // create appropriate files, and let each DefineLoadable fill
-        // in the file for itself.
+        // Walk down the previously constructed headers vector, create
+        // appropriate files, and let each DefineLoadable fill in the
+        // file for itself.
         std::vector<std::pair<CdlDefineLoadable, std::string> >::iterator outer_i;
         std::vector<std::pair<CdlDefineLoadable, std::string> >::iterator inner_i;
         for (outer_i = headers.begin(); outer_i != headers.end(); outer_i++) {