Code

Remove working file phoebedom.h from tree.
[inkscape.git] / buildtool.cpp
index ac7a1a8ae31da6e67d4ebf73ddeeb5cb15038f17..21a7a4aef8131d83b30a315530adc850e15a00d8 100644 (file)
@@ -4,7 +4,7 @@
  * Authors:
  *   Bob Jamison
  *
- * Copyright (C) 2006-2007 Bob Jamison
+ * Copyright (C) 2006-2008 Bob Jamison
  *
  *  This library is free software; you can redistribute it and/or
  *  modify it under the terms of the GNU Lesser General Public
  * To use this file, compile with:
  * <pre>
  * g++ -O3 buildtool.cpp -o btool.exe
- * (or whatever your compiler might be) 
+ * (or whatever your compiler might be)
  * Then
  * btool
- * or 
+ * or
  * btool {target}
- * 
+ *
  * Note: if you are using MinGW, and a not very recent version of it,
  * gettimeofday() might be missing.  If so, just build this file with
  * this command:
  * g++ -O3 -DNEED_GETTIMEOFDAY buildtool.cpp -o btool.exe
- *     
- */  
+ *
+ */
 
-#define BUILDTOOL_VERSION  "BuildTool v0.6.13, 2007 Bob Jamison"
+#define BUILDTOOL_VERSION  "BuildTool v0.8.1, 2007-2008 Bob Jamison"
 
 #include <stdio.h>
 #include <fcntl.h>
@@ -2862,6 +2862,99 @@ private:
 };
 
 
+//########################################################################
+//# F I L E L I S T
+//########################################################################
+/**
+ * This is a simpler, explicitly-named list of files
+ */
+class FileList
+{
+public:
+
+    /**
+     *
+     */
+    FileList()
+        {}
+
+    /**
+     *
+     */
+    FileList(const FileList &other)
+        { assign(other); }
+
+    /**
+     *
+     */
+    FileList &operator=(const FileList &other)
+        { assign(other); return *this; }
+
+    /**
+     *
+     */
+    virtual ~FileList()
+        {}
+
+    /**
+     *
+     */
+    String getDirectory()
+        { return directory; }
+        
+    /**
+     *
+     */
+    void setDirectory(const String &val)
+        { directory = val; }
+
+    /**
+     *
+     */
+    void setFiles(const std::vector<String> &val)
+        { files = val; }
+
+    /**
+     *
+     */
+    std::vector<String> getFiles()
+        { return files; }
+        
+    /**
+     *
+     */
+    unsigned int size()
+        { return files.size(); }
+        
+    /**
+     *
+     */
+    String operator[](int index)
+        { return files[index]; }
+        
+    /**
+     *
+     */
+    void clear()
+        {
+        directory = "";
+        files.clear();
+        }
+        
+
+private:
+
+    void assign(const FileList &other)
+        {
+        directory = other.directory;
+        files     = other.files;
+        }
+
+    String directory;
+    std::vector<String> files;
+};
+
+
 
 
 //########################################################################
@@ -2918,12 +3011,55 @@ public:
     int getLine()
         { return line; }
 
+
+    /**
+     * Set a property to a given value
+     */
+    virtual void setProperty(const String &name, const String &val)
+        {
+        properties[name] = val;
+        }
+
+    /**
+     * Return a named property is found, else a null string
+     */
+    virtual String getProperty(const String &name)
+        {
+        String val;
+        std::map<String, String>::iterator iter = properties.find(name);
+        if (iter != properties.end())
+            val = iter->second;
+        return val;
+        }
+
+    /**
+     * Return true if a named property is found, else false
+     */
+    virtual bool hasProperty(const String &name)
+        {
+        std::map<String, String>::iterator iter = properties.find(name);
+        if (iter == properties.end())
+            return false;
+        return true;
+        }
+
+
 protected:
 
     /**
      *    The path to the file associated with this object
      */     
     URI uri;
+    
+    /**
+     *    If this prefix is seen in a substitution, use an environment
+     *    variable.
+     *             example:  <property environment="env"/>
+     *             ${env.JAVA_HOME}              
+     */     
+    String envPrefix;
+
+
 
 
     /**
@@ -2936,6 +3072,11 @@ protected:
      */
     void status(const char *fmt, ...);
 
