X-Git-Url: https://git.tokkee.org/?a=blobdiff_plain;f=buildtool.cpp;h=2b4307ab0f0e2ca6026a7eabc2a4a874d0d32a8b;hb=6aba22359627ef015ee03b85e4b7b5b98684b834;hp=5d0eb429c0296bfcffc5ddc44747730b8a4fc10c;hpb=0c54bf8763a2f5ed1d0547a1bc71304f1bf1af55;p=inkscape.git diff --git a/buildtool.cpp b/buildtool.cpp index 5d0eb429c..2b4307ab0 100644 --- a/buildtool.cpp +++ b/buildtool.cpp @@ -3,8 +3,9 @@ * * Authors: * Bob Jamison + * Jasper van de Gronde * - * 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 @@ -38,7 +39,7 @@ * */ -#define BUILDTOOL_VERSION "BuildTool v0.7.4, 2007 Bob Jamison" +#define BUILDTOOL_VERSION "BuildTool v0.9.9" #include #include @@ -54,6 +55,8 @@ #include #include #include +#include + #ifdef __WIN32__ #include @@ -204,7 +207,7 @@ TREX_API TRexBool trex_getsubexp(TRex* exp, int n, TRexMatch *subexp); #include //#include "trex.h" -#ifdef _UINCODE +#ifdef _UNICODE #define scisprint iswprint #define scstrlen wcslen #define scprintf wprintf @@ -688,7 +691,7 @@ static const TRexChar *trex_matchnode(TRex* exp,TRexNode *node,const TRexChar *s return cur; } case OP_WB: - if(str == exp->_bol && !isspace(*str) + if((str == exp->_bol && !isspace(*str)) || (str == exp->_eol && !isspace(*(str-1))) || (!isspace(*str) && isspace(*(str+1))) || (isspace(*str) && !isspace(*(str+1))) ) { @@ -2739,6 +2742,98 @@ bool URI::parse(const String &str) //######################################################################## //######################################################################## +//######################################################################## +//# Stat cache to speed up stat requests +//######################################################################## +struct StatResult { + int result; + struct stat statInfo; +}; +typedef std::map statCacheType; +static statCacheType statCache; +static int cachedStat(const String &f, struct stat *s) { + //printf("Stat path: %s\n", f.c_str()); + std::pair result = statCache.insert(statCacheType::value_type(f, StatResult())); + if (result.second) { + result.first->second.result = stat(f.c_str(), &(result.first->second.statInfo)); + } + *s = result.first->second.statInfo; + return result.first->second.result; +} +static void removeFromStatCache(const String f) { + //printf("Removing from cache: %s\n", f.c_str()); + statCache.erase(f); +} + +//######################################################################## +//# Dir cache to speed up dir requests +//######################################################################## +/*struct DirListing { + bool available; + std::vector files; + std::vector dirs; +}; +typedef std::map dirCacheType; +static dirCacheType dirCache; +static const DirListing &cachedDir(String fullDir) +{ + String dirNative = getNativePath(fullDir); + std::pair result = dirCache.insert(dirCacheType::value_type(dirNative, DirListing())); + if (result.second) { + DIR *dir = opendir(dirNative.c_str()); + if (!dir) + { + error("Could not open directory %s : %s", + dirNative.c_str(), strerror(errno)); + result.first->second.available = false; + } + else + { + result.first->second.available = true; + while (true) + { + struct dirent *de = readdir(dir); + if (!de) + break; + + //Get the directory member name + String s = de->d_name; + if (s.size() == 0 || s[0] == '.') + continue; + String childName; + if (dirName.size()>0) + { + childName.append(dirName); + childName.append("/"); + } + childName.append(s); + String fullChild = baseDir; + fullChild.append("/"); + fullChild.append(childName); + + if (isDirectory(fullChild)) + { + //trace("directory: %s", childName.c_str()); + if (!listFiles(baseDir, childName, res)) + return false; + continue; + } + else if (!isRegularFile(fullChild)) + { + error("unknown file:%s", childName.c_str()); + return false; + } + + //all done! + res.push_back(childName); + + } + closedir(dir); + } + } + return result.first->second; +}*/ + //######################################################################## //# F I L E S E T //######################################################################## @@ -2776,7 +2871,7 @@ public: /** * */ - String getDirectory() + String getDirectory() const { return directory; } /** @@ -2794,7 +2889,7 @@ public: /** * */ - std::vector getFiles() + std::vector getFiles() const { return files; } /** @@ -2806,7 +2901,7 @@ public: /** * */ - std::vector getIncludes() + std::vector getIncludes() const { return includes; } /** @@ -2818,19 +2913,19 @@ public: /** * */ - std::vector getExcludes() + std::vector getExcludes() const { return excludes; } /** * */ - unsigned int size() + unsigned int size() const { return files.size(); } /** * */ - String operator[](int index) + String operator[](int index) const { return files[index]; } /** @@ -2862,6 +2957,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 &val) + { files = val; } + + /** + * + */ + std::vector 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 files; +}; + + //######################################################################## @@ -2896,6 +3084,19 @@ public: */ String resolve(const String &otherPath); + /** + * replace variable refs like ${a} with their values + * Assume that the string has already been syntax validated + */ + String eval(const String &s, const String &defaultVal); + + /** + * replace variable refs like ${a} with their values + * return true or false + * Assume that the string has already been syntax validated + */ + bool evalBool(const String &s, bool defaultVal); + /** * Get an element attribute, performing substitutions if necessary */ @@ -2936,7 +3137,10 @@ public: std::map::iterator iter = properties.find(name); if (iter != properties.end()) val = iter->second; - return val; + String sval; + if (!getSubstitutions(val, sval)) + return false; + return sval; } /** @@ -2962,10 +3166,43 @@ protected: * If this prefix is seen in a substitution, use an environment * variable. * example: - * ${env.JAVA_HOME} - */ + * ${env.JAVA_HOME} + */ String envPrefix; + /** + * If this prefix is seen in a substitution, use as a + * pkg-config 'all' query + * example: + * ${pc.gtkmm} + */ + String pcPrefix; + + /** + * If this prefix is seen in a substitution, use as a + * pkg-config 'cflags' query + * example: + * ${pcc.gtkmm} + */ + String pccPrefix; + + /** + * If this prefix is seen in a substitution, use as a + * pkg-config 'libs' query + * example: + * ${pcl.gtkmm} + */ + String pclPrefix; + + /** + * If this prefix is seen in a substitution, use as a + * Bazaar "bzr revno" query + * example: ??? + * ${bzr.Revision} + */ + String bzrPrefix; + + @@ -2979,6 +3216,11 @@ protected: */ void status(const char *fmt, ...); + /** + * Show target status + */ + void targetstatus(const char *fmt, ...); + /** * Print a printf()-like formatted trace message */ @@ -3071,6 +3313,12 @@ protected: bool parseFileSet(Element *elem, MakeBase &propRef, FileSet &fileSet); + /** + * Parse a entry + */ + bool parseFileList(Element *elem, + MakeBase &propRef, + FileList &fileList); /** * Return this object's property list @@ -3081,11 +3329,6 @@ protected: std::map properties; - /** - * Turn 'true' and 'false' into boolean values - */ - bool getBool(const String &str, bool &val); - /** * Create a directory, making intermediate dirs * if necessary @@ -3102,6 +3345,16 @@ protected: */ bool copyFile(const String &srcFile, const String &destFile); + /** + * Delete a file + */ + bool removeFile(const String &file); + + /** + * Tests if the file exists + */ + bool fileExists(const String &fileName); + /** * Tests if the file exists and is a regular file */ @@ -3119,9 +3372,33 @@ protected: private: + bool pkgConfigRecursive(const String packageName, + const String &path, + const String &prefix, + int query, + String &result, + std::set &deplist); + /** - * replace variable refs like ${a} with their values - */ + * utility method to query for "all", "cflags", or "libs" for this package and its + * dependencies. 0, 1, 2 + */ + bool pkgConfigQuery(const String &packageName, int query, String &result); + + /** + * replace a variable ref like ${a} with a value + */ + bool lookupProperty(const String &s, String &result); + + /** + * called by getSubstitutions(). This is in case a looked-up string + * has substitutions also. + */ + bool getSubstitutionsRecursive(const String &s, String &result, int depth); + + /** + * replace variable refs in a string like ${a} with their values + */ bool getSubstitutions(const String &s, String &result); int line; @@ -3131,61 +3408,429 @@ private: - /** - * Print a printf()-like formatted error message + * Define the pkg-config class here, since it will be used in MakeBase method + * implementations. */ -void MakeBase::error(const char *fmt, ...) +class PkgConfig : public MakeBase { - va_list args; - va_start(args,fmt); - fprintf(stderr, "Make error line %d: ", line); - vfprintf(stderr, fmt, args); - fprintf(stderr, "\n"); - va_end(args) ; -} +public: + /** + * + */ + PkgConfig() + { + path = "."; + prefix = "/target"; + init(); + } -/** - * Print a printf()-like formatted trace message - */ -void MakeBase::status(const char *fmt, ...) -{ - va_list args; - va_start(args,fmt); - //fprintf(stdout, " "); - vfprintf(stdout, fmt, args); - fprintf(stdout, "\n"); - va_end(args) ; -} - - + /** + * + */ + PkgConfig(const PkgConfig &other) + { assign(other); } -/** - * Resolve another path relative to this one - */ -String MakeBase::resolve(const String &otherPath) -{ - URI otherURI(otherPath); - URI fullURI = uri.resolve(otherURI); - String ret = fullURI.toString(); - return ret; -} + /** + * + */ + PkgConfig &operator=(const PkgConfig &other) + { assign(other); return *this; } + /** + * + */ + virtual ~PkgConfig() + { } -/** - * Print a printf()-like formatted trace message - */ -void MakeBase::trace(const char *fmt, ...) -{ - va_list args; - va_start(args,fmt); - fprintf(stdout, "Make: "); - vfprintf(stdout, fmt, args); - fprintf(stdout, "\n"); - va_end(args) ; -} + /** + * + */ + 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; } + + /** + * + */ + virtual String getDescription() + { return description; } + + /** + * + */ + virtual String getCflags() + { return cflags; } + + /** + * + */ + virtual String getLibs() + { return libs; } + + /** + * + */ + virtual String getAll() + { + String ret = cflags; + ret.append(" "); + ret.append(libs); + return ret; + } + + /** + * + */ + virtual String getVersion() + { return version; } + + /** + * + */ + virtual int getMajorVersion() + { return majorVersion; } + + /** + * + */ + virtual int getMinorVersion() + { return minorVersion; } + + /** + * + */ + virtual int getMicroVersion() + { return microVersion; } + + /** + * + */ + virtual std::map &getAttributes() + { return attrs; } + + /** + * + */ + virtual std::vector &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 and prefix here + name = ""; + description = ""; + cflags = ""; + libs = ""; + requires = ""; + version = ""; + majorVersion = 0; + minorVersion = 0; + microVersion = 0; + fileName = ""; + attrs.clear(); + requireList.clear(); + } + + void assign(const PkgConfig &other) + { + name = other.name; + path = other.path; + prefix = other.prefix; + description = other.description; + cflags = other.cflags; + libs = other.libs; + requires = other.requires; + version = other.version; + majorVersion = other.majorVersion; + minorVersion = other.minorVersion; + microVersion = other.microVersion; + fileName = other.fileName; + attrs = other.attrs; + requireList = other.requireList; + } + + + + int get(int pos); + + int skipwhite(int pos); + + int getword(int pos, String &ret); + + /** + * Very important + */ + bool parseRequires(); + + void parseVersion(); + + bool parseLine(const String &lineBuf); + + bool parse(const String &buf); + + void dumpAttrs(); + + String name; + + String path; + + String prefix; + + String description; + + String cflags; + + String libs; + + String requires; + + String version; + + int majorVersion; + + int minorVersion; + + int microVersion; + + String fileName; + + std::map attrs; + + std::vector requireList; + + char *parsebuf; + int parselen; +}; + +/** + * Execute the "bzr revno" command and return the result. + * This is a simple, small class. + */ +class BzrRevno : public MakeBase +{ +public: + + /** + * Safe way. Execute "bzr revno" and return the result. + * Safe from changes in format. + */ + bool query(String &res) + { + String cmd = "bzr revno"; + + String outString, errString; + bool ret = executeCommand(cmd.c_str(), "", outString, errString); + if (!ret) + { + error("error executing '%s': %s", cmd.c_str(), errString.c_str()); + return false; + } + res = outString; + return true; + } +}; + +/** + * Execute the "svn info" command and parse the result. + * This is a simple, small class. Define here, because it + * is used by MakeBase implementation methods. + */ +class SvnInfo : public MakeBase +{ +public: + +#if 0 + /** + * Safe way. Execute "svn info --xml" and parse the result. Search for + * elements/attributes. Safe from changes in format. + */ + bool query(const String &name, String &res) + { + String cmd = "svn info --xml"; + + String outString, errString; + bool ret = executeCommand(cmd.c_str(), "", outString, errString); + if (!ret) + { + error("error executing '%s': %s", cmd.c_str(), errString.c_str()); + return false; + } + Parser parser; + Element *elem = parser.parse(outString); + if (!elem) + { + error("error parsing 'svn info' xml result: %s", outString.c_str()); + return false; + } + + res = elem->getTagValue(name); + if (res.size()==0) + { + res = elem->getTagAttribute("entry", name); + } + return true; + } +#else + + + /** + * Universal way. Parse the file directly. Not so safe from + * changes in format. + */ + bool query(const String &name, String &res) + { + String fileName = resolve(".svn/entries"); + String nFileName = getNativePath(fileName); + + std::map properties; + + FILE *f = fopen(nFileName.c_str(), "r"); + if (!f) + { + error("could not open SVN 'entries' file"); + return false; + } + + const char *fieldNames[] = + { + "format-nbr", + "name", + "kind", + "revision", + "url", + "repos", + "schedule", + "text-time", + "checksum", + "committed-date", + "committed-rev", + "last-author", + "has-props", + "has-prop-mods", + "cachable-props", + }; + + for (int i=0 ; i<15 ; i++) + { + inbuf[0] = '\0'; + if (feof(f) || !fgets(inbuf, 255, f)) + break; + properties[fieldNames[i]] = trim(inbuf); + } + fclose(f); + + res = properties[name]; + + return true; + } + +private: + + char inbuf[256]; + +#endif + +}; + + + + + + +/** + * Print a printf()-like formatted error message + */ +void MakeBase::error(const char *fmt, ...) +{ + va_list args; + va_start(args,fmt); + fprintf(stderr, "Make error line %d: ", line); + vfprintf(stderr, fmt, args); + fprintf(stderr, "\n"); + va_end(args) ; +} + + + +/** + * Print a printf()-like formatted trace message + */ +void MakeBase::status(const char *fmt, ...) +{ + va_list args; + //fprintf(stdout, " "); + va_start(args,fmt); + vfprintf(stdout, fmt, args); + va_end(args); + fprintf(stdout, "\n"); + fflush(stdout); +} + + +/** + * Print a printf()-like formatted trace message + */ +void MakeBase::trace(const char *fmt, ...) +{ + va_list args; + fprintf(stdout, "Make: "); + va_start(args,fmt); + vfprintf(stdout, fmt, args); + va_end(args) ; + fprintf(stdout, "\n"); + fflush(stdout); +} + + + +/** + * Resolve another path relative to this one + */ +String MakeBase::resolve(const String &otherPath) +{ + URI otherURI(otherPath); + URI fullURI = uri.resolve(otherURI); + String ret = fullURI.toString(); + return ret; +} @@ -3464,6 +4109,9 @@ static String win32LastError() + +#ifdef __WIN32__ + /** * Execute a system call, using pipes to send data to the * program's stdin, and reading stdout and stderr. @@ -3480,7 +4128,6 @@ bool MakeBase::executeCommand(const String &command, outbuf.clear(); errbuf.clear(); -#ifdef __WIN32__ /* I really hate having win32 code in this program, but the @@ -3524,13 +4171,18 @@ bool MakeBase::executeCommand(const String &command, return false; } SetHandleInformation(stdoutRead, HANDLE_FLAG_INHERIT, 0); - if (!CreatePipe(&stderrRead, &stderrWrite, &saAttr, 0)) - { - error("executeProgram: could not create pipe"); - delete[] paramBuf; - return false; - } - SetHandleInformation(stderrRead, HANDLE_FLAG_INHERIT, 0); + if (&outbuf != &errbuf) { + if (!CreatePipe(&stderrRead, &stderrWrite, &saAttr, 0)) + { + error("executeProgram: could not create pipe"); + delete[] paramBuf; + return false; + } + SetHandleInformation(stderrRead, HANDLE_FLAG_INHERIT, 0); + } else { + stderrRead = stdoutRead; + stderrWrite = stdoutWrite; + } // Create the process STARTUPINFO siStartupInfo; @@ -3572,7 +4224,7 @@ bool MakeBase::executeCommand(const String &command, error("executeCommand: could not close read pipe"); return false; } - if (!CloseHandle(stderrWrite)) + if (stdoutWrite != stderrWrite && !CloseHandle(stderrWrite)) { error("executeCommand: could not close read pipe"); return false; @@ -3630,7 +4282,7 @@ bool MakeBase::executeCommand(const String &command, error("executeCommand: could not close read pipe"); return false; } - if (!CloseHandle(stderrRead)) + if (stdoutRead != stderrRead && !CloseHandle(stderrRead)) { error("executeCommand: could not close read pipe"); return false; @@ -3649,35 +4301,136 @@ bool MakeBase::executeCommand(const String &command, return ret; -#else //do it unix-style +} + +#else /*do it unix style*/ + +#include + + + +/** + * Execute a system call, using pipes to send data to the + * program's stdin, and reading stdout and stderr. + */ +bool MakeBase::executeCommand(const String &command, + const String &inbuf, + String &outbuf, + String &errbuf) +{ + + status("============ cmd ============\n%s\n=============================", + command.c_str()); + + outbuf.clear(); + errbuf.clear(); + + + int outfds[2]; + if (pipe(outfds) < 0) + return false; + int errfds[2]; + if (pipe(errfds) < 0) + return false; + int pid = fork(); + if (pid < 0) + { + close(outfds[0]); + close(outfds[1]); + close(errfds[0]); + close(errfds[1]); + error("launch of command '%s' failed : %s", + command.c_str(), strerror(errno)); + return false; + } + else if (pid > 0) // parent + { + close(outfds[1]); + close(errfds[1]); + } + else // == 0, child + { + close(outfds[0]); + dup2(outfds[1], STDOUT_FILENO); + close(outfds[1]); + close(errfds[0]); + dup2(errfds[1], STDERR_FILENO); + close(errfds[1]); + + char *args[4]; + args[0] = (char *)"sh"; + args[1] = (char *)"-c"; + args[2] = (char *)command.c_str(); + args[3] = NULL; + execv("/bin/sh", args); + exit(EXIT_FAILURE); + } + + String outb; + String errb; + + int outRead = outfds[0]; + int errRead = errfds[0]; + int max = outRead; + if (errRead > max) + max = errRead; - String s; - FILE *f = popen(command.c_str(), "r"); - int errnum = 0; - if (f) + bool outOpen = true; + bool errOpen = true; + + while (outOpen || errOpen) { - while (true) + char ch; + fd_set fdset; + FD_ZERO(&fdset); + if (outOpen) + FD_SET(outRead, &fdset); + if (errOpen) + FD_SET(errRead, &fdset); + int ret = select(max+1, &fdset, NULL, NULL, NULL); + if (ret < 0) + break; + if (FD_ISSET(outRead, &fdset)) { - int ch = fgetc(f); - if (ch < 0) - break; - s.push_back((char)ch); + if (read(outRead, &ch, 1) <= 0) + { outOpen = false; } + else if (ch <= 0) + { /* outOpen = false; */ } + else + { outb.push_back(ch); } + } + if (FD_ISSET(errRead, &fdset)) + { + if (read(errRead, &ch, 1) <= 0) + { errOpen = false; } + else if (ch <= 0) + { /* errOpen = false; */ } + else + { errb.push_back(ch); } } - errnum = pclose(f); } - outbuf = s; - if (errnum != 0) + + int childReturnValue; + wait(&childReturnValue); + + close(outRead); + close(errRead); + + outbuf = outb; + errbuf = errb; + + if (childReturnValue != 0) { error("exec of command '%s' failed : %s", - command.c_str(), strerror(errno)); + command.c_str(), strerror(childReturnValue)); return false; } - else - return true; -#endif + return true; } +#endif + @@ -3689,7 +4442,7 @@ bool MakeBase::listDirectories(const String &baseName, String fullPath = baseName; if (dirName.size()>0) { - fullPath.append("/"); + if (dirName[0]!='/') fullPath.append("/"); fullPath.append(dirName); } DIR *dir = opendir(fullPath.c_str()); @@ -3712,7 +4465,7 @@ bool MakeBase::listDirectories(const String &baseName, fullChildPath.append(childName); struct stat finfo; String childNative = getNativePath(fullChildPath); - if (stat(childNative.c_str(), &finfo)<0) + if (cachedStat(childNative, &finfo)<0) { error("cannot stat file:%s", childNative.c_str()); } @@ -3793,9 +4546,19 @@ bool MakeBase::listFiles(const String &baseDir, } +/** + * Several different classes extend MakeBase. By "propRef", we mean + * the one holding the properties. Likely "Make" itself + */ bool MakeBase::listFiles(MakeBase &propRef, FileSet &fileSet) { - String baseDir = propRef.resolve(fileSet.getDirectory()); + //before doing the list, resolve any property references + //that might have been specified in the directory name, such as ${src} + String fsDir = fileSet.getDirectory(); + String dir; + if (!propRef.getSubstitutions(fsDir, dir)) + return false; + String baseDir = propRef.resolve(dir); std::vector fileList; if (!listFiles(baseDir, "", fileList)) return false; @@ -3816,7 +4579,7 @@ bool MakeBase::listFiles(MakeBase &propRef, FileSet &fileSet) { for (iter = includes.begin() ; iter != includes.end() ; iter++) { - String pattern = *iter; + String &pattern = *iter; std::vector::iterator siter; for (siter = fileList.begin() ; siter != fileList.end() ; siter++) { @@ -3839,7 +4602,7 @@ bool MakeBase::listFiles(MakeBase &propRef, FileSet &fileSet) std::vector::iterator siter; for (siter = excludes.begin() ; siter != excludes.end() ; siter++) { - String pattern = *siter; + String &pattern = *siter; if (regexMatch(s, pattern)) { //trace("EXCLUDED:%s", s.c_str()); @@ -3857,11 +4620,160 @@ bool MakeBase::listFiles(MakeBase &propRef, FileSet &fileSet) } +/** + * 0 == all, 1 = cflags, 2 = libs + */ +bool MakeBase::pkgConfigRecursive(const String packageName, + const String &path, + const String &prefix, + int query, + String &result, + std::set &deplist) +{ + PkgConfig pkgConfig; + if (path.size() > 0) + pkgConfig.setPath(path); + if (prefix.size() > 0) + pkgConfig.setPrefix(prefix); + if (!pkgConfig.query(packageName)) + return false; + if (query == 0) + result = pkgConfig.getAll(); + else if (query == 1) + result = pkgConfig.getCflags(); + else + result = pkgConfig.getLibs(); + deplist.insert(packageName); + std::vector list = pkgConfig.getRequireList(); + for (unsigned int i = 0 ; i deplist; + String path = getProperty("pkg-config-path"); + if (path.size()>0) + path = resolve(path); + String prefix = getProperty("pkg-config-prefix"); + String val; + if (!pkgConfigRecursive(packageName, path, prefix, query, val, deplist)) + return false; + result = val; + return true; +} -bool MakeBase::getSubstitutions(const String &str, String &result) +/** + * replace a variable ref like ${a} with a value + */ +bool MakeBase::lookupProperty(const String &propertyName, String &result) +{ + String varname = propertyName; + if (envPrefix.size() > 0 && + varname.compare(0, envPrefix.size(), envPrefix) == 0) + { + varname = varname.substr(envPrefix.size()); + char *envstr = getenv(varname.c_str()); + if (!envstr) + { + error("environment variable '%s' not defined", varname.c_str()); + return false; + } + result = envstr; + } + else if (pcPrefix.size() > 0 && + varname.compare(0, pcPrefix.size(), pcPrefix) == 0) + { + varname = varname.substr(pcPrefix.size()); + String val; + if (!pkgConfigQuery(varname, 0, val)) + return false; + result = val; + } + else if (pccPrefix.size() > 0 && + varname.compare(0, pccPrefix.size(), pccPrefix) == 0) + { + varname = varname.substr(pccPrefix.size()); + String val; + if (!pkgConfigQuery(varname, 1, val)) + return false; + result = val; + } + else if (pclPrefix.size() > 0 && + varname.compare(0, pclPrefix.size(), pclPrefix) == 0) + { + varname = varname.substr(pclPrefix.size()); + String val; + if (!pkgConfigQuery(varname, 2, val)) + return false; + result = val; + } + else if (bzrPrefix.size() > 0 && + varname.compare(0, bzrPrefix.size(), bzrPrefix) == 0) + { + varname = varname.substr(bzrPrefix.size()); + String val; + //SvnInfo svnInfo; + BzrRevno bzrRevno; + if (varname == "revision") + { + if (!bzrRevno.query(val)) + return ""; + result = "r"+val; + } + /*if (!svnInfo.query(varname, val)) + return false; + result = val;*/ + } + else + { + std::map::iterator iter; + iter = properties.find(varname); + if (iter != properties.end()) + { + result = iter->second; + } + else + { + error("property '%s' not found", varname.c_str()); + return false; + } + } + return true; +} + + + + +/** + * Analyse a string, looking for any substitutions or other + * things that need resolution + */ +bool MakeBase::getSubstitutionsRecursive(const String &str, + String &result, int depth) { + if (depth > 10) + { + error("nesting of substitutions too deep (>10) for '%s'", + str.c_str()); + return false; + } String s = trim(str); int len = (int)s.size(); String val; @@ -3883,32 +4795,15 @@ bool MakeBase::getSubstitutions(const String &str, String &result) } else if (ch == '}') { - std::map::iterator iter; varname = trim(varname); - if (envPrefix.size() > 0 && varname.compare(0, envPrefix.size(), envPrefix) == 0) - { - 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 - { - iter = properties.find(varname); - if (iter != properties.end()) - { - val.append(iter->second); - } - else - { - error("property ${%s} not found", varname.c_str()); - return false; - } - } + String varval; + if (!lookupProperty(varname, varval)) + return false; + String varval2; + //Now see if the answer has ${} in it, too + if (!getSubstitutionsRecursive(varval, varval2, depth + 1)) + return false; + val.append(varval2); break; } else @@ -3927,38 +4822,80 @@ bool MakeBase::getSubstitutions(const String &str, String &result) return true; } - -bool MakeBase::getAttribute(Element *elem, const String &name, - String &result) +/** + * Analyse a string, looking for any substitutions or other + * things that need resilution + */ +bool MakeBase::getSubstitutions(const String &str, String &result) { - String s = elem->getAttribute(name); - return getSubstitutions(s, result); + return getSubstitutionsRecursive(str, result, 0); } -bool MakeBase::getValue(Element *elem, String &result) + +/** + * replace variable refs like ${a} with their values + * Assume that the string has already been syntax validated + */ +String MakeBase::eval(const String &s, const String &defaultVal) { - String s = elem->getValue(); - //Replace all runs of whitespace with a single space - return getSubstitutions(s, result); + if (s.size()==0) + return defaultVal; + String ret; + if (getSubstitutions(s, ret)) + return ret; + else + return defaultVal; } /** - * Turn 'true' and 'false' into boolean values - */ -bool MakeBase::getBool(const String &str, bool &val) -{ - if (str == "true") - val = true; - else if (str == "false") - val = false; + * replace variable refs like ${a} with their values + * return true or false + * Assume that the string has already been syntax validated + */ +bool MakeBase::evalBool(const String &s, bool defaultVal) +{ + if (s.size()==0) + return defaultVal; + String val = eval(s, "false"); + if (val.size()==0) + return defaultVal; + if (val == "true" || val == "TRUE") + return true; else - { - error("expected 'true' or 'false'. found '%s'", str.c_str()); return false; - } - return true; +} + + +/** + * Get a string attribute, testing it for proper syntax and + * property names. + */ +bool MakeBase::getAttribute(Element *elem, const String &name, + String &result) +{ + String s = elem->getAttribute(name); + String tmp; + bool ret = getSubstitutions(s, tmp); + if (ret) + result = s; //assign -if- ok + return ret; +} + + +/** + * Get a string value, testing it for proper syntax and + * property names. + */ +bool MakeBase::getValue(Element *elem, String &result) +{ + String s = elem->getValue(); + String tmp; + bool ret = getSubstitutions(s, tmp); + if (ret) + result = s; //assign -if- ok + return ret; } @@ -4075,6 +5012,49 @@ bool MakeBase::parseFileSet(Element *elem, return true; } +/** + * Parse a 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 fnames; + //Look for child tags, namely "file" + std::vector children = elem->getChildren(); + for (unsigned int i=0 ; igetName(); + if (tagName == "file") + { + String fname = child->getAttribute("name"); + if (fname.size()==0) + { + error(" element requires name="" attribute"); + return false; + } + fnames.push_back(fname); + } + else + { + error("tag <%s> not allowed in ", 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; +} + /** @@ -4092,7 +5072,7 @@ bool MakeBase::createDirectory(const String &dirname) if (strlen(cnative)==2 && cnative[1]==':') return true; #endif - if (stat(cnative, &finfo)==0) + if (cachedStat(nativeDir, &finfo)==0) { if (!S_ISDIR(finfo.st_mode)) { @@ -4128,6 +5108,8 @@ bool MakeBase::createDirectory(const String &dirname) cnative, strerror(errno)); return false; } + + removeFromStatCache(nativeDir); return true; } @@ -4171,7 +5153,7 @@ bool MakeBase::removeDirectory(const String &dirName) struct stat finfo; String childNative = getNativePath(childName); char *cnative = (char *)childNative.c_str(); - if (stat(cnative, &finfo)<0) + if (cachedStat(childNative, &finfo)<0) { error("cannot stat file:%s", cnative); } @@ -4190,10 +5172,8 @@ bool MakeBase::removeDirectory(const String &dirName) else { //trace("DEL file: %s", childName.c_str()); - if (remove(cnative)<0) + if (!removeFile(childName)) { - error("error deleting %s : %s", - cnative, strerror(errno)); return false; } } @@ -4209,6 +5189,8 @@ bool MakeBase::removeDirectory(const String &dirName) return false; } + removeFromStatCache(native); + return true; } @@ -4222,7 +5204,7 @@ bool MakeBase::copyFile(const String &srcFile, const String &destFile) //# 1 Check up-to-date times String srcNative = getNativePath(srcFile); struct stat srcinfo; - if (stat(srcNative.c_str(), &srcinfo)<0) + if (cachedStat(srcNative, &srcinfo)<0) { error("source file %s for copy does not exist", srcNative.c_str()); @@ -4231,7 +5213,7 @@ bool MakeBase::copyFile(const String &srcFile, const String &destFile) String destNative = getNativePath(destFile); struct stat destinfo; - if (stat(destNative.c_str(), &destinfo)==0) + if (cachedStat(destNative, &destinfo)==0) { if (destinfo.st_mtime >= srcinfo.st_mtime) return true; @@ -4258,6 +5240,7 @@ bool MakeBase::copyFile(const String &srcFile, const String &destFile) FILE *destf = fopen(destNative.c_str(), "wb"); if (!destf) { + fclose(srcf); error("copyFile cannot open %s for writing", srcNative.c_str()); return false; } @@ -4281,316 +5264,172 @@ bool MakeBase::copyFile(const String &srcFile, const String &destFile) srcNative.c_str(), destNative.c_str()); return false; } - -#endif /* __WIN32__ */ + +#endif /* __WIN32__ */ + + removeFromStatCache(destNative); + + return true; +} + + +/** + * Delete a file + */ +bool MakeBase::removeFile(const String &file) +{ + String native = getNativePath(file); + + if (!fileExists(native)) + { + return true; + } + +#ifdef WIN32 + // On Windows 'remove' will only delete files + + if (remove(native.c_str())<0) + { + if (errno==EACCES) + { + error("File %s is read-only", native.c_str()); + } + else if (errno==ENOENT) + { + error("File %s does not exist or is a directory", native.c_str()); + } + else + { + error("Failed to delete file %s: %s", native.c_str(), strerror(errno)); + } + return false; + } + +#else + + if (!isRegularFile(native)) + { + error("File %s does not exist or is not a regular file", native.c_str()); + return false; + } + + if (remove(native.c_str())<0) + { + if (errno==EACCES) + { + error("File %s is read-only", native.c_str()); + } + else + { + error( + errno==EACCES ? "File %s is read-only" : + errno==ENOENT ? "File %s does not exist or is a directory" : + "Failed to delete file %s: %s", native.c_str()); + } + return false; + } +#endif + + removeFromStatCache(native); return true; } - /** - * Tests if the file exists and is a regular file + * Tests if the file exists */ -bool MakeBase::isRegularFile(const String &fileName) +bool MakeBase::fileExists(const String &fileName) { String native = getNativePath(fileName); struct stat finfo; //Exists? - if (stat(native.c_str(), &finfo)<0) - return false; - - - //check the file mode - if (!S_ISREG(finfo.st_mode)) + if (cachedStat(native, &finfo)<0) return false; return true; } + /** - * Tests if the file exists and is a directory + * Tests if the file exists and is a regular file */ -bool MakeBase::isDirectory(const String &fileName) +bool MakeBase::isRegularFile(const String &fileName) { String native = getNativePath(fileName); struct stat finfo; //Exists? - if (stat(native.c_str(), &finfo)<0) + if (cachedStat(native, &finfo)<0) return false; //check the file mode - if (!S_ISDIR(finfo.st_mode)) + if (!S_ISREG(finfo.st_mode)) return false; return true; } - - /** - * Tests is the modification of fileA is newer than fileB + * Tests if the file exists and is a directory */ -bool MakeBase::isNewerThan(const String &fileA, const String &fileB) +bool MakeBase::isDirectory(const String &fileName) { - //trace("isNewerThan:'%s' , '%s'", fileA.c_str(), fileB.c_str()); - String nativeA = getNativePath(fileA); - struct stat infoA; - //IF source does not exist, NOT newer - if (stat(nativeA.c_str(), &infoA)<0) - { + String native = getNativePath(fileName); + struct stat finfo; + + //Exists? + if (cachedStat(native, &finfo)<0) return false; - } - - String nativeB = getNativePath(fileB); - struct stat infoB; - //IF dest does not exist, YES, newer - if (stat(nativeB.c_str(), &infoB)<0) - { - return true; - } - - //check the actual times - if (infoA.st_mtime > infoB.st_mtime) - { - return true; - } - - return false; -} - - -//######################################################################## -//# P K G C O N F I G -//######################################################################## - -/** - * - */ -class PkgConfig : public MakeBase -{ - -public: - - /** - * - */ - PkgConfig() - { path="."; init(); } - - /** - * - */ - PkgConfig(const PkgConfig &other) - { assign(other); } - - /** - * - */ - PkgConfig &operator=(const PkgConfig &other) - { assign(other); return *this; } - - /** - * - */ - virtual ~PkgConfig() - { } - - /** - * - */ - 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; } - - /** - * - */ - virtual String getDescription() - { return description; } - - /** - * - */ - virtual String getCflags() - { return cflags; } - - /** - * - */ - virtual String getLibs() - { return libs; } - - /** - * - */ - virtual String getAll() - { - String ret = cflags; - ret.append(" "); - ret.append(libs); - return ret; - } - - /** - * - */ - virtual String getVersion() - { return version; } - - /** - * - */ - virtual int getMajorVersion() - { return majorVersion; } - - /** - * - */ - virtual int getMinorVersion() - { return minorVersion; } - - /** - * - */ - virtual int getMicroVersion() - { return microVersion; } - - /** - * - */ - virtual std::map &getAttributes() - { return attrs; } - - /** - * - */ - virtual std::vector &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 = ""; - libs = ""; - requires = ""; - version = ""; - majorVersion = 0; - minorVersion = 0; - microVersion = 0; - fileName = ""; - attrs.clear(); - requireList.clear(); - } - - void assign(const PkgConfig &other) - { - name = other.name; - path = other.path; - prefix = other.prefix; - description = other.description; - cflags = other.cflags; - libs = other.libs; - requires = other.requires; - version = other.version; - majorVersion = other.majorVersion; - minorVersion = other.minorVersion; - microVersion = other.microVersion; - fileName = other.fileName; - attrs = other.attrs; - requireList = other.requireList; - } - - - - int get(int pos); - - int skipwhite(int pos); - - int getword(int pos, String &ret); - - void parseRequires(); - - void parseVersion(); - - bool parseLine(const String &lineBuf); - - bool parse(const String &buf); - - void dumpAttrs(); - - String name; - - String path; - - String prefix; - - String description; - String cflags; - String libs; + //check the file mode + if (!S_ISDIR(finfo.st_mode)) + return false; - String requires; + return true; +} - String version; - int majorVersion; - int minorVersion; +/** + * Tests is the modification of fileA is newer than fileB + */ +bool MakeBase::isNewerThan(const String &fileA, const String &fileB) +{ + //trace("isNewerThan:'%s' , '%s'", fileA.c_str(), fileB.c_str()); + String nativeA = getNativePath(fileA); + struct stat infoA; + //IF source does not exist, NOT newer + if (cachedStat(nativeA, &infoA)<0) + { + return false; + } - int microVersion; + String nativeB = getNativePath(fileB); + struct stat infoB; + //IF dest does not exist, YES, newer + if (cachedStat(nativeB, &infoB)<0) + { + return true; + } - String fileName; + //check the actual times + if (infoA.st_mtime > infoB.st_mtime) + { + return true; + } - std::map attrs; + return false; +} - std::vector requireList; - char *parsebuf; - int parselen; -}; +//######################################################################## +//# P K G C O N F I G +//######################################################################## /** @@ -4638,7 +5477,7 @@ int PkgConfig::getword(int pos, String &ret) int ch = get(pos); if (ch < 0) break; - if (!isalnum(ch) && ch != '_' && ch != '-'&& ch != '.') + if (!isalnum(ch) && ch != '_' && ch != '-' && ch != '+' && ch != '.') break; ret.push_back((char)ch); pos++; @@ -4646,10 +5485,10 @@ int PkgConfig::getword(int pos, String &ret) return pos; } -void PkgConfig::parseRequires() +bool PkgConfig::parseRequires() { if (requires.size() == 0) - return; + return true; parsebuf = (char *)requires.c_str(); parselen = requires.size(); int pos = 0; @@ -4664,8 +5503,10 @@ void PkgConfig::parseRequires() //trace("val %s", val.c_str()); requireList.push_back(val); } + return true; } + static int getint(const String str) { char *s = (char *)str.c_str(); @@ -4914,15 +5755,16 @@ bool PkgConfig::query(const String &pkgName) fname.append(".pc"); if (!readFile(fname)) + { + error("Cannot find package '%s'. Do you have it installed?", + pkgName.c_str()); return false; + } return true; } - - - //######################################################################## //# D E P T O O L //######################################################################## @@ -5525,8 +6367,8 @@ bool DepTool::scanFile(const String &fname, FileRec *frec) String buf; while (!feof(f)) { - int len = fread(readBuf, 1, readBufSize, f); - readBuf[len] = '\0'; + int nrbytes = fread(readBuf, 1, readBufSize, f); + readBuf[nrbytes] = '\0'; buf.append(readBuf); } fclose(f); @@ -5645,7 +6487,7 @@ bool DepTool::generateDependencies() FileRec *include = iter->second; if (include->type == FileRec::CFILE) { - String cFileName = iter->first; + //String cFileName = iter->first; FileRec *ofile = new FileRec(FileRec::OFILE); ofile->path = include->path; ofile->baseName = include->baseName; @@ -5877,7 +6719,11 @@ public: TASK_NONE, TASK_CC, TASK_COPY, + TASK_CXXTEST_PART, + TASK_CXXTEST_ROOT, + TASK_CXXTEST_RUN, TASK_DELETE, + TASK_ECHO, TASK_JAR, TASK_JAVAC, TASK_LINK, @@ -5976,6 +6822,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; @@ -6002,39 +6861,49 @@ public: TaskCC(MakeBase &par) : Task(par) { - type = TASK_CC; name = "cc"; - ccCommand = "gcc"; - cxxCommand = "g++"; - source = "."; - dest = "."; - flags = ""; - defines = ""; - includes = ""; - fileSet.clear(); + type = TASK_CC; + name = "cc"; } 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::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) @@ -6077,9 +6950,14 @@ public: dname.append(source); dname.append("/"); } - dname.append(*setIter); + dname.append(dirName); incs.append(parent.resolve(dname)); } + + /** + * Compile each of the C files that need it + */ + bool errorOccurred = false; std::vector cfiles; for (viter=deps.begin() ; viter!=deps.end() ; viter++) { @@ -6130,7 +7008,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; } @@ -6153,7 +7031,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; @@ -6211,13 +7089,17 @@ public: fprintf(f, "\n"); fprintf(f, "#### STDOUT ###\n%s\n", outString.c_str()); fprintf(f, "#### STDERR ###\n%s\n\n", errString.c_str()); + fflush(f); } if (!ret) { error("problem compiling: %s", errString.c_str()); - return false; + errorOccurred = true; } - + if (errorOccurred && !continueOnError) + break; + + removeFromStatCache(getNativePath(destFullName)); } if (f) @@ -6225,24 +7107,27 @@ public: fclose(f); } - return true; + return !errorOccurred; } + virtual bool parse(Element *elem) { String s; - if (!parent.getAttribute(elem, "command", s)) + if (!parent.getAttribute(elem, "command", commandOpt)) + return false; + if (commandOpt.size()>0) + { cxxCommandOpt = ccCommandOpt = commandOpt; } + if (!parent.getAttribute(elem, "cc", ccCommandOpt)) return false; - if (s.size()>0) { ccCommand = s; cxxCommand = s; } - if (!parent.getAttribute(elem, "cc", s)) + if (!parent.getAttribute(elem, "cxx", cxxCommandOpt)) return false; - if (s.size()>0) ccCommand = s; - if (!parent.getAttribute(elem, "cxx", s)) + if (!parent.getAttribute(elem, "destdir", destOpt)) return false; - if (s.size()>0) cxxCommand = s; - if (!parent.getAttribute(elem, "destdir", s)) + if (!parent.getAttribute(elem, "continueOnError", continueOnErrorOpt)) + return false; + if (!parent.getAttribute(elem, "refreshCache", refreshCacheOpt)) return false; - if (s.size()>0) dest = s; std::vector children = elem->getChildren(); for (unsigned int i=0 ; igetName(); if (tagName == "flags") { - if (!parent.getValue(child, flags)) + if (!parent.getValue(child, flagsOpt)) return false; - flags = strip(flags); + flagsOpt = strip(flagsOpt); } else if (tagName == "includes") { - if (!parent.getValue(child, includes)) + if (!parent.getValue(child, includesOpt)) return false; - includes = strip(includes); + includesOpt = strip(includesOpt); } else if (tagName == "defines") { - if (!parent.getValue(child, defines)) + if (!parent.getValue(child, definesOpt)) return false; - defines = strip(defines); + definesOpt = strip(definesOpt); } else if (tagName == "fileset") { if (!parseFileSet(child, parent, fileSet)) return false; - source = fileSet.getDirectory(); + sourceOpt = fileSet.getDirectory(); + } + else if (tagName == "excludeinc") + { + if (!parseFileList(child, parent, excludeInc)) + return false; } } @@ -6280,14 +7170,18 @@ public: protected: - String ccCommand; - String cxxCommand; - String source; - String dest; - String flags; - String defines; - String includes; - FileSet fileSet; + String commandOpt; + String ccCommandOpt; + String cxxCommandOpt; + String sourceOpt; + String destOpt; + String flagsOpt; + String definesOpt; + String includesOpt; + String continueOnErrorOpt; + String refreshCacheOpt; + FileSet fileSet; + FileList excludeInc; }; @@ -6309,9 +7203,9 @@ public: TaskCopy(MakeBase &par) : Task(par) { - type = TASK_COPY; name = "copy"; - cptype = CP_NONE; - verbose = false; + type = TASK_COPY; + name = "copy"; + cptype = CP_NONE; haveFileSet = false; } @@ -6320,18 +7214,23 @@ public: virtual bool execute() { + String fileName = parent.eval(fileNameOpt , "."); + String toFileName = parent.eval(toFileNameOpt , "."); + String toDirName = parent.eval(toDirNameOpt , "."); + bool verbose = parent.evalBool(verboseOpt, false); switch (cptype) { case CP_TOFILE: { 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); - //trace("copy %s to file %s", fullSource.c_str(), - // fullDest.c_str()); + if (verbose) + taskstatus("copy %s to file %s", fullSource.c_str(), + fullDest.c_str()); if (!isRegularFile(fullSource)) { error("copy : file %s does not exist", fullSource.c_str()); @@ -6339,12 +7238,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; } @@ -6354,9 +7253,9 @@ public: { if (!listFiles(parent, fileSet)) return false; - String fileSetDir = fileSet.getDirectory(); + String fileSetDir = parent.eval(fileSet.getDirectory(), "."); - status(" : %s to %s", + taskstatus("%s to %s", fileSetDir.c_str(), toDirName.c_str()); int nrFiles = 0; @@ -6396,24 +7295,26 @@ public: destPath.append(fileName); String fullDest = parent.resolve(destPath); //trace("fileName:%s", fileName.c_str()); - //trace("copy %s to new dir : %s", fullSource.c_str(), - // fullDest.c_str()); + if (verbose) + taskstatus("copy %s to new dir : %s", + fullSource.c_str(), fullDest.c_str()); if (!isNewerThan(fullSource, fullDest)) { - //trace("copy skipping %s", fullSource.c_str()); + if (verbose) + taskstatus("copy skipping %s", fullSource.c_str()); continue; } if (!copyFile(fullSource, fullDest)) 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('/'); @@ -6428,8 +7329,9 @@ public: } destPath.append(baseName); String fullDest = parent.resolve(destPath); - //trace("copy %s to new dir : %s", fullSource.c_str(), - // fullDest.c_str()); + if (verbose) + taskstatus("file %s to new dir : %s", fullSource.c_str(), + fullDest.c_str()); if (!isRegularFile(fullSource)) { error("copy : file %s does not exist", fullSource.c_str()); @@ -6437,12 +7339,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; } @@ -6453,24 +7355,260 @@ public: virtual bool parse(Element *elem) { - if (!parent.getAttribute(elem, "file", fileName)) + if (!parent.getAttribute(elem, "file", fileNameOpt)) return false; - if (!parent.getAttribute(elem, "tofile", toFileName)) + if (!parent.getAttribute(elem, "tofile", toFileNameOpt)) return false; - if (toFileName.size() > 0) + if (toFileNameOpt.size() > 0) cptype = CP_TOFILE; - if (!parent.getAttribute(elem, "todir", toDirName)) + if (!parent.getAttribute(elem, "todir", toDirNameOpt)) + return false; + if (toDirNameOpt.size() > 0) + cptype = CP_TODIR; + if (!parent.getAttribute(elem, "verbose", verboseOpt)) + return false; + + haveFileSet = false; + + std::vector children = elem->getChildren(); + for (unsigned int i=0 ; igetName(); + if (tagName == "fileset") + { + if (!parseFileSet(child, parent, fileSet)) + { + error("problem getting fileset"); + return false; + } + haveFileSet = true; + } + } + + //Perform validity checks + if (fileNameOpt.size()>0 && fileSet.size()>0) + { + error(" can only have one of : file= and "); + return false; + } + if (toFileNameOpt.size()>0 && toDirNameOpt.size()>0) + { + error(" can only have one of : tofile= or todir="); + return false; + } + if (haveFileSet && toDirNameOpt.size()==0) + { + error("a task with a must have : todir="); + return false; + } + if (cptype == CP_TOFILE && fileNameOpt.size()==0) + { + error(" tofile= must be associated with : file="); + return false; + } + if (cptype == CP_TODIR && fileNameOpt.size()==0 && !haveFileSet) + { + error(" todir= must be associated with : file= or "); + return false; + } + + return true; + } + +private: + + int cptype; + bool haveFileSet; + + FileSet fileSet; + String fileNameOpt; + String toFileNameOpt; + String toDirNameOpt; + String verboseOpt; +}; + + +/** + * Generate CxxTest files + */ +class TaskCxxTestPart: public Task +{ +public: + + TaskCxxTestPart(MakeBase &par) : Task(par) + { + type = TASK_CXXTEST_PART; + name = "cxxtestpart"; + } + + virtual ~TaskCxxTestPart() + {} + + virtual bool execute() + { + if (!listFiles(parent, fileSet)) + return false; + String fileSetDir = parent.eval(fileSet.getDirectory(), "."); + + String fullDest = parent.resolve(parent.eval(destPathOpt, ".")); + String cmd = parent.eval(commandOpt, "cxxtestgen.py"); + cmd.append(" --part -o "); + cmd.append(fullDest); + + unsigned int newFiles = 0; + for (unsigned int i=0 ; i0) + { + sourcePath.append(fileSetDir); + sourcePath.append("/"); + } + sourcePath.append(fileName); + String fullSource = parent.resolve(sourcePath); + + cmd.append(" "); + cmd.append(fullSource); + if (isNewerThan(fullSource, fullDest)) newFiles++; + } + + if (newFiles>0) { + size_t const lastSlash = fullDest.find_last_of('/'); + if (lastSlash != fullDest.npos) { + String directory(fullDest, 0, lastSlash); + if (!createDirectory(directory)) + return false; + } + + String outString, errString; + if (!executeCommand(cmd.c_str(), "", outString, errString)) + { + error(" problem: %s", errString.c_str()); + return false; + } + removeFromStatCache(getNativePath(fullDest)); + } + + return true; + } + + virtual bool parse(Element *elem) + { + if (!parent.getAttribute(elem, "command", commandOpt)) + return false; + if (!parent.getAttribute(elem, "out", destPathOpt)) + return false; + + std::vector children = elem->getChildren(); + for (unsigned int i=0 ; igetName(); + if (tagName == "fileset") + { + if (!parseFileSet(child, parent, fileSet)) + return false; + } + } + return true; + } + +private: + + String commandOpt; + String destPathOpt; + FileSet fileSet; + +}; + + +/** + * Generate the CxxTest root file + */ +class TaskCxxTestRoot: public Task +{ +public: + + TaskCxxTestRoot(MakeBase &par) : Task(par) + { + type = TASK_CXXTEST_ROOT; + name = "cxxtestroot"; + } + + virtual ~TaskCxxTestRoot() + {} + + virtual bool execute() + { + if (!listFiles(parent, fileSet)) + return false; + String fileSetDir = parent.eval(fileSet.getDirectory(), "."); + unsigned int newFiles = 0; + + String fullDest = parent.resolve(parent.eval(destPathOpt, ".")); + String cmd = parent.eval(commandOpt, "cxxtestgen.py"); + cmd.append(" --root -o "); + cmd.append(fullDest); + String templateFile = parent.eval(templateFileOpt, ""); + if (templateFile.size()>0) { + String fullTemplate = parent.resolve(templateFile); + cmd.append(" --template="); + cmd.append(fullTemplate); + if (isNewerThan(fullTemplate, fullDest)) newFiles++; + } + + for (unsigned int i=0 ; i0) + { + sourcePath.append(fileSetDir); + sourcePath.append("/"); + } + sourcePath.append(fileName); + String fullSource = parent.resolve(sourcePath); + + cmd.append(" "); + cmd.append(fullSource); + if (isNewerThan(fullSource, fullDest)) newFiles++; + } + + if (newFiles>0) { + size_t const lastSlash = fullDest.find_last_of('/'); + if (lastSlash != fullDest.npos) { + String directory(fullDest, 0, lastSlash); + if (!createDirectory(directory)) + return false; + } + + String outString, errString; + if (!executeCommand(cmd.c_str(), "", outString, errString)) + { + error(" problem: %s", errString.c_str()); + return false; + } + removeFromStatCache(getNativePath(fullDest)); + } + + return true; + } + + virtual bool parse(Element *elem) + { + if (!parent.getAttribute(elem, "command", commandOpt)) return false; - if (toDirName.size() > 0) - cptype = CP_TODIR; - String ret; - if (!parent.getAttribute(elem, "verbose", ret)) + if (!parent.getAttribute(elem, "template", templateFileOpt)) return false; - if (ret.size()>0 && !getBool(ret, verbose)) + if (!parent.getAttribute(elem, "out", destPathOpt)) return false; - haveFileSet = false; - std::vector children = elem->getChildren(); for (unsigned int i=0 ; i0 && fileSet.size()>0) - { - error(" can only have one of : file= and "); - return false; - } - if (toFileName.size()>0 && toDirName.size()>0) - { - error(" can only have one of : tofile= or todir="); - return false; +private: + + String commandOpt; + String templateFileOpt; + String destPathOpt; + FileSet fileSet; + +}; + + +/** + * Execute the CxxTest test executable + */ +class TaskCxxTestRun: public Task +{ +public: + + TaskCxxTestRun(MakeBase &par) : Task(par) + { + type = TASK_CXXTEST_RUN; + name = "cxxtestrun"; + } + + virtual ~TaskCxxTestRun() + {} + + virtual bool execute() + { + unsigned int newFiles = 0; + + String workingDir = parent.resolve(parent.eval(workingDirOpt, "inkscape")); + String rawCmd = parent.eval(commandOpt, "build/cxxtests"); + + String cmdExe; + if (fileExists(rawCmd)) { + cmdExe = rawCmd; + } else if (fileExists(rawCmd + ".exe")) { + cmdExe = rawCmd + ".exe"; + } else { + error(" problem: cxxtests executable not found! (command=\"%s\")", rawCmd.c_str()); + } + // Note that the log file names are based on the exact name used to call cxxtests (it uses argv[0] + ".log"/".xml") + if (isNewerThan(cmdExe, rawCmd + ".log") || isNewerThan(cmdExe, rawCmd + ".xml")) newFiles++; + + // Prepend the necessary ../'s + String cmd = rawCmd; + unsigned int workingDirDepth = 0; + bool wasSlash = true; + for(size_t i=0; i0) { + char olddir[1024]; + if (workingDir.size()>0) { + // TODO: Double-check usage of getcwd and handle chdir errors + getcwd(olddir, 1024); + chdir(workingDir.c_str()); } - if (haveFileSet && toDirName.size()==0) - { - error("a task with a must have : todir="); - return false; + + String outString; + if (!executeCommand(cmd.c_str(), "", outString, outString)) + { + error(" problem: %s", outString.c_str()); + return false; + } + + if (workingDir.size()>0) { + // TODO: Handle errors? + chdir(olddir); } - if (cptype == CP_TOFILE && fileName.size()==0) - { - error(" tofile= must be associated with : file="); + + removeFromStatCache(getNativePath(cmd + ".log")); + removeFromStatCache(getNativePath(cmd + ".xml")); + } + + return true; + } + + virtual bool parse(Element *elem) + { + if (!parent.getAttribute(elem, "command", commandOpt)) return false; - } - if (cptype == CP_TODIR && fileName.size()==0 && !haveFileSet) - { - error(" todir= must be associated with : file= or "); + if (!parent.getAttribute(elem, "workingdir", workingDirOpt)) return false; - } - return true; } - + private: - int cptype; - String fileName; - FileSet fileSet; - String toFileName; - String toDirName; - bool verbose; - bool haveFileSet; + String commandOpt; + String workingDirOpt; + }; @@ -6545,12 +7740,9 @@ public: TaskDelete(MakeBase &par) : Task(par) { - type = TASK_DELETE; - name = "delete"; - delType = DEL_FILE; - verbose = false; - quiet = false; - failOnError = true; + type = TASK_DELETE; + name = "delete"; + delType = DEL_FILE; } virtual ~TaskDelete() @@ -6558,37 +7750,38 @@ public: virtual bool execute() { - struct stat finfo; + String dirName = parent.eval(dirNameOpt, "."); + String fileName = parent.eval(fileNameOpt, "."); + bool verbose = parent.evalBool(verboseOpt, false); + bool quiet = parent.evalBool(quietOpt, false); + bool failOnError = parent.evalBool(failOnErrorOpt, true); switch (delType) { case DEL_FILE: { - status(" : %s", fileName.c_str()); + taskstatus("file: %s", fileName.c_str()); String fullName = parent.resolve(fileName); char *fname = (char *)fullName.c_str(); - //does not exist - if (stat(fname, &finfo)<0) - return true; - //exists but is not a regular file - if (!S_ISREG(finfo.st_mode)) - { - error(" failed. '%s' exists and is not a regular file", - fname); - return false; - } - if (remove(fname)<0) + if (!quiet && verbose) + taskstatus("path: %s", fname); + if (failOnError && !removeFile(fullName)) { - error(" failed: %s", strerror(errno)); + //error("Could not delete file '%s'", fullName.c_str()); return false; } return true; } case DEL_DIR: { - status(" : %s", dirName.c_str()); + taskstatus("dir: %s", dirName.c_str()); String fullDir = parent.resolve(dirName); - if (!removeDirectory(fullDir)) + if (!quiet && verbose) + taskstatus("path: %s", fullDir.c_str()); + if (failOnError && !removeDirectory(fullDir)) + { + //error("Could not delete directory '%s'", fullDir.c_str()); return false; + } return true; } } @@ -6597,51 +7790,91 @@ public: virtual bool parse(Element *elem) { - if (!parent.getAttribute(elem, "file", fileName)) + if (!parent.getAttribute(elem, "file", fileNameOpt)) return false; - if (fileName.size() > 0) + if (fileNameOpt.size() > 0) delType = DEL_FILE; - if (!parent.getAttribute(elem, "dir", dirName)) + if (!parent.getAttribute(elem, "dir", dirNameOpt)) return false; - if (dirName.size() > 0) + if (dirNameOpt.size() > 0) delType = DEL_DIR; - if (fileName.size()>0 && dirName.size()>0) + if (fileNameOpt.size()>0 && dirNameOpt.size()>0) { error(" can have one attribute of file= or dir="); return false; } - if (fileName.size()==0 && dirName.size()==0) + if (fileNameOpt.size()==0 && dirNameOpt.size()==0) { error(" must have one attribute of file= or dir="); return false; } - String ret; - if (!parent.getAttribute(elem, "verbose", ret)) + if (!parent.getAttribute(elem, "verbose", verboseOpt)) return false; - if (ret.size()>0 && !getBool(ret, verbose)) + if (!parent.getAttribute(elem, "quiet", quietOpt)) return false; - if (!parent.getAttribute(elem, "quiet", ret)) + if (!parent.getAttribute(elem, "failonerror", failOnErrorOpt)) return false; - if (ret.size()>0 && !getBool(ret, quiet)) - return false; - if (!parent.getAttribute(elem, "failonerror", ret)) + return true; + } + +private: + + int delType; + String dirNameOpt; + String fileNameOpt; + String verboseOpt; + String quietOpt; + String failOnErrorOpt; +}; + + +/** + * Send a message to stdout + */ +class TaskEcho : public Task +{ +public: + + TaskEcho(MakeBase &par) : Task(par) + { type = TASK_ECHO; name = "echo"; } + + virtual ~TaskEcho() + {} + + virtual bool execute() + { + //let message have priority over text + String message = parent.eval(messageOpt, ""); + String text = parent.eval(textOpt, ""); + if (message.size() > 0) + { + fprintf(stdout, "%s\n", message.c_str()); + } + else if (text.size() > 0) + { + fprintf(stdout, "%s\n", text.c_str()); + } + return true; + } + + virtual bool parse(Element *elem) + { + if (!parent.getValue(elem, textOpt)) return false; - if (ret.size()>0 && !getBool(ret, failOnError)) + textOpt = leftJustify(textOpt); + if (!parent.getAttribute(elem, "message", messageOpt)) return false; return true; } private: - int delType; - String dirName; - String fileName; - bool verbose; - bool quiet; - bool failOnError; + String messageOpt; + String textOpt; }; + /** * */ @@ -6657,13 +7890,52 @@ public: virtual bool execute() { + String command = parent.eval(commandOpt, "jar"); + String basedir = parent.eval(basedirOpt, "."); + String destfile = parent.eval(destfileOpt, "."); + + 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(" command '%s' failed :\n %s", + execCmd.c_str(), errString.c_str()); + return false; + } + removeFromStatCache(getNativePath(destfile)); return true; } virtual bool parse(Element *elem) { + if (!parent.getAttribute(elem, "command", commandOpt)) + return false; + if (!parent.getAttribute(elem, "basedir", basedirOpt)) + return false; + if (!parent.getAttribute(elem, "destfile", destfileOpt)) + return false; + if (basedirOpt.size() == 0 || destfileOpt.size() == 0) + { + error(" required both basedir and destfile attributes to be set"); + return false; + } return true; } + +private: + + String commandOpt; + String basedirOpt; + String destfileOpt; }; @@ -6677,7 +7949,6 @@ public: TaskJavac(MakeBase &par) : Task(par) { type = TASK_JAVAC; name = "javac"; - command = "javac"; } virtual ~TaskJavac() @@ -6685,6 +7956,11 @@ public: virtual bool execute() { + String command = parent.eval(commandOpt, "javac"); + String srcdir = parent.eval(srcdirOpt, "."); + String destdir = parent.eval(destdirOpt, "."); + String target = parent.eval(targetOpt, ""); + std::vector fileList; if (!listFiles(srcdir, "", fileList)) { @@ -6693,9 +7969,20 @@ public: 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 command '%s' failed :\n %s", - execCmd.c_str(), errString.c_str()); - return false; - } + String execCmd = cmd; + execCmd.append("@"); + execCmd.append(fname); + + String outString, errString; + bool ret = executeCommand(execCmd.c_str(), "", outString, errString); + if (!ret) + { + error(" command '%s' failed :\n %s", + execCmd.c_str(), errString.c_str()); + return false; } + // TODO: + //removeFromStatCache(getNativePath(........)); return true; } virtual bool parse(Element *elem) { - String s; - if (!parent.getAttribute(elem, "command", s)) + if (!parent.getAttribute(elem, "command", commandOpt)) return false; - if (s.size() > 0) - command = s; - if (!parent.getAttribute(elem, "srcdir", srcdir)) + if (!parent.getAttribute(elem, "srcdir", srcdirOpt)) return false; - if (!parent.getAttribute(elem, "destdir", destdir)) + if (!parent.getAttribute(elem, "destdir", destdirOpt)) return false; - if (srcdir.size() == 0 || destdir.size() == 0) + if (srcdirOpt.size() == 0 || destdirOpt.size() == 0) { error(" required both srcdir and destdir attributes to be set"); return false; } + if (!parent.getAttribute(elem, "target", targetOpt)) + return false; return true; } private: - String command; - String srcdir; - String destdir; + String commandOpt; + String srcdirOpt; + String destdirOpt; + String targetOpt; }; @@ -6771,10 +8072,6 @@ public: TaskLink(MakeBase &par) : Task(par) { type = TASK_LINK; name = "link"; - command = "g++"; - doStrip = false; - stripCommand = "strip"; - objcopyCommand = "objcopy"; } virtual ~TaskLink() @@ -6782,9 +8079,18 @@ public: virtual bool execute() { + String command = parent.eval(commandOpt, "g++"); + String fileName = parent.eval(fileNameOpt, ""); + String flags = parent.eval(flagsOpt, ""); + String libs = parent.eval(libsOpt, ""); + bool doStrip = parent.evalBool(doStripOpt, false); + String symFileName = parent.eval(symFileNameOpt, ""); + String stripCommand = parent.eval(stripCommandOpt, "strip"); + String objcopyCommand = parent.eval(objcopyCommandOpt, "objcopy"); + if (!listFiles(parent, fileSet)) return false; - String fileSetDir = fileSet.getDirectory(); + String fileSetDir = parent.eval(fileSet.getDirectory(), "."); //trace("%d files in %s", fileSet.size(), fileSetDir.c_str()); bool doit = false; String fullTarget = parent.resolve(fileName); @@ -6827,6 +8133,7 @@ public: error("LINK problem: %s", errbuf.c_str()); return false; } + removeFromStatCache(getNativePath(fullTarget)); if (symFileName.size()>0) { @@ -6841,6 +8148,7 @@ public: error(" symbol file failed : %s", errbuf.c_str()); return false; } + removeFromStatCache(getNativePath(symFullName)); } if (doStrip) @@ -6853,6 +8161,7 @@ public: error(" failed : %s", errbuf.c_str()); return false; } + removeFromStatCache(getNativePath(fullTarget)); } return true; @@ -6860,26 +8169,17 @@ public: 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, "objcopycommand", s)) + if (!parent.getAttribute(elem, "command", commandOpt)) return false; - if (s.size()>0) - objcopyCommand = s; - if (!parent.getAttribute(elem, "stripcommand", s)) + if (!parent.getAttribute(elem, "objcopycommand", objcopyCommandOpt)) return false; - if (s.size()>0) - stripCommand = s; - if (!parent.getAttribute(elem, "out", fileName)) + if (!parent.getAttribute(elem, "stripcommand", stripCommandOpt)) return false; - if (!parent.getAttribute(elem, "strip", s)) + if (!parent.getAttribute(elem, "out", fileNameOpt)) return false; - if (s.size()>0 && !getBool(s, doStrip)) + if (!parent.getAttribute(elem, "strip", doStripOpt)) return false; - if (!parent.getAttribute(elem, "symfile", symFileName)) + if (!parent.getAttribute(elem, "symfile", symFileNameOpt)) return false; std::vector children = elem->getChildren(); @@ -6894,15 +8194,15 @@ public: } else if (tagName == "flags") { - if (!parent.getValue(child, flags)) + if (!parent.getValue(child, flagsOpt)) return false; - flags = strip(flags); + flagsOpt = strip(flagsOpt); } else if (tagName == "libs") { - if (!parent.getValue(child, libs)) + if (!parent.getValue(child, libsOpt)) return false; - libs = strip(libs); + libsOpt = strip(libsOpt); } } return true; @@ -6910,22 +8210,23 @@ public: private: - String command; - String fileName; - String flags; - String libs; FileSet fileSet; - bool doStrip; - String symFileName; - String stripCommand; - String objcopyCommand; + + String commandOpt; + String fileNameOpt; + String flagsOpt; + String libsOpt; + String doStripOpt; + String symFileNameOpt; + String stripCommandOpt; + String objcopyCommandOpt; }; /** - * Create a named directory + * Create a named file */ class TaskMakeFile : public Task { @@ -6939,11 +8240,15 @@ public: virtual bool execute() { - status(" : %s", fileName.c_str()); + String fileName = parent.eval(fileNameOpt, ""); + bool force = parent.evalBool(forceOpt, false); + String text = parent.eval(textOpt, ""); + + taskstatus("%s", fileName.c_str()); String fullName = parent.resolve(fileName); - if (!isNewerThan(parent.getURI().getPath(), fullName)) + if (!force && !isNewerThan(parent.getURI().getPath(), fullName)) { - //trace("skipped "); + taskstatus("skipped"); return true; } String fullNative = getNativePath(fullName); @@ -6959,29 +8264,33 @@ public: fputc(text[i], f); fputc('\n', f); fclose(f); + removeFromStatCache(fullNative); return true; } virtual bool parse(Element *elem) { - if (!parent.getAttribute(elem, "file", fileName)) + if (!parent.getAttribute(elem, "file", fileNameOpt)) + return false; + if (!parent.getAttribute(elem, "force", forceOpt)) return false; - if (fileName.size() == 0) + if (fileNameOpt.size() == 0) { error(" requires 'file=\"filename\"' attribute"); return false; } - if (!parent.getValue(elem, text)) + if (!parent.getValue(elem, textOpt)) return false; - text = leftJustify(text); + textOpt = leftJustify(textOpt); //trace("dirname:%s", dirName.c_str()); return true; } private: - String fileName; - String text; + String fileNameOpt; + String forceOpt; + String textOpt; }; @@ -7001,7 +8310,9 @@ public: virtual bool execute() { - status(" : %s", dirName.c_str()); + String dirName = parent.eval(dirNameOpt, "."); + + taskstatus("%s", dirName.c_str()); String fullDir = parent.resolve(dirName); //trace("fullDir:%s", fullDir.c_str()); if (!createDirectory(fullDir)) @@ -7011,9 +8322,9 @@ public: virtual bool parse(Element *elem) { - if (!parent.getAttribute(elem, "dir", dirName)) + if (!parent.getAttribute(elem, "dir", dirNameOpt)) return false; - if (dirName.size() == 0) + if (dirNameOpt.size() == 0) { error(" requires 'dir=\"dirname\"' attribute"); return false; @@ -7023,7 +8334,7 @@ public: private: - String dirName; + String dirNameOpt; }; @@ -7036,19 +8347,18 @@ class TaskMsgFmt: public Task public: TaskMsgFmt(MakeBase &par) : Task(par) - { - type = TASK_MSGFMT; - name = "msgfmt"; - command = "msgfmt"; - owndir = false; - outName = ""; - } + { type = TASK_MSGFMT; name = "msgfmt"; } virtual ~TaskMsgFmt() {} virtual bool execute() { + String command = parent.eval(commandOpt, "msgfmt"); + String toDirName = parent.eval(toDirNameOpt, "."); + String outName = parent.eval(outNameOpt, ""); + bool owndir = parent.evalBool(owndirOpt, false); + if (!listFiles(parent, fileSet)) return false; String fileSetDir = fileSet.getDirectory(); @@ -7124,6 +8434,7 @@ public: error(" problem: %s", errString.c_str()); return false; } + removeFromStatCache(getNativePath(fullDest)); } return true; @@ -7131,18 +8442,13 @@ public: virtual bool parse(Element *elem) { - String s; - if (!parent.getAttribute(elem, "command", s)) + if (!parent.getAttribute(elem, "command", commandOpt)) return false; - if (s.size()>0) - command = s; - if (!parent.getAttribute(elem, "todir", toDirName)) + if (!parent.getAttribute(elem, "todir", toDirNameOpt)) return false; - if (!parent.getAttribute(elem, "out", outName)) + if (!parent.getAttribute(elem, "out", outNameOpt)) return false; - if (!parent.getAttribute(elem, "owndir", s)) - return false; - if (s.size()>0 && !getBool(s, owndir)) + if (!parent.getAttribute(elem, "owndir", owndirOpt)) return false; std::vector children = elem->getChildren(); @@ -7161,11 +8467,12 @@ public: private: - String command; - String toDirName; - String outName; FileSet fileSet; - bool owndir; + + String commandOpt; + String toDirNameOpt; + String outNameOpt; + String owndirOpt; }; @@ -7196,7 +8503,13 @@ public: virtual bool execute() { - String path = parent.resolve(pkg_config_path); + String pkgName = parent.eval(pkgNameOpt, ""); + String prefix = parent.eval(prefixOpt, ""); + String propName = parent.eval(propNameOpt, ""); + String pkgConfigPath = parent.eval(pkgConfigPathOpt,""); + String query = parent.eval(queryOpt, "all"); + + String path = parent.resolve(pkgConfigPath); PkgConfig pkgconfig; pkgconfig.setPath(path); pkgconfig.setPrefix(prefix); @@ -7205,105 +8518,63 @@ public: error(" 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(" unhandled query : %d", query); - return false; - } + String val = ""; + if (query == "cflags") + val = pkgconfig.getCflags(); + else if (query == "libs") + val =pkgconfig.getLibs(); + else if (query == "all") + val = pkgconfig.getAll(); + else + { + error(" unhandled query : %s", query.c_str()); + return false; } - status(" : %s", ret.c_str()); - parent.setProperty(propName, ret); + taskstatus("property %s = '%s'", propName.c_str(), val.c_str()); + parent.setProperty(propName, val); return true; } virtual bool parse(Element *elem) { - String s; //# NAME - if (!parent.getAttribute(elem, "name", s)) + if (!parent.getAttribute(elem, "name", pkgNameOpt)) return false; - if (s.size()>0) - pkgName = s; - else + if (pkgNameOpt.size()==0) { error(" requires 'name=\"package\"' attribute"); return false; } //# PROPERTY - if (!parent.getAttribute(elem, "property", s)) + if (!parent.getAttribute(elem, "property", propNameOpt)) return false; - if (s.size()>0) - propName = s; - else + if (propNameOpt.size()==0) { error(" requires 'property=\"name\"' attribute"); return false; } - if (parent.hasProperty(propName)) - { - error(" property '%s' is already defined", - propName.c_str()); - return false; - } - parent.setProperty(propName, "undefined"); - //# PATH - if (!parent.getAttribute(elem, "path", s)) + if (!parent.getAttribute(elem, "path", pkgConfigPathOpt)) return false; - if (s.size()>0) - pkg_config_path = s; - //# PREFIX - if (!parent.getAttribute(elem, "prefix", s)) + if (!parent.getAttribute(elem, "prefix", prefixOpt)) return false; - if (s.size()>0) - prefix = s; - //# QUERY - if (!parent.getAttribute(elem, "query", s)) - return false; - if (s == "cflags") - query = PKG_CONFIG_QUERY_CFLAGS; - else if (s == "libs") - query = PKG_CONFIG_QUERY_LIBS; - else if (s == "both") - query = PKG_CONFIG_QUERY_ALL; - else - { - error(" requires 'query=\"type\"' attribute"); - error("where type = cflags, libs, or both"); + if (!parent.getAttribute(elem, "query", queryOpt)) return false; - } + return true; } private: - String pkgName; - String prefix; - String propName; - String pkg_config_path; - int query; + String queryOpt; + String pkgNameOpt; + String prefixOpt; + String propNameOpt; + String pkgConfigPathOpt; }; @@ -7320,16 +8591,16 @@ class TaskRanlib : public Task public: TaskRanlib(MakeBase &par) : Task(par) - { - type = TASK_RANLIB; name = "ranlib"; - command = "ranlib"; - } + { type = TASK_RANLIB; name = "ranlib"; } virtual ~TaskRanlib() {} virtual bool execute() { + String fileName = parent.eval(fileNameOpt, ""); + String command = parent.eval(commandOpt, "ranlib"); + String fullName = parent.resolve(fileName); //trace("fullDir:%s", fullDir.c_str()); String cmd = command; @@ -7338,19 +8609,18 @@ public: String outbuf, errbuf; if (!executeCommand(cmd, "", outbuf, errbuf)) return false; + // TODO: + //removeFromStatCache(getNativePath(fullDest)); return true; } virtual bool parse(Element *elem) { - String s; - if (!parent.getAttribute(elem, "command", s)) + if (!parent.getAttribute(elem, "command", commandOpt)) return false; - if (s.size()>0) - command = s; - if (!parent.getAttribute(elem, "file", fileName)) + if (!parent.getAttribute(elem, "file", fileNameOpt)) return false; - if (fileName.size() == 0) + if (fileNameOpt.size() == 0) { error(" requires 'file=\"fileNname\"' attribute"); return false; @@ -7360,30 +8630,32 @@ public: private: - String fileName; - String command; + String fileNameOpt; + String commandOpt; }; /** - * Run the "ar" command to archive .o's into a .a + * Compile a resource file into a binary object */ class TaskRC : public Task { public: TaskRC(MakeBase &par) : Task(par) - { - type = TASK_RC; name = "rc"; - command = "windres"; - } + { type = TASK_RC; name = "rc"; } virtual ~TaskRC() {} virtual bool execute() { + String command = parent.eval(commandOpt, "windres"); + String flags = parent.eval(flagsOpt, ""); + String fileName = parent.eval(fileNameOpt, ""); + String outName = parent.eval(outNameOpt, ""); + String fullFile = parent.resolve(fileName); String fullOut = parent.resolve(outName); if (!isNewerThan(fullFile, fullOut)) @@ -7402,16 +8674,17 @@ public: error("RC problem: %s", errString.c_str()); return false; } + removeFromStatCache(getNativePath(fullOut)); return true; } virtual bool parse(Element *elem) { - if (!parent.getAttribute(elem, "command", command)) + if (!parent.getAttribute(elem, "command", commandOpt)) return false; - if (!parent.getAttribute(elem, "file", fileName)) + if (!parent.getAttribute(elem, "file", fileNameOpt)) return false; - if (!parent.getAttribute(elem, "out", outName)) + if (!parent.getAttribute(elem, "out", outNameOpt)) return false; std::vector children = elem->getChildren(); for (unsigned int i=0 ; igetName(); if (tagName == "flags") { - if (!parent.getValue(child, flags)) + if (!parent.getValue(child, flagsOpt)) return false; } } @@ -7429,10 +8702,10 @@ public: private: - String command; - String flags; - String fileName; - String outName; + String commandOpt; + String flagsOpt; + String fileNameOpt; + String outNameOpt; }; @@ -7446,16 +8719,19 @@ class TaskSharedLib : public Task public: TaskSharedLib(MakeBase &par) : Task(par) - { - type = TASK_SHAREDLIB; name = "dll"; - command = "dllwrap"; - } + { type = TASK_SHAREDLIB; name = "dll"; } virtual ~TaskSharedLib() {} virtual bool execute() { + String command = parent.eval(commandOpt, "dllwrap"); + String fileName = parent.eval(fileNameOpt, ""); + String defFileName = parent.eval(defFileNameOpt, ""); + String impFileName = parent.eval(impFileNameOpt, ""); + String libs = parent.eval(libsOpt, ""); + //trace("###########HERE %d", fileSet.size()); bool doit = false; @@ -7464,7 +8740,7 @@ public: if (!listFiles(parent, fileSet)) return false; - String fileSetDir = fileSet.getDirectory(); + String fileSetDir = parent.eval(fileSet.getDirectory(), "."); for (unsigned int i=0 ; i problem: %s", errString.c_str()); return false; } - + removeFromStatCache(getNativePath(fullOut)); return true; } virtual bool parse(Element *elem) { - if (!parent.getAttribute(elem, "file", fileName)) + if (!parent.getAttribute(elem, "command", commandOpt)) + return false; + if (!parent.getAttribute(elem, "file", fileNameOpt)) return false; - if (!parent.getAttribute(elem, "import", impFileName)) + if (!parent.getAttribute(elem, "import", impFileNameOpt)) return false; - if (!parent.getAttribute(elem, "def", defFileName)) + if (!parent.getAttribute(elem, "def", defFileNameOpt)) return false; std::vector children = elem->getChildren(); @@ -7549,9 +8827,9 @@ public: } else if (tagName == "libs") { - if (!parent.getValue(child, libs)) + if (!parent.getValue(child, libsOpt)) return false; - libs = strip(libs); + libsOpt = strip(libsOpt); } } return true; @@ -7559,12 +8837,13 @@ public: private: - String command; - String fileName; - String defFileName; - String impFileName; FileSet fileSet; - String libs; + + String commandOpt; + String fileNameOpt; + String defFileNameOpt; + String impFileNameOpt; + String libsOpt; }; @@ -7578,17 +8857,16 @@ class TaskStaticLib : public Task public: TaskStaticLib(MakeBase &par) : Task(par) - { - type = TASK_STATICLIB; name = "staticlib"; - command = "ar crv"; - } + { type = TASK_STATICLIB; name = "staticlib"; } virtual ~TaskStaticLib() {} virtual bool execute() { - //trace("###########HERE %d", fileSet.size()); + String command = parent.eval(commandOpt, "ar crv"); + String fileName = parent.eval(fileNameOpt, ""); + bool doit = false; String fullOut = parent.resolve(fileName); @@ -7596,7 +8874,8 @@ public: if (!listFiles(parent, fileSet)) return false; - String fileSetDir = fileSet.getDirectory(); + String fileSetDir = parent.eval(fileSet.getDirectory(), "."); + //trace("###########HERE %s", fileSetDir.c_str()); for (unsigned int i=0 ; i problem: %s", errString.c_str()); return false; } - + removeFromStatCache(getNativePath(fullOut)); return true; } virtual bool parse(Element *elem) { - String s; - if (!parent.getAttribute(elem, "command", s)) + if (!parent.getAttribute(elem, "command", commandOpt)) return false; - if (s.size()>0) - command = s; - if (!parent.getAttribute(elem, "file", fileName)) + if (!parent.getAttribute(elem, "file", fileNameOpt)) return false; std::vector children = elem->getChildren(); @@ -7673,10 +8949,11 @@ public: private: - String command; - String fileName; FileSet fileSet; + String commandOpt; + String fileNameOpt; + }; @@ -7697,6 +8974,10 @@ public: virtual bool execute() { + String command = parent.eval(commandOpt, "strip"); + String fileName = parent.eval(fileNameOpt, ""); + String symFileName = parent.eval(symFileNameOpt, ""); + String fullName = parent.resolve(fileName); //trace("fullDir:%s", fullDir.c_str()); String cmd; @@ -7716,23 +8997,26 @@ public: } } - cmd = "strip "; + cmd = command; cmd.append(getNativePath(fullName)); if (!executeCommand(cmd, "", outbuf, errbuf)) { error(" failed : %s", errbuf.c_str()); return false; } + removeFromStatCache(getNativePath(fullName)); return true; } virtual bool parse(Element *elem) { - if (!parent.getAttribute(elem, "file", fileName)) + if (!parent.getAttribute(elem, "command", commandOpt)) + return false; + if (!parent.getAttribute(elem, "file", fileNameOpt)) return false; - if (!parent.getAttribute(elem, "symfile", symFileName)) + if (!parent.getAttribute(elem, "symfile", symFileNameOpt)) return false; - if (fileName.size() == 0) + if (fileNameOpt.size() == 0) { error(" requires 'file=\"fileName\"' attribute"); return false; @@ -7742,8 +9026,9 @@ public: private: - String fileName; - String symFileName; + String commandOpt; + String fileNameOpt; + String symFileNameOpt; }; @@ -7762,6 +9047,8 @@ public: virtual bool execute() { + String fileName = parent.eval(fileNameOpt, ""); + String fullName = parent.resolve(fileName); String nativeFile = getNativePath(fullName); if (!isRegularFile(fullName) && !isDirectory(fullName)) @@ -7783,15 +9070,16 @@ public: nativeFile.c_str(), strerror(ret)); return false; } + removeFromStatCache(nativeFile); return true; } virtual bool parse(Element *elem) { //trace("touch parse"); - if (!parent.getAttribute(elem, "file", fileName)) + if (!parent.getAttribute(elem, "file", fileNameOpt)) return false; - if (fileName.size() == 0) + if (fileNameOpt.size() == 0) { error(" requires 'file=\"fileName\"' attribute"); return false; @@ -7799,7 +9087,7 @@ public: return true; } - String fileName; + String fileNameOpt; }; @@ -7842,8 +9130,16 @@ Task *Task::createTask(Element *elem, int lineNr) task = new TaskCC(parent); else if (tagName == "copy") task = new TaskCopy(parent); + else if (tagName == "cxxtestpart") + task = new TaskCxxTestPart(parent); + else if (tagName == "cxxtestroot") + task = new TaskCxxTestRoot(parent); + else if (tagName == "cxxtestrun") + task = new TaskCxxTestRun(parent); else if (tagName == "delete") task = new TaskDelete(parent); + else if (tagName == "echo") + task = new TaskEcho(parent); else if (tagName == "jar") task = new TaskJar(parent); else if (tagName == "javac") @@ -8230,7 +9526,11 @@ void Make::init() specifiedTarget = ""; baseDir = ""; description = ""; - envPrefix = ""; + envPrefix = "env."; + pcPrefix = "pc."; + pccPrefix = "pcc."; + pclPrefix = "pcl."; + bzrPrefix = "bzr."; properties.clear(); for (unsigned int i = 0 ; i < allTasks.size() ; i++) delete allTasks[i]; @@ -8323,7 +9623,7 @@ bool Make::executeTarget(Target &target, } } - status("## Target : %s : %s", name.c_str(), + status("##### Target : %s\n##### %s", name.c_str(), target.getDescription().c_str()); //Now let's do the tasks @@ -8331,7 +9631,7 @@ bool Make::executeTarget(Target &target, for (unsigned int i=0 ; igetName().c_str()); + status("--- %s / %s", name.c_str(), task->getName().c_str()); if (!task->execute()) { return false; @@ -8611,11 +9911,6 @@ bool Make::parseProperty(Element *elem) } else if (attrName == "environment") { - if (envPrefix.size() > 0) - { - error("environment prefix can only be set once"); - return false; - } if (attrVal.find('.') != attrVal.npos) { error("environment prefix cannot have a '.' in it"); @@ -8624,6 +9919,46 @@ bool Make::parseProperty(Element *elem) envPrefix = attrVal; envPrefix.push_back('.'); } + else if (attrName == "pkg-config") + { + if (attrVal.find('.') != attrVal.npos) + { + error("pkg-config prefix cannot have a '.' in it"); + return false; + } + pcPrefix = attrVal; + pcPrefix.push_back('.'); + } + else if (attrName == "pkg-config-cflags") + { + if (attrVal.find('.') != attrVal.npos) + { + error("pkg-config-cflags prefix cannot have a '.' in it"); + return false; + } + pccPrefix = attrVal; + pccPrefix.push_back('.'); + } + else if (attrName == "pkg-config-libs") + { + if (attrVal.find('.') != attrVal.npos) + { + error("pkg-config-libs prefix cannot have a '.' in it"); + return false; + } + pclPrefix = attrVal; + pclPrefix.push_back('.'); + } + else if (attrName == "subversion") + { + if (attrVal.find('.') != attrVal.npos) + { + error("bzr prefix cannot have a '.' in it"); + return false; + } + bzrPrefix = attrVal; + bzrPrefix.push_back('.'); + } } return true;