mirror of
https://github.com/eclipse-cdt/cdt
synced 2025-04-29 19:45:01 +02:00
Patch for Sean Evoy:
- Initial makefile generator for managed build.
This commit is contained in:
parent
196aedf345
commit
2ea02e1982
8 changed files with 1084 additions and 188 deletions
|
@ -18,6 +18,7 @@ import junit.framework.TestSuite;
|
||||||
import junit.textui.TestRunner;
|
import junit.textui.TestRunner;
|
||||||
|
|
||||||
import org.eclipse.cdt.core.build.managed.tests.AllBuildTests;
|
import org.eclipse.cdt.core.build.managed.tests.AllBuildTests;
|
||||||
|
import org.eclipse.cdt.core.build.managed.tests.StandardBuildTests;
|
||||||
import org.eclipse.cdt.core.model.failedTests.CModelElementsFailedTests;
|
import org.eclipse.cdt.core.model.failedTests.CModelElementsFailedTests;
|
||||||
import org.eclipse.cdt.core.model.tests.AllCoreTests;
|
import org.eclipse.cdt.core.model.tests.AllCoreTests;
|
||||||
import org.eclipse.cdt.core.model.tests.BinaryTests;
|
import org.eclipse.cdt.core.model.tests.BinaryTests;
|
||||||
|
@ -77,6 +78,7 @@ public class AutomatedIntegrationSuite extends TestSuite
|
||||||
|
|
||||||
// Add all success tests
|
// Add all success tests
|
||||||
suite.addTest(AllBuildTests.suite());
|
suite.addTest(AllBuildTests.suite());
|
||||||
|
suite.addTest(StandardBuildTests.suite());
|
||||||
suite.addTest(ParserTestSuite.suite());
|
suite.addTest(ParserTestSuite.suite());
|
||||||
suite.addTest(AllCoreTests.suite());
|
suite.addTest(AllCoreTests.suite());
|
||||||
suite.addTest(BinaryTests.suite());
|
suite.addTest(BinaryTests.suite());
|
||||||
|
|
|
@ -22,6 +22,15 @@ public interface IManagedBuildInfo {
|
||||||
*/
|
*/
|
||||||
public void addTarget(ITarget target);
|
public void addTarget(ITarget target);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Answers <code>true</code> if the build system knows how to
|
||||||
|
* build a file with the extension passed in the argument.
|
||||||
|
*
|
||||||
|
* @param srcExt
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public boolean buildsFileType(String srcExt);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the name of the artifact to build for the receiver.
|
* Returns the name of the artifact to build for the receiver.
|
||||||
*
|
*
|
||||||
|
@ -29,6 +38,21 @@ public interface IManagedBuildInfo {
|
||||||
*/
|
*/
|
||||||
public String getBuildArtifactName();
|
public String getBuildArtifactName();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Answers the command needed to remove files on the build machine
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public String getCleanCommand();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Answers the name of the default configuration, for example <code>Debug</code>
|
||||||
|
* or <code>Release</code>.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public String getConfigurationName();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the default configuration associated with the receiver
|
* Get the default configuration associated with the receiver
|
||||||
*
|
*
|
||||||
|
@ -53,6 +77,16 @@ public interface IManagedBuildInfo {
|
||||||
*/
|
*/
|
||||||
public String getOutputExtension(String resourceExtension);
|
public String getOutputExtension(String resourceExtension);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Answers the flag to be passed to the build tool to produce a specific output
|
||||||
|
* or an empty <code>String</code> if there is no special flag. For example, the
|
||||||
|
* GCC tools use the -o flag to produce a named output, for example
|
||||||
|
* gcc -c foo.c -o foo.o
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public String getOutputFlag();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the target specified in the argument.
|
* Get the target specified in the argument.
|
||||||
*
|
*
|
||||||
|
@ -88,6 +122,21 @@ public interface IManagedBuildInfo {
|
||||||
*/
|
*/
|
||||||
public String getFlagsForTarget(String extension);
|
public String getFlagsForTarget(String extension);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Answers a string array containing the arguments to be passed to
|
||||||
|
* make. For example, if the user has selected a build that stops
|
||||||
|
* at the first error, the array would contain {"k"}.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public String[] getMakeArguments();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Answers a <code>String</code> containing the make command invocation
|
||||||
|
* for the default target/configuration.
|
||||||
|
*/
|
||||||
|
public String getMakeCommand();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a <code>String</code> containing the command-line invocation
|
* Returns a <code>String</code> containing the command-line invocation
|
||||||
* for the tool associated with the source extension.
|
* for the tool associated with the source extension.
|
||||||
|
@ -120,5 +169,7 @@ public interface IManagedBuildInfo {
|
||||||
* @param target
|
* @param target
|
||||||
*/
|
*/
|
||||||
public void setDefaultTarget(ITarget target);
|
public void setDefaultTarget(ITarget target);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -328,25 +328,6 @@ public class ManagedBuildManager implements IScannerInfoProvider {
|
||||||
getExtensionTargetMap().put(target.getId(), target);
|
getExtensionTargetMap().put(target.getId(), target);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void loadExtensions() {
|
|
||||||
if (extensionTargetsLoaded)
|
|
||||||
return;
|
|
||||||
extensionTargetsLoaded = true;
|
|
||||||
|
|
||||||
IExtensionPoint extensionPoint = CCorePlugin.getDefault().getDescriptor().getExtensionPoint("ManagedBuildInfo");
|
|
||||||
IExtension[] extensions = extensionPoint.getExtensions();
|
|
||||||
for (int i = 0; i < extensions.length; ++i) {
|
|
||||||
IExtension extension = extensions[i];
|
|
||||||
IConfigurationElement[] elements = extension.getConfigurationElements();
|
|
||||||
for (int j = 0; j < elements.length; ++j) {
|
|
||||||
IConfigurationElement element = elements[j];
|
|
||||||
if (element.getName().equals("target")) {
|
|
||||||
new Target(element);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static ManagedBuildInfo loadBuildInfo(IProject project) {
|
private static ManagedBuildInfo loadBuildInfo(IProject project) {
|
||||||
ManagedBuildInfo buildInfo = null;
|
ManagedBuildInfo buildInfo = null;
|
||||||
IFile file = project.getFile(FILE_NAME);
|
IFile file = project.getFile(FILE_NAME);
|
||||||
|
@ -369,6 +350,58 @@ public class ManagedBuildManager implements IScannerInfoProvider {
|
||||||
return buildInfo;
|
return buildInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void loadExtensions() {
|
||||||
|
if (extensionTargetsLoaded)
|
||||||
|
return;
|
||||||
|
extensionTargetsLoaded = true;
|
||||||
|
|
||||||
|
IExtensionPoint extensionPoint = CCorePlugin.getDefault().getDescriptor().getExtensionPoint("ManagedBuildInfo");
|
||||||
|
IExtension[] extensions = extensionPoint.getExtensions();
|
||||||
|
for (int i = 0; i < extensions.length; ++i) {
|
||||||
|
IExtension extension = extensions[i];
|
||||||
|
IConfigurationElement[] elements = extension.getConfigurationElements();
|
||||||
|
for (int j = 0; j < elements.length; ++j) {
|
||||||
|
IConfigurationElement element = elements[j];
|
||||||
|
if (element.getName().equals("target")) {
|
||||||
|
new Target(element);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param project
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static boolean manages(IResource resource) {
|
||||||
|
// The managed build manager manages build information for the
|
||||||
|
// resource IFF it it is a project and has a build file with the proper
|
||||||
|
// root element
|
||||||
|
IProject project = null;
|
||||||
|
if (resource instanceof IProject){
|
||||||
|
project = (IProject)resource;
|
||||||
|
} else if (resource instanceof IFile) {
|
||||||
|
project = ((IFile)resource).getProject();
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
IFile file = project.getFile(FILE_NAME);
|
||||||
|
if (file.exists()) {
|
||||||
|
try {
|
||||||
|
InputStream stream = file.getContents();
|
||||||
|
DocumentBuilder parser = DocumentBuilderFactory.newInstance().newDocumentBuilder();
|
||||||
|
Document document = parser.parse(stream);
|
||||||
|
Node rootElement = document.getFirstChild();
|
||||||
|
if (rootElement.getNodeName().equals(ROOT_ELEM_NAME)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
private static ManagedBuildInfo findBuildInfo(IResource resource, boolean create) {
|
private static ManagedBuildInfo findBuildInfo(IResource resource, boolean create) {
|
||||||
// Make sure the extension information is loaded first
|
// Make sure the extension information is loaded first
|
||||||
loadExtensions();
|
loadExtensions();
|
||||||
|
@ -417,6 +450,11 @@ public class ManagedBuildManager implements IScannerInfoProvider {
|
||||||
* Answers with an interface to the parse information that has been
|
* Answers with an interface to the parse information that has been
|
||||||
* associated with the resource specified in the argument.
|
* associated with the resource specified in the argument.
|
||||||
*
|
*
|
||||||
|
* NOTE: This method is not part of the registration interface. It has
|
||||||
|
* been made public as a short-term workaround for the clients of the
|
||||||
|
* scanner information until the redesign of the build information management
|
||||||
|
* occurs.
|
||||||
|
*
|
||||||
* @param resource
|
* @param resource
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
|
@ -450,6 +488,9 @@ public class ManagedBuildManager implements IScannerInfoProvider {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO Remove all of the IScannerInfoProvider interface methods when
|
||||||
|
// the discovery mechanism is solidified
|
||||||
|
|
||||||
/* (non-Javadoc)
|
/* (non-Javadoc)
|
||||||
* @see org.eclipse.cdt.core.parser.IScannerInfoProvider#managesResource(org.eclipse.core.resources.IResource)
|
* @see org.eclipse.cdt.core.parser.IScannerInfoProvider#managesResource(org.eclipse.core.resources.IResource)
|
||||||
*/
|
*/
|
||||||
|
@ -504,4 +545,5 @@ public class ManagedBuildManager implements IScannerInfoProvider {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -87,6 +87,22 @@ public class ManagedBuildInfo implements IManagedBuildInfo, IScannerInfo {
|
||||||
targets.add(target);
|
targets.add(target);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see org.eclipse.cdt.core.build.managed.IManagedBuildInfo#buildsFileType(java.lang.String)
|
||||||
|
*/
|
||||||
|
public boolean buildsFileType(String srcExt) {
|
||||||
|
// Check to see if there is a rule to build a file with this extension
|
||||||
|
IConfiguration config = getDefaultConfiguration(getDefaultTarget());
|
||||||
|
ITool[] tools = config.getTools();
|
||||||
|
for (int index = 0; index < tools.length; index++) {
|
||||||
|
ITool tool = tools[index];
|
||||||
|
if (tool.buildsFileType(srcExt)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/* (non-Javadoc)
|
/* (non-Javadoc)
|
||||||
* @see org.eclipse.cdt.core.build.managed.IResourceBuildInfo#getBuildArtifactName()
|
* @see org.eclipse.cdt.core.build.managed.IResourceBuildInfo#getBuildArtifactName()
|
||||||
*/
|
*/
|
||||||
|
@ -96,6 +112,23 @@ public class ManagedBuildInfo implements IManagedBuildInfo, IScannerInfo {
|
||||||
return name == null ? new String() : name;
|
return name == null ? new String() : name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see org.eclipse.cdt.core.build.managed.IManagedBuildInfo#getCleanCommand()
|
||||||
|
*/
|
||||||
|
public String getCleanCommand() {
|
||||||
|
// TODO Get from the model
|
||||||
|
return new String("rm -rf");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see org.eclipse.cdt.core.build.managed.IManagedBuildInfo#getConfigurationName()
|
||||||
|
*/
|
||||||
|
public String getConfigurationName() {
|
||||||
|
// Return the human-readable name of the default configuration
|
||||||
|
IConfiguration config = getDefaultConfiguration(getDefaultTarget());
|
||||||
|
return config == null ? new String() : config.getName();
|
||||||
|
}
|
||||||
|
|
||||||
/* (non-Javadoc)
|
/* (non-Javadoc)
|
||||||
* @see org.eclipse.cdt.core.build.managed.IResourceBuildInfo#getDefaultConfiguration()
|
* @see org.eclipse.cdt.core.build.managed.IResourceBuildInfo#getDefaultConfiguration()
|
||||||
*/
|
*/
|
||||||
|
@ -168,6 +201,51 @@ public class ManagedBuildInfo implements IManagedBuildInfo, IScannerInfo {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see org.eclipse.cdt.core.build.managed.IScannerInfo#getIncludePaths()
|
||||||
|
*/
|
||||||
|
public String[] getIncludePaths() {
|
||||||
|
// Return the include paths for the default configuration
|
||||||
|
ArrayList paths = new ArrayList();
|
||||||
|
IConfiguration config = getDefaultConfiguration(getDefaultTarget());
|
||||||
|
ITool[] tools = config.getTools();
|
||||||
|
for (int i = 0; i < tools.length; i++) {
|
||||||
|
ITool tool = tools[i];
|
||||||
|
IOption[] opts = tool.getOptions();
|
||||||
|
for (int j = 0; j < opts.length; j++) {
|
||||||
|
IOption option = opts[j];
|
||||||
|
if (option.getValueType() == IOption.INCLUDE_PATH) {
|
||||||
|
try {
|
||||||
|
paths.addAll(Arrays.asList(option.getIncludePaths()));
|
||||||
|
} catch (BuildException e) {
|
||||||
|
// we should never get here
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
paths.trimToSize();
|
||||||
|
return (String[])paths.toArray(new String[paths.size()]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see org.eclipse.cdt.core.build.managed.IManagedBuildInfo#getMakeArguments()
|
||||||
|
*/
|
||||||
|
public String[] getMakeArguments() {
|
||||||
|
// TODO Stop hard-coding this
|
||||||
|
String[] args = {""};
|
||||||
|
|
||||||
|
return args;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see org.eclipse.cdt.core.build.managed.IManagedBuildInfo#getMakeCommand()
|
||||||
|
*/
|
||||||
|
public String getMakeCommand() {
|
||||||
|
// TODO Don't hard-code this
|
||||||
|
return new String("make");
|
||||||
|
}
|
||||||
|
|
||||||
/* (non-Javadoc)
|
/* (non-Javadoc)
|
||||||
* @see org.eclipse.cdt.core.build.managed.IResourceBuildInfo#getOutputExtension(java.lang.String)
|
* @see org.eclipse.cdt.core.build.managed.IResourceBuildInfo#getOutputExtension(java.lang.String)
|
||||||
*/
|
*/
|
||||||
|
@ -185,6 +263,15 @@ public class ManagedBuildInfo implements IManagedBuildInfo, IScannerInfo {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see org.eclipse.cdt.core.build.managed.IManagedBuildInfo#getOutputFlag()
|
||||||
|
*/
|
||||||
|
public String getOutputFlag() {
|
||||||
|
// TODO Stop hard-coding this
|
||||||
|
String flag = new String("-o");
|
||||||
|
return flag;
|
||||||
|
}
|
||||||
|
|
||||||
public IResource getOwner() {
|
public IResource getOwner() {
|
||||||
return owner;
|
return owner;
|
||||||
}
|
}
|
||||||
|
@ -319,31 +406,5 @@ public class ManagedBuildInfo implements IManagedBuildInfo, IScannerInfo {
|
||||||
return symbols;
|
return symbols;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* (non-Javadoc)
|
|
||||||
* @see org.eclipse.cdt.core.build.managed.IScannerInfo#getIncludePaths()
|
|
||||||
*/
|
|
||||||
public String[] getIncludePaths() {
|
|
||||||
// Return the include paths for the default configuration
|
|
||||||
ArrayList paths = new ArrayList();
|
|
||||||
IConfiguration config = getDefaultConfiguration(getDefaultTarget());
|
|
||||||
ITool[] tools = config.getTools();
|
|
||||||
for (int i = 0; i < tools.length; i++) {
|
|
||||||
ITool tool = tools[i];
|
|
||||||
IOption[] opts = tool.getOptions();
|
|
||||||
for (int j = 0; j < opts.length; j++) {
|
|
||||||
IOption option = opts[j];
|
|
||||||
if (option.getValueType() == IOption.INCLUDE_PATH) {
|
|
||||||
try {
|
|
||||||
paths.addAll(Arrays.asList(option.getIncludePaths()));
|
|
||||||
} catch (BuildException e) {
|
|
||||||
// we should never get here
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
paths.trimToSize();
|
|
||||||
return (String[])paths.toArray(new String[paths.size()]);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,6 +14,7 @@ package org.eclipse.cdt.core;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Vector;
|
||||||
|
|
||||||
import org.eclipse.core.resources.ICommand;
|
import org.eclipse.core.resources.ICommand;
|
||||||
import org.eclipse.core.resources.IProject;
|
import org.eclipse.core.resources.IProject;
|
||||||
|
@ -45,6 +46,22 @@ public class ManagedCProjectNature implements IProjectNature {
|
||||||
// Add the builder to the project
|
// Add the builder to the project
|
||||||
IProjectDescription description = project.getDescription();
|
IProjectDescription description = project.getDescription();
|
||||||
ICommand[] commands = description.getBuildSpec();
|
ICommand[] commands = description.getBuildSpec();
|
||||||
|
|
||||||
|
// TODO Remove this when the new StandardBuild nature adds the cbuilder
|
||||||
|
for (int i = 0; i < commands.length; i++) {
|
||||||
|
ICommand command = commands[i];
|
||||||
|
if (command.getBuilderName().equals("org.eclipse.cdt.core.cbuilder")) {
|
||||||
|
// Remove the command
|
||||||
|
Vector vec = new Vector(Arrays.asList(commands));
|
||||||
|
vec.removeElementAt(i);
|
||||||
|
vec.trimToSize();
|
||||||
|
ICommand[] tempCommands = (ICommand[]) vec.toArray(new ICommand[commands.length-1]);
|
||||||
|
description.setBuildSpec(tempCommands);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
commands = description.getBuildSpec();
|
||||||
boolean found = false;
|
boolean found = false;
|
||||||
// See if the builder is already there
|
// See if the builder is already there
|
||||||
for (int i = 0; i < commands.length; ++i) {
|
for (int i = 0; i < commands.length; ++i) {
|
||||||
|
@ -63,7 +80,7 @@ public class ManagedCProjectNature implements IProjectNature {
|
||||||
newCommands[0] = command;
|
newCommands[0] = command;
|
||||||
description.setBuildSpec(newCommands);
|
description.setBuildSpec(newCommands);
|
||||||
project.setDescription(description, null);
|
project.setDescription(description, null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -7,5 +7,15 @@
|
||||||
CBuilder.build_error= Build Error
|
CBuilder.build_error= Build Error
|
||||||
|
|
||||||
# Generated makefile builder messages
|
# Generated makefile builder messages
|
||||||
MakeBuilder.message.rebuild = Regenerating makefile for project {0}
|
MakeBuilder.message.starting = Starting the build for project {0}
|
||||||
MakeBuilder.message.incremental = Updating makefile for project {0}
|
MakeBuilder.message.rebuild = Regenerating makefiles for project {0}
|
||||||
|
MakeBuilder.message.incremental = Updating makefiles for project {0}
|
||||||
|
MakeBuilder.message.make = Calling {0} for project {1}
|
||||||
|
MakeBuilder.message.error = Build error
|
||||||
|
MakeBuilder.message.finished = Build complete for project {0}
|
||||||
|
MakeBuilder.comment.module.list = # Every module must be described here
|
||||||
|
MakeBuilder.comment.source.list = # Each module must contribute its source files here
|
||||||
|
MakeBuilder.comment.build.rule = # Each module must supply rules for building sources it contributes
|
||||||
|
MakeBuilder.comment.module.make.includes = # Include the makefiles for each source module
|
||||||
|
MakeBuilder.comment.module.dep.includes = # Include automatically-generated dependency list:
|
||||||
|
MakeBuilder.comment.autodeps = # Automatically-generated dependency list:
|
||||||
|
|
|
@ -12,19 +12,34 @@ package org.eclipse.cdt.internal.core;
|
||||||
* **********************************************************************/
|
* **********************************************************************/
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Enumeration;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Properties;
|
||||||
|
import java.util.StringTokenizer;
|
||||||
|
|
||||||
import org.eclipse.cdt.core.CCorePlugin;
|
import org.eclipse.cdt.core.CCorePlugin;
|
||||||
|
import org.eclipse.cdt.core.CommandLauncher;
|
||||||
|
import org.eclipse.cdt.core.ConsoleOutputStream;
|
||||||
|
import org.eclipse.cdt.core.ErrorParserManager;
|
||||||
import org.eclipse.cdt.core.build.managed.IManagedBuildInfo;
|
import org.eclipse.cdt.core.build.managed.IManagedBuildInfo;
|
||||||
import org.eclipse.cdt.core.build.managed.ManagedBuildManager;
|
import org.eclipse.cdt.core.build.managed.ManagedBuildManager;
|
||||||
|
import org.eclipse.cdt.core.model.ICModelMarker;
|
||||||
import org.eclipse.cdt.core.resources.ACBuilder;
|
import org.eclipse.cdt.core.resources.ACBuilder;
|
||||||
|
import org.eclipse.cdt.core.resources.IConsole;
|
||||||
import org.eclipse.cdt.core.resources.MakeUtil;
|
import org.eclipse.cdt.core.resources.MakeUtil;
|
||||||
import org.eclipse.cdt.internal.core.model.Util;
|
|
||||||
import org.eclipse.core.resources.IFile;
|
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.IProject;
|
||||||
import org.eclipse.core.resources.IResource;
|
import org.eclipse.core.resources.IResource;
|
||||||
import org.eclipse.core.resources.IResourceDelta;
|
import org.eclipse.core.resources.IResourceDelta;
|
||||||
import org.eclipse.core.resources.IResourceDeltaVisitor;
|
import org.eclipse.core.resources.IResourceDeltaVisitor;
|
||||||
import org.eclipse.core.resources.IResourceStatus;
|
import org.eclipse.core.resources.IResourceStatus;
|
||||||
|
import org.eclipse.core.resources.IWorkspace;
|
||||||
import org.eclipse.core.resources.IWorkspaceRoot;
|
import org.eclipse.core.resources.IWorkspaceRoot;
|
||||||
import org.eclipse.core.resources.IncrementalProjectBuilder;
|
import org.eclipse.core.resources.IncrementalProjectBuilder;
|
||||||
import org.eclipse.core.runtime.CoreException;
|
import org.eclipse.core.runtime.CoreException;
|
||||||
|
@ -33,18 +48,27 @@ import org.eclipse.core.runtime.IProgressMonitor;
|
||||||
import org.eclipse.core.runtime.NullProgressMonitor;
|
import org.eclipse.core.runtime.NullProgressMonitor;
|
||||||
import org.eclipse.core.runtime.OperationCanceledException;
|
import org.eclipse.core.runtime.OperationCanceledException;
|
||||||
import org.eclipse.core.runtime.Path;
|
import org.eclipse.core.runtime.Path;
|
||||||
|
import org.eclipse.core.runtime.SubProgressMonitor;
|
||||||
|
|
||||||
public class GeneratedMakefileBuilder extends ACBuilder {
|
public class GeneratedMakefileBuilder extends ACBuilder {
|
||||||
// String constants
|
// String constants
|
||||||
private static final String MESSAGE = "MakeBuilder.message"; //$NON-NLS-1$
|
private static final String MESSAGE = "MakeBuilder.message"; //$NON-NLS-1$
|
||||||
private static final String REBUILD = MESSAGE + ".rebuild"; //$NON-NLS-1$
|
private static final String BUILD_ERROR = MESSAGE + ".error"; //$NON-NLS-1$
|
||||||
|
private static final String BUILD_FINISHED = MESSAGE + ".finished"; //$NON-NLS-1$
|
||||||
private static final String INCREMENTAL = MESSAGE + ".incremental"; //$NON-NLS-1$
|
private static final String INCREMENTAL = MESSAGE + ".incremental"; //$NON-NLS-1$
|
||||||
private static final String FILENAME = "makefile"; //$NON-NLS-1$
|
private static final String MAKE = MESSAGE + ".make"; //$NON-NLS-1$
|
||||||
private static final String NEWLINE = System.getProperty("line.separator", "\n"); //$NON-NLS-1$
|
private static final String REBUILD = MESSAGE + ".rebuild"; //$NON-NLS-1$
|
||||||
private static final String COLON = ":";
|
private static final String START = MESSAGE + ".starting"; //$NON-NLS-1$
|
||||||
private static final String TAB = "\t"; //$NON-NLS-1$
|
|
||||||
|
// Status codes
|
||||||
|
public static final int EMPTY_PROJECT_BUILD_ERROR = 1;
|
||||||
|
|
||||||
|
// Local variables
|
||||||
|
protected List resourcesToBuild;
|
||||||
|
protected List ruleList;
|
||||||
|
|
||||||
|
|
||||||
public class MyResourceDeltaVisitor implements IResourceDeltaVisitor {
|
public class ResourceDeltaVisitor implements IResourceDeltaVisitor {
|
||||||
boolean bContinue;
|
boolean bContinue;
|
||||||
|
|
||||||
public boolean visit(IResourceDelta delta) throws CoreException {
|
public boolean visit(IResourceDelta delta) throws CoreException {
|
||||||
|
@ -67,102 +91,21 @@ public class GeneratedMakefileBuilder extends ACBuilder {
|
||||||
super();
|
super();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Add whatever macros we can figure out to the makefile.
|
|
||||||
*
|
|
||||||
* @param buffer
|
|
||||||
*/
|
|
||||||
private void addMacros(StringBuffer buffer, IManagedBuildInfo info) {
|
|
||||||
// TODO this should come from the build model
|
|
||||||
buffer.append("RM = rm -f" + NEWLINE);
|
|
||||||
buffer.append("MAKE = make" + NEWLINE);
|
|
||||||
buffer.append(NEWLINE);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void addRule(StringBuffer buffer, IPath sourcePath, String outputName, IManagedBuildInfo info) {
|
|
||||||
// Add the rule to the makefile
|
|
||||||
buffer.append(outputName + COLON + " " + sourcePath.toString());
|
|
||||||
// Add all of the dependencies on the source file
|
|
||||||
|
|
||||||
buffer.append(NEWLINE);
|
|
||||||
String ext = sourcePath.getFileExtension();
|
|
||||||
String cmd = info.getToolForSource(ext);
|
|
||||||
String flags = info.getFlagsForSource(ext);
|
|
||||||
buffer.append(TAB + cmd + " " + flags + " " + "$?" + NEWLINE + NEWLINE);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a list of dependencies on project resources.
|
|
||||||
*
|
|
||||||
* @param buffer
|
|
||||||
*/
|
|
||||||
private void addSources(StringBuffer buffer, IManagedBuildInfo info) throws CoreException {
|
|
||||||
// Add the list of project files to be built
|
|
||||||
buffer.append("OBJS = \\" + NEWLINE);
|
|
||||||
|
|
||||||
//Get a list of files from the project
|
|
||||||
IResource[] members = getProject().members();
|
|
||||||
for (int i = 0; i < members.length; i++) {
|
|
||||||
IResource resource = members[i];
|
|
||||||
IPath sourcePath = resource.getProjectRelativePath().removeFileExtension();
|
|
||||||
String srcExt = resource.getFileExtension();
|
|
||||||
String outExt = info.getOutputExtension(srcExt);
|
|
||||||
if (outExt != null) {
|
|
||||||
// Add the extension back to path
|
|
||||||
IPath outputPath = sourcePath.addFileExtension(outExt);
|
|
||||||
// Add the file to the list of dependencies for the base target
|
|
||||||
buffer.append(outputPath.toString() + " \\" + NEWLINE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
buffer.append(NEWLINE);
|
|
||||||
|
|
||||||
// Add a rule for building each resource to the makefile
|
|
||||||
for (int j = 0; j < members.length; j++) {
|
|
||||||
IResource resource = members[j];
|
|
||||||
IPath sourcePath = resource.getProjectRelativePath().removeFileExtension();
|
|
||||||
String srcExt = resource.getFileExtension();
|
|
||||||
String outExt = info.getOutputExtension(srcExt);
|
|
||||||
if (outExt != null) {
|
|
||||||
// Add the extension back to path
|
|
||||||
IPath outputPath = sourcePath.addFileExtension(outExt);
|
|
||||||
addRule(buffer, resource.getProjectRelativePath(), outputPath.toString(), info);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param buffer
|
|
||||||
*/
|
|
||||||
private void addTargets(StringBuffer buffer, IManagedBuildInfo info) {
|
|
||||||
// Generate a rule per source
|
|
||||||
|
|
||||||
// This is the top build rule
|
|
||||||
String flags = info.getFlagsForTarget("exe") + " ";
|
|
||||||
String cmd = info.getToolForTarget("exe") + " ";
|
|
||||||
buffer.append(info.getBuildArtifactName() + COLON + " ${OBJS}" + NEWLINE);
|
|
||||||
buffer.append(TAB + cmd + flags + "$@ ${OBJS}" + NEWLINE);
|
|
||||||
buffer.append(NEWLINE);
|
|
||||||
|
|
||||||
// TODO Generate 'all' for now but determine the real rules from UI
|
|
||||||
buffer.append("all: " + info.getBuildArtifactName() + NEWLINE);
|
|
||||||
buffer.append(NEWLINE);
|
|
||||||
|
|
||||||
// Always add a clean target
|
|
||||||
buffer.append("clean:" + NEWLINE);
|
|
||||||
buffer.append(TAB + "$(RM) *.o " + info.getBuildArtifactName() + NEWLINE);
|
|
||||||
buffer.append(NEWLINE);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* (non-Javadoc)
|
/* (non-Javadoc)
|
||||||
* @see org.eclipse.core.internal.events.InternalBuilder#build(int, java.util.Map, org.eclipse.core.runtime.IProgressMonitor)
|
* @see org.eclipse.core.internal.events.InternalBuilder#build(int, java.util.Map, org.eclipse.core.runtime.IProgressMonitor)
|
||||||
*/
|
*/
|
||||||
protected IProject[] build(int kind, Map args, IProgressMonitor monitor) throws CoreException {
|
protected IProject[] build(int kind, Map args, IProgressMonitor monitor) throws CoreException {
|
||||||
|
String statusMsg = CCorePlugin.getFormattedString(START, getProject().getName());
|
||||||
|
if (statusMsg != null) {
|
||||||
|
monitor.subTask(statusMsg);
|
||||||
|
}
|
||||||
|
|
||||||
if (kind == IncrementalProjectBuilder.FULL_BUILD) {
|
if (kind == IncrementalProjectBuilder.FULL_BUILD) {
|
||||||
fullBuild(monitor);
|
fullBuild(monitor);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// Create a delta visitor to make sure we should be rebuilding
|
// Create a delta visitor to make sure we should be rebuilding
|
||||||
MyResourceDeltaVisitor visitor = new MyResourceDeltaVisitor();
|
ResourceDeltaVisitor visitor = new ResourceDeltaVisitor();
|
||||||
IResourceDelta delta = getDelta(getProject());
|
IResourceDelta delta = getDelta(getProject());
|
||||||
if (delta == null) {
|
if (delta == null) {
|
||||||
fullBuild(monitor);
|
fullBuild(monitor);
|
||||||
|
@ -176,52 +119,107 @@ public class GeneratedMakefileBuilder extends ACBuilder {
|
||||||
}
|
}
|
||||||
// Checking to see if the user cancelled the build
|
// Checking to see if the user cancelled the build
|
||||||
checkCancel(monitor);
|
checkCancel(monitor);
|
||||||
// Build referenced projects
|
|
||||||
|
// Ask build mechanism to compute deltas for project dependencies next time
|
||||||
return getProject().getReferencedProjects();
|
return getProject().getReferencedProjects();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check whether the build has been canceled.
|
* Check whether the build has been canceled. Cancellation requests
|
||||||
|
* propagated to the caller by throwing <code>OperationCanceledException</code>.
|
||||||
|
*
|
||||||
|
* @see org.eclipse.core.runtime.OperationCanceledException#OperationCanceledException()
|
||||||
*/
|
*/
|
||||||
public void checkCancel(IProgressMonitor monitor) {
|
public void checkCancel(IProgressMonitor monitor) {
|
||||||
if (monitor != null && monitor.isCanceled())
|
if (monitor != null && monitor.isCanceled()) {
|
||||||
throw new OperationCanceledException();
|
throw new OperationCanceledException();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param monitor
|
* @param monitor
|
||||||
*/
|
*/
|
||||||
private void fullBuild(IProgressMonitor monitor) throws CoreException {
|
protected void fullBuild(IProgressMonitor monitor) throws CoreException {
|
||||||
// Rebuild the entire project
|
// Always need one of these bad boys
|
||||||
IProject currentProject = getProject();
|
|
||||||
String statusMsg = null;
|
|
||||||
|
|
||||||
// Need to report status to the user
|
|
||||||
if (monitor == null) {
|
if (monitor == null) {
|
||||||
monitor = new NullProgressMonitor();
|
monitor = new NullProgressMonitor();
|
||||||
}
|
}
|
||||||
statusMsg = CCorePlugin.getFormattedString(REBUILD, currentProject.getName());
|
|
||||||
|
// We also need one of these ...
|
||||||
|
IProject currentProject = getProject();
|
||||||
|
if (currentProject == null) {
|
||||||
|
// Flag some sort of error and bail
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Regenerate the makefiles for any managed projects this project depends on
|
||||||
|
IProject[] deps = currentProject.getReferencedProjects();
|
||||||
|
for (int i = 0; i < deps.length; i++) {
|
||||||
|
IProject depProject = deps[i];
|
||||||
|
if (ManagedBuildManager.manages(depProject)) {
|
||||||
|
IManagedBuildInfo depInfo = ManagedBuildManager.getBuildInfo(depProject);
|
||||||
|
MakefileGenerator generator = new MakefileGenerator(depProject, depInfo, monitor);
|
||||||
|
try {
|
||||||
|
generator.regenerateMakefiles();
|
||||||
|
} catch (CoreException e) {
|
||||||
|
// This may be an empty project exception
|
||||||
|
if (e.getStatus().getCode() == GeneratedMakefileBuilder.EMPTY_PROJECT_BUILD_ERROR) {
|
||||||
|
// Just keep looking for other projects
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Need to report status to the user
|
||||||
|
String statusMsg = CCorePlugin.getFormattedString(REBUILD, currentProject.getName());
|
||||||
monitor.subTask(statusMsg);
|
monitor.subTask(statusMsg);
|
||||||
|
|
||||||
// Get a filehandle for the makefile
|
// Regenerate the makefiles for this project
|
||||||
IPath filePath = getWorkingDirectory().append(IPath.SEPARATOR + FILENAME);
|
IManagedBuildInfo info = ManagedBuildManager.getBuildInfo(getProject());
|
||||||
String temp = filePath.toString();
|
MakefileGenerator generator = new MakefileGenerator(currentProject, info, monitor);
|
||||||
IFile fileHandle = getMakefile(filePath, monitor);
|
try {
|
||||||
|
generator.regenerateMakefiles();
|
||||||
// Add the items to the makefile
|
} catch (CoreException e) {
|
||||||
populateMakefile(fileHandle, monitor);
|
// See if this is an empty project
|
||||||
|
if (e.getStatus().getCode() == GeneratedMakefileBuilder.EMPTY_PROJECT_BUILD_ERROR) {
|
||||||
|
monitor.worked(1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
IPath topBuildDir = generator.getTopBuildDir();
|
||||||
|
|
||||||
|
// Now call make
|
||||||
|
invokeMake(true, topBuildDir.removeFirstSegments(1), info, monitor);
|
||||||
|
|
||||||
monitor.worked(1);
|
monitor.worked(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected IPath getBuildDirectory(String dirName) throws CoreException {
|
||||||
|
// Create or get the handle for the build directory
|
||||||
|
IFolder folder = getProject().getFolder(dirName);
|
||||||
|
if (!folder.exists()) {
|
||||||
|
try {
|
||||||
|
folder.create(false, true, null);
|
||||||
|
}
|
||||||
|
catch (CoreException e) {
|
||||||
|
if (e.getStatus().getCode() == IResourceStatus.PATH_OCCUPIED)
|
||||||
|
folder.refreshLocal(IResource.DEPTH_ZERO, null);
|
||||||
|
else
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return folder.getFullPath();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the makefile for the project. It may be empty.
|
* Gets the makefile for the project. It may be empty.
|
||||||
*
|
*
|
||||||
* @return The <code>IFile</code> to generate the makefile into.
|
* @return The <code>IFile</code> to generate the makefile into.
|
||||||
*/
|
*/
|
||||||
public IFile getMakefile(IPath filePath, IProgressMonitor monitor) throws CoreException {
|
protected IFile getMakefile(IPath filePath, IProgressMonitor monitor) throws CoreException {
|
||||||
// Create or get the handle for the makefile
|
// Create or get the handle for the makefile
|
||||||
IWorkspaceRoot root= CCorePlugin.getWorkspace().getRoot();
|
IWorkspaceRoot root = CCorePlugin.getWorkspace().getRoot();
|
||||||
IFile newFile = root.getFileForLocation(filePath);
|
IFile newFile = root.getFileForLocation(filePath);
|
||||||
if (newFile == null) {
|
if (newFile == null) {
|
||||||
newFile = root.getFile(filePath);
|
newFile = root.getFile(filePath);
|
||||||
|
@ -242,6 +240,45 @@ public class GeneratedMakefileBuilder extends ACBuilder {
|
||||||
return newFile;
|
return newFile;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param makefilePath
|
||||||
|
* @param info
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
protected String[] getMakeTargets() {
|
||||||
|
List args = new ArrayList();
|
||||||
|
// Add each target
|
||||||
|
String sessionTarget = MakeUtil.getSessionTarget(getProject());
|
||||||
|
StringTokenizer tokens = new StringTokenizer(sessionTarget);
|
||||||
|
while (tokens.hasMoreTokens()) {
|
||||||
|
args.add(tokens.nextToken().trim());
|
||||||
|
}
|
||||||
|
if (args.isEmpty()) {
|
||||||
|
args.add("all");
|
||||||
|
}
|
||||||
|
return (String[])args.toArray(new String[args.size()]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
protected List getResourcesToBuild() {
|
||||||
|
if (resourcesToBuild == null) {
|
||||||
|
resourcesToBuild = new ArrayList();
|
||||||
|
}
|
||||||
|
return resourcesToBuild;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
protected List getRuleList() {
|
||||||
|
if (ruleList == null) {
|
||||||
|
ruleList = new ArrayList();
|
||||||
|
}
|
||||||
|
return ruleList;
|
||||||
|
}
|
||||||
|
|
||||||
/* (non-Javadoc)
|
/* (non-Javadoc)
|
||||||
* @see org.eclipse.cdt.core.resources.ACBuilder#getWorkingDirectory()
|
* @see org.eclipse.cdt.core.resources.ACBuilder#getWorkingDirectory()
|
||||||
*/
|
*/
|
||||||
|
@ -257,7 +294,7 @@ public class GeneratedMakefileBuilder extends ACBuilder {
|
||||||
* @param delta
|
* @param delta
|
||||||
* @param monitor
|
* @param monitor
|
||||||
*/
|
*/
|
||||||
private void incrementalBuild(IResourceDelta delta, IProgressMonitor monitor) throws CoreException {
|
protected void incrementalBuild(IResourceDelta delta, IProgressMonitor monitor) throws CoreException {
|
||||||
// Rebuild the resource tree in the delta
|
// Rebuild the resource tree in the delta
|
||||||
IProject currentProject = getProject();
|
IProject currentProject = getProject();
|
||||||
String statusMsg = null;
|
String statusMsg = null;
|
||||||
|
@ -269,38 +306,140 @@ public class GeneratedMakefileBuilder extends ACBuilder {
|
||||||
statusMsg = CCorePlugin.getFormattedString(INCREMENTAL, currentProject.getName());
|
statusMsg = CCorePlugin.getFormattedString(INCREMENTAL, currentProject.getName());
|
||||||
monitor.subTask(statusMsg);
|
monitor.subTask(statusMsg);
|
||||||
|
|
||||||
// Get a filehandle for the makefile
|
IManagedBuildInfo info = ManagedBuildManager.getBuildInfo(getProject());
|
||||||
IPath filePath = getWorkingDirectory().append(IPath.SEPARATOR + FILENAME);
|
IPath buildDir = new Path(info.getConfigurationName());
|
||||||
IFile fileHandle = getMakefile(filePath, monitor);
|
invokeMake(false, buildDir, info, monitor);
|
||||||
|
|
||||||
// Now populate it
|
|
||||||
populateMakefile(fileHandle, monitor);
|
|
||||||
|
|
||||||
monitor.worked(1);
|
monitor.worked(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
protected void invokeMake(boolean fullBuild, IPath buildDir, IManagedBuildInfo info, IProgressMonitor monitor) {
|
||||||
* Recreate the entire contents of the makefile.
|
boolean isCanceled = false;
|
||||||
*
|
IProject currentProject = getProject();
|
||||||
* @param fileHandle The file to place the contents in.
|
SubProgressMonitor subMonitor = null;
|
||||||
*/
|
if (monitor == null) {
|
||||||
private void populateMakefile(IFile fileHandle, IProgressMonitor monitor) throws CoreException {
|
monitor = new NullProgressMonitor();
|
||||||
// Write out the contents of the build model
|
}
|
||||||
StringBuffer buffer = new StringBuffer();
|
|
||||||
IManagedBuildInfo info = ManagedBuildManager.getBuildInfo(getProject());
|
|
||||||
|
|
||||||
// Add the macro definitions
|
|
||||||
addMacros(buffer, info);
|
|
||||||
|
|
||||||
// Add a list of source files
|
// Flag to the user that make is about to be called
|
||||||
addSources(buffer, info);
|
IPath makeCommand = new Path(info.getMakeCommand());
|
||||||
|
String[] msgs = new String[2];
|
||||||
// Add targets
|
msgs[0] = info.getMakeCommand();
|
||||||
addTargets(buffer, info);
|
msgs[1] = currentProject.getName();
|
||||||
|
String statusMsg = CCorePlugin.getFormattedString(MAKE, msgs);
|
||||||
|
if (statusMsg != null) {
|
||||||
|
monitor.subTask(statusMsg);
|
||||||
|
}
|
||||||
|
|
||||||
// Save the file
|
// Get a build console for the project
|
||||||
Util.save(buffer, fileHandle);
|
IConsole console = null;
|
||||||
|
ConsoleOutputStream consoleOutStream = null;
|
||||||
|
IWorkspace workspace = null;
|
||||||
|
IMarker[] markers = null;
|
||||||
|
try {
|
||||||
|
console = CCorePlugin.getDefault().getConsole();
|
||||||
|
console.start(currentProject);
|
||||||
|
consoleOutStream = console.getOutputStream();
|
||||||
|
|
||||||
|
// Remove all markers for this project
|
||||||
|
workspace = currentProject.getWorkspace();
|
||||||
|
markers = currentProject.findMarkers(ICModelMarker.C_MODEL_PROBLEM_MARKER, true, IResource.DEPTH_INFINITE);
|
||||||
|
if (markers != null) {
|
||||||
|
workspace.deleteMarkers(markers);
|
||||||
|
}
|
||||||
|
} catch (CoreException e) {
|
||||||
|
}
|
||||||
|
|
||||||
|
IPath workingDirectory = getWorkingDirectory().append(buildDir);
|
||||||
|
|
||||||
|
// Get the arguments to be passed to make from build model
|
||||||
|
String[] makeTargets = getMakeTargets();
|
||||||
|
|
||||||
|
// Get a launcher for the make command
|
||||||
|
String errMsg = null;
|
||||||
|
CommandLauncher launcher = new CommandLauncher();
|
||||||
|
launcher.showCommand(true);
|
||||||
|
|
||||||
|
// Set the environmennt, some scripts may need the CWD var to be set.
|
||||||
|
Properties props = launcher.getEnvironment();
|
||||||
|
props.put("CWD", workingDirectory.toOSString());
|
||||||
|
props.put("PWD", workingDirectory.toOSString());
|
||||||
|
String[] env = null;
|
||||||
|
ArrayList envList = new ArrayList();
|
||||||
|
Enumeration names = props.propertyNames();
|
||||||
|
if (names != null) {
|
||||||
|
while (names.hasMoreElements()) {
|
||||||
|
String key = (String) names.nextElement();
|
||||||
|
envList.add(key + "=" + props.getProperty(key));
|
||||||
|
}
|
||||||
|
env = (String[]) envList.toArray(new String[envList.size()]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hook up an error parser
|
||||||
|
ErrorParserManager epm = new ErrorParserManager(this);
|
||||||
|
epm.setOutputStream(consoleOutStream);
|
||||||
|
OutputStream stdout = epm.getOutputStream();
|
||||||
|
OutputStream stderr = epm.getOutputStream();
|
||||||
|
|
||||||
|
// Launch make
|
||||||
|
Process proc = launcher.execute(makeCommand, makeTargets, env, workingDirectory);
|
||||||
|
if (proc != null) {
|
||||||
|
try {
|
||||||
|
// Close the input of the Process explicitely.
|
||||||
|
// We will never write to it.
|
||||||
|
proc.getOutputStream().close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
}
|
||||||
|
subMonitor = new SubProgressMonitor(monitor, IProgressMonitor.UNKNOWN);
|
||||||
|
if (launcher.waitAndRead(stdout, stderr, subMonitor) != CommandLauncher.OK) {
|
||||||
|
errMsg = launcher.getErrorMessage();
|
||||||
|
|
||||||
|
isCanceled = monitor.isCanceled();
|
||||||
|
monitor.setCanceled(false);
|
||||||
|
subMonitor = new SubProgressMonitor(monitor, IProgressMonitor.UNKNOWN);
|
||||||
|
subMonitor.subTask("Refresh From Local");
|
||||||
|
|
||||||
|
try {
|
||||||
|
currentProject.refreshLocal(IResource.DEPTH_INFINITE, subMonitor);
|
||||||
|
} catch (CoreException e) {
|
||||||
|
}
|
||||||
|
|
||||||
|
subMonitor = new SubProgressMonitor(monitor, IProgressMonitor.UNKNOWN);
|
||||||
|
subMonitor.subTask("Parsing");
|
||||||
|
} else {
|
||||||
|
errMsg = launcher.getErrorMessage();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Report either the success or failure of our mission
|
||||||
|
StringBuffer buf = new StringBuffer();
|
||||||
|
if (errMsg != null && errMsg.length() > 0) {
|
||||||
|
String errorDesc = CCorePlugin.getResourceString(BUILD_ERROR);
|
||||||
|
buf.append(errorDesc);
|
||||||
|
buf.append(System.getProperty("line.separator", "\n"));
|
||||||
|
buf.append("(").append(errMsg).append(")");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Report a successful build
|
||||||
|
String successMsg = CCorePlugin.getFormattedString(BUILD_FINISHED, currentProject.getName());
|
||||||
|
buf.append(successMsg);
|
||||||
|
buf.append(System.getProperty("line.separator", "\n"));
|
||||||
|
}
|
||||||
|
// Write your message on the pavement
|
||||||
|
try {
|
||||||
|
consoleOutStream.write(buf.toString().getBytes());
|
||||||
|
consoleOutStream.flush();
|
||||||
|
stdout.close();
|
||||||
|
stderr.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
}
|
||||||
|
|
||||||
|
epm.reportProblems();
|
||||||
|
|
||||||
|
subMonitor.done();
|
||||||
|
monitor.setCanceled(isCanceled);
|
||||||
|
}
|
||||||
|
monitor.done();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,574 @@
|
||||||
|
package org.eclipse.cdt.internal.core;
|
||||||
|
|
||||||
|
/**********************************************************************
|
||||||
|
* Copyright (c) 2002,2003 Rational Software Corporation and others.
|
||||||
|
* All rights reserved. This program and the accompanying materials
|
||||||
|
* are made available under the terms of the Common Public License v0.5
|
||||||
|
* which accompanies this distribution, and is available at
|
||||||
|
* http://www.eclipse.org/legal/cpl-v05.html
|
||||||
|
*
|
||||||
|
* Contributors:
|
||||||
|
* IBM Rational Software - Initial API and implementation
|
||||||
|
* **********************************************************************/
|
||||||
|
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.ListIterator;
|
||||||
|
|
||||||
|
import org.eclipse.cdt.core.CCorePlugin;
|
||||||
|
import org.eclipse.cdt.core.build.managed.IManagedBuildInfo;
|
||||||
|
import org.eclipse.cdt.core.search.ICSearchConstants;
|
||||||
|
import org.eclipse.cdt.internal.core.model.Util;
|
||||||
|
import org.eclipse.cdt.internal.core.sourcedependency.DependencyManager;
|
||||||
|
import org.eclipse.cdt.internal.core.sourcedependency.DependencyQueryJob;
|
||||||
|
import org.eclipse.core.resources.IContainer;
|
||||||
|
import org.eclipse.core.resources.IFile;
|
||||||
|
import org.eclipse.core.resources.IFolder;
|
||||||
|
import org.eclipse.core.resources.IProject;
|
||||||
|
import org.eclipse.core.resources.IResource;
|
||||||
|
import org.eclipse.core.resources.IResourceProxy;
|
||||||
|
import org.eclipse.core.resources.IResourceProxyVisitor;
|
||||||
|
import org.eclipse.core.resources.IResourceStatus;
|
||||||
|
import org.eclipse.core.resources.IWorkspaceRoot;
|
||||||
|
import org.eclipse.core.runtime.CoreException;
|
||||||
|
import org.eclipse.core.runtime.IPath;
|
||||||
|
import org.eclipse.core.runtime.IProgressMonitor;
|
||||||
|
import org.eclipse.core.runtime.IStatus;
|
||||||
|
import org.eclipse.core.runtime.OperationCanceledException;
|
||||||
|
import org.eclipse.core.runtime.Path;
|
||||||
|
import org.eclipse.core.runtime.Status;
|
||||||
|
|
||||||
|
public class MakefileGenerator {
|
||||||
|
// String constants for messages
|
||||||
|
private static final String MESSAGE = "MakeBuilder.message"; //$NON-NLS-1$
|
||||||
|
private static final String BUILD_ERROR = MESSAGE + ".error"; //$NON-NLS-1$
|
||||||
|
private static final String COMMENT = "MakeBuilder.comment"; //$NON-NLS-1$
|
||||||
|
private static final String MOD_LIST = COMMENT + ".module.list"; //$NON-NLS-1$
|
||||||
|
private static final String SRC_LISTS = COMMENT + ".source.list"; //$NON-NLS-1$
|
||||||
|
private static final String MOD_RULES = COMMENT + ".build.rule"; //$NON-NLS-1$
|
||||||
|
private static final String MOD_INCL = COMMENT + ".module.make.includes"; //$NON-NLS-1$
|
||||||
|
private static final String DEP_INCL = COMMENT + ".module.dep.includes"; //$NON-NLS-1$
|
||||||
|
private static final String AUTO_DEP = COMMENT + ".autodeps"; //$NON-NLS-1$
|
||||||
|
|
||||||
|
// String constants for makefile contents
|
||||||
|
protected static final String COLON = ":";
|
||||||
|
protected static final String DEPFILE_NAME = "module.dep"; //$NON-NLS-1$
|
||||||
|
protected static final String DOT = ".";
|
||||||
|
protected static final String MAKEFILE_NAME = "makefile"; //$NON-NLS-1$
|
||||||
|
protected static final String MODFILE_NAME = "module.mk"; //$NON-NLS-1$
|
||||||
|
protected static final String LINEBREAK = "\\";
|
||||||
|
protected static final String NEWLINE = System.getProperty("line.separator");
|
||||||
|
protected static final String SEMI_COLON = ";";
|
||||||
|
protected static final String SEPARATOR = "/";
|
||||||
|
protected static final String TAB = "\t";
|
||||||
|
protected static final String WHITESPACE = " ";
|
||||||
|
protected static final String WILDCARD = "%";
|
||||||
|
|
||||||
|
// Local variables needed by generator
|
||||||
|
protected IManagedBuildInfo info;
|
||||||
|
protected List moduleList;
|
||||||
|
protected IProgressMonitor monitor;
|
||||||
|
protected IProject project;
|
||||||
|
protected List ruleList;
|
||||||
|
protected IPath topBuildDir;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class is used to recursively walk the project and determine which
|
||||||
|
* modules contribute buildable source files.
|
||||||
|
*/
|
||||||
|
protected class ResourceProxyVisitor implements IResourceProxyVisitor {
|
||||||
|
private MakefileGenerator generator;
|
||||||
|
private IManagedBuildInfo info;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a new resource proxy visitor to quickly visit project
|
||||||
|
* resources.
|
||||||
|
*/
|
||||||
|
public ResourceProxyVisitor(MakefileGenerator generator, IManagedBuildInfo info) {
|
||||||
|
this.generator = generator;
|
||||||
|
this.info = info;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see org.eclipse.core.resources.IResourceProxyVisitor#visit(org.eclipse.core.resources.IResourceProxy)
|
||||||
|
*/
|
||||||
|
public boolean visit(IResourceProxy proxy) throws CoreException {
|
||||||
|
// No point in proceeding, is there
|
||||||
|
if (generator == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Is this a resource we should even consider
|
||||||
|
if (proxy.getType() == IResource.FILE) {
|
||||||
|
// Check extension to see if build model should build this file
|
||||||
|
IResource resource = proxy.requestResource();
|
||||||
|
String ext = resource.getFileExtension();
|
||||||
|
if (info.buildsFileType(ext)) {
|
||||||
|
generator.appendModule(resource);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Recurse into subdirectories
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public MakefileGenerator(IProject project, IManagedBuildInfo info, IProgressMonitor monitor) {
|
||||||
|
super();
|
||||||
|
// Save the project so we can get path and member information
|
||||||
|
this.project = project;
|
||||||
|
// Save the monitor reference for reporting back to the user
|
||||||
|
this.monitor = monitor;
|
||||||
|
// Get the build info for the project
|
||||||
|
this.info = info;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param module
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
protected StringBuffer addDeps(IContainer module) throws CoreException {
|
||||||
|
// Calculate the new directory relative to the build output
|
||||||
|
IPath moduleRelativePath = module.getProjectRelativePath();
|
||||||
|
String relativePath = moduleRelativePath.toString();
|
||||||
|
relativePath += relativePath.length() == 0 ? "" : SEPARATOR;
|
||||||
|
|
||||||
|
// Create the buffer to hold the output for the module and a dep calculator
|
||||||
|
StringBuffer buffer = new StringBuffer();
|
||||||
|
buffer.append(CCorePlugin.getResourceString(AUTO_DEP) + NEWLINE);
|
||||||
|
DependencyManager dependencyManager = CCorePlugin.getDefault().getCoreModel().getDependencyManager();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Visit each resource in the folder that we have a rule to build.
|
||||||
|
* The dependency output for each resource will be in the format
|
||||||
|
* <relativePath>/<resourceName>.<outputExtension> : <dep1> ... <depn>
|
||||||
|
* with long lines broken.
|
||||||
|
*/
|
||||||
|
IResource[] resources = module.members();
|
||||||
|
for (int i = 0; i < resources.length; i++) {
|
||||||
|
IResource resource = resources[i];
|
||||||
|
if (resource.getType() == IResource.FILE) {
|
||||||
|
String inputExt = resource.getFileExtension();
|
||||||
|
if (info.buildsFileType(inputExt)) {
|
||||||
|
// Get the filename without an extension
|
||||||
|
String fileName = resource.getFullPath().removeFileExtension().lastSegment();
|
||||||
|
if (fileName == null) continue;
|
||||||
|
String outputExt = info.getOutputExtension(inputExt);
|
||||||
|
if (outputExt != null) {
|
||||||
|
fileName += DOT + outputExt;
|
||||||
|
}
|
||||||
|
// ASk the dep generator to find all the deps for this resource
|
||||||
|
ArrayList dependencies = new ArrayList();
|
||||||
|
try {
|
||||||
|
dependencyManager.performConcurrentJob(new DependencyQueryJob(project, (IFile)resource, dependencyManager, dependencies), ICSearchConstants.WAIT_UNTIL_READY_TO_SEARCH, null);
|
||||||
|
} catch (Exception e) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (dependencies.size() == 0) continue;
|
||||||
|
buffer.append(relativePath + fileName + COLON + WHITESPACE);
|
||||||
|
Iterator iter = dependencies.listIterator();
|
||||||
|
while (iter.hasNext()) {
|
||||||
|
buffer.append(LINEBREAK + NEWLINE);
|
||||||
|
String path = (String)iter.next();
|
||||||
|
buffer.append(path + WHITESPACE);
|
||||||
|
}
|
||||||
|
buffer.append(NEWLINE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param buffer
|
||||||
|
* @param info
|
||||||
|
*/
|
||||||
|
protected StringBuffer addMacros() {
|
||||||
|
StringBuffer buffer = new StringBuffer();
|
||||||
|
|
||||||
|
// Add the ROOT macro
|
||||||
|
buffer.append("ROOT := .." + NEWLINE);
|
||||||
|
|
||||||
|
// Get the clean command from the build model
|
||||||
|
buffer.append("RM := ");
|
||||||
|
buffer.append(info.getCleanCommand() + NEWLINE);
|
||||||
|
|
||||||
|
// Add the macro for the output flag
|
||||||
|
buffer.append("OUTPUT_FLAG := ");
|
||||||
|
buffer.append(info.getOutputFlag() + NEWLINE);
|
||||||
|
|
||||||
|
buffer.append(CCorePlugin.getResourceString(SRC_LISTS) + NEWLINE);
|
||||||
|
buffer.append("C_SRCS := " + NEWLINE);
|
||||||
|
buffer.append("CC_SRCS := " + NEWLINE);
|
||||||
|
|
||||||
|
buffer.append(NEWLINE + NEWLINE);
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
protected StringBuffer addModules() {
|
||||||
|
StringBuffer buffer = new StringBuffer();
|
||||||
|
// Add the comment
|
||||||
|
buffer.append(CCorePlugin.getResourceString(MOD_LIST) + NEWLINE);
|
||||||
|
buffer.append("MODULES := " + LINEBREAK + NEWLINE);
|
||||||
|
buffer.append("." + LINEBREAK + NEWLINE);
|
||||||
|
|
||||||
|
// Get all the module names
|
||||||
|
ListIterator iter = getModuleList().listIterator();
|
||||||
|
while (iter.hasNext()) {
|
||||||
|
IContainer container = (IContainer) iter.next();
|
||||||
|
IPath path = container.getProjectRelativePath();
|
||||||
|
buffer.append(path.toString() + WHITESPACE + LINEBREAK + NEWLINE);
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer.append(NEWLINE);
|
||||||
|
buffer.append(CCorePlugin.getResourceString(MOD_INCL) + NEWLINE);
|
||||||
|
buffer.append("include ${patsubst %, %/module.mk, $(MODULES)}" + NEWLINE);
|
||||||
|
|
||||||
|
buffer.append(NEWLINE + NEWLINE);
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Answers a <code>StringBuffer</code> containing all of the sources contributed by
|
||||||
|
* a container to the build.
|
||||||
|
* @param module
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
protected StringBuffer addSources(IContainer module) throws CoreException {
|
||||||
|
// Calculate the new directory relative to the build output
|
||||||
|
IPath moduleRelativePath = module.getProjectRelativePath();
|
||||||
|
String relativePath = moduleRelativePath.toString();
|
||||||
|
relativePath += relativePath.length() == 0 ? "" : SEPARATOR;
|
||||||
|
|
||||||
|
// String buffers
|
||||||
|
StringBuffer buffer = new StringBuffer();
|
||||||
|
StringBuffer cBuffer = new StringBuffer("C_SRCS += " + LINEBREAK + NEWLINE);
|
||||||
|
cBuffer.append("${addprefix $(ROOT)/" + relativePath + "," + LINEBREAK + NEWLINE);
|
||||||
|
StringBuffer ccBuffer = new StringBuffer("CC_SRCS += \\" + NEWLINE);
|
||||||
|
ccBuffer.append("${addprefix $(ROOT)/" + relativePath + "," + LINEBREAK + NEWLINE);
|
||||||
|
StringBuffer ruleBuffer = new StringBuffer(CCorePlugin.getResourceString(MOD_RULES) + NEWLINE);
|
||||||
|
|
||||||
|
// Put the comment in
|
||||||
|
buffer.append(CCorePlugin.getResourceString(SRC_LISTS) + NEWLINE);
|
||||||
|
|
||||||
|
// Visit the resources in this folder
|
||||||
|
IResource[] resources = module.members();
|
||||||
|
for (int i = 0; i < resources.length; i++) {
|
||||||
|
IResource resource = resources[i];
|
||||||
|
if (resource.getType() == IResource.FILE) {
|
||||||
|
String ext = resource.getFileExtension();
|
||||||
|
if (info.buildsFileType(ext)) {
|
||||||
|
// TODO use build model to determine what list the file goes in
|
||||||
|
ccBuffer.append(resource.getName() + WHITESPACE + LINEBREAK + NEWLINE);
|
||||||
|
// Try to add the rule for the file
|
||||||
|
addRule(relativePath, ruleBuffer, resource);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Finish the commands in the buffers
|
||||||
|
cBuffer.append("}" + NEWLINE + NEWLINE);
|
||||||
|
ccBuffer.append("}" + NEWLINE + NEWLINE);
|
||||||
|
|
||||||
|
// Append them all together
|
||||||
|
buffer.append(cBuffer).append(ccBuffer).append(ruleBuffer);
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Answers a <code>StrinBuffer</code> containing all of the required targets to
|
||||||
|
* properly build the project.
|
||||||
|
*/
|
||||||
|
protected StringBuffer addTargets() {
|
||||||
|
StringBuffer buffer = new StringBuffer();
|
||||||
|
|
||||||
|
// Get the target and it's extension
|
||||||
|
String target = info.getBuildArtifactName();
|
||||||
|
IPath temp = new Path(target);
|
||||||
|
String extension = temp.getFileExtension();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Write out the taqrget rule as:
|
||||||
|
* <target>.<extension>: $(CC_SRCS:$(ROOT)/%.cpp=%.o) $(C_SRCS:$(ROOT)/%.c=%.o)
|
||||||
|
* $(BUILD_TOOL) $(FLAGS) $(OUTPUT_FLAG) $@ $^ $(LIB_DEPS)
|
||||||
|
*/
|
||||||
|
String cmd = info.getToolForTarget(extension);
|
||||||
|
String flags = info.getFlagsForTarget(extension);
|
||||||
|
buffer.append(target + COLON + WHITESPACE + "$(CC_SRCS:$(ROOT)/%.cpp=%.o) $(C_SRCS:$(ROOT)/%.c=%.o)" + NEWLINE);
|
||||||
|
buffer.append(TAB + cmd + WHITESPACE + flags + WHITESPACE + "$(OUTPUT_FLAG) $@" + WHITESPACE + "$^" + WHITESPACE + NEWLINE);
|
||||||
|
buffer.append(NEWLINE);
|
||||||
|
|
||||||
|
// TODO Generate 'all' for now but determine the real rules from UI
|
||||||
|
buffer.append("all: " + target + NEWLINE);
|
||||||
|
buffer.append(NEWLINE);
|
||||||
|
|
||||||
|
// Always add a clean target
|
||||||
|
buffer.append(".PHONY: clean" + NEWLINE);
|
||||||
|
buffer.append("clean:" + NEWLINE);
|
||||||
|
buffer.append(TAB + "$(RM)" + WHITESPACE + "${addprefix ., $(CC_SRCS:$(ROOT)%.cpp=%.o)} ${addprefix ., $(C_SRCS:$(ROOT)%.c=%.o)}" + WHITESPACE + target + NEWLINE);
|
||||||
|
buffer.append(NEWLINE);
|
||||||
|
|
||||||
|
buffer.append(NEWLINE + CCorePlugin.getResourceString(DEP_INCL) + NEWLINE);
|
||||||
|
buffer.append("include ${patsubst %, %/module.dep, $(MODULES)}" + NEWLINE);
|
||||||
|
|
||||||
|
buffer.append(NEWLINE);
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void addRule(String relativePath, StringBuffer buffer, IResource resource) {
|
||||||
|
String rule = null;
|
||||||
|
String cmd = null;
|
||||||
|
String buildFlags = null;
|
||||||
|
String inputExtension = null;
|
||||||
|
String outputExtension = null;
|
||||||
|
|
||||||
|
// Is there a special rule for this file
|
||||||
|
if (false) {
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Get the extension of the resource
|
||||||
|
inputExtension = resource.getFileExtension();
|
||||||
|
// ASk the build model what it will produce from this
|
||||||
|
outputExtension = info.getOutputExtension(inputExtension);
|
||||||
|
/*
|
||||||
|
* Create the pattern rule in the format
|
||||||
|
* <relative_path>/%.o: $(ROOT)/<relative_path>/%.cpp
|
||||||
|
* $(CC) $(CFLAGS) $(OUTPUT_FLAG) $@ $<
|
||||||
|
*
|
||||||
|
* Note that CC CFLAGS and OUTPUT_FLAG all come from the build model
|
||||||
|
* and are resolved to a real command before writing to the module
|
||||||
|
* makefile, so a real command might look something like
|
||||||
|
* source1/%.o: $(ROOT)/source1/%.cpp
|
||||||
|
* g++ -g -O2 -c -I/cygdrive/c/eclipse/workspace/Project/headers -o $@ $<
|
||||||
|
*/
|
||||||
|
rule = relativePath + WILDCARD + DOT + outputExtension + COLON + WHITESPACE + "$(ROOT)" + SEPARATOR + relativePath + WILDCARD + DOT + inputExtension;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if the rule is listed as something we already generated in the makefile
|
||||||
|
if (!getRuleList().contains(rule)) {
|
||||||
|
// Add it to the list
|
||||||
|
getRuleList().add(rule);
|
||||||
|
|
||||||
|
// Add the rule and command to the makefile
|
||||||
|
buffer.append(rule + NEWLINE);
|
||||||
|
cmd = info.getToolForSource(inputExtension);
|
||||||
|
buildFlags = info.getFlagsForSource(inputExtension);
|
||||||
|
|
||||||
|
buffer.append(TAB + cmd + WHITESPACE + buildFlags + WHITESPACE + "$(OUTPUT_FLAG) $@" + WHITESPACE + "$<" + NEWLINE + NEWLINE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param resource
|
||||||
|
*/
|
||||||
|
public void appendModule(IResource resource) {
|
||||||
|
// The build model knows how to build this file
|
||||||
|
IContainer container = resource.getParent();
|
||||||
|
if (!getModuleList().contains(container)) {
|
||||||
|
getModuleList().add(container);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check whether the build has been canceled. Cancellation requests
|
||||||
|
* propagated to the caller by throwing <code>OperationCanceledException</code>.
|
||||||
|
*
|
||||||
|
* @see org.eclipse.core.runtime.OperationCanceledException#OperationCanceledException()
|
||||||
|
*/
|
||||||
|
public void checkCancel() {
|
||||||
|
if (monitor != null && monitor.isCanceled()) {
|
||||||
|
throw new OperationCanceledException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private List getModuleList() {
|
||||||
|
if (moduleList == null) {
|
||||||
|
moduleList = new ArrayList();
|
||||||
|
}
|
||||||
|
return moduleList;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
private List getRuleList() {
|
||||||
|
if (ruleList == null) {
|
||||||
|
ruleList = new ArrayList();
|
||||||
|
}
|
||||||
|
return ruleList;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private IPath createDirectory(String dirName) throws CoreException {
|
||||||
|
// Create or get the handle for the build directory
|
||||||
|
IFolder folder = project.getFolder(dirName);
|
||||||
|
if (!folder.exists()) {
|
||||||
|
|
||||||
|
// Make sure that parent folders exist
|
||||||
|
IPath parentPath = (new Path(dirName)).removeLastSegments(1);
|
||||||
|
// Assume that the parent exists if the path is empty
|
||||||
|
if (!parentPath.isEmpty()) {
|
||||||
|
IFolder parent = project.getFolder(parentPath);
|
||||||
|
if (!parent.exists()) {
|
||||||
|
createDirectory(parentPath.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now make the requested folder
|
||||||
|
try {
|
||||||
|
folder.create(true, true, null);
|
||||||
|
}
|
||||||
|
catch (CoreException e) {
|
||||||
|
if (e.getStatus().getCode() == IResourceStatus.PATH_OCCUPIED)
|
||||||
|
folder.refreshLocal(IResource.DEPTH_ZERO, null);
|
||||||
|
else
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return folder.getFullPath();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param makefilePath
|
||||||
|
* @param monitor
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private IFile createFile(IPath makefilePath) throws CoreException {
|
||||||
|
// Create or get the handle for the makefile
|
||||||
|
IWorkspaceRoot root = CCorePlugin.getWorkspace().getRoot();
|
||||||
|
IFile newFile = root.getFileForLocation(makefilePath);
|
||||||
|
if (newFile == null) {
|
||||||
|
newFile = root.getFile(makefilePath);
|
||||||
|
}
|
||||||
|
// Create the file if it does not exist
|
||||||
|
ByteArrayInputStream contents = new ByteArrayInputStream(new byte[0]);
|
||||||
|
try {
|
||||||
|
newFile.create(contents, false, monitor);
|
||||||
|
}
|
||||||
|
catch (CoreException e) {
|
||||||
|
// If the file already existed locally, just refresh to get contents
|
||||||
|
if (e.getStatus().getCode() == IResourceStatus.PATH_OCCUPIED)
|
||||||
|
newFile.refreshLocal(IResource.DEPTH_ZERO, null);
|
||||||
|
else
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
// TODO handle long running file operation
|
||||||
|
return newFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Answers the <code>IPath</code> of the top directory generated for the build
|
||||||
|
* output, or <code>null</code> if none has been generated.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public IPath getTopBuildDir() {
|
||||||
|
return topBuildDir;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create the entire contents of the makefile.
|
||||||
|
*
|
||||||
|
* @param fileHandle The file to place the contents in.
|
||||||
|
* @param info
|
||||||
|
* @param monitor
|
||||||
|
*/
|
||||||
|
protected void populateMakefile(IFile fileHandle) {
|
||||||
|
StringBuffer buffer = new StringBuffer();
|
||||||
|
|
||||||
|
// Add the macro definitions
|
||||||
|
buffer.append(addMacros());
|
||||||
|
|
||||||
|
// Append the module list
|
||||||
|
buffer.append(addModules());
|
||||||
|
|
||||||
|
// Add targets
|
||||||
|
buffer.append(addTargets());
|
||||||
|
|
||||||
|
// Save the file
|
||||||
|
try {
|
||||||
|
Util.save(buffer, fileHandle);
|
||||||
|
} catch (CoreException e1) {
|
||||||
|
// TODO Auto-generated catch block
|
||||||
|
e1.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param module
|
||||||
|
*/
|
||||||
|
protected void populateModMakefile(IContainer module) throws CoreException {
|
||||||
|
// Calcualte the new directory relative to the build output
|
||||||
|
IPath moduleRelativePath = module.getProjectRelativePath();
|
||||||
|
IPath buildRoot = getTopBuildDir().removeFirstSegments(1);
|
||||||
|
if (buildRoot == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
IPath moduleOutputPath = buildRoot.append(moduleRelativePath);
|
||||||
|
|
||||||
|
// Now create the directory
|
||||||
|
IPath moduleOutputDir = createDirectory(moduleOutputPath.toString());
|
||||||
|
|
||||||
|
// Create a module makefile
|
||||||
|
IFile modMakefile = createFile(moduleOutputDir.addTrailingSeparator().append(MODFILE_NAME));
|
||||||
|
StringBuffer makeBuf = new StringBuffer();
|
||||||
|
makeBuf.append(addSources(module));
|
||||||
|
|
||||||
|
// Create a module dep file
|
||||||
|
IFile modDepfile = createFile(moduleOutputDir.addTrailingSeparator().append(DEPFILE_NAME));
|
||||||
|
StringBuffer depBuf = new StringBuffer();
|
||||||
|
depBuf.append(addDeps(module));
|
||||||
|
|
||||||
|
// Save the files
|
||||||
|
Util.save(makeBuf, modMakefile);
|
||||||
|
Util.save(depBuf, modDepfile);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void regenerateMakefiles() throws CoreException {
|
||||||
|
// Visit the resources in the project
|
||||||
|
ResourceProxyVisitor visitor = new ResourceProxyVisitor(this, info);
|
||||||
|
project.accept(visitor, IResource.NONE);
|
||||||
|
if (getModuleList().isEmpty()) {
|
||||||
|
// There is nothing to build
|
||||||
|
IStatus status = new Status(IStatus.INFO, CCorePlugin.PLUGIN_ID, GeneratedMakefileBuilder.EMPTY_PROJECT_BUILD_ERROR, "", null);
|
||||||
|
throw new CoreException(status);
|
||||||
|
}
|
||||||
|
|
||||||
|
// See if the user has cancelled the build
|
||||||
|
checkCancel();
|
||||||
|
|
||||||
|
// Create the top-level directory for the build output
|
||||||
|
topBuildDir = createDirectory(info.getConfigurationName());
|
||||||
|
|
||||||
|
// Create the top-level makefile
|
||||||
|
IPath makefilePath = topBuildDir.addTrailingSeparator().append(MAKEFILE_NAME);
|
||||||
|
IFile makefileHandle = createFile(makefilePath);
|
||||||
|
|
||||||
|
// Populate the makefile
|
||||||
|
populateMakefile(makefileHandle);
|
||||||
|
checkCancel();
|
||||||
|
|
||||||
|
// Now populate the module makefiles
|
||||||
|
ListIterator iter = getModuleList().listIterator();
|
||||||
|
while (iter.hasNext()) {
|
||||||
|
populateModMakefile((IContainer)iter.next());
|
||||||
|
checkCancel();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Add table
Reference in a new issue