+    /**
+     *  Show target status
+     */
+    void targetstatus(const char *fmt, ...);
+
     /**
      *  Print a printf()-like formatted trace message
      */
@@ -2973,6 +3114,11 @@ protected:
      */
     String trim(const String &s);
 
+    /**
+     *  Return a lower case version of the given string
+     */
+    String toLower(const String &s);
+
     /**
      * Return the native format of the canonical
      * path which we store
@@ -3023,6 +3169,12 @@ protected:
     bool parseFileSet(Element *elem,
                     MakeBase &propRef,
                     FileSet &fileSet);
+    /**
+     * Parse a <filelist> entry
+     */  
+    bool parseFileList(Element *elem,
+                    MakeBase &propRef,
+                    FileList &fileList);
 
     /**
      * Return this object's property list
@@ -3030,19 +3182,6 @@ protected:
     virtual std::map<String, String> &getProperties()
         { return properties; }
 
-    /**
-     * Return a named property if found, else a null string
-     */
-    virtual String getProperty(const String &name)
-        {
-        String val;
-        std::map<String, String>::iterator iter;
-        iter = properties.find(name);
-        if (iter != properties.end())
-            val = iter->second;
-        return val;
-        }
-
 
     std::map<String, String> properties;
 
@@ -3126,7 +3265,6 @@ void MakeBase::status(const char *fmt, ...)
 }
 
 
-
 /**
  *  Resolve another path relative to this one
  */
@@ -3349,6 +3487,24 @@ String MakeBase::trim(const String &s)
     return res;
 }
 
+
+/**
+ *  Return a lower case version of the given string
+ */
+String MakeBase::toLower(const String &s)
+{
+    if (s.size()==0)
+        return s;
+
+    String ret;
+    for(unsigned int i=0; i<s.size() ; i++)
+        {
+        ret.push_back(tolower(s[i]));
+        }
+    return ret;
+}
+
+
 /**
  * Return the native format of the canonical
  * path which we store
@@ -3831,15 +3987,30 @@ bool MakeBase::getSubstitutions(const String &str, String &result)
                 else if (ch == '}')
                     {
                     std::map<String, String>::iterator iter;
-                    iter = properties.find(trim(varname));
-                    if (iter != properties.end())
+                    varname = trim(varname);
+                    if (envPrefix.size() > 0 && varname.compare(0, envPrefix.size(), envPrefix) == 0)
                         {
-                        val.append(iter->second);
+                        varname = varname.substr(envPrefix.size());
+                        char *envstr = getenv(varname.c_str());
+                        if (!envstr)
+                            {
+                            error("environment variable '%s' not defined", varname.c_str());
+                            return false;
+                            }
+                        val.append(envstr);
                         }
                     else
                         {
-                        error("property ${%s} not found", varname.c_str());
-                        return false;
+                        iter = properties.find(varname);
+                        if (iter != properties.end())
+                            {
+                            val.append(iter->second);
+                            }
+                        else
+                            {
+                            error("property ${%s} not found", varname.c_str());
+                            return false;
+                            }
                         }
                     break;
                     }
@@ -4007,6 +4178,49 @@ bool MakeBase::parseFileSet(Element *elem,
     return true;
 }
 
+/**
+ * Parse a <filelist> entry.  This is far simpler than FileSet,
+ * since no directory scanning is needed.  The file names are listed
+ * explicitly.
+ */  
+bool MakeBase::parseFileList(Element *elem,
+                          MakeBase &propRef,
+                          FileList &fileList)
+{
+    std::vector<String> fnames;
+    //Look for child tags, namely "file"
+    std::vector<Element *> children  = elem->getChildren();
+    for (unsigned int i=0 ; i<children.size() ; i++)
+        {
+        Element *child = children[i];
+        String tagName = child->getName();
+        if (tagName == "file")
+            {
+            String fname = child->getAttribute("name");
+            if (fname.size()==0)
+                {
+                error("<file> element requires name="" attribute");
+                return false;
+                }
+            fnames.push_back(fname);
+            }
+        else
+            {
+            error("tag <%s> not allowed in <fileset>", tagName.c_str());
+            return false;
+                       }
+        }
+
+    String dir;
+    //Get the base directory for reading file names
+    if (!propRef.getAttribute(elem, "dir", dir))
+        return false;
+    fileList.setDirectory(dir);
+    fileList.setFiles(fnames);
+
+    return true;
+}
+
 
 
 /**
@@ -4312,13 +4526,7 @@ public:
      *
      */
     PkgConfig()
