Code

Say "skipped" when copying a single file is not necessary
[inkscape.git] / buildtool.cpp
index 8e0fd0e9da1735b0b3946728240f5f98df2e1c59..9fd3e464caaade8943787aa5bc1852e12442c402 100644 (file)
@@ -4,7 +4,7 @@
  * Authors:
  *   Bob Jamison
  *
- * Copyright (C) 2006 Bob Jamison
+ * Copyright (C) 2006-2007 Bob Jamison
  *
  *  This library is free software; you can redistribute it and/or
  *  modify it under the terms of the GNU Lesser General Public
  * btool
  * or 
  * btool {target}
+ * 
+ * Note: recent win32api builds from MinGW have gettimeofday()
+ * defined, so you might need to build with 
+ * g++ -O3 -DHAVE_GETTIMEOFDAY buildtool.cpp -o btool.exe
+ *     
  */  
 
-
+#define BUILDTOOL_VERSION  "BuildTool v0.6.11, 2007 Bob Jamison"
 
 #include <stdio.h>
+#include <fcntl.h>
 #include <unistd.h>
 #include <stdarg.h>
 #include <sys/stat.h>
 #include <time.h>
 #include <sys/time.h>
+#include <utime.h>
 #include <dirent.h>
 
 #include <string>
 #include <errno.h>
 
 
-
-
-namespace buildtool
-{
-
-
-
-//########################################################################
-//########################################################################
-//##  U T I L
 //########################################################################
+//# Definition of gettimeofday() for those who don't have it
 //########################################################################
-
-#ifdef __WIN32__
+#ifndef HAVE_GETTIMEOFDAY
 #include <sys/timeb.h>
+
 struct timezone {
       int tz_minuteswest; /* minutes west of Greenwich */
       int tz_dsttime;     /* type of dst correction */
@@ -92,8 +90,21 @@ static int gettimeofday (struct timeval *tv, struct timezone *tz)
         }
     return 0;
 }
+
 #endif
 
+
+
+
+
+
+
+namespace buildtool
+{
+
+
+
+
 //########################################################################
 //########################################################################
 //##  R E G E X P
@@ -950,18 +961,18 @@ friend class Parser;
 public:
     Element()
         {
-        parent = NULL;
+        init();
         }
 
     Element(const String &nameArg)
         {
-        parent = NULL;
+        init();
         name   = nameArg;
         }
 
     Element(const String &nameArg, const String &valueArg)
         {
-        parent = NULL;
+        init();
         name   = nameArg;
         value  = valueArg;
         }
@@ -1029,9 +1040,18 @@ public:
      * @param elem the element to output
      */
     void print();
+    
+    int getLine()
+        { return line; }
 
 protected:
 
+    void init()
+        {
+        parent = NULL;
+        line   = 0;
+        }
+
     void assign(const Element &other)
         {
         parent     = other.parent;
@@ -1040,6 +1060,7 @@ protected:
         namespaces = other.namespaces;
         name       = other.name;
         value      = other.value;
+        line       = other.line;
         }
 
     void findElementsRecursive(std::vector<Element *>&res, const String &name);
@@ -1055,7 +1076,8 @@ protected:
 
     String name;
     String value;
-
+    
+    int line;
 };
 
 
@@ -1123,15 +1145,17 @@ private:
         currentPosition = 0;
         }
 
-    void getLineAndColumn(long pos, long *lineNr, long *colNr);
+    int countLines(int begin, int end);
+
+    void getLineAndColumn(int pos, int *lineNr, int *colNr);
 
     void error(char *fmt, ...);
 
-    int peek(long pos);
+    int peek(int pos);
 
-    int match(long pos, const char *text);
+    int match(int pos, const char *text);
 
-    int skipwhite(long p);
+    int skipwhite(int p);
 
     int getWord(int p0, String &buf);
 
@@ -1147,12 +1171,10 @@ private:
 
     bool       keepGoing;
     Element    *currentNode;
-    long       parselen;
+    int        parselen;
     XMLCh      *parsebuf;
-    String  cdatabuf;
-    long       currentPosition;
-    int        colNr;
-
+    String     cdatabuf;
+    int        currentPosition;
 };
 
 
@@ -1168,6 +1190,7 @@ Element *Element::clone()
     elem->parent     = parent;
     elem->attributes = attributes;
     elem->namespaces = namespaces;
+    elem->line       = line;
 
     std::vector<Element *>::iterator iter;
     for (iter = children.begin(); iter != children.end() ; iter++)
@@ -1346,10 +1369,24 @@ String Parser::trim(const String &s)
     return res;
 }
 
