Ejemplo n.º 1
0
  /**
   * Process command line arguments: store all command line options in `options' table and return
   * all source filenames.
   *
   * @param args The array of command line arguments.
   */
  protected java.util.List<String> processArgs(String[] flags) {
    int ac = 0;
    while (ac < flags.length) {
      String flag = flags[ac];
      ac++;

      int j;
      for (j = 0; j < recognizedOptions.length; j++) if (recognizedOptions[j].matches(flag)) break;

      if (j == recognizedOptions.length) {
        error("err.invalid.flag", flag);
        return null;
      }

      Option option = recognizedOptions[j];
      if (option.hasArg()) {
        if (ac == flags.length) {
          error("err.req.arg", flag);
          return null;
        }
        String operand = flags[ac];
        ac++;
        if (option.process(flag, operand)) return null;
      } else {
        if (option.process(flag)) return null;
      }
    }

    String sourceString = options.get("-source");
    Source source =
        (sourceString != null)
            ? Source.lookup(sourceString)
            : Source.JDK1_5; // JDK 5 is the latest supported source version
    String targetString = options.get("-target");
    Target target =
        (targetString != null)
            ? Target.lookup(targetString)
            : Target.JDK1_5; // JDK 5 is the latest supported source version
    // We don't check source/target consistency for CLDC, as J2ME
    // profiles are not aligned with J2SE targets; moreover, a
    // single CLDC target may have many profiles.  In addition,
    // this is needed for the continued functioning of the JSR14
    // prototype.
    if (Character.isDigit(target.name.charAt(0)) && target.compareTo(source.requiredTarget()) < 0) {
      if (targetString != null) {
        if (sourceString == null) {
          warning(
              "warn.target.default.source.conflict", targetString, source.requiredTarget().name);
        } else {
          warning("warn.source.target.conflict", sourceString, source.requiredTarget().name);
        }
        return null;
      } else {
        options.put("-target", source.requiredTarget().name);
      }
    }
    return sourceFileNames;
  }
