001    package escjava.ant;
002    
003    import org.apache.tools.ant.BuildException;
004    import org.apache.tools.ant.Project;
005    import org.apache.tools.ant.taskdefs.Execute;
006    import org.apache.tools.ant.taskdefs.Javac;
007    import org.apache.tools.ant.taskdefs.LogStreamHandler;
008    import org.apache.tools.ant.taskdefs.compilers.DefaultCompilerAdapter;
009    import org.apache.tools.ant.types.Commandline;
010    import org.apache.tools.ant.types.Path;
011    import org.apache.tools.ant.util.FileUtils;
012    
013    import java.io.File;
014    import java.io.FileWriter;
015    import java.io.IOException;
016    import java.io.PrintWriter;
017    
018    /**
019     * Define an Escj compiler adapter.  This class is only a very simple
020     * wrapper and does not try to implement of the command line options
021     * of escj.
022     *
023     * @author wsargent
024     * @version $Revision: 1.3 $
025     *
026     * @since May 16, 2004
027     */
028    public class ESCJavaTask extends DefaultCompilerAdapter
029    {
030      private FileUtils fileUtils = FileUtils.newFileUtils();
031    
032      /* (non-Javadoc)
033       * @see org.apache.tools.ant.taskdefs.compilers.DefaultCompilerAdapter#execute()
034       */
035      public boolean execute() throws BuildException
036      {
037        if (super.attributes == null)
038          {
039            throw new BuildException("Null attributes");
040          }
041    
042        if (super.project == null)
043          {
044            throw new BuildException("Null project");
045          }
046    
047        Javac javac = getJavac();
048    
049        if (javac == null)
050          {
051            throw new BuildException("null javac");
052          }
053    
054        super.attributes.log("Using escj compiler", 3);
055    
056        Path classpath = new Path(super.project);
057    
058        if (super.bootclasspath != null)
059          {
060            classpath.append(super.bootclasspath);
061          }
062    
063        classpath.addExtdirs(super.extdirs);
064    
065        if ((super.bootclasspath == null) || (super.bootclasspath.size() == 0))
066          {
067            super.includeJavaRuntime = true;
068          }
069    
070        classpath.append(getCompileClasspath());
071    
072        if (super.compileSourcepath != null)
073          {
074            classpath.append(super.compileSourcepath);
075          } else
076            {
077              classpath.append(super.src);
078            }
079    
080        Commandline cmd = new Commandline();
081        String exec = javac.getExecutable();
082        cmd.setExecutable((exec != null) ? exec : "java");
083    
084        String simplifyProperty = super.project.getProperty(
085                                                            "build.compiler.simplify");
086    
087        // Make sure the simplify argument comes before...
088        if (simplifyProperty != null)
089          {
090            cmd.createArgument().setValue("-Dsimplify=" + simplifyProperty);
091          }
092    
093        cmd.createArgument().setValue("-classpath");
094        cmd.createArgument().setPath(classpath);
095    
096        cmd.createArgument().setValue("escjava.Main");
097    
098        cmd.createArgument().setValue("-classpath");
099        cmd.createArgument().setPath(classpath);
100    
101        /*
102          if (super.deprecation)
103          {
104          cmd.createArgument().setValue("-deprecation");
105          }
106        */
107        /*
108          if (super.destDir != null)
109          {
110          cmd.createArgument().setValue("-d");
111          cmd.createArgument().setFile(super.destDir);
112          }
113        */
114        /*
115          if (super.encoding != null)
116          {
117          cmd.createArgument().setValue("-encoding");
118          cmd.createArgument().setValue(super.encoding);
119          }
120        */
121        /*
122          if (super.debug)
123          {
124          cmd.createArgument().setValue("-g");
125          }
126        */
127        /*
128          if (super.optimize)
129          {
130          cmd.createArgument().setValue("-O");
131          }
132        */
133        setCounterExample(cmd);
134        setDepend(cmd);
135        setEajava(cmd);
136        setEajml(cmd);
137        setEnableAssertions(cmd);
138        setLoopsafe(cmd);
139        setLoop(cmd);
140        setNoCheck(cmd);
141        setNoCautions(cmd);
142        setNoRedundancy(cmd);
143        setNoTrace(cmd);
144        setNoWarn(cmd);
145        setPxLog(cmd);
146        setPlainWarning(cmd);
147        setQuiet(cmd);
148        setRoutine(cmd);
149        setRoutineIndirect(cmd);
150        setSource(cmd);
151        setSourcePath(cmd);
152        setSuggest(cmd);
153        setSxLog(cmd);
154        setTarget(cmd);
155        setTypeCheck(cmd);
156        setUseVars(cmd);
157        setUseFcns(cmd);
158        setUseVarsForModelVars(cmd);
159        setUseFcnsForModelVars(cmd);
160        setWarn(cmd);
161        setVerbose(cmd);
162    
163        // Set the -f value to use the files following.
164        cmd.createArgument().setValue("-f");
165    
166        addCurrentCompilerArgs(cmd);
167    
168        int firstFileName = cmd.size();
169        logAndAddFilesToCompile(cmd);
170    
171        return executeExternalCompile(cmd.getCommandline(), firstFileName) == 0;
172      }
173    
174      /**
175       * @param cmd
176       */
177      private void setUseFcnsForModelVars(/*@ non_null @*/ Commandline cmd) throws BuildException
178      {
179        setTextArgument(cmd, "usefcnsformodelvars", "useFcnsForModelVars");
180      }
181    
182      /**
183       * @param cmd
184       */
185      private void setUseVarsForModelVars(/*@ non_null @*/ Commandline cmd) throws BuildException
186      {
187        setTextArgument(cmd, "usevarsformodelvars", "useVarsForModelVars");
188      }
189    
190      /**
191       * @param cmd
192       */
193      private void setWarn(/*@ non_null @*/ Commandline cmd) throws BuildException
194      {
195        setTextArgument(cmd, "warn", "warn");
196      }
197    
198      /**
199       * @param cmd
200       */
201      private void setUseFcns(/*@ non_null @*/ Commandline cmd) throws BuildException
202      {
203        setArgument(cmd, "usefcns", "useFcns");
204      }
205    
206      /**
207       * @param cmd
208       */
209      private void setRoutineIndirect(/*@ non_null @*/ Commandline cmd) throws BuildException
210      {
211        setTextArgument(cmd, "routineindirect", "routineIndirect");
212      }
213    
214      /**
215       * @param cmd
216       */
217      private void setPlainWarning(/*@ non_null @*/ Commandline cmd) throws BuildException
218      {
219        setArgument(cmd, "plainwarning", "plainwarning");
220      }
221    
222      /**
223       * @param cmd
224       */
225      private void setRoutine(/*@ non_null @*/ Commandline cmd) throws BuildException
226      {
227        String arg = "routine";
228        setTextArgument(cmd, arg, arg);
229      }
230    
231      /**
232       * @param cmd
233       */
234      private void setLoop(/*@ non_null @*/ Commandline cmd) throws BuildException
235      {
236        String arg = "loop";
237        setTextArgument(cmd, arg, arg);
238      }
239    
240      /**
241       * Sets the -quiet option.
242       *
243       * @param cmd
244       */
245      private void setQuiet(/*@ non_null @*/ Commandline cmd) throws BuildException
246      {
247        String arg = "quiet";
248        setArgument(cmd, arg, arg);
249      }
250    
251      private void setVerbose(/*@ non_null @*/ Commandline cmd)
252      {
253        if (super.verbose)
254          {
255            cmd.createArgument().setValue("-v");
256          }
257      }
258    
259      private void setDepend(/*@ non_null @*/ Commandline cmd)
260      {
261        if (super.depend)
262          {
263            cmd.createArgument().setValue("-depend");
264          }
265      }
266    
267      private void setTarget(/*@ non_null @*/ Commandline cmd)
268      {
269        if (super.target != null)
270          {
271            cmd.createArgument().setValue("-target");
272            cmd.createArgument().setValue(super.target);
273          }
274      }
275    
276      private void setNoWarn(/*@ non_null @*/ Commandline cmd) throws BuildException
277      {
278        if (super.attributes == null)
279          {
280            throw new BuildException("Null attributes");
281          }
282    
283        if (super.attributes.getNowarn())
284          {
285            cmd.createArgument().setValue("-nowarn");
286          }
287      }
288    
289      private void setSource(/*@ non_null @*/ Commandline cmd) throws BuildException
290      {
291        if (super.attributes == null)
292          {
293            throw new BuildException("Null attributes");
294          }
295    
296        if (super.attributes.getSource() != null)
297          {
298            cmd.createArgument().setValue("-source");
299            cmd.createArgument().setValue(super.attributes.getSource());
300          }
301      }
302    
303      private void setSourcePath(/*@ non_null @*/ Commandline cmd) throws BuildException
304      {
305        if (super.attributes == null)
306          {
307            throw new BuildException("Null attributes");
308          }
309    
310        if (super.attributes.getSourcepath() != null)
311          {
312            cmd.createArgument().setValue("-sourcepath");
313    
314            Path path = super.attributes.getSourcepath();
315            String pathString = (path == null) ? null : path.toString();
316            cmd.createArgument().setValue(pathString);
317          }
318      }
319    
320      private void setSxLog(/*@ non_null @*/ Commandline cmd) throws BuildException
321      {
322        setTextArgument(cmd, "sxlog", "sxLog");
323      }
324    
325      private void setPxLog(/*@ non_null @*/ Commandline cmd) throws BuildException
326      {
327        setTextArgument(cmd, "pxlog", "pxLog");
328      }
329    
330      private void setCounterExample(/*@ non_null @*/ Commandline cmd) throws BuildException
331      {
332        String arg = "counterexample";
333        setArgument(cmd, arg, arg);
334      }
335    
336      private void setEajava(/*@ non_null @*/ Commandline cmd) throws BuildException
337      {
338        String arg = "eajava";
339        setArgument(cmd, arg, arg);
340      }
341    
342      private void setEajml(/*@ non_null @*/ Commandline cmd) throws BuildException
343      {
344        String arg = "eajml";
345        setArgument(cmd, arg, arg);
346      }
347    
348      private void setEnableAssertions(/*@ non_null @*/ Commandline cmd) throws BuildException
349      {
350        String arg = "enableassertions";
351        setArgument(cmd, arg, arg);
352      }
353    
354      private void setUseVars(/*@ non_null @*/ Commandline cmd) throws BuildException
355      {
356        String arg = "usevars";
357        setArgument(cmd, arg, "useVars");
358      }
359    
360      private void setTypeCheck(/*@ non_null @*/ Commandline cmd) throws BuildException
361      {
362        String arg = "typecheck";
363        setArgument(cmd, arg, arg);
364      }
365    
366      private void setSuggest(/*@ non_null @*/ Commandline cmd) throws BuildException
367      {
368        String arg = "suggest";
369        setArgument(cmd, arg, arg);
370      }
371    
372      private void setNoTrace(/*@ non_null @*/ Commandline cmd) throws BuildException
373      {
374        String arg = "notrace";
375        setArgument(cmd, arg, arg);
376      }
377    
378      private void setNoRedundancy(/*@ non_null @*/ Commandline cmd) throws BuildException
379      {
380        String arg = "noredundancy";
381        setArgument(cmd, arg, arg);
382      }
383    
384      private void setNoCautions(/*@ non_null @*/ Commandline cmd) throws BuildException
385      {
386        String arg = "nocautions";
387        setArgument(cmd, arg, "noCautions");
388      }
389    
390      private void setNoCheck(/*@ non_null @*/ Commandline cmd) throws BuildException
391      {
392        String arg = "nocheck";
393        setArgument(cmd, arg, arg);
394      }
395    
396      private void setLoopsafe(/*@ non_null @*/ Commandline cmd) throws BuildException
397      {
398        String arg = "loopsafe";
399        setArgument(cmd, arg, arg);
400      }
401    
402      /**
403       * Do the compile with the specified arguments.
404       *
405       * @param args - arguments to pass to process on command line
406       * @param firstFileName - index of the first source file in args, if the
407       *        index is negative, no temporary file will ever be created, but
408       *        this may hit the command line length limit on your system.
409       * @param quoteFiles - if set to true, filenames containing spaces will be
410       *        quoted when they appear in the external file. This is necessary
411       *        when running JDK 1.4's javac and probably others.
412       *
413       * @return DOCUMENT ME!
414       *
415       * @throws BuildException DOCUMENT ME!
416       *
417       * @since Ant 1.6
418       */
419      //@ also
420      //@   requires args != null;
421      protected int executeExternalCompile(String[] args,
422                                           int firstFileName,
423                                           boolean quoteFiles)
424      {
425        String[] commandArray = null;
426        File tmpFile = null;
427    
428        try
429          {
430          
431            /*
432             * Many system have been reported to get into trouble with
433             * long command lines - no, not only Windows ;-).
434             *
435             * POSIX seems to define a lower limit of 4k, so use a temporary
436             * file if the total length of the command line exceeds this limit.
437             */
438            if ((Commandline.toString(args).length() > 4096) && (firstFileName >= 0))
439              {
440                PrintWriter out = null;
441    
442                try
443                  {
444                    File userDir = getJavac().getTempdir();
445    
446                    if (userDir == null)
447                      {
448                        String userDirName = System.getProperty("user.dir");
449                        userDir = new File(userDirName);
450                      }
451    
452                    tmpFile = fileUtils.createTempFile("files", "", userDir);
453                    tmpFile.deleteOnExit();
454                    out = new PrintWriter(new FileWriter(tmpFile));
455    
456                    for (int i = firstFileName; i < args.length; i++)
457                      {
458                        if (quoteFiles && (args[i].indexOf(" ") > -1))
459                          {
460                            args[i] = args[i].replace('\\', '/');
461                            out.println("\"" + args[i] + "\"");
462                          } else
463                            {
464                              out.println(args[i]);
465                            }
466                      }
467    
468                    out.flush();
469                    commandArray = new String[firstFileName + 1];
470                    System.arraycopy(args, 0, commandArray, 0, firstFileName);
471                    commandArray[firstFileName] = tmpFile.toString();
472                  } catch (IOException e)
473                    {
474                      throw new BuildException("Error creating temporary file",
475                                               e, location);
476                    } finally
477                      {
478                        if (out != null)
479                          {
480                            try
481                              {
482                                out.close();
483                              } catch (Throwable t)
484                                {
485                                  // ignore
486                                }
487                          }
488                      }
489              } else
490                {
491                  commandArray = args;
492                }
493    
494            try
495              {
496                Execute exe = new Execute(new LogStreamHandler(attributes,
497                                                               Project.MSG_INFO, Project.MSG_WARN));
498                exe.setAntRun(project);
499                exe.setWorkingDirectory(project.getBaseDir());
500                exe.setCommandline(commandArray);
501                exe.execute();
502    
503                return exe.getExitValue();
504              } catch (IOException e)
505                {
506                  throw new BuildException("Error running " + args[0] +
507                                           " compiler", e, location);
508                }
509          } finally
510            {
511              if (tmpFile != null)
512                {
513                  tmpFile.delete();
514                }
515            }
516      }
517    
518      /**
519       * Sets an argument with a text value from a property.
520       *
521       * @param cmd
522       * @param pPropertyName
523       * @param pArgumentName
524       *
525       * @throws BuildException if one of the arguments is null.
526       */
527      private void setTextArgument(/*@ non_null @*/ Commandline cmd,
528                                   /*@ non_null @*/ String pPropertyName,
529                                   /*@ non_null @*/ String pArgumentName) throws BuildException
530      {
531        if (cmd == null)
532          {
533            throw new BuildException("null cmd");
534          }
535    
536        if (pPropertyName == null)
537          {
538            throw new BuildException("null pName");
539          }
540    
541        if (pArgumentName == null)
542          {
543            throw new BuildException("null pArgument");
544          }
545            
546        if (super.project == null)
547          {
548            throw new BuildException("null project");
549          }
550    
551        String propertyValue = super.project.getProperty("build.compiler." +
552                                                         pPropertyName);
553    
554        if (propertyValue != null)
555          {
556            cmd.createArgument().setValue("-" + pArgumentName + "=" +
557                                          propertyValue);
558          }
559      }
560    
561      /**
562       * Sets an argument on the commandline from a boolean property.
563       *
564       * @param cmd
565       * @param pPropertyName
566       * @param pArgumentName
567       *
568       * @throws BuildException DOCUMENT ME!
569       */
570      private void setArgument(/*@ non_null @*/ Commandline cmd,
571                               /*@ non_null @*/ String pPropertyName,
572                               /*@ non_null @*/ String pArgumentName) throws BuildException
573      {
574        if (cmd == null)
575          {
576            throw new BuildException("null cmd");
577          }
578    
579        if (pPropertyName == null)
580          {
581            throw new BuildException("null pName");
582          }
583    
584        if (pArgumentName == null)
585          {
586            throw new BuildException("null pArgument");
587          }
588            
589        if (super.project == null)
590          {
591            throw new BuildException("null super.project");
592          }
593    
594        String propertyName = super.project.getProperty("build.compiler." +
595                                                        pPropertyName);
596    
597        if ((propertyName != null) && Project.toBoolean(propertyName))
598          {
599            cmd.createArgument().setValue("-" + pArgumentName);
600          }
601      }
602    }