diff --git a/buildtool.cpp b/buildtool.cpp
index 3bbe13d4499ed0950044d07ea7339b428726b078..bc6da92d3b6b9865603d5357203e57713dea1646 100644 (file)
--- a/buildtool.cpp
+++ b/buildtool.cpp
*
*/
-#define BUILDTOOL_VERSION "BuildTool v0.8.4"
+#define BUILDTOOL_VERSION "BuildTool v0.9.4"
#include <stdio.h>
#include <fcntl.h>
#include <map>
#include <set>
#include <vector>
+#include <algorithm>
+
#ifdef __WIN32__
#include <windows.h>
@@ -688,7 +690,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))) ) {
/**
* replace variable refs like ${a} with their values
- */
- bool eval(const String &s, String &result);
+ * 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
std::map<String, String>::iterator iter = properties.find(name);
if (iter != properties.end())
val = iter->second;
- return val;
+ String sval;
+ if (!getSubstitutions(val, sval))
+ return false;
+ return sval;
}
/**
* If this prefix is seen in a substitution, use an environment
* variable.
* example: <property environment="env"/>
- * ${env.JAVA_HOME}
- */
+ * ${env.JAVA_HOME}
+ */
String envPrefix;
+ /**
+ * If this prefix is seen in a substitution, use as a
+ * pkg-config 'all' query
+ * example: <property pkg-config="pc"/>
+ * ${pc.gtkmm}
+ */
+ String pcPrefix;
+
+ /**
+ * If this prefix is seen in a substitution, use as a
+ * pkg-config 'cflags' query
+ * example: <property pkg-config="pcc"/>
+ * ${pcc.gtkmm}
+ */
+ String pccPrefix;
+
+ /**
+ * If this prefix is seen in a substitution, use as a
+ * pkg-config 'libs' query
+ * example: <property pkg-config="pcl"/>
+ * ${pcl.gtkmm}
+ */
+ String pclPrefix;
+
+
std::map<String, String> properties;
- /**
- * Turn 'true' and 'false' into boolean values
- */
- bool getBool(const String &str, bool &val);
-
/**
* Create a directory, making intermediate dirs
* if necessary
@@ -3228,1518 +3261,1827 @@ protected:
private:
- int line;
-
-
-};
+ bool pkgConfigRecursive(const String packageName,
+ const String &path,
+ const String &prefix,
+ int query,
+ String &result,
+ std::set<String> &deplist);
+ /**
+ * 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);
-/**
- * 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) ;
-}
+ int line;
+};
-/**
- * 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) ;
-}
/**
- * Resolve another path relative to this one
+ * Define the pkg-config class here, since it will be used in MakeBase method
+ * implementations.
*/
-String MakeBase::resolve(const String &otherPath)
+class PkgConfig : public MakeBase
{
- URI otherURI(otherPath);
- URI fullURI = uri.resolve(otherURI);
- String ret = fullURI.toString();
- return ret;
-}
+public:
-/**
- * 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) ;
-}
+ /**
+ *
+ */
+ PkgConfig()
+ {
+ path = ".";
+ prefix = "/target";
+ init();
+ }
+ /**
+ *
+ */
+ PkgConfig(const PkgConfig &other)
+ { assign(other); }
+ /**
+ *
+ */
+ PkgConfig &operator=(const PkgConfig &other)
+ { assign(other); return *this; }
-/**
- * Check if a given string matches a given regex pattern
- */
-bool MakeBase::regexMatch(const String &str, const String &pattern)
-{
- const TRexChar *terror = NULL;
- const TRexChar *cpat = pattern.c_str();
- TRex *expr = trex_compile(cpat, &terror);
- if (!expr)
- {
- if (!terror)
- terror = "undefined";
- error("compilation error [%s]!\n", terror);
- return false;
- }
+ /**
+ *
+ */
+ virtual ~PkgConfig()
+ { }
- bool ret = true;
+ /**
+ *
+ */
+ virtual String getName()
+ { return name; }
- const TRexChar *cstr = str.c_str();
- if (trex_match(expr, cstr))
- {
- ret = true;
- }
- else
- {
- ret = false;
- }
+ /**
+ *
+ */
+ virtual String getPath()
+ { return path; }
- trex_free(expr);
+ /**
+ *
+ */
+ virtual void setPath(const String &val)
+ { path = val; }
- return ret;
-}
+ /**
+ *
+ */
+ virtual String getPrefix()
+ { return prefix; }
-/**
- * Return the suffix, if any, of a file name
- */
-String MakeBase::getSuffix(const String &fname)
-{
- if (fname.size() < 2)
- return "";
- unsigned int pos = fname.find_last_of('.');
- if (pos == fname.npos)
- return "";
- pos++;
- String res = fname.substr(pos, fname.size()-pos);
- //trace("suffix:%s", res.c_str());
- return res;
-}
+ /**
+ * 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; }
-/**
- * Break up a string into substrings delimited the characters
- * in delimiters. Null-length substrings are ignored
- */
-std::vector<String> MakeBase::tokenize(const String &str,
- const String &delimiters)
-{
+ /**
+ *
+ */
+ virtual String getLibs()
+ { return libs; }
- std::vector<String> res;
- char *del = (char *)delimiters.c_str();
- String dmp;
- for (unsigned int i=0 ; i<str.size() ; i++)
- {
- char ch = str[i];
- char *p = (char *)0;
- for (p=del ; *p ; p++)
- if (*p == ch)
- break;
- if (*p)
- {
- if (dmp.size() > 0)
- {
- res.push_back(dmp);
- dmp.clear();
- }
- }
- else
- {
- dmp.push_back(ch);
- }
- }
- //Add tail
- if (dmp.size() > 0)
+ /**
+ *
+ */
+ virtual String getAll()
{
- res.push_back(dmp);
- dmp.clear();
+ String ret = cflags;
+ ret.append(" ");
+ ret.append(libs);
+ return ret;
}
- return res;
-}
+ /**
+ *
+ */
+ virtual String getVersion()
+ { return version; }
+ /**
+ *
+ */
+ virtual int getMajorVersion()
+ { return majorVersion; }
+ /**
+ *
+ */
+ virtual int getMinorVersion()
+ { return minorVersion; }
-/**
- * replace runs of whitespace with a single space
- */
-String MakeBase::strip(const String &s)
-{
- int len = s.size();
- String stripped;
- for (int i = 0 ; i<len ; i++)
- {
- char ch = s[i];
- if (isspace(ch))
- {
- stripped.push_back(' ');
- for ( ; i<len ; i++)
- {
- ch = s[i];
- if (!isspace(ch))
- {
- stripped.push_back(ch);
- break;
- }
- }
- }
- else
- {
- stripped.push_back(ch);
- }
- }
- return stripped;
-}
+ /**
+ *
+ */
+ virtual int getMicroVersion()
+ { return microVersion; }
-/**
- * remove leading whitespace from each line
- */
-String MakeBase::leftJustify(const String &s)
-{
- String out;
- int len = s.size();
- for (int i = 0 ; i<len ; )
- {
- char ch;
- //Skip to first visible character
- while (i<len)
- {
- ch = s[i];
- if (ch == '\n' || ch == '\r'
- || !isspace(ch))
- break;
- i++;
- }
- //Copy the rest of the line
- while (i<len)
- {
- ch = s[i];
- if (ch == '\n' || ch == '\r')
- {
- if (ch != '\r')
- out.push_back('\n');
- i++;
- break;
- }
- else
- {
- out.push_back(ch);
- }
- i++;
- }
- }
- return out;
-}
+ /**
+ *
+ */
+ virtual std::map<String, String> &getAttributes()
+ { return attrs; }
+ /**
+ *
+ */
+ virtual std::vector<String> &getRequireList()
+ { return requireList; }
-/**
- * Removes whitespace from beginning and end of a string
- */
-String MakeBase::trim(const String &s)
-{
- if (s.size() < 1)
- return s;
-
- //Find first non-ws char
- unsigned int begin = 0;
- for ( ; begin < s.size() ; begin++)
+ /**
+ * 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()
{
- if (!isspace(s[begin]))
- break;
+ //do not set path and prefix here
+ name = "";
+ description = "";
+ cflags = "";
+ libs = "";
+ requires = "";
+ version = "";
+ majorVersion = 0;
+ minorVersion = 0;
+ microVersion = 0;
+ fileName = "";
+ attrs.clear();
+ requireList.clear();
}
- //Find first non-ws char, going in reverse
- unsigned int end = s.size() - 1;
- for ( ; end > begin ; end--)
+ void assign(const PkgConfig &other)
{
- if (!isspace(s[end]))
- break;
+ 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;
}
- //trace("begin:%d end:%d", begin, end);
- String res = s.substr(begin, end-begin+1);
- return res;
-}
-/**
- * Return a lower case version of the given string
- */
-String MakeBase::toLower(const String &s)
-{
- if (s.size()==0)
- return s;
+ int get(int pos);
- String ret;
- for(unsigned int i=0; i<s.size() ; i++)
- {
- ret.push_back(tolower(s[i]));
- }
- return ret;
-}
+ int skipwhite(int pos);
+ int getword(int pos, String &ret);
-/**
- * Return the native format of the canonical
- * path which we store
- */
-String MakeBase::getNativePath(const String &path)
-{
-#ifdef __WIN32__
- String npath;
- unsigned int firstChar = 0;
- if (path.size() >= 3)
- {
- if (path[0] == '/' &&
- isalpha(path[1]) &&
- path[2] == ':')
- firstChar++;
- }
- for (unsigned int i=firstChar ; i<path.size() ; i++)
- {
- char ch = path[i];
- if (ch == '/')
- npath.push_back('\\');
- else
- npath.push_back(ch);
- }
- return npath;
-#else
- return path;
-#endif
-}
+ /**
+ * Very important
+ */
+ bool parseRequires();
+ void parseVersion();
-#ifdef __WIN32__
-#include <tchar.h>
+ bool parseLine(const String &lineBuf);
-static String win32LastError()
-{
+ bool parse(const String &buf);
- DWORD dw = GetLastError();
+ void dumpAttrs();
- LPVOID str;
- FormatMessage(
- FORMAT_MESSAGE_ALLOCATE_BUFFER |
- FORMAT_MESSAGE_FROM_SYSTEM,
- NULL,
- dw,
- 0,
- (LPTSTR) &str,
- 0, NULL );
- LPTSTR p = _tcschr((const char *)str, _T('\r'));
- if(p != NULL)
- { // lose CRLF
- *p = _T('\0');
- }
- String ret = (char *)str;
- LocalFree(str);
+ String name;
- return ret;
-}
-#endif
+ String path;
+ String prefix;
+ String description;
-/**
- * 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)
-{
+ String cflags;
- status("============ cmd ============\n%s\n=============================",
- command.c_str());
+ String libs;
- outbuf.clear();
- errbuf.clear();
-
-#ifdef __WIN32__
+ String requires;
- /*
- I really hate having win32 code in this program, but the
- read buffer in command.com and cmd.exe are just too small
- for the large commands we need for compiling and linking.
- */
+ String version;
- bool ret = true;
+ int majorVersion;
- //# Allocate a separate buffer for safety
- char *paramBuf = new char[command.size() + 1];
- if (!paramBuf)
- {
- error("executeCommand cannot allocate command buffer");
- return false;
- }
- strcpy(paramBuf, (char *)command.c_str());
+ int minorVersion;
- //# Go to http://msdn2.microsoft.com/en-us/library/ms682499.aspx
- //# to see how Win32 pipes work
+ int microVersion;
- //# Create pipes
- SECURITY_ATTRIBUTES saAttr;
- saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
- saAttr.bInheritHandle = TRUE;
- saAttr.lpSecurityDescriptor = NULL;
- HANDLE stdinRead, stdinWrite;
- HANDLE stdoutRead, stdoutWrite;
- HANDLE stderrRead, stderrWrite;
- if (!CreatePipe(&stdinRead, &stdinWrite, &saAttr, 0))
- {
- error("executeProgram: could not create pipe");
- delete[] paramBuf;
- return false;
- }
- SetHandleInformation(stdinWrite, HANDLE_FLAG_INHERIT, 0);
- if (!CreatePipe(&stdoutRead, &stdoutWrite, &saAttr, 0))
- {
- error("executeProgram: could not create pipe");
- delete[] paramBuf;
- 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);
+ String fileName;
- // Create the process
- STARTUPINFO siStartupInfo;
- PROCESS_INFORMATION piProcessInfo;
- memset(&siStartupInfo, 0, sizeof(siStartupInfo));
- memset(&piProcessInfo, 0, sizeof(piProcessInfo));
- siStartupInfo.cb = sizeof(siStartupInfo);
- siStartupInfo.hStdError = stderrWrite;
- siStartupInfo.hStdOutput = stdoutWrite;
- siStartupInfo.hStdInput = stdinRead;
- siStartupInfo.dwFlags |= STARTF_USESTDHANDLES;
-
- if (!CreateProcess(NULL, paramBuf, NULL, NULL, true,
- 0, NULL, NULL, &siStartupInfo,
- &piProcessInfo))
- {
- error("executeCommand : could not create process : %s",
- win32LastError().c_str());
- ret = false;
- }
+ std::map<String, String> attrs;
- delete[] paramBuf;
+ std::vector<String> requireList;
- DWORD bytesWritten;
- if (inbuf.size()>0 &&
- !WriteFile(stdinWrite, inbuf.c_str(), inbuf.size(),
- &bytesWritten, NULL))
- {
- error("executeCommand: could not write to pipe");
- return false;
- }
- if (!CloseHandle(stdinWrite))
- {
- error("executeCommand: could not close write pipe");
- return false;
- }
- if (!CloseHandle(stdoutWrite))
- {
- error("executeCommand: could not close read pipe");
- return false;
- }
- if (!CloseHandle(stderrWrite))
- {
- error("executeCommand: could not close read pipe");
- return false;
- }
+ char *parsebuf;
+ int parselen;
+};
- bool lastLoop = false;
- while (true)
- {
- DWORD avail;
- DWORD bytesRead;
- char readBuf[4096];
- //trace("## stderr");
- PeekNamedPipe(stderrRead, NULL, 0, NULL, &avail, NULL);
- if (avail > 0)
- {
- bytesRead = 0;
- if (avail>4096) avail = 4096;
- ReadFile(stderrRead, readBuf, avail, &bytesRead, NULL);
- if (bytesRead > 0)
- {
- for (unsigned int i=0 ; i<bytesRead ; i++)
- errbuf.push_back(readBuf[i]);
- }
- }
- //trace("## stdout");
- PeekNamedPipe(stdoutRead, NULL, 0, NULL, &avail, NULL);
- if (avail > 0)
- {
- bytesRead = 0;
- if (avail>4096) avail = 4096;
- ReadFile(stdoutRead, readBuf, avail, &bytesRead, NULL);
- if (bytesRead > 0)
- {
- for (unsigned int i=0 ; i<bytesRead ; i++)
- outbuf.push_back(readBuf[i]);
- }
- }
-
- //Was this the final check after program done?
- if (lastLoop)
- break;
- DWORD exitCode;
- GetExitCodeProcess(piProcessInfo.hProcess, &exitCode);
- if (exitCode != STILL_ACTIVE)
- lastLoop = true;
+/**
+ * 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) ;
+}
- Sleep(10);
- }
- //trace("outbuf:%s", outbuf.c_str());
- if (!CloseHandle(stdoutRead))
- {
- error("executeCommand: could not close read pipe");
- return false;
- }
- if (!CloseHandle(stderrRead))
- {
- error("executeCommand: could not close read pipe");
- return false;
- }
- DWORD exitCode;
- GetExitCodeProcess(piProcessInfo.hProcess, &exitCode);
- //trace("exit code:%d", exitCode);
- if (exitCode != 0)
- {
- ret = false;
- }
-
- CloseHandle(piProcessInfo.hProcess);
- CloseHandle(piProcessInfo.hThread);
- return ret;
+/**
+ * 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);
+}
-#else //do it unix-style
- String s;
- FILE *f = popen(command.c_str(), "r");
- int errnum = 0;
- if (f)
- {
- while (true)
- {
- int ch = fgetc(f);
- if (ch < 0)
- break;
- s.push_back((char)ch);
- }
- errnum = pclose(f);
- }
- outbuf = s;
- if (errnum != 0)
- {
- error("exec of command '%s' failed : %s",
- command.c_str(), strerror(errno));
- return false;
- }
- else
- return true;
+/**
+ * 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);
+}
+
-#endif
-}
+/**
+ * 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;
+}
-bool MakeBase::listDirectories(const String &baseName,
- const String &dirName,
- std::vector<String> &res)
+/**
+ * Check if a given string matches a given regex pattern
+ */
+bool MakeBase::regexMatch(const String &str, const String &pattern)
{
- res.push_back(dirName);
- String fullPath = baseName;
- if (dirName.size()>0)
+ const TRexChar *terror = NULL;
+ const TRexChar *cpat = pattern.c_str();
+ TRex *expr = trex_compile(cpat, &terror);
+ if (!expr)
{
- fullPath.append("/");
- fullPath.append(dirName);
+ if (!terror)
+ terror = "undefined";
+ error("compilation error [%s]!\n", terror);
+ return false;
+ }
+
+ bool ret = true;
+
+ const TRexChar *cstr = str.c_str();
+ if (trex_match(expr, cstr))
+ {
+ ret = true;
}
- DIR *dir = opendir(fullPath.c_str());
- while (true)
+ else
{
- struct dirent *de = readdir(dir);
- if (!de)
- break;
+ ret = false;
+ }
- //Get the directory member name
- String s = de->d_name;
- if (s.size() == 0 || s[0] == '.')
- continue;
- String childName = dirName;
- childName.append("/");
- childName.append(s);
+ trex_free(expr);
- String fullChildPath = baseName;
- fullChildPath.append("/");
- fullChildPath.append(childName);
- struct stat finfo;
- String childNative = getNativePath(fullChildPath);
- if (stat(childNative.c_str(), &finfo)<0)
- {
- error("cannot stat file:%s", childNative.c_str());
- }
- else if (S_ISDIR(finfo.st_mode))
- {
- //trace("directory: %s", childName.c_str());
- if (!listDirectories(baseName, childName, res))
- return false;
- }
- }
- closedir(dir);
-
- return true;
+ return ret;
}
-
-bool MakeBase::listFiles(const String &baseDir,
- const String &dirName,
- std::vector<String> &res)
+/**
+ * Return the suffix, if any, of a file name
+ */
+String MakeBase::getSuffix(const String &fname)
{
- String fullDir = baseDir;
- if (dirName.size()>0)
- {
- fullDir.append("/");
- fullDir.append(dirName);
- }
- String dirNative = getNativePath(fullDir);
-
- std::vector<String> subdirs;
- DIR *dir = opendir(dirNative.c_str());
- if (!dir)
- {
- error("Could not open directory %s : %s",
- dirNative.c_str(), strerror(errno));
- return false;
- }
- 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 true;
+ if (fname.size() < 2)
+ return "";
+ unsigned int pos = fname.find_last_of('.');
+ if (pos == fname.npos)
+ return "";
+ pos++;
+ String res = fname.substr(pos, fname.size()-pos);
+ //trace("suffix:%s", res.c_str());
+ return res;
}
-bool MakeBase::listFiles(MakeBase &propRef, FileSet &fileSet)
-{
- String baseDir = propRef.resolve(fileSet.getDirectory());
- std::vector<String> fileList;
- if (!listFiles(baseDir, "", fileList))
- return false;
-
- std::vector<String> includes = fileSet.getIncludes();
- std::vector<String> excludes = fileSet.getExcludes();
-
- std::vector<String> incs;
- std::vector<String>::iterator iter;
- std::sort(fileList.begin(), fileList.end());
+/**
+ * Break up a string into substrings delimited the characters
+ * in delimiters. Null-length substrings are ignored
+ */
+std::vector<String> MakeBase::tokenize(const String &str,
+ const String &delimiters)
+{
- //If there are <includes>, then add files to the output
- //in the order of the include list
- if (includes.size()==0)
- incs = fileList;
- else
+ std::vector<String> res;
+ char *del = (char *)delimiters.c_str();
+ String dmp;
+ for (unsigned int i=0 ; i<str.size() ; i++)
{
- for (iter = includes.begin() ; iter != includes.end() ; iter++)
+ char ch = str[i];
+ char *p = (char *)0;
+ for (p=del ; *p ; p++)
+ if (*p == ch)
+ break;
+ if (*p)
{
- String &pattern = *iter;
- std::vector<String>::iterator siter;
- for (siter = fileList.begin() ; siter != fileList.end() ; siter++)
+ if (dmp.size() > 0)
{
- String s = *siter;
- if (regexMatch(s, pattern))
- {
- //trace("INCLUDED:%s", s.c_str());
- incs.push_back(s);
- }
+ res.push_back(dmp);
+ dmp.clear();
}
}
- }
-
- //Now trim off the <excludes>
- std::vector<String> res;
- for (iter = incs.begin() ; iter != incs.end() ; iter++)
- {
- String s = *iter;
- bool skipme = false;
- std::vector<String>::iterator siter;
- for (siter = excludes.begin() ; siter != excludes.end() ; siter++)
+ else
{
- String &pattern = *siter;
- if (regexMatch(s, pattern))
- {
- //trace("EXCLUDED:%s", s.c_str());
- skipme = true;
- break;
- }
+ dmp.push_back(ch);
}
- if (!skipme)
- res.push_back(s);
}
-
- fileSet.setFiles(res);
+ //Add tail
+ if (dmp.size() > 0)
+ {
+ res.push_back(dmp);
+ dmp.clear();
+ }
- return true;
+ return res;
}
-
/**
- * Analyse a string, looking for any substitutions or other
- * things that need resilution
+ * replace runs of whitespace with a single space
*/
-bool MakeBase::eval(const String &str, String &result)
+String MakeBase::strip(const String &s)
{
- String s = trim(str);
- int len = (int)s.size();
- String val;
- for (int i=0 ; i<len ; i++)
+ int len = s.size();
+ String stripped;
+ for (int i = 0 ; i<len ; i++)
{
char ch = s[i];
- if (ch == '$' && s[i+1] == '{')
+ if (isspace(ch))
{
- String varname;
- int j = i+2;
- for ( ; j<len ; j++)
+ stripped.push_back(' ');
+ for ( ; i<len ; i++)
{
- ch = s[j];
- if (ch == '$' && s[j+1] == '{')
- {
- error("attribute %s cannot have nested variable references",
- s.c_str());
- return false;
- }
- else if (ch == '}')
+ ch = s[i];
+ if (!isspace(ch))
{
- std::map<String, String>::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;
- }
- }
+ stripped.push_back(ch);
break;
}
- else
- {
- varname.push_back(ch);
- }
}
- i = j;
}
else
{
- val.push_back(ch);
+ stripped.push_back(ch);
}
}
- result = val;
- return true;
-}
-
-
-bool MakeBase::getAttribute(Element *elem, const String &name,
- String &result)
-{
- String s = elem->getAttribute(name);
- return eval(s, result);
+ return stripped;
}
-
-bool MakeBase::getValue(Element *elem, String &result)
+/**
+ * remove leading whitespace from each line
+ */
+String MakeBase::leftJustify(const String &s)
{
- String s = elem->getValue();
- //Replace all runs of whitespace with a single space
- return eval(s, result);
+ String out;
+ int len = s.size();
+ for (int i = 0 ; i<len ; )
+ {
+ char ch;
+ //Skip to first visible character
+ while (i<len)
+ {
+ ch = s[i];
+ if (ch == '\n' || ch == '\r'
+ || !isspace(ch))
+ break;
+ i++;
+ }
+ //Copy the rest of the line
+ while (i<len)
+ {
+ ch = s[i];
+ if (ch == '\n' || ch == '\r')
+ {
+ if (ch != '\r')
+ out.push_back('\n');
+ i++;
+ break;
+ }
+ else
+ {
+ out.push_back(ch);
+ }
+ i++;
+ }
+ }
+ return out;
}
/**
- * 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;
- else
- {
- error("expected 'true' or 'false'. found '%s'", str.c_str());
- return false;
+ * Removes whitespace from beginning and end of a string
+ */
+String MakeBase::trim(const String &s)
+{
+ if (s.size() < 1)
+ return s;
+
+ //Find first non-ws char
+ unsigned int begin = 0;
+ for ( ; begin < s.size() ; begin++)
+ {
+ if (!isspace(s[begin]))
+ break;
}
- return true;
-}
-
-
-
-/**
- * Parse a <patternset> entry
- */
-bool MakeBase::parsePatternSet(Element *elem,
- MakeBase &propRef,
- std::vector<String> &includes,
- std::vector<String> &excludes
- )
-{
- std::vector<Element *> children = elem->getChildren();
- for (unsigned int i=0 ; i<children.size() ; i++)
+ //Find first non-ws char, going in reverse
+ unsigned int end = s.size() - 1;
+ for ( ; end > begin ; end--)
{
- Element *child = children[i];
- String tagName = child->getName();
- if (tagName == "exclude")
- {
- String fname;
- if (!propRef.getAttribute(child, "name", fname))
- return false;
- //trace("EXCLUDE: %s", fname.c_str());
- excludes.push_back(fname);
- }
- else if (tagName == "include")
- {
- String fname;
- if (!propRef.getAttribute(child, "name", fname))
- return false;
- //trace("INCLUDE: %s", fname.c_str());
- includes.push_back(fname);
- }
+ if (!isspace(s[end]))
+ break;
}
+ //trace("begin:%d end:%d", begin, end);
- return true;
+ String res = s.substr(begin, end-begin+1);
+ return res;
}
-
-
/**
- * Parse a <fileset> entry, and determine which files
- * should be included
- */
-bool MakeBase::parseFileSet(Element *elem,
- MakeBase &propRef,
- FileSet &fileSet)
+ * Return a lower case version of the given string
+ */
+String MakeBase::toLower(const String &s)
{
- String name = elem->getName();
- if (name != "fileset")
+ if (s.size()==0)
+ return s;
+
+ String ret;
+ for(unsigned int i=0; i<s.size() ; i++)
{
- error("expected <fileset>");
- return false;
+ ret.push_back(tolower(s[i]));
}
+ return ret;
+}
- std::vector<String> includes;
- std::vector<String> excludes;
-
- //A fileset has one implied patternset
- if (!parsePatternSet(elem, propRef, includes, excludes))
+/**
+ * Return the native format of the canonical
+ * path which we store
+ */
+String MakeBase::getNativePath(const String &path)
+{
+#ifdef __WIN32__
+ String npath;
+ unsigned int firstChar = 0;
+ if (path.size() >= 3)
{
- return false;
+ if (path[0] == '/' &&
+ isalpha(path[1]) &&
+ path[2] == ':')
+ firstChar++;
}
- //Look for child tags, including more patternsets
- std::vector<Element *> children = elem->getChildren();
- for (unsigned int i=0 ; i<children.size() ; i++)
+ for (unsigned int i=firstChar ; i<path.size() ; i++)
{
- Element *child = children[i];
- String tagName = child->getName();
- if (tagName == "patternset")
- {
- if (!parsePatternSet(child, propRef, includes, excludes))
- {
- return false;
- }
- }
+ char ch = path[i];
+ if (ch == '/')
+ npath.push_back('\\');
+ else
+ npath.push_back(ch);
}
+ return npath;
+#else
+ return path;
+#endif
+}
- String dir;
- //Now do the stuff
- //Get the base directory for reading file names
- if (!propRef.getAttribute(elem, "dir", dir))
- return false;
- fileSet.setDirectory(dir);
- fileSet.setIncludes(includes);
- fileSet.setExcludes(excludes);
-
- /*
- std::vector<String> fileList;
- if (dir.size() > 0)
- {
- String baseDir = propRef.resolve(dir);
- if (!listFiles(baseDir, "", includes, excludes, fileList))
- return false;
- }
- std::sort(fileList.begin(), fileList.end());
- result = fileList;
- */
+#ifdef __WIN32__
+#include <tchar.h>
-
- /*
- for (unsigned int i=0 ; i<result.size() ; i++)
- {
- trace("RES:%s", result[i].c_str());
- }
- */
+static String win32LastError()
+{
-
- return true;
-}
+ DWORD dw = GetLastError();
-/**
- * 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;
- }
+ LPVOID str;
+ FormatMessage(
+ FORMAT_MESSAGE_ALLOCATE_BUFFER |
+ FORMAT_MESSAGE_FROM_SYSTEM,
+ NULL,
+ dw,
+ 0,
+ (LPTSTR) &str,
+ 0, NULL );
+ LPTSTR p = _tcschr((const char *)str, _T('\r'));
+ if(p != NULL)
+ { // lose CRLF
+ *p = _T('\0');
}
+ String ret = (char *)str;
+ LocalFree(str);
- 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;
+ return ret;
}
+#endif
+
+#ifdef __WIN32__
+
/**
- * Create a directory, making intermediate dirs
- * if necessary
- */
-bool MakeBase::createDirectory(const String &dirname)
+ * 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)
{
- //trace("## createDirectory: %s", dirname.c_str());
- //## first check if it exists
- struct stat finfo;
- String nativeDir = getNativePath(dirname);
- char *cnative = (char *) nativeDir.c_str();
-#ifdef __WIN32__
- if (strlen(cnative)==2 && cnative[1]==':')
- return true;
-#endif
- if (stat(cnative, &finfo)==0)
- {
- if (!S_ISDIR(finfo.st_mode))
- {
- error("mkdir: file %s exists but is not a directory",
- cnative);
- return false;
- }
- else //exists
- {
- return true;
- }
- }
- //## 2: pull off the last path segment, if any,
- //## to make the dir 'above' this one, if necessary
- unsigned int pos = dirname.find_last_of('/');
- if (pos>0 && pos != dirname.npos)
- {
- String subpath = dirname.substr(0, pos);
- //A letter root (c:) ?
- if (!createDirectory(subpath))
- return false;
- }
-
- //## 3: now make
-#ifdef __WIN32__
- if (mkdir(cnative)<0)
-#else
- if (mkdir(cnative, S_IRWXU | S_IRWXG | S_IRWXO)<0)
-#endif
+ status("============ cmd ============\n%s\n=============================",
+ command.c_str());
+
+ outbuf.clear();
+ errbuf.clear();
+
+
+ /*
+ I really hate having win32 code in this program, but the
+ read buffer in command.com and cmd.exe are just too small
+ for the large commands we need for compiling and linking.
+ */
+
+ bool ret = true;
+
+ //# Allocate a separate buffer for safety
+ char *paramBuf = new char[command.size() + 1];
+ if (!paramBuf)
+ {
+ error("executeCommand cannot allocate command buffer");
+ return false;
+ }
+ strcpy(paramBuf, (char *)command.c_str());
+
+ //# Go to http://msdn2.microsoft.com/en-us/library/ms682499.aspx
+ //# to see how Win32 pipes work
+
+ //# Create pipes
+ SECURITY_ATTRIBUTES saAttr;
+ saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
+ saAttr.bInheritHandle = TRUE;
+ saAttr.lpSecurityDescriptor = NULL;
+ HANDLE stdinRead, stdinWrite;
+ HANDLE stdoutRead, stdoutWrite;
+ HANDLE stderrRead, stderrWrite;
+ if (!CreatePipe(&stdinRead, &stdinWrite, &saAttr, 0))
{
- error("cannot make directory '%s' : %s",
- cnative, strerror(errno));
+ error("executeProgram: could not create pipe");
+ delete[] paramBuf;
return false;
- }
-
- return true;
-}
+ }
+ SetHandleInformation(stdinWrite, HANDLE_FLAG_INHERIT, 0);
+ if (!CreatePipe(&stdoutRead, &stdoutWrite, &saAttr, 0))
+ {
+ error("executeProgram: could not create pipe");
+ delete[] paramBuf;
+ 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);
+ // Create the process
+ STARTUPINFO siStartupInfo;
+ PROCESS_INFORMATION piProcessInfo;
+ memset(&siStartupInfo, 0, sizeof(siStartupInfo));
+ memset(&piProcessInfo, 0, sizeof(piProcessInfo));
+ siStartupInfo.cb = sizeof(siStartupInfo);
+ siStartupInfo.hStdError = stderrWrite;
+ siStartupInfo.hStdOutput = stdoutWrite;
+ siStartupInfo.hStdInput = stdinRead;
+ siStartupInfo.dwFlags |= STARTF_USESTDHANDLES;
+
+ if (!CreateProcess(NULL, paramBuf, NULL, NULL, true,
+ 0, NULL, NULL, &siStartupInfo,
+ &piProcessInfo))
+ {
+ error("executeCommand : could not create process : %s",
+ win32LastError().c_str());
+ ret = false;
+ }
-/**
- * Remove a directory recursively
- */
-bool MakeBase::removeDirectory(const String &dirName)
-{
- char *dname = (char *)dirName.c_str();
+ delete[] paramBuf;
- DIR *dir = opendir(dname);
- if (!dir)
+ DWORD bytesWritten;
+ if (inbuf.size()>0 &&
+ !WriteFile(stdinWrite, inbuf.c_str(), inbuf.size(),
+ &bytesWritten, NULL))
{
- //# Let this fail nicely.
- return true;
- //error("error opening directory %s : %s", dname, strerror(errno));
- //return false;
+ error("executeCommand: could not write to pipe");
+ return false;
+ }
+ if (!CloseHandle(stdinWrite))
+ {
+ error("executeCommand: could not close write pipe");
+ return false;
}
-
- while (true)
+ if (!CloseHandle(stdoutWrite))
{
- 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);
+ error("executeCommand: could not close read pipe");
+ return false;
+ }
+ if (!CloseHandle(stderrWrite))
+ {
+ error("executeCommand: could not close read pipe");
+ return false;
+ }
+ bool lastLoop = false;
+ while (true)
+ {
+ DWORD avail;
+ DWORD bytesRead;
+ char readBuf[4096];
- struct stat finfo;
- String childNative = getNativePath(childName);
- char *cnative = (char *)childNative.c_str();
- if (stat(cnative, &finfo)<0)
- {
- error("cannot stat file:%s", cnative);
- }
- else if (S_ISDIR(finfo.st_mode))
+ //trace("## stderr");
+ PeekNamedPipe(stderrRead, NULL, 0, NULL, &avail, NULL);
+ if (avail > 0)
{
- //trace("DEL dir: %s", childName.c_str());
- if (!removeDirectory(childName))
+ bytesRead = 0;
+ if (avail>4096) avail = 4096;
+ ReadFile(stderrRead, readBuf, avail, &bytesRead, NULL);
+ if (bytesRead > 0)
{
- return false;
+ for (unsigned int i=0 ; i<bytesRead ; i++)
+ errbuf.push_back(readBuf[i]);
}
}
- else if (!S_ISREG(finfo.st_mode))
- {
- //trace("not regular: %s", cnative);
- }
- else
+
+ //trace("## stdout");
+ PeekNamedPipe(stdoutRead, NULL, 0, NULL, &avail, NULL);
+ if (avail > 0)
{
- //trace("DEL file: %s", childName.c_str());
- if (remove(cnative)<0)
+ bytesRead = 0;
+ if (avail>4096) avail = 4096;
+ ReadFile(stdoutRead, readBuf, avail, &bytesRead, NULL);
+ if (bytesRead > 0)
{
- error("error deleting %s : %s",
- cnative, strerror(errno));
- return false;
+ for (unsigned int i=0 ; i<bytesRead ; i++)
+ outbuf.push_back(readBuf[i]);
}
}
- }
- closedir(dir);
+
+ //Was this the final check after program done?
+ if (lastLoop)
+ break;
- //Now delete the directory
- String native = getNativePath(dirName);
- if (rmdir(native.c_str())<0)
+ DWORD exitCode;
+ GetExitCodeProcess(piProcessInfo.hProcess, &exitCode);
+ if (exitCode != STILL_ACTIVE)
+ lastLoop = true;
+
+ Sleep(10);
+ }
+ //trace("outbuf:%s", outbuf.c_str());
+ if (!CloseHandle(stdoutRead))
{
- error("could not delete directory %s : %s",
- native.c_str() , strerror(errno));
+ error("executeCommand: could not close read pipe");
return false;
}
-
- return true;
-
-}
-
-
-/**
- * Copy a file from one name to another. Perform only if needed
- */
-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 (!CloseHandle(stderrRead))
{
- error("source file %s for copy does not exist",
- srcNative.c_str());
+ error("executeCommand: could not close read pipe");
return false;
}
- String destNative = getNativePath(destFile);
- struct stat destinfo;
- if (stat(destNative.c_str(), &destinfo)==0)
- {
- if (destinfo.st_mtime >= srcinfo.st_mtime)
- return true;
- }
-
- //# 2 prepare a destination directory if necessary
- unsigned int pos = destFile.find_last_of('/');
- if (pos != destFile.npos)
+ DWORD exitCode;
+ GetExitCodeProcess(piProcessInfo.hProcess, &exitCode);
+ //trace("exit code:%d", exitCode);
+ if (exitCode != 0)
{
- String subpath = destFile.substr(0, pos);
- if (!createDirectory(subpath))
- return false;
+ ret = false;
}
+
+ CloseHandle(piProcessInfo.hProcess);
+ CloseHandle(piProcessInfo.hThread);
- //# 3 do the data copy
-#ifndef __WIN32__
+ return ret;
- FILE *srcf = fopen(srcNative.c_str(), "rb");
- if (!srcf)
- {
- error("copyFile cannot open '%s' for reading", srcNative.c_str());
- return false;
- }
- FILE *destf = fopen(destNative.c_str(), "wb");
- if (!destf)
- {
- error("copyFile cannot open %s for writing", srcNative.c_str());
+}
+
+#else /*do it unix style*/
+
+#include <sys/wait.h>
+
+
+
+/**
+ * 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]);
- while (!feof(srcf))
+ 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;
+
+ bool outOpen = true;
+ bool errOpen = true;
+
+ while (outOpen || errOpen)
{
- int ch = fgetc(srcf);
- if (ch<0)
+ 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;
- fputc(ch, destf);
+ if (FD_ISSET(outRead, &fdset))
+ {
+ 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);
+ }
}
- fclose(destf);
- fclose(srcf);
+ int childReturnValue;
+ wait(&childReturnValue);
-#else
-
- if (!CopyFile(srcNative.c_str(), destNative.c_str(), false))
+ close(outRead);
+ close(errRead);
+
+ outbuf = outb;
+ errbuf = errb;
+
+ if (childReturnValue != 0)
{
- error("copyFile from %s to %s failed",
- srcNative.c_str(), destNative.c_str());
+ error("exec of command '%s' failed : %s",
+ command.c_str(), strerror(childReturnValue));
return false;
}
-
-#endif /* __WIN32__ */
-
return true;
-}
-
-
+}
-/**
- * Tests if the file exists and is a regular file
- */
-bool MakeBase::isRegularFile(const String &fileName)
-{
- String native = getNativePath(fileName);
- struct stat finfo;
-
- //Exists?
- if (stat(native.c_str(), &finfo)<0)
- return false;
+#endif
- //check the file mode
- if (!S_ISREG(finfo.st_mode))
- return false;
- return true;
-}
-/**
- * Tests if the file exists and is a directory
- */
-bool MakeBase::isDirectory(const String &fileName)
+bool MakeBase::listDirectories(const String &baseName,
+ const String &dirName,
+ std::vector<String> &res)
{
- String native = getNativePath(fileName);
- struct stat finfo;
-
- //Exists?
- if (stat(native.c_str(), &finfo)<0)
- return false;
+ res.push_back(dirName);
+ String fullPath = baseName;
+ if (dirName.size()>0)
+ {
+ fullPath.append("/");
+ fullPath.append(dirName);
+ }
+ DIR *dir = opendir(fullPath.c_str());
+ 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 = dirName;
+ childName.append("/");
+ childName.append(s);
- //check the file mode
- if (!S_ISDIR(finfo.st_mode))
- return false;
+ String fullChildPath = baseName;
+ fullChildPath.append("/");
+ fullChildPath.append(childName);
+ struct stat finfo;
+ String childNative = getNativePath(fullChildPath);
+ if (stat(childNative.c_str(), &finfo)<0)
+ {
+ error("cannot stat file:%s", childNative.c_str());
+ }
+ else if (S_ISDIR(finfo.st_mode))
+ {
+ //trace("directory: %s", childName.c_str());
+ if (!listDirectories(baseName, childName, res))
+ return false;
+ }
+ }
+ closedir(dir);
return true;
}
-
-/**
- * Tests is the modification of fileA is newer than fileB
- */
-bool MakeBase::isNewerThan(const String &fileA, const String &fileB)
+bool MakeBase::listFiles(const String &baseDir,
+ const String &dirName,
+ std::vector<String> &res)
{
- //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 fullDir = baseDir;
+ if (dirName.size()>0)
{
- return false;
+ fullDir.append("/");
+ fullDir.append(dirName);
}
+ String dirNative = getNativePath(fullDir);
- String nativeB = getNativePath(fileB);
- struct stat infoB;
- //IF dest does not exist, YES, newer
- if (stat(nativeB.c_str(), &infoB)<0)
+ std::vector<String> subdirs;
+ DIR *dir = opendir(dirNative.c_str());
+ if (!dir)
{
- return true;
+ error("Could not open directory %s : %s",
+ dirNative.c_str(), strerror(errno));
+ return false;
}
-
- //check the actual times
- if (infoA.st_mtime > infoB.st_mtime)
+ while (true)
{
- return 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 false;
+ return true;
}
-//########################################################################
-//# P K G C O N F I G
-//########################################################################
-
/**
- *
+ * Several different classes extend MakeBase. By "propRef", we mean
+ * the one holding the properties. Likely "Make" itself
*/
-class PkgConfig : public MakeBase
+bool MakeBase::listFiles(MakeBase &propRef, FileSet &fileSet)
{
+ //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<String> fileList;
+ if (!listFiles(baseDir, "", fileList))
+ return false;
-public:
-
- /**
- *
- */
- PkgConfig()
- { path="."; init(); }
-
- /**
- *
- */
- PkgConfig(const PkgConfig &other)
- { assign(other); }
-
- /**
- *
- */
- PkgConfig &operator=(const PkgConfig &other)
- { assign(other); return *this; }
+ std::vector<String> includes = fileSet.getIncludes();
+ std::vector<String> excludes = fileSet.getExcludes();
- /**
- *
- */
- virtual ~PkgConfig()
- { }
+ std::vector<String> incs;
+ std::vector<String>::iterator iter;
- /**
- *
- */
- virtual String getName()
- { return name; }
+ std::sort(fileList.begin(), fileList.end());
- /**
- *
- */
- virtual String getPath()
- { return path; }
+ //If there are <includes>, then add files to the output
+ //in the order of the include list
+ if (includes.size()==0)
+ incs = fileList;
+ else
+ {
+ for (iter = includes.begin() ; iter != includes.end() ; iter++)
+ {
+ String &pattern = *iter;
+ std::vector<String>::iterator siter;
+ for (siter = fileList.begin() ; siter != fileList.end() ; siter++)
+ {
+ String s = *siter;
+ if (regexMatch(s, pattern))
+ {
+ //trace("INCLUDED:%s", s.c_str());
+ incs.push_back(s);
+ }
+ }
+ }
+ }
- /**
- *
- */
- virtual void setPath(const String &val)
- { path = val; }
+ //Now trim off the <excludes>
+ std::vector<String> res;
+ for (iter = incs.begin() ; iter != incs.end() ; iter++)
+ {
+ String s = *iter;
+ bool skipme = false;
+ std::vector<String>::iterator siter;
+ for (siter = excludes.begin() ; siter != excludes.end() ; siter++)
+ {
+ String &pattern = *siter;
+ if (regexMatch(s, pattern))
+ {
+ //trace("EXCLUDED:%s", s.c_str());
+ skipme = true;
+ break;
+ }
+ }
+ if (!skipme)
+ res.push_back(s);
+ }
+
+ fileSet.setFiles(res);
+
+ return true;
+}
+
+
+/**
+ * 0 == all, 1 = cflags, 2 = libs
+ */
+bool MakeBase::pkgConfigRecursive(const String packageName,
+ const String &path,
+ const String &prefix,
+ int query,
+ String &result,
+ std::set<String> &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<String> list = pkgConfig.getRequireList();
+ for (unsigned int i = 0 ; i<list.size() ; i++)
+ {
+ String depPkgName = list[i];
+ if (deplist.find(depPkgName) != deplist.end())
+ continue;
+ String val;
+ if (!pkgConfigRecursive(depPkgName, path, prefix, query, val, deplist))
+ {
+ error("Based on 'requires' attribute of package '%s'", packageName.c_str());
+ return false;
+ }
+ result.append(" ");
+ result.append(val);
+ }
+
+ return true;
+}
+
+bool MakeBase::pkgConfigQuery(const String &packageName, int query, String &result)
+{
+ std::set<String> 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;
+}
+
+
+
+/**
+ * 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
+ {
+ std::map<String, String>::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;
+ for (int i=0 ; i<len ; i++)
+ {
+ char ch = s[i];
+ if (ch == '$' && s[i+1] == '{')
+ {
+ String varname;
+ int j = i+2;
+ for ( ; j<len ; j++)
+ {
+ ch = s[j];
+ if (ch == '$' && s[j+1] == '{')
+ {
+ error("attribute %s cannot have nested variable references",
+ s.c_str());
+ return false;
+ }
+ else if (ch == '}')
+ {
+ varname = trim(varname);
+ 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
+ {
+ varname.push_back(ch);
+ }
+ }
+ i = j;
+ }
+ else
+ {
+ val.push_back(ch);
+ }
+ }
+ result = val;
+ return true;
+}
+
+/**
+ * Analyse a string, looking for any substitutions or other
+ * things that need resilution
+ */
+bool MakeBase::getSubstitutions(const String &str, String &result)
+{
+ return getSubstitutionsRecursive(str, result, 0);
+}
+
+
+
+/**
+ * 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)
+{
+ if (s.size()==0)
+ return defaultVal;
+ String ret;
+ if (getSubstitutions(s, ret))
+ return ret;
+ else
+ return defaultVal;
+}
+
+
+/**
+ * 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
+ return false;
+}
+
+
+/**
+ * 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;
+}
+
+
+
+
+/**
+ * Parse a <patternset> entry
+ */
+bool MakeBase::parsePatternSet(Element *elem,
+ MakeBase &propRef,
+ std::vector<String> &includes,
+ std::vector<String> &excludes
+ )
+{
+ 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 == "exclude")
+ {
+ String fname;
+ if (!propRef.getAttribute(child, "name", fname))
+ return false;
+ //trace("EXCLUDE: %s", fname.c_str());
+ excludes.push_back(fname);
+ }
+ else if (tagName == "include")
+ {
+ String fname;
+ if (!propRef.getAttribute(child, "name", fname))
+ return false;
+ //trace("INCLUDE: %s", fname.c_str());
+ includes.push_back(fname);
+ }
+ }
+
+ return true;
+}
+
+
+
+
+/**
+ * Parse a <fileset> entry, and determine which files
+ * should be included
+ */
+bool MakeBase::parseFileSet(Element *elem,
+ MakeBase &propRef,
+ FileSet &fileSet)
+{
+ String name = elem->getName();
+ if (name != "fileset")
+ {
+ error("expected <fileset>");
+ return false;
+ }
+
+
+ std::vector<String> includes;
+ std::vector<String> excludes;
+
+ //A fileset has one implied patternset
+ if (!parsePatternSet(elem, propRef, includes, excludes))
+ {
+ return false;
+ }
+ //Look for child tags, including more patternsets
+ 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 == "patternset")
+ {
+ if (!parsePatternSet(child, propRef, includes, excludes))
+ {
+ return false;
+ }
+ }
+ }
+
+ String dir;
+ //Now do the stuff
+ //Get the base directory for reading file names
+ if (!propRef.getAttribute(elem, "dir", dir))
+ return false;
+
+ fileSet.setDirectory(dir);
+ fileSet.setIncludes(includes);
+ fileSet.setExcludes(excludes);
+
+ /*
+ std::vector<String> fileList;
+ if (dir.size() > 0)
+ {
+ String baseDir = propRef.resolve(dir);
+ if (!listFiles(baseDir, "", includes, excludes, fileList))
+ return false;
+ }
+ std::sort(fileList.begin(), fileList.end());
+ result = fileList;
+ */
+
+
+ /*
+ for (unsigned int i=0 ; i<result.size() ; i++)
+ {
+ trace("RES:%s", result[i].c_str());
+ }
+ */
+
+
+ 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;
+ }
+ }
- /**
- *
- */
- virtual String getPrefix()
- { return prefix; }
+ String dir;
+ //Get the base directory for reading file names
+ if (!propRef.getAttribute(elem, "dir", dir))
+ return false;
+ fileList.setDirectory(dir);
+ fileList.setFiles(fnames);
- /**
- * Allow the user to override the prefix in the file
- */
- virtual void setPrefix(const String &val)
- { prefix = val; }
+ return true;
+}
- /**
- *
- */
- virtual String getDescription()
- { return description; }
- /**
- *
- */
- virtual String getCflags()
- { return cflags; }
- /**
- *
- */
- virtual String getLibs()
- { return libs; }
+/**
+ * Create a directory, making intermediate dirs
+ * if necessary
+ */
+bool MakeBase::createDirectory(const String &dirname)
+{
+ //trace("## createDirectory: %s", dirname.c_str());
+ //## first check if it exists
+ struct stat finfo;
+ String nativeDir = getNativePath(dirname);
+ char *cnative = (char *) nativeDir.c_str();
+#ifdef __WIN32__
+ if (strlen(cnative)==2 && cnative[1]==':')
+ return true;
+#endif
+ if (stat(cnative, &finfo)==0)
+ {
+ if (!S_ISDIR(finfo.st_mode))
+ {
+ error("mkdir: file %s exists but is not a directory",
+ cnative);
+ return false;
+ }
+ else //exists
+ {
+ return true;
+ }
+ }
- /**
- *
- */
- virtual String getAll()
+ //## 2: pull off the last path segment, if any,
+ //## to make the dir 'above' this one, if necessary
+ unsigned int pos = dirname.find_last_of('/');
+ if (pos>0 && pos != dirname.npos)
{
- String ret = cflags;
- ret.append(" ");
- ret.append(libs);
- return ret;
+ String subpath = dirname.substr(0, pos);
+ //A letter root (c:) ?
+ if (!createDirectory(subpath))
+ return false;
+ }
+
+ //## 3: now make
+#ifdef __WIN32__
+ if (mkdir(cnative)<0)
+#else
+ if (mkdir(cnative, S_IRWXU | S_IRWXG | S_IRWXO)<0)
+#endif
+ {
+ error("cannot make directory '%s' : %s",
+ cnative, strerror(errno));
+ return false;
}
+
+ return true;
+}
- /**
- *
- */
- virtual String getVersion()
- { return version; }
- /**
- *
- */
- virtual int getMajorVersion()
- { return majorVersion; }
+/**
+ * Remove a directory recursively
+ */
+bool MakeBase::removeDirectory(const String &dirName)
+{
+ char *dname = (char *)dirName.c_str();
- /**
- *
- */
- virtual int getMinorVersion()
- { return minorVersion; }
+ DIR *dir = opendir(dname);
+ if (!dir)
+ {
+ //# Let this fail nicely.
+ return true;
+ //error("error opening directory %s : %s", dname, strerror(errno));
+ //return false;
+ }
+
+ while (true)
+ {
+ struct dirent *de = readdir(dir);
+ if (!de)
+ break;
- /**
- *
- */
- virtual int getMicroVersion()
- { return microVersion; }
+ //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);
- /**
- *
- */
- virtual std::map<String, String> &getAttributes()
- { return attrs; }
- /**
- *
- */
- virtual std::vector<String> &getRequireList()
- { return requireList; }
+ struct stat finfo;
+ String childNative = getNativePath(childName);
+ char *cnative = (char *)childNative.c_str();
+ if (stat(cnative, &finfo)<0)
+ {
+ error("cannot stat file:%s", cnative);
+ }
+ else if (S_ISDIR(finfo.st_mode))
+ {
+ //trace("DEL dir: %s", childName.c_str());
+ if (!removeDirectory(childName))
+ {
+ return false;
+ }
+ }
+ else if (!S_ISREG(finfo.st_mode))
+ {
+ //trace("not regular: %s", cnative);
+ }
+ else
+ {
+ //trace("DEL file: %s", childName.c_str());
+ if (remove(cnative)<0)
+ {
+ error("error deleting %s : %s",
+ cnative, strerror(errno));
+ return false;
+ }
+ }
+ }
+ closedir(dir);
- /**
- * Read a file for its details
- */
- virtual bool readFile(const String &fileName);
+ //Now delete the directory
+ String native = getNativePath(dirName);
+ if (rmdir(native.c_str())<0)
+ {
+ error("could not delete directory %s : %s",
+ native.c_str() , strerror(errno));
+ return false;
+ }
- /**
- * Read a file for its details
- */
- virtual bool query(const String &name);
+ return true;
+
+}
-private:
- void init()
+/**
+ * Copy a file from one name to another. Perform only if needed
+ */
+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)
{
- //do not set path or prefix here
- name = "";
- description = "";
- cflags = "";
- libs = "";
- requires = "";
- version = "";
- majorVersion = 0;
- minorVersion = 0;
- microVersion = 0;
- fileName = "";
- attrs.clear();
- requireList.clear();
+ error("source file %s for copy does not exist",
+ srcNative.c_str());
+ return false;
}
- void assign(const PkgConfig &other)
+ String destNative = getNativePath(destFile);
+ struct stat destinfo;
+ if (stat(destNative.c_str(), &destinfo)==0)
{
- 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;
+ if (destinfo.st_mtime >= srcinfo.st_mtime)
+ return true;
+ }
+
+ //# 2 prepare a destination directory if necessary
+ unsigned int pos = destFile.find_last_of('/');
+ if (pos != destFile.npos)
+ {
+ String subpath = destFile.substr(0, pos);
+ if (!createDirectory(subpath))
+ return false;
}
+ //# 3 do the data copy
+#ifndef __WIN32__
+ FILE *srcf = fopen(srcNative.c_str(), "rb");
+ if (!srcf)
+ {
+ error("copyFile cannot open '%s' for reading", srcNative.c_str());
+ return false;
+ }
+ FILE *destf = fopen(destNative.c_str(), "wb");
+ if (!destf)
+ {
+ error("copyFile cannot open %s for writing", srcNative.c_str());
+ return false;
+ }
- int get(int pos);
+ while (!feof(srcf))
+ {
+ int ch = fgetc(srcf);
+ if (ch<0)
+ break;
+ fputc(ch, destf);
+ }
- int skipwhite(int pos);
+ fclose(destf);
+ fclose(srcf);
- int getword(int pos, String &ret);
+#else
+
+ if (!CopyFile(srcNative.c_str(), destNative.c_str(), false))
+ {
+ error("copyFile from %s to %s failed",
+ srcNative.c_str(), destNative.c_str());
+ return false;
+ }
+
+#endif /* __WIN32__ */
- void parseRequires();
- void parseVersion();
+ return true;
+}
- bool parseLine(const String &lineBuf);
- bool parse(const String &buf);
- void dumpAttrs();
+/**
+ * Tests if the file exists and is a regular file
+ */
+bool MakeBase::isRegularFile(const String &fileName)
+{
+ String native = getNativePath(fileName);
+ struct stat finfo;
+
+ //Exists?
+ if (stat(native.c_str(), &finfo)<0)
+ return false;
- String name;
- String path;
+ //check the file mode
+ if (!S_ISREG(finfo.st_mode))
+ return false;
- String prefix;
+ return true;
+}
- String description;
+/**
+ * Tests if the file exists and is a directory
+ */
+bool MakeBase::isDirectory(const String &fileName)
+{
+ String native = getNativePath(fileName);
+ struct stat finfo;
+
+ //Exists?
+ if (stat(native.c_str(), &finfo)<0)
+ return false;
- 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 (stat(nativeA.c_str(), &infoA)<0)
+ {
+ return false;
+ }
- int microVersion;
+ String nativeB = getNativePath(fileB);
+ struct stat infoB;
+ //IF dest does not exist, YES, newer
+ if (stat(nativeB.c_str(), &infoB)<0)
+ {
+ return true;
+ }
- String fileName;
+ //check the actual times
+ if (infoA.st_mtime > infoB.st_mtime)
+ {
+ return true;
+ }
- std::map<String, String> attrs;
+ return false;
+}
- std::vector<String> requireList;
- char *parsebuf;
- int parselen;
-};
+//########################################################################
+//# P K G C O N F I G
+//########################################################################
/**
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++;
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;
//trace("val %s", val.c_str());
requireList.push_back(val);
}
+ return true;
}
+
static int getint(const String str)
{
char *s = (char *)str.c_str();
TaskCC(MakeBase &par) : Task(par)
{
type = TASK_CC;
- name = "cc";
- ccCommand = "gcc";
- cxxCommand = "g++";
- source = ".";
- dest = ".";
- flags = "";
- defines = "";
- includes = "";
- continueOnError = false;
- refreshCache = false;
- fileSet.clear();
- excludeInc.clear();
+ name = "cc";
}
virtual ~TaskCC()
{}
-
+
virtual bool isExcludedInc(const String &dirname)
{
for (unsigned int i=0 ; i<excludeInc.size() ; i++)
virtual bool execute()
{
+ //evaluate our parameters
+ String command = parent.eval(commandOpt, "gcc");
+ String ccCommand = parent.eval(ccCommandOpt, "gcc");
+ String cxxCommand = parent.eval(cxxCommandOpt, "g++");
+ String source = parent.eval(sourceOpt, ".");
+ String dest = parent.eval(destOpt, ".");
+ String flags = parent.eval(flagsOpt, "");
+ String defines = parent.eval(definesOpt, "");
+ String includes = parent.eval(includesOpt, "");
+ bool continueOnError = parent.evalBool(continueOnErrorOpt, true);
+ bool refreshCache = parent.evalBool(refreshCacheOpt, false);
+
if (!listFiles(parent, fileSet))
return false;
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) { ccCommand = s; cxxCommand = s; }
- if (!parent.getAttribute(elem, "cc", s))
+ if (commandOpt.size()>0)
+ { cxxCommandOpt = ccCommandOpt = commandOpt; }
+ if (!parent.getAttribute(elem, "cc", ccCommandOpt))
return false;
- if (s.size()>0) ccCommand = s;
- if (!parent.getAttribute(elem, "cxx", s))
+ if (!parent.getAttribute(elem, "cxx", cxxCommandOpt))
return false;
- if (s.size()>0) cxxCommand = s;
- if (!parent.getAttribute(elem, "destdir", s))
+ if (!parent.getAttribute(elem, "destdir", destOpt))
return false;
- if (s.size()>0) dest = s;
- if (!parent.getAttribute(elem, "continueOnError", s))
+ if (!parent.getAttribute(elem, "continueOnError", continueOnErrorOpt))
return false;
- if (s=="true" || s=="yes")
- continueOnError = true;
- if (!parent.getAttribute(elem, "refreshCache", s))
+ if (!parent.getAttribute(elem, "refreshCache", refreshCacheOpt))
return false;
- if (s=="true" || s=="yes")
- refreshCache = true;
std::vector<Element *> children = elem->getChildren();
for (unsigned int i=0 ; i<children.size() ; i++)
String tagName = child->getName();
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")
{
protected:
- String ccCommand;
- String cxxCommand;
- String source;
- String dest;
- String flags;
- String lastflags;
- String defines;
- String includes;
- bool continueOnError;
- bool refreshCache;
+ String commandOpt;
+ String ccCommandOpt;
+ String cxxCommandOpt;
+ String sourceOpt;
+ String destOpt;
+ String flagsOpt;
+ String definesOpt;
+ String includesOpt;
+ String continueOnErrorOpt;
+ String refreshCacheOpt;
FileSet fileSet;
FileList excludeInc;
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;
}
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:
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());
{
if (!listFiles(parent, fileSet))
return false;
- String fileSetDir = fileSet.getDirectory();
+ String fileSetDir = parent.eval(fileSet.getDirectory(), ".");
taskstatus("%s to %s",
fileSetDir.c_str(), toDirName.c_str());
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))
}
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());
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 (toDirName.size() > 0)
+ if (toDirNameOpt.size() > 0)
cptype = CP_TODIR;
- String ret;
- if (!parent.getAttribute(elem, "verbose", ret))
- return false;
- if (ret.size()>0 && !getBool(ret, verbose))
+ if (!parent.getAttribute(elem, "verbose", verboseOpt))
return false;
haveFileSet = false;
}
//Perform validity checks
- if (fileName.size()>0 && fileSet.size()>0)
+ if (fileNameOpt.size()>0 && fileSet.size()>0)
{
error("<copy> can only have one of : file= and <fileset>");
return false;
}
- if (toFileName.size()>0 && toDirName.size()>0)
+ if (toFileNameOpt.size()>0 && toDirNameOpt.size()>0)
{
error("<copy> can only have one of : tofile= or todir=");
return false;
}
- if (haveFileSet && toDirName.size()==0)
+ if (haveFileSet && toDirNameOpt.size()==0)
{
error("a <copy> task with a <fileset> must have : todir=");
return false;
}
- if (cptype == CP_TOFILE && fileName.size()==0)
+ if (cptype == CP_TOFILE && fileNameOpt.size()==0)
{
error("<copy> tofile= must be associated with : file=");
return false;
}
- if (cptype == CP_TODIR && fileName.size()==0 && !haveFileSet)
+ if (cptype == CP_TODIR && fileNameOpt.size()==0 && !haveFileSet)
{
error("<copy> todir= must be associated with : file= or <fileset>");
return false;
private:
int cptype;
- String fileName;
- FileSet fileSet;
- String toFileName;
- String toDirName;
- bool verbose;
bool haveFileSet;
+
+ FileSet fileSet;
+ String fileNameOpt;
+ String toFileNameOpt;
+ String toDirNameOpt;
+ String verboseOpt;
};
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()
virtual bool execute()
{
+ 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);
struct stat finfo;
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();
+ if (!quiet && verbose)
+ taskstatus("path: %s", fname);
//does not exist
if (stat(fname, &finfo)<0)
- return true;
+ {
+ if (failOnError)
+ return false;
+ else
+ return true;
+ }
//exists but is not a regular file
if (!S_ISREG(finfo.st_mode))
{
}
case DEL_DIR:
{
- taskstatus("%s", dirName.c_str());
+ taskstatus("dir: %s", dirName.c_str());
String fullDir = parent.resolve(dirName);
+ if (!quiet && verbose)
+ taskstatus("path: %s", fullDir.c_str());
if (!removeDirectory(fullDir))
return false;
return true;
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("<delete> 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("<delete> must have one attribute of file= or dir=");
return false;
}
- String ret;
- if (!parent.getAttribute(elem, "verbose", ret))
- return false;
- if (ret.size()>0 && !getBool(ret, verbose))
- return false;
- if (!parent.getAttribute(elem, "quiet", ret))
+ if (!parent.getAttribute(elem, "verbose", verboseOpt))
return false;
- if (ret.size()>0 && !getBool(ret, quiet))
+ if (!parent.getAttribute(elem, "quiet", quietOpt))
return false;
- if (!parent.getAttribute(elem, "failonerror", ret))
- return false;
- if (ret.size()>0 && !getBool(ret, failOnError))
+ if (!parent.getAttribute(elem, "failonerror", failOnErrorOpt))
return false;
return true;
}
private:
int delType;
- String dirName;
- String fileName;
- bool verbose;
- bool quiet;
- bool failOnError;
+ String dirNameOpt;
+ String fileNameOpt;
+ String verboseOpt;
+ String quietOpt;
+ String failOnErrorOpt;
};
virtual bool execute()
{
//let message have priority over text
+ String message = parent.eval(messageOpt, "");
+ String text = parent.eval(textOpt, "");
if (message.size() > 0)
{
- String s;
- if (!parent.eval(message, s))
- return false;
- fprintf(stdout, "%s\n", s.c_str());
+ fprintf(stdout, "%s\n", message.c_str());
}
else if (text.size() > 0)
{
- String s;
- if (!parent.eval(text, s))
- return false;
- fprintf(stdout, "%s\n", s.c_str());
+ fprintf(stdout, "%s\n", text.c_str());
}
return true;
}
virtual bool parse(Element *elem)
{
- text = elem->getValue();
- text = leftJustify(text);
- message = elem->getAttribute("message");
+ if (!parent.getValue(elem, textOpt))
+ return false;
+ textOpt = leftJustify(textOpt);
+ if (!parent.getAttribute(elem, "message", messageOpt))
+ return false;
return true;
}
private:
- String message;
- String text;
+ String messageOpt;
+ String textOpt;
};
public:
TaskJar(MakeBase &par) : Task(par)
- { type = TASK_JAR; name = "jar"; command = "jar";}
+ { type = TASK_JAR; name = "jar"; }
virtual ~TaskJar()
{}
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);
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, "basedir", basedir))
+ if (!parent.getAttribute(elem, "basedir", basedirOpt))
return false;
- if (!parent.getAttribute(elem, "destfile", destfile))
+ if (!parent.getAttribute(elem, "destfile", destfileOpt))
return false;
- if (basedir.size() == 0 || destfile.size() == 0)
+ if (basedirOpt.size() == 0 || destfileOpt.size() == 0)
{
error("<jar> required both basedir and destfile attributes to be set");
return false;
}
private:
- String command;
- String basedir;
- String destfile;
+
+ String commandOpt;
+ String basedirOpt;
+ String destfileOpt;
};
TaskJavac(MakeBase &par) : Task(par)
{
type = TASK_JAVAC; name = "javac";
- command = "javac";
}
virtual ~TaskJavac()
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<String> fileList;
if (!listFiles(srcdir, "", fileList))
{
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("<javac> required both srcdir and destdir attributes to be set");
return false;
}
- if (!parent.getAttribute(elem, "target", target))
+ if (!parent.getAttribute(elem, "target", targetOpt))
return false;
return true;
}
private:
- String command;
- String srcdir;
- String destdir;
- String target;
+ String commandOpt;
+ String srcdirOpt;
+ String destdirOpt;
+ String targetOpt;
};
TaskLink(MakeBase &par) : Task(par)
{
type = TASK_LINK; name = "link";
- command = "g++";
- doStrip = false;
- stripCommand = "strip";
- objcopyCommand = "objcopy";
}
virtual ~TaskLink()
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);
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<Element *> children = elem->getChildren();
}
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;
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;
};
virtual bool execute()
{
+ String fileName = parent.eval(fileNameOpt, "");
+ String text = parent.eval(textOpt, "");
+
taskstatus("%s", fileName.c_str());
String fullName = parent.resolve(fileName);
if (!isNewerThan(parent.getURI().getPath(), fullName))
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)
{
error("<makefile> 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 textOpt;
};
virtual bool execute()
{
+ String dirName = parent.eval(dirNameOpt, ".");
+
taskstatus("%s", dirName.c_str());
String fullDir = parent.resolve(dirName);
//trace("fullDir:%s", fullDir.c_str());
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("<mkdir> requires 'dir=\"dirname\"' attribute");
return false;
private:
- String dirName;
+ String dirNameOpt;
};
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();
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, "todir", toDirName))
+ if (!parent.getAttribute(elem, "command", commandOpt))
return false;
- if (!parent.getAttribute(elem, "out", outName))
+ if (!parent.getAttribute(elem, "todir", toDirNameOpt))
return false;
- if (!parent.getAttribute(elem, "owndir", s))
+ if (!parent.getAttribute(elem, "out", outNameOpt))
return false;
- if (s.size()>0 && !getBool(s, owndir))
+ if (!parent.getAttribute(elem, "owndir", owndirOpt))
return false;
std::vector<Element *> children = elem->getChildren();
private:
- String command;
- String toDirName;
- String outName;
FileSet fileSet;
- bool owndir;
+
+ String commandOpt;
+ String toDirNameOpt;
+ String outNameOpt;
+ String owndirOpt;
};
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);
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;
- }
+ String val = "";
+ if (query == "cflags")
+ val = pkgconfig.getCflags();
+ else if (query == "libs")
+ val =pkgconfig.getLibs();
+ else if (query == "all")
+ val = pkgconfig.getAll();
+ else
+ {
+ error("<pkg-config> unhandled query : %s", query.c_str());
+ return false;
}
- taskstatus("property %s = '%s'", propName.c_str(), 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("<pkg-config> 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("<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))
+ 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("<pkg-config> 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;
};
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;
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("<ranlib> requires 'file=\"fileNname\"' attribute");
return false;
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))
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<Element *> children = elem->getChildren();
for (unsigned int i=0 ; i<children.size() ; i++)
String tagName = child->getName();
if (tagName == "flags")
{
- if (!parent.getValue(child, flags))
+ if (!parent.getValue(child, flagsOpt))
return false;
}
}
private:
- String command;
- String flags;
- String fileName;
- String outName;
+ String commandOpt;
+ String flagsOpt;
+ String fileNameOpt;
+ String outNameOpt;
};
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;
if (!listFiles(parent, fileSet))
return false;
- String fileSetDir = fileSet.getDirectory();
+ String fileSetDir = parent.eval(fileSet.getDirectory(), ".");
for (unsigned int i=0 ; i<fileSet.size() ; i++)
{
virtual bool parse(Element *elem)
{
- if (!parent.getAttribute(elem, "file", fileName))
+ if (!parent.getAttribute(elem, "command", commandOpt))
return false;
- if (!parent.getAttribute(elem, "import", impFileName))
+ if (!parent.getAttribute(elem, "file", fileNameOpt))
return false;
- if (!parent.getAttribute(elem, "def", defFileName))
+ if (!parent.getAttribute(elem, "import", impFileNameOpt))
+ return false;
+ if (!parent.getAttribute(elem, "def", defFileNameOpt))
return false;
std::vector<Element *> children = elem->getChildren();
}
else if (tagName == "libs")
{
- if (!parent.getValue(child, libs))
+ if (!parent.getValue(child, libsOpt))
return false;
- libs = strip(libs);
+ libsOpt = strip(libsOpt);
}
}
return true;
private:
- String command;
- String fileName;
- String defFileName;
- String impFileName;
FileSet fileSet;
- String libs;
+
+ String commandOpt;
+ String fileNameOpt;
+ String defFileNameOpt;
+ String impFileNameOpt;
+ String libsOpt;
};
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);
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<fileSet.size() ; i++)
{
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<Element *> children = elem->getChildren();
private:
- String command;
- String fileName;
FileSet fileSet;
+ String commandOpt;
+ String fileNameOpt;
+
};
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;
}
}
- cmd = "strip ";
+ cmd = command;
cmd.append(getNativePath(fullName));
if (!executeCommand(cmd, "", outbuf, errbuf))
{
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("<strip> requires 'file=\"fileName\"' attribute");
return false;
private:
- String fileName;
- String symFileName;
+ String commandOpt;
+ String fileNameOpt;
+ String symFileNameOpt;
};
virtual bool execute()
{
+ String fileName = parent.eval(fileNameOpt, "");
+
String fullName = parent.resolve(fileName);
String nativeFile = getNativePath(fullName);
if (!isRegularFile(fullName) && !isDirectory(fullName))
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("<touch> requires 'file=\"fileName\"' attribute");
return false;
return true;
}
- String fileName;
+ String fileNameOpt;
};
specifiedTarget = "";
baseDir = "";
description = "";
- envPrefix = "";
+ envPrefix = "env.";
+ pcPrefix = "pc.";
+ pccPrefix = "pcc.";
+ pclPrefix = "pcl.";
properties.clear();
for (unsigned int i = 0 ; i < allTasks.size() ; i++)
delete allTasks[i];
}
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");
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('.');
+ }
}
return true;