Ejemplo n.º 2
0
  /**
   * Programmatic interface for main function.
   *
   * @param args The command line parameters.
   */
  public int compile(String[] args, AnnotationProcessorFactory factory) {
    int returnCode = 0;
    providedFactory = factory;

    Context context = new Context();
    options = Options.instance(context);
    Bark bark;

    /*
     * Process the command line options to create the intial
     * options data.  This processing is at least partially reused
     * by any recursive apt calls.
     */

    // For testing: assume all arguments in forcedOpts are
    // prefixed to command line arguments.
    processArgs(forcedOpts);

    /*
     * A run of apt only gets passed the most recently generated
     * files; the initial run of apt gets passed the files from
     * the command line.
     */

    java.util.List<String> origFilenames;
    try {
      // assign args the result of parse to capture results of
      // '@file' expansion
      origFilenames = processArgs((args = CommandLine.parse(args)));
      if (origFilenames == null) {
        return EXIT_CMDERR;
      } else if (origFilenames.size() == 0) {
        // it is allowed to compile nothing if just asking for help
        if (options.get("-help") != null || options.get("-X") != null) return EXIT_OK;
      }
    } catch (java.io.FileNotFoundException e) {
      Bark.printLines(
          out, ownName + ": " + getLocalizedString("err.file.not.found", e.getMessage()));
      return EXIT_SYSERR;
    } catch (IOException ex) {
      ioMessage(ex);
      return EXIT_SYSERR;
    } catch (OutOfMemoryError ex) {
      resourceMessage(ex);
      return EXIT_SYSERR;
    } catch (StackOverflowError ex) {
      resourceMessage(ex);
      return EXIT_SYSERR;
    } catch (FatalError ex) {
      feMessage(ex);
      return EXIT_SYSERR;
    } catch (sun.misc.ServiceConfigurationError sce) {
      sceMessage(sce);
      return EXIT_ABNORMAL;
    } catch (Throwable ex) {
      bugMessage(ex);
      return EXIT_ABNORMAL;
    }

    boolean firstRound = true;
    boolean needSourcePath = false;
    boolean needClassPath = false;
    boolean classesAsDecls = options.get("-XclassesAsDecls") != null;

    /*
     * Create augumented classpath and sourcepath values.
     *
     * If any of the prior apt rounds generated any new source
     * files, the n'th apt round (and any javac invocation) has the
     * source destination path ("-s path") as the last element of
     * the "-sourcepath" to the n'th call.
     *
     * If any of the prior apt rounds generated any new class files,
     * the n'th apt round (and any javac invocation) has the class
     * destination path ("-d path") as the last element of the
     * "-classpath" to the n'th call.
     */
    String augmentedSourcePath = "";
    String augmentedClassPath = "";
    String baseClassPath = "";

    try {
      /*
       * Record original options for future annotation processor
       * invocations.
       */
      origOptions = new HashMap<String, String>(options.size());
      for (String s : options.keySet()) {
        String value;
        if (s.equals(value = options.get(s))) origOptions.put(s, (String) null);
        else origOptions.put(s, value);
      }
      origOptions = Collections.unmodifiableMap(origOptions);

      {
        // Note: it might be necessary to check for an empty
        // component ("") of the source path or class path
        Paths paths = Paths.instance(context);

        String sourceDest = options.get("-s");
        if (paths.sourcePath() != null) {
          for (File f : paths.sourcePath()) augmentedSourcePath += (f + File.pathSeparator);
          augmentedSourcePath += (sourceDest == null) ? "." : sourceDest;
        } else {
          augmentedSourcePath = ".";

          if (sourceDest != null) augmentedSourcePath += (File.pathSeparator + sourceDest);
        }

        String classDest = options.get("-d");
        if (paths.userClassPath() != null) {
          for (File f : paths.userClassPath()) baseClassPath += (f + File.pathSeparator);
          // put baseClassPath into map to handle any
          // value needed for the classloader
          options.put("-classpath", baseClassPath);

          augmentedClassPath = baseClassPath + ((classDest == null) ? "." : classDest);
        } else {
          baseClassPath = ".";
          if (classDest != null)
            augmentedClassPath = baseClassPath + (File.pathSeparator + classDest);
        }
        assert options.get("-classpath") != null;
      }

      /*
       * Create base and augmented class loaders
       */
      ClassLoader augmentedAptCL = null;
      {
        /*
         * Use a url class loader to look for classes on the
         * user-specified class path. Prepend computed bootclass
         * path, which includes extdirs, to the URLClassLoader apt
         * uses.
         */
        String aptclasspath = "";
        Paths paths = Paths.instance(context);
        String bcp = "";
        Collection<File> bootclasspath = paths.bootClassPath();

        if (bootclasspath != null) {
          for (File f : bootclasspath) bcp += (f + File.pathSeparator);
        }

        // If the factory path is set, use that path
        if (providedFactory == null) aptclasspath = options.get("-factorypath");
        if (aptclasspath == null) aptclasspath = options.get("-classpath");

        assert aptclasspath != null;
        aptclasspath = (bcp + aptclasspath);
        aptCL = new URLClassLoader(pathToURLs(aptclasspath));

        if (providedFactory == null
            && options.get("-factorypath") != null) // same CL even if new class files written
        augmentedAptCL = aptCL;
        else {
          // Create class loader in case new class files are
          // written
          augmentedAptCL =
              new URLClassLoader(
                  pathToURLs(augmentedClassPath.substring(baseClassPath.length())), aptCL);
        }
      }

      int round = 0; // For -XPrintAptRounds
      do {
        round++;

        Context newContext = new Context();
        Options newOptions = Options.instance(newContext); // creates a new context
        newOptions.putAll(options);

        // populate with old options... don't bother reparsing command line, etc.

        // if genSource files, must add destination to source path
        if (genSourceFileNames.size() > 0 && !firstRound) {
          newOptions.put("-sourcepath", augmentedSourcePath);
          needSourcePath = true;
        }
        aggregateGenSourceFileNames.addAll(genSourceFileNames);
        sourceFileNames.addAll(genSourceFileNames);
        genSourceFileNames.clear();

        // Don't really need to track this; just have to add -d
        // "foo" to class path if any class files are generated
        if (genClassFileNames.size() > 0) {
          newOptions.put("-classpath", augmentedClassPath);
          aptCL = augmentedAptCL;
          needClassPath = true;
        }
        aggregateGenClassFileNames.addAll(genClassFileNames);
        classFileNames.addAll(genClassFileNames);
        genClassFileNames.clear();

        options = newOptions;

        if (options.get("-XPrintAptRounds") != null) {
          out.println("apt Round : " + round);
          out.println("filenames: " + sourceFileNames);
          if (classesAsDecls) out.println("classnames: " + classFileNames);
          out.println("options: " + options);
        }

        returnCode = compile(args, newContext);
        firstRound = false;

        // Check for reported errors before continuing
        bark = Bark.instance(newContext);
      } while (((genSourceFileNames.size() != 0)
              || (classesAsDecls && genClassFileNames.size() != 0))
          && bark.nerrors == 0);
    } catch (UsageMessageNeededException umne) {
      help();
      return EXIT_CMDERR; // will cause usage message to be printed
    }

    /*
     * Do not compile if a processor has reported an error or if
     * there are no source files to process.  A more sophisticated
     * test would also fail for syntax errors caught by javac.
     */
    if (options.get("-nocompile") == null
        && options.get("-print") == null
        && bark.nerrors == 0
        && (origFilenames.size() > 0 || aggregateGenSourceFileNames.size() > 0)) {
      /*
       * Need to create new argument string for calling javac:
       * 1. apt specific arguments (e.g. -factory) must be stripped out
       * 2. proper settings for sourcepath and classpath must be used
       * 3. generated class names must be added
       * 4. class file names as declarations must be removed
       */

      int newArgsLength =
          args.length
              + (needSourcePath ? 1 : 0)
              + (needClassPath ? 1 : 0)
              + aggregateGenSourceFileNames.size();

      // Null out apt-specific options and don't copy over into
      // newArgs. This loop should be a lot faster; the options
      // array should be replaced with a better data structure
      // which includes a map from strings to options.
      //
      // If treating classes as declarations, must strip out
      // class names from the javac argument list
      argLoop:
      for (int i = 0; i < args.length; i++) {
        int matchPosition = -1;

        // "-A" by itself is recognized by apt but not javac
        if (args[i] != null && args[i].equals("-A")) {
          newArgsLength--;
          args[i] = null;
          continue argLoop;
        } else {
          optionLoop:
          for (int j = 0; j < recognizedOptions.length; j++) {
            if (args[i] != null && recognizedOptions[j].matches(args[i])) {
              matchPosition = j;
              break optionLoop;
            }
          }

          if (matchPosition != -1) {
            Option op = recognizedOptions[matchPosition];
            if (op.aptOnly) {
              newArgsLength--;
              args[i] = null;
              if (op.hasArg()) {
                newArgsLength--;
                args[i + 1] = null;
              }
            } else {
              if (op.hasArg()) { // skip over next string
                i++;
                continue argLoop;
              }

              if ((options.get("-XclassesAsDecls") != null)
                  && (matchPosition == (recognizedOptions.length - 1))) {
                // Remove class file names from
                // consideration by javac.
                if (!args[i].endsWith(".java")) {
                  newArgsLength--;
                  args[i] = null;
                }
              }
            }
          }
        }
      }

      String newArgs[] = new String[newArgsLength];

      int j = 0;
      for (int i = 0; i < args.length; i++) {
        if (args[i] != null) newArgs[j++] = args[i];
      }

      if (needClassPath) newArgs[j++] = "-XD-classpath=" + augmentedClassPath;

      if (needSourcePath) {
        newArgs[j++] = "-XD-sourcepath=" + augmentedSourcePath;

        for (String s : aggregateGenSourceFileNames) newArgs[j++] = s;
      }

      returnCode = com.sun.tools.javac.Main.compile(newArgs);
    }

    return returnCode;
  }