-        { init(); }
-
-    /**
-     *
-     */
-    PkgConfig(const String &namearg)
-        { init(); name = namearg; }
+        { path="."; init(); }
 
     /**
      *
@@ -4344,6 +4552,30 @@ public:
     virtual String getName()
         { return name; }
 
+    /**
+     *
+     */
+    virtual String getPath()
+        { return path; }
+
+    /**
+     *
+     */
+    virtual void setPath(const String &val)
+        { path = val; }
+
+    /**
+     *
+     */
+    virtual String getPrefix()
+        { return prefix; }
+
+    /**
+     *  Allow the user to override the prefix in the file
+     */
+    virtual void setPrefix(const String &val)
+        { prefix = val; }
+
     /**
      *
      */
@@ -4362,6 +4594,17 @@ public:
     virtual String getLibs()
         { return libs; }
 
+    /**
+     *
+     */
+    virtual String getAll()
+        {
+         String ret = cflags;
+         ret.append(" ");
+         ret.append(libs);
+         return ret;
+        }
+
     /**
      *
      */
@@ -4398,12 +4641,21 @@ public:
     virtual std::vector<String> &getRequireList()
         { return requireList; }
 
+    /**
+     *  Read a file for its details
+     */         
     virtual bool readFile(const String &fileName);
 
+    /**
+     *  Read a file for its details
+     */         
+    virtual bool query(const String &name);
+
 private:
 
     void init()
         {
+        //do not set path or prefix here
         name         = "";
         description  = "";
         cflags       = "";
@@ -4421,6 +4673,8 @@ private:
     void assign(const PkgConfig &other)
         {
         name         = other.name;
+        path         = other.path;
+        prefix       = other.prefix;
         description  = other.description;
         cflags       = other.cflags;
         libs         = other.libs;
@@ -4446,12 +4700,18 @@ private:
 
     void parseVersion();
 
+    bool parseLine(const String &lineBuf);
+
     bool parse(const String &buf);
 
     void dumpAttrs();
 
     String name;
 
+    String path;
+
+    String prefix;
+
     String description;
 
     String cflags;
@@ -4495,6 +4755,7 @@ int PkgConfig::get(int pos)
 /**
  *  Skip over all whitespace characters beginning at pos.  Return
  *  the position of the first non-whitespace character.
+ *  Pkg-config is line-oriented, so check for newline
  */
 int PkgConfig::skipwhite(int pos)
 {
@@ -4604,15 +4865,12 @@ void PkgConfig::parseVersion()
 }
 
 
-bool PkgConfig::parse(const String &buf)
+bool PkgConfig::parseLine(const String &lineBuf)
 {
-    init();
-
-    parsebuf = (char *)buf.c_str();
-    parselen = buf.size();
+    parsebuf = (char *)lineBuf.c_str();
+    parselen = lineBuf.size();
     int pos = 0;
-
-
+    
     while (pos < parselen)
         {
         String attrName;
@@ -4633,6 +4891,7 @@ bool PkgConfig::parse(const String &buf)
         pos = getword(pos, attrName);
         if (attrName.size() == 0)
             continue;
+        
         pos = skipwhite(pos);
         ch = get(pos);
         if (ch != ':' && ch != '=')
@@ -4667,10 +4926,18 @@ bool PkgConfig::parse(const String &buf)
                         subName.push_back((char)ch);
                     pos++;
                     }
-                //trace("subName:%s", subName.c_str());
-                String subVal = attrs[subName];
-                //trace("subVal:%s", subVal.c_str());
-                attrVal.append(subVal);
+                //trace("subName:%s %s", subName.c_str(), prefix.c_str());
+                if (subName == "prefix" && prefix.size()>0)
+                    {
+                    attrVal.append(prefix);
+                    //trace("prefix override:%s", prefix.c_str());
+                    }
+                else
+                    {
+                    String subVal = attrs[subName];
+                    //trace("subVal:%s", subVal.c_str());
+                    attrVal.append(subVal);
+                    }
                 }
             else
                 attrVal.push_back((char)ch);
@@ -4680,23 +4947,55 @@ bool PkgConfig::parse(const String &buf)
         attrVal = trim(attrVal);
         attrs[attrName] = attrVal;
 
-        if (attrName == "Name")
+        String attrNameL = toLower(attrName);
+
+        if (attrNameL == "name")
             name = attrVal;
-        else if (attrName == "Description")
+        else if (attrNameL == "description")
             description = attrVal;
-        else if (attrName == "Cflags")
+        else if (attrNameL == "cflags")
             cflags = attrVal;
-        else if (attrName == "Libs")
+        else if (attrNameL == "libs")
             libs = attrVal;
-        else if (attrName == "Requires")
+        else if (attrNameL == "requires")
             requires = attrVal;
-        else if (attrName == "Version")
+        else if (attrNameL == "version")
             version = attrVal;
 
         //trace("name:'%s'  value:'%s'",
         //      attrName.c_str(), attrVal.c_str());
         }
 
+    return true;
+}
+
+
+bool PkgConfig::parse(const String &buf)
+{
+    init();
+
+    String line;
+    int lineNr = 0;
+    for (unsigned int p=0 ; p<buf.size() ; p++)
+        {
+        int ch = buf[p];
+        if (ch == '\n' || ch == '\r')
+            {
+            if (!parseLine(line))
+                return false;
+            line.clear();
+            lineNr++;
+            }
+        else
+            {
+            line.push_back(ch);
+            }
+        }
+    if (line.size()>0)
+        {
+        if (!parseLine(line))
+            return false;
+        }
 
     parseRequires();
     parseVersion();
@@ -4704,6 +5003,9 @@ bool PkgConfig::parse(const String &buf)
     return true;
 }
 
