OSDN Git Service

Add Renderscript support to the ADT builders.
authorXavier Ducrohet <xav@android.com>
Tue, 1 Feb 2011 01:22:59 +0000 (17:22 -0800)
committerXavier Ducrohet <xav@android.com>
Tue, 1 Feb 2011 04:13:09 +0000 (20:13 -0800)
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:
anttasks/src/com/android/ant/RenderScriptTask.java
anttasks/src/com/android/ant/SetupTask.java
eclipse/plugins/com.android.ide.eclipse.adt/plugin.xml
eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/AndroidConstants.java
eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/AidlGenerator.java
eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/GeneratorDeltaVisitor.java
eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/JavaGenerator.java
eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/NonJavaFileBundle.java
eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/RenderScriptGenerator.java [new file with mode: 0644]
eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/builders/PreCompilerBuilder.java
eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/builders/PreCompilerDeltaVisitor.java
eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/manager/FolderTypeRelationship.java
eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/manager/ResourceFolderType.java
sdkmanager/libs/sdklib/src/com/android/sdklib/IAndroidTarget.java
sdkmanager/libs/sdklib/src/com/android/sdklib/PlatformTarget.java
sdkmanager/libs/sdklib/src/com/android/sdklib/SdkConstants.java

index f001311..5aa6612 100644 (file)
@@ -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");
index c3cedfd..6dc2c0f 100644 (file)
@@ -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.
index 2ce6257..ce54cac 100644 (file)
       <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">
index d733080..0ed318a 100644 (file)
@@ -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$
index 24b5b67..3b28107 100644 (file)
@@ -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
index 8419b24..aeda16b 100644 (file)
@@ -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;
     }
 
index 73a18c6..33f3947 100644 (file)
@@ -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();
index e75add0..fe071fb 100644 (file)
@@ -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 (file)
index 0000000..4a8abe5
--- /dev/null
@@ -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>
+     * "&lt;path&gt;:&lt;line&gt;:&lt;col&gt;: &lt;error&gt;"
+     */
+    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);
+            }
+        }
+    }
+}
index e58e96d..8cd7aa4 100644 (file)
@@ -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);
     }
index 25436ee..b39236a 100644 (file)
@@ -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
index 77a8649..168f7fb 100644 (file)
@@ -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);
index 2243e6b..91aec28 100644 (file)
@@ -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);
index 3be51d2..c0dcaa7 100644 (file)
@@ -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
index 817053c..6aeeade 100644 (file)
 
 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);
index 30451cf..f8f7f19 100644 (file)
@@ -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 */