/** Specify which classes are visible to the compiler through -classpath. */
 public void setVisibleClasses(Map<String, Source> vs) {
   visibleSrcs = new HashSet<>();
   for (String s : vs.keySet()) {
     Source src = vs.get(s);
     visibleSrcs.add(src.file().toURI());
   }
 }
 /** Store the source into the set of sources belonging to the given transform. */
 private void addFileToTransform(
     Map<Transformer, Map<String, Set<URI>>> gs, Transformer t, Source s) {
   Map<String, Set<URI>> fs = gs.get(t);
   if (fs == null) {
     fs = new HashMap<>();
     gs.put(t, fs);
   }
   Set<URI> ss = fs.get(s.pkg().name());
   if (ss == null) {
     ss = new HashSet<>();
     fs.put(s.pkg().name(), ss);
   }
   ss.add(s.file().toURI());
 }
  /**
   * Compare the calculate source list, with an explicit list, usually supplied from the makefile.
   * Used to detect bugs where the makefile and sjavac have different opinions on which files should
   * be compiled.
   */
  public void compareWithMakefileList(File makefileSourceList) throws ProblemException {
    // If we are building on win32 using for example cygwin the paths in the makefile source list
    // might be /cygdrive/c/.... which does not match c:\....
    // We need to adjust our calculated sources to be identical, if necessary.
    boolean mightNeedRewriting = File.pathSeparatorChar == ';';

    if (makefileSourceList == null) return;

    Set<String> calculatedSources = new HashSet<>();
    Set<String> listedSources = new HashSet<>();

    // Create a set of filenames with full paths.
    for (Source s : now.sources().values()) {
      // Don't include link only sources when comparing sources to compile
      if (!s.isLinkedOnly()) {
        calculatedSources.add(s.file().getPath());
      }
    }
    // Read in the file and create another set of filenames with full paths.
    try {
      BufferedReader in = new BufferedReader(new FileReader(makefileSourceList));
      for (; ; ) {
        String l = in.readLine();
        if (l == null) break;
        l = l.trim();
        if (mightNeedRewriting) {
          if (l.indexOf(":") == 1 && l.indexOf("\\") == 2) {
            // Everything a-ok, the format is already C:\foo\bar
          } else if (l.indexOf(":") == 1 && l.indexOf("/") == 2) {
            // The format is C:/foo/bar, rewrite into the above format.
            l = l.replaceAll("/", "\\\\");
          } else if (l.charAt(0) == '/' && l.indexOf("/", 1) != -1) {
            // The format might be: /cygdrive/c/foo/bar, rewrite into the above format.
            // Do not hardcode the name cygdrive here.
            int slash = l.indexOf("/", 1);
            l = l.replaceAll("/", "\\\\");
            l = "" + l.charAt(slash + 1) + ":" + l.substring(slash + 2);
          }
          if (Character.isLowerCase(l.charAt(0))) {
            l = Character.toUpperCase(l.charAt(0)) + l.substring(1);
          }
        }
        listedSources.add(l);
      }
    } catch (FileNotFoundException e) {
      throw new ProblemException(
          "Could not open " + makefileSourceList.getPath() + " since it does not exist!");
    } catch (IOException e) {
      throw new ProblemException("Could not read " + makefileSourceList.getPath());
    }

    for (String s : listedSources) {
      if (!calculatedSources.contains(s)) {
        throw new ProblemException(
            "The makefile listed source " + s + " was not calculated by the smart javac wrapper!");
      }
    }

    for (String s : calculatedSources) {
      if (!listedSources.contains(s)) {
        throw new ProblemException(
            "The smart javac wrapper calculated source " + s + " was not listed by the makefiles!");
      }
    }
  }