+
+
+
 void PkgConfig::dumpAttrs()
 {
     //trace("### PkgConfig attributes for %s", fileName.c_str());
@@ -4715,9 +5017,9 @@ void PkgConfig::dumpAttrs()
 }
 
 
-bool PkgConfig::readFile(const String &fileNameArg)
+bool PkgConfig::readFile(const String &fname)
 {
-    fileName = fileNameArg;
+    fileName = getNativePath(fname);
 
     FILE *f = fopen(fileName.c_str(), "r");
     if (!f)
@@ -4741,8 +5043,25 @@ bool PkgConfig::readFile(const String &fileNameArg)
         return false;
         }
 
-    dumpAttrs();
+    //dumpAttrs();
+
+    return true;
+}
+
 
+
+bool PkgConfig::query(const String &pkgName)
+{
+    name = pkgName;
+
+    String fname = path;
+    fname.append("/");
+    fname.append(name);
+    fname.append(".pc");
+
+    if (!readFile(fname))
+        return false;
+    
     return true;
 }
 
@@ -5803,6 +6122,19 @@ protected:
         name = other.name;
         }
         
+    /**
+     *  Show task status
+     */
+    void taskstatus(const char *fmt, ...)
+        {
+        va_list args;
+        va_start(args,fmt);
+        fprintf(stdout, "    %s : ", name.c_str());
+        vfprintf(stdout, fmt, args);
+        fprintf(stdout, "\n");
+        va_end(args) ;
+        }
+
     String getAttribute(Element *elem, const String &attrName)
         {
         String str;
@@ -5838,16 +6170,22 @@ public:
         defines     = "";
         includes    = "";
         fileSet.clear();
+        excludeInc.clear();
         }
 
     virtual ~TaskCC()
         {}
 
