// ********************************************************************** // // Copyright (c) 2003-2007 ZeroC, Inc. All rights reserved. // // This copy of Ice is licensed to you under the terms described in the // ICE_LICENSE file included in this distribution. // // ********************************************************************** //package Ice.Ant; import org.apache.tools.ant.Task; import org.apache.tools.ant.BuildException; import org.apache.tools.ant.DirectoryScanner; import org.apache.tools.ant.types.FileSet; import org.apache.tools.ant.taskdefs.ExecTask; import org.apache.tools.ant.taskdefs.Execute; import org.apache.tools.ant.taskdefs.PumpStreamHandler; import org.apache.tools.ant.types.Commandline; import org.apache.tools.ant.types.Commandline.Argument; import org.apache.tools.ant.types.Path; import org.apache.tools.ant.types.Reference; import java.io.File; import java.io.FileOutputStream; import java.io.FileReader; import java.io.FileWriter; import java.io.StringReader; import java.io.BufferedReader; import java.io.BufferedWriter; /** * An ant task for slice2cpp. This task extends the abstract * SliceTask class which takes care of attributes common to all slice * translators (see SliceTask.java for details on these attributes). * * Attributes specific to slice2cpp: * * translator - The pathname of the translator (default: "slice2cpp"). * tie - The value for the --tie translator option. * checksum - The value for the --checksum translator option. * stream - The value for the --stream translator option. * * Example: * * * * * * * * * * * * * * * * * * * The element installs the slice2cpp task. */ public class Slice2CppTask extends SliceTask { public Slice2CppTask() { _translator = null; _tie = false; _checksum = null; } public void setTranslator(File prog) { _translator = prog; } public void setTie(boolean tie) { _tie = tie; } public void setChecksum(String checksum) { _checksum = checksum; } public void setStream(boolean stream) { _stream = stream; } public void execute() throws BuildException { if(_fileSets.isEmpty()) { throw new BuildException("No fileset specified"); } // // Read the set of dependencies for this task. // java.util.HashMap dependencies = readDependencies(); // // Compose a list of the files that need to be translated. A // file needs to translated if we can't find a dependency in // the dependency table or if its dependency is not up-to-date // anymore (the slice file changed since the dependency was // last updated or a slice file it depends on changed). // java.util.Vector buildList = new java.util.Vector(); java.util.Iterator p = _fileSets.iterator(); while(p.hasNext()) { FileSet fileset = (FileSet)p.next(); DirectoryScanner scanner = fileset.getDirectoryScanner(getProject()); scanner.scan(); String[] files = scanner.getIncludedFiles(); for(int i = 0; i < files.length; i++) { File slice = new File(fileset.getDir(getProject()), files[i]); SliceDependency depend = (SliceDependency)dependencies.get(getTargetKey(slice.toString())); if(depend == null || !depend.isUpToDate()) { buildList.addElement(slice); } else { log("skipping " + files[i]); } } } // // Run the translator // if(!buildList.isEmpty()) { String translator; if(_translator == null) { String iceInstall = getIceHome(); // // If the location of the Ice install is not known, we // rely on a path search to find the translator. // if(iceInstall == null) { translator = "slice2cpp"; } else { translator = new File(iceInstall + File.separator + "bin" + File.separator + "slice2cpp").toString(); } } else { translator = _translator.toString(); } StringBuffer cmd = new StringBuffer(); // // Add --output-dir // if(_outputDir != null) { cmd.append(" --output-dir "); cmd.append(_outputDirString); } // // Add include directives // if(_includePath != null) { String[] dirs = _includePath.list(); for(int i = 0; i < dirs.length; i++) { cmd.append(" -I"); if(dirs[i].indexOf(' ') != -1) { cmd.append('"' + dirs[i] + '"'); } else { cmd.append(dirs[i]); } } } // // Add defines // if(!_defines.isEmpty()) { java.util.Iterator i = _defines.iterator(); while(i.hasNext()) { SliceDefine define = (SliceDefine)i.next(); cmd.append(" -D"); cmd.append(define.getName()); String value = define.getValue(); if(value != null) { cmd.append("="); cmd.append(value); } } } // // Add --tie // if(_tie) { cmd.append(" --tie"); } // // Add --checksum // if(_checksum != null && _checksum.length() > 0) { cmd.append(" --checksum " + _checksum); } // // Add --stream // if(_stream) { cmd.append(" --stream"); } // // Add --meta // if(!_meta.isEmpty()) { java.util.Iterator i = _meta.iterator(); while(i.hasNext()) { SliceMeta m = (SliceMeta)i.next(); cmd.append(" --meta " + m.getValue()); } } // // Add --ice // if(_ice) { cmd.append(" --ice"); } // // Add --case-sensitive // if(_caseSensitive) { cmd.append(" --case-sensitive"); } // // Add files to be translated // for(int i = 0; i < buildList.size(); i++) { File f = (File)buildList.elementAt(i); cmd.append(" "); String s = f.toString(); if(s.indexOf(' ') != -1) { cmd.append('"' + s + '"'); } else { cmd.append(s); } } // // Execute // log(translator + " " + cmd); ExecTask task = (ExecTask)getProject().createTask("exec"); task.setFailonerror(true); Argument arg = task.createArg(); arg.setLine(cmd.toString()); task.setExecutable(translator); task.execute(); // // Update the dependencies. // cmd = new StringBuffer("--depend"); // // Add include directives // if(_includePath != null) { String[] dirs = _includePath.list(); for(int i = 0; i < dirs.length; i++) { cmd.append(" -I"); if(dirs[i].indexOf(' ') != -1) { cmd.append('"' + dirs[i] + '"'); } else { cmd.append(dirs[i]); } } } // // Add files for which we need to check dependencies. // for(int i = 0; i < buildList.size(); i++) { File f = (File)buildList.elementAt(i); cmd.append(" "); String s = f.toString(); if(s.indexOf(' ') != -1) { cmd.append('"' + s + '"'); } else { cmd.append(s); } } // // It's not possible anymore to re-use the same output property since Ant 1.5.x. so we use a // unique property name here. Perhaps we should output the dependencies to a file instead. // final String outputProperty = "slice2cpp.depend." + System.currentTimeMillis(); task = (ExecTask)getProject().createTask("exec"); task.setFailonerror(true); arg = task.createArg(); arg.setLine(cmd.toString()); task.setExecutable(translator); task.setOutputproperty(outputProperty); task.execute(); // // Update dependency file. // //System.out.println("parseDependencies("+getProject().getProperty(outputProperty)+")"); java.util.List newDependencies = parseDependencies(getProject().getProperty(outputProperty)); p = newDependencies.iterator(); while(p.hasNext()) { SliceDependency dep = (SliceDependency)p.next(); dependencies.put(getTargetKey(dep._dependencies[0]), dep); } writeDependencies(dependencies); } } @Override protected java.util.List parseDependencies(String allDependencies) { java.util.List sResult = super.parseDependencies(allDependencies); java.util.Iterator p = sResult.iterator(); while(p.hasNext()) { SliceDependency dep = (SliceDependency)p.next(); assert(dep._dependencies[0].endsWith(".cpp")); String[] newDependencies = new String[dep._dependencies.length - 1]; for(int initNewDep=0;initNewDep < newDependencies.length;++initNewDep) { newDependencies[initNewDep] = dep._dependencies[initNewDep+1]; } dep._dependencies = newDependencies; } return sResult; } private String getTargetKey(String slice) { // // Since the dependency file can be shared by several slice // tasks we need to make sure that each dependency has a // unique key. We use the name of the task, the output // directory and the name of the slice file to be compiled. // // If there's two slice2cpp tasks using the same dependency // file, with the same output dir and which compiles the same // slice file they'll use the same dependency. // return "slice2cpp " + _outputDir.toString() + " " + slice; } private File _translator; private boolean _tie; private String _checksum; private boolean _stream; }