1 /* 2 * Copyright (C) 2010, 2012 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 com.android.ant; 18 19 import org.apache.tools.ant.BuildException; 20 import org.apache.tools.ant.Project; 21 import org.apache.tools.ant.taskdefs.ExecTask; 22 import org.apache.tools.ant.types.Path; 23 24 import java.io.File; 25 import java.util.ArrayList; 26 import java.util.List; 27 28 /** 29 * Task to execute renderscript. 30 * <p> 31 * It expects 7 attributes:<br> 32 * 'executable' ({@link Path} with a single path) for the location of the llvm executable<br> 33 * 'framework' ({@link Path} with 1 or more paths) for the include paths.<br> 34 * 'genFolder' ({@link Path} with a single path) for the location of the gen folder.<br> 35 * 'resFolder' ({@link Path} with a single path) for the location of the res folder.<br> 36 * 'targetApi' for the -target-api value.<br> 37 * 'optLevel' for the -O optimization level.<br> 38 * 'debug' for -g renderscript debugging.<br> 39 * <p> 40 * It also expects one or more inner elements called "source" which are identical to {@link Path} 41 * elements for where to find .rs files. 42 */ 43 public class RenderScriptTask extends MultiFilesTask { 44 45 private String mExecutable; 46 private Path mIncludePath; 47 private String mGenFolder; 48 private String mResFolder; 49 private final List<Path> mPaths = new ArrayList<Path>(); 50 private int mTargetApi = 0; 51 public enum OptLevel { O0, O1, O2, O3 }; 52 private OptLevel mOptLevel; 53 private boolean mDebug = false; 54 55 private class RenderScriptProcessor implements SourceProcessor { 56 57 private final String mTargetApiStr; 58 RenderScriptProcessor(int targetApi)59 public RenderScriptProcessor(int targetApi) { 60 // get the target api value. Must be 11+ or llvm-rs-cc complains. 61 mTargetApiStr = Integer.toString(mTargetApi < 11 ? 11 : mTargetApi); 62 } 63 64 @Override getSourceFileExtension()65 public String getSourceFileExtension() { 66 return "rs"; 67 } 68 69 @Override process(String filePath, String sourceFolder, List<String> sourceFolders, Project taskProject)70 public void process(String filePath, String sourceFolder, List<String> sourceFolders, 71 Project taskProject) { 72 File exe = new File(mExecutable); 73 String execTaskName = exe.getName(); 74 75 ExecTask task = new ExecTask(); 76 task.setTaskName(execTaskName); 77 task.setProject(taskProject); 78 task.setOwningTarget(getOwningTarget()); 79 task.setExecutable(mExecutable); 80 task.setFailonerror(true); 81 82 for (String path : mIncludePath.list()) { 83 File res = new File(path); 84 if (res.isDirectory()) { 85 task.createArg().setValue("-I"); 86 task.createArg().setValue(path); 87 } else { 88 System.out.println(String.format( 89 "WARNING: RenderScript include directory '%s' does not exist!", 90 res.getAbsolutePath())); 91 } 92 93 } 94 95 if (mDebug) { 96 task.createArg().setValue("-g"); 97 } 98 99 task.createArg().setValue("-O"); 100 task.createArg().setValue(Integer.toString(mOptLevel.ordinal())); 101 102 task.createArg().setValue("-target-api"); 103 task.createArg().setValue(mTargetApiStr); 104 105 task.createArg().setValue("-d"); 106 task.createArg().setValue(getDependencyFolder(filePath, sourceFolder)); 107 task.createArg().setValue("-MD"); 108 109 task.createArg().setValue("-p"); 110 task.createArg().setValue(mGenFolder); 111 task.createArg().setValue("-o"); 112 task.createArg().setValue(mResFolder); 113 task.createArg().setValue(filePath); 114 115 // execute it. 116 task.execute(); 117 } 118 119 @Override displayMessage(DisplayType type, int count)120 public void displayMessage(DisplayType type, int count) { 121 switch (type) { 122 case FOUND: 123 System.out.println(String.format("Found %1$d RenderScript files.", count)); 124 break; 125 case COMPILING: 126 if (count > 0) { 127 System.out.println(String.format( 128 "Compiling %1$d RenderScript files with -target-api %2$d", 129 count, mTargetApi)); 130 System.out.println(String.format("Optimization Level: %1$d", mOptLevel.ordinal())); 131 } else { 132 System.out.println("No RenderScript files to compile."); 133 } 134 break; 135 case REMOVE_OUTPUT: 136 System.out.println(String.format("Found %1$d obsolete output files to remove.", 137 count)); 138 break; 139 case REMOVE_DEP: 140 System.out.println( 141 String.format("Found %1$d obsolete dependency files to remove.", 142 count)); 143 break; 144 } 145 } 146 getDependencyFolder(String filePath, String sourceFolder)147 private String getDependencyFolder(String filePath, String sourceFolder) { 148 String relative = filePath.substring(sourceFolder.length()); 149 if (relative.charAt(0) == '/') { 150 relative = relative.substring(1); 151 } 152 153 return new File(mGenFolder, relative).getParent(); 154 } 155 } 156 157 158 /** 159 * Sets the value of the "executable" attribute. 160 * @param executable the value. 161 */ setExecutable(Path executable)162 public void setExecutable(Path executable) { 163 mExecutable = TaskHelper.checkSinglePath("executable", executable); 164 } 165 setIncludePath(Path value)166 public void setIncludePath(Path value) { 167 mIncludePath = value; 168 } 169 setGenFolder(Path value)170 public void setGenFolder(Path value) { 171 mGenFolder = TaskHelper.checkSinglePath("genFolder", value); 172 } 173 setResFolder(Path value)174 public void setResFolder(Path value) { 175 mResFolder = TaskHelper.checkSinglePath("resFolder", value); 176 } 177 setTargetApi(String targetApi)178 public void setTargetApi(String targetApi) { 179 try { 180 mTargetApi = Integer.parseInt(targetApi); 181 if (mTargetApi <= 0) { 182 throw new BuildException("targetApi attribute value must be >= 1"); 183 } 184 } catch (NumberFormatException e) { 185 throw new BuildException("targetApi attribute value must be an integer", e); 186 } 187 } 188 setOptLevel(OptLevel optLevel)189 public void setOptLevel(OptLevel optLevel) { 190 mOptLevel = optLevel; 191 } 192 193 /** Sets the current build type. value is a boolean, true for debug build, false for release */ 194 @Override setBuildType(String buildType)195 public void setBuildType(String buildType) { 196 super.setBuildType(buildType); 197 mDebug = Boolean.valueOf(buildType); 198 } 199 createSource()200 public Path createSource() { 201 Path p = new Path(getProject()); 202 mPaths.add(p); 203 return p; 204 } 205 206 @Override execute()207 public void execute() throws BuildException { 208 if (mExecutable == null) { 209 throw new BuildException("RenderScriptTask's 'executable' is required."); 210 } 211 if (mIncludePath == null) { 212 throw new BuildException("RenderScriptTask's 'includePath' is required."); 213 } 214 if (mGenFolder == null) { 215 throw new BuildException("RenderScriptTask's 'genFolder' is required."); 216 } 217 if (mResFolder == null) { 218 throw new BuildException("RenderScriptTask's 'resFolder' is required."); 219 } 220 if (mTargetApi == 0) { 221 throw new BuildException("RenderScriptTask's 'targetApi' is required."); 222 } 223 224 processFiles(new RenderScriptProcessor(mTargetApi), mPaths, mGenFolder); 225 } 226 } 227