diff options
author | Xavier Ducrohet <xav@android.com> | 2011-10-10 17:53:21 -0700 |
---|---|---|
committer | Xavier Ducrohet <xav@android.com> | 2011-10-10 19:07:48 -0700 |
commit | b92742797f979667fad027e35e04efff6e7df0aa (patch) | |
tree | fb6130ebf6b12f21b4f3cefc5a36d9773f6b6395 /anttasks | |
parent | a6dc10887d24122fa8a9d8b590ac7eff2c36724c (diff) | |
download | sdk-b92742797f979667fad027e35e04efff6e7df0aa.zip sdk-b92742797f979667fad027e35e04efff6e7df0aa.tar.gz sdk-b92742797f979667fad027e35e04efff6e7df0aa.tar.bz2 |
Improved RenderScript support in SDK build.
- renderscript output is now in bin/res/ instead of res/
- Ant build system properly handle dependencies to only recompile
files that need it.
Change-Id: Ic2cd4487a26e7a7fcb0b475ee52fa0ccf8a07c0b
Diffstat (limited to 'anttasks')
-rw-r--r-- | anttasks/src/com/android/ant/AaptExecTask.java | 2 | ||||
-rw-r--r-- | anttasks/src/com/android/ant/AidlExecTask.java | 208 | ||||
-rw-r--r-- | anttasks/src/com/android/ant/ApkBuilderTask.java | 2 | ||||
-rw-r--r-- | anttasks/src/com/android/ant/DexExecTask.java | 2 | ||||
-rw-r--r-- | anttasks/src/com/android/ant/MultiFilesTask.java | 177 | ||||
-rw-r--r-- | anttasks/src/com/android/ant/RenderScriptTask.java | 173 | ||||
-rw-r--r-- | anttasks/src/com/android/ant/SingleDependencyTask.java (renamed from anttasks/src/com/android/ant/BaseTask.java) | 6 |
7 files changed, 338 insertions, 232 deletions
diff --git a/anttasks/src/com/android/ant/AaptExecTask.java b/anttasks/src/com/android/ant/AaptExecTask.java index 504640b..45adc7c 100644 --- a/anttasks/src/com/android/ant/AaptExecTask.java +++ b/anttasks/src/com/android/ant/AaptExecTask.java @@ -52,7 +52,7 @@ import java.util.List; * <tr><td></td><td></td><td></td></tr> * </table> */ -public final class AaptExecTask extends BaseTask { +public final class AaptExecTask extends SingleDependencyTask { /** * Class representing a <nocompress> node in the main task XML. diff --git a/anttasks/src/com/android/ant/AidlExecTask.java b/anttasks/src/com/android/ant/AidlExecTask.java index ab01c71..651cc66 100644 --- a/anttasks/src/com/android/ant/AidlExecTask.java +++ b/anttasks/src/com/android/ant/AidlExecTask.java @@ -18,19 +18,11 @@ package com.android.ant; import org.apache.tools.ant.BuildException; import org.apache.tools.ant.Project; -import org.apache.tools.ant.Task; import org.apache.tools.ant.taskdefs.ExecTask; -import org.apache.tools.ant.types.FileSet; import org.apache.tools.ant.types.Path; -import org.apache.tools.ant.types.PatternSet.NameEntry; -import java.io.File; import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashSet; -import java.util.Iterator; import java.util.List; -import java.util.Set; /** * Task to execute aidl. @@ -44,13 +36,72 @@ import java.util.Set; * It also expects one or more inner elements called "source" which are identical to {@link Path} * elements. */ -public class AidlExecTask extends Task { +public class AidlExecTask extends MultiFilesTask { private String mExecutable; private String mFramework; private String mGenFolder; private final ArrayList<Path> mPaths = new ArrayList<Path>(); + private class AidlProcessor implements SourceProcessor { + + public String getSourceFileExtension() { + return "aidl"; + } + + public void process(String filePath, String sourceFolder, + List<String> sourceFolders, Project taskProject) { + ExecTask task = new ExecTask(); + task.setProject(taskProject); + task.setOwningTarget(getOwningTarget()); + task.setExecutable(mExecutable); + task.setTaskName("aidl"); + task.setFailonerror(true); + + task.createArg().setValue("-p" + mFramework); + task.createArg().setValue("-o" + mGenFolder); + // add all the source folders as import in case an aidl file in a source folder + // imports a parcelable from another source folder. + for (String importFolder : sourceFolders) { + task.createArg().setValue("-I" + importFolder); + } + + // set auto dependency file creation + task.createArg().setValue("-a"); + + task.createArg().setValue(filePath); + + // execute it. + task.execute(); + } + + public void displayMessage(DisplayType type, int count) { + switch (type) { + case FOUND: + System.out.println(String.format("Found %1$d AIDL files.", count)); + break; + case COMPILING: + if (count > 0) { + System.out.println(String.format("Compiling %1$d AIDL files.", + count)); + } else { + System.out.println("No AIDL files to compile."); + } + break; + case REMOVE_OUTPUT: + System.out.println(String.format("Found %1$d obsolete output files to remove.", + count)); + break; + case REMOVE_DEP: + System.out.println( + String.format("Found %1$d obsolete dependency files to remove.", + count)); + break; + } + } + + } + /** * Sets the value of the "executable" attribute. * @param executable the value. @@ -85,144 +136,7 @@ public class AidlExecTask extends Task { throw new BuildException("AidlExecTask's 'genFolder' is required."); } - Project taskProject = getProject(); - - // build a list of all the source folders - ArrayList<String> sourceFolders = new ArrayList<String>(); - for (Path p : mPaths) { - String[] values = p.list(); - if (values != null) { - sourceFolders.addAll(Arrays.asList(values)); - } - } - - // gather all the aidl files from all the source folders. - Set<String> sourceFiles = getFileListByExtension(taskProject, sourceFolders, "**/*.aidl"); - if (sourceFiles.size() > 0) { - System.out.println(String.format("Found %d aidl files.", sourceFiles.size())); - } - - // go look for all dependency files in the gen folder. - Set<String> depFiles = getFileListByExtension(taskProject, mGenFolder, "**/*.d"); - - // parse all the dep files and keep the ones that are aidl and check if they require - // compilation again. - ArrayList<String> toCompile = new ArrayList<String>(); - ArrayList<File> toRemove = new ArrayList<File>(); - ArrayList<String> depsToRemove = new ArrayList<String>(); - for (String depFile : depFiles) { - DependencyGraph graph = new DependencyGraph(depFile, null /*watchPaths*/); - - // get the source file. it's the first item in the pre-reqs - File sourceFile = graph.getFirstPrereq(); - String sourceFilePath = sourceFile.getAbsolutePath(); - - // The gen folder may contain other dependency files not generated by aidl. - // We only care if the first pre-rep is an aidl file. - if (sourceFilePath.toLowerCase().endsWith(".aidl")) { - // remove from the list of sourceFiles to mark as "processed" (but not compiled - // yet, that'll be done by adding it to toCompile) - if (sourceFiles.remove(sourceFilePath) == false) { - // looks like the source file does not exist anymore! - // we'll have to remove the output! - Set<File> outputFiles = graph.getTargets(); - toRemove.addAll(outputFiles); - - // also need to remove the dep file. - depsToRemove.add(depFile); - } else if (graph.dependenciesHaveChanged(false /*printStatus*/)) { - // need to recompile! - toCompile.add(sourceFilePath); - } - } - } - - // add to the list of files to compile, whatever is left in sourceFiles. Those are - // new files that have never been compiled. - toCompile.addAll(sourceFiles); - - if (toCompile.size() > 0) { - System.out.println(String.format("Compiling %d aidl files.", toCompile.size())); - - for (String toCompilePath : toCompile) { - ExecTask task = new ExecTask(); - task.setProject(taskProject); - task.setOwningTarget(getOwningTarget()); - task.setExecutable(mExecutable); - task.setTaskName("aidl"); - task.setFailonerror(true); - - task.createArg().setValue("-p" + mFramework); - task.createArg().setValue("-o" + mGenFolder); - // add all the source folders as import in case an aidl file in a source folder - // imports a parcelable from another source folder. - for (String importFolder : sourceFolders) { - task.createArg().setValue("-I" + importFolder); - } - - // set auto dependency file creation - task.createArg().setValue("-a"); - - task.createArg().setValue(toCompilePath); - - // execute it. - task.execute(); - } - } else { - System.out.println(String.format("No aidl files to compile.")); - } - - if (toRemove.size() > 0) { - System.out.println(String.format("%d obsolete output files to remove.", - toRemove.size())); - for (File toRemoveFile : toRemove) { - if (toRemoveFile.delete() == false) { - System.err.println("Failed to remove " + toRemoveFile.getAbsolutePath()); - } - } - } - - // remove the dependency files that are obsolete - if (depsToRemove.size() > 0) { - System.out.println(String.format("%d obsolete dependency files to remove.", - depsToRemove.size())); - for (String path : depsToRemove) { - if (new File(path).delete() == false) { - System.err.println("Failed to remove " + path); - } - } - } - } - - private Set<String> getFileListByExtension(Project taskProject, - List<String> sourceFolders, String filter) { - HashSet<String> sourceFiles = new HashSet<String>(); - for (String sourceFolder : sourceFolders) { - sourceFiles.addAll(getFileListByExtension(taskProject, sourceFolder, filter)); - } - - return sourceFiles; + processFiles(new AidlProcessor(), mPaths, mGenFolder); } - private Set<String> getFileListByExtension(Project taskProject, - String sourceFolder, String filter) { - HashSet<String> sourceFiles = new HashSet<String>(); - - // create a fileset to find all the files in the folder - FileSet fs = new FileSet(); - fs.setProject(taskProject); - fs.setDir(new File(sourceFolder)); - NameEntry include = fs.createInclude(); - include.setName(filter); - - // loop through the results of the file set - Iterator<?> iter = fs.iterator(); - while (iter.hasNext()) { - sourceFiles.add(iter.next().toString()); - } - - return sourceFiles; - } - - } diff --git a/anttasks/src/com/android/ant/ApkBuilderTask.java b/anttasks/src/com/android/ant/ApkBuilderTask.java index 88bd59c..1cf1c0d 100644 --- a/anttasks/src/com/android/ant/ApkBuilderTask.java +++ b/anttasks/src/com/android/ant/ApkBuilderTask.java @@ -31,7 +31,7 @@ import java.util.ArrayList; import java.util.List; import java.util.regex.Pattern; -public class ApkBuilderTask extends BaseTask { +public class ApkBuilderTask extends SingleDependencyTask { private final static Pattern PATTERN_JAR_EXT = Pattern.compile("^.+\\.jar$", Pattern.CASE_INSENSITIVE); diff --git a/anttasks/src/com/android/ant/DexExecTask.java b/anttasks/src/com/android/ant/DexExecTask.java index 4016417..6be0a98 100644 --- a/anttasks/src/com/android/ant/DexExecTask.java +++ b/anttasks/src/com/android/ant/DexExecTask.java @@ -30,7 +30,7 @@ import java.util.List; /** * Custom task to execute dx while handling dependencies. */ -public class DexExecTask extends BaseTask { +public class DexExecTask extends SingleDependencyTask { private String mExecutable; private String mOutput; diff --git a/anttasks/src/com/android/ant/MultiFilesTask.java b/anttasks/src/com/android/ant/MultiFilesTask.java new file mode 100644 index 0000000..4fb1795 --- /dev/null +++ b/anttasks/src/com/android/ant/MultiFilesTask.java @@ -0,0 +1,177 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.ant; + +import org.apache.tools.ant.Project; +import org.apache.tools.ant.Task; +import org.apache.tools.ant.types.FileSet; +import org.apache.tools.ant.types.Path; +import org.apache.tools.ant.types.PatternSet.NameEntry; + +import java.io.File; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.Map.Entry; + +class MultiFilesTask extends Task { + + static enum DisplayType { + FOUND, COMPILING, REMOVE_OUTPUT, REMOVE_DEP; + } + + interface SourceProcessor { + String getSourceFileExtension(); + void process(String filePath, String sourceFolder, + List<String> sourceFolders, Project taskProject); + void displayMessage(DisplayType type, int count); + } + + protected void processFiles(SourceProcessor processor, List<Path> paths, String genFolder) { + + Project taskProject = getProject(); + + String extension = processor.getSourceFileExtension(); + + // build a list of all the source folders + ArrayList<String> sourceFolders = new ArrayList<String>(); + for (Path p : paths) { + String[] values = p.list(); + if (values != null) { + sourceFolders.addAll(Arrays.asList(values)); + } + } + + // gather all the source files from all the source folders. + Map<String, String> sourceFiles = getFileListByExtension(taskProject, sourceFolders, + "**/*." + extension); + if (sourceFiles.size() > 0) { + processor.displayMessage(DisplayType.FOUND, sourceFiles.size()); + } + + // go look for all dependency files in the gen folder. This will have all dependency + // files but we can filter them based on the first pre-req file. + Map<String, String> depFiles = getFileListByExtension(taskProject, genFolder, "**/*.d"); + + // parse all the dep files and keep the ones that are of the proper type and check if + // they require compilation again. + Map<String, String> toCompile = new HashMap<String, String>(); + ArrayList<File> toRemove = new ArrayList<File>(); + ArrayList<String> depsToRemove = new ArrayList<String>(); + for (String depFile : depFiles.keySet()) { + DependencyGraph graph = new DependencyGraph(depFile, null /*watchPaths*/); + + // get the source file. it's the first item in the pre-reqs + File sourceFile = graph.getFirstPrereq(); + String sourceFilePath = sourceFile.getAbsolutePath(); + + // The gen folder may contain other dependency files not generated by this particular + // processor. + // We only care if the first pre-rep is of the right extension. + if (sourceFilePath.toLowerCase().endsWith("." + extension)) { + // remove from the list of sourceFiles to mark as "processed" (but not compiled + // yet, that'll be done by adding it to toCompile) + String sourceFolder = sourceFiles.get(sourceFilePath); + if (sourceFolder == null) { + // looks like the source file does not exist anymore! + // we'll have to remove the output! + Set<File> outputFiles = graph.getTargets(); + toRemove.addAll(outputFiles); + + // also need to remove the dep file. + depsToRemove.add(depFile); + } else { + // Source file is present. remove it from the list as being processed. + sourceFiles.remove(sourceFilePath); + + // check if it needs to be recompiled. + if (graph.dependenciesHaveChanged(false /*printStatus*/)) { + toCompile.put(sourceFilePath, sourceFolder); + } + } + } + } + + // add to the list of files to compile, whatever is left in sourceFiles. Those are + // new files that have never been compiled. + toCompile.putAll(sourceFiles); + + processor.displayMessage(DisplayType.COMPILING, toCompile.size()); + if (toCompile.size() > 0) { + for (Entry<String, String> toCompilePath : toCompile.entrySet()) { + processor.process(toCompilePath.getKey(), toCompilePath.getValue(), + sourceFolders, taskProject); + } + } + + if (toRemove.size() > 0) { + processor.displayMessage(DisplayType.REMOVE_OUTPUT, toRemove.size()); + + for (File toRemoveFile : toRemove) { + if (toRemoveFile.delete() == false) { + System.err.println("Failed to remove " + toRemoveFile.getAbsolutePath()); + } + } + } + + // remove the dependency files that are obsolete + if (depsToRemove.size() > 0) { + processor.displayMessage(DisplayType.REMOVE_DEP, toRemove.size()); + + for (String path : depsToRemove) { + if (new File(path).delete() == false) { + System.err.println("Failed to remove " + path); + } + } + } + } + + private Map<String, String> getFileListByExtension(Project taskProject, + List<String> sourceFolders, String filter) { + HashMap<String, String> sourceFiles = new HashMap<String, String>(); + for (String sourceFolder : sourceFolders) { + sourceFiles.putAll(getFileListByExtension(taskProject, sourceFolder, filter)); + } + + return sourceFiles; + } + + private Map<String, String> getFileListByExtension(Project taskProject, + String sourceFolder, String filter) { + HashMap<String, String> sourceFiles = new HashMap<String, String>(); + + // create a fileset to find all the files in the folder + FileSet fs = new FileSet(); + fs.setProject(taskProject); + fs.setDir(new File(sourceFolder)); + NameEntry include = fs.createInclude(); + include.setName(filter); + + // loop through the results of the file set + Iterator<?> iter = fs.iterator(); + while (iter.hasNext()) { + sourceFiles.put(iter.next().toString(), sourceFolder); + } + + return sourceFiles; + } + +} diff --git a/anttasks/src/com/android/ant/RenderScriptTask.java b/anttasks/src/com/android/ant/RenderScriptTask.java index 8264aac..96cf62e 100644 --- a/anttasks/src/com/android/ant/RenderScriptTask.java +++ b/anttasks/src/com/android/ant/RenderScriptTask.java @@ -18,16 +18,11 @@ package com.android.ant; import org.apache.tools.ant.BuildException; import org.apache.tools.ant.Project; -import org.apache.tools.ant.Task; import org.apache.tools.ant.taskdefs.ExecTask; -import org.apache.tools.ant.types.FileSet; import org.apache.tools.ant.types.Path; -import org.apache.tools.ant.types.PatternSet.NameEntry; import java.io.File; import java.util.ArrayList; -import java.util.Arrays; -import java.util.Iterator; import java.util.List; /** @@ -43,7 +38,7 @@ import java.util.List; * It also expects one or more inner elements called "source" which are identical to {@link Path} * elements for where to find .rs files. */ -public class RenderScriptTask extends Task { +public class RenderScriptTask extends MultiFilesTask { private String mExecutable; private Path mFramework; @@ -52,6 +47,98 @@ public class RenderScriptTask extends Task { private final List<Path> mPaths = new ArrayList<Path>(); private int mTargetApi = 0; + private class RenderScriptProcessor implements SourceProcessor { + + private final String mTargetApiStr; + + public RenderScriptProcessor(int targetApi) { + // get the target api value. Must be 11+ or llvm-rs-cc complains. + mTargetApiStr = Integer.toString(mTargetApi < 11 ? 11 : mTargetApi); + } + + public String getSourceFileExtension() { + return "rs"; + } + + public void process(String filePath, String sourceFolder, List<String> sourceFolders, + Project taskProject) { + File exe = new File(mExecutable); + String execTaskName = exe.getName(); + + ExecTask task = new ExecTask(); + task.setTaskName(execTaskName); + task.setProject(taskProject); + task.setOwningTarget(getOwningTarget()); + task.setExecutable(mExecutable); + task.setFailonerror(true); + + for (String path : mFramework.list()) { + File res = new File(path); + if (res.isDirectory()) { + task.createArg().setValue("-I"); + task.createArg().setValue(path); + } else { + System.out.println(String.format( + "WARNING: RenderScript include directory '%s' does not exist!", + res.getAbsolutePath())); + } + + } + + task.createArg().setValue("-target-api"); + task.createArg().setValue(mTargetApiStr); + + task.createArg().setValue("-d"); + task.createArg().setValue(getDependencyFolder(filePath, sourceFolder)); + task.createArg().setValue("-MD"); + + task.createArg().setValue("-p"); + task.createArg().setValue(mGenFolder); + task.createArg().setValue("-o"); + task.createArg().setValue(mResFolder); + task.createArg().setValue(filePath); + + // execute it. + task.execute(); + } + + public void displayMessage(DisplayType type, int count) { + switch (type) { + case FOUND: + System.out.println(String.format("Found %1$d RenderScript files.", count)); + break; + case COMPILING: + if (count > 0) { + System.out.println(String.format( + "Compiling %1$d RenderScript files with -target-api %2$d", + count, mTargetApi)); + } else { + System.out.println("No RenderScript files to compile."); + } + break; + case REMOVE_OUTPUT: + System.out.println(String.format("Found %1$d obsolete output files to remove.", + count)); + break; + case REMOVE_DEP: + System.out.println( + String.format("Found %1$d obsolete dependency files to remove.", + count)); + break; + } + } + + private String getDependencyFolder(String filePath, String sourceFolder) { + String relative = filePath.substring(sourceFolder.length()); + if (relative.charAt(0) == '/') { + relative = relative.substring(1); + } + + return new File(mGenFolder, relative).getParent(); + } + } + + /** * Sets the value of the "executable" attribute. * @param executable the value. @@ -107,78 +194,6 @@ public class RenderScriptTask extends Task { throw new BuildException("RenderScriptTask's 'targetApi' is required."); } - Project taskProject = getProject(); - - // build a list of all the source folders - ArrayList<String> sourceFolders = new ArrayList<String>(); - for (Path p : mPaths) { - String[] values = p.list(); - if (values != null) { - sourceFolders.addAll(Arrays.asList(values)); - } - } - - File exe = new File(mExecutable); - String execTaskName = exe.getName(); - - int count = 0; - - // get the target api value. Must be 11+ or llvm-rs-cc complains. - String targetApiStr = Integer.toString(mTargetApi < 11 ? 11 : mTargetApi); - - // now loop on all the source folders to find all the renderscript to compile - // and compile them - for (String sourceFolder : sourceFolders) { - // create a fileset to find all the aidl files in the current source folder - FileSet fs = new FileSet(); - fs.setProject(taskProject); - fs.setDir(new File(sourceFolder)); - NameEntry include = fs.createInclude(); - include.setName("**/*.rs"); - - // loop through the results of the file set - Iterator<?> iter = fs.iterator(); - while (iter.hasNext()) { - Object next = iter.next(); - - ExecTask task = new ExecTask(); - task.setTaskName(execTaskName); - task.setProject(taskProject); - task.setOwningTarget(getOwningTarget()); - task.setExecutable(mExecutable); - task.setFailonerror(true); - - for (String path : mFramework.list()) { - File res = new File(path); - if (res.isDirectory()) { - task.createArg().setValue("-I"); - task.createArg().setValue(path); - } - } - - task.createArg().setValue("-target-api"); - task.createArg().setValue(targetApiStr); - - task.createArg().setValue("-p"); - task.createArg().setValue(mGenFolder); - task.createArg().setValue("-o"); - task.createArg().setValue(mResFolder); - task.createArg().setValue(next.toString()); - - // execute it. - task.execute(); - - count++; - } - } - - if (count > 0) { - System.out.println(String.format( - "Compiled %d renderscript files (with -target-api set to %s)", - count, mTargetApi)); - } else { - System.out.println("No renderscript files to compile."); - } - + processFiles(new RenderScriptProcessor(mTargetApi), mPaths, mGenFolder); } } diff --git a/anttasks/src/com/android/ant/BaseTask.java b/anttasks/src/com/android/ant/SingleDependencyTask.java index b1c37b8..dc3e15d 100644 --- a/anttasks/src/com/android/ant/BaseTask.java +++ b/anttasks/src/com/android/ant/SingleDependencyTask.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009 The Android Open Source Project + * Copyright (C) 2011 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -27,9 +27,9 @@ import java.util.List; import java.util.Set; /** - * A base class for the ant task that contains logic for handling dependency files + * A base class for ant tasks that use a single dependency files to control (re)execution. */ -public abstract class BaseTask extends Task { +public abstract class SingleDependencyTask extends Task { private DependencyGraph mDependencies; private String mPreviousBuildType; |