/* * 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.ndk.internal.discovery; import com.android.ide.eclipse.ndk.internal.Activator; import com.android.ide.eclipse.ndk.internal.build.NdkCommandLauncher; import org.eclipse.cdt.core.CCorePlugin; import org.eclipse.cdt.core.envvar.IEnvironmentVariable; import org.eclipse.cdt.core.envvar.IEnvironmentVariableManager; import org.eclipse.cdt.core.settings.model.ICConfigurationDescription; import org.eclipse.cdt.managedbuilder.core.IBuilder; import org.eclipse.cdt.managedbuilder.core.IManagedBuildInfo; import org.eclipse.cdt.managedbuilder.core.ManagedBuildManager; import org.eclipse.core.resources.IProject; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.FileLocator; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.Path; import java.io.BufferedReader; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.net.URISyntaxException; import java.net.URL; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; public class NdkDiscoveryUpdater { private final NdkDiscoveredPathInfo mPathInfo; private final IProject mProject; private boolean mCPlusPlus = false; private String mCommand; private List<String> mArguments = new ArrayList<String>(); public NdkDiscoveryUpdater(NdkDiscoveredPathInfo pathInfo) { mPathInfo = pathInfo; mProject = pathInfo.getProject(); } public void runUpdate(IProgressMonitor monitor) throws CoreException { try { // Run ndk-build -nB to get the list of commands IPath commandPath = new Path("ndk-build"); //$NON-NLS-1$ String[] args = { "-nB"}; //$NON-NLS-1$ String[] env = calcEnvironment(); File projectDir = new File(mProject.getLocationURI()); IPath changeToDirectory = new Path(projectDir.getAbsolutePath()); Process proc = new NdkCommandLauncher().execute(commandPath, args, env, changeToDirectory, monitor); if (proc == null) // proc failed to start return; BufferedReader reader = new BufferedReader(new InputStreamReader(proc.getInputStream())); String line = reader.readLine(); while (line != null) { checkBuildLine(line); line = reader.readLine(); } if (mCommand == null) { return; } // Run the unique commands with special gcc options to extract the // symbols and paths // -E -P -v -dD mArguments.add("-E"); //$NON-NLS-1$ mArguments.add("-P"); //$NON-NLS-1$ mArguments.add("-v"); //$NON-NLS-1$ mArguments.add("-dD"); //$NON-NLS-1$ URL url = Activator.findFile(new Path( "discovery/" + (mCPlusPlus ? "test.cpp" : "test.c"))); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ File testFile = new File(FileLocator.toFileURL(url).toURI()); String testFileName = testFile.getAbsolutePath().replace('\\', '/'); mArguments.add(testFileName); args = mArguments.toArray(new String[mArguments.size()]); proc = new NdkCommandLauncher().execute(new Path(mCommand), args, env, changeToDirectory, monitor); // Error stream has the includes final InputStream errStream = proc.getErrorStream(); new Thread() { @Override public void run() { checkIncludes(errStream); }; }.start(); // Input stream has the defines checkDefines(proc.getInputStream()); } catch (IOException e) { throw new CoreException(Activator.newStatus(e)); } catch (URISyntaxException e) { throw new CoreException(Activator.newStatus(e)); } } private String[] calcEnvironment() throws CoreException { IManagedBuildInfo info = ManagedBuildManager.getBuildInfo(mProject); IBuilder builder = info.getDefaultConfiguration().getBuilder(); HashMap<String, String> envMap = new HashMap<String, String>(); if (builder.appendEnvironment()) { ICConfigurationDescription cfgDes = ManagedBuildManager .getDescriptionForConfiguration(builder.getParent().getParent()); IEnvironmentVariableManager mngr = CCorePlugin.getDefault() .getBuildEnvironmentManager(); IEnvironmentVariable[] vars = mngr.getVariables(cfgDes, true); for (IEnvironmentVariable var : vars) { envMap.put(var.getName(), var.getValue()); } } // Add variables from build info Map<String, String> builderEnv = builder.getExpandedEnvironment(); if (builderEnv != null) envMap.putAll(builderEnv); List<String> strings = new ArrayList<String>(envMap.size()); for (Entry<String, String> entry : envMap.entrySet()) { StringBuffer buffer = new StringBuffer(entry.getKey()); buffer.append('=').append(entry.getValue()); strings.add(buffer.toString()); } return strings.toArray(new String[strings.size()]); } private static class Line { private final String line; private int pos; public Line(String line) { this.line = line; } public Line(String line, int pos) { this(line); this.pos = pos; } public String getToken() { skipWhiteSpace(); if (pos == line.length()) return null; int start = pos; boolean inQuote = false; while (true) { char c = line.charAt(pos); if (c == ' ') { if (!inQuote) return line.substring(start, pos); } else if (c == '"') { inQuote = !inQuote; } if (++pos == line.length()) return null; } } private String getRemaining() { if (pos == line.length()) return null; skipWhiteSpace(); String rc = line.substring(pos); pos = line.length(); return rc; } private void skipWhiteSpace() { while (true) { if (pos == line.length()) return; char c = line.charAt(pos); if (c == ' ') pos++; else return; } } } private void checkBuildLine(String text) { Line line = new Line(text); String cmd = line.getToken(); if (cmd == null) { return; } else if (cmd.endsWith("g++")) { //$NON-NLS-1$ if (mCommand == null || !mCPlusPlus) { mCommand = cmd; mCPlusPlus = true; } gatherOptions(line); } else if (cmd.endsWith("gcc")) { //$NON-NLS-1$ if (mCommand == null) mCommand = cmd; gatherOptions(line); } } private void gatherOptions(Line line) { for (String option = line.getToken(); option != null; option = line.getToken()) { if (option.startsWith("-")) { //$NON-NLS-1$ // only look at options if (option.equals("-I")) { //$NON-NLS-1$ String dir = line.getToken(); if (dir != null) addArg(option + dir); } else if (option.startsWith("-I")) { //$NON-NLS-1$ addArg(option); } else if (option.equals("-D")) { //$NON-NLS-1$ String def = line.getToken(); if (def != null) addArg(option + def); } else if (option.startsWith("-D")) { //$NON-NLS-1$ addArg(option); } else if (option.startsWith("-f")) { //$NON-NLS-1$ addArg(option); } else if (option.startsWith("-m")) { //$NON-NLS-1$ addArg(option); } else if (option.startsWith("--sysroot")) { //$NON-NLS-1$ addArg(option); } } } } private void addArg(String arg) { if (!mArguments.contains(arg)) mArguments.add(arg); } private void checkIncludes(InputStream in) { try { List<String> includes = new ArrayList<String>(); boolean inIncludes1 = false; boolean inIncludes2 = false; BufferedReader reader = new BufferedReader(new InputStreamReader(in)); String line = reader.readLine(); while (line != null) { if (!inIncludes1) { if (line.equals("#include \"...\" search starts here:")) //$NON-NLS-1$ inIncludes1 = true; } else { if (!inIncludes2) { if (line.equals("#include <...> search starts here:")) //$NON-NLS-1$ inIncludes2 = true; else includes.add(line.trim()); } else { if (line.equals("End of search list.")) { //$NON-NLS-1$ mPathInfo.setIncludePaths(includes); } else { includes.add(line.trim()); } } } line = reader.readLine(); } } catch (IOException e) { Activator.log(e); } } private void checkDefines(InputStream in) { try { Map<String, String> defines = new HashMap<String, String>(); BufferedReader reader = new BufferedReader(new InputStreamReader(in)); String line = reader.readLine(); while (line != null) { if (line.startsWith("#define")) { //$NON-NLS-1$ Line l = new Line(line, 7); String var = l.getToken(); if (var == null) continue; String value = l.getRemaining(); if (value == null) value = ""; //$NON-NLS-1$ defines.put(var, value); } line = reader.readLine(); } mPathInfo.setSymbols(defines); } catch (IOException e) { Activator.log(e); } } }