-    virtual bool needsCompiling(const FileRec &depRec,
-              const String &src, const String &dest)
+    virtual bool isExcludedInc(const String &dirname)
         {
+        for (unsigned int i=0 ; i<excludeInc.size() ; i++)
+            {
+            String fname = excludeInc[i];
+            if (fname == dirname)
+                return true;
+                       }
         return false;
-        }
+               }
 
     virtual bool execute()
         {
@@ -5861,7 +6199,7 @@ public:
         String fullName = parent.resolve("build.dep");
         if (isNewerThan(parent.getURI().getPath(), fullName))
             {
-            status("          : regenerating C/C++ dependency cache");
+            taskstatus("regenerating C/C++ dependency cache");
             refreshCache = true;
             }
 
@@ -5897,6 +6235,10 @@ public:
         std::set<String>::iterator setIter;
         for (setIter=paths.begin() ; setIter!=paths.end() ; setIter++)
             {
+            String dirName = *setIter;
+            //check excludeInc to see if we dont want to include this dir
+            if (isExcludedInc(dirName))
+                continue;
             incs.append(" -I");
             String dname;
             if (source.size()>0)
@@ -5904,7 +6246,7 @@ public:
                 dname.append(source);
                 dname.append("/");
                 }
-            dname.append(*setIter);
+            dname.append(dirName);
             incs.append(parent.resolve(dname));
             }
         std::vector<String> cfiles;
@@ -5957,7 +6299,7 @@ public:
             //# First we check if the source is newer than the .o
             if (isNewerThan(srcFullName, destFullName))
                 {
-                status("          : compile of %s required by %s",
+                taskstatus("compile of %s required by source: %s",
                         destFullName.c_str(), srcFullName.c_str());
                 compileMe = true;
                 }
@@ -5980,7 +6322,7 @@ public:
                     //        destFullName.c_str(), depFullName.c_str());
                     if (depRequires)
                         {
-                        status("          : compile of %s required by %s",
+                        taskstatus("compile of %s required by included: %s",
                                 destFullName.c_str(), depFullName.c_str());
                         compileMe = true;
                         break;
@@ -6100,6 +6442,11 @@ public:
                     return false;
                 source = fileSet.getDirectory();
                 }
+            else if (tagName == "excludeinc")
+                {
+                if (!parseFileList(child, parent, excludeInc))
+                    return false;
+                }
             }
 
         return true;
@@ -6107,14 +6454,16 @@ public:
         
 protected:
 
-    String ccCommand;
-    String cxxCommand;
-    String source;
-    String dest;
-    String flags;
-    String defines;
-    String includes;
-    FileSet fileSet;
+    String   ccCommand;
+    String   cxxCommand;
+    String   source;
+    String   dest;
+    String   flags;
+    String   lastflags;
+    String   defines;
+    String   includes;
+    FileSet  fileSet;
+    FileList excludeInc;
     
 };
 
@@ -6153,7 +6502,7 @@ public:
                {
                if (fileName.size()>0)
                    {
-                   status("          : %s to %s",
+                   taskstatus("%s to %s",
                         fileName.c_str(), toFileName.c_str());
                    String fullSource = parent.resolve(fileName);
                    String fullDest = parent.resolve(toFileName);
@@ -6166,12 +6515,12 @@ public:
                        }
                    if (!isNewerThan(fullSource, fullDest))
                        {
-                       status("          : skipped");
+                       taskstatus("skipped");
                        return true;
                        }
                    if (!copyFile(fullSource, fullDest))
                        return false;
-                   status("          : 1 file copied");
+                   taskstatus("1 file copied");
                    }
                return true;
                }
@@ -6183,7 +6532,7 @@ public:
                        return false;
                    String fileSetDir = fileSet.getDirectory();
 
-                   status("          : %s to %s",
+                   taskstatus("%s to %s",
                        fileSetDir.c_str(), toDirName.c_str());
 
                    int nrFiles = 0;
@@ -6234,13 +6583,13 @@ public:
                            return false;
                        nrFiles++;
                        }
-                   status("          : %d file(s) copied", nrFiles);
+                   taskstatus("%d file(s) copied", nrFiles);
                    }
                else //file source
                    {
                    //For file->dir we want only the basename of
                    //the source appended to the dest dir
-                   status("          : %s to %s", 
+                   taskstatus("%s to %s", 
                        fileName.c_str(), toDirName.c_str());
                    String baseName = fileName;
                    unsigned int pos = baseName.find_last_of('/');
@@ -6264,12 +6613,12 @@ public:
                        }
                    if (!isNewerThan(fullSource, fullDest))
                        {
-                       status("          : skipped");
+                       taskstatus("skipped");
                        return true;
                        }
                    if (!copyFile(fullSource, fullDest))
                        return false;
-                   status("          : 1 file copied");
+                   taskstatus("1 file copied");
                    }
                return true;
                }
