diff options
author | Xavier Ducrohet <xav@android.com> | 2011-01-31 17:22:59 -0800 |
---|---|---|
committer | Xavier Ducrohet <xav@android.com> | 2011-01-31 20:13:09 -0800 |
commit | ea803caeec48eb03db3b93c8098786a439199d54 (patch) | |
tree | 2f70a933e3c3919d3cf61fd849c2d7dd722abdc5 | |
parent | dec739da5551ddf52a8f3cff06c63de4aced2578 (diff) | |
download | sdk-ea803caeec48eb03db3b93c8098786a439199d54.zip sdk-ea803caeec48eb03db3b93c8098786a439199d54.tar.gz sdk-ea803caeec48eb03db3b93c8098786a439199d54.tar.bz2 |
Add Renderscript support to the ADT builders.
This uses the new JavaGenerator mechanism so that all that's needed
is to run llvm-rs-cc on a given list and parsing the dependency file
that's created.
Change-Id: Ib4928c980422dfe1944bc720c77bf6ae5be4c34a
16 files changed, 603 insertions, 79 deletions
diff --git a/anttasks/src/com/android/ant/RenderScriptTask.java b/anttasks/src/com/android/ant/RenderScriptTask.java index f001311..5aa6612 100644 --- a/anttasks/src/com/android/ant/RenderScriptTask.java +++ b/anttasks/src/com/android/ant/RenderScriptTask.java @@ -45,7 +45,7 @@ import java.util.List; public class RenderScriptTask extends Task { private String mExecutable; - private String mFramework; + private Path mFramework; private String mGenFolder; private String mResFolder; private final List<Path> mPaths = new ArrayList<Path>(); @@ -59,7 +59,7 @@ public class RenderScriptTask extends Task { } public void setFramework(Path value) { - mFramework = TaskHelper.checkSinglePath("framework", value); + mFramework = value; } public void setGenFolder(Path value) { @@ -127,8 +127,14 @@ public class RenderScriptTask extends Task { task.setExecutable(mExecutable); task.setFailonerror(true); - task.createArg().setValue("-I"); - task.createArg().setValue(mFramework); + for (String path : mFramework.list()) { + File res = new File(path); + if (res.isDirectory()) { + task.createArg().setValue("-I"); + task.createArg().setValue(path); + } + } + task.createArg().setValue("-p"); task.createArg().setValue(mGenFolder); task.createArg().setValue("-o"); diff --git a/anttasks/src/com/android/ant/SetupTask.java b/anttasks/src/com/android/ant/SetupTask.java index c3cedfd..6dc2c0f 100644 --- a/anttasks/src/com/android/ant/SetupTask.java +++ b/anttasks/src/com/android/ant/SetupTask.java @@ -199,15 +199,19 @@ public final class SetupTask extends ImportTask { String androidAidl = androidTarget.getPath(IAndroidTarget.ANDROID_AIDL); antProject.setProperty(AntConstants.PROP_ANDROID_AIDL, androidAidl); - String androidRS = androidTarget.getPath(IAndroidTarget.ANDROID_RS); - antProject.setProperty(AntConstants.PROP_ANDROID_RENDERSCRIPT, androidRS); + Path includePath = new Path(antProject); + PathElement element = includePath.createPathElement(); + element.setPath(androidTarget.getPath(IAndroidTarget.ANDROID_RS)); + element = includePath.createPathElement(); + element.setPath(androidTarget.getPath(IAndroidTarget.ANDROID_RS_CLANG)); + antProject.setProperty(AntConstants.PROP_ANDROID_RENDERSCRIPT, includePath.toString()); antProject.setProperty(AntConstants.PROP_AAPT, androidTarget.getPath(IAndroidTarget.AAPT)); antProject.setProperty(AntConstants.PROP_AIDL, androidTarget.getPath(IAndroidTarget.AIDL)); antProject.setProperty(AntConstants.PROP_DX, androidTarget.getPath(IAndroidTarget.DX)); antProject.setProperty(AntConstants.PROP_RENDERSCRIPT, sdkOsPath + SdkConstants.OS_SDK_PLATFORM_TOOLS_FOLDER + - SdkConstants.FN_RENDERSCRIPT); + SdkConstants.FN_RENDERSCRIPT); // sets up the boot classpath @@ -215,7 +219,7 @@ public final class SetupTask extends ImportTask { Path bootclasspath = new Path(antProject); // create a PathElement for the framework jar - PathElement element = bootclasspath.createPathElement(); + element = bootclasspath.createPathElement(); element.setPath(androidJar); // create PathElement for each optional library. diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/plugin.xml b/eclipse/plugins/com.android.ide.eclipse.adt/plugin.xml index 2ce6257..ce54cac 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/plugin.xml +++ b/eclipse/plugins/com.android.ide.eclipse.adt/plugin.xml @@ -34,6 +34,14 @@ <persistent value="true"/> </extension> <extension + id="com.android.ide.eclipse.common.rsProblem" + name="Android RenderScript Problem" + point="org.eclipse.core.resources.markers"> + <super type="org.eclipse.core.resources.problemmarker"/> + <super type="org.eclipse.core.resources.textmarker"/> + <persistent value="true"/> + </extension> + <extension id="com.android.ide.eclipse.common.androidProblem" name="Android XML Content Problem" point="org.eclipse.core.resources.markers"> diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/AndroidConstants.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/AndroidConstants.java index d733080..0ed318a 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/AndroidConstants.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/AndroidConstants.java @@ -74,6 +74,8 @@ public class AndroidConstants { public final static String EXT_AIDL = "aidl"; //$NON-NLS-1$ /** Extension of Renderscript files, i.e. "rs" */ public final static String EXT_RS = "rs"; //$NON-NLS-1$ + /** Extension of dependency files, i.e. "d" */ + public final static String EXT_DEP = "d"; //$NON-NLS-1$ /** Extension of native libraries, i.e. "so" */ public final static String EXT_NATIVE_LIB = "so"; //$NON-NLS-1$ /** Extension of dex files, i.e. "dex" */ @@ -95,6 +97,10 @@ public class AndroidConstants { public final static String DOT_JAR = DOT + EXT_JAR; /** Dot-Extension of aidl files, i.e. ".aidl" */ public final static String DOT_AIDL = DOT + EXT_AIDL; + /** Dot-Extension of renderscript files, i.e. ".rs" */ + public final static String DOT_RS = DOT + EXT_RS; + /** Dot-Extension of dependency files, i.e. ".d" */ + public final static String DOT_DEP = DOT + EXT_DEP; /** Dot-Extension of dex files, i.e. ".dex" */ public final static String DOT_DEX = DOT + EXT_DEX; /** Dot-Extension for temporary resource files, ie "ap_ */ @@ -151,9 +157,11 @@ public class AndroidConstants { public final static String RE_DOT = "\\."; //$NON-NLS-1$ /** Regexp for java extension, i.e. "\.java$" */ - public final static String RE_JAVA_EXT = "\\.java$"; //$NON-NLS-1$ + public final static String RE_JAVA_EXT = "\\" + DOT_JAVA + "$"; //$NON-NLS-1$ //$NON-NLS-2$ /** Regexp for aidl extension, i.e. "\.aidl$" */ - public final static String RE_AIDL_EXT = "\\.aidl$"; //$NON-NLS-1$ + public final static String RE_AIDL_EXT = "\\" + DOT_AIDL + "$"; //$NON-NLS-1$ //$NON-NLS-2$ + /** Regexp for rs extension, i.e. "\.rs$" */ + public final static String RE_RS_EXT = "\\" + DOT_RS + "$"; //$NON-NLS-1$ //$NON-NLS-2$ /** * Namespace pattern for the custom resource XML, i.e. "http://schemas.android.com/apk/res/%s" @@ -196,6 +204,9 @@ public class AndroidConstants { /** aidl marker error, only to be used in {@link PreCompilerBuilder} */ public final static String MARKER_AIDL = LEGACY_PLUGIN_ID + ".aidlProblem"; //$NON-NLS-1$ + /** renderscript marker error, only to be used in {@link PreCompilerBuilder} */ + public final static String MARKER_RENDERSCRIPT = LEGACY_PLUGIN_ID + ".rsProblem"; //$NON-NLS-1$ + /** android marker error, only to be used in the Manifest parsing * from the {@link PreCompilerBuilder} */ public final static String MARKER_ANDROID = LEGACY_PLUGIN_ID + ".androidProblem"; //$NON-NLS-1$ diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/AidlGenerator.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/AidlGenerator.java index 24b5b67..3b28107 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/AidlGenerator.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/AidlGenerator.java @@ -90,6 +90,11 @@ public class AidlGenerator extends JavaGenerator { } @Override + protected int getCompilationType() { + return COMPILE_STATUS_CODE; + } + + @Override protected void doCompileFiles(List<IFile> sources, BaseBuilder builder, IProject project, IAndroidTarget projectTarget, List<IPath> sourceFolders, List<IFile> notCompiledOut, IProgressMonitor monitor) @@ -108,9 +113,11 @@ public class AidlGenerator extends JavaGenerator { command[index++] = "-I" + f.getLocation().toOSString(); //$NON-NLS-1$ } + boolean verbose = AdtPrefs.getPrefs().getBuildVerbosity() == BuildVerbosity.VERBOSE; + // loop until we've compile them all for (IFile sourceFile : sources) { - if (AdtPrefs.getPrefs().getBuildVerbosity() == BuildVerbosity.VERBOSE) { + if (verbose) { String name = sourceFile.getName(); IPath sourceFolderPath = getSourceFolderFor(sourceFile); if (sourceFolderPath != null) { @@ -141,7 +148,7 @@ public class AidlGenerator extends JavaGenerator { command[index + 1] = bundle.getOutput().getLocation().toOSString(); // launch the process - if (execAidl(builder, project, command, sourceFile) == false) { + if (execAidl(builder, project, command, sourceFile, verbose) == false) { // aidl failed. File should be marked. We add the file to the list // of file that will need compilation again. notCompiledOut.add(sourceFile); @@ -150,23 +157,6 @@ public class AidlGenerator extends JavaGenerator { } @Override - protected void doRemoveFiles(List<IFile> sources, IProgressMonitor monitor) - throws CoreException { - for (IFile sourceFile : sources) { - // look if we already know the output - NonJavaFileBundle bundle = getBundle(sourceFile); - if (bundle != null) { - IFile outputFile = bundle.getOutput(); - if (outputFile != null && outputFile.exists()) { - // This confirms the java file was generated by the builder, - // we can delete the aidlFile. - outputFile.getLocation().toFile().delete(); - } - } - } - } - - @Override protected void loadOutputAndDependencies() { IProgressMonitor monitor = new NullProgressMonitor(); Collection<NonJavaFileBundle> bundles = getBundles(); @@ -189,12 +179,13 @@ public class AidlGenerator extends JavaGenerator { * @param command the String array containing the command line to execute. * @param file The IFile object representing the aidl file being * compiled. + * @param verbose the build verbosity * @return false if the exec failed, and build needs to be aborted. */ - private boolean execAidl(BaseBuilder builder, IProject project, String[] command, IFile file) { + private boolean execAidl(BaseBuilder builder, IProject project, String[] command, IFile file, + boolean verbose) { // do the exec try { - boolean verbose = AdtPrefs.getPrefs().getBuildVerbosity() == BuildVerbosity.VERBOSE; if (verbose) { StringBuilder sb = new StringBuilder(); for (String c : command) { @@ -224,13 +215,13 @@ public class AidlGenerator extends JavaGenerator { // display the message in the console. if (error) { AdtPlugin.printErrorToConsole(project, results.toArray()); + + // mark the project + BaseProjectHelper.markResource(project, AndroidConstants.MARKER_ADT, + Messages.Unparsed_AIDL_Errors, IMarker.SEVERITY_ERROR); } else { AdtPlugin.printToConsole(project, results.toArray()); } - - // mark the project and exit - BaseProjectHelper.markResource(project, AndroidConstants.MARKER_ADT, - Messages.Unparsed_AIDL_Errors, IMarker.SEVERITY_ERROR); } return false; } @@ -343,29 +334,6 @@ public class AidlGenerator extends JavaGenerator { return null; } - private IPath getSourceFolderFor(IFile file) { - // find the source folder for the class so that we can infer the package from the - // difference between the file and its source folder. - List<IPath> sourceFolders = BaseProjectHelper.getSourceClasspaths(getJavaProject()); - IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot(); - - for (IPath sourceFolderPath : sourceFolders) { - IFolder sourceFolder = root.getFolder(sourceFolderPath); - // we don't look in the 'gen' source folder as there will be no source in there. - if (sourceFolder.exists() && sourceFolder.equals(getGenFolder()) == false) { - // look for the source file parent, until we find this source folder. - IResource parent = file; - while ((parent = parent.getParent()) != null) { - if (parent.equals(sourceFolder)) { - return sourceFolderPath; - } - } - } - } - - return null; - } - /** * Creates the destination folder. Because * {@link IFolder#create(boolean, boolean, IProgressMonitor)} only works if the parent folder diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/GeneratorDeltaVisitor.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/GeneratorDeltaVisitor.java index 8419b24..aeda16b 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/GeneratorDeltaVisitor.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/GeneratorDeltaVisitor.java @@ -81,7 +81,12 @@ public class GeneratorDeltaVisitor { } } - protected boolean filterResourceFolder(IContainer parent) { + /** + * Called to restrict {@link #handleResourceFile(IFile, int)} on selected resource folders. + * @param folder + * @return + */ + protected boolean filterResourceFolder(IContainer folder) { return false; } diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/JavaGenerator.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/JavaGenerator.java index 73a18c6..33f3947 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/JavaGenerator.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/JavaGenerator.java @@ -51,6 +51,10 @@ import java.util.Set; */ public abstract class JavaGenerator { + public final static int COMPILE_STATUS_NONE = 0; + public final static int COMPILE_STATUS_CODE = 0x1; + public final static int COMPILE_STATUS_RES = 0x2; + /** List of all source files, their dependencies, and their output. */ private final Map<IFile, NonJavaFileBundle> mFiles = new HashMap<IFile, NonJavaFileBundle>(); @@ -183,16 +187,25 @@ public abstract class JavaGenerator { saveState(project); } + /** + * Returns the extension of the source files handled by this generator. + * @return + */ protected abstract String getExtension(); protected abstract String getSavePropertyName(); - public final boolean compileFiles(BaseBuilder builder, + /** + * Compiles the source files and return what type of file was generated. + * + * @see #getCompilationType() + */ + public final int compileFiles(BaseBuilder builder, IProject project, IAndroidTarget projectTarget, List<IPath> sourceFolders, IProgressMonitor monitor) throws CoreException { if (mToCompile.size() == 0 && mRemoved.size() == 0) { - return false; + return COMPILE_STATUS_NONE; } // if a source file is being removed before we managed to compile it, it'll be in @@ -214,7 +227,13 @@ public abstract class JavaGenerator { mToCompile.addAll(stillNeedCompilation); // Remove the files created from source files that have been removed. - doRemoveFiles(mRemoved, monitor); + for (IFile sourceFile : mRemoved) { + // look if we already know the output + NonJavaFileBundle bundle = getBundle(sourceFile); + if (bundle != null) { + doRemoveFiles(bundle); + } + } // remove the associated bundles. for (IFile removedFile : mRemoved) { @@ -228,7 +247,7 @@ public abstract class JavaGenerator { // before the project is closed/re-opened.) saveState(project); - return true; + return getCompilationType(); } protected abstract void doCompileFiles( @@ -237,8 +256,22 @@ public abstract class JavaGenerator { List<IPath> sourceFolders, List<IFile> notCompiledOut, IProgressMonitor monitor) throws CoreException; - protected abstract void doRemoveFiles(List<IFile> sources, IProgressMonitor monitor) - throws CoreException; + /** + * Returns the type of compilation. It can be any of (in combination too): + * <p/> + * {@link #COMPILE_STATUS_CODE} means this generator created source files. + * {@link #COMPILE_STATUS_RES} means this generator created resources. + */ + protected abstract int getCompilationType(); + + protected void doRemoveFiles(NonJavaFileBundle bundle) throws CoreException { + List<IFile> outputFiles = bundle.getOutputFiles(); + for (IFile outputFile : outputFiles) { + if (outputFile.exists()) { + outputFile.getLocation().toFile().delete(); + } + } + } public final boolean loadState(IProject project) { return ProjectHelper.loadBooleanProperty(project, getSavePropertyName(), @@ -253,13 +286,37 @@ public abstract class JavaGenerator { protected abstract void loadOutputAndDependencies(); + + protected IPath getSourceFolderFor(IFile file) { + // find the source folder for the class so that we can infer the package from the + // difference between the file and its source folder. + List<IPath> sourceFolders = BaseProjectHelper.getSourceClasspaths(getJavaProject()); + IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot(); + + for (IPath sourceFolderPath : sourceFolders) { + IFolder sourceFolder = root.getFolder(sourceFolderPath); + // we don't look in the 'gen' source folder as there will be no source in there. + if (sourceFolder.exists() && sourceFolder.equals(getGenFolder()) == false) { + // look for the source file parent, until we find this source folder. + IResource parent = file; + while ((parent = parent.getParent()) != null) { + if (parent.equals(sourceFolder)) { + return sourceFolderPath; + } + } + } + } + + return null; + } + /** * Goes through the build paths and fills the list of files to compile. * * @param project The project. * @param sourceFolderPathList The list of source folder paths. */ - protected void buildSourceFileList() { + private final void buildSourceFileList() { mFiles.clear(); IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot(); diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/NonJavaFileBundle.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/NonJavaFileBundle.java index e75add0..fe071fb 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/NonJavaFileBundle.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/NonJavaFileBundle.java @@ -81,6 +81,17 @@ public class NonJavaFileBundle { } } + public void setDependencyFiles(List<IFile> depFiles) { + mDependencyFiles.clear(); + if (depFiles != null) { + mDependencyFiles.addAll(depFiles); + } + } + + public List<IFile> getDependencyFiles() { + return mDependencyFiles; + } + /** * Shortcut access to the first output file. This is useful for generator that only output * one file. diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/RenderScriptGenerator.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/RenderScriptGenerator.java new file mode 100644 index 0000000..4a8abe5 --- /dev/null +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/RenderScriptGenerator.java @@ -0,0 +1,421 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Eclipse Public License, Version 1.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.eclipse.org/org/documents/epl-v10.php + * + * 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.ide.eclipse.adt.internal.build; + +import com.android.ide.eclipse.adt.AdtPlugin; +import com.android.ide.eclipse.adt.AndroidConstants; +import com.android.ide.eclipse.adt.internal.build.builders.BaseBuilder; +import com.android.ide.eclipse.adt.internal.preferences.AdtPrefs; +import com.android.ide.eclipse.adt.internal.preferences.AdtPrefs.BuildVerbosity; +import com.android.ide.eclipse.adt.internal.project.BaseProjectHelper; +import com.android.ide.eclipse.adt.internal.resources.manager.ResourceFolderType; +import com.android.ide.eclipse.adt.internal.sdk.Sdk; +import com.android.sdklib.IAndroidTarget; +import com.android.sdklib.SdkConstants; + +import org.eclipse.core.resources.IContainer; +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IFolder; +import org.eclipse.core.resources.IMarker; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.Path; +import org.eclipse.jdt.core.IJavaProject; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * A {@link JavaGenerator} for RenderScript files. + * + */ +public class RenderScriptGenerator extends JavaGenerator { + + private static final String PROPERTY_COMPILE_RS = "compileRenderScript"; //$NON-NLS-1$ + + /** + * Single line llvm-rs-cc error<br> + * "<path>:<line>:<col>: <error>" + */ + private static Pattern sLlvmPattern1 = Pattern.compile("^(.+?):(\\d+):(\\d+):\\s(.+)$"); //$NON-NLS-1$ + + private static class RSDeltaVisitor extends GeneratorDeltaVisitor { + + @Override + protected boolean filterResourceFolder(IContainer folder) { + return ResourceFolderType.RAW.getName().equals(folder.getName()); + } + } + + public RenderScriptGenerator(IJavaProject javaProject, IFolder genFolder) { + super(javaProject, genFolder, new RSDeltaVisitor()); + } + + @Override + protected String getExtension() { + return AndroidConstants.EXT_RS; + } + + @Override + protected String getSavePropertyName() { + return PROPERTY_COMPILE_RS; + } + + @Override + protected int getCompilationType() { + return COMPILE_STATUS_CODE | COMPILE_STATUS_RES; + } + + @Override + protected void doCompileFiles(List<IFile> sources, BaseBuilder builder, + IProject project, IAndroidTarget projectTarget, List<IPath> sourceFolders, + List<IFile> notCompiledOut, IProgressMonitor monitor) throws CoreException { + + String sdkOsPath = Sdk.getCurrent().getSdkLocation(); + + IFolder genFolder = getGenFolder(); + + IFolder rawFolder = project.getFolder( + new Path(SdkConstants.FD_RES).append(SdkConstants.FD_RAW)); + + // create the command line + String[] command = new String[13]; + int index = 0; + command[index++] = sdkOsPath + SdkConstants.OS_SDK_PLATFORM_TOOLS_FOLDER + + SdkConstants.FN_RENDERSCRIPT; + command[index++] = "-I"; + command[index++] = projectTarget.getPath(IAndroidTarget.ANDROID_RS_CLANG); + command[index++] = "-I"; + command[index++] = projectTarget.getPath(IAndroidTarget.ANDROID_RS); + command[index++] = "-p"; + command[index++] = genFolder.getLocation().toOSString(); + command[index++] = "-o"; + command[index++] = rawFolder.getLocation().toOSString(); + + command[index++] = "-d"; + command[index++] = getDependencyFolder().getLocation().toOSString(); + command[index++] = "-MD"; + + boolean verbose = AdtPrefs.getPrefs().getBuildVerbosity() == BuildVerbosity.VERBOSE; + boolean someSuccess = false; + + // loop until we've compile them all + for (IFile sourceFile : sources) { + if (verbose) { + String name = sourceFile.getName(); + IPath sourceFolderPath = getSourceFolderFor(sourceFile); + if (sourceFolderPath != null) { + // make a path to the source file relative to the source folder. + IPath relative = sourceFile.getFullPath().makeRelativeTo(sourceFolderPath); + name = relative.toString(); + } + AdtPlugin.printToConsole(project, "RenderScript: " + name); + } + + // Remove the RS error markers from the source file and the dependencies + builder.removeMarkersFromFile(sourceFile, AndroidConstants.MARKER_RENDERSCRIPT); + NonJavaFileBundle bundle = getBundle(sourceFile); + if (bundle != null) { + for (IFile dep : bundle.getDependencyFiles()) { + builder.removeMarkersFromFile(dep, AndroidConstants.MARKER_RENDERSCRIPT); + } + } + + // get the path of the source file. + IPath sourcePath = sourceFile.getLocation(); + String osSourcePath = sourcePath.toOSString(); + + // finish to set the command line. + command[index] = osSourcePath; + + // launch the process + if (execLlvmRsCc(builder, project, command, sourceFile, verbose) == false) { + // llvm-rs-cc failed. File should be marked. We add the file to the list + // of file that will need compilation again. + notCompiledOut.add(sourceFile); + } else { + // need to parse the .d file to figure out the dependencies and the generated file + parseDependencyFileFor(sourceFile); + someSuccess = true; + } + } + + if (someSuccess) { + rawFolder.refreshLocal(IResource.DEPTH_ONE, monitor); + } + } + + private boolean execLlvmRsCc(BaseBuilder builder, IProject project, String[] command, + IFile sourceFile, boolean verbose) { + // do the exec + try { + if (verbose) { + StringBuilder sb = new StringBuilder(); + for (String c : command) { + sb.append(c); + sb.append(' '); + } + String cmd_line = sb.toString(); + AdtPlugin.printToConsole(project, cmd_line); + } + + Process p = Runtime.getRuntime().exec(command); + + // list to store each line of stderr + ArrayList<String> results = new ArrayList<String>(); + + // get the output and return code from the process + int result = BuildHelper.grabProcessOutput(project, p, results); + + // attempt to parse the error output + boolean error = parseLlvmOutput(results); + + // If the process failed and we couldn't parse the output + // we print a message, mark the project and exit + if (result != 0) { + + if (error || verbose) { + // display the message in the console. + if (error) { + AdtPlugin.printErrorToConsole(project, results.toArray()); + + // mark the project + BaseProjectHelper.markResource(project, AndroidConstants.MARKER_ADT, + "Unparsed Renderscript error! Check the console for output.", + IMarker.SEVERITY_ERROR); + } else { + AdtPlugin.printToConsole(project, results.toArray()); + } + } + return false; + } + } catch (IOException e) { + // mark the project and exit + String msg = String.format( + "Error executing Renderscript. Please check llvm-rs-cc is present at %1$s", + command[0]); + BaseProjectHelper.markResource(project, AndroidConstants.MARKER_ADT, msg, + IMarker.SEVERITY_ERROR); + return false; + } catch (InterruptedException e) { + // mark the project and exit + String msg = String.format( + "Error executing Renderscript. Please check llvm-rs-cc is present at %1$s", + command[0]); + BaseProjectHelper.markResource(project, AndroidConstants.MARKER_ADT, msg, + IMarker.SEVERITY_ERROR); + return false; + } + + return true; + } + + /** + * Parse the output of llvm-rs-cc and mark the file with any errors. + * @param lines The output to parse. + * @return true if the parsing failed, false if success. + */ + private boolean parseLlvmOutput(ArrayList<String> lines) { + // nothing to parse? just return false; + if (lines.size() == 0) { + return false; + } + + // get the root folder for the project as we're going to ignore everything that's + // not in the project + IProject project = getJavaProject().getProject(); + String rootPath = project.getLocation().toOSString(); + int rootPathLength = rootPath.length(); + + Matcher m; + + boolean parsing = false; + + for (int i = 0; i < lines.size(); i++) { + String p = lines.get(i); + + m = sLlvmPattern1.matcher(p); + if (m.matches()) { + // get the file path. This may, or may not be the main file being compiled. + String filePath = m.group(1); + if (filePath.startsWith(rootPath) == false) { + // looks like the error in a non-project file. Keep parsing, but + // we'll return true + parsing = true; + continue; + } + + // get the actual file. + filePath = filePath.substring(rootPathLength); + // remove starting separator since we want the path to be relative + if (filePath.startsWith(File.separator)) { + filePath = filePath.substring(1); + } + + // get the file + IFile f = project.getFile(new Path(filePath)); + + String lineStr = m.group(2); + // ignore group 3 for now, this is the col number + String msg = m.group(4); + + // get the line number + int line = 0; + try { + line = Integer.parseInt(lineStr); + } catch (NumberFormatException e) { + // looks like the string we extracted wasn't a valid + // file number. Parsing failed and we return true + return true; + } + + // mark the file + BaseProjectHelper.markResource(f, AndroidConstants.MARKER_RENDERSCRIPT, msg, line, + IMarker.SEVERITY_ERROR); + + // success, go to the next line + continue; + } + + // invalid line format, flag as error, and keep going + parsing = true; + } + + return parsing; + } + + + @Override + protected void doRemoveFiles(NonJavaFileBundle bundle) throws CoreException { + // call the super implementation, it will remove the output files + super.doRemoveFiles(bundle); + + // now remove the dependency file. + IFile depFile = getDependencyFileFor(bundle.getSourceFile()); + if (depFile.exists()) { + depFile.getLocation().toFile().delete(); + } + } + + @Override + protected void loadOutputAndDependencies() { + Collection<NonJavaFileBundle> bundles = getBundles(); + for (NonJavaFileBundle bundle : bundles) { + parseDependencyFileFor(bundle.getSourceFile()); + } + } + + private void parseDependencyFileFor(IFile sourceFile) { + IFile depFile = getDependencyFileFor(sourceFile); + File f = depFile.getLocation().toFile(); + if (f.exists()) { + NonJavaFileBundle bundle = getBundle(sourceFile); + if (bundle == null) { + bundle = new NonJavaFileBundle(sourceFile); + addBundle(bundle); + } + parseDependencyFile(bundle, f); + } + } + + private IFolder getDependencyFolder() { + return getJavaProject().getProject().getFolder(SdkConstants.FD_OUTPUT); + } + + private IFile getDependencyFileFor(IFile sourceFile) { + IFolder depFolder = getDependencyFolder(); + return depFolder.getFile(sourceFile.getName().replaceAll(AndroidConstants.RE_RS_EXT, + AndroidConstants.DOT_DEP)); + } + + /** + * Parses the given dependency file and fills the given {@link NonJavaFileBundle} with it. + * + * @param bundle the bundle to fill. + * @param file the dependency file + */ + private void parseDependencyFile(NonJavaFileBundle bundle, File dependencyFile) { + //contents = file.getContents(); + String content = AdtPlugin.readFile(dependencyFile); + + // we're going to be pretty brutal here. + // The format is something like: + // output1 output2 [...]: dep1 dep2 [...] + // expect it's likely split on several lines. So let's move it back on a single line + // first + String[] lines = content.split("\n"); + StringBuilder sb = new StringBuilder(); + for (String line : lines) { + line = line.trim(); + if (line.endsWith("\\")) { + line = line.substring(0, line.length() - 1); + } + + sb.append(line); + } + + // split the left and right part + String[] files = sb.toString().split(":"); + + // get the output files: + String[] outputs = files[0].trim().split(" "); + + // and the dependency files: + String[] dependencies = files[1].trim().split(" "); + + List<IFile> outputFiles = new ArrayList<IFile>(); + List<IFile> dependencyFiles = new ArrayList<IFile>(); + + fillList(outputs, outputFiles); + fillList(dependencies, dependencyFiles); + + bundle.setOutputFiles(outputFiles); + bundle.setDependencyFiles(dependencyFiles); + } + + private void fillList(String[] paths, List<IFile> list) { + // get the root folder for the project as we're going to ignore everything that's + // not in the project + IProject project = getJavaProject().getProject(); + String rootPath = project.getLocation().toOSString(); + int rootPathLength = rootPath.length(); + + // all those should really be in the project + for (String p : paths) { + + if (p.startsWith(rootPath)) { + p = p.substring(rootPathLength); + // remove starting separator since we want the path to be relative + if (p.startsWith(File.separator)) { + p = p.substring(1); + } + + // get the file + IFile f = project.getFile(new Path(p)); + list.add(f); + } + } + } +} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/builders/PreCompilerBuilder.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/builders/PreCompilerBuilder.java index e58e96d..8cd7aa4 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/builders/PreCompilerBuilder.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/builders/PreCompilerBuilder.java @@ -22,6 +22,7 @@ import com.android.ide.eclipse.adt.internal.build.AaptParser; import com.android.ide.eclipse.adt.internal.build.AidlGenerator; import com.android.ide.eclipse.adt.internal.build.JavaGenerator; import com.android.ide.eclipse.adt.internal.build.Messages; +import com.android.ide.eclipse.adt.internal.build.RenderScriptGenerator; import com.android.ide.eclipse.adt.internal.preferences.AdtPrefs; import com.android.ide.eclipse.adt.internal.preferences.AdtPrefs.BuildVerbosity; import com.android.ide.eclipse.adt.internal.project.AndroidManifestHelper; @@ -467,18 +468,33 @@ public class PreCompilerBuilder extends BaseBuilder { saveProjectBooleanProperty(PROPERTY_COMPILE_RESOURCES , mMustCompileResources); } - if (mMustCompileResources) { - handleResources(project, javaPackage, projectTarget, manifestFile, libProjects); - } - // run the Java generators - boolean generatorStatus = false; + int generatorStatus = JavaGenerator.COMPILE_STATUS_NONE; for (JavaGenerator generator : mGeneratorList) { - generatorStatus |= generator.compileFiles(this, - project, projectTarget, sourceFolderPathList, monitor); + try { + generatorStatus |= generator.compileFiles(this, + project, projectTarget, sourceFolderPathList, monitor); + } catch (Throwable t) { + } + } + + // if a generator created some resources file, force recompilation of the resources. + if ((generatorStatus & JavaGenerator.COMPILE_STATUS_RES) != 0) { + mMustCompileResources = true; + // save the current state before attempting the compilation + saveProjectBooleanProperty(PROPERTY_COMPILE_RESOURCES , mMustCompileResources); + } + + // handle the resources, after the java generators are run since some (renderscript) + // generate resources. + boolean compiledTheResources = mMustCompileResources; + if (mMustCompileResources) { + handleResources(project, javaPackage, projectTarget, manifestFile, libProjects); + saveProjectBooleanProperty(PROPERTY_COMPILE_RESOURCES , false); } - if (generatorStatus == false && mMustCompileResources == false) { + if (generatorStatus == JavaGenerator.COMPILE_STATUS_NONE && + compiledTheResources == false) { AdtPlugin.printBuildToConsole(BuildVerbosity.VERBOSE, project, Messages.Nothing_To_Compile); } @@ -539,6 +555,8 @@ public class PreCompilerBuilder extends BaseBuilder { // load the java generators JavaGenerator aidlGenerator = new AidlGenerator(javaProject, mGenFolder); mGeneratorList.add(aidlGenerator); + JavaGenerator renderScriptGenerator = new RenderScriptGenerator(javaProject, mGenFolder); + mGeneratorList.add(renderScriptGenerator); mDerivedProgressMonitor = new DerivedProgressMonitor(mGenFolder); } diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/builders/PreCompilerDeltaVisitor.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/builders/PreCompilerDeltaVisitor.java index 25436ee..b39236a 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/builders/PreCompilerDeltaVisitor.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/builders/PreCompilerDeltaVisitor.java @@ -55,9 +55,7 @@ import java.util.List; * <li>Any modification to aidl files.</li> * */ -class PreCompilerDeltaVisitor extends BaseDeltaVisitor implements - IResourceDeltaVisitor { - +class PreCompilerDeltaVisitor extends BaseDeltaVisitor implements IResourceDeltaVisitor { // Result fields. /** @@ -346,6 +344,10 @@ class PreCompilerDeltaVisitor extends BaseDeltaVisitor implements mBuilder.getProject(), message); } + for (GeneratorDeltaVisitor dv : mGeneratorDeltaVisitors) { + dv.handleResourceFile((IFile)resource, kind); + } + if (AndroidConstants.EXT_XML.equalsIgnoreCase(ext)) { if (kind != IResourceDelta.REMOVED) { // check xml Validity diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/manager/FolderTypeRelationship.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/manager/FolderTypeRelationship.java index 77a8649..168f7fb 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/manager/FolderTypeRelationship.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/manager/FolderTypeRelationship.java @@ -62,6 +62,7 @@ public final class FolderTypeRelationship { folderToTypeMap); add(ResourceType.LAYOUT, ResourceFolderType.LAYOUT, typeToFolderMap, folderToTypeMap); add(ResourceType.MENU, ResourceFolderType.MENU, typeToFolderMap, folderToTypeMap); + add(ResourceType.MIPMAP, ResourceFolderType.MIPMAP, typeToFolderMap, folderToTypeMap); add(ResourceType.PLURALS, ResourceFolderType.VALUES, typeToFolderMap, folderToTypeMap); add(ResourceType.PUBLIC, ResourceFolderType.VALUES, typeToFolderMap, folderToTypeMap); add(ResourceType.RAW, ResourceFolderType.RAW, typeToFolderMap, folderToTypeMap); diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/manager/ResourceFolderType.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/manager/ResourceFolderType.java index 2243e6b..91aec28 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/manager/ResourceFolderType.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/manager/ResourceFolderType.java @@ -30,6 +30,7 @@ public enum ResourceFolderType { INTERPOLATOR(SdkConstants.FD_INTERPOLATOR), LAYOUT(SdkConstants.FD_LAYOUT), MENU(SdkConstants.FD_MENU), + MIPMAP(SdkConstants.FD_MIPMAP), RAW(SdkConstants.FD_RAW), VALUES(SdkConstants.FD_VALUES), XML(SdkConstants.FD_XML); diff --git a/sdkmanager/libs/sdklib/src/com/android/sdklib/IAndroidTarget.java b/sdkmanager/libs/sdklib/src/com/android/sdklib/IAndroidTarget.java index 3be51d2..c0dcaa7 100644 --- a/sdkmanager/libs/sdklib/src/com/android/sdklib/IAndroidTarget.java +++ b/sdkmanager/libs/sdklib/src/com/android/sdklib/IAndroidTarget.java @@ -79,6 +79,8 @@ public interface IAndroidTarget extends Comparable<IAndroidTarget> { public final static int ANT = 24; /** OS Path to the Renderscript include folder. */ public final static int ANDROID_RS = 25; + /** OS Path to the Renderscript(clang) include folder. */ + public final static int ANDROID_RS_CLANG = 26; /** * Return value for {@link #getUsbVendorId()} meaning no USB vendor IDs are defined by the diff --git a/sdkmanager/libs/sdklib/src/com/android/sdklib/PlatformTarget.java b/sdkmanager/libs/sdklib/src/com/android/sdklib/PlatformTarget.java index 817053c..6aeeade 100644 --- a/sdkmanager/libs/sdklib/src/com/android/sdklib/PlatformTarget.java +++ b/sdkmanager/libs/sdklib/src/com/android/sdklib/PlatformTarget.java @@ -16,9 +16,10 @@ package com.android.sdklib; +import com.android.sdklib.util.SparseArray; + import java.io.File; import java.util.Collections; -import java.util.HashMap; import java.util.Map; /** @@ -40,7 +41,7 @@ final class PlatformTarget implements IAndroidTarget { private final String mVersionName; private final int mRevision; private final Map<String, String> mProperties; - private final Map<Integer, String> mPaths = new HashMap<Integer, String>(); + private final SparseArray<String> mPaths = new SparseArray<String>(); private String[] mSkins; @@ -77,6 +78,7 @@ final class PlatformTarget implements IAndroidTarget { mPaths.put(SOURCES, mRootFolderOsPath + SdkConstants.FD_ANDROID_SOURCES); mPaths.put(ANDROID_AIDL, mRootFolderOsPath + SdkConstants.FN_FRAMEWORK_AIDL); mPaths.put(ANDROID_RS, mRootFolderOsPath + SdkConstants.OS_FRAMEWORK_RS); + mPaths.put(ANDROID_RS_CLANG, mRootFolderOsPath + SdkConstants.OS_FRAMEWORK_RS_CLANG); mPaths.put(IMAGES, mRootFolderOsPath + SdkConstants.OS_IMAGES_FOLDER); mPaths.put(SAMPLES, mRootFolderOsPath + SdkConstants.OS_PLATFORM_SAMPLES_FOLDER); mPaths.put(SKINS, mRootFolderOsPath + SdkConstants.OS_SKINS_FOLDER); diff --git a/sdkmanager/libs/sdklib/src/com/android/sdklib/SdkConstants.java b/sdkmanager/libs/sdklib/src/com/android/sdklib/SdkConstants.java index 30451cf..f8f7f19 100644 --- a/sdkmanager/libs/sdklib/src/com/android/sdklib/SdkConstants.java +++ b/sdkmanager/libs/sdklib/src/com/android/sdklib/SdkConstants.java @@ -66,6 +66,8 @@ public final class SdkConstants { public static final String FN_FRAMEWORK_RENDERSCRIPT = "renderscript"; /** framework include folder */ public static final String FN_FRAMEWORK_INCLUDE = "include"; + /** framework include (clang) folder */ + public static final String FN_FRAMEWORK_INCLUDE_CLANG = "clang-include"; /** layoutlib.jar file */ public static final String FN_LAYOUTLIB_JAR = "layoutlib.jar"; /** widget list file */ @@ -192,6 +194,8 @@ public final class SdkConstants { public final static String FD_LAYOUT = "layout"; //$NON-NLS-1$ /** Default menu resource folder name, i.e. "menu" */ public final static String FD_MENU = "menu"; //$NON-NLS-1$ + /** Default menu resource folder name, i.e. "mipmap" */ + public final static String FD_MIPMAP = "mipmap"; //$NON-NLS-1$ /** Default values resource folder name, i.e. "values" */ public final static String FD_VALUES = "values"; //$NON-NLS-1$ /** Default xml resource folder name, i.e. "xml" */ @@ -343,6 +347,9 @@ public final class SdkConstants { /** Path of the renderscript include folder relative to a platform folder. */ public final static String OS_FRAMEWORK_RS = FN_FRAMEWORK_RENDERSCRIPT + File.separator + FN_FRAMEWORK_INCLUDE; + /** Path of the renderscript (clang) include folder relative to a platform folder. */ + public final static String OS_FRAMEWORK_RS_CLANG = + FN_FRAMEWORK_RENDERSCRIPT + File.separator + FN_FRAMEWORK_INCLUDE_CLANG; /* Folder paths relative to a addon folder */ |