-void Parser::getLineAndColumn(long pos, long *lineNr, long *colNr)
+
+int Parser::countLines(int begin, int end)
+{
+    int count = 0;
+    for (int i=begin ; i<end ; i++)
+        {
+        XMLCh ch = parsebuf[i];
+        if (ch == '\n' || ch == '\r')
+            count++;
+        }
+    return count;
+}
+
+
+void Parser::getLineAndColumn(int pos, int *lineNr, int *colNr)
 {
-    long line = 1;
-    long col  = 1;
+    int line = 1;
+    int col  = 1;
     for (long i=0 ; i<pos ; i++)
         {
         XMLCh ch = parsebuf[i];
@@ -1369,11 +1406,11 @@ void Parser::getLineAndColumn(long pos, long *lineNr, long *colNr)
 
 void Parser::error(char *fmt, ...)
 {
-    long lineNr;
-    long colNr;
+    int lineNr;
+    int colNr;
     getLineAndColumn(currentPosition, &lineNr, &colNr);
     va_list args;
-    fprintf(stderr, "xml error at line %ld, column %ld:", lineNr, colNr);
+    fprintf(stderr, "xml error at line %d, column %d:", lineNr, colNr);
     va_start(args,fmt);
     vfprintf(stderr,fmt,args);
     va_end(args) ;
@@ -1382,7 +1419,7 @@ void Parser::error(char *fmt, ...)
 
 
 
-int Parser::peek(long pos)
+int Parser::peek(int pos)
 {
     if (pos >= parselen)
         return -1;
@@ -1418,7 +1455,7 @@ String Parser::encode(const String &str)
 }
 
 
-int Parser::match(long p0, const char *text)
+int Parser::match(int p0, const char *text)
 {
     int p = p0;
     while (*text)
@@ -1432,7 +1469,7 @@ int Parser::match(long p0, const char *text)
 
 
 
-int Parser::skipwhite(long p)
+int Parser::skipwhite(int p)
 {
 
     while (p<parselen)
@@ -1589,7 +1626,9 @@ int Parser::parseDoctype(int p0)
     return p;
 }
 
-int Parser::parseElement(int p0, Element *par,int depth)
+
+
+int Parser::parseElement(int p0, Element *par,int lineNr)
 {
 
     int p = p0;
@@ -1603,6 +1642,9 @@ int Parser::parseElement(int p0, Element *par,int depth)
     if (ch!='<')
         return p0;
 
+    int line, col;
+    //getLineAndColumn(p, &line, &col);
+
     p++;
 
     String openTagName;
@@ -1613,6 +1655,7 @@ int Parser::parseElement(int p0, Element *par,int depth)
 
     //Add element to tree
     Element *n = new Element(openTagName);
+    n->line = lineNr + countLines(p0, p);
     n->parent = par;
     par->addChild(n);
 
@@ -1707,7 +1750,7 @@ int Parser::parseElement(int p0, Element *par,int depth)
         //# CHILD ELEMENT
         if (ch == '<')
             {
-            p2 = parseElement(p, n, depth+1);
+            p2 = parseElement(p, n, lineNr + countLines(p0, p));
             if (p2 == p)
                 {
                 /*
@@ -1799,7 +1842,7 @@ Element *Parser::parse(XMLCh *buf,int pos,int len)
     Element *rootNode = new Element("root");
     pos = parseVersion(pos);
     pos = parseDoctype(pos);
-    pos = parseElement(pos, rootNode, 0);
+    pos = parseElement(pos, rootNode, 1);
     return rootNode;
 }
 
@@ -1866,8 +1909,6 @@ Element *Parser::parseFile(const String &fileName)
     return n;
 }
 
-
-
 //########################################################################
 //########################################################################
 //##  E N D    X M L
@@ -1875,6 +1916,10 @@ Element *Parser::parseFile(const String &fileName)
 //########################################################################
 
 
+
+
+
+
 //########################################################################
 //########################################################################
 //##  U R I
@@ -2320,6 +2365,7 @@ URI URI::resolve(const URI &other) const
 }
 
 
+
 /**
  *  This follows the Java URI algorithm:
  *   1. All "." segments are removed.
@@ -2438,6 +2484,7 @@ void URI::trace(const char *fmt, ...)
 
 
 
+
 //#########################################################################
 //# P A R S I N G
 //#########################################################################
@@ -2825,8 +2872,9 @@ private:
 class MakeBase
 {
 public:
+
     MakeBase()
-        {}
+        { line = 0; }
     virtual ~MakeBase()
         {}
 
@@ -2856,6 +2904,18 @@ public:
      * Get an element value, performing substitutions if necessary
      */
     bool getValue(Element *elem, String &result);
+    
+    /**
+     * Set the current line number in the file
+     */         
+    void setLine(int val)
+        { line = val; }
+        
+    /**
+     * Get the current line number in the file
+     */         
+    int getLine()
+        { return line; }
 
 protected:
 
@@ -3028,6 +3088,7 @@ private:
      */         
     bool getSubstitutions(const String &s, String &result);
 
+    int line;
 
 
 };
@@ -3042,7 +3103,7 @@ void MakeBase::error(char *fmt, ...)
 {
     va_list args;
     va_start(args,fmt);
-    fprintf(stderr, "Make error: ");
+    fprintf(stderr, "Make error line %d: ", line);
     vfprintf(stderr, fmt, args);
     fprintf(stderr, "\n");
     va_end(args) ;
@@ -3384,6 +3445,9 @@ bool MakeBase::executeCommand(const String &command,
        }
     strcpy(paramBuf, (char *)command.c_str());
 
+    //# Go to http://msdn2.microsoft.com/en-us/library/ms682499.aspx
+    //# to see how Win32 pipes work
+
     //# Create pipes
     SECURITY_ATTRIBUTES saAttr; 
     saAttr.nLength = sizeof(SECURITY_ATTRIBUTES); 
@@ -3434,6 +3498,8 @@ bool MakeBase::executeCommand(const String &command,
         ret = false;
         }
 
+    delete[] paramBuf;
+
     DWORD bytesWritten;
     if (inbuf.size()>0 &&
         !WriteFile(stdinWrite, inbuf.c_str(), inbuf.size(), 
@@ -3457,46 +3523,52 @@ bool MakeBase::executeCommand(const String &command,
         error("executeCommand: could not close read pipe");
         return false;
         }
+
+    bool lastLoop = false;
     while (true)
         {
-        //trace("## stderr");
         DWORD avail;
-        if (!PeekNamedPipe(stderrRead, NULL, 0, NULL, &avail, NULL))
-            break;
+        DWORD bytesRead;
+        char readBuf[4096];
+
+        //trace("## stderr");
+        PeekNamedPipe(stderrRead, NULL, 0, NULL, &avail, NULL);
         if (avail > 0)
             {
-            DWORD bytesRead = 0;
-            char readBuf[1025];
-            if (avail>1024) avail = 1024;
-            if (!ReadFile(stderrRead, readBuf, avail, &bytesRead, NULL)
-                || bytesRead == 0)
+            bytesRead = 0;
+            if (avail>4096) avail = 4096;
+            ReadFile(stderrRead, readBuf, avail, &bytesRead, NULL);
+            if (bytesRead > 0)
                 {
-                break;
+                for (unsigned int i=0 ; i<bytesRead ; i++)
+                    errbuf.push_back(readBuf[i]);
                 }
-            for (unsigned int i=0 ; i<bytesRead ; i++)
-                errbuf.push_back(readBuf[i]);
             }
+
         //trace("## stdout");
-        if (!PeekNamedPipe(stdoutRead, NULL, 0, NULL, &avail, NULL))
-            break;
+        PeekNamedPipe(stdoutRead, NULL, 0, NULL, &avail, NULL);
         if (avail > 0)
             {
-            DWORD bytesRead = 0;
-            char readBuf[1025];
-            if (avail>1024) avail = 1024;
-            if (!ReadFile(stdoutRead, readBuf, avail, &bytesRead, NULL)
-                || bytesRead==0)
+            bytesRead = 0;
+            if (avail>4096) avail = 4096;
+            ReadFile(stdoutRead, readBuf, avail, &bytesRead, NULL);
+            if (bytesRead > 0)
                 {
-                break;
+                for (unsigned int i=0 ; i<bytesRead ; i++)
+                    outbuf.push_back(readBuf[i]);
                 }
-            for (unsigned int i=0 ; i<bytesRead ; i++)
-                outbuf.push_back(readBuf[i]);
             }
+            
+        //Was this the final check after program done?
+        if (lastLoop)
+            break;
+
         DWORD exitCode;
         GetExitCodeProcess(piProcessInfo.hProcess, &exitCode);
         if (exitCode != STILL_ACTIVE)
-            break;
-        Sleep(100);
+            lastLoop = true;
+
+        Sleep(10);
         }    
     //trace("outbuf:%s", outbuf.c_str());
     if (!CloseHandle(stdoutRead))
@@ -3518,11 +3590,9 @@ bool MakeBase::executeCommand(const String &command,
         ret = false;
         }
     
-    // Clean up
     CloseHandle(piProcessInfo.hProcess);
     CloseHandle(piProcessInfo.hThread);
 
-
     return ret;
 
 #else //do it unix-style
@@ -4704,23 +4774,23 @@ public:
      *  Constructor
      */
     FileRec()
-        {init(); type = UNKNOWN;}
+        { init(); type = UNKNOWN; }
 
     /**
      *  Copy constructor
      */
     FileRec(const FileRec &other)
-        {init(); assign(other);}
+        { init(); assign(other); }
     /**
      *  Constructor
      */
     FileRec(int typeVal)
-        {init(); type = typeVal;}
+        { init(); type = typeVal; }
     /**
      *  Assignment operator
      */
     FileRec &operator=(const FileRec &other)
-        {init(); assign(other); return *this;}
+        { init(); assign(other); return *this; }
 
 
     /**
@@ -4842,7 +4912,7 @@ private:
         path     = other.path;
         name     = other.name;
         suffix   = other.suffix;
-        files    = other.files;
+        files    = other.files; //avoid recursion
         }
 
 };
@@ -4856,19 +4926,19 @@ public:
      *  Constructor
      */
     DepTool()
-        {init();}
+        { init(); }
 
     /**
      *  Copy constructor
      */
     DepTool(const DepTool &other)
-        {init(); assign(other);}
+        { init(); assign(other); }
 
     /**
      *  Assignment operator
      */
     DepTool &operator=(const DepTool &other)
-        {init(); assign(other); return *this;}
+        { init(); assign(other); return *this; }
 
 
     /**
@@ -4989,9 +5059,7 @@ private:
     /**
      *
      */
-    bool processDependency(FileRec *ofile,
-                           FileRec *include,
-                           int depth);
+    bool processDependency(FileRec *ofile, FileRec *include);
 
     /**
      *
@@ -5010,8 +5078,7 @@ private:
 
     /**
      * A list of all files which will be processed for
-     * dependencies.  This is the only list that has the actual
-     * records.  All other lists have pointers to these records.     
+     * dependencies.
      */
     std::map<String, FileRec *> allFiles;
 
@@ -5019,7 +5086,7 @@ private:
      * The list of .o files, and the
      * dependencies upon them.
      */
-    std::map<String, FileRec *> depFiles;
+    std::map<String, FileRec *> oFiles;
 
     int depFileSize;
     char *depFileBuf;
@@ -5044,13 +5111,15 @@ void DepTool::init()
     fileList.clear();
     directories.clear();
     
-    //clear refs
-    depFiles.clear();
-    //clear records
+    //clear output file list
     std::map<String, FileRec *>::iterator iter;
-    for (iter=allFiles.begin() ; iter!=allFiles.end() ; iter++)
-         delete iter->second;
+    for (iter=oFiles.begin(); iter!=oFiles.end() ; iter++)
+        delete iter->second;
+    oFiles.clear();
 
+    //allFiles actually contains the master copies. delete them
+    for (iter= allFiles.begin(); iter!=allFiles.end() ; iter++)
+        delete iter->second;
     allFiles.clear(); 
 
 }
@@ -5215,7 +5284,8 @@ bool DepTool::sequ(int pos, char *key)
  */
 bool DepTool::addIncludeFile(FileRec *frec, const String &iname)
 {
-
+    //# if the name is an exact match to a path name
+    //# in allFiles, like "myinc.h"
     std::map<String, FileRec *>::iterator iter =
            allFiles.find(iname);
     if (iter != allFiles.end()) //already exists
@@ -5228,6 +5298,7 @@ bool DepTool::addIncludeFile(FileRec *frec, const String &iname)
         }
     else 
         {
+        //## Ok, it was not found directly
         //look in other dirs
         std::vector<String>::iterator diter;
         for (diter=directories.begin() ;
@@ -5236,12 +5307,17 @@ bool DepTool::addIncludeFile(FileRec *frec, const String &iname)
             String dfname = *diter;
             dfname.append("/");
             dfname.append(iname);
-            iter = allFiles.find(dfname);
+            URI fullPathURI(dfname);  //normalize path name
+            String fullPath = fullPathURI.getPath();
+            if (fullPath[0] == '/')
+                fullPath = fullPath.substr(1);
+            //trace("Normalized %s to %s", dfname.c_str(), fullPath.c_str());
+            iter = allFiles.find(fullPath);
             if (iter != allFiles.end())
                 {
                 FileRec *other = iter->second;
                 //trace("other: '%s'", iname.c_str());
-                frec->files[dfname] = other;
+                frec->files[fullPath] = other;
                 return true;
                 }
             }
@@ -5348,9 +5424,7 @@ bool DepTool::scanFile(const String &fname, FileRec *frec)
  *  Recursively check include lists to find all files in allFiles to which
  *  a given file is dependent.
  */
-bool DepTool::processDependency(FileRec *ofile,
-                             FileRec *include,
-                             int depth)
+bool DepTool::processDependency(FileRec *ofile, FileRec *include)
 {
     std::map<String, FileRec *>::iterator iter;
     for (iter=include->files.begin() ; iter!=include->files.end() ; iter++)
@@ -5364,7 +5438,7 @@ bool DepTool::processDependency(FileRec *ofile,
         FileRec *child  = iter->second;
         ofile->files[fname] = child;
       
-        processDependency(ofile, child, depth+1);
+        processDependency(ofile, child);
         }
 
 
@@ -5397,23 +5471,23 @@ bool DepTool::generateDependencies()
         FileRec *include = iter->second;
         if (include->type == FileRec::CFILE)
             {
-            String cFileName = iter->first;
-            FileRec *ofile      = new FileRec(FileRec::OFILE);
-            ofile->path         = include->path;
-            ofile->baseName     = include->baseName;
-            ofile->suffix       = include->suffix;
-            String fname     = include->path;
+            String cFileName   = iter->first;
+            FileRec *ofile     = new FileRec(FileRec::OFILE);
+            ofile->path        = include->path;
+            ofile->baseName    = include->baseName;
+            ofile->suffix      = include->suffix;
+            String fname       = include->path;
             if (fname.size()>0)
                 fname.append("/");
             fname.append(include->baseName);
             fname.append(".o");
-            depFiles[fname]    = ofile;
+            oFiles[fname]    = ofile;
             //add the .c file first?   no, don't
             //ofile->files[cFileName] = include;
             
             //trace("ofile:%s", fname.c_str());
 
-            processDependency(ofile, include, 0);
+            processDependency(ofile, include);
             }
         }
 
@@ -5461,7 +5535,7 @@ bool DepTool::saveDepFile(const String &fileName)
 
     fprintf(f, "<dependencies source='%s'>\n\n", sourceDir.c_str());
     std::map<String, FileRec *>::iterator iter;
-    for (iter=depFiles.begin() ; iter!=depFiles.end() ; iter++)
+    for (iter=oFiles.begin() ; iter!=oFiles.end() ; iter++)
         {
         FileRec *frec = iter->second;
         if (frec->type == FileRec::OFILE)
@@ -5512,7 +5586,7 @@ std::vector<DepRec> DepTool::loadDepFile(const String &depFile)
     if (root->getChildren().size()==0 ||
         root->getChildren()[0]->getName()!="dependencies")
         {
-        error("Main xml element should be <dependencies>");
+        error("loadDepFile: main xml element should be <dependencies>");
         delete root;
         return result;
         }
@@ -5525,47 +5599,53 @@ std::vector<DepRec> DepTool::loadDepFile(const String &depFile)
         {
         Element *objectElem = objects[i];
         String tagName = objectElem->getName();
-        if (tagName == "object")
-            {
-            String objName   = objectElem->getAttribute("name");
-             //trace("object:%s", objName.c_str());
-            DepRec depObject(objName);
-            depObject.path   = objectElem->getAttribute("path");
-            depObject.suffix = objectElem->getAttribute("suffix");
-            //########## DESCRIPTION
-            std::vector<Element *> depElems = objectElem->getChildren();
-            for (unsigned int i=0 ; i<depElems.size() ; i++)
+        if (tagName != "object")
+            {
+            error("loadDepFile: <dependencies> should have only <object> children");
+            return result;
+            }
+
+        String objName   = objectElem->getAttribute("name");
+         //trace("object:%s", objName.c_str());
+        DepRec depObject(objName);
+        depObject.path   = objectElem->getAttribute("path");
+        depObject.suffix = objectElem->getAttribute("suffix");
+        //########## DESCRIPTION
+        std::vector<Element *> depElems = objectElem->getChildren();
+        for (unsigned int i=0 ; i<depElems.size() ; i++)
+            {
+            Element *depElem = depElems[i];
+            tagName = depElem->getName();
+            if (tagName != "dep")
                 {
-                Element *depElem = depElems[i];
-                tagName = depElem->getName();
-                if (tagName == "dep")
-                    {
-                    String depName = depElem->getAttribute("name");
-                    //trace("    dep:%s", depName.c_str());
-                    depObject.files.push_back(depName);
-                    }
+                error("loadDepFile: <object> should have only <dep> children");
+                return result;
                 }
-            //Insert into the result list, in a sorted manner
-            bool inserted = false;
-            std::vector<DepRec>::iterator iter;
-            for (iter = result.begin() ; iter != result.end() ; iter++)
+            String depName = depElem->getAttribute("name");
+            //trace("    dep:%s", depName.c_str());
+            depObject.files.push_back(depName);
+            }
+
+        //Insert into the result list, in a sorted manner
+        bool inserted = false;
+        std::vector<DepRec>::iterator iter;
+        for (iter = result.begin() ; iter != result.end() ; iter++)
+            {
+            String vpath = iter->path;
+            vpath.append("/");
+            vpath.append(iter->name);
+            String opath = depObject.path;
+            opath.append("/");
+            opath.append(depObject.name);
+            if (vpath > opath)
                 {
-                String vpath = iter->path;
-                vpath.append("/");
-                vpath.append(iter->name);
-                String opath = depObject.path;
-                opath.append("/");
-                opath.append(depObject.name);
-                if (vpath > opath)
-                    {
-                    inserted = true;
-                    iter = result.insert(iter, depObject);
-                    break;
-                    }
+                inserted = true;
+                iter = result.insert(iter, depObject);
+                break;
                 }
-            if (!inserted)
-                result.push_back(depObject);
             }
+        if (!inserted)
+            result.push_back(depObject);
         }
 
     delete root;
@@ -5635,6 +5715,7 @@ public:
         TASK_SHAREDLIB,
         TASK_STATICLIB,
         TASK_STRIP,
+        TASK_TOUCH,
         TASK_TSTAMP
         } TaskType;
         
@@ -5703,7 +5784,7 @@ public:
     /**
      *
      */
-    Task *createTask(Element *elem);
+    Task *createTask(Element *elem, int lineNr);
 
 
 protected:
@@ -5760,7 +5841,7 @@ public:
     virtual ~TaskCC()
         {}
 
-    virtual bool needsCompiling(const DepRec &depRec,
+    virtual bool needsCompiling(const FileRec &depRec,
               const String &src, const String &dest)
         {
         return false;
@@ -5770,6 +5851,9 @@ public:
         {
         if (!listFiles(parent, fileSet))
             return false;
+            
+        FILE *f = NULL;
+        f = fopen("compile.lst", "w");
 
         bool refreshCache = false;
         String fullName = parent.resolve("build.dep");
@@ -5829,8 +5913,8 @@ public:
             //## Select command
             String sfx = dep.suffix;
             String command = ccCommand;
-            if (sfx == "cpp" || sfx == "c++" || sfx == "cc"
-                 || sfx == "CC")
+            if (sfx == "cpp" || sfx == "cxx" || sfx == "c++" ||
+                 sfx == "cc" || sfx == "CC")
                 command = cxxCommand;
  
             //## Make paths
@@ -5868,6 +5952,7 @@ public:
             srcName.append(dep.suffix);
             String srcFullName = parent.resolve(srcName);
             bool compileMe = false;
+            //# First we check if the source is newer than the .o
             if (isNewerThan(srcFullName, destFullName))
                 {
                 status("          : compile of %s required by %s",
@@ -5876,17 +5961,22 @@ public:
                 }
             else
                 {
+                //# secondly, we check if any of the included dependencies
+                //# of the .c/.cpp is newer than the .o
                 for (unsigned int i=0 ; i<dep.files.size() ; i++)
                     {
                     String depName;
-                    if (srcPath.size()>0)
+                    if (source.size()>0)
                         {
-                        depName.append(srcPath);
+                        depName.append(source);
                         depName.append("/");
                         }
                     depName.append(dep.files[i]);
                     String depFullName = parent.resolve(depName);
-                    if (isNewerThan(depFullName, destFullName))
+                    bool depRequires = isNewerThan(depFullName, destFullName);
+                    //trace("%d %s %s\n", depRequires,
+                    //        destFullName.c_str(), depFullName.c_str());
+                    if (depRequires)
                         {
                         status("          : compile of %s required by %s",
                                 destFullName.c_str(), depFullName.c_str());
@@ -5916,11 +6006,48 @@ public:
             //## Execute the command
 
             String outString, errString;
-            if (!executeCommand(cmd.c_str(), "", outString, errString))
+            bool ret = executeCommand(cmd.c_str(), "", outString, errString);
+
+            if (f)
+                {
+                fprintf(f, "########################### File : %s\n",
+                             srcFullName.c_str());
+                fprintf(f, "#### COMMAND ###\n");
+                int col = 0;
+                for (int i = 0 ; i < cmd.size() ; i++)
+                    {
+                    char ch = cmd[i];
+                    if (isspace(ch)  && col > 63)
+                        {
+                        fputc('\n', f);
+                        col = 0;
+                        }
+                    else
+                        {
+                        fputc(ch, f);
+                        col++;
+                        }
+                    if (col > 76)
+                        {
+                        fputc('\n', f);
+                        col = 0;
+                        }
+                    }
+                fprintf(f, "\n");
+                fprintf(f, "#### STDOUT ###\n%s\n", outString.c_str());
+                fprintf(f, "#### STDERR ###\n%s\n\n", errString.c_str());
+                }
+            if (!ret)
                 {
                 error("problem compiling: %s", errString.c_str());
                 return false;
                 }
+                
+            }
+
+        if (f)
+            {
+            fclose(f);
             }
         
         return true;
@@ -6037,6 +6164,7 @@ public:
                        }
                    if (!isNewerThan(fullSource, fullDest))
                        {
+                       status("          : skipped");
                        return true;
                        }
                    if (!copyFile(fullSource, fullDest))
@@ -6134,6 +6262,7 @@ public:
                        }
                    if (!isNewerThan(fullSource, fullDest))
                        {
+                       status("          : skipped");
                        return true;
                        }
                    if (!copyFile(fullSource, fullDest))
@@ -6303,7 +6432,12 @@ public:
             delType = DEL_DIR;
         if (fileName.size()>0 && dirName.size()>0)
             {
-            error("<delete> can only have one attribute of file= or dir=");
+            error("<delete> can have one attribute of file= or dir=");
+            return false;
+            }
+        if (fileName.size()==0 && dirName.size()==0)
+            {
+            error("<delete> must have one attribute of file= or dir=");
             return false;
             }
         String ret;
@@ -6498,7 +6632,7 @@ public:
             return false;
         if (!parent.getAttribute(elem, "strip", s))
             return false;
-        if (!getBool(s, doStrip))
+        if (s.size()>0 && !getBool(s, doStrip))
             return false;
         if (!parent.getAttribute(elem, "symfile", symFileName))
             return false;
@@ -6661,6 +6795,7 @@ public:
          name    = "msgfmt";
          command = "msgfmt";
          owndir  = false;
+         outName = "";
          }
 
     virtual ~TaskMsgFmt()
@@ -6702,8 +6837,17 @@ public:
                 destPath.append(subdir);
                 destPath.append("/");
                 }
-            destPath.append(fileName);
-            destPath[destPath.size()-2] = 'm';
+            //Pick the output file name
+            if (outName.size() > 0)
+                {
+                destPath.append(outName);
+                }
+            else
+                {
+                destPath.append(fileName);
+                destPath[destPath.size()-2] = 'm';
+                }
+
             String fullDest = parent.resolve(destPath);
 
             if (!isNewerThan(fullSource, fullDest))
@@ -6748,9 +6892,11 @@ public:
             command = s;
         if (!parent.getAttribute(elem, "todir", toDirName))
             return false;
+        if (!parent.getAttribute(elem, "out", outName))
+            return false;
         if (!parent.getAttribute(elem, "owndir", s))
             return false;
-        if (!getBool(s, owndir))
+        if (s.size()>0 && !getBool(s, owndir))
             return false;
             
         std::vector<Element *> children = elem->getChildren();
@@ -6769,10 +6915,11 @@ public:
 
 private:
 
-    String command;
-    String toDirName;
+    String  command;
+    String  toDirName;
+    String  outName;
     FileSet fileSet;
-    bool owndir;
+    bool    owndir;
 
 };
 
@@ -6916,7 +7063,7 @@ public:
     TaskSharedLib(MakeBase &par) : Task(par)
         {
         type = TASK_SHAREDLIB; name = "dll";
-        command = "ar crv";
+        command = "dllwrap";
         }
 
     virtual ~TaskSharedLib()
@@ -7037,6 +7184,7 @@ private:
 };
 
 
+
 /**
  * Run the "ar" command to archive .o's into a .a
  */
@@ -7113,6 +7261,7 @@ public:
         return true;
         }
 
+
     virtual bool parse(Element *elem)
         {
         String s;
@@ -7146,6 +7295,8 @@ private:
 };
 
 
+
+
 /**
  * Strip an executable
  */
@@ -7211,6 +7362,62 @@ private:
 };
 
 
+/**
+ *
+ */
+class TaskTouch : public Task
+{
+public:
+
+    TaskTouch(MakeBase &par) : Task(par)
+        { type = TASK_TOUCH; name = "touch"; }
+
+    virtual ~TaskTouch()
+        {}
+
+    virtual bool execute()
+        {
+        String fullName = parent.resolve(fileName);
+        String nativeFile = getNativePath(fullName);
+        if (!isRegularFile(fullName) && !isDirectory(fullName))
+            {            
+            // S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH
+            int ret = creat(nativeFile.c_str(), 0666);
+            if (ret != 0) 
+                {
+                error("<touch> could not create '%s' : %s",
+                    nativeFile.c_str(), strerror(ret));
+                return false;
+                }
+            return true;
+            }
+        int ret = utime(nativeFile.c_str(), (struct utimbuf *)0);
+        if (ret != 0)
+            {
+            error("<touch> could not update the modification time for '%s' : %s",
+                nativeFile.c_str(), strerror(ret));
+            return false;
+            }
+        return true;
+        }
+
+    virtual bool parse(Element *elem)
+        {
+        //trace("touch parse");
+        if (!parent.getAttribute(elem, "file", fileName))
+            return false;
+        if (fileName.size() == 0)
+            {
+            error("<touch> requires 'file=\"fileName\"' attribute");
+            return false;
+            }
+        return true;
+        }
+
+    String fileName;
+};
+
+
 /**
  *
  */
@@ -7241,7 +7448,7 @@ public:
 /**
  *
  */
-Task *Task::createTask(Element *elem)
+Task *Task::createTask(Element *elem, int lineNr)
 {
     String tagName = elem->getName();
     //trace("task:%s", tagName.c_str());
@@ -7274,6 +7481,8 @@ Task *Task::createTask(Element *elem)
         task = new TaskStaticLib(parent);
     else if (tagName == "strip")
         task = new TaskStrip(parent);
+    else if (tagName == "touch")
+        task = new TaskTouch(parent);
     else if (tagName == "tstamp")
         task = new TaskTstamp(parent);
     else
@@ -7282,6 +7491,8 @@ Task *Task::createTask(Element *elem)
         return NULL;
         }
 
+    task->setLine(lineNr);
+
     if (!task->parse(elem))
         {
         delete task;
@@ -7506,7 +7717,7 @@ public:
      *
      */
     virtual String version()
-        { return "BuildTool v0.6, 2006 Bob Jamison"; }
+        { return BUILDTOOL_VERSION; }
 
     /**
      * Overload a <property>
@@ -7578,11 +7789,6 @@ private:
      */
     bool parseProperty(Element *elem);
 
-    /**
-     *
-     */
-    bool parseTask(Task &task, Element *elem);
-
     /**
      *
      */
@@ -7943,8 +8149,9 @@ bool Make::parsePropertyFile(const String &fileName,
             return false;
             }
         val = s.substr(p);
-        if (key.size()==0 || val.size()==0)
+        if (key.size()==0)
             continue;
+        //allow property to be set, even if val=""
 
         //trace("key:'%s' val:'%s'", key.c_str(), val.c_str());
         //See if we wanted to overload this property
@@ -7989,10 +8196,8 @@ bool Make::parseProperty(Element *elem)
                 {
                 if (!getAttribute(elem, "location", val))
                     return false;
-                if (val.size() > 0)
-                    {
-                    properties[attrVal] = val;
-                    }
+                //let the property exist, even if not defined
+                properties[attrVal] = val;
                 }
             //See if we wanted to overload this property
             std::map<String, String>::iterator iter =
@@ -8042,6 +8247,8 @@ bool Make::parseFile()
 {
     status("######## PARSE : %s", uri.getPath().c_str());
 
+    setLine(0);
+
     Parser parser;
     Element *root = parser.parseFile(uri.getNativePath());
     if (!root)
@@ -8050,6 +8257,8 @@ bool Make::parseFile()
               uri.getNativePath().c_str());
         return false;
         }
+    
+    setLine(root->getLine());
 
     if (root->getChildren().size()==0 ||
         root->getChildren()[0]->getName()!="project")
@@ -8076,6 +8285,7 @@ bool Make::parseFile()
     for (unsigned int i=0 ; i<children.size() ; i++)
         {
         Element *elem = children[i];
+        setLine(elem->getLine());
         String tagName = elem->getName();
 
         //########## DESCRIPTION
@@ -8110,7 +8320,7 @@ bool Make::parseFile()
                 {
                 Element *telem = telems[i];
                 Task breeder(*this);
-                Task *task = breeder.createTask(telem);
+                Task *task = breeder.createTask(telem, telem->getLine());
                 if (!task)
                     return false;
                 allTasks.push_back(task);
@@ -8132,6 +8342,12 @@ bool Make::parseFile()
             //more work than targets[tname]=target, but avoids default allocator
             targets.insert(std::make_pair<String, Target>(tname, target));
             }
+        //######### none of the above
+        else
+            {
+            error("unknown toplevel tag: <%s>", tagName.c_str());
+            return false;
+            }
 
         }
 
@@ -8206,7 +8422,7 @@ timeDiffString(struct timeval &x, struct timeval &y)
     int millis  = (int)((microsX - microsY)/1000);
 
     int minutes = seconds/60;
-    seconds += minutes*60;
+    seconds -= minutes*60;
     char buf[80];
     snprintf(buf, 79, "%dm %d.%03ds", minutes, seconds, millis);
     String ret = buf;
@@ -8425,7 +8641,7 @@ static bool depTest()
     deptool.setSourceDirectory("/dev/ink/inkscape/src");
     if (!deptool.generateDependencies("build.dep"))
         return false;
-    std::vector<buildtool::DepRec> res =
+    std::vector<buildtool::FileRec> res =
            deptool.loadDepFile("build.dep");
     if (res.size() == 0)
         return false;