@@ -6412,7 +6761,7 @@ public:
                 }
             case DEL_DIR:
                 {
-                status("          : %s", dirName.c_str());
+                taskstatus("%s", dirName.c_str());
                 String fullDir = parent.resolve(dirName);
                 if (!removeDirectory(fullDir))
                     return false;
@@ -6477,20 +6826,56 @@ class TaskJar : public Task
 public:
 
     TaskJar(MakeBase &par) : Task(par)
-        { type = TASK_JAR; name = "jar"; }
+        { type = TASK_JAR; name = "jar"; command = "jar";}
 
     virtual ~TaskJar()
         {}
 
     virtual bool execute()
         {
+        String cmd = command;
+        cmd.append(" -cf ");
+        cmd.append(destfile);
+        cmd.append(" -C ");
+        cmd.append(basedir);
+        cmd.append(" .");
+
+        String execCmd = cmd;
+
+        String outString, errString;
+        bool ret = executeCommand(execCmd.c_str(), "", outString, errString);
+        if (!ret)
+            {
+            error("<jar> command '%s' failed :\n %s",
+                                      execCmd.c_str(), errString.c_str());
+            return false;
+            }
         return true;
         }
 
     virtual bool parse(Element *elem)
         {
+        String s;
+        if (!parent.getAttribute(elem, "command", s))
+            return false;
+        if (s.size() > 0)
+            command = s;
+        if (!parent.getAttribute(elem, "basedir", basedir))
+            return false;
+        if (!parent.getAttribute(elem, "destfile", destfile))
+            return false;
+        if (basedir.size() == 0 || destfile.size() == 0)
+            {
+            error("<jar> required both basedir and destfile attributes to be set");
+            return false;
+            }
         return true;
         }
+
+private:
+    String command;
+    String basedir;
+    String destfile;
 };
 
 
@@ -6502,20 +6887,115 @@ class TaskJavac : public Task
 public:
 
     TaskJavac(MakeBase &par) : Task(par)
-        { type = TASK_JAVAC; name = "javac"; }
+        { 
+        type = TASK_JAVAC; name = "javac";
+        command = "javac";
+        }
 
     virtual ~TaskJavac()
         {}
 
     virtual bool execute()
         {
+        std::vector<String> fileList;
+        if (!listFiles(srcdir, "", fileList))
+            {
+            return false;
+            }
+        String cmd = command;
+        cmd.append(" -d ");
+        cmd.append(destdir);
+        cmd.append(" -classpath ");
+        cmd.append(destdir);
+        cmd.append(" -sourcepath ");
+        cmd.append(srcdir);
+        cmd.append(" ");
+        if (target.size()>0)
+            {
+            cmd.append(" -target ");
+            cmd.append(target);
+            cmd.append(" ");
+                       }
+               String fname = "javalist.btool";
+               FILE *f = fopen(fname.c_str(), "w");
+               int count = 0;
+        for (unsigned int i=0 ; i<fileList.size() ; i++)
+            {
+            String fname = fileList[i];
+            String srcName = fname;
+            if (fname.size()<6) //x.java
+                continue;
+            if (fname.compare(fname.size()-5, 5, ".java") != 0)
+                continue;
+            String baseName = fname.substr(0, fname.size()-5);
+            String destName = baseName;
+            destName.append(".class");
+
+            String fullSrc = srcdir;
+            fullSrc.append("/");
+            fullSrc.append(fname);
+            String fullDest = destdir;
+            fullDest.append("/");
+            fullDest.append(destName);
+            //trace("fullsrc:%s fulldest:%s", fullSrc.c_str(), fullDest.c_str());
+            if (!isNewerThan(fullSrc, fullDest))
+                continue;
+
+            count++;
+            fprintf(f, "%s\n", fullSrc.c_str());
+            }
+        fclose(f);
+        if (!count)
+            {
+            taskstatus("nothing to do");
+            return true;
+                       }
+
+        taskstatus("compiling %d files", count);
+
+        String execCmd = cmd;
+        execCmd.append("@");
+        execCmd.append(fname);
+
+        String outString, errString;
+        bool ret = executeCommand(execCmd.c_str(), "", outString, errString);
+        if (!ret)
+            {
+            error("<javac> command '%s' failed :\n %s",
+                                      execCmd.c_str(), errString.c_str());
+            return false;
+            }
         return true;
         }
 
     virtual bool parse(Element *elem)
         {
+        String s;
+        if (!parent.getAttribute(elem, "command", s))
+            return false;
+        if (s.size() > 0)
+            command = s;
+        if (!parent.getAttribute(elem, "srcdir", srcdir))
+            return false;
+        if (!parent.getAttribute(elem, "destdir", destdir))
+            return false;
+        if (srcdir.size() == 0 || destdir.size() == 0)
+            {
+            error("<javac> required both srcdir and destdir attributes to be set");
+            return false;
+            }
+        if (!parent.getAttribute(elem, "target", target))
+            return false;
         return true;
         }
