Home | History | Annotate | Download | only in ant
      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 
     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
     65         public String getSourceFileExtension() {
     66             return "rs";
     67         }
     68 
     69         @Override
     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
    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 
    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      */
    162     public void setExecutable(Path executable) {
    163         mExecutable = TaskHelper.checkSinglePath("executable", executable);
    164     }
    165 
    166     public void setIncludePath(Path value) {
    167         mIncludePath = value;
    168     }
    169 
    170     public void setGenFolder(Path value) {
    171         mGenFolder = TaskHelper.checkSinglePath("genFolder", value);
    172     }
    173 
    174     public void setResFolder(Path value) {
    175         mResFolder = TaskHelper.checkSinglePath("resFolder", value);
    176     }
    177 
    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 
    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
    195     public void setBuildType(String buildType) {
    196         super.setBuildType(buildType);
    197         mDebug = Boolean.valueOf(buildType);
    198     }
    199 
    200     public Path createSource() {
    201         Path p = new Path(getProject());
    202         mPaths.add(p);
    203         return p;
    204     }
    205 
    206     @Override
    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