diff --git a/buildtool.cpp b/buildtool.cpp
index 42c6c3719ab8bfe7f756f3ef8b972c32b5984bc3..21a7a4aef8131d83b30a315530adc850e15a00d8 100644 (file)
--- a/buildtool.cpp
+++ b/buildtool.cpp
* Authors:
* Bob Jamison
*
- * Copyright (C) 2006-2007 Bob Jamison
+ * Copyright (C) 2006-2008 Bob Jamison
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* To use this file, compile with:
* <pre>
* g++ -O3 buildtool.cpp -o btool.exe
- * (or whatever your compiler might be)
+ * (or whatever your compiler might be)
* Then
* btool
- * or
+ * or
* btool {target}
- *
+ *
* Note: if you are using MinGW, and a not very recent version of it,
* gettimeofday() might be missing. If so, just build this file with
* this command:
* g++ -O3 -DNEED_GETTIMEOFDAY buildtool.cpp -o btool.exe
- *
- */
+ *
+ */
-#define BUILDTOOL_VERSION "BuildTool v0.7.2, 2007 Bob Jamison"
+#define BUILDTOOL_VERSION "BuildTool v0.8.1, 2007-2008 Bob Jamison"
#include <stdio.h>
#include <fcntl.h>
};
+//########################################################################
+//# F I L E L I S T
+//########################################################################
+/**
+ * This is a simpler, explicitly-named list of files
+ */
+class FileList
+{
+public:
+
+ /**
+ *
+ */
+ FileList()
+ {}
+
+ /**
+ *
+ */
+ FileList(const FileList &other)
+ { assign(other); }
+
+ /**
+ *
+ */
+ FileList &operator=(const FileList &other)
+ { assign(other); return *this; }
+
+ /**
+ *
+ */
+ virtual ~FileList()
+ {}
+
+ /**
+ *
+ */
+ String getDirectory()
+ { return directory; }
+
+ /**
+ *
+ */
+ void setDirectory(const String &val)
+ { directory = val; }
+
+ /**
+ *
+ */
+ void setFiles(const std::vector<String> &val)
+ { files = val; }
+
+ /**
+ *
+ */
+ std::vector<String> getFiles()
+ { return files; }
+
+ /**
+ *
+ */
+ unsigned int size()
+ { return files.size(); }
+
+ /**
+ *
+ */
+ String operator[](int index)
+ { return files[index]; }
+
+ /**
+ *
+ */
+ void clear()
+ {
+ directory = "";
+ files.clear();
+ }
+
+
+private:
+
+ void assign(const FileList &other)
+ {
+ directory = other.directory;
+ files = other.files;
+ }
+
+ String directory;
+ std::vector<String> files;
+};
+
+
//########################################################################
* The path to the file associated with this object
*/
URI uri;
+
+ /**
+ * If this prefix is seen in a substitution, use an environment
+ * variable.
+ * example: <property environment="env"/>
+ * ${env.JAVA_HOME}
+ */
+ String envPrefix;
+
+
/**
*/
void status(const char *fmt, ...);
+ /**
+ * Show target status
+ */
+ void targetstatus(const char *fmt, ...);
+
/**
* Print a printf()-like formatted trace message
*/
bool parseFileSet(Element *elem,
MakeBase &propRef,
FileSet &fileSet);
+ /**
+ * Parse a <filelist> entry
+ */
+ bool parseFileList(Element *elem,
+ MakeBase &propRef,
+ FileList &fileList);
/**
* Return this object's property list
}
-
/**
* Resolve another path relative to this one
*/
else if (ch == '}')
{
std::map<String, String>::iterator iter;
- iter = properties.find(trim(varname));
- if (iter != properties.end())
+ varname = trim(varname);
+ if (envPrefix.size() > 0 && varname.compare(0, envPrefix.size(), envPrefix) == 0)
{
- val.append(iter->second);
+ varname = varname.substr(envPrefix.size());
+ char *envstr = getenv(varname.c_str());
+ if (!envstr)
+ {
+ error("environment variable '%s' not defined", varname.c_str());
+ return false;
+ }
+ val.append(envstr);
}
else
{
- error("property ${%s} not found", varname.c_str());
- return false;
+ iter = properties.find(varname);
+ if (iter != properties.end())
+ {
+ val.append(iter->second);
+ }
+ else
+ {
+ error("property ${%s} not found", varname.c_str());
+ return false;
+ }
}
break;
}
return true;
}
+/**
+ * Parse a <filelist> entry. This is far simpler than FileSet,
+ * since no directory scanning is needed. The file names are listed
+ * explicitly.
+ */
+bool MakeBase::parseFileList(Element *elem,
+ MakeBase &propRef,
+ FileList &fileList)
+{
+ std::vector<String> fnames;
+ //Look for child tags, namely "file"
+ std::vector<Element *> children = elem->getChildren();
+ for (unsigned int i=0 ; i<children.size() ; i++)
+ {
+ Element *child = children[i];
+ String tagName = child->getName();
+ if (tagName == "file")
+ {
+ String fname = child->getAttribute("name");
+ if (fname.size()==0)
+ {
+ error("<file> element requires name="" attribute");
+ return false;
+ }
+ fnames.push_back(fname);
+ }
+ else
+ {
+ error("tag <%s> not allowed in <fileset>", tagName.c_str());
+ return false;
+ }
+ }
+
+ String dir;
+ //Get the base directory for reading file names
+ if (!propRef.getAttribute(elem, "dir", dir))
+ return false;
+ fileList.setDirectory(dir);
+ fileList.setFiles(fnames);
+
+ return true;
+}
+
/**
name = other.name;
}
+ /**
+ * Show task status
+ */
+ void taskstatus(const char *fmt, ...)
+ {
+ va_list args;
+ va_start(args,fmt);
+ fprintf(stdout, " %s : ", name.c_str());
+ vfprintf(stdout, fmt, args);
+ fprintf(stdout, "\n");
+ va_end(args) ;
+ }
+
String getAttribute(Element *elem, const String &attrName)
{
String str;
defines = "";
includes = "";
fileSet.clear();
+ excludeInc.clear();
}
virtual ~TaskCC()
{}
- virtual bool needsCompiling(const FileRec &depRec,
- const String &src, const String &dest)
+ virtual bool isExcludedInc(const String &dirname)
{
+ for (unsigned int i=0 ; i<excludeInc.size() ; i++)
+ {
+ String fname = excludeInc[i];
+ if (fname == dirname)
+ return true;
+ }
return false;
- }
+ }
virtual bool execute()
{
String fullName = parent.resolve("build.dep");
if (isNewerThan(parent.getURI().getPath(), fullName))
{
- status(" : regenerating C/C++ dependency cache");
+ taskstatus("regenerating C/C++ dependency cache");
refreshCache = true;
}
std::set<String>::iterator setIter;
for (setIter=paths.begin() ; setIter!=paths.end() ; setIter++)
{
+ String dirName = *setIter;
+ //check excludeInc to see if we dont want to include this dir
+ if (isExcludedInc(dirName))
+ continue;
incs.append(" -I");
String dname;
if (source.size()>0)
dname.append(source);
dname.append("/");
}
- dname.append(*setIter);
+ dname.append(dirName);
incs.append(parent.resolve(dname));
}
std::vector<String> cfiles;
//# First we check if the source is newer than the .o
if (isNewerThan(srcFullName, destFullName))
{
- status(" : compile of %s required by %s",
+ taskstatus("compile of %s required by source: %s",
destFullName.c_str(), srcFullName.c_str());
compileMe = true;
}
// destFullName.c_str(), depFullName.c_str());
if (depRequires)
{
- status(" : compile of %s required by %s",
+ taskstatus("compile of %s required by included: %s",
destFullName.c_str(), depFullName.c_str());
compileMe = true;
break;
return false;
source = fileSet.getDirectory();
}
+ else if (tagName == "excludeinc")
+ {
+ if (!parseFileList(child, parent, excludeInc))
+ return false;
+ }
}
return true;
protected:
- String ccCommand;
- String cxxCommand;
- String source;
- String dest;
- String flags;
- String defines;
- String includes;
- FileSet fileSet;
+ String ccCommand;
+ String cxxCommand;
+ String source;
+ String dest;
+ String flags;
+ String lastflags;
+ String defines;
+ String includes;
+ FileSet fileSet;
+ FileList excludeInc;
};
{
if (fileName.size()>0)
{
- status(" : %s to %s",
+ taskstatus("%s to %s",
fileName.c_str(), toFileName.c_str());
String fullSource = parent.resolve(fileName);
String fullDest = parent.resolve(toFileName);
}
if (!isNewerThan(fullSource, fullDest))
{
- status(" : skipped");
+ taskstatus("skipped");
return true;
}
if (!copyFile(fullSource, fullDest))
return false;
- status(" : 1 file copied");
+ taskstatus("1 file copied");
}
return true;
}
return false;
String fileSetDir = fileSet.getDirectory();
- status(" : %s to %s",
+ taskstatus("%s to %s",
fileSetDir.c_str(), toDirName.c_str());
int nrFiles = 0;
return false;
nrFiles++;
}
- status(" : %d file(s) copied", nrFiles);
+ taskstatus("%d file(s) copied", nrFiles);
}
else //file source
{
//For file->dir we want only the basename of
//the source appended to the dest dir
- status(" : %s to %s",
+ taskstatus("%s to %s",
fileName.c_str(), toDirName.c_str());
String baseName = fileName;
unsigned int pos = baseName.find_last_of('/');
}
if (!isNewerThan(fullSource, fullDest))
{
- status(" : skipped");
+ taskstatus("skipped");
return true;
}
if (!copyFile(fullSource, fullDest))
return false;
- status(" : 1 file copied");
+ taskstatus("1 file copied");
}
return true;
}
}
case DEL_DIR:
{
- status(" : %s", dirName.c_str());
+ taskstatus("%s", dirName.c_str());
String fullDir = parent.resolve(dirName);
if (!removeDirectory(fullDir))
return false;
public:
TaskJar(MakeBase &par) : Task(par)
- { type = TASK_JAR; name = "jar"; }
+ { type = TASK_JAR; name = "jar"; command = "jar";}
virtual ~TaskJar()
{}
virtual bool execute()
{
+ String cmd = command;
+ cmd.append(" -cf ");
+ cmd.append(destfile);
+ cmd.append(" -C ");
+ cmd.append(basedir);
+ cmd.append(" .");
+
+ String execCmd = cmd;
+
+ String outString, errString;
+ bool ret = executeCommand(execCmd.c_str(), "", outString, errString);
+ if (!ret)
+ {
+ error("<jar> command '%s' failed :\n %s",
+ execCmd.c_str(), errString.c_str());
+ return false;
+ }
return true;
}
virtual bool parse(Element *elem)
{
+ String s;
+ if (!parent.getAttribute(elem, "command", s))
+ return false;
+ if (s.size() > 0)
+ command = s;
+ if (!parent.getAttribute(elem, "basedir", basedir))
+ return false;
+ if (!parent.getAttribute(elem, "destfile", destfile))
+ return false;
+ if (basedir.size() == 0 || destfile.size() == 0)
+ {
+ error("<jar> required both basedir and destfile attributes to be set");
+ return false;
+ }
return true;
}
+
+private:
+ String command;
+ String basedir;
+ String destfile;
};
public:
TaskJavac(MakeBase &par) : Task(par)
- { type = TASK_JAVAC; name = "javac"; }
+ {
+ type = TASK_JAVAC; name = "javac";
+ command = "javac";
+ }
virtual ~TaskJavac()
{}
virtual bool execute()
{
+ std::vector<String> fileList;
+ if (!listFiles(srcdir, "", fileList))
+ {
+ return false;
+ }
+ String cmd = command;
+ cmd.append(" -d ");
+ cmd.append(destdir);
+ cmd.append(" -classpath ");
+ cmd.append(destdir);
+ cmd.append(" -sourcepath ");
+ cmd.append(srcdir);
+ cmd.append(" ");
+ if (target.size()>0)
+ {
+ cmd.append(" -target ");
+ cmd.append(target);
+ cmd.append(" ");
+ }
+ String fname = "javalist.btool";
+ FILE *f = fopen(fname.c_str(), "w");
+ int count = 0;
+ for (unsigned int i=0 ; i<fileList.size() ; i++)
+ {
+ String fname = fileList[i];
+ String srcName = fname;
+ if (fname.size()<6) //x.java
+ continue;
+ if (fname.compare(fname.size()-5, 5, ".java") != 0)
+ continue;
+ String baseName = fname.substr(0, fname.size()-5);
+ String destName = baseName;
+ destName.append(".class");
+
+ String fullSrc = srcdir;
+ fullSrc.append("/");
+ fullSrc.append(fname);
+ String fullDest = destdir;
+ fullDest.append("/");
+ fullDest.append(destName);
+ //trace("fullsrc:%s fulldest:%s", fullSrc.c_str(), fullDest.c_str());
+ if (!isNewerThan(fullSrc, fullDest))
+ continue;
+
+ count++;
+ fprintf(f, "%s\n", fullSrc.c_str());
+ }
+ fclose(f);
+ if (!count)
+ {
+ taskstatus("nothing to do");
+ return true;
+ }
+
+ taskstatus("compiling %d files", count);
+
+ String execCmd = cmd;
+ execCmd.append("@");
+ execCmd.append(fname);
+
+ String outString, errString;
+ bool ret = executeCommand(execCmd.c_str(), "", outString, errString);
+ if (!ret)
+ {
+ error("<javac> command '%s' failed :\n %s",
+ execCmd.c_str(), errString.c_str());
+ return false;
+ }
return true;
}
virtual bool parse(Element *elem)
{
+ String s;
+ if (!parent.getAttribute(elem, "command", s))
+ return false;
+ if (s.size() > 0)
+ command = s;
+ if (!parent.getAttribute(elem, "srcdir", srcdir))
+ return false;
+ if (!parent.getAttribute(elem, "destdir", destdir))
+ return false;
+ if (srcdir.size() == 0 || destdir.size() == 0)
+ {
+ error("<javac> required both srcdir and destdir attributes to be set");
+ return false;
+ }
+ if (!parent.getAttribute(elem, "target", target))
+ return false;
return true;
}
+
+private:
+
+ String command;
+ String srcdir;
+ String destdir;
+ String target;
+
};
type = TASK_LINK; name = "link";
command = "g++";
doStrip = false;
- stripCommand = "strip";
- objcopyCommand = "objcopy";
+ stripCommand = "strip";
+ objcopyCommand = "objcopy";
}
virtual ~TaskLink()
virtual bool execute()
{
- status(" : %s", fileName.c_str());
+ taskstatus("%s", fileName.c_str());
String fullName = parent.resolve(fileName);
if (!isNewerThan(parent.getURI().getPath(), fullName))
{
virtual bool execute()
{
- status(" : %s", dirName.c_str());
+ taskstatus("%s", dirName.c_str());
String fullDir = parent.resolve(dirName);
//trace("fullDir:%s", fullDir.c_str());
if (!createDirectory(fullDir))
}
}
- status(" : %s", ret.c_str());
+ taskstatus("%s", ret.c_str());
parent.setProperty(propName, ret);
return true;
}
String description;
- String envAlias;
-
//std::vector<Property> properties;
std::map<String, Target> targets;
specifiedTarget = "";
baseDir = "";
description = "";
- envAlias = "";
+ envPrefix = "";
properties.clear();
for (unsigned int i = 0 ; i < allTasks.size() ; i++)
delete allTasks[i];
}
}
- status("## Target : %s : %s", name.c_str(),
+ status("##### Target : %s\n##### %s", name.c_str(),
target.getDescription().c_str());
//Now let's do the tasks
for (unsigned int i=0 ; i<tasks.size() ; i++)
{
Task *task = tasks[i];
- status("---- task : %s", task->getName().c_str());
+ status("--- %s / %s", name.c_str(), task->getName().c_str());
if (!task->execute())
{
return false;
}
else if (attrName == "environment")
{
- if (envAlias.size() > 0)
+ if (envPrefix.size() > 0)
+ {
+ error("environment prefix can only be set once");
+ return false;
+ }
+ if (attrVal.find('.') != attrVal.npos)
{
- error("environment property can only be set once");
+ error("environment prefix cannot have a '.' in it");
return false;
}
- envAlias = attrVal;
+ envPrefix = attrVal;
+ envPrefix.push_back('.');
}
}