1 /* 2 * Copyright (C) 2013 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package util.build; 18 19 import java.io.File; 20 import java.io.FileWriter; 21 import java.io.IOException; 22 import java.io.Writer; 23 import java.util.ArrayList; 24 import java.util.HashSet; 25 import java.util.List; 26 import java.util.Set; 27 28 public class JackBuildStep extends SourceBuildStep { 29 30 private final String destPath; 31 private final String classPath; 32 private final Set<String> sourceFiles = new HashSet<String>(); 33 34 public JackBuildStep(String destPath, String classPath) { 35 super(new File(destPath)); 36 this.destPath = destPath; 37 this.classPath = classPath; 38 } 39 40 @Override 41 public void addSourceFile(String sourceFile) { 42 sourceFiles.add(sourceFile); 43 } 44 45 @Override 46 boolean build() { 47 if (super.build()) { 48 if (sourceFiles.isEmpty()) { 49 return true; 50 } 51 52 File outDir = new File(destPath).getParentFile(); 53 if (!outDir.exists() && !outDir.mkdirs()) { 54 System.err.println("failed to create output dir: " 55 + outDir.getAbsolutePath()); 56 return false; 57 } 58 59 File tmpOutDir = new File(outDir, outputFile.fileName.getName() + ".dexTmp"); 60 if (!tmpOutDir.exists() && !tmpOutDir.mkdirs()) { 61 System.err.println("failed to create temp dir: " 62 + tmpOutDir.getAbsolutePath()); 63 return false; 64 } 65 File tmpDex = new File(tmpOutDir, "classes.dex"); 66 67 File tmpArgs = new File(outDir, outputFile.fileName.getName() + ".args"); 68 69 Writer argsOut = null; 70 try { 71 argsOut = new FileWriter(tmpArgs); 72 for (String source : sourceFiles) { 73 argsOut.append(source); 74 argsOut.append('\n'); 75 } 76 argsOut.close(); 77 argsOut = null; 78 79 List<String> commandLine = new ArrayList<String>(6 + sourceFiles.size()); 80 commandLine.add("--verbose"); 81 commandLine.add("error"); 82 commandLine.add("--classpath"); 83 commandLine.add(classPath); 84 commandLine.add("--output-dex"); 85 commandLine.add(tmpOutDir.getAbsolutePath()); 86 commandLine.add("@" + tmpArgs.getPath()); 87 88 ExecuteFile exec = new ExecuteFile(JackBuildDalvikSuite.JACK, 89 commandLine.toArray(new String[commandLine.size()])); 90 exec.setErr(System.err); 91 exec.setOut(System.out); 92 if (!exec.run()) { 93 return false; 94 } 95 96 JarBuildStep jarStep = new JarBuildStep( 97 new BuildFile(tmpDex), 98 "classes.dex", 99 outputFile, 100 /* deleteInputFileAfterBuild = */ true); 101 if (!jarStep.build()) { 102 throw new IOException("Failed to make jar: " + outputFile.getPath()); 103 } 104 return true; 105 } catch (Throwable ex) { 106 ex.printStackTrace(); 107 return false; 108 } finally { 109 tmpDex.delete(); 110 tmpArgs.delete(); 111 tmpOutDir.delete(); 112 if (argsOut != null) { 113 try { 114 argsOut.close(); 115 } catch (IOException io) { 116 // Ignore, don't override already thrown exception 117 } 118 } 119 } 120 } 121 return false; 122 } 123 124 @Override 125 public boolean equals(Object obj) { 126 if (super.equals(obj)) { 127 JackBuildStep other = (JackBuildStep) obj; 128 return destPath.equals(other.destPath) && classPath.equals(other.classPath) 129 && sourceFiles.equals(other.sourceFiles); 130 } 131 return false; 132 } 133 134 @Override 135 public int hashCode() { 136 return destPath.hashCode() ^ classPath.hashCode() ^ sourceFiles.hashCode(); 137 } 138 } 139