blob: 891593ff66cd0fb698072701c0f440e70aab791a [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2012 University of Illinois and others. All rights reserved.
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v1.0 which accompanies this distribution,
* and is available at http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Chris Navarro (Illinois/NCSA) - Design and implementation
*******************************************************************************/
package org.eclipse.ptp.internal.etfw;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Map;
import org.eclipse.cdt.make.core.IMakeBuilderInfo;
import org.eclipse.cdt.make.core.IMakeTarget;
import org.eclipse.cdt.make.core.MakeCorePlugin;
import org.eclipse.cdt.make.internal.core.MakeTargetManager;
import org.eclipse.cdt.managedbuilder.core.BuildException;
import org.eclipse.cdt.managedbuilder.core.IConfiguration;
import org.eclipse.cdt.managedbuilder.core.IManagedBuildInfo;
import org.eclipse.cdt.managedbuilder.core.IManagedProject;
import org.eclipse.cdt.managedbuilder.core.IOption;
import org.eclipse.cdt.managedbuilder.core.ITool;
import org.eclipse.cdt.managedbuilder.core.IToolChain;
import org.eclipse.cdt.managedbuilder.core.ManagedBuildManager;
import org.eclipse.core.filesystem.EFS;
import org.eclipse.core.filesystem.IFileInfo;
import org.eclipse.core.filesystem.IFileStore;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IncrementalProjectBuilder;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.OperationCanceledException;
import org.eclipse.core.runtime.Status;
import org.eclipse.debug.core.ILaunchConfiguration;
import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy;
import org.eclipse.ptp.etfw.IBuildLaunchUtils;
import org.eclipse.ptp.etfw.IToolLaunchConfigurationConstants;
import org.eclipse.ptp.internal.etfw.jaxb.data.BuildToolType;
import org.eclipse.ptp.internal.etfw.messages.Messages;
/**
* This class is based on BuilderTool and handles workflow steps that rebuild tools with performance instrumentation.
*
* @see BuilderTool
* @author "Chris Navarro"
*
*/
public class ETFWBuildTool extends ETFWToolStep implements IToolLaunchConfigurationConstants {
private static final String CComp = "CC";
private static final String CxxComp = "CXX";
private static final String FComp = "F90";
private static final String EQ = ":=";
private static int modifyCommand(ITool tool, String command, String args, boolean replace) {
int didChange = 0;
final String toolCommand = tool.getToolCommand();
if (replace) {
final String newcom = command + " " + args; //$NON-NLS-1$
if (!newcom.equals(toolCommand)) {
tool.setToolCommand(command + " " + args); //$NON-NLS-1$
didChange = 1;
}
} else {
String oldcom = toolCommand.trim();
final int lastspc = oldcom.lastIndexOf(' ');
if (lastspc >= 0) {
oldcom = toolCommand.substring(lastspc).trim();
}
final String newcom = command + SPACE + args + SPACE + oldcom;
if (!newcom.equals(toolCommand)) {
tool.setToolCommand(newcom);
didChange = 1;
}
}
return didChange;
}
/**
* The location of the binary rebuilt with performance instrumentation
*/
private String progPath = null;
/**
* False implies that no execution is to take place (either because of an
* error, or user request)
* */
private boolean runbuilt = false;
/** Executable (application) path attribute name */
private IConfiguration newBuildConfig = null;
private String buildConf = null;
private IConfiguration olddefbuildconf = null;
private IManagedBuildInfo buildInfo = null;
private Map<String, String> buildMods = null;
private String newname = null;
private String binary = null;
private BuildToolType tool = null;
private IBuildLaunchUtils utilBlob = null;
public IConfiguration selectedconf = null;
private boolean isManaged;
public ETFWBuildTool(ILaunchConfiguration conf, BuildToolType btool, IBuildLaunchUtils utilBlob) throws CoreException {
super(conf, Messages.BuilderTool_InstrumentingBuilding, utilBlob);
this.utilBlob = utilBlob;
tool = btool;
initBuild(conf);
}
public ETFWBuildTool(ILaunchConfiguration conf, BuildToolType btool, Map<String, String> buildMods, IBuildLaunchUtils utilBlob)
throws CoreException {
super(conf, Messages.BuilderTool_InstrumentingBuilding, utilBlob);
this.buildMods = buildMods;
this.utilBlob = utilBlob;
tool = btool;
initBuild(conf);
}
/**
* Builds the project with managed make if supported, otherwise with
* standard make
*
* @param monitor
* @throws Exception
*/
public void buildIndstrumented(IProgressMonitor monitor) throws Exception {
// if(tool==null)
// throw new Exception("No valid tool configuration found");
// runbuilt = true;
if (tool != null) {
if (!isManaged) {
standardMakeBuild(monitor);
} else {
if (runbuilt) {
runbuilt = initMMBuildConf();
if (runbuilt) {
runbuilt = managedMakeBuild(monitor);
}
}
}
}
}
public String getOutputLocation() {
return outputLocation;
}
public String getProgramPath() {
return progPath;
}
private String getStandardMakeBuildOps(BuildToolType tool, ILaunchConfiguration configuration, String allargs)
throws CoreException {
String ops = EMPTY;
// String tmp;
if (tool.getCcCompiler() != null) {
ops += getStandardMakeOp(CComp, getToolCommand(tool.getCcCompiler(), configuration), allargs, tool.isReplaceCompiler());
}
if (tool.getCxxCompiler() != null) {
ops += getStandardMakeOp(CxxComp, getToolCommand(tool.getCxxCompiler(), configuration), allargs,
tool.isReplaceCompiler());
}
if (tool.getF90Compiler() != null) {
ops += getStandardMakeOp(FComp, getToolCommand(tool.getF90Compiler(), configuration), allargs, tool.isReplaceCompiler());
}
return ops;
}
private String getStandardMakeOp(String var, String command, String args, boolean replace) {
String op = EMPTY;
if (command != null) {
op = var + EQ + command + SPACE + args;
if (!replace) {
op += SPACE + "$(" + var + ")";
}
op += NEWLINE;
}
return op;
}
private void initBuild(ILaunchConfiguration conf) throws CoreException {
buildConf = configuration.getAttribute(ATTR_PERFORMANCEBUILD_CONFIGURATION_NAME, (String) null);
if (tool == null) {
return;
}
buildInfo = ManagedBuildManager.getBuildInfo(thisProject);
olddefbuildconf = buildInfo.getDefaultConfiguration();// TODO: Make sure
// default
// configuration
// always works.
// Prompt user?
isManaged = olddefbuildconf.isManagedBuildOn();
if (isManaged) {
runbuilt = initMMBuild();
} else {
runbuilt = initSMBuild();
}
}
private boolean initMMBuild() throws CoreException {
if (buildInfo == null || !buildInfo.isValid()) {
System.out.println(Messages.BuilderTool_NoInfo);
return false;
}
final IManagedProject managedBuildProj = buildInfo.getManagedProject();
if (managedBuildProj == null) {
System.out.println(Messages.BuilderTool_NoManagedProject);
return false;
}
binary = buildInfo.getBuildArtifactName();
if (binary.equals("${ProjName}")) {
binary = thisProject.getName();
}
final String bextension = buildInfo.getBuildArtifactExtension();
if (bextension.length() > 0) {
binary = binary + "." + bextension; //$NON-NLS-1$
}
// Make a list of the configurations already within the project
final IConfiguration[] buildconfigs = buildInfo.getManagedProject().getConfigurations();
// IConfiguration selectedconf = null;
for (final IConfiguration buildconfig : buildconfigs) {
if ((buildconfig.getName()).equals(buildConf)) {
selectedconf = buildconfig;
break;
}
}
if (selectedconf == null) {
System.out.println(Messages.BuilderTool_NoConfSelected);
return false;
}
if (selectedconf.getName() == null) {
System.out.println(Messages.BuilderTool_SelConfHasNoName);
return false;
}
// Make the new configuration name, and if there is already a
// configuration with that name, remove it.
final String basename = selectedconf.getName();
newname = null;// =basename+"_PerformanceAnalysis"; //TODO: FIX RECOVERY
// OF TOOLID!!!
final String addname = configuration.getAttribute(TOOLCONFNAME + tool.getToolId(), DEFAULT_TOOLCONFNAME);
// if(basename.indexOf(addname)<0)
newname = basename + "_" + addname; //$NON-NLS-1$
if (addname.equals(DEFAULT_TOOLCONFNAME)) {
String nameMod = tool.getToolName();// tool.toolName;
if (nameMod == null) {
nameMod = tool.getToolId();
}
newname += "_" + nameMod; //$NON-NLS-1$
}
progPath = newname + File.separator + binary;
// TODO: Need to get rid of this file
// TODO: We have to do this because PTP puts its output in the build
// directory
if (configuration.getAttribute(EXTOOL_EXECUTABLE_PATH_TAG, (String) null) != null) {
outputLocation = thisProject.getFile(newname).getLocationURI().getPath();// .toOSString();
}
boolean confExists = false;
final IConfiguration[] confs = managedBuildProj.getConfigurations();
for (final IConfiguration conf : confs) {
if (conf.getName().equals(newname) || conf.getName().indexOf(newname) >= 0) {
confExists = true;
newBuildConfig = conf;
break;
// managedBuildProj.removeConfiguration(confs[i].getId());
}
}
// Make a copy of the selected configuration(Clone works, basic create
// does not) and rename it.
if (!confExists) {
newBuildConfig = managedBuildProj.createConfigurationClone(selectedconf, selectedconf.getId()
+ "." + ManagedBuildManager.getRandomNumber()); //$NON-NLS-1$
}
if (newBuildConfig == null) {
System.out.println(Messages.BuilderTool_NoConfig);
return false;
}
return true;
}
/**
* Runs the managed make build system using the performance tool's compilers
* and compiler options. This is accomplished by creating a new build
* configuration and replacing the compiler with the relevant tool commands
*
* @param monitor
* @throws CoreException
* @throws FileNotFoundException
*/
public boolean initMMBuildConf() throws CoreException, FileNotFoundException {
// boolean preconf=false;
if (newBuildConfig.getName().equals(newname)) {
// preconf=true;
} else {
newBuildConfig.setName(newname);
}
final IToolChain chain = newBuildConfig.getToolChain();
final ITool[] tools = chain.getTools();
for (final ITool it : tools) {
for (final IOption op : it.getOptions()) {
if (op == null) {
continue;
}
if (op.getName() == null) {
continue;
}
// if(op.getName().equals("Optimization Level")){
// System.out.println(op.getName()+" ID: "+op.getBaseId());
// for(String vals:op.getApplicableValues())
// {
// System.out.println(vals);
// }
// }
}
}
// TODO: Make sure this never has side-effects.
String allargs = ""; //$NON-NLS-1$
if (tool.getAllCompilers() != null && !tool.getAllCompilers().equals(tool.getCcCompiler())) {
allargs = getToolArguments(tool.getAllCompilers(), configuration);
}
int numChanges = 0;
for (final ITool tool2 : tools) {
if (buildMods != null) {
for (final String opName : buildMods.keySet()) {
// System.out.println(op.getName()+" ID: "+op.getBaseId());
for (final IOption op : tool2.getOptions()) {
// IOption op=tools[i].getOptionById(opId);
if (op.getName().equals(opName))// op.getName().equals("Optimization Level"))
{
try {
op.setValue(buildMods.get(opName));
} catch (final BuildException e) {
e.printStackTrace();
}
}
}
}
}
final String toolid = tool2.getId();
if (toolid.indexOf(".c.") >= 0) //$NON-NLS-1$
{
numChanges += modifyCommand(tool2, getToolCommand(tool.getCcCompiler(), configuration), allargs,
tool.isReplaceCompiler());
}
if (toolid.indexOf(".cpp.") >= 0) //$NON-NLS-1$
{
numChanges += modifyCommand(tool2, getToolCommand(tool.getCxxCompiler(), configuration), allargs,
tool.isReplaceCompiler());
}
if (toolid.indexOf(".fortran.") >= 0) //$NON-NLS-1$
{
numChanges += modifyCommand(tool2, getToolCommand(tool.getF90Compiler(), configuration), allargs,
tool.isReplaceCompiler());
}
}
// System.out.println(tbpath+File.separator+"tau_xxx.sh"+tauCompilerArgs);
if (numChanges > 0) {
ManagedBuildManager.saveBuildInfo(thisProject, true);
}
return true;
}
private boolean initSMBuild() throws CoreException {
if (buildInfo == null || !buildInfo.isValid()) {
System.out.println(Messages.BuilderTool_NoInfo);
return false;
}
// Make a list of the configurations already within the project
final IConfiguration[] buildconfigs = buildInfo.getManagedProject().getConfigurations();
// IConfiguration selectedconf = null;
for (final IConfiguration buildconfig : buildconfigs) {
if ((buildconfig.getName()).equals(buildConf)) {
selectedconf = buildconfig;
break;
}
}
progPath = olddefbuildconf.getEditableBuilder().getBuildLocation().toOSString();// + "?";
newname = progPath;
// progPath = newname + File.separator + binary;
// System.out.println(progPath);
// TODO: We have to do this because PTP puts its output in the build
// directory
if (configuration.getAttribute(EXTOOL_EXECUTABLE_PATH_TAG, (String) null) != null) {
if (newname == null) {
outputLocation = "";
} else {
final IFileStore newFile = utilBlob.getFile(newname);// thisProject.getFile(newname);
if (newFile.fetchInfo().exists()) {
outputLocation = newFile.toURI().getPath(); // buildco.getLocationURI().getPath();
} else {
outputLocation = "";
}
}
}
return true;
}
private boolean managedMakeBuild(IProgressMonitor monitor) {
// Build set the new configuration to default so we can build it.
IFile programPath = null;
IFileStore pathStore = null;
if (isSyncProject) {
pathStore = utilBlob.getFile(outputLocation);
pathStore = pathStore.getChild(progPath);
} else {
programPath = thisProject.getFile(progPath);
pathStore = utilBlob.getFile(programPath.getLocationURI().getPath());
}
// long lastBuilt=-1;
// if(pathStore.fetchInfo().exists()){
// lastBuilt=pathStore.fetchInfo().getLastModified();
// }
ManagedBuildManager.setDefaultConfiguration(thisProject, newBuildConfig);
try {
thisProject.build(IncrementalProjectBuilder.FULL_BUILD, monitor);// .FULL_BUILD
// //.INCREMENTAL_BUILD
} catch (final Exception e) {
return false;
}
while (waitForBuild(-1, programPath, pathStore.fetchInfo())) {// !programPath.exists() || !pathStore.fetchInfo().exists()) {
if (monitor != null && monitor.isCanceled()) {
// ManagedBuildManager.setDefaultConfiguration(thisCProject.getProject(),olddefbuildconf);
restoreBuild();
runbuilt = false;
throw new OperationCanceledException();
}
final long numMillisecondsToSleep = 1000;
try {
Thread.sleep(numMillisecondsToSleep);
} catch (final InterruptedException e) {
}
if (!isSyncProject) {
programPath = thisProject.getFile(progPath);
}
}
restoreBuild();
return true;
}
public void restoreBuild() {
if (isManaged) {
ManagedBuildManager.setDefaultConfiguration(thisProject, olddefbuildconf);
// if(!configuration.getAttribute(NOCLEAN,
// false)&&managedBuildProj!=null&&newBuildConfig!=null)
// managedBuildProj.removeConfiguration(newBuildConfig.getId());
}
}
@Override
protected IStatus run(IProgressMonitor monitor) {
try {
buildIndstrumented(monitor);
} catch (final Exception e) {
return new Status(IStatus.ERROR, "com.ibm.jdg2e.concurrency", IStatus.ERROR, Messages.BuilderTool_BuildIncomplete, e); //$NON-NLS-1$
}
return new Status(IStatus.OK, "com.ibm.jdg2e.concurrency", IStatus.OK, Messages.BuilderTool_BuildSuccessful, null); //$NON-NLS-1$
}
@Override
public void setSuccessAttribute(String value) {
if (tool != null && tool.getSetSuccessAttribute() != null) {
try {
final ILaunchConfigurationWorkingCopy configuration = this.configuration.getWorkingCopy();
configuration.setAttribute(tool.getSetSuccessAttribute(), value);
configuration.doSave();
} catch (final CoreException e) {
// Ignore
}
}
}
/**
* Runs the standard make build system using the tool-supplied compiler and
* compiler options. This is accomplished by temporarily replacing the
* default compiler names in a pre-defined makefile inclusion with the names
* and arguments of the compilers
*
* @param monitor
* @throws CoreException
*/
public void standardMakeBuild(IProgressMonitor monitor) throws CoreException {
final IFileStore projectFileStore = utilBlob.getFile(projectLocation);
final IFileStore compilerInclude = projectFileStore.getChild("eclipse.inc");//new File(projectLocation + File.separator + "eclipse.inc"); //$NON-NLS-1$
//IFileStore compilerDef = projectFileStore.getChild("eclipse.inc.default");// new File(projectLocation + File.separator + "eclipse.inc.default"); //$NON-NLS-1$
try {
// if (compilerInclude.fetchInfo().exists()) {
// compilerInclude.copy(compilerDef, EFS.OVERWRITE, null);
// InputStream in = compilerInclude.openInputStream(EFS.NONE, null);// new FileInputStream(compilerInclude);
// OutputStream out = compilerDef.openOutputStream(EFS.NONE, null);//new FileOutputStream(compilerDef);
//
// byte[] buf = new byte[1024];
// int len;
// while ((len = in.read(buf)) > 0) {
// out.write(buf, 0, len);
// }
// in.close();
// out.close();
// }
final BufferedOutputStream makeOut = new BufferedOutputStream(compilerInclude.openOutputStream(EFS.NONE, null));
final String allargs = getToolArguments(tool.getAllCompilers(), configuration);
final String ops = getStandardMakeBuildOps(tool, configuration, allargs);
makeOut.write(ops.getBytes());
makeOut.close();
} catch (final FileNotFoundException e) {
e.printStackTrace();
} catch (final IOException e) {
e.printStackTrace();
}
final MakeTargetManager targetMan = new MakeTargetManager();
targetMan.startup();
final IMakeTarget[] targs = targetMan.getTargets(thisProject);
IMakeTarget select = null;
for (final IMakeTarget targ : targs) {
if (targ.getName().equals(Messages.BuilderTool_all)) {
select = targ;
break;
}
// System.out.println(targs[i].getName()+" "+targs[i].getTargetBuilderID());
}
if (select == null) {
if (!isSyncProject) {
final IMakeBuilderInfo info = MakeCorePlugin.createBuildInfo(thisProject,
RemoteBuildLaunchUtils.REMOTE_MAKE_BUILDER_ID);
if (info == null || !info.isFullBuildEnabled()) {
System.out.println(Messages.BuilderTool_NoMakeTargetAll);
runbuilt = false;
return;
}
}
thisProject.build(IncrementalProjectBuilder.CLEAN_BUILD, monitor);
thisProject.build(IncrementalProjectBuilder.FULL_BUILD, monitor);
} else {
// System.out.println(select.getBuildLocation());
select.build(monitor);
}
targetMan.shutdown();
// if (compilerDef.fetchInfo().exists()) {
// InputStream in;
try {
// in = compilerDef.openInputStream(EFS.NONE, null);//new FileInputStream(compilerDef);
final OutputStream out = new BufferedOutputStream(compilerInclude.openOutputStream(EFS.NONE, null));// new
// FileOutputStream(compilerInclude);
// Transfer bytes from in to out
final byte[] buf = new byte[1024];
// int len;
// while ((len = in.read(buf)) > 0) {
out.write(buf, 0, 0);
// }
// in.close();
out.close();
} catch (final FileNotFoundException e) {
e.printStackTrace();
} catch (final IOException e) {
e.printStackTrace();
}
// }
runbuilt = true;
return;
}
private boolean waitForBuild(long lastBuilt, IFile programPath, IFileInfo progInfo) {
if ((programPath != null && !programPath.exists()) && !progInfo.exists()) {
return true;
}
// if(progInfo.getLastModified()==lastBuilt)
// return true;
return false;
}
}