+
+private:
+
+    String command;
+    String srcdir;
+    String destdir;
+    String target;
+
 };
 
 
@@ -6531,8 +7011,8 @@ public:
         type = TASK_LINK; name = "link";
         command = "g++";
         doStrip = false;
-                stripCommand = "strip";
-                objcopyCommand = "objcopy";
+        stripCommand = "strip";
+        objcopyCommand = "objcopy";
         }
 
     virtual ~TaskLink()
@@ -6697,15 +7177,16 @@ public:
 
     virtual bool execute()
         {
-        status("          : %s", fileName.c_str());
+        taskstatus("%s", fileName.c_str());
         String fullName = parent.resolve(fileName);
         if (!isNewerThan(parent.getURI().getPath(), fullName))
             {
             //trace("skipped <makefile>");
             return true;
             }
+        String fullNative = getNativePath(fullName);
         //trace("fullName:%s", fullName.c_str());
-        FILE *f = fopen(fullName.c_str(), "w");
+        FILE *f = fopen(fullNative.c_str(), "w");
         if (!f)
             {
             error("<makefile> could not open %s for writing : %s",
@@ -6758,7 +7239,7 @@ public:
 
     virtual bool execute()
         {
-        status("          : %s", dirName.c_str());
+        taskstatus("%s", dirName.c_str());
         String fullDir = parent.resolve(dirName);
         //trace("fullDir:%s", fullDir.c_str());
         if (!createDirectory(fullDir))
@@ -6939,12 +7420,13 @@ public:
         {
         PKG_CONFIG_QUERY_CFLAGS,
         PKG_CONFIG_QUERY_LIBS,
-        PKG_CONFIG_QUERY_BOTH
+        PKG_CONFIG_QUERY_ALL
         } QueryTypes;
 
     TaskPkgConfig(MakeBase &par) : Task(par)
         {
-        type = TASK_PKG_CONFIG; name = "pkg-config";
+        type = TASK_PKG_CONFIG;
+        name = "pkg-config";
         }
 
     virtual ~TaskPkgConfig()
@@ -6953,17 +7435,89 @@ public:
     virtual bool execute()
         {
         String path = parent.resolve(pkg_config_path);
-        //fill this in
+        PkgConfig pkgconfig;
+        pkgconfig.setPath(path);
+        pkgconfig.setPrefix(prefix);
+        if (!pkgconfig.query(pkgName))
+            {
+            error("<pkg-config> query failed for '%s", name.c_str());
+            return false;
+            }
+        String ret;
+        switch (query)
+            {
+            case PKG_CONFIG_QUERY_CFLAGS:
+                {
+                ret = pkgconfig.getCflags();
+                break;
+                }
+            case PKG_CONFIG_QUERY_LIBS:
+                {
+                ret = pkgconfig.getLibs();
+                break;
+                }
+            case PKG_CONFIG_QUERY_ALL:
+                {
+                ret = pkgconfig.getAll();
+                break;
+                }
+            default:
+                {
+                error("<pkg-config> unhandled query : %d", query);
+                return false;
+                }
+            
+            }
+        taskstatus("%s", ret.c_str());
+        parent.setProperty(propName, ret);
         return true;
         }
 
     virtual bool parse(Element *elem)
         {
         String s;
+        //# NAME
+        if (!parent.getAttribute(elem, "name", s))
+            return false;
+        if (s.size()>0)
+           pkgName = s;
+        else
+            {
+            error("<pkg-config> requires 'name=\"package\"' attribute");
+            return false;
+            }
+
+        //# PROPERTY
+        if (!parent.getAttribute(elem, "property", s))
+            return false;
+        if (s.size()>0)
+           propName = s;
+        else
+            {
+            error("<pkg-config> requires 'property=\"name\"' attribute");
+            return false;
+            }
+        if (parent.hasProperty(propName))
+            {
+            error("<pkg-config> property '%s' is already defined",
+                          propName.c_str());
+            return false;
+            }
+        parent.setProperty(propName, "undefined");
+
+        //# PATH
         if (!parent.getAttribute(elem, "path", s))
             return false;
         if (s.size()>0)
            pkg_config_path = s;
+
+        //# PREFIX
+        if (!parent.getAttribute(elem, "prefix", s))
+            return false;
+        if (s.size()>0)
+           prefix = s;
+
+        //# QUERY
         if (!parent.getAttribute(elem, "query", s))
             return false;
         if (s == "cflags")
@@ -6971,7 +7525,7 @@ public:
         else if (s == "libs")
             query = PKG_CONFIG_QUERY_LIBS;
         else if (s == "both")
-            query = PKG_CONFIG_QUERY_BOTH;
+            query = PKG_CONFIG_QUERY_ALL;
         else
             {
             error("<pkg-config> requires 'query=\"type\"' attribute");
@@ -6983,6 +7537,9 @@ public:
 
 private:
 
+    String pkgName;
+    String prefix;
+    String propName;
     String pkg_config_path;
     int query;
 
@@ -7537,6 +8094,8 @@ Task *Task::createTask(Element *elem, int lineNr)
         task = new TaskMkDir(parent);
     else if (tagName == "msgfmt")
         task = new TaskMsgFmt(parent);
+    else if (tagName == "pkg-config")
+        task = new TaskPkgConfig(parent);
     else if (tagName == "ranlib")
         task = new TaskRanlib(parent);
     else if (tagName == "rc")
@@ -7882,8 +8441,6 @@ private:
 
     String description;
     
-    String envAlias;
-
     //std::vector<Property> properties;
     
     std::map<String, Target> targets;
@@ -7911,7 +8468,7 @@ void Make::init()
     specifiedTarget = "";
     baseDir         = "";
     description     = "";
-    envAlias        = "";
+    envPrefix       = "";
     properties.clear();
     for (unsigned int i = 0 ; i < allTasks.size() ; i++)
         delete allTasks[i];
@@ -8004,14 +8561,15 @@ bool Make::executeTarget(Target &target,
             }
         }
 
-    status("## Target : %s", name.c_str());
+    status("##### Target : %s\n##### %s", name.c_str(),
+            target.getDescription().c_str());
 
     //Now let's do the tasks
     std::vector<Task *> &tasks = target.getTasks();
     for (unsigned int i=0 ; i<tasks.size() ; i++)
         {
         Task *task = tasks[i];
-        status("---- task : %s", task->getName().c_str());
+        status("--- %s / %s", name.c_str(), task->getName().c_str());
         if (!task->execute())
             {
             return false;
@@ -8291,12 +8849,18 @@ bool Make::parseProperty(Element *elem)
             }
         else if (attrName == "environment")
             {
-            if (envAlias.size() > 0)
+            if (envPrefix.size() > 0)
+                {
+                error("environment prefix can only be set once");
+                return false;
+                }
+            if (attrVal.find('.') != attrVal.npos)
                 {
-                error("environment property can only be set once");
+                error("environment prefix cannot have a '.' in it");
                 return false;
                 }
-            envAlias = attrVal;
+            envPrefix = attrVal;
+            envPrefix.push_back('.');
             }
         }
 
@@ -8643,7 +9207,7 @@ static bool parseOptions(int argc, char **argv)
                 }
             else if (arg.size()>2 && sequ(arg, "-D"))
                 {
-                String s = arg.substr(2, s.size());
+                String s = arg.substr(2, arg.size());
                 String name, value;
                 if (!parseProperty(s, name, value))
                    {