| /* |
| * 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.annotations.NonNull; |
| import com.android.ide.eclipse.adt.AdtConstants; |
| import com.android.ide.eclipse.adt.AdtPlugin; |
| import com.android.ide.eclipse.adt.internal.project.BaseProjectHelper; |
| import com.android.sdklib.build.RenderScriptProcessor.CommandLineLauncher; |
| |
| 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.IProgressMonitor; |
| import org.eclipse.core.runtime.IStatus; |
| import org.eclipse.core.runtime.Path; |
| |
| import java.io.File; |
| import java.io.IOException; |
| import java.util.ArrayList; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.regex.Matcher; |
| import java.util.regex.Pattern; |
| |
| /** |
| * A {@link SourceProcessor} for RenderScript files. |
| */ |
| public class RenderScriptLauncher implements CommandLineLauncher { |
| |
| /** |
| * Single line llvm-rs-cc error: {@code <path>:<line>:<col>: <error>} |
| */ |
| private static Pattern sLlvmPattern1 = Pattern.compile("^(.+?):(\\d+):(\\d+):\\s(.+)$"); //$NON-NLS-1$ |
| |
| @NonNull |
| private final IProject mProject; |
| @NonNull |
| private final IFolder mSourceOutFolder; |
| @NonNull |
| private final IFolder mResOutFolder; |
| @NonNull |
| private final IProgressMonitor mMonitor; |
| private final boolean mVerbose; |
| |
| public RenderScriptLauncher( |
| @NonNull IProject project, |
| @NonNull IFolder sourceOutFolder, |
| @NonNull IFolder resOutFolder, |
| @NonNull IProgressMonitor monitor, |
| boolean verbose) { |
| mProject = project; |
| mSourceOutFolder = sourceOutFolder; |
| mResOutFolder = resOutFolder; |
| mMonitor = monitor; |
| mVerbose = verbose; |
| } |
| |
| @Override |
| public void launch(File executable, List<String> arguments, Map<String, String> envVariableMap) |
| throws IOException, InterruptedException { |
| // do the exec |
| try { |
| if (mVerbose) { |
| StringBuilder sb = new StringBuilder(executable.getAbsolutePath()); |
| for (String c : arguments) { |
| sb.append(' ').append(c); |
| } |
| String cmd_line = sb.toString(); |
| AdtPlugin.printToConsole(mProject, cmd_line); |
| } |
| |
| String[] commandArray = new String[1 + arguments.size()]; |
| commandArray[0] = executable.getAbsolutePath(); |
| System.arraycopy(arguments.toArray(), 0, commandArray, 1, arguments.size()); |
| |
| ProcessBuilder processBuilder = new ProcessBuilder(commandArray); |
| Map<String, String> processEnvs = processBuilder.environment(); |
| for (Map.Entry<String, String> entry : envVariableMap.entrySet()) { |
| processEnvs.put(entry.getKey(), entry.getValue()); |
| } |
| |
| Process p = processBuilder.start(); |
| |
| // list to store each line of stderr |
| ArrayList<String> stdErr = new ArrayList<String>(); |
| |
| // get the output and return code from the process |
| int returnCode = BuildHelper.grabProcessOutput(mProject, p, stdErr); |
| |
| if (stdErr.size() > 0) { |
| // attempt to parse the error output |
| boolean parsingError = parseLlvmOutput(stdErr); |
| |
| // If the process failed and we couldn't parse the output |
| // we print a message, mark the project and exit |
| if (returnCode != 0) { |
| |
| if (parsingError || mVerbose) { |
| // display the message in the console. |
| if (parsingError) { |
| AdtPlugin.printErrorToConsole(mProject, stdErr.toArray()); |
| |
| // mark the project |
| BaseProjectHelper.markResource(mProject, |
| AdtConstants.MARKER_RENDERSCRIPT, |
| "Unparsed Renderscript error! Check the console for output.", |
| IMarker.SEVERITY_ERROR); |
| } else { |
| AdtPlugin.printToConsole(mProject, stdErr.toArray()); |
| } |
| } |
| return; |
| } |
| } else if (returnCode != 0) { |
| // no stderr output but exec failed. |
| String msg = String.format("Error executing Renderscript: Return code %1$d", |
| returnCode); |
| |
| BaseProjectHelper.markResource(mProject, AdtConstants.MARKER_AIDL, |
| msg, IMarker.SEVERITY_ERROR); |
| |
| return; |
| } |
| } catch (IOException e) { |
| // mark the project and exit |
| String msg = String.format( |
| "Error executing Renderscript. Please check %1$s is present at %2$s", |
| executable.getName(), executable.getAbsolutePath()); |
| AdtPlugin.log(IStatus.ERROR, msg); |
| BaseProjectHelper.markResource(mProject, AdtConstants.MARKER_RENDERSCRIPT, msg, |
| IMarker.SEVERITY_ERROR); |
| throw e; |
| } catch (InterruptedException e) { |
| // mark the project and exit |
| String msg = String.format( |
| "Error executing Renderscript. Please check %1$s is present at %2$s", |
| executable.getName(), executable.getAbsolutePath()); |
| AdtPlugin.log(IStatus.ERROR, msg); |
| BaseProjectHelper.markResource(mProject, AdtConstants.MARKER_RENDERSCRIPT, msg, |
| IMarker.SEVERITY_ERROR); |
| throw e; |
| } |
| |
| try { |
| mSourceOutFolder.refreshLocal(IResource.DEPTH_ONE, mMonitor); |
| mResOutFolder.refreshLocal(IResource.DEPTH_ONE, mMonitor); |
| } catch (CoreException e) { |
| AdtPlugin.log(e, "failed to refresh folders"); |
| } |
| |
| return; |
| } |
| |
| /** |
| * 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 |
| String rootPath = mProject.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 = mProject.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, AdtConstants.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; |
| } |
| } |