001 /* 002 Copyright (c) 2009 Olivier Chafik, All Rights Reserved 003 004 This file is part of JNAerator (http://jnaerator.googlecode.com/). 005 006 JNAerator is free software: you can redistribute it and/or modify 007 it under the terms of the GNU General Public License as published by 008 the Free Software Foundation, either version 3 of the License, or 009 (at your option) any later version. 010 011 JNAerator is distributed in the hope that it will be useful, 012 but WITHOUT ANY WARRANTY; without even the implied warranty of 013 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 014 GNU General Public License for more details. 015 016 You should have received a copy of the GNU General Public License 017 along with JNAerator. If not, see <http://www.gnu.org/licenses/>. 018 */ 019 package com.ochafik.lang.compiler; 020 021 import java.util.*; 022 import java.util.regex.Pattern; 023 import java.io.*; 024 import java.net.MalformedURLException; 025 import java.net.URL; 026 import java.net.URLConnection; 027 import java.net.URLDecoder; 028 029 import javax.tools.*; 030 import javax.tools.Diagnostic.Kind; 031 032 import com.ochafik.io.IOUtils; 033 import com.ochafik.util.listenable.Adapter; 034 import com.ochafik.util.string.RegexUtils; 035 import com.ochafik.util.string.StringUtils; 036 037 public class CompilerUtils { 038 039 public static String getClassPath(Class<?> c, File cacheDirectory) throws MalformedURLException, IOException { 040 041 URL resource = c.getResource(c.getSimpleName() + ".class"); 042 if (resource != null) { 043 String resstr = resource.toString(); 044 // if (resstr.contains("Prog/")) 045 // resstr = "jar:http://ochafik.free.fr/Java/jnaerator.jar!/..."; 046 047 if (resstr.matches("jar:.*!.*")) 048 resstr = resstr.substring("jar:".length(), resstr.indexOf("!")); 049 else { 050 String p = '/' + c.getName().replace('.', '/') + ".class"; 051 if (resstr.endsWith(p)) 052 resstr = resstr.substring(0, resstr.length() - p.length()); 053 } 054 return getLocalFile(new URL(resstr), cacheDirectory).toString(); 055 } 056 /* 057 if (resource != null) { 058 String resstr = resource.toString(); 059 if (resstr.matches("jar:file:.*!.*")) 060 return resstr.substring("jar:file:".length(), resstr.indexOf("!")); 061 else if (resstr.matches("jar:http:.*!.*")) 062 return resstr.substring("jar:".length(), resstr.indexOf("!")); 063 else { 064 String p = '/' + c.getName().replace('.', '/') + ".class"; 065 if (resstr.endsWith(p)) 066 return resstr.substring(0, resstr.length() - p.length()); 067 } 068 }*/ 069 return null; 070 } 071 public static Set<String> getClassPaths(File cacheDirectory, Class<?>... cs) throws MalformedURLException, IOException { 072 Set<String> ret = new TreeSet<String>(); 073 for (Class<?> c : cs) { 074 String cp ; 075 if (c == null || (cp = getClassPath(c, cacheDirectory)) == null) 076 continue; 077 ret.add(cp); 078 } 079 return ret; 080 } 081 static Map<String, File> localURLCaches = new HashMap<String, File>(); 082 static File getLocalFile(URL remoteFile, File cacheDirectory) throws IOException { 083 if ("file".equals(remoteFile.getProtocol())) 084 return new File(URLDecoder.decode(remoteFile.getFile(), "utf-8")); 085 086 String remoteStr = remoteFile.toString(); 087 File f = localURLCaches.get(remoteStr); 088 if (f == null) { 089 String fileName = new File(remoteStr).getName(); 090 URLConnection con = null; 091 try { 092 con = remoteFile.openConnection(); 093 } catch (IOException ex) { 094 ex.printStackTrace(); 095 } 096 if (cacheDirectory != null) { 097 f = new File(cacheDirectory, fileName); 098 if (f.exists() && (con == null || f.lastModified() > con.getLastModified())) { 099 System.out.println("Reusing cached file " + f); 100 if (con != null) 101 con.getInputStream().close(); 102 return f; 103 } 104 } else { 105 f = File.createTempFile(fileName, ".jar"); 106 f.deleteOnExit(); 107 } 108 System.out.print("Downloading file " + remoteFile + " to " + f); 109 110 InputStream in = new BufferedInputStream(remoteFile.openStream()); 111 try { 112 OutputStream out = new BufferedOutputStream(new FileOutputStream(f)); 113 try { 114 //System.out.print("Downloading file '" + remoteStr + "'..."); 115 long length = IOUtils.readWrite(in, out); 116 System.out.println(" OK (" + length + " bytes)"); 117 localURLCaches.put(remoteStr, f.getAbsoluteFile()); 118 } finally { 119 out.close(); 120 } 121 } finally { 122 in.close(); 123 } 124 } 125 return f; 126 } 127 public static void compile(JavaCompiler compiler, MemoryFileManager fileManager, DiagnosticCollector<JavaFileObject> diagnostics, String sourceCompatibility, File cacheDirectory, Class<?>...classpathHints) throws MalformedURLException, IOException { 128 //JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); 129 System.out.println("compiler = " + (compiler == null ? "<none found>" : compiler.getClass().getName())); 130 Set<String> bootclasspaths = getClassPaths(cacheDirectory, classpathHints); 131 bootclasspaths.addAll(getClassPaths(cacheDirectory, String.class)); 132 String bootclasspath = StringUtils.implode(bootclasspaths, File.pathSeparator); 133 System.out.println("bootclasspath = " + bootclasspath); 134 Iterable<? extends JavaFileObject> fileObjects = fileManager.getJavaFileObjects(); 135 List<String> options = sourceCompatibility == null ? null : Arrays.asList( 136 "-target", sourceCompatibility, 137 "-source", sourceCompatibility, 138 "-bootclasspath", bootclasspath, //"/System/Library/Frameworks/JavaVM.framework/Versions/1.6.0/Classes/classes.jar",//bootclasspath, 139 "-classpath", bootclasspath //"/Users/ochafik/Prog/Java/bin/jnaerator.jar"// 140 //"http://ochafik.free.fr/Java/jnaerator.jar"//bootclasspath 141 ); 142 // DebugUtils.println(fileManager.inputs.values()); 143 compiler.getTask(null, fileManager, diagnostics, options, null, fileObjects).call(); 144 145 // for (final Diagnostic<? extends JavaFileObject> diagnostic : diagnostics.getDiagnostics()) { 146 // if (diagnostic == null) 147 // continue; 148 // //diagnostic.getKind() 149 // //System.out.format("Error on line %d in %d%n", diagnostic.getLineNumber(), diagnostic.getSource());//.toUri()); 150 // if (diagnostic.getKind() == Kind.ERROR) { 151 // System.err.println("\n" + diagnostic.getSource().toUri() + ":"); 152 // System.err.println(RegexUtils.regexReplace(Pattern.compile("\n"), "\n" + diagnostic.getSource().getCharContent(true), new Adapter<String[], String>() { 153 // int line = 0; 154 // 155 // @Override 156 // public String adapt(String[] value) { 157 // line++; 158 // return "\n" + line + ":" + (diagnostic.getLineNumber() == line ? ">>>" : "") +"\t\t"; 159 // } 160 // })); 161 // } 162 //// System.out.println("Error on line " + diagnostic.getLineNumber() + ":" + diagnostic.getColumnNumber() + " in " + (diagnostic.getSource() == null ? "<unknown source>" : diagnostic.getSource().getName()) + ": " + diagnostic.getMessage(Locale.getDefault())); 163 // } 164 } 165 166 public static JavaCompiler getJavaCompiler(boolean preferJavac) throws FileNotFoundException { 167 JavaCompiler compiler; 168 if (preferJavac) { 169 compiler = ToolProvider.getSystemJavaCompiler(); 170 if (compiler != null) 171 return compiler; 172 } 173 try { 174 compiler = (JavaCompiler)Class.forName("org.eclipse.jdt.internal.compiler.tool.EclipseCompiler").newInstance(); 175 } catch (Exception e) { 176 compiler = ToolProvider.getSystemJavaCompiler(); 177 if (compiler == null) 178 throw new FileNotFoundException("No Java compiler found (not run from JDK, no Eclipse Compiler in classpath)"); 179 } 180 return compiler; 181 } 182 public static void main2(String[] args) { 183 try { 184 String jarOut = args.length == 0 ? "out.jar" : args[0]; 185 186 JavaCompiler compiler = getJavaCompiler(false); 187 188 DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<JavaFileObject>(); 189 MemoryFileManager fileManager = new MemoryFileManager(compiler.getStandardFileManager(diagnostics, null, null)); 190 fileManager.addSourceInput("test/Main.java", "package test; public class Main { }"); 191 fileManager.close(); 192 193 compile(compiler, fileManager, diagnostics, null, null); 194 for (Diagnostic<? extends JavaFileObject> diagnostic : diagnostics.getDiagnostics()) { 195 //diagnostic.getKind() 196 //System.out.format("Error on line %d in %d%n", diagnostic.getLineNumber(), diagnostic.getSource());//.toUri()); 197 System.out.format("Error on line " + diagnostic.getLineNumber() + ":" + diagnostic.getLineNumber() + " in " + diagnostic.getSource());//.toUri()); 198 } 199 200 boolean outputSources = true; 201 System.out.println("Writing " + jarOut + (outputSources ? " with" : " without") + " sources"); 202 fileManager.writeJar(new FileOutputStream(jarOut), outputSources, null); 203 204 } catch (IOException ex) { 205 ex.printStackTrace(); 206 } 207 } 208 } 209