blob: a6b88f4623e7e9307f45ec863b43a5700d60897c [file] [log] [blame]
/*
* 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);
}
}
}