From 9f660da168a3fe0ee50486eb5a344effc10043cd Mon Sep 17 00:00:00 2001 From: jantje Date: Sun, 9 Oct 2022 05:54:48 +0200 Subject: [PATCH 001/486] #1126 rewriting ArduinoGnuMakefileGenerator Stuff is not finished but to many changes I seperated the code for the main makefile the mksubdir and makefile mksubdir is slowly geting rewritten --- io.sloeber.core/plugin.xml | 14 +- .../core/toolchain/ArchiveNameProvider.java | 45 - .../ArduinoGnuMakefileGenerator.java | 4553 ----------------- .../ArduinoManagedBuildGnuToolInfo.java | 1104 ---- .../IManagedOutputNameProviderJaba.java | 11 - .../core/toolchain/LinkNameProvider.java | 46 - .../Internal/ArchiveNameProvider.java | 33 + .../ArduinoGnuDependencyGroupInfo.java | 2 +- .../Internal/ArduinoGnuMakefileGenerator.java | 1597 ++++++ .../ArduinoManagedBuildGnuToolInfo.java | 1063 ++++ .../Internal/LinkNameProvider.java | 35 + .../managedBuild/Internal/MakeRule.java | 58 + .../Internal/ManagebBuildCommon.java | 607 +++ .../Internal/ManagedBuildConstants.java | 84 + .../Internal/SrcMakeGenerator.java | 146 + .../Internal/SubDirMakeGenerator.java | 1749 +++++++ .../managedBuild/Internal/ToolInfoHolder.java | 44 + .../Internal/TopMakeFileGenerator.java | 820 +++ .../api/IManagedOutputNameProviderJaba.java | 10 + 19 files changed, 6254 insertions(+), 5767 deletions(-) delete mode 100644 io.sloeber.core/src/io/sloeber/core/toolchain/ArchiveNameProvider.java delete mode 100644 io.sloeber.core/src/io/sloeber/core/toolchain/ArduinoGnuMakefileGenerator.java delete mode 100644 io.sloeber.core/src/io/sloeber/core/toolchain/ArduinoManagedBuildGnuToolInfo.java delete mode 100644 io.sloeber.core/src/io/sloeber/core/toolchain/IManagedOutputNameProviderJaba.java delete mode 100644 io.sloeber.core/src/io/sloeber/core/toolchain/LinkNameProvider.java create mode 100644 io.sloeber.core/src/io/sloeber/managedBuild/Internal/ArchiveNameProvider.java rename io.sloeber.core/src/io/sloeber/{core/toolchain => managedBuild/Internal}/ArduinoGnuDependencyGroupInfo.java (92%) create mode 100644 io.sloeber.core/src/io/sloeber/managedBuild/Internal/ArduinoGnuMakefileGenerator.java create mode 100644 io.sloeber.core/src/io/sloeber/managedBuild/Internal/ArduinoManagedBuildGnuToolInfo.java create mode 100644 io.sloeber.core/src/io/sloeber/managedBuild/Internal/LinkNameProvider.java create mode 100644 io.sloeber.core/src/io/sloeber/managedBuild/Internal/MakeRule.java create mode 100644 io.sloeber.core/src/io/sloeber/managedBuild/Internal/ManagebBuildCommon.java create mode 100644 io.sloeber.core/src/io/sloeber/managedBuild/Internal/ManagedBuildConstants.java create mode 100644 io.sloeber.core/src/io/sloeber/managedBuild/Internal/SrcMakeGenerator.java create mode 100644 io.sloeber.core/src/io/sloeber/managedBuild/Internal/SubDirMakeGenerator.java create mode 100644 io.sloeber.core/src/io/sloeber/managedBuild/Internal/ToolInfoHolder.java create mode 100644 io.sloeber.core/src/io/sloeber/managedBuild/Internal/TopMakeFileGenerator.java create mode 100644 io.sloeber.core/src/io/sloeber/managedBuild/api/IManagedOutputNameProviderJaba.java diff --git a/io.sloeber.core/plugin.xml b/io.sloeber.core/plugin.xml index 998e3c120..1b7139b8d 100644 --- a/io.sloeber.core/plugin.xml +++ b/io.sloeber.core/plugin.xml @@ -97,7 +97,7 @@ @@ -201,7 +201,7 @@ buildVariable="AR_OBJ" id="io.sloeber.compiler.cpp.ar.output" name="%outputType.CPP.AR.name" - nameProvider="io.sloeber.core.toolchain.ArchiveNameProvider" + nameProvider="io.sloeber.managedBuild.Internal.ArchiveNameProvider" outputs="o" primaryOutput="true"> @@ -241,7 +241,7 @@ buildVariable="LINK_OBJ" id="io.sloeber.compiler.c.link.output" name="%outputType.C.link.name" - nameProvider="io.sloeber.core.toolchain.LinkNameProvider" + nameProvider="io.sloeber.managedBuild.Internal.LinkNameProvider" outputs="O" primaryOutput="true"> @@ -249,7 +249,7 @@ buildVariable="AR_OBJ" id="io.sloeber.compiler.c.ar.output" name="%outputType.C.AR.name" - nameProvider="io.sloeber.core.toolchain.ArchiveNameProvider" + nameProvider="io.sloeber.managedBuild.Internal.ArchiveNameProvider" outputs="o" primaryOutput="true"> @@ -288,7 +288,7 @@ buildVariable="LINK_OBJ" id="io.sloeber.compiler.S.sketch.link.output" name="%outputType.S.link.name" - nameProvider="io.sloeber.core.toolchain.LinkNameProvider" + nameProvider="io.sloeber.managedBuild.Internal.LinkNameProvider" outputs="o" primaryOutput="true"> @@ -296,7 +296,7 @@ buildVariable="AR_OBJ" id="io.sloeber.compiler.S.ar.output" name="%outputType.S.AR.name" - nameProvider="io.sloeber.core.toolchain.ArchiveNameProvider" + nameProvider="io.sloeber.managedBuild.Internal.ArchiveNameProvider" outputs="o" primaryOutput="true"> diff --git a/io.sloeber.core/src/io/sloeber/core/toolchain/ArchiveNameProvider.java b/io.sloeber.core/src/io/sloeber/core/toolchain/ArchiveNameProvider.java deleted file mode 100644 index d92edfa65..000000000 --- a/io.sloeber.core/src/io/sloeber/core/toolchain/ArchiveNameProvider.java +++ /dev/null @@ -1,45 +0,0 @@ -package io.sloeber.core.toolchain; - -import org.eclipse.cdt.managedbuilder.core.IConfiguration; -import org.eclipse.cdt.managedbuilder.core.ITool; -import org.eclipse.core.resources.IProject; -import org.eclipse.core.runtime.IPath; -import org.eclipse.core.runtime.IStatus; -import org.eclipse.core.runtime.Status; - -import io.sloeber.core.common.Common; -import io.sloeber.core.common.Const; -import io.sloeber.core.tools.Helpers; - -public class ArchiveNameProvider implements IManagedOutputNameProviderJaba { - - @Override - public IPath[] getOutputNames(ITool tool, IPath[] primaryInputNames) { - Common.log(new Status(IStatus.ERROR, Const.CORE_PLUGIN_ID, - "ArchiveNameProvider: The call should go to the overloaded function not here.")); //$NON-NLS-1$ - return null; - } - - @Override - public IPath[] getOutputNames(IProject project, IConfiguration cConf, ITool tool, IPath[] primaryInputNames) { - IPath[] outputNames = new IPath[primaryInputNames.length]; - boolean bUseArchiver = Common - .getBuildEnvironmentVariable(project, cConf.getName(), Const.ENV_KEY_USE_ARCHIVER, Const.TRUE) - .equalsIgnoreCase(Const.TRUE); - if (!bUseArchiver) { - // we don't use archiving so we ignore all files - return null; - } - for (int curPath = 0; curPath < primaryInputNames.length; curPath++) { - IPath infile = primaryInputNames[curPath]; - if (infile.toString().startsWith(Const.ARDUINO_CODE_FOLDER_PATH) - && (!"cxx".equals(infile.getFileExtension()))) { //$NON-NLS-1$ - outputNames[curPath] = Helpers.GetOutputName(infile).addFileExtension("o"); //$NON-NLS-1$ - } else { - return null; - } - } - return outputNames; - } - -} diff --git a/io.sloeber.core/src/io/sloeber/core/toolchain/ArduinoGnuMakefileGenerator.java b/io.sloeber.core/src/io/sloeber/core/toolchain/ArduinoGnuMakefileGenerator.java deleted file mode 100644 index 42be32c61..000000000 --- a/io.sloeber.core/src/io/sloeber/core/toolchain/ArduinoGnuMakefileGenerator.java +++ /dev/null @@ -1,4553 +0,0 @@ -package io.sloeber.core.toolchain; - -import static io.sloeber.core.common.Const.*; - -/** - * This class is a copy of the cdt class GnuMakefileGenerator - * It has been modified but these changes did not (yet) get into - * the source. - * As such sometimes it is good to compare this file with the original. - * I do this as follows - * Copy the content of GnuMakefileGenerator in a java file you can compare - * set your formatting to a formatting allowing easier compares - * that is long lines - * long comments - * replace without regex in the copy - * GnuMakefileGenerator with ArduinoGnuMakefileGenerator - * GnuDependencyGroupInfo with ArduinoGnuDependencyGroupInfo - * ManagedBuildGnuToolInfo with ArduinoManagedBuildGnuToolInfo - * SEPARATOR with FILE_SEPARATOR - * - * replace with regex - * "//.*" with "" (in other words remove single line comments) - * "(?s)/\*.*?\* /" with "" (in other words remove comments) - * Unwanted extra space to not stop comment - * - * - */ -import java.io.ByteArrayInputStream; -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.Reader; -import java.nio.charset.Charset; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.LinkedHashMap; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Map.Entry; -import java.util.Set; -import java.util.Vector; - -import org.apache.commons.io.FileUtils; -import org.eclipse.cdt.core.CCorePlugin; -import org.eclipse.cdt.core.model.CoreModel; -import org.eclipse.cdt.core.settings.model.CSourceEntry; -import org.eclipse.cdt.core.settings.model.ICConfigurationDescription; -import org.eclipse.cdt.core.settings.model.ICProjectDescription; -import org.eclipse.cdt.core.settings.model.ICSettingEntry; -import org.eclipse.cdt.core.settings.model.ICSourceEntry; -import org.eclipse.cdt.core.settings.model.util.CDataUtil; -import org.eclipse.cdt.core.settings.model.util.IPathSettingsContainerVisitor; -import org.eclipse.cdt.core.settings.model.util.PathSettingsContainer; -import org.eclipse.cdt.managedbuilder.core.BuildException; -import org.eclipse.cdt.managedbuilder.core.IBuildObject; -import org.eclipse.cdt.managedbuilder.core.IBuilder; -import org.eclipse.cdt.managedbuilder.core.IConfiguration; -import org.eclipse.cdt.managedbuilder.core.IFileInfo; -import org.eclipse.cdt.managedbuilder.core.IFolderInfo; -import org.eclipse.cdt.managedbuilder.core.IInputType; -import org.eclipse.cdt.managedbuilder.core.IManagedBuildInfo; -import org.eclipse.cdt.managedbuilder.core.IManagedCommandLineGenerator; -import org.eclipse.cdt.managedbuilder.core.IManagedCommandLineInfo; -import org.eclipse.cdt.managedbuilder.core.IManagedOutputNameProvider; -import org.eclipse.cdt.managedbuilder.core.IOption; -import org.eclipse.cdt.managedbuilder.core.IOutputType; -import org.eclipse.cdt.managedbuilder.core.IResourceInfo; -import org.eclipse.cdt.managedbuilder.core.ITool; -import org.eclipse.cdt.managedbuilder.core.ManagedBuildManager; -import org.eclipse.cdt.managedbuilder.core.ManagedBuilderCorePlugin; -import org.eclipse.cdt.managedbuilder.internal.core.ManagedMakeMessages; -import org.eclipse.cdt.managedbuilder.internal.core.Tool; -import org.eclipse.cdt.managedbuilder.internal.macros.BuildMacroProvider; -import org.eclipse.cdt.managedbuilder.internal.macros.FileContextData; -import org.eclipse.cdt.managedbuilder.macros.BuildMacroException; -import org.eclipse.cdt.managedbuilder.macros.IBuildMacroProvider; -import org.eclipse.cdt.managedbuilder.makegen.IManagedBuilderMakefileGenerator; -import org.eclipse.cdt.managedbuilder.makegen.IManagedBuilderMakefileGenerator2; -import org.eclipse.cdt.managedbuilder.makegen.IManagedDependencyCalculator; -import org.eclipse.cdt.managedbuilder.makegen.IManagedDependencyCommands; -import org.eclipse.cdt.managedbuilder.makegen.IManagedDependencyGenerator; -import org.eclipse.cdt.managedbuilder.makegen.IManagedDependencyGenerator2; -import org.eclipse.cdt.managedbuilder.makegen.IManagedDependencyGeneratorType; -import org.eclipse.cdt.managedbuilder.makegen.IManagedDependencyInfo; -import org.eclipse.cdt.managedbuilder.makegen.IManagedDependencyPreBuild; -import org.eclipse.cdt.managedbuilder.makegen.gnu.IManagedBuildGnuToolInfo; -import org.eclipse.cdt.utils.EFSExtensionManager; -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.IResourceDelta; -import org.eclipse.core.resources.IResourceDeltaVisitor; -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.MultiStatus; -import org.eclipse.core.runtime.OperationCanceledException; -import org.eclipse.core.runtime.Path; -import org.eclipse.core.runtime.Status; -import org.eclipse.core.runtime.SubProgressMonitor; - -import io.sloeber.core.Messages; -import io.sloeber.core.common.Common; -import io.sloeber.core.common.Const; - -/** - * This is a specialized makefile generator that takes advantage of the - * extensions present in Gnu Make. - * - * @since 1.2 - * @noextend This class is not intended to be subclassed by clients. - * @noinstantiate This class is not intended to be instantiated by clients. - */ -@SuppressWarnings({ "deprecation", "restriction", "nls", "unused", "synthetic-access", "static-method", "unchecked", - "hiding" }) -public class ArduinoGnuMakefileGenerator implements IManagedBuilderMakefileGenerator2 { - private static final IPath DOT_SLASH_PATH = new Path("./"); - private static final String FILE_SEPARATOR = File.separator; - - /** - * This class walks the delta supplied by the build system to determine what - * resources have been changed. The logic is very simple. If a buildable - * resource (non-header) has been added or removed, the directories in which - * they are located are "dirty" so the makefile fragments for them have to be - * regenerated. - *

- * The actual dependencies are recalculated as a result of the build step - * itself. We are relying on make to do the right things when confronted with a - * dependency on a moved header file. That said, make will treat the missing - * header file in a dependency rule as a target it has to build unless told - * otherwise. These dummy targets are added to the makefile to avoid a missing - * target error. - */ - public class ResourceDeltaVisitor implements IResourceDeltaVisitor { - private final ArduinoGnuMakefileGenerator generator; - private final IConfiguration config; - - /** - * The constructor - */ - public ResourceDeltaVisitor(ArduinoGnuMakefileGenerator generator, IManagedBuildInfo info) { - this.generator = generator; - this.config = info.getDefaultConfiguration(); - } - - public ResourceDeltaVisitor(ArduinoGnuMakefileGenerator generator, IConfiguration cfg) { - this.generator = generator; - this.config = cfg; - } - - /* - * (non-Javadoc) - * - * @see org.eclipse.core.resources.IResourceDeltaVisitor#visit(org.eclipse. - * core.resources.IResourceDelta) - */ - @Override - public boolean visit(IResourceDelta delta) throws CoreException { - // Should the visitor keep iterating in current directory - boolean keepLooking = false; - IResource resource = delta.getResource(); - IResourceInfo rcInfo = config.getResourceInfo(resource.getProjectRelativePath(), false); - IFolderInfo fo = null; - boolean isSource = isSource(resource.getProjectRelativePath()); - if (rcInfo instanceof IFolderInfo) { - fo = (IFolderInfo) rcInfo; - } - // What kind of resource change has occurred - if (isSource) { - if (resource.getType() == IResource.FILE) { - String ext = resource.getFileExtension(); - switch (delta.getKind()) { - case IResourceDelta.ADDED: - if (!generator.isGeneratedResource(resource)) { - // This is a source file so just add its container - if (fo == null || fo.buildsFileType(ext)) { - generator.appendModifiedSubdirectory(resource); - } - } - break; - case IResourceDelta.REMOVED: - // we get this notification if a resource is moved too - if (!generator.isGeneratedResource(resource)) { - // This is a source file so just add its container - if (fo == null || fo.buildsFileType(ext)) { - generator.appendDeletedFile(resource); - generator.appendModifiedSubdirectory(resource); - } - } - break; - default: - keepLooking = true; - break; - } - } - if (resource.getType() == IResource.FOLDER) { - // I only care about delete event - switch (delta.getKind()) { - case IResourceDelta.REMOVED: - if (!generator.isGeneratedResource(resource)) { - generator.appendDeletedSubdirectory((IContainer) resource); - } - break; - } - } - } - if (resource.getType() == IResource.PROJECT) { - // If there is a zero-length delta, something the project - // depends on has changed so just call make - IResourceDelta[] children = delta.getAffectedChildren(); - if (children != null && children.length > 0) { - keepLooking = true; - } - } else { - // If the resource is part of the generated directory structure - // don't recurse - if (resource.getType() == IResource.ROOT || (isSource && !generator.isGeneratedResource(resource))) { - keepLooking = true; - } - } - return keepLooking; - } - } - - /** - * This class is used to recursively walk the project and determine which - * modules contribute buildable source files. - */ - protected class ResourceProxyVisitor implements IResourceProxyVisitor { - private final ArduinoGnuMakefileGenerator generator; - private final IConfiguration config; - - /** - * Constructs a new resource proxy visitor to quickly visit project resources. - */ - public ResourceProxyVisitor(ArduinoGnuMakefileGenerator generator, IManagedBuildInfo info) { - this.generator = generator; - this.config = info.getDefaultConfiguration(); - } - - public ResourceProxyVisitor(ArduinoGnuMakefileGenerator generator, IConfiguration cfg) { - this.generator = generator; - this.config = cfg; - } - - /* - * (non-Javadoc) - * - * @see org.eclipse.core.resources.IResourceProxyVisitor#visit(org.eclipse. - * core.resources.IResourceProxy) - */ - @Override - public boolean visit(IResourceProxy proxy) throws CoreException { - // No point in proceeding, is there - if (generator == null) { - return false; - } - IResource resource = proxy.requestResource(); - boolean isSource = isSource(resource.getProjectRelativePath()); - // Is this a resource we should even consider - if (proxy.getType() == IResource.FILE) { - // If this resource has a Resource Configuration and is not - // excluded or - // if it has a file extension that one of the tools builds, add - // the sudirectory to the list - // boolean willBuild = false; - IResourceInfo rcInfo = config.getResourceInfo(resource.getProjectRelativePath(), false); - if (isSource) { - boolean willBuild = false; - if (rcInfo instanceof IFolderInfo) { - String ext = resource.getFileExtension(); - if (((IFolderInfo) rcInfo).buildsFileType(ext) && !generator.isGeneratedResource(resource)) { - willBuild = true; - } - } else { - willBuild = true; - } - if (willBuild) - generator.appendBuildSubdirectory(resource); - } - return false; - } else if (proxy.getType() == IResource.FOLDER) { - if (!isSource || generator.isGeneratedResource(resource)) - return false; - return true; - } - // Recurse into subdirectories - return true; - } - } - - // String constants for makefile contents and messages - private static final String COMMENT = "MakefileGenerator.comment"; - private static final String HEADER = COMMENT + ".header"; - protected static final String MESSAGE_FINISH_BUILD = ManagedMakeMessages - .getResourceString("MakefileGenerator.message.finish.build"); - protected static final String MESSAGE_FINISH_FILE = ManagedMakeMessages - .getResourceString("MakefileGenerator.message.finish.file"); - protected static final String MESSAGE_START_BUILD = ManagedMakeMessages - .getResourceString("MakefileGenerator.message.start.build"); - protected static final String MESSAGE_START_FILE = ManagedMakeMessages - .getResourceString("MakefileGenerator.message.start.file"); - protected static final String MESSAGE_START_DEPENDENCY = ManagedMakeMessages - .getResourceString("MakefileGenerator.message.start.dependency"); - protected static final String MESSAGE_NO_TARGET_TOOL = ManagedMakeMessages - .getResourceString("MakefileGenerator.message.no.target"); - private static final String MOD_LIST = COMMENT + ".module.list"; - private static final String MOD_VARS = COMMENT + ".module.variables"; - private static final String MOD_RULES = COMMENT + ".build.rule"; - private static final String BUILD_TOP = COMMENT + ".build.toprules"; - private static final String ALL_TARGET = COMMENT + ".build.alltarget"; - private static final String MAINBUILD_TARGET = COMMENT + ".build.mainbuildtarget"; - private static final String BUILD_TARGETS = COMMENT + ".build.toptargets"; - private static final String SRC_LISTS = COMMENT + ".source.list"; - private static final String EMPTY_STRING = ""; - private static final String[] EMPTY_STRING_ARRAY = new String[0]; - private static final String OBJS_MACRO = "OBJS"; - private static final String MACRO_ADDITION_ADDPREFIX_HEADER = "${addprefix "; - private static final String MACRO_ADDITION_ADDPREFIX_SUFFIX = "," + WHITESPACE + LINEBREAK; - private static final String MACRO_ADDITION_PREFIX_SUFFIX = "+=" + WHITESPACE + LINEBREAK; - private static final String PREBUILD = "pre-build"; - private static final String MAINBUILD = "main-build"; - private static final String POSTBUILD = "post-build"; - private static final String SECONDARY_OUTPUTS = "secondary-outputs"; - // Enumerations - public static final int PROJECT_RELATIVE = 1, PROJECT_SUBDIR_RELATIVE = 2, ABSOLUTE = 3; - - class ToolInfoHolder { - ITool[] buildTools; - boolean[] buildToolsUsed; - ArduinoManagedBuildGnuToolInfo[] gnuToolInfos; - Set outputExtensionsSet; - List dependencyMakefiles; - } - - // Local variables needed by generator - private String buildTargetName; - private String buildTargetExt; - IConfiguration config; - private IBuilder builder; - private PathSettingsContainer toolInfos; - private Vector deletedFileList; - private Vector deletedDirList; - private Vector invalidDirList; - /** Collection of Folders in which sources files have been modified */ - private Collection modifiedList; - private IProgressMonitor monitor; - private IProject project; - private IResource[] projectResources; - private Vector ruleList; - private Vector depLineList; - // lines - private Vector depRuleList; - // dependency files - /** Collection of Containers which contribute source files to the build */ - private Collection subdirList; - private IPath topBuildDir; - final HashMap> buildSrcVars = new HashMap<>(); - final HashMap> buildOutVars = new HashMap<>(); - final HashMap buildDepVars = new HashMap<>(); - private final LinkedHashMap topBuildOutVars = new LinkedHashMap<>(); - // Dependency file variables - // private Vector dependencyMakefiles; // IPath's - relative to the top - // build directory or absolute - private ICSourceEntry srcEntries[]; - // Added by jaba - private IOutputType usedOutType = null; - // End of added by jaba - - public ArduinoGnuMakefileGenerator() { - super(); - } - - /************************************************************************* - * IManagedBuilderMakefileGenerator M E T H O D S - ************************************************************************/ - /* - * (non-Javadoc) - * - * @see org.eclipse.cdt.managedbuilder.makegen.IManagedBuilderMakefileGenerator - * #initialize(IProject, IManagedBuildInfo, IProgressMonitor) - */ - @Override - public void initialize(IProject project, IManagedBuildInfo info, IProgressMonitor monitor) { - this.project = project; - try { - projectResources = project.members(); - } catch (CoreException e) { - projectResources = null; - } - // Save the monitor reference for reporting back to the user - this.monitor = monitor; - // Get the name of the build target - buildTargetName = info.getBuildArtifactName(); - // Get its extension - buildTargetExt = info.getBuildArtifactExtension(); - try { - // try to resolve the build macros in the target extension - buildTargetExt = ManagedBuildManager.getBuildMacroProvider().resolveValueToMakefileFormat(buildTargetExt, - "", " ", IBuildMacroProvider.CONTEXT_CONFIGURATION, info.getDefaultConfiguration()); - } catch (BuildMacroException e) { - /* JABA is not going to write this code */ - } - try { - // try to resolve the build macros in the target name - String resolved = ManagedBuildManager.getBuildMacroProvider().resolveValueToMakefileFormat(buildTargetName, - "", " ", IBuildMacroProvider.CONTEXT_CONFIGURATION, info.getDefaultConfiguration()); - if (resolved != null && (resolved = resolved.trim()).length() > 0) - buildTargetName = resolved; - } catch (BuildMacroException e) { - /* JABA is not going to write this code */ - } - if (buildTargetExt == null) { - buildTargetExt = ""; - } - // Cache the build tools - config = info.getDefaultConfiguration(); - builder = config.getEditableBuilder(); - initToolInfos(); - // set the top build dir path - topBuildDir = project.getFolder(info.getConfigurationName()).getFullPath(); - } - - /** - * This method calls the dependency postprocessors defined for the tool chain - */ - private void callDependencyPostProcessors(IResourceInfo rcInfo, ToolInfoHolder h, IFile depFile, - IManagedDependencyGenerator2[] postProcessors, boolean callPopulateDummyTargets, boolean force) - throws CoreException { - try { - updateMonitor(ManagedMakeMessages - .getFormattedString("ArduinoGnuMakefileGenerator.message.postproc.dep.file", depFile.getName())); - if (postProcessors != null) { - IPath absolutePath = new Path( - EFSExtensionManager.getDefault().getPathFromURI(depFile.getLocationURI())); - // Convert to build directory relative - IPath depPath = ManagedBuildManager.calculateRelativePath(getTopBuildDir(), absolutePath); - for (int i = 0; i < postProcessors.length; i++) { - IManagedDependencyGenerator2 depGen = postProcessors[i]; - if (depGen != null) { - depGen.postProcessDependencyFile(depPath, config, h.buildTools[i], getTopBuildDir()); - } - } - } - if (callPopulateDummyTargets) { - populateDummyTargets(rcInfo, depFile, force); - } - } catch (CoreException e) { - throw e; - } catch (IOException e) { - /* JABA is not going to write this code */ - } - } - - /** - * This method collects the dependency postprocessors and file extensions - * defined for the tool chain - */ - private boolean collectDependencyGeneratorInformation(ToolInfoHolder h, Vector depExts, - IManagedDependencyGenerator2[] postProcessors) { - boolean callPopulateDummyTargets = false; - for (int i = 0; i < h.buildTools.length; i++) { - ITool tool = h.buildTools[i]; - IManagedDependencyGeneratorType depType = tool - .getDependencyGeneratorForExtension(tool.getDefaultInputExtension()); - if (depType != null) { - int calcType = depType.getCalculatorType(); - if (calcType <= IManagedDependencyGeneratorType.TYPE_OLD_TYPE_LIMIT) { - if (calcType == IManagedDependencyGeneratorType.TYPE_COMMAND) { - callPopulateDummyTargets = true; - depExts.add(DEP_EXT); - } - } else { - if (calcType == IManagedDependencyGeneratorType.TYPE_BUILD_COMMANDS - || calcType == IManagedDependencyGeneratorType.TYPE_PREBUILD_COMMANDS) { - IManagedDependencyGenerator2 depGen = (IManagedDependencyGenerator2) depType; - String depExt = depGen.getDependencyFileExtension(config, tool); - if (depExt != null) { - postProcessors[i] = depGen; - depExts.add(depExt); - } - } - } - } - } - return callPopulateDummyTargets; - } - - protected boolean isSource(IPath path) { - return !CDataUtil.isExcluded(path, srcEntries); - } - - private class DepInfo { - Vector depExts; - IManagedDependencyGenerator2[] postProcessors; - boolean callPopulateDummyTargets; - } - - /* - * (non-Javadoc) - * - * @see org.eclipse.cdt.managedbuilder.makegen.IManagedBuilderMakefileGenerator - * #generateDependencies() - */ - @Override - public void generateDependencies() throws CoreException { - final PathSettingsContainer postProcs = PathSettingsContainer.createRootContainer(); - // Note: PopulateDummyTargets is a hack for the pre-3.x GCC compilers - // Collect the methods that will need to be called - toolInfos.accept(new IPathSettingsContainerVisitor() { - @Override - public boolean visit(PathSettingsContainer container) { - ToolInfoHolder h = (ToolInfoHolder) container.getValue(); - Vector depExts = new Vector<>(); - IManagedDependencyGenerator2[] postProcessors = new IManagedDependencyGenerator2[h.buildTools.length]; - boolean callPopulateDummyTargets = collectDependencyGeneratorInformation(h, depExts, postProcessors); - // Is there anyone to call if we do find dependency files? - if (!callPopulateDummyTargets) { - int i; - for (i = 0; i < postProcessors.length; i++) { - if (postProcessors[i] != null) - break; - } - if (i == postProcessors.length) - return true; - } - PathSettingsContainer child = postProcs.getChildContainer(container.getPath(), true, true); - DepInfo di = new DepInfo(); - di.depExts = depExts; - di.postProcessors = postProcessors; - di.callPopulateDummyTargets = callPopulateDummyTargets; - child.setValue(di); - return true; - } - }); - IWorkspaceRoot root = CCorePlugin.getWorkspace().getRoot(); - for (IResource res : getSubdirList()) { - // The builder creates a subdir with same name as source in the - // build location - IContainer subDir = (IContainer) res; - IPath projectRelativePath = subDir.getProjectRelativePath(); - IResourceInfo rcInfo = config.getResourceInfo(projectRelativePath, false); - PathSettingsContainer cr = postProcs.getChildContainer(rcInfo.getPath(), false, true); - if (cr == null || cr.getValue() == null) - continue; - DepInfo di = (DepInfo) cr.getValue(); - ToolInfoHolder h = getToolInfo(projectRelativePath); - IPath buildRelativePath = topBuildDir.append(projectRelativePath); - IFolder buildFolder = root.getFolder(buildRelativePath); - if (buildFolder == null) - continue; - if (!buildFolder.exists()) - continue; - // Find all of the dep files in the generated subdirectories - IResource[] files = buildFolder.members(); - for (IResource file : files) { - String fileExt = file.getFileExtension(); - for (String ext : di.depExts) { - if (ext.equals(fileExt)) { - IFile depFile = root.getFile(file.getFullPath()); - if (depFile == null) - continue; - callDependencyPostProcessors(rcInfo, h, depFile, di.postProcessors, di.callPopulateDummyTargets, - false); - } - } - } - } - } - - /* - * (non-Javadoc) - * - * @see org.eclipse.cdt.managedbuilder.makegen.IManagedBuilderMakefileGenerator# - * generateMakefiles(org.eclipse.core.resources.IResourceDelta) - */ - @Override - public MultiStatus generateMakefiles(IResourceDelta delta) throws CoreException { - /* - * Let's do a sanity check right now. 1. This is an incremental build, so if the - * top-level directory is not there, then a rebuild is needed. - */ - IFolder folder = project.getFolder(config.getName()); - if (!folder.exists()) { - return regenerateMakefiles(); - } - // Return value - MultiStatus status; - // Visit the resources in the delta and compile a list of subdirectories - // to regenerate - updateMonitor( - ManagedMakeMessages.getFormattedString("MakefileGenerator.message.calc.delta", project.getName())); - ResourceDeltaVisitor visitor = new ResourceDeltaVisitor(this, config); - delta.accept(visitor); - checkCancel(); - // Get all the subdirectories participating in the build - updateMonitor( - ManagedMakeMessages.getFormattedString("MakefileGenerator.message.finding.sources", project.getName())); - ResourceProxyVisitor resourceVisitor = new ResourceProxyVisitor(this, config); - project.accept(resourceVisitor, IResource.NONE); - checkCancel(); - // Bug 303953: Ensure that if all resources have been removed from a - // folder, than the folder still - // appears in the subdir list so it's subdir.mk is correctly regenerated - getSubdirList().addAll(getModifiedList()); - // Make sure there is something to build - if (getSubdirList().isEmpty()) { - String info = ManagedMakeMessages.getFormattedString("MakefileGenerator.warning.no.source", - project.getName()); - updateMonitor(info); - status = new MultiStatus(ManagedBuilderCorePlugin.getUniqueIdentifier(), IStatus.INFO, "", null); - status.add(new Status(IStatus.INFO, ManagedBuilderCorePlugin.getUniqueIdentifier(), NO_SOURCE_FOLDERS, info, - null)); - return status; - } - // Make sure the build directory is available - topBuildDir = createDirectory(config.getName()); - checkCancel(); - // Make sure that there is a makefile containing all the folders - // participating - IPath srcsFilePath = topBuildDir.append(SRCSFILE_NAME); - IFile srcsFileHandle = createFile(srcsFilePath); - buildSrcVars.clear(); - buildOutVars.clear(); - buildDepVars.clear(); - topBuildOutVars.clear(); - populateSourcesMakefile(srcsFileHandle); - checkCancel(); - // Regenerate any fragments that are missing for the exisiting - // directories NOT modified - for (IResource res : getSubdirList()) { - IContainer subdirectory = (IContainer) res; - if (!getModifiedList().contains(subdirectory)) { - // Make sure the directory exists (it may have been deleted) - if (!subdirectory.exists()) { - appendDeletedSubdirectory(subdirectory); - continue; - } - // Make sure a fragment makefile exists - IPath fragmentPath = getBuildWorkingDir().append(subdirectory.getProjectRelativePath()) - .append(MODFILE_NAME); - IFile makeFragment = project.getFile(fragmentPath); - if (!makeFragment.exists()) { - // If one or both are missing, then add it to the list to be - // generated - getModifiedList().add(subdirectory); - } - } - } - // Delete the old dependency files for any deleted resources - for (IResource deletedFile : getDeletedFileList()) { - deleteDepFile(deletedFile); - deleteBuildTarget(deletedFile); - } - // Regenerate any fragments for modified directories - for (IResource res : getModifiedList()) { - IContainer subDir = (IContainer) res; - // Make sure the directory exists (it may have been deleted) - if (!subDir.exists()) { - appendDeletedSubdirectory(subDir); - continue; - } - // populateFragmentMakefile(subDir); // See below - checkCancel(); - } - // Recreate all module makefiles - // NOTE WELL: For now, always recreate all of the fragment makefile. - // This is necessary - // in order to re-populate the buildVariable lists. In the future, the - // list could - // possibly segmented by subdir so that all fragments didn't need to be - // regenerated - for (IResource res : getSubdirList()) { - IContainer subDir = (IContainer) res; - try { - populateFragmentMakefile(subDir); - } catch (CoreException e) { - // Probably should ask user if they want to continue - checkCancel(); - continue; - } - checkCancel(); - } - // Calculate the inputs and outputs of the Tools to be generated in the - // main makefile - calculateToolInputsOutputs(); - checkCancel(); - // Re-create the top-level makefile - IPath makefilePath = topBuildDir.append(MAKEFILE_NAME); - IFile makefileHandle = createFile(makefilePath); - populateTopMakefile(makefileHandle, false); - checkCancel(); - // Remove deleted folders from generated build directory - for (IResource res : getDeletedDirList()) { - IContainer subDir = (IContainer) res; - removeGeneratedDirectory(subDir); - checkCancel(); - } - // How did we do - if (!getInvalidDirList().isEmpty()) { - status = new MultiStatus(ManagedBuilderCorePlugin.getUniqueIdentifier(), IStatus.WARNING, "", null); - // Add a new status for each of the bad folders - // TODO: fix error message - for (IResource res : getInvalidDirList()) { - IContainer subDir = (IContainer) res; - status.add(new Status(IStatus.WARNING, ManagedBuilderCorePlugin.getUniqueIdentifier(), SPACES_IN_PATH, - subDir.getFullPath().toString(), null)); - } - } else { - status = new MultiStatus(ManagedBuilderCorePlugin.getUniqueIdentifier(), IStatus.OK, "", null); - } - return status; - } - - /* - * (non-Javadoc) - * - * @see org.eclipse.cdt.managedbuilder.makegen.IManagedBuilderMakefileGenerator# - * getBuildWorkingDir() - */ - @Override - public IPath getBuildWorkingDir() { - if (topBuildDir != null) { - return topBuildDir.removeFirstSegments(1); - } - return null; - } - - /* - * (non-Javadoc) - * - * @see org.eclipse.cdt.managedbuilder.makegen.IManagedBuilderMakefileGenerator# - * getMakefileName() - */ - @Override - public String getMakefileName() { - return MAKEFILE_NAME; - } - - /* - * (non-Javadoc) - * - * @see org.eclipse.cdt.managedbuilder.makegen.IManagedBuilderMakefileGenerator# - * isGeneratedResource(org.eclipse.core.resources.IResource) - */ - @Override - public boolean isGeneratedResource(IResource resource) { - // Is this a generated directory ... - IPath path = resource.getProjectRelativePath(); - // TODO: fix to use builder output dir instead - String[] configNames = ManagedBuildManager.getBuildInfo(project).getConfigurationNames(); - for (String name : configNames) { - IPath root = new Path(name); - // It is if it is a root of the resource pathname - if (root.isPrefixOf(path)) - return true; - } - return false; - } - - private static void save(StringBuffer buffer, IFile file) throws CoreException { - String encoding = null; - try { - encoding = file.getCharset(); - } catch (CoreException ce) { - // use no encoding - } - byte[] bytes = null; - if (encoding != null) { - try { - bytes = buffer.toString().getBytes(encoding); - } catch (Exception e) { - /* JABA is not going to write this code */ - } - } else { - bytes = buffer.toString().getBytes(); - } - ByteArrayInputStream stream = new ByteArrayInputStream(bytes); - // use a platform operation to update the resource contents - boolean force = true; - file.setContents(stream, force, false, null); - } - - /* - * (non-Javadoc) - * - * @see org.eclipse.cdt.managedbuilder.makegen.IManagedBuilderMakefileGenerator# - * regenerateDependencies() - */ - @Override - public void regenerateDependencies(boolean force) throws CoreException { - // A hack for the pre-3.x GCC compilers is to put dummy targets for deps - final IWorkspaceRoot root = CCorePlugin.getWorkspace().getRoot(); - final CoreException[] es = new CoreException[1]; - toolInfos.accept(new IPathSettingsContainerVisitor() { - @Override - public boolean visit(PathSettingsContainer container) { - ToolInfoHolder h = (ToolInfoHolder) container.getValue(); - // Collect the methods that will need to be called - Vector depExts = new Vector(); - IManagedDependencyGenerator2[] postProcessors = new IManagedDependencyGenerator2[h.buildTools.length]; - boolean callPopulateDummyTargets = collectDependencyGeneratorInformation(h, depExts, postProcessors); - // Is there anyone to call if we do find dependency files? - if (!callPopulateDummyTargets) { - int i; - for (i = 0; i < postProcessors.length; i++) { - if (postProcessors[i] != null) - break; - } - if (i == postProcessors.length) - return true; - } - IResourceInfo rcInfo = config.getResourceInfo(container.getPath(), false); - for (IPath path : getDependencyMakefiles(h)) { - // The path to search for the dependency makefile - IPath relDepFilePath = topBuildDir.append(path); - IFile depFile = root.getFile(relDepFilePath); - if (depFile == null || !depFile.isAccessible()) - continue; - try { - callDependencyPostProcessors(rcInfo, h, depFile, postProcessors, callPopulateDummyTargets, - true); - } catch (CoreException e) { - es[0] = e; - return false; - } - } - return true; - } - }); - if (es[0] != null) - throw es[0]; - } - - /* - * (non-Javadoc) - * - * @see org.eclipse.cdt.managedbuilder.makegen.IManagedBuilderMakefileGenerator# - * regenerateMakefiles() - */ - @Override - public MultiStatus regenerateMakefiles() throws CoreException { - MultiStatus status; - // Visit the resources in the project - ResourceProxyVisitor visitor = new ResourceProxyVisitor(this, config); - project.accept(visitor, IResource.NONE); - // See if the user has cancelled the build - checkCancel(); - // Populate the makefile if any buildable source files have been found - // in the project - if (getSubdirList().isEmpty()) { - String info = ManagedMakeMessages.getFormattedString("MakefileGenerator.warning.no.source", - project.getName()); - updateMonitor(info); - status = new MultiStatus(ManagedBuilderCorePlugin.getUniqueIdentifier(), IStatus.INFO, "", null); - status.add(new Status(IStatus.INFO, ManagedBuilderCorePlugin.getUniqueIdentifier(), NO_SOURCE_FOLDERS, info, - null)); - return status; - } - // Create the top-level directory for the build output - topBuildDir = createDirectory(config.getName()); - checkCancel(); - // Get the list of subdirectories - IPath srcsFilePath = topBuildDir.append(SRCSFILE_NAME); - IFile srcsFileHandle = createFile(srcsFilePath); - buildSrcVars.clear(); - buildOutVars.clear(); - buildDepVars.clear(); - topBuildOutVars.clear(); - populateSourcesMakefile(srcsFileHandle); - checkCancel(); - // Now populate the module makefiles - for (IResource res : getSubdirList()) { - IContainer subDir = (IContainer) res; - try { - populateFragmentMakefile(subDir); - } catch (CoreException e) { - // Probably should ask user if they want to continue - checkCancel(); - continue; - } - checkCancel(); - } - // Calculate the inputs and outputs of the Tools to be generated in the - // main makefile - calculateToolInputsOutputs(); - checkCancel(); - // Create the top-level makefile - IPath makefilePath = topBuildDir.append(MAKEFILE_NAME); - IFile makefileHandle = createFile(makefilePath); - populateTopMakefile(makefileHandle, true); - // JABA SLOEBER create the size.awk file - ICConfigurationDescription confDesc = ManagedBuildManager.getDescriptionForConfiguration(config); - IWorkspaceRoot root = CCorePlugin.getWorkspace().getRoot(); - IFile sizeAwkFile1 = root.getFile(topBuildDir.append("size.awk")); - File sizeAwkFile = sizeAwkFile1.getLocation().toFile(); - String regex = Common.getBuildEnvironmentVariable(confDesc, "recipe.size.regex", EMPTY); - String awkContent = "/" + regex + "/ {arduino_size += $2 }\n"; - regex = Common.getBuildEnvironmentVariable(confDesc, "recipe.size.regex.data", EMPTY); - awkContent += "/" + regex + "/ {arduino_data += $2 }\n"; - regex = Common.getBuildEnvironmentVariable(confDesc, "recipe.size.regex.eeprom", EMPTY); - awkContent += "/" + regex + "/ {arduino_eeprom += $2 }\n"; - awkContent += "END { print \"\\n"; - String max = Common.getBuildEnvironmentVariable(confDesc, "upload.maximum_size", "10000"); - awkContent += Messages.sizeReportSketch.replace("maximum_size", max); - awkContent += "\\n"; - max = Common.getBuildEnvironmentVariable(confDesc, "upload.maximum_data_size", "10000"); - awkContent += Messages.sizeReportData.replace("maximum_data_size", max); - awkContent += "\\n"; - awkContent += "\"}"; - - try { - FileUtils.write(sizeAwkFile, awkContent, Charset.defaultCharset()); - } catch (IOException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - // END JABA SLOEBER create the size.awk file - checkCancel(); - // Now finish up by adding all the object files - IPath objFilePath = topBuildDir.append(OBJECTS_MAKFILE); - IFile objsFileHandle = createFile(objFilePath); - populateObjectsMakefile(objsFileHandle); - checkCancel(); - // How did we do - if (!getInvalidDirList().isEmpty()) { - status = new MultiStatus(ManagedBuilderCorePlugin.getUniqueIdentifier(), IStatus.WARNING, "", null); - // Add a new status for each of the bad folders - // TODO: fix error message - for (IResource dir : getInvalidDirList()) { - status.add(new Status(IStatus.WARNING, ManagedBuilderCorePlugin.getUniqueIdentifier(), SPACES_IN_PATH, - dir.getFullPath().toString(), null)); - } - } else { - status = new MultiStatus(ManagedBuilderCorePlugin.getUniqueIdentifier(), IStatus.OK, "", null); - } - return status; - } - - /************************************************************************* - * M A K E F I L E S P O P U L A T I O N M E T H O D S - ************************************************************************/ - /** - * This method generates a "fragment" make file (subdir.mk). One of these is - * generated for each project directory/subdirectory that contains source files. - */ - protected void populateFragmentMakefile(IContainer module) throws CoreException { - // Calculate the new directory relative to the build output - IPath moduleRelativePath = module.getProjectRelativePath(); - IPath buildRoot = getBuildWorkingDir(); - if (buildRoot == null) { - return; - } - IPath moduleOutputPath = buildRoot.append(moduleRelativePath); - updateMonitor(ManagedMakeMessages.getFormattedString("MakefileGenerator.message.gen.source.makefile", - moduleOutputPath.toString())); - // Now create the directory - IPath moduleOutputDir = createDirectory(moduleOutputPath.toString()); - // Create a module makefile - IFile modMakefile = createFile(moduleOutputDir.append(MODFILE_NAME)); - StringBuffer makeBuf = new StringBuffer(); - makeBuf.append(addFragmentMakefileHeader()); - makeBuf.append(addSources(module)); - // Save the files - save(makeBuf, modMakefile); - } - - /** - * The makefile generator generates a Macro for each type of output, other than - * final artifact, created by the build. - * - * @param fileHandle - * The file that should be populated with the output - */ - protected void populateObjectsMakefile(IFile fileHandle) throws CoreException { - // Master list of "object" dependencies, i.e. dependencies between input - // files and output files. - StringBuffer macroBuffer = new StringBuffer(); - List valueList; - macroBuffer.append(addDefaultHeader()); - // Map of macro names (String) to its definition (List of Strings) - HashMap> outputMacros = new HashMap>(); - // Add the predefined LIBS, USER_OBJS macros - // Add the libraries this project depends on - valueList = new ArrayList(); - String[] libs = config.getLibs(buildTargetExt); - for (String lib : libs) { - valueList.add(lib); - } - outputMacros.put("LIBS", valueList); - // Add the extra user-specified objects - valueList = new ArrayList(); - String[] userObjs = config.getUserObjects(buildTargetExt); - for (String obj : userObjs) { - valueList.add(obj); - } - outputMacros.put("USER_OBJS", valueList); - // Write every macro to the file - for (Entry> entry : outputMacros.entrySet()) { - macroBuffer.append(entry.getKey()).append(" :="); - valueList = entry.getValue(); - for (String path : valueList) { - // These macros will also be used within commands. - // Make all the slashes go forward so they aren't - // interpreted as escapes and get lost. - // See https://bugs.eclipse.org/163672. - path = path.replace('\\', '/'); - path = ensurePathIsGNUMakeTargetRuleCompatibleSyntax(path); - macroBuffer.append(WHITESPACE); - macroBuffer.append(path); - } - // terminate the macro definition line - macroBuffer.append(NEWLINE); - // leave a blank line before the next macro - macroBuffer.append(NEWLINE); - } - // For now, just save the buffer that was populated when the rules were - // created - save(macroBuffer, fileHandle); - } - - protected void populateSourcesMakefile(IFile fileHandle) throws CoreException { - // Add the comment - StringBuffer buffer = addDefaultHeader(); - // Determine the set of macros - toolInfos.accept(new IPathSettingsContainerVisitor() { - @Override - public boolean visit(PathSettingsContainer container) { - ToolInfoHolder h = (ToolInfoHolder) container.getValue(); - ITool[] buildTools = h.buildTools; - HashSet handledInputExtensions = new HashSet(); - String buildMacro; - for (ITool buildTool : buildTools) { - if (buildTool.getCustomBuildStep()) - continue; - // Add the known sources macros - String[] extensionsList = buildTool.getAllInputExtensions(); - for (String ext : extensionsList) { - // create a macro of the form "EXTENSION_SRCS :=" - String extensionName = ext; - if (!handledInputExtensions.contains(extensionName)) { - handledInputExtensions.add(extensionName); - buildMacro = getSourceMacroName(extensionName).toString(); - if (!buildSrcVars.containsKey(buildMacro)) { - buildSrcVars.put(buildMacro, new ArrayList()); - } - // Add any generated dependency file macros - IManagedDependencyGeneratorType depType = buildTool - .getDependencyGeneratorForExtension(extensionName); - if (depType != null) { - int calcType = depType.getCalculatorType(); - if (calcType == IManagedDependencyGeneratorType.TYPE_COMMAND - || calcType == IManagedDependencyGeneratorType.TYPE_BUILD_COMMANDS - || calcType == IManagedDependencyGeneratorType.TYPE_PREBUILD_COMMANDS) { - buildMacro = getDepMacroName(extensionName).toString(); - if (!buildDepVars.containsKey(buildMacro)) { - buildDepVars.put(buildMacro, new ArduinoGnuDependencyGroupInfo(buildMacro, - (calcType != IManagedDependencyGeneratorType.TYPE_PREBUILD_COMMANDS))); - } - if (!buildOutVars.containsKey(buildMacro)) { - buildOutVars.put(buildMacro, new ArrayList()); - } - } - } - } - } - // Add the specified output build variables - IOutputType[] outTypes = buildTool.getOutputTypes(); - if (outTypes != null && outTypes.length > 0) { - for (IOutputType outputType : outTypes) { - buildMacro = outputType.getBuildVariable(); - if (!buildOutVars.containsKey(buildMacro)) { - buildOutVars.put(buildMacro, new ArrayList()); - } - } - } else { - // For support of pre-CDT 3.0 integrations. - buildMacro = OBJS_MACRO; - if (!buildOutVars.containsKey(buildMacro)) { - buildOutVars.put(buildMacro, new ArrayList()); - } - } - } - return true; - } - }); - // Add the macros to the makefile - for (Entry> entry : buildSrcVars.entrySet()) { - String macroName = new Path(entry.getKey()).toOSString(); - buffer.append(macroName).append(WHITESPACE).append(":=").append(WHITESPACE).append(NEWLINE); - } - Set>> set = buildOutVars.entrySet(); - for (Entry> entry : set) { - String macroName = new Path(entry.getKey()).toOSString(); - buffer.append(macroName).append(WHITESPACE).append(":=").append(WHITESPACE).append(NEWLINE); - } - // Add a list of subdirectories to the makefile - buffer.append(NEWLINE).append(addSubdirectories()); - // Save the file - save(buffer, fileHandle); - } - - /** - * Create the entire contents of the makefile. - * - * @param fileHandle - * The file to place the contents in. - * @param rebuild - * FLag signaling that the user is doing a full rebuild - */ - protected void populateTopMakefile(IFile fileHandle, boolean rebuild) throws CoreException { - StringBuffer buffer = new StringBuffer(); - // Add the header - buffer.append(addTopHeader()); - // Add the macro definitions - buffer.append(addMacros()); - // List to collect needed build output variables - List outputVarsAdditionsList = new ArrayList(); - // Determine target rules - StringBuffer targetRules = addTargets(outputVarsAdditionsList, rebuild); - // Add outputMacros that were added to by the target rules - buffer.append(writeTopAdditionMacros(outputVarsAdditionsList, getTopBuildOutputVars())); - // Add target rules - buffer.append(targetRules); - // Save the file - save(buffer, fileHandle); - } - - /************************************************************************* - * M A I N (makefile) M A K E F I L E M E T H O D S - ************************************************************************/ - /** - * Answers a StringBuffer containing the comment(s) for the - * top-level makefile. - */ - protected StringBuffer addTopHeader() { - return addDefaultHeader(); - } - - /** - */ - private StringBuffer addMacros() { - StringBuffer buffer = new StringBuffer(); - buffer.append("-include " + ROOT + FILE_SEPARATOR + MAKEFILE_INIT).append(NEWLINE); - buffer.append(NEWLINE); - // Get the clean command from the build model - buffer.append("RM := "); - // support macros in the clean command - String cleanCommand = config.getCleanCommand(); - try { - cleanCommand = ManagedBuildManager.getBuildMacroProvider().resolveValueToMakefileFormat( - config.getCleanCommand(), EMPTY_STRING, WHITESPACE, IBuildMacroProvider.CONTEXT_CONFIGURATION, - config); - } catch (BuildMacroException e) { - // jaba is not going to write this code - } - - buffer.append(cleanCommand).append(NEWLINE); - buffer.append(NEWLINE); - // Now add the source providers - buffer.append(COMMENT_SYMBOL).append(WHITESPACE).append(ManagedMakeMessages.getResourceString(SRC_LISTS)) - .append(NEWLINE); - buffer.append("-include sources.mk").append(NEWLINE); - // JABA Change the include of the "root" (our sketch) folder to be - // before - // libraries and other files - buffer.append("-include subdir.mk").append(NEWLINE); - // Add includes for each subdir in child-subdir-first order (required - // for makefile rule matching to work). - List subDirList = new ArrayList<>(); - for (IContainer subDir : getSubdirList()) { - String projectRelativePath = subDir.getProjectRelativePath().toOSString(); - if (!projectRelativePath.isEmpty()) - subDirList.add(0, projectRelativePath); - } - Collections.sort(subDirList, Collections.reverseOrder()); - for (String dir : subDirList) { - buffer.append("-include ").append(escapeWhitespaces(dir)).append(FILE_SEPARATOR).append("subdir.mk") - .append(NEWLINE); - } - // Change the include of the "root" (our sketch) folder to be before - // libraries and other files - // buffer.append("-include subdir.mk" + NEWLINE); // - buffer.append("-include objects.mk").append(NEWLINE).append(NEWLINE); - // Include generated dependency makefiles if non-empty AND a "clean" has - // not been requested - if (!buildDepVars.isEmpty()) { - buffer.append("ifneq ($(MAKECMDGOALS),clean)").append(NEWLINE); - for (Entry entry : buildDepVars.entrySet()) { - String depsMacro = entry.getKey(); - ArduinoGnuDependencyGroupInfo info = entry.getValue(); - buffer.append("ifneq ($(strip $(").append(depsMacro).append(")),)").append(NEWLINE); - if (info.conditionallyInclude) { - buffer.append("-include $(").append(depsMacro).append(')').append(NEWLINE); - } else { - buffer.append("include $(").append(depsMacro).append(')').append(NEWLINE); - } - buffer.append("endif").append(NEWLINE); - } - buffer.append("endif").append(NEWLINE).append(NEWLINE); - } - // Include makefile.defs supplemental makefile - buffer.append("-include ").append(ROOT).append(FILE_SEPARATOR).append(MAKEFILE_DEFS).append(NEWLINE); - return (buffer.append(NEWLINE)); - } - - private StringBuffer addTargets(List outputVarsAdditionsList, boolean rebuild) { - StringBuffer buffer = new StringBuffer(); - // IConfiguration config = info.getDefaultConfiguration(); - // Assemble the information needed to generate the targets - String prebuildStep = config.getPrebuildStep(); - // JABA issue927 adding recipe.hooks.sketch.prebuild.NUMBER.pattern as cdt - // prebuild command if needed - ICConfigurationDescription confDesc = ManagedBuildManager.getDescriptionForConfiguration(config); - String sketchPrebuild = io.sloeber.core.common.Common.getBuildEnvironmentVariable(confDesc, "sloeber.prebuild", - new String(), false); - if (!sketchPrebuild.isEmpty()) { - String separator = new String(); - if (!prebuildStep.isEmpty()) { - prebuildStep = prebuildStep + "\n\t" + sketchPrebuild; - } else { - prebuildStep = sketchPrebuild; - } - } - // end off JABA issue927 - try { - // try to resolve the build macros in the prebuild step - prebuildStep = ManagedBuildManager.getBuildMacroProvider().resolveValueToMakefileFormat(prebuildStep, - EMPTY_STRING, WHITESPACE, IBuildMacroProvider.CONTEXT_CONFIGURATION, config); - } catch (BuildMacroException e) { - /* JABA is not going to write this code */ - } - prebuildStep = prebuildStep.trim(); - String postbuildStep = config.getPostbuildStep(); - try { - // try to resolve the build macros in the postbuild step - postbuildStep = ManagedBuildManager.getBuildMacroProvider().resolveValueToMakefileFormat(postbuildStep, - EMPTY_STRING, WHITESPACE, IBuildMacroProvider.CONTEXT_CONFIGURATION, config); - } catch (BuildMacroException e) { - /* JABA is not going to write this code */ - } - postbuildStep = postbuildStep.trim(); - String preannouncebuildStep = config.getPreannouncebuildStep(); - String postannouncebuildStep = config.getPostannouncebuildStep(); - String targets = rebuild ? "clean all" : "all"; - ITool targetTool = config.calculateTargetTool(); - // if (targetTool == null) { - // targetTool = info.getToolFromOutputExtension(buildTargetExt); - // } - // Get all the projects the build target depends on - // If this configuration produces a static archive, building the archive - // doesn't depend on the output - // from any of the referenced configurations - IConfiguration[] refConfigs = new IConfiguration[0]; - if (config.getBuildArtefactType() == null || !ManagedBuildManager.BUILD_ARTEFACT_TYPE_PROPERTY_STATICLIB - .equals(config.getBuildArtefactType().getId())) - refConfigs = ManagedBuildManager.getReferencedConfigurations(config); - /* - * try { refdProjects = project.getReferencedProjects(); } catch (CoreException - * e) { // There are 2 exceptions; the project does not exist or it is not open - * // and neither conditions apply if we are building for it .... } - */ - // If a prebuild step exists, redefine the all target to be - // all: {pre-build} main-build - // and then reset the "traditional" all target to main-build - // This will allow something meaningful to happen if the generated - // makefile is - // extracted and run standalone via "make all" - // - - // JABA add the arduino upload/program targets - buffer.append("\n#bootloaderTest\n" + "BurnBootLoader: \n" - + "\t@echo trying to burn bootloader ${bootloader.tool}\n" - + "\t${tools.${bootloader.tool}.erase.pattern}\n" + "\t${tools.${bootloader.tool}.bootloader.pattern}\n" - + "\n" + "uploadWithBuild: all\n" - + "\t@echo trying to build and upload with upload tool ${upload.tool}\n" - + "\t${tools.${upload.tool}.upload.pattern}\n" + "\n" + "uploadWithoutBuild: \n" - + "\t@echo trying to upload without build with upload tool ${upload.tool}\n" - + "\t${tools.${upload.tool}.upload.pattern}\n" + " \n" + "uploadWithProgrammerWithBuild: all\n" - + "\t@echo trying to build and upload with programmer ${program.tool}\n" - + "\t${tools.${program.tool}.program.pattern}\n" + "\n" + "uploadWithProgrammerWithoutBuild: \n" - + "\t@echo trying to upload with programmer ${program.tool} without build\n" - + "\t${tools.${program.tool}.program.pattern}\n\n"); - String defaultTarget = "all:"; - if (prebuildStep.length() > 0) { - // Add the comment for the "All" target - buffer.append(COMMENT_SYMBOL).append(WHITESPACE).append(ManagedMakeMessages.getResourceString(ALL_TARGET)) - .append(NEWLINE); - buffer.append(defaultTarget).append(NEWLINE); - buffer.append(TAB).append(MAKE).append(WHITESPACE).append(NO_PRINT_DIR).append(WHITESPACE).append(PREBUILD) - .append(NEWLINE); - buffer.append(TAB).append(MAKE).append(WHITESPACE).append(NO_PRINT_DIR).append(WHITESPACE).append(MAINBUILD) - .append(NEWLINE); - buffer.append(NEWLINE); - defaultTarget = MAINBUILD.concat(COLON); - buffer.append(COMMENT_SYMBOL).append(WHITESPACE) - .append(ManagedMakeMessages.getResourceString(MAINBUILD_TARGET)).append(NEWLINE); - } else - // Add the comment for the "All" target - buffer.append(COMMENT_SYMBOL).append(WHITESPACE).append(ManagedMakeMessages.getResourceString(ALL_TARGET)) - .append(NEWLINE); - // Write out the all target first in case someone just runs make - // all: or mainbuild: - String outputPrefix = EMPTY_STRING; - if (targetTool != null) { - outputPrefix = targetTool.getOutputPrefix(); - } - buffer.append(defaultTarget).append(WHITESPACE).append(outputPrefix) - .append(ensurePathIsGNUMakeTargetRuleCompatibleSyntax(buildTargetName)); - if (buildTargetExt.length() > 0) { - buffer.append(DOT).append(buildTargetExt); - } - // Add the Secondary Outputs to the all target, if any - IOutputType[] secondaryOutputs = config.getToolChain().getSecondaryOutputs(); - if (secondaryOutputs.length > 0) { - buffer.append(WHITESPACE).append(SECONDARY_OUTPUTS); - } - buffer.append(NEWLINE).append(NEWLINE); - /* - * The build target may depend on other projects in the workspace. These are - * captured in the deps target: deps: ; $(MAKE) [clean - * all | all]> - */ - // Vector managedProjectOutputs = new Vector(refdProjects.length); - // if (refdProjects.length > 0) { - Vector managedProjectOutputs = new Vector(refConfigs.length); - if (refConfigs.length > 0) { - boolean addDeps = true; - // if (refdProjects != null) { - for (IConfiguration depCfg : refConfigs) { - // IProject dep = refdProjects[i]; - if (!depCfg.isManagedBuildOn()) - continue; - // if (!dep.exists()) continue; - if (addDeps) { - buffer.append("dependents:").append(NEWLINE); - addDeps = false; - } - String buildDir = depCfg.getOwner().getLocation().toOSString(); - String depTargets = targets; - // if (ManagedBuildManager.manages(dep)) { - // Add the current configuration to the makefile path - // IManagedBuildInfo depInfo = - // ManagedBuildManager.getBuildInfo(dep); - buildDir += FILE_SEPARATOR + depCfg.getName(); - // Extract the build artifact to add to the dependency list - String depTarget = depCfg.getArtifactName(); - String depExt = depCfg.getArtifactExtension(); - try { - // try to resolve the build macros in the artifact extension - depExt = ManagedBuildManager.getBuildMacroProvider().resolveValueToMakefileFormat(depExt, "", " ", - IBuildMacroProvider.CONTEXT_CONFIGURATION, depCfg); - } catch (BuildMacroException e) { - /* JABA is not going to write this code */ - } - try { - // try to resolve the build macros in the artifact name - String resolved = ManagedBuildManager.getBuildMacroProvider().resolveValueToMakefileFormat( - depTarget, "", " ", IBuildMacroProvider.CONTEXT_CONFIGURATION, depCfg); - if ((resolved = resolved.trim()).length() > 0) - depTarget = resolved; - } catch (BuildMacroException e) { - /* JABA is not going to write this code */ - } - String depPrefix = depCfg.getOutputPrefix(depExt); - if (depCfg.needsRebuild()) { - depTargets = "clean all"; - } - String dependency = buildDir + FILE_SEPARATOR + depPrefix + depTarget; - if (depExt.length() > 0) { - dependency += DOT + depExt; - } - dependency = escapeWhitespaces(dependency); - managedProjectOutputs.add(dependency); - // } - buffer.append(TAB).append("-cd").append(WHITESPACE).append(escapeWhitespaces(buildDir)) - .append(WHITESPACE).append(LOGICAL_AND).append(WHITESPACE).append("$(MAKE) ").append(depTargets) - .append(NEWLINE); - } - // } - buffer.append(NEWLINE); - } - // Add the targets tool rules - buffer.append(addTargetsRules(targetTool, outputVarsAdditionsList, managedProjectOutputs, - (postbuildStep.length() > 0))); - // Add the prebuild step target, if specified - if (prebuildStep.length() > 0) { - buffer.append(PREBUILD).append(COLON).append(NEWLINE); - if (preannouncebuildStep.length() > 0) { - buffer.append(TAB).append(DASH).append(AT).append(escapedEcho(preannouncebuildStep)); - } - buffer.append(TAB).append(DASH).append(prebuildStep).append(NEWLINE); - buffer.append(TAB).append(DASH).append(AT).append(ECHO_BLANK_LINE).append(NEWLINE); - } - // Add the postbuild step, if specified - if (postbuildStep.length() > 0) { - buffer.append(POSTBUILD).append(COLON).append(NEWLINE); - if (postannouncebuildStep.length() > 0) { - buffer.append(TAB).append(DASH).append(AT).append(escapedEcho(postannouncebuildStep)); - } - buffer.append(TAB).append(DASH).append(postbuildStep).append(NEWLINE); - buffer.append(TAB).append(DASH).append(AT).append(ECHO_BLANK_LINE).append(NEWLINE); - } - // Add the Secondary Outputs target, if needed - if (secondaryOutputs.length > 0) { - buffer.append(SECONDARY_OUTPUTS).append(COLON); - Vector outs2 = calculateSecondaryOutputs(secondaryOutputs); - for (int i = 0; i < outs2.size(); i++) { - buffer.append(WHITESPACE).append("$(").append(outs2.get(i)).append(')'); - } - buffer.append(NEWLINE).append(NEWLINE); - } - // Add all the needed dummy and phony targets - buffer.append(".PHONY: all clean dependents"); - if (prebuildStep.length() > 0) { - buffer.append(WHITESPACE).append(MAINBUILD).append(WHITESPACE).append(PREBUILD); - } - if (postbuildStep.length() > 0) { - buffer.append(WHITESPACE).append(POSTBUILD); - } - buffer.append(NEWLINE); - for (String output : managedProjectOutputs) { - buffer.append(output).append(COLON).append(NEWLINE); - } - buffer.append(NEWLINE); - // Include makefile.targets supplemental makefile - buffer.append("-include ").append(ROOT).append(FILE_SEPARATOR).append(MAKEFILE_TARGETS).append(NEWLINE); - return buffer; - } - - /** - * Returns the targets rules. The targets make file (top makefile) contains: 1 - * the rule for the final target tool 2 the rules for all of the tools that use - * multipleOfType in their primary input type 3 the rules for all tools that use - * the output of #2 tools - * - * @param outputVarsAdditionsList - * list to add needed build output variables to - * @param managedProjectOutputs - * Other projects in the workspace that this project depends upon - * @return StringBuffer - */ - private StringBuffer addTargetsRules(ITool targetTool, List outputVarsAdditionsList, - Vector managedProjectOutputs, boolean postbuildStep) { - StringBuffer buffer = new StringBuffer(); - // Add the comment - buffer.append(COMMENT_SYMBOL).append(WHITESPACE).append(ManagedMakeMessages.getResourceString(BUILD_TOP)) - .append(NEWLINE); - ToolInfoHolder h = (ToolInfoHolder) toolInfos.getValue(); - ITool[] buildTools = h.buildTools; - boolean[] buildToolsUsed = h.buildToolsUsed; - // Get the target tool and generate the rule - if (targetTool != null) { - // Note that the name of the target we pass to addRuleForTool does - // not - // appear to be used there (and tool outputs are consulted - // directly), but - // we quote it anyway just in case it starts to use it in future. - if (addRuleForTool(targetTool, buffer, true, ensurePathIsGNUMakeTargetRuleCompatibleSyntax(buildTargetName), - buildTargetExt, outputVarsAdditionsList, managedProjectOutputs, postbuildStep)) { - // Mark the target tool as processed - for (int i = 0; i < buildTools.length; i++) { - if (targetTool == buildTools[i]) { - buildToolsUsed[i] = true; - } - } - } - } else { - buffer.append(TAB).append(AT).append(escapedEcho(MESSAGE_NO_TARGET_TOOL + WHITESPACE + OUT_MACRO)); - } - // Generate the rules for all Tools that specify - // InputType.multipleOfType, and any Tools that - // consume the output of those tools. This does not apply to pre-3.0 - // integrations, since - // the only "multipleOfType" tool is the "target" tool - for (int i = 0; i < buildTools.length; i++) { - ITool tool = buildTools[i]; - IInputType type = tool.getPrimaryInputType(); - if (type != null && type.getMultipleOfType()) { - if (!buildToolsUsed[i]) { - addRuleForTool(tool, buffer, false, null, null, outputVarsAdditionsList, null, false); - // Mark the target tool as processed - buildToolsUsed[i] = true; - // Look for tools that consume the output - generateRulesForConsumers(tool, outputVarsAdditionsList, buffer); - } - } - } - // Add the comment - buffer.append(COMMENT_SYMBOL).append(WHITESPACE).append(ManagedMakeMessages.getResourceString(BUILD_TARGETS)) - .append(NEWLINE); - // Always add a clean target - buffer.append("clean:").append(NEWLINE); - buffer.append(TAB).append("-$(RM)").append(WHITESPACE); - for (Entry> entry : buildOutVars.entrySet()) { - String macroName = entry.getKey(); - buffer.append("$(").append(macroName).append(')'); - } - String outputPrefix = EMPTY_STRING; - if (targetTool != null) { - outputPrefix = targetTool.getOutputPrefix(); - } - String completeBuildTargetName = outputPrefix + buildTargetName; - if (buildTargetExt.length() > 0) { - completeBuildTargetName = completeBuildTargetName + DOT + buildTargetExt; - } - // if (completeBuildTargetName.contains(" ")) { - // buffer.append(WHITESPACE + "\"" + completeBuildTargetName + "\""); - // } else { - // buffer.append(WHITESPACE + completeBuildTargetName); - // } - buffer.append(NEWLINE); - buffer.append(TAB).append(DASH).append(AT).append(ECHO_BLANK_LINE).append(NEWLINE); - return buffer; - } - - /** - * Create the rule - * - * @param buffer - * Buffer to add makefile rules to - * @param bTargetTool - * True if this is the target tool - * @param targetName - * If this is the "targetTool", the target file name, else - * null - * @param targetExt - * If this is the "targetTool", the target file extension, else - * null - * @param outputVarsAdditionsList - * list to add needed build output variables to - * @param managedProjectOutputs - * Other projects in the workspace that this project depends upon - * @param bEmitPostBuildStepCall - * Emit post-build step invocation - */ - protected boolean addRuleForTool(ITool tool, StringBuffer buffer, boolean bTargetTool, String targetName, - String targetExt, List outputVarsAdditionsList, Vector managedProjectOutputs, - boolean bEmitPostBuildStepCall) { - Vector inputs = new Vector(); - Vector dependencies = new Vector(); - Vector outputs = new Vector(); - Vector enumeratedPrimaryOutputs = new Vector(); - Vector enumeratedSecondaryOutputs = new Vector(); - Vector outputVariables = new Vector(); - Vector additionalTargets = new Vector(); - String outputPrefix = EMPTY_STRING; - if (!getToolInputsOutputs(tool, inputs, dependencies, outputs, enumeratedPrimaryOutputs, - enumeratedSecondaryOutputs, outputVariables, additionalTargets, bTargetTool, managedProjectOutputs)) { - return false; - } - // If we have no primary output, make all of the secondary outputs the - // primary output - if (enumeratedPrimaryOutputs.size() == 0) { - enumeratedPrimaryOutputs = enumeratedSecondaryOutputs; - enumeratedSecondaryOutputs.clear(); - } - // Add the output variables for this tool to our list - outputVarsAdditionsList.addAll(outputVariables); - // Create the build rule - String buildRule = EMPTY_STRING; - String outflag = tool.getOutputFlag(); - String primaryOutputs = EMPTY_STRING; - String primaryOutputsQuoted = EMPTY_STRING; - boolean first = true; - for (int i = 0; i < enumeratedPrimaryOutputs.size(); i++) { - String output = enumeratedPrimaryOutputs.get(i); - if (!first) { - primaryOutputs += WHITESPACE; - primaryOutputsQuoted += WHITESPACE; - } - first = false; - primaryOutputs += new Path(output).toOSString(); - primaryOutputsQuoted += ensurePathIsGNUMakeTargetRuleCompatibleSyntax(new Path(output).toOSString()); - } - buildRule += (primaryOutputsQuoted + COLON + WHITESPACE); - first = true; - String calculatedDependencies = EMPTY_STRING; - for (int i = 0; i < dependencies.size(); i++) { - String input = dependencies.get(i); - if (!first) - calculatedDependencies += WHITESPACE; - first = false; - calculatedDependencies += input; - } - buildRule += calculatedDependencies; - // We can't have duplicates in a makefile - if (getRuleList().contains(buildRule)) { - /* JABA is not going to write this code */ - } else { - getRuleList().add(buildRule); - buffer.append(buildRule).append(NEWLINE); - if (bTargetTool) { - buffer.append(TAB).append(AT).append(escapedEcho(MESSAGE_START_BUILD + WHITESPACE + OUT_MACRO)); - } - buffer.append(TAB).append(AT).append(escapedEcho(tool.getAnnouncement())); - // Get the command line for this tool invocation - String[] flags; - try { - flags = tool.getToolCommandFlags(null, null); - } catch (BuildException ex) { - // TODO report error - flags = EMPTY_STRING_ARRAY; - } - String command = tool.getToolCommand(); - try { - // try to resolve the build macros in the tool command - String resolvedCommand = ManagedBuildManager.getBuildMacroProvider().resolveValueToMakefileFormat( - command, EMPTY_STRING, WHITESPACE, IBuildMacroProvider.CONTEXT_FILE, - new FileContextData(null, null, null, tool)); - if ((resolvedCommand = resolvedCommand.trim()).length() > 0) { - command = resolvedCommand.replace(" \"\" ", " "); - } - } catch (BuildMacroException e) { - /* JABA is not going to write this code */ - } - String[] cmdInputs = inputs.toArray(new String[inputs.size()]); - IManagedCommandLineGenerator gen = tool.getCommandLineGenerator(); - IManagedCommandLineInfo cmdLInfo = gen.generateCommandLineInfo(tool, command, flags, outflag, outputPrefix, - primaryOutputs, cmdInputs, getToolCommandLinePattern(tool)); - // The command to build - String buildCmd = null; - if (cmdLInfo == null) { - String toolFlags; - try { - toolFlags = tool.getToolCommandFlagsString(null, null); - } catch (BuildException ex) { - // TODO report error - toolFlags = EMPTY_STRING; - } - buildCmd = command + WHITESPACE + toolFlags + WHITESPACE + outflag + WHITESPACE + outputPrefix - + primaryOutputs + WHITESPACE + IN_MACRO; - } else - buildCmd = cmdLInfo.getCommandLine(); - // resolve any remaining macros in the command after it has been - // generated - try { - //TOFIX JABA heavy hack to get the combiner to work properly - //if the command contains ${ARCHIVES} - //remove the ${AR} - //replace ${ARCHIVES} with ${AR} - String ARCHIVES = " ${ARCHIVES} "; - String AR = " $(AR) "; - if (buildCmd.contains(ARCHIVES)) { - buildCmd = buildCmd.replace(AR, " "); - buildCmd = buildCmd.replace(ARCHIVES, AR); - } - //end JABA heavy hack - String resolvedCommand = ManagedBuildManager.getBuildMacroProvider().resolveValueToMakefileFormat( - buildCmd, EMPTY_STRING, WHITESPACE, IBuildMacroProvider.CONTEXT_FILE, - new FileContextData(null, null, null, tool)); - if ((resolvedCommand = resolvedCommand.trim()).length() > 0) { - buildCmd = resolvedCommand.replace(" \"\" ", " "); - } - } catch (BuildMacroException e) { - /* JABA is not going to write this code */ - } - // buffer.append(TAB).append(AT).append(escapedEcho(buildCmd)); - // buffer.append(TAB).append(AT).append(buildCmd); - buffer.append(TAB).append(buildCmd); - // TODO - // NOTE WELL: Dependency file generation is not handled for this - // type of Tool - // Echo finished message - buffer.append(NEWLINE); - buffer.append(TAB).append(AT).append( - escapedEcho((bTargetTool ? MESSAGE_FINISH_BUILD : MESSAGE_FINISH_FILE) + WHITESPACE + OUT_MACRO)); - buffer.append(TAB).append(AT).append(ECHO_BLANK_LINE); - // If there is a post build step, then add a recursive invocation of - // MAKE to invoke it after the main build - // Note that $(MAKE) will instantiate in the recusive invocation to - // the make command that was used to invoke - // the makefile originally - if (bEmitPostBuildStepCall) { - buffer.append(TAB).append(MAKE).append(WHITESPACE).append(NO_PRINT_DIR).append(WHITESPACE) - .append(POSTBUILD).append(NEWLINE).append(NEWLINE); - } else { - // Just emit a blank line - buffer.append(NEWLINE); - } - } - // If we have secondary outputs, output dependency rules without - // commands - if (enumeratedSecondaryOutputs.size() > 0 || additionalTargets.size() > 0) { - String primaryOutput = enumeratedPrimaryOutputs.get(0); - Vector addlOutputs = new Vector(); - addlOutputs.addAll(enumeratedSecondaryOutputs); - addlOutputs.addAll(additionalTargets); - for (int i = 0; i < addlOutputs.size(); i++) { - String output = addlOutputs.get(i); - String depLine = output + COLON + WHITESPACE + primaryOutput + WHITESPACE + calculatedDependencies - + NEWLINE; - if (!getDepLineList().contains(depLine)) { - getDepLineList().add(depLine); - buffer.append(depLine); - } - } - buffer.append(NEWLINE); - } - return true; - } - - /** - * @param outputVarsAdditionsList - * list to add needed build output variables to - * @param buffer - * buffer to add rules to - */ - private void generateRulesForConsumers(ITool generatingTool, List outputVarsAdditionsList, - StringBuffer buffer) { - // Generate a build rule for any tool that consumes the output of this - // tool - ToolInfoHolder h = (ToolInfoHolder) toolInfos.getValue(); - ITool[] buildTools = h.buildTools; - boolean[] buildToolsUsed = h.buildToolsUsed; - IOutputType[] outTypes = generatingTool.getOutputTypes(); - for (IOutputType outType : outTypes) { - String[] outExts = outType.getOutputExtensions(generatingTool); - String outVariable = outType.getBuildVariable(); - if (outExts != null) { - for (String outExt : outExts) { - for (int k = 0; k < buildTools.length; k++) { - ITool tool = buildTools[k]; - if (!buildToolsUsed[k]) { - // Also has to match build variables if specified - IInputType inType = tool.getInputType(outExt); - if (inType != null) { - String inVariable = inType.getBuildVariable(); - if ((outVariable == null && inVariable == null) || (outVariable != null - && inVariable != null && outVariable.equals(inVariable))) { - if (addRuleForTool(buildTools[k], buffer, false, null, null, - outputVarsAdditionsList, null, false)) { - buildToolsUsed[k] = true; - // Look for tools that consume the - // output - generateRulesForConsumers(buildTools[k], outputVarsAdditionsList, buffer); - } - } - } - } - } - } - } - } - } - - protected boolean getToolInputsOutputs(ITool tool, Vector inputs, Vector dependencies, - Vector outputs, Vector enumeratedPrimaryOutputs, Vector enumeratedSecondaryOutputs, - Vector outputVariables, Vector additionalTargets, boolean bTargetTool, - Vector managedProjectOutputs) { - ToolInfoHolder h = (ToolInfoHolder) toolInfos.getValue(); - ITool[] buildTools = h.buildTools; - ArduinoManagedBuildGnuToolInfo[] gnuToolInfos = h.gnuToolInfos; - // Get the information regarding the tool's inputs and outputs from the - // objects - // created by calculateToolInputsOutputs - IManagedBuildGnuToolInfo toolInfo = null; - for (int i = 0; i < buildTools.length; i++) { - if (tool == buildTools[i]) { - toolInfo = gnuToolInfos[i]; - break; - } - } - if (toolInfo == null) - return false; - // Populate the output Vectors - inputs.addAll(toolInfo.getCommandInputs()); - outputs.addAll(toolInfo.getCommandOutputs()); - enumeratedPrimaryOutputs.addAll(toolInfo.getEnumeratedPrimaryOutputs()); - enumeratedSecondaryOutputs.addAll(toolInfo.getEnumeratedSecondaryOutputs()); - outputVariables.addAll(toolInfo.getOutputVariables()); - Vector unprocessedDependencies = toolInfo.getCommandDependencies(); - for (String path : unprocessedDependencies) { - dependencies.add(ensurePathIsGNUMakeTargetRuleCompatibleSyntax(path)); - } - additionalTargets.addAll(toolInfo.getAdditionalTargets()); - if (bTargetTool && managedProjectOutputs != null) { - for (String output : managedProjectOutputs) { - dependencies.add(output); - } - } - return true; - } - - protected Vector calculateSecondaryOutputs(IOutputType[] secondaryOutputs) { - ToolInfoHolder h = (ToolInfoHolder) toolInfos.getValue(); - ITool[] buildTools = h.buildTools; - Vector buildVars = new Vector(); - for (int i = 0; i < buildTools.length; i++) { - // Add the specified output build variables - IOutputType[] outTypes = buildTools[i].getOutputTypes(); - if (outTypes != null && outTypes.length > 0) { - for (int j = 0; j < outTypes.length; j++) { - IOutputType outType = outTypes[j]; - // Is this one of the secondary outputs? - // Look for an outputType with this ID, or one with a - // superclass with this id - thisType: for (int k = 0; k < secondaryOutputs.length; k++) { - IOutputType matchType = outType; - do { - if (matchType.getId().equals(secondaryOutputs[k].getId())) { - buildVars.add(outType.getBuildVariable()); - break thisType; - } - matchType = matchType.getSuperClass(); - } while (matchType != null); - } - } - } - } - return buildVars; - } - - protected boolean isSecondaryOutputVar(ToolInfoHolder h, IOutputType[] secondaryOutputs, String varName) { - ITool[] buildTools = h.buildTools; - for (ITool buildTool : buildTools) { - // Add the specified output build variables - IOutputType[] outTypes = buildTool.getOutputTypes(); - if (outTypes != null && outTypes.length > 0) { - for (IOutputType outType : outTypes) { - // Is this one of the secondary outputs? - // Look for an outputType with this ID, or one with a - // superclass with this id - for (IOutputType secondaryOutput : secondaryOutputs) { - IOutputType matchType = outType; - do { - if (matchType.getId().equals(secondaryOutput.getId())) { - if (outType.getBuildVariable().equals(varName)) { - return true; - } - } - matchType = matchType.getSuperClass(); - } while (matchType != null); - } - } - } - } - return false; - } - - /************************************************************************* - * S O U R C E S (sources.mk) M A K E F I L E M E T H O D S - ************************************************************************/ - private StringBuffer addSubdirectories() { - StringBuffer buffer = new StringBuffer(); - // Add the comment - buffer.append(COMMENT_SYMBOL).append(WHITESPACE).append(ManagedMakeMessages.getResourceString(MOD_LIST)) - .append(NEWLINE); - buffer.append("SUBDIRS := ").append(LINEBREAK); - // Get all the module names - for (IResource container : getSubdirList()) { - updateMonitor(ManagedMakeMessages.getFormattedString("MakefileGenerator.message.adding.source.folder", - container.getFullPath().toOSString())); - // Check the special case where the module is the project root - if (container.getFullPath() == project.getFullPath()) { - buffer.append(DOT).append(WHITESPACE).append(LINEBREAK); - } else { - IPath path = container.getProjectRelativePath(); - buffer.append(escapeWhitespaces(path.toOSString())).append(WHITESPACE).append(LINEBREAK); - } - } - buffer.append(NEWLINE); - return buffer; - } - - /************************************************************************* - * F R A G M E N T (subdir.mk) M A K E F I L E M E T H O D S - ************************************************************************/ - /** - * Returns a StringBuffer containing the comment(s) for a fragment - * makefile (subdir.mk). - */ - - protected StringBuffer addFragmentMakefileHeader() { - return addDefaultHeader(); - } - - /** - * Returns a StringBuffer containing makefile text for all of the - * sources contributed by a container (project directory/subdirectory) to the - * fragement makefile - * - * @param module - * project resource directory/subdirectory - * @return StringBuffer generated text for the fragement makefile - */ - protected StringBuffer addSources(IContainer module) throws CoreException { - // Calculate the new directory relative to the build output - IPath moduleRelativePath = module.getProjectRelativePath(); - String relativePath = moduleRelativePath.toOSString(); - relativePath += relativePath.length() == 0 ? "" : FILE_SEPARATOR; - // For build macros in the configuration, create a map which will map - // them - // to a string which holds its list of sources. - LinkedHashMap buildVarToRuleStringMap = new LinkedHashMap(); - // Add statements that add the source files in this folder, - // and generated source files, and generated dependency files - // to the build macros - for (Entry> entry : buildSrcVars.entrySet()) { - String macroName = entry.getKey(); - addMacroAdditionPrefix(buildVarToRuleStringMap, macroName, null, false); - } - for (Entry> entry : buildOutVars.entrySet()) { - String macroName = entry.getKey(); - addMacroAdditionPrefix(buildVarToRuleStringMap, macroName, DOT_SLASH_PATH.append(relativePath).toOSString(), - false); - } - // String buffers - StringBuffer buffer = new StringBuffer(); - StringBuffer ruleBuffer = new StringBuffer( - COMMENT_SYMBOL + WHITESPACE + ManagedMakeMessages.getResourceString(MOD_RULES) + NEWLINE); - // Visit the resources in this folder and add each one to a sources - // macro, and generate a build rule, if appropriate - IResource[] resources = module.members(); - IResourceInfo rcInfo; - IFolder folder = project.getFolder(config.getName()); - for (IResource resource : resources) { - if (resource.getType() == IResource.FILE) { - // Check whether this resource is excluded from build - IPath rcProjRelPath = resource.getProjectRelativePath(); - if (!isSource(rcProjRelPath)) - continue; - rcInfo = config.getResourceInfo(rcProjRelPath, false); - // if( (rcInfo.isExcluded()) ) - // continue; - addFragmentMakefileEntriesForSource(buildVarToRuleStringMap, ruleBuffer, folder, relativePath, resource, - getPathForResource(resource), rcInfo, null, false); - } - } - // Write out the macro addition entries to the buffer - buffer.append(writeAdditionMacros(buildVarToRuleStringMap)); - return buffer.append(ruleBuffer).append(NEWLINE); - } - - /* - * (non-Javadoc Adds the entries for a particular source file to the fragment - * makefile - * - * @param buildVarToRuleStringMap map of build variable names to the list of - * files assigned to the variable - * - * @param ruleBuffer buffer to add generated nmakefile text to - * - * @param folder the top level build output directory - * - * @param relativePath build output directory relative path of the current - * output directory - * - * @param resource the source file for this invocation of the tool - this may be - * null for a generated output - * - * @param sourceLocation the full path of the source - * - * @param resConfig the IResourceConfiguration associated with this file or null - * - * @param varName the build variable to add this invocation's outputs to if - * null, use the file extension to find the name - * - * @param generatedSource if true, this file was generated by - * another tool in the tool-chain - */ - protected void addFragmentMakefileEntriesForSource(LinkedHashMap buildVarToRuleStringMap, - StringBuffer ruleBuffer, IFolder folder, String relativePath, IResource resource, IPath sourceLocation, - IResourceInfo rcInfo, String varName, boolean generatedSource) { - // Determine which tool, if any, builds files with this extension - String ext = sourceLocation.getFileExtension(); - // jaba ignore .ino files - if ("ino".equalsIgnoreCase(ext) || "pde".equalsIgnoreCase(ext)) - return; - // end jaba ignore .ino files - ITool tool = null; - // TODO: remove - // IResourceConfiguration resConfig = null; - // if(rcInfo instanceof IFileInfo){ - // resConfig = (IFileInfo)rcInfo; - // } - // end remove - // Use the tool from the resource configuration if there is one - if (rcInfo instanceof IFileInfo) { - IFileInfo fi = (IFileInfo) rcInfo; - ITool[] tools = fi.getToolsToInvoke(); - if (tools != null && tools.length > 0) { - tool = tools[0]; - // if(!tool.getCustomBuildStep()) - addToBuildVar(buildVarToRuleStringMap, ext, varName, relativePath, sourceLocation, generatedSource); - } - } - ToolInfoHolder h = getToolInfo(rcInfo.getPath()); - ITool buildTools[] = h.buildTools; - // if(tool == null){ - // for (int j=0; j generatedOutputs = new Vector(); - Vector generatedDepFiles = new Vector(); - // MODED moved JABA JAn Baeyens get the out type from the add - // source call - usedOutType = null; - addRuleForSource(relativePath, ruleBuffer, resource, sourceLocation, rcInfo, generatedSource, - generatedDepFiles, generatedOutputs); - // If the rule generates a dependency file(s), add the file(s) - // to the variable - if (generatedDepFiles.size() > 0) { - for (int k = 0; k < generatedDepFiles.size(); k++) { - IPath generatedDepFile = generatedDepFiles.get(k); - addMacroAdditionFile(buildVarToRuleStringMap, getDepMacroName(ext).toString(), - (generatedDepFile.isAbsolute() ? "" : DOT_SLASH_PATH.toOSString()) - + generatedDepFile.toOSString()); - } - } - // If the generated outputs of this tool are input to another - // tool, - // 1. add the output to the appropriate macro - // 2. If the tool does not have multipleOfType input, generate - // the rule. - // IOutputType outType = tool.getPrimaryOutputType(); - // MODED - // moved JABA JAn Baeyens get the out type from the add source - // call - String buildVariable = null; - if (usedOutType != null) { - if (tool.getCustomBuildStep()) { - // TODO: This is somewhat of a hack since a custom build - // step - // tool does not currently define a build variable - if (generatedOutputs.size() > 0) { - IPath firstOutput = generatedOutputs.get(0); - String firstExt = firstOutput.getFileExtension(); - ToolInfoHolder tmpH = getFolderToolInfo(rcInfo.getPath()); - ITool[] tmpBuildTools = tmpH.buildTools; - for (ITool tmpBuildTool : tmpBuildTools) { - if (tmpBuildTool.buildsFileType(firstExt)) { - String bV = tmpBuildTool.getPrimaryInputType().getBuildVariable(); - if (bV.length() > 0) { - buildVariable = bV; - break; - } - } - } - } - } else { - buildVariable = usedOutType.getBuildVariable(); - } - } else { - // For support of pre-CDT 3.0 integrations. - buildVariable = OBJS_MACRO; - } - for (int k = 0; k < generatedOutputs.size(); k++) { - IPath generatedOutput; - IResource generateOutputResource; - if (generatedOutputs.get(k).isAbsolute()) { - // TODO: Should we use relative paths when possible - // (e.g., see MbsMacroSupplier.calculateRelPath) - generatedOutput = generatedOutputs.get(k); - // If this file has an absolute path, then the - // generateOutputResource will not be correct - // because the file is not under the project. We use - // this resource in the calls to the dependency - // generator - generateOutputResource = project.getFile(generatedOutput); - } else { - generatedOutput = getPathForResource(project).append(getBuildWorkingDir()) - .append(generatedOutputs.get(k)); - generateOutputResource = project.getFile(getBuildWorkingDir().append(generatedOutputs.get(k))); - } - IResourceInfo nextRcInfo; - if (rcInfo instanceof IFileInfo) { - nextRcInfo = config.getResourceInfo(rcInfo.getPath().removeLastSegments(1), false); - } else { - nextRcInfo = rcInfo; - } - addFragmentMakefileEntriesForSource(buildVarToRuleStringMap, ruleBuffer, folder, relativePath, - generateOutputResource, generatedOutput, nextRcInfo, buildVariable, true); - } - } - } else { - // If this is a secondary input, add it to build vars - if (varName == null) { - for (ITool buildTool : buildTools) { - if (buildTool.isInputFileType(ext)) { - addToBuildVar(buildVarToRuleStringMap, ext, varName, relativePath, sourceLocation, - generatedSource); - break; - } - } - } - // If this generated output is identified as a secondary output, add - // the file to the build variable - else { - IOutputType[] secondaryOutputs = config.getToolChain().getSecondaryOutputs(); - if (secondaryOutputs.length > 0) { - if (isSecondaryOutputVar(h, secondaryOutputs, varName)) { - addMacroAdditionFile(buildVarToRuleStringMap, varName, relativePath, sourceLocation, - generatedSource); - } - } - } - } - } - - /** - * Gets a path for a resource by extracting the Path field from its location - * URI. - * - * @return IPath - * @since 6.0 - */ - - protected IPath getPathForResource(IResource resource) { - return new Path(resource.getLocationURI().getPath()); - } - - /** - * Adds the source file to the appropriate build variable - * - * @param buildVarToRuleStringMap - * map of build variable names to the list of files assigned to the - * variable - * @param ext - * the file extension of the file - * @param varName - * the build variable to add this invocation's outputs to if - * null, use the file extension to find the name - * @param relativePath - * build output directory relative path of the current output - * directory - * @param sourceLocation - * the full path of the source - * @param generatedSource - * if true, this file was generated by another tool in - * the tool-chain - */ - protected void addToBuildVar(LinkedHashMap buildVarToRuleStringMap, String ext, String varName, - String relativePath, IPath sourceLocation, boolean generatedSource) { - List varList = null; - if (varName == null) { - // Get the proper source build variable based upon the extension - varName = getSourceMacroName(ext).toString(); - varList = buildSrcVars.get(varName); - } else { - varList = buildOutVars.get(varName); - } - // Add the resource to the list of all resources associated with a - // variable. - // Do not allow duplicates - there is no reason to and it can be 'bad' - - // e.g., having the same object in the OBJS list can cause duplicate - // symbol errors from the linker - if ((varList != null) && !(varList.contains(sourceLocation))) { - // Since we don't know how these files will be used, we store them - // using a "location" - // path rather than a relative path - varList.add(sourceLocation); - if (!buildVarToRuleStringMap.containsKey(varName)) { - // TODO - is this an error? - } else { - // Add the resource name to the makefile line that adds - // resources to the build variable - addMacroAdditionFile(buildVarToRuleStringMap, varName, relativePath, sourceLocation, generatedSource); - } - } - } - - private IManagedCommandLineInfo generateToolCommandLineInfo(ITool tool, String sourceExtension, String[] flags, - String outputFlag, String outputPrefix, String outputName, String[] inputResources, IPath inputLocation, - IPath outputLocation) { - String cmd = tool.getToolCommand(); - // try to resolve the build macros in the tool command - try { - String resolvedCommand = null; - if ((inputLocation != null && inputLocation.toString().indexOf(" ") != -1) - || (outputLocation != null && outputLocation.toString().indexOf(" ") != -1)) { - resolvedCommand = ManagedBuildManager.getBuildMacroProvider().resolveValue(cmd, "", " ", - IBuildMacroProvider.CONTEXT_FILE, - new FileContextData(inputLocation, outputLocation, null, tool)); - } else { - resolvedCommand = ManagedBuildManager.getBuildMacroProvider().resolveValueToMakefileFormat(cmd, "", " ", - IBuildMacroProvider.CONTEXT_FILE, - new FileContextData(inputLocation, outputLocation, null, tool)); - } - if ((resolvedCommand = resolvedCommand.trim()).length() > 0) - cmd = resolvedCommand; - } catch (BuildMacroException e) { - /* JABA is not going to write this code */ - } - IManagedCommandLineGenerator gen = tool.getCommandLineGenerator(); - return gen.generateCommandLineInfo(tool, cmd, flags, outputFlag, outputPrefix, outputName, inputResources, - getToolCommandLinePattern(tool)); - } - - /** - * Create a rule for this source file. We create a pattern rule if possible. - * This is an example of a pattern rule: /%.: - * ..//%. - * - * @echo Building file: $< - * @echo Invoking tool xxx - * @echo $@ $< - * @ $@ $< && \ echo -n $(@:%.o=%.d) ' - * /' >> $(@:%.o=%.d) && \ -P -MM -MG $< - * >> $(@:%.o=%.d) - * @echo Finished building: $< - * @echo ' ' Note that the macros 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: ../source1/%.cpp - * @echo Building file: $< - * @echo Invoking tool xxx - * @echo g++ -g -O2 -c -I/cygdrive/c/eclipse/workspace/Project/headers -o$@ - * $< @g++ -g -O2 -c -I/cygdrive/c/eclipse/workspace/Project/headers -o$@ - * $< && \ echo -n $(@:%.o=%.d) ' source1/' >> $(@:%.o=%.d) && \ g++ -P - * -MM -MG -g -O2 -c -I/cygdrive/c/eclipse/workspace/Project/headers $< >> - * $(@:%.o=%.d) - * @echo Finished building: $< - * @echo ' ' - * @param relativePath - * top build output directory relative path of the current output - * directory - * @param buffer - * buffer to populate with the build rule - * @param resource - * the source file for this invocation of the tool - * @param sourceLocation - * the full path of the source - * @param rcInfo - * the IResourceInfo associated with this file or null - * @param generatedSource - * true if the resource is a generated output - * @param enumeratedOutputs - * vector of the filenames that are the output of this rule - */ - protected void addRuleForSource(String relativePath, StringBuffer buffer, IResource resource, IPath sourceLocation, - IResourceInfo rcInfo, boolean generatedSource, List generatedDepFiles, - List enumeratedOutputs) { - String fileName = sourceLocation.removeFileExtension().lastSegment(); - String inputExtension = sourceLocation.getFileExtension(); - String outputExtension = null; - ITool tool = null; - if (rcInfo instanceof IFileInfo) { - IFileInfo fi = (IFileInfo) rcInfo; - ITool[] tools = fi.getToolsToInvoke(); - if (tools != null && tools.length > 0) { - tool = tools[0]; - } - } else { - IFolderInfo foInfo = (IFolderInfo) rcInfo; - tool = foInfo.getToolFromInputExtension(inputExtension); - } - ToolInfoHolder h = getToolInfo(rcInfo.getPath()); - if (tool != null) - outputExtension = tool.getOutputExtension(inputExtension); - if (outputExtension == null) - outputExtension = EMPTY_STRING; - // Get the dependency generator information for this tool and file - // extension - IManagedDependencyGenerator oldDepGen = null; - IManagedDependencyGenerator2 depGen = null; - IManagedDependencyInfo depInfo = null; - IManagedDependencyCommands depCommands = null; - IManagedDependencyPreBuild depPreBuild = null; - IPath[] depFiles = null; - boolean doDepGen = false; - { - IManagedDependencyGeneratorType t = null; - if (tool != null) - t = tool.getDependencyGeneratorForExtension(inputExtension); - if (t != null) { - int calcType = t.getCalculatorType(); - if (calcType <= IManagedDependencyGeneratorType.TYPE_OLD_TYPE_LIMIT) { - oldDepGen = (IManagedDependencyGenerator) t; - doDepGen = (calcType == IManagedDependencyGeneratorType.TYPE_COMMAND); - if (doDepGen) { - IPath depFile = Path.fromOSString(relativePath + fileName + DOT + DEP_EXT); - getDependencyMakefiles(h).add(depFile); - generatedDepFiles.add(depFile); - } - } else { - depGen = (IManagedDependencyGenerator2) t; - doDepGen = (calcType == IManagedDependencyGeneratorType.TYPE_BUILD_COMMANDS); - IBuildObject buildContext = rcInfo; - depInfo = depGen.getDependencySourceInfo(resource.getProjectRelativePath(), resource, buildContext, - tool, getBuildWorkingDir()); - if (calcType == IManagedDependencyGeneratorType.TYPE_BUILD_COMMANDS) { - depCommands = (IManagedDependencyCommands) depInfo; - depFiles = depCommands.getDependencyFiles(); - } else if (calcType == IManagedDependencyGeneratorType.TYPE_PREBUILD_COMMANDS) { - depPreBuild = (IManagedDependencyPreBuild) depInfo; - depFiles = depPreBuild.getDependencyFiles(); - } - if (depFiles != null) { - for (IPath depFile : depFiles) { - getDependencyMakefiles(h).add(depFile); - generatedDepFiles.add(depFile); - } - } - } - } - } - // Figure out the output paths - String optDotExt = EMPTY_STRING; - if (outputExtension.length() > 0) - optDotExt = DOT + outputExtension; - Vector ruleOutputs = new Vector(); - Vector enumeratedPrimaryOutputs = new Vector(); - Vector enumeratedSecondaryOutputs = new Vector(); - // JABA - usedOutType = tool.getPrimaryOutputType(); - calculateOutputsForSource(tool, relativePath, resource, sourceLocation, ruleOutputs, enumeratedPrimaryOutputs, - enumeratedSecondaryOutputs); - enumeratedOutputs.addAll(enumeratedPrimaryOutputs); - enumeratedOutputs.addAll(enumeratedSecondaryOutputs); - String primaryOutputName = null; - if (enumeratedPrimaryOutputs.size() > 0) { - primaryOutputName = escapeWhitespaces(enumeratedPrimaryOutputs.get(0).toOSString()); - } else { - primaryOutputName = escapeWhitespaces(relativePath + fileName + optDotExt); - } - String otherPrimaryOutputs = EMPTY_STRING; - for (int i = 1; i < enumeratedPrimaryOutputs.size(); i++) { - otherPrimaryOutputs += WHITESPACE + escapeWhitespaces(enumeratedPrimaryOutputs.get(i).toOSString()); - } - // Output file location needed for the file-specific build macros - IPath outputLocation = Path.fromOSString(primaryOutputName); - if (!outputLocation.isAbsolute()) { - outputLocation = getPathForResource(project).append(getBuildWorkingDir()).append(primaryOutputName); - } - // A separate rule is needed for the resource in the case where explicit - // file-specific macros - // are referenced, or if the resource contains special characters in its - // path (e.g., whitespace) - /* - * fix for 137674 We only need an explicit rule if one of the following is true: - * - The resource is linked, and its full path to its real location contains - * special characters - The resource is not linked, but its project relative - * path contains special characters - */ - boolean resourceNameRequiresExplicitRule = (resource.isLinked() - && containsSpecialCharacters(sourceLocation.toOSString())) - || (!resource.isLinked() && containsSpecialCharacters(resource.getProjectRelativePath().toOSString())); - boolean needExplicitRuleForFile = resourceNameRequiresExplicitRule - || BuildMacroProvider.getReferencedExplitFileMacros(tool).length > 0 - || BuildMacroProvider.getReferencedExplitFileMacros(tool.getToolCommand(), - IBuildMacroProvider.CONTEXT_FILE, - new FileContextData(sourceLocation, outputLocation, null, tool)).length > 0; - // Get and resolve the command - String cmd = tool.getToolCommand(); - try { - String resolvedCommand = null; - if (!needExplicitRuleForFile) { - resolvedCommand = ManagedBuildManager.getBuildMacroProvider().resolveValueToMakefileFormat(cmd, - EMPTY_STRING, WHITESPACE, IBuildMacroProvider.CONTEXT_FILE, - new FileContextData(sourceLocation, outputLocation, null, tool)); - } else { - // if we need an explicit rule then don't use any builder - // variables, resolve everything - // to explicit strings - resolvedCommand = ManagedBuildManager.getBuildMacroProvider().resolveValue(cmd, EMPTY_STRING, - WHITESPACE, IBuildMacroProvider.CONTEXT_FILE, - new FileContextData(sourceLocation, outputLocation, null, tool)); - } - if ((resolvedCommand = resolvedCommand.trim()).length() > 0) - cmd = resolvedCommand; - } catch (BuildMacroException e) { - /* JABA is not going to write this code */ - } - String defaultOutputName = EMPTY_STRING; - String primaryDependencyName = EMPTY_STRING; - String patternPrimaryDependencyName = EMPTY_STRING; - String home = (generatedSource) ? DOT : ROOT; - String resourcePath = null; - boolean patternRule = true; - boolean isItLinked = false; - if (resource.isLinked(IResource.CHECK_ANCESTORS)) { - // it IS linked, so use the actual location - isItLinked = true; - resourcePath = sourceLocation.toOSString(); - // Need a hardcoded rule, not a pattern rule, as a linked file - // can reside in any path - defaultOutputName = escapeWhitespaces(relativePath + fileName + optDotExt); - primaryDependencyName = escapeWhitespaces(resourcePath); - patternRule = false; - } else { - // Use the relative path (not really needed to store per se but in - // the future someone may want this) - resourcePath = relativePath; - // The rule and command to add to the makefile - if (rcInfo instanceof IFileInfo || needExplicitRuleForFile) { - // Need a hardcoded rule, not a pattern rule - defaultOutputName = escapeWhitespaces(resourcePath + fileName + optDotExt); - patternRule = false; - } else { - defaultOutputName = relativePath + WILDCARD + optDotExt; - } - primaryDependencyName = escapeWhitespaces( - home + FILE_SEPARATOR + resourcePath + fileName + DOT + inputExtension); - patternPrimaryDependencyName = home + FILE_SEPARATOR + resourcePath + WILDCARD + DOT + inputExtension; - } // end fix for PR 70491 - // If the tool specifies a dependency calculator of - // TYPE_BUILD_COMMANDS, - // ask whether - // the dependency commands are "generic" (i.e., we can use a pattern - // rule) - boolean needExplicitDependencyCommands = false; - if (depCommands != null) { - needExplicitDependencyCommands = !depCommands.areCommandsGeneric(); - } - // If we still think that we are using a pattern rule, check a few more - // things - if (patternRule) { - patternRule = false; - // Make sure that at least one of the rule outputs contains a %. - for (int i = 0; i < ruleOutputs.size(); i++) { - String ruleOutput = ruleOutputs.get(i).toOSString(); - if (ruleOutput.indexOf('%') >= 0) { - patternRule = true; - break; - } - } - if (patternRule) { - patternRule = !needExplicitDependencyCommands; - } - } - // Begin building the rule for this source file - String buildRule = EMPTY_STRING; - if (patternRule) { - if (ruleOutputs.size() == 0) { - buildRule += defaultOutputName; - } else { - boolean first = true; - for (int i = 0; i < ruleOutputs.size(); i++) { - String ruleOutput = ruleOutputs.get(i).toOSString(); - if (ruleOutput.indexOf('%') >= 0) { - if (first) { - first = false; - } else { - buildRule += WHITESPACE; - } - buildRule += ruleOutput; - } - } - } - } else { - buildRule += primaryOutputName; - } - String buildRuleDependencies = primaryDependencyName; - String patternBuildRuleDependencies = patternPrimaryDependencyName; - // Other additional inputs - // Get any additional dependencies specified for the tool in other - // InputType elements and AdditionalInput elements - IPath[] addlDepPaths = tool.getAdditionalDependencies(); - for (IPath addlDepPath : addlDepPaths) { - // Translate the path from project relative to build directory - // relative - IPath addlPath = addlDepPath; - if (!(addlPath.toString().startsWith("$("))) { - if (!addlPath.isAbsolute()) { - IPath tempPath = project.getLocation().append(new Path(ensureUnquoted(addlPath.toString()))); - if (tempPath != null) { - addlPath = ManagedBuildManager.calculateRelativePath(getTopBuildDir(), tempPath); - } - } - } - String suitablePath = ensurePathIsGNUMakeTargetRuleCompatibleSyntax(addlPath.toOSString()); - buildRuleDependencies += WHITESPACE + suitablePath; - patternBuildRuleDependencies += WHITESPACE + suitablePath; - } - buildRule += COLON + WHITESPACE + (patternRule ? patternBuildRuleDependencies : buildRuleDependencies); - // No duplicates in a makefile. If we already have this rule, don't add - // it or the commands to build the file - if (getRuleList().contains(buildRule)) { - // TODO: Should we assert that this is a pattern rule? - } else { - getRuleList().add(buildRule); - // Echo starting message - buffer.append(buildRule).append(NEWLINE); - buffer.append(TAB).append(AT).append(escapedEcho(MESSAGE_START_FILE + WHITESPACE + IN_MACRO)); - buffer.append(TAB).append(AT).append(escapedEcho(tool.getAnnouncement())); - // If the tool specifies a dependency calculator of - // TYPE_BUILD_COMMANDS, ask whether - // there are any pre-tool commands. - if (depCommands != null) { - String[] preToolCommands = depCommands.getPreToolDependencyCommands(); - if (preToolCommands != null && preToolCommands.length > 0) { - for (String preCmd : preToolCommands) { - try { - String resolvedCommand; - IBuildMacroProvider provider = ManagedBuildManager.getBuildMacroProvider(); - if (!needExplicitRuleForFile) { - resolvedCommand = provider.resolveValueToMakefileFormat(preCmd, EMPTY_STRING, - WHITESPACE, IBuildMacroProvider.CONTEXT_FILE, - new FileContextData(sourceLocation, outputLocation, null, tool)); - } else { - // if we need an explicit rule then don't use - // any builder - // variables, resolve everything to explicit - // strings - resolvedCommand = provider.resolveValue(preCmd, EMPTY_STRING, WHITESPACE, - IBuildMacroProvider.CONTEXT_FILE, - new FileContextData(sourceLocation, outputLocation, null, tool)); - } - if (resolvedCommand != null) - buffer.append(resolvedCommand).append(NEWLINE); - } catch (BuildMacroException e) { - /* JABA is not going to write this code */ - } - } - } - } - // Generate the command line - Vector inputs = new Vector(); - inputs.add(IN_MACRO); - // Other additional inputs - // Get any additional dependencies specified for the tool in other - // InputType elements and AdditionalInput elements - IPath[] addlInputPaths = getAdditionalResourcesForSource(tool); - for (IPath addlInputPath : addlInputPaths) { - // Translate the path from project relative to build directory - // relative - IPath addlPath = addlInputPath; - if (!(addlPath.toString().startsWith("$("))) { - if (!addlPath.isAbsolute()) { - IPath tempPath = getPathForResource(project).append(addlPath); - if (tempPath != null) { - addlPath = ManagedBuildManager.calculateRelativePath(getTopBuildDir(), tempPath); - } - } - } - inputs.add(addlPath.toOSString()); - } - String[] inputStrings = inputs.toArray(new String[inputs.size()]); - String[] flags = null; - // Get the tool command line options - try { - flags = tool.getToolCommandFlags(sourceLocation, outputLocation); - } catch (BuildException ex) { - // TODO add some routines to catch this - flags = EMPTY_STRING_ARRAY; - } - // If we have a TYPE_BUILD_COMMANDS dependency generator, determine - // if there are any options that - // it wants added to the command line - if (depCommands != null) { - flags = addDependencyOptions(depCommands, flags); - } - IManagedCommandLineInfo cmdLInfo = null; - String outflag = null; - String outputPrefix = null; - if (rcInfo instanceof IFileInfo || needExplicitRuleForFile || needExplicitDependencyCommands) { - outflag = tool.getOutputFlag(); - outputPrefix = tool.getOutputPrefix(); - // Call the command line generator - IManagedCommandLineGenerator cmdLGen = tool.getCommandLineGenerator(); - cmdLInfo = cmdLGen.generateCommandLineInfo(tool, cmd, flags, outflag, outputPrefix, - OUT_MACRO + otherPrimaryOutputs, inputStrings, getToolCommandLinePattern(tool)); - } else { - outflag = tool.getOutputFlag(); - outputPrefix = tool.getOutputPrefix(); - // Call the command line generator - cmdLInfo = generateToolCommandLineInfo(tool, inputExtension, flags, outflag, outputPrefix, - OUT_MACRO + otherPrimaryOutputs, inputStrings, sourceLocation, outputLocation); - } - // The command to build - String buildCmd; - if (cmdLInfo != null) { - buildCmd = cmdLInfo.getCommandLine(); - } else { - StringBuffer buildFlags = new StringBuffer(); - for (String flag : flags) { - if (flag != null) { - buildFlags.append(flag).append(WHITESPACE); - } - } - buildCmd = cmd + WHITESPACE + buildFlags.toString().trim() + WHITESPACE + outflag + WHITESPACE - + outputPrefix + OUT_MACRO + otherPrimaryOutputs + WHITESPACE + IN_MACRO; - } - // resolve any remaining macros in the command after it has been - // generated - try { - String resolvedCommand; - IBuildMacroProvider provider = ManagedBuildManager.getBuildMacroProvider(); - if (!needExplicitRuleForFile) { - resolvedCommand = provider.resolveValueToMakefileFormat(buildCmd, EMPTY_STRING, WHITESPACE, - IBuildMacroProvider.CONTEXT_FILE, - new FileContextData(sourceLocation, outputLocation, null, tool)); - } else { - // if we need an explicit rule then don't use any builder - // variables, resolve everything to explicit strings - resolvedCommand = provider.resolveValue(buildCmd, EMPTY_STRING, WHITESPACE, - IBuildMacroProvider.CONTEXT_FILE, - new FileContextData(sourceLocation, outputLocation, null, tool)); - } - if ((resolvedCommand = resolvedCommand.trim()).length() > 0) - buildCmd = resolvedCommand; - } catch (BuildMacroException e) { - /* JABA is not going to write this code */ - } - // buffer.append(TAB).append(AT).append(escapedEcho(buildCmd)); - // buffer.append(TAB).append(AT).append(buildCmd); - // JABA add sketch.prebuild and postbouild if needed - if ("sloeber.ino".equals(fileName)) { - ICConfigurationDescription confDesc = ManagedBuildManager.getDescriptionForConfiguration(config); - String sketchPrebuild = io.sloeber.core.common.Common.getBuildEnvironmentVariable(confDesc, - "sloeber.sketch.prebuild", new String(), true); - String sketchPostBuild = io.sloeber.core.common.Common.getBuildEnvironmentVariable(confDesc, - "sloeber.sketch.postbuild", new String(), true); - if (!sketchPrebuild.isEmpty()) { - buffer.append(TAB).append(sketchPrebuild); - } - buffer.append(TAB).append(buildCmd).append(NEWLINE); - if (!sketchPostBuild.isEmpty()) { - buffer.append(TAB).append(sketchPostBuild); - } - } else { - buffer.append(TAB).append(buildCmd); - } - // end JABA add sketch.prebuild and postbouild if needed - - // Determine if there are any dependencies to calculate - if (doDepGen) { - // Get the dependency rule out of the generator - String[] depCmds = null; - if (oldDepGen != null) { - depCmds = new String[1]; - depCmds[0] = oldDepGen.getDependencyCommand(resource, ManagedBuildManager.getBuildInfo(project)); - } else { - if (depCommands != null) { - depCmds = depCommands.getPostToolDependencyCommands(); - } - } - if (depCmds != null) { - for (String depCmd : depCmds) { - // Resolve any macros in the dep command after it has - // been generated. - // Note: do not trim the result because it will strip - // out necessary tab characters. - buffer.append(WHITESPACE).append(LOGICAL_AND).append(WHITESPACE).append(LINEBREAK); - try { - if (!needExplicitRuleForFile) { - depCmd = ManagedBuildManager.getBuildMacroProvider().resolveValueToMakefileFormat( - depCmd, EMPTY_STRING, WHITESPACE, IBuildMacroProvider.CONTEXT_FILE, - new FileContextData(sourceLocation, outputLocation, null, tool)); - } else { - depCmd = ManagedBuildManager.getBuildMacroProvider().resolveValue(depCmd, EMPTY_STRING, - WHITESPACE, IBuildMacroProvider.CONTEXT_FILE, - new FileContextData(sourceLocation, outputLocation, null, tool)); - } - } catch (BuildMacroException e) { - /* JABA is not going to do this */ - } - buffer.append(depCmd); - } - } - } - // Echo finished message - buffer.append(NEWLINE); - buffer.append(TAB).append(AT).append(escapedEcho(MESSAGE_FINISH_FILE + WHITESPACE + IN_MACRO)); - buffer.append(TAB).append(AT).append(ECHO_BLANK_LINE).append(NEWLINE); - } - // Determine if there are calculated dependencies - IPath[] addlDeps = null; - IPath[] addlTargets = null; - String calculatedDependencies = null; - boolean addedDepLines = false; - String depLine; - if (oldDepGen != null && oldDepGen.getCalculatorType() != IManagedDependencyGeneratorType.TYPE_COMMAND) { - addlDeps = oldCalculateDependenciesForSource(oldDepGen, tool, relativePath, resource); - } else { - if (depGen != null && depGen.getCalculatorType() == IManagedDependencyGeneratorType.TYPE_CUSTOM) { - if (depInfo instanceof IManagedDependencyCalculator) { - IManagedDependencyCalculator depCalculator = (IManagedDependencyCalculator) depInfo; - addlDeps = calculateDependenciesForSource(depCalculator); - addlTargets = depCalculator.getAdditionalTargets(); - } - } - } - if (addlDeps != null && addlDeps.length > 0) { - calculatedDependencies = ""; - for (IPath addlDep : addlDeps) { - calculatedDependencies += WHITESPACE + escapeWhitespaces(addlDep.toOSString()); - } - } - if (calculatedDependencies != null) { - depLine = primaryOutputName + COLON + calculatedDependencies + NEWLINE; - if (!getDepLineList().contains(depLine)) { - getDepLineList().add(depLine); - addedDepLines = true; - buffer.append(depLine); - } - } - // Add any additional outputs here using dependency lines - Vector addlOutputs = new Vector(); - if (enumeratedPrimaryOutputs.size() > 1) { - // Starting with 1 is intentional in order to skip the primary - // output - for (int i = 1; i < enumeratedPrimaryOutputs.size(); i++) - addlOutputs.add(enumeratedPrimaryOutputs.get(i)); - } - addlOutputs.addAll(enumeratedSecondaryOutputs); - if (addlTargets != null) { - for (IPath addlTarget : addlTargets) - addlOutputs.add(addlTarget); - } - for (int i = 0; i < addlOutputs.size(); i++) { - depLine = escapeWhitespaces(addlOutputs.get(i).toOSString()) + COLON + WHITESPACE + primaryOutputName; - if (calculatedDependencies != null) - depLine += calculatedDependencies; - depLine += NEWLINE; - if (!getDepLineList().contains(depLine)) { - getDepLineList().add(depLine); - addedDepLines = true; - buffer.append(depLine); - } - } - if (addedDepLines) { - buffer.append(NEWLINE); - } - // If we are using a dependency calculator of type - // TYPE_PREBUILD_COMMANDS, - // get the rule to build the dependency file - if (depPreBuild != null && depFiles != null) { - addedDepLines = false; - String[] preBuildCommands = depPreBuild.getDependencyCommands(); - if (preBuildCommands != null) { - depLine = ""; - // Can we use a pattern rule? - patternRule = !isItLinked && !needExplicitRuleForFile && depPreBuild.areCommandsGeneric(); - // Begin building the rule - for (int i = 0; i < depFiles.length; i++) { - if (i > 0) - depLine += WHITESPACE; - if (patternRule) { - optDotExt = EMPTY_STRING; - String depExt = depFiles[i].getFileExtension(); - if (depExt != null && depExt.length() > 0) - optDotExt = DOT + depExt; - depLine += escapeWhitespaces(relativePath + WILDCARD + optDotExt); - } else { - depLine += escapeWhitespaces((depFiles[i]).toOSString()); - } - } - depLine += COLON + WHITESPACE + (patternRule ? patternBuildRuleDependencies : buildRuleDependencies); - if (!getDepRuleList().contains(depLine)) { - getDepRuleList().add(depLine); - addedDepLines = true; - buffer.append(depLine).append(NEWLINE); - buffer.append(TAB).append(AT) - .append(escapedEcho(MESSAGE_START_DEPENDENCY + WHITESPACE + OUT_MACRO)); - for (String preBuildCommand : preBuildCommands) { - depLine = preBuildCommand; - // Resolve macros - try { - if (!needExplicitRuleForFile) { - depLine = ManagedBuildManager.getBuildMacroProvider().resolveValueToMakefileFormat( - depLine, EMPTY_STRING, WHITESPACE, IBuildMacroProvider.CONTEXT_FILE, - new FileContextData(sourceLocation, outputLocation, null, tool)); - } else { - depLine = ManagedBuildManager.getBuildMacroProvider().resolveValue(depLine, - EMPTY_STRING, WHITESPACE, IBuildMacroProvider.CONTEXT_FILE, - new FileContextData(sourceLocation, outputLocation, null, tool)); - } - } catch (BuildMacroException e) { - // JABA is not going to write this code - } - // buffer.append(TAB + AT + escapedEcho(depLine)); - // buffer.append(TAB + AT + depLine + NEWLINE); - buffer.append(TAB).append(depLine).append(NEWLINE); - } - } - if (addedDepLines) { - buffer.append(TAB).append(AT).append(ECHO_BLANK_LINE).append(NEWLINE); - } - } - } - } - - /* - * Add any dependency calculator options to the tool options - */ - private String[] addDependencyOptions(IManagedDependencyCommands depCommands, String[] flags) { - String[] depOptions = depCommands.getDependencyCommandOptions(); - if (depOptions != null && depOptions.length > 0) { - int flagsLen = flags.length; - String[] flagsCopy = new String[flags.length + depOptions.length]; - for (int i = 0; i < flags.length; i++) { - flagsCopy[i] = flags[i]; - } - for (int i = 0; i < depOptions.length; i++) { - flagsCopy[i + flagsLen] = depOptions[i]; - } - flags = flagsCopy; - } - return flags; - } - - /** - * Returns any additional resources specified for the tool in other InputType - * elements and AdditionalInput elements - */ - protected IPath[] getAdditionalResourcesForSource(ITool tool) { - List allRes = new ArrayList<>(); - IInputType[] types = tool.getInputTypes(); - for (IInputType type : types) { - // Additional resources come from 2 places. - // 1. From AdditionalInput childen - IPath[] res = type.getAdditionalResources(); - for (IPath re : res) { - allRes.add(re); - } - // 2. From InputTypes that other than the primary input type - if (!type.getPrimaryInput() && type != tool.getPrimaryInputType()) { - String var = type.getBuildVariable(); - if (var != null && var.length() > 0) { - allRes.add(Path.fromOSString("$(" + type.getBuildVariable() + ")")); - } else { - // Use file extensions - String[] typeExts = type.getSourceExtensions(tool); - for (IResource projectResource : projectResources) { - if (projectResource.getType() == IResource.FILE) { - String fileExt = projectResource.getFileExtension(); - if (fileExt == null) { - fileExt = ""; - } - for (String typeExt : typeExts) { - if (fileExt.equals(typeExt)) { - allRes.add(projectResource.getProjectRelativePath()); - break; - } - } - } - } - } - // If an assignToOption has been specified, set the value of the - // option to the inputs - IOption assignToOption = tool.getOptionBySuperClassId(type.getAssignToOptionId()); - IOption option = tool.getOptionBySuperClassId(type.getOptionId()); - if (assignToOption != null && option == null) { - try { - int optType = assignToOption.getValueType(); - IResourceInfo rcInfo = tool.getParentResourceInfo(); - if (rcInfo != null) { - if (optType == IOption.STRING) { - String optVal = ""; - for (int j = 0; j < allRes.size(); j++) { - if (j != 0) { - optVal += " "; - } - String resPath = allRes.get(j).toString(); - if (!resPath.startsWith("$(")) { - IResource addlResource = project.getFile(resPath); - if (addlResource != null) { - IPath addlPath = addlResource.getLocation(); - if (addlPath != null) { - resPath = ManagedBuildManager - .calculateRelativePath(getTopBuildDir(), addlPath).toString(); - } - } - } - optVal += ManagedBuildManager - .calculateRelativePath(getTopBuildDir(), Path.fromOSString(resPath)) - .toString(); - } - ManagedBuildManager.setOption(rcInfo, tool, assignToOption, optVal); - } else if (optType == IOption.STRING_LIST || optType == IOption.LIBRARIES - || optType == IOption.OBJECTS || optType == IOption.INCLUDE_FILES - || optType == IOption.LIBRARY_PATHS || optType == IOption.LIBRARY_FILES - || optType == IOption.MACRO_FILES) { - // TODO: do we need to do anything with undefs - // here? - // Note that the path(s) must be translated from - // project relative - // to top build directory relative - String[] paths = new String[allRes.size()]; - for (int j = 0; j < allRes.size(); j++) { - paths[j] = allRes.get(j).toString(); - if (!paths[j].startsWith("$(")) { - IResource addlResource = project.getFile(paths[j]); - if (addlResource != null) { - IPath addlPath = addlResource.getLocation(); - if (addlPath != null) { - paths[j] = ManagedBuildManager - .calculateRelativePath(getTopBuildDir(), addlPath).toString(); - } - } - } - } - ManagedBuildManager.setOption(rcInfo, tool, assignToOption, paths); - } else if (optType == IOption.BOOLEAN) { - boolean b = false; - if (allRes.size() > 0) - b = true; - ManagedBuildManager.setOption(rcInfo, tool, assignToOption, b); - } else if (optType == IOption.ENUMERATED || optType == IOption.TREE) { - if (allRes.size() > 0) { - String s = allRes.get(0).toString(); - ManagedBuildManager.setOption(rcInfo, tool, assignToOption, s); - } - } - allRes.clear(); - } - } catch (BuildException ex) { - /* JABA is not going to write this code */ - } - } - } - } - return allRes.toArray(new IPath[allRes.size()]); - } - - /** - * Returns the output IPaths for this invocation of the tool with - * the specified source file The priorities for determining the names of the - * outputs of a tool are: 1. If the tool is the build target and primary output, - * use artifact name & extension - This case does not apply here... 2. If an - * option is specified, use the value of the option 3. If a nameProvider is - * specified, call it 4. If outputNames is specified, use it 5. Use the name - * pattern to generate a transformation macro so that the source names can be - * transformed into the target names using the built-in string substitution - * functions of make. - * - * @param relativePath - * build output directory relative path of the current output - * directory - * @param ruleOutputs - * Vector of rule IPaths that are relative to the build directory - * @param enumeratedPrimaryOutputs - * Vector of IPaths of primary outputs that are relative to the build - * directory - * @param enumeratedSecondaryOutputs - * Vector of IPaths of secondary outputs that are relative to the - * build directory - */ - protected void calculateOutputsForSource(ITool tool, String relativePath, IResource resource, IPath sourceLocation, - Vector ruleOutputs, Vector enumeratedPrimaryOutputs, - Vector enumeratedSecondaryOutputs) { - String inExt = sourceLocation.getFileExtension(); - String outExt = tool.getOutputExtension(inExt); - // IResourceInfo rcInfo = tool.getParentResourceInfo(); - IOutputType[] outTypes = tool.getOutputTypes(); - if (outTypes != null && outTypes.length > 0) { - for (IOutputType type : outTypes) { - boolean primaryOutput = (type == tool.getPrimaryOutputType()); - // if (primaryOutput && ignorePrimary) continue; - String outputPrefix = type.getOutputPrefix(); - // Resolve any macros in the outputPrefix - // Note that we cannot use file macros because if we do a clean - // we need to know the actual name of the file to clean, and - // cannot use any builder variables such as $@. Hence we use the - // next best thing, i.e. configuration context. - // figure out the configuration we're using - // IBuildObject toolParent = tool.getParent(); - // IConfiguration config = null; - // if the parent is a config then we're done - // if (toolParent instanceof IConfiguration) - // config = (IConfiguration) toolParent; - // else if (toolParent instanceof IToolChain) { - // // must be a toolchain - // config = (IConfiguration) ((IToolChain) toolParent) - // .getParent(); - // } - // - // else if (toolParent instanceof IResourceConfiguration) { - // config = (IConfiguration) ((IResourceConfiguration) - // toolParent) - // .getParent(); - // } - // else { - // // bad - // throw new AssertionError( - // "tool parent must be one of configuration, toolchain, or - // resource configuration"); - // } - // if (config != null) { - try { - if (containsSpecialCharacters(sourceLocation.toOSString())) { - outputPrefix = ManagedBuildManager.getBuildMacroProvider().resolveValue(outputPrefix, "", " ", - IBuildMacroProvider.CONTEXT_CONFIGURATION, config); - } else { - outputPrefix = ManagedBuildManager.getBuildMacroProvider().resolveValueToMakefileFormat( - outputPrefix, "", " ", IBuildMacroProvider.CONTEXT_CONFIGURATION, config); - } - } catch (BuildMacroException e) { - /* JABA is not going to write this code */ - } - // } - boolean multOfType = type.getMultipleOfType(); - IOption option = tool.getOptionBySuperClassId(type.getOptionId()); - IManagedOutputNameProvider nameProvider = type.getNameProvider(); - String[] outputNames = type.getOutputNames(); - // 1. If the tool is the build target and this is the primary - // output, - // use artifact name & extension - // Not appropriate here... - // 2. If an option is specified, use the value of the option - if (option != null) { - try { - List outputList = new ArrayList(); - int optType = option.getValueType(); - if (optType == IOption.STRING) { - outputList.add(outputPrefix + option.getStringValue()); - } else if (optType == IOption.STRING_LIST || optType == IOption.LIBRARIES - || optType == IOption.OBJECTS || optType == IOption.INCLUDE_FILES - || optType == IOption.LIBRARY_PATHS || optType == IOption.LIBRARY_FILES - || optType == IOption.MACRO_FILES) { - List value = (List) option.getValue(); - outputList = value; - ((Tool) tool).filterValues(optType, outputList); - // Add outputPrefix to each if necessary - if (outputPrefix.length() > 0) { - for (int j = 0; j < outputList.size(); j++) { - outputList.set(j, outputPrefix + outputList.get(j)); - } - } - } - for (int j = 0; j < outputList.size(); j++) { - String outputName = outputList.get(j); - // try to resolve the build macros in the output - // names - try { - String resolved = null; - if (containsSpecialCharacters(sourceLocation.toOSString())) { - resolved = ManagedBuildManager.getBuildMacroProvider().resolveValue(outputName, "", - " ", IBuildMacroProvider.CONTEXT_FILE, - new FileContextData(sourceLocation, null, option, tool)); - } else { - resolved = ManagedBuildManager.getBuildMacroProvider().resolveValueToMakefileFormat( - outputName, "", " ", IBuildMacroProvider.CONTEXT_FILE, - new FileContextData(sourceLocation, null, option, tool)); - } - if ((resolved = resolved.trim()).length() > 0) - outputName = resolved; - } catch (BuildMacroException e) { - /* JABA is not going to write this code */ - } - IPath outPath = Path.fromOSString(outputName); - // If only a file name is specified, add the - // relative path of this output directory - if (outPath.segmentCount() == 1) { - outPath = Path.fromOSString(relativePath + outputList.get(j)); - } - if (primaryOutput) { - ruleOutputs.add(j, outPath); - enumeratedPrimaryOutputs.add(j, resolvePercent(outPath, sourceLocation)); - } else { - ruleOutputs.add(outPath); - enumeratedSecondaryOutputs.add(resolvePercent(outPath, sourceLocation)); - } - } - } catch (BuildException ex) { - /* JABA is not going to write this code */ - } - } else - // 3. If a nameProvider is specified, call it - if (nameProvider != null) { - IPath[] inPaths = new IPath[1]; - inPaths[0] = resource.getProjectRelativePath(); - IPath[] outPaths = null; - // try to find out if thisd is JABA name provider - try { - IManagedOutputNameProviderJaba newNameProvider = (IManagedOutputNameProviderJaba) nameProvider; - outPaths = newNameProvider.getOutputNames(project, config, tool, inPaths); - } catch (Exception e) { - outPaths = nameProvider.getOutputNames(tool, inPaths); - } - if (outPaths != null) { // MODDED BY JABA ADDED to handle - // null as return value - usedOutType = type; // MODDED By JABA added to - // retun the - // output type used to generate the - // command line - for (int j = 0; j < outPaths.length; j++) { - IPath outPath = outPaths[j]; - String outputName = outPaths[j].toOSString(); - // try to resolve the build macros in the output - // names - try { - String resolved = null; - if (containsSpecialCharacters(sourceLocation.toOSString())) { - resolved = ManagedBuildManager.getBuildMacroProvider().resolveValue(outputName, "", - " ", IBuildMacroProvider.CONTEXT_FILE, - new FileContextData(sourceLocation, null, option, tool)); - } else { - resolved = ManagedBuildManager.getBuildMacroProvider().resolveValueToMakefileFormat( - outputName, "", " ", IBuildMacroProvider.CONTEXT_FILE, - new FileContextData(sourceLocation, null, option, tool)); - } - if ((resolved = resolved.trim()).length() > 0) - outputName = resolved; - } catch (BuildMacroException e) { - // JABA is not - // going to write - // this code - } - // If only a file name is specified, add the - // relative path of this output directory - if (outPath.segmentCount() == 1) { - outPath = Path.fromOSString(relativePath + outPath.toOSString()); - } - if (type.getPrimaryOutput()) { - ruleOutputs.add(j, outPath); - enumeratedPrimaryOutputs.add(j, resolvePercent(outPath, sourceLocation)); - } else { - ruleOutputs.add(outPath); - enumeratedSecondaryOutputs.add(resolvePercent(outPath, sourceLocation)); - } - } - } // MODDED BY JABA ADDED - } else - // 4. If outputNames is specified, use it - if (outputNames != null) { - for (int j = 0; j < outputNames.length; j++) { - String outputName = outputNames[j]; - try { - // try to resolve the build macros in the output - // names - String resolved = ManagedBuildManager.getBuildMacroProvider().resolveValueToMakefileFormat( - outputName, "", " ", IBuildMacroProvider.CONTEXT_FILE, - new FileContextData(sourceLocation, null, option, tool)); - if ((resolved = resolved.trim()).length() > 0) - outputName = resolved; - } catch (BuildMacroException e) { - /* JABA is not going to write this code */ - } - IPath outPath = Path.fromOSString(outputName); - // If only a file name is specified, add the relative - // path of this output directory - if (outPath.segmentCount() == 1) { - outPath = Path.fromOSString(relativePath + outPath.toOSString()); - } - if (primaryOutput) { - ruleOutputs.add(j, outPath); - enumeratedPrimaryOutputs.add(j, resolvePercent(outPath, sourceLocation)); - } else { - ruleOutputs.add(outPath); - enumeratedSecondaryOutputs.add(resolvePercent(outPath, sourceLocation)); - } - } - } else { - // 5. Use the name pattern to generate a transformation - // macro - // so that the source names can be transformed into the - // target names - // using the built-in string substitution functions of - // make. - if (multOfType) { - // This case is not handled - a nameProvider or - // outputNames must be specified - // TODO - report error - } else { - String namePattern = type.getNamePattern(); - IPath namePatternPath = null; - if (namePattern == null || namePattern.length() == 0) { - namePattern = relativePath + outputPrefix + IManagedBuilderMakefileGenerator.WILDCARD; - if (outExt != null && outExt.length() > 0) { - namePattern += DOT + outExt; - } - namePatternPath = Path.fromOSString(namePattern); - } else { - if (outputPrefix.length() > 0) { - namePattern = outputPrefix + namePattern; - } - namePatternPath = Path.fromOSString(namePattern); - // If only a file name is specified, add the - // relative path of this output directory - if (namePatternPath.segmentCount() == 1) { - namePatternPath = Path.fromOSString(relativePath + namePatternPath.toOSString()); - } - } - if (primaryOutput) { - ruleOutputs.add(0, namePatternPath); - enumeratedPrimaryOutputs.add(0, resolvePercent(namePatternPath, sourceLocation)); - } else { - ruleOutputs.add(namePatternPath); - enumeratedSecondaryOutputs.add(resolvePercent(namePatternPath, sourceLocation)); - } - } - } - } - } else { - // For support of pre-CDT 3.0 integrations. - // NOTE WELL: This only supports the case of a single "target tool" - // that consumes exactly all of the object files, $OBJS, produced - // by other tools in the build and produces a single output. - // In this case, the output file name is the input file name with - // the output extension. - // if (!ignorePrimary) { - String outPrefix = tool.getOutputPrefix(); - IPath outPath = Path.fromOSString(relativePath + outPrefix + WILDCARD); - outPath = outPath.addFileExtension(outExt); - ruleOutputs.add(0, outPath); - enumeratedPrimaryOutputs.add(0, resolvePercent(outPath, sourceLocation)); - // } - } - } - - /** - * If the path contains a %, returns the path resolved using the resource name - */ - protected IPath resolvePercent(IPath outPath, IPath sourceLocation) { - // Get the input file name - String fileName = sourceLocation.removeFileExtension().lastSegment(); - // Replace the % with the file name - String outName = outPath.toOSString().replace("%", fileName); - IPath result = Path.fromOSString(outName); - return DOT_SLASH_PATH.isPrefixOf(outPath) ? DOT_SLASH_PATH.append(result) : result; - } - - /** - * Returns the dependency IPaths for this invocation of the tool - * with the specified source file - * - * @param depGen - * the dependency calculator - * @param tool - * tool used to build the source file - * @param relativePath - * build output directory relative path of the current output - * directory - * @param resource - * source file to scan for dependencies - * @return Vector of IPaths that are relative to the build directory - */ - protected IPath[] oldCalculateDependenciesForSource(IManagedDependencyGenerator depGen, ITool tool, - String relativePath, IResource resource) { - Vector deps = new Vector(); - int type = depGen.getCalculatorType(); - switch (type) { - case IManagedDependencyGeneratorType.TYPE_INDEXER: - case IManagedDependencyGeneratorType.TYPE_EXTERNAL: - IResource[] res = depGen.findDependencies(resource, project); - if (res != null) { - for (IResource re : res) { - IPath dep = null; - if (re != null) { - IPath addlPath = re.getLocation(); - if (addlPath != null) { - dep = ManagedBuildManager.calculateRelativePath(getTopBuildDir(), addlPath); - } - } - if (dep != null) { - deps.add(dep); - } - } - } - break; - case IManagedDependencyGeneratorType.TYPE_NODEPS: - default: - break; - } - return deps.toArray(new IPath[deps.size()]); - } - - /** - * Returns the dependency IPaths relative to the build directory - * - * @param depCalculator - * the dependency calculator - * @return IPath[] that are relative to the build directory - */ - protected IPath[] calculateDependenciesForSource(IManagedDependencyCalculator depCalculator) { - IPath[] addlDeps = depCalculator.getDependencies(); - if (addlDeps != null) { - for (int i = 0; i < addlDeps.length; i++) { - if (!addlDeps[i].isAbsolute()) { - // Convert from project relative to build directory relative - IPath absolutePath = project.getLocation().append(addlDeps[i]); - addlDeps[i] = ManagedBuildManager.calculateRelativePath(getTopBuildDir(), absolutePath); - } - } - } - return addlDeps; - } - - /************************************************************************* - * M A K E F I L E G E N E R A T I O N C O M M O N M E T H O D S - ************************************************************************/ - /** - * Generates a source macro name from a file extension - */ - public StringBuffer getSourceMacroName(String extensionName) { - StringBuffer macroName = new StringBuffer(); - // We need to handle case sensitivity in file extensions (e.g. .c vs - // .C), so if the - // extension was already upper case, tack on an "UPPER_" to the macro - // name. - // In theory this means there could be a conflict if you had for - // example, - // extensions .c_upper, and .C, but realistically speaking the chances - // of this are - // practically nil so it doesn't seem worth the hassle of generating a - // truly - // unique name. - if (extensionName.equals(extensionName.toUpperCase())) { - macroName.append(extensionName.toUpperCase()).append("_UPPER"); - } else { - // lower case... no need for "UPPER_" - macroName.append(extensionName.toUpperCase()); - } - macroName.append("_SRCS"); - return macroName; - } - - /** - * Generates a generated dependency file macro name from a file extension - */ - public StringBuffer getDepMacroName(String extensionName) { - StringBuffer macroName = new StringBuffer(); - // We need to handle case sensitivity in file extensions (e.g. .c vs - // .C), so if the - // extension was already upper case, tack on an "UPPER_" to the macro - // name. - // In theory this means there could be a conflict if you had for - // example, - // extensions .c_upper, and .C, but realistically speaking the chances - // of this are - // practically nil so it doesn't seem worth the hassle of generating a - // truly - // unique name. - if (extensionName.equals(extensionName.toUpperCase())) { - macroName.append(extensionName.toUpperCase()).append("_UPPER"); - } else { - // lower case... no need for "UPPER_" - macroName.append(extensionName.toUpperCase()); - } - macroName.append("_DEPS"); - return macroName; - } - - /** - * Answers all of the output extensions that the target of the build has tools - * defined to work on. - * - * @return a Set containing all of the output extensions - */ - public Set getOutputExtensions(ToolInfoHolder h) { - if (h.outputExtensionsSet == null) { - // The set of output extensions which will be produced by this tool. - // It is presumed that this set is not very large (likely < 10) so - // a HashSet should provide good performance. - h.outputExtensionsSet = new HashSet<>(); - // For each tool for the target, lookup the kinds of sources it - // outputs - // and add that to our list of output extensions. - for (ITool tool : h.buildTools) { - String[] outputs = tool.getAllOutputExtensions(); - if (outputs != null) { - h.outputExtensionsSet.addAll(Arrays.asList(outputs)); - } - } - } - return h.outputExtensionsSet; - } - - /** - * This method postprocesses a .d file created by a build. It's main job is to - * add dummy targets for the header files dependencies. This prevents make from - * aborting the build if the header file does not exist. A secondary job is to - * work in tandem with the "echo" command that is used by some tool-chains in - * order to get the "targets" part of the dependency rule correct. This method - * adds a comment to the beginning of the dependency file which it checks for to - * determine if this dependency file has already been updated. - * - * @return a true if the dependency file is modified - */ - static public boolean populateDummyTargets(IConfiguration cfg, IFile makefile, boolean force) - throws CoreException, IOException { - return populateDummyTargets(cfg.getRootFolderInfo(), makefile, force); - } - - static public boolean populateDummyTargets(IResourceInfo rcInfo, IFile makefile, boolean force) - throws CoreException, IOException { - if (makefile == null || !makefile.exists()) - return false; - // Get the contents of the dependency file - InputStream contentStream = makefile.getContents(false); - StringBuffer inBuffer = null; - // JABA made sure thgere are no emory leaks - try (Reader in = new InputStreamReader(contentStream);) { - int chunkSize = contentStream.available(); - inBuffer = new StringBuffer(chunkSize); - char[] readBuffer = new char[chunkSize]; - int n = in.read(readBuffer); - while (n > 0) { - inBuffer.append(readBuffer); - n = in.read(readBuffer); - } - contentStream.close(); - in.close(); - } - // The rest of this operation is equally expensive, so - // if we are doing an incremental build, only update the - // files that do not have a comment - String inBufferString = inBuffer.toString(); - if (!force && inBufferString.startsWith(COMMENT_SYMBOL)) { - return false; - } - // Try to determine if this file already has dummy targets defined. - // If so, we will only add the comment. - String[] bufferLines = inBufferString.split("[\\r\\n]"); - for (String bufferLine : bufferLines) { - if (bufferLine.endsWith(":")) { - StringBuffer outBuffer = addDefaultHeader(); - outBuffer.append(inBuffer); - save(outBuffer, makefile); - return true; - } - } - // Reconstruct the buffer tokens into useful chunks of dependency - // information - Vector bufferTokens = new Vector(Arrays.asList(inBufferString.split("\\s"))); - Vector deps = new Vector(bufferTokens.size()); - Iterator tokenIter = bufferTokens.iterator(); - while (tokenIter.hasNext()) { - String token = tokenIter.next(); - if (token.lastIndexOf("\\") == token.length() - 1 && token.length() > 1) { - // This is escaped so keep adding to the token until we find the - // end - while (tokenIter.hasNext()) { - String nextToken = tokenIter.next(); - token += WHITESPACE + nextToken; - if (!nextToken.endsWith("\\")) { - break; - } - } - } - deps.add(token); - } - deps.trimToSize(); - // Now find the header file dependencies and make dummy targets for them - boolean save = false; - StringBuffer outBuffer = null; - // If we are doing an incremental build, only update the files that do - // not have a comment - String firstToken; - try { - firstToken = deps.get(0); - } catch (ArrayIndexOutOfBoundsException e) { - // This makes no sense so bail - return false; - } - // Put the generated comments in the output buffer - if (!firstToken.startsWith(COMMENT_SYMBOL)) { - outBuffer = addDefaultHeader(); - } else { - outBuffer = new StringBuffer(); - } - // Some echo implementations misbehave and put the -n and newline in the - // output - if (firstToken.startsWith("-n")) { - // Now let's parse: - // Win32 outputs -n '/.d /' - // POSIX outputs -n /.d / - // Get the dep file name - String secondToken; - try { - secondToken = deps.get(1); - } catch (ArrayIndexOutOfBoundsException e) { - secondToken = ""; - } - if (secondToken.startsWith("'")) { - // This is the Win32 implementation of echo (MinGW without MSYS) - outBuffer.append(secondToken.substring(1)).append(WHITESPACE); - } else { - outBuffer.append(secondToken).append(WHITESPACE); - } - // The relative path to the build goal comes next - String thirdToken; - try { - thirdToken = deps.get(2); - } catch (ArrayIndexOutOfBoundsException e) { - thirdToken = ""; - } - int lastIndex = thirdToken.lastIndexOf("'"); - if (lastIndex != -1) { - if (lastIndex == 0) { - outBuffer.append(WHITESPACE); - } else { - outBuffer.append(thirdToken.substring(0, lastIndex - 1)); - } - } else { - outBuffer.append(thirdToken); - } - // Followed by the target output by the compiler plus ':' - // If we see any empty tokens here, assume they are the result of - // a line feed output by "echo" and skip them - String fourthToken; - int nToken = 3; - try { - do { - fourthToken = deps.get(nToken++); - } while (fourthToken.length() == 0); - } catch (ArrayIndexOutOfBoundsException e) { - fourthToken = ""; - } - outBuffer.append(fourthToken).append(WHITESPACE); - // Followed by the actual dependencies - try { - for (String nextElement : deps) { - if (nextElement.endsWith("\\")) { - outBuffer.append(nextElement).append(NEWLINE).append(WHITESPACE); - } else { - outBuffer.append(nextElement).append(WHITESPACE); - } - } - } catch (IndexOutOfBoundsException e) { - /* JABA is not going to write this code */ - } - } else { - outBuffer.append(inBuffer); - } - outBuffer.append(NEWLINE); - save = true; - IFolderInfo fo = null; - if (rcInfo instanceof IFolderInfo) { - fo = (IFolderInfo) rcInfo; - } else { - IConfiguration c = rcInfo.getParent(); - fo = (IFolderInfo) c.getResourceInfo(rcInfo.getPath().removeLastSegments(1), false); - } - // Dummy targets to add to the makefile - for (String dummy : deps) { - IPath dep = new Path(dummy); - String extension = dep.getFileExtension(); - if (fo.isHeaderFile(extension)) { - /* - * The formatting here is : - */ - outBuffer.append(dummy).append(COLON).append(NEWLINE).append(NEWLINE); - } - } - // Write them out to the makefile - if (save) { - save(outBuffer, makefile); - return true; - } - return false; - } - - /** - * prepend all instanced of '\' or '"' with a backslash - * - * @return resulting string - */ - static public String escapedEcho(String string) { - String escapedString = string.replace("'", "'\"'\"'"); - return ECHO + WHITESPACE + SINGLE_QUOTE + escapedString + SINGLE_QUOTE + NEWLINE; - } - - static public String ECHO_BLANK_LINE = ECHO + WHITESPACE + SINGLE_QUOTE + WHITESPACE + SINGLE_QUOTE + NEWLINE; - - /** - * Outputs a comment formatted as follows: ##### ....... ##### # ##### ....... ##### - */ - static protected StringBuffer addDefaultHeader() { - StringBuffer buffer = new StringBuffer(); - outputCommentLine(buffer); - buffer.append(COMMENT_SYMBOL).append(WHITESPACE).append(ManagedMakeMessages.getResourceString(HEADER)) - .append(NEWLINE); - outputCommentLine(buffer); - buffer.append(NEWLINE); - return buffer; - } - - /** - * Put COLS_PER_LINE comment charaters in the argument. - */ - static protected void outputCommentLine(StringBuffer buffer) { - for (int i = 0; i < COLS_PER_LINE; i++) { - buffer.append(COMMENT_SYMBOL); - } - buffer.append(NEWLINE); - } - - static public boolean containsSpecialCharacters(String path) { - return path.matches(".*(\\s|[\\{\\}\\(\\)\\$\\@%=;]).*"); - } - - /** - * Answers the argument with all whitespaces replaced with an escape sequence. - */ - static public String escapeWhitespaces(String path) { - // Escape the spaces in the path/filename if it has any - String[] segments = path.split("\\s"); - if (segments.length > 1) { - StringBuffer escapedPath = new StringBuffer(); - for (int index = 0; index < segments.length; ++index) { - escapedPath.append(segments[index]); - if (index + 1 < segments.length) { - escapedPath.append("\\ "); - } - } - return escapedPath.toString().trim(); - } - return path; - } - - /** - * Adds a macro addition prefix to a map of macro names to entries. Entry - * prefixes look like: C_SRCS += \ ${addprefix $(ROOT)/, \ - */ - protected void addMacroAdditionPrefix(LinkedHashMap map, String macroName, String relativePath, - boolean addPrefix) { - // there is no entry in the map, so create a buffer for this macro - StringBuffer tempBuffer = new StringBuffer(); - tempBuffer.append(macroName).append(WHITESPACE).append(MACRO_ADDITION_PREFIX_SUFFIX); - if (addPrefix) { - tempBuffer.append(new Path(MACRO_ADDITION_ADDPREFIX_HEADER).append(relativePath) - .append(MACRO_ADDITION_ADDPREFIX_SUFFIX).toOSString()); - } - // have to store the buffer in String form as StringBuffer is not a - // sublcass of Object - map.put(macroName, tempBuffer.toString()); - } - - /** - * Adds a file to an entry in a map of macro names to entries. File additions - * look like: example.c, \ - */ - protected void addMacroAdditionFile(HashMap map, String macroName, String filename) { - StringBuffer buffer = new StringBuffer(); - buffer.append(map.get(macroName)); - filename = escapeWhitespaces(filename); - buffer.append(filename).append(WHITESPACE).append(LINEBREAK); - map.put(macroName, buffer.toString()); - } - - /** - * Adds a file to an entry in a map of macro names to entries. File additions - * look like: example.c, \ - */ - protected void addMacroAdditionFile(HashMap map, String macroName, String relativePath, - IPath sourceLocation, boolean generatedSource) { - // Add the source file path to the makefile line that adds source files - // to the build variable - String srcName; - IPath projectLocation = getPathForResource(project); - IPath dirLocation = projectLocation; - if (generatedSource) { - dirLocation = dirLocation.append(getBuildWorkingDir()); - } - if (dirLocation.isPrefixOf(sourceLocation)) { - IPath srcPath = sourceLocation.removeFirstSegments(dirLocation.segmentCount()).setDevice(null); - if (generatedSource) { - srcName = DOT_SLASH_PATH.append(srcPath).toOSString(); - } else { - srcName = ROOT + FILE_SEPARATOR + srcPath.toOSString(); - } - } else { - if (generatedSource && !sourceLocation.isAbsolute()) { - srcName = DOT_SLASH_PATH.append(relativePath).append(sourceLocation.lastSegment()).toOSString(); - } else { - // TODO: Should we use relative paths when possible (e.g., see - // MbsMacroSupplier.calculateRelPath) - srcName = sourceLocation.toOSString(); - } - } - addMacroAdditionFile(map, macroName, srcName); - } - - /** - * Adds file(s) to an entry in a map of macro names to entries. File additions - * look like: example.c, \ - */ - public void addMacroAdditionFiles(HashMap map, String macroName, Vector filenames) { - StringBuffer buffer = new StringBuffer(); - buffer.append(map.get(macroName)); - for (int i = 0; i < filenames.size(); i++) { - String filename = filenames.get(i); - if (filename.length() > 0) { - filename = ensurePathIsGNUMakeTargetRuleCompatibleSyntax(filename); - buffer.append(new Path(filename).toOSString()).append(WHITESPACE).append(LINEBREAK); - } - } - // re-insert string in the map - map.put(macroName, buffer.toString()); - } - - /** - * Write all macro addition entries in a map to the buffer - */ - protected StringBuffer writeAdditionMacros(LinkedHashMap map) { - StringBuffer buffer = new StringBuffer(); - // Add the comment - buffer.append(COMMENT_SYMBOL).append(WHITESPACE).append(ManagedMakeMessages.getResourceString(MOD_VARS)) - .append(NEWLINE); - for (String macroString : map.values()) { - // Check if we added any files to the rule - // Currently, we do this by comparing the end of the rule buffer to - // MACRO_ADDITION_PREFIX_SUFFIX - if (!(macroString.endsWith(MACRO_ADDITION_PREFIX_SUFFIX))) { - StringBuffer currentBuffer = new StringBuffer(); - // Remove the final "/" - if (macroString.endsWith(LINEBREAK)) { - macroString = macroString.substring(0, (macroString.length() - 2)) + NEWLINE; - } - currentBuffer.append(macroString); - currentBuffer.append(NEWLINE); - // append the contents of the buffer to the master buffer for - // the whole file - buffer.append(currentBuffer); - } - } - return buffer.append(NEWLINE); - } - - /** - * Write all macro addition entries in a map to the buffer - */ - protected StringBuffer writeTopAdditionMacros(List varList, HashMap varMap) { - StringBuffer buffer = new StringBuffer(); - // Add the comment - buffer.append(COMMENT_SYMBOL).append(WHITESPACE).append(ManagedMakeMessages.getResourceString(MOD_VARS)) - .append(NEWLINE); - for (int i = 0; i < varList.size(); i++) { - String addition = varMap.get(varList.get(i)); - StringBuffer currentBuffer = new StringBuffer(); - currentBuffer.append(addition); - currentBuffer.append(NEWLINE); - // append the contents of the buffer to the master buffer for the - // whole file - buffer.append(currentBuffer); - } - return buffer.append(NEWLINE); - } - - /** - * Calculates the inputs and outputs for tools that will be generated in the top - * makefile. This information is used by the top level makefile generation - * methods. - */ - protected void calculateToolInputsOutputs() { - toolInfos.accept(new IPathSettingsContainerVisitor() { - @Override - public boolean visit(PathSettingsContainer container) { - ToolInfoHolder h = (ToolInfoHolder) container.getValue(); - ITool[] buildTools = h.buildTools; - ArduinoManagedBuildGnuToolInfo[] gnuToolInfos = h.gnuToolInfos; - // We are "done" when the information for all tools has been - // calculated, - // or we are not making any progress - boolean done = false; - boolean lastChance = false; - int[] doneState = new int[buildTools.length]; - // Identify the target tool - ITool targetTool = config.calculateTargetTool(); - // if (targetTool == null) { - // targetTool = info.getToolFromOutputExtension(buildTargetExt); - // } - // Initialize the tool info array and the done state - if (buildTools.length != 0 && buildTools[0].getCustomBuildStep()) - return true; - for (int i = 0; i < buildTools.length; i++) { - if ((buildTools[i] == targetTool)) { - String ext = config.getArtifactExtension(); - // try to resolve the build macros in the artifact - // extension - try { - ext = ManagedBuildManager.getBuildMacroProvider().resolveValueToMakefileFormat(ext, "", " ", - IBuildMacroProvider.CONTEXT_CONFIGURATION, config); - } catch (BuildMacroException e) { - /* JABA is not going to write this code */ - } - String name = config.getArtifactName(); - // try to resolve the build macros in the artifact name - try { - String resolved = ManagedBuildManager.getBuildMacroProvider().resolveValueToMakefileFormat( - name, "", " ", IBuildMacroProvider.CONTEXT_CONFIGURATION, config); - if ((resolved = resolved.trim()).length() > 0) - name = resolved; - } catch (BuildMacroException e) { - /* JABA is not going to write this code */ - } - gnuToolInfos[i] = new ArduinoManagedBuildGnuToolInfo(project, buildTools[i], true, name, ext); - } else { - gnuToolInfos[i] = new ArduinoManagedBuildGnuToolInfo(project, buildTools[i], false, null, null); - } - doneState[i] = 0; - } - // Initialize the build output variable to file additions map - LinkedHashMap map = getTopBuildOutputVars(); - Set>> set = buildOutVars.entrySet(); - for (Entry> entry : set) { - String macroName = entry.getKey(); - // for projects with specific setting on folders/files do - // not clear the macro value on subsequent passes - if (!map.containsKey(macroName)) { - addMacroAdditionPrefix(map, macroName, "", false); - } - } - // Set of input extensions for which macros have been created so - // far - HashSet handledDepsInputExtensions = new HashSet<>(); - HashSet handledOutsInputExtensions = new HashSet<>(); - while (!done) { - int[] testState = new int[doneState.length]; - for (int i = 0; i < testState.length; i++) - testState[i] = 0; - // Calculate inputs - for (int i = 0; i < gnuToolInfos.length; i++) { - if (gnuToolInfos[i].areInputsCalculated()) { - testState[i]++; - } else { - if (gnuToolInfos[i].calculateInputs(ArduinoGnuMakefileGenerator.this, config, - projectResources, h, lastChance)) { - testState[i]++; - } - } - } - // Calculate dependencies - for (int i = 0; i < gnuToolInfos.length; i++) { - if (gnuToolInfos[i].areDependenciesCalculated()) { - testState[i]++; - } else { - if (gnuToolInfos[i].calculateDependencies(ArduinoGnuMakefileGenerator.this, config, - handledDepsInputExtensions, h, lastChance)) { - testState[i]++; - } - } - } - // Calculate outputs - for (int i = 0; i < gnuToolInfos.length; i++) { - if (gnuToolInfos[i].areOutputsCalculated()) { - testState[i]++; - } else { - if (gnuToolInfos[i].calculateOutputs(ArduinoGnuMakefileGenerator.this, config, - handledOutsInputExtensions, lastChance)) { - testState[i]++; - } - } - } - // Are all calculated? If so, done. - done = true; - for (int element : testState) { - if (element != 3) { - done = false; - break; - } - } - // Test our "done" state vs. the previous "done" state. - // If we have made no progress, give it a "last chance" and - // then quit - if (!done) { - done = true; - for (int i = 0; i < testState.length; i++) { - if (testState[i] != doneState[i]) { - done = false; - break; - } - } - } - if (done) { - if (!lastChance) { - lastChance = true; - done = false; - } - } - if (!done) { - doneState = testState; - } - } - return true; - } - }); - } - - /** - * Returns the (String) list of files associated with the build variable - * - * @param variable - * the variable name - * @param locationType - * the format in which we want the filenames returned - * @param directory - * project relative directory path used with locationType == - * DIRECTORY_RELATIVE - * @param getAll - * only return the list if all tools that are going to contrubute to - * this variable have done so. - * @return List - */ - public List getBuildVariableList(ToolInfoHolder h, String variable, int locationType, IPath directory, - boolean getAll) { - ArduinoManagedBuildGnuToolInfo[] gnuToolInfos = h.gnuToolInfos; - boolean done = true; - for (int i = 0; i < gnuToolInfos.length; i++) { - if (!gnuToolInfos[i].areOutputVariablesCalculated()) { - done = false; - } - } - if (!done && getAll) - return null; - List list = buildSrcVars.get(variable); - if (list == null) { - list = buildOutVars.get(variable); - } - List fileList = null; - if (list != null) { - // Convert the items in the list to the location-type wanted by the - // caller, - // and to a string list - IPath dirLocation = null; - if (locationType != ABSOLUTE) { - dirLocation = project.getLocation(); - if (locationType == PROJECT_SUBDIR_RELATIVE) { - dirLocation = dirLocation.append(directory); - } - } - for (int i = 0; i < list.size(); i++) { - IPath path = list.get(i); - if (locationType != ABSOLUTE) { - if (dirLocation != null && dirLocation.isPrefixOf(path)) { - path = path.removeFirstSegments(dirLocation.segmentCount()).setDevice(null); - } - } - if (fileList == null) { - fileList = new Vector(); - } - fileList.add(path.toString()); - } - } - return fileList; - } - - /** - * Returns the map of build variables to list of files - * - * @return HashMap - */ - public HashMap> getBuildOutputVars() { - return buildOutVars; - } - - /** - * Returns the map of build variables used in the top makefile to list of files - * - * @return HashMap - */ - public LinkedHashMap getTopBuildOutputVars() { - return topBuildOutVars; - } - - /** - * Returns the list of known build rules. This keeps me from generating - * duplicate rules for known file extensions. - * - * @return List - */ - protected Vector getRuleList() { - if (ruleList == null) { - ruleList = new Vector(); - } - return ruleList; - } - - /** - * Returns the list of known dependency lines. This keeps me from generating - * duplicate lines. - * - * @return List - */ - protected Vector getDepLineList() { - if (depLineList == null) { - depLineList = new Vector(); - } - return depLineList; - } - - /** - * Returns the list of known dependency file generation lines. This keeps me - * from generating duplicate lines. - * - * @return List - */ - protected Vector getDepRuleList() { - if (depRuleList == null) { - depRuleList = new Vector(); - } - return depRuleList; - } - - /************************************************************************* - * R E S O U R C E V I S I T O R M E T H O D S - ************************************************************************/ - /** - * Adds the container of the argument to the list of folders in the project that - * contribute source files to the build. The resource visitor has already - * established that the build model knows how to build the files. It has also - * checked that the resource is not generated as part of the build. - */ - protected void appendBuildSubdirectory(IResource resource) { - IContainer container = resource.getParent(); - // Only add the container once - if (!getSubdirList().contains(container)) - getSubdirList().add(container); - } - - /** - * Adds the container of the argument to a list of subdirectories that are to be - * deleted. As a result, the directories that are generated for the output - * should be removed as well. - */ - protected void appendDeletedSubdirectory(IContainer container) { - // No point in adding a folder if the parent is already there - IContainer parent = container.getParent(); - if (!getDeletedDirList().contains(container) && !getDeletedDirList().contains(parent)) { - getDeletedDirList().add(container); - } - } - - /** - * If a file is removed from a source folder (either because of a delete or move - * action on the part of the user), the makefilegenerator has to remove the - * dependency makefile along with the old build goal - */ - protected void appendDeletedFile(IResource resource) { - // Cache this for now - getDeletedFileList().add(resource); - } - - /** - * Adds the container of the argument to a list of subdirectories that are part - * of an incremental rebuild of the project. The makefile fragments for these - * directories will be regenerated as a result of the build. - */ - protected void appendModifiedSubdirectory(IResource resource) { - IContainer container = resource.getParent(); - if (!getModifiedList().contains(container)) { - getModifiedList().add(container); - } - } - - /************************************************************************* - * O T H E R M E T H O D S - ************************************************************************/ - protected void cancel(String message) { - if (monitor != null && !monitor.isCanceled()) { - throw new OperationCanceledException(message); - } - } - - /** - * Check whether the build has been cancelled. Cancellation requests propagated - * to the caller by throwing OperationCanceledException. - * - * @see org.eclipse.core.runtime.OperationCanceledException#OperationCanceledException() - */ - protected void checkCancel() { - if (monitor != null && monitor.isCanceled()) { - throw new OperationCanceledException(); - } - } - - /** - * Return or create the folder needed for the build output. If we are creating - * the folder, set the derived bit to true so the CM system ignores the - * contents. If the resource exists, respect the existing derived setting. - */ - 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; - } - // Make sure the folder is marked as derived so it is not added to - // CM - if (!folder.isDerived()) { - folder.setDerived(true, null); - } - } - return folder.getFullPath(); - } - - /** - * Return or create the makefile needed for the build. If we are creating the - * resource, set the derived bit to true so the CM system ignores the contents. - * If the resource exists, respect the existing derived setting. - */ - 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, new SubProgressMonitor(monitor, 1)); - // Make sure the new file is marked as derived - if (!newFile.isDerived()) { - newFile.setDerived(true, null); - } - } 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; - } - return newFile; - } - - private void deleteBuildTarget(IResource deletedFile) { - // Get the project relative path of the file - String fileName = getFileName(deletedFile); - String srcExtension = deletedFile.getFileExtension(); - IPath folderPath = inFullPathFromOutFullPath(deletedFile.getFullPath().removeLastSegments(1)); - if (folderPath != null) { - folderPath = folderPath.removeFirstSegments(1); - } else { - folderPath = new Path(""); - } - IResourceInfo rcInfo = config.getResourceInfo(folderPath, false); - if (rcInfo instanceof IFileInfo) { - rcInfo = config.getResourceInfo(folderPath.removeLastSegments(1), false); - } - String targetExtension = ((IFolderInfo) rcInfo).getOutputExtension(srcExtension); - if (!targetExtension.isEmpty()) - fileName += DOT + targetExtension; - IPath projectRelativePath = deletedFile.getProjectRelativePath().removeLastSegments(1); - IPath targetFilePath = getBuildWorkingDir().append(projectRelativePath).append(fileName); - IResource depFile = project.findMember(targetFilePath); - if (depFile != null && depFile.exists()) { - try { - depFile.delete(true, new SubProgressMonitor(monitor, 1)); - } catch (CoreException e) { - // This had better be allowed during a build - } - } - } - - private IPath inFullPathFromOutFullPath(IPath path) { - IPath inPath = null; - if (topBuildDir.isPrefixOf(path)) { - inPath = path.removeFirstSegments(topBuildDir.segmentCount()); - inPath = project.getFullPath().append(path); - } - return inPath; - } - - private void deleteDepFile(IResource deletedFile) { - // Calculate the top build directory relative paths of the dependency - // files - IPath[] depFilePaths = null; - ITool tool = null; - IManagedDependencyGeneratorType depType = null; - String sourceExtension = deletedFile.getFileExtension(); - IPath folderPath = inFullPathFromOutFullPath(deletedFile.getFullPath().removeLastSegments(1)); - if (folderPath != null) { - folderPath = folderPath.removeFirstSegments(1); - } else { - folderPath = new Path(""); - ToolInfoHolder h = getToolInfo(folderPath); - ITool[] tools = h.buildTools; - for (int index = 0; index < tools.length; ++index) { - if (tools[index].buildsFileType(sourceExtension)) { - tool = tools[index]; - depType = tool.getDependencyGeneratorForExtension(sourceExtension); - break; - } - } - if (depType != null) { - int calcType = depType.getCalculatorType(); - if (calcType == IManagedDependencyGeneratorType.TYPE_COMMAND) { - depFilePaths = new IPath[1]; - IPath absolutePath = deletedFile.getLocation(); - depFilePaths[0] = ManagedBuildManager.calculateRelativePath(getTopBuildDir(), absolutePath); - depFilePaths[0] = depFilePaths[0].removeFileExtension().addFileExtension(DEP_EXT); - } else if (calcType == IManagedDependencyGeneratorType.TYPE_BUILD_COMMANDS - || calcType == IManagedDependencyGeneratorType.TYPE_PREBUILD_COMMANDS) { - IManagedDependencyGenerator2 depGen = (IManagedDependencyGenerator2) depType; - IManagedDependencyInfo depInfo = depGen.getDependencySourceInfo( - deletedFile.getProjectRelativePath(), deletedFile, config, tool, getBuildWorkingDir()); - if (depInfo != null) { - if (calcType == IManagedDependencyGeneratorType.TYPE_BUILD_COMMANDS) { - IManagedDependencyCommands depCommands = (IManagedDependencyCommands) depInfo; - depFilePaths = depCommands.getDependencyFiles(); - } else if (calcType == IManagedDependencyGeneratorType.TYPE_PREBUILD_COMMANDS) { - IManagedDependencyPreBuild depPreBuild = (IManagedDependencyPreBuild) depInfo; - depFilePaths = depPreBuild.getDependencyFiles(); - } - } - } - } - // Delete the files if they exist - if (depFilePaths != null) { - for (IPath dfp : depFilePaths) { - IPath depFilePath = getBuildWorkingDir().append(dfp); - IResource depFile = project.findMember(depFilePath); - if (depFile != null && depFile.exists()) { - try { - depFile.delete(true, new SubProgressMonitor(monitor, 1)); - } catch (CoreException e) { - // This had better be allowed during a build - } - } - } - } - } - } - - /** - * Returns the current build configuration. - * - * @return String - * @since 8.0 - */ - protected IConfiguration getConfig() { - return config; - } - - /** - * Returns the build target extension. - * - * @return String - * @since 8.0 - */ - protected String getBuildTargetExt() { - return buildTargetExt; - } - - /** - * Returns the build target name. - * - * @return String - * @since 8.0 - */ - protected String getBuildTargetName() { - return buildTargetName; - } - - /** - * @return Returns the deletedDirList. - */ - private Vector getDeletedDirList() { - if (deletedDirList == null) { - deletedDirList = new Vector(); - } - return deletedDirList; - } - - private Vector getDeletedFileList() { - if (deletedFileList == null) { - deletedFileList = new Vector(); - } - return deletedFileList; - } - - private List getDependencyMakefiles(ToolInfoHolder h) { - if (h.dependencyMakefiles == null) { - h.dependencyMakefiles = new ArrayList(); - } - return h.dependencyMakefiles; - } - - /** - * Strips off the file extension from the argument and returns the name - * component in a String - */ - private String getFileName(IResource file) { - String answer = ""; - String lastSegment = file.getName(); - int extensionSeparator = lastSegment.lastIndexOf(DOT); - if (extensionSeparator != -1) { - answer = lastSegment.substring(0, extensionSeparator); - } - return answer; - } - - /** - * Answers a Vector containing a list of directories that are invalid for the - * build for some reason. At the moment, the only reason a directory would not - * be considered for the build is if it contains a space in the relative path - * from the project root. - * - * @return a a list of directories that are invalid for the build - */ - private Vector getInvalidDirList() { - if (invalidDirList == null) { - invalidDirList = new Vector(); - } - return invalidDirList; - } - - /** - * @return Collection of Containers which contain modified source files - */ - private Collection getModifiedList() { - if (modifiedList == null) - modifiedList = new LinkedHashSet(); - return modifiedList; - } - - /** - * @return Collection of subdirectories (IContainers) contributing source code - * to the build - */ - private Collection getSubdirList() { - if (subdirList == null) - subdirList = new LinkedHashSet(); - return subdirList; - } - - private void removeGeneratedDirectory(IContainer subDir) { - try { - // The source directory isn't empty - if (subDir.exists() && subDir.members().length > 0) - return; - } catch (CoreException e) { - // The resource doesn't exist so we should delete the output folder - } - // Figure out what the generated directory name is and delete it - IPath moduleRelativePath = subDir.getProjectRelativePath(); - IPath buildRoot = getBuildWorkingDir(); - if (buildRoot == null) { - return; - } - IPath moduleOutputPath = buildRoot.append(moduleRelativePath); - IFolder folder = project.getFolder(moduleOutputPath); - if (folder.exists()) { - try { - folder.delete(true, new SubProgressMonitor(monitor, 1)); - } catch (CoreException e) { - // JABA added some logging - Common.log(new Status(IStatus.INFO, Const.CORE_PLUGIN_ID, "Folder deletion failed " + folder.toString(), // - e)); - } - } - } - - protected void updateMonitor(String msg) { - if (monitor != null && !monitor.isCanceled()) { - monitor.subTask(msg); - monitor.worked(1); - } - } - - /** - * Return the configuration's top build directory as an absolute path - */ - public IPath getTopBuildDir() { - return getPathForResource(project).append(getBuildWorkingDir()); - } - - /** - * Process a String denoting a filepath in a way compatible for GNU Make rules, - * handling windows drive letters and whitespace appropriately. - *

- *

- * The context these paths appear in is on the right hand side of a rule header. - * i.e. - *

- *

- * target : dep1 dep2 dep3 - *

- * - * @param path - * the String denoting the path to process - * @throws NullPointerException - * is path is null - * @return a suitable Make rule compatible path - */ - /* see https://bugs.eclipse.org/bugs/show_bug.cgi?id=129782 */ - public String ensurePathIsGNUMakeTargetRuleCompatibleSyntax(String path) { - return escapeWhitespaces(ensureUnquoted(path)); - } - - /** - * Strips outermost quotes of Strings of the form "a" and 'a' or returns the - * original string if the input is not of this form. - * - * @throws NullPointerException - * if path is null - * @return a String without the outermost quotes (if the input has them) - */ - public static String ensureUnquoted(String path) { - boolean doubleQuoted = path.startsWith("\"") && path.endsWith("\""); - boolean singleQuoted = path.startsWith("'") && path.endsWith("'"); - return doubleQuoted || singleQuoted ? path.substring(1, path.length() - 1) : path; - } - - @Override - public void initialize(int buildKind, IConfiguration cfg, IBuilder builder, IProgressMonitor monitor) { - // Save the project so we can get path and member information - this.project = cfg.getOwner().getProject(); - if (builder == null) { - builder = cfg.getEditableBuilder(); - } - try { - projectResources = project.members(); - } catch (CoreException e) { - projectResources = null; - } - // Save the monitor reference for reporting back to the user - this.monitor = monitor; - // Get the build info for the project - // info = info; - // Get the name of the build target - buildTargetName = cfg.getArtifactName(); - // Get its extension - buildTargetExt = cfg.getArtifactExtension(); - try { - // try to resolve the build macros in the target extension - buildTargetExt = ManagedBuildManager.getBuildMacroProvider().resolveValueToMakefileFormat(buildTargetExt, - "", " ", IBuildMacroProvider.CONTEXT_CONFIGURATION, builder); - } catch (BuildMacroException e) { - /* JABA is not going to write this code */ - } - try { - // try to resolve the build macros in the target name - String resolved = ManagedBuildManager.getBuildMacroProvider().resolveValueToMakefileFormat(buildTargetName, - "", " ", IBuildMacroProvider.CONTEXT_CONFIGURATION, builder); - if (resolved != null) { - resolved = resolved.trim(); - if (resolved.length() > 0) - buildTargetName = resolved; - } - } catch (BuildMacroException e) { - /* JABA is not going to write this code */ - } - if (buildTargetExt == null) { - buildTargetExt = ""; - } - // Cache the build tools - config = cfg; - this.builder = builder; - initToolInfos(); - // set the top build dir path - topBuildDir = project.getFolder(cfg.getName()).getFullPath(); - srcEntries = config.getSourceEntries(); - if (srcEntries.length == 0) { - srcEntries = new ICSourceEntry[] { - new CSourceEntry(Path.EMPTY, null, ICSettingEntry.RESOLVED | ICSettingEntry.VALUE_WORKSPACE_PATH) }; - } else { - ICConfigurationDescription cfgDes = ManagedBuildManager.getDescriptionForConfiguration(config); - srcEntries = CDataUtil.resolveEntries(srcEntries, cfgDes); - } - } - - private void initToolInfos() { - toolInfos = PathSettingsContainer.createRootContainer(); - IResourceInfo rcInfos[] = config.getResourceInfos(); - for (IResourceInfo rcInfo : rcInfos) { - if (rcInfo.isExcluded()) - continue; - ToolInfoHolder h = getToolInfo(rcInfo.getPath(), true); - if (rcInfo instanceof IFolderInfo) { - IFolderInfo fo = (IFolderInfo) rcInfo; - h.buildTools = fo.getFilteredTools(); - h.buildToolsUsed = new boolean[h.buildTools.length]; - h.gnuToolInfos = new ArduinoManagedBuildGnuToolInfo[h.buildTools.length]; - } else { - IFileInfo fi = (IFileInfo) rcInfo; - h.buildTools = fi.getToolsToInvoke(); - h.buildToolsUsed = new boolean[h.buildTools.length]; - h.gnuToolInfos = new ArduinoManagedBuildGnuToolInfo[h.buildTools.length]; - } - } - } - - private ToolInfoHolder getToolInfo(IPath path) { - return getToolInfo(path, false); - } - - private ToolInfoHolder getFolderToolInfo(IPath path) { - IResourceInfo rcInfo = config.getResourceInfo(path, false); - while (rcInfo instanceof IFileInfo) { - path = path.removeLastSegments(1); - rcInfo = config.getResourceInfo(path, false); - } - return getToolInfo(path, false); - } - - private ToolInfoHolder getToolInfo(IPath path, boolean create) { - PathSettingsContainer child = toolInfos.getChildContainer(path, create, create); - ToolInfoHolder h = null; - if (child != null) { - h = (ToolInfoHolder) child.getValue(); - if (h == null && create) { - h = new ToolInfoHolder(); - child.setValue(h); - } - } - return h; - } - - private String getToolCommandLinePattern(ITool tool) { - String orgPattern = tool.getCommandLinePattern(); - if (orgPattern.contains("$")) { - //if the pattern contains a space no use to try to expand it - return orgPattern; - } - ICProjectDescription prjDesc = CoreModel.getDefault().getProjectDescription(project); - ICConfigurationDescription confDesc = prjDesc.getConfigurationByName(config.getName()); - return Common.getBuildEnvironmentVariable(confDesc, orgPattern, orgPattern, false); - - } -} diff --git a/io.sloeber.core/src/io/sloeber/core/toolchain/ArduinoManagedBuildGnuToolInfo.java b/io.sloeber.core/src/io/sloeber/core/toolchain/ArduinoManagedBuildGnuToolInfo.java deleted file mode 100644 index 5e2cb8988..000000000 --- a/io.sloeber.core/src/io/sloeber/core/toolchain/ArduinoManagedBuildGnuToolInfo.java +++ /dev/null @@ -1,1104 +0,0 @@ -package io.sloeber.core.toolchain; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Set; -import java.util.Vector; - -import org.eclipse.cdt.managedbuilder.core.BuildException; -import org.eclipse.cdt.managedbuilder.core.IAdditionalInput; -import org.eclipse.cdt.managedbuilder.core.IConfiguration; -import org.eclipse.cdt.managedbuilder.core.IInputType; -import org.eclipse.cdt.managedbuilder.core.IManagedOutputNameProvider; -import org.eclipse.cdt.managedbuilder.core.IOption; -import org.eclipse.cdt.managedbuilder.core.IOutputType; -import org.eclipse.cdt.managedbuilder.core.ITool; -import org.eclipse.cdt.managedbuilder.core.ManagedBuildManager; -import org.eclipse.cdt.managedbuilder.internal.core.ManagedMakeMessages; -import org.eclipse.cdt.managedbuilder.internal.core.Tool; -import org.eclipse.cdt.managedbuilder.internal.macros.OptionContextData; -import org.eclipse.cdt.managedbuilder.macros.BuildMacroException; -import org.eclipse.cdt.managedbuilder.macros.IBuildMacroProvider; -import org.eclipse.cdt.managedbuilder.makegen.IManagedBuilderMakefileGenerator; -import org.eclipse.cdt.managedbuilder.makegen.IManagedDependencyCalculator; -import org.eclipse.cdt.managedbuilder.makegen.IManagedDependencyGenerator; -import org.eclipse.cdt.managedbuilder.makegen.IManagedDependencyGenerator2; -import org.eclipse.cdt.managedbuilder.makegen.IManagedDependencyGeneratorType; -import org.eclipse.cdt.managedbuilder.makegen.IManagedDependencyInfo; -import org.eclipse.cdt.managedbuilder.makegen.gnu.IManagedBuildGnuToolInfo; -import org.eclipse.core.resources.IProject; -import org.eclipse.core.resources.IResource; -import org.eclipse.core.runtime.IPath; -import org.eclipse.core.runtime.IStatus; -import org.eclipse.core.runtime.Path; -import org.eclipse.core.runtime.Status; - -import io.sloeber.core.common.Common; -import io.sloeber.core.common.Const; -import io.sloeber.core.toolchain.ArduinoGnuMakefileGenerator.ToolInfoHolder; - -/** - * This class represents information about a Tool's inputs and outputs while a - * Gnu makefile is being generated. - * - * @noextend This class is not intended to be subclassed by clients. - */ -@SuppressWarnings({ "restriction", "deprecation" ,"unused"}) -public class ArduinoManagedBuildGnuToolInfo implements IManagedBuildGnuToolInfo { - - /* - * Members - */ - private IProject project; - private Tool tool; - private boolean bIsTargetTool; - private String targetName; - private String targetExt; - private boolean inputsCalculated = false; - private boolean outputsCalculated = false; - private boolean outputVariablesCalculated = false; - private boolean dependenciesCalculated = false; - private Vector commandInputs = new Vector<>(); - private Vector enumeratedInputs = new Vector<>(); - private Vector commandOutputs = new Vector<>(); - private Vector enumeratedPrimaryOutputs = new Vector<>(); - private Vector enumeratedSecondaryOutputs = new Vector<>(); - private Vector outputVariables = new Vector<>(); - private Vector commandDependencies = new Vector<>(); - private Vector additionalTargets = new Vector<>(); - - // private Vector enumeratedDependencies = new Vector(); - // Map of macro names (String) to values (List) - - /* - * Constructor - */ - public ArduinoManagedBuildGnuToolInfo(IProject project, ITool tool, boolean targetTool, String name, String ext) { - this.project = project; - this.tool = (Tool) tool; - this.bIsTargetTool = targetTool; - if (this.bIsTargetTool) { - this.targetName = name; - this.targetExt = ext; - } - } - - /* - * IManagedBuildGnuToolInfo Methods - */ - @Override - public boolean areInputsCalculated() { - return this.inputsCalculated; - } - - // Command inputs are top build directory relative - @Override - public Vector getCommandInputs() { - return this.commandInputs; - } - - // Enumerated inputs are project relative - @Override - public Vector getEnumeratedInputs() { - return this.enumeratedInputs; - } - - @Override - public boolean areOutputsCalculated() { - return this.outputsCalculated; - } - - // Command outputs are top build directory relative - @Override - public Vector getCommandOutputs() { - return this.commandOutputs; - } - - @Override - public Vector getEnumeratedPrimaryOutputs() { - return this.enumeratedPrimaryOutputs; - } - - @Override - public Vector getEnumeratedSecondaryOutputs() { - return this.enumeratedSecondaryOutputs; - } - - @Override - public Vector getOutputVariables() { - return this.outputVariables; - } - - public boolean areOutputVariablesCalculated() { - return this.outputVariablesCalculated; - } - - @Override - public boolean areDependenciesCalculated() { - return this.dependenciesCalculated; - } - - // Command dependencies are top build directory relative - @Override - public Vector getCommandDependencies() { - return this.commandDependencies; - } - - // Additional targets are top build directory relative - @Override - public Vector getAdditionalTargets() { - return this.additionalTargets; - } - - // public Vector getEnumeratedDependencies() { - // return enumeratedDependencies; - // } - - @Override - public boolean isTargetTool() { - return this.bIsTargetTool; - } - - /* - * Other Methods - */ - - public boolean calculateInputs(ArduinoGnuMakefileGenerator makeGen, IConfiguration config, - IResource[] projResources, ToolInfoHolder h, boolean lastChance) { - // Get the inputs for this tool invocation - // Note that command inputs that are also dependencies are also added to - // the command dependencies list - - /* - * The priorities for determining the names of the inputs of a tool are: - * 1. If an option is specified, use the value of the option. 2. If a - * build variable is specified, use the files that have been added to - * the build variable as the output(s) of other build steps. 3. Use the - * file extensions and the resources in the project - */ - boolean done = true; - Vector myCommandInputs = new Vector<>(); // Inputs for the - // tool command - // line - Vector myCommandDependencies = new Vector<>(); // Dependencies - // for the - // make - // rule - Vector myEnumeratedInputs = new Vector<>(); // Complete - // list of - // individual - // inputs - - IInputType[] inTypes = this.tool.getInputTypes(); - if (inTypes != null && inTypes.length > 0) { - for (IInputType type : inTypes) { - Vector itCommandInputs = new Vector<>(); // Inputs - // for - // the - // tool - // command - // line - // for - // this - // input-type - Vector itCommandDependencies = new Vector<>(); // Dependencies - // for - // the - // make - // rule - // for - // this - // input-type - Vector itEnumeratedInputs = new Vector<>(); // Complete - // list - // of - // individual - // inputs - // for - // this - // input-type - String variable = type.getBuildVariable(); - boolean primaryInput = type.getPrimaryInput(); - boolean useFileExts = false; - IOption option = this.tool.getOptionBySuperClassId(type.getOptionId()); - IOption assignToOption = this.tool.getOptionBySuperClassId(type.getAssignToOptionId()); - - // Option? - if (option != null) { - try { - List inputs = new ArrayList<>(); - int optType = option.getValueType(); - if (optType == IOption.STRING) { - inputs.add(option.getStringValue()); - } else if (optType == IOption.STRING_LIST || optType == IOption.LIBRARIES - || optType == IOption.OBJECTS || optType == IOption.INCLUDE_FILES - || optType == IOption.LIBRARY_PATHS || optType == IOption.LIBRARY_FILES - || optType == IOption.MACRO_FILES) { - @SuppressWarnings("unchecked") - List valueList = (List) option.getValue(); - inputs = valueList; - this.tool.filterValues(optType, inputs); - this.tool.filterValues(optType, inputs); - } - for (int j = 0; j < inputs.size(); j++) { - String inputName = inputs.get(j); - - try { - // try to resolve the build macros in the output - // names - - String resolved = null; - - // does the input name contain spaces? - // TODO: support other special characters - if (inputName.indexOf(" ") != -1) //$NON-NLS-1$ - { - // resolve to string - resolved = ManagedBuildManager.getBuildMacroProvider().resolveValue(inputName, "", //$NON-NLS-1$ - " ", //$NON-NLS-1$ - IBuildMacroProvider.CONTEXT_OPTION, - new OptionContextData(option, this.tool)); - } else { - - // resolve to makefile variable format - resolved = ManagedBuildManager.getBuildMacroProvider().resolveValueToMakefileFormat( - inputName, "", //$NON-NLS-1$ - " ", //$NON-NLS-1$ - IBuildMacroProvider.CONTEXT_OPTION, - new OptionContextData(option, this.tool)); - } - - if ((resolved = resolved.trim()).length() > 0) - inputName = resolved; - } catch (BuildMacroException e) {// JABA is not - // going to add - // code - } - - if (primaryInput) { - itCommandDependencies.add(j, inputName); - } else { - itCommandDependencies.add(inputName); - } - // NO - itCommandInputs.add(inputName); - // NO - itEnumeratedInputs.add(inputName); - } - } catch (BuildException ex) {// JABA is not going to add - // code - } - - } else { - - // Build Variable? - if (variable.length() > 0) { - String cmdVariable = variable = "$(" + variable + ")"; //$NON-NLS-1$ //$NON-NLS-2$ - itCommandInputs.add(cmdVariable); - if (primaryInput) { - itCommandDependencies.add(0, cmdVariable); - } else { - itCommandDependencies.add(cmdVariable); - } - // If there is an output variable with the same name, - // get - // the files associated with it. - List outMacroList = makeGen.getBuildVariableList(h, variable, - ArduinoGnuMakefileGenerator.PROJECT_RELATIVE, null, true); - if (outMacroList != null) { - itEnumeratedInputs.addAll(outMacroList); - } else { - // If "last chance", then calculate using file - // extensions below - if (lastChance) { - useFileExts = true; - } else { - done = false; - break; - } - } - } - - // Use file extensions - if (variable.length() == 0 || useFileExts) { - // if (type.getMultipleOfType()) { - // Calculate EnumeratedInputs using the file extensions - // and the resources in the project - // Note: This is only correct for tools with - // multipleOfType == true, but for other tools - // it gives us an input resource for generating default - // names - // Determine the set of source input macros to use - HashSet handledInputExtensions = new HashSet<>(); - String[] exts = type.getSourceExtensions(this.tool); - if (projResources != null) { - for (IResource rc : projResources) { - if (rc.getType() == IResource.FILE) { - String fileExt = rc.getFileExtension(); - - // fix for NPE, bugzilla 99483 - if (fileExt == null) { - fileExt = ""; //$NON-NLS-1$ - } - - for (int k = 0; k < exts.length; k++) { - if (fileExt.equals(exts[k])) { - if (!useFileExts) { - if (!handledInputExtensions.contains(fileExt)) { - handledInputExtensions.add(fileExt); - String buildMacro = "$(" //$NON-NLS-1$ - + makeGen.getSourceMacroName(fileExt).toString() + ")"; //$NON-NLS-1$ - itCommandInputs.add(buildMacro); - if (primaryInput) { - itCommandDependencies.add(0, buildMacro); - } else { - itCommandDependencies.add(buildMacro); - } - } - } - if (type.getMultipleOfType() || itEnumeratedInputs.size() == 0) { - // Add a path that is relative - // to the project directory - itEnumeratedInputs.add(rc.getProjectRelativePath().toOSString()); - } - break; - } - } - } - } - } - // } - } - } - - // Get any additional inputs specified in the manifest file or - // the project file - IAdditionalInput[] addlInputs = type.getAdditionalInputs(); - if (addlInputs != null) { - for (int j = 0; j < addlInputs.length; j++) { - IAdditionalInput addlInput = addlInputs[j]; - int kind = addlInput.getKind(); - if (kind == IAdditionalInput.KIND_ADDITIONAL_INPUT - || kind == IAdditionalInput.KIND_ADDITIONAL_INPUT_DEPENDENCY) { - String[] paths = addlInput.getPaths(); - if (paths != null) { - for (int k = 0; k < paths.length; k++) { - String path = paths[k]; - itEnumeratedInputs.add(path); - // Translate the path from project relative - // to build directory relative - if (!(path.startsWith("$("))) { //$NON-NLS-1$ - IResource addlResource = this.project.getFile(path); - if (addlResource != null) { - IPath addlPath = addlResource.getLocation(); - if (addlPath != null) { - path = ManagedBuildManager - .calculateRelativePath(makeGen.getTopBuildDir(), addlPath) - .toOSString(); - } - } - } - itCommandInputs.add(path); - } - } - } - } - } - - // If the assignToOption attribute is specified, set the - // input(s) as the value of that option - if (assignToOption != null && option == null) { - try { - int optType = assignToOption.getValueType(); - if (optType == IOption.STRING) { - String optVal = ""; //$NON-NLS-1$ - for (int j = 0; j < itCommandInputs.size(); j++) { - if (j != 0) { - optVal += " "; //$NON-NLS-1$ - } - optVal += itCommandInputs.get(j); - } - ManagedBuildManager.setOption(config, this.tool, assignToOption, optVal); - } else if (optType == IOption.STRING_LIST || optType == IOption.LIBRARIES - || optType == IOption.OBJECTS || optType == IOption.INCLUDE_FILES - || optType == IOption.LIBRARY_PATHS || optType == IOption.LIBRARY_FILES - || optType == IOption.MACRO_FILES) { - // TODO: do we need to do anything with undefs here? - // Mote that when using the enumerated inputs, the - // path(s) must be translated from project relative - // to top build directory relative - String[] paths = new String[itEnumeratedInputs.size()]; - for (int j = 0; j < itEnumeratedInputs.size(); j++) { - paths[j] = itEnumeratedInputs.get(j); - IResource enumResource = this.project.getFile(paths[j]); - if (enumResource != null) { - IPath enumPath = enumResource.getLocation(); - if (enumPath != null) { - paths[j] = ManagedBuildManager - .calculateRelativePath(makeGen.getTopBuildDir(), enumPath).toOSString(); - } - } - } - ManagedBuildManager.setOption(config, this.tool, assignToOption, paths); - } else if (optType == IOption.BOOLEAN) { - if (itEnumeratedInputs.size() > 0) { - ManagedBuildManager.setOption(config, this.tool, assignToOption, true); - } else { - ManagedBuildManager.setOption(config, this.tool, assignToOption, false); - } - } else if (optType == IOption.ENUMERATED || optType == IOption.TREE) { - if (itCommandInputs.size() > 0) { - ManagedBuildManager.setOption(config, this.tool, assignToOption, - itCommandInputs.firstElement()); - } - } - itCommandInputs.removeAllElements(); - // itEnumeratedInputs.removeAllElements(); - } catch (BuildException ex) {// JABA is not going to add - // code - } - } - - myCommandInputs.addAll(itCommandInputs); - myCommandDependencies.addAll(itCommandDependencies); - myEnumeratedInputs.addAll(itEnumeratedInputs); - } - } else { - // For support of pre-CDT 3.0 integrations. - if (this.bIsTargetTool) { - // NOTE WELL: This only supports the case of a single - // "target tool" - // with the following characteristics: - // 1. The tool consumes exactly all of the object files produced - // by other tools in the build and produces a single output - // 2. The target name comes from the configuration artifact name - // The rule looks like: - // .: $(OBJS) - myCommandInputs.add("$(OBJS)"); //$NON-NLS-1$ - myCommandInputs.add("$(USER_OBJS)"); //$NON-NLS-1$ - myCommandInputs.add("$(LIBS)"); //$NON-NLS-1$ - } else { - // Rule will be generated by addRuleForSource - } - } - - if (done) { - this.commandInputs.addAll(myCommandInputs); - this.commandDependencies.addAll(0, myCommandDependencies); - this.enumeratedInputs.addAll(myEnumeratedInputs); - this.inputsCalculated = true; - return true; - } - - return false; - } - - /* - * The priorities for determining the names of the outputs of a tool are: 1. - * If the tool is the build target and primary output, use artifact name & - * extension 2. If an option is specified, use the value of the option 3. If - * a nameProvider is specified, call it 4. If outputNames is specified, use - * it 5. Use the name pattern to generate a transformation macro so that the - * source names can be transformed into the target names using the built-in - * string substitution functions of make. - * - * NOTE: If an option is not specified and this is not the primary output - * type, the outputs from the type are not added to the command line - */ - public boolean calculateOutputs(ArduinoGnuMakefileGenerator makeGen, IConfiguration config, - HashSet handledInputExtensions, boolean lastChance) { - - boolean done = true; - Vector myCommandOutputs = new Vector<>(); - Vector myEnumeratedPrimaryOutputs = new Vector<>(); - Vector myEnumeratedSecondaryOutputs = new Vector<>(); - HashMap> myOutputMacros = new HashMap<>(); - // The next two fields are used together - Vector myBuildVars = new Vector<>(); - Vector> myBuildVarsValues = new Vector<>(); - - // Get the outputs for this tool invocation - IOutputType[] outTypes = this.tool.getOutputTypes(); - if (outTypes != null && outTypes.length > 0) { - for (int i = 0; i < outTypes.length; i++) { - Vector typeEnumeratedOutputs = new Vector<>(); - IOutputType type = outTypes[i]; - String outputPrefix = type.getOutputPrefix(); - - // Resolve any macros in the outputPrefix - // Note that we cannot use file macros because if we do a clean - // we need to know the actual name of the file to clean, and - // cannot use any builder variables such as $@. Hence we use the - // next best thing, i.e. configuration context. - - if (config != null) { - - try { - outputPrefix = ManagedBuildManager.getBuildMacroProvider().resolveValueToMakefileFormat( - outputPrefix, "", //$NON-NLS-1$ - " ", //$NON-NLS-1$ - IBuildMacroProvider.CONTEXT_CONFIGURATION, config); - } - - catch (BuildMacroException e) {// JABA is not going to add - // code - } - } - - String variable = type.getBuildVariable(); - boolean multOfType = type.getMultipleOfType(); - boolean primaryOutput = (type == this.tool.getPrimaryOutputType()); - IOption option = this.tool.getOptionBySuperClassId(type.getOptionId()); - IManagedOutputNameProvider nameProvider = type.getNameProvider(); - String[] outputNames = type.getOutputNames(); - - // 1. If the tool is the build target and this is the primary - // output, - // use artifact name & extension - if (this.bIsTargetTool && primaryOutput) { - String outputName = outputPrefix + this.targetName; - if (this.targetExt.length() > 0) { - outputName += (DOT + this.targetExt); - } - myCommandOutputs.add(outputName); - typeEnumeratedOutputs.add(outputName); - // But this doesn't use any output macro... - } else - // 2. If an option is specified, use the value of the option - if (option != null) { - try { - List outputs = new ArrayList<>(); - int optType = option.getValueType(); - if (optType == IOption.STRING) { - outputs.add(outputPrefix + option.getStringValue()); - } else if (optType == IOption.STRING_LIST || optType == IOption.LIBRARIES - || optType == IOption.OBJECTS || optType == IOption.INCLUDE_FILES - || optType == IOption.LIBRARY_PATHS || optType == IOption.LIBRARY_FILES - || optType == IOption.MACRO_FILES) { - @SuppressWarnings("unchecked") - List value = (List) option.getValue(); - outputs = value; - this.tool.filterValues(optType, outputs); - // Add outputPrefix to each if necessary - if (outputPrefix.length() > 0) { - for (int j = 0; j < outputs.size(); j++) { - outputs.set(j, outputPrefix + outputs.get(j)); - } - } - } - for (int j = 0; j < outputs.size(); j++) { - String outputName = outputs.get(j); - try { - // try to resolve the build macros in the output - // names - String resolved = ManagedBuildManager.getBuildMacroProvider() - .resolveValueToMakefileFormat(outputName, "", //$NON-NLS-1$ - " ", //$NON-NLS-1$ - IBuildMacroProvider.CONTEXT_OPTION, - new OptionContextData(option, this.tool)); - if ((resolved = resolved.trim()).length() > 0) - outputs.set(j, resolved); - } catch (BuildMacroException e) {// JABA is not - // going to add - // code - } - } - - // NO - myCommandOutputs.addAll(outputs); - typeEnumeratedOutputs.addAll(outputs); - if (variable.length() > 0) { - List outputPaths = new ArrayList<>(); - for (int j = 0; j < outputs.size(); j++) { - outputPaths.add(Path.fromOSString(outputs.get(j))); - } - if (myOutputMacros.containsKey(variable)) { - List currList = myOutputMacros.get(variable); - currList.addAll(outputPaths); - myOutputMacros.put(variable, currList); - } else { - myOutputMacros.put(variable, outputPaths); - } - } - } catch (BuildException ex) {// JABA is not going to add - // code - } - } else - // 3. If a nameProvider is specified, call it - if (nameProvider != null) { - // The inputs must have been calculated before we can do - // this - IPath[] outNames = null; - if (!this.inputsCalculated) { - done = false; - } else { - Vector inputs = getEnumeratedInputs(); - IPath[] inputPaths = new IPath[inputs.size()]; - for (int j = 0; j < inputPaths.length; j++) { - inputPaths[j] = Path.fromOSString(inputs.get(j)); - } - // JABA: I inserted this code to cater for bin or hex - // extensions based on the board. Basically you need the - // Project - // to get to information to know whether this is a sam - // or avr project (having it in the platform file would - // be easier) - // To make it as much compliant as possible with the - // "CDT way" I added a getOutputNames which takes al the - // info needed to - // know the correct output name - // if (inputPaths.length == 0) { - try { - IManagedOutputNameProviderJaba newNameProvider = (IManagedOutputNameProviderJaba) nameProvider; - outNames = newNameProvider.getOutputNames(this.project, config, this.tool, inputPaths); - } catch (Exception e) { - // The provided class is not a - // IManagedOutputNameProviderJaba class; - Common.log(new Status(IStatus.ERROR, Const.CORE_PLUGIN_ID, - "The provided class is not of type IManagedOutputNameProviderJaba", e)); //$NON-NLS-1$ - } - // } else { - // outNames = nameProvider.getOutputNames(tool, - // inputPaths); - // } - // JABA end of insertion - if (outNames != null) { - for (int j = 0; j < outNames.length; j++) { - String outputName = outNames[j].toOSString(); - try { - // try to resolve the build macros in the - // output names - String resolved = ManagedBuildManager.getBuildMacroProvider() - .resolveValueToMakefileFormat(outputName, "", //$NON-NLS-1$ - " ", //$NON-NLS-1$ - IBuildMacroProvider.CONTEXT_CONFIGURATION, config); - if ((resolved = resolved.trim()).length() > 0) { - outputName = resolved; - outNames[j] = Path.fromOSString(resolved); - } - } catch (BuildMacroException e) {// JABA is not - // going to add - // code - } - - if (primaryOutput) { - myCommandOutputs.add(outputName); - } - typeEnumeratedOutputs.add(outputName); - } - } - } - if (variable.length() > 0 && outNames != null) { - if (myOutputMacros.containsKey(variable)) { - List currList = myOutputMacros.get(variable); - currList.addAll(Arrays.asList(outNames)); - myOutputMacros.put(variable, currList); - } else { - myOutputMacros.put(variable, new ArrayList<>(Arrays.asList(outNames))); - } - } - } else - // 4. If outputNames is specified, use it - if (outputNames != null) { - if (outputNames.length > 0) { - for (int j = 0; j < outputNames.length; j++) { - String outputName = outputNames[j]; - try { - // try to resolve the build macros in the output - // names - String resolved = ManagedBuildManager.getBuildMacroProvider() - .resolveValueToMakefileFormat(outputName, "", //$NON-NLS-1$ - " ", //$NON-NLS-1$ - IBuildMacroProvider.CONTEXT_OPTION, - new OptionContextData(option, this.tool)); - if ((resolved = resolved.trim()).length() > 0) - outputNames[j] = resolved; - } catch (BuildMacroException e) {// JABA is not - // going to add - // code - } - } - List namesList = Arrays.asList(outputNames); - if (primaryOutput) { - myCommandOutputs.addAll(namesList); - } - typeEnumeratedOutputs.addAll(namesList); - if (variable.length() > 0) { - List outputPaths = new ArrayList<>(); - for (int j = 0; j < namesList.size(); j++) { - outputPaths.add(Path.fromOSString(namesList.get(j))); - } - if (myOutputMacros.containsKey(variable)) { - List currList = myOutputMacros.get(variable); - currList.addAll(outputPaths); - myOutputMacros.put(variable, currList); - } else { - myOutputMacros.put(variable, outputPaths); - } - } - } - } else { - // 5. Use the name pattern to generate a transformation - // macro - // so that the source names can be transformed into the - // target names - // using the built-in string substitution functions of - // make. - if (multOfType) { - // This case is not handled - a nameProvider or - // outputNames must be specified - List errList = new ArrayList<>(); - errList.add(ManagedMakeMessages.getResourceString("MakefileGenerator.error.no.nameprovider")); //$NON-NLS-1$ - myCommandOutputs.addAll(errList); - } else { - String namePattern = type.getNamePattern(); - if (namePattern == null || namePattern.length() == 0) { - namePattern = outputPrefix + IManagedBuilderMakefileGenerator.WILDCARD; - String outExt = (type.getOutputExtensions(this.tool))[0]; - if (outExt != null && outExt.length() > 0) { - namePattern += DOT + outExt; - } - } else if (outputPrefix.length() > 0) { - namePattern = outputPrefix + namePattern; - } - - // Calculate the output name - // The inputs must have been calculated before we can do - // this - if (!this.inputsCalculated) { - done = false; - } else { - Vector inputs = getEnumeratedInputs(); - String fileName; - if (inputs.size() > 0) { - // Get the input file name - fileName = (Path.fromOSString(inputs.get(0))).removeFileExtension().lastSegment(); - // Check if this is a build macro. If so, use - // the raw macro name. - if (fileName.startsWith("$(") && fileName.endsWith(")")) { //$NON-NLS-1$ //$NON-NLS-2$ - fileName = fileName.substring(2, fileName.length() - 1); - } - } else { - fileName = "default"; //$NON-NLS-1$ - } - // Replace the % with the file name - if (primaryOutput) { - myCommandOutputs.add(namePattern.replace("%", fileName)); //$NON-NLS-1$ - } - typeEnumeratedOutputs.add(namePattern.replace("%", fileName)); //$NON-NLS-1$ - if (variable.length() > 0) { - List outputs = new ArrayList<>(); - outputs.add(Path.fromOSString(fileName)); - if (myOutputMacros.containsKey(variable)) { - List currList = myOutputMacros.get(variable); - currList.addAll(outputs); - myOutputMacros.put(variable, currList); - } else { - myOutputMacros.put(variable, outputs); - } - } - } - } - } - if (variable.length() > 0) { - myBuildVars.add(variable); - myBuildVarsValues.add(typeEnumeratedOutputs); - } - if (primaryOutput) { - myEnumeratedPrimaryOutputs.addAll(typeEnumeratedOutputs); - } else { - myEnumeratedSecondaryOutputs.addAll(typeEnumeratedOutputs); - } - } - } else { - if (this.bIsTargetTool) { - String outputPrefix = this.tool.getOutputPrefix(); - String outputName = outputPrefix + this.targetName; - if (this.targetExt.length() > 0) { - outputName += (DOT + this.targetExt); - } - myCommandOutputs.add(outputName); - myEnumeratedPrimaryOutputs.add(outputName); - } else { - // For support of pre-CDT 3.0 integrations. - // NOTE WELL: This only supports the case of a single - // "target tool" - // that consumes exactly all of the object files, $OBJS, - // produced - // by other tools in the build and produces a single output - } - } - - // Add the output macros of this tool to the buildOutVars map - Set>> entrySet = myOutputMacros.entrySet(); - for (Entry> entry : entrySet) { - String macroName = entry.getKey(); - List newMacroValue = entry.getValue(); - Map> map = makeGen.getBuildOutputVars(); - if (map.containsKey(macroName)) { - List macroValue = map.get(macroName); - macroValue.addAll(newMacroValue); - map.put(macroName, macroValue); - } else { - map.put(macroName, newMacroValue); - } - } - this.outputVariablesCalculated = true; - - if (done) { - this.commandOutputs.addAll(myCommandOutputs); - this.enumeratedPrimaryOutputs.addAll(myEnumeratedPrimaryOutputs); - this.enumeratedSecondaryOutputs.addAll(myEnumeratedSecondaryOutputs); - this.outputVariables.addAll(myOutputMacros.keySet()); - this.outputsCalculated = true; - for (int i = 0; i < myBuildVars.size(); i++) { - makeGen.addMacroAdditionFiles(makeGen.getTopBuildOutputVars(), myBuildVars.get(i), - myBuildVarsValues.get(i)); - } - return true; - } - - return false; - } - - private boolean callDependencyCalculator(ArduinoGnuMakefileGenerator makeGen, IConfiguration config, - HashSet handledInputExtensions, IManagedDependencyGeneratorType depGen, String[] extensionsList, - Vector myCommandDependencies, HashMap> myOutputMacros, - Vector myAdditionalTargets, ToolInfoHolder h, boolean _done) { - boolean done = _done; - int calcType = depGen.getCalculatorType(); - switch (calcType) { - case IManagedDependencyGeneratorType.TYPE_COMMAND: - case IManagedDependencyGeneratorType.TYPE_BUILD_COMMANDS: - // iterate over all extensions that the tool knows how to handle - for (int i = 0; i < extensionsList.length; i++) { - String extensionName = extensionsList[i]; - - // Generated files should not appear in the list. - if (!makeGen.getOutputExtensions(h).contains(extensionName) - && !handledInputExtensions.contains(extensionName)) { - handledInputExtensions.add(extensionName); - String depExt = IManagedBuilderMakefileGenerator.DEP_EXT; - if (calcType == IManagedDependencyGeneratorType.TYPE_BUILD_COMMANDS) { - IManagedDependencyGenerator2 depGen2 = (IManagedDependencyGenerator2) depGen; - String xt = depGen2.getDependencyFileExtension(config, this.tool); - if (xt != null && xt.length() > 0) - depExt = xt; - } - String depsMacroEntry = calculateSourceMacro(makeGen, extensionName, depExt, - IManagedBuilderMakefileGenerator.WILDCARD); - - List depsList = new ArrayList<>(); - depsList.add(Path.fromOSString(depsMacroEntry)); - String depsMacro = makeGen.getDepMacroName(extensionName).toString(); - if (myOutputMacros.containsKey(depsMacro)) { - List currList = myOutputMacros.get(depsMacro); - currList.addAll(depsList); - myOutputMacros.put(depsMacro, currList); - } else { - myOutputMacros.put(depsMacro, depsList); - } - } - } - break; - - case IManagedDependencyGeneratorType.TYPE_INDEXER: - case IManagedDependencyGeneratorType.TYPE_EXTERNAL: - case IManagedDependencyGeneratorType.TYPE_CUSTOM: - // The inputs must have been calculated before we can do this - if (!this.inputsCalculated) { - done = false; - } else { - Vector inputs = getEnumeratedInputs(); - - if (calcType == IManagedDependencyGeneratorType.TYPE_CUSTOM) { - IManagedDependencyGenerator2 depGen2 = (IManagedDependencyGenerator2) depGen; - IManagedDependencyInfo depInfo = null; - for (int i = 0; i < inputs.size(); i++) { - - depInfo = depGen2.getDependencySourceInfo(Path.fromOSString(inputs.get(i)), config, this.tool, - makeGen.getBuildWorkingDir()); - - if (depInfo instanceof IManagedDependencyCalculator) { - IManagedDependencyCalculator depCalc = (IManagedDependencyCalculator) depInfo; - IPath[] depPaths = depCalc.getDependencies(); - if (depPaths != null) { - for (int j = 0; j < depPaths.length; j++) { - if (!depPaths[j].isAbsolute()) { - // Convert from project relative to - // build directory relative - IPath absolutePath = this.project.getLocation().append(depPaths[j]); - depPaths[j] = ManagedBuildManager - .calculateRelativePath(makeGen.getTopBuildDir(), absolutePath); - } - myCommandDependencies.add(depPaths[j].toOSString()); - } - } - IPath[] targetPaths = depCalc.getAdditionalTargets(); - if (targetPaths != null) { - for (int j = 0; j < targetPaths.length; j++) { - myAdditionalTargets.add(targetPaths[j].toOSString()); - } - } - } - } - } else { - IManagedDependencyGenerator oldDepGen = (IManagedDependencyGenerator) depGen; - for (String input : inputs) { - IResource[] outNames = oldDepGen.findDependencies(this.project.getFile(input), this.project); - if (outNames != null) { - for (IResource outName : outNames) { - myCommandDependencies.add(outName.toString()); - } - } - } - } - } - break; - - default: - break; - } - - return done; - } - - /** - * @param lastChance - */ - public boolean calculateDependencies(ArduinoGnuMakefileGenerator makeGen, IConfiguration config, - HashSet handledInputExtensions, ToolInfoHolder h, boolean lastChance) { - // Get the dependencies for this tool invocation - boolean done = true; - Vector myCommandDependencies = new Vector<>(); - Vector myAdditionalTargets = new Vector<>(); - // Vector myEnumeratedDependencies = new Vector(); - HashMap> myOutputMacros = new HashMap<>(); - - IInputType[] inTypes = this.tool.getInputTypes(); - if (inTypes != null && inTypes.length > 0) { - for (int i = 0; i < inTypes.length; i++) { - IInputType type = inTypes[i]; - - // Handle dependencies from the dependencyCalculator - IManagedDependencyGeneratorType depGen = type.getDependencyGenerator(); - String[] extensionsList = type.getSourceExtensions(this.tool); - if (depGen != null) { - done = callDependencyCalculator(makeGen, config, handledInputExtensions, depGen, extensionsList, - myCommandDependencies, myOutputMacros, myAdditionalTargets, h, done); - } - - // Add additional dependencies specified in AdditionalInput - // elements - IAdditionalInput[] addlInputs = type.getAdditionalInputs(); - if (addlInputs != null && addlInputs.length > 0) { - for (int j = 0; j < addlInputs.length; j++) { - IAdditionalInput addlInput = addlInputs[j]; - int kind = addlInput.getKind(); - if (kind == IAdditionalInput.KIND_ADDITIONAL_DEPENDENCY - || kind == IAdditionalInput.KIND_ADDITIONAL_INPUT_DEPENDENCY) { - String[] paths = addlInput.getPaths(); - if (paths != null) { - for (int k = 0; k < paths.length; k++) { - // Translate the path from project relative - // to - // build directory relative - String path = paths[k]; - if (!(path.startsWith("$("))) { //$NON-NLS-1$ - IResource addlResource = this.project.getFile(path); - if (addlResource != null) { - IPath addlPath = addlResource.getLocation(); - if (addlPath != null) { - path = ManagedBuildManager - .calculateRelativePath(makeGen.getTopBuildDir(), addlPath) - .toOSString(); - } - } - } - myCommandDependencies.add(path); - // myEnumeratedInputs.add(path); - } - } - } - } - } - } - } else { - if (this.bIsTargetTool) { - // For support of pre-CDT 3.0 integrations. - // NOTE WELL: This only supports the case of a single - // "target tool" - // with the following characteristics: - // 1. The tool consumes exactly all of the object files produced - // by other tools in the build and produces a single output - // 2. The target name comes from the configuration artifact name - // The rule looks like: - // .: $(OBJS) - myCommandDependencies.add("$(OBJS)"); //$NON-NLS-1$ - myCommandDependencies.add("$(USER_OBJS)"); //$NON-NLS-1$ - } else { - // Handle dependencies from the dependencyCalculator - IManagedDependencyGeneratorType depGen = this.tool.getDependencyGenerator(); - String[] extensionsList = this.tool.getAllInputExtensions(); - if (depGen != null) { - done = callDependencyCalculator(makeGen, config, handledInputExtensions, depGen, extensionsList, - myCommandDependencies, myOutputMacros, myAdditionalTargets, h, done); - } - - } - } - - // Add the output macros of this tool to the buildOutVars map - Set>> entrySet = myOutputMacros.entrySet(); - for (Entry> entry : entrySet) { - String macroName = entry.getKey(); - List newMacroValue = entry.getValue(); - Map> map = makeGen.getBuildOutputVars(); - if (map.containsKey(macroName)) { - List macroValue = map.get(macroName); - macroValue.addAll(newMacroValue); - map.put(macroName, macroValue); - } else { - map.put(macroName, newMacroValue); - } - } - - if (done) { - this.commandDependencies.addAll(myCommandDependencies); - this.additionalTargets.addAll(myAdditionalTargets); - // enumeratedDependencies.addAll(myEnumeratedDependencies); - this.dependenciesCalculated = true; - return true; - } - - return false; - } - - /* - * Calculate the source macro for the given extension - */ - protected String calculateSourceMacro(ArduinoGnuMakefileGenerator makeGen, String srcExtensionName, - String outExtensionName, String wildcard) { - StringBuffer macroName = makeGen.getSourceMacroName(srcExtensionName); - String OptDotExt = ""; //$NON-NLS-1$ - if (outExtensionName != null) { - OptDotExt = DOT + outExtensionName; - } else if (this.tool.getOutputExtension(srcExtensionName) != "") //$NON-NLS-1$ - OptDotExt = DOT + this.tool.getOutputExtension(srcExtensionName); - - // create rule of the form - // OBJS = $(macroName1: ../%.input1=%.output1) ... $(macroNameN: - // ../%.inputN=%.outputN) - StringBuffer objectsBuffer = new StringBuffer(); - objectsBuffer.append(IManagedBuilderMakefileGenerator.WHITESPACE + "$(" + macroName + //$NON-NLS-1$ - IManagedBuilderMakefileGenerator.COLON + IManagedBuilderMakefileGenerator.ROOT - + IManagedBuilderMakefileGenerator.SEPARATOR + IManagedBuilderMakefileGenerator.WILDCARD + DOT - + srcExtensionName + "=" + wildcard + OptDotExt + ")"); //$NON-NLS-1$ //$NON-NLS-2$ - return objectsBuffer.toString(); - } - -} diff --git a/io.sloeber.core/src/io/sloeber/core/toolchain/IManagedOutputNameProviderJaba.java b/io.sloeber.core/src/io/sloeber/core/toolchain/IManagedOutputNameProviderJaba.java deleted file mode 100644 index 417fcca98..000000000 --- a/io.sloeber.core/src/io/sloeber/core/toolchain/IManagedOutputNameProviderJaba.java +++ /dev/null @@ -1,11 +0,0 @@ -package io.sloeber.core.toolchain; - -import org.eclipse.cdt.managedbuilder.core.IConfiguration; -import org.eclipse.cdt.managedbuilder.core.IManagedOutputNameProvider; -import org.eclipse.cdt.managedbuilder.core.ITool; -import org.eclipse.core.resources.IProject; -import org.eclipse.core.runtime.IPath; - -public interface IManagedOutputNameProviderJaba extends IManagedOutputNameProvider { - public IPath[] getOutputNames(IProject project, IConfiguration cConf, ITool tool, IPath[] primaryInputNames); -} diff --git a/io.sloeber.core/src/io/sloeber/core/toolchain/LinkNameProvider.java b/io.sloeber.core/src/io/sloeber/core/toolchain/LinkNameProvider.java deleted file mode 100644 index 00d05656b..000000000 --- a/io.sloeber.core/src/io/sloeber/core/toolchain/LinkNameProvider.java +++ /dev/null @@ -1,46 +0,0 @@ -package io.sloeber.core.toolchain; - -import org.eclipse.cdt.managedbuilder.core.IConfiguration; -import org.eclipse.cdt.managedbuilder.core.ITool; -import org.eclipse.core.resources.IProject; -import org.eclipse.core.runtime.IPath; -import org.eclipse.core.runtime.IStatus; -import org.eclipse.core.runtime.Status; - -import io.sloeber.core.common.Common; -import io.sloeber.core.common.Const; -import io.sloeber.core.tools.Helpers; - -public class LinkNameProvider implements IManagedOutputNameProviderJaba { - @Override - public IPath[] getOutputNames(ITool tool, IPath[] primaryInputNames) { - - Common.log( - new Status(IStatus.ERROR, Const.CORE_PLUGIN_ID, "LinkNameProvider: The call should go to the overloaded function not here.")); //$NON-NLS-1$ - return null; - } - - @Override - public IPath[] getOutputNames(IProject project, IConfiguration cConf, ITool tool, IPath[] primaryInputNames) { - boolean bUseArchiver = Common.getBuildEnvironmentVariable(project, cConf.getName(), Const.ENV_KEY_USE_ARCHIVER, Const.TRUE) - .equalsIgnoreCase(Const.TRUE); - IPath[] outputNames = new IPath[primaryInputNames.length]; - for (int curPath = 0; curPath < outputNames.length; curPath++) { - if (primaryInputNames[curPath].toString().startsWith(Const.ARDUINO_CODE_FOLDER_PATH) && (bUseArchiver)) { - return null; - } - if (primaryInputNames[curPath].toString().endsWith(".ino")) { //$NON-NLS-1$ - return null; - } - if (primaryInputNames[curPath].toString().endsWith(".pde")) { //$NON-NLS-1$ - return null; - } - if (primaryInputNames[curPath].toString().endsWith(".cxx")) { //$NON-NLS-1$ - return null; - } - outputNames[curPath] = Helpers.GetOutputName(primaryInputNames[curPath]).addFileExtension("o"); //$NON-NLS-1$ - } - return outputNames; - } - -} diff --git a/io.sloeber.core/src/io/sloeber/managedBuild/Internal/ArchiveNameProvider.java b/io.sloeber.core/src/io/sloeber/managedBuild/Internal/ArchiveNameProvider.java new file mode 100644 index 000000000..dd908bf2c --- /dev/null +++ b/io.sloeber.core/src/io/sloeber/managedBuild/Internal/ArchiveNameProvider.java @@ -0,0 +1,33 @@ +package io.sloeber.managedBuild.Internal; + +import org.eclipse.cdt.managedbuilder.core.IConfiguration; +import org.eclipse.cdt.managedbuilder.core.ITool; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.runtime.IPath; + +import io.sloeber.core.common.Common; +import io.sloeber.core.common.Const; +import io.sloeber.core.tools.Helpers; +import io.sloeber.managedBuild.api.IManagedOutputNameProviderJaba; + +public class ArchiveNameProvider implements IManagedOutputNameProviderJaba { + + @Override + public IPath getOutputName(IProject project, IConfiguration cConf, ITool tool, IPath primaryInput) { + + boolean bUseArchiver = Common + .getBuildEnvironmentVariable(project, cConf.getName(), Const.ENV_KEY_USE_ARCHIVER, Const.TRUE) + .equalsIgnoreCase(Const.TRUE); + if (!bUseArchiver) { + // we don't use archiving so we ignore all files + return null; + } + + if (primaryInput.toString().startsWith(Const.ARDUINO_CODE_FOLDER_PATH) + && (!"cxx".equals(primaryInput.getFileExtension()))) { //$NON-NLS-1$ + return Helpers.GetOutputName(primaryInput).addFileExtension("o"); //$NON-NLS-1$ + } + return null; + } + +} diff --git a/io.sloeber.core/src/io/sloeber/core/toolchain/ArduinoGnuDependencyGroupInfo.java b/io.sloeber.core/src/io/sloeber/managedBuild/Internal/ArduinoGnuDependencyGroupInfo.java similarity index 92% rename from io.sloeber.core/src/io/sloeber/core/toolchain/ArduinoGnuDependencyGroupInfo.java rename to io.sloeber.core/src/io/sloeber/managedBuild/Internal/ArduinoGnuDependencyGroupInfo.java index f1d527227..22eb1389d 100644 --- a/io.sloeber.core/src/io/sloeber/core/toolchain/ArduinoGnuDependencyGroupInfo.java +++ b/io.sloeber.core/src/io/sloeber/managedBuild/Internal/ArduinoGnuDependencyGroupInfo.java @@ -1,4 +1,4 @@ -package io.sloeber.core.toolchain; +package io.sloeber.managedBuild.Internal; /** * diff --git a/io.sloeber.core/src/io/sloeber/managedBuild/Internal/ArduinoGnuMakefileGenerator.java b/io.sloeber.core/src/io/sloeber/managedBuild/Internal/ArduinoGnuMakefileGenerator.java new file mode 100644 index 000000000..c408a55c0 --- /dev/null +++ b/io.sloeber.core/src/io/sloeber/managedBuild/Internal/ArduinoGnuMakefileGenerator.java @@ -0,0 +1,1597 @@ +package io.sloeber.managedBuild.Internal; + +import static io.sloeber.core.common.Const.*; +import static io.sloeber.managedBuild.Internal.ManagebBuildCommon.*; +import static io.sloeber.managedBuild.Internal.ManagedBuildConstants.*; + +import java.io.File; +import java.io.IOException; +import java.nio.charset.Charset; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map.Entry; +import java.util.Set; +import java.util.Vector; + +import org.apache.commons.io.FileUtils; +import org.eclipse.cdt.core.CCorePlugin; +import org.eclipse.cdt.core.settings.model.CSourceEntry; +import org.eclipse.cdt.core.settings.model.ICConfigurationDescription; +import org.eclipse.cdt.core.settings.model.ICSettingEntry; +import org.eclipse.cdt.core.settings.model.ICSourceEntry; +import org.eclipse.cdt.core.settings.model.util.CDataUtil; +import org.eclipse.cdt.core.settings.model.util.IPathSettingsContainerVisitor; +import org.eclipse.cdt.core.settings.model.util.PathSettingsContainer; +import org.eclipse.cdt.managedbuilder.core.IBuilder; +import org.eclipse.cdt.managedbuilder.core.IConfiguration; +import org.eclipse.cdt.managedbuilder.core.IFileInfo; +import org.eclipse.cdt.managedbuilder.core.IFolderInfo; +import org.eclipse.cdt.managedbuilder.core.IManagedBuildInfo; +import org.eclipse.cdt.managedbuilder.core.IOutputType; +import org.eclipse.cdt.managedbuilder.core.IResourceInfo; +import org.eclipse.cdt.managedbuilder.core.ITool; +import org.eclipse.cdt.managedbuilder.core.ManagedBuildManager; +import org.eclipse.cdt.managedbuilder.core.ManagedBuilderCorePlugin; +import org.eclipse.cdt.managedbuilder.internal.core.ManagedMakeMessages; +import org.eclipse.cdt.managedbuilder.macros.BuildMacroException; +import org.eclipse.cdt.managedbuilder.macros.IBuildMacroProvider; +import org.eclipse.cdt.managedbuilder.makegen.IManagedBuilderMakefileGenerator2; +import org.eclipse.cdt.managedbuilder.makegen.IManagedDependencyCommands; +import org.eclipse.cdt.managedbuilder.makegen.IManagedDependencyGenerator2; +import org.eclipse.cdt.managedbuilder.makegen.IManagedDependencyGeneratorType; +import org.eclipse.cdt.managedbuilder.makegen.IManagedDependencyInfo; +import org.eclipse.cdt.managedbuilder.makegen.IManagedDependencyPreBuild; +import org.eclipse.cdt.utils.EFSExtensionManager; +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.IResourceDelta; +import org.eclipse.core.resources.IResourceDeltaVisitor; +import org.eclipse.core.resources.IResourceProxy; +import org.eclipse.core.resources.IResourceProxyVisitor; +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.MultiStatus; +import org.eclipse.core.runtime.OperationCanceledException; +import org.eclipse.core.runtime.Path; +import org.eclipse.core.runtime.Status; +import org.eclipse.core.runtime.SubProgressMonitor; + +import io.sloeber.core.Messages; +import io.sloeber.core.common.Common; +import io.sloeber.core.common.Const; + +/** + * This is a specialized makefile generator that takes advantage of the + * extensions present in Gnu Make. + * + * @since 1.2 + * @noextend This class is not intended to be subclassed by clients. + * @noinstantiate This class is not intended to be instantiated by clients. + */ +@SuppressWarnings({ "deprecation", "restriction", "nls", "unused", "synthetic-access", "static-method", "unchecked", + "hiding" }) +public class ArduinoGnuMakefileGenerator implements IManagedBuilderMakefileGenerator2 { + SubDirMakeGenerator mySubDirMakeGenerator = null; + TopMakeFileGenerator myTopMakeFileGenerator = null; + SrcMakeGenerator mySrcMakeGenerator = null; + + /** + * This class walks the delta supplied by the build system to determine what + * resources have been changed. The logic is very simple. If a buildable + * resource (non-header) has been added or removed, the directories in which + * they are located are "dirty" so the makefile fragments for them have to be + * regenerated. + *

+ * The actual dependencies are recalculated as a result of the build step + * itself. We are relying on make to do the right things when confronted with a + * dependency on a moved header file. That said, make will treat the missing + * header file in a dependency rule as a target it has to build unless told + * otherwise. These dummy targets are added to the makefile to avoid a missing + * target error. + */ + public class ResourceDeltaVisitor implements IResourceDeltaVisitor { + private final ArduinoGnuMakefileGenerator generator; + private final IConfiguration config; + + /** + * The constructor + */ + public ResourceDeltaVisitor(ArduinoGnuMakefileGenerator generator, IManagedBuildInfo info) { + this.generator = generator; + this.config = info.getDefaultConfiguration(); + } + + public ResourceDeltaVisitor(ArduinoGnuMakefileGenerator generator, IConfiguration cfg) { + this.generator = generator; + this.config = cfg; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.core.resources.IResourceDeltaVisitor#visit(org.eclipse. + * core.resources.IResourceDelta) + */ + @Override + public boolean visit(IResourceDelta delta) throws CoreException { + // Should the visitor keep iterating in current directory + boolean keepLooking = false; + IResource resource = delta.getResource(); + IResourceInfo rcInfo = config.getResourceInfo(resource.getProjectRelativePath(), false); + IFolderInfo fo = null; + boolean isSource = isSource(resource.getProjectRelativePath()); + if (rcInfo instanceof IFolderInfo) { + fo = (IFolderInfo) rcInfo; + } + // What kind of resource change has occurred + if (isSource) { + if (resource.getType() == IResource.FILE) { + String ext = resource.getFileExtension(); + switch (delta.getKind()) { + case IResourceDelta.ADDED: + if (!generator.isGeneratedResource(resource)) { + // This is a source file so just add its container + if (fo == null || fo.buildsFileType(ext)) { + generator.appendModifiedSubdirectory(resource); + } + } + break; + case IResourceDelta.REMOVED: + // we get this notification if a resource is moved too + if (!generator.isGeneratedResource(resource)) { + // This is a source file so just add its container + if (fo == null || fo.buildsFileType(ext)) { + generator.appendDeletedFile(resource); + generator.appendModifiedSubdirectory(resource); + } + } + break; + default: + keepLooking = true; + break; + } + } + if (resource.getType() == IResource.FOLDER) { + // I only care about delete event + switch (delta.getKind()) { + case IResourceDelta.REMOVED: + if (!generator.isGeneratedResource(resource)) { + generator.appendDeletedSubdirectory((IContainer) resource); + } + break; + } + } + } + if (resource.getType() == IResource.PROJECT) { + // If there is a zero-length delta, something the project + // depends on has changed so just call make + IResourceDelta[] children = delta.getAffectedChildren(); + if (children != null && children.length > 0) { + keepLooking = true; + } + } else { + // If the resource is part of the generated directory structure + // don't recurse + if (resource.getType() == IResource.ROOT || (isSource && !generator.isGeneratedResource(resource))) { + keepLooking = true; + } + } + return keepLooking; + } + } + + /** + * This class is used to recursively walk the project and determine which + * modules contribute buildable source files. + */ + protected class ResourceProxyVisitor implements IResourceProxyVisitor { + private final ArduinoGnuMakefileGenerator generator; + private final IConfiguration config; + + /** + * Constructs a new resource proxy visitor to quickly visit project resources. + */ + public ResourceProxyVisitor(ArduinoGnuMakefileGenerator generator, IManagedBuildInfo info) { + this.generator = generator; + this.config = info.getDefaultConfiguration(); + } + + public ResourceProxyVisitor(ArduinoGnuMakefileGenerator generator, IConfiguration cfg) { + this.generator = generator; + this.config = cfg; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.core.resources.IResourceProxyVisitor#visit(org.eclipse. + * core.resources.IResourceProxy) + */ + @Override + public boolean visit(IResourceProxy proxy) throws CoreException { + // No point in proceeding, is there + if (generator == null) { + return false; + } + IResource resource = proxy.requestResource(); + boolean isSource = isSource(resource.getProjectRelativePath()); + // Is this a resource we should even consider + if (proxy.getType() == IResource.FILE) { + // If this resource has a Resource Configuration and is not + // excluded or + // if it has a file extension that one of the tools builds, add + // the sudirectory to the list + // boolean willBuild = false; + IResourceInfo rcInfo = config.getResourceInfo(resource.getProjectRelativePath(), false); + if (isSource) { + boolean willBuild = false; + if (rcInfo instanceof IFolderInfo) { + String ext = resource.getFileExtension(); + if (((IFolderInfo) rcInfo).buildsFileType(ext) && !generator.isGeneratedResource(resource)) { + willBuild = true; + } + } else { + willBuild = true; + } + if (willBuild) + generator.appendBuildSubdirectory(resource); + } + return false; + } else if (proxy.getType() == IResource.FOLDER) { + if (!isSource || generator.isGeneratedResource(resource)) + return false; + return true; + } + // Recurse into subdirectories + return true; + } + } + + // Local variables needed by generator + String buildTargetName; + String buildTargetExt; + IConfiguration config; + private IBuilder builder; + protected PathSettingsContainer toolInfos; + private Vector deletedFileList; + private Vector deletedDirList; + private Vector invalidDirList; + /** Collection of Folders in which sources files have been modified */ + private Collection modifiedList; + private IProgressMonitor monitor; + private IProject project; + IResource[] projectResources; + private Vector ruleList; + + // lines + private Vector depRuleList; + // dependency files + /** Collection of Containers which contribute source files to the build */ + private Collection subdirList; + private IPath topBuildDir; + final HashMap> buildSrcVars = new HashMap<>(); + final HashMap> buildOutVars = new HashMap<>(); + final HashMap buildDepVars = new HashMap<>(); + private final LinkedHashMap topBuildOutVars = new LinkedHashMap<>(); + // Dependency file variables + // private Vector dependencyMakefiles; // IPath's - relative to the top + // build directory or absolute + private ICSourceEntry srcEntries[]; + // Added by jaba + IOutputType usedOutType = null; + // End of added by jaba + + public ArduinoGnuMakefileGenerator() { + super(); + } + + /************************************************************************* + * IManagedBuilderMakefileGenerator M E T H O D S + ************************************************************************/ + /* + * (non-Javadoc) + * + * @see org.eclipse.cdt.managedbuilder.makegen.IManagedBuilderMakefileGenerator + * #initialize(IProject, IManagedBuildInfo, IProgressMonitor) + */ + @Override + public void initialize(IProject project, IManagedBuildInfo info, IProgressMonitor monitor) { + + this.project = project; + mySubDirMakeGenerator = new SubDirMakeGenerator(this); + myTopMakeFileGenerator = new TopMakeFileGenerator(this); + mySrcMakeGenerator = new SrcMakeGenerator(this); + try { + projectResources = project.members(); + } catch (CoreException e) { + projectResources = null; + } + // Save the monitor reference for reporting back to the user + this.monitor = monitor; + // Get the name of the build target + buildTargetName = info.getBuildArtifactName(); + // Get its extension + buildTargetExt = info.getBuildArtifactExtension(); + try { + // try to resolve the build macros in the target extension + buildTargetExt = ManagedBuildManager.getBuildMacroProvider().resolveValueToMakefileFormat(buildTargetExt, + "", " ", IBuildMacroProvider.CONTEXT_CONFIGURATION, info.getDefaultConfiguration()); + } catch (BuildMacroException e) { + /* JABA is not going to write this code */ + } + try { + // try to resolve the build macros in the target name + String resolved = ManagedBuildManager.getBuildMacroProvider().resolveValueToMakefileFormat(buildTargetName, + "", " ", IBuildMacroProvider.CONTEXT_CONFIGURATION, info.getDefaultConfiguration()); + if (resolved != null && (resolved = resolved.trim()).length() > 0) + buildTargetName = resolved; + } catch (BuildMacroException e) { + /* JABA is not going to write this code */ + } + if (buildTargetExt == null) { + buildTargetExt = ""; + } + // Cache the build tools + config = info.getDefaultConfiguration(); + builder = config.getEditableBuilder(); + initToolInfos(); + // set the top build dir path + topBuildDir = project.getFolder(info.getConfigurationName()).getFullPath(); + } + + /** + * This method calls the dependency postprocessors defined for the tool chain + */ + private void callDependencyPostProcessors(IResourceInfo rcInfo, ToolInfoHolder h, IFile depFile, + IManagedDependencyGenerator2[] postProcessors, boolean callPopulateDummyTargets, boolean force) + throws CoreException { + try { + updateMonitor(ManagedMakeMessages + .getFormattedString("ArduinoGnuMakefileGenerator.message.postproc.dep.file", depFile.getName())); + if (postProcessors != null) { + IPath absolutePath = new Path( + EFSExtensionManager.getDefault().getPathFromURI(depFile.getLocationURI())); + // Convert to build directory relative + IPath depPath = ManagedBuildManager.calculateRelativePath(getTopBuildDir(), absolutePath); + for (int i = 0; i < postProcessors.length; i++) { + IManagedDependencyGenerator2 depGen = postProcessors[i]; + if (depGen != null) { + depGen.postProcessDependencyFile(depPath, config, h.buildTools[i], getTopBuildDir()); + } + } + } + if (callPopulateDummyTargets) { + populateDummyTargets(rcInfo, depFile, force); + } + } catch (CoreException e) { + throw e; + } catch (IOException e) { + /* JABA is not going to write this code */ + } + } + + /** + * This method collects the dependency postprocessors and file extensions + * defined for the tool chain + */ + private boolean collectDependencyGeneratorInformation(ToolInfoHolder h, Vector depExts, + IManagedDependencyGenerator2[] postProcessors) { + boolean callPopulateDummyTargets = false; + for (int i = 0; i < h.buildTools.length; i++) { + ITool tool = h.buildTools[i]; + IManagedDependencyGeneratorType depType = tool + .getDependencyGeneratorForExtension(tool.getDefaultInputExtension()); + if (depType != null) { + int calcType = depType.getCalculatorType(); + if (calcType <= IManagedDependencyGeneratorType.TYPE_OLD_TYPE_LIMIT) { + if (calcType == IManagedDependencyGeneratorType.TYPE_COMMAND) { + callPopulateDummyTargets = true; + depExts.add(DEP_EXT); + } + } else { + if (calcType == IManagedDependencyGeneratorType.TYPE_BUILD_COMMANDS + || calcType == IManagedDependencyGeneratorType.TYPE_PREBUILD_COMMANDS) { + IManagedDependencyGenerator2 depGen = (IManagedDependencyGenerator2) depType; + String depExt = depGen.getDependencyFileExtension(config, tool); + if (depExt != null) { + postProcessors[i] = depGen; + depExts.add(depExt); + } + } + } + } + } + return callPopulateDummyTargets; + } + + public boolean isSource(IPath path) { + return !CDataUtil.isExcluded(path, srcEntries); + } + + private class DepInfo { + Vector depExts; + IManagedDependencyGenerator2[] postProcessors; + boolean callPopulateDummyTargets; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.cdt.managedbuilder.makegen.IManagedBuilderMakefileGenerator + * #generateDependencies() + */ + @Override + public void generateDependencies() throws CoreException { + final PathSettingsContainer postProcs = PathSettingsContainer.createRootContainer(); + // Note: PopulateDummyTargets is a hack for the pre-3.x GCC compilers + // Collect the methods that will need to be called + toolInfos.accept(new IPathSettingsContainerVisitor() { + @Override + public boolean visit(PathSettingsContainer container) { + ToolInfoHolder h = (ToolInfoHolder) container.getValue(); + Vector depExts = new Vector<>(); + IManagedDependencyGenerator2[] postProcessors = new IManagedDependencyGenerator2[h.buildTools.length]; + boolean callPopulateDummyTargets = collectDependencyGeneratorInformation(h, depExts, postProcessors); + // Is there anyone to call if we do find dependency files? + if (!callPopulateDummyTargets) { + int i; + for (i = 0; i < postProcessors.length; i++) { + if (postProcessors[i] != null) + break; + } + if (i == postProcessors.length) + return true; + } + PathSettingsContainer child = postProcs.getChildContainer(container.getPath(), true, true); + DepInfo di = new DepInfo(); + di.depExts = depExts; + di.postProcessors = postProcessors; + di.callPopulateDummyTargets = callPopulateDummyTargets; + child.setValue(di); + return true; + } + }); + IWorkspaceRoot root = CCorePlugin.getWorkspace().getRoot(); + for (IResource res : getSubdirList()) { + // The builder creates a subdir with same name as source in the + // build location + IContainer subDir = (IContainer) res; + IPath projectRelativePath = subDir.getProjectRelativePath(); + IResourceInfo rcInfo = config.getResourceInfo(projectRelativePath, false); + PathSettingsContainer cr = postProcs.getChildContainer(rcInfo.getPath(), false, true); + if (cr == null || cr.getValue() == null) + continue; + DepInfo di = (DepInfo) cr.getValue(); + ToolInfoHolder h = ToolInfoHolder.getToolInfo(this, projectRelativePath); + IPath buildRelativePath = topBuildDir.append(projectRelativePath); + IFolder buildFolder = root.getFolder(buildRelativePath); + if (buildFolder == null) + continue; + if (!buildFolder.exists()) + continue; + // Find all of the dep files in the generated subdirectories + IResource[] files = buildFolder.members(); + for (IResource file : files) { + String fileExt = file.getFileExtension(); + for (String ext : di.depExts) { + if (ext.equals(fileExt)) { + IFile depFile = root.getFile(file.getFullPath()); + if (depFile == null) + continue; + callDependencyPostProcessors(rcInfo, h, depFile, di.postProcessors, di.callPopulateDummyTargets, + false); + } + } + } + } + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.cdt.managedbuilder.makegen.IManagedBuilderMakefileGenerator# + * generateMakefiles(org.eclipse.core.resources.IResourceDelta) + */ + @Override + public MultiStatus generateMakefiles(IResourceDelta delta) throws CoreException { + /* + * Let's do a sanity check right now. 1. This is an incremental build, so if the + * top-level directory is not there, then a rebuild is needed. + */ + IFolder folder = project.getFolder(config.getName()); + if (!folder.exists()) { + return regenerateMakefiles(); + } + // Return value + MultiStatus status; + // Visit the resources in the delta and compile a list of subdirectories + // to regenerate + updateMonitor( + ManagedMakeMessages.getFormattedString("MakefileGenerator.message.calc.delta", project.getName())); + ResourceDeltaVisitor visitor = new ResourceDeltaVisitor(this, config); + delta.accept(visitor); + checkCancel(); + // Get all the subdirectories participating in the build + updateMonitor( + ManagedMakeMessages.getFormattedString("MakefileGenerator.message.finding.sources", project.getName())); + ResourceProxyVisitor resourceVisitor = new ResourceProxyVisitor(this, config); + project.accept(resourceVisitor, IResource.NONE); + checkCancel(); + // Bug 303953: Ensure that if all resources have been removed from a + // folder, than the folder still + // appears in the subdir list so it's subdir.mk is correctly regenerated + getSubdirList().addAll(getModifiedList()); + // Make sure there is something to build + if (getSubdirList().isEmpty()) { + String info = ManagedMakeMessages.getFormattedString("MakefileGenerator.warning.no.source", + project.getName()); + updateMonitor(info); + status = new MultiStatus(ManagedBuilderCorePlugin.getUniqueIdentifier(), IStatus.INFO, "", null); + status.add(new Status(IStatus.INFO, ManagedBuilderCorePlugin.getUniqueIdentifier(), NO_SOURCE_FOLDERS, info, + null)); + return status; + } + // Make sure the build directory is available + topBuildDir = createDirectory(project, config.getName()); + checkCancel(); + // Make sure that there is a makefile containing all the folders + // participating + IPath srcsFilePath = topBuildDir.append(SRCSFILE_NAME); + IFile srcsFileHandle = createFile(srcsFilePath); + buildSrcVars.clear(); + buildOutVars.clear(); + buildDepVars.clear(); + topBuildOutVars.clear(); + mySrcMakeGenerator.populateSourcesMakefile(srcsFileHandle, toolInfos, subdirList); + checkCancel(); + // Regenerate any fragments that are missing for the exisiting + // directories NOT modified + for (IResource res : getSubdirList()) { + IContainer subdirectory = (IContainer) res; + if (!getModifiedList().contains(subdirectory)) { + // Make sure the directory exists (it may have been deleted) + if (!subdirectory.exists()) { + appendDeletedSubdirectory(subdirectory); + continue; + } + // Make sure a fragment makefile exists + IPath fragmentPath = getBuildWorkingDir().append(subdirectory.getProjectRelativePath()) + .append(MODFILE_NAME); + IFile makeFragment = project.getFile(fragmentPath); + if (!makeFragment.exists()) { + // If one or both are missing, then add it to the list to be + // generated + getModifiedList().add(subdirectory); + } + } + } + // Delete the old dependency files for any deleted resources + for (IResource deletedFile : getDeletedFileList()) { + deleteDepFile(deletedFile); + deleteBuildTarget(deletedFile); + } + // Regenerate any fragments for modified directories + for (IResource res : getModifiedList()) { + IContainer subDir = (IContainer) res; + // Make sure the directory exists (it may have been deleted) + if (!subDir.exists()) { + appendDeletedSubdirectory(subDir); + continue; + } + // populateFragmentMakefile(subDir); // See below + checkCancel(); + } + // Recreate all module makefiles + // NOTE WELL: For now, always recreate all of the fragment makefile. + // This is necessary + // in order to re-populate the buildVariable lists. In the future, the + // list could + // possibly segmented by subdir so that all fragments didn't need to be + // regenerated + for (IResource res : getSubdirList()) { + IContainer subDir = (IContainer) res; + try { + mySubDirMakeGenerator.populateFragmentMakefile(subDir); + } catch (CoreException e) { + // Probably should ask user if they want to continue + checkCancel(); + continue; + } + checkCancel(); + } + // Calculate the inputs and outputs of the Tools to be generated in the + // main makefile + calculateToolInputsOutputs(); + checkCancel(); + // Re-create the top-level makefile + IPath makefilePath = topBuildDir.append(MAKEFILE_NAME); + IFile makefileHandle = createFile(makefilePath); + myTopMakeFileGenerator.populateTopMakefile(makefileHandle, false); + checkCancel(); + // Remove deleted folders from generated build directory + for (IResource res : getDeletedDirList()) { + IContainer subDir = (IContainer) res; + removeGeneratedDirectory(subDir); + checkCancel(); + } + // How did we do + if (!getInvalidDirList().isEmpty()) { + status = new MultiStatus(ManagedBuilderCorePlugin.getUniqueIdentifier(), IStatus.WARNING, "", null); + // Add a new status for each of the bad folders + // TODO: fix error message + for (IResource res : getInvalidDirList()) { + IContainer subDir = (IContainer) res; + status.add(new Status(IStatus.WARNING, ManagedBuilderCorePlugin.getUniqueIdentifier(), SPACES_IN_PATH, + subDir.getFullPath().toString(), null)); + } + } else { + status = new MultiStatus(ManagedBuilderCorePlugin.getUniqueIdentifier(), IStatus.OK, "", null); + } + return status; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.cdt.managedbuilder.makegen.IManagedBuilderMakefileGenerator# + * getBuildWorkingDir() + */ + @Override + public IPath getBuildWorkingDir() { + if (topBuildDir != null) { + return topBuildDir.removeFirstSegments(1); + } + return null; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.cdt.managedbuilder.makegen.IManagedBuilderMakefileGenerator# + * getMakefileName() + */ + @Override + public String getMakefileName() { + return MAKEFILE_NAME; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.cdt.managedbuilder.makegen.IManagedBuilderMakefileGenerator# + * isGeneratedResource(org.eclipse.core.resources.IResource) + */ + @Override + public boolean isGeneratedResource(IResource resource) { + // Is this a generated directory ... + IPath path = resource.getProjectRelativePath(); + // TODO: fix to use builder output dir instead + String[] configNames = ManagedBuildManager.getBuildInfo(project).getConfigurationNames(); + for (String name : configNames) { + IPath root = new Path(name); + // It is if it is a root of the resource pathname + if (root.isPrefixOf(path)) + return true; + } + return false; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.cdt.managedbuilder.makegen.IManagedBuilderMakefileGenerator# + * regenerateDependencies() + */ + @Override + public void regenerateDependencies(boolean force) throws CoreException { + // A hack for the pre-3.x GCC compilers is to put dummy targets for deps + final IWorkspaceRoot root = CCorePlugin.getWorkspace().getRoot(); + final CoreException[] es = new CoreException[1]; + toolInfos.accept(new IPathSettingsContainerVisitor() { + @Override + public boolean visit(PathSettingsContainer container) { + ToolInfoHolder h = (ToolInfoHolder) container.getValue(); + // Collect the methods that will need to be called + Vector depExts = new Vector(); + IManagedDependencyGenerator2[] postProcessors = new IManagedDependencyGenerator2[h.buildTools.length]; + boolean callPopulateDummyTargets = collectDependencyGeneratorInformation(h, depExts, postProcessors); + // Is there anyone to call if we do find dependency files? + if (!callPopulateDummyTargets) { + int i; + for (i = 0; i < postProcessors.length; i++) { + if (postProcessors[i] != null) + break; + } + if (i == postProcessors.length) + return true; + } + IResourceInfo rcInfo = config.getResourceInfo(container.getPath(), false); + for (IPath path : getDependencyMakefiles(h)) { + // The path to search for the dependency makefile + IPath relDepFilePath = topBuildDir.append(path); + IFile depFile = root.getFile(relDepFilePath); + if (depFile == null || !depFile.isAccessible()) + continue; + try { + callDependencyPostProcessors(rcInfo, h, depFile, postProcessors, callPopulateDummyTargets, + true); + } catch (CoreException e) { + es[0] = e; + return false; + } + } + return true; + } + }); + if (es[0] != null) + throw es[0]; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.cdt.managedbuilder.makegen.IManagedBuilderMakefileGenerator# + * regenerateMakefiles() + */ + @Override + public MultiStatus regenerateMakefiles() throws CoreException { + MultiStatus status; + // Visit the resources in the project + ResourceProxyVisitor visitor = new ResourceProxyVisitor(this, config); + project.accept(visitor, IResource.NONE); + // See if the user has cancelled the build + checkCancel(); + // Populate the makefile if any buildable source files have been found + // in the project + if (getSubdirList().isEmpty()) { + String info = ManagedMakeMessages.getFormattedString("MakefileGenerator.warning.no.source", + project.getName()); + updateMonitor(info); + status = new MultiStatus(ManagedBuilderCorePlugin.getUniqueIdentifier(), IStatus.INFO, "", null); + status.add(new Status(IStatus.INFO, ManagedBuilderCorePlugin.getUniqueIdentifier(), NO_SOURCE_FOLDERS, info, + null)); + return status; + } + // Create the top-level directory for the build output + topBuildDir = createDirectory(project, config.getName()); + checkCancel(); + // Get the list of subdirectories + IPath srcsFilePath = topBuildDir.append(SRCSFILE_NAME); + IFile srcsFileHandle = createFile(srcsFilePath); + buildSrcVars.clear(); + buildOutVars.clear(); + buildDepVars.clear(); + topBuildOutVars.clear(); + mySrcMakeGenerator.populateSourcesMakefile(srcsFileHandle, toolInfos, subdirList); + checkCancel(); + // Now populate the module makefiles + for (IResource res : getSubdirList()) { + IContainer subDir = (IContainer) res; + try { + mySubDirMakeGenerator.populateFragmentMakefile(subDir); + } catch (CoreException e) { + // Probably should ask user if they want to continue + checkCancel(); + continue; + } + checkCancel(); + } + // Calculate the inputs and outputs of the Tools to be generated in the + // main makefile + calculateToolInputsOutputs(); + checkCancel(); + // Create the top-level makefile + IPath makefilePath = topBuildDir.append(MAKEFILE_NAME); + IFile makefileHandle = createFile(makefilePath); + myTopMakeFileGenerator.populateTopMakefile(makefileHandle, true); + // JABA SLOEBER create the size.awk file + ICConfigurationDescription confDesc = ManagedBuildManager.getDescriptionForConfiguration(config); + IWorkspaceRoot root = CCorePlugin.getWorkspace().getRoot(); + IFile sizeAwkFile1 = root.getFile(topBuildDir.append("size.awk")); + File sizeAwkFile = sizeAwkFile1.getLocation().toFile(); + String regex = Common.getBuildEnvironmentVariable(confDesc, "recipe.size.regex", EMPTY); + String awkContent = "/" + regex + "/ {arduino_size += $2 }\n"; + regex = Common.getBuildEnvironmentVariable(confDesc, "recipe.size.regex.data", EMPTY); + awkContent += "/" + regex + "/ {arduino_data += $2 }\n"; + regex = Common.getBuildEnvironmentVariable(confDesc, "recipe.size.regex.eeprom", EMPTY); + awkContent += "/" + regex + "/ {arduino_eeprom += $2 }\n"; + awkContent += "END { print \"\\n"; + String max = Common.getBuildEnvironmentVariable(confDesc, "upload.maximum_size", "10000"); + awkContent += Messages.sizeReportSketch.replace("maximum_size", max); + awkContent += "\\n"; + max = Common.getBuildEnvironmentVariable(confDesc, "upload.maximum_data_size", "10000"); + awkContent += Messages.sizeReportData.replace("maximum_data_size", max); + awkContent += "\\n"; + awkContent += "\"}"; + + try { + FileUtils.write(sizeAwkFile, awkContent, Charset.defaultCharset()); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + // END JABA SLOEBER create the size.awk file + checkCancel(); + // Now finish up by adding all the object files + IPath objFilePath = topBuildDir.append(OBJECTS_MAKFILE); + IFile objsFileHandle = createFile(objFilePath); + populateObjectsMakefile(objsFileHandle); + checkCancel(); + // How did we do + if (!getInvalidDirList().isEmpty()) { + status = new MultiStatus(ManagedBuilderCorePlugin.getUniqueIdentifier(), IStatus.WARNING, "", null); + // Add a new status for each of the bad folders + // TODO: fix error message + for (IResource dir : getInvalidDirList()) { + status.add(new Status(IStatus.WARNING, ManagedBuilderCorePlugin.getUniqueIdentifier(), SPACES_IN_PATH, + dir.getFullPath().toString(), null)); + } + } else { + status = new MultiStatus(ManagedBuilderCorePlugin.getUniqueIdentifier(), IStatus.OK, "", null); + } + return status; + } + + /** + * The makefile generator generates a Macro for each type of output, other than + * final artifact, created by the build. + * + * @param fileHandle + * The file that should be populated with the output + */ + protected void populateObjectsMakefile(IFile fileHandle) throws CoreException { + // Master list of "object" dependencies, i.e. dependencies between input + // files and output files. + StringBuffer macroBuffer = new StringBuffer(); + List valueList; + macroBuffer.append(addDefaultHeader()); + // Map of macro names (String) to its definition (List of Strings) + HashMap> outputMacros = new HashMap>(); + // Add the predefined LIBS, USER_OBJS macros + // Add the libraries this project depends on + valueList = new ArrayList(); + String[] libs = config.getLibs(buildTargetExt); + for (String lib : libs) { + valueList.add(lib); + } + outputMacros.put("LIBS", valueList); + // Add the extra user-specified objects + valueList = new ArrayList(); + String[] userObjs = config.getUserObjects(buildTargetExt); + for (String obj : userObjs) { + valueList.add(obj); + } + outputMacros.put("USER_OBJS", valueList); + // Write every macro to the file + for (Entry> entry : outputMacros.entrySet()) { + macroBuffer.append(entry.getKey()).append(" :="); + valueList = entry.getValue(); + for (String path : valueList) { + // These macros will also be used within commands. + // Make all the slashes go forward so they aren't + // interpreted as escapes and get lost. + // See https://bugs.eclipse.org/163672. + path = path.replace('\\', '/'); + path = ensurePathIsGNUMakeTargetRuleCompatibleSyntax(path); + macroBuffer.append(WHITESPACE); + macroBuffer.append(path); + } + // terminate the macro definition line + macroBuffer.append(NEWLINE); + // leave a blank line before the next macro + macroBuffer.append(NEWLINE); + } + // For now, just save the buffer that was populated when the rules were + // created + save(macroBuffer, fileHandle); + } + + /************************************************************************* + * M A K E F I L E G E N E R A T I O N C O M M O N M E T H O D S + ************************************************************************/ + + /** + * Answers all of the output extensions that the target of the build has tools + * defined to work on. + * + * @return a Set containing all of the output extensions + */ + public Set getOutputExtensions(ToolInfoHolder h) { + if (h.outputExtensionsSet == null) { + // The set of output extensions which will be produced by this tool. + // It is presumed that this set is not very large (likely < 10) so + // a HashSet should provide good performance. + h.outputExtensionsSet = new HashSet<>(); + // For each tool for the target, lookup the kinds of sources it + // outputs + // and add that to our list of output extensions. + for (ITool tool : h.buildTools) { + String[] outputs = tool.getAllOutputExtensions(); + if (outputs != null) { + h.outputExtensionsSet.addAll(Arrays.asList(outputs)); + } + } + } + return h.outputExtensionsSet; + } + + /** + * Adds file(s) to an entry in a map of macro names to entries. File additions + * look like: example.c, \ + */ + public void addMacroAdditionFiles(HashMap map, String macroName, List list) { + StringBuffer buffer = new StringBuffer(); + buffer.append(map.get(macroName)); + for (int i = 0; i < list.size(); i++) { + String filename = list.get(i); + if (filename.length() > 0) { + filename = ensurePathIsGNUMakeTargetRuleCompatibleSyntax(filename); + buffer.append(new Path(filename).toOSString()).append(WHITESPACE).append(LINEBREAK); + } + } + // re-insert string in the map + map.put(macroName, buffer.toString()); + } + + /** + * Calculates the inputs and outputs for tools that will be generated in the top + * makefile. This information is used by the top level makefile generation + * methods. + */ + protected void calculateToolInputsOutputs() { + toolInfos.accept(new IPathSettingsContainerVisitor() { + @Override + public boolean visit(PathSettingsContainer container) { + ToolInfoHolder h = (ToolInfoHolder) container.getValue(); + ITool[] buildTools = h.buildTools; + ArduinoManagedBuildGnuToolInfo[] gnuToolInfos = h.gnuToolInfos; + // We are "done" when the information for all tools has been + // calculated, + // or we are not making any progress + boolean done = false; + boolean lastChance = false; + int[] doneState = new int[buildTools.length]; + // Identify the target tool + ITool targetTool = config.calculateTargetTool(); + // if (targetTool == null) { + // targetTool = info.getToolFromOutputExtension(buildTargetExt); + // } + // Initialize the tool info array and the done state + if (buildTools.length != 0 && buildTools[0].getCustomBuildStep()) + return true; + for (int i = 0; i < buildTools.length; i++) { + if ((buildTools[i] == targetTool)) { + String ext = config.getArtifactExtension(); + // try to resolve the build macros in the artifact + // extension + try { + ext = ManagedBuildManager.getBuildMacroProvider().resolveValueToMakefileFormat(ext, "", " ", + IBuildMacroProvider.CONTEXT_CONFIGURATION, config); + } catch (BuildMacroException e) { + /* JABA is not going to write this code */ + } + String name = config.getArtifactName(); + // try to resolve the build macros in the artifact name + try { + String resolved = ManagedBuildManager.getBuildMacroProvider().resolveValueToMakefileFormat( + name, "", " ", IBuildMacroProvider.CONTEXT_CONFIGURATION, config); + if ((resolved = resolved.trim()).length() > 0) + name = resolved; + } catch (BuildMacroException e) { + /* JABA is not going to write this code */ + } + gnuToolInfos[i] = new ArduinoManagedBuildGnuToolInfo(project, buildTools[i], true, name, ext); + } else { + gnuToolInfos[i] = new ArduinoManagedBuildGnuToolInfo(project, buildTools[i], false, null, null); + } + doneState[i] = 0; + } + // Initialize the build output variable to file additions map + LinkedHashMap map = getTopBuildOutputVars(); + Set>> set = buildOutVars.entrySet(); + for (Entry> entry : set) { + String macroName = entry.getKey(); + // for projects with specific setting on folders/files do + // not clear the macro value on subsequent passes + if (!map.containsKey(macroName)) { + addMacroAdditionPrefix(map, macroName, "", false); + } + } + // Set of input extensions for which macros have been created so + // far + HashSet handledDepsInputExtensions = new HashSet<>(); + HashSet handledOutsInputExtensions = new HashSet<>(); + while (!done) { + int[] testState = new int[doneState.length]; + for (int i = 0; i < testState.length; i++) + testState[i] = 0; + // Calculate inputs + for (int i = 0; i < gnuToolInfos.length; i++) { + if (gnuToolInfos[i].areInputsCalculated()) { + testState[i]++; + } else { + if (gnuToolInfos[i].calculateInputs(ArduinoGnuMakefileGenerator.this, config, + projectResources, h, lastChance)) { + testState[i]++; + } + } + } + // Calculate dependencies + for (int i = 0; i < gnuToolInfos.length; i++) { + if (gnuToolInfos[i].areDependenciesCalculated()) { + testState[i]++; + } else { + if (gnuToolInfos[i].calculateDependencies(ArduinoGnuMakefileGenerator.this, config, + handledDepsInputExtensions, h, lastChance)) { + testState[i]++; + } + } + } + // Calculate outputs + for (int i = 0; i < gnuToolInfos.length; i++) { + if (gnuToolInfos[i].areOutputsCalculated()) { + testState[i]++; + } else { + if (gnuToolInfos[i].calculateOutputs(ArduinoGnuMakefileGenerator.this, config, + handledOutsInputExtensions, lastChance)) { + testState[i]++; + } + } + } + // Are all calculated? If so, done. + done = true; + for (int element : testState) { + if (element != 3) { + done = false; + break; + } + } + // Test our "done" state vs. the previous "done" state. + // If we have made no progress, give it a "last chance" and + // then quit + if (!done) { + done = true; + for (int i = 0; i < testState.length; i++) { + if (testState[i] != doneState[i]) { + done = false; + break; + } + } + } + if (done) { + if (!lastChance) { + lastChance = true; + done = false; + } + } + if (!done) { + doneState = testState; + } + } + return true; + } + }); + } + + /** + * Returns the (String) list of files associated with the build variable + * + * @param variable + * the variable name + * @param locationType + * the format in which we want the filenames returned + * @param directory + * project relative directory path used with locationType == + * DIRECTORY_RELATIVE + * @param getAll + * only return the list if all tools that are going to contrubute to + * this variable have done so. + * @return List + */ + public List getBuildVariableList(ToolInfoHolder h, String variable, int locationType, IPath directory, + boolean getAll) { + ArduinoManagedBuildGnuToolInfo[] gnuToolInfos = h.gnuToolInfos; + boolean done = true; + for (int i = 0; i < gnuToolInfos.length; i++) { + if (!gnuToolInfos[i].areOutputVariablesCalculated()) { + done = false; + } + } + if (!done && getAll) + return null; + List list = buildSrcVars.get(variable); + if (list == null) { + list = buildOutVars.get(variable); + } + List fileList = null; + if (list != null) { + // Convert the items in the list to the location-type wanted by the + // caller, + // and to a string list + IPath dirLocation = null; + if (locationType != ABSOLUTE) { + dirLocation = project.getLocation(); + if (locationType == PROJECT_SUBDIR_RELATIVE) { + dirLocation = dirLocation.append(directory); + } + } + for (int i = 0; i < list.size(); i++) { + IPath path = list.get(i); + if (locationType != ABSOLUTE) { + if (dirLocation != null && dirLocation.isPrefixOf(path)) { + path = path.removeFirstSegments(dirLocation.segmentCount()).setDevice(null); + } + } + if (fileList == null) { + fileList = new Vector(); + } + fileList.add(path.toString()); + } + } + return fileList; + } + + /** + * Returns the map of build variables to list of files + * + * @return HashMap + */ + public HashMap> getBuildOutputVars() { + return buildOutVars; + } + + /** + * Returns the map of build variables used in the top makefile to list of files + * + * @return HashMap + */ + public LinkedHashMap getTopBuildOutputVars() { + return topBuildOutVars; + } + + /** + * Returns the list of known build rules. This keeps me from generating + * duplicate rules for known file extensions. + * + * @return List + */ + protected Vector getRuleList() { + if (ruleList == null) { + ruleList = new Vector(); + } + return ruleList; + } + + /** + * Returns the list of known dependency file generation lines. This keeps me + * from generating duplicate lines. + * + * @return List + */ + protected Vector getDepRuleList() { + if (depRuleList == null) { + depRuleList = new Vector(); + } + return depRuleList; + } + + /************************************************************************* + * R E S O U R C E V I S I T O R M E T H O D S + ************************************************************************/ + /** + * Adds the container of the argument to the list of folders in the project that + * contribute source files to the build. The resource visitor has already + * established that the build model knows how to build the files. It has also + * checked that the resource is not generated as part of the build. + */ + protected void appendBuildSubdirectory(IResource resource) { + IContainer container = resource.getParent(); + // Only add the container once + if (!getSubdirList().contains(container)) + getSubdirList().add(container); + } + + /** + * Adds the container of the argument to a list of subdirectories that are to be + * deleted. As a result, the directories that are generated for the output + * should be removed as well. + */ + protected void appendDeletedSubdirectory(IContainer container) { + // No point in adding a folder if the parent is already there + IContainer parent = container.getParent(); + if (!getDeletedDirList().contains(container) && !getDeletedDirList().contains(parent)) { + getDeletedDirList().add(container); + } + } + + /** + * If a file is removed from a source folder (either because of a delete or move + * action on the part of the user), the makefilegenerator has to remove the + * dependency makefile along with the old build goal + */ + protected void appendDeletedFile(IResource resource) { + // Cache this for now + getDeletedFileList().add(resource); + } + + /** + * Adds the container of the argument to a list of subdirectories that are part + * of an incremental rebuild of the project. The makefile fragments for these + * directories will be regenerated as a result of the build. + */ + protected void appendModifiedSubdirectory(IResource resource) { + IContainer container = resource.getParent(); + if (!getModifiedList().contains(container)) { + getModifiedList().add(container); + } + } + + /************************************************************************* + * O T H E R M E T H O D S + ************************************************************************/ + protected void cancel(String message) { + if (monitor != null && !monitor.isCanceled()) { + throw new OperationCanceledException(message); + } + } + + /** + * Check whether the build has been cancelled. Cancellation requests propagated + * to the caller by throwing OperationCanceledException. + * + * @see org.eclipse.core.runtime.OperationCanceledException#OperationCanceledException() + */ + protected void checkCancel() { + if (monitor != null && monitor.isCanceled()) { + throw new OperationCanceledException(); + } + } + + private void deleteBuildTarget(IResource deletedFile) { + // Get the project relative path of the file + String fileName = getFileName(deletedFile); + String srcExtension = deletedFile.getFileExtension(); + IPath folderPath = inFullPathFromOutFullPath(deletedFile.getFullPath().removeLastSegments(1)); + if (folderPath != null) { + folderPath = folderPath.removeFirstSegments(1); + } else { + folderPath = new Path(""); + } + IResourceInfo rcInfo = config.getResourceInfo(folderPath, false); + if (rcInfo instanceof IFileInfo) { + rcInfo = config.getResourceInfo(folderPath.removeLastSegments(1), false); + } + String targetExtension = ((IFolderInfo) rcInfo).getOutputExtension(srcExtension); + if (!targetExtension.isEmpty()) + fileName += DOT + targetExtension; + IPath projectRelativePath = deletedFile.getProjectRelativePath().removeLastSegments(1); + IPath targetFilePath = getBuildWorkingDir().append(projectRelativePath).append(fileName); + IResource depFile = project.findMember(targetFilePath); + if (depFile != null && depFile.exists()) { + try { + depFile.delete(true, new SubProgressMonitor(monitor, 1)); + } catch (CoreException e) { + // This had better be allowed during a build + } + } + } + + private IPath inFullPathFromOutFullPath(IPath path) { + IPath inPath = null; + if (topBuildDir.isPrefixOf(path)) { + inPath = path.removeFirstSegments(topBuildDir.segmentCount()); + inPath = project.getFullPath().append(path); + } + return inPath; + } + + private void deleteDepFile(IResource deletedFile) { + // Calculate the top build directory relative paths of the dependency + // files + IPath[] depFilePaths = null; + ITool tool = null; + IManagedDependencyGeneratorType depType = null; + String sourceExtension = deletedFile.getFileExtension(); + IPath folderPath = inFullPathFromOutFullPath(deletedFile.getFullPath().removeLastSegments(1)); + if (folderPath != null) { + folderPath = folderPath.removeFirstSegments(1); + } else { + folderPath = new Path(""); + ToolInfoHolder h = ToolInfoHolder.getToolInfo(this, folderPath); + ITool[] tools = h.buildTools; + for (int index = 0; index < tools.length; ++index) { + if (tools[index].buildsFileType(sourceExtension)) { + tool = tools[index]; + depType = tool.getDependencyGeneratorForExtension(sourceExtension); + break; + } + } + if (depType != null) { + int calcType = depType.getCalculatorType(); + if (calcType == IManagedDependencyGeneratorType.TYPE_COMMAND) { + depFilePaths = new IPath[1]; + IPath absolutePath = deletedFile.getLocation(); + depFilePaths[0] = ManagedBuildManager.calculateRelativePath(getTopBuildDir(), absolutePath); + depFilePaths[0] = depFilePaths[0].removeFileExtension().addFileExtension(DEP_EXT); + } else if (calcType == IManagedDependencyGeneratorType.TYPE_BUILD_COMMANDS + || calcType == IManagedDependencyGeneratorType.TYPE_PREBUILD_COMMANDS) { + IManagedDependencyGenerator2 depGen = (IManagedDependencyGenerator2) depType; + IManagedDependencyInfo depInfo = depGen.getDependencySourceInfo( + deletedFile.getProjectRelativePath(), deletedFile, config, tool, getBuildWorkingDir()); + if (depInfo != null) { + if (calcType == IManagedDependencyGeneratorType.TYPE_BUILD_COMMANDS) { + IManagedDependencyCommands depCommands = (IManagedDependencyCommands) depInfo; + depFilePaths = depCommands.getDependencyFiles(); + } else if (calcType == IManagedDependencyGeneratorType.TYPE_PREBUILD_COMMANDS) { + IManagedDependencyPreBuild depPreBuild = (IManagedDependencyPreBuild) depInfo; + depFilePaths = depPreBuild.getDependencyFiles(); + } + } + } + } + // Delete the files if they exist + if (depFilePaths != null) { + for (IPath dfp : depFilePaths) { + IPath depFilePath = getBuildWorkingDir().append(dfp); + IResource depFile = project.findMember(depFilePath); + if (depFile != null && depFile.exists()) { + try { + depFile.delete(true, new SubProgressMonitor(monitor, 1)); + } catch (CoreException e) { + // This had better be allowed during a build + } + } + } + } + } + } + + /** + * Returns the current build configuration. + * + * @return String + * @since 8.0 + */ + protected IConfiguration getConfig() { + return config; + } + + /** + * Returns the build target extension. + * + * @return String + * @since 8.0 + */ + protected String getBuildTargetExt() { + return buildTargetExt; + } + + /** + * Returns the build target name. + * + * @return String + * @since 8.0 + */ + protected String getBuildTargetName() { + return buildTargetName; + } + + /** + * @return Returns the deletedDirList. + */ + private Vector getDeletedDirList() { + if (deletedDirList == null) { + deletedDirList = new Vector(); + } + return deletedDirList; + } + + private Vector getDeletedFileList() { + if (deletedFileList == null) { + deletedFileList = new Vector(); + } + return deletedFileList; + } + + public List getDependencyMakefiles(ToolInfoHolder h) { + if (h.dependencyMakefiles == null) { + h.dependencyMakefiles = new ArrayList(); + } + return h.dependencyMakefiles; + } + + /** + * Strips off the file extension from the argument and returns the name + * component in a String + */ + private String getFileName(IResource file) { + String answer = ""; + String lastSegment = file.getName(); + int extensionSeparator = lastSegment.lastIndexOf(DOT); + if (extensionSeparator != -1) { + answer = lastSegment.substring(0, extensionSeparator); + } + return answer; + } + + /** + * Answers a Vector containing a list of directories that are invalid for the + * build for some reason. At the moment, the only reason a directory would not + * be considered for the build is if it contains a space in the relative path + * from the project root. + * + * @return a a list of directories that are invalid for the build + */ + private Vector getInvalidDirList() { + if (invalidDirList == null) { + invalidDirList = new Vector(); + } + return invalidDirList; + } + + /** + * @return Collection of Containers which contain modified source files + */ + private Collection getModifiedList() { + if (modifiedList == null) + modifiedList = new LinkedHashSet(); + return modifiedList; + } + + /** + * @return Collection of subdirectories (IContainers) contributing source code + * to the build + */ + public Collection getSubdirList() { + if (subdirList == null) + subdirList = new LinkedHashSet(); + return subdirList; + } + + private void removeGeneratedDirectory(IContainer subDir) { + try { + // The source directory isn't empty + if (subDir.exists() && subDir.members().length > 0) + return; + } catch (CoreException e) { + // The resource doesn't exist so we should delete the output folder + } + // Figure out what the generated directory name is and delete it + IPath moduleRelativePath = subDir.getProjectRelativePath(); + IPath buildRoot = getBuildWorkingDir(); + if (buildRoot == null) { + return; + } + IPath moduleOutputPath = buildRoot.append(moduleRelativePath); + IFolder folder = project.getFolder(moduleOutputPath); + if (folder.exists()) { + try { + folder.delete(true, new SubProgressMonitor(monitor, 1)); + } catch (CoreException e) { + // JABA added some logging + Common.log(new Status(IStatus.INFO, Const.CORE_PLUGIN_ID, "Folder deletion failed " + folder.toString(), // + e)); + } + } + } + + protected void updateMonitor(String msg) { + if (monitor != null && !monitor.isCanceled()) { + monitor.subTask(msg); + monitor.worked(1); + } + } + + /** + * Return the configuration's top build directory as an absolute path + */ + public IPath getTopBuildDir() { + return getPathForResource(project).append(getBuildWorkingDir()); + } + + @Override + public void initialize(int buildKind, IConfiguration cfg, IBuilder builder, IProgressMonitor monitor) { + // Save the project so we can get path and member information + this.project = cfg.getOwner().getProject(); + mySubDirMakeGenerator = new SubDirMakeGenerator(this); + myTopMakeFileGenerator = new TopMakeFileGenerator(this); + mySrcMakeGenerator = new SrcMakeGenerator(this); + if (builder == null) { + builder = cfg.getEditableBuilder(); + } + try { + projectResources = project.members(); + } catch (CoreException e) { + projectResources = null; + } + // Save the monitor reference for reporting back to the user + this.monitor = monitor; + // Get the build info for the project + // info = info; + // Get the name of the build target + buildTargetName = cfg.getArtifactName(); + // Get its extension + buildTargetExt = cfg.getArtifactExtension(); + try { + // try to resolve the build macros in the target extension + buildTargetExt = ManagedBuildManager.getBuildMacroProvider().resolveValueToMakefileFormat(buildTargetExt, + "", " ", IBuildMacroProvider.CONTEXT_CONFIGURATION, builder); + } catch (BuildMacroException e) { + /* JABA is not going to write this code */ + } + try { + // try to resolve the build macros in the target name + String resolved = ManagedBuildManager.getBuildMacroProvider().resolveValueToMakefileFormat(buildTargetName, + "", " ", IBuildMacroProvider.CONTEXT_CONFIGURATION, builder); + if (resolved != null) { + resolved = resolved.trim(); + if (resolved.length() > 0) + buildTargetName = resolved; + } + } catch (BuildMacroException e) { + /* JABA is not going to write this code */ + } + if (buildTargetExt == null) { + buildTargetExt = ""; + } + // Cache the build tools + config = cfg; + this.builder = builder; + initToolInfos(); + // set the top build dir path + topBuildDir = project.getFolder(cfg.getName()).getFullPath(); + srcEntries = config.getSourceEntries(); + if (srcEntries.length == 0) { + srcEntries = new ICSourceEntry[] { + new CSourceEntry(Path.EMPTY, null, ICSettingEntry.RESOLVED | ICSettingEntry.VALUE_WORKSPACE_PATH) }; + } else { + ICConfigurationDescription cfgDes = ManagedBuildManager.getDescriptionForConfiguration(config); + srcEntries = CDataUtil.resolveEntries(srcEntries, cfgDes); + } + } + + private void initToolInfos() { + toolInfos = PathSettingsContainer.createRootContainer(); + IResourceInfo rcInfos[] = config.getResourceInfos(); + for (IResourceInfo rcInfo : rcInfos) { + if (rcInfo.isExcluded()) + continue; + ToolInfoHolder h = ToolInfoHolder.getToolInfo(this, rcInfo.getPath(), true); + if (rcInfo instanceof IFolderInfo) { + IFolderInfo fo = (IFolderInfo) rcInfo; + h.buildTools = fo.getFilteredTools(); + h.buildToolsUsed = new boolean[h.buildTools.length]; + h.gnuToolInfos = new ArduinoManagedBuildGnuToolInfo[h.buildTools.length]; + } else { + IFileInfo fi = (IFileInfo) rcInfo; + h.buildTools = fi.getToolsToInvoke(); + h.buildToolsUsed = new boolean[h.buildTools.length]; + h.gnuToolInfos = new ArduinoManagedBuildGnuToolInfo[h.buildTools.length]; + } + } + } + + public List getDepLineList() { + return mySubDirMakeGenerator.getDepLineList(); + } + + public PathSettingsContainer getToolInfos() { + return toolInfos; + } + + public IProject getProject() { + return project; + } +} diff --git a/io.sloeber.core/src/io/sloeber/managedBuild/Internal/ArduinoManagedBuildGnuToolInfo.java b/io.sloeber.core/src/io/sloeber/managedBuild/Internal/ArduinoManagedBuildGnuToolInfo.java new file mode 100644 index 000000000..dab4c64e9 --- /dev/null +++ b/io.sloeber.core/src/io/sloeber/managedBuild/Internal/ArduinoManagedBuildGnuToolInfo.java @@ -0,0 +1,1063 @@ +package io.sloeber.managedBuild.Internal; + +import static io.sloeber.managedBuild.Internal.ManagebBuildCommon.*; +import static io.sloeber.managedBuild.Internal.ManagedBuildConstants.*; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; +import java.util.Vector; + +import org.eclipse.cdt.managedbuilder.core.BuildException; +import org.eclipse.cdt.managedbuilder.core.IAdditionalInput; +import org.eclipse.cdt.managedbuilder.core.IConfiguration; +import org.eclipse.cdt.managedbuilder.core.IInputType; +import org.eclipse.cdt.managedbuilder.core.IOption; +import org.eclipse.cdt.managedbuilder.core.IOutputType; +import org.eclipse.cdt.managedbuilder.core.ITool; +import org.eclipse.cdt.managedbuilder.core.ManagedBuildManager; +import org.eclipse.cdt.managedbuilder.internal.core.ManagedMakeMessages; +import org.eclipse.cdt.managedbuilder.internal.core.Tool; +import org.eclipse.cdt.managedbuilder.internal.macros.OptionContextData; +import org.eclipse.cdt.managedbuilder.macros.BuildMacroException; +import org.eclipse.cdt.managedbuilder.macros.IBuildMacroProvider; +import org.eclipse.cdt.managedbuilder.makegen.IManagedBuilderMakefileGenerator; +import org.eclipse.cdt.managedbuilder.makegen.IManagedDependencyCalculator; +import org.eclipse.cdt.managedbuilder.makegen.IManagedDependencyGenerator; +import org.eclipse.cdt.managedbuilder.makegen.IManagedDependencyGenerator2; +import org.eclipse.cdt.managedbuilder.makegen.IManagedDependencyGeneratorType; +import org.eclipse.cdt.managedbuilder.makegen.IManagedDependencyInfo; +import org.eclipse.cdt.managedbuilder.makegen.gnu.IManagedBuildGnuToolInfo; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.Path; + +import io.sloeber.managedBuild.api.IManagedOutputNameProviderJaba; + +/** + * This class represents information about a Tool's inputs and outputs while a + * Gnu makefile is being generated. + * + * @noextend This class is not intended to be subclassed by clients. + */ +@SuppressWarnings({ "restriction", "deprecation", "unused" }) +public class ArduinoManagedBuildGnuToolInfo implements IManagedBuildGnuToolInfo { + + /* + * Members + */ + private IProject project; + private Tool tool; + private boolean bIsTargetTool; + private String targetName; + private String targetExt; + private boolean inputsCalculated = false; + private boolean outputsCalculated = false; + private boolean outputVariablesCalculated = false; + private boolean dependenciesCalculated = false; + private Vector commandInputs = new Vector<>(); + private Vector enumeratedInputs = new Vector<>(); + private Vector commandOutputs = new Vector<>(); + private Vector enumeratedPrimaryOutputs = new Vector<>(); + private Vector enumeratedSecondaryOutputs = new Vector<>(); + private Vector outputVariables = new Vector<>(); + private Vector commandDependencies = new Vector<>(); + private Vector additionalTargets = new Vector<>(); + + // private Vector enumeratedDependencies = new Vector(); + // Map of macro names (String) to values (List) + + /* + * Constructor + */ + public ArduinoManagedBuildGnuToolInfo(IProject project, ITool tool, boolean targetTool, String name, String ext) { + this.project = project; + this.tool = (Tool) tool; + this.bIsTargetTool = targetTool; + if (this.bIsTargetTool) { + this.targetName = name; + this.targetExt = ext; + } + } + + /* + * IManagedBuildGnuToolInfo Methods + */ + @Override + public boolean areInputsCalculated() { + return this.inputsCalculated; + } + + // Command inputs are top build directory relative + @Override + public Vector getCommandInputs() { + return this.commandInputs; + } + + // Enumerated inputs are project relative + @Override + public Vector getEnumeratedInputs() { + return this.enumeratedInputs; + } + + @Override + public boolean areOutputsCalculated() { + return this.outputsCalculated; + } + + // Command outputs are top build directory relative + @Override + public Vector getCommandOutputs() { + return this.commandOutputs; + } + + @Override + public Vector getEnumeratedPrimaryOutputs() { + return this.enumeratedPrimaryOutputs; + } + + @Override + public Vector getEnumeratedSecondaryOutputs() { + return this.enumeratedSecondaryOutputs; + } + + @Override + public Vector getOutputVariables() { + return this.outputVariables; + } + + public boolean areOutputVariablesCalculated() { + return this.outputVariablesCalculated; + } + + @Override + public boolean areDependenciesCalculated() { + return this.dependenciesCalculated; + } + + // Command dependencies are top build directory relative + @Override + public Vector getCommandDependencies() { + return this.commandDependencies; + } + + // Additional targets are top build directory relative + @Override + public Vector getAdditionalTargets() { + return this.additionalTargets; + } + + // public Vector getEnumeratedDependencies() { + // return enumeratedDependencies; + // } + + @Override + public boolean isTargetTool() { + return this.bIsTargetTool; + } + + /* + * Other Methods + */ + + public boolean calculateInputs(ArduinoGnuMakefileGenerator makeGen, IConfiguration config, + IResource[] projResources, ToolInfoHolder h, boolean lastChance) { + // Get the inputs for this tool invocation + // Note that command inputs that are also dependencies are also added to + // the command dependencies list + + /* + * The priorities for determining the names of the inputs of a tool are: + * 1. If an option is specified, use the value of the option. 2. If a + * build variable is specified, use the files that have been added to + * the build variable as the output(s) of other build steps. 3. Use the + * file extensions and the resources in the project + */ + boolean done = true; + Vector myCommandInputs = new Vector<>(); // Inputs for the + // tool command + // line + Vector myCommandDependencies = new Vector<>(); // Dependencies + // for the + // make + // rule + Vector myEnumeratedInputs = new Vector<>(); // Complete + // list of + // individual + // inputs + + IInputType[] inTypes = this.tool.getInputTypes(); + if (inTypes != null && inTypes.length > 0) { + for (IInputType type : inTypes) { + Vector itCommandInputs = new Vector<>(); // Inputs + // for + // the + // tool + // command + // line + // for + // this + // input-type + Vector itCommandDependencies = new Vector<>(); // Dependencies + // for + // the + // make + // rule + // for + // this + // input-type + Vector itEnumeratedInputs = new Vector<>(); // Complete + // list + // of + // individual + // inputs + // for + // this + // input-type + String variable = type.getBuildVariable(); + boolean primaryInput = type.getPrimaryInput(); + boolean useFileExts = false; + IOption option = this.tool.getOptionBySuperClassId(type.getOptionId()); + IOption assignToOption = this.tool.getOptionBySuperClassId(type.getAssignToOptionId()); + + // Option? + if (option != null) { + try { + List inputs = new ArrayList<>(); + int optType = option.getValueType(); + if (optType == IOption.STRING) { + inputs.add(option.getStringValue()); + } else if (optType == IOption.STRING_LIST || optType == IOption.LIBRARIES + || optType == IOption.OBJECTS || optType == IOption.INCLUDE_FILES + || optType == IOption.LIBRARY_PATHS || optType == IOption.LIBRARY_FILES + || optType == IOption.MACRO_FILES) { + @SuppressWarnings("unchecked") + List valueList = (List) option.getValue(); + inputs = valueList; + this.tool.filterValues(optType, inputs); + this.tool.filterValues(optType, inputs); + } + for (int j = 0; j < inputs.size(); j++) { + String inputName = inputs.get(j); + + try { + // try to resolve the build macros in the output + // names + + String resolved = null; + + // does the input name contain spaces? + // TODO: support other special characters + if (inputName.indexOf(" ") != -1) //$NON-NLS-1$ + { + // resolve to string + resolved = ManagedBuildManager.getBuildMacroProvider().resolveValue(inputName, "", //$NON-NLS-1$ + " ", //$NON-NLS-1$ + IBuildMacroProvider.CONTEXT_OPTION, + new OptionContextData(option, this.tool)); + } else { + + // resolve to makefile variable format + resolved = ManagedBuildManager.getBuildMacroProvider().resolveValueToMakefileFormat( + inputName, "", //$NON-NLS-1$ + " ", //$NON-NLS-1$ + IBuildMacroProvider.CONTEXT_OPTION, + new OptionContextData(option, this.tool)); + } + + if ((resolved = resolved.trim()).length() > 0) + inputName = resolved; + } catch (BuildMacroException e) {// JABA is not + // going to add + // code + } + + if (primaryInput) { + itCommandDependencies.add(j, inputName); + } else { + itCommandDependencies.add(inputName); + } + // NO - itCommandInputs.add(inputName); + // NO - itEnumeratedInputs.add(inputName); + } + } catch (BuildException ex) {// JABA is not going to add + // code + } + + } else { + + // Build Variable? + if (variable.length() > 0) { + String cmdVariable = variable = "$(" + variable + ")"; //$NON-NLS-1$ //$NON-NLS-2$ + itCommandInputs.add(cmdVariable); + if (primaryInput) { + itCommandDependencies.add(0, cmdVariable); + } else { + itCommandDependencies.add(cmdVariable); + } + // If there is an output variable with the same name, + // get + // the files associated with it. + List outMacroList = makeGen.getBuildVariableList(h, variable, PROJECT_RELATIVE, null, + true); + if (outMacroList != null) { + itEnumeratedInputs.addAll(outMacroList); + } else { + // If "last chance", then calculate using file + // extensions below + if (lastChance) { + useFileExts = true; + } else { + done = false; + break; + } + } + } + + // Use file extensions + if (variable.length() == 0 || useFileExts) { + // if (type.getMultipleOfType()) { + // Calculate EnumeratedInputs using the file extensions + // and the resources in the project + // Note: This is only correct for tools with + // multipleOfType == true, but for other tools + // it gives us an input resource for generating default + // names + // Determine the set of source input macros to use + HashSet handledInputExtensions = new HashSet<>(); + String[] exts = type.getSourceExtensions(this.tool); + if (projResources != null) { + for (IResource rc : projResources) { + if (rc.getType() == IResource.FILE) { + String fileExt = rc.getFileExtension(); + + // fix for NPE, bugzilla 99483 + if (fileExt == null) { + fileExt = ""; //$NON-NLS-1$ + } + + for (int k = 0; k < exts.length; k++) { + if (fileExt.equals(exts[k])) { + if (!useFileExts) { + if (!handledInputExtensions.contains(fileExt)) { + handledInputExtensions.add(fileExt); + String buildMacro = "$(" //$NON-NLS-1$ + + getSourceMacroName(fileExt).toString() + ")"; //$NON-NLS-1$ + itCommandInputs.add(buildMacro); + if (primaryInput) { + itCommandDependencies.add(0, buildMacro); + } else { + itCommandDependencies.add(buildMacro); + } + } + } + if (type.getMultipleOfType() || itEnumeratedInputs.size() == 0) { + // Add a path that is relative + // to the project directory + itEnumeratedInputs.add(rc.getProjectRelativePath().toOSString()); + } + break; + } + } + } + } + } + // } + } + } + + // Get any additional inputs specified in the manifest file or + // the project file + IAdditionalInput[] addlInputs = type.getAdditionalInputs(); + if (addlInputs != null) { + for (int j = 0; j < addlInputs.length; j++) { + IAdditionalInput addlInput = addlInputs[j]; + int kind = addlInput.getKind(); + if (kind == IAdditionalInput.KIND_ADDITIONAL_INPUT + || kind == IAdditionalInput.KIND_ADDITIONAL_INPUT_DEPENDENCY) { + String[] paths = addlInput.getPaths(); + if (paths != null) { + for (int k = 0; k < paths.length; k++) { + String path = paths[k]; + itEnumeratedInputs.add(path); + // Translate the path from project relative + // to build directory relative + if (!(path.startsWith("$("))) { //$NON-NLS-1$ + IResource addlResource = this.project.getFile(path); + if (addlResource != null) { + IPath addlPath = addlResource.getLocation(); + if (addlPath != null) { + path = ManagedBuildManager + .calculateRelativePath(makeGen.getTopBuildDir(), addlPath) + .toOSString(); + } + } + } + itCommandInputs.add(path); + } + } + } + } + } + + // If the assignToOption attribute is specified, set the + // input(s) as the value of that option + if (assignToOption != null && option == null) { + try { + int optType = assignToOption.getValueType(); + if (optType == IOption.STRING) { + String optVal = ""; //$NON-NLS-1$ + for (int j = 0; j < itCommandInputs.size(); j++) { + if (j != 0) { + optVal += " "; //$NON-NLS-1$ + } + optVal += itCommandInputs.get(j); + } + ManagedBuildManager.setOption(config, this.tool, assignToOption, optVal); + } else if (optType == IOption.STRING_LIST || optType == IOption.LIBRARIES + || optType == IOption.OBJECTS || optType == IOption.INCLUDE_FILES + || optType == IOption.LIBRARY_PATHS || optType == IOption.LIBRARY_FILES + || optType == IOption.MACRO_FILES) { + // TODO: do we need to do anything with undefs here? + // Mote that when using the enumerated inputs, the + // path(s) must be translated from project relative + // to top build directory relative + String[] paths = new String[itEnumeratedInputs.size()]; + for (int j = 0; j < itEnumeratedInputs.size(); j++) { + paths[j] = itEnumeratedInputs.get(j); + IResource enumResource = this.project.getFile(paths[j]); + if (enumResource != null) { + IPath enumPath = enumResource.getLocation(); + if (enumPath != null) { + paths[j] = ManagedBuildManager + .calculateRelativePath(makeGen.getTopBuildDir(), enumPath).toOSString(); + } + } + } + ManagedBuildManager.setOption(config, this.tool, assignToOption, paths); + } else if (optType == IOption.BOOLEAN) { + if (itEnumeratedInputs.size() > 0) { + ManagedBuildManager.setOption(config, this.tool, assignToOption, true); + } else { + ManagedBuildManager.setOption(config, this.tool, assignToOption, false); + } + } else if (optType == IOption.ENUMERATED || optType == IOption.TREE) { + if (itCommandInputs.size() > 0) { + ManagedBuildManager.setOption(config, this.tool, assignToOption, + itCommandInputs.firstElement()); + } + } + itCommandInputs.removeAllElements(); + // itEnumeratedInputs.removeAllElements(); + } catch (BuildException ex) {// JABA is not going to add + // code + } + } + + myCommandInputs.addAll(itCommandInputs); + myCommandDependencies.addAll(itCommandDependencies); + myEnumeratedInputs.addAll(itEnumeratedInputs); + } + } else { + // For support of pre-CDT 3.0 integrations. + if (this.bIsTargetTool) { + // NOTE WELL: This only supports the case of a single + // "target tool" + // with the following characteristics: + // 1. The tool consumes exactly all of the object files produced + // by other tools in the build and produces a single output + // 2. The target name comes from the configuration artifact name + // The rule looks like: + // .: $(OBJS) + myCommandInputs.add("$(OBJS)"); //$NON-NLS-1$ + myCommandInputs.add("$(USER_OBJS)"); //$NON-NLS-1$ + myCommandInputs.add("$(LIBS)"); //$NON-NLS-1$ + } else { + // Rule will be generated by addRuleForSource + } + } + + if (done) { + this.commandInputs.addAll(myCommandInputs); + this.commandDependencies.addAll(0, myCommandDependencies); + this.enumeratedInputs.addAll(myEnumeratedInputs); + this.inputsCalculated = true; + return true; + } + + return false; + } + + /* + * The priorities for determining the names of the outputs of a tool are: 1. + * If the tool is the build target and primary output, use artifact name & + * extension 2. If an option is specified, use the value of the option 3. If + * a nameProvider is specified, call it 4. If outputNames is specified, use + * it 5. Use the name pattern to generate a transformation macro so that the + * source names can be transformed into the target names using the built-in + * string substitution functions of make. + * + * NOTE: If an option is not specified and this is not the primary output + * type, the outputs from the type are not added to the command line + */ + public boolean calculateOutputs(ArduinoGnuMakefileGenerator makeGen, IConfiguration config, + HashSet handledInputExtensions, boolean lastChance) { + + boolean done = true; + List myCommandOutputs = new LinkedList<>(); + List myEnumeratedOutputs = new LinkedList<>(); + HashMap> myOutputMacros = new HashMap<>(); + // The next two fields are used together + List myBuildVars = new LinkedList<>(); + List> myBuildVarsValues = new LinkedList<>(); + + // Get the outputs for this tool invocation + IOutputType[] outTypes = this.tool.getOutputTypes(); + if (outTypes != null && outTypes.length > 0) { + for (int i = 0; i < outTypes.length; i++) { + List typeEnumeratedOutputs = new LinkedList<>(); + IOutputType type = outTypes[i]; + String outputPrefix = type.getOutputPrefix(); + + // Resolve any macros in the outputPrefix + // Note that we cannot use file macros because if we do a clean + // we need to know the actual name of the file to clean, and + // cannot use any builder variables such as $@. Hence we use the + // next best thing, i.e. configuration context. + + if (config != null) { + + try { + outputPrefix = ManagedBuildManager.getBuildMacroProvider().resolveValueToMakefileFormat( + outputPrefix, "", //$NON-NLS-1$ + " ", //$NON-NLS-1$ + IBuildMacroProvider.CONTEXT_CONFIGURATION, config); + } + + catch (BuildMacroException e) {// JABA is not going to add + // code + } + } + + String variable = type.getBuildVariable(); + boolean multOfType = type.getMultipleOfType(); + IOption option = this.tool.getOptionBySuperClassId(type.getOptionId()); + IManagedOutputNameProviderJaba nameProvider = getJABANameProvider(type); + String[] outputNames = type.getOutputNames(); + + // 1. If the tool is the build target and this is the primary + // output, + // use artifact name & extension + if (this.bIsTargetTool) { + String outputName = outputPrefix + this.targetName; + if (this.targetExt.length() > 0) { + outputName += (DOT + this.targetExt); + } + myCommandOutputs.add(outputName); + typeEnumeratedOutputs.add(outputName); + // But this doesn't use any output macro... + } else + // 2. If an option is specified, use the value of the option + if (option != null) { + try { + List outputs = new ArrayList<>(); + int optType = option.getValueType(); + if (optType == IOption.STRING) { + outputs.add(outputPrefix + option.getStringValue()); + } else if (optType == IOption.STRING_LIST || optType == IOption.LIBRARIES + || optType == IOption.OBJECTS || optType == IOption.INCLUDE_FILES + || optType == IOption.LIBRARY_PATHS || optType == IOption.LIBRARY_FILES + || optType == IOption.MACRO_FILES) { + @SuppressWarnings("unchecked") + List value = (List) option.getValue(); + outputs = value; + this.tool.filterValues(optType, outputs); + // Add outputPrefix to each if necessary + if (outputPrefix.length() > 0) { + for (int j = 0; j < outputs.size(); j++) { + outputs.set(j, outputPrefix + outputs.get(j)); + } + } + } + for (int j = 0; j < outputs.size(); j++) { + String outputName = outputs.get(j); + try { + // try to resolve the build macros in the output + // names + String resolved = ManagedBuildManager.getBuildMacroProvider() + .resolveValueToMakefileFormat(outputName, "", //$NON-NLS-1$ + " ", //$NON-NLS-1$ + IBuildMacroProvider.CONTEXT_OPTION, + new OptionContextData(option, this.tool)); + if ((resolved = resolved.trim()).length() > 0) + outputs.set(j, resolved); + } catch (BuildMacroException e) {// JABA is not + // going to add + // code + } + } + + // NO - myCommandOutputs.addAll(outputs); + typeEnumeratedOutputs.addAll(outputs); + if (variable.length() > 0) { + List outputPaths = new ArrayList<>(); + for (int j = 0; j < outputs.size(); j++) { + outputPaths.add(Path.fromOSString(outputs.get(j))); + } + if (myOutputMacros.containsKey(variable)) { + List currList = myOutputMacros.get(variable); + currList.addAll(outputPaths); + myOutputMacros.put(variable, currList); + } else { + myOutputMacros.put(variable, outputPaths); + } + } + } catch (BuildException ex) {// JABA is not going to add + // code + } + } else + // 3. If a nameProvider is specified, call it + if (nameProvider != null) { + // The inputs must have been calculated before we can do + // this + List outNames = new LinkedList<>(); + if (!this.inputsCalculated) { + done = false; + } else { + for (String curInput : getEnumeratedInputs()) { + outNames.add(nameProvider.getOutputName(project, config, tool, new Path(curInput))); + } + typeEnumeratedOutputs.addAll(resolvePaths(outNames, config)); + } + if (variable.length() > 0 && outNames != null) { + if (myOutputMacros.containsKey(variable)) { + List currList = myOutputMacros.get(variable); + currList.addAll(outNames); + myOutputMacros.put(variable, currList); + } else { + myOutputMacros.put(variable, outNames); + } + } + } else + // 4. If outputNames is specified, use it + if (outputNames != null) { + if (outputNames.length > 0) { + for (int j = 0; j < outputNames.length; j++) { + String outputName = outputNames[j]; + try { + // try to resolve the build macros in the output + // names + String resolved = ManagedBuildManager.getBuildMacroProvider() + .resolveValueToMakefileFormat(outputName, "", //$NON-NLS-1$ + " ", //$NON-NLS-1$ + IBuildMacroProvider.CONTEXT_OPTION, + new OptionContextData(option, this.tool)); + if ((resolved = resolved.trim()).length() > 0) + outputNames[j] = resolved; + } catch (BuildMacroException e) {// JABA is not + // going to add + // code + } + } + List namesList = Arrays.asList(outputNames); + typeEnumeratedOutputs.addAll(namesList); + if (variable.length() > 0) { + List outputPaths = new ArrayList<>(); + for (int j = 0; j < namesList.size(); j++) { + outputPaths.add(Path.fromOSString(namesList.get(j))); + } + if (myOutputMacros.containsKey(variable)) { + List currList = myOutputMacros.get(variable); + currList.addAll(outputPaths); + myOutputMacros.put(variable, currList); + } else { + myOutputMacros.put(variable, outputPaths); + } + } + } + } else { + // 5. Use the name pattern to generate a transformation + // macro + // so that the source names can be transformed into the + // target names + // using the built-in string substitution functions of + // make. + if (multOfType) { + // This case is not handled - a nameProvider or + // outputNames must be specified + List errList = new ArrayList<>(); + errList.add(ManagedMakeMessages.getResourceString("MakefileGenerator.error.no.nameprovider")); //$NON-NLS-1$ + myCommandOutputs.addAll(errList); + } else { + String namePattern = type.getNamePattern(); + if (namePattern == null || namePattern.length() == 0) { + namePattern = outputPrefix + IManagedBuilderMakefileGenerator.WILDCARD; + String outExt = (type.getOutputExtensions(this.tool))[0]; + if (outExt != null && outExt.length() > 0) { + namePattern += DOT + outExt; + } + } else if (outputPrefix.length() > 0) { + namePattern = outputPrefix + namePattern; + } + + // Calculate the output name + // The inputs must have been calculated before we can do + // this + if (!this.inputsCalculated) { + done = false; + } else { + Vector inputs = getEnumeratedInputs(); + String fileName; + if (inputs.size() > 0) { + // Get the input file name + fileName = (Path.fromOSString(inputs.get(0))).removeFileExtension().lastSegment(); + // Check if this is a build macro. If so, use + // the raw macro name. + if (fileName.startsWith("$(") && fileName.endsWith(")")) { //$NON-NLS-1$ //$NON-NLS-2$ + fileName = fileName.substring(2, fileName.length() - 1); + } + } else { + fileName = "default"; //$NON-NLS-1$ + } + // Replace the % with the file name + typeEnumeratedOutputs.add(namePattern.replace("%", fileName)); //$NON-NLS-1$ + if (variable.length() > 0) { + List outputs = new ArrayList<>(); + outputs.add(Path.fromOSString(fileName)); + if (myOutputMacros.containsKey(variable)) { + List currList = myOutputMacros.get(variable); + currList.addAll(outputs); + myOutputMacros.put(variable, currList); + } else { + myOutputMacros.put(variable, outputs); + } + } + } + } + } + if (variable.length() > 0) { + myBuildVars.add(variable); + myBuildVarsValues.add(typeEnumeratedOutputs); + } + myEnumeratedOutputs.addAll(typeEnumeratedOutputs); + } + } else + + { + if (this.bIsTargetTool) { + String outputPrefix = this.tool.getOutputPrefix(); + String outputName = outputPrefix + this.targetName; + if (this.targetExt.length() > 0) { + outputName += (DOT + this.targetExt); + } + myCommandOutputs.add(outputName); + myEnumeratedOutputs.add(outputName); + } else { + // For support of pre-CDT 3.0 integrations. + // NOTE WELL: This only supports the case of a single + // "target tool" + // that consumes exactly all of the object files, $OBJS, + // produced + // by other tools in the build and produces a single output + } + } + + // Add the output macros of this tool to the buildOutVars map + Set>> entrySet = myOutputMacros.entrySet(); + for (Entry> entry : entrySet) { + String macroName = entry.getKey(); + List newMacroValue = entry.getValue(); + Map> map = makeGen.getBuildOutputVars(); + if (map.containsKey(macroName)) { + List macroValue = map.get(macroName); + macroValue.addAll(newMacroValue); + map.put(macroName, macroValue); + } else { + map.put(macroName, newMacroValue); + } + } + this.outputVariablesCalculated = true; + + if (done) { + this.commandOutputs.addAll(myCommandOutputs); + this.enumeratedPrimaryOutputs.addAll(myEnumeratedOutputs); + this.enumeratedSecondaryOutputs.addAll(myEnumeratedOutputs); + this.outputVariables.addAll(myOutputMacros.keySet()); + this.outputsCalculated = true; + for (int i = 0; i < myBuildVars.size(); i++) { + makeGen.addMacroAdditionFiles(makeGen.getTopBuildOutputVars(), myBuildVars.get(i), + myBuildVarsValues.get(i)); + } + return true; + } + + return false; + } + + private boolean callDependencyCalculator(ArduinoGnuMakefileGenerator makeGen, IConfiguration config, + HashSet handledInputExtensions, IManagedDependencyGeneratorType depGen, String[] extensionsList, + Vector myCommandDependencies, HashMap> myOutputMacros, + Vector myAdditionalTargets, ToolInfoHolder h, boolean _done) { + boolean done = _done; + int calcType = depGen.getCalculatorType(); + switch (calcType) { + case IManagedDependencyGeneratorType.TYPE_COMMAND: + case IManagedDependencyGeneratorType.TYPE_BUILD_COMMANDS: + // iterate over all extensions that the tool knows how to handle + for (int i = 0; i < extensionsList.length; i++) { + String extensionName = extensionsList[i]; + + // Generated files should not appear in the list. + if (!makeGen.getOutputExtensions(h).contains(extensionName) + && !handledInputExtensions.contains(extensionName)) { + handledInputExtensions.add(extensionName); + String depExt = IManagedBuilderMakefileGenerator.DEP_EXT; + if (calcType == IManagedDependencyGeneratorType.TYPE_BUILD_COMMANDS) { + IManagedDependencyGenerator2 depGen2 = (IManagedDependencyGenerator2) depGen; + String xt = depGen2.getDependencyFileExtension(config, this.tool); + if (xt != null && xt.length() > 0) + depExt = xt; + } + String depsMacroEntry = calculateSourceMacro(makeGen, extensionName, depExt, + IManagedBuilderMakefileGenerator.WILDCARD); + + List depsList = new ArrayList<>(); + depsList.add(Path.fromOSString(depsMacroEntry)); + String depsMacro = getDepMacroName(extensionName).toString(); + if (myOutputMacros.containsKey(depsMacro)) { + List currList = myOutputMacros.get(depsMacro); + currList.addAll(depsList); + myOutputMacros.put(depsMacro, currList); + } else { + myOutputMacros.put(depsMacro, depsList); + } + } + } + break; + + case IManagedDependencyGeneratorType.TYPE_INDEXER: + case IManagedDependencyGeneratorType.TYPE_EXTERNAL: + case IManagedDependencyGeneratorType.TYPE_CUSTOM: + // The inputs must have been calculated before we can do this + if (!this.inputsCalculated) { + done = false; + } else { + Vector inputs = getEnumeratedInputs(); + + if (calcType == IManagedDependencyGeneratorType.TYPE_CUSTOM) { + IManagedDependencyGenerator2 depGen2 = (IManagedDependencyGenerator2) depGen; + IManagedDependencyInfo depInfo = null; + for (int i = 0; i < inputs.size(); i++) { + + depInfo = depGen2.getDependencySourceInfo(Path.fromOSString(inputs.get(i)), config, this.tool, + makeGen.getBuildWorkingDir()); + + if (depInfo instanceof IManagedDependencyCalculator) { + IManagedDependencyCalculator depCalc = (IManagedDependencyCalculator) depInfo; + IPath[] depPaths = depCalc.getDependencies(); + if (depPaths != null) { + for (int j = 0; j < depPaths.length; j++) { + if (!depPaths[j].isAbsolute()) { + // Convert from project relative to + // build directory relative + IPath absolutePath = this.project.getLocation().append(depPaths[j]); + depPaths[j] = ManagedBuildManager + .calculateRelativePath(makeGen.getTopBuildDir(), absolutePath); + } + myCommandDependencies.add(depPaths[j].toOSString()); + } + } + IPath[] targetPaths = depCalc.getAdditionalTargets(); + if (targetPaths != null) { + for (int j = 0; j < targetPaths.length; j++) { + myAdditionalTargets.add(targetPaths[j].toOSString()); + } + } + } + } + } else { + IManagedDependencyGenerator oldDepGen = (IManagedDependencyGenerator) depGen; + for (String input : inputs) { + IResource[] outNames = oldDepGen.findDependencies(this.project.getFile(input), this.project); + if (outNames != null) { + for (IResource outName : outNames) { + myCommandDependencies.add(outName.toString()); + } + } + } + } + } + break; + + default: + break; + } + + return done; + } + + /** + * @param lastChance + */ + public boolean calculateDependencies(ArduinoGnuMakefileGenerator makeGen, IConfiguration config, + HashSet handledInputExtensions, ToolInfoHolder h, boolean lastChance) { + // Get the dependencies for this tool invocation + boolean done = true; + Vector myCommandDependencies = new Vector<>(); + Vector myAdditionalTargets = new Vector<>(); + // Vector myEnumeratedDependencies = new Vector(); + HashMap> myOutputMacros = new HashMap<>(); + + IInputType[] inTypes = this.tool.getInputTypes(); + if (inTypes != null && inTypes.length > 0) { + for (int i = 0; i < inTypes.length; i++) { + IInputType type = inTypes[i]; + + // Handle dependencies from the dependencyCalculator + IManagedDependencyGeneratorType depGen = type.getDependencyGenerator(); + String[] extensionsList = type.getSourceExtensions(this.tool); + if (depGen != null) { + done = callDependencyCalculator(makeGen, config, handledInputExtensions, depGen, extensionsList, + myCommandDependencies, myOutputMacros, myAdditionalTargets, h, done); + } + + // Add additional dependencies specified in AdditionalInput + // elements + IAdditionalInput[] addlInputs = type.getAdditionalInputs(); + if (addlInputs != null && addlInputs.length > 0) { + for (int j = 0; j < addlInputs.length; j++) { + IAdditionalInput addlInput = addlInputs[j]; + int kind = addlInput.getKind(); + if (kind == IAdditionalInput.KIND_ADDITIONAL_DEPENDENCY + || kind == IAdditionalInput.KIND_ADDITIONAL_INPUT_DEPENDENCY) { + String[] paths = addlInput.getPaths(); + if (paths != null) { + for (int k = 0; k < paths.length; k++) { + // Translate the path from project relative + // to + // build directory relative + String path = paths[k]; + if (!(path.startsWith("$("))) { //$NON-NLS-1$ + IResource addlResource = this.project.getFile(path); + if (addlResource != null) { + IPath addlPath = addlResource.getLocation(); + if (addlPath != null) { + path = ManagedBuildManager + .calculateRelativePath(makeGen.getTopBuildDir(), addlPath) + .toOSString(); + } + } + } + myCommandDependencies.add(path); + // myEnumeratedInputs.add(path); + } + } + } + } + } + } + } else { + if (this.bIsTargetTool) { + // For support of pre-CDT 3.0 integrations. + // NOTE WELL: This only supports the case of a single + // "target tool" + // with the following characteristics: + // 1. The tool consumes exactly all of the object files produced + // by other tools in the build and produces a single output + // 2. The target name comes from the configuration artifact name + // The rule looks like: + // .: $(OBJS) + myCommandDependencies.add("$(OBJS)"); //$NON-NLS-1$ + myCommandDependencies.add("$(USER_OBJS)"); //$NON-NLS-1$ + } else { + // Handle dependencies from the dependencyCalculator + IManagedDependencyGeneratorType depGen = this.tool.getDependencyGenerator(); + String[] extensionsList = this.tool.getAllInputExtensions(); + if (depGen != null) { + done = callDependencyCalculator(makeGen, config, handledInputExtensions, depGen, extensionsList, + myCommandDependencies, myOutputMacros, myAdditionalTargets, h, done); + } + + } + } + + // Add the output macros of this tool to the buildOutVars map + Set>> entrySet = myOutputMacros.entrySet(); + for (Entry> entry : entrySet) { + String macroName = entry.getKey(); + List newMacroValue = entry.getValue(); + Map> map = makeGen.getBuildOutputVars(); + if (map.containsKey(macroName)) { + List macroValue = map.get(macroName); + macroValue.addAll(newMacroValue); + map.put(macroName, macroValue); + } else { + map.put(macroName, newMacroValue); + } + } + + if (done) { + this.commandDependencies.addAll(myCommandDependencies); + this.additionalTargets.addAll(myAdditionalTargets); + // enumeratedDependencies.addAll(myEnumeratedDependencies); + this.dependenciesCalculated = true; + return true; + } + + return false; + } + + /* + * Calculate the source macro for the given extension + */ + protected String calculateSourceMacro(ArduinoGnuMakefileGenerator makeGen, String srcExtensionName, + String outExtensionName, String wildcard) { + StringBuffer macroName = getSourceMacroName(srcExtensionName); + String OptDotExt = ""; //$NON-NLS-1$ + if (outExtensionName != null) { + OptDotExt = DOT + outExtensionName; + } else if (this.tool.getOutputExtension(srcExtensionName) != "") //$NON-NLS-1$ + OptDotExt = DOT + this.tool.getOutputExtension(srcExtensionName); + + // create rule of the form + // OBJS = $(macroName1: ../%.input1=%.output1) ... $(macroNameN: + // ../%.inputN=%.outputN) + StringBuffer objectsBuffer = new StringBuffer(); + objectsBuffer.append(IManagedBuilderMakefileGenerator.WHITESPACE + "$(" + macroName + //$NON-NLS-1$ + IManagedBuilderMakefileGenerator.COLON + IManagedBuilderMakefileGenerator.ROOT + + IManagedBuilderMakefileGenerator.SEPARATOR + IManagedBuilderMakefileGenerator.WILDCARD + DOT + + srcExtensionName + "=" + wildcard + OptDotExt + ")"); //$NON-NLS-1$ //$NON-NLS-2$ + return objectsBuffer.toString(); + } + + private void resolveStrings(List toResolve, IConfiguration config) { + if (toResolve.isEmpty()) + return; + for (String curOutput : toResolve) { + try { + // try to resolve the build macros in the + // output names + String resolved = ManagedBuildManager.getBuildMacroProvider().resolveValueToMakefileFormat(curOutput, + "", //$NON-NLS-1$ + " ", //$NON-NLS-1$ + IBuildMacroProvider.CONTEXT_CONFIGURATION, config); + if ((resolved = resolved.trim()).length() > 0) { + toResolve.remove(curOutput); + toResolve.add(resolved); + } + } catch (BuildMacroException e) { + //If we can not resolve we keep the original + } + } + } + +} \ No newline at end of file diff --git a/io.sloeber.core/src/io/sloeber/managedBuild/Internal/LinkNameProvider.java b/io.sloeber.core/src/io/sloeber/managedBuild/Internal/LinkNameProvider.java new file mode 100644 index 000000000..12d6fa6d2 --- /dev/null +++ b/io.sloeber.core/src/io/sloeber/managedBuild/Internal/LinkNameProvider.java @@ -0,0 +1,35 @@ +package io.sloeber.managedBuild.Internal; + +import org.eclipse.cdt.managedbuilder.core.IConfiguration; +import org.eclipse.cdt.managedbuilder.core.ITool; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.runtime.IPath; + +import io.sloeber.core.common.Common; +import io.sloeber.core.common.Const; +import io.sloeber.core.tools.Helpers; +import io.sloeber.managedBuild.api.IManagedOutputNameProviderJaba; + +public class LinkNameProvider implements IManagedOutputNameProviderJaba { + + @Override + public IPath getOutputName(IProject project, IConfiguration cConf, ITool tool, IPath inputName) { + boolean bUseArchiver = Common + .getBuildEnvironmentVariable(project, cConf.getName(), Const.ENV_KEY_USE_ARCHIVER, Const.TRUE) + .equalsIgnoreCase(Const.TRUE); + if (inputName.toString().startsWith(Const.ARDUINO_CODE_FOLDER_PATH) && (bUseArchiver)) { + return null; + } + if (inputName.toString().endsWith(".ino")) { //$NON-NLS-1$ + return null; + } + if (inputName.toString().endsWith(".pde")) { //$NON-NLS-1$ + return null; + } + if (inputName.toString().endsWith(".cxx")) { //$NON-NLS-1$ + return null; + } + return Helpers.GetOutputName(inputName).addFileExtension("o"); //$NON-NLS-1$ + } + +} diff --git a/io.sloeber.core/src/io/sloeber/managedBuild/Internal/MakeRule.java b/io.sloeber.core/src/io/sloeber/managedBuild/Internal/MakeRule.java new file mode 100644 index 000000000..1d844521e --- /dev/null +++ b/io.sloeber.core/src/io/sloeber/managedBuild/Internal/MakeRule.java @@ -0,0 +1,58 @@ +package io.sloeber.managedBuild.Internal; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +import org.eclipse.core.runtime.IPath; + +public class MakeRule { + + Map> targets = new HashMap<>(); //Macro file target map + Map> prerequisites = new HashMap<>();//Macro file prerequisites map + List rules = new LinkedList<>(); + + public HashSet getMacros() { + HashSet ret = new HashSet<>(); + ret.addAll(targets.keySet()); + ret.addAll(prerequisites.keySet()); + return ret; + } + + public HashSet getMacroElements(String macroName) { + HashSet ret = new HashSet<>(); + List list = targets.get(macroName); + if (list != null) { + ret.addAll(list); + } + list = prerequisites.get(macroName); + if (list != null) { + ret.addAll(list); + } + return ret; + } + + public void addTarget(String Macro, IPath file) { + List files = targets.get(Macro); + if (files == null) { + files = new LinkedList<>(); + files.add(file); + targets.put(Macro, files); + } else { + files.add(file); + } + } + + public void addPrerequisite(String Macro, IPath file) { + List files = prerequisites.get(Macro); + if (files == null) { + files = new LinkedList<>(); + files.add(file); + prerequisites.put(Macro, files); + } else { + files.add(file); + } + } +} diff --git a/io.sloeber.core/src/io/sloeber/managedBuild/Internal/ManagebBuildCommon.java b/io.sloeber.core/src/io/sloeber/managedBuild/Internal/ManagebBuildCommon.java new file mode 100644 index 000000000..55ecf7965 --- /dev/null +++ b/io.sloeber.core/src/io/sloeber/managedBuild/Internal/ManagebBuildCommon.java @@ -0,0 +1,607 @@ +package io.sloeber.managedBuild.Internal; + +import static io.sloeber.managedBuild.Internal.ManagedBuildConstants.*; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.Reader; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Vector; + +import org.eclipse.cdt.core.CCorePlugin; +import org.eclipse.cdt.core.model.CoreModel; +import org.eclipse.cdt.core.settings.model.ICConfigurationDescription; +import org.eclipse.cdt.core.settings.model.ICProjectDescription; +import org.eclipse.cdt.managedbuilder.core.IConfiguration; +import org.eclipse.cdt.managedbuilder.core.IFolderInfo; +import org.eclipse.cdt.managedbuilder.core.IOutputType; +import org.eclipse.cdt.managedbuilder.core.IResourceInfo; +import org.eclipse.cdt.managedbuilder.core.ITool; +import org.eclipse.cdt.managedbuilder.core.ManagedBuildManager; +import org.eclipse.cdt.managedbuilder.internal.core.ManagedMakeMessages; +import org.eclipse.cdt.managedbuilder.internal.core.OutputType; +import org.eclipse.cdt.managedbuilder.macros.BuildMacroException; +import org.eclipse.cdt.managedbuilder.macros.IBuildMacroProvider; +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.IResourceStatus; +import org.eclipse.core.resources.IWorkspaceRoot; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IConfigurationElement; +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.NullProgressMonitor; +import org.eclipse.core.runtime.Path; + +import io.sloeber.core.common.Common; +import io.sloeber.managedBuild.api.IManagedOutputNameProviderJaba; + +@SuppressWarnings("nls") +public class ManagebBuildCommon { + /** + * Answers the argument with all whitespaces replaced with an escape sequence. + */ + static public String escapeWhitespaces(String path) { + // Escape the spaces in the path/filename if it has any + String[] segments = path.split("\\s"); + if (segments.length > 1) { + StringBuffer escapedPath = new StringBuffer(); + for (int index = 0; index < segments.length; ++index) { + escapedPath.append(segments[index]); + if (index + 1 < segments.length) { + escapedPath.append("\\ "); + } + } + return escapedPath.toString().trim(); + } + return path; + } + + /** + * Put COLS_PER_LINE comment charaters in the argument. + */ + static protected void outputCommentLine(StringBuffer buffer) { + for (int i = 0; i < COLS_PER_LINE; i++) { + buffer.append(COMMENT_SYMBOL); + } + buffer.append(NEWLINE); + } + + static public boolean containsSpecialCharacters(String path) { + return path.matches(".*(\\s|[\\{\\}\\(\\)\\$\\@%=;]).*"); + } + + /** + * Generates a source macro name from a file extension + */ + static public StringBuffer getSourceMacroName(String extensionName) { + StringBuffer macroName = new StringBuffer(); + if (extensionName == null) { + return null; + } + // We need to handle case sensitivity in file extensions (e.g. .c vs + // .C), so if the + // extension was already upper case, tack on an "UPPER_" to the macro + // name. + // In theory this means there could be a conflict if you had for + // example, + // extensions .c_upper, and .C, but realistically speaking the chances + // of this are + // practically nil so it doesn't seem worth the hassle of generating a + // truly + // unique name. + if (extensionName.equals(extensionName.toUpperCase())) { + macroName.append(extensionName.toUpperCase()).append("_UPPER"); + } else { + // lower case... no need for "UPPER_" + macroName.append(extensionName.toUpperCase()); + } + macroName.append("_SRCS"); + return macroName; + } + + public static void save(StringBuffer buffer, IFile file) throws CoreException { + String encoding = null; + try { + encoding = file.getCharset(); + } catch (CoreException ce) { + // use no encoding + } + byte[] bytes = null; + if (encoding != null) { + try { + bytes = buffer.toString().getBytes(encoding); + } catch (Exception e) { + /* JABA is not going to write this code */ + } + } else { + bytes = buffer.toString().getBytes(); + } + ByteArrayInputStream stream = new ByteArrayInputStream(bytes); + // use a platform operation to update the resource contents + boolean force = true; + file.setContents(stream, force, false, null); + } + + /** + * Generates a generated dependency file macro name from a file extension + */ + + public static StringBuffer getDepMacroName(String extensionName) { + StringBuffer macroName = new StringBuffer(); + // We need to handle case sensitivity in file extensions (e.g. .c vs + // .C), so if the + // extension was already upper case, tack on an "UPPER_" to the macro + // name. + // In theory this means there could be a conflict if you had for + // example, + // extensions .c_upper, and .C, but realistically speaking the chances + // of this are + // practically nil so it doesn't seem worth the hassle of generating a + // truly + // unique name. + if (extensionName.equals(extensionName.toUpperCase())) { + macroName.append(extensionName.toUpperCase()).append("_UPPER"); + } else { + // lower case... no need for "UPPER_" + macroName.append(extensionName.toUpperCase()); + } + macroName.append("_DEPS"); + return macroName; + } + + /** + * This method postprocesses a .d file created by a build. It's main job is to + * add dummy targets for the header files dependencies. This prevents make from + * aborting the build if the header file does not exist. A secondary job is to + * work in tandem with the "echo" command that is used by some tool-chains in + * order to get the "targets" part of the dependency rule correct. This method + * adds a comment to the beginning of the dependency file which it checks for to + * determine if this dependency file has already been updated. + * + * @return a true if the dependency file is modified + */ + static public boolean populateDummyTargets(IConfiguration cfg, IFile makefile, boolean force) + throws CoreException, IOException { + return populateDummyTargets(cfg.getRootFolderInfo(), makefile, force); + } + + static public boolean populateDummyTargets(IResourceInfo rcInfo, IFile makefile, boolean force) + throws CoreException, IOException { + if (makefile == null || !makefile.exists()) + return false; + // Get the contents of the dependency file + InputStream contentStream = makefile.getContents(false); + StringBuffer inBuffer = null; + // JABA made sure thgere are no emory leaks + try (Reader in = new InputStreamReader(contentStream);) { + int chunkSize = contentStream.available(); + inBuffer = new StringBuffer(chunkSize); + char[] readBuffer = new char[chunkSize]; + int n = in.read(readBuffer); + while (n > 0) { + inBuffer.append(readBuffer); + n = in.read(readBuffer); + } + contentStream.close(); + in.close(); + } + // The rest of this operation is equally expensive, so + // if we are doing an incremental build, only update the + // files that do not have a comment + String inBufferString = inBuffer.toString(); + if (!force && inBufferString.startsWith(COMMENT_SYMBOL)) { + return false; + } + // Try to determine if this file already has dummy targets defined. + // If so, we will only add the comment. + String[] bufferLines = inBufferString.split("[\\r\\n]"); + for (String bufferLine : bufferLines) { + if (bufferLine.endsWith(":")) { + StringBuffer outBuffer = addDefaultHeader(); + outBuffer.append(inBuffer); + save(outBuffer, makefile); + return true; + } + } + // Reconstruct the buffer tokens into useful chunks of dependency + // information + Vector bufferTokens = new Vector(Arrays.asList(inBufferString.split("\\s"))); + Vector deps = new Vector(bufferTokens.size()); + Iterator tokenIter = bufferTokens.iterator(); + while (tokenIter.hasNext()) { + String token = tokenIter.next(); + if (token.lastIndexOf("\\") == token.length() - 1 && token.length() > 1) { + // This is escaped so keep adding to the token until we find the + // end + while (tokenIter.hasNext()) { + String nextToken = tokenIter.next(); + token += WHITESPACE + nextToken; + if (!nextToken.endsWith("\\")) { + break; + } + } + } + deps.add(token); + } + deps.trimToSize(); + // Now find the header file dependencies and make dummy targets for them + boolean save = false; + StringBuffer outBuffer = null; + // If we are doing an incremental build, only update the files that do + // not have a comment + String firstToken; + try { + firstToken = deps.get(0); + } catch (ArrayIndexOutOfBoundsException e) { + // This makes no sense so bail + return false; + } + // Put the generated comments in the output buffer + if (!firstToken.startsWith(COMMENT_SYMBOL)) { + outBuffer = addDefaultHeader(); + } else { + outBuffer = new StringBuffer(); + } + // Some echo implementations misbehave and put the -n and newline in the + // output + if (firstToken.startsWith("-n")) { + // Now let's parse: + // Win32 outputs -n '/.d /' + // POSIX outputs -n /.d / + // Get the dep file name + String secondToken; + try { + secondToken = deps.get(1); + } catch (ArrayIndexOutOfBoundsException e) { + secondToken = ""; + } + if (secondToken.startsWith("'")) { + // This is the Win32 implementation of echo (MinGW without MSYS) + outBuffer.append(secondToken.substring(1)).append(WHITESPACE); + } else { + outBuffer.append(secondToken).append(WHITESPACE); + } + // The relative path to the build goal comes next + String thirdToken; + try { + thirdToken = deps.get(2); + } catch (ArrayIndexOutOfBoundsException e) { + thirdToken = ""; + } + int lastIndex = thirdToken.lastIndexOf("'"); + if (lastIndex != -1) { + if (lastIndex == 0) { + outBuffer.append(WHITESPACE); + } else { + outBuffer.append(thirdToken.substring(0, lastIndex - 1)); + } + } else { + outBuffer.append(thirdToken); + } + // Followed by the target output by the compiler plus ':' + // If we see any empty tokens here, assume they are the result of + // a line feed output by "echo" and skip them + String fourthToken; + int nToken = 3; + try { + do { + fourthToken = deps.get(nToken++); + } while (fourthToken.length() == 0); + } catch (ArrayIndexOutOfBoundsException e) { + fourthToken = ""; + } + outBuffer.append(fourthToken).append(WHITESPACE); + // Followed by the actual dependencies + try { + for (String nextElement : deps) { + if (nextElement.endsWith("\\")) { + outBuffer.append(nextElement).append(NEWLINE).append(WHITESPACE); + } else { + outBuffer.append(nextElement).append(WHITESPACE); + } + } + } catch (IndexOutOfBoundsException e) { + /* JABA is not going to write this code */ + } + } else { + outBuffer.append(inBuffer); + } + outBuffer.append(NEWLINE); + save = true; + IFolderInfo fo = null; + if (rcInfo instanceof IFolderInfo) { + fo = (IFolderInfo) rcInfo; + } else { + IConfiguration c = rcInfo.getParent(); + fo = (IFolderInfo) c.getResourceInfo(rcInfo.getPath().removeLastSegments(1), false); + } + // Dummy targets to add to the makefile + for (String dummy : deps) { + IPath dep = new Path(dummy); + String extension = dep.getFileExtension(); + if (fo.isHeaderFile(extension)) { + /* + * The formatting here is : + */ + outBuffer.append(dummy).append(COLON).append(NEWLINE).append(NEWLINE); + } + } + // Write them out to the makefile + if (save) { + save(outBuffer, makefile); + return true; + } + return false; + } + + /** + * prepend all instanced of '\' or '"' with a backslash + * + * @return resulting string + */ + static public String escapedEcho(String string) { + String escapedString = string.replace("'", "'\"'\"'"); + return ECHO + WHITESPACE + SINGLE_QUOTE + escapedString + SINGLE_QUOTE + NEWLINE; + } + + static public String ECHO_BLANK_LINE = ECHO + WHITESPACE + SINGLE_QUOTE + WHITESPACE + SINGLE_QUOTE + NEWLINE; + + /** + * Outputs a comment formatted as follows: ##### ....... ##### # ##### ....... ##### + */ + static protected StringBuffer addDefaultHeader() { + StringBuffer buffer = new StringBuffer(); + outputCommentLine(buffer); + buffer.append(COMMENT_SYMBOL).append(WHITESPACE).append(ManagedMakeMessages.getResourceString(HEADER)) + .append(NEWLINE); + outputCommentLine(buffer); + buffer.append(NEWLINE); + return buffer; + } + + /** + * Strips outermost quotes of Strings of the form "a" and 'a' or returns the + * original string if the input is not of this form. + * + * @throws NullPointerException + * if path is null + * @return a String without the outermost quotes (if the input has them) + */ + public static String ensureUnquoted(String path) { + boolean doubleQuoted = path.startsWith("\"") && path.endsWith("\""); + boolean singleQuoted = path.startsWith("'") && path.endsWith("'"); + return doubleQuoted || singleQuoted ? path.substring(1, path.length() - 1) : path; + } + + public static List resolvePaths(List toResolve, IConfiguration config) { + List ret = new LinkedList<>(); + if (toResolve.isEmpty()) + return ret; + for (IPath curOutputPath : toResolve) { + try { + if (curOutputPath != null) { + String curOutput = curOutputPath.toOSString(); + // try to resolve the build macros in the + // output names + String resolved = ManagedBuildManager.getBuildMacroProvider().resolveValueToMakefileFormat( + curOutput, "", //$NON-NLS-1$ + " ", //$NON-NLS-1$ + IBuildMacroProvider.CONTEXT_CONFIGURATION, config); + if ((resolved = resolved.trim()).length() > 0) { + ret.add(resolved); + } else { + ret.add(curOutput); + } + } + } catch (BuildMacroException e) { + //If we can not resolve we keep the original + } + } + return ret; + } + + /** + * Return or create the folder needed for the build output. If we are creating + * the folder, set the derived bit to true so the CM system ignores the + * contents. If the resource exists, respect the existing derived setting. + */ + public static IPath createDirectory(IProject project, 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(project, 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; + } + // Make sure the folder is marked as derived so it is not added to + // CM + if (!folder.isDerived()) { + folder.setDerived(true, null); + } + } + return folder.getFullPath(); + } + + /** + * Return or create the makefile needed for the build. If we are creating the + * resource, set the derived bit to true so the CM system ignores the contents. + * If the resource exists, respect the existing derived setting. + */ + public static 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, new NullProgressMonitor()); + // Make sure the new file is marked as derived + if (!newFile.isDerived()) { + newFile.setDerived(true, null); + } + } 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; + } + return newFile; + } + + /** + * Adds a macro addition prefix to a map of macro names to entries. Entry + * prefixes look like: C_SRCS += \ ${addprefix $(ROOT)/, \ + */ + public static void addMacroAdditionPrefix(LinkedHashMap map, String macroName, String relativePath, + boolean addPrefix) { + // there is no entry in the map, so create a buffer for this macro + StringBuffer tempBuffer = new StringBuffer(); + tempBuffer.append(macroName).append(WHITESPACE).append(MACRO_ADDITION_PREFIX_SUFFIX); + if (addPrefix) { + tempBuffer.append(new Path(MACRO_ADDITION_ADDPREFIX_HEADER).append(relativePath) + .append(MACRO_ADDITION_ADDPREFIX_SUFFIX).toOSString()); + } + // have to store the buffer in String form as StringBuffer is not a + // sublcass of Object + map.put(macroName, tempBuffer.toString()); + } + + /** + * Gets a path for a resource by extracting the Path field from its location + * URI. + * + * @return IPath + * @since 6.0 + */ + + public static IPath getPathForResource(IResource resource) { + return new Path(resource.getLocationURI().getPath()); + } + + /** + * Adds a file to an entry in a map of macro names to entries. File additions + * look like: example.c, \ + */ + static public void addMacroAdditionFile(HashMap map, String macroName, String filename) { + StringBuffer buffer = new StringBuffer(); + buffer.append(map.get(macroName)); + filename = escapeWhitespaces(filename); + buffer.append(filename).append(WHITESPACE).append(LINEBREAK); + map.put(macroName, buffer.toString()); + } + + /** + * Adds a file to an entry in a map of macro names to entries. File additions + * look like: example.c, \ + */ + static public void addMacroAdditionFile(ArduinoGnuMakefileGenerator caller, HashMap map, + String macroName, String relativePath, IPath sourceLocation, boolean generatedSource) { + // Add the source file path to the makefile line that adds source files + // to the build variable + IProject project = caller.getProject(); + IPath buildWorkingDir = caller.getBuildWorkingDir(); + String srcName; + IPath projectLocation = getPathForResource(project); + IPath dirLocation = projectLocation; + if (generatedSource) { + dirLocation = dirLocation.append(caller.getBuildWorkingDir()); + } + if (dirLocation.isPrefixOf(sourceLocation)) { + IPath srcPath = sourceLocation.removeFirstSegments(dirLocation.segmentCount()).setDevice(null); + if (generatedSource) { + srcName = DOT_SLASH_PATH.append(srcPath).toOSString(); + } else { + srcName = ROOT + FILE_SEPARATOR + srcPath.toOSString(); + } + } else { + if (generatedSource && !sourceLocation.isAbsolute()) { + srcName = DOT_SLASH_PATH.append(relativePath).append(sourceLocation.lastSegment()).toOSString(); + } else { + // TODO: Should we use relative paths when possible (e.g., see + // MbsMacroSupplier.calculateRelPath) + srcName = sourceLocation.toOSString(); + } + } + addMacroAdditionFile(map, macroName, srcName); + } + + /** + * Process a String denoting a filepath in a way compatible for GNU Make rules, + * handling windows drive letters and whitespace appropriately. + *

+ *

+ * The context these paths appear in is on the right hand side of a rule header. + * i.e. + *

+ *

+ * target : dep1 dep2 dep3 + *

+ * + * @param path + * the String denoting the path to process + * @throws NullPointerException + * is path is null + * @return a suitable Make rule compatible path + */ + /* see https://bugs.eclipse.org/bugs/show_bug.cgi?id=129782 */ + static public String ensurePathIsGNUMakeTargetRuleCompatibleSyntax(String path) { + return escapeWhitespaces(ensureUnquoted(path)); + } + + static public String getToolCommandLinePattern(IConfiguration config, ITool tool) { + IProject project = config.getOwner().getProject(); + String orgPattern = tool.getCommandLinePattern(); + if (orgPattern.contains("$")) { + //if the pattern contains a space no use to try to expand it + return orgPattern; + } + ICProjectDescription prjDesc = CoreModel.getDefault().getProjectDescription(project); + ICConfigurationDescription confDesc = prjDesc.getConfigurationByName(config.getName()); + return Common.getBuildEnvironmentVariable(confDesc, orgPattern, orgPattern, false); + + } + + static public IManagedOutputNameProviderJaba getJABANameProvider(IOutputType iType) { + OutputType type = (OutputType) iType; + IConfigurationElement element = type.getNameProviderElement(); + if (element != null) { + try { + if (element.getAttribute(IOutputType.NAME_PROVIDER) != null) { + return (IManagedOutputNameProviderJaba) element + .createExecutableExtension(IOutputType.NAME_PROVIDER); + } + } catch (CoreException e) { + //ignore errors + } + } + return null; + } +} diff --git a/io.sloeber.core/src/io/sloeber/managedBuild/Internal/ManagedBuildConstants.java b/io.sloeber.core/src/io/sloeber/managedBuild/Internal/ManagedBuildConstants.java new file mode 100644 index 000000000..354ea0b83 --- /dev/null +++ b/io.sloeber.core/src/io/sloeber/managedBuild/Internal/ManagedBuildConstants.java @@ -0,0 +1,84 @@ +package io.sloeber.managedBuild.Internal; + +import java.io.File; + +import org.eclipse.cdt.managedbuilder.internal.core.ManagedMakeMessages; +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.Path; + +@SuppressWarnings("nls") +public class ManagedBuildConstants { + public static final String AT = "@"; + public static final String COLON = ":"; + public static final int COLS_PER_LINE = 80; + public static final String COMMENT_SYMBOL = "#"; + public static final String DOLLAR_SYMBOL = "$"; + public static final String DEP_EXT = "d"; + public static final String DEPFILE_NAME = "subdir.dep"; + public static final String DOT = "."; + public static final String DASH = "-"; + public static final String ECHO = "echo"; + public static final String IN_MACRO = "$<"; + public static final String LINEBREAK = "\\\n"; + public static final String LOGICAL_AND = "&&"; + public static final String MAKEFILE_DEFS = "makefile.defs"; + public static final String MAKEFILE_INIT = "makefile.init"; + public static final String MAKEFILE_NAME = "makefile"; + public static final String MAKEFILE_TARGETS = "makefile.targets"; + public static final String MAKE = "$(MAKE)"; + public static final String NO_PRINT_DIR = "--no-print-directory"; + + public static final String MODFILE_NAME = "subdir.mk"; + public static final String NEWLINE = System.getProperty("line.separator"); + public static final String OBJECTS_MAKFILE = "objects.mk"; + public static final String OUT_MACRO = "$@"; + public static final String ROOT = ".."; + public static final String SEPARATOR = "/"; + public static final String SINGLE_QUOTE = "'"; + public static final String SRCSFILE_NAME = "sources.mk"; + public static final String TAB = "\t"; + public static final String WHITESPACE = " "; + public static final String WILDCARD = "%"; + + // String constants for makefile contents and messages + public static final String COMMENT = "MakefileGenerator.comment"; + public static final String HEADER = COMMENT + ".header"; + public static final String MESSAGE_FINISH_BUILD = ManagedMakeMessages + .getResourceString("MakefileGenerator.message.finish.build"); + public static final String MESSAGE_FINISH_FILE = ManagedMakeMessages + .getResourceString("MakefileGenerator.message.finish.file"); + public static final String MESSAGE_START_BUILD = ManagedMakeMessages + .getResourceString("MakefileGenerator.message.start.build"); + public static final String MESSAGE_START_FILE = ManagedMakeMessages + .getResourceString("MakefileGenerator.message.start.file"); + public static final String MESSAGE_START_DEPENDENCY = ManagedMakeMessages + .getResourceString("MakefileGenerator.message.start.dependency"); + public static final String MESSAGE_NO_TARGET_TOOL = ManagedMakeMessages + .getResourceString("MakefileGenerator.message.no.target"); + + public static final String MOD_LIST = COMMENT + ".module.list"; + public static final String MOD_LIST_MESSAGE = ManagedMakeMessages.getResourceString(MOD_LIST); + public static final String MOD_VARS = COMMENT + ".module.variables"; + public static final String MOD_RULES = COMMENT + ".build.rule"; + public static final String BUILD_TOP = COMMENT + ".build.toprules"; + public static final String ALL_TARGET = COMMENT + ".build.alltarget"; + public static final String MAINBUILD_TARGET = COMMENT + ".build.mainbuildtarget"; + public static final String BUILD_TARGETS = COMMENT + ".build.toptargets"; + public static final String SRC_LISTS = COMMENT + ".source.list"; + public static final String EMPTY_STRING = ""; + public static final String[] EMPTY_STRING_ARRAY = new String[0]; + public static final String OBJS_MACRO = "OBJS"; + public static final String MACRO_ADDITION_ADDPREFIX_HEADER = "${addprefix "; + public static final String MACRO_ADDITION_ADDPREFIX_SUFFIX = "," + WHITESPACE + LINEBREAK; + public static final String MACRO_ADDITION_PREFIX_SUFFIX = "+=" + WHITESPACE + LINEBREAK; + public static final String PREBUILD = "pre-build"; + public static final String MAINBUILD = "main-build"; + public static final String POSTBUILD = "post-build"; + public static final String SECONDARY_OUTPUTS = "secondary-outputs"; + + public static final IPath DOT_SLASH_PATH = new Path("./"); + public static final String FILE_SEPARATOR = File.separator; + // Enumerations + public static final int PROJECT_RELATIVE = 1, PROJECT_SUBDIR_RELATIVE = 2, ABSOLUTE = 3; + +} diff --git a/io.sloeber.core/src/io/sloeber/managedBuild/Internal/SrcMakeGenerator.java b/io.sloeber.core/src/io/sloeber/managedBuild/Internal/SrcMakeGenerator.java new file mode 100644 index 000000000..38da7eb54 --- /dev/null +++ b/io.sloeber.core/src/io/sloeber/managedBuild/Internal/SrcMakeGenerator.java @@ -0,0 +1,146 @@ +package io.sloeber.managedBuild.Internal; + +import static io.sloeber.managedBuild.Internal.ManagebBuildCommon.*; +import static io.sloeber.managedBuild.Internal.ManagedBuildConstants.*; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashSet; +import java.util.List; +import java.util.Map.Entry; +import java.util.Set; + +import org.eclipse.cdt.core.settings.model.util.IPathSettingsContainerVisitor; +import org.eclipse.cdt.core.settings.model.util.PathSettingsContainer; +import org.eclipse.cdt.managedbuilder.core.IOutputType; +import org.eclipse.cdt.managedbuilder.core.ITool; +import org.eclipse.cdt.managedbuilder.internal.core.ManagedMakeMessages; +import org.eclipse.cdt.managedbuilder.makegen.IManagedDependencyGeneratorType; +import org.eclipse.core.resources.IContainer; +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.Path; + +public class SrcMakeGenerator { + + private ArduinoGnuMakefileGenerator caller; + + SrcMakeGenerator(ArduinoGnuMakefileGenerator theCaller) { + caller = theCaller; + } + + private IProject getProject() { + return caller.getProject(); + } + + public void populateSourcesMakefile(IFile fileHandle, PathSettingsContainer toolInfos, + Collection subDirs) throws CoreException { + // Add the comment + StringBuffer buffer = addDefaultHeader(); + // Determine the set of macros + toolInfos.accept(new IPathSettingsContainerVisitor() { + @Override + public boolean visit(PathSettingsContainer container) { + ToolInfoHolder h = (ToolInfoHolder) container.getValue(); + ITool[] buildTools = h.buildTools; + HashSet handledInputExtensions = new HashSet<>(); + String buildMacro; + for (ITool buildTool : buildTools) { + if (buildTool.getCustomBuildStep()) + continue; + // Add the known sources macros + String[] extensionsList = buildTool.getAllInputExtensions(); + for (String ext : extensionsList) { + // create a macro of the form "EXTENSION_SRCS :=" + String extensionName = ext; + if (!handledInputExtensions.contains(extensionName)) { + handledInputExtensions.add(extensionName); + buildMacro = getSourceMacroName(extensionName).toString(); + if (!caller.buildSrcVars.containsKey(buildMacro)) { + caller.buildSrcVars.put(buildMacro, new ArrayList()); + } + // Add any generated dependency file macros + IManagedDependencyGeneratorType depType = buildTool + .getDependencyGeneratorForExtension(extensionName); + if (depType != null) { + int calcType = depType.getCalculatorType(); + if (calcType == IManagedDependencyGeneratorType.TYPE_COMMAND + || calcType == IManagedDependencyGeneratorType.TYPE_BUILD_COMMANDS + || calcType == IManagedDependencyGeneratorType.TYPE_PREBUILD_COMMANDS) { + buildMacro = getDepMacroName(extensionName).toString(); + if (!caller.buildDepVars.containsKey(buildMacro)) { + caller.buildDepVars.put(buildMacro, new ArduinoGnuDependencyGroupInfo( + buildMacro, + (calcType != IManagedDependencyGeneratorType.TYPE_PREBUILD_COMMANDS))); + } + if (!caller.buildOutVars.containsKey(buildMacro)) { + caller.buildOutVars.put(buildMacro, new ArrayList()); + } + } + } + } + } + // Add the specified output build variables + IOutputType[] outTypes = buildTool.getOutputTypes(); + if (outTypes != null && outTypes.length > 0) { + for (IOutputType outputType : outTypes) { + buildMacro = outputType.getBuildVariable(); + if (!caller.buildOutVars.containsKey(buildMacro)) { + caller.buildOutVars.put(buildMacro, new ArrayList()); + } + } + } else { + // For support of pre-CDT 3.0 integrations. + buildMacro = OBJS_MACRO; + if (!caller.buildOutVars.containsKey(buildMacro)) { + caller.buildOutVars.put(buildMacro, new ArrayList()); + } + } + } + return true; + } + }); + // Add the macros to the makefile + for (Entry> entry : caller.buildSrcVars.entrySet()) { + String macroName = new Path(entry.getKey()).toOSString(); + buffer.append(macroName).append(WHITESPACE).append(":=").append(WHITESPACE).append(NEWLINE); //$NON-NLS-1$ + } + Set>> set = caller.buildOutVars.entrySet(); + for (Entry> entry : set) { + String macroName = new Path(entry.getKey()).toOSString(); + buffer.append(macroName).append(WHITESPACE).append(":=").append(WHITESPACE).append(NEWLINE); //$NON-NLS-1$ + } + // Add a list of subdirectories to the makefile + buffer.append(NEWLINE).append(addSubdirectories(subDirs)); + // Save the file + save(buffer, fileHandle); + } + + /************************************************************************* + * S O U R C E S (sources.mk) M A K E F I L E M E T H O D S + ************************************************************************/ + private StringBuffer addSubdirectories(Collection subDirs) { + IProject project = getProject(); + StringBuffer buffer = new StringBuffer(); + // Add the comment + buffer.append(COMMENT_SYMBOL).append(WHITESPACE).append(MOD_LIST_MESSAGE).append(NEWLINE); + buffer.append("SUBDIRS := ").append(LINEBREAK); //$NON-NLS-1$ + // Get all the module names + for (IResource container : subDirs) { + caller.updateMonitor(ManagedMakeMessages.getFormattedString( + "MakefileGenerator.message.adding.source.folder", container.getFullPath().toOSString())); //$NON-NLS-1$ + // Check the special case where the module is the project root + if (container.getFullPath() == project.getFullPath()) { + buffer.append(DOT).append(WHITESPACE).append(LINEBREAK); + } else { + IPath path = container.getProjectRelativePath(); + buffer.append(escapeWhitespaces(path.toOSString())).append(WHITESPACE).append(LINEBREAK); + } + } + buffer.append(NEWLINE); + return buffer; + } +} diff --git a/io.sloeber.core/src/io/sloeber/managedBuild/Internal/SubDirMakeGenerator.java b/io.sloeber.core/src/io/sloeber/managedBuild/Internal/SubDirMakeGenerator.java new file mode 100644 index 000000000..50aad077a --- /dev/null +++ b/io.sloeber.core/src/io/sloeber/managedBuild/Internal/SubDirMakeGenerator.java @@ -0,0 +1,1749 @@ +package io.sloeber.managedBuild.Internal; + +import static io.sloeber.managedBuild.Internal.ManagebBuildCommon.*; +//import static io.sloeber.managedBuild.Internal.ManagebBuildCommon.*; +import static io.sloeber.managedBuild.Internal.ManagedBuildConstants.*; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map.Entry; +import java.util.Vector; + +import org.eclipse.cdt.core.settings.model.ICConfigurationDescription; +import org.eclipse.cdt.managedbuilder.core.BuildException; +import org.eclipse.cdt.managedbuilder.core.IBuildObject; +import org.eclipse.cdt.managedbuilder.core.IConfiguration; +import org.eclipse.cdt.managedbuilder.core.IFileInfo; +import org.eclipse.cdt.managedbuilder.core.IFolderInfo; +import org.eclipse.cdt.managedbuilder.core.IInputType; +import org.eclipse.cdt.managedbuilder.core.IManagedCommandLineGenerator; +import org.eclipse.cdt.managedbuilder.core.IManagedCommandLineInfo; +import org.eclipse.cdt.managedbuilder.core.IOption; +import org.eclipse.cdt.managedbuilder.core.IOutputType; +import org.eclipse.cdt.managedbuilder.core.IResourceInfo; +import org.eclipse.cdt.managedbuilder.core.ITool; +import org.eclipse.cdt.managedbuilder.core.ManagedBuildManager; +import org.eclipse.cdt.managedbuilder.internal.core.ManagedMakeMessages; +import org.eclipse.cdt.managedbuilder.internal.core.Tool; +import org.eclipse.cdt.managedbuilder.internal.macros.BuildMacroProvider; +import org.eclipse.cdt.managedbuilder.internal.macros.FileContextData; +import org.eclipse.cdt.managedbuilder.macros.BuildMacroException; +import org.eclipse.cdt.managedbuilder.macros.IBuildMacroProvider; +import org.eclipse.cdt.managedbuilder.makegen.IManagedBuilderMakefileGenerator; +import org.eclipse.cdt.managedbuilder.makegen.IManagedDependencyCalculator; +import org.eclipse.cdt.managedbuilder.makegen.IManagedDependencyCommands; +import org.eclipse.cdt.managedbuilder.makegen.IManagedDependencyGenerator; +import org.eclipse.cdt.managedbuilder.makegen.IManagedDependencyGenerator2; +import org.eclipse.cdt.managedbuilder.makegen.IManagedDependencyGeneratorType; +import org.eclipse.cdt.managedbuilder.makegen.IManagedDependencyInfo; +import org.eclipse.cdt.managedbuilder.makegen.IManagedDependencyPreBuild; +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.runtime.CoreException; +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.Path; + +import io.sloeber.managedBuild.api.IManagedOutputNameProviderJaba; + +public class SubDirMakeGenerator { + private List depLineList = new LinkedList<>(); + private ArduinoGnuMakefileGenerator caller; + + SubDirMakeGenerator(ArduinoGnuMakefileGenerator theCaller) { + caller = theCaller; + } + + public List getDepLineList() { + return depLineList; + } + + private IPath getBuildWorkingDir() { + return caller.getBuildWorkingDir(); + } + + private List getDependencyMakefiles(ToolInfoHolder h) { + return caller.getDependencyMakefiles(h); + } + + private IPath getTopBuildDir() { + return caller.getTopBuildDir(); + } + + private Vector getRuleList() { + return caller.getRuleList(); + } + + private IConfiguration getConfig() { + return caller.getConfig(); + } + + private IProject getProject() { + return caller.getProject(); + } + + private Vector getDepRuleList() { + return caller.getDepRuleList(); + } + + /************************************************************************* + * M A K E F I L E S P O P U L A T I O N M E T H O D S + ************************************************************************/ + /** + * This method generates a "fragment" make file (subdir.mk). One of these is + * generated for each project directory/subdirectory that contains source files. + */ + public void populateFragmentMakefile(IContainer module) throws CoreException { + //create the parent folder on disk and file in eclispe + IProject project = getProject(); + IPath buildRoot = getBuildWorkingDir(); + if (buildRoot == null) { + return; + } + IPath moduleOutputPath = buildRoot.append(module.getProjectRelativePath()); + caller.updateMonitor(ManagedMakeMessages.getFormattedString("MakefileGenerator.message.gen.source.makefile", + moduleOutputPath.toString())); + IPath moduleOutputDir = createDirectory(project, moduleOutputPath.toString()); + IFile modMakefile = createFile(moduleOutputDir.append(MODFILE_NAME)); + + //get the data + List makeRules = getMakeRules(module); + + //make the file + + StringBuffer makeBuf = getHeader(); + makeBuf.append(GenerateMacros(makeRules)); + makeBuf.append(GenerateRules(makeRules)); + makeBuf.append(addSources(module)); + + // Save the files + save(makeBuf, modMakefile); + } + + private StringBuffer GenerateMacros(List makeRules) { + StringBuffer buffer = new StringBuffer(); + IPath buildRoot = getTopBuildDir(); + buffer.append("#GenerateMacros not yet implemented"); + buffer.append(NEWLINE); + HashSet macroNames = new HashSet<>(); + for (MakeRule makeRule : makeRules) { + macroNames.addAll(makeRule.getMacros()); + } + for (String macroName : macroNames) { + HashSet files = new HashSet<>(); + for (MakeRule makeRule : makeRules) { + files.addAll(makeRule.getMacroElements(macroName)); + } + if (files.size() > 0) { + buffer.append(macroName).append("+=").append(WHITESPACE); + for (IPath file : files) { + buffer.append(LINEBREAK); + buffer.append(GetNiceFileName(buildRoot, file)).append(WHITESPACE); + } + buffer.append(NEWLINE); + } + } + return buffer; + } + + private String GetNiceFileName(IPath buildPath, IPath path) { + if (buildPath.isPrefixOf(path)) { + return DOT_SLASH_PATH.append(path.makeRelativeTo(buildPath)).toOSString(); + } else { + if (buildPath.removeLastSegments(1).isPrefixOf(path)) { + return path.makeRelativeTo(buildPath).toOSString(); + } + } + + return path.toOSString(); + // if (dirLocation.isPrefixOf(sourceLocation)) { + // IPath srcPath = sourceLocation.removeFirstSegments(dirLocation.segmentCount()).setDevice(null); + // if (generatedSource) { + // srcName = DOT_SLASH_PATH.append(srcPath).toOSString(); + // } else { + // srcName = ROOT + FILE_SEPARATOR + srcPath.toOSString(); + // } + // } else { + // if (generatedSource && !sourceLocation.isAbsolute()) { + // srcName = DOT_SLASH_PATH.append(relativePath).append(sourceLocation.lastSegment()).toOSString(); + // } else { + // // TODO: Should we use relative paths when possible (e.g., see + // // MbsMacroSupplier.calculateRelPath) + // srcName = sourceLocation.toOSString(); + // } + // } + } + + private StringBuffer GenerateRules(List makeRules) { + StringBuffer buffer = new StringBuffer(); + buffer.append("#GenerateRules not yet implemented"); + buffer.append(NEWLINE); + return buffer; + } + + static private StringBuffer getHeader() { + return addDefaultHeader(); + } + + private List getMakeRules(IContainer module) { + IConfiguration config = getConfig(); + IPath buildPath = getTopBuildDir(); + List makeRules = new LinkedList<>(); + // Visit the resources in this folder a + IResource[] resources; + try { + resources = module.members(); + + IFolder folder = getProject().getFolder(config.getName()); + for (IResource resource : resources) { + if (resource.getType() == IResource.FILE) { + IFile inputFile = (IFile) resource; + // Check whether this resource is excluded from build + IPath rcProjRelPath = resource.getProjectRelativePath(); + if (!caller.isSource(rcProjRelPath)) + continue; + IResourceInfo rcInfo = config.getResourceInfo(rcProjRelPath, false); + + ITool tool = null; + String varName = null; + String ext = rcProjRelPath.getFileExtension(); + if (ext != null) { + varName = getSourceMacroName(ext).toString(); + } + + //try to find tool + if (rcInfo instanceof IFileInfo) { + IFileInfo fi = (IFileInfo) rcInfo; + ITool[] tools = fi.getToolsToInvoke(); + if (tools != null && tools.length > 0) { + tool = tools[0]; + } + } + + //No tool found try other way + if (tool == null) { + ToolInfoHolder h = ToolInfoHolder.getToolInfo(caller, rcInfo.getPath()); + ITool buildTools[] = h.buildTools; + h = ToolInfoHolder.getToolInfo(caller, Path.EMPTY); + buildTools = h.buildTools; + for (ITool buildTool : buildTools) { + if (buildTool.buildsFileType(ext)) { + tool = buildTool; + break; + } + } + } + + //We found a tool get the other info + if (tool != null) { + MakeRule newMakeRule = new MakeRule(); + makeRules.add(newMakeRule); + // Generate the rule to build this source file + IInputType inputType = tool.getPrimaryInputType(); + if (inputType == null) { + inputType = tool.getInputType(ext); + } + if (inputType != null) { + if (inputType.getBuildVariable() != null) { + varName = inputType.getBuildVariable(); + } + } + newMakeRule.addPrerequisite(varName, inputFile.getLocation()); + for (String curExtension : tool.getAllOutputExtensions()) { + IOutputType outputType = tool.getOutputType(curExtension); + String OutMacroName = outputType.getBuildVariable(); + IManagedOutputNameProviderJaba nameProvider = getJABANameProvider(outputType); + if (nameProvider != null) { + IPath outputFile = nameProvider.getOutputName(getProject(), config, tool, + resource.getFullPath()); + if (outputFile != null) { + newMakeRule.addTarget(OutMacroName, + buildPath.append(outputFile.removeFirstSegments(1))); + } + + } + } + + // if ((primaryInputType != null && !primaryInputType.getMultipleOfType()) + // || (inputType == null && tool != caller.config.calculateTargetTool())) { + // // Try to add the rule for the file + // Vector generatedOutputs = new Vector(); + // Vector generatedDepFiles = new Vector(); + // // MODED moved JABA JAn Baeyens get the out type from the add + // // source call + // caller.usedOutType = null; + // addRuleForSource(project, relativePath, ruleBuffer, resource, sourceLocation, rcInfo, + // generatedSource, generatedDepFiles, generatedOutputs); + // // If the rule generates a dependency file(s), add the file(s) + // // to the variable + // if (generatedDepFiles.size() > 0) { + // for (int k = 0; k < generatedDepFiles.size(); k++) { + // IPath generatedDepFile = generatedDepFiles.get(k); + // addMacroAdditionFile(buildVarToRuleStringMap, getDepMacroName(ext).toString(), + // (generatedDepFile.isAbsolute() ? "" : DOT_SLASH_PATH.toOSString()) + // + generatedDepFile.toOSString()); + // } + // } + // // If the generated outputs of this tool are input to another + // // tool, + // // 1. add the output to the appropriate macro + // // 2. If the tool does not have multipleOfType input, generate + // // the rule. + // // IOutputType outType = tool.getPrimaryOutputType(); + // // MODED + // // moved JABA JAn Baeyens get the out type from the add source + // // call + // String buildVariable = null; + // if (caller.usedOutType != null) { + // if (tool.getCustomBuildStep()) { + // // TODO: This is somewhat of a hack since a custom build + // // step + // // tool does not currently define a build variable + // if (generatedOutputs.size() > 0) { + // IPath firstOutput = generatedOutputs.get(0); + // String firstExt = firstOutput.getFileExtension(); + // ToolInfoHolder tmpH = ToolInfoHolder.getFolderToolInfo(caller, rcInfo.getPath()); + // ITool[] tmpBuildTools = tmpH.buildTools; + // for (ITool tmpBuildTool : tmpBuildTools) { + // if (tmpBuildTool.buildsFileType(firstExt)) { + // String bV = tmpBuildTool.getPrimaryInputType().getBuildVariable(); + // if (bV.length() > 0) { + // buildVariable = bV; + // break; + // } + // } + // } + // } + // } else { + // buildVariable = caller.usedOutType.getBuildVariable(); + // } + // } else { + // // For support of pre-CDT 3.0 integrations. + // buildVariable = OBJS_MACRO; + // } + // for (int k = 0; k < generatedOutputs.size(); k++) { + // IPath generatedOutput; + // IResource generateOutputResource; + // if (generatedOutputs.get(k).isAbsolute()) { + // // TODO: Should we use relative paths when possible + // // (e.g., see MbsMacroSupplier.calculateRelPath) + // generatedOutput = generatedOutputs.get(k); + // // If this file has an absolute path, then the + // // generateOutputResource will not be correct + // // because the file is not under the project. We use + // // this resource in the calls to the dependency + // // generator + // generateOutputResource = project.getFile(generatedOutput); + // } else { + // generatedOutput = getPathForResource(project).append(caller.getBuildWorkingDir()) + // .append(generatedOutputs.get(k)); + // generateOutputResource = project + // .getFile(caller.getBuildWorkingDir().append(generatedOutputs.get(k))); + // } + // IResourceInfo nextRcInfo; + // if (rcInfo instanceof IFileInfo) { + // nextRcInfo = caller.config.getResourceInfo(rcInfo.getPath().removeLastSegments(1), + // false); + // } else { + // nextRcInfo = rcInfo; + // } + // addFragmentMakefileEntriesForSource(buildVarToRuleStringMap, ruleBuffer, folder, + // relativePath, generateOutputResource, generatedOutput, nextRcInfo, buildVariable, + // true); + // } + // } + // } else { + // // If this is a secondary input, add it to build vars + // if (varName == null) { + // for (ITool buildTool : buildTools) { + // if (buildTool.isInputFileType(ext)) { + // addToBuildVar(buildVarToRuleStringMap, ext, varName, relativePath, sourceLocation, + // generatedSource); + // break; + // } + // } + // } + // // If this generated output is identified as a secondary output, add + // // the file to the build variable + // else { + // IOutputType[] secondaryOutputs = caller.config.getToolChain().getSecondaryOutputs(); + // if (secondaryOutputs.length > 0) { + // if (isSecondaryOutputVar(h, secondaryOutputs, varName)) { + // addMacroAdditionFile(caller, buildVarToRuleStringMap, varName, relativePath, + // sourceLocation, generatedSource); + // } + // } + // } + } + + } + } + } catch (CoreException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + return makeRules; + } + + /** + * Returns a StringBuffer containing makefile text for all of the + * sources contributed by a container (project directory/subdirectory) to the + * fragement makefile + * + * @param module + * project resource directory/subdirectory + * @return StringBuffer generated text for the fragement makefile + */ + private StringBuffer addSources(IContainer module) throws CoreException { + IProject project = getProject(); + // Calculate the new directory relative to the build output + IPath moduleRelativePath = module.getProjectRelativePath(); + String relativePath = moduleRelativePath.toOSString(); + relativePath += relativePath.length() == 0 ? "" : FILE_SEPARATOR; + // For build macros in the configuration, create a map which will map + // them + // to a string which holds its list of sources. + LinkedHashMap buildVarToRuleStringMap = new LinkedHashMap(); + // Add statements that add the source files in this folder, + // and generated source files, and generated dependency files + // to the build macros + for (Entry> entry : caller.buildSrcVars.entrySet()) { + String macroName = entry.getKey(); + addMacroAdditionPrefix(buildVarToRuleStringMap, macroName, null, false); + } + for (Entry> entry : caller.buildOutVars.entrySet()) { + String macroName = entry.getKey(); + addMacroAdditionPrefix(buildVarToRuleStringMap, macroName, DOT_SLASH_PATH.append(relativePath).toOSString(), + false); + } + // String buffers + StringBuffer buffer = new StringBuffer(); + StringBuffer ruleBuffer = new StringBuffer( + COMMENT_SYMBOL + WHITESPACE + ManagedMakeMessages.getResourceString(MOD_RULES) + NEWLINE); + // Visit the resources in this folder and add each one to a sources + // macro, and generate a build rule, if appropriate + IResource[] resources = module.members(); + IResourceInfo rcInfo; + IFolder folder = project.getFolder(caller.config.getName()); + for (IResource resource : resources) { + if (resource.getType() == IResource.FILE) { + // Check whether this resource is excluded from build + IPath rcProjRelPath = resource.getProjectRelativePath(); + if (!caller.isSource(rcProjRelPath)) + continue; + rcInfo = caller.config.getResourceInfo(rcProjRelPath, false); + // if( (rcInfo.isExcluded()) ) + // continue; + addFragmentMakefileEntriesForSource(buildVarToRuleStringMap, ruleBuffer, folder, relativePath, resource, + getPathForResource(resource), rcInfo, null, false); + } + } + // Write out the macro addition entries to the buffer + buffer.append(writeAdditionMacros(buildVarToRuleStringMap)); + return buffer.append(ruleBuffer).append(NEWLINE); + } + + /* + * (non-Javadoc Adds the entries for a particular source file to the fragment + * makefile + * + * @param buildVarToRuleStringMap map of build variable names to the list of + * files assigned to the variable + * + * @param ruleBuffer buffer to add generated nmakefile text to + * + * @param folder the top level build output directory + * + * @param relativePath build output directory relative path of the current + * output directory + * + * @param resource the source file for this invocation of the tool - this may be + * null for a generated output + * + * @param sourceLocation the full path of the source + * + * @param resConfig the IResourceConfiguration associated with this file or null + * + * @param varName the build variable to add this invocation's outputs to if + * null, use the file extension to find the name + * + * @param generatedSource if true, this file was generated by + * another tool in the tool-chain + */ + private void addFragmentMakefileEntriesForSource(LinkedHashMap buildVarToRuleStringMap, + StringBuffer ruleBuffer, IFolder folder, String relativePath, IResource resource, IPath sourceLocation, + IResourceInfo rcInfo, String varName, boolean generatedSource) { + IProject project = getProject(); + // Determine which tool, if any, builds files with this extension + String ext = sourceLocation.getFileExtension(); + ITool tool = null; + + if (rcInfo instanceof IFileInfo) { + IFileInfo fi = (IFileInfo) rcInfo; + ITool[] tools = fi.getToolsToInvoke(); + if (tools != null && tools.length > 0) { + tool = tools[0]; + addToBuildVar(buildVarToRuleStringMap, ext, varName, relativePath, sourceLocation, generatedSource); + } + } + ToolInfoHolder h = ToolInfoHolder.getToolInfo(caller, rcInfo.getPath()); + ITool buildTools[] = h.buildTools; + + if (tool == null) { + h = ToolInfoHolder.getToolInfo(caller, Path.EMPTY); + buildTools = h.buildTools; + for (ITool buildTool : buildTools) { + if (buildTool.buildsFileType(ext)) { + tool = buildTool; + addToBuildVar(buildVarToRuleStringMap, ext, varName, relativePath, sourceLocation, generatedSource); + break; + } + } + } + if (tool != null) { + // Generate the rule to build this source file + IInputType primaryInputType = tool.getPrimaryInputType(); + IInputType inputType = tool.getInputType(ext); + if ((primaryInputType != null && !primaryInputType.getMultipleOfType()) + || (inputType == null && tool != caller.config.calculateTargetTool())) { + // Try to add the rule for the file + Vector generatedOutputs = new Vector(); + Vector generatedDepFiles = new Vector(); + // MODED moved JABA JAn Baeyens get the out type from the add + // source call + caller.usedOutType = null; + addRuleForSource(project, relativePath, ruleBuffer, resource, sourceLocation, rcInfo, generatedSource, + generatedDepFiles, generatedOutputs); + // If the rule generates a dependency file(s), add the file(s) + // to the variable + if (generatedDepFiles.size() > 0) { + for (int k = 0; k < generatedDepFiles.size(); k++) { + IPath generatedDepFile = generatedDepFiles.get(k); + addMacroAdditionFile(buildVarToRuleStringMap, getDepMacroName(ext).toString(), + (generatedDepFile.isAbsolute() ? "" : DOT_SLASH_PATH.toOSString()) + + generatedDepFile.toOSString()); + } + } + // If the generated outputs of this tool are input to another + // tool, + // 1. add the output to the appropriate macro + // 2. If the tool does not have multipleOfType input, generate + // the rule. + // IOutputType outType = tool.getPrimaryOutputType(); + // MODED + // moved JABA JAn Baeyens get the out type from the add source + // call + String buildVariable = null; + if (caller.usedOutType != null) { + if (tool.getCustomBuildStep()) { + // TODO: This is somewhat of a hack since a custom build + // step + // tool does not currently define a build variable + if (generatedOutputs.size() > 0) { + IPath firstOutput = generatedOutputs.get(0); + String firstExt = firstOutput.getFileExtension(); + ToolInfoHolder tmpH = ToolInfoHolder.getFolderToolInfo(caller, rcInfo.getPath()); + ITool[] tmpBuildTools = tmpH.buildTools; + for (ITool tmpBuildTool : tmpBuildTools) { + if (tmpBuildTool.buildsFileType(firstExt)) { + String bV = tmpBuildTool.getPrimaryInputType().getBuildVariable(); + if (bV.length() > 0) { + buildVariable = bV; + break; + } + } + } + } + } else { + buildVariable = caller.usedOutType.getBuildVariable(); + } + } else { + // For support of pre-CDT 3.0 integrations. + buildVariable = OBJS_MACRO; + } + for (int k = 0; k < generatedOutputs.size(); k++) { + IPath generatedOutput; + IResource generateOutputResource; + if (generatedOutputs.get(k).isAbsolute()) { + // TODO: Should we use relative paths when possible + // (e.g., see MbsMacroSupplier.calculateRelPath) + generatedOutput = generatedOutputs.get(k); + // If this file has an absolute path, then the + // generateOutputResource will not be correct + // because the file is not under the project. We use + // this resource in the calls to the dependency + // generator + generateOutputResource = project.getFile(generatedOutput); + } else { + generatedOutput = getPathForResource(project).append(caller.getBuildWorkingDir()) + .append(generatedOutputs.get(k)); + generateOutputResource = project + .getFile(caller.getBuildWorkingDir().append(generatedOutputs.get(k))); + } + IResourceInfo nextRcInfo; + if (rcInfo instanceof IFileInfo) { + nextRcInfo = caller.config.getResourceInfo(rcInfo.getPath().removeLastSegments(1), false); + } else { + nextRcInfo = rcInfo; + } + addFragmentMakefileEntriesForSource(buildVarToRuleStringMap, ruleBuffer, folder, relativePath, + generateOutputResource, generatedOutput, nextRcInfo, buildVariable, true); + } + } + } else { + // If this is a secondary input, add it to build vars + if (varName == null) { + for (ITool buildTool : buildTools) { + if (buildTool.isInputFileType(ext)) { + addToBuildVar(buildVarToRuleStringMap, ext, varName, relativePath, sourceLocation, + generatedSource); + break; + } + } + } + // If this generated output is identified as a secondary output, add + // the file to the build variable + else { + IOutputType[] secondaryOutputs = caller.config.getToolChain().getSecondaryOutputs(); + if (secondaryOutputs.length > 0) { + if (isSecondaryOutputVar(h, secondaryOutputs, varName)) { + addMacroAdditionFile(caller, buildVarToRuleStringMap, varName, relativePath, sourceLocation, + generatedSource); + } + } + } + } + } + + /** + * Write all macro addition entries in a map to the buffer + */ + static private StringBuffer writeAdditionMacros(LinkedHashMap map) { + StringBuffer buffer = new StringBuffer(); + // Add the comment + buffer.append(COMMENT_SYMBOL).append(WHITESPACE).append(ManagedMakeMessages.getResourceString(MOD_VARS)) + .append(NEWLINE); + for (String macroString : map.values()) { + // Check if we added any files to the rule + // Currently, we do this by comparing the end of the rule buffer to + // MACRO_ADDITION_PREFIX_SUFFIX + if (!(macroString.endsWith(MACRO_ADDITION_PREFIX_SUFFIX))) { + StringBuffer currentBuffer = new StringBuffer(); + // Remove the final "/" + if (macroString.endsWith(LINEBREAK)) { + macroString = macroString.substring(0, (macroString.length() - 2)) + NEWLINE; + } + currentBuffer.append(macroString); + currentBuffer.append(NEWLINE); + // append the contents of the buffer to the master buffer for + // the whole file + buffer.append(currentBuffer); + } + } + return buffer.append(NEWLINE); + } + + static private boolean isSecondaryOutputVar(ToolInfoHolder h, IOutputType[] secondaryOutputs, String varName) { + ITool[] buildTools = h.buildTools; + for (ITool buildTool : buildTools) { + // Add the specified output build variables + IOutputType[] outTypes = buildTool.getOutputTypes(); + if (outTypes != null && outTypes.length > 0) { + for (IOutputType outType : outTypes) { + // Is this one of the secondary outputs? + // Look for an outputType with this ID, or one with a + // superclass with this id + for (IOutputType secondaryOutput : secondaryOutputs) { + IOutputType matchType = outType; + do { + if (matchType.getId().equals(secondaryOutput.getId())) { + if (outType.getBuildVariable().equals(varName)) { + return true; + } + } + matchType = matchType.getSuperClass(); + } while (matchType != null); + } + } + } + } + return false; + } + + /** + * Create a rule for this source file. We create a pattern rule if possible. + * This is an example of a pattern rule: /%.: + * ..//%. + * + * @echo Building file: $< + * @echo Invoking tool xxx + * @echo $@ $< + * @ $@ $< && \ echo -n $(@:%.o=%.d) ' + * /' >> $(@:%.o=%.d) && \ -P -MM -MG $< + * >> $(@:%.o=%.d) + * @echo Finished building: $< + * @echo ' ' Note that the macros 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: ../source1/%.cpp + * @echo Building file: $< + * @echo Invoking tool xxx + * @echo g++ -g -O2 -c -I/cygdrive/c/eclipse/workspace/Project/headers -o$@ + * $< @g++ -g -O2 -c -I/cygdrive/c/eclipse/workspace/Project/headers -o$@ + * $< && \ echo -n $(@:%.o=%.d) ' source1/' >> $(@:%.o=%.d) && \ g++ -P + * -MM -MG -g -O2 -c -I/cygdrive/c/eclipse/workspace/Project/headers $< >> + * $(@:%.o=%.d) + * @echo Finished building: $< + * @echo ' ' + * @param relativePath + * top build output directory relative path of the current output + * directory + * @param buffer + * buffer to populate with the build rule + * @param resource + * the source file for this invocation of the tool + * @param sourceLocation + * the full path of the source + * @param rcInfo + * the IResourceInfo associated with this file or null + * @param generatedSource + * true if the resource is a generated output + * @param enumeratedOutputs + * vector of the filenames that are the output of this rule + */ + private void addRuleForSource(IProject project, String relativePath, StringBuffer buffer, IResource resource, + IPath sourceLocation, IResourceInfo rcInfo, boolean generatedSource, List generatedDepFiles, + List enumeratedOutputs) { + IConfiguration config = getConfig(); + String fileName = sourceLocation.removeFileExtension().lastSegment(); + String inputExtension = sourceLocation.getFileExtension(); + String outputExtension = null; + ITool tool = null; + if (rcInfo instanceof IFileInfo) { + IFileInfo fi = (IFileInfo) rcInfo; + ITool[] tools = fi.getToolsToInvoke(); + if (tools != null && tools.length > 0) { + tool = tools[0]; + } + } else { + IFolderInfo foInfo = (IFolderInfo) rcInfo; + tool = foInfo.getToolFromInputExtension(inputExtension); + } + ToolInfoHolder h = ToolInfoHolder.getToolInfo(caller, rcInfo.getPath()); + if (tool != null) + outputExtension = tool.getOutputExtension(inputExtension); + if (outputExtension == null) + outputExtension = EMPTY_STRING; + // Get the dependency generator information for this tool and file + // extension + IManagedDependencyGenerator oldDepGen = null; + IManagedDependencyGenerator2 depGen = null; + IManagedDependencyInfo depInfo = null; + IManagedDependencyCommands depCommands = null; + IManagedDependencyPreBuild depPreBuild = null; + IPath[] depFiles = null; + boolean doDepGen = false; + { + IManagedDependencyGeneratorType t = null; + if (tool != null) + t = tool.getDependencyGeneratorForExtension(inputExtension); + if (t != null) { + int calcType = t.getCalculatorType(); + if (calcType <= IManagedDependencyGeneratorType.TYPE_OLD_TYPE_LIMIT) { + oldDepGen = (IManagedDependencyGenerator) t; + doDepGen = (calcType == IManagedDependencyGeneratorType.TYPE_COMMAND); + if (doDepGen) { + IPath depFile = Path.fromOSString(relativePath + fileName + DOT + DEP_EXT); + getDependencyMakefiles(h).add(depFile); + generatedDepFiles.add(depFile); + } + } else { + depGen = (IManagedDependencyGenerator2) t; + doDepGen = (calcType == IManagedDependencyGeneratorType.TYPE_BUILD_COMMANDS); + IBuildObject buildContext = rcInfo; + depInfo = depGen.getDependencySourceInfo(resource.getProjectRelativePath(), resource, buildContext, + tool, getBuildWorkingDir()); + if (calcType == IManagedDependencyGeneratorType.TYPE_BUILD_COMMANDS) { + depCommands = (IManagedDependencyCommands) depInfo; + depFiles = depCommands.getDependencyFiles(); + } else if (calcType == IManagedDependencyGeneratorType.TYPE_PREBUILD_COMMANDS) { + depPreBuild = (IManagedDependencyPreBuild) depInfo; + depFiles = depPreBuild.getDependencyFiles(); + } + if (depFiles != null) { + for (IPath depFile : depFiles) { + getDependencyMakefiles(h).add(depFile); + generatedDepFiles.add(depFile); + } + } + } + } + } + // Figure out the output paths + String optDotExt = EMPTY_STRING; + if (outputExtension.length() > 0) + optDotExt = DOT + outputExtension; + // JABA + caller.usedOutType = tool.getPrimaryOutputType(); + calculateOutputsForSource(tool, relativePath, resource, sourceLocation, enumeratedOutputs); + String primaryOutputName = null; + if (enumeratedOutputs.size() > 0) { + primaryOutputName = escapeWhitespaces(enumeratedOutputs.get(0).toOSString()); + } else { + primaryOutputName = escapeWhitespaces(relativePath + fileName + optDotExt); + } + String otherPrimaryOutputs = EMPTY_STRING; + for (IPath curOutput : enumeratedOutputs) { + otherPrimaryOutputs += WHITESPACE + escapeWhitespaces(curOutput.toOSString()); + } + // Output file location needed for the file-build macros + IPath outputLocation = Path.fromOSString(primaryOutputName); + if (!outputLocation.isAbsolute()) { + outputLocation = getPathForResource(project).append(getBuildWorkingDir()).append(primaryOutputName); + } + // A separate rule is needed for the resource in the case where explicit + // file-specific macros + // are referenced, or if the resource contains special characters in its + // path (e.g., whitespace) + /* + * fix for 137674 We only need an explicit rule if one of the following is true: + * - The resource is linked, and its full path to its real location contains + * special characters - The resource is not linked, but its project relative + * path contains special characters + */ + boolean resourceNameRequiresExplicitRule = (resource.isLinked() + && containsSpecialCharacters(sourceLocation.toOSString())) + || (!resource.isLinked() && containsSpecialCharacters(resource.getProjectRelativePath().toOSString())); + boolean needExplicitRuleForFile = resourceNameRequiresExplicitRule + || BuildMacroProvider.getReferencedExplitFileMacros(tool).length > 0 + || BuildMacroProvider.getReferencedExplitFileMacros(tool.getToolCommand(), + IBuildMacroProvider.CONTEXT_FILE, + new FileContextData(sourceLocation, outputLocation, null, tool)).length > 0; + // Get and resolve the command + String cmd = tool.getToolCommand(); + try { + String resolvedCommand = null; + if (!needExplicitRuleForFile) { + resolvedCommand = ManagedBuildManager.getBuildMacroProvider().resolveValueToMakefileFormat(cmd, + EMPTY_STRING, WHITESPACE, IBuildMacroProvider.CONTEXT_FILE, + new FileContextData(sourceLocation, outputLocation, null, tool)); + } else { + // if we need an explicit rule then don't use any builder + // variables, resolve everything + // to explicit strings + resolvedCommand = ManagedBuildManager.getBuildMacroProvider().resolveValue(cmd, EMPTY_STRING, + WHITESPACE, IBuildMacroProvider.CONTEXT_FILE, + new FileContextData(sourceLocation, outputLocation, null, tool)); + } + if ((resolvedCommand = resolvedCommand.trim()).length() > 0) + cmd = resolvedCommand; + } catch (BuildMacroException e) { + /* JABA is not going to write this code */ + } + String defaultOutputName = EMPTY_STRING; + String primaryDependencyName = EMPTY_STRING; + String patternPrimaryDependencyName = EMPTY_STRING; + String home = (generatedSource) ? DOT : ROOT; + String resourcePath = null; + boolean patternRule = true; + boolean isItLinked = false; + if (resource.isLinked(IResource.CHECK_ANCESTORS)) { + // it IS linked, so use the actual location + isItLinked = true; + resourcePath = sourceLocation.toOSString(); + // Need a hardcoded rule, not a pattern rule, as a linked file + // can reside in any path + defaultOutputName = escapeWhitespaces(relativePath + fileName + optDotExt); + primaryDependencyName = escapeWhitespaces(resourcePath); + patternRule = false; + } else { + // Use the relative path (not really needed to store per se but in + // the future someone may want this) + resourcePath = relativePath; + // The rule and command to add to the makefile + if (rcInfo instanceof IFileInfo || needExplicitRuleForFile) { + // Need a hardcoded rule, not a pattern rule + defaultOutputName = escapeWhitespaces(resourcePath + fileName + optDotExt); + patternRule = false; + } else { + defaultOutputName = relativePath + WILDCARD + optDotExt; + } + primaryDependencyName = escapeWhitespaces( + home + FILE_SEPARATOR + resourcePath + fileName + DOT + inputExtension); + patternPrimaryDependencyName = home + FILE_SEPARATOR + resourcePath + WILDCARD + DOT + inputExtension; + } // end fix for PR 70491 + // If the tool specifies a dependency calculator of + // TYPE_BUILD_COMMANDS, + // ask whether + // the dependency commands are "generic" (i.e., we can use a pattern + // rule) + boolean needExplicitDependencyCommands = false; + if (depCommands != null) { + needExplicitDependencyCommands = !depCommands.areCommandsGeneric(); + } + // If we still think that we are using a pattern rule, check a few more + // things + if (patternRule) { + patternRule = false; + // Make sure that at least one of the rule outputs contains a %. + for (IPath output : enumeratedOutputs) { + String ruleOutput = output.toOSString(); + if (ruleOutput.indexOf('%') >= 0) { + patternRule = true; + break; + } + } + if (patternRule) { + patternRule = !needExplicitDependencyCommands; + } + } + // Begin building the rule for this source file + String buildRule = EMPTY_STRING; + if (patternRule) { + if (enumeratedOutputs.size() == 0) { + buildRule += defaultOutputName; + } else { + boolean first = true; + for (IPath curOutput : enumeratedOutputs) { + String ruleOutput = curOutput.toOSString(); + if (ruleOutput.indexOf('%') >= 0) { + if (first) { + first = false; + } else { + buildRule += WHITESPACE; + } + buildRule += ruleOutput; + } + } + } + } else { + buildRule += primaryOutputName; + } + String buildRuleDependencies = primaryDependencyName; + String patternBuildRuleDependencies = patternPrimaryDependencyName; + // Other additional inputs + // Get any additional dependencies specified for the tool in other + // InputType elements and AdditionalInput elements + IPath[] addlDepPaths = tool.getAdditionalDependencies(); + for (IPath addlDepPath : addlDepPaths) { + // Translate the path from project relative to build directory + // relative + IPath addlPath = addlDepPath; + if (!(addlPath.toString().startsWith("$("))) { + if (!addlPath.isAbsolute()) { + IPath tempPath = project.getLocation().append(new Path(ensureUnquoted(addlPath.toString()))); + if (tempPath != null) { + addlPath = ManagedBuildManager.calculateRelativePath(getTopBuildDir(), tempPath); + } + } + } + String suitablePath = ensurePathIsGNUMakeTargetRuleCompatibleSyntax(addlPath.toOSString()); + buildRuleDependencies += WHITESPACE + suitablePath; + patternBuildRuleDependencies += WHITESPACE + suitablePath; + } + buildRule += COLON + WHITESPACE + (patternRule ? patternBuildRuleDependencies : buildRuleDependencies); + // No duplicates in a makefile. If we already have this rule, don't add + // it or the commands to build the file + if (getRuleList().contains(buildRule)) { + // TODO: Should we assert that this is a pattern rule? + } else { + getRuleList().add(buildRule); + // Echo starting message + buffer.append(buildRule).append(NEWLINE); + buffer.append(TAB).append(AT).append(escapedEcho(MESSAGE_START_FILE + WHITESPACE + IN_MACRO)); + buffer.append(TAB).append(AT).append(escapedEcho(tool.getAnnouncement())); + // If the tool specifies a dependency calculator of + // TYPE_BUILD_COMMANDS, ask whether + // there are any pre-tool commands. + if (depCommands != null) { + String[] preToolCommands = depCommands.getPreToolDependencyCommands(); + if (preToolCommands != null && preToolCommands.length > 0) { + for (String preCmd : preToolCommands) { + try { + String resolvedCommand; + IBuildMacroProvider provider = ManagedBuildManager.getBuildMacroProvider(); + if (!needExplicitRuleForFile) { + resolvedCommand = provider.resolveValueToMakefileFormat(preCmd, EMPTY_STRING, + WHITESPACE, IBuildMacroProvider.CONTEXT_FILE, + new FileContextData(sourceLocation, outputLocation, null, tool)); + } else { + // if we need an explicit rule then don't use + // any builder + // variables, resolve everything to explicit + // strings + resolvedCommand = provider.resolveValue(preCmd, EMPTY_STRING, WHITESPACE, + IBuildMacroProvider.CONTEXT_FILE, + new FileContextData(sourceLocation, outputLocation, null, tool)); + } + if (resolvedCommand != null) + buffer.append(resolvedCommand).append(NEWLINE); + } catch (BuildMacroException e) { + /* JABA is not going to write this code */ + } + } + } + } + // Generate the command line + Vector inputs = new Vector(); + inputs.add(IN_MACRO); + // Other additional inputs + // Get any additional dependencies specified for the tool in other + // InputType elements and AdditionalInput elements + IPath[] addlInputPaths = getAdditionalResourcesForSource(tool); + for (IPath addlInputPath : addlInputPaths) { + // Translate the path from project relative to build directory + // relative + IPath addlPath = addlInputPath; + if (!(addlPath.toString().startsWith("$("))) { + if (!addlPath.isAbsolute()) { + IPath tempPath = getPathForResource(project).append(addlPath); + if (tempPath != null) { + addlPath = ManagedBuildManager.calculateRelativePath(getTopBuildDir(), tempPath); + } + } + } + inputs.add(addlPath.toOSString()); + } + String[] inputStrings = inputs.toArray(new String[inputs.size()]); + String[] flags = null; + // Get the tool command line options + try { + flags = tool.getToolCommandFlags(sourceLocation, outputLocation); + } catch (BuildException ex) { + // TODO add some routines to catch this + flags = EMPTY_STRING_ARRAY; + } + // If we have a TYPE_BUILD_COMMANDS dependency generator, determine + // if there are any options that + // it wants added to the command line + if (depCommands != null) { + flags = addDependencyOptions(depCommands, flags); + } + IManagedCommandLineInfo cmdLInfo = null; + String outflag = null; + String outputPrefix = null; + if (rcInfo instanceof IFileInfo || needExplicitRuleForFile || needExplicitDependencyCommands) { + outflag = tool.getOutputFlag(); + outputPrefix = tool.getOutputPrefix(); + // Call the command line generator + IManagedCommandLineGenerator cmdLGen = tool.getCommandLineGenerator(); + cmdLInfo = cmdLGen.generateCommandLineInfo(tool, cmd, flags, outflag, outputPrefix, + OUT_MACRO + otherPrimaryOutputs, inputStrings, getToolCommandLinePattern(config, tool)); + } else { + outflag = tool.getOutputFlag(); + outputPrefix = tool.getOutputPrefix(); + // Call the command line generator + cmdLInfo = generateToolCommandLineInfo(tool, inputExtension, flags, outflag, outputPrefix, + OUT_MACRO + otherPrimaryOutputs, inputStrings, sourceLocation, outputLocation); + } + // The command to build + String buildCmd; + if (cmdLInfo != null) { + buildCmd = cmdLInfo.getCommandLine(); + } else { + StringBuffer buildFlags = new StringBuffer(); + for (String flag : flags) { + if (flag != null) { + buildFlags.append(flag).append(WHITESPACE); + } + } + buildCmd = cmd + WHITESPACE + buildFlags.toString().trim() + WHITESPACE + outflag + WHITESPACE + + outputPrefix + OUT_MACRO + otherPrimaryOutputs + WHITESPACE + IN_MACRO; + } + // resolve any remaining macros in the command after it has been + // generated + try { + String resolvedCommand; + IBuildMacroProvider provider = ManagedBuildManager.getBuildMacroProvider(); + if (!needExplicitRuleForFile) { + resolvedCommand = provider.resolveValueToMakefileFormat(buildCmd, EMPTY_STRING, WHITESPACE, + IBuildMacroProvider.CONTEXT_FILE, + new FileContextData(sourceLocation, outputLocation, null, tool)); + } else { + // if we need an explicit rule then don't use any builder + // variables, resolve everything to explicit strings + resolvedCommand = provider.resolveValue(buildCmd, EMPTY_STRING, WHITESPACE, + IBuildMacroProvider.CONTEXT_FILE, + new FileContextData(sourceLocation, outputLocation, null, tool)); + } + if ((resolvedCommand = resolvedCommand.trim()).length() > 0) + buildCmd = resolvedCommand; + } catch (BuildMacroException e) { + /* JABA is not going to write this code */ + } + // buffer.append(TAB).append(AT).append(escapedEcho(buildCmd)); + // buffer.append(TAB).append(AT).append(buildCmd); + // JABA add sketch.prebuild and postbouild if needed + if ("sloeber.ino".equals(fileName)) { + ICConfigurationDescription confDesc = ManagedBuildManager.getDescriptionForConfiguration(config); + String sketchPrebuild = io.sloeber.core.common.Common.getBuildEnvironmentVariable(confDesc, + "sloeber.sketch.prebuild", new String(), true); + String sketchPostBuild = io.sloeber.core.common.Common.getBuildEnvironmentVariable(confDesc, + "sloeber.sketch.postbuild", new String(), true); + if (!sketchPrebuild.isEmpty()) { + buffer.append(TAB).append(sketchPrebuild); + } + buffer.append(TAB).append(buildCmd).append(NEWLINE); + if (!sketchPostBuild.isEmpty()) { + buffer.append(TAB).append(sketchPostBuild); + } + } else { + buffer.append(TAB).append(buildCmd); + } + // end JABA add sketch.prebuild and postbouild if needed + + // Determine if there are any dependencies to calculate + if (doDepGen) { + // Get the dependency rule out of the generator + String[] depCmds = null; + if (oldDepGen != null) { + depCmds = new String[1]; + depCmds[0] = oldDepGen.getDependencyCommand(resource, ManagedBuildManager.getBuildInfo(project)); + } else { + if (depCommands != null) { + depCmds = depCommands.getPostToolDependencyCommands(); + } + } + if (depCmds != null) { + for (String depCmd : depCmds) { + // Resolve any macros in the dep command after it has + // been generated. + // Note: do not trim the result because it will strip + // out necessary tab characters. + buffer.append(WHITESPACE).append(LOGICAL_AND).append(WHITESPACE).append(LINEBREAK); + try { + if (!needExplicitRuleForFile) { + depCmd = ManagedBuildManager.getBuildMacroProvider().resolveValueToMakefileFormat( + depCmd, EMPTY_STRING, WHITESPACE, IBuildMacroProvider.CONTEXT_FILE, + new FileContextData(sourceLocation, outputLocation, null, tool)); + } else { + depCmd = ManagedBuildManager.getBuildMacroProvider().resolveValue(depCmd, EMPTY_STRING, + WHITESPACE, IBuildMacroProvider.CONTEXT_FILE, + new FileContextData(sourceLocation, outputLocation, null, tool)); + } + } catch (BuildMacroException e) { + /* JABA is not going to do this */ + } + buffer.append(depCmd); + } + } + } + // Echo finished message + buffer.append(NEWLINE); + buffer.append(TAB).append(AT).append(escapedEcho(MESSAGE_FINISH_FILE + WHITESPACE + IN_MACRO)); + buffer.append(TAB).append(AT).append(ECHO_BLANK_LINE).append(NEWLINE); + } + // Determine if there are calculated dependencies + IPath[] addlDeps = null; + IPath[] addlTargets = null; + String calculatedDependencies = null; + boolean addedDepLines = false; + String depLine; + if (oldDepGen != null && oldDepGen.getCalculatorType() != IManagedDependencyGeneratorType.TYPE_COMMAND) { + addlDeps = oldCalculateDependenciesForSource(oldDepGen, tool, relativePath, resource); + } else { + if (depGen != null && depGen.getCalculatorType() == IManagedDependencyGeneratorType.TYPE_CUSTOM) { + if (depInfo instanceof IManagedDependencyCalculator) { + IManagedDependencyCalculator depCalculator = (IManagedDependencyCalculator) depInfo; + addlDeps = calculateDependenciesForSource(depCalculator); + addlTargets = depCalculator.getAdditionalTargets(); + } + } + } + if (addlDeps != null && addlDeps.length > 0) { + calculatedDependencies = ""; + for (IPath addlDep : addlDeps) { + calculatedDependencies += WHITESPACE + escapeWhitespaces(addlDep.toOSString()); + } + } + if (calculatedDependencies != null) { + depLine = primaryOutputName + COLON + calculatedDependencies + NEWLINE; + if (!getDepLineList().contains(depLine)) { + getDepLineList().add(depLine); + addedDepLines = true; + buffer.append(depLine); + } + } + + for (IPath curOutput : enumeratedOutputs) { + depLine = escapeWhitespaces(curOutput.toOSString()) + COLON + WHITESPACE + primaryOutputName; + if (calculatedDependencies != null) + depLine += calculatedDependencies; + depLine += NEWLINE; + if (!getDepLineList().contains(depLine)) { + getDepLineList().add(depLine); + addedDepLines = true; + buffer.append(depLine); + } + } + if (addedDepLines) { + buffer.append(NEWLINE); + } + // If we are using a dependency calculator of type + // TYPE_PREBUILD_COMMANDS, + // get the rule to build the dependency file + if (depPreBuild != null && depFiles != null) { + addedDepLines = false; + String[] preBuildCommands = depPreBuild.getDependencyCommands(); + if (preBuildCommands != null) { + depLine = ""; + // Can we use a pattern rule? + patternRule = !isItLinked && !needExplicitRuleForFile && depPreBuild.areCommandsGeneric(); + // Begin building the rule + for (int i = 0; i < depFiles.length; i++) { + if (i > 0) + depLine += WHITESPACE; + if (patternRule) { + optDotExt = EMPTY_STRING; + String depExt = depFiles[i].getFileExtension(); + if (depExt != null && depExt.length() > 0) + optDotExt = DOT + depExt; + depLine += escapeWhitespaces(relativePath + WILDCARD + optDotExt); + } else { + depLine += escapeWhitespaces((depFiles[i]).toOSString()); + } + } + depLine += COLON + WHITESPACE + (patternRule ? patternBuildRuleDependencies : buildRuleDependencies); + if (!getDepRuleList().contains(depLine)) { + getDepRuleList().add(depLine); + addedDepLines = true; + buffer.append(depLine).append(NEWLINE); + buffer.append(TAB).append(AT) + .append(escapedEcho(MESSAGE_START_DEPENDENCY + WHITESPACE + OUT_MACRO)); + for (String preBuildCommand : preBuildCommands) { + depLine = preBuildCommand; + // Resolve macros + try { + if (!needExplicitRuleForFile) { + depLine = ManagedBuildManager.getBuildMacroProvider().resolveValueToMakefileFormat( + depLine, EMPTY_STRING, WHITESPACE, IBuildMacroProvider.CONTEXT_FILE, + new FileContextData(sourceLocation, outputLocation, null, tool)); + } else { + depLine = ManagedBuildManager.getBuildMacroProvider().resolveValue(depLine, + EMPTY_STRING, WHITESPACE, IBuildMacroProvider.CONTEXT_FILE, + new FileContextData(sourceLocation, outputLocation, null, tool)); + } + } catch (BuildMacroException e) { + // JABA is not going to write this code + } + // buffer.append(TAB + AT + escapedEcho(depLine)); + // buffer.append(TAB + AT + depLine + NEWLINE); + buffer.append(TAB).append(depLine).append(NEWLINE); + } + } + if (addedDepLines) { + buffer.append(TAB).append(AT).append(ECHO_BLANK_LINE).append(NEWLINE); + } + } + } + } + + /************************************************************************* + * F R A G M E N T (subdir.mk) M A K E F I L E M E T H O D S + ************************************************************************/ + /** + * Returns a StringBuffer containing the comment(s) for a fragment + * makefile (subdir.mk). + */ + + /** + * Adds the source file to the appropriate build variable + * + * @param buildVarToRuleStringMap + * map of build variable names to the list of files assigned to the + * variable + * @param ext + * the file extension of the file + * @param varName + * the build variable to add this invocation's outputs to if + * null, use the file extension to find the name + * @param relativePath + * build output directory relative path of the current output + * directory + * @param sourceLocation + * the full path of the source + * @param generatedSource + * if true, this file was generated by another tool in + * the tool-chain + */ + private void addToBuildVar(LinkedHashMap buildVarToRuleStringMap, String ext, String varName, + String relativePath, IPath sourceLocation, boolean generatedSource) { + List varList = null; + if (varName == null) { + // Get the proper source build variable based upon the extension + varName = getSourceMacroName(ext).toString(); + varList = caller.buildSrcVars.get(varName); + } else { + varList = caller.buildOutVars.get(varName); + } + // Add the resource to the list of all resources associated with a + // variable. + // Do not allow duplicates - there is no reason to and it can be 'bad' - + // e.g., having the same object in the OBJS list can cause duplicate + // symbol errors from the linker + if ((varList != null) && !(varList.contains(sourceLocation))) { + // Since we don't know how these files will be used, we store them + // using a "location" + // path rather than a relative path + varList.add(sourceLocation); + if (!buildVarToRuleStringMap.containsKey(varName)) { + // TODO - is this an error? + } else { + // Add the resource name to the makefile line that adds + // resources to the build variable + addMacroAdditionFile(caller, buildVarToRuleStringMap, varName, relativePath, sourceLocation, + generatedSource); + } + } + } + + /** + * Returns the output IPaths for this invocation of the tool with + * the specified source file The priorities for determining the names of the + * outputs of a tool are: 1. If the tool is the build target and primary output, + * use artifact name & extension - This case does not apply here... 2. If an + * option is specified, use the value of the option 3. If a nameProvider is + * specified, call it 4. If outputNames is specified, use it 5. Use the name + * pattern to generate a transformation macro so that the source names can be + * transformed into the target names using the built-in string substitution + * functions of make. + * + * @param relativePath + * build output directory relative path of the current output + * directory + * @param enumeratedOutputs + * Vector of IPaths of outputs that are relative to the build + * directory + */ + private void calculateOutputsForSource(ITool tool, String relativePath, IResource resource, IPath sourceLocation, + List enumeratedOutputs) { + IProject project = getProject(); + IConfiguration config = getConfig(); + String inExt = sourceLocation.getFileExtension(); + String outExt = tool.getOutputExtension(inExt); + // IResourceInfo rcInfo = tool.getParentResourceInfo(); + IOutputType[] outTypes = tool.getOutputTypes(); + if (outTypes != null && outTypes.length > 0) { + for (IOutputType type : outTypes) { + String outputPrefix = type.getOutputPrefix(); + + try { + if (containsSpecialCharacters(sourceLocation.toOSString())) { + outputPrefix = ManagedBuildManager.getBuildMacroProvider().resolveValue(outputPrefix, "", " ", + IBuildMacroProvider.CONTEXT_CONFIGURATION, config); + } else { + outputPrefix = ManagedBuildManager.getBuildMacroProvider().resolveValueToMakefileFormat( + outputPrefix, "", " ", IBuildMacroProvider.CONTEXT_CONFIGURATION, config); + } + } catch (BuildMacroException e) { + /* JABA is not going to write this code */ + } + // } + boolean multOfType = type.getMultipleOfType(); + IOption option = tool.getOptionBySuperClassId(type.getOptionId()); + IManagedOutputNameProviderJaba nameProvider = getJABANameProvider(type); + String[] outputNames = type.getOutputNames(); + // 1. If the tool is the build target and this is the primary + // output, + // use artifact name & extension + // Not appropriate here... + // 2. If an option is specified, use the value of the option + if (option != null) { + try { + List outputList = new ArrayList(); + int optType = option.getValueType(); + if (optType == IOption.STRING) { + outputList.add(outputPrefix + option.getStringValue()); + } else if (optType == IOption.STRING_LIST || optType == IOption.LIBRARIES + || optType == IOption.OBJECTS || optType == IOption.INCLUDE_FILES + || optType == IOption.LIBRARY_PATHS || optType == IOption.LIBRARY_FILES + || optType == IOption.MACRO_FILES) { + List value = (List) option.getValue(); + outputList = value; + ((Tool) tool).filterValues(optType, outputList); + // Add outputPrefix to each if necessary + if (outputPrefix.length() > 0) { + for (int j = 0; j < outputList.size(); j++) { + outputList.set(j, outputPrefix + outputList.get(j)); + } + } + } + for (int j = 0; j < outputList.size(); j++) { + String outputName = outputList.get(j); + // try to resolve the build macros in the output + // names + try { + String resolved = null; + if (containsSpecialCharacters(sourceLocation.toOSString())) { + resolved = ManagedBuildManager.getBuildMacroProvider().resolveValue(outputName, "", + " ", IBuildMacroProvider.CONTEXT_FILE, + new FileContextData(sourceLocation, null, option, tool)); + } else { + resolved = ManagedBuildManager.getBuildMacroProvider().resolveValueToMakefileFormat( + outputName, "", " ", IBuildMacroProvider.CONTEXT_FILE, + new FileContextData(sourceLocation, null, option, tool)); + } + if ((resolved = resolved.trim()).length() > 0) + outputName = resolved; + } catch (BuildMacroException e) { + /* JABA is not going to write this code */ + } + IPath outPath = Path.fromOSString(outputName); + // If only a file name is specified, add the + // relative path of this output directory + if (outPath.segmentCount() == 1) { + outPath = Path.fromOSString(relativePath + outputList.get(j)); + } + enumeratedOutputs.add(resolvePercent(outPath, sourceLocation)); + } + } catch (BuildException ex) { + /* JABA is not going to write this code */ + } + } else + // 3. If a nameProvider is specified, call it + if (nameProvider != null) { + IPath outPath = null; + outPath = nameProvider.getOutputName(project, config, tool, resource.getProjectRelativePath()); + if (outPath != null) { // MODDED BY JABA ADDED to handle + // null as return value + caller.usedOutType = type; // MODDED By JABA added to + // return the + // output type used to generate the + // command line + String outputName = outPath.toOSString(); + // try to resolve the build macros in the output + // names + try { + String resolved = null; + if (containsSpecialCharacters(sourceLocation.toOSString())) { + resolved = ManagedBuildManager.getBuildMacroProvider().resolveValue(outputName, "", " ", + IBuildMacroProvider.CONTEXT_FILE, + new FileContextData(sourceLocation, null, option, tool)); + } else { + resolved = ManagedBuildManager.getBuildMacroProvider().resolveValueToMakefileFormat( + outputName, "", " ", IBuildMacroProvider.CONTEXT_FILE, + new FileContextData(sourceLocation, null, option, tool)); + } + if ((resolved = resolved.trim()).length() > 0) + outputName = resolved; + } catch (BuildMacroException e) { + // JABA is not + // going to write + // this code + } + // If only a file name is specified, add the + // relative path of this output directory + if (outPath.segmentCount() == 1) { + outPath = Path.fromOSString(relativePath + outPath.toOSString()); + } + enumeratedOutputs.add(resolvePercent(outPath, sourceLocation)); + } // MODDED BY JABA ADDED + } else + // 4. If outputNames is specified, use it + if (outputNames != null) { + for (int j = 0; j < outputNames.length; j++) { + String outputName = outputNames[j]; + try { + // try to resolve the build macros in the output + // names + String resolved = ManagedBuildManager.getBuildMacroProvider().resolveValueToMakefileFormat( + outputName, "", " ", IBuildMacroProvider.CONTEXT_FILE, + new FileContextData(sourceLocation, null, option, tool)); + if ((resolved = resolved.trim()).length() > 0) + outputName = resolved; + } catch (BuildMacroException e) { + /* JABA is not going to write this code */ + } + IPath outPath = Path.fromOSString(outputName); + // If only a file name is specified, add the relative + // path of this output directory + if (outPath.segmentCount() == 1) { + outPath = Path.fromOSString(relativePath + outPath.toOSString()); + } + enumeratedOutputs.add(resolvePercent(outPath, sourceLocation)); + } + } else { + // 5. Use the name pattern to generate a transformation + // macro + // so that the source names can be transformed into the + // target names + // using the built-in string substitution functions of + // make. + if (multOfType) { + // This case is not handled - a nameProvider or + // outputNames must be specified + // TODO - report error + } else { + String namePattern = type.getNamePattern(); + IPath namePatternPath = null; + if (namePattern == null || namePattern.length() == 0) { + namePattern = relativePath + outputPrefix + IManagedBuilderMakefileGenerator.WILDCARD; + if (outExt != null && outExt.length() > 0) { + namePattern += DOT + outExt; + } + namePatternPath = Path.fromOSString(namePattern); + } else { + if (outputPrefix.length() > 0) { + namePattern = outputPrefix + namePattern; + } + namePatternPath = Path.fromOSString(namePattern); + // If only a file name is specified, add the + // relative path of this output directory + if (namePatternPath.segmentCount() == 1) { + namePatternPath = Path.fromOSString(relativePath + namePatternPath.toOSString()); + } + } + enumeratedOutputs.add(resolvePercent(namePatternPath, sourceLocation)); + } + } + } + } + } + + /** + * Returns any additional resources specified for the tool in other InputType + * elements and AdditionalInput elements + */ + protected IPath[] getAdditionalResourcesForSource(ITool tool) { + IProject project = getProject(); + List allRes = new ArrayList<>(); + IInputType[] types = tool.getInputTypes(); + for (IInputType type : types) { + // Additional resources come from 2 places. + // 1. From AdditionalInput childen + IPath[] res = type.getAdditionalResources(); + for (IPath re : res) { + allRes.add(re); + } + // 2. From InputTypes that other than the primary input type + if (!type.getPrimaryInput() && type != tool.getPrimaryInputType()) { + String var = type.getBuildVariable(); + if (var != null && var.length() > 0) { + allRes.add(Path.fromOSString("$(" + type.getBuildVariable() + ")")); + } else { + // Use file extensions + String[] typeExts = type.getSourceExtensions(tool); + for (IResource projectResource : caller.projectResources) { + if (projectResource.getType() == IResource.FILE) { + String fileExt = projectResource.getFileExtension(); + if (fileExt == null) { + fileExt = ""; + } + for (String typeExt : typeExts) { + if (fileExt.equals(typeExt)) { + allRes.add(projectResource.getProjectRelativePath()); + break; + } + } + } + } + } + // If an assignToOption has been specified, set the value of the + // option to the inputs + IOption assignToOption = tool.getOptionBySuperClassId(type.getAssignToOptionId()); + IOption option = tool.getOptionBySuperClassId(type.getOptionId()); + if (assignToOption != null && option == null) { + try { + int optType = assignToOption.getValueType(); + IResourceInfo rcInfo = tool.getParentResourceInfo(); + if (rcInfo != null) { + if (optType == IOption.STRING) { + String optVal = ""; + for (int j = 0; j < allRes.size(); j++) { + if (j != 0) { + optVal += " "; + } + String resPath = allRes.get(j).toString(); + if (!resPath.startsWith("$(")) { + IResource addlResource = project.getFile(resPath); + if (addlResource != null) { + IPath addlPath = addlResource.getLocation(); + if (addlPath != null) { + resPath = ManagedBuildManager + .calculateRelativePath(getTopBuildDir(), addlPath).toString(); + } + } + } + optVal += ManagedBuildManager + .calculateRelativePath(getTopBuildDir(), Path.fromOSString(resPath)) + .toString(); + } + ManagedBuildManager.setOption(rcInfo, tool, assignToOption, optVal); + } else if (optType == IOption.STRING_LIST || optType == IOption.LIBRARIES + || optType == IOption.OBJECTS || optType == IOption.INCLUDE_FILES + || optType == IOption.LIBRARY_PATHS || optType == IOption.LIBRARY_FILES + || optType == IOption.MACRO_FILES) { + // TODO: do we need to do anything with undefs + // here? + // Note that the path(s) must be translated from + // project relative + // to top build directory relative + String[] paths = new String[allRes.size()]; + for (int j = 0; j < allRes.size(); j++) { + paths[j] = allRes.get(j).toString(); + if (!paths[j].startsWith("$(")) { + IResource addlResource = project.getFile(paths[j]); + if (addlResource != null) { + IPath addlPath = addlResource.getLocation(); + if (addlPath != null) { + paths[j] = ManagedBuildManager + .calculateRelativePath(getTopBuildDir(), addlPath).toString(); + } + } + } + } + ManagedBuildManager.setOption(rcInfo, tool, assignToOption, paths); + } else if (optType == IOption.BOOLEAN) { + boolean b = false; + if (allRes.size() > 0) + b = true; + ManagedBuildManager.setOption(rcInfo, tool, assignToOption, b); + } else if (optType == IOption.ENUMERATED || optType == IOption.TREE) { + if (allRes.size() > 0) { + String s = allRes.get(0).toString(); + ManagedBuildManager.setOption(rcInfo, tool, assignToOption, s); + } + } + allRes.clear(); + } + } catch (BuildException ex) { + /* JABA is not going to write this code */ + } + } + } + } + return allRes.toArray(new IPath[allRes.size()]); + } + + /** + * If the path contains a %, returns the path resolved using the resource name + */ + private IPath resolvePercent(IPath outPath, IPath sourceLocation) { + // Get the input file name + String fileName = sourceLocation.removeFileExtension().lastSegment(); + // Replace the % with the file name + String outName = outPath.toOSString().replace("%", fileName); + IPath result = Path.fromOSString(outName); + return DOT_SLASH_PATH.isPrefixOf(outPath) ? DOT_SLASH_PATH.append(result) : result; + } + + /* + * Add any dependency calculator options to the tool options + */ + private String[] addDependencyOptions(IManagedDependencyCommands depCommands, String[] flags) { + String[] depOptions = depCommands.getDependencyCommandOptions(); + if (depOptions != null && depOptions.length > 0) { + int flagsLen = flags.length; + String[] flagsCopy = new String[flags.length + depOptions.length]; + for (int i = 0; i < flags.length; i++) { + flagsCopy[i] = flags[i]; + } + for (int i = 0; i < depOptions.length; i++) { + flagsCopy[i + flagsLen] = depOptions[i]; + } + flags = flagsCopy; + } + return flags; + } + + private IManagedCommandLineInfo generateToolCommandLineInfo(ITool tool, String sourceExtension, String[] flags, + String outputFlag, String outputPrefix, String outputName, String[] inputResources, IPath inputLocation, + IPath outputLocation) { + IConfiguration config = getConfig(); + String cmd = tool.getToolCommand(); + // try to resolve the build macros in the tool command + try { + String resolvedCommand = null; + if ((inputLocation != null && inputLocation.toString().indexOf(" ") != -1) + || (outputLocation != null && outputLocation.toString().indexOf(" ") != -1)) { + resolvedCommand = ManagedBuildManager.getBuildMacroProvider().resolveValue(cmd, "", " ", + IBuildMacroProvider.CONTEXT_FILE, + new FileContextData(inputLocation, outputLocation, null, tool)); + } else { + resolvedCommand = ManagedBuildManager.getBuildMacroProvider().resolveValueToMakefileFormat(cmd, "", " ", + IBuildMacroProvider.CONTEXT_FILE, + new FileContextData(inputLocation, outputLocation, null, tool)); + } + if ((resolvedCommand = resolvedCommand.trim()).length() > 0) + cmd = resolvedCommand; + } catch (BuildMacroException e) { + /* JABA is not going to write this code */ + } + IManagedCommandLineGenerator gen = tool.getCommandLineGenerator(); + return gen.generateCommandLineInfo(tool, cmd, flags, outputFlag, outputPrefix, outputName, inputResources, + getToolCommandLinePattern(config, tool)); + } + + /** + * Returns the dependency IPaths for this invocation of the tool + * with the specified source file + * + * @param depGen + * the dependency calculator + * @param tool + * tool used to build the source file + * @param relativePath + * build output directory relative path of the current output + * directory + * @param resource + * source file to scan for dependencies + * @return Vector of IPaths that are relative to the build directory + */ + private IPath[] oldCalculateDependenciesForSource(IManagedDependencyGenerator depGen, ITool tool, + String relativePath, IResource resource) { + IProject project = getProject(); + Vector deps = new Vector(); + int type = depGen.getCalculatorType(); + switch (type) { + case IManagedDependencyGeneratorType.TYPE_INDEXER: + case IManagedDependencyGeneratorType.TYPE_EXTERNAL: + IResource[] res = depGen.findDependencies(resource, project); + if (res != null) { + for (IResource re : res) { + IPath dep = null; + if (re != null) { + IPath addlPath = re.getLocation(); + if (addlPath != null) { + dep = ManagedBuildManager.calculateRelativePath(getTopBuildDir(), addlPath); + } + } + if (dep != null) { + deps.add(dep); + } + } + } + break; + case IManagedDependencyGeneratorType.TYPE_NODEPS: + default: + break; + } + return deps.toArray(new IPath[deps.size()]); + } + + /** + * Returns the dependency IPaths relative to the build directory + * + * @param depCalculator + * the dependency calculator + * @return IPath[] that are relative to the build directory + */ + private IPath[] calculateDependenciesForSource(IManagedDependencyCalculator depCalculator) { + IProject project = getProject(); + IPath[] addlDeps = depCalculator.getDependencies(); + if (addlDeps != null) { + for (int i = 0; i < addlDeps.length; i++) { + if (!addlDeps[i].isAbsolute()) { + // Convert from project relative to build directory relative + IPath absolutePath = project.getLocation().append(addlDeps[i]); + addlDeps[i] = ManagedBuildManager.calculateRelativePath(getTopBuildDir(), absolutePath); + } + } + } + return addlDeps; + } + +} diff --git a/io.sloeber.core/src/io/sloeber/managedBuild/Internal/ToolInfoHolder.java b/io.sloeber.core/src/io/sloeber/managedBuild/Internal/ToolInfoHolder.java new file mode 100644 index 000000000..b41d07e2d --- /dev/null +++ b/io.sloeber.core/src/io/sloeber/managedBuild/Internal/ToolInfoHolder.java @@ -0,0 +1,44 @@ +package io.sloeber.managedBuild.Internal; + +import java.util.List; +import java.util.Set; + +import org.eclipse.cdt.core.settings.model.util.PathSettingsContainer; +import org.eclipse.cdt.managedbuilder.core.IFileInfo; +import org.eclipse.cdt.managedbuilder.core.IResourceInfo; +import org.eclipse.cdt.managedbuilder.core.ITool; +import org.eclipse.core.runtime.IPath; + +public class ToolInfoHolder { + public ITool[] buildTools; + public boolean[] buildToolsUsed; + public ArduinoManagedBuildGnuToolInfo[] gnuToolInfos; + public Set outputExtensionsSet; + public List dependencyMakefiles; + + public static ToolInfoHolder getToolInfo(ArduinoGnuMakefileGenerator caller, IPath path) { + return getToolInfo(caller, path, false); + } + + public static ToolInfoHolder getToolInfo(ArduinoGnuMakefileGenerator caller, IPath path, boolean create) { + PathSettingsContainer child = caller.toolInfos.getChildContainer(path, create, create); + ToolInfoHolder h = null; + if (child != null) { + h = (ToolInfoHolder) child.getValue(); + if (h == null && create) { + h = new ToolInfoHolder(); + child.setValue(h); + } + } + return h; + } + + public static ToolInfoHolder getFolderToolInfo(ArduinoGnuMakefileGenerator caller, IPath path) { + IResourceInfo rcInfo = caller.config.getResourceInfo(path, false); + while (rcInfo instanceof IFileInfo) { + path = path.removeLastSegments(1); + rcInfo = caller.config.getResourceInfo(path, false); + } + return getToolInfo(caller, path, false); + } +} diff --git a/io.sloeber.core/src/io/sloeber/managedBuild/Internal/TopMakeFileGenerator.java b/io.sloeber.core/src/io/sloeber/managedBuild/Internal/TopMakeFileGenerator.java new file mode 100644 index 000000000..db77db6de --- /dev/null +++ b/io.sloeber.core/src/io/sloeber/managedBuild/Internal/TopMakeFileGenerator.java @@ -0,0 +1,820 @@ +package io.sloeber.managedBuild.Internal; + +import static io.sloeber.managedBuild.Internal.ManagebBuildCommon.*; +import static io.sloeber.managedBuild.Internal.ManagedBuildConstants.*; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map.Entry; +import java.util.Vector; + +import org.eclipse.cdt.core.settings.model.ICConfigurationDescription; +import org.eclipse.cdt.core.settings.model.util.PathSettingsContainer; +import org.eclipse.cdt.managedbuilder.core.BuildException; +import org.eclipse.cdt.managedbuilder.core.IConfiguration; +import org.eclipse.cdt.managedbuilder.core.IInputType; +import org.eclipse.cdt.managedbuilder.core.IManagedCommandLineGenerator; +import org.eclipse.cdt.managedbuilder.core.IManagedCommandLineInfo; +import org.eclipse.cdt.managedbuilder.core.IOutputType; +import org.eclipse.cdt.managedbuilder.core.ITool; +import org.eclipse.cdt.managedbuilder.core.ManagedBuildManager; +import org.eclipse.cdt.managedbuilder.internal.core.ManagedMakeMessages; +import org.eclipse.cdt.managedbuilder.internal.macros.FileContextData; +import org.eclipse.cdt.managedbuilder.macros.BuildMacroException; +import org.eclipse.cdt.managedbuilder.macros.IBuildMacroProvider; +import org.eclipse.cdt.managedbuilder.makegen.gnu.IManagedBuildGnuToolInfo; +import org.eclipse.core.resources.IContainer; +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.Path; + +public class TopMakeFileGenerator { + private ArduinoGnuMakefileGenerator caller; + + private IConfiguration getConfig() { + return caller.getConfig(); + } + + private IProject getProject() { + return caller.getProject(); + } + + TopMakeFileGenerator(ArduinoGnuMakefileGenerator theCaller) { + caller = theCaller; + } + + /** + * Returns the map of build variables used in the top makefile to list of files + * + * @return HashMap + */ + private LinkedHashMap getTopBuildOutputVars() { + return caller.getTopBuildOutputVars(); + } + + /** + * @return Collection of subdirectories (IContainers) contributing source code + * to the build + */ + private Collection getSubdirList() { + return caller.getSubdirList(); + } + + private Vector getRuleList() { + return caller.getRuleList(); + } + + public List getDepLineList() { + return caller.getDepLineList(); + } + + public PathSettingsContainer getToolInfos() { + return caller.getToolInfos(); + } + + /** + * Create the entire contents of the makefile. + * + * @param fileHandle + * The file to place the contents in. + * @param rebuild + * FLag signaling that the user is doing a full rebuild + */ + public void populateTopMakefile(IFile fileHandle, boolean rebuild) throws CoreException { + StringBuffer buffer = new StringBuffer(); + // Add the header + buffer.append(addTopHeader()); + // Add the macro definitions + buffer.append(addMacros()); + // List to collect needed build output variables + List outputVarsAdditionsList = new ArrayList(); + // Determine target rules + StringBuffer targetRules = addTargets(outputVarsAdditionsList, rebuild); + // Add outputMacros that were added to by the target rules + buffer.append(writeTopAdditionMacros(outputVarsAdditionsList, getTopBuildOutputVars())); + // Add target rules + buffer.append(targetRules); + // Save the file + save(buffer, fileHandle); + } + + /************************************************************************* + * M A I N (makefile) M A K E F I L E M E T H O D S + ************************************************************************/ + /** + * Answers a StringBuffer containing the comment(s) for the + * top-level makefile. + */ + private StringBuffer addTopHeader() { + return addDefaultHeader(); + } + + /** + */ + private StringBuffer addMacros() { + IConfiguration config = getConfig(); + StringBuffer buffer = new StringBuffer(); + buffer.append("-include " + ROOT + FILE_SEPARATOR + MAKEFILE_INIT).append(NEWLINE); + buffer.append(NEWLINE); + // Get the clean command from the build model + buffer.append("RM := "); + // support macros in the clean command + String cleanCommand = config.getCleanCommand(); + try { + cleanCommand = ManagedBuildManager.getBuildMacroProvider().resolveValueToMakefileFormat( + config.getCleanCommand(), EMPTY_STRING, WHITESPACE, IBuildMacroProvider.CONTEXT_CONFIGURATION, + config); + } catch (BuildMacroException e) { + // jaba is not going to write this code + } + + buffer.append(cleanCommand).append(NEWLINE); + buffer.append(NEWLINE); + // Now add the source providers + buffer.append(COMMENT_SYMBOL).append(WHITESPACE).append(ManagedMakeMessages.getResourceString(SRC_LISTS)) + .append(NEWLINE); + buffer.append("-include sources.mk").append(NEWLINE); + // JABA Change the include of the "root" (our sketch) folder to be + // before + // libraries and other files + buffer.append("-include subdir.mk").append(NEWLINE); + // Add includes for each subdir in child-subdir-first order (required + // for makefile rule matching to work). + List subDirList = new ArrayList<>(); + for (IContainer subDir : getSubdirList()) { + String projectRelativePath = subDir.getProjectRelativePath().toOSString(); + if (!projectRelativePath.isEmpty()) + subDirList.add(0, projectRelativePath); + } + Collections.sort(subDirList, Collections.reverseOrder()); + for (String dir : subDirList) { + buffer.append("-include ").append(escapeWhitespaces(dir)).append(FILE_SEPARATOR).append("subdir.mk") + .append(NEWLINE); + } + // Change the include of the "root" (our sketch) folder to be before + // libraries and other files + // buffer.append("-include subdir.mk" + NEWLINE); // + buffer.append("-include objects.mk").append(NEWLINE).append(NEWLINE); + // Include generated dependency makefiles if non-empty AND a "clean" has + // not been requested + if (!caller.buildDepVars.isEmpty()) { + buffer.append("ifneq ($(MAKECMDGOALS),clean)").append(NEWLINE); + for (Entry entry : caller.buildDepVars.entrySet()) { + String depsMacro = entry.getKey(); + ArduinoGnuDependencyGroupInfo info = entry.getValue(); + buffer.append("ifneq ($(strip $(").append(depsMacro).append(")),)").append(NEWLINE); + if (info.conditionallyInclude) { + buffer.append("-include $(").append(depsMacro).append(')').append(NEWLINE); + } else { + buffer.append("include $(").append(depsMacro).append(')').append(NEWLINE); + } + buffer.append("endif").append(NEWLINE); + } + buffer.append("endif").append(NEWLINE).append(NEWLINE); + } + // Include makefile.defs supplemental makefile + buffer.append("-include ").append(ROOT).append(FILE_SEPARATOR).append(MAKEFILE_DEFS).append(NEWLINE); + return (buffer.append(NEWLINE)); + } + + private StringBuffer addTargets(List outputVarsAdditionsList, boolean rebuild) { + IConfiguration config = getConfig(); + StringBuffer buffer = new StringBuffer(); + // IConfiguration config = info.getDefaultConfiguration(); + // Assemble the information needed to generate the targets + String prebuildStep = config.getPrebuildStep(); + // JABA issue927 adding recipe.hooks.sketch.prebuild.NUMBER.pattern as cdt + // prebuild command if needed + ICConfigurationDescription confDesc = ManagedBuildManager.getDescriptionForConfiguration(config); + String sketchPrebuild = io.sloeber.core.common.Common.getBuildEnvironmentVariable(confDesc, "sloeber.prebuild", + new String(), false); + if (!sketchPrebuild.isEmpty()) { + String separator = new String(); + if (!prebuildStep.isEmpty()) { + prebuildStep = prebuildStep + "\n\t" + sketchPrebuild; + } else { + prebuildStep = sketchPrebuild; + } + } + // end off JABA issue927 + try { + // try to resolve the build macros in the prebuild step + prebuildStep = ManagedBuildManager.getBuildMacroProvider().resolveValueToMakefileFormat(prebuildStep, + EMPTY_STRING, WHITESPACE, IBuildMacroProvider.CONTEXT_CONFIGURATION, config); + } catch (BuildMacroException e) { + /* JABA is not going to write this code */ + } + prebuildStep = prebuildStep.trim(); + String postbuildStep = config.getPostbuildStep(); + try { + // try to resolve the build macros in the postbuild step + postbuildStep = ManagedBuildManager.getBuildMacroProvider().resolveValueToMakefileFormat(postbuildStep, + EMPTY_STRING, WHITESPACE, IBuildMacroProvider.CONTEXT_CONFIGURATION, config); + } catch (BuildMacroException e) { + /* JABA is not going to write this code */ + } + postbuildStep = postbuildStep.trim(); + String preannouncebuildStep = config.getPreannouncebuildStep(); + String postannouncebuildStep = config.getPostannouncebuildStep(); + String targets = rebuild ? "clean all" : "all"; + ITool targetTool = config.calculateTargetTool(); + // if (targetTool == null) { + // targetTool = info.getToolFromOutputExtension(buildTargetExt); + // } + // Get all the projects the build target depends on + // If this configuration produces a static archive, building the archive + // doesn't depend on the output + // from any of the referenced configurations + IConfiguration[] refConfigs = new IConfiguration[0]; + if (config.getBuildArtefactType() == null || !ManagedBuildManager.BUILD_ARTEFACT_TYPE_PROPERTY_STATICLIB + .equals(config.getBuildArtefactType().getId())) + refConfigs = ManagedBuildManager.getReferencedConfigurations(config); + /* + * try { refdProjects = project.getReferencedProjects(); } catch (CoreException + * e) { // There are 2 exceptions; the project does not exist or it is not open + * // and neither conditions apply if we are building for it .... } + */ + // If a prebuild step exists, redefine the all target to be + // all: {pre-build} main-build + // and then reset the "traditional" all target to main-build + // This will allow something meaningful to happen if the generated + // makefile is + // extracted and run standalone via "make all" + // + + // JABA add the arduino upload/program targets + buffer.append("\n#bootloaderTest\n" + "BurnBootLoader: \n" + + "\t@echo trying to burn bootloader ${bootloader.tool}\n" + + "\t${tools.${bootloader.tool}.erase.pattern}\n" + "\t${tools.${bootloader.tool}.bootloader.pattern}\n" + + "\n" + "uploadWithBuild: all\n" + + "\t@echo trying to build and upload with upload tool ${upload.tool}\n" + + "\t${tools.${upload.tool}.upload.pattern}\n" + "\n" + "uploadWithoutBuild: \n" + + "\t@echo trying to upload without build with upload tool ${upload.tool}\n" + + "\t${tools.${upload.tool}.upload.pattern}\n" + " \n" + "uploadWithProgrammerWithBuild: all\n" + + "\t@echo trying to build and upload with programmer ${program.tool}\n" + + "\t${tools.${program.tool}.program.pattern}\n" + "\n" + "uploadWithProgrammerWithoutBuild: \n" + + "\t@echo trying to upload with programmer ${program.tool} without build\n" + + "\t${tools.${program.tool}.program.pattern}\n\n"); + String defaultTarget = "all:"; + if (prebuildStep.length() > 0) { + // Add the comment for the "All" target + buffer.append(COMMENT_SYMBOL).append(WHITESPACE).append(ManagedMakeMessages.getResourceString(ALL_TARGET)) + .append(NEWLINE); + buffer.append(defaultTarget).append(NEWLINE); + buffer.append(TAB).append(MAKE).append(WHITESPACE).append(NO_PRINT_DIR).append(WHITESPACE).append(PREBUILD) + .append(NEWLINE); + buffer.append(TAB).append(MAKE).append(WHITESPACE).append(NO_PRINT_DIR).append(WHITESPACE).append(MAINBUILD) + .append(NEWLINE); + buffer.append(NEWLINE); + defaultTarget = MAINBUILD.concat(COLON); + buffer.append(COMMENT_SYMBOL).append(WHITESPACE) + .append(ManagedMakeMessages.getResourceString(MAINBUILD_TARGET)).append(NEWLINE); + } else + // Add the comment for the "All" target + buffer.append(COMMENT_SYMBOL).append(WHITESPACE).append(ManagedMakeMessages.getResourceString(ALL_TARGET)) + .append(NEWLINE); + // Write out the all target first in case someone just runs make + // all: or mainbuild: + String outputPrefix = EMPTY_STRING; + if (targetTool != null) { + outputPrefix = targetTool.getOutputPrefix(); + } + buffer.append(defaultTarget).append(WHITESPACE).append(outputPrefix) + .append(ensurePathIsGNUMakeTargetRuleCompatibleSyntax(caller.buildTargetName)); + if (caller.buildTargetExt.length() > 0) { + buffer.append(DOT).append(caller.buildTargetExt); + } + // Add the Secondary Outputs to the all target, if any + IOutputType[] secondaryOutputs = config.getToolChain().getSecondaryOutputs(); + if (secondaryOutputs.length > 0) { + buffer.append(WHITESPACE).append(SECONDARY_OUTPUTS); + } + buffer.append(NEWLINE).append(NEWLINE); + /* + * The build target may depend on other projects in the workspace. These are + * captured in the deps target: deps: ; $(MAKE) [clean + * all | all]> + */ + // Vector managedProjectOutputs = new Vector(refdProjects.length); + // if (refdProjects.length > 0) { + Vector managedProjectOutputs = new Vector(refConfigs.length); + if (refConfigs.length > 0) { + boolean addDeps = true; + // if (refdProjects != null) { + for (IConfiguration depCfg : refConfigs) { + // IProject dep = refdProjects[i]; + if (!depCfg.isManagedBuildOn()) + continue; + // if (!dep.exists()) continue; + if (addDeps) { + buffer.append("dependents:").append(NEWLINE); + addDeps = false; + } + String buildDir = depCfg.getOwner().getLocation().toOSString(); + String depTargets = targets; + // if (ManagedBuildManager.manages(dep)) { + // Add the current configuration to the makefile path + // IManagedBuildInfo depInfo = + // ManagedBuildManager.getBuildInfo(dep); + buildDir += FILE_SEPARATOR + depCfg.getName(); + // Extract the build artifact to add to the dependency list + String depTarget = depCfg.getArtifactName(); + String depExt = depCfg.getArtifactExtension(); + try { + // try to resolve the build macros in the artifact extension + depExt = ManagedBuildManager.getBuildMacroProvider().resolveValueToMakefileFormat(depExt, "", " ", + IBuildMacroProvider.CONTEXT_CONFIGURATION, depCfg); + } catch (BuildMacroException e) { + /* JABA is not going to write this code */ + } + try { + // try to resolve the build macros in the artifact name + String resolved = ManagedBuildManager.getBuildMacroProvider().resolveValueToMakefileFormat( + depTarget, "", " ", IBuildMacroProvider.CONTEXT_CONFIGURATION, depCfg); + if ((resolved = resolved.trim()).length() > 0) + depTarget = resolved; + } catch (BuildMacroException e) { + /* JABA is not going to write this code */ + } + String depPrefix = depCfg.getOutputPrefix(depExt); + if (depCfg.needsRebuild()) { + depTargets = "clean all"; + } + String dependency = buildDir + FILE_SEPARATOR + depPrefix + depTarget; + if (depExt.length() > 0) { + dependency += DOT + depExt; + } + dependency = escapeWhitespaces(dependency); + managedProjectOutputs.add(dependency); + // } + buffer.append(TAB).append("-cd").append(WHITESPACE).append(escapeWhitespaces(buildDir)) + .append(WHITESPACE).append(LOGICAL_AND).append(WHITESPACE).append("$(MAKE) ").append(depTargets) + .append(NEWLINE); + } + // } + buffer.append(NEWLINE); + } + // Add the targets tool rules + buffer.append(addTargetsRules(targetTool, outputVarsAdditionsList, managedProjectOutputs, + (postbuildStep.length() > 0))); + // Add the prebuild step target, if specified + if (prebuildStep.length() > 0) { + buffer.append(PREBUILD).append(COLON).append(NEWLINE); + if (preannouncebuildStep.length() > 0) { + buffer.append(TAB).append(DASH).append(AT).append(escapedEcho(preannouncebuildStep)); + } + buffer.append(TAB).append(DASH).append(prebuildStep).append(NEWLINE); + buffer.append(TAB).append(DASH).append(AT).append(ECHO_BLANK_LINE).append(NEWLINE); + } + // Add the postbuild step, if specified + if (postbuildStep.length() > 0) { + buffer.append(POSTBUILD).append(COLON).append(NEWLINE); + if (postannouncebuildStep.length() > 0) { + buffer.append(TAB).append(DASH).append(AT).append(escapedEcho(postannouncebuildStep)); + } + buffer.append(TAB).append(DASH).append(postbuildStep).append(NEWLINE); + buffer.append(TAB).append(DASH).append(AT).append(ECHO_BLANK_LINE).append(NEWLINE); + } + // Add the Secondary Outputs target, if needed + if (secondaryOutputs.length > 0) { + buffer.append(SECONDARY_OUTPUTS).append(COLON); + Vector outs2 = calculateSecondaryOutputs(secondaryOutputs); + for (int i = 0; i < outs2.size(); i++) { + buffer.append(WHITESPACE).append("$(").append(outs2.get(i)).append(')'); + } + buffer.append(NEWLINE).append(NEWLINE); + } + // Add all the needed dummy and phony targets + buffer.append(".PHONY: all clean dependents"); + if (prebuildStep.length() > 0) { + buffer.append(WHITESPACE).append(MAINBUILD).append(WHITESPACE).append(PREBUILD); + } + if (postbuildStep.length() > 0) { + buffer.append(WHITESPACE).append(POSTBUILD); + } + buffer.append(NEWLINE); + for (String output : managedProjectOutputs) { + buffer.append(output).append(COLON).append(NEWLINE); + } + buffer.append(NEWLINE); + // Include makefile.targets supplemental makefile + buffer.append("-include ").append(ROOT).append(FILE_SEPARATOR).append(MAKEFILE_TARGETS).append(NEWLINE); + return buffer; + } + + /** + * Create the rule + * + * @param buffer + * Buffer to add makefile rules to + * @param bTargetTool + * True if this is the target tool + * @param targetName + * If this is the "targetTool", the target file name, else + * null + * @param targetExt + * If this is the "targetTool", the target file extension, else + * null + * @param outputVarsAdditionsList + * list to add needed build output variables to + * @param managedProjectOutputs + * Other projects in the workspace that this project depends upon + * @param bEmitPostBuildStepCall + * Emit post-build step invocation + */ + protected boolean addRuleForTool(ITool tool, StringBuffer buffer, boolean bTargetTool, String targetName, + String targetExt, List outputVarsAdditionsList, Vector managedProjectOutputs, + boolean bEmitPostBuildStepCall) { + IConfiguration config = getConfig(); + Vector inputs = new Vector(); + Vector dependencies = new Vector(); + Vector outputs = new Vector(); + Vector enumeratedPrimaryOutputs = new Vector(); + Vector enumeratedSecondaryOutputs = new Vector(); + Vector outputVariables = new Vector(); + Vector additionalTargets = new Vector(); + String outputPrefix = EMPTY_STRING; + if (!getToolInputsOutputs(tool, inputs, dependencies, outputs, enumeratedPrimaryOutputs, + enumeratedSecondaryOutputs, outputVariables, additionalTargets, bTargetTool, managedProjectOutputs)) { + return false; + } + // If we have no primary output, make all of the secondary outputs the + // primary output + if (enumeratedPrimaryOutputs.size() == 0) { + enumeratedPrimaryOutputs = enumeratedSecondaryOutputs; + enumeratedSecondaryOutputs.clear(); + } + // Add the output variables for this tool to our list + outputVarsAdditionsList.addAll(outputVariables); + // Create the build rule + String buildRule = EMPTY_STRING; + String outflag = tool.getOutputFlag(); + String primaryOutputs = EMPTY_STRING; + String primaryOutputsQuoted = EMPTY_STRING; + boolean first = true; + for (int i = 0; i < enumeratedPrimaryOutputs.size(); i++) { + String output = enumeratedPrimaryOutputs.get(i); + if (!first) { + primaryOutputs += WHITESPACE; + primaryOutputsQuoted += WHITESPACE; + } + first = false; + primaryOutputs += new Path(output).toOSString(); + primaryOutputsQuoted += ensurePathIsGNUMakeTargetRuleCompatibleSyntax(new Path(output).toOSString()); + } + buildRule += (primaryOutputsQuoted + COLON + WHITESPACE); + first = true; + String calculatedDependencies = EMPTY_STRING; + for (int i = 0; i < dependencies.size(); i++) { + String input = dependencies.get(i); + if (!first) + calculatedDependencies += WHITESPACE; + first = false; + calculatedDependencies += input; + } + buildRule += calculatedDependencies; + // We can't have duplicates in a makefile + if (getRuleList().contains(buildRule)) { + /* JABA is not going to write this code */ + } else { + getRuleList().add(buildRule); + buffer.append(buildRule).append(NEWLINE); + if (bTargetTool) { + buffer.append(TAB).append(AT).append(escapedEcho(MESSAGE_START_BUILD + WHITESPACE + OUT_MACRO)); + } + buffer.append(TAB).append(AT).append(escapedEcho(tool.getAnnouncement())); + // Get the command line for this tool invocation + String[] flags; + try { + flags = tool.getToolCommandFlags(null, null); + } catch (BuildException ex) { + // TODO report error + flags = EMPTY_STRING_ARRAY; + } + String command = tool.getToolCommand(); + try { + // try to resolve the build macros in the tool command + String resolvedCommand = ManagedBuildManager.getBuildMacroProvider().resolveValueToMakefileFormat( + command, EMPTY_STRING, WHITESPACE, IBuildMacroProvider.CONTEXT_FILE, + new FileContextData(null, null, null, tool)); + if ((resolvedCommand = resolvedCommand.trim()).length() > 0) { + command = resolvedCommand.replace(" \"\" ", " "); + } + } catch (BuildMacroException e) { + /* JABA is not going to write this code */ + } + String[] cmdInputs = inputs.toArray(new String[inputs.size()]); + IManagedCommandLineGenerator gen = tool.getCommandLineGenerator(); + IManagedCommandLineInfo cmdLInfo = gen.generateCommandLineInfo(tool, command, flags, outflag, outputPrefix, + primaryOutputs, cmdInputs, getToolCommandLinePattern(config, tool)); + // The command to build + String buildCmd = null; + if (cmdLInfo == null) { + String toolFlags; + try { + toolFlags = tool.getToolCommandFlagsString(null, null); + } catch (BuildException ex) { + // TODO report error + toolFlags = EMPTY_STRING; + } + buildCmd = command + WHITESPACE + toolFlags + WHITESPACE + outflag + WHITESPACE + outputPrefix + + primaryOutputs + WHITESPACE + IN_MACRO; + } else + buildCmd = cmdLInfo.getCommandLine(); + // resolve any remaining macros in the command after it has been + // generated + try { + //TOFIX JABA heavy hack to get the combiner to work properly + //if the command contains ${ARCHIVES} + //remove the ${AR} + //replace ${ARCHIVES} with ${AR} + String ARCHIVES = " ${ARCHIVES} "; + String AR = " $(AR) "; + if (buildCmd.contains(ARCHIVES)) { + buildCmd = buildCmd.replace(AR, " "); + buildCmd = buildCmd.replace(ARCHIVES, AR); + } + //end JABA heavy hack + String resolvedCommand = ManagedBuildManager.getBuildMacroProvider().resolveValueToMakefileFormat( + buildCmd, EMPTY_STRING, WHITESPACE, IBuildMacroProvider.CONTEXT_FILE, + new FileContextData(null, null, null, tool)); + if ((resolvedCommand = resolvedCommand.trim()).length() > 0) { + buildCmd = resolvedCommand.replace(" \"\" ", " "); + } + } catch (BuildMacroException e) { + /* JABA is not going to write this code */ + } + // buffer.append(TAB).append(AT).append(escapedEcho(buildCmd)); + // buffer.append(TAB).append(AT).append(buildCmd); + buffer.append(TAB).append(buildCmd); + // TODO + // NOTE WELL: Dependency file generation is not handled for this + // type of Tool + // Echo finished message + buffer.append(NEWLINE); + buffer.append(TAB).append(AT).append( + escapedEcho((bTargetTool ? MESSAGE_FINISH_BUILD : MESSAGE_FINISH_FILE) + WHITESPACE + OUT_MACRO)); + buffer.append(TAB).append(AT).append(ECHO_BLANK_LINE); + // If there is a post build step, then add a recursive invocation of + // MAKE to invoke it after the main build + // Note that $(MAKE) will instantiate in the recusive invocation to + // the make command that was used to invoke + // the makefile originally + if (bEmitPostBuildStepCall) { + buffer.append(TAB).append(MAKE).append(WHITESPACE).append(NO_PRINT_DIR).append(WHITESPACE) + .append(POSTBUILD).append(NEWLINE).append(NEWLINE); + } else { + // Just emit a blank line + buffer.append(NEWLINE); + } + } + // If we have secondary outputs, output dependency rules without + // commands + if (enumeratedSecondaryOutputs.size() > 0 || additionalTargets.size() > 0) { + String primaryOutput = enumeratedPrimaryOutputs.get(0); + Vector addlOutputs = new Vector(); + addlOutputs.addAll(enumeratedSecondaryOutputs); + addlOutputs.addAll(additionalTargets); + for (int i = 0; i < addlOutputs.size(); i++) { + String output = addlOutputs.get(i); + String depLine = output + COLON + WHITESPACE + primaryOutput + WHITESPACE + calculatedDependencies + + NEWLINE; + if (!getDepLineList().contains(depLine)) { + getDepLineList().add(depLine); + buffer.append(depLine); + } + } + buffer.append(NEWLINE); + } + return true; + } + + /** + * @param outputVarsAdditionsList + * list to add needed build output variables to + * @param buffer + * buffer to add rules to + */ + private void generateRulesForConsumers(ITool generatingTool, List outputVarsAdditionsList, + StringBuffer buffer) { + // Generate a build rule for any tool that consumes the output of this + // tool + PathSettingsContainer toolInfos = getToolInfos(); + ToolInfoHolder h = (ToolInfoHolder) toolInfos.getValue(); + ITool[] buildTools = h.buildTools; + boolean[] buildToolsUsed = h.buildToolsUsed; + IOutputType[] outTypes = generatingTool.getOutputTypes(); + for (IOutputType outType : outTypes) { + String[] outExts = outType.getOutputExtensions(generatingTool); + String outVariable = outType.getBuildVariable(); + if (outExts != null) { + for (String outExt : outExts) { + for (int k = 0; k < buildTools.length; k++) { + ITool tool = buildTools[k]; + if (!buildToolsUsed[k]) { + // Also has to match build variables if specified + IInputType inType = tool.getInputType(outExt); + if (inType != null) { + String inVariable = inType.getBuildVariable(); + if ((outVariable == null && inVariable == null) || (outVariable != null + && inVariable != null && outVariable.equals(inVariable))) { + if (addRuleForTool(buildTools[k], buffer, false, null, null, + outputVarsAdditionsList, null, false)) { + buildToolsUsed[k] = true; + // Look for tools that consume the + // output + generateRulesForConsumers(buildTools[k], outputVarsAdditionsList, buffer); + } + } + } + } + } + } + } + } + } + + /** + * Returns the targets rules. The targets make file (top makefile) contains: 1 + * the rule for the final target tool 2 the rules for all of the tools that use + * multipleOfType in their primary input type 3 the rules for all tools that use + * the output of #2 tools + * + * @param outputVarsAdditionsList + * list to add needed build output variables to + * @param managedProjectOutputs + * Other projects in the workspace that this project depends upon + * @return StringBuffer + */ + private StringBuffer addTargetsRules(ITool targetTool, List outputVarsAdditionsList, + Vector managedProjectOutputs, boolean postbuildStep) { + StringBuffer buffer = new StringBuffer(); + // Add the comment + buffer.append(COMMENT_SYMBOL).append(WHITESPACE).append(ManagedMakeMessages.getResourceString(BUILD_TOP)) + .append(NEWLINE); + PathSettingsContainer toolInfos = getToolInfos(); + ToolInfoHolder h = (ToolInfoHolder) toolInfos.getValue(); + ITool[] buildTools = h.buildTools; + boolean[] buildToolsUsed = h.buildToolsUsed; + // Get the target tool and generate the rule + if (targetTool != null) { + // Note that the name of the target we pass to addRuleForTool does + // not + // appear to be used there (and tool outputs are consulted + // directly), but + // we quote it anyway just in case it starts to use it in future. + if (addRuleForTool(targetTool, buffer, true, + ensurePathIsGNUMakeTargetRuleCompatibleSyntax(caller.buildTargetName), caller.buildTargetExt, + outputVarsAdditionsList, managedProjectOutputs, postbuildStep)) { + // Mark the target tool as processed + for (int i = 0; i < buildTools.length; i++) { + if (targetTool == buildTools[i]) { + buildToolsUsed[i] = true; + } + } + } + } else { + buffer.append(TAB).append(AT).append(escapedEcho(MESSAGE_NO_TARGET_TOOL + WHITESPACE + OUT_MACRO)); + } + // Generate the rules for all Tools that specify + // InputType.multipleOfType, and any Tools that + // consume the output of those tools. This does not apply to pre-3.0 + // integrations, since + // the only "multipleOfType" tool is the "target" tool + for (int i = 0; i < buildTools.length; i++) { + ITool tool = buildTools[i]; + IInputType type = tool.getPrimaryInputType(); + if (type != null && type.getMultipleOfType()) { + if (!buildToolsUsed[i]) { + addRuleForTool(tool, buffer, false, null, null, outputVarsAdditionsList, null, false); + // Mark the target tool as processed + buildToolsUsed[i] = true; + // Look for tools that consume the output + generateRulesForConsumers(tool, outputVarsAdditionsList, buffer); + } + } + } + // Add the comment + buffer.append(COMMENT_SYMBOL).append(WHITESPACE).append(ManagedMakeMessages.getResourceString(BUILD_TARGETS)) + .append(NEWLINE); + // Always add a clean target + buffer.append("clean:").append(NEWLINE); + buffer.append(TAB).append("-$(RM)").append(WHITESPACE); + for (Entry> entry : caller.buildOutVars.entrySet()) { + String macroName = entry.getKey(); + buffer.append("$(").append(macroName).append(')'); + } + String outputPrefix = EMPTY_STRING; + if (targetTool != null) { + outputPrefix = targetTool.getOutputPrefix(); + } + String completeBuildTargetName = outputPrefix + caller.buildTargetName; + if (caller.buildTargetExt.length() > 0) { + completeBuildTargetName = completeBuildTargetName + DOT + caller.buildTargetExt; + } + // if (completeBuildTargetName.contains(" ")) { + // buffer.append(WHITESPACE + "\"" + completeBuildTargetName + "\""); + // } else { + // buffer.append(WHITESPACE + completeBuildTargetName); + // } + buffer.append(NEWLINE); + buffer.append(TAB).append(DASH).append(AT).append(ECHO_BLANK_LINE).append(NEWLINE); + return buffer; + } + + /** + * Write all macro addition entries in a map to the buffer + */ + private StringBuffer writeTopAdditionMacros(List varList, HashMap varMap) { + StringBuffer buffer = new StringBuffer(); + // Add the comment + buffer.append(COMMENT_SYMBOL).append(WHITESPACE).append(ManagedMakeMessages.getResourceString(MOD_VARS)) + .append(NEWLINE); + for (int i = 0; i < varList.size(); i++) { + String addition = varMap.get(varList.get(i)); + StringBuffer currentBuffer = new StringBuffer(); + currentBuffer.append(addition); + currentBuffer.append(NEWLINE); + // append the contents of the buffer to the master buffer for the + // whole file + buffer.append(currentBuffer); + } + return buffer.append(NEWLINE); + } + + private Vector calculateSecondaryOutputs(IOutputType[] secondaryOutputs) { + PathSettingsContainer toolInfos = getToolInfos(); + ToolInfoHolder h = (ToolInfoHolder) toolInfos.getValue(); + ITool[] buildTools = h.buildTools; + Vector buildVars = new Vector(); + for (int i = 0; i < buildTools.length; i++) { + // Add the specified output build variables + IOutputType[] outTypes = buildTools[i].getOutputTypes(); + if (outTypes != null && outTypes.length > 0) { + for (int j = 0; j < outTypes.length; j++) { + IOutputType outType = outTypes[j]; + // Is this one of the secondary outputs? + // Look for an outputType with this ID, or one with a + // superclass with this id + thisType: for (int k = 0; k < secondaryOutputs.length; k++) { + IOutputType matchType = outType; + do { + if (matchType.getId().equals(secondaryOutputs[k].getId())) { + buildVars.add(outType.getBuildVariable()); + break thisType; + } + matchType = matchType.getSuperClass(); + } while (matchType != null); + } + } + } + } + return buildVars; + } + + private boolean getToolInputsOutputs(ITool tool, Vector inputs, Vector dependencies, + Vector outputs, Vector enumeratedPrimaryOutputs, Vector enumeratedSecondaryOutputs, + Vector outputVariables, Vector additionalTargets, boolean bTargetTool, + Vector managedProjectOutputs) { + PathSettingsContainer toolInfos = getToolInfos(); + ToolInfoHolder h = (ToolInfoHolder) toolInfos.getValue(); + ITool[] buildTools = h.buildTools; + ArduinoManagedBuildGnuToolInfo[] gnuToolInfos = h.gnuToolInfos; + // Get the information regarding the tool's inputs and outputs from the + // objects + // created by calculateToolInputsOutputs + IManagedBuildGnuToolInfo toolInfo = null; + for (int i = 0; i < buildTools.length; i++) { + if (tool == buildTools[i]) { + toolInfo = gnuToolInfos[i]; + break; + } + } + if (toolInfo == null) + return false; + // Populate the output Vectors + inputs.addAll(toolInfo.getCommandInputs()); + outputs.addAll(toolInfo.getCommandOutputs()); + enumeratedPrimaryOutputs.addAll(toolInfo.getEnumeratedPrimaryOutputs()); + enumeratedSecondaryOutputs.addAll(toolInfo.getEnumeratedSecondaryOutputs()); + outputVariables.addAll(toolInfo.getOutputVariables()); + Vector unprocessedDependencies = toolInfo.getCommandDependencies(); + for (String path : unprocessedDependencies) { + dependencies.add(ensurePathIsGNUMakeTargetRuleCompatibleSyntax(path)); + } + additionalTargets.addAll(toolInfo.getAdditionalTargets()); + if (bTargetTool && managedProjectOutputs != null) { + for (String output : managedProjectOutputs) { + dependencies.add(output); + } + } + return true; + } + +} diff --git a/io.sloeber.core/src/io/sloeber/managedBuild/api/IManagedOutputNameProviderJaba.java b/io.sloeber.core/src/io/sloeber/managedBuild/api/IManagedOutputNameProviderJaba.java new file mode 100644 index 000000000..99fa3c7ba --- /dev/null +++ b/io.sloeber.core/src/io/sloeber/managedBuild/api/IManagedOutputNameProviderJaba.java @@ -0,0 +1,10 @@ +package io.sloeber.managedBuild.api; + +import org.eclipse.cdt.managedbuilder.core.IConfiguration; +import org.eclipse.cdt.managedbuilder.core.ITool; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.runtime.IPath; + +public interface IManagedOutputNameProviderJaba { + public IPath getOutputName(IProject project, IConfiguration cConf, ITool tool, IPath primaryInputNames); +} From 3916eb10e30df39e9b075a555ebec8f7dc146a18 Mon Sep 17 00:00:00 2001 From: jantje Date: Fri, 14 Oct 2022 05:37:17 +0200 Subject: [PATCH 002/486] #1126 subdir.mk starts to look like something Changing a header file does not trigger the needed builds --- io.sloeber.core/plugin.xml | 6 +- .../Internal/ArduinoGnuMakefileGenerator.java | 47 +- .../ArduinoManagedBuildGnuToolInfo.java | 17 +- .../managedBuild/Internal/MakeRule.java | 457 +++++- .../Internal/ManagebBuildCommon.java | 31 +- .../Internal/ManagedBuildConstants.java | 15 +- .../Internal/SubDirMakeGenerator.java | 1295 +---------------- 7 files changed, 588 insertions(+), 1280 deletions(-) diff --git a/io.sloeber.core/plugin.xml b/io.sloeber.core/plugin.xml index 1b7139b8d..200c45278 100644 --- a/io.sloeber.core/plugin.xml +++ b/io.sloeber.core/plugin.xml @@ -186,7 +186,7 @@ dependencyContentType="org.eclipse.cdt.core.cxxHeader" id="io.sloeber.compiler.cpp.sketch.input" name="%inputType.CPP.name" - primaryInput="true" + primaryInput="false" sourceContentType="org.eclipse.cdt.core.cxxSource"> subdirList; - private IPath topBuildDir; + private IFile topBuildDir; final HashMap> buildSrcVars = new HashMap<>(); final HashMap> buildOutVars = new HashMap<>(); final HashMap buildDepVars = new HashMap<>(); @@ -348,7 +348,7 @@ public void initialize(IProject project, IManagedBuildInfo info, IProgressMonito builder = config.getEditableBuilder(); initToolInfos(); // set the top build dir path - topBuildDir = project.getFolder(info.getConfigurationName()).getFullPath(); + topBuildDir = project.getFile(info.getConfigurationName()); } /** @@ -364,11 +364,12 @@ private void callDependencyPostProcessors(IResourceInfo rcInfo, ToolInfoHolder h IPath absolutePath = new Path( EFSExtensionManager.getDefault().getPathFromURI(depFile.getLocationURI())); // Convert to build directory relative - IPath depPath = ManagedBuildManager.calculateRelativePath(getTopBuildDir(), absolutePath); + IPath depPath = ManagedBuildManager.calculateRelativePath(getTopBuildDir().getFullPath(), absolutePath); for (int i = 0; i < postProcessors.length; i++) { IManagedDependencyGenerator2 depGen = postProcessors[i]; if (depGen != null) { - depGen.postProcessDependencyFile(depPath, config, h.buildTools[i], getTopBuildDir()); + depGen.postProcessDependencyFile(depPath, config, h.buildTools[i], + getTopBuildDir().getFullPath()); } } } @@ -475,7 +476,7 @@ public boolean visit(PathSettingsContainer container) { continue; DepInfo di = (DepInfo) cr.getValue(); ToolInfoHolder h = ToolInfoHolder.getToolInfo(this, projectRelativePath); - IPath buildRelativePath = topBuildDir.append(projectRelativePath); + IPath buildRelativePath = topBuildDir.getFullPath().append(projectRelativePath); IFolder buildFolder = root.getFolder(buildRelativePath); if (buildFolder == null) continue; @@ -544,11 +545,12 @@ public MultiStatus generateMakefiles(IResourceDelta delta) throws CoreException return status; } // Make sure the build directory is available - topBuildDir = createDirectory(project, config.getName()); + topBuildDir = project.getFile(config.getName()); + createDirectory(project, config.getName()); checkCancel(); // Make sure that there is a makefile containing all the folders // participating - IPath srcsFilePath = topBuildDir.append(SRCSFILE_NAME); + IPath srcsFilePath = topBuildDir.getFullPath().append(SRCSFILE_NAME); IFile srcsFileHandle = createFile(srcsFilePath); buildSrcVars.clear(); buildOutVars.clear(); @@ -616,7 +618,7 @@ public MultiStatus generateMakefiles(IResourceDelta delta) throws CoreException calculateToolInputsOutputs(); checkCancel(); // Re-create the top-level makefile - IPath makefilePath = topBuildDir.append(MAKEFILE_NAME); + IPath makefilePath = topBuildDir.getFullPath().append(MAKEFILE_NAME); IFile makefileHandle = createFile(makefilePath); myTopMakeFileGenerator.populateTopMakefile(makefileHandle, false); checkCancel(); @@ -651,7 +653,7 @@ public MultiStatus generateMakefiles(IResourceDelta delta) throws CoreException @Override public IPath getBuildWorkingDir() { if (topBuildDir != null) { - return topBuildDir.removeFirstSegments(1); + return topBuildDir.getFullPath().removeFirstSegments(1); } return null; } @@ -720,7 +722,7 @@ public boolean visit(PathSettingsContainer container) { IResourceInfo rcInfo = config.getResourceInfo(container.getPath(), false); for (IPath path : getDependencyMakefiles(h)) { // The path to search for the dependency makefile - IPath relDepFilePath = topBuildDir.append(path); + IPath relDepFilePath = topBuildDir.getFullPath().append(path); IFile depFile = root.getFile(relDepFilePath); if (depFile == null || !depFile.isAccessible()) continue; @@ -765,10 +767,11 @@ public MultiStatus regenerateMakefiles() throws CoreException { return status; } // Create the top-level directory for the build output - topBuildDir = createDirectory(project, config.getName()); + topBuildDir = project.getFile(config.getName()); + createDirectory(project, config.getName()); checkCancel(); // Get the list of subdirectories - IPath srcsFilePath = topBuildDir.append(SRCSFILE_NAME); + IPath srcsFilePath = topBuildDir.getFullPath().append(SRCSFILE_NAME); IFile srcsFileHandle = createFile(srcsFilePath); buildSrcVars.clear(); buildOutVars.clear(); @@ -793,13 +796,13 @@ public MultiStatus regenerateMakefiles() throws CoreException { calculateToolInputsOutputs(); checkCancel(); // Create the top-level makefile - IPath makefilePath = topBuildDir.append(MAKEFILE_NAME); + IPath makefilePath = topBuildDir.getFullPath().append(MAKEFILE_NAME); IFile makefileHandle = createFile(makefilePath); myTopMakeFileGenerator.populateTopMakefile(makefileHandle, true); // JABA SLOEBER create the size.awk file ICConfigurationDescription confDesc = ManagedBuildManager.getDescriptionForConfiguration(config); IWorkspaceRoot root = CCorePlugin.getWorkspace().getRoot(); - IFile sizeAwkFile1 = root.getFile(topBuildDir.append("size.awk")); + IFile sizeAwkFile1 = root.getFile(topBuildDir.getFullPath().append("size.awk")); File sizeAwkFile = sizeAwkFile1.getLocation().toFile(); String regex = Common.getBuildEnvironmentVariable(confDesc, "recipe.size.regex", EMPTY); String awkContent = "/" + regex + "/ {arduino_size += $2 }\n"; @@ -825,7 +828,7 @@ public MultiStatus regenerateMakefiles() throws CoreException { // END JABA SLOEBER create the size.awk file checkCancel(); // Now finish up by adding all the object files - IPath objFilePath = topBuildDir.append(OBJECTS_MAKFILE); + IPath objFilePath = topBuildDir.getLocation().append(OBJECTS_MAKFILE); IFile objsFileHandle = createFile(objFilePath); populateObjectsMakefile(objsFileHandle); checkCancel(); @@ -1290,8 +1293,9 @@ private void deleteBuildTarget(IResource deletedFile) { private IPath inFullPathFromOutFullPath(IPath path) { IPath inPath = null; - if (topBuildDir.isPrefixOf(path)) { - inPath = path.removeFirstSegments(topBuildDir.segmentCount()); + IPath topBuildPath = topBuildDir.getFullPath(); + if (topBuildPath.isPrefixOf(path)) { + inPath = path.removeFirstSegments(topBuildPath.segmentCount()); inPath = project.getFullPath().append(path); } return inPath; @@ -1323,7 +1327,8 @@ private void deleteDepFile(IResource deletedFile) { if (calcType == IManagedDependencyGeneratorType.TYPE_COMMAND) { depFilePaths = new IPath[1]; IPath absolutePath = deletedFile.getLocation(); - depFilePaths[0] = ManagedBuildManager.calculateRelativePath(getTopBuildDir(), absolutePath); + depFilePaths[0] = ManagedBuildManager.calculateRelativePath(getTopBuildDir().getFullPath(), + absolutePath); depFilePaths[0] = depFilePaths[0].removeFileExtension().addFileExtension(DEP_EXT); } else if (calcType == IManagedDependencyGeneratorType.TYPE_BUILD_COMMANDS || calcType == IManagedDependencyGeneratorType.TYPE_PREBUILD_COMMANDS) { @@ -1497,8 +1502,8 @@ protected void updateMonitor(String msg) { /** * Return the configuration's top build directory as an absolute path */ - public IPath getTopBuildDir() { - return getPathForResource(project).append(getBuildWorkingDir()); + public IFile getTopBuildDir() { + return topBuildDir; } @Override @@ -1551,7 +1556,7 @@ public void initialize(int buildKind, IConfiguration cfg, IBuilder builder, IPro this.builder = builder; initToolInfos(); // set the top build dir path - topBuildDir = project.getFolder(cfg.getName()).getFullPath(); + topBuildDir = project.getFile(cfg.getName()); srcEntries = config.getSourceEntries(); if (srcEntries.length == 0) { srcEntries = new ICSourceEntry[] { diff --git a/io.sloeber.core/src/io/sloeber/managedBuild/Internal/ArduinoManagedBuildGnuToolInfo.java b/io.sloeber.core/src/io/sloeber/managedBuild/Internal/ArduinoManagedBuildGnuToolInfo.java index dab4c64e9..af0f76c9f 100644 --- a/io.sloeber.core/src/io/sloeber/managedBuild/Internal/ArduinoManagedBuildGnuToolInfo.java +++ b/io.sloeber.core/src/io/sloeber/managedBuild/Internal/ArduinoManagedBuildGnuToolInfo.java @@ -394,9 +394,8 @@ public boolean calculateInputs(ArduinoGnuMakefileGenerator makeGen, IConfigurati if (addlResource != null) { IPath addlPath = addlResource.getLocation(); if (addlPath != null) { - path = ManagedBuildManager - .calculateRelativePath(makeGen.getTopBuildDir(), addlPath) - .toOSString(); + path = ManagedBuildManager.calculateRelativePath( + makeGen.getTopBuildDir().getFullPath(), addlPath).toOSString(); } } } @@ -437,7 +436,8 @@ public boolean calculateInputs(ArduinoGnuMakefileGenerator makeGen, IConfigurati IPath enumPath = enumResource.getLocation(); if (enumPath != null) { paths[j] = ManagedBuildManager - .calculateRelativePath(makeGen.getTopBuildDir(), enumPath).toOSString(); + .calculateRelativePath(makeGen.getTopBuildDir().getFullPath(), enumPath) + .toOSString(); } } } @@ -869,8 +869,8 @@ private boolean callDependencyCalculator(ArduinoGnuMakefileGenerator makeGen, IC // Convert from project relative to // build directory relative IPath absolutePath = this.project.getLocation().append(depPaths[j]); - depPaths[j] = ManagedBuildManager - .calculateRelativePath(makeGen.getTopBuildDir(), absolutePath); + depPaths[j] = ManagedBuildManager.calculateRelativePath( + makeGen.getTopBuildDir().getFullPath(), absolutePath); } myCommandDependencies.add(depPaths[j].toOSString()); } @@ -950,9 +950,8 @@ public boolean calculateDependencies(ArduinoGnuMakefileGenerator makeGen, IConfi if (addlResource != null) { IPath addlPath = addlResource.getLocation(); if (addlPath != null) { - path = ManagedBuildManager - .calculateRelativePath(makeGen.getTopBuildDir(), addlPath) - .toOSString(); + path = ManagedBuildManager.calculateRelativePath( + makeGen.getTopBuildDir().getFullPath(), addlPath).toOSString(); } } } diff --git a/io.sloeber.core/src/io/sloeber/managedBuild/Internal/MakeRule.java b/io.sloeber.core/src/io/sloeber/managedBuild/Internal/MakeRule.java index 1d844521e..0fa3d4573 100644 --- a/io.sloeber.core/src/io/sloeber/managedBuild/Internal/MakeRule.java +++ b/io.sloeber.core/src/io/sloeber/managedBuild/Internal/MakeRule.java @@ -1,58 +1,475 @@ package io.sloeber.managedBuild.Internal; +import static io.sloeber.managedBuild.Internal.ManagebBuildCommon.*; +import static io.sloeber.managedBuild.Internal.ManagedBuildConstants.*; + +import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; -import org.eclipse.core.runtime.IPath; +import org.eclipse.cdt.core.settings.model.ICConfigurationDescription; +import org.eclipse.cdt.managedbuilder.core.BuildException; +import org.eclipse.cdt.managedbuilder.core.IConfiguration; +import org.eclipse.cdt.managedbuilder.core.IInputType; +import org.eclipse.cdt.managedbuilder.core.IOutputType; +import org.eclipse.cdt.managedbuilder.core.IResourceInfo; +import org.eclipse.cdt.managedbuilder.core.ITool; +import org.eclipse.cdt.managedbuilder.core.ManagedBuildManager; +import org.eclipse.cdt.managedbuilder.internal.macros.BuildMacroProvider; +import org.eclipse.cdt.managedbuilder.internal.macros.FileContextData; +import org.eclipse.cdt.managedbuilder.macros.BuildMacroException; +import org.eclipse.cdt.managedbuilder.macros.IBuildMacroProvider; +import org.eclipse.cdt.managedbuilder.makegen.IManagedDependencyCommands; +import org.eclipse.cdt.managedbuilder.makegen.IManagedDependencyGenerator2; +import org.eclipse.cdt.managedbuilder.makegen.IManagedDependencyGeneratorType; +import org.eclipse.cdt.managedbuilder.makegen.IManagedDependencyInfo; +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IProject; public class MakeRule { - Map> targets = new HashMap<>(); //Macro file target map - Map> prerequisites = new HashMap<>();//Macro file prerequisites map - List rules = new LinkedList<>(); + Map> targets = new HashMap<>(); //Macro file target map + Map> prerequisites = new HashMap<>();//Macro file prerequisites map + ITool tool = null; + + public HashSet getPrerequisites() { + HashSet ret = new HashSet<>(); + for (List cur : prerequisites.values()) { + ret.addAll(cur); + } + return ret; + } + + public HashSet getTargets() { + HashSet ret = new HashSet<>(); + for (List cur : targets.values()) { + ret.addAll(cur); + } + return ret; + } public HashSet getMacros() { HashSet ret = new HashSet<>(); - ret.addAll(targets.keySet()); - ret.addAll(prerequisites.keySet()); + for (IOutputType cur : targets.keySet()) { + ret.add(cur.getBuildVariable()); + } + for (IInputType cur : prerequisites.keySet()) { + ret.add(cur.getBuildVariable()); + } return ret; } - public HashSet getMacroElements(String macroName) { - HashSet ret = new HashSet<>(); - List list = targets.get(macroName); - if (list != null) { - ret.addAll(list); + public HashSet getMacroElements(String macroName) { + HashSet ret = new HashSet<>(); + + for (Entry> cur : targets.entrySet()) { + if (macroName.equals(cur.getKey().getBuildVariable())) { + ret.addAll(cur.getValue()); + } } - list = prerequisites.get(macroName); - if (list != null) { - ret.addAll(list); + for (Entry> cur : prerequisites.entrySet()) { + if (macroName.equals(cur.getKey().getBuildVariable())) { + ret.addAll(cur.getValue()); + } } return ret; } - public void addTarget(String Macro, IPath file) { - List files = targets.get(Macro); + public void addTarget(IOutputType outputType, IFile file) { + List files = targets.get(outputType); if (files == null) { files = new LinkedList<>(); files.add(file); - targets.put(Macro, files); + targets.put(outputType, files); } else { files.add(file); } } - public void addPrerequisite(String Macro, IPath file) { - List files = prerequisites.get(Macro); + public void addPrerequisite(IInputType inputType, IFile file) { + List files = prerequisites.get(inputType); if (files == null) { files = new LinkedList<>(); files.add(file); - prerequisites.put(Macro, files); + prerequisites.put(inputType, files); } else { files.add(file); } } + + private String enumTargets(IFile buildFolder) { + String ret = new String(); + for (List curFiles : targets.values()) { + for (IFile curFile : curFiles) { + ret = ret + GetNiceFileName(buildFolder, curFile) + WHITESPACE; + } + } + return ret; + //return StringUtils.join(targets.values(), WHITESPACE); + } + + private String enumPrerequisites(IFile buildFolder) { + String ret = new String(); + for (List curFiles : prerequisites.values()) { + for (IFile curFile : curFiles) { + ret = ret + GetNiceFileName(buildFolder, curFile) + WHITESPACE; + } + } + return ret; + // return StringUtils.join(prerequisites.values(), WHITESPACE); + } + + public StringBuffer getRule(IProject project, IFile niceBuildFolder, IConfiguration config) { + + String cmd = tool.getToolCommand(); + //For now assume 1 target with 1 or more prerequisites + // if there is more than 1 prerequisite we take the flags of the first prerequisite only + HashSet local_targets = getTargets(); + HashSet local_prerequisites = getPrerequisites(); + if (local_targets.size() != 1) { + System.err.println("Only 1 target per build rule is supported in this managed build"); //$NON-NLS-1$ + return new StringBuffer(); + } + if (local_prerequisites.size() == 0) { + System.err.println("0 prerequisites is not supported in this managed build"); //$NON-NLS-1$ + return new StringBuffer(); + } + IFile outputLocation = local_targets.toArray(new IFile[0])[0]; + + //Primary outputs is not supported + String otherPrimaryOutputs = EMPTY_STRING; + Set niceNameList = new HashSet<>(); + IFile sourceLocation = null; + for (IFile curPrerequisite : local_prerequisites) { + niceNameList.add(GetNiceFileName(niceBuildFolder, curPrerequisite)); + sourceLocation = curPrerequisite; + } + final String fileName = sourceLocation.getFullPath().removeFileExtension().lastSegment(); + final String inputExtension = sourceLocation.getFileExtension(); + + Set flags = getBuildFlags(niceBuildFolder, config, sourceLocation, outputLocation); + + boolean needExplicitRuleForFile = false; + boolean needExplicitDependencyCommands = false; + boolean resourceNameRequiresExplicitRule = containsSpecialCharacters(sourceLocation.getLocation().toOSString()); + needExplicitRuleForFile = resourceNameRequiresExplicitRule + || BuildMacroProvider.getReferencedExplitFileMacros(tool).length > 0 + || BuildMacroProvider.getReferencedExplitFileMacros(cmd, IBuildMacroProvider.CONTEXT_FILE, + new FileContextData(sourceLocation.getFullPath(), outputLocation.getFullPath(), null, + tool)).length > 0; + + String outflag = tool.getOutputFlag(); + String buildCmd = cmd + WHITESPACE + flags.toString().trim() + WHITESPACE + outflag + WHITESPACE + + tool.getOutputPrefix() + OUT_MACRO + otherPrimaryOutputs + WHITESPACE + IN_MACRO; + if (needExplicitRuleForFile || needExplicitDependencyCommands) { + buildCmd = expandCommandLinePattern(cmd, flags, outflag, OUT_MACRO + otherPrimaryOutputs, niceNameList, + getToolCommandLinePattern(config, tool)); + } else { + buildCmd = expandCommandLinePattern(config, inputExtension, flags, outflag, OUT_MACRO + otherPrimaryOutputs, + niceNameList, sourceLocation, outputLocation); + } + // resolve any remaining macros in the command after it has been + // generated + try { + String resolvedCommand; + IBuildMacroProvider provider = ManagedBuildManager.getBuildMacroProvider(); + if (!needExplicitRuleForFile) { + resolvedCommand = provider.resolveValueToMakefileFormat(buildCmd, EMPTY_STRING, WHITESPACE, + IBuildMacroProvider.CONTEXT_FILE, + new FileContextData(sourceLocation.getFullPath(), outputLocation.getFullPath(), null, tool)); + } else { + // if we need an explicit rule then don't use any builder + // variables, resolve everything to explicit strings + resolvedCommand = provider.resolveValue(buildCmd, EMPTY_STRING, WHITESPACE, + IBuildMacroProvider.CONTEXT_FILE, + new FileContextData(sourceLocation.getFullPath(), outputLocation.getFullPath(), null, tool)); + } + if (!resolvedCommand.isBlank()) + buildCmd = resolvedCommand.trim(); + } catch (BuildMacroException e) { + /* JABA is not going to write this code */ + } + + StringBuffer buffer = new StringBuffer(); + buffer.append(enumTargets(niceBuildFolder)).append(COLON).append(WHITESPACE); + buffer.append(enumPrerequisites(niceBuildFolder)).append(NEWLINE); + buffer.append(TAB).append(AT).append(escapedEcho(MESSAGE_START_FILE + WHITESPACE + IN_MACRO)); + buffer.append(TAB).append(AT).append(escapedEcho(tool.getAnnouncement())); + + // JABA add sketch.prebuild and postbouild if needed + //TOFIX this should not be here + if ("sloeber.ino".equals(fileName)) { //$NON-NLS-1$ + ICConfigurationDescription confDesc = ManagedBuildManager.getDescriptionForConfiguration(config); + String sketchPrebuild = io.sloeber.core.common.Common.getBuildEnvironmentVariable(confDesc, + "sloeber.sketch.prebuild", new String(), true); //$NON-NLS-1$ + String sketchPostBuild = io.sloeber.core.common.Common.getBuildEnvironmentVariable(confDesc, + "sloeber.sketch.postbuild", new String(), true); //$NON-NLS-1$ + if (!sketchPrebuild.isEmpty()) { + buffer.append(TAB).append(sketchPrebuild); + } + buffer.append(TAB).append(buildCmd).append(NEWLINE); + if (!sketchPostBuild.isEmpty()) { + buffer.append(TAB).append(sketchPostBuild); + } + } else { + buffer.append(TAB).append(buildCmd); + } + // end JABA add sketch.prebuild and postbouild if needed + + // Determine if there are any dependencies to calculate + // if (doDepGen) { + // // Get the dependency rule out of the generator + // String[] depCmds = null; + // if (depCommands != null) { + // depCmds = depCommands.getPostToolDependencyCommands(); + // } + // if (depCmds != null) { + // for (String depCmd : depCmds) { + // // Resolve any macros in the dep command after it has + // // been generated. + // // Note: do not trim the result because it will strip + // // out necessary tab characters. + // buffer.append(WHITESPACE).append(LOGICAL_AND).append(WHITESPACE).append(LINEBREAK); + // try { + // if (!needExplicitRuleForFile) { + // depCmd = ManagedBuildManager.getBuildMacroProvider().resolveValueToMakefileFormat(depCmd, + // EMPTY_STRING, WHITESPACE, IBuildMacroProvider.CONTEXT_FILE, + // new FileContextData(sourceLocation, outputLocation, null, tool)); + // } else { + // depCmd = ManagedBuildManager.getBuildMacroProvider().resolveValue(depCmd, EMPTY_STRING, + // WHITESPACE, IBuildMacroProvider.CONTEXT_FILE, + // new FileContextData(sourceLocation, outputLocation, null, tool)); + // } + // } catch (BuildMacroException e) { + // /* JABA is not going to do this */ + // } + // buffer.append(depCmd); + // } + // } + // } + // Echo finished message + buffer.append(NEWLINE); + buffer.append(TAB).append(AT).append(escapedEcho(MESSAGE_FINISH_FILE + WHITESPACE + IN_MACRO)); + buffer.append(TAB).append(AT).append(ECHO_BLANK_LINE).append(NEWLINE); + return buffer; + } + + private Set getBuildFlags(IFile buildFolder, IConfiguration config, IFile sourceFile, IFile outputFile) { + Set flags = new HashSet<>(); + // Get the tool command line options + try { + + IResourceInfo buildContext = config.getResourceInfo(sourceFile.getFullPath().removeLastSegments(1), false); + flags.addAll(Arrays.asList(tool.getToolCommandFlags(sourceFile.getLocation(), outputFile.getLocation()))); + + IInputType[] inputTypes = tool.getInputTypes(); //.getDependencyGeneratorForExtension(inputExtension); + for (IInputType inputType : inputTypes) { + IManagedDependencyGeneratorType t = inputType.getDependencyGenerator(); + if (t != null) { + if (t.getCalculatorType() == IManagedDependencyGeneratorType.TYPE_BUILD_COMMANDS) { + IManagedDependencyGenerator2 depGen = (IManagedDependencyGenerator2) t; + IManagedDependencyInfo depInfo = depGen.getDependencySourceInfo( + sourceFile.getProjectRelativePath(), sourceFile, buildContext, tool, + buildFolder.getFullPath()); + IManagedDependencyCommands depCommands = (IManagedDependencyCommands) depInfo; + if (depCommands != null) { + flags.addAll(Arrays.asList(depCommands.getDependencyCommandOptions())); + } + + } + } + } + } catch (BuildException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + return flags; + } + + private String expandCommandLinePattern(IConfiguration config, String sourceExtension, Set flags, + String outputFlag, String outputName, Set inputResources, IFile inputLocation, + IFile outputLocation) { + String cmd = tool.getToolCommand(); + // try to resolve the build macros in the tool command + try { + String resolvedCommand = null; + if ((inputLocation != null && inputLocation.toString().indexOf(WHITESPACE) != -1) + || (outputLocation != null && outputLocation.toString().indexOf(WHITESPACE) != -1)) { + resolvedCommand = ManagedBuildManager.getBuildMacroProvider().resolveValue(cmd, EMPTY_STRING, + WHITESPACE, IBuildMacroProvider.CONTEXT_FILE, + new FileContextData(inputLocation.getFullPath(), outputLocation.getFullPath(), null, tool)); + } else { + resolvedCommand = ManagedBuildManager.getBuildMacroProvider().resolveValueToMakefileFormat(cmd, + EMPTY_STRING, WHITESPACE, IBuildMacroProvider.CONTEXT_FILE, + new FileContextData(inputLocation.getFullPath(), outputLocation.getFullPath(), null, tool)); + } + if ((resolvedCommand = resolvedCommand.trim()).length() > 0) + cmd = resolvedCommand; + } catch (BuildMacroException e) { + /* JABA is not going to write this code */ + } + return expandCommandLinePattern(cmd, flags, outputFlag, outputName, inputResources, + getToolCommandLinePattern(config, tool)); + } + + // /** + // * Returns any additional resources specified for the tool in other InputType + // * elements and AdditionalInput elements + // */ + // private IPath[] getAdditionalResourcesForSource(ITool tool) { + // IProject project = getProject(); + // List allRes = new ArrayList<>(); + // IInputType[] types = tool.getInputTypes(); + // for (IInputType type : types) { + // // Additional resources come from 2 places. + // // 1. From AdditionalInput childen + // IPath[] res = type.getAdditionalResources(); + // for (IPath re : res) { + // allRes.add(re); + // } + // // 2. From InputTypes that other than the primary input type + // if (!type.getPrimaryInput() && type != tool.getPrimaryInputType()) { + // String var = type.getBuildVariable(); + // if (var != null && var.length() > 0) { + // allRes.add(Path.fromOSString("$(" + type.getBuildVariable() + ")")); + // } else { + // // Use file extensions + // String[] typeExts = type.getSourceExtensions(tool); + // for (IResource projectResource : caller.projectResources) { + // if (projectResource.getType() == IResource.FILE) { + // String fileExt = projectResource.getFileExtension(); + // if (fileExt == null) { + // fileExt = ""; + // } + // for (String typeExt : typeExts) { + // if (fileExt.equals(typeExt)) { + // allRes.add(projectResource.getProjectRelativePath()); + // break; + // } + // } + // } + // } + // } + // // If an assignToOption has been specified, set the value of the + // // option to the inputs + // IOption assignToOption = tool.getOptionBySuperClassId(type.getAssignToOptionId()); + // IOption option = tool.getOptionBySuperClassId(type.getOptionId()); + // if (assignToOption != null && option == null) { + // try { + // int optType = assignToOption.getValueType(); + // IResourceInfo rcInfo = tool.getParentResourceInfo(); + // if (rcInfo != null) { + // if (optType == IOption.STRING) { + // String optVal = ""; + // for (int j = 0; j < allRes.size(); j++) { + // if (j != 0) { + // optVal += " "; + // } + // String resPath = allRes.get(j).toString(); + // if (!resPath.startsWith("$(")) { + // IResource addlResource = project.getFile(resPath); + // if (addlResource != null) { + // IPath addlPath = addlResource.getLocation(); + // if (addlPath != null) { + // resPath = ManagedBuildManager + // .calculateRelativePath(getTopBuildDir(), addlPath).toString(); + // } + // } + // } + // optVal += ManagedBuildManager + // .calculateRelativePath(getTopBuildDir(), Path.fromOSString(resPath)) + // .toString(); + // } + // ManagedBuildManager.setOption(rcInfo, tool, assignToOption, optVal); + // } else if (optType == IOption.STRING_LIST || optType == IOption.LIBRARIES + // || optType == IOption.OBJECTS || optType == IOption.INCLUDE_FILES + // || optType == IOption.LIBRARY_PATHS || optType == IOption.LIBRARY_FILES + // || optType == IOption.MACRO_FILES) { + // // TODO: do we need to do anything with undefs + // // here? + // // Note that the path(s) must be translated from + // // project relative + // // to top build directory relative + // String[] paths = new String[allRes.size()]; + // for (int j = 0; j < allRes.size(); j++) { + // paths[j] = allRes.get(j).toString(); + // if (!paths[j].startsWith("$(")) { + // IResource addlResource = project.getFile(paths[j]); + // if (addlResource != null) { + // IPath addlPath = addlResource.getLocation(); + // if (addlPath != null) { + // paths[j] = ManagedBuildManager + // .calculateRelativePath(getTopBuildDir(), addlPath).toString(); + // } + // } + // } + // } + // ManagedBuildManager.setOption(rcInfo, tool, assignToOption, paths); + // } else if (optType == IOption.BOOLEAN) { + // boolean b = false; + // if (allRes.size() > 0) + // b = true; + // ManagedBuildManager.setOption(rcInfo, tool, assignToOption, b); + // } else if (optType == IOption.ENUMERATED || optType == IOption.TREE) { + // if (allRes.size() > 0) { + // String s = allRes.get(0).toString(); + // ManagedBuildManager.setOption(rcInfo, tool, assignToOption, s); + // } + // } + // allRes.clear(); + // } + // } catch (BuildException ex) { + // /* JABA is not going to write this code */ + // } + // } + // } + // } + // return allRes.toArray(new IPath[allRes.size()]); + // } + + private String expandCommandLinePattern(String commandName, Set flags, String outputFlag, String outputName, + Set inputResources, String commandLinePattern) { + + String command = commandLinePattern; + if (commandLinePattern == null || commandLinePattern.length() <= 0) { + command = DEFAULT_PATTERN; + } + + String quotedOutputName = outputName; + // if the output name isn't a variable then quote it + if (quotedOutputName.length() > 0 && quotedOutputName.indexOf("$(") != 0) { //$NON-NLS-1$ + quotedOutputName = DOUBLE_QUOTE + quotedOutputName + DOUBLE_QUOTE; + } + + String inputsStr = ""; //$NON-NLS-1$ + if (inputResources != null) { + for (String inp : inputResources) { + if (inp != null && !inp.isEmpty()) { + // if the input resource isn't a variable then quote it + if (inp.indexOf("$(") != 0) { //$NON-NLS-1$ + inp = DOUBLE_QUOTE + inp + DOUBLE_QUOTE; + } + inputsStr = inputsStr + inp + WHITESPACE; + } + } + inputsStr = inputsStr.trim(); + } + + String flagsStr = String.join(WHITESPACE, flags); + + command = command.replace(makeVariable(CMD_LINE_PRM_NAME), commandName); + command = command.replace(makeVariable(FLAGS_PRM_NAME), flagsStr); + command = command.replace(makeVariable(OUTPUT_FLAG_PRM_NAME), outputFlag); + command = command.replace(makeVariable(OUTPUT_PREFIX_PRM_NAME), tool.getOutputPrefix()); + command = command.replace(makeVariable(OUTPUT_PRM_NAME), quotedOutputName); + command = command.replace(makeVariable(INPUTS_PRM_NAME), inputsStr); + + return command; + } + } diff --git a/io.sloeber.core/src/io/sloeber/managedBuild/Internal/ManagebBuildCommon.java b/io.sloeber.core/src/io/sloeber/managedBuild/Internal/ManagebBuildCommon.java index 55ecf7965..d07f0c779 100644 --- a/io.sloeber.core/src/io/sloeber/managedBuild/Internal/ManagebBuildCommon.java +++ b/io.sloeber.core/src/io/sloeber/managedBuild/Internal/ManagebBuildCommon.java @@ -214,8 +214,8 @@ static public boolean populateDummyTargets(IResourceInfo rcInfo, IFile makefile, } // Reconstruct the buffer tokens into useful chunks of dependency // information - Vector bufferTokens = new Vector(Arrays.asList(inBufferString.split("\\s"))); - Vector deps = new Vector(bufferTokens.size()); + Vector bufferTokens = new Vector<>(Arrays.asList(inBufferString.split("\\s"))); + Vector deps = new Vector<>(bufferTokens.size()); Iterator tokenIter = bufferTokens.iterator(); while (tokenIter.hasNext()) { String token = tokenIter.next(); @@ -241,7 +241,7 @@ static public boolean populateDummyTargets(IResourceInfo rcInfo, IFile makefile, String firstToken; try { firstToken = deps.get(0); - } catch (ArrayIndexOutOfBoundsException e) { + } catch (@SuppressWarnings("unused") ArrayIndexOutOfBoundsException e) { // This makes no sense so bail return false; } @@ -513,8 +513,8 @@ public static IPath getPathForResource(IResource resource) { static public void addMacroAdditionFile(HashMap map, String macroName, String filename) { StringBuffer buffer = new StringBuffer(); buffer.append(map.get(macroName)); - filename = escapeWhitespaces(filename); - buffer.append(filename).append(WHITESPACE).append(LINEBREAK); + String escapedFilename = escapeWhitespaces(filename); + buffer.append(escapedFilename).append(WHITESPACE).append(LINEBREAK); map.put(macroName, buffer.toString()); } @@ -532,7 +532,7 @@ static public void addMacroAdditionFile(ArduinoGnuMakefileGenerator caller, Hash IPath projectLocation = getPathForResource(project); IPath dirLocation = projectLocation; if (generatedSource) { - dirLocation = dirLocation.append(caller.getBuildWorkingDir()); + dirLocation = dirLocation.append(buildWorkingDir); } if (dirLocation.isPrefixOf(sourceLocation)) { IPath srcPath = sourceLocation.removeFirstSegments(dirLocation.segmentCount()).setDevice(null); @@ -598,10 +598,27 @@ static public IManagedOutputNameProviderJaba getJABANameProvider(IOutputType iTy return (IManagedOutputNameProviderJaba) element .createExecutableExtension(IOutputType.NAME_PROVIDER); } - } catch (CoreException e) { + } catch (@SuppressWarnings("unused") CoreException e) { //ignore errors } } return null; } + + static public String GetNiceFileName(IFile buildPath, IFile path) { + IPath buildLocation = buildPath.getLocation(); + IPath fileLocation = path.getLocation(); + if (buildLocation.isPrefixOf(path.getLocation())) { + return DOT_SLASH_PATH.append(fileLocation.makeRelativeTo(buildLocation)).toOSString(); + } + if (buildLocation.removeLastSegments(1).isPrefixOf(fileLocation)) { + return fileLocation.makeRelativeTo(buildLocation).toOSString(); + + } + return fileLocation.toOSString(); + } + + static public String makeVariable(String variableName) { + return VARIABLE_PREFIX + variableName + VARIABLE_SUFFIX; + } } diff --git a/io.sloeber.core/src/io/sloeber/managedBuild/Internal/ManagedBuildConstants.java b/io.sloeber.core/src/io/sloeber/managedBuild/Internal/ManagedBuildConstants.java index 354ea0b83..320240055 100644 --- a/io.sloeber.core/src/io/sloeber/managedBuild/Internal/ManagedBuildConstants.java +++ b/io.sloeber.core/src/io/sloeber/managedBuild/Internal/ManagedBuildConstants.java @@ -70,7 +70,8 @@ public class ManagedBuildConstants { public static final String OBJS_MACRO = "OBJS"; public static final String MACRO_ADDITION_ADDPREFIX_HEADER = "${addprefix "; public static final String MACRO_ADDITION_ADDPREFIX_SUFFIX = "," + WHITESPACE + LINEBREAK; - public static final String MACRO_ADDITION_PREFIX_SUFFIX = "+=" + WHITESPACE + LINEBREAK; + public static final String JAVA_ADDITION = "+="; + public static final String MACRO_ADDITION_PREFIX_SUFFIX = JAVA_ADDITION + WHITESPACE + LINEBREAK; public static final String PREBUILD = "pre-build"; public static final String MAINBUILD = "main-build"; public static final String POSTBUILD = "post-build"; @@ -81,4 +82,16 @@ public class ManagedBuildConstants { // Enumerations public static final int PROJECT_RELATIVE = 1, PROJECT_SUBDIR_RELATIVE = 2, ABSOLUTE = 3; + public static final String DEFAULT_PATTERN = "${COMMAND} ${FLAGS} ${OUTPUT_FLAG} ${OUTPUT_PREFIX}${OUTPUT} ${INPUTS}"; + public static final String DOUBLE_QUOTE = "\""; + + public static final String CMD_LINE_PRM_NAME = "COMMAND"; + public static final String FLAGS_PRM_NAME = "FLAGS"; + public static final String OUTPUT_FLAG_PRM_NAME = "OUTPUT_FLAG"; + public static final String OUTPUT_PREFIX_PRM_NAME = "OUTPUT_PREFIX"; + public static final String OUTPUT_PRM_NAME = "OUTPUT"; + public static final String INPUTS_PRM_NAME = "INPUTS"; + public static final String VARIABLE_PREFIX = "${"; + public static final String VARIABLE_SUFFIX = "}"; + } diff --git a/io.sloeber.core/src/io/sloeber/managedBuild/Internal/SubDirMakeGenerator.java b/io.sloeber.core/src/io/sloeber/managedBuild/Internal/SubDirMakeGenerator.java index 50aad077a..aebb7a84b 100644 --- a/io.sloeber.core/src/io/sloeber/managedBuild/Internal/SubDirMakeGenerator.java +++ b/io.sloeber.core/src/io/sloeber/managedBuild/Internal/SubDirMakeGenerator.java @@ -9,15 +9,11 @@ import java.util.LinkedHashMap; import java.util.LinkedList; import java.util.List; -import java.util.Map.Entry; import java.util.Vector; -import org.eclipse.cdt.core.settings.model.ICConfigurationDescription; import org.eclipse.cdt.managedbuilder.core.BuildException; -import org.eclipse.cdt.managedbuilder.core.IBuildObject; import org.eclipse.cdt.managedbuilder.core.IConfiguration; import org.eclipse.cdt.managedbuilder.core.IFileInfo; -import org.eclipse.cdt.managedbuilder.core.IFolderInfo; import org.eclipse.cdt.managedbuilder.core.IInputType; import org.eclipse.cdt.managedbuilder.core.IManagedCommandLineGenerator; import org.eclipse.cdt.managedbuilder.core.IManagedCommandLineInfo; @@ -28,21 +24,13 @@ import org.eclipse.cdt.managedbuilder.core.ManagedBuildManager; import org.eclipse.cdt.managedbuilder.internal.core.ManagedMakeMessages; import org.eclipse.cdt.managedbuilder.internal.core.Tool; -import org.eclipse.cdt.managedbuilder.internal.macros.BuildMacroProvider; import org.eclipse.cdt.managedbuilder.internal.macros.FileContextData; import org.eclipse.cdt.managedbuilder.macros.BuildMacroException; import org.eclipse.cdt.managedbuilder.macros.IBuildMacroProvider; import org.eclipse.cdt.managedbuilder.makegen.IManagedBuilderMakefileGenerator; -import org.eclipse.cdt.managedbuilder.makegen.IManagedDependencyCalculator; import org.eclipse.cdt.managedbuilder.makegen.IManagedDependencyCommands; -import org.eclipse.cdt.managedbuilder.makegen.IManagedDependencyGenerator; -import org.eclipse.cdt.managedbuilder.makegen.IManagedDependencyGenerator2; -import org.eclipse.cdt.managedbuilder.makegen.IManagedDependencyGeneratorType; -import org.eclipse.cdt.managedbuilder.makegen.IManagedDependencyInfo; -import org.eclipse.cdt.managedbuilder.makegen.IManagedDependencyPreBuild; 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.runtime.CoreException; @@ -71,7 +59,7 @@ private List getDependencyMakefiles(ToolInfoHolder h) { return caller.getDependencyMakefiles(h); } - private IPath getTopBuildDir() { + private IFile getTopBuildDir() { return caller.getTopBuildDir(); } @@ -114,12 +102,10 @@ public void populateFragmentMakefile(IContainer module) throws CoreException { //get the data List makeRules = getMakeRules(module); - //make the file - - StringBuffer makeBuf = getHeader(); + //generate the file content + StringBuffer makeBuf = addDefaultHeader(); makeBuf.append(GenerateMacros(makeRules)); - makeBuf.append(GenerateRules(makeRules)); - makeBuf.append(addSources(module)); + makeBuf.append(GenerateRules(makeRules, getConfig())); // Save the files save(makeBuf, modMakefile); @@ -127,258 +113,117 @@ public void populateFragmentMakefile(IContainer module) throws CoreException { private StringBuffer GenerateMacros(List makeRules) { StringBuffer buffer = new StringBuffer(); - IPath buildRoot = getTopBuildDir(); - buffer.append("#GenerateMacros not yet implemented"); + IFile buildRoot = getTopBuildDir(); buffer.append(NEWLINE); HashSet macroNames = new HashSet<>(); for (MakeRule makeRule : makeRules) { macroNames.addAll(makeRule.getMacros()); } for (String macroName : macroNames) { - HashSet files = new HashSet<>(); + HashSet files = new HashSet<>(); for (MakeRule makeRule : makeRules) { files.addAll(makeRule.getMacroElements(macroName)); } if (files.size() > 0) { - buffer.append(macroName).append("+=").append(WHITESPACE); - for (IPath file : files) { + buffer.append(macroName).append(JAVA_ADDITION).append(WHITESPACE); + for (IFile file : files) { buffer.append(LINEBREAK); buffer.append(GetNiceFileName(buildRoot, file)).append(WHITESPACE); } buffer.append(NEWLINE); + buffer.append(NEWLINE); } } return buffer; } - private String GetNiceFileName(IPath buildPath, IPath path) { - if (buildPath.isPrefixOf(path)) { - return DOT_SLASH_PATH.append(path.makeRelativeTo(buildPath)).toOSString(); - } else { - if (buildPath.removeLastSegments(1).isPrefixOf(path)) { - return path.makeRelativeTo(buildPath).toOSString(); - } - } - - return path.toOSString(); - // if (dirLocation.isPrefixOf(sourceLocation)) { - // IPath srcPath = sourceLocation.removeFirstSegments(dirLocation.segmentCount()).setDevice(null); - // if (generatedSource) { - // srcName = DOT_SLASH_PATH.append(srcPath).toOSString(); - // } else { - // srcName = ROOT + FILE_SEPARATOR + srcPath.toOSString(); - // } - // } else { - // if (generatedSource && !sourceLocation.isAbsolute()) { - // srcName = DOT_SLASH_PATH.append(relativePath).append(sourceLocation.lastSegment()).toOSString(); - // } else { - // // TODO: Should we use relative paths when possible (e.g., see - // // MbsMacroSupplier.calculateRelPath) - // srcName = sourceLocation.toOSString(); - // } - // } - } - - private StringBuffer GenerateRules(List makeRules) { + private StringBuffer GenerateRules(List makeRules, IConfiguration config) { StringBuffer buffer = new StringBuffer(); - buffer.append("#GenerateRules not yet implemented"); buffer.append(NEWLINE); - return buffer; - } - static private StringBuffer getHeader() { - return addDefaultHeader(); + for (MakeRule makeRule : makeRules) { + buffer.append(makeRule.getRule(getProject(), getTopBuildDir(), config)); + } + + return buffer; } + //Get the rules for the source files private List getMakeRules(IContainer module) { IConfiguration config = getConfig(); - IPath buildPath = getTopBuildDir(); + IFile buildPath = getTopBuildDir(); + IProject project = getProject(); List makeRules = new LinkedList<>(); - // Visit the resources in this folder a - IResource[] resources; + // Visit the resources in this folder try { - resources = module.members(); - - IFolder folder = getProject().getFolder(config.getName()); - for (IResource resource : resources) { - if (resource.getType() == IResource.FILE) { - IFile inputFile = (IFile) resource; - // Check whether this resource is excluded from build - IPath rcProjRelPath = resource.getProjectRelativePath(); - if (!caller.isSource(rcProjRelPath)) - continue; - IResourceInfo rcInfo = config.getResourceInfo(rcProjRelPath, false); + for (IResource resource : module.members()) { + if (resource.getType() != IResource.FILE) { + //only handle files + continue; + } + IFile inputFile = (IFile) resource; + IPath rcProjRelPath = resource.getProjectRelativePath(); + if (!caller.isSource(rcProjRelPath)) { + // this resource is excluded from build + continue; + } + IResourceInfo rcInfo = config.getResourceInfo(rcProjRelPath, false); + String ext = rcProjRelPath.getFileExtension(); - ITool tool = null; - String varName = null; - String ext = rcProjRelPath.getFileExtension(); - if (ext != null) { - varName = getSourceMacroName(ext).toString(); + ITool tool = null; + //try to find tool + if (rcInfo instanceof IFileInfo) { + IFileInfo fi = (IFileInfo) rcInfo; + ITool[] tools = fi.getToolsToInvoke(); + if (tools != null && tools.length > 0) { + tool = tools[0]; } + } - //try to find tool - if (rcInfo instanceof IFileInfo) { - IFileInfo fi = (IFileInfo) rcInfo; - ITool[] tools = fi.getToolsToInvoke(); - if (tools != null && tools.length > 0) { - tool = tools[0]; + //No tool found yet try other way + if (tool == null) { + ToolInfoHolder h = ToolInfoHolder.getToolInfo(caller, rcInfo.getPath()); + ITool buildTools[] = h.buildTools; + h = ToolInfoHolder.getToolInfo(caller, Path.EMPTY); + buildTools = h.buildTools; + for (ITool buildTool : buildTools) { + if (buildTool.buildsFileType(ext)) { + tool = buildTool; + break; } } + } - //No tool found try other way - if (tool == null) { - ToolInfoHolder h = ToolInfoHolder.getToolInfo(caller, rcInfo.getPath()); - ITool buildTools[] = h.buildTools; - h = ToolInfoHolder.getToolInfo(caller, Path.EMPTY); - buildTools = h.buildTools; - for (ITool buildTool : buildTools) { - if (buildTool.buildsFileType(ext)) { - tool = buildTool; - break; - } - } + //We found a tool get the other info + //TOFIX we should simply loop over all available tools + if (tool != null) { + + // Generate the rule to build this source file + //TOFIX check wether this tool can handle this file + IInputType inputType = tool.getPrimaryInputType(); + if (inputType == null) { + inputType = tool.getInputType(ext); } - //We found a tool get the other info - if (tool != null) { - MakeRule newMakeRule = new MakeRule(); - makeRules.add(newMakeRule); - // Generate the rule to build this source file - IInputType inputType = tool.getPrimaryInputType(); - if (inputType == null) { - inputType = tool.getInputType(ext); - } - if (inputType != null) { - if (inputType.getBuildVariable() != null) { - varName = inputType.getBuildVariable(); - } - } - newMakeRule.addPrerequisite(varName, inputFile.getLocation()); - for (String curExtension : tool.getAllOutputExtensions()) { - IOutputType outputType = tool.getOutputType(curExtension); - String OutMacroName = outputType.getBuildVariable(); - IManagedOutputNameProviderJaba nameProvider = getJABANameProvider(outputType); - if (nameProvider != null) { - IPath outputFile = nameProvider.getOutputName(getProject(), config, tool, - resource.getFullPath()); - if (outputFile != null) { - newMakeRule.addTarget(OutMacroName, - buildPath.append(outputFile.removeFirstSegments(1))); - } + for (IOutputType outputType : tool.getOutputTypes()) { + IManagedOutputNameProviderJaba nameProvider = getJABANameProvider(outputType); + if (nameProvider != null) { + IPath outputFile = nameProvider.getOutputName(getProject(), config, tool, + resource.getFullPath()); + if (outputFile != null) { + //We found a tool that provides a outputfile for our source file + //TOFIX if this is a multiple to one we should only create one MakeRule + IPath correctOutputPath = new Path(config.getName()) + .append(outputFile.removeFirstSegments(1)); + MakeRule newMakeRule = new MakeRule(); + newMakeRule.addPrerequisite(inputType, inputFile); + newMakeRule.addTarget(outputType, project.getFile(correctOutputPath)); + newMakeRule.tool = tool; + makeRules.add(newMakeRule); } - } - // if ((primaryInputType != null && !primaryInputType.getMultipleOfType()) - // || (inputType == null && tool != caller.config.calculateTargetTool())) { - // // Try to add the rule for the file - // Vector generatedOutputs = new Vector(); - // Vector generatedDepFiles = new Vector(); - // // MODED moved JABA JAn Baeyens get the out type from the add - // // source call - // caller.usedOutType = null; - // addRuleForSource(project, relativePath, ruleBuffer, resource, sourceLocation, rcInfo, - // generatedSource, generatedDepFiles, generatedOutputs); - // // If the rule generates a dependency file(s), add the file(s) - // // to the variable - // if (generatedDepFiles.size() > 0) { - // for (int k = 0; k < generatedDepFiles.size(); k++) { - // IPath generatedDepFile = generatedDepFiles.get(k); - // addMacroAdditionFile(buildVarToRuleStringMap, getDepMacroName(ext).toString(), - // (generatedDepFile.isAbsolute() ? "" : DOT_SLASH_PATH.toOSString()) - // + generatedDepFile.toOSString()); - // } - // } - // // If the generated outputs of this tool are input to another - // // tool, - // // 1. add the output to the appropriate macro - // // 2. If the tool does not have multipleOfType input, generate - // // the rule. - // // IOutputType outType = tool.getPrimaryOutputType(); - // // MODED - // // moved JABA JAn Baeyens get the out type from the add source - // // call - // String buildVariable = null; - // if (caller.usedOutType != null) { - // if (tool.getCustomBuildStep()) { - // // TODO: This is somewhat of a hack since a custom build - // // step - // // tool does not currently define a build variable - // if (generatedOutputs.size() > 0) { - // IPath firstOutput = generatedOutputs.get(0); - // String firstExt = firstOutput.getFileExtension(); - // ToolInfoHolder tmpH = ToolInfoHolder.getFolderToolInfo(caller, rcInfo.getPath()); - // ITool[] tmpBuildTools = tmpH.buildTools; - // for (ITool tmpBuildTool : tmpBuildTools) { - // if (tmpBuildTool.buildsFileType(firstExt)) { - // String bV = tmpBuildTool.getPrimaryInputType().getBuildVariable(); - // if (bV.length() > 0) { - // buildVariable = bV; - // break; - // } - // } - // } - // } - // } else { - // buildVariable = caller.usedOutType.getBuildVariable(); - // } - // } else { - // // For support of pre-CDT 3.0 integrations. - // buildVariable = OBJS_MACRO; - // } - // for (int k = 0; k < generatedOutputs.size(); k++) { - // IPath generatedOutput; - // IResource generateOutputResource; - // if (generatedOutputs.get(k).isAbsolute()) { - // // TODO: Should we use relative paths when possible - // // (e.g., see MbsMacroSupplier.calculateRelPath) - // generatedOutput = generatedOutputs.get(k); - // // If this file has an absolute path, then the - // // generateOutputResource will not be correct - // // because the file is not under the project. We use - // // this resource in the calls to the dependency - // // generator - // generateOutputResource = project.getFile(generatedOutput); - // } else { - // generatedOutput = getPathForResource(project).append(caller.getBuildWorkingDir()) - // .append(generatedOutputs.get(k)); - // generateOutputResource = project - // .getFile(caller.getBuildWorkingDir().append(generatedOutputs.get(k))); - // } - // IResourceInfo nextRcInfo; - // if (rcInfo instanceof IFileInfo) { - // nextRcInfo = caller.config.getResourceInfo(rcInfo.getPath().removeLastSegments(1), - // false); - // } else { - // nextRcInfo = rcInfo; - // } - // addFragmentMakefileEntriesForSource(buildVarToRuleStringMap, ruleBuffer, folder, - // relativePath, generateOutputResource, generatedOutput, nextRcInfo, buildVariable, - // true); - // } - // } - // } else { - // // If this is a secondary input, add it to build vars - // if (varName == null) { - // for (ITool buildTool : buildTools) { - // if (buildTool.isInputFileType(ext)) { - // addToBuildVar(buildVarToRuleStringMap, ext, varName, relativePath, sourceLocation, - // generatedSource); - // break; - // } - // } - // } - // // If this generated output is identified as a secondary output, add - // // the file to the build variable - // else { - // IOutputType[] secondaryOutputs = caller.config.getToolChain().getSecondaryOutputs(); - // if (secondaryOutputs.length > 0) { - // if (isSecondaryOutputVar(h, secondaryOutputs, varName)) { - // addMacroAdditionFile(caller, buildVarToRuleStringMap, varName, relativePath, - // sourceLocation, generatedSource); - // } - // } - // } + } } } @@ -390,236 +235,6 @@ private List getMakeRules(IContainer module) { return makeRules; } - /** - * Returns a StringBuffer containing makefile text for all of the - * sources contributed by a container (project directory/subdirectory) to the - * fragement makefile - * - * @param module - * project resource directory/subdirectory - * @return StringBuffer generated text for the fragement makefile - */ - private StringBuffer addSources(IContainer module) throws CoreException { - IProject project = getProject(); - // Calculate the new directory relative to the build output - IPath moduleRelativePath = module.getProjectRelativePath(); - String relativePath = moduleRelativePath.toOSString(); - relativePath += relativePath.length() == 0 ? "" : FILE_SEPARATOR; - // For build macros in the configuration, create a map which will map - // them - // to a string which holds its list of sources. - LinkedHashMap buildVarToRuleStringMap = new LinkedHashMap(); - // Add statements that add the source files in this folder, - // and generated source files, and generated dependency files - // to the build macros - for (Entry> entry : caller.buildSrcVars.entrySet()) { - String macroName = entry.getKey(); - addMacroAdditionPrefix(buildVarToRuleStringMap, macroName, null, false); - } - for (Entry> entry : caller.buildOutVars.entrySet()) { - String macroName = entry.getKey(); - addMacroAdditionPrefix(buildVarToRuleStringMap, macroName, DOT_SLASH_PATH.append(relativePath).toOSString(), - false); - } - // String buffers - StringBuffer buffer = new StringBuffer(); - StringBuffer ruleBuffer = new StringBuffer( - COMMENT_SYMBOL + WHITESPACE + ManagedMakeMessages.getResourceString(MOD_RULES) + NEWLINE); - // Visit the resources in this folder and add each one to a sources - // macro, and generate a build rule, if appropriate - IResource[] resources = module.members(); - IResourceInfo rcInfo; - IFolder folder = project.getFolder(caller.config.getName()); - for (IResource resource : resources) { - if (resource.getType() == IResource.FILE) { - // Check whether this resource is excluded from build - IPath rcProjRelPath = resource.getProjectRelativePath(); - if (!caller.isSource(rcProjRelPath)) - continue; - rcInfo = caller.config.getResourceInfo(rcProjRelPath, false); - // if( (rcInfo.isExcluded()) ) - // continue; - addFragmentMakefileEntriesForSource(buildVarToRuleStringMap, ruleBuffer, folder, relativePath, resource, - getPathForResource(resource), rcInfo, null, false); - } - } - // Write out the macro addition entries to the buffer - buffer.append(writeAdditionMacros(buildVarToRuleStringMap)); - return buffer.append(ruleBuffer).append(NEWLINE); - } - - /* - * (non-Javadoc Adds the entries for a particular source file to the fragment - * makefile - * - * @param buildVarToRuleStringMap map of build variable names to the list of - * files assigned to the variable - * - * @param ruleBuffer buffer to add generated nmakefile text to - * - * @param folder the top level build output directory - * - * @param relativePath build output directory relative path of the current - * output directory - * - * @param resource the source file for this invocation of the tool - this may be - * null for a generated output - * - * @param sourceLocation the full path of the source - * - * @param resConfig the IResourceConfiguration associated with this file or null - * - * @param varName the build variable to add this invocation's outputs to if - * null, use the file extension to find the name - * - * @param generatedSource if true, this file was generated by - * another tool in the tool-chain - */ - private void addFragmentMakefileEntriesForSource(LinkedHashMap buildVarToRuleStringMap, - StringBuffer ruleBuffer, IFolder folder, String relativePath, IResource resource, IPath sourceLocation, - IResourceInfo rcInfo, String varName, boolean generatedSource) { - IProject project = getProject(); - // Determine which tool, if any, builds files with this extension - String ext = sourceLocation.getFileExtension(); - ITool tool = null; - - if (rcInfo instanceof IFileInfo) { - IFileInfo fi = (IFileInfo) rcInfo; - ITool[] tools = fi.getToolsToInvoke(); - if (tools != null && tools.length > 0) { - tool = tools[0]; - addToBuildVar(buildVarToRuleStringMap, ext, varName, relativePath, sourceLocation, generatedSource); - } - } - ToolInfoHolder h = ToolInfoHolder.getToolInfo(caller, rcInfo.getPath()); - ITool buildTools[] = h.buildTools; - - if (tool == null) { - h = ToolInfoHolder.getToolInfo(caller, Path.EMPTY); - buildTools = h.buildTools; - for (ITool buildTool : buildTools) { - if (buildTool.buildsFileType(ext)) { - tool = buildTool; - addToBuildVar(buildVarToRuleStringMap, ext, varName, relativePath, sourceLocation, generatedSource); - break; - } - } - } - if (tool != null) { - // Generate the rule to build this source file - IInputType primaryInputType = tool.getPrimaryInputType(); - IInputType inputType = tool.getInputType(ext); - if ((primaryInputType != null && !primaryInputType.getMultipleOfType()) - || (inputType == null && tool != caller.config.calculateTargetTool())) { - // Try to add the rule for the file - Vector generatedOutputs = new Vector(); - Vector generatedDepFiles = new Vector(); - // MODED moved JABA JAn Baeyens get the out type from the add - // source call - caller.usedOutType = null; - addRuleForSource(project, relativePath, ruleBuffer, resource, sourceLocation, rcInfo, generatedSource, - generatedDepFiles, generatedOutputs); - // If the rule generates a dependency file(s), add the file(s) - // to the variable - if (generatedDepFiles.size() > 0) { - for (int k = 0; k < generatedDepFiles.size(); k++) { - IPath generatedDepFile = generatedDepFiles.get(k); - addMacroAdditionFile(buildVarToRuleStringMap, getDepMacroName(ext).toString(), - (generatedDepFile.isAbsolute() ? "" : DOT_SLASH_PATH.toOSString()) - + generatedDepFile.toOSString()); - } - } - // If the generated outputs of this tool are input to another - // tool, - // 1. add the output to the appropriate macro - // 2. If the tool does not have multipleOfType input, generate - // the rule. - // IOutputType outType = tool.getPrimaryOutputType(); - // MODED - // moved JABA JAn Baeyens get the out type from the add source - // call - String buildVariable = null; - if (caller.usedOutType != null) { - if (tool.getCustomBuildStep()) { - // TODO: This is somewhat of a hack since a custom build - // step - // tool does not currently define a build variable - if (generatedOutputs.size() > 0) { - IPath firstOutput = generatedOutputs.get(0); - String firstExt = firstOutput.getFileExtension(); - ToolInfoHolder tmpH = ToolInfoHolder.getFolderToolInfo(caller, rcInfo.getPath()); - ITool[] tmpBuildTools = tmpH.buildTools; - for (ITool tmpBuildTool : tmpBuildTools) { - if (tmpBuildTool.buildsFileType(firstExt)) { - String bV = tmpBuildTool.getPrimaryInputType().getBuildVariable(); - if (bV.length() > 0) { - buildVariable = bV; - break; - } - } - } - } - } else { - buildVariable = caller.usedOutType.getBuildVariable(); - } - } else { - // For support of pre-CDT 3.0 integrations. - buildVariable = OBJS_MACRO; - } - for (int k = 0; k < generatedOutputs.size(); k++) { - IPath generatedOutput; - IResource generateOutputResource; - if (generatedOutputs.get(k).isAbsolute()) { - // TODO: Should we use relative paths when possible - // (e.g., see MbsMacroSupplier.calculateRelPath) - generatedOutput = generatedOutputs.get(k); - // If this file has an absolute path, then the - // generateOutputResource will not be correct - // because the file is not under the project. We use - // this resource in the calls to the dependency - // generator - generateOutputResource = project.getFile(generatedOutput); - } else { - generatedOutput = getPathForResource(project).append(caller.getBuildWorkingDir()) - .append(generatedOutputs.get(k)); - generateOutputResource = project - .getFile(caller.getBuildWorkingDir().append(generatedOutputs.get(k))); - } - IResourceInfo nextRcInfo; - if (rcInfo instanceof IFileInfo) { - nextRcInfo = caller.config.getResourceInfo(rcInfo.getPath().removeLastSegments(1), false); - } else { - nextRcInfo = rcInfo; - } - addFragmentMakefileEntriesForSource(buildVarToRuleStringMap, ruleBuffer, folder, relativePath, - generateOutputResource, generatedOutput, nextRcInfo, buildVariable, true); - } - } - } else { - // If this is a secondary input, add it to build vars - if (varName == null) { - for (ITool buildTool : buildTools) { - if (buildTool.isInputFileType(ext)) { - addToBuildVar(buildVarToRuleStringMap, ext, varName, relativePath, sourceLocation, - generatedSource); - break; - } - } - } - // If this generated output is identified as a secondary output, add - // the file to the build variable - else { - IOutputType[] secondaryOutputs = caller.config.getToolChain().getSecondaryOutputs(); - if (secondaryOutputs.length > 0) { - if (isSecondaryOutputVar(h, secondaryOutputs, varName)) { - addMacroAdditionFile(caller, buildVarToRuleStringMap, varName, relativePath, sourceLocation, - generatedSource); - } - } - } - } - } - /** * Write all macro addition entries in a map to the buffer */ @@ -675,581 +290,6 @@ static private boolean isSecondaryOutputVar(ToolInfoHolder h, IOutputType[] seco return false; } - /** - * Create a rule for this source file. We create a pattern rule if possible. - * This is an example of a pattern rule: /%.: - * ..//%. - * - * @echo Building file: $< - * @echo Invoking tool xxx - * @echo $@ $< - * @ $@ $< && \ echo -n $(@:%.o=%.d) ' - * /' >> $(@:%.o=%.d) && \ -P -MM -MG $< - * >> $(@:%.o=%.d) - * @echo Finished building: $< - * @echo ' ' Note that the macros 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: ../source1/%.cpp - * @echo Building file: $< - * @echo Invoking tool xxx - * @echo g++ -g -O2 -c -I/cygdrive/c/eclipse/workspace/Project/headers -o$@ - * $< @g++ -g -O2 -c -I/cygdrive/c/eclipse/workspace/Project/headers -o$@ - * $< && \ echo -n $(@:%.o=%.d) ' source1/' >> $(@:%.o=%.d) && \ g++ -P - * -MM -MG -g -O2 -c -I/cygdrive/c/eclipse/workspace/Project/headers $< >> - * $(@:%.o=%.d) - * @echo Finished building: $< - * @echo ' ' - * @param relativePath - * top build output directory relative path of the current output - * directory - * @param buffer - * buffer to populate with the build rule - * @param resource - * the source file for this invocation of the tool - * @param sourceLocation - * the full path of the source - * @param rcInfo - * the IResourceInfo associated with this file or null - * @param generatedSource - * true if the resource is a generated output - * @param enumeratedOutputs - * vector of the filenames that are the output of this rule - */ - private void addRuleForSource(IProject project, String relativePath, StringBuffer buffer, IResource resource, - IPath sourceLocation, IResourceInfo rcInfo, boolean generatedSource, List generatedDepFiles, - List enumeratedOutputs) { - IConfiguration config = getConfig(); - String fileName = sourceLocation.removeFileExtension().lastSegment(); - String inputExtension = sourceLocation.getFileExtension(); - String outputExtension = null; - ITool tool = null; - if (rcInfo instanceof IFileInfo) { - IFileInfo fi = (IFileInfo) rcInfo; - ITool[] tools = fi.getToolsToInvoke(); - if (tools != null && tools.length > 0) { - tool = tools[0]; - } - } else { - IFolderInfo foInfo = (IFolderInfo) rcInfo; - tool = foInfo.getToolFromInputExtension(inputExtension); - } - ToolInfoHolder h = ToolInfoHolder.getToolInfo(caller, rcInfo.getPath()); - if (tool != null) - outputExtension = tool.getOutputExtension(inputExtension); - if (outputExtension == null) - outputExtension = EMPTY_STRING; - // Get the dependency generator information for this tool and file - // extension - IManagedDependencyGenerator oldDepGen = null; - IManagedDependencyGenerator2 depGen = null; - IManagedDependencyInfo depInfo = null; - IManagedDependencyCommands depCommands = null; - IManagedDependencyPreBuild depPreBuild = null; - IPath[] depFiles = null; - boolean doDepGen = false; - { - IManagedDependencyGeneratorType t = null; - if (tool != null) - t = tool.getDependencyGeneratorForExtension(inputExtension); - if (t != null) { - int calcType = t.getCalculatorType(); - if (calcType <= IManagedDependencyGeneratorType.TYPE_OLD_TYPE_LIMIT) { - oldDepGen = (IManagedDependencyGenerator) t; - doDepGen = (calcType == IManagedDependencyGeneratorType.TYPE_COMMAND); - if (doDepGen) { - IPath depFile = Path.fromOSString(relativePath + fileName + DOT + DEP_EXT); - getDependencyMakefiles(h).add(depFile); - generatedDepFiles.add(depFile); - } - } else { - depGen = (IManagedDependencyGenerator2) t; - doDepGen = (calcType == IManagedDependencyGeneratorType.TYPE_BUILD_COMMANDS); - IBuildObject buildContext = rcInfo; - depInfo = depGen.getDependencySourceInfo(resource.getProjectRelativePath(), resource, buildContext, - tool, getBuildWorkingDir()); - if (calcType == IManagedDependencyGeneratorType.TYPE_BUILD_COMMANDS) { - depCommands = (IManagedDependencyCommands) depInfo; - depFiles = depCommands.getDependencyFiles(); - } else if (calcType == IManagedDependencyGeneratorType.TYPE_PREBUILD_COMMANDS) { - depPreBuild = (IManagedDependencyPreBuild) depInfo; - depFiles = depPreBuild.getDependencyFiles(); - } - if (depFiles != null) { - for (IPath depFile : depFiles) { - getDependencyMakefiles(h).add(depFile); - generatedDepFiles.add(depFile); - } - } - } - } - } - // Figure out the output paths - String optDotExt = EMPTY_STRING; - if (outputExtension.length() > 0) - optDotExt = DOT + outputExtension; - // JABA - caller.usedOutType = tool.getPrimaryOutputType(); - calculateOutputsForSource(tool, relativePath, resource, sourceLocation, enumeratedOutputs); - String primaryOutputName = null; - if (enumeratedOutputs.size() > 0) { - primaryOutputName = escapeWhitespaces(enumeratedOutputs.get(0).toOSString()); - } else { - primaryOutputName = escapeWhitespaces(relativePath + fileName + optDotExt); - } - String otherPrimaryOutputs = EMPTY_STRING; - for (IPath curOutput : enumeratedOutputs) { - otherPrimaryOutputs += WHITESPACE + escapeWhitespaces(curOutput.toOSString()); - } - // Output file location needed for the file-build macros - IPath outputLocation = Path.fromOSString(primaryOutputName); - if (!outputLocation.isAbsolute()) { - outputLocation = getPathForResource(project).append(getBuildWorkingDir()).append(primaryOutputName); - } - // A separate rule is needed for the resource in the case where explicit - // file-specific macros - // are referenced, or if the resource contains special characters in its - // path (e.g., whitespace) - /* - * fix for 137674 We only need an explicit rule if one of the following is true: - * - The resource is linked, and its full path to its real location contains - * special characters - The resource is not linked, but its project relative - * path contains special characters - */ - boolean resourceNameRequiresExplicitRule = (resource.isLinked() - && containsSpecialCharacters(sourceLocation.toOSString())) - || (!resource.isLinked() && containsSpecialCharacters(resource.getProjectRelativePath().toOSString())); - boolean needExplicitRuleForFile = resourceNameRequiresExplicitRule - || BuildMacroProvider.getReferencedExplitFileMacros(tool).length > 0 - || BuildMacroProvider.getReferencedExplitFileMacros(tool.getToolCommand(), - IBuildMacroProvider.CONTEXT_FILE, - new FileContextData(sourceLocation, outputLocation, null, tool)).length > 0; - // Get and resolve the command - String cmd = tool.getToolCommand(); - try { - String resolvedCommand = null; - if (!needExplicitRuleForFile) { - resolvedCommand = ManagedBuildManager.getBuildMacroProvider().resolveValueToMakefileFormat(cmd, - EMPTY_STRING, WHITESPACE, IBuildMacroProvider.CONTEXT_FILE, - new FileContextData(sourceLocation, outputLocation, null, tool)); - } else { - // if we need an explicit rule then don't use any builder - // variables, resolve everything - // to explicit strings - resolvedCommand = ManagedBuildManager.getBuildMacroProvider().resolveValue(cmd, EMPTY_STRING, - WHITESPACE, IBuildMacroProvider.CONTEXT_FILE, - new FileContextData(sourceLocation, outputLocation, null, tool)); - } - if ((resolvedCommand = resolvedCommand.trim()).length() > 0) - cmd = resolvedCommand; - } catch (BuildMacroException e) { - /* JABA is not going to write this code */ - } - String defaultOutputName = EMPTY_STRING; - String primaryDependencyName = EMPTY_STRING; - String patternPrimaryDependencyName = EMPTY_STRING; - String home = (generatedSource) ? DOT : ROOT; - String resourcePath = null; - boolean patternRule = true; - boolean isItLinked = false; - if (resource.isLinked(IResource.CHECK_ANCESTORS)) { - // it IS linked, so use the actual location - isItLinked = true; - resourcePath = sourceLocation.toOSString(); - // Need a hardcoded rule, not a pattern rule, as a linked file - // can reside in any path - defaultOutputName = escapeWhitespaces(relativePath + fileName + optDotExt); - primaryDependencyName = escapeWhitespaces(resourcePath); - patternRule = false; - } else { - // Use the relative path (not really needed to store per se but in - // the future someone may want this) - resourcePath = relativePath; - // The rule and command to add to the makefile - if (rcInfo instanceof IFileInfo || needExplicitRuleForFile) { - // Need a hardcoded rule, not a pattern rule - defaultOutputName = escapeWhitespaces(resourcePath + fileName + optDotExt); - patternRule = false; - } else { - defaultOutputName = relativePath + WILDCARD + optDotExt; - } - primaryDependencyName = escapeWhitespaces( - home + FILE_SEPARATOR + resourcePath + fileName + DOT + inputExtension); - patternPrimaryDependencyName = home + FILE_SEPARATOR + resourcePath + WILDCARD + DOT + inputExtension; - } // end fix for PR 70491 - // If the tool specifies a dependency calculator of - // TYPE_BUILD_COMMANDS, - // ask whether - // the dependency commands are "generic" (i.e., we can use a pattern - // rule) - boolean needExplicitDependencyCommands = false; - if (depCommands != null) { - needExplicitDependencyCommands = !depCommands.areCommandsGeneric(); - } - // If we still think that we are using a pattern rule, check a few more - // things - if (patternRule) { - patternRule = false; - // Make sure that at least one of the rule outputs contains a %. - for (IPath output : enumeratedOutputs) { - String ruleOutput = output.toOSString(); - if (ruleOutput.indexOf('%') >= 0) { - patternRule = true; - break; - } - } - if (patternRule) { - patternRule = !needExplicitDependencyCommands; - } - } - // Begin building the rule for this source file - String buildRule = EMPTY_STRING; - if (patternRule) { - if (enumeratedOutputs.size() == 0) { - buildRule += defaultOutputName; - } else { - boolean first = true; - for (IPath curOutput : enumeratedOutputs) { - String ruleOutput = curOutput.toOSString(); - if (ruleOutput.indexOf('%') >= 0) { - if (first) { - first = false; - } else { - buildRule += WHITESPACE; - } - buildRule += ruleOutput; - } - } - } - } else { - buildRule += primaryOutputName; - } - String buildRuleDependencies = primaryDependencyName; - String patternBuildRuleDependencies = patternPrimaryDependencyName; - // Other additional inputs - // Get any additional dependencies specified for the tool in other - // InputType elements and AdditionalInput elements - IPath[] addlDepPaths = tool.getAdditionalDependencies(); - for (IPath addlDepPath : addlDepPaths) { - // Translate the path from project relative to build directory - // relative - IPath addlPath = addlDepPath; - if (!(addlPath.toString().startsWith("$("))) { - if (!addlPath.isAbsolute()) { - IPath tempPath = project.getLocation().append(new Path(ensureUnquoted(addlPath.toString()))); - if (tempPath != null) { - addlPath = ManagedBuildManager.calculateRelativePath(getTopBuildDir(), tempPath); - } - } - } - String suitablePath = ensurePathIsGNUMakeTargetRuleCompatibleSyntax(addlPath.toOSString()); - buildRuleDependencies += WHITESPACE + suitablePath; - patternBuildRuleDependencies += WHITESPACE + suitablePath; - } - buildRule += COLON + WHITESPACE + (patternRule ? patternBuildRuleDependencies : buildRuleDependencies); - // No duplicates in a makefile. If we already have this rule, don't add - // it or the commands to build the file - if (getRuleList().contains(buildRule)) { - // TODO: Should we assert that this is a pattern rule? - } else { - getRuleList().add(buildRule); - // Echo starting message - buffer.append(buildRule).append(NEWLINE); - buffer.append(TAB).append(AT).append(escapedEcho(MESSAGE_START_FILE + WHITESPACE + IN_MACRO)); - buffer.append(TAB).append(AT).append(escapedEcho(tool.getAnnouncement())); - // If the tool specifies a dependency calculator of - // TYPE_BUILD_COMMANDS, ask whether - // there are any pre-tool commands. - if (depCommands != null) { - String[] preToolCommands = depCommands.getPreToolDependencyCommands(); - if (preToolCommands != null && preToolCommands.length > 0) { - for (String preCmd : preToolCommands) { - try { - String resolvedCommand; - IBuildMacroProvider provider = ManagedBuildManager.getBuildMacroProvider(); - if (!needExplicitRuleForFile) { - resolvedCommand = provider.resolveValueToMakefileFormat(preCmd, EMPTY_STRING, - WHITESPACE, IBuildMacroProvider.CONTEXT_FILE, - new FileContextData(sourceLocation, outputLocation, null, tool)); - } else { - // if we need an explicit rule then don't use - // any builder - // variables, resolve everything to explicit - // strings - resolvedCommand = provider.resolveValue(preCmd, EMPTY_STRING, WHITESPACE, - IBuildMacroProvider.CONTEXT_FILE, - new FileContextData(sourceLocation, outputLocation, null, tool)); - } - if (resolvedCommand != null) - buffer.append(resolvedCommand).append(NEWLINE); - } catch (BuildMacroException e) { - /* JABA is not going to write this code */ - } - } - } - } - // Generate the command line - Vector inputs = new Vector(); - inputs.add(IN_MACRO); - // Other additional inputs - // Get any additional dependencies specified for the tool in other - // InputType elements and AdditionalInput elements - IPath[] addlInputPaths = getAdditionalResourcesForSource(tool); - for (IPath addlInputPath : addlInputPaths) { - // Translate the path from project relative to build directory - // relative - IPath addlPath = addlInputPath; - if (!(addlPath.toString().startsWith("$("))) { - if (!addlPath.isAbsolute()) { - IPath tempPath = getPathForResource(project).append(addlPath); - if (tempPath != null) { - addlPath = ManagedBuildManager.calculateRelativePath(getTopBuildDir(), tempPath); - } - } - } - inputs.add(addlPath.toOSString()); - } - String[] inputStrings = inputs.toArray(new String[inputs.size()]); - String[] flags = null; - // Get the tool command line options - try { - flags = tool.getToolCommandFlags(sourceLocation, outputLocation); - } catch (BuildException ex) { - // TODO add some routines to catch this - flags = EMPTY_STRING_ARRAY; - } - // If we have a TYPE_BUILD_COMMANDS dependency generator, determine - // if there are any options that - // it wants added to the command line - if (depCommands != null) { - flags = addDependencyOptions(depCommands, flags); - } - IManagedCommandLineInfo cmdLInfo = null; - String outflag = null; - String outputPrefix = null; - if (rcInfo instanceof IFileInfo || needExplicitRuleForFile || needExplicitDependencyCommands) { - outflag = tool.getOutputFlag(); - outputPrefix = tool.getOutputPrefix(); - // Call the command line generator - IManagedCommandLineGenerator cmdLGen = tool.getCommandLineGenerator(); - cmdLInfo = cmdLGen.generateCommandLineInfo(tool, cmd, flags, outflag, outputPrefix, - OUT_MACRO + otherPrimaryOutputs, inputStrings, getToolCommandLinePattern(config, tool)); - } else { - outflag = tool.getOutputFlag(); - outputPrefix = tool.getOutputPrefix(); - // Call the command line generator - cmdLInfo = generateToolCommandLineInfo(tool, inputExtension, flags, outflag, outputPrefix, - OUT_MACRO + otherPrimaryOutputs, inputStrings, sourceLocation, outputLocation); - } - // The command to build - String buildCmd; - if (cmdLInfo != null) { - buildCmd = cmdLInfo.getCommandLine(); - } else { - StringBuffer buildFlags = new StringBuffer(); - for (String flag : flags) { - if (flag != null) { - buildFlags.append(flag).append(WHITESPACE); - } - } - buildCmd = cmd + WHITESPACE + buildFlags.toString().trim() + WHITESPACE + outflag + WHITESPACE - + outputPrefix + OUT_MACRO + otherPrimaryOutputs + WHITESPACE + IN_MACRO; - } - // resolve any remaining macros in the command after it has been - // generated - try { - String resolvedCommand; - IBuildMacroProvider provider = ManagedBuildManager.getBuildMacroProvider(); - if (!needExplicitRuleForFile) { - resolvedCommand = provider.resolveValueToMakefileFormat(buildCmd, EMPTY_STRING, WHITESPACE, - IBuildMacroProvider.CONTEXT_FILE, - new FileContextData(sourceLocation, outputLocation, null, tool)); - } else { - // if we need an explicit rule then don't use any builder - // variables, resolve everything to explicit strings - resolvedCommand = provider.resolveValue(buildCmd, EMPTY_STRING, WHITESPACE, - IBuildMacroProvider.CONTEXT_FILE, - new FileContextData(sourceLocation, outputLocation, null, tool)); - } - if ((resolvedCommand = resolvedCommand.trim()).length() > 0) - buildCmd = resolvedCommand; - } catch (BuildMacroException e) { - /* JABA is not going to write this code */ - } - // buffer.append(TAB).append(AT).append(escapedEcho(buildCmd)); - // buffer.append(TAB).append(AT).append(buildCmd); - // JABA add sketch.prebuild and postbouild if needed - if ("sloeber.ino".equals(fileName)) { - ICConfigurationDescription confDesc = ManagedBuildManager.getDescriptionForConfiguration(config); - String sketchPrebuild = io.sloeber.core.common.Common.getBuildEnvironmentVariable(confDesc, - "sloeber.sketch.prebuild", new String(), true); - String sketchPostBuild = io.sloeber.core.common.Common.getBuildEnvironmentVariable(confDesc, - "sloeber.sketch.postbuild", new String(), true); - if (!sketchPrebuild.isEmpty()) { - buffer.append(TAB).append(sketchPrebuild); - } - buffer.append(TAB).append(buildCmd).append(NEWLINE); - if (!sketchPostBuild.isEmpty()) { - buffer.append(TAB).append(sketchPostBuild); - } - } else { - buffer.append(TAB).append(buildCmd); - } - // end JABA add sketch.prebuild and postbouild if needed - - // Determine if there are any dependencies to calculate - if (doDepGen) { - // Get the dependency rule out of the generator - String[] depCmds = null; - if (oldDepGen != null) { - depCmds = new String[1]; - depCmds[0] = oldDepGen.getDependencyCommand(resource, ManagedBuildManager.getBuildInfo(project)); - } else { - if (depCommands != null) { - depCmds = depCommands.getPostToolDependencyCommands(); - } - } - if (depCmds != null) { - for (String depCmd : depCmds) { - // Resolve any macros in the dep command after it has - // been generated. - // Note: do not trim the result because it will strip - // out necessary tab characters. - buffer.append(WHITESPACE).append(LOGICAL_AND).append(WHITESPACE).append(LINEBREAK); - try { - if (!needExplicitRuleForFile) { - depCmd = ManagedBuildManager.getBuildMacroProvider().resolveValueToMakefileFormat( - depCmd, EMPTY_STRING, WHITESPACE, IBuildMacroProvider.CONTEXT_FILE, - new FileContextData(sourceLocation, outputLocation, null, tool)); - } else { - depCmd = ManagedBuildManager.getBuildMacroProvider().resolveValue(depCmd, EMPTY_STRING, - WHITESPACE, IBuildMacroProvider.CONTEXT_FILE, - new FileContextData(sourceLocation, outputLocation, null, tool)); - } - } catch (BuildMacroException e) { - /* JABA is not going to do this */ - } - buffer.append(depCmd); - } - } - } - // Echo finished message - buffer.append(NEWLINE); - buffer.append(TAB).append(AT).append(escapedEcho(MESSAGE_FINISH_FILE + WHITESPACE + IN_MACRO)); - buffer.append(TAB).append(AT).append(ECHO_BLANK_LINE).append(NEWLINE); - } - // Determine if there are calculated dependencies - IPath[] addlDeps = null; - IPath[] addlTargets = null; - String calculatedDependencies = null; - boolean addedDepLines = false; - String depLine; - if (oldDepGen != null && oldDepGen.getCalculatorType() != IManagedDependencyGeneratorType.TYPE_COMMAND) { - addlDeps = oldCalculateDependenciesForSource(oldDepGen, tool, relativePath, resource); - } else { - if (depGen != null && depGen.getCalculatorType() == IManagedDependencyGeneratorType.TYPE_CUSTOM) { - if (depInfo instanceof IManagedDependencyCalculator) { - IManagedDependencyCalculator depCalculator = (IManagedDependencyCalculator) depInfo; - addlDeps = calculateDependenciesForSource(depCalculator); - addlTargets = depCalculator.getAdditionalTargets(); - } - } - } - if (addlDeps != null && addlDeps.length > 0) { - calculatedDependencies = ""; - for (IPath addlDep : addlDeps) { - calculatedDependencies += WHITESPACE + escapeWhitespaces(addlDep.toOSString()); - } - } - if (calculatedDependencies != null) { - depLine = primaryOutputName + COLON + calculatedDependencies + NEWLINE; - if (!getDepLineList().contains(depLine)) { - getDepLineList().add(depLine); - addedDepLines = true; - buffer.append(depLine); - } - } - - for (IPath curOutput : enumeratedOutputs) { - depLine = escapeWhitespaces(curOutput.toOSString()) + COLON + WHITESPACE + primaryOutputName; - if (calculatedDependencies != null) - depLine += calculatedDependencies; - depLine += NEWLINE; - if (!getDepLineList().contains(depLine)) { - getDepLineList().add(depLine); - addedDepLines = true; - buffer.append(depLine); - } - } - if (addedDepLines) { - buffer.append(NEWLINE); - } - // If we are using a dependency calculator of type - // TYPE_PREBUILD_COMMANDS, - // get the rule to build the dependency file - if (depPreBuild != null && depFiles != null) { - addedDepLines = false; - String[] preBuildCommands = depPreBuild.getDependencyCommands(); - if (preBuildCommands != null) { - depLine = ""; - // Can we use a pattern rule? - patternRule = !isItLinked && !needExplicitRuleForFile && depPreBuild.areCommandsGeneric(); - // Begin building the rule - for (int i = 0; i < depFiles.length; i++) { - if (i > 0) - depLine += WHITESPACE; - if (patternRule) { - optDotExt = EMPTY_STRING; - String depExt = depFiles[i].getFileExtension(); - if (depExt != null && depExt.length() > 0) - optDotExt = DOT + depExt; - depLine += escapeWhitespaces(relativePath + WILDCARD + optDotExt); - } else { - depLine += escapeWhitespaces((depFiles[i]).toOSString()); - } - } - depLine += COLON + WHITESPACE + (patternRule ? patternBuildRuleDependencies : buildRuleDependencies); - if (!getDepRuleList().contains(depLine)) { - getDepRuleList().add(depLine); - addedDepLines = true; - buffer.append(depLine).append(NEWLINE); - buffer.append(TAB).append(AT) - .append(escapedEcho(MESSAGE_START_DEPENDENCY + WHITESPACE + OUT_MACRO)); - for (String preBuildCommand : preBuildCommands) { - depLine = preBuildCommand; - // Resolve macros - try { - if (!needExplicitRuleForFile) { - depLine = ManagedBuildManager.getBuildMacroProvider().resolveValueToMakefileFormat( - depLine, EMPTY_STRING, WHITESPACE, IBuildMacroProvider.CONTEXT_FILE, - new FileContextData(sourceLocation, outputLocation, null, tool)); - } else { - depLine = ManagedBuildManager.getBuildMacroProvider().resolveValue(depLine, - EMPTY_STRING, WHITESPACE, IBuildMacroProvider.CONTEXT_FILE, - new FileContextData(sourceLocation, outputLocation, null, tool)); - } - } catch (BuildMacroException e) { - // JABA is not going to write this code - } - // buffer.append(TAB + AT + escapedEcho(depLine)); - // buffer.append(TAB + AT + depLine + NEWLINE); - buffer.append(TAB).append(depLine).append(NEWLINE); - } - } - if (addedDepLines) { - buffer.append(TAB).append(AT).append(ECHO_BLANK_LINE).append(NEWLINE); - } - } - } - } - - /************************************************************************* - * F R A G M E N T (subdir.mk) M A K E F I L E M E T H O D S - ************************************************************************/ - /** - * Returns a StringBuffer containing the comment(s) for a fragment - * makefile (subdir.mk). - */ - /** * Adds the source file to the appropriate build variable * @@ -1504,121 +544,6 @@ private void calculateOutputsForSource(ITool tool, String relativePath, IResourc } } - /** - * Returns any additional resources specified for the tool in other InputType - * elements and AdditionalInput elements - */ - protected IPath[] getAdditionalResourcesForSource(ITool tool) { - IProject project = getProject(); - List allRes = new ArrayList<>(); - IInputType[] types = tool.getInputTypes(); - for (IInputType type : types) { - // Additional resources come from 2 places. - // 1. From AdditionalInput childen - IPath[] res = type.getAdditionalResources(); - for (IPath re : res) { - allRes.add(re); - } - // 2. From InputTypes that other than the primary input type - if (!type.getPrimaryInput() && type != tool.getPrimaryInputType()) { - String var = type.getBuildVariable(); - if (var != null && var.length() > 0) { - allRes.add(Path.fromOSString("$(" + type.getBuildVariable() + ")")); - } else { - // Use file extensions - String[] typeExts = type.getSourceExtensions(tool); - for (IResource projectResource : caller.projectResources) { - if (projectResource.getType() == IResource.FILE) { - String fileExt = projectResource.getFileExtension(); - if (fileExt == null) { - fileExt = ""; - } - for (String typeExt : typeExts) { - if (fileExt.equals(typeExt)) { - allRes.add(projectResource.getProjectRelativePath()); - break; - } - } - } - } - } - // If an assignToOption has been specified, set the value of the - // option to the inputs - IOption assignToOption = tool.getOptionBySuperClassId(type.getAssignToOptionId()); - IOption option = tool.getOptionBySuperClassId(type.getOptionId()); - if (assignToOption != null && option == null) { - try { - int optType = assignToOption.getValueType(); - IResourceInfo rcInfo = tool.getParentResourceInfo(); - if (rcInfo != null) { - if (optType == IOption.STRING) { - String optVal = ""; - for (int j = 0; j < allRes.size(); j++) { - if (j != 0) { - optVal += " "; - } - String resPath = allRes.get(j).toString(); - if (!resPath.startsWith("$(")) { - IResource addlResource = project.getFile(resPath); - if (addlResource != null) { - IPath addlPath = addlResource.getLocation(); - if (addlPath != null) { - resPath = ManagedBuildManager - .calculateRelativePath(getTopBuildDir(), addlPath).toString(); - } - } - } - optVal += ManagedBuildManager - .calculateRelativePath(getTopBuildDir(), Path.fromOSString(resPath)) - .toString(); - } - ManagedBuildManager.setOption(rcInfo, tool, assignToOption, optVal); - } else if (optType == IOption.STRING_LIST || optType == IOption.LIBRARIES - || optType == IOption.OBJECTS || optType == IOption.INCLUDE_FILES - || optType == IOption.LIBRARY_PATHS || optType == IOption.LIBRARY_FILES - || optType == IOption.MACRO_FILES) { - // TODO: do we need to do anything with undefs - // here? - // Note that the path(s) must be translated from - // project relative - // to top build directory relative - String[] paths = new String[allRes.size()]; - for (int j = 0; j < allRes.size(); j++) { - paths[j] = allRes.get(j).toString(); - if (!paths[j].startsWith("$(")) { - IResource addlResource = project.getFile(paths[j]); - if (addlResource != null) { - IPath addlPath = addlResource.getLocation(); - if (addlPath != null) { - paths[j] = ManagedBuildManager - .calculateRelativePath(getTopBuildDir(), addlPath).toString(); - } - } - } - } - ManagedBuildManager.setOption(rcInfo, tool, assignToOption, paths); - } else if (optType == IOption.BOOLEAN) { - boolean b = false; - if (allRes.size() > 0) - b = true; - ManagedBuildManager.setOption(rcInfo, tool, assignToOption, b); - } else if (optType == IOption.ENUMERATED || optType == IOption.TREE) { - if (allRes.size() > 0) { - String s = allRes.get(0).toString(); - ManagedBuildManager.setOption(rcInfo, tool, assignToOption, s); - } - } - allRes.clear(); - } - } catch (BuildException ex) { - /* JABA is not going to write this code */ - } - } - } - } - return allRes.toArray(new IPath[allRes.size()]); - } - /** * If the path contains a %, returns the path resolved using the resource name */ @@ -1678,72 +603,4 @@ private IManagedCommandLineInfo generateToolCommandLineInfo(ITool tool, String s getToolCommandLinePattern(config, tool)); } - /** - * Returns the dependency IPaths for this invocation of the tool - * with the specified source file - * - * @param depGen - * the dependency calculator - * @param tool - * tool used to build the source file - * @param relativePath - * build output directory relative path of the current output - * directory - * @param resource - * source file to scan for dependencies - * @return Vector of IPaths that are relative to the build directory - */ - private IPath[] oldCalculateDependenciesForSource(IManagedDependencyGenerator depGen, ITool tool, - String relativePath, IResource resource) { - IProject project = getProject(); - Vector deps = new Vector(); - int type = depGen.getCalculatorType(); - switch (type) { - case IManagedDependencyGeneratorType.TYPE_INDEXER: - case IManagedDependencyGeneratorType.TYPE_EXTERNAL: - IResource[] res = depGen.findDependencies(resource, project); - if (res != null) { - for (IResource re : res) { - IPath dep = null; - if (re != null) { - IPath addlPath = re.getLocation(); - if (addlPath != null) { - dep = ManagedBuildManager.calculateRelativePath(getTopBuildDir(), addlPath); - } - } - if (dep != null) { - deps.add(dep); - } - } - } - break; - case IManagedDependencyGeneratorType.TYPE_NODEPS: - default: - break; - } - return deps.toArray(new IPath[deps.size()]); - } - - /** - * Returns the dependency IPaths relative to the build directory - * - * @param depCalculator - * the dependency calculator - * @return IPath[] that are relative to the build directory - */ - private IPath[] calculateDependenciesForSource(IManagedDependencyCalculator depCalculator) { - IProject project = getProject(); - IPath[] addlDeps = depCalculator.getDependencies(); - if (addlDeps != null) { - for (int i = 0; i < addlDeps.length; i++) { - if (!addlDeps[i].isAbsolute()) { - // Convert from project relative to build directory relative - IPath absolutePath = project.getLocation().append(addlDeps[i]); - addlDeps[i] = ManagedBuildManager.calculateRelativePath(getTopBuildDir(), absolutePath); - } - } - } - return addlDeps; - } - } From c10c4ebca1ad43859c8a8d05162b9c93574de5dd Mon Sep 17 00:00:00 2001 From: jantje Date: Fri, 14 Oct 2022 13:39:00 +0200 Subject: [PATCH 003/486] #1126 removal of dead code --- .../Internal/SubDirMakeGenerator.java | 397 +----------------- 1 file changed, 1 insertion(+), 396 deletions(-) diff --git a/io.sloeber.core/src/io/sloeber/managedBuild/Internal/SubDirMakeGenerator.java b/io.sloeber.core/src/io/sloeber/managedBuild/Internal/SubDirMakeGenerator.java index aebb7a84b..33cdf299b 100644 --- a/io.sloeber.core/src/io/sloeber/managedBuild/Internal/SubDirMakeGenerator.java +++ b/io.sloeber.core/src/io/sloeber/managedBuild/Internal/SubDirMakeGenerator.java @@ -4,31 +4,17 @@ //import static io.sloeber.managedBuild.Internal.ManagebBuildCommon.*; import static io.sloeber.managedBuild.Internal.ManagedBuildConstants.*; -import java.util.ArrayList; import java.util.HashSet; -import java.util.LinkedHashMap; import java.util.LinkedList; import java.util.List; -import java.util.Vector; -import org.eclipse.cdt.managedbuilder.core.BuildException; import org.eclipse.cdt.managedbuilder.core.IConfiguration; import org.eclipse.cdt.managedbuilder.core.IFileInfo; import org.eclipse.cdt.managedbuilder.core.IInputType; -import org.eclipse.cdt.managedbuilder.core.IManagedCommandLineGenerator; -import org.eclipse.cdt.managedbuilder.core.IManagedCommandLineInfo; -import org.eclipse.cdt.managedbuilder.core.IOption; import org.eclipse.cdt.managedbuilder.core.IOutputType; import org.eclipse.cdt.managedbuilder.core.IResourceInfo; import org.eclipse.cdt.managedbuilder.core.ITool; -import org.eclipse.cdt.managedbuilder.core.ManagedBuildManager; import org.eclipse.cdt.managedbuilder.internal.core.ManagedMakeMessages; -import org.eclipse.cdt.managedbuilder.internal.core.Tool; -import org.eclipse.cdt.managedbuilder.internal.macros.FileContextData; -import org.eclipse.cdt.managedbuilder.macros.BuildMacroException; -import org.eclipse.cdt.managedbuilder.macros.IBuildMacroProvider; -import org.eclipse.cdt.managedbuilder.makegen.IManagedBuilderMakefileGenerator; -import org.eclipse.cdt.managedbuilder.makegen.IManagedDependencyCommands; import org.eclipse.core.resources.IContainer; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IProject; @@ -55,18 +41,10 @@ private IPath getBuildWorkingDir() { return caller.getBuildWorkingDir(); } - private List getDependencyMakefiles(ToolInfoHolder h) { - return caller.getDependencyMakefiles(h); - } - private IFile getTopBuildDir() { return caller.getTopBuildDir(); } - private Vector getRuleList() { - return caller.getRuleList(); - } - private IConfiguration getConfig() { return caller.getConfig(); } @@ -75,10 +53,6 @@ private IProject getProject() { return caller.getProject(); } - private Vector getDepRuleList() { - return caller.getDepRuleList(); - } - /************************************************************************* * M A K E F I L E S P O P U L A T I O N M E T H O D S ************************************************************************/ @@ -94,7 +68,7 @@ public void populateFragmentMakefile(IContainer module) throws CoreException { return; } IPath moduleOutputPath = buildRoot.append(module.getProjectRelativePath()); - caller.updateMonitor(ManagedMakeMessages.getFormattedString("MakefileGenerator.message.gen.source.makefile", + caller.updateMonitor(ManagedMakeMessages.getFormattedString("MakefileGenerator.message.gen.source.makefile", //$NON-NLS-1$ moduleOutputPath.toString())); IPath moduleOutputDir = createDirectory(project, moduleOutputPath.toString()); IFile modMakefile = createFile(moduleOutputDir.append(MODFILE_NAME)); @@ -151,7 +125,6 @@ private StringBuffer GenerateRules(List makeRules, IConfiguration conf //Get the rules for the source files private List getMakeRules(IContainer module) { IConfiguration config = getConfig(); - IFile buildPath = getTopBuildDir(); IProject project = getProject(); List makeRules = new LinkedList<>(); // Visit the resources in this folder @@ -235,372 +208,4 @@ private List getMakeRules(IContainer module) { return makeRules; } - /** - * Write all macro addition entries in a map to the buffer - */ - static private StringBuffer writeAdditionMacros(LinkedHashMap map) { - StringBuffer buffer = new StringBuffer(); - // Add the comment - buffer.append(COMMENT_SYMBOL).append(WHITESPACE).append(ManagedMakeMessages.getResourceString(MOD_VARS)) - .append(NEWLINE); - for (String macroString : map.values()) { - // Check if we added any files to the rule - // Currently, we do this by comparing the end of the rule buffer to - // MACRO_ADDITION_PREFIX_SUFFIX - if (!(macroString.endsWith(MACRO_ADDITION_PREFIX_SUFFIX))) { - StringBuffer currentBuffer = new StringBuffer(); - // Remove the final "/" - if (macroString.endsWith(LINEBREAK)) { - macroString = macroString.substring(0, (macroString.length() - 2)) + NEWLINE; - } - currentBuffer.append(macroString); - currentBuffer.append(NEWLINE); - // append the contents of the buffer to the master buffer for - // the whole file - buffer.append(currentBuffer); - } - } - return buffer.append(NEWLINE); - } - - static private boolean isSecondaryOutputVar(ToolInfoHolder h, IOutputType[] secondaryOutputs, String varName) { - ITool[] buildTools = h.buildTools; - for (ITool buildTool : buildTools) { - // Add the specified output build variables - IOutputType[] outTypes = buildTool.getOutputTypes(); - if (outTypes != null && outTypes.length > 0) { - for (IOutputType outType : outTypes) { - // Is this one of the secondary outputs? - // Look for an outputType with this ID, or one with a - // superclass with this id - for (IOutputType secondaryOutput : secondaryOutputs) { - IOutputType matchType = outType; - do { - if (matchType.getId().equals(secondaryOutput.getId())) { - if (outType.getBuildVariable().equals(varName)) { - return true; - } - } - matchType = matchType.getSuperClass(); - } while (matchType != null); - } - } - } - } - return false; - } - - /** - * Adds the source file to the appropriate build variable - * - * @param buildVarToRuleStringMap - * map of build variable names to the list of files assigned to the - * variable - * @param ext - * the file extension of the file - * @param varName - * the build variable to add this invocation's outputs to if - * null, use the file extension to find the name - * @param relativePath - * build output directory relative path of the current output - * directory - * @param sourceLocation - * the full path of the source - * @param generatedSource - * if true, this file was generated by another tool in - * the tool-chain - */ - private void addToBuildVar(LinkedHashMap buildVarToRuleStringMap, String ext, String varName, - String relativePath, IPath sourceLocation, boolean generatedSource) { - List varList = null; - if (varName == null) { - // Get the proper source build variable based upon the extension - varName = getSourceMacroName(ext).toString(); - varList = caller.buildSrcVars.get(varName); - } else { - varList = caller.buildOutVars.get(varName); - } - // Add the resource to the list of all resources associated with a - // variable. - // Do not allow duplicates - there is no reason to and it can be 'bad' - - // e.g., having the same object in the OBJS list can cause duplicate - // symbol errors from the linker - if ((varList != null) && !(varList.contains(sourceLocation))) { - // Since we don't know how these files will be used, we store them - // using a "location" - // path rather than a relative path - varList.add(sourceLocation); - if (!buildVarToRuleStringMap.containsKey(varName)) { - // TODO - is this an error? - } else { - // Add the resource name to the makefile line that adds - // resources to the build variable - addMacroAdditionFile(caller, buildVarToRuleStringMap, varName, relativePath, sourceLocation, - generatedSource); - } - } - } - - /** - * Returns the output IPaths for this invocation of the tool with - * the specified source file The priorities for determining the names of the - * outputs of a tool are: 1. If the tool is the build target and primary output, - * use artifact name & extension - This case does not apply here... 2. If an - * option is specified, use the value of the option 3. If a nameProvider is - * specified, call it 4. If outputNames is specified, use it 5. Use the name - * pattern to generate a transformation macro so that the source names can be - * transformed into the target names using the built-in string substitution - * functions of make. - * - * @param relativePath - * build output directory relative path of the current output - * directory - * @param enumeratedOutputs - * Vector of IPaths of outputs that are relative to the build - * directory - */ - private void calculateOutputsForSource(ITool tool, String relativePath, IResource resource, IPath sourceLocation, - List enumeratedOutputs) { - IProject project = getProject(); - IConfiguration config = getConfig(); - String inExt = sourceLocation.getFileExtension(); - String outExt = tool.getOutputExtension(inExt); - // IResourceInfo rcInfo = tool.getParentResourceInfo(); - IOutputType[] outTypes = tool.getOutputTypes(); - if (outTypes != null && outTypes.length > 0) { - for (IOutputType type : outTypes) { - String outputPrefix = type.getOutputPrefix(); - - try { - if (containsSpecialCharacters(sourceLocation.toOSString())) { - outputPrefix = ManagedBuildManager.getBuildMacroProvider().resolveValue(outputPrefix, "", " ", - IBuildMacroProvider.CONTEXT_CONFIGURATION, config); - } else { - outputPrefix = ManagedBuildManager.getBuildMacroProvider().resolveValueToMakefileFormat( - outputPrefix, "", " ", IBuildMacroProvider.CONTEXT_CONFIGURATION, config); - } - } catch (BuildMacroException e) { - /* JABA is not going to write this code */ - } - // } - boolean multOfType = type.getMultipleOfType(); - IOption option = tool.getOptionBySuperClassId(type.getOptionId()); - IManagedOutputNameProviderJaba nameProvider = getJABANameProvider(type); - String[] outputNames = type.getOutputNames(); - // 1. If the tool is the build target and this is the primary - // output, - // use artifact name & extension - // Not appropriate here... - // 2. If an option is specified, use the value of the option - if (option != null) { - try { - List outputList = new ArrayList(); - int optType = option.getValueType(); - if (optType == IOption.STRING) { - outputList.add(outputPrefix + option.getStringValue()); - } else if (optType == IOption.STRING_LIST || optType == IOption.LIBRARIES - || optType == IOption.OBJECTS || optType == IOption.INCLUDE_FILES - || optType == IOption.LIBRARY_PATHS || optType == IOption.LIBRARY_FILES - || optType == IOption.MACRO_FILES) { - List value = (List) option.getValue(); - outputList = value; - ((Tool) tool).filterValues(optType, outputList); - // Add outputPrefix to each if necessary - if (outputPrefix.length() > 0) { - for (int j = 0; j < outputList.size(); j++) { - outputList.set(j, outputPrefix + outputList.get(j)); - } - } - } - for (int j = 0; j < outputList.size(); j++) { - String outputName = outputList.get(j); - // try to resolve the build macros in the output - // names - try { - String resolved = null; - if (containsSpecialCharacters(sourceLocation.toOSString())) { - resolved = ManagedBuildManager.getBuildMacroProvider().resolveValue(outputName, "", - " ", IBuildMacroProvider.CONTEXT_FILE, - new FileContextData(sourceLocation, null, option, tool)); - } else { - resolved = ManagedBuildManager.getBuildMacroProvider().resolveValueToMakefileFormat( - outputName, "", " ", IBuildMacroProvider.CONTEXT_FILE, - new FileContextData(sourceLocation, null, option, tool)); - } - if ((resolved = resolved.trim()).length() > 0) - outputName = resolved; - } catch (BuildMacroException e) { - /* JABA is not going to write this code */ - } - IPath outPath = Path.fromOSString(outputName); - // If only a file name is specified, add the - // relative path of this output directory - if (outPath.segmentCount() == 1) { - outPath = Path.fromOSString(relativePath + outputList.get(j)); - } - enumeratedOutputs.add(resolvePercent(outPath, sourceLocation)); - } - } catch (BuildException ex) { - /* JABA is not going to write this code */ - } - } else - // 3. If a nameProvider is specified, call it - if (nameProvider != null) { - IPath outPath = null; - outPath = nameProvider.getOutputName(project, config, tool, resource.getProjectRelativePath()); - if (outPath != null) { // MODDED BY JABA ADDED to handle - // null as return value - caller.usedOutType = type; // MODDED By JABA added to - // return the - // output type used to generate the - // command line - String outputName = outPath.toOSString(); - // try to resolve the build macros in the output - // names - try { - String resolved = null; - if (containsSpecialCharacters(sourceLocation.toOSString())) { - resolved = ManagedBuildManager.getBuildMacroProvider().resolveValue(outputName, "", " ", - IBuildMacroProvider.CONTEXT_FILE, - new FileContextData(sourceLocation, null, option, tool)); - } else { - resolved = ManagedBuildManager.getBuildMacroProvider().resolveValueToMakefileFormat( - outputName, "", " ", IBuildMacroProvider.CONTEXT_FILE, - new FileContextData(sourceLocation, null, option, tool)); - } - if ((resolved = resolved.trim()).length() > 0) - outputName = resolved; - } catch (BuildMacroException e) { - // JABA is not - // going to write - // this code - } - // If only a file name is specified, add the - // relative path of this output directory - if (outPath.segmentCount() == 1) { - outPath = Path.fromOSString(relativePath + outPath.toOSString()); - } - enumeratedOutputs.add(resolvePercent(outPath, sourceLocation)); - } // MODDED BY JABA ADDED - } else - // 4. If outputNames is specified, use it - if (outputNames != null) { - for (int j = 0; j < outputNames.length; j++) { - String outputName = outputNames[j]; - try { - // try to resolve the build macros in the output - // names - String resolved = ManagedBuildManager.getBuildMacroProvider().resolveValueToMakefileFormat( - outputName, "", " ", IBuildMacroProvider.CONTEXT_FILE, - new FileContextData(sourceLocation, null, option, tool)); - if ((resolved = resolved.trim()).length() > 0) - outputName = resolved; - } catch (BuildMacroException e) { - /* JABA is not going to write this code */ - } - IPath outPath = Path.fromOSString(outputName); - // If only a file name is specified, add the relative - // path of this output directory - if (outPath.segmentCount() == 1) { - outPath = Path.fromOSString(relativePath + outPath.toOSString()); - } - enumeratedOutputs.add(resolvePercent(outPath, sourceLocation)); - } - } else { - // 5. Use the name pattern to generate a transformation - // macro - // so that the source names can be transformed into the - // target names - // using the built-in string substitution functions of - // make. - if (multOfType) { - // This case is not handled - a nameProvider or - // outputNames must be specified - // TODO - report error - } else { - String namePattern = type.getNamePattern(); - IPath namePatternPath = null; - if (namePattern == null || namePattern.length() == 0) { - namePattern = relativePath + outputPrefix + IManagedBuilderMakefileGenerator.WILDCARD; - if (outExt != null && outExt.length() > 0) { - namePattern += DOT + outExt; - } - namePatternPath = Path.fromOSString(namePattern); - } else { - if (outputPrefix.length() > 0) { - namePattern = outputPrefix + namePattern; - } - namePatternPath = Path.fromOSString(namePattern); - // If only a file name is specified, add the - // relative path of this output directory - if (namePatternPath.segmentCount() == 1) { - namePatternPath = Path.fromOSString(relativePath + namePatternPath.toOSString()); - } - } - enumeratedOutputs.add(resolvePercent(namePatternPath, sourceLocation)); - } - } - } - } - } - - /** - * If the path contains a %, returns the path resolved using the resource name - */ - private IPath resolvePercent(IPath outPath, IPath sourceLocation) { - // Get the input file name - String fileName = sourceLocation.removeFileExtension().lastSegment(); - // Replace the % with the file name - String outName = outPath.toOSString().replace("%", fileName); - IPath result = Path.fromOSString(outName); - return DOT_SLASH_PATH.isPrefixOf(outPath) ? DOT_SLASH_PATH.append(result) : result; - } - - /* - * Add any dependency calculator options to the tool options - */ - private String[] addDependencyOptions(IManagedDependencyCommands depCommands, String[] flags) { - String[] depOptions = depCommands.getDependencyCommandOptions(); - if (depOptions != null && depOptions.length > 0) { - int flagsLen = flags.length; - String[] flagsCopy = new String[flags.length + depOptions.length]; - for (int i = 0; i < flags.length; i++) { - flagsCopy[i] = flags[i]; - } - for (int i = 0; i < depOptions.length; i++) { - flagsCopy[i + flagsLen] = depOptions[i]; - } - flags = flagsCopy; - } - return flags; - } - - private IManagedCommandLineInfo generateToolCommandLineInfo(ITool tool, String sourceExtension, String[] flags, - String outputFlag, String outputPrefix, String outputName, String[] inputResources, IPath inputLocation, - IPath outputLocation) { - IConfiguration config = getConfig(); - String cmd = tool.getToolCommand(); - // try to resolve the build macros in the tool command - try { - String resolvedCommand = null; - if ((inputLocation != null && inputLocation.toString().indexOf(" ") != -1) - || (outputLocation != null && outputLocation.toString().indexOf(" ") != -1)) { - resolvedCommand = ManagedBuildManager.getBuildMacroProvider().resolveValue(cmd, "", " ", - IBuildMacroProvider.CONTEXT_FILE, - new FileContextData(inputLocation, outputLocation, null, tool)); - } else { - resolvedCommand = ManagedBuildManager.getBuildMacroProvider().resolveValueToMakefileFormat(cmd, "", " ", - IBuildMacroProvider.CONTEXT_FILE, - new FileContextData(inputLocation, outputLocation, null, tool)); - } - if ((resolvedCommand = resolvedCommand.trim()).length() > 0) - cmd = resolvedCommand; - } catch (BuildMacroException e) { - /* JABA is not going to write this code */ - } - IManagedCommandLineGenerator gen = tool.getCommandLineGenerator(); - return gen.generateCommandLineInfo(tool, cmd, flags, outputFlag, outputPrefix, outputName, inputResources, - getToolCommandLinePattern(config, tool)); - } - } From 7d811136cf3e69aeadcf9d434e04d2eaa2d30e28 Mon Sep 17 00:00:00 2001 From: jantje Date: Fri, 14 Oct 2022 19:06:52 +0200 Subject: [PATCH 004/486] #1126 only deps need to be added to output file --- io.sloeber.core/plugin.xml | 5 +- .../managedBuild/Internal/MakeRule.java | 129 +++++++++--------- .../Internal/ManagebBuildCommon.java | 3 +- .../Internal/SubDirMakeGenerator.java | 16 ++- 4 files changed, 74 insertions(+), 79 deletions(-) diff --git a/io.sloeber.core/plugin.xml b/io.sloeber.core/plugin.xml index 200c45278..90c48d67a 100644 --- a/io.sloeber.core/plugin.xml +++ b/io.sloeber.core/plugin.xml @@ -186,7 +186,7 @@ dependencyContentType="org.eclipse.cdt.core.cxxHeader" id="io.sloeber.compiler.cpp.sketch.input" name="%inputType.CPP.name" - primaryInput="false" + primaryInput="true" sourceContentType="org.eclipse.cdt.core.cxxSource"> > targets = new HashMap<>(); //Macro file target map - Map> prerequisites = new HashMap<>();//Macro file prerequisites map - ITool tool = null; + private Map> myTargets = new HashMap<>(); //Macro file target map + private Map> myPrerequisites = new HashMap<>();//Macro file prerequisites map + private Map> myDependencies = new HashMap<>(); //Macro file target map + private ITool myTool = null; + + public MakeRule(ITool tool, IInputType inputType, IFile inputFile, IOutputType outputType, IFile outFile) { + addPrerequisite(inputType, inputFile); + addTarget(outputType, outFile); + myTool = tool; + calculateDependencies(); + } + + private void calculateDependencies() { + myDependencies.clear(); + //TOFIX the stuff below should be calculated + boolean toolGeneratesDependencyFiles = true; + if (!toolGeneratesDependencyFiles) { + return; + } + IPath[] deps = myTool.getAdditionalDependencies(); + + } public HashSet getPrerequisites() { HashSet ret = new HashSet<>(); - for (List cur : prerequisites.values()) { + for (List cur : myPrerequisites.values()) { ret.addAll(cur); } return ret; @@ -47,7 +67,7 @@ public HashSet getPrerequisites() { public HashSet getTargets() { HashSet ret = new HashSet<>(); - for (List cur : targets.values()) { + for (List cur : myTargets.values()) { ret.addAll(cur); } return ret; @@ -55,48 +75,55 @@ public HashSet getTargets() { public HashSet getMacros() { HashSet ret = new HashSet<>(); - for (IOutputType cur : targets.keySet()) { + for (IOutputType cur : myTargets.keySet()) { ret.add(cur.getBuildVariable()); } - for (IInputType cur : prerequisites.keySet()) { + for (IInputType cur : myPrerequisites.keySet()) { ret.add(cur.getBuildVariable()); } + for (String cur : myDependencies.keySet()) { + ret.add(cur); + } return ret; } public HashSet getMacroElements(String macroName) { HashSet ret = new HashSet<>(); - for (Entry> cur : targets.entrySet()) { + for (Entry> cur : myTargets.entrySet()) { if (macroName.equals(cur.getKey().getBuildVariable())) { ret.addAll(cur.getValue()); } } - for (Entry> cur : prerequisites.entrySet()) { + for (Entry> cur : myPrerequisites.entrySet()) { if (macroName.equals(cur.getKey().getBuildVariable())) { ret.addAll(cur.getValue()); } } + List tmp = myDependencies.get(macroName); + if (tmp != null) { + ret.addAll(tmp); + } return ret; } - public void addTarget(IOutputType outputType, IFile file) { - List files = targets.get(outputType); + private void addTarget(IOutputType outputType, IFile file) { + List files = myTargets.get(outputType); if (files == null) { files = new LinkedList<>(); files.add(file); - targets.put(outputType, files); + myTargets.put(outputType, files); } else { files.add(file); } } - public void addPrerequisite(IInputType inputType, IFile file) { - List files = prerequisites.get(inputType); + private void addPrerequisite(IInputType inputType, IFile file) { + List files = myPrerequisites.get(inputType); if (files == null) { files = new LinkedList<>(); files.add(file); - prerequisites.put(inputType, files); + myPrerequisites.put(inputType, files); } else { files.add(file); } @@ -104,29 +131,27 @@ public void addPrerequisite(IInputType inputType, IFile file) { private String enumTargets(IFile buildFolder) { String ret = new String(); - for (List curFiles : targets.values()) { + for (List curFiles : myTargets.values()) { for (IFile curFile : curFiles) { ret = ret + GetNiceFileName(buildFolder, curFile) + WHITESPACE; } } return ret; - //return StringUtils.join(targets.values(), WHITESPACE); } private String enumPrerequisites(IFile buildFolder) { String ret = new String(); - for (List curFiles : prerequisites.values()) { + for (List curFiles : myPrerequisites.values()) { for (IFile curFile : curFiles) { ret = ret + GetNiceFileName(buildFolder, curFile) + WHITESPACE; } } return ret; - // return StringUtils.join(prerequisites.values(), WHITESPACE); } public StringBuffer getRule(IProject project, IFile niceBuildFolder, IConfiguration config) { - String cmd = tool.getToolCommand(); + String cmd = myTool.getToolCommand(); //For now assume 1 target with 1 or more prerequisites // if there is more than 1 prerequisite we take the flags of the first prerequisite only HashSet local_targets = getTargets(); @@ -158,17 +183,17 @@ public StringBuffer getRule(IProject project, IFile niceBuildFolder, IConfigurat boolean needExplicitDependencyCommands = false; boolean resourceNameRequiresExplicitRule = containsSpecialCharacters(sourceLocation.getLocation().toOSString()); needExplicitRuleForFile = resourceNameRequiresExplicitRule - || BuildMacroProvider.getReferencedExplitFileMacros(tool).length > 0 + || BuildMacroProvider.getReferencedExplitFileMacros(myTool).length > 0 || BuildMacroProvider.getReferencedExplitFileMacros(cmd, IBuildMacroProvider.CONTEXT_FILE, new FileContextData(sourceLocation.getFullPath(), outputLocation.getFullPath(), null, - tool)).length > 0; + myTool)).length > 0; - String outflag = tool.getOutputFlag(); + String outflag = myTool.getOutputFlag(); String buildCmd = cmd + WHITESPACE + flags.toString().trim() + WHITESPACE + outflag + WHITESPACE - + tool.getOutputPrefix() + OUT_MACRO + otherPrimaryOutputs + WHITESPACE + IN_MACRO; + + myTool.getOutputPrefix() + OUT_MACRO + otherPrimaryOutputs + WHITESPACE + IN_MACRO; if (needExplicitRuleForFile || needExplicitDependencyCommands) { buildCmd = expandCommandLinePattern(cmd, flags, outflag, OUT_MACRO + otherPrimaryOutputs, niceNameList, - getToolCommandLinePattern(config, tool)); + getToolCommandLinePattern(config, myTool)); } else { buildCmd = expandCommandLinePattern(config, inputExtension, flags, outflag, OUT_MACRO + otherPrimaryOutputs, niceNameList, sourceLocation, outputLocation); @@ -181,13 +206,13 @@ public StringBuffer getRule(IProject project, IFile niceBuildFolder, IConfigurat if (!needExplicitRuleForFile) { resolvedCommand = provider.resolveValueToMakefileFormat(buildCmd, EMPTY_STRING, WHITESPACE, IBuildMacroProvider.CONTEXT_FILE, - new FileContextData(sourceLocation.getFullPath(), outputLocation.getFullPath(), null, tool)); + new FileContextData(sourceLocation.getFullPath(), outputLocation.getFullPath(), null, myTool)); } else { // if we need an explicit rule then don't use any builder // variables, resolve everything to explicit strings resolvedCommand = provider.resolveValue(buildCmd, EMPTY_STRING, WHITESPACE, IBuildMacroProvider.CONTEXT_FILE, - new FileContextData(sourceLocation.getFullPath(), outputLocation.getFullPath(), null, tool)); + new FileContextData(sourceLocation.getFullPath(), outputLocation.getFullPath(), null, myTool)); } if (!resolvedCommand.isBlank()) buildCmd = resolvedCommand.trim(); @@ -199,7 +224,7 @@ public StringBuffer getRule(IProject project, IFile niceBuildFolder, IConfigurat buffer.append(enumTargets(niceBuildFolder)).append(COLON).append(WHITESPACE); buffer.append(enumPrerequisites(niceBuildFolder)).append(NEWLINE); buffer.append(TAB).append(AT).append(escapedEcho(MESSAGE_START_FILE + WHITESPACE + IN_MACRO)); - buffer.append(TAB).append(AT).append(escapedEcho(tool.getAnnouncement())); + buffer.append(TAB).append(AT).append(escapedEcho(myTool.getAnnouncement())); // JABA add sketch.prebuild and postbouild if needed //TOFIX this should not be here @@ -221,38 +246,6 @@ public StringBuffer getRule(IProject project, IFile niceBuildFolder, IConfigurat } // end JABA add sketch.prebuild and postbouild if needed - // Determine if there are any dependencies to calculate - // if (doDepGen) { - // // Get the dependency rule out of the generator - // String[] depCmds = null; - // if (depCommands != null) { - // depCmds = depCommands.getPostToolDependencyCommands(); - // } - // if (depCmds != null) { - // for (String depCmd : depCmds) { - // // Resolve any macros in the dep command after it has - // // been generated. - // // Note: do not trim the result because it will strip - // // out necessary tab characters. - // buffer.append(WHITESPACE).append(LOGICAL_AND).append(WHITESPACE).append(LINEBREAK); - // try { - // if (!needExplicitRuleForFile) { - // depCmd = ManagedBuildManager.getBuildMacroProvider().resolveValueToMakefileFormat(depCmd, - // EMPTY_STRING, WHITESPACE, IBuildMacroProvider.CONTEXT_FILE, - // new FileContextData(sourceLocation, outputLocation, null, tool)); - // } else { - // depCmd = ManagedBuildManager.getBuildMacroProvider().resolveValue(depCmd, EMPTY_STRING, - // WHITESPACE, IBuildMacroProvider.CONTEXT_FILE, - // new FileContextData(sourceLocation, outputLocation, null, tool)); - // } - // } catch (BuildMacroException e) { - // /* JABA is not going to do this */ - // } - // buffer.append(depCmd); - // } - // } - // } - // Echo finished message buffer.append(NEWLINE); buffer.append(TAB).append(AT).append(escapedEcho(MESSAGE_FINISH_FILE + WHITESPACE + IN_MACRO)); buffer.append(TAB).append(AT).append(ECHO_BLANK_LINE).append(NEWLINE); @@ -265,16 +258,16 @@ private Set getBuildFlags(IFile buildFolder, IConfiguration config, IFil try { IResourceInfo buildContext = config.getResourceInfo(sourceFile.getFullPath().removeLastSegments(1), false); - flags.addAll(Arrays.asList(tool.getToolCommandFlags(sourceFile.getLocation(), outputFile.getLocation()))); + flags.addAll(Arrays.asList(myTool.getToolCommandFlags(sourceFile.getLocation(), outputFile.getLocation()))); - IInputType[] inputTypes = tool.getInputTypes(); //.getDependencyGeneratorForExtension(inputExtension); + IInputType[] inputTypes = myTool.getInputTypes(); //.getDependencyGeneratorForExtension(inputExtension); for (IInputType inputType : inputTypes) { IManagedDependencyGeneratorType t = inputType.getDependencyGenerator(); if (t != null) { if (t.getCalculatorType() == IManagedDependencyGeneratorType.TYPE_BUILD_COMMANDS) { IManagedDependencyGenerator2 depGen = (IManagedDependencyGenerator2) t; IManagedDependencyInfo depInfo = depGen.getDependencySourceInfo( - sourceFile.getProjectRelativePath(), sourceFile, buildContext, tool, + sourceFile.getProjectRelativePath(), sourceFile, buildContext, myTool, buildFolder.getFullPath()); IManagedDependencyCommands depCommands = (IManagedDependencyCommands) depInfo; if (depCommands != null) { @@ -294,7 +287,7 @@ private Set getBuildFlags(IFile buildFolder, IConfiguration config, IFil private String expandCommandLinePattern(IConfiguration config, String sourceExtension, Set flags, String outputFlag, String outputName, Set inputResources, IFile inputLocation, IFile outputLocation) { - String cmd = tool.getToolCommand(); + String cmd = myTool.getToolCommand(); // try to resolve the build macros in the tool command try { String resolvedCommand = null; @@ -302,11 +295,11 @@ private String expandCommandLinePattern(IConfiguration config, String sourceExte || (outputLocation != null && outputLocation.toString().indexOf(WHITESPACE) != -1)) { resolvedCommand = ManagedBuildManager.getBuildMacroProvider().resolveValue(cmd, EMPTY_STRING, WHITESPACE, IBuildMacroProvider.CONTEXT_FILE, - new FileContextData(inputLocation.getFullPath(), outputLocation.getFullPath(), null, tool)); + new FileContextData(inputLocation.getFullPath(), outputLocation.getFullPath(), null, myTool)); } else { resolvedCommand = ManagedBuildManager.getBuildMacroProvider().resolveValueToMakefileFormat(cmd, EMPTY_STRING, WHITESPACE, IBuildMacroProvider.CONTEXT_FILE, - new FileContextData(inputLocation.getFullPath(), outputLocation.getFullPath(), null, tool)); + new FileContextData(inputLocation.getFullPath(), outputLocation.getFullPath(), null, myTool)); } if ((resolvedCommand = resolvedCommand.trim()).length() > 0) cmd = resolvedCommand; @@ -314,7 +307,7 @@ private String expandCommandLinePattern(IConfiguration config, String sourceExte /* JABA is not going to write this code */ } return expandCommandLinePattern(cmd, flags, outputFlag, outputName, inputResources, - getToolCommandLinePattern(config, tool)); + getToolCommandLinePattern(config, myTool)); } // /** @@ -465,7 +458,7 @@ private String expandCommandLinePattern(String commandName, Set flags, S command = command.replace(makeVariable(CMD_LINE_PRM_NAME), commandName); command = command.replace(makeVariable(FLAGS_PRM_NAME), flagsStr); command = command.replace(makeVariable(OUTPUT_FLAG_PRM_NAME), outputFlag); - command = command.replace(makeVariable(OUTPUT_PREFIX_PRM_NAME), tool.getOutputPrefix()); + command = command.replace(makeVariable(OUTPUT_PREFIX_PRM_NAME), myTool.getOutputPrefix()); command = command.replace(makeVariable(OUTPUT_PRM_NAME), quotedOutputName); command = command.replace(makeVariable(INPUTS_PRM_NAME), inputsStr); diff --git a/io.sloeber.core/src/io/sloeber/managedBuild/Internal/ManagebBuildCommon.java b/io.sloeber.core/src/io/sloeber/managedBuild/Internal/ManagebBuildCommon.java index d07f0c779..8b095b1d1 100644 --- a/io.sloeber.core/src/io/sloeber/managedBuild/Internal/ManagebBuildCommon.java +++ b/io.sloeber.core/src/io/sloeber/managedBuild/Internal/ManagebBuildCommon.java @@ -609,7 +609,8 @@ static public String GetNiceFileName(IFile buildPath, IFile path) { IPath buildLocation = buildPath.getLocation(); IPath fileLocation = path.getLocation(); if (buildLocation.isPrefixOf(path.getLocation())) { - return DOT_SLASH_PATH.append(fileLocation.makeRelativeTo(buildLocation)).toOSString(); + return fileLocation.makeRelativeTo(buildLocation).toOSString(); + //return DOT_SLASH_PATH.append(fileLocation.makeRelativeTo(buildLocation)).toOSString(); } if (buildLocation.removeLastSegments(1).isPrefixOf(fileLocation)) { return fileLocation.makeRelativeTo(buildLocation).toOSString(); diff --git a/io.sloeber.core/src/io/sloeber/managedBuild/Internal/SubDirMakeGenerator.java b/io.sloeber.core/src/io/sloeber/managedBuild/Internal/SubDirMakeGenerator.java index 33cdf299b..02893e9d5 100644 --- a/io.sloeber.core/src/io/sloeber/managedBuild/Internal/SubDirMakeGenerator.java +++ b/io.sloeber.core/src/io/sloeber/managedBuild/Internal/SubDirMakeGenerator.java @@ -89,6 +89,8 @@ private StringBuffer GenerateMacros(List makeRules) { StringBuffer buffer = new StringBuffer(); IFile buildRoot = getTopBuildDir(); buffer.append(NEWLINE); + buffer.append(COMMENT_SYMBOL).append(WHITESPACE).append(ManagedMakeMessages.getResourceString(MOD_VARS)) + .append(NEWLINE); HashSet macroNames = new HashSet<>(); for (MakeRule makeRule : makeRules) { macroNames.addAll(makeRule.getMacros()); @@ -114,6 +116,8 @@ private StringBuffer GenerateMacros(List makeRules) { private StringBuffer GenerateRules(List makeRules, IConfiguration config) { StringBuffer buffer = new StringBuffer(); buffer.append(NEWLINE); + buffer.append(COMMENT_SYMBOL).append(WHITESPACE).append(ManagedMakeMessages.getResourceString(MOD_RULES)) + .append(NEWLINE); for (MakeRule makeRule : makeRules) { buffer.append(makeRule.getRule(getProject(), getTopBuildDir(), config)); @@ -182,16 +186,14 @@ private List getMakeRules(IContainer module) { IManagedOutputNameProviderJaba nameProvider = getJABANameProvider(outputType); if (nameProvider != null) { IPath outputFile = nameProvider.getOutputName(getProject(), config, tool, - resource.getFullPath()); + resource.getProjectRelativePath()); if (outputFile != null) { //We found a tool that provides a outputfile for our source file //TOFIX if this is a multiple to one we should only create one MakeRule - IPath correctOutputPath = new Path(config.getName()) - .append(outputFile.removeFirstSegments(1)); - MakeRule newMakeRule = new MakeRule(); - newMakeRule.addPrerequisite(inputType, inputFile); - newMakeRule.addTarget(outputType, project.getFile(correctOutputPath)); - newMakeRule.tool = tool; + IPath correctOutputPath = new Path(config.getName()).append(outputFile); + MakeRule newMakeRule = new MakeRule(tool, inputType, inputFile, outputType, + project.getFile(correctOutputPath)); + makeRules.add(newMakeRule); } From 09c6ce2c5af32117195b065c0547576b142b0dd1 Mon Sep 17 00:00:00 2001 From: jantje Date: Fri, 14 Oct 2022 20:58:42 +0200 Subject: [PATCH 005/486] #1126 the subdir.mk now also contains the dependencies I'm not yet happy with the use of caller --- .../managedBuild/Internal/MakeRule.java | 69 +++++++++++++++++-- .../Internal/SubDirMakeGenerator.java | 2 +- 2 files changed, 66 insertions(+), 5 deletions(-) diff --git a/io.sloeber.core/src/io/sloeber/managedBuild/Internal/MakeRule.java b/io.sloeber.core/src/io/sloeber/managedBuild/Internal/MakeRule.java index 81e2e06d9..89d279ce2 100644 --- a/io.sloeber.core/src/io/sloeber/managedBuild/Internal/MakeRule.java +++ b/io.sloeber.core/src/io/sloeber/managedBuild/Internal/MakeRule.java @@ -14,6 +14,7 @@ import org.eclipse.cdt.core.settings.model.ICConfigurationDescription; import org.eclipse.cdt.managedbuilder.core.BuildException; +import org.eclipse.cdt.managedbuilder.core.IBuildObject; import org.eclipse.cdt.managedbuilder.core.IConfiguration; import org.eclipse.cdt.managedbuilder.core.IInputType; import org.eclipse.cdt.managedbuilder.core.IOutputType; @@ -24,6 +25,7 @@ import org.eclipse.cdt.managedbuilder.internal.macros.FileContextData; import org.eclipse.cdt.managedbuilder.macros.BuildMacroException; import org.eclipse.cdt.managedbuilder.macros.IBuildMacroProvider; +import org.eclipse.cdt.managedbuilder.makegen.IManagedDependencyCalculator; import org.eclipse.cdt.managedbuilder.makegen.IManagedDependencyCommands; import org.eclipse.cdt.managedbuilder.makegen.IManagedDependencyGenerator2; import org.eclipse.cdt.managedbuilder.makegen.IManagedDependencyGeneratorType; @@ -39,22 +41,81 @@ public class MakeRule { private Map> myDependencies = new HashMap<>(); //Macro file target map private ITool myTool = null; - public MakeRule(ITool tool, IInputType inputType, IFile inputFile, IOutputType outputType, IFile outFile) { + //TOFIX get rid of caller argument + public MakeRule(ArduinoGnuMakefileGenerator caller, ITool tool, IInputType inputType, IFile inputFile, + IOutputType outputType, IFile outFile) { addPrerequisite(inputType, inputFile); addTarget(outputType, outFile); myTool = tool; - calculateDependencies(); + calculateDependencies(caller); } - private void calculateDependencies() { + private void calculateDependencies(ArduinoGnuMakefileGenerator caller) { myDependencies.clear(); //TOFIX the stuff below should be calculated boolean toolGeneratesDependencyFiles = true; if (!toolGeneratesDependencyFiles) { return; } - IPath[] deps = myTool.getAdditionalDependencies(); + for (Entry> curprerequisite : myPrerequisites.entrySet()) { + IInputType curInputType = curprerequisite.getKey(); + IManagedDependencyGeneratorType t = curInputType.getDependencyGenerator(); + if (t == null) { + continue; + } + List files = curprerequisite.getValue(); + String depkey = curInputType.getBuildVariable() + "_DEPS"; + for (IFile file : files) { + IResourceInfo rcInfo = caller.getConfig().getResourceInfo(file.getFullPath(), false); + int calcType = t.getCalculatorType(); + + IManagedDependencyGenerator2 depGen = (IManagedDependencyGenerator2) t; + IBuildObject buildContext = rcInfo; + IManagedDependencyInfo depInfo = depGen.getDependencySourceInfo(file.getProjectRelativePath(), file, + buildContext, myTool, caller.getBuildWorkingDir()); + + // if (calcType== IManagedDependencyGeneratorType.TYPE_CUSTOM) { + if (depInfo instanceof IManagedDependencyCalculator) { + IManagedDependencyCalculator depCalculator = (IManagedDependencyCalculator) depInfo; + IPath[] addlDeps = calculateDependenciesForSource(caller, depCalculator); + IPath[] addlTargets = depCalculator.getAdditionalTargets(); + // } + } + if (depInfo instanceof IManagedDependencyCommands) { + IManagedDependencyCommands tmp = (IManagedDependencyCommands) depInfo; + IPath[] addlTargets = tmp.getDependencyFiles(); + List depFiles = new LinkedList<>(); + for (IPath curPath : addlTargets) { + depFiles.add(caller.getProject().getFile(caller.getBuildWorkingDir().append(curPath))); + } + myDependencies.put(depkey, depFiles); + } + } + } + } + + /** + * Returns the dependency IPaths relative to the build directory + * + * @param depCalculator + * the dependency calculator + * @return IPath[] that are relative to the build directory + */ + private IPath[] calculateDependenciesForSource(ArduinoGnuMakefileGenerator caller, + IManagedDependencyCalculator depCalculator) { + IPath[] addlDeps = depCalculator.getDependencies(); + if (addlDeps != null) { + for (int i = 0; i < addlDeps.length; i++) { + if (!addlDeps[i].isAbsolute()) { + // Convert from project relative to build directory relative + IPath absolutePath = caller.getProject().getLocation().append(addlDeps[i]); + addlDeps[i] = ManagedBuildManager.calculateRelativePath(caller.getTopBuildDir().getLocation(), + absolutePath); + } + } + } + return addlDeps; } public HashSet getPrerequisites() { diff --git a/io.sloeber.core/src/io/sloeber/managedBuild/Internal/SubDirMakeGenerator.java b/io.sloeber.core/src/io/sloeber/managedBuild/Internal/SubDirMakeGenerator.java index 02893e9d5..260540813 100644 --- a/io.sloeber.core/src/io/sloeber/managedBuild/Internal/SubDirMakeGenerator.java +++ b/io.sloeber.core/src/io/sloeber/managedBuild/Internal/SubDirMakeGenerator.java @@ -191,7 +191,7 @@ private List getMakeRules(IContainer module) { //We found a tool that provides a outputfile for our source file //TOFIX if this is a multiple to one we should only create one MakeRule IPath correctOutputPath = new Path(config.getName()).append(outputFile); - MakeRule newMakeRule = new MakeRule(tool, inputType, inputFile, outputType, + MakeRule newMakeRule = new MakeRule(caller, tool, inputType, inputFile, outputType, project.getFile(correctOutputPath)); makeRules.add(newMakeRule); From 24bea2b123c205c2d4fcc03fcab9bca01aec1442 Mon Sep 17 00:00:00 2001 From: jantje Date: Sat, 15 Oct 2022 03:12:25 +0200 Subject: [PATCH 006/486] #1126 All seems fine except for the makefile rules I want to check in as I did lots of changes Building doesn't work anymore as the top level rules are missing --- .../Internal/ArduinoGnuMakefileGenerator.java | 725 ++++++--------- .../ArduinoManagedBuildGnuToolInfo.java | 848 +++++++++--------- .../managedBuild/Internal/MakeRule.java | 54 +- .../Internal/ManagebBuildCommon.java | 41 +- .../Internal/ManagedBuildConstants.java | 5 +- .../Internal/SrcMakeGenerator.java | 136 +-- .../Internal/SubDirMakeGenerator.java | 156 ++-- .../Internal/TopMakeFileGenerator.java | 81 +- 8 files changed, 918 insertions(+), 1128 deletions(-) diff --git a/io.sloeber.core/src/io/sloeber/managedBuild/Internal/ArduinoGnuMakefileGenerator.java b/io.sloeber.core/src/io/sloeber/managedBuild/Internal/ArduinoGnuMakefileGenerator.java index c6a54ea95..4e8976638 100644 --- a/io.sloeber.core/src/io/sloeber/managedBuild/Internal/ArduinoGnuMakefileGenerator.java +++ b/io.sloeber.core/src/io/sloeber/managedBuild/Internal/ArduinoGnuMakefileGenerator.java @@ -2,7 +2,6 @@ import static io.sloeber.core.common.Const.*; import static io.sloeber.managedBuild.Internal.ManagebBuildCommon.*; -import static io.sloeber.managedBuild.Internal.ManagedBuildConstants.*; import java.io.File; import java.io.IOException; @@ -12,10 +11,10 @@ import java.util.Collection; import java.util.HashMap; import java.util.HashSet; -import java.util.LinkedHashMap; import java.util.LinkedHashSet; +import java.util.LinkedList; import java.util.List; -import java.util.Map.Entry; +import java.util.Map; import java.util.Set; import java.util.Vector; @@ -83,9 +82,6 @@ @SuppressWarnings({ "deprecation", "restriction", "nls", "unused", "synthetic-access", "static-method", "unchecked", "hiding" }) public class ArduinoGnuMakefileGenerator implements IManagedBuilderMakefileGenerator2 { - SubDirMakeGenerator mySubDirMakeGenerator = null; - TopMakeFileGenerator myTopMakeFileGenerator = null; - SrcMakeGenerator mySrcMakeGenerator = null; /** * This class walks the delta supplied by the build system to determine what @@ -279,12 +275,8 @@ public boolean visit(IResourceProxy proxy) throws CoreException { private Vector depRuleList; // dependency files /** Collection of Containers which contribute source files to the build */ - private Collection subdirList; + private Collection subdirList = new LinkedHashSet(); private IFile topBuildDir; - final HashMap> buildSrcVars = new HashMap<>(); - final HashMap> buildOutVars = new HashMap<>(); - final HashMap buildDepVars = new HashMap<>(); - private final LinkedHashMap topBuildOutVars = new LinkedHashMap<>(); // Dependency file variables // private Vector dependencyMakefiles; // IPath's - relative to the top // build directory or absolute @@ -310,9 +302,6 @@ public ArduinoGnuMakefileGenerator() { public void initialize(IProject project, IManagedBuildInfo info, IProgressMonitor monitor) { this.project = project; - mySubDirMakeGenerator = new SubDirMakeGenerator(this); - myTopMakeFileGenerator = new TopMakeFileGenerator(this); - mySrcMakeGenerator = new SrcMakeGenerator(this); try { projectResources = project.members(); } catch (CoreException e) { @@ -465,10 +454,9 @@ public boolean visit(PathSettingsContainer container) { } }); IWorkspaceRoot root = CCorePlugin.getWorkspace().getRoot(); - for (IResource res : getSubdirList()) { + for (IContainer subDir : getSubdirList()) { // The builder creates a subdir with same name as source in the // build location - IContainer subDir = (IContainer) res; IPath projectRelativePath = subDir.getProjectRelativePath(); IResourceInfo rcInfo = config.getResourceInfo(projectRelativePath, false); PathSettingsContainer cr = postProcs.getChildContainer(rcInfo.getPath(), false, true); @@ -511,137 +499,125 @@ public MultiStatus generateMakefiles(IResourceDelta delta) throws CoreException * Let's do a sanity check right now. 1. This is an incremental build, so if the * top-level directory is not there, then a rebuild is needed. */ - IFolder folder = project.getFolder(config.getName()); - if (!folder.exists()) { - return regenerateMakefiles(); - } - // Return value - MultiStatus status; - // Visit the resources in the delta and compile a list of subdirectories - // to regenerate - updateMonitor( - ManagedMakeMessages.getFormattedString("MakefileGenerator.message.calc.delta", project.getName())); - ResourceDeltaVisitor visitor = new ResourceDeltaVisitor(this, config); - delta.accept(visitor); - checkCancel(); - // Get all the subdirectories participating in the build - updateMonitor( - ManagedMakeMessages.getFormattedString("MakefileGenerator.message.finding.sources", project.getName())); - ResourceProxyVisitor resourceVisitor = new ResourceProxyVisitor(this, config); - project.accept(resourceVisitor, IResource.NONE); - checkCancel(); - // Bug 303953: Ensure that if all resources have been removed from a - // folder, than the folder still - // appears in the subdir list so it's subdir.mk is correctly regenerated - getSubdirList().addAll(getModifiedList()); - // Make sure there is something to build - if (getSubdirList().isEmpty()) { - String info = ManagedMakeMessages.getFormattedString("MakefileGenerator.warning.no.source", - project.getName()); - updateMonitor(info); - status = new MultiStatus(ManagedBuilderCorePlugin.getUniqueIdentifier(), IStatus.INFO, "", null); - status.add(new Status(IStatus.INFO, ManagedBuilderCorePlugin.getUniqueIdentifier(), NO_SOURCE_FOLDERS, info, - null)); - return status; - } - // Make sure the build directory is available - topBuildDir = project.getFile(config.getName()); - createDirectory(project, config.getName()); - checkCancel(); - // Make sure that there is a makefile containing all the folders - // participating - IPath srcsFilePath = topBuildDir.getFullPath().append(SRCSFILE_NAME); - IFile srcsFileHandle = createFile(srcsFilePath); - buildSrcVars.clear(); - buildOutVars.clear(); - buildDepVars.clear(); - topBuildOutVars.clear(); - mySrcMakeGenerator.populateSourcesMakefile(srcsFileHandle, toolInfos, subdirList); - checkCancel(); - // Regenerate any fragments that are missing for the exisiting - // directories NOT modified - for (IResource res : getSubdirList()) { - IContainer subdirectory = (IContainer) res; - if (!getModifiedList().contains(subdirectory)) { - // Make sure the directory exists (it may have been deleted) - if (!subdirectory.exists()) { - appendDeletedSubdirectory(subdirectory); - continue; - } - // Make sure a fragment makefile exists - IPath fragmentPath = getBuildWorkingDir().append(subdirectory.getProjectRelativePath()) - .append(MODFILE_NAME); - IFile makeFragment = project.getFile(fragmentPath); - if (!makeFragment.exists()) { - // If one or both are missing, then add it to the list to be - // generated - getModifiedList().add(subdirectory); - } - } - } - // Delete the old dependency files for any deleted resources - for (IResource deletedFile : getDeletedFileList()) { - deleteDepFile(deletedFile); - deleteBuildTarget(deletedFile); - } - // Regenerate any fragments for modified directories - for (IResource res : getModifiedList()) { - IContainer subDir = (IContainer) res; - // Make sure the directory exists (it may have been deleted) - if (!subDir.exists()) { - appendDeletedSubdirectory(subDir); - continue; - } - // populateFragmentMakefile(subDir); // See below - checkCancel(); - } - // Recreate all module makefiles - // NOTE WELL: For now, always recreate all of the fragment makefile. - // This is necessary - // in order to re-populate the buildVariable lists. In the future, the - // list could - // possibly segmented by subdir so that all fragments didn't need to be - // regenerated - for (IResource res : getSubdirList()) { - IContainer subDir = (IContainer) res; - try { - mySubDirMakeGenerator.populateFragmentMakefile(subDir); - } catch (CoreException e) { - // Probably should ask user if they want to continue - checkCancel(); - continue; - } - checkCancel(); - } - // Calculate the inputs and outputs of the Tools to be generated in the - // main makefile - calculateToolInputsOutputs(); - checkCancel(); - // Re-create the top-level makefile - IPath makefilePath = topBuildDir.getFullPath().append(MAKEFILE_NAME); - IFile makefileHandle = createFile(makefilePath); - myTopMakeFileGenerator.populateTopMakefile(makefileHandle, false); - checkCancel(); - // Remove deleted folders from generated build directory - for (IResource res : getDeletedDirList()) { - IContainer subDir = (IContainer) res; - removeGeneratedDirectory(subDir); - checkCancel(); - } - // How did we do - if (!getInvalidDirList().isEmpty()) { - status = new MultiStatus(ManagedBuilderCorePlugin.getUniqueIdentifier(), IStatus.WARNING, "", null); - // Add a new status for each of the bad folders - // TODO: fix error message - for (IResource res : getInvalidDirList()) { - IContainer subDir = (IContainer) res; - status.add(new Status(IStatus.WARNING, ManagedBuilderCorePlugin.getUniqueIdentifier(), SPACES_IN_PATH, - subDir.getFullPath().toString(), null)); - } - } else { - status = new MultiStatus(ManagedBuilderCorePlugin.getUniqueIdentifier(), IStatus.OK, "", null); - } - return status; + return regenerateMakefiles(); + // IFolder folder = project.getFolder(config.getName()); + // if (!folder.exists()) { + // return regenerateMakefiles(); + // } + // // Return value + // MultiStatus status; + // // Visit the resources in the delta and compile a list of subdirectories + // // to regenerate + // updateMonitor( + // ManagedMakeMessages.getFormattedString("MakefileGenerator.message.calc.delta", project.getName())); + // ResourceDeltaVisitor visitor = new ResourceDeltaVisitor(this, config); + // delta.accept(visitor); + // checkCancel(); + // // Get all the subdirectories participating in the build + // updateMonitor( + // ManagedMakeMessages.getFormattedString("MakefileGenerator.message.finding.sources", project.getName())); + // ResourceProxyVisitor resourceVisitor = new ResourceProxyVisitor(this, config); + // project.accept(resourceVisitor, IResource.NONE); + // checkCancel(); + // // Bug 303953: Ensure that if all resources have been removed from a + // // folder, than the folder still + // // appears in the subdir list so it's subdir.mk is correctly regenerated + // getSubdirList().addAll(getModifiedList()); + // // Make sure there is something to build + // if (getSubdirList().isEmpty()) { + // String info = ManagedMakeMessages.getFormattedString("MakefileGenerator.warning.no.source", + // project.getName()); + // updateMonitor(info); + // status = new MultiStatus(ManagedBuilderCorePlugin.getUniqueIdentifier(), IStatus.INFO, "", null); + // status.add(new Status(IStatus.INFO, ManagedBuilderCorePlugin.getUniqueIdentifier(), NO_SOURCE_FOLDERS, info, + // null)); + // return status; + // } + // // Make sure the build directory is available + // topBuildDir = project.getFile(config.getName()); + // createDirectory(project, config.getName()); + // checkCancel(); + // // Make sure that there is a makefile containing all the folders + // // participating + // IPath srcsFilePath = topBuildDir.getFullPath().append(SRCSFILE_NAME); + // IFile srcsFileHandle = createFile(srcsFilePath); + // checkCancel(); + // // Regenerate any fragments that are missing for the exisiting + // // directories NOT modified + // for (IContainer subdirectory : getSubdirList()) { + // if (!getModifiedList().contains(subdirectory)) { + // // Make sure the directory exists (it may have been deleted) + // if (!subdirectory.exists()) { + // appendDeletedSubdirectory(subdirectory); + // continue; + // } + // // Make sure a fragment makefile exists + // IPath fragmentPath = getBuildWorkingDir().append(subdirectory.getProjectRelativePath()) + // .append(MODFILE_NAME); + // IFile makeFragment = project.getFile(fragmentPath); + // if (!makeFragment.exists()) { + // // If one or both are missing, then add it to the list to be + // // generated + // getModifiedList().add(subdirectory); + // } + // } + // } + // // Delete the old dependency files for any deleted resources + // for (IResource deletedFile : getDeletedFileList()) { + // deleteDepFile(deletedFile); + // deleteBuildTarget(deletedFile); + // } + // // Regenerate any fragments for modified directories + // for (IResource res : getModifiedList()) { + // IContainer subDir = (IContainer) res; + // // Make sure the directory exists (it may have been deleted) + // if (!subDir.exists()) { + // appendDeletedSubdirectory(subDir); + // continue; + // } + // // populateFragmentMakefile(subDir); // See below + // checkCancel(); + // } + // // Recreate all module makefiles + // // NOTE WELL: For now, always recreate all of the fragment makefile. + // // This is necessary + // // in order to re-populate the buildVariable lists. In the future, the + // // list could + // // possibly segmented by subdir so that all fragments didn't need to be + // // regenerated + // for (IContainer subDir : getSubdirList()) { + // mySubDirMakeGenerators.add(new SubDirMakeGenerator(this, subDir)); + // checkCancel(); + // } + // // Calculate the inputs and outputs of the Tools to be generated in the + // // main makefile + // calculateToolInputsOutputs(); + // checkCancel(); + // // Re-create the top-level makefile + // IPath makefilePath = topBuildDir.getFullPath().append(MAKEFILE_NAME); + // IFile makefileHandle = createFile(makefilePath); + // myTopMakeFileGenerator.populateTopMakefile(makefileHandle, false); + // checkCancel(); + // // Remove deleted folders from generated build directory + // for (IResource res : getDeletedDirList()) { + // IContainer subDir = (IContainer) res; + // removeGeneratedDirectory(subDir); + // checkCancel(); + // } + // // How did we do + // if (!getInvalidDirList().isEmpty()) { + // status = new MultiStatus(ManagedBuilderCorePlugin.getUniqueIdentifier(), IStatus.WARNING, "", null); + // // Add a new status for each of the bad folders + // // TODO: fix error message + // for (IResource res : getInvalidDirList()) { + // IContainer subDir = (IContainer) res; + // status.add(new Status(IStatus.WARNING, ManagedBuilderCorePlugin.getUniqueIdentifier(), SPACES_IN_PATH, + // subDir.getFullPath().toString(), null)); + // } + // } else { + // status = new MultiStatus(ManagedBuilderCorePlugin.getUniqueIdentifier(), IStatus.OK, "", null); + // } + // return status; } /* @@ -768,37 +744,29 @@ public MultiStatus regenerateMakefiles() throws CoreException { } // Create the top-level directory for the build output topBuildDir = project.getFile(config.getName()); - createDirectory(project, config.getName()); - checkCancel(); - // Get the list of subdirectories - IPath srcsFilePath = topBuildDir.getFullPath().append(SRCSFILE_NAME); - IFile srcsFileHandle = createFile(srcsFilePath); - buildSrcVars.clear(); - buildOutVars.clear(); - buildDepVars.clear(); - topBuildOutVars.clear(); - mySrcMakeGenerator.populateSourcesMakefile(srcsFileHandle, toolInfos, subdirList); checkCancel(); - // Now populate the module makefiles - for (IResource res : getSubdirList()) { - IContainer subDir = (IContainer) res; - try { - mySubDirMakeGenerator.populateFragmentMakefile(subDir); - } catch (CoreException e) { - // Probably should ask user if they want to continue - checkCancel(); - continue; - } + // Get the data for the makefile generation + List subDirMakeGenerators = new LinkedList<>(); + Map> allSourceTargets = new HashMap<>(); + Set dependencyMacros = new HashSet<>(); + Set dependencyFiles = new HashSet<>(); + + for (IContainer res : getSubdirList()) { + SubDirMakeGenerator subDirMakeGenerator = new SubDirMakeGenerator(this, res); + allSourceTargets.putAll(subDirMakeGenerator.getTargets()); + dependencyMacros.addAll(subDirMakeGenerator.getDependecyMacros()); + dependencyFiles.addAll(subDirMakeGenerator.getDependencyFiles()); + subDirMakeGenerators.add(subDirMakeGenerator); checkCancel(); } - // Calculate the inputs and outputs of the Tools to be generated in the + TopMakeFileGenerator topMakeFileGenerator = new TopMakeFileGenerator(this, allSourceTargets, dependencyMacros, + dependencyFiles); // main makefile - calculateToolInputsOutputs(); + // calculateToolInputsOutputs(); checkCancel(); // Create the top-level makefile - IPath makefilePath = topBuildDir.getFullPath().append(MAKEFILE_NAME); - IFile makefileHandle = createFile(makefilePath); - myTopMakeFileGenerator.populateTopMakefile(makefileHandle, true); + IFile makefileHandle = project.getFile(config.getName() + '/' + MAKEFILE_NAME); + topMakeFileGenerator.populateTopMakefile(makefileHandle, true); // JABA SLOEBER create the size.awk file ICConfigurationDescription confDesc = ManagedBuildManager.getDescriptionForConfiguration(config); IWorkspaceRoot root = CCorePlugin.getWorkspace().getRoot(); @@ -828,9 +796,19 @@ public MultiStatus regenerateMakefiles() throws CoreException { // END JABA SLOEBER create the size.awk file checkCancel(); // Now finish up by adding all the object files - IPath objFilePath = topBuildDir.getLocation().append(OBJECTS_MAKFILE); - IFile objsFileHandle = createFile(objFilePath); - populateObjectsMakefile(objsFileHandle); + + Set srcMacroNames = new LinkedHashSet<>(); + Set objMacroNames = new LinkedHashSet<>(); + for (SubDirMakeGenerator curSubDirMake : subDirMakeGenerators) { + curSubDirMake.generateMakefile(); + srcMacroNames.addAll(curSubDirMake.getPrerequisiteMacros()); + srcMacroNames.addAll(curSubDirMake.getDependecyMacros()); + objMacroNames.addAll(curSubDirMake.getTargetMacros()); + } + //TOFIX also need to add macro's from main makefile + + SrcMakeGenerator.generateSourceMakefile(project, config, srcMacroNames, subdirList); + SrcMakeGenerator.generateObjectsMakefile(project, config, objMacroNames); checkCancel(); // How did we do if (!getInvalidDirList().isEmpty()) { @@ -847,60 +825,6 @@ public MultiStatus regenerateMakefiles() throws CoreException { return status; } - /** - * The makefile generator generates a Macro for each type of output, other than - * final artifact, created by the build. - * - * @param fileHandle - * The file that should be populated with the output - */ - protected void populateObjectsMakefile(IFile fileHandle) throws CoreException { - // Master list of "object" dependencies, i.e. dependencies between input - // files and output files. - StringBuffer macroBuffer = new StringBuffer(); - List valueList; - macroBuffer.append(addDefaultHeader()); - // Map of macro names (String) to its definition (List of Strings) - HashMap> outputMacros = new HashMap>(); - // Add the predefined LIBS, USER_OBJS macros - // Add the libraries this project depends on - valueList = new ArrayList(); - String[] libs = config.getLibs(buildTargetExt); - for (String lib : libs) { - valueList.add(lib); - } - outputMacros.put("LIBS", valueList); - // Add the extra user-specified objects - valueList = new ArrayList(); - String[] userObjs = config.getUserObjects(buildTargetExt); - for (String obj : userObjs) { - valueList.add(obj); - } - outputMacros.put("USER_OBJS", valueList); - // Write every macro to the file - for (Entry> entry : outputMacros.entrySet()) { - macroBuffer.append(entry.getKey()).append(" :="); - valueList = entry.getValue(); - for (String path : valueList) { - // These macros will also be used within commands. - // Make all the slashes go forward so they aren't - // interpreted as escapes and get lost. - // See https://bugs.eclipse.org/163672. - path = path.replace('\\', '/'); - path = ensurePathIsGNUMakeTargetRuleCompatibleSyntax(path); - macroBuffer.append(WHITESPACE); - macroBuffer.append(path); - } - // terminate the macro definition line - macroBuffer.append(NEWLINE); - // leave a blank line before the next macro - macroBuffer.append(NEWLINE); - } - // For now, just save the buffer that was populated when the rules were - // created - save(macroBuffer, fileHandle); - } - /************************************************************************* * M A K E F I L E G E N E R A T I O N C O M M O N M E T H O D S ************************************************************************/ @@ -953,216 +877,130 @@ public void addMacroAdditionFiles(HashMap map, String macroName, * makefile. This information is used by the top level makefile generation * methods. */ - protected void calculateToolInputsOutputs() { - toolInfos.accept(new IPathSettingsContainerVisitor() { - @Override - public boolean visit(PathSettingsContainer container) { - ToolInfoHolder h = (ToolInfoHolder) container.getValue(); - ITool[] buildTools = h.buildTools; - ArduinoManagedBuildGnuToolInfo[] gnuToolInfos = h.gnuToolInfos; - // We are "done" when the information for all tools has been - // calculated, - // or we are not making any progress - boolean done = false; - boolean lastChance = false; - int[] doneState = new int[buildTools.length]; - // Identify the target tool - ITool targetTool = config.calculateTargetTool(); - // if (targetTool == null) { - // targetTool = info.getToolFromOutputExtension(buildTargetExt); - // } - // Initialize the tool info array and the done state - if (buildTools.length != 0 && buildTools[0].getCustomBuildStep()) - return true; - for (int i = 0; i < buildTools.length; i++) { - if ((buildTools[i] == targetTool)) { - String ext = config.getArtifactExtension(); - // try to resolve the build macros in the artifact - // extension - try { - ext = ManagedBuildManager.getBuildMacroProvider().resolveValueToMakefileFormat(ext, "", " ", - IBuildMacroProvider.CONTEXT_CONFIGURATION, config); - } catch (BuildMacroException e) { - /* JABA is not going to write this code */ - } - String name = config.getArtifactName(); - // try to resolve the build macros in the artifact name - try { - String resolved = ManagedBuildManager.getBuildMacroProvider().resolveValueToMakefileFormat( - name, "", " ", IBuildMacroProvider.CONTEXT_CONFIGURATION, config); - if ((resolved = resolved.trim()).length() > 0) - name = resolved; - } catch (BuildMacroException e) { - /* JABA is not going to write this code */ - } - gnuToolInfos[i] = new ArduinoManagedBuildGnuToolInfo(project, buildTools[i], true, name, ext); - } else { - gnuToolInfos[i] = new ArduinoManagedBuildGnuToolInfo(project, buildTools[i], false, null, null); - } - doneState[i] = 0; - } - // Initialize the build output variable to file additions map - LinkedHashMap map = getTopBuildOutputVars(); - Set>> set = buildOutVars.entrySet(); - for (Entry> entry : set) { - String macroName = entry.getKey(); - // for projects with specific setting on folders/files do - // not clear the macro value on subsequent passes - if (!map.containsKey(macroName)) { - addMacroAdditionPrefix(map, macroName, "", false); - } - } - // Set of input extensions for which macros have been created so - // far - HashSet handledDepsInputExtensions = new HashSet<>(); - HashSet handledOutsInputExtensions = new HashSet<>(); - while (!done) { - int[] testState = new int[doneState.length]; - for (int i = 0; i < testState.length; i++) - testState[i] = 0; - // Calculate inputs - for (int i = 0; i < gnuToolInfos.length; i++) { - if (gnuToolInfos[i].areInputsCalculated()) { - testState[i]++; - } else { - if (gnuToolInfos[i].calculateInputs(ArduinoGnuMakefileGenerator.this, config, - projectResources, h, lastChance)) { - testState[i]++; - } - } - } - // Calculate dependencies - for (int i = 0; i < gnuToolInfos.length; i++) { - if (gnuToolInfos[i].areDependenciesCalculated()) { - testState[i]++; - } else { - if (gnuToolInfos[i].calculateDependencies(ArduinoGnuMakefileGenerator.this, config, - handledDepsInputExtensions, h, lastChance)) { - testState[i]++; - } - } - } - // Calculate outputs - for (int i = 0; i < gnuToolInfos.length; i++) { - if (gnuToolInfos[i].areOutputsCalculated()) { - testState[i]++; - } else { - if (gnuToolInfos[i].calculateOutputs(ArduinoGnuMakefileGenerator.this, config, - handledOutsInputExtensions, lastChance)) { - testState[i]++; - } - } - } - // Are all calculated? If so, done. - done = true; - for (int element : testState) { - if (element != 3) { - done = false; - break; - } - } - // Test our "done" state vs. the previous "done" state. - // If we have made no progress, give it a "last chance" and - // then quit - if (!done) { - done = true; - for (int i = 0; i < testState.length; i++) { - if (testState[i] != doneState[i]) { - done = false; - break; - } - } - } - if (done) { - if (!lastChance) { - lastChance = true; - done = false; - } - } - if (!done) { - doneState = testState; - } - } - return true; - } - }); - } - - /** - * Returns the (String) list of files associated with the build variable - * - * @param variable - * the variable name - * @param locationType - * the format in which we want the filenames returned - * @param directory - * project relative directory path used with locationType == - * DIRECTORY_RELATIVE - * @param getAll - * only return the list if all tools that are going to contrubute to - * this variable have done so. - * @return List - */ - public List getBuildVariableList(ToolInfoHolder h, String variable, int locationType, IPath directory, - boolean getAll) { - ArduinoManagedBuildGnuToolInfo[] gnuToolInfos = h.gnuToolInfos; - boolean done = true; - for (int i = 0; i < gnuToolInfos.length; i++) { - if (!gnuToolInfos[i].areOutputVariablesCalculated()) { - done = false; - } - } - if (!done && getAll) - return null; - List list = buildSrcVars.get(variable); - if (list == null) { - list = buildOutVars.get(variable); - } - List fileList = null; - if (list != null) { - // Convert the items in the list to the location-type wanted by the - // caller, - // and to a string list - IPath dirLocation = null; - if (locationType != ABSOLUTE) { - dirLocation = project.getLocation(); - if (locationType == PROJECT_SUBDIR_RELATIVE) { - dirLocation = dirLocation.append(directory); - } - } - for (int i = 0; i < list.size(); i++) { - IPath path = list.get(i); - if (locationType != ABSOLUTE) { - if (dirLocation != null && dirLocation.isPrefixOf(path)) { - path = path.removeFirstSegments(dirLocation.segmentCount()).setDevice(null); - } - } - if (fileList == null) { - fileList = new Vector(); - } - fileList.add(path.toString()); - } - } - return fileList; - } - - /** - * Returns the map of build variables to list of files - * - * @return HashMap - */ - public HashMap> getBuildOutputVars() { - return buildOutVars; - } - - /** - * Returns the map of build variables used in the top makefile to list of files - * - * @return HashMap - */ - public LinkedHashMap getTopBuildOutputVars() { - return topBuildOutVars; - } + // protected void calculateToolInputsOutputs() { + // toolInfos.accept(new IPathSettingsContainerVisitor() { + // @Override + // public boolean visit(PathSettingsContainer container) { + // ToolInfoHolder h = (ToolInfoHolder) container.getValue(); + // ITool[] buildTools = h.buildTools; + // ArduinoManagedBuildGnuToolInfo[] gnuToolInfos = h.gnuToolInfos; + // // We are "done" when the information for all tools has been + // // calculated, + // // or we are not making any progress + // boolean done = false; + // boolean lastChance = false; + // int[] doneState = new int[buildTools.length]; + // // Identify the target tool + // ITool targetTool = config.calculateTargetTool(); + // // if (targetTool == null) { + // // targetTool = info.getToolFromOutputExtension(buildTargetExt); + // // } + // // Initialize the tool info array and the done state + // if (buildTools.length != 0 && buildTools[0].getCustomBuildStep()) + // return true; + // for (int i = 0; i < buildTools.length; i++) { + // if ((buildTools[i] == targetTool)) { + // String ext = config.getArtifactExtension(); + // // try to resolve the build macros in the artifact + // // extension + // try { + // ext = ManagedBuildManager.getBuildMacroProvider().resolveValueToMakefileFormat(ext, "", " ", + // IBuildMacroProvider.CONTEXT_CONFIGURATION, config); + // } catch (BuildMacroException e) { + // /* JABA is not going to write this code */ + // } + // String name = config.getArtifactName(); + // // try to resolve the build macros in the artifact name + // try { + // String resolved = ManagedBuildManager.getBuildMacroProvider().resolveValueToMakefileFormat( + // name, "", " ", IBuildMacroProvider.CONTEXT_CONFIGURATION, config); + // if ((resolved = resolved.trim()).length() > 0) + // name = resolved; + // } catch (BuildMacroException e) { + // /* JABA is not going to write this code */ + // } + // gnuToolInfos[i] = new ArduinoManagedBuildGnuToolInfo(project, buildTools[i], true, name, ext); + // } else { + // gnuToolInfos[i] = new ArduinoManagedBuildGnuToolInfo(project, buildTools[i], false, null, null); + // } + // doneState[i] = 0; + // } + // + // // Set of input extensions for which macros have been created so + // // far + // HashSet handledDepsInputExtensions = new HashSet<>(); + // HashSet handledOutsInputExtensions = new HashSet<>(); + // while (!done) { + // int[] testState = new int[doneState.length]; + // for (int i = 0; i < testState.length; i++) + // testState[i] = 0; + // // Calculate inputs + // for (int i = 0; i < gnuToolInfos.length; i++) { + // if (gnuToolInfos[i].areInputsCalculated()) { + // testState[i]++; + // } else { + // if (gnuToolInfos[i].calculateInputs(ArduinoGnuMakefileGenerator.this, config, + // projectResources, h, lastChance)) { + // testState[i]++; + // } + // } + // } + // // Calculate dependencies + // for (int i = 0; i < gnuToolInfos.length; i++) { + // if (gnuToolInfos[i].areDependenciesCalculated()) { + // testState[i]++; + // } else { + // if (gnuToolInfos[i].calculateDependencies(ArduinoGnuMakefileGenerator.this, config, + // handledDepsInputExtensions, h, lastChance)) { + // testState[i]++; + // } + // } + // } + // // Calculate outputs + // for (int i = 0; i < gnuToolInfos.length; i++) { + // if (gnuToolInfos[i].areOutputsCalculated()) { + // testState[i]++; + // } else { + // if (gnuToolInfos[i].calculateOutputs(ArduinoGnuMakefileGenerator.this, config, + // handledOutsInputExtensions, lastChance)) { + // testState[i]++; + // } + // } + // } + // // Are all calculated? If so, done. + // done = true; + // for (int element : testState) { + // if (element != 3) { + // done = false; + // break; + // } + // } + // // Test our "done" state vs. the previous "done" state. + // // If we have made no progress, give it a "last chance" and + // // then quit + // if (!done) { + // done = true; + // for (int i = 0; i < testState.length; i++) { + // if (testState[i] != doneState[i]) { + // done = false; + // break; + // } + // } + // } + // if (done) { + // if (!lastChance) { + // lastChance = true; + // done = false; + // } + // } + // if (!done) { + // doneState = testState; + // } + // } + // return true; + // } + // }); + // } /** * Returns the list of known build rules. This keeps me from generating @@ -1460,8 +1298,6 @@ private Collection getModifiedList() { * to the build */ public Collection getSubdirList() { - if (subdirList == null) - subdirList = new LinkedHashSet(); return subdirList; } @@ -1510,9 +1346,6 @@ public IFile getTopBuildDir() { public void initialize(int buildKind, IConfiguration cfg, IBuilder builder, IProgressMonitor monitor) { // Save the project so we can get path and member information this.project = cfg.getOwner().getProject(); - mySubDirMakeGenerator = new SubDirMakeGenerator(this); - myTopMakeFileGenerator = new TopMakeFileGenerator(this); - mySrcMakeGenerator = new SrcMakeGenerator(this); if (builder == null) { builder = cfg.getEditableBuilder(); } @@ -1588,10 +1421,6 @@ private void initToolInfos() { } } - public List getDepLineList() { - return mySubDirMakeGenerator.getDepLineList(); - } - public PathSettingsContainer getToolInfos() { return toolInfos; } diff --git a/io.sloeber.core/src/io/sloeber/managedBuild/Internal/ArduinoManagedBuildGnuToolInfo.java b/io.sloeber.core/src/io/sloeber/managedBuild/Internal/ArduinoManagedBuildGnuToolInfo.java index af0f76c9f..6b4bf25c9 100644 --- a/io.sloeber.core/src/io/sloeber/managedBuild/Internal/ArduinoManagedBuildGnuToolInfo.java +++ b/io.sloeber.core/src/io/sloeber/managedBuild/Internal/ArduinoManagedBuildGnuToolInfo.java @@ -1,17 +1,11 @@ package io.sloeber.managedBuild.Internal; import static io.sloeber.managedBuild.Internal.ManagebBuildCommon.*; -import static io.sloeber.managedBuild.Internal.ManagedBuildConstants.*; import java.util.ArrayList; -import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; -import java.util.LinkedList; import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Set; import java.util.Vector; import org.eclipse.cdt.managedbuilder.core.BuildException; @@ -19,10 +13,8 @@ import org.eclipse.cdt.managedbuilder.core.IConfiguration; import org.eclipse.cdt.managedbuilder.core.IInputType; import org.eclipse.cdt.managedbuilder.core.IOption; -import org.eclipse.cdt.managedbuilder.core.IOutputType; import org.eclipse.cdt.managedbuilder.core.ITool; import org.eclipse.cdt.managedbuilder.core.ManagedBuildManager; -import org.eclipse.cdt.managedbuilder.internal.core.ManagedMakeMessages; import org.eclipse.cdt.managedbuilder.internal.core.Tool; import org.eclipse.cdt.managedbuilder.internal.macros.OptionContextData; import org.eclipse.cdt.managedbuilder.macros.BuildMacroException; @@ -39,8 +31,6 @@ import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.Path; -import io.sloeber.managedBuild.api.IManagedOutputNameProviderJaba; - /** * This class represents information about a Tool's inputs and outputs while a * Gnu makefile is being generated. @@ -305,20 +295,20 @@ public boolean calculateInputs(ArduinoGnuMakefileGenerator makeGen, IConfigurati // If there is an output variable with the same name, // get // the files associated with it. - List outMacroList = makeGen.getBuildVariableList(h, variable, PROJECT_RELATIVE, null, - true); - if (outMacroList != null) { - itEnumeratedInputs.addAll(outMacroList); - } else { - // If "last chance", then calculate using file - // extensions below - if (lastChance) { - useFileExts = true; - } else { - done = false; - break; - } - } + // List outMacroList = makeGen.getBuildVariableList(h, variable, PROJECT_RELATIVE, null, + // true); + // if (outMacroList != null) { + // itEnumeratedInputs.addAll(outMacroList); + // } else { + // // If "last chance", then calculate using file + // // extensions below + // if (lastChance) { + // useFileExts = true; + // } else { + // done = false; + // break; + // } + // } } // Use file extensions @@ -508,299 +498,297 @@ public boolean calculateInputs(ArduinoGnuMakefileGenerator makeGen, IConfigurati * NOTE: If an option is not specified and this is not the primary output * type, the outputs from the type are not added to the command line */ - public boolean calculateOutputs(ArduinoGnuMakefileGenerator makeGen, IConfiguration config, - HashSet handledInputExtensions, boolean lastChance) { - - boolean done = true; - List myCommandOutputs = new LinkedList<>(); - List myEnumeratedOutputs = new LinkedList<>(); - HashMap> myOutputMacros = new HashMap<>(); - // The next two fields are used together - List myBuildVars = new LinkedList<>(); - List> myBuildVarsValues = new LinkedList<>(); - - // Get the outputs for this tool invocation - IOutputType[] outTypes = this.tool.getOutputTypes(); - if (outTypes != null && outTypes.length > 0) { - for (int i = 0; i < outTypes.length; i++) { - List typeEnumeratedOutputs = new LinkedList<>(); - IOutputType type = outTypes[i]; - String outputPrefix = type.getOutputPrefix(); - - // Resolve any macros in the outputPrefix - // Note that we cannot use file macros because if we do a clean - // we need to know the actual name of the file to clean, and - // cannot use any builder variables such as $@. Hence we use the - // next best thing, i.e. configuration context. - - if (config != null) { - - try { - outputPrefix = ManagedBuildManager.getBuildMacroProvider().resolveValueToMakefileFormat( - outputPrefix, "", //$NON-NLS-1$ - " ", //$NON-NLS-1$ - IBuildMacroProvider.CONTEXT_CONFIGURATION, config); - } - - catch (BuildMacroException e) {// JABA is not going to add - // code - } - } - - String variable = type.getBuildVariable(); - boolean multOfType = type.getMultipleOfType(); - IOption option = this.tool.getOptionBySuperClassId(type.getOptionId()); - IManagedOutputNameProviderJaba nameProvider = getJABANameProvider(type); - String[] outputNames = type.getOutputNames(); - - // 1. If the tool is the build target and this is the primary - // output, - // use artifact name & extension - if (this.bIsTargetTool) { - String outputName = outputPrefix + this.targetName; - if (this.targetExt.length() > 0) { - outputName += (DOT + this.targetExt); - } - myCommandOutputs.add(outputName); - typeEnumeratedOutputs.add(outputName); - // But this doesn't use any output macro... - } else - // 2. If an option is specified, use the value of the option - if (option != null) { - try { - List outputs = new ArrayList<>(); - int optType = option.getValueType(); - if (optType == IOption.STRING) { - outputs.add(outputPrefix + option.getStringValue()); - } else if (optType == IOption.STRING_LIST || optType == IOption.LIBRARIES - || optType == IOption.OBJECTS || optType == IOption.INCLUDE_FILES - || optType == IOption.LIBRARY_PATHS || optType == IOption.LIBRARY_FILES - || optType == IOption.MACRO_FILES) { - @SuppressWarnings("unchecked") - List value = (List) option.getValue(); - outputs = value; - this.tool.filterValues(optType, outputs); - // Add outputPrefix to each if necessary - if (outputPrefix.length() > 0) { - for (int j = 0; j < outputs.size(); j++) { - outputs.set(j, outputPrefix + outputs.get(j)); - } - } - } - for (int j = 0; j < outputs.size(); j++) { - String outputName = outputs.get(j); - try { - // try to resolve the build macros in the output - // names - String resolved = ManagedBuildManager.getBuildMacroProvider() - .resolveValueToMakefileFormat(outputName, "", //$NON-NLS-1$ - " ", //$NON-NLS-1$ - IBuildMacroProvider.CONTEXT_OPTION, - new OptionContextData(option, this.tool)); - if ((resolved = resolved.trim()).length() > 0) - outputs.set(j, resolved); - } catch (BuildMacroException e) {// JABA is not - // going to add - // code - } - } - - // NO - myCommandOutputs.addAll(outputs); - typeEnumeratedOutputs.addAll(outputs); - if (variable.length() > 0) { - List outputPaths = new ArrayList<>(); - for (int j = 0; j < outputs.size(); j++) { - outputPaths.add(Path.fromOSString(outputs.get(j))); - } - if (myOutputMacros.containsKey(variable)) { - List currList = myOutputMacros.get(variable); - currList.addAll(outputPaths); - myOutputMacros.put(variable, currList); - } else { - myOutputMacros.put(variable, outputPaths); - } - } - } catch (BuildException ex) {// JABA is not going to add - // code - } - } else - // 3. If a nameProvider is specified, call it - if (nameProvider != null) { - // The inputs must have been calculated before we can do - // this - List outNames = new LinkedList<>(); - if (!this.inputsCalculated) { - done = false; - } else { - for (String curInput : getEnumeratedInputs()) { - outNames.add(nameProvider.getOutputName(project, config, tool, new Path(curInput))); - } - typeEnumeratedOutputs.addAll(resolvePaths(outNames, config)); - } - if (variable.length() > 0 && outNames != null) { - if (myOutputMacros.containsKey(variable)) { - List currList = myOutputMacros.get(variable); - currList.addAll(outNames); - myOutputMacros.put(variable, currList); - } else { - myOutputMacros.put(variable, outNames); - } - } - } else - // 4. If outputNames is specified, use it - if (outputNames != null) { - if (outputNames.length > 0) { - for (int j = 0; j < outputNames.length; j++) { - String outputName = outputNames[j]; - try { - // try to resolve the build macros in the output - // names - String resolved = ManagedBuildManager.getBuildMacroProvider() - .resolveValueToMakefileFormat(outputName, "", //$NON-NLS-1$ - " ", //$NON-NLS-1$ - IBuildMacroProvider.CONTEXT_OPTION, - new OptionContextData(option, this.tool)); - if ((resolved = resolved.trim()).length() > 0) - outputNames[j] = resolved; - } catch (BuildMacroException e) {// JABA is not - // going to add - // code - } - } - List namesList = Arrays.asList(outputNames); - typeEnumeratedOutputs.addAll(namesList); - if (variable.length() > 0) { - List outputPaths = new ArrayList<>(); - for (int j = 0; j < namesList.size(); j++) { - outputPaths.add(Path.fromOSString(namesList.get(j))); - } - if (myOutputMacros.containsKey(variable)) { - List currList = myOutputMacros.get(variable); - currList.addAll(outputPaths); - myOutputMacros.put(variable, currList); - } else { - myOutputMacros.put(variable, outputPaths); - } - } - } - } else { - // 5. Use the name pattern to generate a transformation - // macro - // so that the source names can be transformed into the - // target names - // using the built-in string substitution functions of - // make. - if (multOfType) { - // This case is not handled - a nameProvider or - // outputNames must be specified - List errList = new ArrayList<>(); - errList.add(ManagedMakeMessages.getResourceString("MakefileGenerator.error.no.nameprovider")); //$NON-NLS-1$ - myCommandOutputs.addAll(errList); - } else { - String namePattern = type.getNamePattern(); - if (namePattern == null || namePattern.length() == 0) { - namePattern = outputPrefix + IManagedBuilderMakefileGenerator.WILDCARD; - String outExt = (type.getOutputExtensions(this.tool))[0]; - if (outExt != null && outExt.length() > 0) { - namePattern += DOT + outExt; - } - } else if (outputPrefix.length() > 0) { - namePattern = outputPrefix + namePattern; - } - - // Calculate the output name - // The inputs must have been calculated before we can do - // this - if (!this.inputsCalculated) { - done = false; - } else { - Vector inputs = getEnumeratedInputs(); - String fileName; - if (inputs.size() > 0) { - // Get the input file name - fileName = (Path.fromOSString(inputs.get(0))).removeFileExtension().lastSegment(); - // Check if this is a build macro. If so, use - // the raw macro name. - if (fileName.startsWith("$(") && fileName.endsWith(")")) { //$NON-NLS-1$ //$NON-NLS-2$ - fileName = fileName.substring(2, fileName.length() - 1); - } - } else { - fileName = "default"; //$NON-NLS-1$ - } - // Replace the % with the file name - typeEnumeratedOutputs.add(namePattern.replace("%", fileName)); //$NON-NLS-1$ - if (variable.length() > 0) { - List outputs = new ArrayList<>(); - outputs.add(Path.fromOSString(fileName)); - if (myOutputMacros.containsKey(variable)) { - List currList = myOutputMacros.get(variable); - currList.addAll(outputs); - myOutputMacros.put(variable, currList); - } else { - myOutputMacros.put(variable, outputs); - } - } - } - } - } - if (variable.length() > 0) { - myBuildVars.add(variable); - myBuildVarsValues.add(typeEnumeratedOutputs); - } - myEnumeratedOutputs.addAll(typeEnumeratedOutputs); - } - } else - - { - if (this.bIsTargetTool) { - String outputPrefix = this.tool.getOutputPrefix(); - String outputName = outputPrefix + this.targetName; - if (this.targetExt.length() > 0) { - outputName += (DOT + this.targetExt); - } - myCommandOutputs.add(outputName); - myEnumeratedOutputs.add(outputName); - } else { - // For support of pre-CDT 3.0 integrations. - // NOTE WELL: This only supports the case of a single - // "target tool" - // that consumes exactly all of the object files, $OBJS, - // produced - // by other tools in the build and produces a single output - } - } - - // Add the output macros of this tool to the buildOutVars map - Set>> entrySet = myOutputMacros.entrySet(); - for (Entry> entry : entrySet) { - String macroName = entry.getKey(); - List newMacroValue = entry.getValue(); - Map> map = makeGen.getBuildOutputVars(); - if (map.containsKey(macroName)) { - List macroValue = map.get(macroName); - macroValue.addAll(newMacroValue); - map.put(macroName, macroValue); - } else { - map.put(macroName, newMacroValue); - } - } - this.outputVariablesCalculated = true; - - if (done) { - this.commandOutputs.addAll(myCommandOutputs); - this.enumeratedPrimaryOutputs.addAll(myEnumeratedOutputs); - this.enumeratedSecondaryOutputs.addAll(myEnumeratedOutputs); - this.outputVariables.addAll(myOutputMacros.keySet()); - this.outputsCalculated = true; - for (int i = 0; i < myBuildVars.size(); i++) { - makeGen.addMacroAdditionFiles(makeGen.getTopBuildOutputVars(), myBuildVars.get(i), - myBuildVarsValues.get(i)); - } - return true; - } - - return false; - } + // public boolean calculateOutputs(ArduinoGnuMakefileGenerator makeGen, IConfiguration config, + // HashSet handledInputExtensions, boolean lastChance) { + // + // boolean done = true; + // List myCommandOutputs = new LinkedList<>(); + // List myEnumeratedOutputs = new LinkedList<>(); + // HashMap> myOutputMacros = new HashMap<>(); + // // The next two fields are used together + // Map> myBuildVars = new HashMap<>(); + // //List> myBuildVarsValues = new LinkedList<>(); + // + // // Get the outputs for this tool invocation + // IOutputType[] outTypes = this.tool.getOutputTypes(); + // if (outTypes != null && outTypes.length > 0) { + // for (int i = 0; i < outTypes.length; i++) { + // List typeEnumeratedOutputs = new LinkedList<>(); + // IOutputType type = outTypes[i]; + // String outputPrefix = type.getOutputPrefix(); + // + // // Resolve any macros in the outputPrefix + // // Note that we cannot use file macros because if we do a clean + // // we need to know the actual name of the file to clean, and + // // cannot use any builder variables such as $@. Hence we use the + // // next best thing, i.e. configuration context. + // + // if (config != null) { + // + // try { + // outputPrefix = ManagedBuildManager.getBuildMacroProvider().resolveValueToMakefileFormat( + // outputPrefix, "", //$NON-NLS-1$ + // " ", //$NON-NLS-1$ + // IBuildMacroProvider.CONTEXT_CONFIGURATION, config); + // } + // + // catch (BuildMacroException e) {// JABA is not going to add + // // code + // } + // } + // + // String variable = type.getBuildVariable(); + // boolean multOfType = type.getMultipleOfType(); + // IOption option = this.tool.getOptionBySuperClassId(type.getOptionId()); + // IManagedOutputNameProviderJaba nameProvider = getJABANameProvider(type); + // String[] outputNames = type.getOutputNames(); + // + // // 1. If the tool is the build target and this is the primary + // // output, + // // use artifact name & extension + // if (this.bIsTargetTool) { + // String outputName = outputPrefix + this.targetName; + // if (this.targetExt.length() > 0) { + // outputName += (DOT + this.targetExt); + // } + // myCommandOutputs.add(outputName); + // typeEnumeratedOutputs.add(outputName); + // // But this doesn't use any output macro... + // } else + // // 2. If an option is specified, use the value of the option + // if (option != null) { + // try { + // List outputs = new ArrayList<>(); + // int optType = option.getValueType(); + // if (optType == IOption.STRING) { + // outputs.add(outputPrefix + option.getStringValue()); + // } else if (optType == IOption.STRING_LIST || optType == IOption.LIBRARIES + // || optType == IOption.OBJECTS || optType == IOption.INCLUDE_FILES + // || optType == IOption.LIBRARY_PATHS || optType == IOption.LIBRARY_FILES + // || optType == IOption.MACRO_FILES) { + // @SuppressWarnings("unchecked") + // List value = (List) option.getValue(); + // outputs = value; + // this.tool.filterValues(optType, outputs); + // // Add outputPrefix to each if necessary + // if (outputPrefix.length() > 0) { + // for (int j = 0; j < outputs.size(); j++) { + // outputs.set(j, outputPrefix + outputs.get(j)); + // } + // } + // } + // for (int j = 0; j < outputs.size(); j++) { + // String outputName = outputs.get(j); + // try { + // // try to resolve the build macros in the output + // // names + // String resolved = ManagedBuildManager.getBuildMacroProvider() + // .resolveValueToMakefileFormat(outputName, "", //$NON-NLS-1$ + // " ", //$NON-NLS-1$ + // IBuildMacroProvider.CONTEXT_OPTION, + // new OptionContextData(option, this.tool)); + // if ((resolved = resolved.trim()).length() > 0) + // outputs.set(j, resolved); + // } catch (BuildMacroException e) {// JABA is not + // // going to add + // // code + // } + // } + // + // // NO - myCommandOutputs.addAll(outputs); + // typeEnumeratedOutputs.addAll(outputs); + // if (variable.length() > 0) { + // List outputPaths = new ArrayList<>(); + // for (int j = 0; j < outputs.size(); j++) { + // outputPaths.add(Path.fromOSString(outputs.get(j))); + // } + // if (myOutputMacros.containsKey(variable)) { + // List currList = myOutputMacros.get(variable); + // currList.addAll(outputPaths); + // myOutputMacros.put(variable, currList); + // } else { + // myOutputMacros.put(variable, outputPaths); + // } + // } + // } catch (BuildException ex) {// JABA is not going to add + // // code + // } + // } else + // // 3. If a nameProvider is specified, call it + // if (nameProvider != null) { + // // The inputs must have been calculated before we can do + // // this + // List outNames = new LinkedList<>(); + // if (!this.inputsCalculated) { + // done = false; + // } else { + // for (String curInput : getEnumeratedInputs()) { + // outNames.add(nameProvider.getOutputName(project, config, tool, new Path(curInput))); + // } + // typeEnumeratedOutputs.addAll(resolvePaths(outNames, config)); + // } + // if (variable.length() > 0 && outNames != null) { + // if (myOutputMacros.containsKey(variable)) { + // List currList = myOutputMacros.get(variable); + // currList.addAll(outNames); + // myOutputMacros.put(variable, currList); + // } else { + // myOutputMacros.put(variable, outNames); + // } + // } + // } else + // // 4. If outputNames is specified, use it + // if (outputNames != null) { + // if (outputNames.length > 0) { + // for (int j = 0; j < outputNames.length; j++) { + // String outputName = outputNames[j]; + // try { + // // try to resolve the build macros in the output + // // names + // String resolved = ManagedBuildManager.getBuildMacroProvider() + // .resolveValueToMakefileFormat(outputName, "", //$NON-NLS-1$ + // " ", //$NON-NLS-1$ + // IBuildMacroProvider.CONTEXT_OPTION, + // new OptionContextData(option, this.tool)); + // if ((resolved = resolved.trim()).length() > 0) + // outputNames[j] = resolved; + // } catch (BuildMacroException e) {// JABA is not + // // going to add + // // code + // } + // } + // List namesList = Arrays.asList(outputNames); + // typeEnumeratedOutputs.addAll(namesList); + // if (variable.length() > 0) { + // List outputPaths = new ArrayList<>(); + // for (int j = 0; j < namesList.size(); j++) { + // outputPaths.add(Path.fromOSString(namesList.get(j))); + // } + // if (myOutputMacros.containsKey(variable)) { + // List currList = myOutputMacros.get(variable); + // currList.addAll(outputPaths); + // myOutputMacros.put(variable, currList); + // } else { + // myOutputMacros.put(variable, outputPaths); + // } + // } + // } + // } else { + // // 5. Use the name pattern to generate a transformation + // // macro + // // so that the source names can be transformed into the + // // target names + // // using the built-in string substitution functions of + // // make. + // if (multOfType) { + // // This case is not handled - a nameProvider or + // // outputNames must be specified + // List errList = new ArrayList<>(); + // errList.add(ManagedMakeMessages.getResourceString("MakefileGenerator.error.no.nameprovider")); //$NON-NLS-1$ + // myCommandOutputs.addAll(errList); + // } else { + // String namePattern = type.getNamePattern(); + // if (namePattern == null || namePattern.length() == 0) { + // namePattern = outputPrefix + IManagedBuilderMakefileGenerator.WILDCARD; + // String outExt = (type.getOutputExtensions(this.tool))[0]; + // if (outExt != null && outExt.length() > 0) { + // namePattern += DOT + outExt; + // } + // } else if (outputPrefix.length() > 0) { + // namePattern = outputPrefix + namePattern; + // } + // + // // Calculate the output name + // // The inputs must have been calculated before we can do + // // this + // if (!this.inputsCalculated) { + // done = false; + // } else { + // Vector inputs = getEnumeratedInputs(); + // String fileName; + // if (inputs.size() > 0) { + // // Get the input file name + // fileName = (Path.fromOSString(inputs.get(0))).removeFileExtension().lastSegment(); + // // Check if this is a build macro. If so, use + // // the raw macro name. + // if (fileName.startsWith("$(") && fileName.endsWith(")")) { //$NON-NLS-1$ //$NON-NLS-2$ + // fileName = fileName.substring(2, fileName.length() - 1); + // } + // } else { + // fileName = "default"; //$NON-NLS-1$ + // } + // // Replace the % with the file name + // typeEnumeratedOutputs.add(namePattern.replace("%", fileName)); //$NON-NLS-1$ + // if (variable.length() > 0) { + // List outputs = new ArrayList<>(); + // outputs.add(Path.fromOSString(fileName)); + // if (myOutputMacros.containsKey(variable)) { + // List currList = myOutputMacros.get(variable); + // currList.addAll(outputs); + // myOutputMacros.put(variable, currList); + // } else { + // myOutputMacros.put(variable, outputs); + // } + // } + // } + // } + // } + // if (variable.length() > 0) { + // myBuildVars.put(variable, typeEnumeratedOutputs); + // } + // myEnumeratedOutputs.addAll(typeEnumeratedOutputs); + // } + // } else + // + // { + // if (this.bIsTargetTool) { + // String outputPrefix = this.tool.getOutputPrefix(); + // String outputName = outputPrefix + this.targetName; + // if (this.targetExt.length() > 0) { + // outputName += (DOT + this.targetExt); + // } + // myCommandOutputs.add(outputName); + // myEnumeratedOutputs.add(outputName); + // } else { + // // For support of pre-CDT 3.0 integrations. + // // NOTE WELL: This only supports the case of a single + // // "target tool" + // // that consumes exactly all of the object files, $OBJS, + // // produced + // // by other tools in the build and produces a single output + // } + // } + // + // // Add the output macros of this tool to the buildOutVars map + // Set>> entrySet = myOutputMacros.entrySet(); + // for (Entry> entry : entrySet) { + // String macroName = entry.getKey(); + // List newMacroValue = entry.getValue(); + // Map> map = makeGen.getBuildOutputVars(); + // if (map.containsKey(macroName)) { + // List macroValue = map.get(macroName); + // macroValue.addAll(newMacroValue); + // map.put(macroName, macroValue); + // } else { + // map.put(macroName, newMacroValue); + // } + // } + // this.outputVariablesCalculated = true; + // + // if (done) { + // this.commandOutputs.addAll(myCommandOutputs); + // this.enumeratedPrimaryOutputs.addAll(myEnumeratedOutputs); + // this.enumeratedSecondaryOutputs.addAll(myEnumeratedOutputs); + // this.outputVariables.addAll(myOutputMacros.keySet()); + // this.outputsCalculated = true; + // for (Entry> curVar : myBuildVars.entrySet()) { + // makeGen.addMacroAdditionFiles(makeGen.getTopBuildOutputVars(), curVar.getKey(), curVar.getValue()); + // } + // return true; + // } + // + // return false; + // } private boolean callDependencyCalculator(ArduinoGnuMakefileGenerator makeGen, IConfiguration config, HashSet handledInputExtensions, IManagedDependencyGeneratorType depGen, String[] extensionsList, @@ -904,120 +892,122 @@ private boolean callDependencyCalculator(ArduinoGnuMakefileGenerator makeGen, IC return done; } - /** - * @param lastChance - */ - public boolean calculateDependencies(ArduinoGnuMakefileGenerator makeGen, IConfiguration config, - HashSet handledInputExtensions, ToolInfoHolder h, boolean lastChance) { - // Get the dependencies for this tool invocation - boolean done = true; - Vector myCommandDependencies = new Vector<>(); - Vector myAdditionalTargets = new Vector<>(); - // Vector myEnumeratedDependencies = new Vector(); - HashMap> myOutputMacros = new HashMap<>(); - - IInputType[] inTypes = this.tool.getInputTypes(); - if (inTypes != null && inTypes.length > 0) { - for (int i = 0; i < inTypes.length; i++) { - IInputType type = inTypes[i]; - - // Handle dependencies from the dependencyCalculator - IManagedDependencyGeneratorType depGen = type.getDependencyGenerator(); - String[] extensionsList = type.getSourceExtensions(this.tool); - if (depGen != null) { - done = callDependencyCalculator(makeGen, config, handledInputExtensions, depGen, extensionsList, - myCommandDependencies, myOutputMacros, myAdditionalTargets, h, done); - } - - // Add additional dependencies specified in AdditionalInput - // elements - IAdditionalInput[] addlInputs = type.getAdditionalInputs(); - if (addlInputs != null && addlInputs.length > 0) { - for (int j = 0; j < addlInputs.length; j++) { - IAdditionalInput addlInput = addlInputs[j]; - int kind = addlInput.getKind(); - if (kind == IAdditionalInput.KIND_ADDITIONAL_DEPENDENCY - || kind == IAdditionalInput.KIND_ADDITIONAL_INPUT_DEPENDENCY) { - String[] paths = addlInput.getPaths(); - if (paths != null) { - for (int k = 0; k < paths.length; k++) { - // Translate the path from project relative - // to - // build directory relative - String path = paths[k]; - if (!(path.startsWith("$("))) { //$NON-NLS-1$ - IResource addlResource = this.project.getFile(path); - if (addlResource != null) { - IPath addlPath = addlResource.getLocation(); - if (addlPath != null) { - path = ManagedBuildManager.calculateRelativePath( - makeGen.getTopBuildDir().getFullPath(), addlPath).toOSString(); - } - } - } - myCommandDependencies.add(path); - // myEnumeratedInputs.add(path); - } - } - } - } - } - } - } else { - if (this.bIsTargetTool) { - // For support of pre-CDT 3.0 integrations. - // NOTE WELL: This only supports the case of a single - // "target tool" - // with the following characteristics: - // 1. The tool consumes exactly all of the object files produced - // by other tools in the build and produces a single output - // 2. The target name comes from the configuration artifact name - // The rule looks like: - // .: $(OBJS) - myCommandDependencies.add("$(OBJS)"); //$NON-NLS-1$ - myCommandDependencies.add("$(USER_OBJS)"); //$NON-NLS-1$ - } else { - // Handle dependencies from the dependencyCalculator - IManagedDependencyGeneratorType depGen = this.tool.getDependencyGenerator(); - String[] extensionsList = this.tool.getAllInputExtensions(); - if (depGen != null) { - done = callDependencyCalculator(makeGen, config, handledInputExtensions, depGen, extensionsList, - myCommandDependencies, myOutputMacros, myAdditionalTargets, h, done); - } - - } - } - - // Add the output macros of this tool to the buildOutVars map - Set>> entrySet = myOutputMacros.entrySet(); - for (Entry> entry : entrySet) { - String macroName = entry.getKey(); - List newMacroValue = entry.getValue(); - Map> map = makeGen.getBuildOutputVars(); - if (map.containsKey(macroName)) { - List macroValue = map.get(macroName); - macroValue.addAll(newMacroValue); - map.put(macroName, macroValue); - } else { - map.put(macroName, newMacroValue); - } - } - - if (done) { - this.commandDependencies.addAll(myCommandDependencies); - this.additionalTargets.addAll(myAdditionalTargets); - // enumeratedDependencies.addAll(myEnumeratedDependencies); - this.dependenciesCalculated = true; - return true; - } - - return false; - } + // /** + // * @param lastChance + // */ + // public boolean calculateDependencies(ArduinoGnuMakefileGenerator makeGen, IConfiguration config, + // HashSet handledInputExtensions, ToolInfoHolder h, boolean lastChance) { + // // Get the dependencies for this tool invocation + // boolean done = true; + // Vector myCommandDependencies = new Vector<>(); + // Vector myAdditionalTargets = new Vector<>(); + // // Vector myEnumeratedDependencies = new Vector(); + // HashMap> myOutputMacros = new HashMap<>(); + // + // IInputType[] inTypes = this.tool.getInputTypes(); + // if (inTypes != null && inTypes.length > 0) { + // for (int i = 0; i < inTypes.length; i++) { + // IInputType type = inTypes[i]; + // + // // Handle dependencies from the dependencyCalculator + // IManagedDependencyGeneratorType depGen = type.getDependencyGenerator(); + // String[] extensionsList = type.getSourceExtensions(this.tool); + // if (depGen != null) { + // done = callDependencyCalculator(makeGen, config, handledInputExtensions, depGen, extensionsList, + // myCommandDependencies, myOutputMacros, myAdditionalTargets, h, done); + // } + // + // // Add additional dependencies specified in AdditionalInput + // // elements + // IAdditionalInput[] addlInputs = type.getAdditionalInputs(); + // if (addlInputs != null && addlInputs.length > 0) { + // for (int j = 0; j < addlInputs.length; j++) { + // IAdditionalInput addlInput = addlInputs[j]; + // int kind = addlInput.getKind(); + // if (kind == IAdditionalInput.KIND_ADDITIONAL_DEPENDENCY + // || kind == IAdditionalInput.KIND_ADDITIONAL_INPUT_DEPENDENCY) { + // String[] paths = addlInput.getPaths(); + // if (paths != null) { + // for (int k = 0; k < paths.length; k++) { + // // Translate the path from project relative + // // to + // // build directory relative + // String path = paths[k]; + // if (!(path.startsWith("$("))) { //$NON-NLS-1$ + // IResource addlResource = this.project.getFile(path); + // if (addlResource != null) { + // IPath addlPath = addlResource.getLocation(); + // if (addlPath != null) { + // path = ManagedBuildManager.calculateRelativePath( + // makeGen.getTopBuildDir().getFullPath(), addlPath).toOSString(); + // } + // } + // } + // myCommandDependencies.add(path); + // // myEnumeratedInputs.add(path); + // } + // } + // } + // } + // } + // } + // } else { + // if (this.bIsTargetTool) { + // // For support of pre-CDT 3.0 integrations. + // // NOTE WELL: This only supports the case of a single + // // "target tool" + // // with the following characteristics: + // // 1. The tool consumes exactly all of the object files produced + // // by other tools in the build and produces a single output + // // 2. The target name comes from the configuration artifact name + // // The rule looks like: + // // .: $(OBJS) + // myCommandDependencies.add("$(OBJS)"); //$NON-NLS-1$ + // myCommandDependencies.add("$(USER_OBJS)"); //$NON-NLS-1$ + // } else { + // // Handle dependencies from the dependencyCalculator + // IManagedDependencyGeneratorType depGen = this.tool.getDependencyGenerator(); + // String[] extensionsList = this.tool.getAllInputExtensions(); + // if (depGen != null) { + // done = callDependencyCalculator(makeGen, config, handledInputExtensions, depGen, extensionsList, + // myCommandDependencies, myOutputMacros, myAdditionalTargets, h, done); + // } + // + // } + // } + // + // // Add the output macros of this tool to the buildOutVars map + // Set>> entrySet = myOutputMacros.entrySet(); + // for (Entry> entry : entrySet) { + // String macroName = entry.getKey(); + // List newMacroValue = entry.getValue(); + // Map> map = makeGen.getBuildOutputVars(); + // if (map.containsKey(macroName)) { + // List macroValue = map.get(macroName); + // macroValue.addAll(newMacroValue); + // map.put(macroName, macroValue); + // } else { + // map.put(macroName, newMacroValue); + // } + // } + // + // if (done) { + // this.commandDependencies.addAll(myCommandDependencies); + // this.additionalTargets.addAll(myAdditionalTargets); + // // enumeratedDependencies.addAll(myEnumeratedDependencies); + // this.dependenciesCalculated = true; + // return true; + // } + // + // return false; + // } /* - * Calculate the source macro for the given extension - */ + Calculate the + source macro for + the given extension*/ + protected String calculateSourceMacro(ArduinoGnuMakefileGenerator makeGen, String srcExtensionName, String outExtensionName, String wildcard) { StringBuffer macroName = getSourceMacroName(srcExtensionName); diff --git a/io.sloeber.core/src/io/sloeber/managedBuild/Internal/MakeRule.java b/io.sloeber.core/src/io/sloeber/managedBuild/Internal/MakeRule.java index 89d279ce2..8f276114a 100644 --- a/io.sloeber.core/src/io/sloeber/managedBuild/Internal/MakeRule.java +++ b/io.sloeber.core/src/io/sloeber/managedBuild/Internal/MakeRule.java @@ -4,8 +4,9 @@ import static io.sloeber.managedBuild.Internal.ManagedBuildConstants.*; import java.util.Arrays; -import java.util.HashMap; import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; import java.util.LinkedList; import java.util.List; import java.util.Map; @@ -36,9 +37,9 @@ public class MakeRule { - private Map> myTargets = new HashMap<>(); //Macro file target map - private Map> myPrerequisites = new HashMap<>();//Macro file prerequisites map - private Map> myDependencies = new HashMap<>(); //Macro file target map + private Map> myTargets = new LinkedHashMap<>(); //Macro file target map + private Map> myPrerequisites = new LinkedHashMap<>();//Macro file prerequisites map + private Map> myDependencies = new LinkedHashMap<>(); //Macro file target map private ITool myTool = null; //TOFIX get rid of caller argument @@ -80,7 +81,7 @@ private void calculateDependencies(ArduinoGnuMakefileGenerator caller) { IManagedDependencyCalculator depCalculator = (IManagedDependencyCalculator) depInfo; IPath[] addlDeps = calculateDependenciesForSource(caller, depCalculator); IPath[] addlTargets = depCalculator.getAdditionalTargets(); - // } + //TOFIX when is this call path used? } if (depInfo instanceof IManagedDependencyCommands) { IManagedDependencyCommands tmp = (IManagedDependencyCommands) depInfo; @@ -126,22 +127,51 @@ public HashSet getPrerequisites() { return ret; } - public HashSet getTargets() { - HashSet ret = new HashSet<>(); + public Set getTargetFiles() { + Set ret = new HashSet<>(); for (List cur : myTargets.values()) { ret.addAll(cur); } return ret; } - public HashSet getMacros() { - HashSet ret = new HashSet<>(); + public Set getDependencyFiles() { + Set ret = new HashSet<>(); + for (List cur : myDependencies.values()) { + ret.addAll(cur); + } + return ret; + } + + public Map> getTargets() { + return myTargets; + } + + public Set getAllMacros() { + Set ret = getTargetMacros(); + ret.addAll(getPrerequisiteMacros()); + ret.addAll(getDependecyMacros()); + return ret; + } + + public Set getTargetMacros() { + HashSet ret = new LinkedHashSet<>(); for (IOutputType cur : myTargets.keySet()) { ret.add(cur.getBuildVariable()); } + return ret; + } + + public Set getPrerequisiteMacros() { + HashSet ret = new LinkedHashSet<>(); for (IInputType cur : myPrerequisites.keySet()) { ret.add(cur.getBuildVariable()); } + return ret; + } + + public Set getDependecyMacros() { + HashSet ret = new LinkedHashSet<>(); for (String cur : myDependencies.keySet()) { ret.add(cur); } @@ -215,8 +245,8 @@ public StringBuffer getRule(IProject project, IFile niceBuildFolder, IConfigurat String cmd = myTool.getToolCommand(); //For now assume 1 target with 1 or more prerequisites // if there is more than 1 prerequisite we take the flags of the first prerequisite only - HashSet local_targets = getTargets(); - HashSet local_prerequisites = getPrerequisites(); + Set local_targets = getTargetFiles(); + Set local_prerequisites = getPrerequisites(); if (local_targets.size() != 1) { System.err.println("Only 1 target per build rule is supported in this managed build"); //$NON-NLS-1$ return new StringBuffer(); @@ -314,7 +344,7 @@ public StringBuffer getRule(IProject project, IFile niceBuildFolder, IConfigurat } private Set getBuildFlags(IFile buildFolder, IConfiguration config, IFile sourceFile, IFile outputFile) { - Set flags = new HashSet<>(); + Set flags = new LinkedHashSet<>(); // Get the tool command line options try { diff --git a/io.sloeber.core/src/io/sloeber/managedBuild/Internal/ManagebBuildCommon.java b/io.sloeber.core/src/io/sloeber/managedBuild/Internal/ManagebBuildCommon.java index 8b095b1d1..436becde9 100644 --- a/io.sloeber.core/src/io/sloeber/managedBuild/Internal/ManagebBuildCommon.java +++ b/io.sloeber.core/src/io/sloeber/managedBuild/Internal/ManagebBuildCommon.java @@ -109,26 +109,29 @@ static public StringBuffer getSourceMacroName(String extensionName) { } public static void save(StringBuffer buffer, IFile file) throws CoreException { - String encoding = null; - try { - encoding = file.getCharset(); - } catch (CoreException ce) { - // use no encoding - } - byte[] bytes = null; - if (encoding != null) { - try { - bytes = buffer.toString().getBytes(encoding); - } catch (Exception e) { - /* JABA is not going to write this code */ - } + + byte[] bytes = buffer.toString().getBytes(); + ByteArrayInputStream stream = new ByteArrayInputStream(bytes); + if (file.exists()) { + file.setContents(stream, true, false, null); } else { - bytes = buffer.toString().getBytes(); + IFolder fileFolder = file.getProject().getFolder(file.getParent().getProjectRelativePath()); + createFolder(fileFolder); + file.create(stream, false, null); } - ByteArrayInputStream stream = new ByteArrayInputStream(bytes); - // use a platform operation to update the resource contents - boolean force = true; - file.setContents(stream, force, false, null); + file.setDerived(true, null); + } + + public static void createFolder(IFolder folder) throws CoreException { + // Create or get the handle for the build directory + if (folder.exists()) { + return; + } + if (!folder.getParent().exists()) { + createFolder(folder.getFolder("..")); + } + folder.create(true, true, null); + folder.setDerived(true, null); } /** @@ -484,7 +487,7 @@ public static void addMacroAdditionPrefix(LinkedHashMap map, Str boolean addPrefix) { // there is no entry in the map, so create a buffer for this macro StringBuffer tempBuffer = new StringBuffer(); - tempBuffer.append(macroName).append(WHITESPACE).append(MACRO_ADDITION_PREFIX_SUFFIX); + tempBuffer.append(macroName).append(MACRO_ADDITION_PREFIX_SUFFIX); if (addPrefix) { tempBuffer.append(new Path(MACRO_ADDITION_ADDPREFIX_HEADER).append(relativePath) .append(MACRO_ADDITION_ADDPREFIX_SUFFIX).toOSString()); diff --git a/io.sloeber.core/src/io/sloeber/managedBuild/Internal/ManagedBuildConstants.java b/io.sloeber.core/src/io/sloeber/managedBuild/Internal/ManagedBuildConstants.java index 320240055..a2f2bf95b 100644 --- a/io.sloeber.core/src/io/sloeber/managedBuild/Internal/ManagedBuildConstants.java +++ b/io.sloeber.core/src/io/sloeber/managedBuild/Internal/ManagedBuildConstants.java @@ -70,8 +70,9 @@ public class ManagedBuildConstants { public static final String OBJS_MACRO = "OBJS"; public static final String MACRO_ADDITION_ADDPREFIX_HEADER = "${addprefix "; public static final String MACRO_ADDITION_ADDPREFIX_SUFFIX = "," + WHITESPACE + LINEBREAK; - public static final String JAVA_ADDITION = "+="; - public static final String MACRO_ADDITION_PREFIX_SUFFIX = JAVA_ADDITION + WHITESPACE + LINEBREAK; + public static final String MAKE_ADDITION = " +="; + public static final String MAKE_EQUAL = " :="; + public static final String MACRO_ADDITION_PREFIX_SUFFIX = MAKE_ADDITION + LINEBREAK; public static final String PREBUILD = "pre-build"; public static final String MAINBUILD = "main-build"; public static final String POSTBUILD = "post-build"; diff --git a/io.sloeber.core/src/io/sloeber/managedBuild/Internal/SrcMakeGenerator.java b/io.sloeber.core/src/io/sloeber/managedBuild/Internal/SrcMakeGenerator.java index 38da7eb54..b8661e1be 100644 --- a/io.sloeber.core/src/io/sloeber/managedBuild/Internal/SrcMakeGenerator.java +++ b/io.sloeber.core/src/io/sloeber/managedBuild/Internal/SrcMakeGenerator.java @@ -3,136 +3,34 @@ import static io.sloeber.managedBuild.Internal.ManagebBuildCommon.*; import static io.sloeber.managedBuild.Internal.ManagedBuildConstants.*; -import java.util.ArrayList; import java.util.Collection; -import java.util.HashSet; -import java.util.List; -import java.util.Map.Entry; import java.util.Set; -import org.eclipse.cdt.core.settings.model.util.IPathSettingsContainerVisitor; -import org.eclipse.cdt.core.settings.model.util.PathSettingsContainer; -import org.eclipse.cdt.managedbuilder.core.IOutputType; -import org.eclipse.cdt.managedbuilder.core.ITool; -import org.eclipse.cdt.managedbuilder.internal.core.ManagedMakeMessages; -import org.eclipse.cdt.managedbuilder.makegen.IManagedDependencyGeneratorType; +import org.eclipse.cdt.managedbuilder.core.IConfiguration; import org.eclipse.core.resources.IContainer; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResource; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; -import org.eclipse.core.runtime.Path; public class SrcMakeGenerator { - private ArduinoGnuMakefileGenerator caller; - - SrcMakeGenerator(ArduinoGnuMakefileGenerator theCaller) { - caller = theCaller; - } - - private IProject getProject() { - return caller.getProject(); - } - - public void populateSourcesMakefile(IFile fileHandle, PathSettingsContainer toolInfos, + static public void generateSourceMakefile(IProject project, IConfiguration config, Set macroNames, Collection subDirs) throws CoreException { // Add the comment StringBuffer buffer = addDefaultHeader(); - // Determine the set of macros - toolInfos.accept(new IPathSettingsContainerVisitor() { - @Override - public boolean visit(PathSettingsContainer container) { - ToolInfoHolder h = (ToolInfoHolder) container.getValue(); - ITool[] buildTools = h.buildTools; - HashSet handledInputExtensions = new HashSet<>(); - String buildMacro; - for (ITool buildTool : buildTools) { - if (buildTool.getCustomBuildStep()) - continue; - // Add the known sources macros - String[] extensionsList = buildTool.getAllInputExtensions(); - for (String ext : extensionsList) { - // create a macro of the form "EXTENSION_SRCS :=" - String extensionName = ext; - if (!handledInputExtensions.contains(extensionName)) { - handledInputExtensions.add(extensionName); - buildMacro = getSourceMacroName(extensionName).toString(); - if (!caller.buildSrcVars.containsKey(buildMacro)) { - caller.buildSrcVars.put(buildMacro, new ArrayList()); - } - // Add any generated dependency file macros - IManagedDependencyGeneratorType depType = buildTool - .getDependencyGeneratorForExtension(extensionName); - if (depType != null) { - int calcType = depType.getCalculatorType(); - if (calcType == IManagedDependencyGeneratorType.TYPE_COMMAND - || calcType == IManagedDependencyGeneratorType.TYPE_BUILD_COMMANDS - || calcType == IManagedDependencyGeneratorType.TYPE_PREBUILD_COMMANDS) { - buildMacro = getDepMacroName(extensionName).toString(); - if (!caller.buildDepVars.containsKey(buildMacro)) { - caller.buildDepVars.put(buildMacro, new ArduinoGnuDependencyGroupInfo( - buildMacro, - (calcType != IManagedDependencyGeneratorType.TYPE_PREBUILD_COMMANDS))); - } - if (!caller.buildOutVars.containsKey(buildMacro)) { - caller.buildOutVars.put(buildMacro, new ArrayList()); - } - } - } - } - } - // Add the specified output build variables - IOutputType[] outTypes = buildTool.getOutputTypes(); - if (outTypes != null && outTypes.length > 0) { - for (IOutputType outputType : outTypes) { - buildMacro = outputType.getBuildVariable(); - if (!caller.buildOutVars.containsKey(buildMacro)) { - caller.buildOutVars.put(buildMacro, new ArrayList()); - } - } - } else { - // For support of pre-CDT 3.0 integrations. - buildMacro = OBJS_MACRO; - if (!caller.buildOutVars.containsKey(buildMacro)) { - caller.buildOutVars.put(buildMacro, new ArrayList()); - } - } - } - return true; - } - }); // Add the macros to the makefile - for (Entry> entry : caller.buildSrcVars.entrySet()) { - String macroName = new Path(entry.getKey()).toOSString(); - buffer.append(macroName).append(WHITESPACE).append(":=").append(WHITESPACE).append(NEWLINE); //$NON-NLS-1$ - } - Set>> set = caller.buildOutVars.entrySet(); - for (Entry> entry : set) { - String macroName = new Path(entry.getKey()).toOSString(); + for (String macroName : macroNames) { buffer.append(macroName).append(WHITESPACE).append(":=").append(WHITESPACE).append(NEWLINE); //$NON-NLS-1$ } // Add a list of subdirectories to the makefile - buffer.append(NEWLINE).append(addSubdirectories(subDirs)); - // Save the file - save(buffer, fileHandle); - } - - /************************************************************************* - * S O U R C E S (sources.mk) M A K E F I L E M E T H O D S - ************************************************************************/ - private StringBuffer addSubdirectories(Collection subDirs) { - IProject project = getProject(); - StringBuffer buffer = new StringBuffer(); + buffer.append(NEWLINE); // Add the comment buffer.append(COMMENT_SYMBOL).append(WHITESPACE).append(MOD_LIST_MESSAGE).append(NEWLINE); buffer.append("SUBDIRS := ").append(LINEBREAK); //$NON-NLS-1$ // Get all the module names for (IResource container : subDirs) { - caller.updateMonitor(ManagedMakeMessages.getFormattedString( - "MakefileGenerator.message.adding.source.folder", container.getFullPath().toOSString())); //$NON-NLS-1$ - // Check the special case where the module is the project root if (container.getFullPath() == project.getFullPath()) { buffer.append(DOT).append(WHITESPACE).append(LINEBREAK); } else { @@ -141,6 +39,30 @@ private StringBuffer addSubdirectories(Collection subDirs) { } } buffer.append(NEWLINE); - return buffer; + // Save the file + IFile fileHandle = project.getFile(config.getName() + '/' + SRCSFILE_NAME); + save(buffer, fileHandle); } + + /** + * The makefile generator generates a Macro for each type of output, other than + * final artifact, created by the build. + * + * @param fileHandle + * The file that should be populated with the output + */ + protected static void generateObjectsMakefile(IProject project, IConfiguration config, Set outputMacros) + throws CoreException { + StringBuffer macroBuffer = new StringBuffer(); + macroBuffer.append(addDefaultHeader()); + + for (String macroName : outputMacros) { + macroBuffer.append(macroName).append(MAKE_EQUAL); + macroBuffer.append(NEWLINE); + macroBuffer.append(NEWLINE); + } + IFile fileHandle = project.getFile(config.getName() + '/' + OBJECTS_MAKFILE); + save(macroBuffer, fileHandle); + } + } diff --git a/io.sloeber.core/src/io/sloeber/managedBuild/Internal/SubDirMakeGenerator.java b/io.sloeber.core/src/io/sloeber/managedBuild/Internal/SubDirMakeGenerator.java index 260540813..1488b4bf1 100644 --- a/io.sloeber.core/src/io/sloeber/managedBuild/Internal/SubDirMakeGenerator.java +++ b/io.sloeber.core/src/io/sloeber/managedBuild/Internal/SubDirMakeGenerator.java @@ -5,8 +5,11 @@ import static io.sloeber.managedBuild.Internal.ManagedBuildConstants.*; import java.util.HashSet; -import java.util.LinkedList; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; import java.util.List; +import java.util.Map; +import java.util.Set; import org.eclipse.cdt.managedbuilder.core.IConfiguration; import org.eclipse.cdt.managedbuilder.core.IFileInfo; @@ -26,15 +29,70 @@ import io.sloeber.managedBuild.api.IManagedOutputNameProviderJaba; public class SubDirMakeGenerator { - private List depLineList = new LinkedList<>(); private ArduinoGnuMakefileGenerator caller; + private Set myMakeRules = new LinkedHashSet<>(); + private IContainer myModule; - SubDirMakeGenerator(ArduinoGnuMakefileGenerator theCaller) { + SubDirMakeGenerator(ArduinoGnuMakefileGenerator theCaller, IContainer module) { caller = theCaller; + myModule = module; + getMakeRules(); } - public List getDepLineList() { - return depLineList; + public Set getDependecyMacros() { + HashSet ret = new LinkedHashSet<>(); + for (MakeRule curMakeRule : myMakeRules) { + ret.addAll(curMakeRule.getDependecyMacros()); + } + return ret; + } + + public Set getAllMacros() { + HashSet ret = new LinkedHashSet<>(); + for (MakeRule curMakeRule : myMakeRules) { + ret.addAll(curMakeRule.getAllMacros()); + } + return ret; + } + + public Set getTargetMacros() { + HashSet ret = new LinkedHashSet<>(); + for (MakeRule curMakeRule : myMakeRules) { + ret.addAll(curMakeRule.getTargetMacros()); + } + return ret; + } + + public Set getPrerequisiteMacros() { + HashSet ret = new LinkedHashSet<>(); + for (MakeRule curMakeRule : myMakeRules) { + ret.addAll(curMakeRule.getPrerequisiteMacros()); + } + return ret; + } + + public Set getTargetFiles() { + Set ret = new LinkedHashSet<>(); + for (MakeRule curMakeRule : myMakeRules) { + ret.addAll(curMakeRule.getTargetFiles()); + } + return ret; + } + + public Set getDependencyFiles() { + Set ret = new LinkedHashSet<>(); + for (MakeRule curMakeRule : myMakeRules) { + ret.addAll(curMakeRule.getDependencyFiles()); + } + return ret; + } + + public Map> getTargets() { + Map> ret = new LinkedHashMap<>(); + for (MakeRule curMakeRule : myMakeRules) { + ret.putAll(curMakeRule.getTargets()); + } + return ret; } private IPath getBuildWorkingDir() { @@ -60,48 +118,42 @@ private IProject getProject() { * This method generates a "fragment" make file (subdir.mk). One of these is * generated for each project directory/subdirectory that contains source files. */ - public void populateFragmentMakefile(IContainer module) throws CoreException { + public void generateMakefile() throws CoreException { //create the parent folder on disk and file in eclispe IProject project = getProject(); IPath buildRoot = getBuildWorkingDir(); if (buildRoot == null) { return; } - IPath moduleOutputPath = buildRoot.append(module.getProjectRelativePath()); - caller.updateMonitor(ManagedMakeMessages.getFormattedString("MakefileGenerator.message.gen.source.makefile", //$NON-NLS-1$ - moduleOutputPath.toString())); - IPath moduleOutputDir = createDirectory(project, moduleOutputPath.toString()); - IFile modMakefile = createFile(moduleOutputDir.append(MODFILE_NAME)); - - //get the data - List makeRules = getMakeRules(module); + IPath moduleOutputPath = buildRoot.append(myModule.getProjectRelativePath()); + IFile modMakefile = project.getFile(moduleOutputPath.append(MODFILE_NAME)); //generate the file content StringBuffer makeBuf = addDefaultHeader(); - makeBuf.append(GenerateMacros(makeRules)); - makeBuf.append(GenerateRules(makeRules, getConfig())); + makeBuf.append(GenerateMacros()); + makeBuf.append(GenerateRules(getConfig())); // Save the files save(makeBuf, modMakefile); } - private StringBuffer GenerateMacros(List makeRules) { + private StringBuffer GenerateMacros() { StringBuffer buffer = new StringBuffer(); IFile buildRoot = getTopBuildDir(); buffer.append(NEWLINE); buffer.append(COMMENT_SYMBOL).append(WHITESPACE).append(ManagedMakeMessages.getResourceString(MOD_VARS)) .append(NEWLINE); HashSet macroNames = new HashSet<>(); - for (MakeRule makeRule : makeRules) { - macroNames.addAll(makeRule.getMacros()); + for (MakeRule makeRule : myMakeRules) { + macroNames.addAll(makeRule.getAllMacros()); } for (String macroName : macroNames) { HashSet files = new HashSet<>(); - for (MakeRule makeRule : makeRules) { + for (MakeRule makeRule : myMakeRules) { files.addAll(makeRule.getMacroElements(macroName)); } if (files.size() > 0) { - buffer.append(macroName).append(JAVA_ADDITION).append(WHITESPACE); + buffer.append(macroName).append(MAKE_ADDITION); for (IFile file : files) { buffer.append(LINEBREAK); buffer.append(GetNiceFileName(buildRoot, file)).append(WHITESPACE); @@ -113,13 +165,13 @@ private StringBuffer GenerateMacros(List makeRules) { return buffer; } - private StringBuffer GenerateRules(List makeRules, IConfiguration config) { + private StringBuffer GenerateRules(IConfiguration config) { StringBuffer buffer = new StringBuffer(); buffer.append(NEWLINE); buffer.append(COMMENT_SYMBOL).append(WHITESPACE).append(ManagedMakeMessages.getResourceString(MOD_RULES)) .append(NEWLINE); - for (MakeRule makeRule : makeRules) { + for (MakeRule makeRule : myMakeRules) { buffer.append(makeRule.getRule(getProject(), getTopBuildDir(), config)); } @@ -127,19 +179,20 @@ private StringBuffer GenerateRules(List makeRules, IConfiguration conf } //Get the rules for the source files - private List getMakeRules(IContainer module) { + private void getMakeRules() { + myMakeRules.clear(); IConfiguration config = getConfig(); IProject project = getProject(); - List makeRules = new LinkedList<>(); + // Visit the resources in this folder try { - for (IResource resource : module.members()) { + for (IResource resource : myModule.members()) { if (resource.getType() != IResource.FILE) { //only handle files continue; } IFile inputFile = (IFile) resource; - IPath rcProjRelPath = resource.getProjectRelativePath(); + IPath rcProjRelPath = inputFile.getProjectRelativePath(); if (!caller.isSource(rcProjRelPath)) { // this resource is excluded from build continue; @@ -173,41 +226,38 @@ private List getMakeRules(IContainer module) { //We found a tool get the other info //TOFIX we should simply loop over all available tools - if (tool != null) { - - // Generate the rule to build this source file - //TOFIX check wether this tool can handle this file - IInputType inputType = tool.getPrimaryInputType(); - if (inputType == null) { - inputType = tool.getInputType(ext); - } - - for (IOutputType outputType : tool.getOutputTypes()) { - IManagedOutputNameProviderJaba nameProvider = getJABANameProvider(outputType); - if (nameProvider != null) { - IPath outputFile = nameProvider.getOutputName(getProject(), config, tool, - resource.getProjectRelativePath()); - if (outputFile != null) { - //We found a tool that provides a outputfile for our source file - //TOFIX if this is a multiple to one we should only create one MakeRule - IPath correctOutputPath = new Path(config.getName()).append(outputFile); - MakeRule newMakeRule = new MakeRule(caller, tool, inputType, inputFile, outputType, - project.getFile(correctOutputPath)); - - makeRules.add(newMakeRule); + if (tool == null) { + continue; + } - } + // Generate the rule to build this source file + //TOFIX check wether this tool can handle this file + IInputType inputType = tool.getPrimaryInputType(); + if (inputType == null) { + inputType = tool.getInputType(ext); + } - } + for (IOutputType outputType : tool.getOutputTypes()) { + IManagedOutputNameProviderJaba nameProvider = getJABANameProvider(outputType); + if (nameProvider == null) { + continue; } + IPath outputFile = nameProvider.getOutputName(getProject(), config, tool, + resource.getProjectRelativePath()); + if (outputFile != null) { + //We found a tool that provides a outputfile for our source file + //TOFIX if this is a multiple to one we should only create one MakeRule + IPath correctOutputPath = new Path(config.getName()).append(outputFile); + MakeRule newMakeRule = new MakeRule(caller, tool, inputType, inputFile, outputType, + project.getFile(correctOutputPath)); + myMakeRules.add(newMakeRule); + } } } } catch (CoreException e) { // TODO Auto-generated catch block e.printStackTrace(); } - return makeRules; } - } diff --git a/io.sloeber.core/src/io/sloeber/managedBuild/Internal/TopMakeFileGenerator.java b/io.sloeber.core/src/io/sloeber/managedBuild/Internal/TopMakeFileGenerator.java index db77db6de..66ce11b82 100644 --- a/io.sloeber.core/src/io/sloeber/managedBuild/Internal/TopMakeFileGenerator.java +++ b/io.sloeber.core/src/io/sloeber/managedBuild/Internal/TopMakeFileGenerator.java @@ -7,9 +7,9 @@ import java.util.Collection; import java.util.Collections; import java.util.HashMap; -import java.util.LinkedHashMap; import java.util.List; -import java.util.Map.Entry; +import java.util.Map; +import java.util.Set; import java.util.Vector; import org.eclipse.cdt.core.settings.model.ICConfigurationDescription; @@ -31,11 +31,13 @@ import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IProject; import org.eclipse.core.runtime.CoreException; -import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.Path; public class TopMakeFileGenerator { - private ArduinoGnuMakefileGenerator caller; + private ArduinoGnuMakefileGenerator caller = null; + private Map> myAllSourceTargets = null; + private Set myDependencyMacros = null; + private Set myDependencyFiles = null; private IConfiguration getConfig() { return caller.getConfig(); @@ -45,17 +47,12 @@ private IProject getProject() { return caller.getProject(); } - TopMakeFileGenerator(ArduinoGnuMakefileGenerator theCaller) { + TopMakeFileGenerator(ArduinoGnuMakefileGenerator theCaller, Map> allSourceTargets, + Set dependecyMacros, Set dependencyFiles) { caller = theCaller; - } - - /** - * Returns the map of build variables used in the top makefile to list of files - * - * @return HashMap - */ - private LinkedHashMap getTopBuildOutputVars() { - return caller.getTopBuildOutputVars(); + myAllSourceTargets = allSourceTargets; + myDependencyMacros = dependecyMacros; + myDependencyFiles = dependencyFiles; } /** @@ -70,10 +67,6 @@ private Vector getRuleList() { return caller.getRuleList(); } - public List getDepLineList() { - return caller.getDepLineList(); - } - public PathSettingsContainer getToolInfos() { return caller.getToolInfos(); } @@ -89,7 +82,7 @@ public PathSettingsContainer getToolInfos() { public void populateTopMakefile(IFile fileHandle, boolean rebuild) throws CoreException { StringBuffer buffer = new StringBuffer(); // Add the header - buffer.append(addTopHeader()); + buffer.append(addDefaultHeader()); // Add the macro definitions buffer.append(addMacros()); // List to collect needed build output variables @@ -97,26 +90,14 @@ public void populateTopMakefile(IFile fileHandle, boolean rebuild) throws CoreEx // Determine target rules StringBuffer targetRules = addTargets(outputVarsAdditionsList, rebuild); // Add outputMacros that were added to by the target rules - buffer.append(writeTopAdditionMacros(outputVarsAdditionsList, getTopBuildOutputVars())); + //TOFIX reenable line below + //buffer.append(writeTopAdditionMacros(outputVarsAdditionsList, getTopBuildOutputVars())); // Add target rules buffer.append(targetRules); // Save the file save(buffer, fileHandle); } - /************************************************************************* - * M A I N (makefile) M A K E F I L E M E T H O D S - ************************************************************************/ - /** - * Answers a StringBuffer containing the comment(s) for the - * top-level makefile. - */ - private StringBuffer addTopHeader() { - return addDefaultHeader(); - } - - /** - */ private StringBuffer addMacros() { IConfiguration config = getConfig(); StringBuffer buffer = new StringBuffer(); @@ -161,19 +142,11 @@ private StringBuffer addMacros() { // libraries and other files // buffer.append("-include subdir.mk" + NEWLINE); // buffer.append("-include objects.mk").append(NEWLINE).append(NEWLINE); - // Include generated dependency makefiles if non-empty AND a "clean" has - // not been requested - if (!caller.buildDepVars.isEmpty()) { + if (!myDependencyMacros.isEmpty()) { buffer.append("ifneq ($(MAKECMDGOALS),clean)").append(NEWLINE); - for (Entry entry : caller.buildDepVars.entrySet()) { - String depsMacro = entry.getKey(); - ArduinoGnuDependencyGroupInfo info = entry.getValue(); + for (String depsMacro : myDependencyMacros) { buffer.append("ifneq ($(strip $(").append(depsMacro).append(")),)").append(NEWLINE); - if (info.conditionallyInclude) { - buffer.append("-include $(").append(depsMacro).append(')').append(NEWLINE); - } else { - buffer.append("include $(").append(depsMacro).append(')').append(NEWLINE); - } + buffer.append("-include $(").append(depsMacro).append(')').append(NEWLINE); buffer.append("endif").append(NEWLINE); } buffer.append("endif").append(NEWLINE).append(NEWLINE); @@ -585,10 +558,7 @@ protected boolean addRuleForTool(ITool tool, StringBuffer buffer, boolean bTarge String output = addlOutputs.get(i); String depLine = output + COLON + WHITESPACE + primaryOutput + WHITESPACE + calculatedDependencies + NEWLINE; - if (!getDepLineList().contains(depLine)) { - getDepLineList().add(depLine); - buffer.append(depLine); - } + buffer.append(depLine); } buffer.append(NEWLINE); } @@ -706,8 +676,8 @@ private StringBuffer addTargetsRules(ITool targetTool, List outputVarsAd // Always add a clean target buffer.append("clean:").append(NEWLINE); buffer.append(TAB).append("-$(RM)").append(WHITESPACE); - for (Entry> entry : caller.buildOutVars.entrySet()) { - String macroName = entry.getKey(); + for (IOutputType entry : myAllSourceTargets.keySet()) { + String macroName = entry.getBuildVariable(); buffer.append("$(").append(macroName).append(')'); } String outputPrefix = EMPTY_STRING; @@ -736,14 +706,9 @@ private StringBuffer writeTopAdditionMacros(List varList, HashMap Date: Fri, 21 Oct 2022 01:29:40 +0200 Subject: [PATCH 007/486] #1126 still redesigning checking in due to to much change The makefile is starting to get populated --- .../Internal/ArduinoGnuMakefileGenerator.java | 730 +++++------- .../ArduinoManagedBuildGnuToolInfo.java | 1052 ----------------- .../managedBuild/Internal/MakeRule.java | 236 ++-- .../managedBuild/Internal/MakeRules.java | 105 ++ .../Internal/ManagebBuildCommon.java | 25 + .../Internal/ManagedBuildConstants.java | 1 + .../Internal/SubDirMakeGenerator.java | 122 +- .../managedBuild/Internal/ToolInfoHolder.java | 44 - .../Internal/TopMakeFileGenerator.java | 426 ++++--- .../api/IManagedOutputNameProviderJaba.java | 2 +- 10 files changed, 881 insertions(+), 1862 deletions(-) delete mode 100644 io.sloeber.core/src/io/sloeber/managedBuild/Internal/ArduinoManagedBuildGnuToolInfo.java create mode 100644 io.sloeber.core/src/io/sloeber/managedBuild/Internal/MakeRules.java delete mode 100644 io.sloeber.core/src/io/sloeber/managedBuild/Internal/ToolInfoHolder.java diff --git a/io.sloeber.core/src/io/sloeber/managedBuild/Internal/ArduinoGnuMakefileGenerator.java b/io.sloeber.core/src/io/sloeber/managedBuild/Internal/ArduinoGnuMakefileGenerator.java index 4e8976638..f3308599c 100644 --- a/io.sloeber.core/src/io/sloeber/managedBuild/Internal/ArduinoGnuMakefileGenerator.java +++ b/io.sloeber.core/src/io/sloeber/managedBuild/Internal/ArduinoGnuMakefileGenerator.java @@ -6,15 +6,12 @@ import java.io.File; import java.io.IOException; import java.nio.charset.Charset; -import java.util.ArrayList; -import java.util.Arrays; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedHashSet; import java.util.LinkedList; import java.util.List; -import java.util.Map; import java.util.Set; import java.util.Vector; @@ -25,7 +22,6 @@ import org.eclipse.cdt.core.settings.model.ICSettingEntry; import org.eclipse.cdt.core.settings.model.ICSourceEntry; import org.eclipse.cdt.core.settings.model.util.CDataUtil; -import org.eclipse.cdt.core.settings.model.util.IPathSettingsContainerVisitor; import org.eclipse.cdt.core.settings.model.util.PathSettingsContainer; import org.eclipse.cdt.managedbuilder.core.IBuilder; import org.eclipse.cdt.managedbuilder.core.IConfiguration; @@ -34,19 +30,12 @@ import org.eclipse.cdt.managedbuilder.core.IManagedBuildInfo; import org.eclipse.cdt.managedbuilder.core.IOutputType; import org.eclipse.cdt.managedbuilder.core.IResourceInfo; -import org.eclipse.cdt.managedbuilder.core.ITool; import org.eclipse.cdt.managedbuilder.core.ManagedBuildManager; import org.eclipse.cdt.managedbuilder.core.ManagedBuilderCorePlugin; import org.eclipse.cdt.managedbuilder.internal.core.ManagedMakeMessages; import org.eclipse.cdt.managedbuilder.macros.BuildMacroException; import org.eclipse.cdt.managedbuilder.macros.IBuildMacroProvider; import org.eclipse.cdt.managedbuilder.makegen.IManagedBuilderMakefileGenerator2; -import org.eclipse.cdt.managedbuilder.makegen.IManagedDependencyCommands; -import org.eclipse.cdt.managedbuilder.makegen.IManagedDependencyGenerator2; -import org.eclipse.cdt.managedbuilder.makegen.IManagedDependencyGeneratorType; -import org.eclipse.cdt.managedbuilder.makegen.IManagedDependencyInfo; -import org.eclipse.cdt.managedbuilder.makegen.IManagedDependencyPreBuild; -import org.eclipse.cdt.utils.EFSExtensionManager; import org.eclipse.core.resources.IContainer; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IFolder; @@ -83,43 +72,15 @@ "hiding" }) public class ArduinoGnuMakefileGenerator implements IManagedBuilderMakefileGenerator2 { - /** - * This class walks the delta supplied by the build system to determine what - * resources have been changed. The logic is very simple. If a buildable - * resource (non-header) has been added or removed, the directories in which - * they are located are "dirty" so the makefile fragments for them have to be - * regenerated. - *

- * The actual dependencies are recalculated as a result of the build step - * itself. We are relying on make to do the right things when confronted with a - * dependency on a moved header file. That said, make will treat the missing - * header file in a dependency rule as a target it has to build unless told - * otherwise. These dummy targets are added to the makefile to avoid a missing - * target error. - */ public class ResourceDeltaVisitor implements IResourceDeltaVisitor { private final ArduinoGnuMakefileGenerator generator; private final IConfiguration config; - /** - * The constructor - */ - public ResourceDeltaVisitor(ArduinoGnuMakefileGenerator generator, IManagedBuildInfo info) { - this.generator = generator; - this.config = info.getDefaultConfiguration(); - } - public ResourceDeltaVisitor(ArduinoGnuMakefileGenerator generator, IConfiguration cfg) { this.generator = generator; this.config = cfg; } - /* - * (non-Javadoc) - * - * @see org.eclipse.core.resources.IResourceDeltaVisitor#visit(org.eclipse. - * core.resources.IResourceDelta) - */ @Override public boolean visit(IResourceDelta delta) throws CoreException { // Should the visitor keep iterating in current directory @@ -195,57 +156,38 @@ public boolean visit(IResourceDelta delta) throws CoreException { protected class ResourceProxyVisitor implements IResourceProxyVisitor { private final ArduinoGnuMakefileGenerator generator; private final IConfiguration config; + private Collection subdirList = new LinkedHashSet(); - /** - * Constructs a new resource proxy visitor to quickly visit project resources. - */ - public ResourceProxyVisitor(ArduinoGnuMakefileGenerator generator, IManagedBuildInfo info) { - this.generator = generator; - this.config = info.getDefaultConfiguration(); + Collection getSubdirList() { + return subdirList; } public ResourceProxyVisitor(ArduinoGnuMakefileGenerator generator, IConfiguration cfg) { this.generator = generator; this.config = cfg; + } - /* - * (non-Javadoc) - * - * @see org.eclipse.core.resources.IResourceProxyVisitor#visit(org.eclipse. - * core.resources.IResourceProxy) - */ @Override public boolean visit(IResourceProxy proxy) throws CoreException { - // No point in proceeding, is there if (generator == null) { return false; } IResource resource = proxy.requestResource(); boolean isSource = isSource(resource.getProjectRelativePath()); // Is this a resource we should even consider - if (proxy.getType() == IResource.FILE) { + switch (proxy.getType()) { + case IResource.FILE: // If this resource has a Resource Configuration and is not // excluded or // if it has a file extension that one of the tools builds, add // the sudirectory to the list - // boolean willBuild = false; - IResourceInfo rcInfo = config.getResourceInfo(resource.getProjectRelativePath(), false); if (isSource) { - boolean willBuild = false; - if (rcInfo instanceof IFolderInfo) { - String ext = resource.getFileExtension(); - if (((IFolderInfo) rcInfo).buildsFileType(ext) && !generator.isGeneratedResource(resource)) { - willBuild = true; - } - } else { - willBuild = true; - } - if (willBuild) - generator.appendBuildSubdirectory(resource); + subdirList.add(resource.getParent()); + return false; } - return false; - } else if (proxy.getType() == IResource.FOLDER) { + return true; + case IResource.FOLDER: if (!isSource || generator.isGeneratedResource(resource)) return false; return true; @@ -275,7 +217,7 @@ public boolean visit(IResourceProxy proxy) throws CoreException { private Vector depRuleList; // dependency files /** Collection of Containers which contribute source files to the build */ - private Collection subdirList = new LinkedHashSet(); + private IFile topBuildDir; // Dependency file variables // private Vector dependencyMakefiles; // IPath's - relative to the top @@ -335,7 +277,7 @@ public void initialize(IProject project, IManagedBuildInfo info, IProgressMonito // Cache the build tools config = info.getDefaultConfiguration(); builder = config.getEditableBuilder(); - initToolInfos(); + // initToolInfos(); // set the top build dir path topBuildDir = project.getFile(info.getConfigurationName()); } @@ -343,78 +285,78 @@ public void initialize(IProject project, IManagedBuildInfo info, IProgressMonito /** * This method calls the dependency postprocessors defined for the tool chain */ - private void callDependencyPostProcessors(IResourceInfo rcInfo, ToolInfoHolder h, IFile depFile, - IManagedDependencyGenerator2[] postProcessors, boolean callPopulateDummyTargets, boolean force) - throws CoreException { - try { - updateMonitor(ManagedMakeMessages - .getFormattedString("ArduinoGnuMakefileGenerator.message.postproc.dep.file", depFile.getName())); - if (postProcessors != null) { - IPath absolutePath = new Path( - EFSExtensionManager.getDefault().getPathFromURI(depFile.getLocationURI())); - // Convert to build directory relative - IPath depPath = ManagedBuildManager.calculateRelativePath(getTopBuildDir().getFullPath(), absolutePath); - for (int i = 0; i < postProcessors.length; i++) { - IManagedDependencyGenerator2 depGen = postProcessors[i]; - if (depGen != null) { - depGen.postProcessDependencyFile(depPath, config, h.buildTools[i], - getTopBuildDir().getFullPath()); - } - } - } - if (callPopulateDummyTargets) { - populateDummyTargets(rcInfo, depFile, force); - } - } catch (CoreException e) { - throw e; - } catch (IOException e) { - /* JABA is not going to write this code */ - } - } + // private void callDependencyPostProcessors(IResourceInfo rcInfo, ToolInfoHolder h, IFile depFile, + // IManagedDependencyGenerator2[] postProcessors, boolean callPopulateDummyTargets, boolean force) + // throws CoreException { + // try { + // updateMonitor(ManagedMakeMessages + // .getFormattedString("ArduinoGnuMakefileGenerator.message.postproc.dep.file", depFile.getName())); + // if (postProcessors != null) { + // IPath absolutePath = new Path( + // EFSExtensionManager.getDefault().getPathFromURI(depFile.getLocationURI())); + // // Convert to build directory relative + // IPath depPath = ManagedBuildManager.calculateRelativePath(getTopBuildDir().getFullPath(), absolutePath); + // for (int i = 0; i < postProcessors.length; i++) { + // IManagedDependencyGenerator2 depGen = postProcessors[i]; + // if (depGen != null) { + // depGen.postProcessDependencyFile(depPath, config, h.buildTools[i], + // getTopBuildDir().getFullPath()); + // } + // } + // } + // if (callPopulateDummyTargets) { + // populateDummyTargets(rcInfo, depFile, force); + // } + // } catch (CoreException e) { + // throw e; + // } catch (IOException e) { + // /* JABA is not going to write this code */ + // } + // } /** * This method collects the dependency postprocessors and file extensions * defined for the tool chain */ - private boolean collectDependencyGeneratorInformation(ToolInfoHolder h, Vector depExts, - IManagedDependencyGenerator2[] postProcessors) { - boolean callPopulateDummyTargets = false; - for (int i = 0; i < h.buildTools.length; i++) { - ITool tool = h.buildTools[i]; - IManagedDependencyGeneratorType depType = tool - .getDependencyGeneratorForExtension(tool.getDefaultInputExtension()); - if (depType != null) { - int calcType = depType.getCalculatorType(); - if (calcType <= IManagedDependencyGeneratorType.TYPE_OLD_TYPE_LIMIT) { - if (calcType == IManagedDependencyGeneratorType.TYPE_COMMAND) { - callPopulateDummyTargets = true; - depExts.add(DEP_EXT); - } - } else { - if (calcType == IManagedDependencyGeneratorType.TYPE_BUILD_COMMANDS - || calcType == IManagedDependencyGeneratorType.TYPE_PREBUILD_COMMANDS) { - IManagedDependencyGenerator2 depGen = (IManagedDependencyGenerator2) depType; - String depExt = depGen.getDependencyFileExtension(config, tool); - if (depExt != null) { - postProcessors[i] = depGen; - depExts.add(depExt); - } - } - } - } - } - return callPopulateDummyTargets; - } + // private boolean collectDependencyGeneratorInformation(ToolInfoHolder h, Vector depExts, + // IManagedDependencyGenerator2[] postProcessors) { + // boolean callPopulateDummyTargets = false; + // for (int i = 0; i < h.buildTools.length; i++) { + // ITool tool = h.buildTools[i]; + // IManagedDependencyGeneratorType depType = tool + // .getDependencyGeneratorForExtension(tool.getDefaultInputExtension()); + // if (depType != null) { + // int calcType = depType.getCalculatorType(); + // if (calcType <= IManagedDependencyGeneratorType.TYPE_OLD_TYPE_LIMIT) { + // if (calcType == IManagedDependencyGeneratorType.TYPE_COMMAND) { + // callPopulateDummyTargets = true; + // depExts.add(DEP_EXT); + // } + // } else { + // if (calcType == IManagedDependencyGeneratorType.TYPE_BUILD_COMMANDS + // || calcType == IManagedDependencyGeneratorType.TYPE_PREBUILD_COMMANDS) { + // IManagedDependencyGenerator2 depGen = (IManagedDependencyGenerator2) depType; + // String depExt = depGen.getDependencyFileExtension(config, tool); + // if (depExt != null) { + // postProcessors[i] = depGen; + // depExts.add(depExt); + // } + // } + // } + // } + // } + // return callPopulateDummyTargets; + // } public boolean isSource(IPath path) { return !CDataUtil.isExcluded(path, srcEntries); } - private class DepInfo { - Vector depExts; - IManagedDependencyGenerator2[] postProcessors; - boolean callPopulateDummyTargets; - } + // private class DepInfo { + // Vector depExts; + // IManagedDependencyGenerator2[] postProcessors; + // boolean callPopulateDummyTargets; + // } /* * (non-Javadoc) @@ -424,67 +366,67 @@ private class DepInfo { */ @Override public void generateDependencies() throws CoreException { - final PathSettingsContainer postProcs = PathSettingsContainer.createRootContainer(); - // Note: PopulateDummyTargets is a hack for the pre-3.x GCC compilers - // Collect the methods that will need to be called - toolInfos.accept(new IPathSettingsContainerVisitor() { - @Override - public boolean visit(PathSettingsContainer container) { - ToolInfoHolder h = (ToolInfoHolder) container.getValue(); - Vector depExts = new Vector<>(); - IManagedDependencyGenerator2[] postProcessors = new IManagedDependencyGenerator2[h.buildTools.length]; - boolean callPopulateDummyTargets = collectDependencyGeneratorInformation(h, depExts, postProcessors); - // Is there anyone to call if we do find dependency files? - if (!callPopulateDummyTargets) { - int i; - for (i = 0; i < postProcessors.length; i++) { - if (postProcessors[i] != null) - break; - } - if (i == postProcessors.length) - return true; - } - PathSettingsContainer child = postProcs.getChildContainer(container.getPath(), true, true); - DepInfo di = new DepInfo(); - di.depExts = depExts; - di.postProcessors = postProcessors; - di.callPopulateDummyTargets = callPopulateDummyTargets; - child.setValue(di); - return true; - } - }); - IWorkspaceRoot root = CCorePlugin.getWorkspace().getRoot(); - for (IContainer subDir : getSubdirList()) { - // The builder creates a subdir with same name as source in the - // build location - IPath projectRelativePath = subDir.getProjectRelativePath(); - IResourceInfo rcInfo = config.getResourceInfo(projectRelativePath, false); - PathSettingsContainer cr = postProcs.getChildContainer(rcInfo.getPath(), false, true); - if (cr == null || cr.getValue() == null) - continue; - DepInfo di = (DepInfo) cr.getValue(); - ToolInfoHolder h = ToolInfoHolder.getToolInfo(this, projectRelativePath); - IPath buildRelativePath = topBuildDir.getFullPath().append(projectRelativePath); - IFolder buildFolder = root.getFolder(buildRelativePath); - if (buildFolder == null) - continue; - if (!buildFolder.exists()) - continue; - // Find all of the dep files in the generated subdirectories - IResource[] files = buildFolder.members(); - for (IResource file : files) { - String fileExt = file.getFileExtension(); - for (String ext : di.depExts) { - if (ext.equals(fileExt)) { - IFile depFile = root.getFile(file.getFullPath()); - if (depFile == null) - continue; - callDependencyPostProcessors(rcInfo, h, depFile, di.postProcessors, di.callPopulateDummyTargets, - false); - } - } - } - } + // final PathSettingsContainer postProcs = PathSettingsContainer.createRootContainer(); + // // Note: PopulateDummyTargets is a hack for the pre-3.x GCC compilers + // // Collect the methods that will need to be called + // toolInfos.accept(new IPathSettingsContainerVisitor() { + // @Override + // public boolean visit(PathSettingsContainer container) { + // ToolInfoHolder h = (ToolInfoHolder) container.getValue(); + // Vector depExts = new Vector<>(); + // IManagedDependencyGenerator2[] postProcessors = new IManagedDependencyGenerator2[h.buildTools.length]; + // boolean callPopulateDummyTargets = collectDependencyGeneratorInformation(h, depExts, postProcessors); + // // Is there anyone to call if we do find dependency files? + // if (!callPopulateDummyTargets) { + // int i; + // for (i = 0; i < postProcessors.length; i++) { + // if (postProcessors[i] != null) + // break; + // } + // if (i == postProcessors.length) + // return true; + // } + // PathSettingsContainer child = postProcs.getChildContainer(container.getPath(), true, true); + // DepInfo di = new DepInfo(); + // di.depExts = depExts; + // di.postProcessors = postProcessors; + // di.callPopulateDummyTargets = callPopulateDummyTargets; + // child.setValue(di); + // return true; + // } + // }); + // IWorkspaceRoot root = CCorePlugin.getWorkspace().getRoot(); + // for (IContainer subDir : getSubdirList()) { + // // The builder creates a subdir with same name as source in the + // // build location + // IPath projectRelativePath = subDir.getProjectRelativePath(); + // IResourceInfo rcInfo = config.getResourceInfo(projectRelativePath, false); + // PathSettingsContainer cr = postProcs.getChildContainer(rcInfo.getPath(), false, true); + // if (cr == null || cr.getValue() == null) + // continue; + // DepInfo di = (DepInfo) cr.getValue(); + // //ToolInfoHolder h = ToolInfoHolder.getToolInfo(this, projectRelativePath); + // IPath buildRelativePath = topBuildDir.getFullPath().append(projectRelativePath); + // IFolder buildFolder = root.getFolder(buildRelativePath); + // if (buildFolder == null) + // continue; + // if (!buildFolder.exists()) + // continue; + // // Find all of the dep files in the generated subdirectories + // IResource[] files = buildFolder.members(); + // for (IResource file : files) { + // String fileExt = file.getFileExtension(); + // for (String ext : di.depExts) { + // if (ext.equals(fileExt)) { + // IFile depFile = root.getFile(file.getFullPath()); + // if (depFile == null) + // continue; + // // callDependencyPostProcessors(rcInfo, h, depFile, di.postProcessors, di.callPopulateDummyTargets, + // // false); + // } + // } + // } + // } } /* @@ -675,46 +617,46 @@ public boolean isGeneratedResource(IResource resource) { @Override public void regenerateDependencies(boolean force) throws CoreException { // A hack for the pre-3.x GCC compilers is to put dummy targets for deps - final IWorkspaceRoot root = CCorePlugin.getWorkspace().getRoot(); - final CoreException[] es = new CoreException[1]; - toolInfos.accept(new IPathSettingsContainerVisitor() { - @Override - public boolean visit(PathSettingsContainer container) { - ToolInfoHolder h = (ToolInfoHolder) container.getValue(); - // Collect the methods that will need to be called - Vector depExts = new Vector(); - IManagedDependencyGenerator2[] postProcessors = new IManagedDependencyGenerator2[h.buildTools.length]; - boolean callPopulateDummyTargets = collectDependencyGeneratorInformation(h, depExts, postProcessors); - // Is there anyone to call if we do find dependency files? - if (!callPopulateDummyTargets) { - int i; - for (i = 0; i < postProcessors.length; i++) { - if (postProcessors[i] != null) - break; - } - if (i == postProcessors.length) - return true; - } - IResourceInfo rcInfo = config.getResourceInfo(container.getPath(), false); - for (IPath path : getDependencyMakefiles(h)) { - // The path to search for the dependency makefile - IPath relDepFilePath = topBuildDir.getFullPath().append(path); - IFile depFile = root.getFile(relDepFilePath); - if (depFile == null || !depFile.isAccessible()) - continue; - try { - callDependencyPostProcessors(rcInfo, h, depFile, postProcessors, callPopulateDummyTargets, - true); - } catch (CoreException e) { - es[0] = e; - return false; - } - } - return true; - } - }); - if (es[0] != null) - throw es[0]; + // final IWorkspaceRoot root = CCorePlugin.getWorkspace().getRoot(); + // final CoreException[] es = new CoreException[1]; + // toolInfos.accept(new IPathSettingsContainerVisitor() { + // @Override + // public boolean visit(PathSettingsContainer container) { + // ToolInfoHolder h = (ToolInfoHolder) container.getValue(); + // // Collect the methods that will need to be called + // Vector depExts = new Vector(); + // IManagedDependencyGenerator2[] postProcessors = new IManagedDependencyGenerator2[h.buildTools.length]; + // boolean callPopulateDummyTargets = collectDependencyGeneratorInformation(h, depExts, postProcessors); + // // Is there anyone to call if we do find dependency files? + // if (!callPopulateDummyTargets) { + // int i; + // for (i = 0; i < postProcessors.length; i++) { + // if (postProcessors[i] != null) + // break; + // } + // if (i == postProcessors.length) + // return true; + // } + // IResourceInfo rcInfo = config.getResourceInfo(container.getPath(), false); + // for (IPath path : getDependencyMakefiles(h)) { + // // The path to search for the dependency makefile + // IPath relDepFilePath = topBuildDir.getFullPath().append(path); + // IFile depFile = root.getFile(relDepFilePath); + // if (depFile == null || !depFile.isAccessible()) + // continue; + // try { + // callDependencyPostProcessors(rcInfo, h, depFile, postProcessors, callPopulateDummyTargets, + // true); + // } catch (CoreException e) { + // es[0] = e; + // return false; + // } + // } + // return true; + // } + // }); + // if (es[0] != null) + // throw es[0]; } /* @@ -727,13 +669,12 @@ public boolean visit(PathSettingsContainer container) { public MultiStatus regenerateMakefiles() throws CoreException { MultiStatus status; // Visit the resources in the project - ResourceProxyVisitor visitor = new ResourceProxyVisitor(this, config); - project.accept(visitor, IResource.NONE); + ResourceProxyVisitor subDirVisitor = new ResourceProxyVisitor(this, config); + project.accept(subDirVisitor, IResource.NONE); // See if the user has cancelled the build checkCancel(); - // Populate the makefile if any buildable source files have been found - // in the project - if (getSubdirList().isEmpty()) { + Collection foldersToInvestigate = subDirVisitor.getSubdirList(); + if (foldersToInvestigate.isEmpty()) { String info = ManagedMakeMessages.getFormattedString("MakefileGenerator.warning.no.source", project.getName()); updateMonitor(info); @@ -747,26 +688,53 @@ public MultiStatus regenerateMakefiles() throws CoreException { checkCancel(); // Get the data for the makefile generation List subDirMakeGenerators = new LinkedList<>(); - Map> allSourceTargets = new HashMap<>(); - Set dependencyMacros = new HashSet<>(); - Set dependencyFiles = new HashSet<>(); + Set subDirMakeRules = new HashSet<>(); + Collection foldersToBuild = new LinkedHashSet<>(); - for (IContainer res : getSubdirList()) { + for (IContainer res : foldersToInvestigate) { + //For all the folders get the make rules for this folder SubDirMakeGenerator subDirMakeGenerator = new SubDirMakeGenerator(this, res); - allSourceTargets.putAll(subDirMakeGenerator.getTargets()); - dependencyMacros.addAll(subDirMakeGenerator.getDependecyMacros()); - dependencyFiles.addAll(subDirMakeGenerator.getDependencyFiles()); - subDirMakeGenerators.add(subDirMakeGenerator); + if (!subDirMakeGenerator.isEmpty()) { + foldersToBuild.add(res); + subDirMakeGenerators.add(subDirMakeGenerator); + //also store all these rules in one set to provide them to the top make file + subDirMakeRules.addAll(subDirMakeGenerator.getMakeRules()); + } checkCancel(); } - TopMakeFileGenerator topMakeFileGenerator = new TopMakeFileGenerator(this, allSourceTargets, dependencyMacros, - dependencyFiles); - // main makefile - // calculateToolInputsOutputs(); + TopMakeFileGenerator topMakeFileGenerator = new TopMakeFileGenerator(this, subDirMakeRules, foldersToBuild); + + checkCancel(); + + Set srcMacroNames = new LinkedHashSet<>(); + Set objMacroNames = new LinkedHashSet<>(); + for (SubDirMakeGenerator curSubDirMake : subDirMakeGenerators) { + curSubDirMake.generateMakefile(); + srcMacroNames.addAll(curSubDirMake.getPrerequisiteMacros()); + srcMacroNames.addAll(curSubDirMake.getDependecyMacros()); + objMacroNames.addAll(curSubDirMake.getTargetMacros()); + } + //TOFIX also need to add macro's from main makefile + + SrcMakeGenerator.generateSourceMakefile(project, config, srcMacroNames, foldersToBuild); + SrcMakeGenerator.generateObjectsMakefile(project, config, objMacroNames); + topMakeFileGenerator.generateMakefile(); + checkCancel(); - // Create the top-level makefile - IFile makefileHandle = project.getFile(config.getName() + '/' + MAKEFILE_NAME); - topMakeFileGenerator.populateTopMakefile(makefileHandle, true); + // How did we do + if (!getInvalidDirList().isEmpty()) { + status = new MultiStatus(ManagedBuilderCorePlugin.getUniqueIdentifier(), IStatus.WARNING, "", null); + // Add a new status for each of the bad folders + // TODO: fix error message + for (IResource dir : getInvalidDirList()) { + status.add(new Status(IStatus.WARNING, ManagedBuilderCorePlugin.getUniqueIdentifier(), SPACES_IN_PATH, + dir.getFullPath().toString(), null)); + } + } else { + status = new MultiStatus(ManagedBuilderCorePlugin.getUniqueIdentifier(), IStatus.OK, "", null); + } + + //TOFIX this should be done differently // JABA SLOEBER create the size.awk file ICConfigurationDescription confDesc = ManagedBuildManager.getDescriptionForConfiguration(config); IWorkspaceRoot root = CCorePlugin.getWorkspace().getRoot(); @@ -794,34 +762,7 @@ public MultiStatus regenerateMakefiles() throws CoreException { e.printStackTrace(); } // END JABA SLOEBER create the size.awk file - checkCancel(); - // Now finish up by adding all the object files - - Set srcMacroNames = new LinkedHashSet<>(); - Set objMacroNames = new LinkedHashSet<>(); - for (SubDirMakeGenerator curSubDirMake : subDirMakeGenerators) { - curSubDirMake.generateMakefile(); - srcMacroNames.addAll(curSubDirMake.getPrerequisiteMacros()); - srcMacroNames.addAll(curSubDirMake.getDependecyMacros()); - objMacroNames.addAll(curSubDirMake.getTargetMacros()); - } - //TOFIX also need to add macro's from main makefile - SrcMakeGenerator.generateSourceMakefile(project, config, srcMacroNames, subdirList); - SrcMakeGenerator.generateObjectsMakefile(project, config, objMacroNames); - checkCancel(); - // How did we do - if (!getInvalidDirList().isEmpty()) { - status = new MultiStatus(ManagedBuilderCorePlugin.getUniqueIdentifier(), IStatus.WARNING, "", null); - // Add a new status for each of the bad folders - // TODO: fix error message - for (IResource dir : getInvalidDirList()) { - status.add(new Status(IStatus.WARNING, ManagedBuilderCorePlugin.getUniqueIdentifier(), SPACES_IN_PATH, - dir.getFullPath().toString(), null)); - } - } else { - status = new MultiStatus(ManagedBuilderCorePlugin.getUniqueIdentifier(), IStatus.OK, "", null); - } return status; } @@ -835,24 +776,24 @@ public MultiStatus regenerateMakefiles() throws CoreException { * * @return a Set containing all of the output extensions */ - public Set getOutputExtensions(ToolInfoHolder h) { - if (h.outputExtensionsSet == null) { - // The set of output extensions which will be produced by this tool. - // It is presumed that this set is not very large (likely < 10) so - // a HashSet should provide good performance. - h.outputExtensionsSet = new HashSet<>(); - // For each tool for the target, lookup the kinds of sources it - // outputs - // and add that to our list of output extensions. - for (ITool tool : h.buildTools) { - String[] outputs = tool.getAllOutputExtensions(); - if (outputs != null) { - h.outputExtensionsSet.addAll(Arrays.asList(outputs)); - } - } - } - return h.outputExtensionsSet; - } + // public Set getOutputExtensions(ToolInfoHolder h) { + // if (h.outputExtensionsSet == null) { + // // The set of output extensions which will be produced by this tool. + // // It is presumed that this set is not very large (likely < 10) so + // // a HashSet should provide good performance. + // h.outputExtensionsSet = new HashSet<>(); + // // For each tool for the target, lookup the kinds of sources it + // // outputs + // // and add that to our list of output extensions. + // for (ITool tool : h.buildTools) { + // String[] outputs = tool.getAllOutputExtensions(); + // if (outputs != null) { + // h.outputExtensionsSet.addAll(Arrays.asList(outputs)); + // } + // } + // } + // return h.outputExtensionsSet; + // } /** * Adds file(s) to an entry in a map of macro names to entries. File additions @@ -1031,18 +972,16 @@ protected Vector getDepRuleList() { /************************************************************************* * R E S O U R C E V I S I T O R M E T H O D S ************************************************************************/ - /** - * Adds the container of the argument to the list of folders in the project that - * contribute source files to the build. The resource visitor has already - * established that the build model knows how to build the files. It has also - * checked that the resource is not generated as part of the build. - */ - protected void appendBuildSubdirectory(IResource resource) { - IContainer container = resource.getParent(); - // Only add the container once - if (!getSubdirList().contains(container)) - getSubdirList().add(container); - } + // /** + // * Adds the container of the argument to the list of folders in the project that + // * contribute source files to the build. The resource visitor has already + // * established that the build model knows how to build the files. It has also + // * checked that the resource is not generated as part of the build. + // */ + // protected void appendBuildSubdirectory(IResource resource) { + // IContainer container = resource.getParent(); + // subdirList.add(container); + // } /** * Adds the container of the argument to a list of subdirectories that are to be @@ -1139,67 +1078,67 @@ private IPath inFullPathFromOutFullPath(IPath path) { return inPath; } - private void deleteDepFile(IResource deletedFile) { - // Calculate the top build directory relative paths of the dependency - // files - IPath[] depFilePaths = null; - ITool tool = null; - IManagedDependencyGeneratorType depType = null; - String sourceExtension = deletedFile.getFileExtension(); - IPath folderPath = inFullPathFromOutFullPath(deletedFile.getFullPath().removeLastSegments(1)); - if (folderPath != null) { - folderPath = folderPath.removeFirstSegments(1); - } else { - folderPath = new Path(""); - ToolInfoHolder h = ToolInfoHolder.getToolInfo(this, folderPath); - ITool[] tools = h.buildTools; - for (int index = 0; index < tools.length; ++index) { - if (tools[index].buildsFileType(sourceExtension)) { - tool = tools[index]; - depType = tool.getDependencyGeneratorForExtension(sourceExtension); - break; - } - } - if (depType != null) { - int calcType = depType.getCalculatorType(); - if (calcType == IManagedDependencyGeneratorType.TYPE_COMMAND) { - depFilePaths = new IPath[1]; - IPath absolutePath = deletedFile.getLocation(); - depFilePaths[0] = ManagedBuildManager.calculateRelativePath(getTopBuildDir().getFullPath(), - absolutePath); - depFilePaths[0] = depFilePaths[0].removeFileExtension().addFileExtension(DEP_EXT); - } else if (calcType == IManagedDependencyGeneratorType.TYPE_BUILD_COMMANDS - || calcType == IManagedDependencyGeneratorType.TYPE_PREBUILD_COMMANDS) { - IManagedDependencyGenerator2 depGen = (IManagedDependencyGenerator2) depType; - IManagedDependencyInfo depInfo = depGen.getDependencySourceInfo( - deletedFile.getProjectRelativePath(), deletedFile, config, tool, getBuildWorkingDir()); - if (depInfo != null) { - if (calcType == IManagedDependencyGeneratorType.TYPE_BUILD_COMMANDS) { - IManagedDependencyCommands depCommands = (IManagedDependencyCommands) depInfo; - depFilePaths = depCommands.getDependencyFiles(); - } else if (calcType == IManagedDependencyGeneratorType.TYPE_PREBUILD_COMMANDS) { - IManagedDependencyPreBuild depPreBuild = (IManagedDependencyPreBuild) depInfo; - depFilePaths = depPreBuild.getDependencyFiles(); - } - } - } - } - // Delete the files if they exist - if (depFilePaths != null) { - for (IPath dfp : depFilePaths) { - IPath depFilePath = getBuildWorkingDir().append(dfp); - IResource depFile = project.findMember(depFilePath); - if (depFile != null && depFile.exists()) { - try { - depFile.delete(true, new SubProgressMonitor(monitor, 1)); - } catch (CoreException e) { - // This had better be allowed during a build - } - } - } - } - } - } + // private void deleteDepFile(IResource deletedFile) { + // // Calculate the top build directory relative paths of the dependency + // // files + // IPath[] depFilePaths = null; + // ITool tool = null; + // IManagedDependencyGeneratorType depType = null; + // String sourceExtension = deletedFile.getFileExtension(); + // IPath folderPath = inFullPathFromOutFullPath(deletedFile.getFullPath().removeLastSegments(1)); + // if (folderPath != null) { + // folderPath = folderPath.removeFirstSegments(1); + // } else { + // folderPath = new Path(""); + // ToolInfoHolder h = ToolInfoHolder.getToolInfo(this, folderPath); + // ITool[] tools = h.buildTools; + // for (int index = 0; index < tools.length; ++index) { + // if (tools[index].buildsFileType(sourceExtension)) { + // tool = tools[index]; + // depType = tool.getDependencyGeneratorForExtension(sourceExtension); + // break; + // } + // } + // if (depType != null) { + // int calcType = depType.getCalculatorType(); + // if (calcType == IManagedDependencyGeneratorType.TYPE_COMMAND) { + // depFilePaths = new IPath[1]; + // IPath absolutePath = deletedFile.getLocation(); + // depFilePaths[0] = ManagedBuildManager.calculateRelativePath(getTopBuildDir().getFullPath(), + // absolutePath); + // depFilePaths[0] = depFilePaths[0].removeFileExtension().addFileExtension(DEP_EXT); + // } else if (calcType == IManagedDependencyGeneratorType.TYPE_BUILD_COMMANDS + // || calcType == IManagedDependencyGeneratorType.TYPE_PREBUILD_COMMANDS) { + // IManagedDependencyGenerator2 depGen = (IManagedDependencyGenerator2) depType; + // IManagedDependencyInfo depInfo = depGen.getDependencySourceInfo( + // deletedFile.getProjectRelativePath(), deletedFile, config, tool, getBuildWorkingDir()); + // if (depInfo != null) { + // if (calcType == IManagedDependencyGeneratorType.TYPE_BUILD_COMMANDS) { + // IManagedDependencyCommands depCommands = (IManagedDependencyCommands) depInfo; + // depFilePaths = depCommands.getDependencyFiles(); + // } else if (calcType == IManagedDependencyGeneratorType.TYPE_PREBUILD_COMMANDS) { + // IManagedDependencyPreBuild depPreBuild = (IManagedDependencyPreBuild) depInfo; + // depFilePaths = depPreBuild.getDependencyFiles(); + // } + // } + // } + // } + // // Delete the files if they exist + // if (depFilePaths != null) { + // for (IPath dfp : depFilePaths) { + // IPath depFilePath = getBuildWorkingDir().append(dfp); + // IResource depFile = project.findMember(depFilePath); + // if (depFile != null && depFile.exists()) { + // try { + // depFile.delete(true, new SubProgressMonitor(monitor, 1)); + // } catch (CoreException e) { + // // This had better be allowed during a build + // } + // } + // } + // } + // } + // } /** * Returns the current build configuration. @@ -1248,12 +1187,12 @@ private Vector getDeletedFileList() { return deletedFileList; } - public List getDependencyMakefiles(ToolInfoHolder h) { - if (h.dependencyMakefiles == null) { - h.dependencyMakefiles = new ArrayList(); - } - return h.dependencyMakefiles; - } + // public List getDependencyMakefiles(ToolInfoHolder h) { + // if (h.dependencyMakefiles == null) { + // h.dependencyMakefiles = new ArrayList(); + // } + // return h.dependencyMakefiles; + // } /** * Strips off the file extension from the argument and returns the name @@ -1293,13 +1232,13 @@ private Collection getModifiedList() { return modifiedList; } - /** - * @return Collection of subdirectories (IContainers) contributing source code - * to the build - */ - public Collection getSubdirList() { - return subdirList; - } + // /** + // * @return Collection of subdirectories (IContainers) contributing source code + // * to the build + // */ + // public Collection getSubdirList() { + // return subdirList; + // } private void removeGeneratedDirectory(IContainer subDir) { try { @@ -1387,7 +1326,7 @@ public void initialize(int buildKind, IConfiguration cfg, IBuilder builder, IPro // Cache the build tools config = cfg; this.builder = builder; - initToolInfos(); + // initToolInfos(); // set the top build dir path topBuildDir = project.getFile(cfg.getName()); srcEntries = config.getSourceEntries(); @@ -1400,27 +1339,6 @@ public void initialize(int buildKind, IConfiguration cfg, IBuilder builder, IPro } } - private void initToolInfos() { - toolInfos = PathSettingsContainer.createRootContainer(); - IResourceInfo rcInfos[] = config.getResourceInfos(); - for (IResourceInfo rcInfo : rcInfos) { - if (rcInfo.isExcluded()) - continue; - ToolInfoHolder h = ToolInfoHolder.getToolInfo(this, rcInfo.getPath(), true); - if (rcInfo instanceof IFolderInfo) { - IFolderInfo fo = (IFolderInfo) rcInfo; - h.buildTools = fo.getFilteredTools(); - h.buildToolsUsed = new boolean[h.buildTools.length]; - h.gnuToolInfos = new ArduinoManagedBuildGnuToolInfo[h.buildTools.length]; - } else { - IFileInfo fi = (IFileInfo) rcInfo; - h.buildTools = fi.getToolsToInvoke(); - h.buildToolsUsed = new boolean[h.buildTools.length]; - h.gnuToolInfos = new ArduinoManagedBuildGnuToolInfo[h.buildTools.length]; - } - } - } - public PathSettingsContainer getToolInfos() { return toolInfos; } diff --git a/io.sloeber.core/src/io/sloeber/managedBuild/Internal/ArduinoManagedBuildGnuToolInfo.java b/io.sloeber.core/src/io/sloeber/managedBuild/Internal/ArduinoManagedBuildGnuToolInfo.java deleted file mode 100644 index 6b4bf25c9..000000000 --- a/io.sloeber.core/src/io/sloeber/managedBuild/Internal/ArduinoManagedBuildGnuToolInfo.java +++ /dev/null @@ -1,1052 +0,0 @@ -package io.sloeber.managedBuild.Internal; - -import static io.sloeber.managedBuild.Internal.ManagebBuildCommon.*; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Vector; - -import org.eclipse.cdt.managedbuilder.core.BuildException; -import org.eclipse.cdt.managedbuilder.core.IAdditionalInput; -import org.eclipse.cdt.managedbuilder.core.IConfiguration; -import org.eclipse.cdt.managedbuilder.core.IInputType; -import org.eclipse.cdt.managedbuilder.core.IOption; -import org.eclipse.cdt.managedbuilder.core.ITool; -import org.eclipse.cdt.managedbuilder.core.ManagedBuildManager; -import org.eclipse.cdt.managedbuilder.internal.core.Tool; -import org.eclipse.cdt.managedbuilder.internal.macros.OptionContextData; -import org.eclipse.cdt.managedbuilder.macros.BuildMacroException; -import org.eclipse.cdt.managedbuilder.macros.IBuildMacroProvider; -import org.eclipse.cdt.managedbuilder.makegen.IManagedBuilderMakefileGenerator; -import org.eclipse.cdt.managedbuilder.makegen.IManagedDependencyCalculator; -import org.eclipse.cdt.managedbuilder.makegen.IManagedDependencyGenerator; -import org.eclipse.cdt.managedbuilder.makegen.IManagedDependencyGenerator2; -import org.eclipse.cdt.managedbuilder.makegen.IManagedDependencyGeneratorType; -import org.eclipse.cdt.managedbuilder.makegen.IManagedDependencyInfo; -import org.eclipse.cdt.managedbuilder.makegen.gnu.IManagedBuildGnuToolInfo; -import org.eclipse.core.resources.IProject; -import org.eclipse.core.resources.IResource; -import org.eclipse.core.runtime.IPath; -import org.eclipse.core.runtime.Path; - -/** - * This class represents information about a Tool's inputs and outputs while a - * Gnu makefile is being generated. - * - * @noextend This class is not intended to be subclassed by clients. - */ -@SuppressWarnings({ "restriction", "deprecation", "unused" }) -public class ArduinoManagedBuildGnuToolInfo implements IManagedBuildGnuToolInfo { - - /* - * Members - */ - private IProject project; - private Tool tool; - private boolean bIsTargetTool; - private String targetName; - private String targetExt; - private boolean inputsCalculated = false; - private boolean outputsCalculated = false; - private boolean outputVariablesCalculated = false; - private boolean dependenciesCalculated = false; - private Vector commandInputs = new Vector<>(); - private Vector enumeratedInputs = new Vector<>(); - private Vector commandOutputs = new Vector<>(); - private Vector enumeratedPrimaryOutputs = new Vector<>(); - private Vector enumeratedSecondaryOutputs = new Vector<>(); - private Vector outputVariables = new Vector<>(); - private Vector commandDependencies = new Vector<>(); - private Vector additionalTargets = new Vector<>(); - - // private Vector enumeratedDependencies = new Vector(); - // Map of macro names (String) to values (List) - - /* - * Constructor - */ - public ArduinoManagedBuildGnuToolInfo(IProject project, ITool tool, boolean targetTool, String name, String ext) { - this.project = project; - this.tool = (Tool) tool; - this.bIsTargetTool = targetTool; - if (this.bIsTargetTool) { - this.targetName = name; - this.targetExt = ext; - } - } - - /* - * IManagedBuildGnuToolInfo Methods - */ - @Override - public boolean areInputsCalculated() { - return this.inputsCalculated; - } - - // Command inputs are top build directory relative - @Override - public Vector getCommandInputs() { - return this.commandInputs; - } - - // Enumerated inputs are project relative - @Override - public Vector getEnumeratedInputs() { - return this.enumeratedInputs; - } - - @Override - public boolean areOutputsCalculated() { - return this.outputsCalculated; - } - - // Command outputs are top build directory relative - @Override - public Vector getCommandOutputs() { - return this.commandOutputs; - } - - @Override - public Vector getEnumeratedPrimaryOutputs() { - return this.enumeratedPrimaryOutputs; - } - - @Override - public Vector getEnumeratedSecondaryOutputs() { - return this.enumeratedSecondaryOutputs; - } - - @Override - public Vector getOutputVariables() { - return this.outputVariables; - } - - public boolean areOutputVariablesCalculated() { - return this.outputVariablesCalculated; - } - - @Override - public boolean areDependenciesCalculated() { - return this.dependenciesCalculated; - } - - // Command dependencies are top build directory relative - @Override - public Vector getCommandDependencies() { - return this.commandDependencies; - } - - // Additional targets are top build directory relative - @Override - public Vector getAdditionalTargets() { - return this.additionalTargets; - } - - // public Vector getEnumeratedDependencies() { - // return enumeratedDependencies; - // } - - @Override - public boolean isTargetTool() { - return this.bIsTargetTool; - } - - /* - * Other Methods - */ - - public boolean calculateInputs(ArduinoGnuMakefileGenerator makeGen, IConfiguration config, - IResource[] projResources, ToolInfoHolder h, boolean lastChance) { - // Get the inputs for this tool invocation - // Note that command inputs that are also dependencies are also added to - // the command dependencies list - - /* - * The priorities for determining the names of the inputs of a tool are: - * 1. If an option is specified, use the value of the option. 2. If a - * build variable is specified, use the files that have been added to - * the build variable as the output(s) of other build steps. 3. Use the - * file extensions and the resources in the project - */ - boolean done = true; - Vector myCommandInputs = new Vector<>(); // Inputs for the - // tool command - // line - Vector myCommandDependencies = new Vector<>(); // Dependencies - // for the - // make - // rule - Vector myEnumeratedInputs = new Vector<>(); // Complete - // list of - // individual - // inputs - - IInputType[] inTypes = this.tool.getInputTypes(); - if (inTypes != null && inTypes.length > 0) { - for (IInputType type : inTypes) { - Vector itCommandInputs = new Vector<>(); // Inputs - // for - // the - // tool - // command - // line - // for - // this - // input-type - Vector itCommandDependencies = new Vector<>(); // Dependencies - // for - // the - // make - // rule - // for - // this - // input-type - Vector itEnumeratedInputs = new Vector<>(); // Complete - // list - // of - // individual - // inputs - // for - // this - // input-type - String variable = type.getBuildVariable(); - boolean primaryInput = type.getPrimaryInput(); - boolean useFileExts = false; - IOption option = this.tool.getOptionBySuperClassId(type.getOptionId()); - IOption assignToOption = this.tool.getOptionBySuperClassId(type.getAssignToOptionId()); - - // Option? - if (option != null) { - try { - List inputs = new ArrayList<>(); - int optType = option.getValueType(); - if (optType == IOption.STRING) { - inputs.add(option.getStringValue()); - } else if (optType == IOption.STRING_LIST || optType == IOption.LIBRARIES - || optType == IOption.OBJECTS || optType == IOption.INCLUDE_FILES - || optType == IOption.LIBRARY_PATHS || optType == IOption.LIBRARY_FILES - || optType == IOption.MACRO_FILES) { - @SuppressWarnings("unchecked") - List valueList = (List) option.getValue(); - inputs = valueList; - this.tool.filterValues(optType, inputs); - this.tool.filterValues(optType, inputs); - } - for (int j = 0; j < inputs.size(); j++) { - String inputName = inputs.get(j); - - try { - // try to resolve the build macros in the output - // names - - String resolved = null; - - // does the input name contain spaces? - // TODO: support other special characters - if (inputName.indexOf(" ") != -1) //$NON-NLS-1$ - { - // resolve to string - resolved = ManagedBuildManager.getBuildMacroProvider().resolveValue(inputName, "", //$NON-NLS-1$ - " ", //$NON-NLS-1$ - IBuildMacroProvider.CONTEXT_OPTION, - new OptionContextData(option, this.tool)); - } else { - - // resolve to makefile variable format - resolved = ManagedBuildManager.getBuildMacroProvider().resolveValueToMakefileFormat( - inputName, "", //$NON-NLS-1$ - " ", //$NON-NLS-1$ - IBuildMacroProvider.CONTEXT_OPTION, - new OptionContextData(option, this.tool)); - } - - if ((resolved = resolved.trim()).length() > 0) - inputName = resolved; - } catch (BuildMacroException e) {// JABA is not - // going to add - // code - } - - if (primaryInput) { - itCommandDependencies.add(j, inputName); - } else { - itCommandDependencies.add(inputName); - } - // NO - itCommandInputs.add(inputName); - // NO - itEnumeratedInputs.add(inputName); - } - } catch (BuildException ex) {// JABA is not going to add - // code - } - - } else { - - // Build Variable? - if (variable.length() > 0) { - String cmdVariable = variable = "$(" + variable + ")"; //$NON-NLS-1$ //$NON-NLS-2$ - itCommandInputs.add(cmdVariable); - if (primaryInput) { - itCommandDependencies.add(0, cmdVariable); - } else { - itCommandDependencies.add(cmdVariable); - } - // If there is an output variable with the same name, - // get - // the files associated with it. - // List outMacroList = makeGen.getBuildVariableList(h, variable, PROJECT_RELATIVE, null, - // true); - // if (outMacroList != null) { - // itEnumeratedInputs.addAll(outMacroList); - // } else { - // // If "last chance", then calculate using file - // // extensions below - // if (lastChance) { - // useFileExts = true; - // } else { - // done = false; - // break; - // } - // } - } - - // Use file extensions - if (variable.length() == 0 || useFileExts) { - // if (type.getMultipleOfType()) { - // Calculate EnumeratedInputs using the file extensions - // and the resources in the project - // Note: This is only correct for tools with - // multipleOfType == true, but for other tools - // it gives us an input resource for generating default - // names - // Determine the set of source input macros to use - HashSet handledInputExtensions = new HashSet<>(); - String[] exts = type.getSourceExtensions(this.tool); - if (projResources != null) { - for (IResource rc : projResources) { - if (rc.getType() == IResource.FILE) { - String fileExt = rc.getFileExtension(); - - // fix for NPE, bugzilla 99483 - if (fileExt == null) { - fileExt = ""; //$NON-NLS-1$ - } - - for (int k = 0; k < exts.length; k++) { - if (fileExt.equals(exts[k])) { - if (!useFileExts) { - if (!handledInputExtensions.contains(fileExt)) { - handledInputExtensions.add(fileExt); - String buildMacro = "$(" //$NON-NLS-1$ - + getSourceMacroName(fileExt).toString() + ")"; //$NON-NLS-1$ - itCommandInputs.add(buildMacro); - if (primaryInput) { - itCommandDependencies.add(0, buildMacro); - } else { - itCommandDependencies.add(buildMacro); - } - } - } - if (type.getMultipleOfType() || itEnumeratedInputs.size() == 0) { - // Add a path that is relative - // to the project directory - itEnumeratedInputs.add(rc.getProjectRelativePath().toOSString()); - } - break; - } - } - } - } - } - // } - } - } - - // Get any additional inputs specified in the manifest file or - // the project file - IAdditionalInput[] addlInputs = type.getAdditionalInputs(); - if (addlInputs != null) { - for (int j = 0; j < addlInputs.length; j++) { - IAdditionalInput addlInput = addlInputs[j]; - int kind = addlInput.getKind(); - if (kind == IAdditionalInput.KIND_ADDITIONAL_INPUT - || kind == IAdditionalInput.KIND_ADDITIONAL_INPUT_DEPENDENCY) { - String[] paths = addlInput.getPaths(); - if (paths != null) { - for (int k = 0; k < paths.length; k++) { - String path = paths[k]; - itEnumeratedInputs.add(path); - // Translate the path from project relative - // to build directory relative - if (!(path.startsWith("$("))) { //$NON-NLS-1$ - IResource addlResource = this.project.getFile(path); - if (addlResource != null) { - IPath addlPath = addlResource.getLocation(); - if (addlPath != null) { - path = ManagedBuildManager.calculateRelativePath( - makeGen.getTopBuildDir().getFullPath(), addlPath).toOSString(); - } - } - } - itCommandInputs.add(path); - } - } - } - } - } - - // If the assignToOption attribute is specified, set the - // input(s) as the value of that option - if (assignToOption != null && option == null) { - try { - int optType = assignToOption.getValueType(); - if (optType == IOption.STRING) { - String optVal = ""; //$NON-NLS-1$ - for (int j = 0; j < itCommandInputs.size(); j++) { - if (j != 0) { - optVal += " "; //$NON-NLS-1$ - } - optVal += itCommandInputs.get(j); - } - ManagedBuildManager.setOption(config, this.tool, assignToOption, optVal); - } else if (optType == IOption.STRING_LIST || optType == IOption.LIBRARIES - || optType == IOption.OBJECTS || optType == IOption.INCLUDE_FILES - || optType == IOption.LIBRARY_PATHS || optType == IOption.LIBRARY_FILES - || optType == IOption.MACRO_FILES) { - // TODO: do we need to do anything with undefs here? - // Mote that when using the enumerated inputs, the - // path(s) must be translated from project relative - // to top build directory relative - String[] paths = new String[itEnumeratedInputs.size()]; - for (int j = 0; j < itEnumeratedInputs.size(); j++) { - paths[j] = itEnumeratedInputs.get(j); - IResource enumResource = this.project.getFile(paths[j]); - if (enumResource != null) { - IPath enumPath = enumResource.getLocation(); - if (enumPath != null) { - paths[j] = ManagedBuildManager - .calculateRelativePath(makeGen.getTopBuildDir().getFullPath(), enumPath) - .toOSString(); - } - } - } - ManagedBuildManager.setOption(config, this.tool, assignToOption, paths); - } else if (optType == IOption.BOOLEAN) { - if (itEnumeratedInputs.size() > 0) { - ManagedBuildManager.setOption(config, this.tool, assignToOption, true); - } else { - ManagedBuildManager.setOption(config, this.tool, assignToOption, false); - } - } else if (optType == IOption.ENUMERATED || optType == IOption.TREE) { - if (itCommandInputs.size() > 0) { - ManagedBuildManager.setOption(config, this.tool, assignToOption, - itCommandInputs.firstElement()); - } - } - itCommandInputs.removeAllElements(); - // itEnumeratedInputs.removeAllElements(); - } catch (BuildException ex) {// JABA is not going to add - // code - } - } - - myCommandInputs.addAll(itCommandInputs); - myCommandDependencies.addAll(itCommandDependencies); - myEnumeratedInputs.addAll(itEnumeratedInputs); - } - } else { - // For support of pre-CDT 3.0 integrations. - if (this.bIsTargetTool) { - // NOTE WELL: This only supports the case of a single - // "target tool" - // with the following characteristics: - // 1. The tool consumes exactly all of the object files produced - // by other tools in the build and produces a single output - // 2. The target name comes from the configuration artifact name - // The rule looks like: - // .: $(OBJS) - myCommandInputs.add("$(OBJS)"); //$NON-NLS-1$ - myCommandInputs.add("$(USER_OBJS)"); //$NON-NLS-1$ - myCommandInputs.add("$(LIBS)"); //$NON-NLS-1$ - } else { - // Rule will be generated by addRuleForSource - } - } - - if (done) { - this.commandInputs.addAll(myCommandInputs); - this.commandDependencies.addAll(0, myCommandDependencies); - this.enumeratedInputs.addAll(myEnumeratedInputs); - this.inputsCalculated = true; - return true; - } - - return false; - } - - /* - * The priorities for determining the names of the outputs of a tool are: 1. - * If the tool is the build target and primary output, use artifact name & - * extension 2. If an option is specified, use the value of the option 3. If - * a nameProvider is specified, call it 4. If outputNames is specified, use - * it 5. Use the name pattern to generate a transformation macro so that the - * source names can be transformed into the target names using the built-in - * string substitution functions of make. - * - * NOTE: If an option is not specified and this is not the primary output - * type, the outputs from the type are not added to the command line - */ - // public boolean calculateOutputs(ArduinoGnuMakefileGenerator makeGen, IConfiguration config, - // HashSet handledInputExtensions, boolean lastChance) { - // - // boolean done = true; - // List myCommandOutputs = new LinkedList<>(); - // List myEnumeratedOutputs = new LinkedList<>(); - // HashMap> myOutputMacros = new HashMap<>(); - // // The next two fields are used together - // Map> myBuildVars = new HashMap<>(); - // //List> myBuildVarsValues = new LinkedList<>(); - // - // // Get the outputs for this tool invocation - // IOutputType[] outTypes = this.tool.getOutputTypes(); - // if (outTypes != null && outTypes.length > 0) { - // for (int i = 0; i < outTypes.length; i++) { - // List typeEnumeratedOutputs = new LinkedList<>(); - // IOutputType type = outTypes[i]; - // String outputPrefix = type.getOutputPrefix(); - // - // // Resolve any macros in the outputPrefix - // // Note that we cannot use file macros because if we do a clean - // // we need to know the actual name of the file to clean, and - // // cannot use any builder variables such as $@. Hence we use the - // // next best thing, i.e. configuration context. - // - // if (config != null) { - // - // try { - // outputPrefix = ManagedBuildManager.getBuildMacroProvider().resolveValueToMakefileFormat( - // outputPrefix, "", //$NON-NLS-1$ - // " ", //$NON-NLS-1$ - // IBuildMacroProvider.CONTEXT_CONFIGURATION, config); - // } - // - // catch (BuildMacroException e) {// JABA is not going to add - // // code - // } - // } - // - // String variable = type.getBuildVariable(); - // boolean multOfType = type.getMultipleOfType(); - // IOption option = this.tool.getOptionBySuperClassId(type.getOptionId()); - // IManagedOutputNameProviderJaba nameProvider = getJABANameProvider(type); - // String[] outputNames = type.getOutputNames(); - // - // // 1. If the tool is the build target and this is the primary - // // output, - // // use artifact name & extension - // if (this.bIsTargetTool) { - // String outputName = outputPrefix + this.targetName; - // if (this.targetExt.length() > 0) { - // outputName += (DOT + this.targetExt); - // } - // myCommandOutputs.add(outputName); - // typeEnumeratedOutputs.add(outputName); - // // But this doesn't use any output macro... - // } else - // // 2. If an option is specified, use the value of the option - // if (option != null) { - // try { - // List outputs = new ArrayList<>(); - // int optType = option.getValueType(); - // if (optType == IOption.STRING) { - // outputs.add(outputPrefix + option.getStringValue()); - // } else if (optType == IOption.STRING_LIST || optType == IOption.LIBRARIES - // || optType == IOption.OBJECTS || optType == IOption.INCLUDE_FILES - // || optType == IOption.LIBRARY_PATHS || optType == IOption.LIBRARY_FILES - // || optType == IOption.MACRO_FILES) { - // @SuppressWarnings("unchecked") - // List value = (List) option.getValue(); - // outputs = value; - // this.tool.filterValues(optType, outputs); - // // Add outputPrefix to each if necessary - // if (outputPrefix.length() > 0) { - // for (int j = 0; j < outputs.size(); j++) { - // outputs.set(j, outputPrefix + outputs.get(j)); - // } - // } - // } - // for (int j = 0; j < outputs.size(); j++) { - // String outputName = outputs.get(j); - // try { - // // try to resolve the build macros in the output - // // names - // String resolved = ManagedBuildManager.getBuildMacroProvider() - // .resolveValueToMakefileFormat(outputName, "", //$NON-NLS-1$ - // " ", //$NON-NLS-1$ - // IBuildMacroProvider.CONTEXT_OPTION, - // new OptionContextData(option, this.tool)); - // if ((resolved = resolved.trim()).length() > 0) - // outputs.set(j, resolved); - // } catch (BuildMacroException e) {// JABA is not - // // going to add - // // code - // } - // } - // - // // NO - myCommandOutputs.addAll(outputs); - // typeEnumeratedOutputs.addAll(outputs); - // if (variable.length() > 0) { - // List outputPaths = new ArrayList<>(); - // for (int j = 0; j < outputs.size(); j++) { - // outputPaths.add(Path.fromOSString(outputs.get(j))); - // } - // if (myOutputMacros.containsKey(variable)) { - // List currList = myOutputMacros.get(variable); - // currList.addAll(outputPaths); - // myOutputMacros.put(variable, currList); - // } else { - // myOutputMacros.put(variable, outputPaths); - // } - // } - // } catch (BuildException ex) {// JABA is not going to add - // // code - // } - // } else - // // 3. If a nameProvider is specified, call it - // if (nameProvider != null) { - // // The inputs must have been calculated before we can do - // // this - // List outNames = new LinkedList<>(); - // if (!this.inputsCalculated) { - // done = false; - // } else { - // for (String curInput : getEnumeratedInputs()) { - // outNames.add(nameProvider.getOutputName(project, config, tool, new Path(curInput))); - // } - // typeEnumeratedOutputs.addAll(resolvePaths(outNames, config)); - // } - // if (variable.length() > 0 && outNames != null) { - // if (myOutputMacros.containsKey(variable)) { - // List currList = myOutputMacros.get(variable); - // currList.addAll(outNames); - // myOutputMacros.put(variable, currList); - // } else { - // myOutputMacros.put(variable, outNames); - // } - // } - // } else - // // 4. If outputNames is specified, use it - // if (outputNames != null) { - // if (outputNames.length > 0) { - // for (int j = 0; j < outputNames.length; j++) { - // String outputName = outputNames[j]; - // try { - // // try to resolve the build macros in the output - // // names - // String resolved = ManagedBuildManager.getBuildMacroProvider() - // .resolveValueToMakefileFormat(outputName, "", //$NON-NLS-1$ - // " ", //$NON-NLS-1$ - // IBuildMacroProvider.CONTEXT_OPTION, - // new OptionContextData(option, this.tool)); - // if ((resolved = resolved.trim()).length() > 0) - // outputNames[j] = resolved; - // } catch (BuildMacroException e) {// JABA is not - // // going to add - // // code - // } - // } - // List namesList = Arrays.asList(outputNames); - // typeEnumeratedOutputs.addAll(namesList); - // if (variable.length() > 0) { - // List outputPaths = new ArrayList<>(); - // for (int j = 0; j < namesList.size(); j++) { - // outputPaths.add(Path.fromOSString(namesList.get(j))); - // } - // if (myOutputMacros.containsKey(variable)) { - // List currList = myOutputMacros.get(variable); - // currList.addAll(outputPaths); - // myOutputMacros.put(variable, currList); - // } else { - // myOutputMacros.put(variable, outputPaths); - // } - // } - // } - // } else { - // // 5. Use the name pattern to generate a transformation - // // macro - // // so that the source names can be transformed into the - // // target names - // // using the built-in string substitution functions of - // // make. - // if (multOfType) { - // // This case is not handled - a nameProvider or - // // outputNames must be specified - // List errList = new ArrayList<>(); - // errList.add(ManagedMakeMessages.getResourceString("MakefileGenerator.error.no.nameprovider")); //$NON-NLS-1$ - // myCommandOutputs.addAll(errList); - // } else { - // String namePattern = type.getNamePattern(); - // if (namePattern == null || namePattern.length() == 0) { - // namePattern = outputPrefix + IManagedBuilderMakefileGenerator.WILDCARD; - // String outExt = (type.getOutputExtensions(this.tool))[0]; - // if (outExt != null && outExt.length() > 0) { - // namePattern += DOT + outExt; - // } - // } else if (outputPrefix.length() > 0) { - // namePattern = outputPrefix + namePattern; - // } - // - // // Calculate the output name - // // The inputs must have been calculated before we can do - // // this - // if (!this.inputsCalculated) { - // done = false; - // } else { - // Vector inputs = getEnumeratedInputs(); - // String fileName; - // if (inputs.size() > 0) { - // // Get the input file name - // fileName = (Path.fromOSString(inputs.get(0))).removeFileExtension().lastSegment(); - // // Check if this is a build macro. If so, use - // // the raw macro name. - // if (fileName.startsWith("$(") && fileName.endsWith(")")) { //$NON-NLS-1$ //$NON-NLS-2$ - // fileName = fileName.substring(2, fileName.length() - 1); - // } - // } else { - // fileName = "default"; //$NON-NLS-1$ - // } - // // Replace the % with the file name - // typeEnumeratedOutputs.add(namePattern.replace("%", fileName)); //$NON-NLS-1$ - // if (variable.length() > 0) { - // List outputs = new ArrayList<>(); - // outputs.add(Path.fromOSString(fileName)); - // if (myOutputMacros.containsKey(variable)) { - // List currList = myOutputMacros.get(variable); - // currList.addAll(outputs); - // myOutputMacros.put(variable, currList); - // } else { - // myOutputMacros.put(variable, outputs); - // } - // } - // } - // } - // } - // if (variable.length() > 0) { - // myBuildVars.put(variable, typeEnumeratedOutputs); - // } - // myEnumeratedOutputs.addAll(typeEnumeratedOutputs); - // } - // } else - // - // { - // if (this.bIsTargetTool) { - // String outputPrefix = this.tool.getOutputPrefix(); - // String outputName = outputPrefix + this.targetName; - // if (this.targetExt.length() > 0) { - // outputName += (DOT + this.targetExt); - // } - // myCommandOutputs.add(outputName); - // myEnumeratedOutputs.add(outputName); - // } else { - // // For support of pre-CDT 3.0 integrations. - // // NOTE WELL: This only supports the case of a single - // // "target tool" - // // that consumes exactly all of the object files, $OBJS, - // // produced - // // by other tools in the build and produces a single output - // } - // } - // - // // Add the output macros of this tool to the buildOutVars map - // Set>> entrySet = myOutputMacros.entrySet(); - // for (Entry> entry : entrySet) { - // String macroName = entry.getKey(); - // List newMacroValue = entry.getValue(); - // Map> map = makeGen.getBuildOutputVars(); - // if (map.containsKey(macroName)) { - // List macroValue = map.get(macroName); - // macroValue.addAll(newMacroValue); - // map.put(macroName, macroValue); - // } else { - // map.put(macroName, newMacroValue); - // } - // } - // this.outputVariablesCalculated = true; - // - // if (done) { - // this.commandOutputs.addAll(myCommandOutputs); - // this.enumeratedPrimaryOutputs.addAll(myEnumeratedOutputs); - // this.enumeratedSecondaryOutputs.addAll(myEnumeratedOutputs); - // this.outputVariables.addAll(myOutputMacros.keySet()); - // this.outputsCalculated = true; - // for (Entry> curVar : myBuildVars.entrySet()) { - // makeGen.addMacroAdditionFiles(makeGen.getTopBuildOutputVars(), curVar.getKey(), curVar.getValue()); - // } - // return true; - // } - // - // return false; - // } - - private boolean callDependencyCalculator(ArduinoGnuMakefileGenerator makeGen, IConfiguration config, - HashSet handledInputExtensions, IManagedDependencyGeneratorType depGen, String[] extensionsList, - Vector myCommandDependencies, HashMap> myOutputMacros, - Vector myAdditionalTargets, ToolInfoHolder h, boolean _done) { - boolean done = _done; - int calcType = depGen.getCalculatorType(); - switch (calcType) { - case IManagedDependencyGeneratorType.TYPE_COMMAND: - case IManagedDependencyGeneratorType.TYPE_BUILD_COMMANDS: - // iterate over all extensions that the tool knows how to handle - for (int i = 0; i < extensionsList.length; i++) { - String extensionName = extensionsList[i]; - - // Generated files should not appear in the list. - if (!makeGen.getOutputExtensions(h).contains(extensionName) - && !handledInputExtensions.contains(extensionName)) { - handledInputExtensions.add(extensionName); - String depExt = IManagedBuilderMakefileGenerator.DEP_EXT; - if (calcType == IManagedDependencyGeneratorType.TYPE_BUILD_COMMANDS) { - IManagedDependencyGenerator2 depGen2 = (IManagedDependencyGenerator2) depGen; - String xt = depGen2.getDependencyFileExtension(config, this.tool); - if (xt != null && xt.length() > 0) - depExt = xt; - } - String depsMacroEntry = calculateSourceMacro(makeGen, extensionName, depExt, - IManagedBuilderMakefileGenerator.WILDCARD); - - List depsList = new ArrayList<>(); - depsList.add(Path.fromOSString(depsMacroEntry)); - String depsMacro = getDepMacroName(extensionName).toString(); - if (myOutputMacros.containsKey(depsMacro)) { - List currList = myOutputMacros.get(depsMacro); - currList.addAll(depsList); - myOutputMacros.put(depsMacro, currList); - } else { - myOutputMacros.put(depsMacro, depsList); - } - } - } - break; - - case IManagedDependencyGeneratorType.TYPE_INDEXER: - case IManagedDependencyGeneratorType.TYPE_EXTERNAL: - case IManagedDependencyGeneratorType.TYPE_CUSTOM: - // The inputs must have been calculated before we can do this - if (!this.inputsCalculated) { - done = false; - } else { - Vector inputs = getEnumeratedInputs(); - - if (calcType == IManagedDependencyGeneratorType.TYPE_CUSTOM) { - IManagedDependencyGenerator2 depGen2 = (IManagedDependencyGenerator2) depGen; - IManagedDependencyInfo depInfo = null; - for (int i = 0; i < inputs.size(); i++) { - - depInfo = depGen2.getDependencySourceInfo(Path.fromOSString(inputs.get(i)), config, this.tool, - makeGen.getBuildWorkingDir()); - - if (depInfo instanceof IManagedDependencyCalculator) { - IManagedDependencyCalculator depCalc = (IManagedDependencyCalculator) depInfo; - IPath[] depPaths = depCalc.getDependencies(); - if (depPaths != null) { - for (int j = 0; j < depPaths.length; j++) { - if (!depPaths[j].isAbsolute()) { - // Convert from project relative to - // build directory relative - IPath absolutePath = this.project.getLocation().append(depPaths[j]); - depPaths[j] = ManagedBuildManager.calculateRelativePath( - makeGen.getTopBuildDir().getFullPath(), absolutePath); - } - myCommandDependencies.add(depPaths[j].toOSString()); - } - } - IPath[] targetPaths = depCalc.getAdditionalTargets(); - if (targetPaths != null) { - for (int j = 0; j < targetPaths.length; j++) { - myAdditionalTargets.add(targetPaths[j].toOSString()); - } - } - } - } - } else { - IManagedDependencyGenerator oldDepGen = (IManagedDependencyGenerator) depGen; - for (String input : inputs) { - IResource[] outNames = oldDepGen.findDependencies(this.project.getFile(input), this.project); - if (outNames != null) { - for (IResource outName : outNames) { - myCommandDependencies.add(outName.toString()); - } - } - } - } - } - break; - - default: - break; - } - - return done; - } - - // /** - // * @param lastChance - // */ - // public boolean calculateDependencies(ArduinoGnuMakefileGenerator makeGen, IConfiguration config, - // HashSet handledInputExtensions, ToolInfoHolder h, boolean lastChance) { - // // Get the dependencies for this tool invocation - // boolean done = true; - // Vector myCommandDependencies = new Vector<>(); - // Vector myAdditionalTargets = new Vector<>(); - // // Vector myEnumeratedDependencies = new Vector(); - // HashMap> myOutputMacros = new HashMap<>(); - // - // IInputType[] inTypes = this.tool.getInputTypes(); - // if (inTypes != null && inTypes.length > 0) { - // for (int i = 0; i < inTypes.length; i++) { - // IInputType type = inTypes[i]; - // - // // Handle dependencies from the dependencyCalculator - // IManagedDependencyGeneratorType depGen = type.getDependencyGenerator(); - // String[] extensionsList = type.getSourceExtensions(this.tool); - // if (depGen != null) { - // done = callDependencyCalculator(makeGen, config, handledInputExtensions, depGen, extensionsList, - // myCommandDependencies, myOutputMacros, myAdditionalTargets, h, done); - // } - // - // // Add additional dependencies specified in AdditionalInput - // // elements - // IAdditionalInput[] addlInputs = type.getAdditionalInputs(); - // if (addlInputs != null && addlInputs.length > 0) { - // for (int j = 0; j < addlInputs.length; j++) { - // IAdditionalInput addlInput = addlInputs[j]; - // int kind = addlInput.getKind(); - // if (kind == IAdditionalInput.KIND_ADDITIONAL_DEPENDENCY - // || kind == IAdditionalInput.KIND_ADDITIONAL_INPUT_DEPENDENCY) { - // String[] paths = addlInput.getPaths(); - // if (paths != null) { - // for (int k = 0; k < paths.length; k++) { - // // Translate the path from project relative - // // to - // // build directory relative - // String path = paths[k]; - // if (!(path.startsWith("$("))) { //$NON-NLS-1$ - // IResource addlResource = this.project.getFile(path); - // if (addlResource != null) { - // IPath addlPath = addlResource.getLocation(); - // if (addlPath != null) { - // path = ManagedBuildManager.calculateRelativePath( - // makeGen.getTopBuildDir().getFullPath(), addlPath).toOSString(); - // } - // } - // } - // myCommandDependencies.add(path); - // // myEnumeratedInputs.add(path); - // } - // } - // } - // } - // } - // } - // } else { - // if (this.bIsTargetTool) { - // // For support of pre-CDT 3.0 integrations. - // // NOTE WELL: This only supports the case of a single - // // "target tool" - // // with the following characteristics: - // // 1. The tool consumes exactly all of the object files produced - // // by other tools in the build and produces a single output - // // 2. The target name comes from the configuration artifact name - // // The rule looks like: - // // .: $(OBJS) - // myCommandDependencies.add("$(OBJS)"); //$NON-NLS-1$ - // myCommandDependencies.add("$(USER_OBJS)"); //$NON-NLS-1$ - // } else { - // // Handle dependencies from the dependencyCalculator - // IManagedDependencyGeneratorType depGen = this.tool.getDependencyGenerator(); - // String[] extensionsList = this.tool.getAllInputExtensions(); - // if (depGen != null) { - // done = callDependencyCalculator(makeGen, config, handledInputExtensions, depGen, extensionsList, - // myCommandDependencies, myOutputMacros, myAdditionalTargets, h, done); - // } - // - // } - // } - // - // // Add the output macros of this tool to the buildOutVars map - // Set>> entrySet = myOutputMacros.entrySet(); - // for (Entry> entry : entrySet) { - // String macroName = entry.getKey(); - // List newMacroValue = entry.getValue(); - // Map> map = makeGen.getBuildOutputVars(); - // if (map.containsKey(macroName)) { - // List macroValue = map.get(macroName); - // macroValue.addAll(newMacroValue); - // map.put(macroName, macroValue); - // } else { - // map.put(macroName, newMacroValue); - // } - // } - // - // if (done) { - // this.commandDependencies.addAll(myCommandDependencies); - // this.additionalTargets.addAll(myAdditionalTargets); - // // enumeratedDependencies.addAll(myEnumeratedDependencies); - // this.dependenciesCalculated = true; - // return true; - // } - // - // return false; - // } - - /* - Calculate the - source macro for - the given extension*/ - - protected String calculateSourceMacro(ArduinoGnuMakefileGenerator makeGen, String srcExtensionName, - String outExtensionName, String wildcard) { - StringBuffer macroName = getSourceMacroName(srcExtensionName); - String OptDotExt = ""; //$NON-NLS-1$ - if (outExtensionName != null) { - OptDotExt = DOT + outExtensionName; - } else if (this.tool.getOutputExtension(srcExtensionName) != "") //$NON-NLS-1$ - OptDotExt = DOT + this.tool.getOutputExtension(srcExtensionName); - - // create rule of the form - // OBJS = $(macroName1: ../%.input1=%.output1) ... $(macroNameN: - // ../%.inputN=%.outputN) - StringBuffer objectsBuffer = new StringBuffer(); - objectsBuffer.append(IManagedBuilderMakefileGenerator.WHITESPACE + "$(" + macroName + //$NON-NLS-1$ - IManagedBuilderMakefileGenerator.COLON + IManagedBuilderMakefileGenerator.ROOT - + IManagedBuilderMakefileGenerator.SEPARATOR + IManagedBuilderMakefileGenerator.WILDCARD + DOT - + srcExtensionName + "=" + wildcard + OptDotExt + ")"); //$NON-NLS-1$ //$NON-NLS-2$ - return objectsBuffer.toString(); - } - - private void resolveStrings(List toResolve, IConfiguration config) { - if (toResolve.isEmpty()) - return; - for (String curOutput : toResolve) { - try { - // try to resolve the build macros in the - // output names - String resolved = ManagedBuildManager.getBuildMacroProvider().resolveValueToMakefileFormat(curOutput, - "", //$NON-NLS-1$ - " ", //$NON-NLS-1$ - IBuildMacroProvider.CONTEXT_CONFIGURATION, config); - if ((resolved = resolved.trim()).length() > 0) { - toResolve.remove(curOutput); - toResolve.add(resolved); - } - } catch (BuildMacroException e) { - //If we can not resolve we keep the original - } - } - } - -} \ No newline at end of file diff --git a/io.sloeber.core/src/io/sloeber/managedBuild/Internal/MakeRule.java b/io.sloeber.core/src/io/sloeber/managedBuild/Internal/MakeRule.java index 8f276114a..55520dfaf 100644 --- a/io.sloeber.core/src/io/sloeber/managedBuild/Internal/MakeRule.java +++ b/io.sloeber.core/src/io/sloeber/managedBuild/Internal/MakeRule.java @@ -7,8 +7,6 @@ import java.util.HashSet; import java.util.LinkedHashMap; import java.util.LinkedHashSet; -import java.util.LinkedList; -import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; @@ -37,46 +35,52 @@ public class MakeRule { - private Map> myTargets = new LinkedHashMap<>(); //Macro file target map - private Map> myPrerequisites = new LinkedHashMap<>();//Macro file prerequisites map - private Map> myDependencies = new LinkedHashMap<>(); //Macro file target map + private Map> myTargets = new LinkedHashMap<>(); //Macro file target map + private Map> myPrerequisites = new LinkedHashMap<>();//Macro file prerequisites map + private Map> myDependencies = new LinkedHashMap<>(); //Macro file target map private ITool myTool = null; - //TOFIX get rid of caller argument - public MakeRule(ArduinoGnuMakefileGenerator caller, ITool tool, IInputType inputType, IFile inputFile, - IOutputType outputType, IFile outFile) { + public MakeRule(ITool tool, IInputType inputType, IFile inputFile, IOutputType outputType, IFile outFile) { addPrerequisite(inputType, inputFile); addTarget(outputType, outFile); myTool = tool; - calculateDependencies(caller); } - private void calculateDependencies(ArduinoGnuMakefileGenerator caller) { - myDependencies.clear(); - //TOFIX the stuff below should be calculated - boolean toolGeneratesDependencyFiles = true; - if (!toolGeneratesDependencyFiles) { - return; + public MakeRule(ITool tool, IInputType inputType, Set inputFiles, IOutputType outputType, IFile outFile) { + for (IFile inputFile : inputFiles) { + addPrerequisite(inputType, inputFile); } + addTarget(outputType, outFile); + myTool = tool; + } - for (Entry> curprerequisite : myPrerequisites.entrySet()) { + public MakeRule(ArduinoGnuMakefileGenerator caller, ITool tool, IInputType inputType, Set inputFiles, + IOutputType outputType, IFile outFile) { + for (IFile inputFile : inputFiles) { + addPrerequisite(inputType, inputFile); + } + addTarget(outputType, outFile); + myTool = tool; + } + + public void addDependencies(ArduinoGnuMakefileGenerator caller) { + myDependencies.clear(); + + for (Entry> curprerequisite : myPrerequisites.entrySet()) { IInputType curInputType = curprerequisite.getKey(); IManagedDependencyGeneratorType t = curInputType.getDependencyGenerator(); if (t == null) { continue; } - List files = curprerequisite.getValue(); - String depkey = curInputType.getBuildVariable() + "_DEPS"; + Set files = curprerequisite.getValue(); + String depkey = curInputType.getBuildVariable() + DEPENDENCY_SUFFIX; for (IFile file : files) { - IResourceInfo rcInfo = caller.getConfig().getResourceInfo(file.getFullPath(), false); - int calcType = t.getCalculatorType(); + IBuildObject buildContext = caller.getConfig().getResourceInfo(file.getFullPath(), false); IManagedDependencyGenerator2 depGen = (IManagedDependencyGenerator2) t; - IBuildObject buildContext = rcInfo; IManagedDependencyInfo depInfo = depGen.getDependencySourceInfo(file.getProjectRelativePath(), file, buildContext, myTool, caller.getBuildWorkingDir()); - // if (calcType== IManagedDependencyGeneratorType.TYPE_CUSTOM) { if (depInfo instanceof IManagedDependencyCalculator) { IManagedDependencyCalculator depCalculator = (IManagedDependencyCalculator) depInfo; IPath[] addlDeps = calculateDependenciesForSource(caller, depCalculator); @@ -86,7 +90,7 @@ private void calculateDependencies(ArduinoGnuMakefileGenerator caller) { if (depInfo instanceof IManagedDependencyCommands) { IManagedDependencyCommands tmp = (IManagedDependencyCommands) depInfo; IPath[] addlTargets = tmp.getDependencyFiles(); - List depFiles = new LinkedList<>(); + Set depFiles = new HashSet<>(); for (IPath curPath : addlTargets) { depFiles.add(caller.getProject().getFile(caller.getBuildWorkingDir().append(curPath))); } @@ -119,17 +123,21 @@ private IPath[] calculateDependenciesForSource(ArduinoGnuMakefileGenerator calle return addlDeps; } - public HashSet getPrerequisites() { + public Set getPrerequisiteFiles() { HashSet ret = new HashSet<>(); - for (List cur : myPrerequisites.values()) { + for (Set cur : myPrerequisites.values()) { ret.addAll(cur); } return ret; } + public Map> getPrerequisites() { + return myPrerequisites; + } + public Set getTargetFiles() { Set ret = new HashSet<>(); - for (List cur : myTargets.values()) { + for (Set cur : myTargets.values()) { ret.addAll(cur); } return ret; @@ -137,13 +145,13 @@ public Set getTargetFiles() { public Set getDependencyFiles() { Set ret = new HashSet<>(); - for (List cur : myDependencies.values()) { + for (Set cur : myDependencies.values()) { ret.addAll(cur); } return ret; } - public Map> getTargets() { + public Map> getTargets() { return myTargets; } @@ -181,17 +189,17 @@ public Set getDependecyMacros() { public HashSet getMacroElements(String macroName) { HashSet ret = new HashSet<>(); - for (Entry> cur : myTargets.entrySet()) { + for (Entry> cur : myTargets.entrySet()) { if (macroName.equals(cur.getKey().getBuildVariable())) { ret.addAll(cur.getValue()); } } - for (Entry> cur : myPrerequisites.entrySet()) { + for (Entry> cur : myPrerequisites.entrySet()) { if (macroName.equals(cur.getKey().getBuildVariable())) { ret.addAll(cur.getValue()); } } - List tmp = myDependencies.get(macroName); + Set tmp = myDependencies.get(macroName); if (tmp != null) { ret.addAll(tmp); } @@ -199,9 +207,9 @@ public HashSet getMacroElements(String macroName) { } private void addTarget(IOutputType outputType, IFile file) { - List files = myTargets.get(outputType); + Set files = myTargets.get(outputType); if (files == null) { - files = new LinkedList<>(); + files = new HashSet<>(); files.add(file); myTargets.put(outputType, files); } else { @@ -210,9 +218,9 @@ private void addTarget(IOutputType outputType, IFile file) { } private void addPrerequisite(IInputType inputType, IFile file) { - List files = myPrerequisites.get(inputType); + Set files = myPrerequisites.get(inputType); if (files == null) { - files = new LinkedList<>(); + files = new HashSet<>(); files.add(file); myPrerequisites.put(inputType, files); } else { @@ -222,7 +230,7 @@ private void addPrerequisite(IInputType inputType, IFile file) { private String enumTargets(IFile buildFolder) { String ret = new String(); - for (List curFiles : myTargets.values()) { + for (Set curFiles : myTargets.values()) { for (IFile curFile : curFiles) { ret = ret + GetNiceFileName(buildFolder, curFile) + WHITESPACE; } @@ -232,7 +240,7 @@ private String enumTargets(IFile buildFolder) { private String enumPrerequisites(IFile buildFolder) { String ret = new String(); - for (List curFiles : myPrerequisites.values()) { + for (Set curFiles : myPrerequisites.values()) { for (IFile curFile : curFiles) { ret = ret + GetNiceFileName(buildFolder, curFile) + WHITESPACE; } @@ -246,7 +254,7 @@ public StringBuffer getRule(IProject project, IFile niceBuildFolder, IConfigurat //For now assume 1 target with 1 or more prerequisites // if there is more than 1 prerequisite we take the flags of the first prerequisite only Set local_targets = getTargetFiles(); - Set local_prerequisites = getPrerequisites(); + Set local_prerequisites = getPrerequisiteFiles(); if (local_targets.size() != 1) { System.err.println("Only 1 target per build rule is supported in this managed build"); //$NON-NLS-1$ return new StringBuffer(); @@ -401,121 +409,6 @@ private String expandCommandLinePattern(IConfiguration config, String sourceExte getToolCommandLinePattern(config, myTool)); } - // /** - // * Returns any additional resources specified for the tool in other InputType - // * elements and AdditionalInput elements - // */ - // private IPath[] getAdditionalResourcesForSource(ITool tool) { - // IProject project = getProject(); - // List allRes = new ArrayList<>(); - // IInputType[] types = tool.getInputTypes(); - // for (IInputType type : types) { - // // Additional resources come from 2 places. - // // 1. From AdditionalInput childen - // IPath[] res = type.getAdditionalResources(); - // for (IPath re : res) { - // allRes.add(re); - // } - // // 2. From InputTypes that other than the primary input type - // if (!type.getPrimaryInput() && type != tool.getPrimaryInputType()) { - // String var = type.getBuildVariable(); - // if (var != null && var.length() > 0) { - // allRes.add(Path.fromOSString("$(" + type.getBuildVariable() + ")")); - // } else { - // // Use file extensions - // String[] typeExts = type.getSourceExtensions(tool); - // for (IResource projectResource : caller.projectResources) { - // if (projectResource.getType() == IResource.FILE) { - // String fileExt = projectResource.getFileExtension(); - // if (fileExt == null) { - // fileExt = ""; - // } - // for (String typeExt : typeExts) { - // if (fileExt.equals(typeExt)) { - // allRes.add(projectResource.getProjectRelativePath()); - // break; - // } - // } - // } - // } - // } - // // If an assignToOption has been specified, set the value of the - // // option to the inputs - // IOption assignToOption = tool.getOptionBySuperClassId(type.getAssignToOptionId()); - // IOption option = tool.getOptionBySuperClassId(type.getOptionId()); - // if (assignToOption != null && option == null) { - // try { - // int optType = assignToOption.getValueType(); - // IResourceInfo rcInfo = tool.getParentResourceInfo(); - // if (rcInfo != null) { - // if (optType == IOption.STRING) { - // String optVal = ""; - // for (int j = 0; j < allRes.size(); j++) { - // if (j != 0) { - // optVal += " "; - // } - // String resPath = allRes.get(j).toString(); - // if (!resPath.startsWith("$(")) { - // IResource addlResource = project.getFile(resPath); - // if (addlResource != null) { - // IPath addlPath = addlResource.getLocation(); - // if (addlPath != null) { - // resPath = ManagedBuildManager - // .calculateRelativePath(getTopBuildDir(), addlPath).toString(); - // } - // } - // } - // optVal += ManagedBuildManager - // .calculateRelativePath(getTopBuildDir(), Path.fromOSString(resPath)) - // .toString(); - // } - // ManagedBuildManager.setOption(rcInfo, tool, assignToOption, optVal); - // } else if (optType == IOption.STRING_LIST || optType == IOption.LIBRARIES - // || optType == IOption.OBJECTS || optType == IOption.INCLUDE_FILES - // || optType == IOption.LIBRARY_PATHS || optType == IOption.LIBRARY_FILES - // || optType == IOption.MACRO_FILES) { - // // TODO: do we need to do anything with undefs - // // here? - // // Note that the path(s) must be translated from - // // project relative - // // to top build directory relative - // String[] paths = new String[allRes.size()]; - // for (int j = 0; j < allRes.size(); j++) { - // paths[j] = allRes.get(j).toString(); - // if (!paths[j].startsWith("$(")) { - // IResource addlResource = project.getFile(paths[j]); - // if (addlResource != null) { - // IPath addlPath = addlResource.getLocation(); - // if (addlPath != null) { - // paths[j] = ManagedBuildManager - // .calculateRelativePath(getTopBuildDir(), addlPath).toString(); - // } - // } - // } - // } - // ManagedBuildManager.setOption(rcInfo, tool, assignToOption, paths); - // } else if (optType == IOption.BOOLEAN) { - // boolean b = false; - // if (allRes.size() > 0) - // b = true; - // ManagedBuildManager.setOption(rcInfo, tool, assignToOption, b); - // } else if (optType == IOption.ENUMERATED || optType == IOption.TREE) { - // if (allRes.size() > 0) { - // String s = allRes.get(0).toString(); - // ManagedBuildManager.setOption(rcInfo, tool, assignToOption, s); - // } - // } - // allRes.clear(); - // } - // } catch (BuildException ex) { - // /* JABA is not going to write this code */ - // } - // } - // } - // } - // return allRes.toArray(new IPath[allRes.size()]); - // } - private String expandCommandLinePattern(String commandName, Set flags, String outputFlag, String outputName, Set inputResources, String commandLinePattern) { @@ -556,4 +449,41 @@ private String expandCommandLinePattern(String commandName, Set flags, S return command; } + public void addPrerequisites(IInputType inputType, Set files) { + Set entrypoint = myPrerequisites.get(inputType); + if (entrypoint != null) { + entrypoint.addAll(files); + } else { + Set copyOfFiles = new HashSet<>(); + copyOfFiles.addAll(files); + myPrerequisites.put(inputType, copyOfFiles); + } + } + + /** + * A simple rule is a rule that takes exactly 1 input type containing exactly + * one file + * and exactly 1 output type containing exactly 1 file + * + * @return true if this rule is a simple rule + * otherwise false + */ + + public boolean isSimpleRule() { + int counter = 0; + for (Set files : myTargets.values()) { + if ((++counter > 1) || (files.size() != 1)) { + return false; + } + } + counter = 0; + for (Set files : myPrerequisites.values()) { + if ((++counter > 1) || (files.size() != 1)) { + return false; + } + } + return true; + + } + } diff --git a/io.sloeber.core/src/io/sloeber/managedBuild/Internal/MakeRules.java b/io.sloeber.core/src/io/sloeber/managedBuild/Internal/MakeRules.java new file mode 100644 index 000000000..90b705e26 --- /dev/null +++ b/io.sloeber.core/src/io/sloeber/managedBuild/Internal/MakeRules.java @@ -0,0 +1,105 @@ +package io.sloeber.managedBuild.Internal; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedHashSet; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; + +import org.eclipse.cdt.managedbuilder.core.IInputType; +import org.eclipse.cdt.managedbuilder.core.IOutputType; +import org.eclipse.cdt.managedbuilder.core.ITool; +import org.eclipse.core.resources.IFile; + +public class MakeRules { + private Set myMakeRules = new LinkedHashSet<>(); + + public void addRule(MakeRule newMakeRule) { + if (newMakeRule.isSimpleRule()) { + Map> targets = newMakeRule.getTargets(); + + IOutputType outputType = null; + IFile correctOutputPath = null; + for (Entry> curTarget : targets.entrySet()) { + outputType = curTarget.getKey(); + correctOutputPath = curTarget.getValue().toArray(new IFile[1])[0]; + } + MakeRule makerule = findTarget(outputType, correctOutputPath); + if (makerule != null) { + Map> prerequisites = newMakeRule.getPrerequisites(); + + IInputType inputType = null; + Set files = null; + + for (Entry> curTarget : prerequisites.entrySet()) { + inputType = curTarget.getKey(); + files = curTarget.getValue(); + } + newMakeRule.addPrerequisites(inputType, files); + } + } + myMakeRules.add(newMakeRule); + } + + public MakeRule findTarget(IOutputType outputType, IFile correctOutputPath) { + for (MakeRule makeRule : myMakeRules) { + for (Entry> target : makeRule.getTargets().entrySet()) { + if ((target.getKey() == outputType) && (target.getValue().contains(correctOutputPath))) { + return makeRule; + } + } + } + return null; + } + + public void addRule(ITool tool, IInputType inputType, String macroName, Set InputFiles, + IOutputType outputType, IFile correctOutputFile) { + MakeRule newMakeRule = findTarget(outputType, correctOutputFile); + if (newMakeRule == null) { + newMakeRule = new MakeRule(tool, inputType, InputFiles, outputType, correctOutputFile); + } + newMakeRule.addPrerequisites(inputType, InputFiles); + addRule(newMakeRule); + + } + + public int size() { + return myMakeRules.size(); + } + + public void addRules(MakeRules makeRules) { + for (MakeRule makeRule : makeRules.getMakeRules()) { + addRule(makeRule); + } + } + + public Map> getTargets() { + Map> ret = new HashMap<>(); + for (MakeRule makeRule : myMakeRules) { + ret.putAll(makeRule.getTargets()); + } + return ret; + } + + public Set getMacroNames() { + Set ret = new HashSet<>(); + for (MakeRule makeRule : myMakeRules) { + ret.addAll(makeRule.getAllMacros()); + } + return ret; + } + + public Set getMacroElements(String macroName) { + Set ret = new HashSet<>(); + for (MakeRule makeRule : myMakeRules) { + ret.addAll(makeRule.getMacroElements(macroName)); + } + return ret; + } + + public Set getMakeRules() { + return myMakeRules; + } + +} diff --git a/io.sloeber.core/src/io/sloeber/managedBuild/Internal/ManagebBuildCommon.java b/io.sloeber.core/src/io/sloeber/managedBuild/Internal/ManagebBuildCommon.java index 436becde9..ac757d826 100644 --- a/io.sloeber.core/src/io/sloeber/managedBuild/Internal/ManagebBuildCommon.java +++ b/io.sloeber.core/src/io/sloeber/managedBuild/Internal/ManagebBuildCommon.java @@ -605,6 +605,31 @@ static public IManagedOutputNameProviderJaba getJABANameProvider(IOutputType iTy //ignore errors } } + String[] outputNames = type.getOutputNames(); + if (outputNames != null && outputNames.length > 0) { + String outputName = outputNames[0]; + return new IManagedOutputNameProviderJaba() { + + @Override + public IPath getOutputName(IProject project, IConfiguration cConf, ITool tool, IPath inputName) { + return new Path(outputName); + //return project.getFile(cConf.getName()).getFullPath().append(outputName); + } + }; + } + + String[] outputExtensions = type.getOutputExtensionsAttribute(); + if (outputExtensions != null && outputExtensions.length > 0) { + String outputExtension = outputExtensions[0]; + return new IManagedOutputNameProviderJaba() { + + @Override + public IPath getOutputName(IProject project, IConfiguration cConf, ITool tool, IPath inputName) { + return inputName.addFileExtension(outputExtension); + } + }; + } + return null; } diff --git a/io.sloeber.core/src/io/sloeber/managedBuild/Internal/ManagedBuildConstants.java b/io.sloeber.core/src/io/sloeber/managedBuild/Internal/ManagedBuildConstants.java index a2f2bf95b..eed1cf279 100644 --- a/io.sloeber.core/src/io/sloeber/managedBuild/Internal/ManagedBuildConstants.java +++ b/io.sloeber.core/src/io/sloeber/managedBuild/Internal/ManagedBuildConstants.java @@ -94,5 +94,6 @@ public class ManagedBuildConstants { public static final String INPUTS_PRM_NAME = "INPUTS"; public static final String VARIABLE_PREFIX = "${"; public static final String VARIABLE_SUFFIX = "}"; + public static final String DEPENDENCY_SUFFIX = "_DEPS"; } diff --git a/io.sloeber.core/src/io/sloeber/managedBuild/Internal/SubDirMakeGenerator.java b/io.sloeber.core/src/io/sloeber/managedBuild/Internal/SubDirMakeGenerator.java index 1488b4bf1..9cada7ce9 100644 --- a/io.sloeber.core/src/io/sloeber/managedBuild/Internal/SubDirMakeGenerator.java +++ b/io.sloeber.core/src/io/sloeber/managedBuild/Internal/SubDirMakeGenerator.java @@ -7,15 +7,12 @@ import java.util.HashSet; import java.util.LinkedHashMap; import java.util.LinkedHashSet; -import java.util.List; import java.util.Map; import java.util.Set; import org.eclipse.cdt.managedbuilder.core.IConfiguration; -import org.eclipse.cdt.managedbuilder.core.IFileInfo; import org.eclipse.cdt.managedbuilder.core.IInputType; import org.eclipse.cdt.managedbuilder.core.IOutputType; -import org.eclipse.cdt.managedbuilder.core.IResourceInfo; import org.eclipse.cdt.managedbuilder.core.ITool; import org.eclipse.cdt.managedbuilder.internal.core.ManagedMakeMessages; import org.eclipse.core.resources.IContainer; @@ -31,12 +28,18 @@ public class SubDirMakeGenerator { private ArduinoGnuMakefileGenerator caller; private Set myMakeRules = new LinkedHashSet<>(); - private IContainer myModule; + private IFile myMakefile; SubDirMakeGenerator(ArduinoGnuMakefileGenerator theCaller, IContainer module) { caller = theCaller; - myModule = module; - getMakeRules(); + IProject project = getProject(); + IPath buildRoot = getBuildWorkingDir(); + if (buildRoot == null) { + return; + } + IPath moduleOutputPath = buildRoot.append(module.getProjectRelativePath()); + myMakefile = project.getFile(moduleOutputPath.append(MODFILE_NAME)); + getMakeRulesFromSourceFiles(module); } public Set getDependecyMacros() { @@ -63,6 +66,10 @@ public Set getTargetMacros() { return ret; } + public Set getMakeRules() { + return myMakeRules; + } + public Set getPrerequisiteMacros() { HashSet ret = new LinkedHashSet<>(); for (MakeRule curMakeRule : myMakeRules) { @@ -87,8 +94,8 @@ public Set getDependencyFiles() { return ret; } - public Map> getTargets() { - Map> ret = new LinkedHashMap<>(); + public Map> getTargets() { + Map> ret = new LinkedHashMap<>(); for (MakeRule curMakeRule : myMakeRules) { ret.putAll(curMakeRule.getTargets()); } @@ -119,22 +126,13 @@ private IProject getProject() { * generated for each project directory/subdirectory that contains source files. */ public void generateMakefile() throws CoreException { - //create the parent folder on disk and file in eclispe - IProject project = getProject(); - IPath buildRoot = getBuildWorkingDir(); - if (buildRoot == null) { - return; - } - IPath moduleOutputPath = buildRoot.append(myModule.getProjectRelativePath()); - IFile modMakefile = project.getFile(moduleOutputPath.append(MODFILE_NAME)); - //generate the file content StringBuffer makeBuf = addDefaultHeader(); makeBuf.append(GenerateMacros()); makeBuf.append(GenerateRules(getConfig())); // Save the files - save(makeBuf, modMakefile); + save(makeBuf, myMakefile); } private StringBuffer GenerateMacros() { @@ -179,85 +177,65 @@ private StringBuffer GenerateRules(IConfiguration config) { } //Get the rules for the source files - private void getMakeRules() { + private void getMakeRulesFromSourceFiles(IContainer module) { myMakeRules.clear(); IConfiguration config = getConfig(); IProject project = getProject(); // Visit the resources in this folder try { - for (IResource resource : myModule.members()) { + for (IResource resource : module.members()) { if (resource.getType() != IResource.FILE) { //only handle files continue; } IFile inputFile = (IFile) resource; + String ext = inputFile.getFileExtension(); + if (ext == null || ext.isBlank()) { + continue; + } IPath rcProjRelPath = inputFile.getProjectRelativePath(); if (!caller.isSource(rcProjRelPath)) { // this resource is excluded from build continue; } - IResourceInfo rcInfo = config.getResourceInfo(rcProjRelPath, false); - String ext = rcProjRelPath.getFileExtension(); - ITool tool = null; - //try to find tool - if (rcInfo instanceof IFileInfo) { - IFileInfo fi = (IFileInfo) rcInfo; - ITool[] tools = fi.getToolsToInvoke(); - if (tools != null && tools.length > 0) { - tool = tools[0]; - } - } - - //No tool found yet try other way - if (tool == null) { - ToolInfoHolder h = ToolInfoHolder.getToolInfo(caller, rcInfo.getPath()); - ITool buildTools[] = h.buildTools; - h = ToolInfoHolder.getToolInfo(caller, Path.EMPTY); - buildTools = h.buildTools; - for (ITool buildTool : buildTools) { - if (buildTool.buildsFileType(ext)) { - tool = buildTool; - break; + for (ITool tool : config.getTools()) { + for (IInputType inputType : tool.getInputTypes()) { + if (!inputType.isSourceExtension(tool, ext)) { + continue; + } + for (IOutputType outputType : tool.getOutputTypes()) { + IManagedOutputNameProviderJaba nameProvider = getJABANameProvider(outputType); + if (nameProvider == null) { + continue; + } + IPath outputFile = nameProvider.getOutputName(getProject(), config, tool, + resource.getProjectRelativePath()); + if (outputFile == null) { + continue; + } + //We found a tool that provides a outputfile for our source file + //TOFIX if this is a multiple to one we should only create one MakeRule + IPath correctOutputPath = new Path(config.getName()).append(outputFile); + MakeRule newMakeRule = new MakeRule(tool, inputType, inputFile, outputType, + project.getFile(correctOutputPath)); + newMakeRule.addDependencies(caller); + + myMakeRules.add(newMakeRule); } } } - //We found a tool get the other info - //TOFIX we should simply loop over all available tools - if (tool == null) { - continue; - } - - // Generate the rule to build this source file - //TOFIX check wether this tool can handle this file - IInputType inputType = tool.getPrimaryInputType(); - if (inputType == null) { - inputType = tool.getInputType(ext); - } - - for (IOutputType outputType : tool.getOutputTypes()) { - IManagedOutputNameProviderJaba nameProvider = getJABANameProvider(outputType); - if (nameProvider == null) { - continue; - } - IPath outputFile = nameProvider.getOutputName(getProject(), config, tool, - resource.getProjectRelativePath()); - if (outputFile != null) { - //We found a tool that provides a outputfile for our source file - //TOFIX if this is a multiple to one we should only create one MakeRule - IPath correctOutputPath = new Path(config.getName()).append(outputFile); - MakeRule newMakeRule = new MakeRule(caller, tool, inputType, inputFile, outputType, - project.getFile(correctOutputPath)); - - myMakeRules.add(newMakeRule); - } - } } } catch (CoreException e) { // TODO Auto-generated catch block e.printStackTrace(); } } + + public boolean isEmpty() { + return myMakeRules.size() == 0; + } + } diff --git a/io.sloeber.core/src/io/sloeber/managedBuild/Internal/ToolInfoHolder.java b/io.sloeber.core/src/io/sloeber/managedBuild/Internal/ToolInfoHolder.java deleted file mode 100644 index b41d07e2d..000000000 --- a/io.sloeber.core/src/io/sloeber/managedBuild/Internal/ToolInfoHolder.java +++ /dev/null @@ -1,44 +0,0 @@ -package io.sloeber.managedBuild.Internal; - -import java.util.List; -import java.util.Set; - -import org.eclipse.cdt.core.settings.model.util.PathSettingsContainer; -import org.eclipse.cdt.managedbuilder.core.IFileInfo; -import org.eclipse.cdt.managedbuilder.core.IResourceInfo; -import org.eclipse.cdt.managedbuilder.core.ITool; -import org.eclipse.core.runtime.IPath; - -public class ToolInfoHolder { - public ITool[] buildTools; - public boolean[] buildToolsUsed; - public ArduinoManagedBuildGnuToolInfo[] gnuToolInfos; - public Set outputExtensionsSet; - public List dependencyMakefiles; - - public static ToolInfoHolder getToolInfo(ArduinoGnuMakefileGenerator caller, IPath path) { - return getToolInfo(caller, path, false); - } - - public static ToolInfoHolder getToolInfo(ArduinoGnuMakefileGenerator caller, IPath path, boolean create) { - PathSettingsContainer child = caller.toolInfos.getChildContainer(path, create, create); - ToolInfoHolder h = null; - if (child != null) { - h = (ToolInfoHolder) child.getValue(); - if (h == null && create) { - h = new ToolInfoHolder(); - child.setValue(h); - } - } - return h; - } - - public static ToolInfoHolder getFolderToolInfo(ArduinoGnuMakefileGenerator caller, IPath path) { - IResourceInfo rcInfo = caller.config.getResourceInfo(path, false); - while (rcInfo instanceof IFileInfo) { - path = path.removeLastSegments(1); - rcInfo = caller.config.getResourceInfo(path, false); - } - return getToolInfo(caller, path, false); - } -} diff --git a/io.sloeber.core/src/io/sloeber/managedBuild/Internal/TopMakeFileGenerator.java b/io.sloeber.core/src/io/sloeber/managedBuild/Internal/TopMakeFileGenerator.java index 66ce11b82..308e2d0d5 100644 --- a/io.sloeber.core/src/io/sloeber/managedBuild/Internal/TopMakeFileGenerator.java +++ b/io.sloeber.core/src/io/sloeber/managedBuild/Internal/TopMakeFileGenerator.java @@ -7,8 +7,11 @@ import java.util.Collection; import java.util.Collections; import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedHashSet; import java.util.List; import java.util.Map; +import java.util.Map.Entry; import java.util.Set; import java.util.Vector; @@ -26,18 +29,22 @@ import org.eclipse.cdt.managedbuilder.internal.macros.FileContextData; import org.eclipse.cdt.managedbuilder.macros.BuildMacroException; import org.eclipse.cdt.managedbuilder.macros.IBuildMacroProvider; -import org.eclipse.cdt.managedbuilder.makegen.gnu.IManagedBuildGnuToolInfo; import org.eclipse.core.resources.IContainer; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IProject; import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.Path; +import io.sloeber.managedBuild.api.IManagedOutputNameProviderJaba; + public class TopMakeFileGenerator { private ArduinoGnuMakefileGenerator caller = null; - private Map> myAllSourceTargets = null; - private Set myDependencyMacros = null; - private Set myDependencyFiles = null; + private Set mySubDirMakeRules = new LinkedHashSet<>(); + private MakeRules myMakeRules = new MakeRules(); + private Collection myFoldersToBuild; + private Map> myAllSourceTargets = new HashMap<>(); + private Set myDependencyMacros = new HashSet<>(); private IConfiguration getConfig() { return caller.getConfig(); @@ -47,20 +54,44 @@ private IProject getProject() { return caller.getProject(); } - TopMakeFileGenerator(ArduinoGnuMakefileGenerator theCaller, Map> allSourceTargets, - Set dependecyMacros, Set dependencyFiles) { + TopMakeFileGenerator(ArduinoGnuMakefileGenerator theCaller, Set subDirMakeRules, + Collection foldersToBuild) { caller = theCaller; - myAllSourceTargets = allSourceTargets; - myDependencyMacros = dependecyMacros; - myDependencyFiles = dependencyFiles; - } + mySubDirMakeRules = subDirMakeRules; + myFoldersToBuild = foldersToBuild; + for (MakeRule curMakeRule : mySubDirMakeRules) { + myAllSourceTargets.putAll(curMakeRule.getTargets()); + myDependencyMacros.addAll(curMakeRule.getDependecyMacros()); + } + MakeRules makeRules = new MakeRules(); + Map> generatedFiles = new HashMap<>(); + for (MakeRule makeRule : subDirMakeRules) { + Map> targets = makeRule.getTargets(); + for (Entry> curTarget : targets.entrySet()) { + Set esxistingTarget = generatedFiles.get(curTarget.getKey()); + if (esxistingTarget != null) { + esxistingTarget.addAll(curTarget.getValue()); + } else { + Set copySet = new HashSet<>(); + copySet.addAll(curTarget.getValue()); + generatedFiles.put(curTarget.getKey(), copySet); + } + + } + } + int depth = 10; + while (depth > 0) { + makeRules = getMakeRulesFromGeneratedFiles(generatedFiles); + generatedFiles.clear(); + if (makeRules.size() > 0) { + depth--; + myMakeRules.addRules(makeRules); + generatedFiles.putAll(makeRules.getTargets()); + } else { + depth = 0; + } + } - /** - * @return Collection of subdirectories (IContainers) contributing source code - * to the build - */ - private Collection getSubdirList() { - return caller.getSubdirList(); } private Vector getRuleList() { @@ -71,30 +102,27 @@ public PathSettingsContainer getToolInfos() { return caller.getToolInfos(); } - /** - * Create the entire contents of the makefile. - * - * @param fileHandle - * The file to place the contents in. - * @param rebuild - * FLag signaling that the user is doing a full rebuild - */ - public void populateTopMakefile(IFile fileHandle, boolean rebuild) throws CoreException { + public void generateMakefile() throws CoreException { + IProject project = getProject(); + IConfiguration config = getConfig(); + StringBuffer buffer = new StringBuffer(); - // Add the header buffer.append(addDefaultHeader()); - // Add the macro definitions buffer.append(addMacros()); - // List to collect needed build output variables - List outputVarsAdditionsList = new ArrayList(); + List outputVarsAdditionsList = new ArrayList<>(); // Determine target rules - StringBuffer targetRules = addTargets(outputVarsAdditionsList, rebuild); + //TOFIX removed line + //StringBuffer targetRules = addTargets(outputVarsAdditionsList, true); // Add outputMacros that were added to by the target rules - //TOFIX reenable line below - //buffer.append(writeTopAdditionMacros(outputVarsAdditionsList, getTopBuildOutputVars())); + //TOFIX removed line + // buffer.append(writeTopAdditionMacros(outputVarsAdditionsList, mySecondaryMacros)); // Add target rules - buffer.append(targetRules); + //buffer.append(targetRules); // Save the file + buffer.append(GenerateMacros()); + buffer.append(GenerateRules(getConfig())); + + IFile fileHandle = project.getFile(config.getName() + '/' + MAKEFILE_NAME); save(buffer, fileHandle); } @@ -106,29 +134,25 @@ private StringBuffer addMacros() { // Get the clean command from the build model buffer.append("RM := "); // support macros in the clean command - String cleanCommand = config.getCleanCommand(); try { - cleanCommand = ManagedBuildManager.getBuildMacroProvider().resolveValueToMakefileFormat( + String cleanCommand = ManagedBuildManager.getBuildMacroProvider().resolveValueToMakefileFormat( config.getCleanCommand(), EMPTY_STRING, WHITESPACE, IBuildMacroProvider.CONTEXT_CONFIGURATION, config); + buffer.append(cleanCommand).append(NEWLINE); + buffer.append(NEWLINE); } catch (BuildMacroException e) { // jaba is not going to write this code } - buffer.append(cleanCommand).append(NEWLINE); - buffer.append(NEWLINE); // Now add the source providers buffer.append(COMMENT_SYMBOL).append(WHITESPACE).append(ManagedMakeMessages.getResourceString(SRC_LISTS)) .append(NEWLINE); buffer.append("-include sources.mk").append(NEWLINE); - // JABA Change the include of the "root" (our sketch) folder to be - // before - // libraries and other files buffer.append("-include subdir.mk").append(NEWLINE); // Add includes for each subdir in child-subdir-first order (required // for makefile rule matching to work). List subDirList = new ArrayList<>(); - for (IContainer subDir : getSubdirList()) { + for (IContainer subDir : myFoldersToBuild) { String projectRelativePath = subDir.getProjectRelativePath().toOSString(); if (!projectRelativePath.isEmpty()) subDirList.add(0, projectRelativePath); @@ -355,14 +379,15 @@ private StringBuffer addTargets(List outputVarsAdditionsList, boolean re buffer.append(TAB).append(DASH).append(AT).append(ECHO_BLANK_LINE).append(NEWLINE); } // Add the Secondary Outputs target, if needed - if (secondaryOutputs.length > 0) { - buffer.append(SECONDARY_OUTPUTS).append(COLON); - Vector outs2 = calculateSecondaryOutputs(secondaryOutputs); - for (int i = 0; i < outs2.size(); i++) { - buffer.append(WHITESPACE).append("$(").append(outs2.get(i)).append(')'); - } - buffer.append(NEWLINE).append(NEWLINE); - } + //TOFIX removed this + // if (secondaryOutputs.length > 0) { + // buffer.append(SECONDARY_OUTPUTS).append(COLON); + // Vector outs2 = calculateSecondaryOutputs(secondaryOutputs); + // for (int i = 0; i < outs2.size(); i++) { + // buffer.append(WHITESPACE).append("$(").append(outs2.get(i)).append(')'); + // } + // buffer.append(NEWLINE).append(NEWLINE); + // } // Add all the needed dummy and phony targets buffer.append(".PHONY: all clean dependents"); if (prebuildStep.length() > 0) { @@ -413,10 +438,11 @@ protected boolean addRuleForTool(ITool tool, StringBuffer buffer, boolean bTarge Vector outputVariables = new Vector(); Vector additionalTargets = new Vector(); String outputPrefix = EMPTY_STRING; - if (!getToolInputsOutputs(tool, inputs, dependencies, outputs, enumeratedPrimaryOutputs, - enumeratedSecondaryOutputs, outputVariables, additionalTargets, bTargetTool, managedProjectOutputs)) { - return false; - } + //TOFIX removed this + // if (!getToolInputsOutputs(tool, inputs, dependencies, outputs, enumeratedPrimaryOutputs, + // enumeratedSecondaryOutputs, outputVariables, additionalTargets, bTargetTool, managedProjectOutputs)) { + // return false; + // } // If we have no primary output, make all of the secondary outputs the // primary output if (enumeratedPrimaryOutputs.size() == 0) { @@ -576,9 +602,11 @@ private void generateRulesForConsumers(ITool generatingTool, List output // Generate a build rule for any tool that consumes the output of this // tool PathSettingsContainer toolInfos = getToolInfos(); - ToolInfoHolder h = (ToolInfoHolder) toolInfos.getValue(); - ITool[] buildTools = h.buildTools; - boolean[] buildToolsUsed = h.buildToolsUsed; + // ToolInfoHolder h = (ToolInfoHolder) toolInfos.getValue(); + // ITool[] buildTools = h.buildTools; + ITool[] buildTools = null; + //boolean[] buildToolsUsed = h.buildToolsUsed; + boolean[] buildToolsUsed = null; IOutputType[] outTypes = generatingTool.getOutputTypes(); for (IOutputType outType : outTypes) { String[] outExts = outType.getOutputExtensions(generatingTool); @@ -629,9 +657,11 @@ private StringBuffer addTargetsRules(ITool targetTool, List outputVarsAd buffer.append(COMMENT_SYMBOL).append(WHITESPACE).append(ManagedMakeMessages.getResourceString(BUILD_TOP)) .append(NEWLINE); PathSettingsContainer toolInfos = getToolInfos(); - ToolInfoHolder h = (ToolInfoHolder) toolInfos.getValue(); - ITool[] buildTools = h.buildTools; - boolean[] buildToolsUsed = h.buildToolsUsed; + // ToolInfoHolder h = (ToolInfoHolder) toolInfos.getValue(); + // ITool[] buildTools = h.buildTools; + // boolean[] buildToolsUsed = h.buildToolsUsed; + ITool[] buildTools = null; + boolean[] buildToolsUsed = null; // Get the target tool and generate the rule if (targetTool != null) { // Note that the name of the target we pass to addRuleForTool does @@ -657,19 +687,19 @@ private StringBuffer addTargetsRules(ITool targetTool, List outputVarsAd // consume the output of those tools. This does not apply to pre-3.0 // integrations, since // the only "multipleOfType" tool is the "target" tool - for (int i = 0; i < buildTools.length; i++) { - ITool tool = buildTools[i]; - IInputType type = tool.getPrimaryInputType(); - if (type != null && type.getMultipleOfType()) { - if (!buildToolsUsed[i]) { - addRuleForTool(tool, buffer, false, null, null, outputVarsAdditionsList, null, false); - // Mark the target tool as processed - buildToolsUsed[i] = true; - // Look for tools that consume the output - generateRulesForConsumers(tool, outputVarsAdditionsList, buffer); - } - } - } + // for (int i = 0; i < buildTools.length; i++) { + // ITool tool = buildTools[i]; + // IInputType type = tool.getPrimaryInputType(); + // if (type != null && type.getMultipleOfType()) { + // if (!buildToolsUsed[i]) { + // addRuleForTool(tool, buffer, false, null, null, outputVarsAdditionsList, null, false); + // // Mark the target tool as processed + // buildToolsUsed[i] = true; + // // Look for tools that consume the output + // generateRulesForConsumers(tool, outputVarsAdditionsList, buffer); + // } + // } + // } // Add the comment buffer.append(COMMENT_SYMBOL).append(WHITESPACE).append(ManagedMakeMessages.getResourceString(BUILD_TARGETS)) .append(NEWLINE); @@ -688,11 +718,6 @@ private StringBuffer addTargetsRules(ITool targetTool, List outputVarsAd if (caller.buildTargetExt.length() > 0) { completeBuildTargetName = completeBuildTargetName + DOT + caller.buildTargetExt; } - // if (completeBuildTargetName.contains(" ")) { - // buffer.append(WHITESPACE + "\"" + completeBuildTargetName + "\""); - // } else { - // buffer.append(WHITESPACE + completeBuildTargetName); - // } buffer.append(NEWLINE); buffer.append(TAB).append(DASH).append(AT).append(ECHO_BLANK_LINE).append(NEWLINE); return buffer; @@ -713,73 +738,206 @@ private StringBuffer writeTopAdditionMacros(List varList, HashMap calculateSecondaryOutputs(IOutputType[] secondaryOutputs) { - PathSettingsContainer toolInfos = getToolInfos(); - ToolInfoHolder h = (ToolInfoHolder) toolInfos.getValue(); - ITool[] buildTools = h.buildTools; - Vector buildVars = new Vector(); - for (int i = 0; i < buildTools.length; i++) { - // Add the specified output build variables - IOutputType[] outTypes = buildTools[i].getOutputTypes(); - if (outTypes != null && outTypes.length > 0) { - for (int j = 0; j < outTypes.length; j++) { - IOutputType outType = outTypes[j]; - // Is this one of the secondary outputs? - // Look for an outputType with this ID, or one with a - // superclass with this id - thisType: for (int k = 0; k < secondaryOutputs.length; k++) { - IOutputType matchType = outType; - do { - if (matchType.getId().equals(secondaryOutputs[k].getId())) { - buildVars.add(outType.getBuildVariable()); - break thisType; + // private Vector calculateSecondaryOutputs(IOutputType[] secondaryOutputs) { + // PathSettingsContainer toolInfos = getToolInfos(); + // // ToolInfoHolder h = (ToolInfoHolder) toolInfos.getValue(); + // // ITool[] buildTools = h.buildTools; + // ITool[] buildTools = null; + // Vector buildVars = new Vector(); + // for (int i = 0; i < buildTools.length; i++) { + // // Add the specified output build variables + // IOutputType[] outTypes = buildTools[i].getOutputTypes(); + // if (outTypes != null && outTypes.length > 0) { + // for (int j = 0; j < outTypes.length; j++) { + // IOutputType outType = outTypes[j]; + // // Is this one of the secondary outputs? + // // Look for an outputType with this ID, or one with a + // // superclass with this id + // thisType: for (int k = 0; k < secondaryOutputs.length; k++) { + // IOutputType matchType = outType; + // do { + // if (matchType.getId().equals(secondaryOutputs[k].getId())) { + // buildVars.add(outType.getBuildVariable()); + // break thisType; + // } + // matchType = matchType.getSuperClass(); + // } while (matchType != null); + // } + // } + // } + // } + // return buildVars; + // } + + // private boolean getToolInputsOutputs(ITool tool, Vector inputs, Vector dependencies, + // Vector outputs, Vector enumeratedPrimaryOutputs, Vector enumeratedSecondaryOutputs, + // Vector outputVariables, Vector additionalTargets, boolean bTargetTool, + // Vector managedProjectOutputs) { + // PathSettingsContainer toolInfos = getToolInfos(); + // // ToolInfoHolder h = (ToolInfoHolder) toolInfos.getValue(); + // // ITool[] buildTools = h.buildTools; + // ITool[] buildTools = null; + // // Get the information regarding the tool's inputs and outputs from the + // // objects + // // created by calculateToolInputsOutputs + // IManagedBuildGnuToolInfo toolInfo = null; + // // for (int i = 0; i < buildTools.length; i++) { + // // if (tool == buildTools[i]) { + // // break; + // // } + // // } + // if (toolInfo == null) + // return false; + // // Populate the output Vectors + // inputs.addAll(toolInfo.getCommandInputs()); + // outputs.addAll(toolInfo.getCommandOutputs()); + // enumeratedPrimaryOutputs.addAll(toolInfo.getEnumeratedPrimaryOutputs()); + // enumeratedSecondaryOutputs.addAll(toolInfo.getEnumeratedSecondaryOutputs()); + // outputVariables.addAll(toolInfo.getOutputVariables()); + // Vector unprocessedDependencies = toolInfo.getCommandDependencies(); + // for (String path : unprocessedDependencies) { + // dependencies.add(ensurePathIsGNUMakeTargetRuleCompatibleSyntax(path)); + // } + // additionalTargets.addAll(toolInfo.getAdditionalTargets()); + // if (bTargetTool && managedProjectOutputs != null) { + // for (String output : managedProjectOutputs) { + // dependencies.add(output); + // } + // } + // return true; + // } + + //Get the rules for the generated files + private MakeRules getMakeRulesFromGeneratedFiles(Map> generatedFiles) { + MakeRules makeRules = new MakeRules(); + IConfiguration config = getConfig(); + IProject project = getProject(); + + // Visit the resources in this set + for (Entry> entry : generatedFiles.entrySet()) { + IOutputType outputTypeIn = entry.getKey(); + Set files = entry.getValue(); + String macroName = outputTypeIn.getBuildVariable(); + for (ITool tool : config.getTools()) { + for (IInputType inputType : tool.getInputTypes()) { + if (!macroName.equals(inputType.getBuildVariable())) { + continue; + } + if (inputType.getMultipleOfType()) { + for (IOutputType outputType : tool.getOutputTypes()) { + IManagedOutputNameProviderJaba nameProvider = getJABANameProvider(outputType); + if (nameProvider == null) { + continue; } - matchType = matchType.getSuperClass(); - } while (matchType != null); + IPath outputFile = nameProvider.getOutputName(null, null, null, null); + if (outputFile != null) { + //This is a multiple to 1 based on var name + IFile correctOutputFile = getProject() + .getFile(new Path(config.getName()).append(outputFile)); + makeRules.addRule(tool, inputType, macroName, files, outputType, correctOutputFile); + + continue; + } + IPath firstFilePath = files.toArray(new IFile[files.size()])[0].getProjectRelativePath(); + outputFile = nameProvider.getOutputName(project, config, tool, firstFilePath); + if (outputFile == null) { + continue; + } + //This is a multiple to 1 not based on var name + IPath correctOutputPath = new Path(config.getName()).append(outputFile); + MakeRule newMakeRule = new MakeRule(caller, tool, inputType, files, outputType, + project.getFile(correctOutputPath)); + + makeRules.addRule(newMakeRule); + } + } else { + //The link is based on the varname but the files are one on one + for (IOutputType outputType : tool.getOutputTypes()) { + IManagedOutputNameProviderJaba nameProvider = getJABANameProvider(outputType); + if (nameProvider == null) { + continue; + } + for (IFile file : files) { + IPath outputFile = nameProvider.getOutputName(project, config, tool, + file.getProjectRelativePath()); + if (outputFile == null) { + continue; + } + //This is a multiple to 1 not based on var name + IPath correctOutputPath = new Path(config.getName()).append(outputFile); + MakeRule newMakeRule = new MakeRule(tool, inputType, file, outputType, + project.getFile(correctOutputPath)); + newMakeRule.addDependencies(caller); + makeRules.addRule(newMakeRule); + } + } } } + // else { + // for (IOutputType outputType : tool.getOutputTypes()) { + // IManagedOutputNameProviderJaba nameProvider = getJABANameProvider(outputType); + // if (nameProvider == null) { + // continue; + // } + // for (IFile file : files) { + // IPath outputFile = nameProvider.getOutputName(getProject(), config, tool, + // file.getProjectRelativePath()); + // if (outputFile != null) { + // //We found a tool that provides a outputfile for our source file + // //TOFIX if this is a multiple to one we should only create one MakeRule + // IPath correctOutputPath = new Path(config.getName()).append(outputFile); + // MakeRule newMakeRule = new MakeRule(caller, tool, inputType, file, outputType, + // project.getFile(correctOutputPath)); + // + // makeRules.add(newMakeRule); + // } + // } + // } + // } + // } + } } - return buildVars; + return makeRules; + } - private boolean getToolInputsOutputs(ITool tool, Vector inputs, Vector dependencies, - Vector outputs, Vector enumeratedPrimaryOutputs, Vector enumeratedSecondaryOutputs, - Vector outputVariables, Vector additionalTargets, boolean bTargetTool, - Vector managedProjectOutputs) { - PathSettingsContainer toolInfos = getToolInfos(); - ToolInfoHolder h = (ToolInfoHolder) toolInfos.getValue(); - ITool[] buildTools = h.buildTools; - ArduinoManagedBuildGnuToolInfo[] gnuToolInfos = h.gnuToolInfos; - // Get the information regarding the tool's inputs and outputs from the - // objects - // created by calculateToolInputsOutputs - IManagedBuildGnuToolInfo toolInfo = null; - for (int i = 0; i < buildTools.length; i++) { - if (tool == buildTools[i]) { - toolInfo = gnuToolInfos[i]; - break; + private StringBuffer GenerateMacros() { + StringBuffer buffer = new StringBuffer(); + IFile buildRoot = caller.getTopBuildDir(); + buffer.append(NEWLINE); + buffer.append(COMMENT_SYMBOL).append(WHITESPACE).append(ManagedMakeMessages.getResourceString(MOD_VARS)) + .append(NEWLINE); + + for (String macroName : myMakeRules.getMacroNames()) { + Set files = myMakeRules.getMacroElements(macroName); + if (files.size() > 0) { + buffer.append(macroName).append(MAKE_ADDITION); + for (IFile file : files) { + if (files.size() != 1) { + buffer.append(LINEBREAK); + } + buffer.append(GetNiceFileName(buildRoot, file)).append(WHITESPACE); + } + buffer.append(NEWLINE); + buffer.append(NEWLINE); } + } - if (toolInfo == null) - return false; - // Populate the output Vectors - inputs.addAll(toolInfo.getCommandInputs()); - outputs.addAll(toolInfo.getCommandOutputs()); - enumeratedPrimaryOutputs.addAll(toolInfo.getEnumeratedPrimaryOutputs()); - enumeratedSecondaryOutputs.addAll(toolInfo.getEnumeratedSecondaryOutputs()); - outputVariables.addAll(toolInfo.getOutputVariables()); - Vector unprocessedDependencies = toolInfo.getCommandDependencies(); - for (String path : unprocessedDependencies) { - dependencies.add(ensurePathIsGNUMakeTargetRuleCompatibleSyntax(path)); - } - additionalTargets.addAll(toolInfo.getAdditionalTargets()); - if (bTargetTool && managedProjectOutputs != null) { - for (String output : managedProjectOutputs) { - dependencies.add(output); - } + return buffer; + } + + private StringBuffer GenerateRules(IConfiguration config) { + StringBuffer buffer = new StringBuffer(); + buffer.append(NEWLINE); + buffer.append(COMMENT_SYMBOL).append(WHITESPACE).append(ManagedMakeMessages.getResourceString(MOD_RULES)) + .append(NEWLINE); + + for (MakeRule makeRule : myMakeRules.getMakeRules()) { + buffer.append(makeRule.getRule(getProject(), caller.getTopBuildDir(), config)); } - return true; + + return buffer; } } diff --git a/io.sloeber.core/src/io/sloeber/managedBuild/api/IManagedOutputNameProviderJaba.java b/io.sloeber.core/src/io/sloeber/managedBuild/api/IManagedOutputNameProviderJaba.java index 99fa3c7ba..b4d45d816 100644 --- a/io.sloeber.core/src/io/sloeber/managedBuild/api/IManagedOutputNameProviderJaba.java +++ b/io.sloeber.core/src/io/sloeber/managedBuild/api/IManagedOutputNameProviderJaba.java @@ -6,5 +6,5 @@ import org.eclipse.core.runtime.IPath; public interface IManagedOutputNameProviderJaba { - public IPath getOutputName(IProject project, IConfiguration cConf, ITool tool, IPath primaryInputNames); + public IPath getOutputName(IProject project, IConfiguration cConf, ITool tool, IPath inputName); } From 17a7414f0b3b6cb3c212bd05feace3cb5c79f325 Mon Sep 17 00:00:00 2001 From: jantje Date: Sun, 23 Oct 2022 04:47:35 +0200 Subject: [PATCH 008/486] #1126 build nearly works --- .../Internal/ArchiveNameProvider.java | 4 +- .../Internal/ArduinoGnuMakefileGenerator.java | 4 ++ .../Internal/LinkNameProvider.java | 4 +- .../managedBuild/Internal/MakeRule.java | 57 +++++++++---------- .../managedBuild/Internal/MakeRules.java | 6 +- .../Internal/ManagebBuildCommon.java | 52 +++++++++++------ .../Internal/SubDirMakeGenerator.java | 18 ++++-- .../Internal/TopMakeFileGenerator.java | 37 +++++------- ...ava => INewManagedOutputNameProvider.java} | 2 +- 9 files changed, 102 insertions(+), 82 deletions(-) rename io.sloeber.core/src/io/sloeber/managedBuild/api/{IManagedOutputNameProviderJaba.java => INewManagedOutputNameProvider.java} (86%) diff --git a/io.sloeber.core/src/io/sloeber/managedBuild/Internal/ArchiveNameProvider.java b/io.sloeber.core/src/io/sloeber/managedBuild/Internal/ArchiveNameProvider.java index dd908bf2c..43ef86254 100644 --- a/io.sloeber.core/src/io/sloeber/managedBuild/Internal/ArchiveNameProvider.java +++ b/io.sloeber.core/src/io/sloeber/managedBuild/Internal/ArchiveNameProvider.java @@ -8,9 +8,9 @@ import io.sloeber.core.common.Common; import io.sloeber.core.common.Const; import io.sloeber.core.tools.Helpers; -import io.sloeber.managedBuild.api.IManagedOutputNameProviderJaba; +import io.sloeber.managedBuild.api.INewManagedOutputNameProvider; -public class ArchiveNameProvider implements IManagedOutputNameProviderJaba { +public class ArchiveNameProvider implements INewManagedOutputNameProvider { @Override public IPath getOutputName(IProject project, IConfiguration cConf, ITool tool, IPath primaryInput) { diff --git a/io.sloeber.core/src/io/sloeber/managedBuild/Internal/ArduinoGnuMakefileGenerator.java b/io.sloeber.core/src/io/sloeber/managedBuild/Internal/ArduinoGnuMakefileGenerator.java index f3308599c..9cbda933d 100644 --- a/io.sloeber.core/src/io/sloeber/managedBuild/Internal/ArduinoGnuMakefileGenerator.java +++ b/io.sloeber.core/src/io/sloeber/managedBuild/Internal/ArduinoGnuMakefileGenerator.java @@ -576,6 +576,10 @@ public IPath getBuildWorkingDir() { return null; } + public IFile getBuildFolder() { + return topBuildDir; + } + /* * (non-Javadoc) * diff --git a/io.sloeber.core/src/io/sloeber/managedBuild/Internal/LinkNameProvider.java b/io.sloeber.core/src/io/sloeber/managedBuild/Internal/LinkNameProvider.java index 12d6fa6d2..dcf033700 100644 --- a/io.sloeber.core/src/io/sloeber/managedBuild/Internal/LinkNameProvider.java +++ b/io.sloeber.core/src/io/sloeber/managedBuild/Internal/LinkNameProvider.java @@ -8,9 +8,9 @@ import io.sloeber.core.common.Common; import io.sloeber.core.common.Const; import io.sloeber.core.tools.Helpers; -import io.sloeber.managedBuild.api.IManagedOutputNameProviderJaba; +import io.sloeber.managedBuild.api.INewManagedOutputNameProvider; -public class LinkNameProvider implements IManagedOutputNameProviderJaba { +public class LinkNameProvider implements INewManagedOutputNameProvider { @Override public IPath getOutputName(IProject project, IConfiguration cConf, ITool tool, IPath inputName) { diff --git a/io.sloeber.core/src/io/sloeber/managedBuild/Internal/MakeRule.java b/io.sloeber.core/src/io/sloeber/managedBuild/Internal/MakeRule.java index 55520dfaf..a7af4e3e1 100644 --- a/io.sloeber.core/src/io/sloeber/managedBuild/Internal/MakeRule.java +++ b/io.sloeber.core/src/io/sloeber/managedBuild/Internal/MakeRule.java @@ -21,7 +21,6 @@ import org.eclipse.cdt.managedbuilder.core.ITool; import org.eclipse.cdt.managedbuilder.core.ManagedBuildManager; import org.eclipse.cdt.managedbuilder.internal.macros.BuildMacroProvider; -import org.eclipse.cdt.managedbuilder.internal.macros.FileContextData; import org.eclipse.cdt.managedbuilder.macros.BuildMacroException; import org.eclipse.cdt.managedbuilder.macros.IBuildMacroProvider; import org.eclipse.cdt.managedbuilder.makegen.IManagedDependencyCalculator; @@ -249,7 +248,7 @@ private String enumPrerequisites(IFile buildFolder) { } public StringBuffer getRule(IProject project, IFile niceBuildFolder, IConfiguration config) { - + ICConfigurationDescription confDesc = ManagedBuildManager.getDescriptionForConfiguration(config); String cmd = myTool.getToolCommand(); //For now assume 1 target with 1 or more prerequisites // if there is more than 1 prerequisite we take the flags of the first prerequisite only @@ -283,9 +282,8 @@ public StringBuffer getRule(IProject project, IFile niceBuildFolder, IConfigurat boolean resourceNameRequiresExplicitRule = containsSpecialCharacters(sourceLocation.getLocation().toOSString()); needExplicitRuleForFile = resourceNameRequiresExplicitRule || BuildMacroProvider.getReferencedExplitFileMacros(myTool).length > 0 - || BuildMacroProvider.getReferencedExplitFileMacros(cmd, IBuildMacroProvider.CONTEXT_FILE, - new FileContextData(sourceLocation.getFullPath(), outputLocation.getFullPath(), null, - myTool)).length > 0; + || BuildMacroProvider.getReferencedExplitFileMacros(cmd, IBuildMacroProvider.CONTEXT_CONFIGURATION, + confDesc).length > 0; String outflag = myTool.getOutputFlag(); String buildCmd = cmd + WHITESPACE + flags.toString().trim() + WHITESPACE + outflag + WHITESPACE @@ -304,19 +302,17 @@ public StringBuffer getRule(IProject project, IFile niceBuildFolder, IConfigurat IBuildMacroProvider provider = ManagedBuildManager.getBuildMacroProvider(); if (!needExplicitRuleForFile) { resolvedCommand = provider.resolveValueToMakefileFormat(buildCmd, EMPTY_STRING, WHITESPACE, - IBuildMacroProvider.CONTEXT_FILE, - new FileContextData(sourceLocation.getFullPath(), outputLocation.getFullPath(), null, myTool)); + IBuildMacroProvider.CONTEXT_CONFIGURATION, confDesc); } else { // if we need an explicit rule then don't use any builder // variables, resolve everything to explicit strings resolvedCommand = provider.resolveValue(buildCmd, EMPTY_STRING, WHITESPACE, - IBuildMacroProvider.CONTEXT_FILE, - new FileContextData(sourceLocation.getFullPath(), outputLocation.getFullPath(), null, myTool)); + IBuildMacroProvider.CONTEXT_CONFIGURATION, confDesc); } - if (!resolvedCommand.isBlank()) + if (resolvedCommand != null && !resolvedCommand.isBlank()) buildCmd = resolvedCommand.trim(); } catch (BuildMacroException e) { - /* JABA is not going to write this code */ + //Continue using the default buildCmd value } StringBuffer buffer = new StringBuffer(); @@ -328,7 +324,7 @@ public StringBuffer getRule(IProject project, IFile niceBuildFolder, IConfigurat // JABA add sketch.prebuild and postbouild if needed //TOFIX this should not be here if ("sloeber.ino".equals(fileName)) { //$NON-NLS-1$ - ICConfigurationDescription confDesc = ManagedBuildManager.getDescriptionForConfiguration(config); + String sketchPrebuild = io.sloeber.core.common.Common.getBuildEnvironmentVariable(confDesc, "sloeber.sketch.prebuild", new String(), true); //$NON-NLS-1$ String sketchPostBuild = io.sloeber.core.common.Common.getBuildEnvironmentVariable(confDesc, @@ -386,6 +382,7 @@ private Set getBuildFlags(IFile buildFolder, IConfiguration config, IFil private String expandCommandLinePattern(IConfiguration config, String sourceExtension, Set flags, String outputFlag, String outputName, Set inputResources, IFile inputLocation, IFile outputLocation) { + ICConfigurationDescription confDesc = ManagedBuildManager.getDescriptionForConfiguration(config); String cmd = myTool.getToolCommand(); // try to resolve the build macros in the tool command try { @@ -393,14 +390,12 @@ private String expandCommandLinePattern(IConfiguration config, String sourceExte if ((inputLocation != null && inputLocation.toString().indexOf(WHITESPACE) != -1) || (outputLocation != null && outputLocation.toString().indexOf(WHITESPACE) != -1)) { resolvedCommand = ManagedBuildManager.getBuildMacroProvider().resolveValue(cmd, EMPTY_STRING, - WHITESPACE, IBuildMacroProvider.CONTEXT_FILE, - new FileContextData(inputLocation.getFullPath(), outputLocation.getFullPath(), null, myTool)); + WHITESPACE, IBuildMacroProvider.CONTEXT_CONFIGURATION, confDesc); } else { resolvedCommand = ManagedBuildManager.getBuildMacroProvider().resolveValueToMakefileFormat(cmd, - EMPTY_STRING, WHITESPACE, IBuildMacroProvider.CONTEXT_FILE, - new FileContextData(inputLocation.getFullPath(), outputLocation.getFullPath(), null, myTool)); + EMPTY_STRING, WHITESPACE, IBuildMacroProvider.CONTEXT_CONFIGURATION, confDesc); } - if ((resolvedCommand = resolvedCommand.trim()).length() > 0) + if (resolvedCommand != null && (resolvedCommand = resolvedCommand.trim()).length() > 0) cmd = resolvedCommand; } catch (BuildMacroException e) { /* JABA is not going to write this code */ @@ -461,8 +456,7 @@ public void addPrerequisites(IInputType inputType, Set files) { } /** - * A simple rule is a rule that takes exactly 1 input type containing exactly - * one file + * A simple rule is a rule that takes exactly 1 input type * and exactly 1 output type containing exactly 1 file * * @return true if this rule is a simple rule @@ -470,18 +464,21 @@ public void addPrerequisites(IInputType inputType, Set files) { */ public boolean isSimpleRule() { - int counter = 0; - for (Set files : myTargets.values()) { - if ((++counter > 1) || (files.size() != 1)) { - return false; - } - } - counter = 0; - for (Set files : myPrerequisites.values()) { - if ((++counter > 1) || (files.size() != 1)) { - return false; - } + if ((myTargets.size() != 1) || (myTargets.size() != 1)) { + return false; } + // int counter = 0; + // for (Set files : myTargets.values()) { + // if ((++counter > 1) || (files.size() != 1)) { + // return false; + // } + // } + // counter = 0; + // for (Set files : myPrerequisites.values()) { + // if ((++counter > 1)) { + // return false; + // } + // } return true; } diff --git a/io.sloeber.core/src/io/sloeber/managedBuild/Internal/MakeRules.java b/io.sloeber.core/src/io/sloeber/managedBuild/Internal/MakeRules.java index 90b705e26..0de4d656f 100644 --- a/io.sloeber.core/src/io/sloeber/managedBuild/Internal/MakeRules.java +++ b/io.sloeber.core/src/io/sloeber/managedBuild/Internal/MakeRules.java @@ -36,10 +36,12 @@ public void addRule(MakeRule newMakeRule) { inputType = curTarget.getKey(); files = curTarget.getValue(); } - newMakeRule.addPrerequisites(inputType, files); + makerule.addPrerequisites(inputType, files); + } else { + myMakeRules.add(newMakeRule); } } - myMakeRules.add(newMakeRule); + } public MakeRule findTarget(IOutputType outputType, IFile correctOutputPath) { diff --git a/io.sloeber.core/src/io/sloeber/managedBuild/Internal/ManagebBuildCommon.java b/io.sloeber.core/src/io/sloeber/managedBuild/Internal/ManagebBuildCommon.java index ac757d826..03a7812be 100644 --- a/io.sloeber.core/src/io/sloeber/managedBuild/Internal/ManagebBuildCommon.java +++ b/io.sloeber.core/src/io/sloeber/managedBuild/Internal/ManagebBuildCommon.java @@ -42,7 +42,7 @@ import org.eclipse.core.runtime.Path; import io.sloeber.core.common.Common; -import io.sloeber.managedBuild.api.IManagedOutputNameProviderJaba; +import io.sloeber.managedBuild.api.INewManagedOutputNameProvider; @SuppressWarnings("nls") public class ManagebBuildCommon { @@ -592,14 +592,14 @@ static public String getToolCommandLinePattern(IConfiguration config, ITool tool } - static public IManagedOutputNameProviderJaba getJABANameProvider(IOutputType iType) { + static public INewManagedOutputNameProvider getJABANameProvider(IConfiguration cConf, IPath referencedFrom, + IOutputType iType) { OutputType type = (OutputType) iType; IConfigurationElement element = type.getNameProviderElement(); if (element != null) { try { if (element.getAttribute(IOutputType.NAME_PROVIDER) != null) { - return (IManagedOutputNameProviderJaba) element - .createExecutableExtension(IOutputType.NAME_PROVIDER); + return (INewManagedOutputNameProvider) element.createExecutableExtension(IOutputType.NAME_PROVIDER); } } catch (@SuppressWarnings("unused") CoreException e) { //ignore errors @@ -608,12 +608,25 @@ static public IManagedOutputNameProviderJaba getJABANameProvider(IOutputType iTy String[] outputNames = type.getOutputNames(); if (outputNames != null && outputNames.length > 0) { String outputName = outputNames[0]; - return new IManagedOutputNameProviderJaba() { + IBuildMacroProvider provider = ManagedBuildManager.getBuildMacroProvider(); + String expanded = outputName; + try { + expanded = provider.resolveValue(outputName, EMPTY_STRING, WHITESPACE, + IBuildMacroProvider.CONTEXT_CONFIGURATION, cConf); + } catch (BuildMacroException e) { + // default will do + e.printStackTrace(); + } + IPath expandedPath = new Path(expanded); + if (expandedPath.segmentCount() > 1) { + expandedPath = GetNiceFileName(referencedFrom, new Path(expanded)); + } + final IPath ret=expandedPath; + return new INewManagedOutputNameProvider() { @Override public IPath getOutputName(IProject project, IConfiguration cConf, ITool tool, IPath inputName) { - return new Path(outputName); - //return project.getFile(cConf.getName()).getFullPath().append(outputName); + return ret; } }; } @@ -621,11 +634,15 @@ public IPath getOutputName(IProject project, IConfiguration cConf, ITool tool, I String[] outputExtensions = type.getOutputExtensionsAttribute(); if (outputExtensions != null && outputExtensions.length > 0) { String outputExtension = outputExtensions[0]; - return new IManagedOutputNameProviderJaba() { + return new INewManagedOutputNameProvider() { @Override public IPath getOutputName(IProject project, IConfiguration cConf, ITool tool, IPath inputName) { - return inputName.addFileExtension(outputExtension); + ICProjectDescription prjDesc = CoreModel.getDefault().getProjectDescription(project); + ICConfigurationDescription confDesc = prjDesc.getConfigurationByName(cConf.getName()); + String expanded = Common.getBuildEnvironmentVariable(confDesc, inputName.toString(), + inputName.toString(), true); + return new Path(expanded).addFileExtension(outputExtension); } }; } @@ -634,17 +651,18 @@ public IPath getOutputName(IProject project, IConfiguration cConf, ITool tool, I } static public String GetNiceFileName(IFile buildPath, IFile path) { - IPath buildLocation = buildPath.getLocation(); - IPath fileLocation = path.getLocation(); - if (buildLocation.isPrefixOf(path.getLocation())) { - return fileLocation.makeRelativeTo(buildLocation).toOSString(); - //return DOT_SLASH_PATH.append(fileLocation.makeRelativeTo(buildLocation)).toOSString(); + return GetNiceFileName(buildPath.getLocation(), path.getLocation()).toOSString(); + } + + static public IPath GetNiceFileName(IPath buildPath, IPath filePath) { + if (buildPath.isPrefixOf(filePath)) { + return filePath.makeRelativeTo(buildPath); } - if (buildLocation.removeLastSegments(1).isPrefixOf(fileLocation)) { - return fileLocation.makeRelativeTo(buildLocation).toOSString(); + if (buildPath.removeLastSegments(1).isPrefixOf(filePath)) { + return filePath.makeRelativeTo(buildPath); } - return fileLocation.toOSString(); + return filePath; } static public String makeVariable(String variableName) { diff --git a/io.sloeber.core/src/io/sloeber/managedBuild/Internal/SubDirMakeGenerator.java b/io.sloeber.core/src/io/sloeber/managedBuild/Internal/SubDirMakeGenerator.java index 9cada7ce9..cdd7c7bc9 100644 --- a/io.sloeber.core/src/io/sloeber/managedBuild/Internal/SubDirMakeGenerator.java +++ b/io.sloeber.core/src/io/sloeber/managedBuild/Internal/SubDirMakeGenerator.java @@ -23,7 +23,7 @@ import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.Path; -import io.sloeber.managedBuild.api.IManagedOutputNameProviderJaba; +import io.sloeber.managedBuild.api.INewManagedOutputNameProvider; public class SubDirMakeGenerator { private ArduinoGnuMakefileGenerator caller; @@ -33,11 +33,11 @@ public class SubDirMakeGenerator { SubDirMakeGenerator(ArduinoGnuMakefileGenerator theCaller, IContainer module) { caller = theCaller; IProject project = getProject(); - IPath buildRoot = getBuildWorkingDir(); - if (buildRoot == null) { + IPath buildPath = getBuildPath(); + if (buildPath == null) { return; } - IPath moduleOutputPath = buildRoot.append(module.getProjectRelativePath()); + IPath moduleOutputPath = buildPath.append(module.getProjectRelativePath()); myMakefile = project.getFile(moduleOutputPath.append(MODFILE_NAME)); getMakeRulesFromSourceFiles(module); } @@ -102,10 +102,14 @@ public Map> getTargets() { return ret; } - private IPath getBuildWorkingDir() { + private IPath getBuildPath() { return caller.getBuildWorkingDir(); } + private IPath getBuildFolder() { + return caller.getBuildFolder().getLocation(); + } + private IFile getTopBuildDir() { return caller.getTopBuildDir(); } @@ -181,6 +185,7 @@ private void getMakeRulesFromSourceFiles(IContainer module) { myMakeRules.clear(); IConfiguration config = getConfig(); IProject project = getProject(); + IPath buildPath = getBuildFolder(); // Visit the resources in this folder try { @@ -206,7 +211,8 @@ private void getMakeRulesFromSourceFiles(IContainer module) { continue; } for (IOutputType outputType : tool.getOutputTypes()) { - IManagedOutputNameProviderJaba nameProvider = getJABANameProvider(outputType); + INewManagedOutputNameProvider nameProvider = getJABANameProvider(config, buildPath, + outputType); if (nameProvider == null) { continue; } diff --git a/io.sloeber.core/src/io/sloeber/managedBuild/Internal/TopMakeFileGenerator.java b/io.sloeber.core/src/io/sloeber/managedBuild/Internal/TopMakeFileGenerator.java index 308e2d0d5..ed9e3b1db 100644 --- a/io.sloeber.core/src/io/sloeber/managedBuild/Internal/TopMakeFileGenerator.java +++ b/io.sloeber.core/src/io/sloeber/managedBuild/Internal/TopMakeFileGenerator.java @@ -36,7 +36,7 @@ import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.Path; -import io.sloeber.managedBuild.api.IManagedOutputNameProviderJaba; +import io.sloeber.managedBuild.api.INewManagedOutputNameProvider; public class TopMakeFileGenerator { private ArduinoGnuMakefileGenerator caller = null; @@ -98,10 +98,14 @@ private Vector getRuleList() { return caller.getRuleList(); } - public PathSettingsContainer getToolInfos() { + private PathSettingsContainer getToolInfos() { return caller.getToolInfos(); } + private IPath getBuildFolder() { + return caller.getBuildFolder().getLocation(); + } + public void generateMakefile() throws CoreException { IProject project = getProject(); IConfiguration config = getConfig(); @@ -111,8 +115,7 @@ public void generateMakefile() throws CoreException { buffer.append(addMacros()); List outputVarsAdditionsList = new ArrayList<>(); // Determine target rules - //TOFIX removed line - //StringBuffer targetRules = addTargets(outputVarsAdditionsList, true); + buffer.append(addTargets(outputVarsAdditionsList, true)); // Add outputMacros that were added to by the target rules //TOFIX removed line // buffer.append(writeTopAdditionMacros(outputVarsAdditionsList, mySecondaryMacros)); @@ -656,12 +659,6 @@ private StringBuffer addTargetsRules(ITool targetTool, List outputVarsAd // Add the comment buffer.append(COMMENT_SYMBOL).append(WHITESPACE).append(ManagedMakeMessages.getResourceString(BUILD_TOP)) .append(NEWLINE); - PathSettingsContainer toolInfos = getToolInfos(); - // ToolInfoHolder h = (ToolInfoHolder) toolInfos.getValue(); - // ITool[] buildTools = h.buildTools; - // boolean[] buildToolsUsed = h.buildToolsUsed; - ITool[] buildTools = null; - boolean[] buildToolsUsed = null; // Get the target tool and generate the rule if (targetTool != null) { // Note that the name of the target we pass to addRuleForTool does @@ -669,16 +666,9 @@ private StringBuffer addTargetsRules(ITool targetTool, List outputVarsAd // appear to be used there (and tool outputs are consulted // directly), but // we quote it anyway just in case it starts to use it in future. - if (addRuleForTool(targetTool, buffer, true, + addRuleForTool(targetTool, buffer, true, ensurePathIsGNUMakeTargetRuleCompatibleSyntax(caller.buildTargetName), caller.buildTargetExt, - outputVarsAdditionsList, managedProjectOutputs, postbuildStep)) { - // Mark the target tool as processed - for (int i = 0; i < buildTools.length; i++) { - if (targetTool == buildTools[i]) { - buildToolsUsed[i] = true; - } - } - } + outputVarsAdditionsList, managedProjectOutputs, postbuildStep); } else { buffer.append(TAB).append(AT).append(escapedEcho(MESSAGE_NO_TARGET_TOOL + WHITESPACE + OUT_MACRO)); } @@ -812,6 +802,7 @@ private MakeRules getMakeRulesFromGeneratedFiles(Map> ge MakeRules makeRules = new MakeRules(); IConfiguration config = getConfig(); IProject project = getProject(); + IPath buildPath = getBuildFolder(); // Visit the resources in this set for (Entry> entry : generatedFiles.entrySet()) { @@ -825,11 +816,12 @@ private MakeRules getMakeRulesFromGeneratedFiles(Map> ge } if (inputType.getMultipleOfType()) { for (IOutputType outputType : tool.getOutputTypes()) { - IManagedOutputNameProviderJaba nameProvider = getJABANameProvider(outputType); + INewManagedOutputNameProvider nameProvider = getJABANameProvider(config, buildPath, + outputType); if (nameProvider == null) { continue; } - IPath outputFile = nameProvider.getOutputName(null, null, null, null); + IPath outputFile = nameProvider.getOutputName(project, config, null, null); if (outputFile != null) { //This is a multiple to 1 based on var name IFile correctOutputFile = getProject() @@ -853,7 +845,8 @@ private MakeRules getMakeRulesFromGeneratedFiles(Map> ge } else { //The link is based on the varname but the files are one on one for (IOutputType outputType : tool.getOutputTypes()) { - IManagedOutputNameProviderJaba nameProvider = getJABANameProvider(outputType); + INewManagedOutputNameProvider nameProvider = getJABANameProvider(config, buildPath, + outputType); if (nameProvider == null) { continue; } diff --git a/io.sloeber.core/src/io/sloeber/managedBuild/api/IManagedOutputNameProviderJaba.java b/io.sloeber.core/src/io/sloeber/managedBuild/api/INewManagedOutputNameProvider.java similarity index 86% rename from io.sloeber.core/src/io/sloeber/managedBuild/api/IManagedOutputNameProviderJaba.java rename to io.sloeber.core/src/io/sloeber/managedBuild/api/INewManagedOutputNameProvider.java index b4d45d816..867f3b721 100644 --- a/io.sloeber.core/src/io/sloeber/managedBuild/api/IManagedOutputNameProviderJaba.java +++ b/io.sloeber.core/src/io/sloeber/managedBuild/api/INewManagedOutputNameProvider.java @@ -5,6 +5,6 @@ import org.eclipse.core.resources.IProject; import org.eclipse.core.runtime.IPath; -public interface IManagedOutputNameProviderJaba { +public interface INewManagedOutputNameProvider { public IPath getOutputName(IProject project, IConfiguration cConf, ITool tool, IPath inputName); } From d2a7bb41bd57473a75e274792cd918d2bd784645 Mon Sep 17 00:00:00 2001 From: gast1 Date: Mon, 24 Oct 2022 18:42:09 +0200 Subject: [PATCH 009/486] sloeber regression now works #1126 --- .../Internal/ArduinoGnuMakefileGenerator.java | 944 +----------- .../managedBuild/Internal/MakeRule.java | 9 +- .../managedBuild/Internal/MakeRules.java | 10 + .../Internal/ManagebBuildCommon.java | 3 +- .../Internal/ManagedBuildConstants.java | 165 +-- .../Internal/SubDirMakeGenerator.java | 8 +- .../Internal/TopMakeFileGenerator.java | 1303 +++++------------ 7 files changed, 517 insertions(+), 1925 deletions(-) diff --git a/io.sloeber.core/src/io/sloeber/managedBuild/Internal/ArduinoGnuMakefileGenerator.java b/io.sloeber.core/src/io/sloeber/managedBuild/Internal/ArduinoGnuMakefileGenerator.java index 9cbda933d..d032f8234 100644 --- a/io.sloeber.core/src/io/sloeber/managedBuild/Internal/ArduinoGnuMakefileGenerator.java +++ b/io.sloeber.core/src/io/sloeber/managedBuild/Internal/ArduinoGnuMakefileGenerator.java @@ -1,20 +1,15 @@ package io.sloeber.managedBuild.Internal; import static io.sloeber.core.common.Const.*; -import static io.sloeber.managedBuild.Internal.ManagebBuildCommon.*; - import java.io.File; import java.io.IOException; import java.nio.charset.Charset; import java.util.Collection; -import java.util.HashMap; import java.util.HashSet; import java.util.LinkedHashSet; import java.util.LinkedList; import java.util.List; import java.util.Set; -import java.util.Vector; - import org.apache.commons.io.FileUtils; import org.eclipse.cdt.core.CCorePlugin; import org.eclipse.cdt.core.settings.model.CSourceEntry; @@ -22,14 +17,9 @@ import org.eclipse.cdt.core.settings.model.ICSettingEntry; import org.eclipse.cdt.core.settings.model.ICSourceEntry; import org.eclipse.cdt.core.settings.model.util.CDataUtil; -import org.eclipse.cdt.core.settings.model.util.PathSettingsContainer; import org.eclipse.cdt.managedbuilder.core.IBuilder; import org.eclipse.cdt.managedbuilder.core.IConfiguration; -import org.eclipse.cdt.managedbuilder.core.IFileInfo; -import org.eclipse.cdt.managedbuilder.core.IFolderInfo; import org.eclipse.cdt.managedbuilder.core.IManagedBuildInfo; -import org.eclipse.cdt.managedbuilder.core.IOutputType; -import org.eclipse.cdt.managedbuilder.core.IResourceInfo; import org.eclipse.cdt.managedbuilder.core.ManagedBuildManager; import org.eclipse.cdt.managedbuilder.core.ManagedBuilderCorePlugin; import org.eclipse.cdt.managedbuilder.internal.core.ManagedMakeMessages; @@ -38,11 +28,9 @@ import org.eclipse.cdt.managedbuilder.makegen.IManagedBuilderMakefileGenerator2; 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.IResourceDelta; -import org.eclipse.core.resources.IResourceDeltaVisitor; import org.eclipse.core.resources.IResourceProxy; import org.eclipse.core.resources.IResourceProxyVisitor; import org.eclipse.core.resources.IWorkspaceRoot; @@ -54,11 +42,8 @@ import org.eclipse.core.runtime.OperationCanceledException; import org.eclipse.core.runtime.Path; import org.eclipse.core.runtime.Status; -import org.eclipse.core.runtime.SubProgressMonitor; - import io.sloeber.core.Messages; import io.sloeber.core.common.Common; -import io.sloeber.core.common.Const; /** * This is a specialized makefile generator that takes advantage of the @@ -68,103 +53,22 @@ * @noextend This class is not intended to be subclassed by clients. * @noinstantiate This class is not intended to be instantiated by clients. */ -@SuppressWarnings({ "deprecation", "restriction", "nls", "unused", "synthetic-access", "static-method", "unchecked", - "hiding" }) public class ArduinoGnuMakefileGenerator implements IManagedBuilderMakefileGenerator2 { - - public class ResourceDeltaVisitor implements IResourceDeltaVisitor { - private final ArduinoGnuMakefileGenerator generator; - private final IConfiguration config; - - public ResourceDeltaVisitor(ArduinoGnuMakefileGenerator generator, IConfiguration cfg) { - this.generator = generator; - this.config = cfg; - } - - @Override - public boolean visit(IResourceDelta delta) throws CoreException { - // Should the visitor keep iterating in current directory - boolean keepLooking = false; - IResource resource = delta.getResource(); - IResourceInfo rcInfo = config.getResourceInfo(resource.getProjectRelativePath(), false); - IFolderInfo fo = null; - boolean isSource = isSource(resource.getProjectRelativePath()); - if (rcInfo instanceof IFolderInfo) { - fo = (IFolderInfo) rcInfo; - } - // What kind of resource change has occurred - if (isSource) { - if (resource.getType() == IResource.FILE) { - String ext = resource.getFileExtension(); - switch (delta.getKind()) { - case IResourceDelta.ADDED: - if (!generator.isGeneratedResource(resource)) { - // This is a source file so just add its container - if (fo == null || fo.buildsFileType(ext)) { - generator.appendModifiedSubdirectory(resource); - } - } - break; - case IResourceDelta.REMOVED: - // we get this notification if a resource is moved too - if (!generator.isGeneratedResource(resource)) { - // This is a source file so just add its container - if (fo == null || fo.buildsFileType(ext)) { - generator.appendDeletedFile(resource); - generator.appendModifiedSubdirectory(resource); - } - } - break; - default: - keepLooking = true; - break; - } - } - if (resource.getType() == IResource.FOLDER) { - // I only care about delete event - switch (delta.getKind()) { - case IResourceDelta.REMOVED: - if (!generator.isGeneratedResource(resource)) { - generator.appendDeletedSubdirectory((IContainer) resource); - } - break; - } - } - } - if (resource.getType() == IResource.PROJECT) { - // If there is a zero-length delta, something the project - // depends on has changed so just call make - IResourceDelta[] children = delta.getAffectedChildren(); - if (children != null && children.length > 0) { - keepLooking = true; - } - } else { - // If the resource is part of the generated directory structure - // don't recurse - if (resource.getType() == IResource.ROOT || (isSource && !generator.isGeneratedResource(resource))) { - keepLooking = true; - } - } - return keepLooking; - } - } - + /** * This class is used to recursively walk the project and determine which * modules contribute buildable source files. */ protected class ResourceProxyVisitor implements IResourceProxyVisitor { private final ArduinoGnuMakefileGenerator generator; - private final IConfiguration config; private Collection subdirList = new LinkedHashSet(); Collection getSubdirList() { return subdirList; } - public ResourceProxyVisitor(ArduinoGnuMakefileGenerator generator, IConfiguration cfg) { + public ResourceProxyVisitor(ArduinoGnuMakefileGenerator generator) { this.generator = generator; - this.config = cfg; } @@ -201,20 +105,9 @@ public boolean visit(IResourceProxy proxy) throws CoreException { String buildTargetName; String buildTargetExt; IConfiguration config; - private IBuilder builder; - protected PathSettingsContainer toolInfos; - private Vector deletedFileList; - private Vector deletedDirList; - private Vector invalidDirList; /** Collection of Folders in which sources files have been modified */ - private Collection modifiedList; private IProgressMonitor monitor; private IProject project; - IResource[] projectResources; - private Vector ruleList; - - // lines - private Vector depRuleList; // dependency files /** Collection of Containers which contribute source files to the build */ @@ -223,17 +116,10 @@ public boolean visit(IResourceProxy proxy) throws CoreException { // private Vector dependencyMakefiles; // IPath's - relative to the top // build directory or absolute private ICSourceEntry srcEntries[]; - // Added by jaba - IOutputType usedOutType = null; - // End of added by jaba - public ArduinoGnuMakefileGenerator() { super(); } - /************************************************************************* - * IManagedBuilderMakefileGenerator M E T H O D S - ************************************************************************/ /* * (non-Javadoc) * @@ -244,11 +130,7 @@ public ArduinoGnuMakefileGenerator() { public void initialize(IProject project, IManagedBuildInfo info, IProgressMonitor monitor) { this.project = project; - try { - projectResources = project.members(); - } catch (CoreException e) { - projectResources = null; - } + // Save the monitor reference for reporting back to the user this.monitor = monitor; // Get the name of the build target @@ -276,290 +158,25 @@ public void initialize(IProject project, IManagedBuildInfo info, IProgressMonito } // Cache the build tools config = info.getDefaultConfiguration(); - builder = config.getEditableBuilder(); // initToolInfos(); // set the top build dir path topBuildDir = project.getFile(info.getConfigurationName()); } - /** - * This method calls the dependency postprocessors defined for the tool chain - */ - // private void callDependencyPostProcessors(IResourceInfo rcInfo, ToolInfoHolder h, IFile depFile, - // IManagedDependencyGenerator2[] postProcessors, boolean callPopulateDummyTargets, boolean force) - // throws CoreException { - // try { - // updateMonitor(ManagedMakeMessages - // .getFormattedString("ArduinoGnuMakefileGenerator.message.postproc.dep.file", depFile.getName())); - // if (postProcessors != null) { - // IPath absolutePath = new Path( - // EFSExtensionManager.getDefault().getPathFromURI(depFile.getLocationURI())); - // // Convert to build directory relative - // IPath depPath = ManagedBuildManager.calculateRelativePath(getTopBuildDir().getFullPath(), absolutePath); - // for (int i = 0; i < postProcessors.length; i++) { - // IManagedDependencyGenerator2 depGen = postProcessors[i]; - // if (depGen != null) { - // depGen.postProcessDependencyFile(depPath, config, h.buildTools[i], - // getTopBuildDir().getFullPath()); - // } - // } - // } - // if (callPopulateDummyTargets) { - // populateDummyTargets(rcInfo, depFile, force); - // } - // } catch (CoreException e) { - // throw e; - // } catch (IOException e) { - // /* JABA is not going to write this code */ - // } - // } - - /** - * This method collects the dependency postprocessors and file extensions - * defined for the tool chain - */ - // private boolean collectDependencyGeneratorInformation(ToolInfoHolder h, Vector depExts, - // IManagedDependencyGenerator2[] postProcessors) { - // boolean callPopulateDummyTargets = false; - // for (int i = 0; i < h.buildTools.length; i++) { - // ITool tool = h.buildTools[i]; - // IManagedDependencyGeneratorType depType = tool - // .getDependencyGeneratorForExtension(tool.getDefaultInputExtension()); - // if (depType != null) { - // int calcType = depType.getCalculatorType(); - // if (calcType <= IManagedDependencyGeneratorType.TYPE_OLD_TYPE_LIMIT) { - // if (calcType == IManagedDependencyGeneratorType.TYPE_COMMAND) { - // callPopulateDummyTargets = true; - // depExts.add(DEP_EXT); - // } - // } else { - // if (calcType == IManagedDependencyGeneratorType.TYPE_BUILD_COMMANDS - // || calcType == IManagedDependencyGeneratorType.TYPE_PREBUILD_COMMANDS) { - // IManagedDependencyGenerator2 depGen = (IManagedDependencyGenerator2) depType; - // String depExt = depGen.getDependencyFileExtension(config, tool); - // if (depExt != null) { - // postProcessors[i] = depGen; - // depExts.add(depExt); - // } - // } - // } - // } - // } - // return callPopulateDummyTargets; - // } public boolean isSource(IPath path) { return !CDataUtil.isExcluded(path, srcEntries); } - // private class DepInfo { - // Vector depExts; - // IManagedDependencyGenerator2[] postProcessors; - // boolean callPopulateDummyTargets; - // } - /* - * (non-Javadoc) - * - * @see org.eclipse.cdt.managedbuilder.makegen.IManagedBuilderMakefileGenerator - * #generateDependencies() - */ + @Override public void generateDependencies() throws CoreException { - // final PathSettingsContainer postProcs = PathSettingsContainer.createRootContainer(); - // // Note: PopulateDummyTargets is a hack for the pre-3.x GCC compilers - // // Collect the methods that will need to be called - // toolInfos.accept(new IPathSettingsContainerVisitor() { - // @Override - // public boolean visit(PathSettingsContainer container) { - // ToolInfoHolder h = (ToolInfoHolder) container.getValue(); - // Vector depExts = new Vector<>(); - // IManagedDependencyGenerator2[] postProcessors = new IManagedDependencyGenerator2[h.buildTools.length]; - // boolean callPopulateDummyTargets = collectDependencyGeneratorInformation(h, depExts, postProcessors); - // // Is there anyone to call if we do find dependency files? - // if (!callPopulateDummyTargets) { - // int i; - // for (i = 0; i < postProcessors.length; i++) { - // if (postProcessors[i] != null) - // break; - // } - // if (i == postProcessors.length) - // return true; - // } - // PathSettingsContainer child = postProcs.getChildContainer(container.getPath(), true, true); - // DepInfo di = new DepInfo(); - // di.depExts = depExts; - // di.postProcessors = postProcessors; - // di.callPopulateDummyTargets = callPopulateDummyTargets; - // child.setValue(di); - // return true; - // } - // }); - // IWorkspaceRoot root = CCorePlugin.getWorkspace().getRoot(); - // for (IContainer subDir : getSubdirList()) { - // // The builder creates a subdir with same name as source in the - // // build location - // IPath projectRelativePath = subDir.getProjectRelativePath(); - // IResourceInfo rcInfo = config.getResourceInfo(projectRelativePath, false); - // PathSettingsContainer cr = postProcs.getChildContainer(rcInfo.getPath(), false, true); - // if (cr == null || cr.getValue() == null) - // continue; - // DepInfo di = (DepInfo) cr.getValue(); - // //ToolInfoHolder h = ToolInfoHolder.getToolInfo(this, projectRelativePath); - // IPath buildRelativePath = topBuildDir.getFullPath().append(projectRelativePath); - // IFolder buildFolder = root.getFolder(buildRelativePath); - // if (buildFolder == null) - // continue; - // if (!buildFolder.exists()) - // continue; - // // Find all of the dep files in the generated subdirectories - // IResource[] files = buildFolder.members(); - // for (IResource file : files) { - // String fileExt = file.getFileExtension(); - // for (String ext : di.depExts) { - // if (ext.equals(fileExt)) { - // IFile depFile = root.getFile(file.getFullPath()); - // if (depFile == null) - // continue; - // // callDependencyPostProcessors(rcInfo, h, depFile, di.postProcessors, di.callPopulateDummyTargets, - // // false); - // } - // } - // } - // } } - /* - * (non-Javadoc) - * - * @see org.eclipse.cdt.managedbuilder.makegen.IManagedBuilderMakefileGenerator# - * generateMakefiles(org.eclipse.core.resources.IResourceDelta) - */ @Override public MultiStatus generateMakefiles(IResourceDelta delta) throws CoreException { - /* - * Let's do a sanity check right now. 1. This is an incremental build, so if the - * top-level directory is not there, then a rebuild is needed. - */ return regenerateMakefiles(); - // IFolder folder = project.getFolder(config.getName()); - // if (!folder.exists()) { - // return regenerateMakefiles(); - // } - // // Return value - // MultiStatus status; - // // Visit the resources in the delta and compile a list of subdirectories - // // to regenerate - // updateMonitor( - // ManagedMakeMessages.getFormattedString("MakefileGenerator.message.calc.delta", project.getName())); - // ResourceDeltaVisitor visitor = new ResourceDeltaVisitor(this, config); - // delta.accept(visitor); - // checkCancel(); - // // Get all the subdirectories participating in the build - // updateMonitor( - // ManagedMakeMessages.getFormattedString("MakefileGenerator.message.finding.sources", project.getName())); - // ResourceProxyVisitor resourceVisitor = new ResourceProxyVisitor(this, config); - // project.accept(resourceVisitor, IResource.NONE); - // checkCancel(); - // // Bug 303953: Ensure that if all resources have been removed from a - // // folder, than the folder still - // // appears in the subdir list so it's subdir.mk is correctly regenerated - // getSubdirList().addAll(getModifiedList()); - // // Make sure there is something to build - // if (getSubdirList().isEmpty()) { - // String info = ManagedMakeMessages.getFormattedString("MakefileGenerator.warning.no.source", - // project.getName()); - // updateMonitor(info); - // status = new MultiStatus(ManagedBuilderCorePlugin.getUniqueIdentifier(), IStatus.INFO, "", null); - // status.add(new Status(IStatus.INFO, ManagedBuilderCorePlugin.getUniqueIdentifier(), NO_SOURCE_FOLDERS, info, - // null)); - // return status; - // } - // // Make sure the build directory is available - // topBuildDir = project.getFile(config.getName()); - // createDirectory(project, config.getName()); - // checkCancel(); - // // Make sure that there is a makefile containing all the folders - // // participating - // IPath srcsFilePath = topBuildDir.getFullPath().append(SRCSFILE_NAME); - // IFile srcsFileHandle = createFile(srcsFilePath); - // checkCancel(); - // // Regenerate any fragments that are missing for the exisiting - // // directories NOT modified - // for (IContainer subdirectory : getSubdirList()) { - // if (!getModifiedList().contains(subdirectory)) { - // // Make sure the directory exists (it may have been deleted) - // if (!subdirectory.exists()) { - // appendDeletedSubdirectory(subdirectory); - // continue; - // } - // // Make sure a fragment makefile exists - // IPath fragmentPath = getBuildWorkingDir().append(subdirectory.getProjectRelativePath()) - // .append(MODFILE_NAME); - // IFile makeFragment = project.getFile(fragmentPath); - // if (!makeFragment.exists()) { - // // If one or both are missing, then add it to the list to be - // // generated - // getModifiedList().add(subdirectory); - // } - // } - // } - // // Delete the old dependency files for any deleted resources - // for (IResource deletedFile : getDeletedFileList()) { - // deleteDepFile(deletedFile); - // deleteBuildTarget(deletedFile); - // } - // // Regenerate any fragments for modified directories - // for (IResource res : getModifiedList()) { - // IContainer subDir = (IContainer) res; - // // Make sure the directory exists (it may have been deleted) - // if (!subDir.exists()) { - // appendDeletedSubdirectory(subDir); - // continue; - // } - // // populateFragmentMakefile(subDir); // See below - // checkCancel(); - // } - // // Recreate all module makefiles - // // NOTE WELL: For now, always recreate all of the fragment makefile. - // // This is necessary - // // in order to re-populate the buildVariable lists. In the future, the - // // list could - // // possibly segmented by subdir so that all fragments didn't need to be - // // regenerated - // for (IContainer subDir : getSubdirList()) { - // mySubDirMakeGenerators.add(new SubDirMakeGenerator(this, subDir)); - // checkCancel(); - // } - // // Calculate the inputs and outputs of the Tools to be generated in the - // // main makefile - // calculateToolInputsOutputs(); - // checkCancel(); - // // Re-create the top-level makefile - // IPath makefilePath = topBuildDir.getFullPath().append(MAKEFILE_NAME); - // IFile makefileHandle = createFile(makefilePath); - // myTopMakeFileGenerator.populateTopMakefile(makefileHandle, false); - // checkCancel(); - // // Remove deleted folders from generated build directory - // for (IResource res : getDeletedDirList()) { - // IContainer subDir = (IContainer) res; - // removeGeneratedDirectory(subDir); - // checkCancel(); - // } - // // How did we do - // if (!getInvalidDirList().isEmpty()) { - // status = new MultiStatus(ManagedBuilderCorePlugin.getUniqueIdentifier(), IStatus.WARNING, "", null); - // // Add a new status for each of the bad folders - // // TODO: fix error message - // for (IResource res : getInvalidDirList()) { - // IContainer subDir = (IContainer) res; - // status.add(new Status(IStatus.WARNING, ManagedBuilderCorePlugin.getUniqueIdentifier(), SPACES_IN_PATH, - // subDir.getFullPath().toString(), null)); - // } - // } else { - // status = new MultiStatus(ManagedBuilderCorePlugin.getUniqueIdentifier(), IStatus.OK, "", null); - // } - // return status; } /* @@ -576,8 +193,8 @@ public IPath getBuildWorkingDir() { return null; } - public IFile getBuildFolder() { - return topBuildDir; + public IPath getBuildFolder() { + return topBuildDir.getLocation(); } /* @@ -620,48 +237,7 @@ public boolean isGeneratedResource(IResource resource) { */ @Override public void regenerateDependencies(boolean force) throws CoreException { - // A hack for the pre-3.x GCC compilers is to put dummy targets for deps - // final IWorkspaceRoot root = CCorePlugin.getWorkspace().getRoot(); - // final CoreException[] es = new CoreException[1]; - // toolInfos.accept(new IPathSettingsContainerVisitor() { - // @Override - // public boolean visit(PathSettingsContainer container) { - // ToolInfoHolder h = (ToolInfoHolder) container.getValue(); - // // Collect the methods that will need to be called - // Vector depExts = new Vector(); - // IManagedDependencyGenerator2[] postProcessors = new IManagedDependencyGenerator2[h.buildTools.length]; - // boolean callPopulateDummyTargets = collectDependencyGeneratorInformation(h, depExts, postProcessors); - // // Is there anyone to call if we do find dependency files? - // if (!callPopulateDummyTargets) { - // int i; - // for (i = 0; i < postProcessors.length; i++) { - // if (postProcessors[i] != null) - // break; - // } - // if (i == postProcessors.length) - // return true; - // } - // IResourceInfo rcInfo = config.getResourceInfo(container.getPath(), false); - // for (IPath path : getDependencyMakefiles(h)) { - // // The path to search for the dependency makefile - // IPath relDepFilePath = topBuildDir.getFullPath().append(path); - // IFile depFile = root.getFile(relDepFilePath); - // if (depFile == null || !depFile.isAccessible()) - // continue; - // try { - // callDependencyPostProcessors(rcInfo, h, depFile, postProcessors, callPopulateDummyTargets, - // true); - // } catch (CoreException e) { - // es[0] = e; - // return false; - // } - // } - // return true; - // } - // }); - // if (es[0] != null) - // throw es[0]; - } + } /* * (non-Javadoc) @@ -673,7 +249,7 @@ public void regenerateDependencies(boolean force) throws CoreException { public MultiStatus regenerateMakefiles() throws CoreException { MultiStatus status; // Visit the resources in the project - ResourceProxyVisitor subDirVisitor = new ResourceProxyVisitor(this, config); + ResourceProxyVisitor subDirVisitor = new ResourceProxyVisitor(this); project.accept(subDirVisitor, IResource.NONE); // See if the user has cancelled the build checkCancel(); @@ -726,17 +302,7 @@ public MultiStatus regenerateMakefiles() throws CoreException { checkCancel(); // How did we do - if (!getInvalidDirList().isEmpty()) { - status = new MultiStatus(ManagedBuilderCorePlugin.getUniqueIdentifier(), IStatus.WARNING, "", null); - // Add a new status for each of the bad folders - // TODO: fix error message - for (IResource dir : getInvalidDirList()) { - status.add(new Status(IStatus.WARNING, ManagedBuilderCorePlugin.getUniqueIdentifier(), SPACES_IN_PATH, - dir.getFullPath().toString(), null)); - } - } else { status = new MultiStatus(ManagedBuilderCorePlugin.getUniqueIdentifier(), IStatus.OK, "", null); - } //TOFIX this should be done differently // JABA SLOEBER create the size.awk file @@ -774,262 +340,8 @@ public MultiStatus regenerateMakefiles() throws CoreException { * M A K E F I L E G E N E R A T I O N C O M M O N M E T H O D S ************************************************************************/ - /** - * Answers all of the output extensions that the target of the build has tools - * defined to work on. - * - * @return a Set containing all of the output extensions - */ - // public Set getOutputExtensions(ToolInfoHolder h) { - // if (h.outputExtensionsSet == null) { - // // The set of output extensions which will be produced by this tool. - // // It is presumed that this set is not very large (likely < 10) so - // // a HashSet should provide good performance. - // h.outputExtensionsSet = new HashSet<>(); - // // For each tool for the target, lookup the kinds of sources it - // // outputs - // // and add that to our list of output extensions. - // for (ITool tool : h.buildTools) { - // String[] outputs = tool.getAllOutputExtensions(); - // if (outputs != null) { - // h.outputExtensionsSet.addAll(Arrays.asList(outputs)); - // } - // } - // } - // return h.outputExtensionsSet; - // } - - /** - * Adds file(s) to an entry in a map of macro names to entries. File additions - * look like: example.c, \ - */ - public void addMacroAdditionFiles(HashMap map, String macroName, List list) { - StringBuffer buffer = new StringBuffer(); - buffer.append(map.get(macroName)); - for (int i = 0; i < list.size(); i++) { - String filename = list.get(i); - if (filename.length() > 0) { - filename = ensurePathIsGNUMakeTargetRuleCompatibleSyntax(filename); - buffer.append(new Path(filename).toOSString()).append(WHITESPACE).append(LINEBREAK); - } - } - // re-insert string in the map - map.put(macroName, buffer.toString()); - } - - /** - * Calculates the inputs and outputs for tools that will be generated in the top - * makefile. This information is used by the top level makefile generation - * methods. - */ - // protected void calculateToolInputsOutputs() { - // toolInfos.accept(new IPathSettingsContainerVisitor() { - // @Override - // public boolean visit(PathSettingsContainer container) { - // ToolInfoHolder h = (ToolInfoHolder) container.getValue(); - // ITool[] buildTools = h.buildTools; - // ArduinoManagedBuildGnuToolInfo[] gnuToolInfos = h.gnuToolInfos; - // // We are "done" when the information for all tools has been - // // calculated, - // // or we are not making any progress - // boolean done = false; - // boolean lastChance = false; - // int[] doneState = new int[buildTools.length]; - // // Identify the target tool - // ITool targetTool = config.calculateTargetTool(); - // // if (targetTool == null) { - // // targetTool = info.getToolFromOutputExtension(buildTargetExt); - // // } - // // Initialize the tool info array and the done state - // if (buildTools.length != 0 && buildTools[0].getCustomBuildStep()) - // return true; - // for (int i = 0; i < buildTools.length; i++) { - // if ((buildTools[i] == targetTool)) { - // String ext = config.getArtifactExtension(); - // // try to resolve the build macros in the artifact - // // extension - // try { - // ext = ManagedBuildManager.getBuildMacroProvider().resolveValueToMakefileFormat(ext, "", " ", - // IBuildMacroProvider.CONTEXT_CONFIGURATION, config); - // } catch (BuildMacroException e) { - // /* JABA is not going to write this code */ - // } - // String name = config.getArtifactName(); - // // try to resolve the build macros in the artifact name - // try { - // String resolved = ManagedBuildManager.getBuildMacroProvider().resolveValueToMakefileFormat( - // name, "", " ", IBuildMacroProvider.CONTEXT_CONFIGURATION, config); - // if ((resolved = resolved.trim()).length() > 0) - // name = resolved; - // } catch (BuildMacroException e) { - // /* JABA is not going to write this code */ - // } - // gnuToolInfos[i] = new ArduinoManagedBuildGnuToolInfo(project, buildTools[i], true, name, ext); - // } else { - // gnuToolInfos[i] = new ArduinoManagedBuildGnuToolInfo(project, buildTools[i], false, null, null); - // } - // doneState[i] = 0; - // } - // - // // Set of input extensions for which macros have been created so - // // far - // HashSet handledDepsInputExtensions = new HashSet<>(); - // HashSet handledOutsInputExtensions = new HashSet<>(); - // while (!done) { - // int[] testState = new int[doneState.length]; - // for (int i = 0; i < testState.length; i++) - // testState[i] = 0; - // // Calculate inputs - // for (int i = 0; i < gnuToolInfos.length; i++) { - // if (gnuToolInfos[i].areInputsCalculated()) { - // testState[i]++; - // } else { - // if (gnuToolInfos[i].calculateInputs(ArduinoGnuMakefileGenerator.this, config, - // projectResources, h, lastChance)) { - // testState[i]++; - // } - // } - // } - // // Calculate dependencies - // for (int i = 0; i < gnuToolInfos.length; i++) { - // if (gnuToolInfos[i].areDependenciesCalculated()) { - // testState[i]++; - // } else { - // if (gnuToolInfos[i].calculateDependencies(ArduinoGnuMakefileGenerator.this, config, - // handledDepsInputExtensions, h, lastChance)) { - // testState[i]++; - // } - // } - // } - // // Calculate outputs - // for (int i = 0; i < gnuToolInfos.length; i++) { - // if (gnuToolInfos[i].areOutputsCalculated()) { - // testState[i]++; - // } else { - // if (gnuToolInfos[i].calculateOutputs(ArduinoGnuMakefileGenerator.this, config, - // handledOutsInputExtensions, lastChance)) { - // testState[i]++; - // } - // } - // } - // // Are all calculated? If so, done. - // done = true; - // for (int element : testState) { - // if (element != 3) { - // done = false; - // break; - // } - // } - // // Test our "done" state vs. the previous "done" state. - // // If we have made no progress, give it a "last chance" and - // // then quit - // if (!done) { - // done = true; - // for (int i = 0; i < testState.length; i++) { - // if (testState[i] != doneState[i]) { - // done = false; - // break; - // } - // } - // } - // if (done) { - // if (!lastChance) { - // lastChance = true; - // done = false; - // } - // } - // if (!done) { - // doneState = testState; - // } - // } - // return true; - // } - // }); - // } - /** - * Returns the list of known build rules. This keeps me from generating - * duplicate rules for known file extensions. - * - * @return List - */ - protected Vector getRuleList() { - if (ruleList == null) { - ruleList = new Vector(); - } - return ruleList; - } - - /** - * Returns the list of known dependency file generation lines. This keeps me - * from generating duplicate lines. - * - * @return List - */ - protected Vector getDepRuleList() { - if (depRuleList == null) { - depRuleList = new Vector(); - } - return depRuleList; - } - - /************************************************************************* - * R E S O U R C E V I S I T O R M E T H O D S - ************************************************************************/ - // /** - // * Adds the container of the argument to the list of folders in the project that - // * contribute source files to the build. The resource visitor has already - // * established that the build model knows how to build the files. It has also - // * checked that the resource is not generated as part of the build. - // */ - // protected void appendBuildSubdirectory(IResource resource) { - // IContainer container = resource.getParent(); - // subdirList.add(container); - // } - - /** - * Adds the container of the argument to a list of subdirectories that are to be - * deleted. As a result, the directories that are generated for the output - * should be removed as well. - */ - protected void appendDeletedSubdirectory(IContainer container) { - // No point in adding a folder if the parent is already there - IContainer parent = container.getParent(); - if (!getDeletedDirList().contains(container) && !getDeletedDirList().contains(parent)) { - getDeletedDirList().add(container); - } - } - - /** - * If a file is removed from a source folder (either because of a delete or move - * action on the part of the user), the makefilegenerator has to remove the - * dependency makefile along with the old build goal - */ - protected void appendDeletedFile(IResource resource) { - // Cache this for now - getDeletedFileList().add(resource); - } - - /** - * Adds the container of the argument to a list of subdirectories that are part - * of an incremental rebuild of the project. The makefile fragments for these - * directories will be regenerated as a result of the build. - */ - protected void appendModifiedSubdirectory(IResource resource) { - IContainer container = resource.getParent(); - if (!getModifiedList().contains(container)) { - getModifiedList().add(container); - } - } - - /************************************************************************* - * O T H E R M E T H O D S - ************************************************************************/ - protected void cancel(String message) { - if (monitor != null && !monitor.isCanceled()) { - throw new OperationCanceledException(message); - } - } + /** * Check whether the build has been cancelled. Cancellation requests propagated @@ -1037,241 +349,20 @@ protected void cancel(String message) { * * @see org.eclipse.core.runtime.OperationCanceledException#OperationCanceledException() */ - protected void checkCancel() { + private void checkCancel() { if (monitor != null && monitor.isCanceled()) { throw new OperationCanceledException(); } } - private void deleteBuildTarget(IResource deletedFile) { - // Get the project relative path of the file - String fileName = getFileName(deletedFile); - String srcExtension = deletedFile.getFileExtension(); - IPath folderPath = inFullPathFromOutFullPath(deletedFile.getFullPath().removeLastSegments(1)); - if (folderPath != null) { - folderPath = folderPath.removeFirstSegments(1); - } else { - folderPath = new Path(""); - } - IResourceInfo rcInfo = config.getResourceInfo(folderPath, false); - if (rcInfo instanceof IFileInfo) { - rcInfo = config.getResourceInfo(folderPath.removeLastSegments(1), false); - } - String targetExtension = ((IFolderInfo) rcInfo).getOutputExtension(srcExtension); - if (!targetExtension.isEmpty()) - fileName += DOT + targetExtension; - IPath projectRelativePath = deletedFile.getProjectRelativePath().removeLastSegments(1); - IPath targetFilePath = getBuildWorkingDir().append(projectRelativePath).append(fileName); - IResource depFile = project.findMember(targetFilePath); - if (depFile != null && depFile.exists()) { - try { - depFile.delete(true, new SubProgressMonitor(monitor, 1)); - } catch (CoreException e) { - // This had better be allowed during a build - } - } - } - - private IPath inFullPathFromOutFullPath(IPath path) { - IPath inPath = null; - IPath topBuildPath = topBuildDir.getFullPath(); - if (topBuildPath.isPrefixOf(path)) { - inPath = path.removeFirstSegments(topBuildPath.segmentCount()); - inPath = project.getFullPath().append(path); - } - return inPath; - } - - // private void deleteDepFile(IResource deletedFile) { - // // Calculate the top build directory relative paths of the dependency - // // files - // IPath[] depFilePaths = null; - // ITool tool = null; - // IManagedDependencyGeneratorType depType = null; - // String sourceExtension = deletedFile.getFileExtension(); - // IPath folderPath = inFullPathFromOutFullPath(deletedFile.getFullPath().removeLastSegments(1)); - // if (folderPath != null) { - // folderPath = folderPath.removeFirstSegments(1); - // } else { - // folderPath = new Path(""); - // ToolInfoHolder h = ToolInfoHolder.getToolInfo(this, folderPath); - // ITool[] tools = h.buildTools; - // for (int index = 0; index < tools.length; ++index) { - // if (tools[index].buildsFileType(sourceExtension)) { - // tool = tools[index]; - // depType = tool.getDependencyGeneratorForExtension(sourceExtension); - // break; - // } - // } - // if (depType != null) { - // int calcType = depType.getCalculatorType(); - // if (calcType == IManagedDependencyGeneratorType.TYPE_COMMAND) { - // depFilePaths = new IPath[1]; - // IPath absolutePath = deletedFile.getLocation(); - // depFilePaths[0] = ManagedBuildManager.calculateRelativePath(getTopBuildDir().getFullPath(), - // absolutePath); - // depFilePaths[0] = depFilePaths[0].removeFileExtension().addFileExtension(DEP_EXT); - // } else if (calcType == IManagedDependencyGeneratorType.TYPE_BUILD_COMMANDS - // || calcType == IManagedDependencyGeneratorType.TYPE_PREBUILD_COMMANDS) { - // IManagedDependencyGenerator2 depGen = (IManagedDependencyGenerator2) depType; - // IManagedDependencyInfo depInfo = depGen.getDependencySourceInfo( - // deletedFile.getProjectRelativePath(), deletedFile, config, tool, getBuildWorkingDir()); - // if (depInfo != null) { - // if (calcType == IManagedDependencyGeneratorType.TYPE_BUILD_COMMANDS) { - // IManagedDependencyCommands depCommands = (IManagedDependencyCommands) depInfo; - // depFilePaths = depCommands.getDependencyFiles(); - // } else if (calcType == IManagedDependencyGeneratorType.TYPE_PREBUILD_COMMANDS) { - // IManagedDependencyPreBuild depPreBuild = (IManagedDependencyPreBuild) depInfo; - // depFilePaths = depPreBuild.getDependencyFiles(); - // } - // } - // } - // } - // // Delete the files if they exist - // if (depFilePaths != null) { - // for (IPath dfp : depFilePaths) { - // IPath depFilePath = getBuildWorkingDir().append(dfp); - // IResource depFile = project.findMember(depFilePath); - // if (depFile != null && depFile.exists()) { - // try { - // depFile.delete(true, new SubProgressMonitor(monitor, 1)); - // } catch (CoreException e) { - // // This had better be allowed during a build - // } - // } - // } - // } - // } - // } - - /** - * Returns the current build configuration. - * - * @return String - * @since 8.0 - */ - protected IConfiguration getConfig() { + public IConfiguration getConfig() { return config; } - /** - * Returns the build target extension. - * - * @return String - * @since 8.0 - */ - protected String getBuildTargetExt() { - return buildTargetExt; - } - - /** - * Returns the build target name. - * - * @return String - * @since 8.0 - */ - protected String getBuildTargetName() { - return buildTargetName; - } - - /** - * @return Returns the deletedDirList. - */ - private Vector getDeletedDirList() { - if (deletedDirList == null) { - deletedDirList = new Vector(); - } - return deletedDirList; - } - - private Vector getDeletedFileList() { - if (deletedFileList == null) { - deletedFileList = new Vector(); - } - return deletedFileList; - } - - // public List getDependencyMakefiles(ToolInfoHolder h) { - // if (h.dependencyMakefiles == null) { - // h.dependencyMakefiles = new ArrayList(); - // } - // return h.dependencyMakefiles; - // } - - /** - * Strips off the file extension from the argument and returns the name - * component in a String - */ - private String getFileName(IResource file) { - String answer = ""; - String lastSegment = file.getName(); - int extensionSeparator = lastSegment.lastIndexOf(DOT); - if (extensionSeparator != -1) { - answer = lastSegment.substring(0, extensionSeparator); - } - return answer; - } - - /** - * Answers a Vector containing a list of directories that are invalid for the - * build for some reason. At the moment, the only reason a directory would not - * be considered for the build is if it contains a space in the relative path - * from the project root. - * - * @return a a list of directories that are invalid for the build - */ - private Vector getInvalidDirList() { - if (invalidDirList == null) { - invalidDirList = new Vector(); - } - return invalidDirList; - } - - /** - * @return Collection of Containers which contain modified source files - */ - private Collection getModifiedList() { - if (modifiedList == null) - modifiedList = new LinkedHashSet(); - return modifiedList; - } - // /** - // * @return Collection of subdirectories (IContainers) contributing source code - // * to the build - // */ - // public Collection getSubdirList() { - // return subdirList; - // } - private void removeGeneratedDirectory(IContainer subDir) { - try { - // The source directory isn't empty - if (subDir.exists() && subDir.members().length > 0) - return; - } catch (CoreException e) { - // The resource doesn't exist so we should delete the output folder - } - // Figure out what the generated directory name is and delete it - IPath moduleRelativePath = subDir.getProjectRelativePath(); - IPath buildRoot = getBuildWorkingDir(); - if (buildRoot == null) { - return; - } - IPath moduleOutputPath = buildRoot.append(moduleRelativePath); - IFolder folder = project.getFolder(moduleOutputPath); - if (folder.exists()) { - try { - folder.delete(true, new SubProgressMonitor(monitor, 1)); - } catch (CoreException e) { - // JABA added some logging - Common.log(new Status(IStatus.INFO, Const.CORE_PLUGIN_ID, "Folder deletion failed " + folder.toString(), // - e)); - } - } - } - protected void updateMonitor(String msg) { + private void updateMonitor(String msg) { if (monitor != null && !monitor.isCanceled()) { monitor.subTask(msg); monitor.worked(1); @@ -1292,11 +383,8 @@ public void initialize(int buildKind, IConfiguration cfg, IBuilder builder, IPro if (builder == null) { builder = cfg.getEditableBuilder(); } - try { - projectResources = project.members(); - } catch (CoreException e) { - projectResources = null; - } + + // Save the monitor reference for reporting back to the user this.monitor = monitor; // Get the build info for the project @@ -1329,7 +417,6 @@ public void initialize(int buildKind, IConfiguration cfg, IBuilder builder, IPro } // Cache the build tools config = cfg; - this.builder = builder; // initToolInfos(); // set the top build dir path topBuildDir = project.getFile(cfg.getName()); @@ -1343,9 +430,6 @@ public void initialize(int buildKind, IConfiguration cfg, IBuilder builder, IPro } } - public PathSettingsContainer getToolInfos() { - return toolInfos; - } public IProject getProject() { return project; diff --git a/io.sloeber.core/src/io/sloeber/managedBuild/Internal/MakeRule.java b/io.sloeber.core/src/io/sloeber/managedBuild/Internal/MakeRule.java index a7af4e3e1..cb299e013 100644 --- a/io.sloeber.core/src/io/sloeber/managedBuild/Internal/MakeRule.java +++ b/io.sloeber.core/src/io/sloeber/managedBuild/Internal/MakeRule.java @@ -247,6 +247,7 @@ private String enumPrerequisites(IFile buildFolder) { return ret; } + //FIXME JABA says: this code is weirdly crazy and way longer then I would expect. Should see why public StringBuffer getRule(IProject project, IFile niceBuildFolder, IConfiguration config) { ICConfigurationDescription confDesc = ManagedBuildManager.getDescriptionForConfiguration(config); String cmd = myTool.getToolCommand(); @@ -318,7 +319,7 @@ public StringBuffer getRule(IProject project, IFile niceBuildFolder, IConfigurat StringBuffer buffer = new StringBuffer(); buffer.append(enumTargets(niceBuildFolder)).append(COLON).append(WHITESPACE); buffer.append(enumPrerequisites(niceBuildFolder)).append(NEWLINE); - buffer.append(TAB).append(AT).append(escapedEcho(MESSAGE_START_FILE + WHITESPACE + IN_MACRO)); + buffer.append(TAB).append(AT).append(escapedEcho(MESSAGE_START_FILE + WHITESPACE + OUT_MACRO)); buffer.append(TAB).append(AT).append(escapedEcho(myTool.getAnnouncement())); // JABA add sketch.prebuild and postbouild if needed @@ -342,7 +343,7 @@ public StringBuffer getRule(IProject project, IFile niceBuildFolder, IConfigurat // end JABA add sketch.prebuild and postbouild if needed buffer.append(NEWLINE); - buffer.append(TAB).append(AT).append(escapedEcho(MESSAGE_FINISH_FILE + WHITESPACE + IN_MACRO)); + buffer.append(TAB).append(AT).append(escapedEcho(MESSAGE_FINISH_FILE + WHITESPACE + OUT_MACRO)); buffer.append(TAB).append(AT).append(ECHO_BLANK_LINE).append(NEWLINE); return buffer; } @@ -483,4 +484,8 @@ public boolean isSimpleRule() { } + public boolean isTool(ITool targetTool) { + return myTool.getName().equals(targetTool.getName()); + } + } diff --git a/io.sloeber.core/src/io/sloeber/managedBuild/Internal/MakeRules.java b/io.sloeber.core/src/io/sloeber/managedBuild/Internal/MakeRules.java index 0de4d656f..c533eddbc 100644 --- a/io.sloeber.core/src/io/sloeber/managedBuild/Internal/MakeRules.java +++ b/io.sloeber.core/src/io/sloeber/managedBuild/Internal/MakeRules.java @@ -104,4 +104,14 @@ public Set getMakeRules() { return myMakeRules; } + public Set getTargetsForTool(ITool targetTool) { + Set ret=new HashSet<>(); + for(MakeRule curMakeRule :myMakeRules) { + if(curMakeRule.isTool(targetTool)) { + ret.addAll( curMakeRule.getTargetFiles()); + } + } + return ret; + } + } diff --git a/io.sloeber.core/src/io/sloeber/managedBuild/Internal/ManagebBuildCommon.java b/io.sloeber.core/src/io/sloeber/managedBuild/Internal/ManagebBuildCommon.java index 03a7812be..285bcb4fe 100644 --- a/io.sloeber.core/src/io/sloeber/managedBuild/Internal/ManagebBuildCommon.java +++ b/io.sloeber.core/src/io/sloeber/managedBuild/Internal/ManagebBuildCommon.java @@ -25,7 +25,6 @@ import org.eclipse.cdt.managedbuilder.core.IResourceInfo; import org.eclipse.cdt.managedbuilder.core.ITool; import org.eclipse.cdt.managedbuilder.core.ManagedBuildManager; -import org.eclipse.cdt.managedbuilder.internal.core.ManagedMakeMessages; import org.eclipse.cdt.managedbuilder.internal.core.OutputType; import org.eclipse.cdt.managedbuilder.macros.BuildMacroException; import org.eclipse.cdt.managedbuilder.macros.IBuildMacroProvider; @@ -365,7 +364,7 @@ static public String escapedEcho(String string) { static protected StringBuffer addDefaultHeader() { StringBuffer buffer = new StringBuffer(); outputCommentLine(buffer); - buffer.append(COMMENT_SYMBOL).append(WHITESPACE).append(ManagedMakeMessages.getResourceString(HEADER)) + buffer.append(COMMENT_SYMBOL).append(WHITESPACE).append(MESSAGE_HEADER) .append(NEWLINE); outputCommentLine(buffer); buffer.append(NEWLINE); diff --git a/io.sloeber.core/src/io/sloeber/managedBuild/Internal/ManagedBuildConstants.java b/io.sloeber.core/src/io/sloeber/managedBuild/Internal/ManagedBuildConstants.java index eed1cf279..0611799ed 100644 --- a/io.sloeber.core/src/io/sloeber/managedBuild/Internal/ManagedBuildConstants.java +++ b/io.sloeber.core/src/io/sloeber/managedBuild/Internal/ManagedBuildConstants.java @@ -1,5 +1,4 @@ package io.sloeber.managedBuild.Internal; - import java.io.File; import org.eclipse.cdt.managedbuilder.internal.core.ManagedMakeMessages; @@ -8,92 +7,94 @@ @SuppressWarnings("nls") public class ManagedBuildConstants { - public static final String AT = "@"; - public static final String COLON = ":"; - public static final int COLS_PER_LINE = 80; - public static final String COMMENT_SYMBOL = "#"; - public static final String DOLLAR_SYMBOL = "$"; - public static final String DEP_EXT = "d"; - public static final String DEPFILE_NAME = "subdir.dep"; - public static final String DOT = "."; - public static final String DASH = "-"; - public static final String ECHO = "echo"; - public static final String IN_MACRO = "$<"; - public static final String LINEBREAK = "\\\n"; - public static final String LOGICAL_AND = "&&"; - public static final String MAKEFILE_DEFS = "makefile.defs"; - public static final String MAKEFILE_INIT = "makefile.init"; - public static final String MAKEFILE_NAME = "makefile"; - public static final String MAKEFILE_TARGETS = "makefile.targets"; - public static final String MAKE = "$(MAKE)"; - public static final String NO_PRINT_DIR = "--no-print-directory"; + public static final String AT = "@"; + public static final String COLON = ":"; + public static final int COLS_PER_LINE = 80; + public static final String COMMENT_SYMBOL = "#"; + public static final String COMMENT_START = "# "; + public static final String DOLLAR_SYMBOL = "$"; + public static final String DEP_EXT = "d"; + public static final String DEPFILE_NAME = "subdir.dep"; + public static final String DOT = "."; + public static final String DASH = "-"; + public static final String ECHO = "echo"; + public static final String IN_MACRO = "$<"; + public static final String LINEBREAK = "\\\n"; + public static final String LOGICAL_AND = "&&"; + public static final String MAKEFILE_DEFS = "makefile.defs"; + public static final String MAKEFILE_INIT = "makefile.init"; + public static final String MAKEFILE_NAME = "makefile"; + public static final String MAKEFILE_TARGETS = "makefile.targets"; + public static final String MAKE = "$(MAKE)"; + public static final String NO_PRINT_DIR = "--no-print-directory"; - public static final String MODFILE_NAME = "subdir.mk"; - public static final String NEWLINE = System.getProperty("line.separator"); - public static final String OBJECTS_MAKFILE = "objects.mk"; - public static final String OUT_MACRO = "$@"; - public static final String ROOT = ".."; - public static final String SEPARATOR = "/"; - public static final String SINGLE_QUOTE = "'"; - public static final String SRCSFILE_NAME = "sources.mk"; - public static final String TAB = "\t"; - public static final String WHITESPACE = " "; - public static final String WILDCARD = "%"; + public static final String MODFILE_NAME = "subdir.mk"; + public static final String NEWLINE = System.getProperty("line.separator"); + public static final String OBJECTS_MAKFILE = "objects.mk"; + public static final String OUT_MACRO = "$@"; + public static final String ROOT = ".."; + public static final String SEPARATOR = "/"; + public static final String SINGLE_QUOTE = "'"; + public static final String SRCSFILE_NAME = "sources.mk"; + public static final String TAB = "\t"; + public static final String WHITESPACE = " "; + public static final String WILDCARD = "%"; - // String constants for makefile contents and messages - public static final String COMMENT = "MakefileGenerator.comment"; - public static final String HEADER = COMMENT + ".header"; - public static final String MESSAGE_FINISH_BUILD = ManagedMakeMessages - .getResourceString("MakefileGenerator.message.finish.build"); - public static final String MESSAGE_FINISH_FILE = ManagedMakeMessages - .getResourceString("MakefileGenerator.message.finish.file"); - public static final String MESSAGE_START_BUILD = ManagedMakeMessages - .getResourceString("MakefileGenerator.message.start.build"); - public static final String MESSAGE_START_FILE = ManagedMakeMessages - .getResourceString("MakefileGenerator.message.start.file"); - public static final String MESSAGE_START_DEPENDENCY = ManagedMakeMessages - .getResourceString("MakefileGenerator.message.start.dependency"); - public static final String MESSAGE_NO_TARGET_TOOL = ManagedMakeMessages - .getResourceString("MakefileGenerator.message.no.target"); + // String constants for makefile contents and messages + public static final String COMMENT = "MakefileGenerator.comment"; + public static final String HEADER = COMMENT + ".header"; - public static final String MOD_LIST = COMMENT + ".module.list"; - public static final String MOD_LIST_MESSAGE = ManagedMakeMessages.getResourceString(MOD_LIST); - public static final String MOD_VARS = COMMENT + ".module.variables"; - public static final String MOD_RULES = COMMENT + ".build.rule"; - public static final String BUILD_TOP = COMMENT + ".build.toprules"; - public static final String ALL_TARGET = COMMENT + ".build.alltarget"; - public static final String MAINBUILD_TARGET = COMMENT + ".build.mainbuildtarget"; - public static final String BUILD_TARGETS = COMMENT + ".build.toptargets"; - public static final String SRC_LISTS = COMMENT + ".source.list"; - public static final String EMPTY_STRING = ""; - public static final String[] EMPTY_STRING_ARRAY = new String[0]; - public static final String OBJS_MACRO = "OBJS"; - public static final String MACRO_ADDITION_ADDPREFIX_HEADER = "${addprefix "; - public static final String MACRO_ADDITION_ADDPREFIX_SUFFIX = "," + WHITESPACE + LINEBREAK; - public static final String MAKE_ADDITION = " +="; - public static final String MAKE_EQUAL = " :="; - public static final String MACRO_ADDITION_PREFIX_SUFFIX = MAKE_ADDITION + LINEBREAK; - public static final String PREBUILD = "pre-build"; - public static final String MAINBUILD = "main-build"; - public static final String POSTBUILD = "post-build"; - public static final String SECONDARY_OUTPUTS = "secondary-outputs"; + public static final String BUILD_TOP = COMMENT + ".build.toprules"; + public static final String BUILD_TARGETS = COMMENT + ".build.toptargets"; + public static final String EMPTY_STRING = ""; + public static final String[] EMPTY_STRING_ARRAY = new String[0]; + public static final String OBJS_MACRO = "OBJS"; + public static final String MACRO_ADDITION_ADDPREFIX_HEADER = "${addprefix "; + public static final String MACRO_ADDITION_ADDPREFIX_SUFFIX = "," + WHITESPACE + LINEBREAK; + public static final String MAKE_ADDITION = " +="; + public static final String MAKE_EQUAL = " :="; + public static final String MACRO_ADDITION_PREFIX_SUFFIX = MAKE_ADDITION + LINEBREAK; + public static final String PREBUILD = "pre-build"; + public static final String MAINBUILD = "main-build"; + public static final String POSTBUILD = "post-build"; + public static final String SECONDARY_OUTPUTS = "secondary-outputs"; - public static final IPath DOT_SLASH_PATH = new Path("./"); - public static final String FILE_SEPARATOR = File.separator; - // Enumerations - public static final int PROJECT_RELATIVE = 1, PROJECT_SUBDIR_RELATIVE = 2, ABSOLUTE = 3; + public static final IPath DOT_SLASH_PATH = new Path("./"); + public static final String FILE_SEPARATOR = File.separator; + // Enumerations + public static final int PROJECT_RELATIVE = 1, PROJECT_SUBDIR_RELATIVE = 2, ABSOLUTE = 3; - public static final String DEFAULT_PATTERN = "${COMMAND} ${FLAGS} ${OUTPUT_FLAG} ${OUTPUT_PREFIX}${OUTPUT} ${INPUTS}"; - public static final String DOUBLE_QUOTE = "\""; + public static final String DEFAULT_PATTERN = "${COMMAND} ${FLAGS} ${OUTPUT_FLAG} ${OUTPUT_PREFIX}${OUTPUT} ${INPUTS}"; + public static final String DOUBLE_QUOTE = "\""; - public static final String CMD_LINE_PRM_NAME = "COMMAND"; - public static final String FLAGS_PRM_NAME = "FLAGS"; - public static final String OUTPUT_FLAG_PRM_NAME = "OUTPUT_FLAG"; - public static final String OUTPUT_PREFIX_PRM_NAME = "OUTPUT_PREFIX"; - public static final String OUTPUT_PRM_NAME = "OUTPUT"; - public static final String INPUTS_PRM_NAME = "INPUTS"; - public static final String VARIABLE_PREFIX = "${"; - public static final String VARIABLE_SUFFIX = "}"; - public static final String DEPENDENCY_SUFFIX = "_DEPS"; + public static final String CMD_LINE_PRM_NAME = "COMMAND"; + public static final String FLAGS_PRM_NAME = "FLAGS"; + public static final String OUTPUT_FLAG_PRM_NAME = "OUTPUT_FLAG"; + public static final String OUTPUT_PREFIX_PRM_NAME = "OUTPUT_PREFIX"; + public static final String OUTPUT_PRM_NAME = "OUTPUT"; + public static final String INPUTS_PRM_NAME = "INPUTS"; + public static final String VARIABLE_PREFIX = "${"; + public static final String VARIABLE_SUFFIX = "}"; + public static final String DEPENDENCY_SUFFIX = "_DEPS"; + public static final String MESSAGE_FINISH_BUILD = ManagedMakeMessages + .getResourceString("MakefileGenerator.message.finish.build"); + public static final String MESSAGE_FINISH_FILE = ManagedMakeMessages + .getResourceString("MakefileGenerator.message.finish.file"); + public static final String MESSAGE_START_BUILD = ManagedMakeMessages + .getResourceString("MakefileGenerator.message.start.build"); + public static final String MESSAGE_START_FILE = ManagedMakeMessages + .getResourceString("MakefileGenerator.message.start.file"); + public static final String MESSAGE_START_DEPENDENCY = ManagedMakeMessages + .getResourceString("MakefileGenerator.message.start.dependency"); + public static final String MESSAGE_NO_TARGET_TOOL = ManagedMakeMessages + .getResourceString("MakefileGenerator.message.no.target"); + public static final String MESSAGE_MOD_VARS = ManagedMakeMessages.getResourceString(COMMENT + ".module.variables"); + public static final String MESSAGE_MOD_RULES = ManagedMakeMessages.getResourceString(COMMENT + ".build.rule"); + public static final String MOD_LIST_MESSAGE = ManagedMakeMessages.getResourceString(COMMENT + ".module.list"); + public static final String MESSAGE_MAINBUILD_TARGET = ManagedMakeMessages + .getResourceString(COMMENT + ".build.mainbuildtarget"); + public static final String MESSAGE_ALL_TARGET = ManagedMakeMessages.getResourceString(COMMENT + ".build.alltarget"); + public static final String MESSAGE_SRC_LISTS = ManagedMakeMessages.getResourceString(COMMENT + ".source.list"); + public static final String MESSAGE_HEADER =ManagedMakeMessages.getResourceString(HEADER); } diff --git a/io.sloeber.core/src/io/sloeber/managedBuild/Internal/SubDirMakeGenerator.java b/io.sloeber.core/src/io/sloeber/managedBuild/Internal/SubDirMakeGenerator.java index cdd7c7bc9..fd10183a6 100644 --- a/io.sloeber.core/src/io/sloeber/managedBuild/Internal/SubDirMakeGenerator.java +++ b/io.sloeber.core/src/io/sloeber/managedBuild/Internal/SubDirMakeGenerator.java @@ -14,7 +14,6 @@ import org.eclipse.cdt.managedbuilder.core.IInputType; import org.eclipse.cdt.managedbuilder.core.IOutputType; import org.eclipse.cdt.managedbuilder.core.ITool; -import org.eclipse.cdt.managedbuilder.internal.core.ManagedMakeMessages; import org.eclipse.core.resources.IContainer; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IProject; @@ -107,7 +106,7 @@ private IPath getBuildPath() { } private IPath getBuildFolder() { - return caller.getBuildFolder().getLocation(); + return caller.getBuildFolder(); } private IFile getTopBuildDir() { @@ -143,7 +142,7 @@ private StringBuffer GenerateMacros() { StringBuffer buffer = new StringBuffer(); IFile buildRoot = getTopBuildDir(); buffer.append(NEWLINE); - buffer.append(COMMENT_SYMBOL).append(WHITESPACE).append(ManagedMakeMessages.getResourceString(MOD_VARS)) + buffer.append(COMMENT_SYMBOL).append(WHITESPACE).append(MESSAGE_MOD_VARS) .append(NEWLINE); HashSet macroNames = new HashSet<>(); for (MakeRule makeRule : myMakeRules) { @@ -170,7 +169,7 @@ private StringBuffer GenerateMacros() { private StringBuffer GenerateRules(IConfiguration config) { StringBuffer buffer = new StringBuffer(); buffer.append(NEWLINE); - buffer.append(COMMENT_SYMBOL).append(WHITESPACE).append(ManagedMakeMessages.getResourceString(MOD_RULES)) + buffer.append(COMMENT_SYMBOL).append(WHITESPACE).append(MESSAGE_MOD_RULES) .append(NEWLINE); for (MakeRule makeRule : myMakeRules) { @@ -235,7 +234,6 @@ private void getMakeRulesFromSourceFiles(IContainer module) { } } catch (CoreException e) { - // TODO Auto-generated catch block e.printStackTrace(); } } diff --git a/io.sloeber.core/src/io/sloeber/managedBuild/Internal/TopMakeFileGenerator.java b/io.sloeber.core/src/io/sloeber/managedBuild/Internal/TopMakeFileGenerator.java index ed9e3b1db..296d2a40d 100644 --- a/io.sloeber.core/src/io/sloeber/managedBuild/Internal/TopMakeFileGenerator.java +++ b/io.sloeber.core/src/io/sloeber/managedBuild/Internal/TopMakeFileGenerator.java @@ -3,30 +3,19 @@ import static io.sloeber.managedBuild.Internal.ManagebBuildCommon.*; import static io.sloeber.managedBuild.Internal.ManagedBuildConstants.*; -import java.util.ArrayList; import java.util.Collection; -import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedHashSet; -import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; -import java.util.Vector; - import org.eclipse.cdt.core.settings.model.ICConfigurationDescription; -import org.eclipse.cdt.core.settings.model.util.PathSettingsContainer; -import org.eclipse.cdt.managedbuilder.core.BuildException; import org.eclipse.cdt.managedbuilder.core.IConfiguration; import org.eclipse.cdt.managedbuilder.core.IInputType; -import org.eclipse.cdt.managedbuilder.core.IManagedCommandLineGenerator; -import org.eclipse.cdt.managedbuilder.core.IManagedCommandLineInfo; import org.eclipse.cdt.managedbuilder.core.IOutputType; import org.eclipse.cdt.managedbuilder.core.ITool; import org.eclipse.cdt.managedbuilder.core.ManagedBuildManager; -import org.eclipse.cdt.managedbuilder.internal.core.ManagedMakeMessages; -import org.eclipse.cdt.managedbuilder.internal.macros.FileContextData; import org.eclipse.cdt.managedbuilder.macros.BuildMacroException; import org.eclipse.cdt.managedbuilder.macros.IBuildMacroProvider; import org.eclipse.core.resources.IContainer; @@ -39,898 +28,404 @@ import io.sloeber.managedBuild.api.INewManagedOutputNameProvider; public class TopMakeFileGenerator { - private ArduinoGnuMakefileGenerator caller = null; - private Set mySubDirMakeRules = new LinkedHashSet<>(); - private MakeRules myMakeRules = new MakeRules(); - private Collection myFoldersToBuild; - private Map> myAllSourceTargets = new HashMap<>(); - private Set myDependencyMacros = new HashSet<>(); - - private IConfiguration getConfig() { - return caller.getConfig(); - } - - private IProject getProject() { - return caller.getProject(); - } - - TopMakeFileGenerator(ArduinoGnuMakefileGenerator theCaller, Set subDirMakeRules, - Collection foldersToBuild) { - caller = theCaller; - mySubDirMakeRules = subDirMakeRules; - myFoldersToBuild = foldersToBuild; - for (MakeRule curMakeRule : mySubDirMakeRules) { - myAllSourceTargets.putAll(curMakeRule.getTargets()); - myDependencyMacros.addAll(curMakeRule.getDependecyMacros()); - } - MakeRules makeRules = new MakeRules(); - Map> generatedFiles = new HashMap<>(); - for (MakeRule makeRule : subDirMakeRules) { - Map> targets = makeRule.getTargets(); - for (Entry> curTarget : targets.entrySet()) { - Set esxistingTarget = generatedFiles.get(curTarget.getKey()); - if (esxistingTarget != null) { - esxistingTarget.addAll(curTarget.getValue()); - } else { - Set copySet = new HashSet<>(); - copySet.addAll(curTarget.getValue()); - generatedFiles.put(curTarget.getKey(), copySet); - } - - } - } - int depth = 10; - while (depth > 0) { - makeRules = getMakeRulesFromGeneratedFiles(generatedFiles); - generatedFiles.clear(); - if (makeRules.size() > 0) { - depth--; - myMakeRules.addRules(makeRules); - generatedFiles.putAll(makeRules.getTargets()); - } else { - depth = 0; - } - } - - } - - private Vector getRuleList() { - return caller.getRuleList(); - } - - private PathSettingsContainer getToolInfos() { - return caller.getToolInfos(); - } - - private IPath getBuildFolder() { - return caller.getBuildFolder().getLocation(); - } - - public void generateMakefile() throws CoreException { - IProject project = getProject(); - IConfiguration config = getConfig(); - - StringBuffer buffer = new StringBuffer(); - buffer.append(addDefaultHeader()); - buffer.append(addMacros()); - List outputVarsAdditionsList = new ArrayList<>(); - // Determine target rules - buffer.append(addTargets(outputVarsAdditionsList, true)); - // Add outputMacros that were added to by the target rules - //TOFIX removed line - // buffer.append(writeTopAdditionMacros(outputVarsAdditionsList, mySecondaryMacros)); - // Add target rules - //buffer.append(targetRules); - // Save the file - buffer.append(GenerateMacros()); - buffer.append(GenerateRules(getConfig())); - - IFile fileHandle = project.getFile(config.getName() + '/' + MAKEFILE_NAME); - save(buffer, fileHandle); - } - - private StringBuffer addMacros() { - IConfiguration config = getConfig(); - StringBuffer buffer = new StringBuffer(); - buffer.append("-include " + ROOT + FILE_SEPARATOR + MAKEFILE_INIT).append(NEWLINE); - buffer.append(NEWLINE); - // Get the clean command from the build model - buffer.append("RM := "); - // support macros in the clean command - try { - String cleanCommand = ManagedBuildManager.getBuildMacroProvider().resolveValueToMakefileFormat( - config.getCleanCommand(), EMPTY_STRING, WHITESPACE, IBuildMacroProvider.CONTEXT_CONFIGURATION, - config); - buffer.append(cleanCommand).append(NEWLINE); - buffer.append(NEWLINE); - } catch (BuildMacroException e) { - // jaba is not going to write this code - } - - // Now add the source providers - buffer.append(COMMENT_SYMBOL).append(WHITESPACE).append(ManagedMakeMessages.getResourceString(SRC_LISTS)) - .append(NEWLINE); - buffer.append("-include sources.mk").append(NEWLINE); - buffer.append("-include subdir.mk").append(NEWLINE); - // Add includes for each subdir in child-subdir-first order (required - // for makefile rule matching to work). - List subDirList = new ArrayList<>(); - for (IContainer subDir : myFoldersToBuild) { - String projectRelativePath = subDir.getProjectRelativePath().toOSString(); - if (!projectRelativePath.isEmpty()) - subDirList.add(0, projectRelativePath); - } - Collections.sort(subDirList, Collections.reverseOrder()); - for (String dir : subDirList) { - buffer.append("-include ").append(escapeWhitespaces(dir)).append(FILE_SEPARATOR).append("subdir.mk") - .append(NEWLINE); - } - // Change the include of the "root" (our sketch) folder to be before - // libraries and other files - // buffer.append("-include subdir.mk" + NEWLINE); // - buffer.append("-include objects.mk").append(NEWLINE).append(NEWLINE); - if (!myDependencyMacros.isEmpty()) { - buffer.append("ifneq ($(MAKECMDGOALS),clean)").append(NEWLINE); - for (String depsMacro : myDependencyMacros) { - buffer.append("ifneq ($(strip $(").append(depsMacro).append(")),)").append(NEWLINE); - buffer.append("-include $(").append(depsMacro).append(')').append(NEWLINE); - buffer.append("endif").append(NEWLINE); - } - buffer.append("endif").append(NEWLINE).append(NEWLINE); - } - // Include makefile.defs supplemental makefile - buffer.append("-include ").append(ROOT).append(FILE_SEPARATOR).append(MAKEFILE_DEFS).append(NEWLINE); - return (buffer.append(NEWLINE)); - } - - private StringBuffer addTargets(List outputVarsAdditionsList, boolean rebuild) { - IConfiguration config = getConfig(); - StringBuffer buffer = new StringBuffer(); - // IConfiguration config = info.getDefaultConfiguration(); - // Assemble the information needed to generate the targets - String prebuildStep = config.getPrebuildStep(); - // JABA issue927 adding recipe.hooks.sketch.prebuild.NUMBER.pattern as cdt - // prebuild command if needed - ICConfigurationDescription confDesc = ManagedBuildManager.getDescriptionForConfiguration(config); - String sketchPrebuild = io.sloeber.core.common.Common.getBuildEnvironmentVariable(confDesc, "sloeber.prebuild", - new String(), false); - if (!sketchPrebuild.isEmpty()) { - String separator = new String(); - if (!prebuildStep.isEmpty()) { - prebuildStep = prebuildStep + "\n\t" + sketchPrebuild; - } else { - prebuildStep = sketchPrebuild; - } - } - // end off JABA issue927 - try { - // try to resolve the build macros in the prebuild step - prebuildStep = ManagedBuildManager.getBuildMacroProvider().resolveValueToMakefileFormat(prebuildStep, - EMPTY_STRING, WHITESPACE, IBuildMacroProvider.CONTEXT_CONFIGURATION, config); - } catch (BuildMacroException e) { - /* JABA is not going to write this code */ - } - prebuildStep = prebuildStep.trim(); - String postbuildStep = config.getPostbuildStep(); - try { - // try to resolve the build macros in the postbuild step - postbuildStep = ManagedBuildManager.getBuildMacroProvider().resolveValueToMakefileFormat(postbuildStep, - EMPTY_STRING, WHITESPACE, IBuildMacroProvider.CONTEXT_CONFIGURATION, config); - } catch (BuildMacroException e) { - /* JABA is not going to write this code */ - } - postbuildStep = postbuildStep.trim(); - String preannouncebuildStep = config.getPreannouncebuildStep(); - String postannouncebuildStep = config.getPostannouncebuildStep(); - String targets = rebuild ? "clean all" : "all"; - ITool targetTool = config.calculateTargetTool(); - // if (targetTool == null) { - // targetTool = info.getToolFromOutputExtension(buildTargetExt); - // } - // Get all the projects the build target depends on - // If this configuration produces a static archive, building the archive - // doesn't depend on the output - // from any of the referenced configurations - IConfiguration[] refConfigs = new IConfiguration[0]; - if (config.getBuildArtefactType() == null || !ManagedBuildManager.BUILD_ARTEFACT_TYPE_PROPERTY_STATICLIB - .equals(config.getBuildArtefactType().getId())) - refConfigs = ManagedBuildManager.getReferencedConfigurations(config); - /* - * try { refdProjects = project.getReferencedProjects(); } catch (CoreException - * e) { // There are 2 exceptions; the project does not exist or it is not open - * // and neither conditions apply if we are building for it .... } - */ - // If a prebuild step exists, redefine the all target to be - // all: {pre-build} main-build - // and then reset the "traditional" all target to main-build - // This will allow something meaningful to happen if the generated - // makefile is - // extracted and run standalone via "make all" - // - - // JABA add the arduino upload/program targets - buffer.append("\n#bootloaderTest\n" + "BurnBootLoader: \n" - + "\t@echo trying to burn bootloader ${bootloader.tool}\n" - + "\t${tools.${bootloader.tool}.erase.pattern}\n" + "\t${tools.${bootloader.tool}.bootloader.pattern}\n" - + "\n" + "uploadWithBuild: all\n" - + "\t@echo trying to build and upload with upload tool ${upload.tool}\n" - + "\t${tools.${upload.tool}.upload.pattern}\n" + "\n" + "uploadWithoutBuild: \n" - + "\t@echo trying to upload without build with upload tool ${upload.tool}\n" - + "\t${tools.${upload.tool}.upload.pattern}\n" + " \n" + "uploadWithProgrammerWithBuild: all\n" - + "\t@echo trying to build and upload with programmer ${program.tool}\n" - + "\t${tools.${program.tool}.program.pattern}\n" + "\n" + "uploadWithProgrammerWithoutBuild: \n" - + "\t@echo trying to upload with programmer ${program.tool} without build\n" - + "\t${tools.${program.tool}.program.pattern}\n\n"); - String defaultTarget = "all:"; - if (prebuildStep.length() > 0) { - // Add the comment for the "All" target - buffer.append(COMMENT_SYMBOL).append(WHITESPACE).append(ManagedMakeMessages.getResourceString(ALL_TARGET)) - .append(NEWLINE); - buffer.append(defaultTarget).append(NEWLINE); - buffer.append(TAB).append(MAKE).append(WHITESPACE).append(NO_PRINT_DIR).append(WHITESPACE).append(PREBUILD) - .append(NEWLINE); - buffer.append(TAB).append(MAKE).append(WHITESPACE).append(NO_PRINT_DIR).append(WHITESPACE).append(MAINBUILD) - .append(NEWLINE); - buffer.append(NEWLINE); - defaultTarget = MAINBUILD.concat(COLON); - buffer.append(COMMENT_SYMBOL).append(WHITESPACE) - .append(ManagedMakeMessages.getResourceString(MAINBUILD_TARGET)).append(NEWLINE); - } else - // Add the comment for the "All" target - buffer.append(COMMENT_SYMBOL).append(WHITESPACE).append(ManagedMakeMessages.getResourceString(ALL_TARGET)) - .append(NEWLINE); - // Write out the all target first in case someone just runs make - // all: or mainbuild: - String outputPrefix = EMPTY_STRING; - if (targetTool != null) { - outputPrefix = targetTool.getOutputPrefix(); - } - buffer.append(defaultTarget).append(WHITESPACE).append(outputPrefix) - .append(ensurePathIsGNUMakeTargetRuleCompatibleSyntax(caller.buildTargetName)); - if (caller.buildTargetExt.length() > 0) { - buffer.append(DOT).append(caller.buildTargetExt); - } - // Add the Secondary Outputs to the all target, if any - IOutputType[] secondaryOutputs = config.getToolChain().getSecondaryOutputs(); - if (secondaryOutputs.length > 0) { - buffer.append(WHITESPACE).append(SECONDARY_OUTPUTS); - } - buffer.append(NEWLINE).append(NEWLINE); - /* - * The build target may depend on other projects in the workspace. These are - * captured in the deps target: deps: ; $(MAKE) [clean - * all | all]> - */ - // Vector managedProjectOutputs = new Vector(refdProjects.length); - // if (refdProjects.length > 0) { - Vector managedProjectOutputs = new Vector(refConfigs.length); - if (refConfigs.length > 0) { - boolean addDeps = true; - // if (refdProjects != null) { - for (IConfiguration depCfg : refConfigs) { - // IProject dep = refdProjects[i]; - if (!depCfg.isManagedBuildOn()) - continue; - // if (!dep.exists()) continue; - if (addDeps) { - buffer.append("dependents:").append(NEWLINE); - addDeps = false; - } - String buildDir = depCfg.getOwner().getLocation().toOSString(); - String depTargets = targets; - // if (ManagedBuildManager.manages(dep)) { - // Add the current configuration to the makefile path - // IManagedBuildInfo depInfo = - // ManagedBuildManager.getBuildInfo(dep); - buildDir += FILE_SEPARATOR + depCfg.getName(); - // Extract the build artifact to add to the dependency list - String depTarget = depCfg.getArtifactName(); - String depExt = depCfg.getArtifactExtension(); - try { - // try to resolve the build macros in the artifact extension - depExt = ManagedBuildManager.getBuildMacroProvider().resolveValueToMakefileFormat(depExt, "", " ", - IBuildMacroProvider.CONTEXT_CONFIGURATION, depCfg); - } catch (BuildMacroException e) { - /* JABA is not going to write this code */ - } - try { - // try to resolve the build macros in the artifact name - String resolved = ManagedBuildManager.getBuildMacroProvider().resolveValueToMakefileFormat( - depTarget, "", " ", IBuildMacroProvider.CONTEXT_CONFIGURATION, depCfg); - if ((resolved = resolved.trim()).length() > 0) - depTarget = resolved; - } catch (BuildMacroException e) { - /* JABA is not going to write this code */ - } - String depPrefix = depCfg.getOutputPrefix(depExt); - if (depCfg.needsRebuild()) { - depTargets = "clean all"; - } - String dependency = buildDir + FILE_SEPARATOR + depPrefix + depTarget; - if (depExt.length() > 0) { - dependency += DOT + depExt; - } - dependency = escapeWhitespaces(dependency); - managedProjectOutputs.add(dependency); - // } - buffer.append(TAB).append("-cd").append(WHITESPACE).append(escapeWhitespaces(buildDir)) - .append(WHITESPACE).append(LOGICAL_AND).append(WHITESPACE).append("$(MAKE) ").append(depTargets) - .append(NEWLINE); - } - // } - buffer.append(NEWLINE); - } - // Add the targets tool rules - buffer.append(addTargetsRules(targetTool, outputVarsAdditionsList, managedProjectOutputs, - (postbuildStep.length() > 0))); - // Add the prebuild step target, if specified - if (prebuildStep.length() > 0) { - buffer.append(PREBUILD).append(COLON).append(NEWLINE); - if (preannouncebuildStep.length() > 0) { - buffer.append(TAB).append(DASH).append(AT).append(escapedEcho(preannouncebuildStep)); - } - buffer.append(TAB).append(DASH).append(prebuildStep).append(NEWLINE); - buffer.append(TAB).append(DASH).append(AT).append(ECHO_BLANK_LINE).append(NEWLINE); - } - // Add the postbuild step, if specified - if (postbuildStep.length() > 0) { - buffer.append(POSTBUILD).append(COLON).append(NEWLINE); - if (postannouncebuildStep.length() > 0) { - buffer.append(TAB).append(DASH).append(AT).append(escapedEcho(postannouncebuildStep)); - } - buffer.append(TAB).append(DASH).append(postbuildStep).append(NEWLINE); - buffer.append(TAB).append(DASH).append(AT).append(ECHO_BLANK_LINE).append(NEWLINE); - } - // Add the Secondary Outputs target, if needed - //TOFIX removed this - // if (secondaryOutputs.length > 0) { - // buffer.append(SECONDARY_OUTPUTS).append(COLON); - // Vector outs2 = calculateSecondaryOutputs(secondaryOutputs); - // for (int i = 0; i < outs2.size(); i++) { - // buffer.append(WHITESPACE).append("$(").append(outs2.get(i)).append(')'); - // } - // buffer.append(NEWLINE).append(NEWLINE); - // } - // Add all the needed dummy and phony targets - buffer.append(".PHONY: all clean dependents"); - if (prebuildStep.length() > 0) { - buffer.append(WHITESPACE).append(MAINBUILD).append(WHITESPACE).append(PREBUILD); - } - if (postbuildStep.length() > 0) { - buffer.append(WHITESPACE).append(POSTBUILD); - } - buffer.append(NEWLINE); - for (String output : managedProjectOutputs) { - buffer.append(output).append(COLON).append(NEWLINE); - } - buffer.append(NEWLINE); - // Include makefile.targets supplemental makefile - buffer.append("-include ").append(ROOT).append(FILE_SEPARATOR).append(MAKEFILE_TARGETS).append(NEWLINE); - return buffer; - } - - /** - * Create the rule - * - * @param buffer - * Buffer to add makefile rules to - * @param bTargetTool - * True if this is the target tool - * @param targetName - * If this is the "targetTool", the target file name, else - * null - * @param targetExt - * If this is the "targetTool", the target file extension, else - * null - * @param outputVarsAdditionsList - * list to add needed build output variables to - * @param managedProjectOutputs - * Other projects in the workspace that this project depends upon - * @param bEmitPostBuildStepCall - * Emit post-build step invocation - */ - protected boolean addRuleForTool(ITool tool, StringBuffer buffer, boolean bTargetTool, String targetName, - String targetExt, List outputVarsAdditionsList, Vector managedProjectOutputs, - boolean bEmitPostBuildStepCall) { - IConfiguration config = getConfig(); - Vector inputs = new Vector(); - Vector dependencies = new Vector(); - Vector outputs = new Vector(); - Vector enumeratedPrimaryOutputs = new Vector(); - Vector enumeratedSecondaryOutputs = new Vector(); - Vector outputVariables = new Vector(); - Vector additionalTargets = new Vector(); - String outputPrefix = EMPTY_STRING; - //TOFIX removed this - // if (!getToolInputsOutputs(tool, inputs, dependencies, outputs, enumeratedPrimaryOutputs, - // enumeratedSecondaryOutputs, outputVariables, additionalTargets, bTargetTool, managedProjectOutputs)) { - // return false; - // } - // If we have no primary output, make all of the secondary outputs the - // primary output - if (enumeratedPrimaryOutputs.size() == 0) { - enumeratedPrimaryOutputs = enumeratedSecondaryOutputs; - enumeratedSecondaryOutputs.clear(); - } - // Add the output variables for this tool to our list - outputVarsAdditionsList.addAll(outputVariables); - // Create the build rule - String buildRule = EMPTY_STRING; - String outflag = tool.getOutputFlag(); - String primaryOutputs = EMPTY_STRING; - String primaryOutputsQuoted = EMPTY_STRING; - boolean first = true; - for (int i = 0; i < enumeratedPrimaryOutputs.size(); i++) { - String output = enumeratedPrimaryOutputs.get(i); - if (!first) { - primaryOutputs += WHITESPACE; - primaryOutputsQuoted += WHITESPACE; - } - first = false; - primaryOutputs += new Path(output).toOSString(); - primaryOutputsQuoted += ensurePathIsGNUMakeTargetRuleCompatibleSyntax(new Path(output).toOSString()); - } - buildRule += (primaryOutputsQuoted + COLON + WHITESPACE); - first = true; - String calculatedDependencies = EMPTY_STRING; - for (int i = 0; i < dependencies.size(); i++) { - String input = dependencies.get(i); - if (!first) - calculatedDependencies += WHITESPACE; - first = false; - calculatedDependencies += input; - } - buildRule += calculatedDependencies; - // We can't have duplicates in a makefile - if (getRuleList().contains(buildRule)) { - /* JABA is not going to write this code */ - } else { - getRuleList().add(buildRule); - buffer.append(buildRule).append(NEWLINE); - if (bTargetTool) { - buffer.append(TAB).append(AT).append(escapedEcho(MESSAGE_START_BUILD + WHITESPACE + OUT_MACRO)); - } - buffer.append(TAB).append(AT).append(escapedEcho(tool.getAnnouncement())); - // Get the command line for this tool invocation - String[] flags; - try { - flags = tool.getToolCommandFlags(null, null); - } catch (BuildException ex) { - // TODO report error - flags = EMPTY_STRING_ARRAY; - } - String command = tool.getToolCommand(); - try { - // try to resolve the build macros in the tool command - String resolvedCommand = ManagedBuildManager.getBuildMacroProvider().resolveValueToMakefileFormat( - command, EMPTY_STRING, WHITESPACE, IBuildMacroProvider.CONTEXT_FILE, - new FileContextData(null, null, null, tool)); - if ((resolvedCommand = resolvedCommand.trim()).length() > 0) { - command = resolvedCommand.replace(" \"\" ", " "); - } - } catch (BuildMacroException e) { - /* JABA is not going to write this code */ - } - String[] cmdInputs = inputs.toArray(new String[inputs.size()]); - IManagedCommandLineGenerator gen = tool.getCommandLineGenerator(); - IManagedCommandLineInfo cmdLInfo = gen.generateCommandLineInfo(tool, command, flags, outflag, outputPrefix, - primaryOutputs, cmdInputs, getToolCommandLinePattern(config, tool)); - // The command to build - String buildCmd = null; - if (cmdLInfo == null) { - String toolFlags; - try { - toolFlags = tool.getToolCommandFlagsString(null, null); - } catch (BuildException ex) { - // TODO report error - toolFlags = EMPTY_STRING; - } - buildCmd = command + WHITESPACE + toolFlags + WHITESPACE + outflag + WHITESPACE + outputPrefix - + primaryOutputs + WHITESPACE + IN_MACRO; - } else - buildCmd = cmdLInfo.getCommandLine(); - // resolve any remaining macros in the command after it has been - // generated - try { - //TOFIX JABA heavy hack to get the combiner to work properly - //if the command contains ${ARCHIVES} - //remove the ${AR} - //replace ${ARCHIVES} with ${AR} - String ARCHIVES = " ${ARCHIVES} "; - String AR = " $(AR) "; - if (buildCmd.contains(ARCHIVES)) { - buildCmd = buildCmd.replace(AR, " "); - buildCmd = buildCmd.replace(ARCHIVES, AR); - } - //end JABA heavy hack - String resolvedCommand = ManagedBuildManager.getBuildMacroProvider().resolveValueToMakefileFormat( - buildCmd, EMPTY_STRING, WHITESPACE, IBuildMacroProvider.CONTEXT_FILE, - new FileContextData(null, null, null, tool)); - if ((resolvedCommand = resolvedCommand.trim()).length() > 0) { - buildCmd = resolvedCommand.replace(" \"\" ", " "); - } - } catch (BuildMacroException e) { - /* JABA is not going to write this code */ - } - // buffer.append(TAB).append(AT).append(escapedEcho(buildCmd)); - // buffer.append(TAB).append(AT).append(buildCmd); - buffer.append(TAB).append(buildCmd); - // TODO - // NOTE WELL: Dependency file generation is not handled for this - // type of Tool - // Echo finished message - buffer.append(NEWLINE); - buffer.append(TAB).append(AT).append( - escapedEcho((bTargetTool ? MESSAGE_FINISH_BUILD : MESSAGE_FINISH_FILE) + WHITESPACE + OUT_MACRO)); - buffer.append(TAB).append(AT).append(ECHO_BLANK_LINE); - // If there is a post build step, then add a recursive invocation of - // MAKE to invoke it after the main build - // Note that $(MAKE) will instantiate in the recusive invocation to - // the make command that was used to invoke - // the makefile originally - if (bEmitPostBuildStepCall) { - buffer.append(TAB).append(MAKE).append(WHITESPACE).append(NO_PRINT_DIR).append(WHITESPACE) - .append(POSTBUILD).append(NEWLINE).append(NEWLINE); - } else { - // Just emit a blank line - buffer.append(NEWLINE); - } - } - // If we have secondary outputs, output dependency rules without - // commands - if (enumeratedSecondaryOutputs.size() > 0 || additionalTargets.size() > 0) { - String primaryOutput = enumeratedPrimaryOutputs.get(0); - Vector addlOutputs = new Vector(); - addlOutputs.addAll(enumeratedSecondaryOutputs); - addlOutputs.addAll(additionalTargets); - for (int i = 0; i < addlOutputs.size(); i++) { - String output = addlOutputs.get(i); - String depLine = output + COLON + WHITESPACE + primaryOutput + WHITESPACE + calculatedDependencies - + NEWLINE; - buffer.append(depLine); - } - buffer.append(NEWLINE); - } - return true; - } - - /** - * @param outputVarsAdditionsList - * list to add needed build output variables to - * @param buffer - * buffer to add rules to - */ - private void generateRulesForConsumers(ITool generatingTool, List outputVarsAdditionsList, - StringBuffer buffer) { - // Generate a build rule for any tool that consumes the output of this - // tool - PathSettingsContainer toolInfos = getToolInfos(); - // ToolInfoHolder h = (ToolInfoHolder) toolInfos.getValue(); - // ITool[] buildTools = h.buildTools; - ITool[] buildTools = null; - //boolean[] buildToolsUsed = h.buildToolsUsed; - boolean[] buildToolsUsed = null; - IOutputType[] outTypes = generatingTool.getOutputTypes(); - for (IOutputType outType : outTypes) { - String[] outExts = outType.getOutputExtensions(generatingTool); - String outVariable = outType.getBuildVariable(); - if (outExts != null) { - for (String outExt : outExts) { - for (int k = 0; k < buildTools.length; k++) { - ITool tool = buildTools[k]; - if (!buildToolsUsed[k]) { - // Also has to match build variables if specified - IInputType inType = tool.getInputType(outExt); - if (inType != null) { - String inVariable = inType.getBuildVariable(); - if ((outVariable == null && inVariable == null) || (outVariable != null - && inVariable != null && outVariable.equals(inVariable))) { - if (addRuleForTool(buildTools[k], buffer, false, null, null, - outputVarsAdditionsList, null, false)) { - buildToolsUsed[k] = true; - // Look for tools that consume the - // output - generateRulesForConsumers(buildTools[k], outputVarsAdditionsList, buffer); - } - } - } - } - } - } - } - } - } - - /** - * Returns the targets rules. The targets make file (top makefile) contains: 1 - * the rule for the final target tool 2 the rules for all of the tools that use - * multipleOfType in their primary input type 3 the rules for all tools that use - * the output of #2 tools - * - * @param outputVarsAdditionsList - * list to add needed build output variables to - * @param managedProjectOutputs - * Other projects in the workspace that this project depends upon - * @return StringBuffer - */ - private StringBuffer addTargetsRules(ITool targetTool, List outputVarsAdditionsList, - Vector managedProjectOutputs, boolean postbuildStep) { - StringBuffer buffer = new StringBuffer(); - // Add the comment - buffer.append(COMMENT_SYMBOL).append(WHITESPACE).append(ManagedMakeMessages.getResourceString(BUILD_TOP)) - .append(NEWLINE); - // Get the target tool and generate the rule - if (targetTool != null) { - // Note that the name of the target we pass to addRuleForTool does - // not - // appear to be used there (and tool outputs are consulted - // directly), but - // we quote it anyway just in case it starts to use it in future. - addRuleForTool(targetTool, buffer, true, - ensurePathIsGNUMakeTargetRuleCompatibleSyntax(caller.buildTargetName), caller.buildTargetExt, - outputVarsAdditionsList, managedProjectOutputs, postbuildStep); - } else { - buffer.append(TAB).append(AT).append(escapedEcho(MESSAGE_NO_TARGET_TOOL + WHITESPACE + OUT_MACRO)); - } - // Generate the rules for all Tools that specify - // InputType.multipleOfType, and any Tools that - // consume the output of those tools. This does not apply to pre-3.0 - // integrations, since - // the only "multipleOfType" tool is the "target" tool - // for (int i = 0; i < buildTools.length; i++) { - // ITool tool = buildTools[i]; - // IInputType type = tool.getPrimaryInputType(); - // if (type != null && type.getMultipleOfType()) { - // if (!buildToolsUsed[i]) { - // addRuleForTool(tool, buffer, false, null, null, outputVarsAdditionsList, null, false); - // // Mark the target tool as processed - // buildToolsUsed[i] = true; - // // Look for tools that consume the output - // generateRulesForConsumers(tool, outputVarsAdditionsList, buffer); - // } - // } - // } - // Add the comment - buffer.append(COMMENT_SYMBOL).append(WHITESPACE).append(ManagedMakeMessages.getResourceString(BUILD_TARGETS)) - .append(NEWLINE); - // Always add a clean target - buffer.append("clean:").append(NEWLINE); - buffer.append(TAB).append("-$(RM)").append(WHITESPACE); - for (IOutputType entry : myAllSourceTargets.keySet()) { - String macroName = entry.getBuildVariable(); - buffer.append("$(").append(macroName).append(')'); - } - String outputPrefix = EMPTY_STRING; - if (targetTool != null) { - outputPrefix = targetTool.getOutputPrefix(); - } - String completeBuildTargetName = outputPrefix + caller.buildTargetName; - if (caller.buildTargetExt.length() > 0) { - completeBuildTargetName = completeBuildTargetName + DOT + caller.buildTargetExt; - } - buffer.append(NEWLINE); - buffer.append(TAB).append(DASH).append(AT).append(ECHO_BLANK_LINE).append(NEWLINE); - return buffer; - } - - /** - * Write all macro addition entries in a map to the buffer - */ - private StringBuffer writeTopAdditionMacros(List varList, HashMap varMap) { - StringBuffer buffer = new StringBuffer(); - // Add the comment - buffer.append(COMMENT_SYMBOL).append(WHITESPACE).append(ManagedMakeMessages.getResourceString(MOD_VARS)) - .append(NEWLINE); - for (String curVar : varList) { - buffer.append(varMap.get(curVar)); - buffer.append(NEWLINE); - } - return buffer.append(NEWLINE); - } - - // private Vector calculateSecondaryOutputs(IOutputType[] secondaryOutputs) { - // PathSettingsContainer toolInfos = getToolInfos(); - // // ToolInfoHolder h = (ToolInfoHolder) toolInfos.getValue(); - // // ITool[] buildTools = h.buildTools; - // ITool[] buildTools = null; - // Vector buildVars = new Vector(); - // for (int i = 0; i < buildTools.length; i++) { - // // Add the specified output build variables - // IOutputType[] outTypes = buildTools[i].getOutputTypes(); - // if (outTypes != null && outTypes.length > 0) { - // for (int j = 0; j < outTypes.length; j++) { - // IOutputType outType = outTypes[j]; - // // Is this one of the secondary outputs? - // // Look for an outputType with this ID, or one with a - // // superclass with this id - // thisType: for (int k = 0; k < secondaryOutputs.length; k++) { - // IOutputType matchType = outType; - // do { - // if (matchType.getId().equals(secondaryOutputs[k].getId())) { - // buildVars.add(outType.getBuildVariable()); - // break thisType; - // } - // matchType = matchType.getSuperClass(); - // } while (matchType != null); - // } - // } - // } - // } - // return buildVars; - // } - - // private boolean getToolInputsOutputs(ITool tool, Vector inputs, Vector dependencies, - // Vector outputs, Vector enumeratedPrimaryOutputs, Vector enumeratedSecondaryOutputs, - // Vector outputVariables, Vector additionalTargets, boolean bTargetTool, - // Vector managedProjectOutputs) { - // PathSettingsContainer toolInfos = getToolInfos(); - // // ToolInfoHolder h = (ToolInfoHolder) toolInfos.getValue(); - // // ITool[] buildTools = h.buildTools; - // ITool[] buildTools = null; - // // Get the information regarding the tool's inputs and outputs from the - // // objects - // // created by calculateToolInputsOutputs - // IManagedBuildGnuToolInfo toolInfo = null; - // // for (int i = 0; i < buildTools.length; i++) { - // // if (tool == buildTools[i]) { - // // break; - // // } - // // } - // if (toolInfo == null) - // return false; - // // Populate the output Vectors - // inputs.addAll(toolInfo.getCommandInputs()); - // outputs.addAll(toolInfo.getCommandOutputs()); - // enumeratedPrimaryOutputs.addAll(toolInfo.getEnumeratedPrimaryOutputs()); - // enumeratedSecondaryOutputs.addAll(toolInfo.getEnumeratedSecondaryOutputs()); - // outputVariables.addAll(toolInfo.getOutputVariables()); - // Vector unprocessedDependencies = toolInfo.getCommandDependencies(); - // for (String path : unprocessedDependencies) { - // dependencies.add(ensurePathIsGNUMakeTargetRuleCompatibleSyntax(path)); - // } - // additionalTargets.addAll(toolInfo.getAdditionalTargets()); - // if (bTargetTool && managedProjectOutputs != null) { - // for (String output : managedProjectOutputs) { - // dependencies.add(output); - // } - // } - // return true; - // } - - //Get the rules for the generated files - private MakeRules getMakeRulesFromGeneratedFiles(Map> generatedFiles) { - MakeRules makeRules = new MakeRules(); - IConfiguration config = getConfig(); - IProject project = getProject(); - IPath buildPath = getBuildFolder(); - - // Visit the resources in this set - for (Entry> entry : generatedFiles.entrySet()) { - IOutputType outputTypeIn = entry.getKey(); - Set files = entry.getValue(); - String macroName = outputTypeIn.getBuildVariable(); - for (ITool tool : config.getTools()) { - for (IInputType inputType : tool.getInputTypes()) { - if (!macroName.equals(inputType.getBuildVariable())) { - continue; - } - if (inputType.getMultipleOfType()) { - for (IOutputType outputType : tool.getOutputTypes()) { - INewManagedOutputNameProvider nameProvider = getJABANameProvider(config, buildPath, - outputType); - if (nameProvider == null) { - continue; - } - IPath outputFile = nameProvider.getOutputName(project, config, null, null); - if (outputFile != null) { - //This is a multiple to 1 based on var name - IFile correctOutputFile = getProject() - .getFile(new Path(config.getName()).append(outputFile)); - makeRules.addRule(tool, inputType, macroName, files, outputType, correctOutputFile); - - continue; - } - IPath firstFilePath = files.toArray(new IFile[files.size()])[0].getProjectRelativePath(); - outputFile = nameProvider.getOutputName(project, config, tool, firstFilePath); - if (outputFile == null) { - continue; - } - //This is a multiple to 1 not based on var name - IPath correctOutputPath = new Path(config.getName()).append(outputFile); - MakeRule newMakeRule = new MakeRule(caller, tool, inputType, files, outputType, - project.getFile(correctOutputPath)); - - makeRules.addRule(newMakeRule); - } - } else { - //The link is based on the varname but the files are one on one - for (IOutputType outputType : tool.getOutputTypes()) { - INewManagedOutputNameProvider nameProvider = getJABANameProvider(config, buildPath, - outputType); - if (nameProvider == null) { - continue; - } - for (IFile file : files) { - IPath outputFile = nameProvider.getOutputName(project, config, tool, - file.getProjectRelativePath()); - if (outputFile == null) { - continue; - } - //This is a multiple to 1 not based on var name - IPath correctOutputPath = new Path(config.getName()).append(outputFile); - MakeRule newMakeRule = new MakeRule(tool, inputType, file, outputType, - project.getFile(correctOutputPath)); - newMakeRule.addDependencies(caller); - makeRules.addRule(newMakeRule); - } - } - } - } - // else { - // for (IOutputType outputType : tool.getOutputTypes()) { - // IManagedOutputNameProviderJaba nameProvider = getJABANameProvider(outputType); - // if (nameProvider == null) { - // continue; - // } - // for (IFile file : files) { - // IPath outputFile = nameProvider.getOutputName(getProject(), config, tool, - // file.getProjectRelativePath()); - // if (outputFile != null) { - // //We found a tool that provides a outputfile for our source file - // //TOFIX if this is a multiple to one we should only create one MakeRule - // IPath correctOutputPath = new Path(config.getName()).append(outputFile); - // MakeRule newMakeRule = new MakeRule(caller, tool, inputType, file, outputType, - // project.getFile(correctOutputPath)); - // - // makeRules.add(newMakeRule); - // } - // } - // } - // } - // } - - } - } - return makeRules; - - } - - private StringBuffer GenerateMacros() { - StringBuffer buffer = new StringBuffer(); - IFile buildRoot = caller.getTopBuildDir(); - buffer.append(NEWLINE); - buffer.append(COMMENT_SYMBOL).append(WHITESPACE).append(ManagedMakeMessages.getResourceString(MOD_VARS)) - .append(NEWLINE); - - for (String macroName : myMakeRules.getMacroNames()) { - Set files = myMakeRules.getMacroElements(macroName); - if (files.size() > 0) { - buffer.append(macroName).append(MAKE_ADDITION); - for (IFile file : files) { - if (files.size() != 1) { - buffer.append(LINEBREAK); - } - buffer.append(GetNiceFileName(buildRoot, file)).append(WHITESPACE); - } - buffer.append(NEWLINE); - buffer.append(NEWLINE); - } - - } - return buffer; - } - - private StringBuffer GenerateRules(IConfiguration config) { - StringBuffer buffer = new StringBuffer(); - buffer.append(NEWLINE); - buffer.append(COMMENT_SYMBOL).append(WHITESPACE).append(ManagedMakeMessages.getResourceString(MOD_RULES)) - .append(NEWLINE); - - for (MakeRule makeRule : myMakeRules.getMakeRules()) { - buffer.append(makeRule.getRule(getProject(), caller.getTopBuildDir(), config)); - } - - return buffer; - } + private ArduinoGnuMakefileGenerator caller = null; + private Set mySubDirMakeRules = new LinkedHashSet<>(); + private MakeRules myMakeRules = new MakeRules(); + private Collection myFoldersToBuild; + private Map> myAllSourceTargets = new HashMap<>(); + private Set myDependencyMacros = new HashSet<>(); + + private IConfiguration getConfig() { + return caller.getConfig(); + } + + private IProject getProject() { + return caller.getProject(); + } + + private IPath getBuildFolder() { + return caller.getBuildFolder(); + } + + TopMakeFileGenerator(ArduinoGnuMakefileGenerator theCaller, Set subDirMakeRules, + Collection foldersToBuild) { + caller = theCaller; + mySubDirMakeRules = subDirMakeRules; + myFoldersToBuild = foldersToBuild; + for (MakeRule curMakeRule : mySubDirMakeRules) { + myAllSourceTargets.putAll(curMakeRule.getTargets()); + myDependencyMacros.addAll(curMakeRule.getDependecyMacros()); + } + MakeRules makeRules = new MakeRules(); + Map> generatedFiles = new HashMap<>(); + for (MakeRule makeRule : subDirMakeRules) { + Map> targets = makeRule.getTargets(); + for (Entry> curTarget : targets.entrySet()) { + Set esxistingTarget = generatedFiles.get(curTarget.getKey()); + if (esxistingTarget != null) { + esxistingTarget.addAll(curTarget.getValue()); + } else { + Set copySet = new HashSet<>(); + copySet.addAll(curTarget.getValue()); + generatedFiles.put(curTarget.getKey(), copySet); + } + + } + } + int depth = 10; + while (depth > 0) { + makeRules = getMakeRulesFromGeneratedFiles(generatedFiles); + generatedFiles.clear(); + if (makeRules.size() > 0) { + depth--; + myMakeRules.addRules(makeRules); + generatedFiles.putAll(makeRules.getTargets()); + } else { + depth = 0; + } + } + + } + + public void generateMakefile() throws CoreException { + IProject project = getProject(); + IConfiguration config = getConfig(); + + StringBuffer buffer = new StringBuffer(); + buffer.append(addDefaultHeader()); + + buffer.append(getMakeIncludeSubDirs()); + buffer.append(getMakeIncludeDependencies()); + buffer.append(getMakeRMCommand()); + buffer.append(getMakeTopTargets());// this is the include dependencies + // TOFIX the content from the append below should come from a registered method + buffer.append("\n#bootloaderTest\n" + "BurnBootLoader: \n" + + "\t@echo trying to burn bootloader ${bootloader.tool}\n" + + "\t${tools.${bootloader.tool}.erase.pattern}\n" + "\t${tools.${bootloader.tool}.bootloader.pattern}\n" + + "\n" + "uploadWithBuild: all\n" + + "\t@echo trying to build and upload with upload tool ${upload.tool}\n" + + "\t${tools.${upload.tool}.upload.pattern}\n" + "\n" + "uploadWithoutBuild: \n" + + "\t@echo trying to upload without build with upload tool ${upload.tool}\n" + + "\t${tools.${upload.tool}.upload.pattern}\n" + " \n" + "uploadWithProgrammerWithBuild: all\n" + + "\t@echo trying to build and upload with programmer ${program.tool}\n" + + "\t${tools.${program.tool}.program.pattern}\n" + "\n" + "uploadWithProgrammerWithoutBuild: \n" + + "\t@echo trying to upload with programmer ${program.tool} without build\n" + + "\t${tools.${program.tool}.program.pattern}\n\n"); + buffer.append(getMakeMacros()); + buffer.append(getMakeRules()); + buffer.append(getMakeFinalTargets("", "")); + + IFile fileHandle = project.getFile(config.getName() + '/' + MAKEFILE_NAME); + save(buffer, fileHandle); + } + + private StringBuffer getMakeIncludeSubDirs() { + StringBuffer buffer = new StringBuffer(); + + for (IContainer subDir : myFoldersToBuild) { + String includeFile = subDir.getProjectRelativePath().append(MODFILE_NAME).toOSString(); + buffer.append("-include " + includeFile).append(NEWLINE); + } + buffer.append("-include sources.mk").append(NEWLINE); + buffer.append("-include objects.mk").append(NEWLINE).append(NEWLINE); + return buffer; + } + + private StringBuffer getMakeRMCommand() { + IConfiguration config = getConfig(); + StringBuffer buffer = new StringBuffer(); + buffer.append("-include " + ROOT + FILE_SEPARATOR + MAKEFILE_INIT).append(NEWLINE); + buffer.append(NEWLINE); + // Get the clean command from the build model + buffer.append("RM := "); + // support macros in the clean command + try { + String cleanCommand = ManagedBuildManager.getBuildMacroProvider().resolveValueToMakefileFormat( + config.getCleanCommand(), EMPTY_STRING, WHITESPACE, IBuildMacroProvider.CONTEXT_CONFIGURATION, + config); + buffer.append(cleanCommand).append(NEWLINE); + buffer.append(NEWLINE); + } catch (BuildMacroException e) { + // jaba is not going to write this code + } + + if (!myDependencyMacros.isEmpty()) { + buffer.append("ifneq ($(MAKECMDGOALS),clean)").append(NEWLINE); + for (String depsMacro : myDependencyMacros) { + buffer.append("ifneq ($(strip $(").append(depsMacro).append(")),)").append(NEWLINE); + buffer.append("-include $(").append(depsMacro).append(')').append(NEWLINE); + buffer.append("endif").append(NEWLINE); + } + buffer.append("endif").append(NEWLINE).append(NEWLINE); + } + // Include makefile.defs supplemental makefile + buffer.append("-include ").append(ROOT).append(FILE_SEPARATOR).append(MAKEFILE_DEFS).append(NEWLINE); + return (buffer.append(NEWLINE)); + } + + private String getPreBuildStep() { + IConfiguration config = getConfig(); + String prebuildStep = config.getPrebuildStep(); + // JABA issue927 adding recipe.hooks.sketch.prebuild.NUMBER.pattern as cdt + // prebuild command if needed + ICConfigurationDescription confDesc = ManagedBuildManager.getDescriptionForConfiguration(config); + String sketchPrebuild = io.sloeber.core.common.Common.getBuildEnvironmentVariable(confDesc, "sloeber.prebuild", + new String(), false); + if (!sketchPrebuild.isEmpty()) { + if (!prebuildStep.isEmpty()) { + prebuildStep = prebuildStep + "\n\t" + sketchPrebuild; + } else { + prebuildStep = sketchPrebuild; + } + } + // end off JABA issue927 + try { + // try to resolve the build macros in the prebuild step + prebuildStep = ManagedBuildManager.getBuildMacroProvider().resolveValueToMakefileFormat(prebuildStep, + EMPTY_STRING, WHITESPACE, IBuildMacroProvider.CONTEXT_CONFIGURATION, config); + } catch (BuildMacroException e) { + /* JABA is not going to write this code */ + } + return prebuildStep.trim(); + } + + private StringBuffer getMakeIncludeDependencies() { + + // JABA add the arduino upload/program targets + StringBuffer buffer = new StringBuffer(); + + String defaultTarget = "all:"; + String prebuildStep = getPreBuildStep(); + if (prebuildStep.length() > 0) { + // Add the comment for the "All" target + buffer.append(COMMENT_START).append(MESSAGE_ALL_TARGET).append(NEWLINE); + buffer.append(defaultTarget).append(NEWLINE); + buffer.append(TAB).append(MAKE).append(WHITESPACE).append(NO_PRINT_DIR).append(WHITESPACE).append(PREBUILD) + .append(NEWLINE); + buffer.append(TAB).append(MAKE).append(WHITESPACE).append(NO_PRINT_DIR).append(WHITESPACE).append(MAINBUILD) + .append(NEWLINE); + buffer.append(NEWLINE); + // defaultTarget = MAINBUILD.concat(COLON); + buffer.append(COMMENT_SYMBOL).append(WHITESPACE).append(MESSAGE_MAINBUILD_TARGET).append(NEWLINE); + + } else { + // Add the comment for the "All" target + buffer.append(COMMENT_START).append(MESSAGE_ALL_TARGET).append(NEWLINE); + } + return buffer; + } + + private StringBuffer getMakeTopTargets() { + IConfiguration config = getConfig(); + IPath buildFolder = getBuildFolder(); + + StringBuffer buffer = new StringBuffer(); + + ITool targetTool = config.calculateTargetTool(); + buffer.append("all:").append(WHITESPACE); + if (targetTool != null) { + Set allTargets = myMakeRules.getTargetsForTool(targetTool); + for (IFile curTarget : allTargets) { + String targetString = GetNiceFileName(buildFolder, curTarget.getLocation()).toOSString(); + buffer.append(ensurePathIsGNUMakeTargetRuleCompatibleSyntax(targetString)); + buffer.append(WHITESPACE); + } + } + + // Add the Secondary Outputs to the all target, if any + IOutputType[] secondaryOutputs = config.getToolChain().getSecondaryOutputs(); + if (secondaryOutputs.length > 0) { + buffer.append(WHITESPACE).append(SECONDARY_OUTPUTS); + } + buffer.append(NEWLINE).append(NEWLINE); + + String prebuildStep = getPreBuildStep(); + if (prebuildStep.length() > 0) { + + String preannouncebuildStep = config.getPreannouncebuildStep(); + buffer.append(PREBUILD).append(COLON).append(NEWLINE); + if (preannouncebuildStep.length() > 0) { + buffer.append(TAB).append(DASH).append(AT).append(escapedEcho(preannouncebuildStep)); + } + buffer.append(TAB).append(DASH).append(prebuildStep).append(NEWLINE); + buffer.append(TAB).append(DASH).append(AT).append(ECHO_BLANK_LINE).append(NEWLINE); + } + + String postbuildStep = config.getPostbuildStep(); + try { + // try to resolve the build macros in the postbuild step + postbuildStep = ManagedBuildManager.getBuildMacroProvider().resolveValueToMakefileFormat(postbuildStep, + EMPTY_STRING, WHITESPACE, IBuildMacroProvider.CONTEXT_CONFIGURATION, config); + } catch (BuildMacroException e) { + /* JABA is not going to write this code */ + } + postbuildStep = postbuildStep.trim(); + // Add the postbuild step, if specified + if (postbuildStep.length() > 0) { + String postannouncebuildStep = config.getPostannouncebuildStep(); + buffer.append(POSTBUILD).append(COLON).append(NEWLINE); + if (postannouncebuildStep.length() > 0) { + buffer.append(TAB).append(DASH).append(AT).append(escapedEcho(postannouncebuildStep)); + } + buffer.append(TAB).append(DASH).append(postbuildStep).append(NEWLINE); + buffer.append(TAB).append(DASH).append(AT).append(ECHO_BLANK_LINE).append(NEWLINE); + } + + return buffer; + } + + private StringBuffer getMakeFinalTargets(String prebuildStep, String postbuildStep) { + StringBuffer buffer = new StringBuffer(); + buffer.append(NEWLINE).append(NEWLINE); + + // Add all the needed dummy and phony targets + buffer.append(".PHONY: all clean dependents"); + if (prebuildStep.length() > 0) { + buffer.append(WHITESPACE).append(MAINBUILD).append(WHITESPACE).append(PREBUILD); + } + if (postbuildStep.length() > 0) { + buffer.append(WHITESPACE).append(POSTBUILD); + } + + buffer.append(NEWLINE); + // Include makefile.targets supplemental makefile + buffer.append("-include ").append(ROOT).append(FILE_SEPARATOR).append(MAKEFILE_TARGETS).append(NEWLINE); + return buffer; + } + + // Get the rules for the generated files + private MakeRules getMakeRulesFromGeneratedFiles(Map> generatedFiles) { + MakeRules makeRules = new MakeRules(); + IConfiguration config = getConfig(); + IProject project = getProject(); + IPath buildPath = getBuildFolder(); + + // Visit the resources in this set + for (Entry> entry : generatedFiles.entrySet()) { + IOutputType outputTypeIn = entry.getKey(); + Set files = entry.getValue(); + String macroName = outputTypeIn.getBuildVariable(); + for (ITool tool : config.getTools()) { + for (IInputType inputType : tool.getInputTypes()) { + if (!macroName.equals(inputType.getBuildVariable())) { + continue; + } + if (inputType.getMultipleOfType()) { + for (IOutputType outputType : tool.getOutputTypes()) { + INewManagedOutputNameProvider nameProvider = getJABANameProvider(config, buildPath, + outputType); + if (nameProvider == null) { + continue; + } + IPath outputFile = nameProvider.getOutputName(project, config, null, null); + if (outputFile != null) { + // This is a multiple to 1 based on var name + IFile correctOutputFile = getProject() + .getFile(new Path(config.getName()).append(outputFile)); + makeRules.addRule(tool, inputType, macroName, files, outputType, correctOutputFile); + + continue; + } + IPath firstFilePath = files.toArray(new IFile[files.size()])[0].getProjectRelativePath(); + outputFile = nameProvider.getOutputName(project, config, tool, firstFilePath); + if (outputFile == null) { + continue; + } + // This is a multiple to 1 not based on var name + IPath correctOutputPath = new Path(config.getName()).append(outputFile); + MakeRule newMakeRule = new MakeRule(caller, tool, inputType, files, outputType, + project.getFile(correctOutputPath)); + + makeRules.addRule(newMakeRule); + } + } else { + // The link is based on the varname but the files are one on one + for (IOutputType outputType : tool.getOutputTypes()) { + INewManagedOutputNameProvider nameProvider = getJABANameProvider(config, buildPath, + outputType); + if (nameProvider == null) { + continue; + } + for (IFile file : files) { + IPath outputFile = nameProvider.getOutputName(project, config, tool, + file.getProjectRelativePath()); + if (outputFile == null) { + continue; + } + // This is a multiple to 1 not based on var name + IPath correctOutputPath = new Path(config.getName()).append(outputFile); + MakeRule newMakeRule = new MakeRule(tool, inputType, file, outputType, + project.getFile(correctOutputPath)); + newMakeRule.addDependencies(caller); + makeRules.addRule(newMakeRule); + } + } + } + } + // else { + // for (IOutputType outputType : tool.getOutputTypes()) { + // IManagedOutputNameProviderJaba nameProvider = + // getJABANameProvider(outputType); + // if (nameProvider == null) { + // continue; + // } + // for (IFile file : files) { + // IPath outputFile = nameProvider.getOutputName(getProject(), config, tool, + // file.getProjectRelativePath()); + // if (outputFile != null) { + // //We found a tool that provides a outputfile for our source file + // //TOFIX if this is a multiple to one we should only create one MakeRule + // IPath correctOutputPath = new Path(config.getName()).append(outputFile); + // MakeRule newMakeRule = new MakeRule(caller, tool, inputType, file, + // outputType, + // project.getFile(correctOutputPath)); + // + // makeRules.add(newMakeRule); + // } + // } + // } + // } + // } + } + } + return makeRules; + } + + private StringBuffer getMakeMacros() { + StringBuffer buffer = new StringBuffer(); + IFile buildRoot = caller.getTopBuildDir(); + buffer.append(NEWLINE); + buffer.append(COMMENT_START).append(MESSAGE_MOD_VARS).append(NEWLINE); + + for (String macroName : myMakeRules.getMacroNames()) { + Set files = myMakeRules.getMacroElements(macroName); + if (files.size() > 0) { + buffer.append(macroName).append(MAKE_ADDITION); + for (IFile file : files) { + if (files.size() != 1) { + buffer.append(LINEBREAK); + } + buffer.append(GetNiceFileName(buildRoot, file)).append(WHITESPACE); + } + buffer.append(NEWLINE); + buffer.append(NEWLINE); + } + } + return buffer; + } + + private StringBuffer getMakeRules() { + StringBuffer buffer = new StringBuffer(); + IProject project = getProject(); + IConfiguration config = getConfig(); + IFile topBuildDir = caller.getTopBuildDir(); + buffer.append(NEWLINE); + buffer.append(COMMENT_START).append(MESSAGE_MOD_RULES).append(NEWLINE); + + for (MakeRule makeRule : myMakeRules.getMakeRules()) { + buffer.append(makeRule.getRule(project, topBuildDir, config)); + } + return buffer; + } } From 4ece0139f9cadea5e86823accfb4d861e5a19ca5 Mon Sep 17 00:00:00 2001 From: gast1 Date: Mon, 24 Oct 2022 19:43:08 +0200 Subject: [PATCH 010/486] remove ArduinoGnuDependencyGroupInfo #1126 --- .../ArduinoGnuDependencyGroupInfo.java | 25 ------------------- io.sloeber.tests/.gitignore | 1 + 2 files changed, 1 insertion(+), 25 deletions(-) delete mode 100644 io.sloeber.core/src/io/sloeber/managedBuild/Internal/ArduinoGnuDependencyGroupInfo.java diff --git a/io.sloeber.core/src/io/sloeber/managedBuild/Internal/ArduinoGnuDependencyGroupInfo.java b/io.sloeber.core/src/io/sloeber/managedBuild/Internal/ArduinoGnuDependencyGroupInfo.java deleted file mode 100644 index 22eb1389d..000000000 --- a/io.sloeber.core/src/io/sloeber/managedBuild/Internal/ArduinoGnuDependencyGroupInfo.java +++ /dev/null @@ -1,25 +0,0 @@ -package io.sloeber.managedBuild.Internal; - -/** - * - * This class contains the description of a group of generated dependency files, e.g., .d files created by compilations - * - */ - -public class ArduinoGnuDependencyGroupInfo { - - // Member Variables - String groupBuildVar; - boolean conditionallyInclude; - - // ArrayList groupFiles; - - // Constructor - public ArduinoGnuDependencyGroupInfo(String groupName, boolean bConditionallyInclude) { - this.groupBuildVar = groupName; - this.conditionallyInclude = bConditionallyInclude; - // Note: not yet needed - // groupFiles = null; - } - -} diff --git a/io.sloeber.tests/.gitignore b/io.sloeber.tests/.gitignore index 09e3bc9b2..a7ad3c10e 100644 --- a/io.sloeber.tests/.gitignore +++ b/io.sloeber.tests/.gitignore @@ -1,2 +1,3 @@ /bin/ /target/ +/*.log From d3b5850ef68fc998488020ba27af40794365e167 Mon Sep 17 00:00:00 2001 From: gast1 Date: Mon, 24 Oct 2022 23:10:37 +0200 Subject: [PATCH 011/486] trying to create a plugin to get the toolchain in CDT #1126 --- io.sloeber.ManagedBuild/.classpath | 11 + io.sloeber.ManagedBuild/.gitignore | 2 + io.sloeber.ManagedBuild/.project | 34 + io.sloeber.ManagedBuild/META-INF/MANIFEST.MF | 14 + .../OSGI-INF/l10n/bundle.properties | 43 + io.sloeber.ManagedBuild/build.properties | 13 + io.sloeber.ManagedBuild/plugin.properties | 2 + io.sloeber.ManagedBuild/plugin.xml | 460 +++ io.sloeber.ManagedBuild/pom.xml | 13 + .../schema/ManagedBuildTools.exsd | 763 +++++ .../schema/buildDefinitions.exsd | 2526 +++++++++++++++++ .../Internal/ArchiveNameProvider.java | 33 + .../Internal/ArduinoGnuMakefileGenerator.java | 437 +++ .../Internal/LinkNameProvider.java | 35 + .../managedBuild/Internal/MakeRule.java | 491 ++++ .../managedBuild/Internal/MakeRules.java | 117 + .../Internal/ManagebBuildCommon.java | 670 +++++ .../Internal/ManagedBuildConstants.java | 100 + .../Internal/SrcMakeGenerator.java | 68 + .../Internal/SubDirMakeGenerator.java | 245 ++ .../Internal/TopMakeFileGenerator.java | 431 +++ .../managedBuild/api/AbstractBuildRunner.java | 48 + .../managedBuild/api/BuildException.java | 27 + .../managedBuild/api/IAdditionalInput.java | 90 + .../managedBuild/api/IBuildObject.java | 43 + .../managedBuild/api/IBuildPathResolver.java | 34 + .../io/sloeber/managedBuild/api/IBuilder.java | 316 +++ .../managedBuild/api/IConfiguration.java | 616 ++++ .../managedBuild/api/IEnvVarBuildPath.java | 64 + .../sloeber/managedBuild/api/IFileInfo.java | 27 + .../sloeber/managedBuild/api/IFolderInfo.java | 70 + .../managedBuild/api/IHoldsOptions.java | 173 ++ .../sloeber/managedBuild/api/IInputOrder.java | 98 + .../sloeber/managedBuild/api/IInputType.java | 420 +++ .../managedBuild/api/IManagedBuildInfo.java | 375 +++ .../api/IManagedBuilderMakefileGenerator.java | 108 + .../api/IManagedCommandLineGenerator.java | 20 + .../api/IManagedCommandLineInfo.java | 58 + .../api/IManagedConfigElement.java | 48 + .../api/IManagedOptionValueHandler.java | 132 + .../managedBuild/api/IManagedProject.java | 166 ++ .../managedBuild/api/IModificationStatus.java | 69 + .../api/INewManagedOutputNameProvider.java | 8 + .../io/sloeber/managedBuild/api/IOption.java | 740 +++++ .../api/IOptionApplicability.java | 65 + .../managedBuild/api/IOptionCategory.java | 118 + .../api/IOptionCategoryApplicability.java | 38 + .../api/IOptionCommandGenerator.java | 39 + .../api/IOptionDefaultValueGenerator.java | 37 + .../api/IOptionPathConverter.java | 37 + .../sloeber/managedBuild/api/IOutputType.java | 259 ++ .../api/IResourceConfiguration.java | 236 ++ .../managedBuild/api/IResourceInfo.java | 107 + .../managedBuild/api/ITargetPlatform.java | 150 + .../io/sloeber/managedBuild/api/ITool.java | 657 +++++ .../sloeber/managedBuild/api/IToolChain.java | 401 +++ .../managedBuild/api/OptionStringValue.java | 195 ++ 57 files changed, 12597 insertions(+) create mode 100644 io.sloeber.ManagedBuild/.classpath create mode 100644 io.sloeber.ManagedBuild/.gitignore create mode 100644 io.sloeber.ManagedBuild/.project create mode 100644 io.sloeber.ManagedBuild/META-INF/MANIFEST.MF create mode 100644 io.sloeber.ManagedBuild/OSGI-INF/l10n/bundle.properties create mode 100644 io.sloeber.ManagedBuild/build.properties create mode 100644 io.sloeber.ManagedBuild/plugin.properties create mode 100644 io.sloeber.ManagedBuild/plugin.xml create mode 100644 io.sloeber.ManagedBuild/pom.xml create mode 100644 io.sloeber.ManagedBuild/schema/ManagedBuildTools.exsd create mode 100644 io.sloeber.ManagedBuild/schema/buildDefinitions.exsd create mode 100644 io.sloeber.ManagedBuild/src/io/sloeber/managedBuild/Internal/ArchiveNameProvider.java create mode 100644 io.sloeber.ManagedBuild/src/io/sloeber/managedBuild/Internal/ArduinoGnuMakefileGenerator.java create mode 100644 io.sloeber.ManagedBuild/src/io/sloeber/managedBuild/Internal/LinkNameProvider.java create mode 100644 io.sloeber.ManagedBuild/src/io/sloeber/managedBuild/Internal/MakeRule.java create mode 100644 io.sloeber.ManagedBuild/src/io/sloeber/managedBuild/Internal/MakeRules.java create mode 100644 io.sloeber.ManagedBuild/src/io/sloeber/managedBuild/Internal/ManagebBuildCommon.java create mode 100644 io.sloeber.ManagedBuild/src/io/sloeber/managedBuild/Internal/ManagedBuildConstants.java create mode 100644 io.sloeber.ManagedBuild/src/io/sloeber/managedBuild/Internal/SrcMakeGenerator.java create mode 100644 io.sloeber.ManagedBuild/src/io/sloeber/managedBuild/Internal/SubDirMakeGenerator.java create mode 100644 io.sloeber.ManagedBuild/src/io/sloeber/managedBuild/Internal/TopMakeFileGenerator.java create mode 100644 io.sloeber.ManagedBuild/src/io/sloeber/managedBuild/api/AbstractBuildRunner.java create mode 100644 io.sloeber.ManagedBuild/src/io/sloeber/managedBuild/api/BuildException.java create mode 100644 io.sloeber.ManagedBuild/src/io/sloeber/managedBuild/api/IAdditionalInput.java create mode 100644 io.sloeber.ManagedBuild/src/io/sloeber/managedBuild/api/IBuildObject.java create mode 100644 io.sloeber.ManagedBuild/src/io/sloeber/managedBuild/api/IBuildPathResolver.java create mode 100644 io.sloeber.ManagedBuild/src/io/sloeber/managedBuild/api/IBuilder.java create mode 100644 io.sloeber.ManagedBuild/src/io/sloeber/managedBuild/api/IConfiguration.java create mode 100644 io.sloeber.ManagedBuild/src/io/sloeber/managedBuild/api/IEnvVarBuildPath.java create mode 100644 io.sloeber.ManagedBuild/src/io/sloeber/managedBuild/api/IFileInfo.java create mode 100644 io.sloeber.ManagedBuild/src/io/sloeber/managedBuild/api/IFolderInfo.java create mode 100644 io.sloeber.ManagedBuild/src/io/sloeber/managedBuild/api/IHoldsOptions.java create mode 100644 io.sloeber.ManagedBuild/src/io/sloeber/managedBuild/api/IInputOrder.java create mode 100644 io.sloeber.ManagedBuild/src/io/sloeber/managedBuild/api/IInputType.java create mode 100644 io.sloeber.ManagedBuild/src/io/sloeber/managedBuild/api/IManagedBuildInfo.java create mode 100644 io.sloeber.ManagedBuild/src/io/sloeber/managedBuild/api/IManagedBuilderMakefileGenerator.java create mode 100644 io.sloeber.ManagedBuild/src/io/sloeber/managedBuild/api/IManagedCommandLineGenerator.java create mode 100644 io.sloeber.ManagedBuild/src/io/sloeber/managedBuild/api/IManagedCommandLineInfo.java create mode 100644 io.sloeber.ManagedBuild/src/io/sloeber/managedBuild/api/IManagedConfigElement.java create mode 100644 io.sloeber.ManagedBuild/src/io/sloeber/managedBuild/api/IManagedOptionValueHandler.java create mode 100644 io.sloeber.ManagedBuild/src/io/sloeber/managedBuild/api/IManagedProject.java create mode 100644 io.sloeber.ManagedBuild/src/io/sloeber/managedBuild/api/IModificationStatus.java create mode 100644 io.sloeber.ManagedBuild/src/io/sloeber/managedBuild/api/INewManagedOutputNameProvider.java create mode 100644 io.sloeber.ManagedBuild/src/io/sloeber/managedBuild/api/IOption.java create mode 100644 io.sloeber.ManagedBuild/src/io/sloeber/managedBuild/api/IOptionApplicability.java create mode 100644 io.sloeber.ManagedBuild/src/io/sloeber/managedBuild/api/IOptionCategory.java create mode 100644 io.sloeber.ManagedBuild/src/io/sloeber/managedBuild/api/IOptionCategoryApplicability.java create mode 100644 io.sloeber.ManagedBuild/src/io/sloeber/managedBuild/api/IOptionCommandGenerator.java create mode 100644 io.sloeber.ManagedBuild/src/io/sloeber/managedBuild/api/IOptionDefaultValueGenerator.java create mode 100644 io.sloeber.ManagedBuild/src/io/sloeber/managedBuild/api/IOptionPathConverter.java create mode 100644 io.sloeber.ManagedBuild/src/io/sloeber/managedBuild/api/IOutputType.java create mode 100644 io.sloeber.ManagedBuild/src/io/sloeber/managedBuild/api/IResourceConfiguration.java create mode 100644 io.sloeber.ManagedBuild/src/io/sloeber/managedBuild/api/IResourceInfo.java create mode 100644 io.sloeber.ManagedBuild/src/io/sloeber/managedBuild/api/ITargetPlatform.java create mode 100644 io.sloeber.ManagedBuild/src/io/sloeber/managedBuild/api/ITool.java create mode 100644 io.sloeber.ManagedBuild/src/io/sloeber/managedBuild/api/IToolChain.java create mode 100644 io.sloeber.ManagedBuild/src/io/sloeber/managedBuild/api/OptionStringValue.java diff --git a/io.sloeber.ManagedBuild/.classpath b/io.sloeber.ManagedBuild/.classpath new file mode 100644 index 000000000..f0d0c735f --- /dev/null +++ b/io.sloeber.ManagedBuild/.classpath @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/io.sloeber.ManagedBuild/.gitignore b/io.sloeber.ManagedBuild/.gitignore new file mode 100644 index 000000000..09e3bc9b2 --- /dev/null +++ b/io.sloeber.ManagedBuild/.gitignore @@ -0,0 +1,2 @@ +/bin/ +/target/ diff --git a/io.sloeber.ManagedBuild/.project b/io.sloeber.ManagedBuild/.project new file mode 100644 index 000000000..464af33cb --- /dev/null +++ b/io.sloeber.ManagedBuild/.project @@ -0,0 +1,34 @@ + + + io.sloeber.ManagedBuild + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.pde.ManifestBuilder + + + + + org.eclipse.pde.SchemaBuilder + + + + + org.eclipse.m2e.core.maven2Builder + + + + + + org.eclipse.m2e.core.maven2Nature + org.eclipse.pde.PluginNature + org.eclipse.jdt.core.javanature + + diff --git a/io.sloeber.ManagedBuild/META-INF/MANIFEST.MF b/io.sloeber.ManagedBuild/META-INF/MANIFEST.MF new file mode 100644 index 000000000..37fd532ce --- /dev/null +++ b/io.sloeber.ManagedBuild/META-INF/MANIFEST.MF @@ -0,0 +1,14 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: Sloeber Managed Build +Bundle-SymbolicName: io.sloeber.ManagedBuild;singleton:=true +Bundle-Version: 4.4.1.qualifier +Bundle-RequiredExecutionEnvironment: JavaSE-11 +Bundle-Vendor: Sloeber.io +Bundle-ActivationPolicy: lazy +Bundle-ClassPath: . +Require-Bundle: org.eclipse.cdt.core;bundle-version="7.0.0", + org.eclipse.equinox.registry, + org.eclipse.core.resources, + org.eclipse.core.contenttype +Automatic-Module-Name: io.sloeber.core diff --git a/io.sloeber.ManagedBuild/OSGI-INF/l10n/bundle.properties b/io.sloeber.ManagedBuild/OSGI-INF/l10n/bundle.properties new file mode 100644 index 000000000..131b30b9b --- /dev/null +++ b/io.sloeber.ManagedBuild/OSGI-INF/l10n/bundle.properties @@ -0,0 +1,43 @@ +#Properties file for io.sloeber.core +configuration.name = Release +content-type.hexdump.flash.name = HEX Dump for Flash ROM +content-type.hexdump.name = HEX Dump for EEPROM +inputType.archiver.name = OBJ Files to archive +inputType.Asembly.name = Assembly source files +inputType.C.name = C Source Files +inputType.CPP.name = CPP source files +inputType.linker.name = OBJ link Files +inputType.objcopy.name = objcopy input +option.include.path.name = Include Paths (-I) +optionCategory.include.name = Include Folders +outputType.archiver.name = Archive file +outputType.C.AR.name = Object Files ( C ar) +outputType.C.link.name = Object Files ( C link) +outputType.CPP.AR.name = Object Files (CPP ar) +outputType.CPP.link.name = Object Files (CPP link) +outputType.elf.name = ELF Binary Files as output +outputType.hexdump.name = Hex dump for eep output +outputType.S.AR.name = Object Files ( S ar) +outputType.S.link.name = Object Files ( S link) +projectType.name = Arduino sketch +targetPlatform.name = Arduino Target +tool.archiver.name = Arduino archiver +tool.Arduino.archiver.announcement = Starting archiver +tool.Arduino.C.announcement = Starting C compile +tool.Arduino.C2O.name = Arduino C Compiler +tool.Arduino.combiner.announcement = Starting combiner +tool.Arduino.CPP.announcement = Starting C++ compile +tool.Arduino.CPP2O.name = Arduino C++ Compiler +tool.Arduino.S.announcement = Starting S compile +tool.Arduino.S20.name= Arduino Assembler +tool.combiner.name = Arduino combiner +tool.obcopy.announcement = Do all objcopy commands +tool.objcopy.name = Arduino tool objcopy command +tool.printsize.announcement = Printing size: +tool.printsize.name = Arduino tool Print Size +toolchain.builder.name = Sloeber: Arduino Make Builder +toolchain.gnu.builder.name = Arduino sketch builder +toolChain.name = Arduino Toolchain (Sloeber edition) +provider.compoler.settings.name = Arduino Compiler Settings +launchConfigurationType.arduio.name = Arduino Launch +builder.ino.to.cpp = Convert Ino to CPP files \ No newline at end of file diff --git a/io.sloeber.ManagedBuild/build.properties b/io.sloeber.ManagedBuild/build.properties new file mode 100644 index 000000000..9a25e490a --- /dev/null +++ b/io.sloeber.ManagedBuild/build.properties @@ -0,0 +1,13 @@ +source.. = src/ +output.. = bin/ +bin.includes = .,\ + plugin.xml,\ + plugin.properties,\ + src/io/sloeber/core/templates/sketch.cpp,\ + src/io/sloeber/core/templates/sketch.h,\ + META-INF/,\ + config/,\ + OSGI-INF/,\ + src/io/sloeber/core/templates/sketch.ino,\ + OSGI-INF/l10n/bundle.properties +jars.compile.order = . diff --git a/io.sloeber.ManagedBuild/plugin.properties b/io.sloeber.ManagedBuild/plugin.properties new file mode 100644 index 000000000..c73a0e991 --- /dev/null +++ b/io.sloeber.ManagedBuild/plugin.properties @@ -0,0 +1,2 @@ +pluginName=Arduino Eclipse Plugin named Sloeber +providerName=Jan Baeyens diff --git a/io.sloeber.ManagedBuild/plugin.xml b/io.sloeber.ManagedBuild/plugin.xml new file mode 100644 index 000000000..41fa2e3a0 --- /dev/null +++ b/io.sloeber.ManagedBuild/plugin.xml @@ -0,0 +1,460 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/io.sloeber.ManagedBuild/pom.xml b/io.sloeber.ManagedBuild/pom.xml new file mode 100644 index 000000000..88f2549b2 --- /dev/null +++ b/io.sloeber.ManagedBuild/pom.xml @@ -0,0 +1,13 @@ + + + 4.0.0 + + io.sloeber.arduino-eclipse-plugin + io.sloeber.parent + 4.4.1-SNAPSHOT + ../io.sloeber.parent + + + io.sloeber.core + eclipse-plugin + diff --git a/io.sloeber.ManagedBuild/schema/ManagedBuildTools.exsd b/io.sloeber.ManagedBuild/schema/ManagedBuildTools.exsd new file mode 100644 index 000000000..140c0bcfc --- /dev/null +++ b/io.sloeber.ManagedBuild/schema/ManagedBuildTools.exsd @@ -0,0 +1,763 @@ + + + + + + + + + The managed build information model describes targets, configurations, and toolchains for the build system. + + + + + + + Defines a single value of an enumerated option. + + + + + + + Unique identifier for the option enumeration. + + + + + + + A descriptive name for the enumeration. + + + + + + + + + + Flags this enumerated value as the default to apply to the option if the user has not changed the setting. + + + + + + + The command that the enumerated value translates to on the command line. + + + + + + + + + + An option is associated with a tool. Options can contain boolean values, a simple text string, a selection from an enumerated list, or a list of values. Options also map the value they contain to a command-line flag, such as '-g' in the case of debugging symbol information for compilers. + + + + + + + + + + + A unique identifier for the option. + + + + + + + A descriptive name for the option. + + + + + + + + + + General options can be one of the following types; 'string' for catch-all entries for options that cannot be easily defined any other way, 'string list' for entries that consist of a list of values such as defined symbols or paths, 'boolean' for options that have two values, and 'enumerated' for options that are one-of a list of values. + +Additional special types exist to flag options of special relevance to the build model; 'include', 'libs', 'userObjs' and 'definedSymbols'. You can pre-populate with optionValues, and they will display in the UI the same way the 'stringList' options do. The build model will look specifically for these value types when clients query for include paths and preprocessor defines. The makefile generator will treat the libs and userObjs entries differently than other stringLists. + + + + + + + + + + + + + + + + + + + + + + + + + + + This is the id of the option category for this option. The id can be the id of the tool which is also a category. + + + + + + + Specifies the default value for the option if the 'value' field is blank. For enumerated options the optionEnums will be searched for the default. For string list options, all defined optionValues will be treated as defaults. For boolean values, specify truth using the string 'true'. All other strings will be treated as false. + + + + + + + An optional value that specifies the actual command that will be passed to the tool on the command line. + + + + + + + An optional value, used only with options of type Boolean, that specifies the actual command that will be passed to the tool on the command line when the value of the Boolean option is False. + + + + + + + This value is used for list (and related) options only. If you need a list option to prompt the user to browse for a file or directory when adding a new value, set the value of the attribute accordingly. By default the value is treated as no browsing needed. + + + + + + + + + + + + + + + + + This field is unused in 2.0 + + + + + + + + + + Specifies a "tip" that can be displayed in hover help or on the property page. Not implemented in 2.0. + + + + + + + + + + + + + Defines a tool used in the build process. + + + + + + + + + + + A unique identifier for the tool that will be used by the build model. + + + + + + + Human-readable name for the tool to be used in the UI. + + + + + + + + + + A comma-separated list of file extensions that the tool will produce output for. + + + + + + + The extension that the tool will produce from a given input. + + + + + + + The command that invokes the tool. For example, gcc for the Gnu C compiler, or g++ for the Gnu C++ compiler. + + + + + + + An optional flag for tools that allow users to specify a name for the artifact of the tool. For example, the GCC compiler and linker tools typically allow the user to specify the name of the output with the '-o' flag, whereas the archiver that creates libraries does not. + + + + + + + Some tools produce files with a special prefix that must be specified. For example, a librarian on POSIX systems expects the output to be lib<target>.a, so 'lib' would be the prefix. + + + + + + + This is an optional field that specifies the class that provides the source file dependency calculation for a given tool. You can replace the default calculator with a class that implements the <code>IManagedDependencyGenerator</code> interface. + + + + + + + + + + A comma-separated list of file extensions that are used for header files. Since many other files depend on the interfaces defined in header files, the build system needs to be able to determine that a header file has changed to properly rebuild its dependents. + + + + + + + Filter the display (and use) of the tool by the nature of the project. Selecting a value of 'cnature' insures that the tool will be displayed IFF there is a cnature associated with the project. A ccnature will filter this tool out. If 'ccnature' is selected, the tool will only be available for C++ projects. If 'both' is selected, the tool will be displayed when either nature is present. + + + + + + + + + + + + + + + + + + + + Represents a type of resource that is the target of the build process, for example, a Linux static library. A target contains a sequence of tool definitions and configurations. Targets are arranged in an inheritance hierarchy where a target inherits the list of tools from it's parent and can add to or override tools in this list. + + + + + + + + + + + + Used by the build model to uniquely identify the target. + + + + + + + A human-readable target name, such as 'Executable'. This will be the name the user sees displayed in the UI. + + + + + + + + + + This is a UI property. If set to true, users should not be able to create project configurations targeted at this target. + + + + + + + The id of a target that this tool inherits from. + + + + + + + This is the name of the final build artifact associated with the target. The user will specify this is the UI, so there is no need to supply a default value. + + + + + + + This is the extensionthat will be applied to any build artifact created by the target. + + + + + + + A an optional field that flags a target as a test-only target. If true, the target will not appear in the UI. + + + + + + + This attribute maintains the command that removes files for a particular target. For example, on POSIX targets like Linuc, Solaris, or Cygwin, the command would be <code>rm -rf</code> whereas on Win32 platforms it would be <code>del /F /S /Q</code> + + + + + + + Specifies the default command to start the build utility for your toolchain. If the user changes this through the UI, the overriden value will be stored in the project build file. The build model will default to this value if the user ever resets a change. + + + + + + + Specifies the additional, default arguments that will be passed to the build utility when it is called by the builder. If the user changes the flags through the UI, the overriden value will be stored in the project build settings file. The build model will default to this value if the user ever resets a change. + + + + + + + Set this to the ID of the binary parser for the output format of your target. Currently there are only 2 choices: org.eclipse.cdt.core.ELF for *nix targets, and "org.eclipse.cdt.core.PE64" for targets that build for Windows, like Cygwin. + + + + + + + This field is used by the managed build system to decide when to show the user the target. The value should be a comma-separated list. Current values are "win32", "linux", "solaris", "hpux", "aix" or "any". + + + + + + + This field is used by the managed build system to decide when to show the user the target. The value should be a comma-separated list. Current values include "x86", "sparc", "ppc"; or "all". + + + + + + + Specifies the default list of error parsers to be used by projects created from this target. It is an ordered, semi-colon separated list of parser IDs. The order specifies the order in which the error parsers are invoked during a build. + + + + + + + Specifies a class that implements the <code>IManagedScannerInfoCollector</code> for gathering the built-in compiler settings for a toolchain. + + + + + + + + + + Allows you to supply a custom makefile generator that conforms to the <code>IManagedBuilderMakefileGenerator</code> interface. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + A configuration is used to gather together certain default tools and options to build target a certain way. For example, a "Debug" configuration might supply tools with the options set to build with debugging symbols, whereas a "Release" configuration would supply tools with options set to create the best performance. + + + + + + + + + + Unique identifier for the configuration. + + + + + + + A descriptive name for the configuration to be used in the UI. + + + + + + + + + + + + + This is reserved for future use. It currently gets instantiated for saving tool settings. + + + + + + + + + + The unique ID of the tool that the reference is for. + + + + + + + The overridden command for the tool the reference is for. + + + + + + + A comma-separated list of extensions that this tool reference will create. This completely overrides the the output extension in the tool the reference is for. + + + + + + + The prefix that will be applied to the output of the tool. This completely overrides the output defined in the referenced tool. + + + + + + + Overrides the output flag of the referenced tool. + + + + + + + + + + Option references hold onto information the user has changed through the UI. Not all fields will be populated, depending on the option type the reference overrides. For example, the 'name' field is used by enumerated options only. + + + + + + + + + + + The unique ID of the option the reference is for. + + + + + + + This field is used to record the value of the option that the user has set in the build settings file. For example, if the user has set the verbose flag to true, the project's build settings file will contain an option reference for the verbose option, with the defaultvalue set to true. +<p>The attribute is also used to override the default option setting for a configuration in a toolchain. For example, a 'Debug' configuration may setthe value of a debug flag differently than the default value defined in the tool. + + + + + + + This field is unused in 2.0 + + + + + + + + + + An optional, but useful, mechanism for grouping options together. + + + + + + + Used by the build model to uniquely identify the option category. + + + + + + + A human-readable category name, such as 'Preprocessor Options'. This will be the name the user sees displayed in the UI. + + + + + + + + + + Option categories can belong to a tool or be nested inside other option categories. This is the ID of the owner of the category. + + + + + + + + + + A value for defining individual elements of a list option. + + + + + + + The contents of the list item. + + + + + + + This attribute flags the list value as a built-in value as opposed to something the user has entered. Built-ins will not be passed to clients that generate command lines (like the makefile generator). However, clients that need to take these settings into account (like the indexing service), will receive these settings. These values will appear grey in the UI. + + + + + + + + + + An optional element that allows a tool implementor to supply a class that creates one or more dynamic toolchain elements. For example, the class might create a new tool reference based on the contents of a special file, and a new target that uses that reference. + + + + + + + The class that implements the <code>IManagedConfigElementProvider</code> interface. The logic of determining the elements is left to the implementer, but they must be correctly formed or the build model will have trouble loading. + + + + + + + + + + A meaningful name for the type of element being provided. + + + + + + + + + + + + + <p> +Version identifier for the managed build extension point. It is a string representation, consisting of three (3) tokens separated by a decimal point. The 3 tokens are positive integer numbers. For example, the following are valid version identifiers: + <ul> + <li><code>0.0.0</code></li> + <li><code>1.0.1234</code></li> + <li><code>1.9</code> (interpreted as <code>1.9.0</code>)</li> + <li><code>3</code> (interpreted as <code>3.0.0</code>)</li> + </ul> +</p> + + + + + + + The actual string containing the three version tokens. + + + + + + + + + + + + 1.2 + + + + + + + + + The following is an example of the extension point usage: +<p> +<pre> + <extension + id="buildExample" + name="Tools for Build Example" + point="org.eclipse.cdt.core.ManagedBuildInfo"> + <target + makeFlags="-k" + isTest="false" + cleanCommand="rm -rf" + name="Executable" + defaultExtension=".exe" + isAbstract="false" + makeCommand="make" + id="example.target.executable"> + <tool + sources="C" + name="Compiler" + outputFlag="-o" + outputs="exe" + command="g++" + id="executable.compiler"> + <optionCategory + owner="executable.compiler" + name="Flags" + id="compiler.category.flags"> + </optionCategory> + <option + defaultValue="-c" + name="Compiler Flags" + category="compiler.category.flags" + valueType="string" + id="category.flags.comp_flags"> + </option> + </tool> + <configuration + name="Default" + id="example.config.default"> + </configuration> + </target> + </extension> +</pre> + + + + + + + + + + An implementation of this extension point is supplied in <samp>org.eclipse.cdt.ui</samp> + + + + + + + + + Copyright (c) 2003, 2004 IBM Corporation and others. +This program and the accompanying materials are made available under the terms of the Eclipse Public License 2.0 which accompanies this distribution, and is available on the <a href="http://www.eclipse.org/legal/epl-2.0/"> Eclipse</a> website. + + + + diff --git a/io.sloeber.ManagedBuild/schema/buildDefinitions.exsd b/io.sloeber.ManagedBuild/schema/buildDefinitions.exsd new file mode 100644 index 000000000..e758c2654 --- /dev/null +++ b/io.sloeber.ManagedBuild/schema/buildDefinitions.exsd @@ -0,0 +1,2526 @@ + + + + + + + + + The managed build object model describes project-types, configurations, tool-chains, etc. for the managed build system. + + + + + + + represents the property value + + + + + + + represents the property value id + + + + + + + + + + A value for defining individual elements of a list option. + + + + + + + The contents of the list item. The build model will apply the command defined in the option to each value in the list. + + + + + + + This attribute flags the list value as a built-in value as opposed to something the user has entered. Built-ins will not be passed to clients that generate command lines (like the makefile generator). However, clients that need to take these settings into account (like the indexing service), will receive these settings. These values will appear grey in the UI. + + + + + + + + + + An option is associated with a tool. Options can contain boolean values, a simple text string, a selection from an enumerated list, or a list of values. Options also map the value they contain to a command-line flag, such as '-g' in the case of debugging symbol information for compilers. +Options can also be associated with a toolchain. However in such a case the option must be contained in a optionCategory. + + + + + + + + + + + + + + + A unique identifier for the option. + + + + + + + A descriptive name for the option. + + + + + + + + + + The id of an option that this option is derived from. + + + + + + + An optional field that flags an option as abstract. An abstract option must be defined as a top level object in the model definition and cannot be selected by the user in the UI, but options derived from this option will inherit its attributes and children. The default is false. + + + + + + + A semi-colon separated list of child IDs of the superclass' children that should not be automatically inherited by this element. Note: This attribute is not yet implemented. + + + + + + + The id of the option category for this option. The id can be the id of the tool which is also a category. The default category is the parent tool. Note that an optionCategory id must be supplied as the value for an option that is a child of a toolChain. + + + + + + + Filters the display (and use) of the option by the type of the resource (currently Project or File). The value 'project' causes the option to be used when applied to a project. The value 'file' causes the option to be used when applied to a file. If 'all' is selected, the option applies to all types of resources. The default is "all". + + + + + + + + + + + + + + + + + General options can be one of the following types; 'string' for catch-all entries for options that cannot be easily defined any other way, 'string list' for entries that consist of a list of values such as defined symbols or paths, 'boolean' for options that have two values, and 'enumerated' for options that are one-of a list of values. + +Additional special types exist to flag options of special relevance to the build model; 'include', 'libs', 'userObjs' and 'definedSymbols'. You can pre-populate with optionValues, and they will display in the UI the same way the 'stringList' options do. The build model will look specifically for these value types when clients query for include paths and preprocessor defines. The makefile generator treats the libs and userObjs entries differently than other stringLists. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + This value is used for string and stringlist (and related) options only. If you need a list option to prompt the user to browse for a file or directory when adding a new value, set the value of the attribute accordingly. By default the value is treated as no browsing needed. + + + + + + + + + + + + + + + + + An optional value that specifies the default filter-path for the underlying file or directory browse-dialog. Macros in the value will be expanded. This attribute only applies when user chooses to browse the file-system. + + + + + + + An optional value that specifies a comma-separated string of file-extension filters for the underlying file browse-dialog. For filters with multiple extensions, use semicolon as a separator - eg. "*.lib;*.a;*.cmd,*.*". This attribute only applies when user chooses to browse the file-system, and only when browseType is 'file'. + + + + + + + Specifies the value assigned to the option by the end user or in a default configuration. For boolean values, specify truth using the string 'true'. All other strings will be treated as false. + + + + + + + Specifies the default value for the option if the 'value' attribute is blank. For enumerated options the optionEnums will be searched for the default. For string list options, all defined optionValues will be treated as defaults. For boolean values, specify truth using the string 'true'. All other strings will be treated as false. + + + + + + + Optional class which can be used to override the default value for an option. This class must implement the IOptionDefaultValueGenerator interface. If no generator is specified then the 'defaultValue' attribute is used to generate the option's default value. + + + + + + + + + + An optional value that specifies the actual command that will be passed to the tool on the command line. The attribute value provides a "pattern" for specifying where the option "value" should be placed for options of type string and stringlist. If no ${value} is specified in the command, the option value is appended to the end of the specified command. + + + + + + + Optional class which can be used to override the default command-generation logic for an option. This class must impelment the IOptionCommandGenerator interface. If no generator is specified then the 'comand' attribute is used to generate the option's command. + + + + + + + + + + An optional value, used only with options of type Boolean, that specifies the actual command that will be passed to the tool on the command line when the value of the Boolean option is False. + + + + + + + An optional field to allow the option additionally to be passed to scanner discovery of built-in compiler macros and paths. The default is false. + + + + + + + This field is unused in 2.0 + + + + + + + + + + Specifies a "tip" that can be displayed in hover help or on the property page. + + + + + + + + + + specify a fully qualified context id for supplying context sensitive help for an option. + + + + + + + The id of a class that implements the IManagedOptionValueHandler interface. This interface is used to dynamically manage the value of an option. + + + + + + + + + + An optional extra text string that is passed into the valueHandler. + + + + + + + Optional class which is used to determine dynamically at runtime whether the option is visible, enabled, and used in command line generation. This class must implement the IOptionApplicability interface. If no calculator is specified then the option is always visible, enabled, and used in command line generation. + + + + + + + + + + Optional ID of the custom field-editor to represent this build-option in the project Properties dialog UI. If no custom field-editor ID is specified then the option will be represented by one of the built-in field-editors based on the option's <code>valueType</code> attribute. + +A custom field-editor needs to be registered, under the same ID, through the <code>org.eclipse.cdt.managedbuilder.ui.buildDefinitionsUI</code> extension-point's <code>&lt;fieldEditor&gt;</code> element. + + + + + + + + + + An optional extra text string that is passed into the field-editor. Can be used to parameterize the field-editor instance. + + + + + + + + + + Defines a tool used in the build process. + + + + + + + + + + + + + + + + A unique identifier for the tool that will be used by the build model. + + + + + + + Human-readable name for the tool to be used in the UI. + + + + + + + + + + The id of a tool that this tool is derived from. + + + + + + + An optional field that flags a tool as abstract. An abstract tool must be defined as a top level object in the model definition and cannot be selected by the user in the UI, but tools derived from this tool will inherit its attributes and children. The default is false. + + + + + + + An optional flag for tools that allow users to specify a name for the artifact of the tool. For example, the GCC compiler and linker tools typically allow the user to specify the name of the output with the '-o' flag, whereas the archiver that creates libraries does not. + + + + + + + Filters the display (and use) of the tool by the nature of the project. Selecting a value of 'cnature' insures that the tool will be displayed IFF there is a cnature associated with the project. A ccnature will filter this tool out. If 'ccnature' is selected, the tool will only be available for C++ projects. If 'both' is selected, the tool will be displayed when either nature is present. This attribute is required if it is not inherited from its superClass. The default value is "both". + + + + + + + + + + + + + + + + + The command that invokes the tool. For example, gcc for the Gnu C compiler, or g++ for the Gnu C++ compiler. This attribute supports MBS file context macros. + + + + + + + Specifies the command "pattern" that indicates how the parts of the command line are used to create the entire command line. The pattern consists of the replaceable variables COMMAND, FLAGS, OUTPUT_FLAG, OUTPUT_PREFIX, OUTPUT and INPUTS. The default command line pattern is ${COMMAND} ${FLAGS} ${OUTPUT_FLAG}${OUTPUT_PREFIX}${OUTPUT} ${INPUTS}, except when customBuildStep is true, where the default is $(COMMAND). White space and other characters are significant and are copied to the generated command. This attribute supports MBS file context macros. + + + + + + + Specifies the name of the class that implements IManagedCommandLineGenerator in order to provide custom command line generation logic. + + + + + + + + + + Does this tool generate dependency files. + + + + + + + Specifies the default list of error parsers used by the tool. Error parsers specified by the tool are added to this list specified by the tool-chain when a project resource is defined to use the tool. It is automatically removed when there are no more project resources using the tool. It is an ordered, semi-colon separated list of parser IDs. The order specifies the order in which the error parsers are invoked during a build. + + + + + + + Specifies whether the Tool wants the MBS to display the Advanced Input category with the Tool's property categories. This allows the user to specify input order and additional inputs. The default is false. Note: This attribute is not yet implemented + + + + + + + Specifies whether this Tool represents a user-define custom build step. The default is false. When True, the default value of the commandLinePattern attribute changes to "$(command)". + + + + + + + Specifies a string that is written to the build output prior to each invocation of the tool. The default value is "Invoking tool-name (tool-id)..." + + + + + + + + + + Path to a 16x16 pixel big icon that is to be displayed instead of the default icon. The path is relative to the plug-in directory which defines .buildDefinitions. + + + + + + + + + + Specifies whether or not the tool supports managed build. Default value is true. + + + + + + + the system elements are used by the system for specific needs and are not displayed in UI + + + + + + + Specifies whether or not the tool is hidden within the setting tab of the user interface. This attribute should be set to true when a tool is internal to the toolchain and options cannot be changed by the user. Default value is false. + + + + + + + + + + A tool-integrator-defined, ordered set of tools that tranform the project's resources into the project's outputs. A tool-chain can be defined as part of a configuration, or as an independent specification that is referenced from a separate configuration via the tool-chain superClass attribute. + + + + + + + + + + + + + + + Unique identifier for the tool-chain. + + + + + + + A descriptive name for the tool-chain to be used in the UI. + + + + + + + + + + The id of a toolChain that this toolChain is derived from. + + + + + + + An optional field that flags a tool-chain as abstract. An abstract tool-chain must be defined as a top level object in the model definition and cannot be selected by the user in the UI, but tool-chains derived from this tool-chain will inherit its attributes and children. The default is false. + + + + + + + A semi-colon separated list of child IDs of the superclass' children that should not be automatically inherited by this element. Note: This attribute is not yet implemented. + + + + + + + This field lists the host operating systems on which the tool-chain runs and is used by the managed build system to decide when the tool-chain is applicable. The value should be a comma-separated list. Valid values are the strings returned by the Eclipse API Platform.getOS() and include strings like "win32", "linux", "solaris", "hpux", "aix". Do not specify this attribute or specify "all" to allow all host operating systems. + + + + + + + This field lists the host architectures on which the tool-chain runs and is used by the managed build system to decide when the tool-chain is applicable. The value should be a comma-separated list. Valid values are the strings returned by the Eclipse API Platform.getOSArch() and include strings like "ia32". Do not specify this attribute or specify "all" to allow all host architectures. + + + + + + + The semi-colon separated list of the default error parsers to be used with this tool-chain. The list is ordered with the first error parser on the list invoked first, the second error parser second, and so on. The list may contain the error parsers defined by CDT and/or other installed error parser extensions. When specified, this overrides the tool errorParsers attributes of the tool children of the tool-chain and the builder child of the tool-chain. + + + + + + + Semicolon-separated list of providers ID implementing ILanguageSettingProvider interface. This list could be adjusted on configuration level in the corresponding attribute. + + + + + + + Specifies an id of scanner configuration discovery profile for gathering the built-in compiler settings for a toolchain. + + + + + + + Specifies a semi-colon separated list of the Tool(s) that can create the final build artifact (the end target of the build). The first tool found in the configuration is used. A list is needed, for example, when a tool-chain has different tools for different project natures. + + + + + + + A semi-colon separated list of IDs of other outputTypes, besides the primary outputType of the targetTool, that are also considered to be build artifacts. The build file generator will ensure that the outputs get built. + + + + + + + Specifies the name of the class that implements IManagedIsToolChainSupported. This provides a method to be called to determine if support for the tool-chain is currently installed on the system. MBS uses this information in order to filter the choices presented to the CDT user and to inform the user when support needed by their project is not installed. If the isToolChainSupported callback is not provided by the tool-chain definition, the tool-chain is treated as supported. If all configurations defined for the given project type are not supported the project type is treated as unsupported. + + + + + + + + + + Specifies the name of the class that implements IConfigurationEnvironmentVariableSupplier in order to provide configuration level environment variables. + + + + + + + + + + Specifies the name of the class that implements IConfigurationBuildMacroSupplier in order to provide configuration level build macros. + + + + + + + + + + Specifies a comma delimited list of versions of this tool-chain that can be loaded without invoking a converter. + + + + + + + The identifier of a tool-chain, that tool-chains loaded using this definition should be converted to. MBS will invoke a proper converter. + + + + + + + Toolchains like Cygwin based Gnu tools can accept paths which are not valid for the OS platform. E.g. "/usr/include" is well difined for a Cygwin gcc compiler while it is not a meaningful path for a java.io.File. Therefore toolchains can specify a pathConverter which will be applied to include and library paths configured in the Managed Build System. + +The pathConverter of a toolchain applies for all tools of the toolchain except if a tool defines it's own pathConverter. In this case the pathConverter supplied by the toolchain is ignored. + + + + + + + + + + Specifies whether or not the tool-chain supports managed build. Default value is true. + + + + + + + the system elements are used by the system for specific needs and are not displayed in UI + + + + + + + + + + A configuration is used to gather together certain default tools and options to build project a certain way. For example, a "Debug" configuration might supply tools with the options set to build with debugging symbols, whereas a "Release" configuration would supply tools with options set to create the best performance. + + + + + + + + + + + + + + Unique identifier for the configuration. + + + + + + + A descriptive name for the configuration to be used in the UI. + + + + + + + + + + The configuration that this configuration was cloned from. + + + + + + + This is the name of the final build artifact associated with the configuration. The user will specify this is the UI, so there is no need to supply a default value. + + + + + + + This is the extension that will be applied (if necessary) to any build artifact created by the configuration. + + + + + + + This attribute maintains the command that removes the intermediate and output files for a particular configuration. For example, on POSIX platforms like Linuc, Solaris, or Cygwin, the command would be <code>rm -rf</code> whereas on Win32 platforms it would be <code>del /F /S /Q</code> + + + + + + + The semi-colon separated list of the default error parsers to be used with this configuration. The list is ordered with the first error parser on the list invoked first, the second error parser second, and so on. The list may contain the error parsers defined by CDT and/or other installed error parser extensions. The list of error parsers to be used may be changed by the user on a per-configuration basis. When specified, this overrides the tool-chain errorParsers attribute. + + + + + + + Semicolon-separated list of providers ID implementing ILanguageSettingProvider interface. +This field could be amended with toolchain-level providers list by using ${Toolchain} keyword. Provider ID can be prefixed with "-" which will cause id to be removed from the preceeding list including providers defined with ${Toolchain} keyword. +If this field is not specified, "org.eclipse.cdt.managedbuilder.core.MBSLanguageSettingsProvider" (MBS Language Settings Provider) is used by default. + + + + + + + Specifies the pre-build command, which runs prior to the standard MBS build. + + + + + + + Specifies the post-build command, which runs after the standard MBS build. + + + + + + + Specifies the string to be displayed when the pre-build command step is run. + + + + + + + + + + Specifies the string to be displayed when the post-build command step is run. + + + + + + + + + + Specifies the description of the configuration that will be displayed to the user while creating a project and managing configurations. The description is only displayed in the UI - it is not considered to be part of the configuration name. + + + + + + + + + + Specifies the comma-separated list of build property type - value pairs defined for this configuration. +property type-value pairs are specified in the type_id=value_id format. + + + + + + + the attribute specified the Build Artefact Type. can contain the value id of the "org.eclipse.cdt.build.core.buildArtefactType" build property. Default values contributed with the build system are +"org.eclipse.cdt.build.core.buildArtefactType.exe" - represents executable, +"org.eclipse.cdt.build.core.buildArtefactType.staticLib" - represents static library, +"org.eclipse.cdt.build.core.buildArtefactType.sharedLib" - represents dynamic library +Custom values can be contributed via the "org.eclipse.cdt.managedbuilder.core.buildProperties" extension point. See the description of that extension point for more detail. + +Specifying this attribute is fully equivalent to specifying the "org.eclipse.cdt.build.core.buildArtefactType" via tne buildProperties attribute. The buildArtefactType attribute, the "buildArtefactType" attribute value takes precedence over the artefact type specified via the "buildProperties" attribute + + + + + + + + + + Represents a class of project which acts as a template for the projects that the user will create, for example, a Linux static library. A project type contains a sequence of configurations. Project types are arranged in an inheritance hierarchy where a project type inherits the list of configurations from it's parent and can add to or override configurations in this list. + + + + + + + + + + Used by the build model to uniquely identify the project type. + + + + + + + A human-readable project type name, such as 'Executable'. This will be the name the user sees displayed in the UI. + + + + + + + + + + The id of a projectType that this projectType is derived from. + + + + + + + An optional field that flags a project type as abstract. If true, the project type will not appear in the UI. The project type is used by other project types as their "superclass". The default value is false. + + + + + + + A semi-colon separated list of child IDs of the superclass' children that should not be automatically inherited by this element. Note: This attribute is not yet implemented. + + + + + + + An optional field that flags a project type as test-only. If true, the project type will not appear in the UI. The project type can be manipulated programmatically in JUnit tests, for example. The default value is false. + + + + + + + Specifies the name of the class that implements IProjectEnvironmentVariableSupplier in order to provide project level environment variables. + + + + + + + + + + Specifies the name of the class that implements IProjectBuildMacroSupplier in order to provide project level build macros. + + + + + + + + + + Contains the name of a class that implements an interface with a method for returning a default name for a configuration. The configuration names in a user's project must be unique. A projectType can contain configuration children with the same name. In this case, a configurationNameProvider must be specified to make the names unique before they are displayed to the user in the New Project and New Configuration dialog boxes. + + + + + + + + + + The identifier of a projectType, that project types loaded using this definition should be converted to. MBS will invoke a proper converter. + + + + + + + Specifies the comma-separated list of build property type - value pairs to be applied for all configurations of this project type. +property type-value pairs are specified in the type_id=value_id format. + + + + + + + the attribute specified the Build Artefact Type. can contain the value id of the "org.eclipse.cdt.build.core.buildArtefactType" build property. Default values contributed with the build system are +"org.eclipse.cdt.build.core.buildArtefactType.exe" - represents executable, +"org.eclipse.cdt.build.core.buildArtefactType.staticLib" - represents static library, +"org.eclipse.cdt.build.core.buildArtefactType.sharedLib" - represents dynamic library +Custom values can be contributed via the "org.eclipse.cdt.managedbuilder.core.buildProperties" extension point. See the description of that extension point for more detail. + +Specifying this attribute is fully equivalent to specifying the "org.eclipse.cdt.build.core.buildArtefactType" via tne buildProperties attribute. The buildArtefactType attribute, the "buildArtefactType" attribute value takes precedence over the artefact type specified via the "buildProperties" attribute + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + The project element is an instance of a projectType element. It appears in the .cdtbuild file, not in an extension definition. + + + + + + + + + + The name of the project that the user sees displayed in the UI. This is the name that the user entered in the New Project wizard. + + + + + + + + + + The id of the projectType that this project is an instance of. + + + + + + + + + + A place to store build attributes of individual resources that are different from the configuration as a whole. + + + + + + + + + + The path of the project resource to which this element applies. + + + + + + + Specifies whether the resource is excluded from building in the parent configuration. The default is false. The resourceConfiguration element retains its tool children, if any exist, even when excluded from the build. + + + + + + + Identifies how the user desires to apply a resource custom build step: + 1. Apply rcbs tool before any other tools defined for the resource. + 2. Apply rcbs tool after any other tools defined for the resource. + 3. Apply rcbs tool overriding any other tools defined for the resource. + 4. Disable (don't apply) the rcbs tool. + + + + + + + + + + + + + + + + + + + Identifies which tools to invoke by a semicolon separated list of child tool ids. Applies as follows: + 1. Defaults to all tools in the order found + 2. Use specified ordered list of children to invoke + 3. If empty string, treat as if no resource configuration existed, i.e., use project level tool. + + + + + + + + + + Defines a type of input for the tool. Note that the calculated dependencies of an input type are not described by a separate input type, but are described by attributes of this element. + + + + + + + + + + + + A unique identifier for the input-type that will be used by the build model. + + + + + + + The name of the input type that is displayed to the user in the UI. + + + + + + + + + + The id of an input-type that this input-type is derived from. + + + + + + + The id of an Eclipse content type that describes this type of input. Either this attribute or the sources attribute must be specified by this element or a superclass. If both are specified, and the content type specified here is defined by Eclipse, the sources attribute is not used. + + + + + + + A comma-separated list of file extensions that identify files of this input type. Note that the user will not be able to modify the set of file extensions as they can when sourceContentType is specified. + + + + + + + The id of an Eclipse content type that describes the calculated dependencies for this type of input. If dependencyExtensions is also specified, and the content type specified here is defined by Eclipse, the dependencyExtensions attribute is not used. + + + + + + + A comma-separated list of file extensions that are used for calculated dependencies of this input-type. Note that the user will not be able to modify the set of file extensions as they can when dependencyContentType is specified. + + + + + + + The id of an Option element that is used on the command line to identify inputs of this type. If specified, the name(s) of the input files for this input type are taken from the value specified for the option. + + + + + + + The id of an Option element whose value is to be assigned to the file(s) calculated for this input type. The default is not to assign the input file(s) to a command line option but to assign the files to the ${Inputs} part of the command line. Note that the option value is only updated during build file generation and therefore could be out of sync with the project until build file generation occurs. + + + + + + + Specifies whether all inputs of this type are used in one invocation of the tool. The inputs can be project resources, and the outputs of other Tools in the Tool-chain. The default is false. + + + + + + + Specifies an id of scanner configuration discovery profile for gathering the built-in compiler settings for resource type presented with this input type. + + + + + + + Represents the language id, i.e. the id of language defined via the org.eclipse.cdt.core.language extension point + +The value of this attribute is used only in case languageInfoCalculator is not specified + + + + + + + Specifies the name of the class that implements org.eclipse.cdt.managedbuilder.core.ILanguageInfoCalculator for dinamic providing the language id info. +Overrides language id specified with the languageId attribute. + + + + + + + + + + + + + Describes optional, ordering, information regarding the inputs of an inputType. Note: This element is not yet implemented + + + + + + + Defines the relative or absolute path of the resource to which this element applies. The resource must be a member of the project, or the output from another tool in the tool-chain. + + + + + + + A comma-separated list of integer values that specify the input order of this resource. In most cases, a single value is used. A list is used if the same input resource appears multiple times in the input list. The order number begins at 1. All unordered input resources fill the first gap in the specified order values. + + + + + + + If True, this input resource is not used as an input to the tool. + + + + + + + + + + Describes optional information regarding additional inputs and/or dependencies. + + + + + + + Defines a semi-colon delimited list of relative or absolute paths of the resource to which this element applies. The resources must be a member of the project, the output from another tool in the tool-chain, or an external file. The file name of the path can use GNU Make pattern rule syntax in order to generate the name from the filename of the input file. + + + + + + + Defines the type of additional input, whether the resource is added to the dependency list, the inputs on the command line, or both. The default is to add the inputs to both. + + + + + + + + + + + + + + + + + + + + Defines a type of output for a tool. + + + + + + + + + + A unique identifier for the output-type that will be used by the build model. + + + + + + + The name of the output type that is displayed to the user in the UI. + + + + + + + + + + The id of an output-type that this output-type is derived from. + + + + + + + The id of an Eclipse content type that describes this type of output. Either this attribute or the outputs attribute must be specified by this element or a superclass. If both are specified, and the content type specified here is defined by Eclipse, the outputs attribute is not used. + + + + + + + The file extension that identify files of this output type. Note that the user will not be able to modify the set of file extensions as they can when outputContentType is specified. + + + + + + + The id of an Option element that is used on the command line to specify this output. The default is to use the Tool outputFlag attribute if primaryOutput is True. If option is not specified, and primaryOutput is False, then the output file(s) of this outputType are not added to the command line. If specified, the nameProvider, namePattern and outputNames are ignored. + + + + + + + Some tools produce files with a special prefix that must be specified. For example, a librarian on POSIX systems expects the output to be libtarget.a, so 'lib' would be the prefix. The default is to use the Tool "outputPrefix" attribute if primaryOutput is True, otherwise the default is an empty string. This attribute supports MBS configuration context macros. + + + + + + + The output file name generated for this outputType. If specified, the namePattern is ignored. This attribute supports MBS file context macros. + + + + + + + Specifies a pattern, using the Gnu Make pattern rule syntax, for deriving the output resource name from the input resource name. The default, "%" is to use the input resource base name with the first output extension. + + + + + + + The name of the class that implements the <code>IManagedOutputNameProvider</code> interface. If specified, the outputNames and namePattern are ignored. When multipleOfType is true, this attribute, or the outputNames attribute, is required in order for MBS to know the names of the output files. + + + + + + + + + + A variable used in the build file to represent the output file(s). The same variable name can be used in an inputType element to identify a set of output files that contribute to a tool's input. The default name is chosen by MBS. + + + + + + + + + + An optional, but useful, mechanism for grouping options together. + + + + + + + + + + Used by the build model to uniquely identify the option category. + + + + + + + A human-readable category name, such as 'Preprocessor Options'. This will be the name the user sees displayed in the UI. + + + + + + + + + + Option categories can belong to a tool, a toolChain or be nested inside other option categories. This is the ID of the owner of the category. The default owner if the parent tool or tool-chain. + + + + + + + Path to a 16x16 pixel big icon that is to be displayed instead of the default icon. +The path is relative to the plug-in directory which defines .buildDefinitions. + + + + + + + + + + Optional class which is used to determine dynamically at runtime whether the option category is visible. This class must implement the IOptionCategoryApplicability interface. If no calculator is specified then the option category is always visible. + + + + + + + + + + + + + Defines a single value of an enumerated option. + + + + + + + + + + Unique identifier for the option enumeration. + + + + + + + A descriptive name for the enumeration. + + + + + + + + + + Flags this enumerated value as the default to apply to the option if the user has not changed the setting. + + + + + + + The command that the enumerated value translates to on the command line. + + + + + + + + + + + + + + + The id should be the value used for determining which treeOption is selected, it has to be unique within the tree. + + + + + + + Display name for the option + + + + + + + + + + Description of the option to be presented to the user + + + + + + + + + + The command that the tree value translates to on the command line. + + + + + + + Flags this tree value as the default to apply to the option if the user has not changed the setting. + + + + + + + An icon to be used for this node in the tree representation. Should use full path for the icon: e.g., platform:/plugin/org.eclipse.cdt/icons/wizard.png + + + + + + + + + + An integer representing the order of this option within its peers in the tree. The order is a relative number, were smaller numbers appear on top of larger numbers. +If no order is defined a default order is assumed, see "org.eclipse.cdt.managedbuilder.core.IOption.ITreeOption.DEFAULT_ORDER" for more details. + + + + + + + + + + Represents the root of a tree of options. Note that the root is never shown to the user and can't be selected. It is a place holder for settings affecting the options tree behavior + + + + + + + + + + + + + + + + + + + + + + + + The tree root icon can be used in branding the UI representation of the tree. Should use full path for the icon: e.g., platform:/plugin/org.eclipse.cdt/icons/wizard.png + + + + + + + + + + Determines whether this tree allows selecting categories as well as leaf nodes, or leaf nodes only. +Default is true (leaf nodes only). + + + + + + + + + + Represents the utility that drives the build process (typically, but not necessarily, a variant of "make"). + + + + + + + + + + A unique identifier for the builder that will be used by the build model. + + + + + + + Human-readable name for the builder to be used in the UI. + + + + + + + + + + The id of a builder that this builder is derived from. + + + + + + + An optional field that flags a builder as abstract. An abstract builder must be defined as a top level object in the model definition and cannot be selected by the user in the UI, but builders derived from this builder will inherit its attributes and children. The default is false. + + + + + + + A semi-colon separated list of child IDs of the superclass' children that should not be automatically inherited by this element. Note: This attribute is not yet implemented. + + + + + + + Specifies the default command to start the build utility for your toolchain. If the user changes this through the UI, the overriden value will be stored in the project build file. The build model will default to this value if the user ever resets a change. The default is 'make'. + + + + + + + Specifies the additional, default arguments that will be passed to the build utility when it is called by the builder. If the user changes the flags through the UI, the overriden value will be stored in the project build settings file. The build model will default to this value if the user ever resets a change. The default is '-k'. + + + + + + + Allows you to supply a custom build file generator that conforms to the <code>IManagedBuilderMakefileGenerator</code> interface. + + + + + + + + + + Specifies the default list of error parsers used by the builder. These error parsers are added to this list specified by the parent tool-chain. It is an ordered, semi-colon separated list of parser IDs. The order specifies the order in which the error parsers are invoked during a build. + + + + + + + The value of this attribute should be set to the expression representing the builder variable format. For example, to generate macros with the ${macro} format, the attribute would contain ${=}. To generate macros with the @macro format, the attribute would contain @=. +This information would be used wile buildfile generation to keep the environment build macros unresolved in the makefile. +If the attribute is not specified or contains the empty string, this would mean that the builder can not treat environment variables as its own variables. In this case, the build macros that contain environment variables are resolved by MBS to their actual value. + + + + + + + Specifies whether the builder variables are case sensitive or not. Can be set to either "true" or "false". The default is "true". If the builder does not support case-sensitive variables and there are some build environment variables that differ only in case (Environment variables on Unix-like operating systems are case sensitive), then those macros will always get resolved in the buildfile. + + + + + + + Comma-separated list of reserved macro names. The macro name could contain either the exact name or the java regular expression. The latter could be used to supply the pattern of variable names that are generated by MBS in case the "buildVariable" attribute of the "InputType" element is not specified, etc. +If this attribute is specified and the reservedMacroNameSupplier is not specified, the following macro names will be treated as reserved: +1. a macro name that is equal to one of the names specified in the reservedMacroNames value +2. a macro name that matches one of the regexp patterns specified in the reservedMacroNames value +3. a macro name that is equal to one of the build variable names specified InputType elements of the tools used in the tool-chain +If this attribute is not specified, MBS will assume that there are no reserved macro names that could conflict with the build environment variable macros, except names specified in the "buildVariable" attribute of the "InputType" elements: these names will always be treated as reserved + + + + + + + Should be set to the name of the class that implements the IReservedMacroNameSupplier interface. If this attribute is specified the reservedMacroNames attribute is ignored, and the following macro names will be treated as reserved: +1. macro names that the IReservedMacroNamesSupplier specifies as reserved +2. a macro name that is equal to one of the build variable names specified int the InputType elements of the tools used in the tool-chain + + + + + + + + + + Represents the InputFileName macro value. The macro specifies the input file name. The input file has the following meaning: +1. If a tool does not accept building multiple files of the primary input type with one tool invocation, the input file is the file of the primary input type being built. +2. If a tool accepts building multiple files of the primary input type with one tool invocation the input file is undefined and the macros representing the input file contain information about one of the inputs of the primary input type being built. + + + + + + + Represents the InputFileExt macro value. The macro specifies the extension of the input file. + + + + + + + Represents the InputFileBaseName macro value. The macro specifies the base name of the input file. That is the file name with an extension stripped. + + + + + + + Represents the InputFileRelPath macro value. The macro specifies the input file path relative to the builder current directory. + + + + + + + Represents the InputDirRelPath macro value. The macro specifies the input file directory path relative to the builder current directory. + + + + + + + Represents the OutputFileName macro value. The macro specifies the output file name. The output file has the following meaning: +1. If a tool is not capable of producing multiple files of the primary output type with one tool invocation the output file is the file of the primary output type that is built with a given tool invocation. +2. If a tool is capable of producing multiple files of the primary output type with one tool invocation the output file is undefined and the macros representing the output file contain information about one of the files of the primary output type that are built with a given tool invocation. + + + + + + + Represents the OutputFileExt macro value. The macro specifies the output file extension. + + + + + + + Represents the OutputFileBaseName macro value. The macro specifies the output file base name. That is the output file name with an extension stripped. + + + + + + + Represents the OutputFileRelPath macro value. The macro specifies the output file path relative to the current builder directory. + + + + + + + Represents the OutputDirRelPath macro value. The macro specifies the output file directory path relative to the current builder directory. + + + + + + + Specifies a comma delimited list of versions of this builder that can be loaded without invoking a converter. + + + + + + + The identifier of a builder, that builders loaded using this definition should be converted to. MBS will invoke a proper converter. + + + + + + + Specifies whether the duilder supports managed build. Default value is true. + + + + + + + represents the build target to be used for auto build + + + + + + + represents the build target to be used for incremental build + + + + + + + represents the build target to be used for clean build + + + + + + + specifies the "ignore error" builder option. + + + + + + + Specifies the command for "parallel build". +If the builder supports specifying custom number of parallel jobs the option definition may contain "*". The Build System will substitute the "*" with the number of parallel threads to be used. In case of "unlimited" jobs jobs number will be omitted. +For example, builder representing GNU make would define parallelBuildCmd as "-j*". + + + + + + + Defines if the parallel build is enabled in newly created project by default (when parallel build is supported). The number of jobs is defined by "parallelizationNumber" attribute. If "parallelizationNumber" is not defined "optimal" value will be used. + + + + + + + Sets maximum number of parallel threads/jobs to be used by builder (that value can be changed after creation of project by user). +A positive number or value "optimal" or "unlimited" are recognized: +- number 1 will cause parallel build to be turned off, +- "optimal" will set maximum number of jobs to number of processors on the system, +- "unlimited" will make builder to run as many threads/jobs as possible. + + + + + + + the system elements are used by the system for specific needs and are not displayed in UI + + + + + + + A concrete Java class that implements org.eclipse.cdt.core.ICommandLauncher to launch the builder command. + + + + + + + + + + A runner for the build. Overrides or extends the built-in external and internal build runners. + + + + + + + + + + + + + Represents the os/architecture combination(s) upon which the outputs of a tool-chain can be deployed. + + + + + + + A unique identifier for the target platform that will be used by the build model. + + + + + + + Human-readable name for the target platform to be used in the UI. + + + + + + + + + + The id of a target platform that this target platform is derived from. + + + + + + + An optional field that flags a target platform as abstract. An abstract target platform must be defined as a top level object in the model definition and cannot be selected by the user in the UI, but target platforms derived from this targetPlatform will inherit its attributes and children. The default is false. + + + + + + + A semi-colon separated list of child IDs of the superclass' children that should not be automatically inherited by this element. Note: This attribute is not yet implemented. + + + + + + + This field lists the target operating systems on which the outputs of a tool-chain runs. The value should be a comma-separated list. Valid values are the strings returned by the Eclipse API Platform.getOS() and include strings like "win32", "linux", "solaris", "hpux", "aix". Do not specify this attribute or specify "all" to allow all target operating systems. + + + + + + + This field lists the target architectures on which the outputs of a tool-chain runs. The value should be a comma-separated list. Valid values are the strings returned by the Eclipse API Platform.getOSArch() and include strings like "ia32". Do not specify this attribute or specify "all" to allow all target architectures. + + + + + + + Set this to the ID of the binary parser for the output format of your configuration. + + + + + + + + + + An optional element that allows a tool implementor to supply a class that creates one or more dynamic toolchain elements. For example, the class might create a new tool reference based on the contents of a special file, and a new target that uses that reference. + + + + + + + The class that implements the <code>IManagedConfigElementProvider</code> interface. The logic of determining the elements is left to the implementer, but they must be correctly formed or the build model will have trouble loading. + + + + + + + + + + A meaningful name for the type of element being provided. + + + + + + + + + + + + + An optional element that allows a tool implementor to supply a class that insures a plugin that modifies any build configruation attributes (e.g. the build config id) will get loaded before initial project information is created. + + + + + + + The class that implements the <code>IManagedBuildDefinitionsStartup</code> interface. This class may not actually do anything, but additional initialization can be done here is desired. + + + + + + + + + + A meaningful name for the type of element being provided. + + + + + + + + + + <p> +Version identifier for the managed build extension point. It is a string representation, consisting of three (3) tokens separated by a decimal point. The 3 tokens are positive integer numbers. For example, the following are valid version identifiers: + <ul> + <li><code>0.0.0</code></li> + <li><code>1.0.1234</code></li> + <li><code>1.9</code> (interpreted as <code>1.9.0</code>)</li> + <li><code>3</code> (interpreted as <code>3.0.0</code>)</li> + </ul> +</p> + + + + + + + The actual string containing the three version tokens. + + + + + + + + + + Defines a set of environment variables used by a tool to represent the build paths (include paths or library paths). + + + + + + + The build path type. Can be one of the following: "buildpathInclude", "buildpathLibrary" + + + + + + + + + + + + + + + comma-separated list of the environment variable names used to store the include paths + + + + + + + Represent the delimiter used to separate the paths. If omitted the default system delimiter will be used. That is the ":" for Unix-like systems and the ";" for Win32 systems. +If the "buildPathResolver" attribute is specified, the "pathDelimiter" is ignored + + + + + + + Should be set to the IBuildPathResolver interface that the tool-integrator can supply in order to provide his/her own logic of resolving the variable values to the build paths + + + + + + + + + + + + + Contains boolean expression that specifies option applicability + + + + + + + + + + + + + + + + + + Represents the applicability type for this enablement. +Can contain the following values: +UI_VISIBILITY - the given enablement expression specifies whether the option is to be visible in UI, +UI_ENABLEMENT - the given enablement expression specifies the enable state of the controls that represent the option in UI, +CMD_USAGE - the given enablement expression specifies whether the option is to be used in command line +CONTAINER_ATTRIBUTE - the given enablement expressions specifies thecontainer attribute value +ALL - this value means the combination of all the above values. + +Several types could be specified simultaneously using the "|" as a delimiter, e.g.: +type="UI_VISIBILITY|CMD_USAGE" + + + + + + + This attribute should be used only for the CONTAINER_ATTRIBUTE enablement to specify the name of the attribute for which this enablement applies. Currently the following option attributes are supported: +"command" +"commandFalse" +"defaultValue" +"value" +"artifactExtension" + + + + + + + + + + + + + + + + + + + + + This attribute should be used only for the CONTAINER_ATTRIBUTE enablement to specify the value of the attribute specified in the "attribute" for which this enablement applies + + + + + + + The attribute is valid for the CONTAINER_ATTRIBUTE enablement type. +true specifies that the enablement is defined for adjusting extension elements (extension elements are adjusted on tool-chain definition load) +false specifies that the enablement is defined for non-extension elements adjustment. This adjustment is performed, e.g. when the Build properties set is chenged for configuration +Default value is true. + + + + + + + + + + Represents boolean "and" operation + + + + + + + + + + + + + + + + + + + Represents boolean "or" operation + + + + + + + + + + + + + + + + + + + Represents boolean "not" operation + + + + + + + + + + + + + + + + + + + Performs an option value check. The option value can be checked either agains some pre-defined value or against the value of another option + + + + + + + The option id. The default is the id of the option that holds this expression. When searching for the option to be checked, MBS will examine all the options the holder contains along with all superclasses of each option to find the option with the specified id. + + + + + + + The option holder id that holds the option. The default is the id of the holder that holds the container of this expression. When searching for the needed holder, MBS will examine all the holders the current configuration contains along with all superclasses of each holder in order to find the holder with the specified id. + + + + + + + Specifies the expected value. If the current option value matches the value specified in this attribute, the checkOption element is treated as true, otherwise - as false. +The expected value could be specified either as a string that may contain build macros or as a regular expression. During the comparison, the build macros are resolved and the option value is checked to match the resulting string or regular expression. The way the expected value is specified and treated depends on the value of the isRegex attribute + + + + + + + Specifies whether the string specified in the "value" attribute should be treated as a regular eexpression. The default is false + + + + + + + The id of the option which is to be compared with the option specified with the "optionId" attribute. The default is the id of the option that holds this expression. If the "value" attribute is specified, both the "otherOptionId" and the "otherHolderId" attributes are ignored. When searching for the option to be checked, MBS will examine all the options the holder contains along with all superclasses of each option to find the option with the specified id. + + + + + + + The option holder id that holds the option specified with the "otherOptionId" attribute. The default is the id of the holder that holds the container of this expression. If the "value" attribute is specified, both the "otherOptionId" and the "otherHolderId" attributes are ingnored. When searching for the needed holder, MBS will examine all the holders the current configuration contains along with all superclasses of each holder in order to find the holder with the specified id. + + + + + + + + + + Performs a string check. + + + + + + + Represents the string to be checked. The string will typically contain the build macros. + + + + + + + Specifies the expected value. If the current string specified in the "string" attribute matches the value specified in this attribute, the checkString element is treated as true, otherwise - as false. +The expected value could be specified either as a string that might contain the build macros or as a regular expression. +The way the value is specified and treated depends on the value of the isRegex attribute. + + + + + + + Specifies whether the string specified in the "value" attribute should be treated as a regular eexpression. The default is false + + + + + + + + + + Represents the "false" value. This element can be used as a direct child of the "enablement" element to represent that the given option applicability is disabled. E.g. to specify that the option is never displayed in UI or never used in the command line. + + + + + + + + Performs the holder check. + + + + + + + Specifies the holder id to be checked. The checkHolder is treated as true if the id specified in this attribute matches with the option's holder id or the id of some holder's super-class. Otherwise the checkHolder is treated as false. + + + + + + + + + + Performs the Build Property check + + + + + + + specifies the id of the Build Property to be checked + + + + + + + Specifies the Build Property Value id to be checked + + + + + + + + + + contains the list of supported properties + + + + + + + + + + + + + contains the supported values for the property + + + + + + + + + + the property type id + + + + + + + + + + Represents per-folder settings. + + + + + + + + + + Project-relative resource path + + + + + + + Specifies whether the resource is excluded from building in the parent configuration. The default is false. The resourceConfiguration element retains its tool children, if any exist, even when excluded from the build. + + + + + + + + + + Represents per-file settings. +This element has the same meaning as resourceConfiguration. +It is added for consistency with the folderInfo element. +The only difference between this element and the resourceConfiguration is that resourceConfiguration specifies the resource full path, while the fileInfo specifies project-relative resource path in the same way as the folderInfo does. + + + + + + + Project-relative resource path + + + + + + + Specifies whether the resource is excluded from building in the parent configuration. The default is false. The resourceConfiguration element retains its tool children, if any exist, even when excluded from the build. + + + + + + + Identifies how the user desires to apply a resource custom build step: + 1. Apply rcbs tool before any other tools defined for the resource. + 2. Apply rcbs tool after any other tools defined for the resource. + 3. Apply rcbs tool overriding any other tools defined for the resource. + 4. Disable (don't apply) the rcbs tool. + + + + + + + + + + + + + + + + + + + Identifies which tools to invoke by a semicolon separated list of child tool ids. Applies as follows: + 1. Defaults to all tools in the order found + 2. Use specified ordered list of children to invoke + 3. If empty string, treat as if no resource configuration existed, i.e., use project level tool. + + + + + + + + + + Checks whether the project containing the resource has a given nature + + + + + + + The id of the nature + + + + + + + + + + + + This extension point was added in CDT 2.1 + + + + + + + + + [Enter examples here.] + + + + + + + + + [Enter API information here.] + + + + + + + + + An implementation of this extension point is supplied in <samp>org.eclipse.cdt.ui</samp> + + + + + + + + + Copyright (c) 2003, 2006 IBM Corporation and others. +This program and the accompanying materials are made available under the terms of the Eclipse Public License 2.0 which accompanies this distribution, and is available on the <a href="http://www.eclipse.org/legal/epl-2.0/"> Eclipse</a> website. + + + + diff --git a/io.sloeber.ManagedBuild/src/io/sloeber/managedBuild/Internal/ArchiveNameProvider.java b/io.sloeber.ManagedBuild/src/io/sloeber/managedBuild/Internal/ArchiveNameProvider.java new file mode 100644 index 000000000..43ef86254 --- /dev/null +++ b/io.sloeber.ManagedBuild/src/io/sloeber/managedBuild/Internal/ArchiveNameProvider.java @@ -0,0 +1,33 @@ +package io.sloeber.managedBuild.Internal; + +import org.eclipse.cdt.managedbuilder.core.IConfiguration; +import org.eclipse.cdt.managedbuilder.core.ITool; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.runtime.IPath; + +import io.sloeber.core.common.Common; +import io.sloeber.core.common.Const; +import io.sloeber.core.tools.Helpers; +import io.sloeber.managedBuild.api.INewManagedOutputNameProvider; + +public class ArchiveNameProvider implements INewManagedOutputNameProvider { + + @Override + public IPath getOutputName(IProject project, IConfiguration cConf, ITool tool, IPath primaryInput) { + + boolean bUseArchiver = Common + .getBuildEnvironmentVariable(project, cConf.getName(), Const.ENV_KEY_USE_ARCHIVER, Const.TRUE) + .equalsIgnoreCase(Const.TRUE); + if (!bUseArchiver) { + // we don't use archiving so we ignore all files + return null; + } + + if (primaryInput.toString().startsWith(Const.ARDUINO_CODE_FOLDER_PATH) + && (!"cxx".equals(primaryInput.getFileExtension()))) { //$NON-NLS-1$ + return Helpers.GetOutputName(primaryInput).addFileExtension("o"); //$NON-NLS-1$ + } + return null; + } + +} diff --git a/io.sloeber.ManagedBuild/src/io/sloeber/managedBuild/Internal/ArduinoGnuMakefileGenerator.java b/io.sloeber.ManagedBuild/src/io/sloeber/managedBuild/Internal/ArduinoGnuMakefileGenerator.java new file mode 100644 index 000000000..d032f8234 --- /dev/null +++ b/io.sloeber.ManagedBuild/src/io/sloeber/managedBuild/Internal/ArduinoGnuMakefileGenerator.java @@ -0,0 +1,437 @@ +package io.sloeber.managedBuild.Internal; + +import static io.sloeber.core.common.Const.*; +import java.io.File; +import java.io.IOException; +import java.nio.charset.Charset; +import java.util.Collection; +import java.util.HashSet; +import java.util.LinkedHashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Set; +import org.apache.commons.io.FileUtils; +import org.eclipse.cdt.core.CCorePlugin; +import org.eclipse.cdt.core.settings.model.CSourceEntry; +import org.eclipse.cdt.core.settings.model.ICConfigurationDescription; +import org.eclipse.cdt.core.settings.model.ICSettingEntry; +import org.eclipse.cdt.core.settings.model.ICSourceEntry; +import org.eclipse.cdt.core.settings.model.util.CDataUtil; +import org.eclipse.cdt.managedbuilder.core.IBuilder; +import org.eclipse.cdt.managedbuilder.core.IConfiguration; +import org.eclipse.cdt.managedbuilder.core.IManagedBuildInfo; +import org.eclipse.cdt.managedbuilder.core.ManagedBuildManager; +import org.eclipse.cdt.managedbuilder.core.ManagedBuilderCorePlugin; +import org.eclipse.cdt.managedbuilder.internal.core.ManagedMakeMessages; +import org.eclipse.cdt.managedbuilder.macros.BuildMacroException; +import org.eclipse.cdt.managedbuilder.macros.IBuildMacroProvider; +import org.eclipse.cdt.managedbuilder.makegen.IManagedBuilderMakefileGenerator2; +import org.eclipse.core.resources.IContainer; +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.resources.IResourceDelta; +import org.eclipse.core.resources.IResourceProxy; +import org.eclipse.core.resources.IResourceProxyVisitor; +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.MultiStatus; +import org.eclipse.core.runtime.OperationCanceledException; +import org.eclipse.core.runtime.Path; +import org.eclipse.core.runtime.Status; +import io.sloeber.core.Messages; +import io.sloeber.core.common.Common; + +/** + * This is a specialized makefile generator that takes advantage of the + * extensions present in Gnu Make. + * + * @since 1.2 + * @noextend This class is not intended to be subclassed by clients. + * @noinstantiate This class is not intended to be instantiated by clients. + */ +public class ArduinoGnuMakefileGenerator implements IManagedBuilderMakefileGenerator2 { + + /** + * This class is used to recursively walk the project and determine which + * modules contribute buildable source files. + */ + protected class ResourceProxyVisitor implements IResourceProxyVisitor { + private final ArduinoGnuMakefileGenerator generator; + private Collection subdirList = new LinkedHashSet(); + + Collection getSubdirList() { + return subdirList; + } + + public ResourceProxyVisitor(ArduinoGnuMakefileGenerator generator) { + this.generator = generator; + + } + + @Override + public boolean visit(IResourceProxy proxy) throws CoreException { + if (generator == null) { + return false; + } + IResource resource = proxy.requestResource(); + boolean isSource = isSource(resource.getProjectRelativePath()); + // Is this a resource we should even consider + switch (proxy.getType()) { + case IResource.FILE: + // If this resource has a Resource Configuration and is not + // excluded or + // if it has a file extension that one of the tools builds, add + // the sudirectory to the list + if (isSource) { + subdirList.add(resource.getParent()); + return false; + } + return true; + case IResource.FOLDER: + if (!isSource || generator.isGeneratedResource(resource)) + return false; + return true; + } + // Recurse into subdirectories + return true; + } + } + + // Local variables needed by generator + String buildTargetName; + String buildTargetExt; + IConfiguration config; + /** Collection of Folders in which sources files have been modified */ + private IProgressMonitor monitor; + private IProject project; + // dependency files + /** Collection of Containers which contribute source files to the build */ + + private IFile topBuildDir; + // Dependency file variables + // private Vector dependencyMakefiles; // IPath's - relative to the top + // build directory or absolute + private ICSourceEntry srcEntries[]; + public ArduinoGnuMakefileGenerator() { + super(); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.cdt.managedbuilder.makegen.IManagedBuilderMakefileGenerator + * #initialize(IProject, IManagedBuildInfo, IProgressMonitor) + */ + @Override + public void initialize(IProject project, IManagedBuildInfo info, IProgressMonitor monitor) { + + this.project = project; + + // Save the monitor reference for reporting back to the user + this.monitor = monitor; + // Get the name of the build target + buildTargetName = info.getBuildArtifactName(); + // Get its extension + buildTargetExt = info.getBuildArtifactExtension(); + try { + // try to resolve the build macros in the target extension + buildTargetExt = ManagedBuildManager.getBuildMacroProvider().resolveValueToMakefileFormat(buildTargetExt, + "", " ", IBuildMacroProvider.CONTEXT_CONFIGURATION, info.getDefaultConfiguration()); + } catch (BuildMacroException e) { + /* JABA is not going to write this code */ + } + try { + // try to resolve the build macros in the target name + String resolved = ManagedBuildManager.getBuildMacroProvider().resolveValueToMakefileFormat(buildTargetName, + "", " ", IBuildMacroProvider.CONTEXT_CONFIGURATION, info.getDefaultConfiguration()); + if (resolved != null && (resolved = resolved.trim()).length() > 0) + buildTargetName = resolved; + } catch (BuildMacroException e) { + /* JABA is not going to write this code */ + } + if (buildTargetExt == null) { + buildTargetExt = ""; + } + // Cache the build tools + config = info.getDefaultConfiguration(); + // initToolInfos(); + // set the top build dir path + topBuildDir = project.getFile(info.getConfigurationName()); + } + + + public boolean isSource(IPath path) { + return !CDataUtil.isExcluded(path, srcEntries); + } + + + + @Override + public void generateDependencies() throws CoreException { + } + + @Override + public MultiStatus generateMakefiles(IResourceDelta delta) throws CoreException { + return regenerateMakefiles(); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.cdt.managedbuilder.makegen.IManagedBuilderMakefileGenerator# + * getBuildWorkingDir() + */ + @Override + public IPath getBuildWorkingDir() { + if (topBuildDir != null) { + return topBuildDir.getFullPath().removeFirstSegments(1); + } + return null; + } + + public IPath getBuildFolder() { + return topBuildDir.getLocation(); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.cdt.managedbuilder.makegen.IManagedBuilderMakefileGenerator# + * getMakefileName() + */ + @Override + public String getMakefileName() { + return MAKEFILE_NAME; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.cdt.managedbuilder.makegen.IManagedBuilderMakefileGenerator# + * isGeneratedResource(org.eclipse.core.resources.IResource) + */ + @Override + public boolean isGeneratedResource(IResource resource) { + // Is this a generated directory ... + IPath path = resource.getProjectRelativePath(); + // TODO: fix to use builder output dir instead + String[] configNames = ManagedBuildManager.getBuildInfo(project).getConfigurationNames(); + for (String name : configNames) { + IPath root = new Path(name); + // It is if it is a root of the resource pathname + if (root.isPrefixOf(path)) + return true; + } + return false; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.cdt.managedbuilder.makegen.IManagedBuilderMakefileGenerator# + * regenerateDependencies() + */ + @Override + public void regenerateDependencies(boolean force) throws CoreException { + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.cdt.managedbuilder.makegen.IManagedBuilderMakefileGenerator# + * regenerateMakefiles() + */ + @Override + public MultiStatus regenerateMakefiles() throws CoreException { + MultiStatus status; + // Visit the resources in the project + ResourceProxyVisitor subDirVisitor = new ResourceProxyVisitor(this); + project.accept(subDirVisitor, IResource.NONE); + // See if the user has cancelled the build + checkCancel(); + Collection foldersToInvestigate = subDirVisitor.getSubdirList(); + if (foldersToInvestigate.isEmpty()) { + String info = ManagedMakeMessages.getFormattedString("MakefileGenerator.warning.no.source", + project.getName()); + updateMonitor(info); + status = new MultiStatus(ManagedBuilderCorePlugin.getUniqueIdentifier(), IStatus.INFO, "", null); + status.add(new Status(IStatus.INFO, ManagedBuilderCorePlugin.getUniqueIdentifier(), NO_SOURCE_FOLDERS, info, + null)); + return status; + } + // Create the top-level directory for the build output + topBuildDir = project.getFile(config.getName()); + checkCancel(); + // Get the data for the makefile generation + List subDirMakeGenerators = new LinkedList<>(); + Set subDirMakeRules = new HashSet<>(); + Collection foldersToBuild = new LinkedHashSet<>(); + + for (IContainer res : foldersToInvestigate) { + //For all the folders get the make rules for this folder + SubDirMakeGenerator subDirMakeGenerator = new SubDirMakeGenerator(this, res); + if (!subDirMakeGenerator.isEmpty()) { + foldersToBuild.add(res); + subDirMakeGenerators.add(subDirMakeGenerator); + //also store all these rules in one set to provide them to the top make file + subDirMakeRules.addAll(subDirMakeGenerator.getMakeRules()); + } + checkCancel(); + } + TopMakeFileGenerator topMakeFileGenerator = new TopMakeFileGenerator(this, subDirMakeRules, foldersToBuild); + + checkCancel(); + + Set srcMacroNames = new LinkedHashSet<>(); + Set objMacroNames = new LinkedHashSet<>(); + for (SubDirMakeGenerator curSubDirMake : subDirMakeGenerators) { + curSubDirMake.generateMakefile(); + srcMacroNames.addAll(curSubDirMake.getPrerequisiteMacros()); + srcMacroNames.addAll(curSubDirMake.getDependecyMacros()); + objMacroNames.addAll(curSubDirMake.getTargetMacros()); + } + //TOFIX also need to add macro's from main makefile + + SrcMakeGenerator.generateSourceMakefile(project, config, srcMacroNames, foldersToBuild); + SrcMakeGenerator.generateObjectsMakefile(project, config, objMacroNames); + topMakeFileGenerator.generateMakefile(); + + checkCancel(); + // How did we do + status = new MultiStatus(ManagedBuilderCorePlugin.getUniqueIdentifier(), IStatus.OK, "", null); + + //TOFIX this should be done differently + // JABA SLOEBER create the size.awk file + ICConfigurationDescription confDesc = ManagedBuildManager.getDescriptionForConfiguration(config); + IWorkspaceRoot root = CCorePlugin.getWorkspace().getRoot(); + IFile sizeAwkFile1 = root.getFile(topBuildDir.getFullPath().append("size.awk")); + File sizeAwkFile = sizeAwkFile1.getLocation().toFile(); + String regex = Common.getBuildEnvironmentVariable(confDesc, "recipe.size.regex", EMPTY); + String awkContent = "/" + regex + "/ {arduino_size += $2 }\n"; + regex = Common.getBuildEnvironmentVariable(confDesc, "recipe.size.regex.data", EMPTY); + awkContent += "/" + regex + "/ {arduino_data += $2 }\n"; + regex = Common.getBuildEnvironmentVariable(confDesc, "recipe.size.regex.eeprom", EMPTY); + awkContent += "/" + regex + "/ {arduino_eeprom += $2 }\n"; + awkContent += "END { print \"\\n"; + String max = Common.getBuildEnvironmentVariable(confDesc, "upload.maximum_size", "10000"); + awkContent += Messages.sizeReportSketch.replace("maximum_size", max); + awkContent += "\\n"; + max = Common.getBuildEnvironmentVariable(confDesc, "upload.maximum_data_size", "10000"); + awkContent += Messages.sizeReportData.replace("maximum_data_size", max); + awkContent += "\\n"; + awkContent += "\"}"; + + try { + FileUtils.write(sizeAwkFile, awkContent, Charset.defaultCharset()); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + // END JABA SLOEBER create the size.awk file + + return status; + } + + /************************************************************************* + * M A K E F I L E G E N E R A T I O N C O M M O N M E T H O D S + ************************************************************************/ + + + + + /** + * Check whether the build has been cancelled. Cancellation requests propagated + * to the caller by throwing OperationCanceledException. + * + * @see org.eclipse.core.runtime.OperationCanceledException#OperationCanceledException() + */ + private void checkCancel() { + if (monitor != null && monitor.isCanceled()) { + throw new OperationCanceledException(); + } + } + + public IConfiguration getConfig() { + return config; + } + + + + + private void updateMonitor(String msg) { + if (monitor != null && !monitor.isCanceled()) { + monitor.subTask(msg); + monitor.worked(1); + } + } + + /** + * Return the configuration's top build directory as an absolute path + */ + public IFile getTopBuildDir() { + return topBuildDir; + } + + @Override + public void initialize(int buildKind, IConfiguration cfg, IBuilder builder, IProgressMonitor monitor) { + // Save the project so we can get path and member information + this.project = cfg.getOwner().getProject(); + if (builder == null) { + builder = cfg.getEditableBuilder(); + } + + + // Save the monitor reference for reporting back to the user + this.monitor = monitor; + // Get the build info for the project + // info = info; + // Get the name of the build target + buildTargetName = cfg.getArtifactName(); + // Get its extension + buildTargetExt = cfg.getArtifactExtension(); + try { + // try to resolve the build macros in the target extension + buildTargetExt = ManagedBuildManager.getBuildMacroProvider().resolveValueToMakefileFormat(buildTargetExt, + "", " ", IBuildMacroProvider.CONTEXT_CONFIGURATION, builder); + } catch (BuildMacroException e) { + /* JABA is not going to write this code */ + } + try { + // try to resolve the build macros in the target name + String resolved = ManagedBuildManager.getBuildMacroProvider().resolveValueToMakefileFormat(buildTargetName, + "", " ", IBuildMacroProvider.CONTEXT_CONFIGURATION, builder); + if (resolved != null) { + resolved = resolved.trim(); + if (resolved.length() > 0) + buildTargetName = resolved; + } + } catch (BuildMacroException e) { + /* JABA is not going to write this code */ + } + if (buildTargetExt == null) { + buildTargetExt = ""; + } + // Cache the build tools + config = cfg; + // initToolInfos(); + // set the top build dir path + topBuildDir = project.getFile(cfg.getName()); + srcEntries = config.getSourceEntries(); + if (srcEntries.length == 0) { + srcEntries = new ICSourceEntry[] { + new CSourceEntry(Path.EMPTY, null, ICSettingEntry.RESOLVED | ICSettingEntry.VALUE_WORKSPACE_PATH) }; + } else { + ICConfigurationDescription cfgDes = ManagedBuildManager.getDescriptionForConfiguration(config); + srcEntries = CDataUtil.resolveEntries(srcEntries, cfgDes); + } + } + + + public IProject getProject() { + return project; + } +} diff --git a/io.sloeber.ManagedBuild/src/io/sloeber/managedBuild/Internal/LinkNameProvider.java b/io.sloeber.ManagedBuild/src/io/sloeber/managedBuild/Internal/LinkNameProvider.java new file mode 100644 index 000000000..dcf033700 --- /dev/null +++ b/io.sloeber.ManagedBuild/src/io/sloeber/managedBuild/Internal/LinkNameProvider.java @@ -0,0 +1,35 @@ +package io.sloeber.managedBuild.Internal; + +import org.eclipse.cdt.managedbuilder.core.IConfiguration; +import org.eclipse.cdt.managedbuilder.core.ITool; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.runtime.IPath; + +import io.sloeber.core.common.Common; +import io.sloeber.core.common.Const; +import io.sloeber.core.tools.Helpers; +import io.sloeber.managedBuild.api.INewManagedOutputNameProvider; + +public class LinkNameProvider implements INewManagedOutputNameProvider { + + @Override + public IPath getOutputName(IProject project, IConfiguration cConf, ITool tool, IPath inputName) { + boolean bUseArchiver = Common + .getBuildEnvironmentVariable(project, cConf.getName(), Const.ENV_KEY_USE_ARCHIVER, Const.TRUE) + .equalsIgnoreCase(Const.TRUE); + if (inputName.toString().startsWith(Const.ARDUINO_CODE_FOLDER_PATH) && (bUseArchiver)) { + return null; + } + if (inputName.toString().endsWith(".ino")) { //$NON-NLS-1$ + return null; + } + if (inputName.toString().endsWith(".pde")) { //$NON-NLS-1$ + return null; + } + if (inputName.toString().endsWith(".cxx")) { //$NON-NLS-1$ + return null; + } + return Helpers.GetOutputName(inputName).addFileExtension("o"); //$NON-NLS-1$ + } + +} diff --git a/io.sloeber.ManagedBuild/src/io/sloeber/managedBuild/Internal/MakeRule.java b/io.sloeber.ManagedBuild/src/io/sloeber/managedBuild/Internal/MakeRule.java new file mode 100644 index 000000000..d34a13f1f --- /dev/null +++ b/io.sloeber.ManagedBuild/src/io/sloeber/managedBuild/Internal/MakeRule.java @@ -0,0 +1,491 @@ +package io.sloeber.managedBuild.Internal; + +import static io.sloeber.managedBuild.Internal.ManagebBuildCommon.*; +import static io.sloeber.managedBuild.Internal.ManagedBuildConstants.*; + +import java.util.Arrays; +import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; + +import org.eclipse.cdt.core.settings.model.ICConfigurationDescription; +import org.eclipse.cdt.managedbuilder.core.BuildException; +import org.eclipse.cdt.managedbuilder.core.IBuildObject; +import org.eclipse.cdt.managedbuilder.core.IConfiguration; +import org.eclipse.cdt.managedbuilder.core.IInputType; +import org.eclipse.cdt.managedbuilder.core.IOutputType; +import org.eclipse.cdt.managedbuilder.core.IResourceInfo; +import org.eclipse.cdt.managedbuilder.core.ITool; +import org.eclipse.cdt.managedbuilder.core.ManagedBuildManager; +import org.eclipse.cdt.managedbuilder.internal.macros.BuildMacroProvider; +import org.eclipse.cdt.managedbuilder.macros.BuildMacroException; +import org.eclipse.cdt.managedbuilder.macros.IBuildMacroProvider; +import org.eclipse.cdt.managedbuilder.makegen.IManagedDependencyCalculator; +import org.eclipse.cdt.managedbuilder.makegen.IManagedDependencyCommands; +import org.eclipse.cdt.managedbuilder.makegen.IManagedDependencyGenerator2; +import org.eclipse.cdt.managedbuilder.makegen.IManagedDependencyGeneratorType; +import org.eclipse.cdt.managedbuilder.makegen.IManagedDependencyInfo; +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.runtime.IPath; + +public class MakeRule { + + private Map> myTargets = new LinkedHashMap<>(); //Macro file target map + private Map> myPrerequisites = new LinkedHashMap<>();//Macro file prerequisites map + private Map> myDependencies = new LinkedHashMap<>(); //Macro file target map + private ITool myTool = null; + + public MakeRule(ITool tool, IInputType inputType, IFile inputFile, IOutputType outputType, IFile outFile) { + addPrerequisite(inputType, inputFile); + addTarget(outputType, outFile); + myTool = tool; + } + + public MakeRule(ITool tool, IInputType inputType, Set inputFiles, IOutputType outputType, IFile outFile) { + for (IFile inputFile : inputFiles) { + addPrerequisite(inputType, inputFile); + } + addTarget(outputType, outFile); + myTool = tool; + } + + public MakeRule(ArduinoGnuMakefileGenerator caller, ITool tool, IInputType inputType, Set inputFiles, + IOutputType outputType, IFile outFile) { + for (IFile inputFile : inputFiles) { + addPrerequisite(inputType, inputFile); + } + addTarget(outputType, outFile); + myTool = tool; + } + + public void addDependencies(ArduinoGnuMakefileGenerator caller) { + myDependencies.clear(); + + for (Entry> curprerequisite : myPrerequisites.entrySet()) { + IInputType curInputType = curprerequisite.getKey(); + IManagedDependencyGeneratorType t = curInputType.getDependencyGenerator(); + if (t == null) { + continue; + } + Set files = curprerequisite.getValue(); + String depkey = curInputType.getBuildVariable() + DEPENDENCY_SUFFIX; + for (IFile file : files) { + IBuildObject buildContext = caller.getConfig().getResourceInfo(file.getFullPath(), false); + + IManagedDependencyGenerator2 depGen = (IManagedDependencyGenerator2) t; + IManagedDependencyInfo depInfo = depGen.getDependencySourceInfo(file.getProjectRelativePath(), file, + buildContext, myTool, caller.getBuildWorkingDir()); + + if (depInfo instanceof IManagedDependencyCalculator) { + IManagedDependencyCalculator depCalculator = (IManagedDependencyCalculator) depInfo; + IPath[] addlDeps = calculateDependenciesForSource(caller, depCalculator); + IPath[] addlTargets = depCalculator.getAdditionalTargets(); + //TOFIX when is this call path used? + } + if (depInfo instanceof IManagedDependencyCommands) { + IManagedDependencyCommands tmp = (IManagedDependencyCommands) depInfo; + IPath[] addlTargets = tmp.getDependencyFiles(); + Set depFiles = new HashSet<>(); + for (IPath curPath : addlTargets) { + depFiles.add(caller.getProject().getFile(caller.getBuildWorkingDir().append(curPath))); + } + myDependencies.put(depkey, depFiles); + } + } + } + } + + /** + * Returns the dependency IPaths relative to the build directory + * + * @param depCalculator + * the dependency calculator + * @return IPath[] that are relative to the build directory + */ + private IPath[] calculateDependenciesForSource(ArduinoGnuMakefileGenerator caller, + IManagedDependencyCalculator depCalculator) { + IPath[] addlDeps = depCalculator.getDependencies(); + if (addlDeps != null) { + for (int i = 0; i < addlDeps.length; i++) { + if (!addlDeps[i].isAbsolute()) { + // Convert from project relative to build directory relative + IPath absolutePath = caller.getProject().getLocation().append(addlDeps[i]); + addlDeps[i] = ManagedBuildManager.calculateRelativePath(caller.getTopBuildDir().getLocation(), + absolutePath); + } + } + } + return addlDeps; + } + + public Set getPrerequisiteFiles() { + HashSet ret = new HashSet<>(); + for (Set cur : myPrerequisites.values()) { + ret.addAll(cur); + } + return ret; + } + + public Map> getPrerequisites() { + return myPrerequisites; + } + + public Set getTargetFiles() { + Set ret = new HashSet<>(); + for (Set cur : myTargets.values()) { + ret.addAll(cur); + } + return ret; + } + + public Set getDependencyFiles() { + Set ret = new HashSet<>(); + for (Set cur : myDependencies.values()) { + ret.addAll(cur); + } + return ret; + } + + public Map> getTargets() { + return myTargets; + } + + public Set getAllMacros() { + Set ret = getTargetMacros(); + ret.addAll(getPrerequisiteMacros()); + ret.addAll(getDependecyMacros()); + return ret; + } + + public Set getTargetMacros() { + HashSet ret = new LinkedHashSet<>(); + for (IOutputType cur : myTargets.keySet()) { + ret.add(cur.getBuildVariable()); + } + return ret; + } + + public Set getPrerequisiteMacros() { + HashSet ret = new LinkedHashSet<>(); + for (IInputType cur : myPrerequisites.keySet()) { + ret.add(cur.getBuildVariable()); + } + return ret; + } + + public Set getDependecyMacros() { + HashSet ret = new LinkedHashSet<>(); + for (String cur : myDependencies.keySet()) { + ret.add(cur); + } + return ret; + } + + public HashSet getMacroElements(String macroName) { + HashSet ret = new HashSet<>(); + + for (Entry> cur : myTargets.entrySet()) { + if (macroName.equals(cur.getKey().getBuildVariable())) { + ret.addAll(cur.getValue()); + } + } + for (Entry> cur : myPrerequisites.entrySet()) { + if (macroName.equals(cur.getKey().getBuildVariable())) { + ret.addAll(cur.getValue()); + } + } + Set tmp = myDependencies.get(macroName); + if (tmp != null) { + ret.addAll(tmp); + } + return ret; + } + + private void addTarget(IOutputType outputType, IFile file) { + Set files = myTargets.get(outputType); + if (files == null) { + files = new HashSet<>(); + files.add(file); + myTargets.put(outputType, files); + } else { + files.add(file); + } + } + + private void addPrerequisite(IInputType inputType, IFile file) { + Set files = myPrerequisites.get(inputType); + if (files == null) { + files = new HashSet<>(); + files.add(file); + myPrerequisites.put(inputType, files); + } else { + files.add(file); + } + } + + private String enumTargets(IFile buildFolder) { + String ret = new String(); + for (Set curFiles : myTargets.values()) { + for (IFile curFile : curFiles) { + ret = ret + GetNiceFileName(buildFolder, curFile) + WHITESPACE; + } + } + return ret; + } + + private String enumPrerequisites(IFile buildFolder) { + String ret = new String(); + for (Set curFiles : myPrerequisites.values()) { + for (IFile curFile : curFiles) { + ret = ret + GetNiceFileName(buildFolder, curFile) + WHITESPACE; + } + } + return ret; + } + + //FIXME JABA says: this code is weirdly crazy and way longer then I would expect. Should see why + public StringBuffer getRule(IProject project, IFile niceBuildFolder, IConfiguration config) { + ICConfigurationDescription confDesc = ManagedBuildManager.getDescriptionForConfiguration(config); + String cmd = myTool.getToolCommand(); + //For now assume 1 target with 1 or more prerequisites + // if there is more than 1 prerequisite we take the flags of the first prerequisite only + Set local_targets = getTargetFiles(); + Set local_prerequisites = getPrerequisiteFiles(); + if (local_targets.size() != 1) { + System.err.println("Only 1 target per build rule is supported in this managed build"); //$NON-NLS-1$ + return new StringBuffer(); + } + if (local_prerequisites.size() == 0) { + System.err.println("0 prerequisites is not supported in this managed build"); //$NON-NLS-1$ + return new StringBuffer(); + } + IFile outputLocation = local_targets.toArray(new IFile[0])[0]; + + //Primary outputs is not supported + String otherPrimaryOutputs = EMPTY_STRING; + Set niceNameList = new HashSet<>(); + IFile sourceLocation = null; + for (IFile curPrerequisite : local_prerequisites) { + niceNameList.add(GetNiceFileName(niceBuildFolder, curPrerequisite)); + sourceLocation = curPrerequisite; + } + final String fileName = sourceLocation.getFullPath().removeFileExtension().lastSegment(); + final String inputExtension = sourceLocation.getFileExtension(); + + Set flags = getBuildFlags(niceBuildFolder, config, sourceLocation, outputLocation); + + boolean needExplicitRuleForFile = false; + boolean needExplicitDependencyCommands = false; + boolean resourceNameRequiresExplicitRule = containsSpecialCharacters(sourceLocation.getLocation().toOSString()); + needExplicitRuleForFile = resourceNameRequiresExplicitRule + || BuildMacroProvider.getReferencedExplitFileMacros(myTool).length > 0 + || BuildMacroProvider.getReferencedExplitFileMacros(cmd, IBuildMacroProvider.CONTEXT_CONFIGURATION, + confDesc).length > 0; + + String outflag = myTool.getOutputFlag(); + String buildCmd = cmd + WHITESPACE + flags.toString().trim() + WHITESPACE + outflag + WHITESPACE + + myTool.getOutputPrefix() + OUT_MACRO + otherPrimaryOutputs + WHITESPACE + IN_MACRO; + if (needExplicitRuleForFile || needExplicitDependencyCommands) { + buildCmd = expandCommandLinePattern(cmd, flags, outflag, OUT_MACRO + otherPrimaryOutputs, niceNameList, + getToolCommandLinePattern(config, myTool)); + } else { + buildCmd = expandCommandLinePattern(config, inputExtension, flags, outflag, OUT_MACRO + otherPrimaryOutputs, + niceNameList, sourceLocation, outputLocation); + } + // resolve any remaining macros in the command after it has been + // generated + try { + String resolvedCommand; + IBuildMacroProvider provider = ManagedBuildManager.getBuildMacroProvider(); + if (!needExplicitRuleForFile) { + resolvedCommand = provider.resolveValueToMakefileFormat(buildCmd, EMPTY_STRING, WHITESPACE, + IBuildMacroProvider.CONTEXT_CONFIGURATION, confDesc); + } else { + // if we need an explicit rule then don't use any builder + // variables, resolve everything to explicit strings + resolvedCommand = provider.resolveValue(buildCmd, EMPTY_STRING, WHITESPACE, + IBuildMacroProvider.CONTEXT_CONFIGURATION, confDesc); + } + if (resolvedCommand != null && !resolvedCommand.isBlank()) + buildCmd = resolvedCommand.trim(); + } catch (BuildMacroException e) { + //Continue using the default buildCmd value + } + + StringBuffer buffer = new StringBuffer(); + buffer.append(enumTargets(niceBuildFolder)).append(COLON).append(WHITESPACE); + buffer.append(enumPrerequisites(niceBuildFolder)).append(NEWLINE); + buffer.append(TAB).append(AT).append(escapedEcho(MESSAGE_START_FILE + WHITESPACE + OUT_MACRO)); + buffer.append(TAB).append(AT).append(escapedEcho(myTool.getAnnouncement())); + + // JABA add sketch.prebuild and postbouild if needed + //TOFIX this should not be here + if ("sloeber.ino".equals(fileName)) { //$NON-NLS-1$ + + String sketchPrebuild = io.sloeber.core.common.Common.getBuildEnvironmentVariable(confDesc, + "sloeber.sketch.prebuild", new String(), true); //$NON-NLS-1$ + String sketchPostBuild = io.sloeber.core.common.Common.getBuildEnvironmentVariable(confDesc, + "sloeber.sketch.postbuild", new String(), true); //$NON-NLS-1$ + if (!sketchPrebuild.isEmpty()) { + buffer.append(TAB).append(sketchPrebuild); + } + buffer.append(TAB).append(buildCmd).append(NEWLINE); + if (!sketchPostBuild.isEmpty()) { + buffer.append(TAB).append(sketchPostBuild); + } + } else { + buffer.append(TAB).append(buildCmd); + } + // end JABA add sketch.prebuild and postbouild if needed + + buffer.append(NEWLINE); + buffer.append(TAB).append(AT).append(escapedEcho(MESSAGE_FINISH_FILE + WHITESPACE + OUT_MACRO)); + buffer.append(TAB).append(AT).append(ECHO_BLANK_LINE).append(NEWLINE); + return buffer; + } + + private Set getBuildFlags(IFile buildFolder, IConfiguration config, IFile sourceFile, IFile outputFile) { + Set flags = new LinkedHashSet<>(); + // Get the tool command line options + try { + + IResourceInfo buildContext = config.getResourceInfo(sourceFile.getFullPath().removeLastSegments(1), false); + flags.addAll(Arrays.asList(myTool.getToolCommandFlags(sourceFile.getLocation(), outputFile.getLocation()))); + + IInputType[] inputTypes = myTool.getInputTypes(); //.getDependencyGeneratorForExtension(inputExtension); + for (IInputType inputType : inputTypes) { + IManagedDependencyGeneratorType t = inputType.getDependencyGenerator(); + if (t != null) { + if (t.getCalculatorType() == IManagedDependencyGeneratorType.TYPE_BUILD_COMMANDS) { + IManagedDependencyGenerator2 depGen = (IManagedDependencyGenerator2) t; + IManagedDependencyInfo depInfo = depGen.getDependencySourceInfo( + sourceFile.getProjectRelativePath(), sourceFile, buildContext, myTool, + buildFolder.getFullPath()); + IManagedDependencyCommands depCommands = (IManagedDependencyCommands) depInfo; + if (depCommands != null) { + flags.addAll(Arrays.asList(depCommands.getDependencyCommandOptions())); + } + + } + } + } + } catch (BuildException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + return flags; + } + + private String expandCommandLinePattern(IConfiguration config, String sourceExtension, Set flags, + String outputFlag, String outputName, Set inputResources, IFile inputLocation, + IFile outputLocation) { + ICConfigurationDescription confDesc = ManagedBuildManager.getDescriptionForConfiguration(config); + String cmd = myTool.getToolCommand(); + // try to resolve the build macros in the tool command + try { + String resolvedCommand = null; + if ((inputLocation != null && inputLocation.toString().indexOf(WHITESPACE) != -1) + || (outputLocation != null && outputLocation.toString().indexOf(WHITESPACE) != -1)) { + resolvedCommand = ManagedBuildManager.getBuildMacroProvider().resolveValue(cmd, EMPTY_STRING, + WHITESPACE, IBuildMacroProvider.CONTEXT_CONFIGURATION, confDesc); + } else { + resolvedCommand = ManagedBuildManager.getBuildMacroProvider().resolveValueToMakefileFormat(cmd, + EMPTY_STRING, WHITESPACE, IBuildMacroProvider.CONTEXT_CONFIGURATION, confDesc); + } + if (resolvedCommand != null && (resolvedCommand = resolvedCommand.trim()).length() > 0) + cmd = resolvedCommand; + } catch (BuildMacroException e) { + /* JABA is not going to write this code */ + } + return expandCommandLinePattern(cmd, flags, outputFlag, outputName, inputResources, + getToolCommandLinePattern(config, myTool)); + } + + private String expandCommandLinePattern(String commandName, Set flags, String outputFlag, String outputName, + Set inputResources, String commandLinePattern) { + + String command = commandLinePattern; + if (commandLinePattern == null || commandLinePattern.length() <= 0) { + command = DEFAULT_PATTERN; + } + + String quotedOutputName = outputName; + // if the output name isn't a variable then quote it + if (quotedOutputName.length() > 0 && quotedOutputName.indexOf("$(") != 0) { //$NON-NLS-1$ + quotedOutputName = DOUBLE_QUOTE + quotedOutputName + DOUBLE_QUOTE; + } + + String inputsStr = ""; //$NON-NLS-1$ + if (inputResources != null) { + for (String inp : inputResources) { + if (inp != null && !inp.isEmpty()) { + // if the input resource isn't a variable then quote it + if (inp.indexOf("$(") != 0) { //$NON-NLS-1$ + inp = DOUBLE_QUOTE + inp + DOUBLE_QUOTE; + } + inputsStr = inputsStr + inp + WHITESPACE; + } + } + inputsStr = inputsStr.trim(); + } + + String flagsStr = String.join(WHITESPACE, flags); + + command = command.replace(makeVariable(CMD_LINE_PRM_NAME), commandName); + command = command.replace(makeVariable(FLAGS_PRM_NAME), flagsStr); + command = command.replace(makeVariable(OUTPUT_FLAG_PRM_NAME), outputFlag); + command = command.replace(makeVariable(OUTPUT_PREFIX_PRM_NAME), myTool.getOutputPrefix()); + command = command.replace(makeVariable(OUTPUT_PRM_NAME), quotedOutputName); + command = command.replace(makeVariable(INPUTS_PRM_NAME), inputsStr); + + return command; + } + + public void addPrerequisites(IInputType inputType, Set files) { + Set entrypoint = myPrerequisites.get(inputType); + if (entrypoint != null) { + entrypoint.addAll(files); + } else { + Set copyOfFiles = new HashSet<>(); + copyOfFiles.addAll(files); + myPrerequisites.put(inputType, copyOfFiles); + } + } + + /** + * A simple rule is a rule that takes exactly 1 input type + * and exactly 1 output type containing exactly 1 file + * + * @return true if this rule is a simple rule + * otherwise false + */ + + public boolean isSimpleRule() { + if ((myTargets.size() != 1) || (myTargets.size() != 1)) { + return false; + } + // int counter = 0; + // for (Set files : myTargets.values()) { + // if ((++counter > 1) || (files.size() != 1)) { + // return false; + // } + // } + // counter = 0; + // for (Set files : myPrerequisites.values()) { + // if ((++counter > 1)) { + // return false; + // } + // } + return true; + + } + + public boolean isTool(ITool targetTool) { + return myTool.getName().equals(targetTool.getName()); + } + +} diff --git a/io.sloeber.ManagedBuild/src/io/sloeber/managedBuild/Internal/MakeRules.java b/io.sloeber.ManagedBuild/src/io/sloeber/managedBuild/Internal/MakeRules.java new file mode 100644 index 000000000..5ddd65f23 --- /dev/null +++ b/io.sloeber.ManagedBuild/src/io/sloeber/managedBuild/Internal/MakeRules.java @@ -0,0 +1,117 @@ +package io.sloeber.managedBuild.Internal; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedHashSet; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; + +import org.eclipse.cdt.managedbuilder.core.IInputType; +import org.eclipse.cdt.managedbuilder.core.IOutputType; +import org.eclipse.cdt.managedbuilder.core.ITool; +import org.eclipse.core.resources.IFile; + +public class MakeRules { + private Set myMakeRules = new LinkedHashSet<>(); + + public void addRule(MakeRule newMakeRule) { + if (newMakeRule.isSimpleRule()) { + Map> targets = newMakeRule.getTargets(); + + IOutputType outputType = null; + IFile correctOutputPath = null; + for (Entry> curTarget : targets.entrySet()) { + outputType = curTarget.getKey(); + correctOutputPath = curTarget.getValue().toArray(new IFile[1])[0]; + } + MakeRule makerule = findTarget(outputType, correctOutputPath); + if (makerule != null) { + Map> prerequisites = newMakeRule.getPrerequisites(); + + IInputType inputType = null; + Set files = null; + + for (Entry> curTarget : prerequisites.entrySet()) { + inputType = curTarget.getKey(); + files = curTarget.getValue(); + } + makerule.addPrerequisites(inputType, files); + } else { + myMakeRules.add(newMakeRule); + } + } + + } + + public MakeRule findTarget(IOutputType outputType, IFile correctOutputPath) { + for (MakeRule makeRule : myMakeRules) { + for (Entry> target : makeRule.getTargets().entrySet()) { + if ((target.getKey() == outputType) && (target.getValue().contains(correctOutputPath))) { + return makeRule; + } + } + } + return null; + } + + public void addRule(ITool tool, IInputType inputType, String macroName, Set InputFiles, + IOutputType outputType, IFile correctOutputFile) { + MakeRule newMakeRule = findTarget(outputType, correctOutputFile); + if (newMakeRule == null) { + newMakeRule = new MakeRule(tool, inputType, InputFiles, outputType, correctOutputFile); + } + newMakeRule.addPrerequisites(inputType, InputFiles); + addRule(newMakeRule); + + } + + public int size() { + return myMakeRules.size(); + } + + public void addRules(MakeRules makeRules) { + for (MakeRule makeRule : makeRules.getMakeRules()) { + addRule(makeRule); + } + } + + public Map> getTargets() { + Map> ret = new HashMap<>(); + for (MakeRule makeRule : myMakeRules) { + ret.putAll(makeRule.getTargets()); + } + return ret; + } + + public Set getMacroNames() { + Set ret = new HashSet<>(); + for (MakeRule makeRule : myMakeRules) { + ret.addAll(makeRule.getAllMacros()); + } + return ret; + } + + public Set getMacroElements(String macroName) { + Set ret = new HashSet<>(); + for (MakeRule makeRule : myMakeRules) { + ret.addAll(makeRule.getMacroElements(macroName)); + } + return ret; + } + + public Set getMakeRules() { + return myMakeRules; + } + + public Set getTargetsForTool(ITool targetTool) { + Set ret=new HashSet<>(); + for(MakeRule curMakeRule :myMakeRules) { + if(curMakeRule.isTool(targetTool)) { + ret.addAll( curMakeRule.getTargetFiles()); + } + } + return ret; + } + +} diff --git a/io.sloeber.ManagedBuild/src/io/sloeber/managedBuild/Internal/ManagebBuildCommon.java b/io.sloeber.ManagedBuild/src/io/sloeber/managedBuild/Internal/ManagebBuildCommon.java new file mode 100644 index 000000000..0a13478cf --- /dev/null +++ b/io.sloeber.ManagedBuild/src/io/sloeber/managedBuild/Internal/ManagebBuildCommon.java @@ -0,0 +1,670 @@ +package io.sloeber.managedBuild.Internal; + +import static io.sloeber.managedBuild.Internal.ManagedBuildConstants.*; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.Reader; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Vector; + +import org.eclipse.cdt.core.CCorePlugin; +import org.eclipse.cdt.core.model.CoreModel; +import org.eclipse.cdt.core.settings.model.ICConfigurationDescription; +import org.eclipse.cdt.core.settings.model.ICProjectDescription; +import org.eclipse.cdt.managedbuilder.core.IConfiguration; +import org.eclipse.cdt.managedbuilder.core.IFolderInfo; +import org.eclipse.cdt.managedbuilder.core.IOutputType; +import org.eclipse.cdt.managedbuilder.core.IResourceInfo; +import org.eclipse.cdt.managedbuilder.core.ITool; +import org.eclipse.cdt.managedbuilder.core.ManagedBuildManager; +import org.eclipse.cdt.managedbuilder.internal.core.OutputType; +import org.eclipse.cdt.managedbuilder.macros.BuildMacroException; +import org.eclipse.cdt.managedbuilder.macros.IBuildMacroProvider; +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.IResourceStatus; +import org.eclipse.core.resources.IWorkspaceRoot; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IConfigurationElement; +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.NullProgressMonitor; +import org.eclipse.core.runtime.Path; + +import io.sloeber.core.common.Common; +import io.sloeber.managedBuild.api.INewManagedOutputNameProvider; + +@SuppressWarnings("nls") +public class ManagebBuildCommon { + /** + * Answers the argument with all whitespaces replaced with an escape sequence. + */ + static public String escapeWhitespaces(String path) { + // Escape the spaces in the path/filename if it has any + String[] segments = path.split("\\s"); + if (segments.length > 1) { + StringBuffer escapedPath = new StringBuffer(); + for (int index = 0; index < segments.length; ++index) { + escapedPath.append(segments[index]); + if (index + 1 < segments.length) { + escapedPath.append("\\ "); + } + } + return escapedPath.toString().trim(); + } + return path; + } + + /** + * Put COLS_PER_LINE comment charaters in the argument. + */ + static protected void outputCommentLine(StringBuffer buffer) { + for (int i = 0; i < COLS_PER_LINE; i++) { + buffer.append(COMMENT_SYMBOL); + } + buffer.append(NEWLINE); + } + + static public boolean containsSpecialCharacters(String path) { + return path.matches(".*(\\s|[\\{\\}\\(\\)\\$\\@%=;]).*"); + } + + /** + * Generates a source macro name from a file extension + */ + static public StringBuffer getSourceMacroName(String extensionName) { + StringBuffer macroName = new StringBuffer(); + if (extensionName == null) { + return null; + } + // We need to handle case sensitivity in file extensions (e.g. .c vs + // .C), so if the + // extension was already upper case, tack on an "UPPER_" to the macro + // name. + // In theory this means there could be a conflict if you had for + // example, + // extensions .c_upper, and .C, but realistically speaking the chances + // of this are + // practically nil so it doesn't seem worth the hassle of generating a + // truly + // unique name. + if (extensionName.equals(extensionName.toUpperCase())) { + macroName.append(extensionName.toUpperCase()).append("_UPPER"); + } else { + // lower case... no need for "UPPER_" + macroName.append(extensionName.toUpperCase()); + } + macroName.append("_SRCS"); + return macroName; + } + + public static void save(StringBuffer buffer, IFile file) throws CoreException { + + byte[] bytes = buffer.toString().getBytes(); + ByteArrayInputStream stream = new ByteArrayInputStream(bytes); + if (file.exists()) { + file.setContents(stream, true, false, null); + } else { + IFolder fileFolder = file.getProject().getFolder(file.getParent().getProjectRelativePath()); + createFolder(fileFolder); + file.create(stream, false, null); + } + file.setDerived(true, null); + } + + public static void createFolder(IFolder folder) throws CoreException { + // Create or get the handle for the build directory + if (folder.exists()) { + return; + } + if (!folder.getParent().exists()) { + createFolder(folder.getFolder("..")); + } + folder.create(true, true, null); + folder.setDerived(true, null); + } + + /** + * Generates a generated dependency file macro name from a file extension + */ + + public static StringBuffer getDepMacroName(String extensionName) { + StringBuffer macroName = new StringBuffer(); + // We need to handle case sensitivity in file extensions (e.g. .c vs + // .C), so if the + // extension was already upper case, tack on an "UPPER_" to the macro + // name. + // In theory this means there could be a conflict if you had for + // example, + // extensions .c_upper, and .C, but realistically speaking the chances + // of this are + // practically nil so it doesn't seem worth the hassle of generating a + // truly + // unique name. + if (extensionName.equals(extensionName.toUpperCase())) { + macroName.append(extensionName.toUpperCase()).append("_UPPER"); + } else { + // lower case... no need for "UPPER_" + macroName.append(extensionName.toUpperCase()); + } + macroName.append("_DEPS"); + return macroName; + } + + /** + * This method postprocesses a .d file created by a build. It's main job is to + * add dummy targets for the header files dependencies. This prevents make from + * aborting the build if the header file does not exist. A secondary job is to + * work in tandem with the "echo" command that is used by some tool-chains in + * order to get the "targets" part of the dependency rule correct. This method + * adds a comment to the beginning of the dependency file which it checks for to + * determine if this dependency file has already been updated. + * + * @return a true if the dependency file is modified + */ + static public boolean populateDummyTargets(IConfiguration cfg, IFile makefile, boolean force) + throws CoreException, IOException { + return populateDummyTargets(cfg.getRootFolderInfo(), makefile, force); + } + + static public boolean populateDummyTargets(IResourceInfo rcInfo, IFile makefile, boolean force) + throws CoreException, IOException { + if (makefile == null || !makefile.exists()) + return false; + // Get the contents of the dependency file + InputStream contentStream = makefile.getContents(false); + StringBuffer inBuffer = null; + // JABA made sure thgere are no emory leaks + try (Reader in = new InputStreamReader(contentStream);) { + int chunkSize = contentStream.available(); + inBuffer = new StringBuffer(chunkSize); + char[] readBuffer = new char[chunkSize]; + int n = in.read(readBuffer); + while (n > 0) { + inBuffer.append(readBuffer); + n = in.read(readBuffer); + } + contentStream.close(); + in.close(); + } + // The rest of this operation is equally expensive, so + // if we are doing an incremental build, only update the + // files that do not have a comment + String inBufferString = inBuffer.toString(); + if (!force && inBufferString.startsWith(COMMENT_SYMBOL)) { + return false; + } + // Try to determine if this file already has dummy targets defined. + // If so, we will only add the comment. + String[] bufferLines = inBufferString.split("[\\r\\n]"); + for (String bufferLine : bufferLines) { + if (bufferLine.endsWith(":")) { + StringBuffer outBuffer = addDefaultHeader(); + outBuffer.append(inBuffer); + save(outBuffer, makefile); + return true; + } + } + // Reconstruct the buffer tokens into useful chunks of dependency + // information + Vector bufferTokens = new Vector<>(Arrays.asList(inBufferString.split("\\s"))); + Vector deps = new Vector<>(bufferTokens.size()); + Iterator tokenIter = bufferTokens.iterator(); + while (tokenIter.hasNext()) { + String token = tokenIter.next(); + if (token.lastIndexOf("\\") == token.length() - 1 && token.length() > 1) { + // This is escaped so keep adding to the token until we find the + // end + while (tokenIter.hasNext()) { + String nextToken = tokenIter.next(); + token += WHITESPACE + nextToken; + if (!nextToken.endsWith("\\")) { + break; + } + } + } + deps.add(token); + } + deps.trimToSize(); + // Now find the header file dependencies and make dummy targets for them + boolean save = false; + StringBuffer outBuffer = null; + // If we are doing an incremental build, only update the files that do + // not have a comment + String firstToken; + try { + firstToken = deps.get(0); + } catch (@SuppressWarnings("unused") ArrayIndexOutOfBoundsException e) { + // This makes no sense so bail + return false; + } + // Put the generated comments in the output buffer + if (!firstToken.startsWith(COMMENT_SYMBOL)) { + outBuffer = addDefaultHeader(); + } else { + outBuffer = new StringBuffer(); + } + // Some echo implementations misbehave and put the -n and newline in the + // output + if (firstToken.startsWith("-n")) { + // Now let's parse: + // Win32 outputs -n '/.d /' + // POSIX outputs -n /.d / + // Get the dep file name + String secondToken; + try { + secondToken = deps.get(1); + } catch (ArrayIndexOutOfBoundsException e) { + secondToken = ""; + } + if (secondToken.startsWith("'")) { + // This is the Win32 implementation of echo (MinGW without MSYS) + outBuffer.append(secondToken.substring(1)).append(WHITESPACE); + } else { + outBuffer.append(secondToken).append(WHITESPACE); + } + // The relative path to the build goal comes next + String thirdToken; + try { + thirdToken = deps.get(2); + } catch (ArrayIndexOutOfBoundsException e) { + thirdToken = ""; + } + int lastIndex = thirdToken.lastIndexOf("'"); + if (lastIndex != -1) { + if (lastIndex == 0) { + outBuffer.append(WHITESPACE); + } else { + outBuffer.append(thirdToken.substring(0, lastIndex - 1)); + } + } else { + outBuffer.append(thirdToken); + } + // Followed by the target output by the compiler plus ':' + // If we see any empty tokens here, assume they are the result of + // a line feed output by "echo" and skip them + String fourthToken; + int nToken = 3; + try { + do { + fourthToken = deps.get(nToken++); + } while (fourthToken.length() == 0); + } catch (ArrayIndexOutOfBoundsException e) { + fourthToken = ""; + } + outBuffer.append(fourthToken).append(WHITESPACE); + // Followed by the actual dependencies + try { + for (String nextElement : deps) { + if (nextElement.endsWith("\\")) { + outBuffer.append(nextElement).append(NEWLINE).append(WHITESPACE); + } else { + outBuffer.append(nextElement).append(WHITESPACE); + } + } + } catch (IndexOutOfBoundsException e) { + /* JABA is not going to write this code */ + } + } else { + outBuffer.append(inBuffer); + } + outBuffer.append(NEWLINE); + save = true; + IFolderInfo fo = null; + if (rcInfo instanceof IFolderInfo) { + fo = (IFolderInfo) rcInfo; + } else { + IConfiguration c = rcInfo.getParent(); + fo = (IFolderInfo) c.getResourceInfo(rcInfo.getPath().removeLastSegments(1), false); + } + // Dummy targets to add to the makefile + for (String dummy : deps) { + IPath dep = new Path(dummy); + String extension = dep.getFileExtension(); + if (fo.isHeaderFile(extension)) { + /* + * The formatting here is : + */ + outBuffer.append(dummy).append(COLON).append(NEWLINE).append(NEWLINE); + } + } + // Write them out to the makefile + if (save) { + save(outBuffer, makefile); + return true; + } + return false; + } + + /** + * prepend all instanced of '\' or '"' with a backslash + * + * @return resulting string + */ + static public String escapedEcho(String string) { + String escapedString = string.replace("'", "'\"'\"'"); + return ECHO + WHITESPACE + SINGLE_QUOTE + escapedString + SINGLE_QUOTE + NEWLINE; + } + + static public String ECHO_BLANK_LINE = ECHO + WHITESPACE + SINGLE_QUOTE + WHITESPACE + SINGLE_QUOTE + NEWLINE; + + /** + * Outputs a comment formatted as follows: ##### ....... ##### # ##### ....... ##### + */ + static protected StringBuffer addDefaultHeader() { + StringBuffer buffer = new StringBuffer(); + outputCommentLine(buffer); + buffer.append(COMMENT_SYMBOL).append(WHITESPACE).append(MESSAGE_HEADER) + .append(NEWLINE); + outputCommentLine(buffer); + buffer.append(NEWLINE); + return buffer; + } + + /** + * Strips outermost quotes of Strings of the form "a" and 'a' or returns the + * original string if the input is not of this form. + * + * @throws NullPointerException + * if path is null + * @return a String without the outermost quotes (if the input has them) + */ + public static String ensureUnquoted(String path) { + boolean doubleQuoted = path.startsWith("\"") && path.endsWith("\""); + boolean singleQuoted = path.startsWith("'") && path.endsWith("'"); + return doubleQuoted || singleQuoted ? path.substring(1, path.length() - 1) : path; + } + + public static List resolvePaths(List toResolve, IConfiguration config) { + List ret = new LinkedList<>(); + if (toResolve.isEmpty()) + return ret; + for (IPath curOutputPath : toResolve) { + try { + if (curOutputPath != null) { + String curOutput = curOutputPath.toOSString(); + // try to resolve the build macros in the + // output names + String resolved = ManagedBuildManager.getBuildMacroProvider().resolveValueToMakefileFormat( + curOutput, "", //$NON-NLS-1$ + " ", //$NON-NLS-1$ + IBuildMacroProvider.CONTEXT_CONFIGURATION, config); + if ((resolved = resolved.trim()).length() > 0) { + ret.add(resolved); + } else { + ret.add(curOutput); + } + } + } catch (BuildMacroException e) { + //If we can not resolve we keep the original + } + } + return ret; + } + + /** + * Return or create the folder needed for the build output. If we are creating + * the folder, set the derived bit to true so the CM system ignores the + * contents. If the resource exists, respect the existing derived setting. + */ + public static IPath createDirectory(IProject project, 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(project, 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; + } + // Make sure the folder is marked as derived so it is not added to + // CM + if (!folder.isDerived()) { + folder.setDerived(true, null); + } + } + return folder.getFullPath(); + } + + /** + * Return or create the makefile needed for the build. If we are creating the + * resource, set the derived bit to true so the CM system ignores the contents. + * If the resource exists, respect the existing derived setting. + */ + public static 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, new NullProgressMonitor()); + // Make sure the new file is marked as derived + if (!newFile.isDerived()) { + newFile.setDerived(true, null); + } + } 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; + } + return newFile; + } + + /** + * Adds a macro addition prefix to a map of macro names to entries. Entry + * prefixes look like: C_SRCS += \ ${addprefix $(ROOT)/, \ + */ + public static void addMacroAdditionPrefix(LinkedHashMap map, String macroName, String relativePath, + boolean addPrefix) { + // there is no entry in the map, so create a buffer for this macro + StringBuffer tempBuffer = new StringBuffer(); + tempBuffer.append(macroName).append(MACRO_ADDITION_PREFIX_SUFFIX); + if (addPrefix) { + tempBuffer.append(new Path(MACRO_ADDITION_ADDPREFIX_HEADER).append(relativePath) + .append(MACRO_ADDITION_ADDPREFIX_SUFFIX).toOSString()); + } + // have to store the buffer in String form as StringBuffer is not a + // sublcass of Object + map.put(macroName, tempBuffer.toString()); + } + + /** + * Gets a path for a resource by extracting the Path field from its location + * URI. + * + * @return IPath + * @since 6.0 + */ + + public static IPath getPathForResource(IResource resource) { + return new Path(resource.getLocationURI().getPath()); + } + + /** + * Adds a file to an entry in a map of macro names to entries. File additions + * look like: example.c, \ + */ + static public void addMacroAdditionFile(HashMap map, String macroName, String filename) { + StringBuffer buffer = new StringBuffer(); + buffer.append(map.get(macroName)); + String escapedFilename = escapeWhitespaces(filename); + buffer.append(escapedFilename).append(WHITESPACE).append(LINEBREAK); + map.put(macroName, buffer.toString()); + } + + /** + * Adds a file to an entry in a map of macro names to entries. File additions + * look like: example.c, \ + */ + static public void addMacroAdditionFile(ArduinoGnuMakefileGenerator caller, HashMap map, + String macroName, String relativePath, IPath sourceLocation, boolean generatedSource) { + // Add the source file path to the makefile line that adds source files + // to the build variable + IProject project = caller.getProject(); + IPath buildWorkingDir = caller.getBuildWorkingDir(); + String srcName; + IPath projectLocation = getPathForResource(project); + IPath dirLocation = projectLocation; + if (generatedSource) { + dirLocation = dirLocation.append(buildWorkingDir); + } + if (dirLocation.isPrefixOf(sourceLocation)) { + IPath srcPath = sourceLocation.removeFirstSegments(dirLocation.segmentCount()).setDevice(null); + if (generatedSource) { + srcName = DOT_SLASH_PATH.append(srcPath).toOSString(); + } else { + srcName = ROOT + FILE_SEPARATOR + srcPath.toOSString(); + } + } else { + if (generatedSource && !sourceLocation.isAbsolute()) { + srcName = DOT_SLASH_PATH.append(relativePath).append(sourceLocation.lastSegment()).toOSString(); + } else { + // TODO: Should we use relative paths when possible (e.g., see + // MbsMacroSupplier.calculateRelPath) + srcName = sourceLocation.toOSString(); + } + } + addMacroAdditionFile(map, macroName, srcName); + } + + /** + * Process a String denoting a filepath in a way compatible for GNU Make rules, + * handling windows drive letters and whitespace appropriately. + *

+ *

+ * The context these paths appear in is on the right hand side of a rule header. + * i.e. + *

+ *

+ * target : dep1 dep2 dep3 + *

+ * + * @param path + * the String denoting the path to process + * @throws NullPointerException + * is path is null + * @return a suitable Make rule compatible path + */ + /* see https://bugs.eclipse.org/bugs/show_bug.cgi?id=129782 */ + static public String ensurePathIsGNUMakeTargetRuleCompatibleSyntax(String path) { + return escapeWhitespaces(ensureUnquoted(path)); + } + + static public String getToolCommandLinePattern(IConfiguration config, ITool tool) { + IProject project = config.getOwner().getProject(); + String orgPattern = tool.getCommandLinePattern(); + if (orgPattern.contains("$")) { + //if the pattern contains a space no use to try to expand it + return orgPattern; + } + ICProjectDescription prjDesc = CoreModel.getDefault().getProjectDescription(project); + ICConfigurationDescription confDesc = prjDesc.getConfigurationByName(config.getName()); + return Common.getBuildEnvironmentVariable(confDesc, orgPattern, orgPattern, false); + + } + + static public INewManagedOutputNameProvider getJABANameProvider(IConfiguration cConf, IPath referencedFrom, + IOutputType iType) { + OutputType type = (OutputType) iType; + IConfigurationElement element = type.getNameProviderElement(); + if (element != null) { + try { + if (element.getAttribute(IOutputType.NAME_PROVIDER) != null) { + return (INewManagedOutputNameProvider) element.createExecutableExtension(IOutputType.NAME_PROVIDER); + } + } catch (@SuppressWarnings("unused") CoreException e) { + //ignore errors + } + } + String[] outputNames = type.getOutputNames(); + if (outputNames != null && outputNames.length > 0) { + String outputName = outputNames[0]; + IBuildMacroProvider provider = ManagedBuildManager.getBuildMacroProvider(); + String expanded = outputName; + try { + expanded = provider.resolveValue(outputName, EMPTY_STRING, WHITESPACE, + IBuildMacroProvider.CONTEXT_CONFIGURATION, cConf); + } catch (BuildMacroException e) { + // default will do + e.printStackTrace(); + } + IPath expandedPath = new Path(expanded); + if (expandedPath.segmentCount() > 1) { + expandedPath = GetNiceFileName(referencedFrom, new Path(expanded)); + } + final IPath ret=expandedPath; + return new INewManagedOutputNameProvider() { + + @Override + public IPath getOutputName(IProject project, IConfiguration cConf, ITool tool, IPath inputName) { + return ret; + } + }; + } + + String[] outputExtensions = type.getOutputExtensionsAttribute(); + if (outputExtensions != null && outputExtensions.length > 0) { + String outputExtension = outputExtensions[0]; + return new INewManagedOutputNameProvider() { + + @Override + public IPath getOutputName(IProject project, IConfiguration cConf, ITool tool, IPath inputName) { + ICProjectDescription prjDesc = CoreModel.getDefault().getProjectDescription(project); + ICConfigurationDescription confDesc = prjDesc.getConfigurationByName(cConf.getName()); + String expanded = Common.getBuildEnvironmentVariable(confDesc, inputName.toString(), + inputName.toString(), true); + return new Path(expanded).addFileExtension(outputExtension); + } + }; + } + + return null; + } + + static public String GetNiceFileName(IFile buildPath, IFile path) { + return GetNiceFileName(buildPath.getLocation(), path.getLocation()).toOSString(); + } + + static public IPath GetNiceFileName(IPath buildPath, IPath filePath) { + if (buildPath.isPrefixOf(filePath)) { + return filePath.makeRelativeTo(buildPath); + } + if (buildPath.removeLastSegments(1).isPrefixOf(filePath)) { + return filePath.makeRelativeTo(buildPath); + + } + return filePath; + } + + static public String makeVariable(String variableName) { + return VARIABLE_PREFIX + variableName + VARIABLE_SUFFIX; + } +} diff --git a/io.sloeber.ManagedBuild/src/io/sloeber/managedBuild/Internal/ManagedBuildConstants.java b/io.sloeber.ManagedBuild/src/io/sloeber/managedBuild/Internal/ManagedBuildConstants.java new file mode 100644 index 000000000..772edae4d --- /dev/null +++ b/io.sloeber.ManagedBuild/src/io/sloeber/managedBuild/Internal/ManagedBuildConstants.java @@ -0,0 +1,100 @@ +package io.sloeber.managedBuild.Internal; +import java.io.File; + +import org.eclipse.cdt.managedbuilder.internal.core.ManagedMakeMessages; +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.Path; + +@SuppressWarnings("nls") +public class ManagedBuildConstants { + public static final String AT = "@"; + public static final String COLON = ":"; + public static final int COLS_PER_LINE = 80; + public static final String COMMENT_SYMBOL = "#"; + public static final String COMMENT_START = "# "; + public static final String DOLLAR_SYMBOL = "$"; + public static final String DEP_EXT = "d"; + public static final String DEPFILE_NAME = "subdir.dep"; + public static final String DOT = "."; + public static final String DASH = "-"; + public static final String ECHO = "echo"; + public static final String IN_MACRO = "$<"; + public static final String LINEBREAK = "\\\n"; + public static final String LOGICAL_AND = "&&"; + public static final String MAKEFILE_DEFS = "makefile.defs"; + public static final String MAKEFILE_INIT = "makefile.init"; + public static final String MAKEFILE_NAME = "makefile"; + public static final String MAKEFILE_TARGETS = "makefile.targets"; + public static final String MAKE = "$(MAKE)"; + public static final String NO_PRINT_DIR = "--no-print-directory"; + + public static final String MODFILE_NAME = "subdir.mk"; + public static final String NEWLINE = System.getProperty("line.separator"); + public static final String OBJECTS_MAKFILE = "objects.mk"; + public static final String OUT_MACRO = "$@"; + public static final String ROOT = ".."; + public static final String SEPARATOR = "/"; + public static final String SINGLE_QUOTE = "'"; + public static final String SRCSFILE_NAME = "sources.mk"; + public static final String TAB = "\t"; + public static final String WHITESPACE = " "; + public static final String WILDCARD = "%"; + + // String constants for makefile contents and messages + public static final String COMMENT = "MakefileGenerator.comment"; + public static final String HEADER = COMMENT + ".header"; + + public static final String BUILD_TOP = COMMENT + ".build.toprules"; + public static final String BUILD_TARGETS = COMMENT + ".build.toptargets"; + public static final String EMPTY_STRING = ""; + public static final String[] EMPTY_STRING_ARRAY = new String[0]; + public static final String OBJS_MACRO = "OBJS"; + public static final String MACRO_ADDITION_ADDPREFIX_HEADER = "${addprefix "; + public static final String MACRO_ADDITION_ADDPREFIX_SUFFIX = "," + WHITESPACE + LINEBREAK; + public static final String MAKE_ADDITION = " +="; + public static final String MAKE_EQUAL = " :="; + public static final String MACRO_ADDITION_PREFIX_SUFFIX = MAKE_ADDITION + LINEBREAK; + public static final String PREBUILD = "pre-build"; + public static final String MAINBUILD = "main-build"; + public static final String POSTBUILD = "post-build"; + public static final String SECONDARY_OUTPUTS = "secondary-outputs"; + + public static final IPath DOT_SLASH_PATH = new Path("./"); + public static final String FILE_SEPARATOR = File.separator; + // Enumerations + public static final int PROJECT_RELATIVE = 1, PROJECT_SUBDIR_RELATIVE = 2, ABSOLUTE = 3; + + public static final String DEFAULT_PATTERN = "${COMMAND} ${FLAGS} ${OUTPUT_FLAG} ${OUTPUT_PREFIX}${OUTPUT} ${INPUTS}"; + public static final String DOUBLE_QUOTE = "\""; + + public static final String CMD_LINE_PRM_NAME = "COMMAND"; + public static final String FLAGS_PRM_NAME = "FLAGS"; + public static final String OUTPUT_FLAG_PRM_NAME = "OUTPUT_FLAG"; + public static final String OUTPUT_PREFIX_PRM_NAME = "OUTPUT_PREFIX"; + public static final String OUTPUT_PRM_NAME = "OUTPUT"; + public static final String INPUTS_PRM_NAME = "INPUTS"; + public static final String VARIABLE_PREFIX = "${"; + public static final String VARIABLE_SUFFIX = "}"; + public static final String DEPENDENCY_SUFFIX = "_DEPS"; + + public static final String MESSAGE_FINISH_BUILD = ManagedMakeMessages + .getResourceString("MakefileGenerator.message.finish.build"); + public static final String MESSAGE_FINISH_FILE = ManagedMakeMessages + .getResourceString("MakefileGenerator.message.finish.file"); + public static final String MESSAGE_START_BUILD = ManagedMakeMessages + .getResourceString("MakefileGenerator.message.start.build"); + public static final String MESSAGE_START_FILE = ManagedMakeMessages + .getResourceString("MakefileGenerator.message.start.file"); + public static final String MESSAGE_START_DEPENDENCY = ManagedMakeMessages + .getResourceString("MakefileGenerator.message.start.dependency"); + public static final String MESSAGE_NO_TARGET_TOOL = ManagedMakeMessages + .getResourceString("MakefileGenerator.message.no.target"); + public static final String MESSAGE_MOD_VARS = ManagedMakeMessages.getResourceString(COMMENT + ".module.variables"); + public static final String MESSAGE_MOD_RULES = ManagedMakeMessages.getResourceString(COMMENT + ".build.rule"); + public static final String MOD_LIST_MESSAGE = ManagedMakeMessages.getResourceString(COMMENT + ".module.list"); + public static final String MESSAGE_MAINBUILD_TARGET = ManagedMakeMessages + .getResourceString(COMMENT + ".build.mainbuildtarget"); + public static final String MESSAGE_ALL_TARGET = ManagedMakeMessages.getResourceString(COMMENT + ".build.alltarget"); + public static final String MESSAGE_SRC_LISTS = ManagedMakeMessages.getResourceString(COMMENT + ".source.list"); + public static final String MESSAGE_HEADER =ManagedMakeMessages.getResourceString(HEADER); +} diff --git a/io.sloeber.ManagedBuild/src/io/sloeber/managedBuild/Internal/SrcMakeGenerator.java b/io.sloeber.ManagedBuild/src/io/sloeber/managedBuild/Internal/SrcMakeGenerator.java new file mode 100644 index 000000000..9d56057d4 --- /dev/null +++ b/io.sloeber.ManagedBuild/src/io/sloeber/managedBuild/Internal/SrcMakeGenerator.java @@ -0,0 +1,68 @@ +package io.sloeber.managedBuild.Internal; + +import static io.sloeber.managedBuild.Internal.ManagebBuildCommon.*; +import static io.sloeber.managedBuild.Internal.ManagedBuildConstants.*; + +import java.util.Collection; +import java.util.Set; + +import org.eclipse.cdt.managedbuilder.core.IConfiguration; +import org.eclipse.core.resources.IContainer; +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IPath; + +public class SrcMakeGenerator { + + static public void generateSourceMakefile(IProject project, IConfiguration config, Set macroNames, + Collection subDirs) throws CoreException { + // Add the comment + StringBuffer buffer = addDefaultHeader(); + // Add the macros to the makefile + for (String macroName : macroNames) { + buffer.append(macroName).append(WHITESPACE).append(":=").append(WHITESPACE).append(NEWLINE); //$NON-NLS-1$ + } + // Add a list of subdirectories to the makefile + buffer.append(NEWLINE); + // Add the comment + buffer.append(COMMENT_SYMBOL).append(WHITESPACE).append(MOD_LIST_MESSAGE).append(NEWLINE); + buffer.append("SUBDIRS := ").append(LINEBREAK); //$NON-NLS-1$ + // Get all the module names + for (IResource container : subDirs) { + if (container.getFullPath() == project.getFullPath()) { + buffer.append(DOT).append(WHITESPACE).append(LINEBREAK); + } else { + IPath path = container.getProjectRelativePath(); + buffer.append(escapeWhitespaces(path.toOSString())).append(WHITESPACE).append(LINEBREAK); + } + } + buffer.append(NEWLINE); + // Save the file + IFile fileHandle = project.getFile(config.getName() + '/' + SRCSFILE_NAME); + save(buffer, fileHandle); + } + + /** + * The makefile generator generates a Macro for each type of output, other than + * final artifact, created by the build. + * + * @param fileHandle + * The file that should be populated with the output + */ + protected static void generateObjectsMakefile(IProject project, IConfiguration config, Set outputMacros) + throws CoreException { + StringBuffer macroBuffer = new StringBuffer(); + macroBuffer.append(addDefaultHeader()); + + for (String macroName : outputMacros) { + macroBuffer.append(macroName).append(MAKE_EQUAL); + macroBuffer.append(NEWLINE); + macroBuffer.append(NEWLINE); + } + IFile fileHandle = project.getFile(config.getName() + '/' + OBJECTS_MAKFILE); + save(macroBuffer, fileHandle); + } + +} diff --git a/io.sloeber.ManagedBuild/src/io/sloeber/managedBuild/Internal/SubDirMakeGenerator.java b/io.sloeber.ManagedBuild/src/io/sloeber/managedBuild/Internal/SubDirMakeGenerator.java new file mode 100644 index 000000000..cf58484b3 --- /dev/null +++ b/io.sloeber.ManagedBuild/src/io/sloeber/managedBuild/Internal/SubDirMakeGenerator.java @@ -0,0 +1,245 @@ +package io.sloeber.managedBuild.Internal; + +import static io.sloeber.managedBuild.Internal.ManagebBuildCommon.*; +//import static io.sloeber.managedBuild.Internal.ManagebBuildCommon.*; +import static io.sloeber.managedBuild.Internal.ManagedBuildConstants.*; + +import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.Map; +import java.util.Set; + +import org.eclipse.cdt.managedbuilder.core.IConfiguration; +import org.eclipse.cdt.managedbuilder.core.IInputType; +import org.eclipse.cdt.managedbuilder.core.IOutputType; +import org.eclipse.cdt.managedbuilder.core.ITool; +import org.eclipse.core.resources.IContainer; +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.Path; + +import io.sloeber.managedBuild.api.INewManagedOutputNameProvider; + +public class SubDirMakeGenerator { + private ArduinoGnuMakefileGenerator caller; + private Set myMakeRules = new LinkedHashSet<>(); + private IFile myMakefile; + + SubDirMakeGenerator(ArduinoGnuMakefileGenerator theCaller, IContainer module) { + caller = theCaller; + IProject project = getProject(); + IPath buildPath = getBuildPath(); + if (buildPath == null) { + return; + } + IPath moduleOutputPath = buildPath.append(module.getProjectRelativePath()); + myMakefile = project.getFile(moduleOutputPath.append(MODFILE_NAME)); + getMakeRulesFromSourceFiles(module); + } + + public Set getDependecyMacros() { + HashSet ret = new LinkedHashSet<>(); + for (MakeRule curMakeRule : myMakeRules) { + ret.addAll(curMakeRule.getDependecyMacros()); + } + return ret; + } + + public Set getAllMacros() { + HashSet ret = new LinkedHashSet<>(); + for (MakeRule curMakeRule : myMakeRules) { + ret.addAll(curMakeRule.getAllMacros()); + } + return ret; + } + + public Set getTargetMacros() { + HashSet ret = new LinkedHashSet<>(); + for (MakeRule curMakeRule : myMakeRules) { + ret.addAll(curMakeRule.getTargetMacros()); + } + return ret; + } + + public Set getMakeRules() { + return myMakeRules; + } + + public Set getPrerequisiteMacros() { + HashSet ret = new LinkedHashSet<>(); + for (MakeRule curMakeRule : myMakeRules) { + ret.addAll(curMakeRule.getPrerequisiteMacros()); + } + return ret; + } + + public Set getTargetFiles() { + Set ret = new LinkedHashSet<>(); + for (MakeRule curMakeRule : myMakeRules) { + ret.addAll(curMakeRule.getTargetFiles()); + } + return ret; + } + + public Set getDependencyFiles() { + Set ret = new LinkedHashSet<>(); + for (MakeRule curMakeRule : myMakeRules) { + ret.addAll(curMakeRule.getDependencyFiles()); + } + return ret; + } + + public Map> getTargets() { + Map> ret = new LinkedHashMap<>(); + for (MakeRule curMakeRule : myMakeRules) { + ret.putAll(curMakeRule.getTargets()); + } + return ret; + } + + private IPath getBuildPath() { + return caller.getBuildWorkingDir(); + } + + private IPath getBuildFolder() { + return caller.getBuildFolder(); + } + + private IFile getTopBuildDir() { + return caller.getTopBuildDir(); + } + + private IConfiguration getConfig() { + return caller.getConfig(); + } + + private IProject getProject() { + return caller.getProject(); + } + + /************************************************************************* + * M A K E F I L E S P O P U L A T I O N M E T H O D S + ************************************************************************/ + /** + * This method generates a "fragment" make file (subdir.mk). One of these is + * generated for each project directory/subdirectory that contains source files. + */ + public void generateMakefile() throws CoreException { + //generate the file content + StringBuffer makeBuf = addDefaultHeader(); + makeBuf.append(GenerateMacros()); + makeBuf.append(GenerateRules(getConfig())); + + // Save the files + save(makeBuf, myMakefile); + } + + private StringBuffer GenerateMacros() { + StringBuffer buffer = new StringBuffer(); + IFile buildRoot = getTopBuildDir(); + buffer.append(NEWLINE); + buffer.append(COMMENT_SYMBOL).append(WHITESPACE).append(MESSAGE_MOD_VARS) + .append(NEWLINE); + HashSet macroNames = new HashSet<>(); + for (MakeRule makeRule : myMakeRules) { + macroNames.addAll(makeRule.getAllMacros()); + } + for (String macroName : macroNames) { + HashSet files = new HashSet<>(); + for (MakeRule makeRule : myMakeRules) { + files.addAll(makeRule.getMacroElements(macroName)); + } + if (files.size() > 0) { + buffer.append(macroName).append(MAKE_ADDITION); + for (IFile file : files) { + buffer.append(LINEBREAK); + buffer.append(GetNiceFileName(buildRoot, file)).append(WHITESPACE); + } + buffer.append(NEWLINE); + buffer.append(NEWLINE); + } + } + return buffer; + } + + private StringBuffer GenerateRules(IConfiguration config) { + StringBuffer buffer = new StringBuffer(); + buffer.append(NEWLINE); + buffer.append(COMMENT_SYMBOL).append(WHITESPACE).append(MESSAGE_MOD_RULES) + .append(NEWLINE); + + for (MakeRule makeRule : myMakeRules) { + buffer.append(makeRule.getRule(getProject(), getTopBuildDir(), config)); + } + + return buffer; + } + + //Get the rules for the source files + private void getMakeRulesFromSourceFiles(IContainer module) { + myMakeRules.clear(); + IConfiguration config = getConfig(); + IProject project = getProject(); + IPath buildPath = getBuildFolder(); + + // Visit the resources in this folder + try { + for (IResource resource : module.members()) { + if (resource.getType() != IResource.FILE) { + //only handle files + continue; + } + IFile inputFile = (IFile) resource; + String ext = inputFile.getFileExtension(); + if (ext == null || ext.isBlank()) { + continue; + } + IPath rcProjRelPath = inputFile.getProjectRelativePath(); + if (!caller.isSource(rcProjRelPath)) { + // this resource is excluded from build + continue; + } + + for (ITool tool : config.getTools()) { + for (IInputType inputType : tool.getInputTypes()) { + if (!inputType.isSourceExtension(tool, ext)) { + continue; + } + for (IOutputType outputType : tool.getOutputTypes()) { + INewManagedOutputNameProvider nameProvider = getJABANameProvider(config, buildPath, + outputType); + if (nameProvider == null) { + continue; + } + IPath outputFile = nameProvider.getOutputName(getProject(), config, tool, + resource.getProjectRelativePath()); + if (outputFile == null) { + continue; + } + //We found a tool that provides a outputfile for our source file + //TOFIX if this is a multiple to one we should only create one MakeRule + IPath correctOutputPath = new Path(config.getName()).append(outputFile); + MakeRule newMakeRule = new MakeRule(tool, inputType, inputFile, outputType, + project.getFile(correctOutputPath)); + newMakeRule.addDependencies(caller); + + myMakeRules.add(newMakeRule); + } + } + } + + } + } catch (CoreException e) { + e.printStackTrace(); + } + } + + public boolean isEmpty() { + return myMakeRules.size() == 0; + } + +} diff --git a/io.sloeber.ManagedBuild/src/io/sloeber/managedBuild/Internal/TopMakeFileGenerator.java b/io.sloeber.ManagedBuild/src/io/sloeber/managedBuild/Internal/TopMakeFileGenerator.java new file mode 100644 index 000000000..d163578e9 --- /dev/null +++ b/io.sloeber.ManagedBuild/src/io/sloeber/managedBuild/Internal/TopMakeFileGenerator.java @@ -0,0 +1,431 @@ +package io.sloeber.managedBuild.Internal; + +import static io.sloeber.managedBuild.Internal.ManagebBuildCommon.*; +import static io.sloeber.managedBuild.Internal.ManagedBuildConstants.*; + +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedHashSet; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; +import org.eclipse.cdt.core.settings.model.ICConfigurationDescription; +import org.eclipse.cdt.managedbuilder.core.IConfiguration; +import org.eclipse.cdt.managedbuilder.core.IInputType; +import org.eclipse.cdt.managedbuilder.core.IOutputType; +import org.eclipse.cdt.managedbuilder.core.ITool; +import org.eclipse.cdt.managedbuilder.core.ManagedBuildManager; +import org.eclipse.cdt.managedbuilder.macros.BuildMacroException; +import org.eclipse.cdt.managedbuilder.macros.IBuildMacroProvider; +import org.eclipse.core.resources.IContainer; +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.Path; + +import io.sloeber.managedBuild.api.INewManagedOutputNameProvider; + +public class TopMakeFileGenerator { + private ArduinoGnuMakefileGenerator caller = null; + private Set mySubDirMakeRules = new LinkedHashSet<>(); + private MakeRules myMakeRules = new MakeRules(); + private Collection myFoldersToBuild; + private Map> myAllSourceTargets = new HashMap<>(); + private Set myDependencyMacros = new HashSet<>(); + + private IConfiguration getConfig() { + return caller.getConfig(); + } + + private IProject getProject() { + return caller.getProject(); + } + + private IPath getBuildFolder() { + return caller.getBuildFolder(); + } + + TopMakeFileGenerator(ArduinoGnuMakefileGenerator theCaller, Set subDirMakeRules, + Collection foldersToBuild) { + caller = theCaller; + mySubDirMakeRules = subDirMakeRules; + myFoldersToBuild = foldersToBuild; + for (MakeRule curMakeRule : mySubDirMakeRules) { + myAllSourceTargets.putAll(curMakeRule.getTargets()); + myDependencyMacros.addAll(curMakeRule.getDependecyMacros()); + } + MakeRules makeRules = new MakeRules(); + Map> generatedFiles = new HashMap<>(); + for (MakeRule makeRule : subDirMakeRules) { + Map> targets = makeRule.getTargets(); + for (Entry> curTarget : targets.entrySet()) { + Set esxistingTarget = generatedFiles.get(curTarget.getKey()); + if (esxistingTarget != null) { + esxistingTarget.addAll(curTarget.getValue()); + } else { + Set copySet = new HashSet<>(); + copySet.addAll(curTarget.getValue()); + generatedFiles.put(curTarget.getKey(), copySet); + } + + } + } + int depth = 10; + while (depth > 0) { + makeRules = getMakeRulesFromGeneratedFiles(generatedFiles); + generatedFiles.clear(); + if (makeRules.size() > 0) { + depth--; + myMakeRules.addRules(makeRules); + generatedFiles.putAll(makeRules.getTargets()); + } else { + depth = 0; + } + } + + } + + public void generateMakefile() throws CoreException { + IProject project = getProject(); + IConfiguration config = getConfig(); + + StringBuffer buffer = new StringBuffer(); + buffer.append(addDefaultHeader()); + + buffer.append(getMakeIncludeSubDirs()); + buffer.append(getMakeIncludeDependencies()); + buffer.append(getMakeRMCommand()); + buffer.append(getMakeTopTargets());// this is the include dependencies + // TOFIX the content from the append below should come from a registered method + buffer.append("\n#bootloaderTest\n" + "BurnBootLoader: \n" + + "\t@echo trying to burn bootloader ${bootloader.tool}\n" + + "\t${tools.${bootloader.tool}.erase.pattern}\n" + "\t${tools.${bootloader.tool}.bootloader.pattern}\n" + + "\n" + "uploadWithBuild: all\n" + + "\t@echo trying to build and upload with upload tool ${upload.tool}\n" + + "\t${tools.${upload.tool}.upload.pattern}\n" + "\n" + "uploadWithoutBuild: \n" + + "\t@echo trying to upload without build with upload tool ${upload.tool}\n" + + "\t${tools.${upload.tool}.upload.pattern}\n" + " \n" + "uploadWithProgrammerWithBuild: all\n" + + "\t@echo trying to build and upload with programmer ${program.tool}\n" + + "\t${tools.${program.tool}.program.pattern}\n" + "\n" + "uploadWithProgrammerWithoutBuild: \n" + + "\t@echo trying to upload with programmer ${program.tool} without build\n" + + "\t${tools.${program.tool}.program.pattern}\n\n"); + buffer.append(getMakeMacros()); + buffer.append(getMakeRules()); + buffer.append(getMakeFinalTargets("", "")); + + IFile fileHandle = project.getFile(config.getName() + '/' + MAKEFILE_NAME); + save(buffer, fileHandle); + } + + private StringBuffer getMakeIncludeSubDirs() { + StringBuffer buffer = new StringBuffer(); + + for (IContainer subDir : myFoldersToBuild) { + String includeFile = subDir.getProjectRelativePath().append(MODFILE_NAME).toOSString(); + buffer.append("-include " + includeFile).append(NEWLINE); + } + buffer.append("-include sources.mk").append(NEWLINE); + buffer.append("-include objects.mk").append(NEWLINE).append(NEWLINE); + return buffer; + } + + private StringBuffer getMakeRMCommand() { + IConfiguration config = getConfig(); + StringBuffer buffer = new StringBuffer(); + buffer.append("-include " + ROOT + FILE_SEPARATOR + MAKEFILE_INIT).append(NEWLINE); + buffer.append(NEWLINE); + // Get the clean command from the build model + buffer.append("RM := "); + // support macros in the clean command + try { + String cleanCommand = ManagedBuildManager.getBuildMacroProvider().resolveValueToMakefileFormat( + config.getCleanCommand(), EMPTY_STRING, WHITESPACE, IBuildMacroProvider.CONTEXT_CONFIGURATION, + config); + buffer.append(cleanCommand).append(NEWLINE); + buffer.append(NEWLINE); + } catch (BuildMacroException e) { + // jaba is not going to write this code + } + + if (!myDependencyMacros.isEmpty()) { + buffer.append("ifneq ($(MAKECMDGOALS),clean)").append(NEWLINE); + for (String depsMacro : myDependencyMacros) { + buffer.append("ifneq ($(strip $(").append(depsMacro).append(")),)").append(NEWLINE); + buffer.append("-include $(").append(depsMacro).append(')').append(NEWLINE); + buffer.append("endif").append(NEWLINE); + } + buffer.append("endif").append(NEWLINE).append(NEWLINE); + } + // Include makefile.defs supplemental makefile + buffer.append("-include ").append(ROOT).append(FILE_SEPARATOR).append(MAKEFILE_DEFS).append(NEWLINE); + return (buffer.append(NEWLINE)); + } + + private String getPreBuildStep() { + IConfiguration config = getConfig(); + String prebuildStep = config.getPrebuildStep(); + // JABA issue927 adding recipe.hooks.sketch.prebuild.NUMBER.pattern as cdt + // prebuild command if needed + ICConfigurationDescription confDesc = ManagedBuildManager.getDescriptionForConfiguration(config); + String sketchPrebuild = io.sloeber.core.common.Common.getBuildEnvironmentVariable(confDesc, "sloeber.prebuild", + new String(), false); + if (!sketchPrebuild.isEmpty()) { + if (!prebuildStep.isEmpty()) { + prebuildStep = prebuildStep + "\n\t" + sketchPrebuild; + } else { + prebuildStep = sketchPrebuild; + } + } + // end off JABA issue927 + try { + // try to resolve the build macros in the prebuild step + prebuildStep = ManagedBuildManager.getBuildMacroProvider().resolveValueToMakefileFormat(prebuildStep, + EMPTY_STRING, WHITESPACE, IBuildMacroProvider.CONTEXT_CONFIGURATION, config); + } catch (BuildMacroException e) { + /* JABA is not going to write this code */ + } + return prebuildStep.trim(); + } + + private StringBuffer getMakeIncludeDependencies() { + + // JABA add the arduino upload/program targets + StringBuffer buffer = new StringBuffer(); + + String defaultTarget = "all:"; + String prebuildStep = getPreBuildStep(); + if (prebuildStep.length() > 0) { + // Add the comment for the "All" target + buffer.append(COMMENT_START).append(MESSAGE_ALL_TARGET).append(NEWLINE); + buffer.append(defaultTarget).append(NEWLINE); + buffer.append(TAB).append(MAKE).append(WHITESPACE).append(NO_PRINT_DIR).append(WHITESPACE).append(PREBUILD) + .append(NEWLINE); + buffer.append(TAB).append(MAKE).append(WHITESPACE).append(NO_PRINT_DIR).append(WHITESPACE).append(MAINBUILD) + .append(NEWLINE); + buffer.append(NEWLINE); + // defaultTarget = MAINBUILD.concat(COLON); + buffer.append(COMMENT_SYMBOL).append(WHITESPACE).append(MESSAGE_MAINBUILD_TARGET).append(NEWLINE); + + } else { + // Add the comment for the "All" target + buffer.append(COMMENT_START).append(MESSAGE_ALL_TARGET).append(NEWLINE); + } + return buffer; + } + + private StringBuffer getMakeTopTargets() { + IConfiguration config = getConfig(); + IPath buildFolder = getBuildFolder(); + + StringBuffer buffer = new StringBuffer(); + + ITool targetTool = config.calculateTargetTool(); + buffer.append("all:").append(WHITESPACE); + if (targetTool != null) { + Set allTargets = myMakeRules.getTargetsForTool(targetTool); + for (IFile curTarget : allTargets) { + String targetString = GetNiceFileName(buildFolder, curTarget.getLocation()).toOSString(); + buffer.append(ensurePathIsGNUMakeTargetRuleCompatibleSyntax(targetString)); + buffer.append(WHITESPACE); + } + } + + // Add the Secondary Outputs to the all target, if any + IOutputType[] secondaryOutputs = config.getToolChain().getSecondaryOutputs(); + if (secondaryOutputs.length > 0) { + buffer.append(WHITESPACE).append(SECONDARY_OUTPUTS); + } + buffer.append(NEWLINE).append(NEWLINE); + + String prebuildStep = getPreBuildStep(); + if (prebuildStep.length() > 0) { + + String preannouncebuildStep = config.getPreannouncebuildStep(); + buffer.append(PREBUILD).append(COLON).append(NEWLINE); + if (preannouncebuildStep.length() > 0) { + buffer.append(TAB).append(DASH).append(AT).append(escapedEcho(preannouncebuildStep)); + } + buffer.append(TAB).append(DASH).append(prebuildStep).append(NEWLINE); + buffer.append(TAB).append(DASH).append(AT).append(ECHO_BLANK_LINE).append(NEWLINE); + } + + String postbuildStep = config.getPostbuildStep(); + try { + // try to resolve the build macros in the postbuild step + postbuildStep = ManagedBuildManager.getBuildMacroProvider().resolveValueToMakefileFormat(postbuildStep, + EMPTY_STRING, WHITESPACE, IBuildMacroProvider.CONTEXT_CONFIGURATION, config); + } catch (BuildMacroException e) { + /* JABA is not going to write this code */ + } + postbuildStep = postbuildStep.trim(); + // Add the postbuild step, if specified + if (postbuildStep.length() > 0) { + String postannouncebuildStep = config.getPostannouncebuildStep(); + buffer.append(POSTBUILD).append(COLON).append(NEWLINE); + if (postannouncebuildStep.length() > 0) { + buffer.append(TAB).append(DASH).append(AT).append(escapedEcho(postannouncebuildStep)); + } + buffer.append(TAB).append(DASH).append(postbuildStep).append(NEWLINE); + buffer.append(TAB).append(DASH).append(AT).append(ECHO_BLANK_LINE).append(NEWLINE); + } + + return buffer; + } + + private StringBuffer getMakeFinalTargets(String prebuildStep, String postbuildStep) { + StringBuffer buffer = new StringBuffer(); + buffer.append(NEWLINE).append(NEWLINE); + + // Add all the needed dummy and phony targets + buffer.append(".PHONY: all clean dependents"); + if (prebuildStep.length() > 0) { + buffer.append(WHITESPACE).append(MAINBUILD).append(WHITESPACE).append(PREBUILD); + } + if (postbuildStep.length() > 0) { + buffer.append(WHITESPACE).append(POSTBUILD); + } + + buffer.append(NEWLINE); + // Include makefile.targets supplemental makefile + buffer.append("-include ").append(ROOT).append(FILE_SEPARATOR).append(MAKEFILE_TARGETS).append(NEWLINE); + return buffer; + } + + // Get the rules for the generated files + private MakeRules getMakeRulesFromGeneratedFiles(Map> generatedFiles) { + MakeRules makeRules = new MakeRules(); + IConfiguration config = getConfig(); + IProject project = getProject(); + IPath buildPath = getBuildFolder(); + + // Visit the resources in this set + for (Entry> entry : generatedFiles.entrySet()) { + IOutputType outputTypeIn = entry.getKey(); + Set files = entry.getValue(); + String macroName = outputTypeIn.getBuildVariable(); + for (ITool tool : config.getTools()) { + for (IInputType inputType : tool.getInputTypes()) { + if (!macroName.equals(inputType.getBuildVariable())) { + continue; + } + if (inputType.getMultipleOfType()) { + for (IOutputType outputType : tool.getOutputTypes()) { + INewManagedOutputNameProvider nameProvider = getJABANameProvider(config, buildPath, + outputType); + if (nameProvider == null) { + continue; + } + IPath outputFile = nameProvider.getOutputName(project, config, null, null); + if (outputFile != null) { + // This is a multiple to 1 based on var name + IFile correctOutputFile = getProject() + .getFile(new Path(config.getName()).append(outputFile)); + makeRules.addRule(tool, inputType, macroName, files, outputType, correctOutputFile); + + continue; + } + IPath firstFilePath = files.toArray(new IFile[files.size()])[0].getProjectRelativePath(); + outputFile = nameProvider.getOutputName(project, config, tool, firstFilePath); + if (outputFile == null) { + continue; + } + // This is a multiple to 1 not based on var name + IPath correctOutputPath = new Path(config.getName()).append(outputFile); + MakeRule newMakeRule = new MakeRule(caller, tool, inputType, files, outputType, + project.getFile(correctOutputPath)); + + makeRules.addRule(newMakeRule); + } + } else { + // The link is based on the varname but the files are one on one + for (IOutputType outputType : tool.getOutputTypes()) { + INewManagedOutputNameProvider nameProvider = getJABANameProvider(config, buildPath, + outputType); + if (nameProvider == null) { + continue; + } + for (IFile file : files) { + IPath outputFile = nameProvider.getOutputName(project, config, tool, + file.getProjectRelativePath()); + if (outputFile == null) { + continue; + } + // This is a multiple to 1 not based on var name + IPath correctOutputPath = new Path(config.getName()).append(outputFile); + MakeRule newMakeRule = new MakeRule(tool, inputType, file, outputType, + project.getFile(correctOutputPath)); + newMakeRule.addDependencies(caller); + makeRules.addRule(newMakeRule); + } + } + } + } + // else { + // for (IOutputType outputType : tool.getOutputTypes()) { + // IManagedOutputNameProviderJaba nameProvider = + // getJABANameProvider(outputType); + // if (nameProvider == null) { + // continue; + // } + // for (IFile file : files) { + // IPath outputFile = nameProvider.getOutputName(getProject(), config, tool, + // file.getProjectRelativePath()); + // if (outputFile != null) { + // //We found a tool that provides a outputfile for our source file + // //TOFIX if this is a multiple to one we should only create one MakeRule + // IPath correctOutputPath = new Path(config.getName()).append(outputFile); + // MakeRule newMakeRule = new MakeRule(caller, tool, inputType, file, + // outputType, + // project.getFile(correctOutputPath)); + // + // makeRules.add(newMakeRule); + // } + // } + // } + // } + // } + } + } + return makeRules; + } + + private StringBuffer getMakeMacros() { + StringBuffer buffer = new StringBuffer(); + IFile buildRoot = caller.getTopBuildDir(); + buffer.append(NEWLINE); + buffer.append(COMMENT_START).append(MESSAGE_MOD_VARS).append(NEWLINE); + + for (String macroName : myMakeRules.getMacroNames()) { + Set files = myMakeRules.getMacroElements(macroName); + if (files.size() > 0) { + buffer.append(macroName).append(MAKE_ADDITION); + for (IFile file : files) { + if (files.size() != 1) { + buffer.append(LINEBREAK); + } + buffer.append(GetNiceFileName(buildRoot, file)).append(WHITESPACE); + } + buffer.append(NEWLINE); + buffer.append(NEWLINE); + } + } + return buffer; + } + + private StringBuffer getMakeRules() { + StringBuffer buffer = new StringBuffer(); + IProject project = getProject(); + IConfiguration config = getConfig(); + IFile topBuildDir = caller.getTopBuildDir(); + buffer.append(NEWLINE); + buffer.append(COMMENT_START).append(MESSAGE_MOD_RULES).append(NEWLINE); + + for (MakeRule makeRule : myMakeRules.getMakeRules()) { + buffer.append(makeRule.getRule(project, topBuildDir, config)); + } + return buffer; + } + +} diff --git a/io.sloeber.ManagedBuild/src/io/sloeber/managedBuild/api/AbstractBuildRunner.java b/io.sloeber.ManagedBuild/src/io/sloeber/managedBuild/api/AbstractBuildRunner.java new file mode 100644 index 000000000..d48199c74 --- /dev/null +++ b/io.sloeber.ManagedBuild/src/io/sloeber/managedBuild/api/AbstractBuildRunner.java @@ -0,0 +1,48 @@ +/******************************************************************************* + * Copyright (c) 2010, 2012 Wind River Systems and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Wind River Systems - Initial API and implementation + * James Blackburn (Broadcom Corp.) + *******************************************************************************/ +package io.sloeber.managedBuild.api; + +import org.eclipse.cdt.core.IMarkerGenerator; +import org.eclipse.cdt.core.resources.IConsole; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.IncrementalProjectBuilder; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IProgressMonitor; + +/** + * Interface implemented by toolchain integrators to perform the actual build. + * + * @author Doug Schaefer + * @since 8.0 + */ +public abstract class AbstractBuildRunner { + + /** + * Perform the build. + * + * @param kind - kind from the IncrementalProjectBuilder + * @param project - project being built + * @param configuration - configuration being built + * @param console - console to use for build output + * @param markerGenerator - generator to add markers for build problems + * @param monitor - progress monitor in the initial state where {@link IProgressMonitor#beginTask(String, int)} + * has not been called yet. + * @throws CoreException standard core exception if something goes wrong + */ + public abstract boolean invokeBuild(int kind, IProject project, IConfiguration configuration, IBuilder builder, + IConsole console, IMarkerGenerator markerGenerator, IncrementalProjectBuilder projectBuilder, + IProgressMonitor monitor) throws CoreException; + +} diff --git a/io.sloeber.ManagedBuild/src/io/sloeber/managedBuild/api/BuildException.java b/io.sloeber.ManagedBuild/src/io/sloeber/managedBuild/api/BuildException.java new file mode 100644 index 000000000..dd199577b --- /dev/null +++ b/io.sloeber.ManagedBuild/src/io/sloeber/managedBuild/api/BuildException.java @@ -0,0 +1,27 @@ +/******************************************************************************* + * Copyright (c) 2003, 2010 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM - Initial API and implementation + *******************************************************************************/ +package io.sloeber.managedBuild.api; + +/** + * @noextend This class is not intended to be subclassed by clients. + */ +public class BuildException extends Exception { + + public static final int BUILD_FAILED = -1; + + public BuildException(String msg) { + super(msg); + } + +} diff --git a/io.sloeber.ManagedBuild/src/io/sloeber/managedBuild/api/IAdditionalInput.java b/io.sloeber.ManagedBuild/src/io/sloeber/managedBuild/api/IAdditionalInput.java new file mode 100644 index 000000000..ed9176946 --- /dev/null +++ b/io.sloeber.ManagedBuild/src/io/sloeber/managedBuild/api/IAdditionalInput.java @@ -0,0 +1,90 @@ +/******************************************************************************* + * Copyright (c) 2005, 2010 Intel Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Intel Corporation - Initial API and implementation + *******************************************************************************/ +package io.sloeber.managedBuild.api; + +/** + * This interface represents an additionalInput instance in the managed build system. + * This element is only present if the user or a tool integrator needs to define + * additional inputs or dependencies to a tool. An inputType element can have + * multiple additionalInput children. + * + * @since 3.0 + * @noextend This class is not intended to be subclassed by clients. + * @noimplement This interface is not intended to be implemented by clients. + */ +public interface IAdditionalInput { + + // Schema attribute names for additionalInput elements + public static final String ADDITIONAL_INPUT_ELEMENT_NAME = "additionalInput"; //$NON-NLS-1$ + public static final String PATHS = "paths"; //$NON-NLS-1$ + public static final String KIND = "kind"; //$NON-NLS-1$ + public static final String ADDITIONAL_DEPENDENCY = "additionaldependency"; //$NON-NLS-1$ + public static final int KIND_ADDITIONAL_DEPENDENCY = 1; + public static final String ADDITIONAL_INPUT = "additionalinput"; //$NON-NLS-1$ + public static final int KIND_ADDITIONAL_INPUT = 2; + public static final String ADDITIONAL_INPUT_DEPENDENCY = "additionalinputdependency"; //$NON-NLS-1$ + public static final int KIND_ADDITIONAL_INPUT_DEPENDENCY = 3; + + /** + * Returns the InputType parent of this AdditionalInput. + * + * @return IInputType + */ + public IInputType getParent(); + + /** + * Returns an array of the relative or absolute paths of the resources + * to which this element applies. + * The resources must be a member of the project, the output from another tool in the + * tool-chain, or an external file. The file name of the path can use GNU Make pattern + * rule syntax (in order to generate the name from the input file name). + * + * @return String[] + */ + public String[] getPaths(); + + /** + * Sets semicolon separated list of the relative or absolute paths of the resources to + * which this element applies. + */ + public void setPaths(String paths); + + /** + * Returns the kind of additional input. The valid values are: + * KIND_ADDITIONAL_DEPENDENCY - added as a tool dependency, but not to the command line. + * KIND_ADDITIONAL_INPUT - added as an additional input to the command line, but not as a dependency. + * KIND_ADDITIONAL_INPUT_DEPENDENCY - added as both. + * The default is KIND_ADDITIONAL_INPUT_DEPENDENCY + */ + public int getKind(); + + /** + * Sets the kind of additional input. + */ + public void setKind(int kind); + + /** + * Returns true if this element has changes that need to + * be saved in the project file, else false. + * + * @return boolean + */ + public boolean isDirty(); + + /** + * Sets the element's "dirty" (have I been modified?) flag. + */ + public void setDirty(boolean isDirty); + +} diff --git a/io.sloeber.ManagedBuild/src/io/sloeber/managedBuild/api/IBuildObject.java b/io.sloeber.ManagedBuild/src/io/sloeber/managedBuild/api/IBuildObject.java new file mode 100644 index 000000000..3c8690b29 --- /dev/null +++ b/io.sloeber.ManagedBuild/src/io/sloeber/managedBuild/api/IBuildObject.java @@ -0,0 +1,43 @@ +/******************************************************************************* + * Copyright (c) 2003, 2010 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM - Initial API and implementation + *******************************************************************************/ +package io.sloeber.managedBuild.api; + +// import org.osgi.framework.Version; + +/** + * @noextend This class is not intended to be subclassed by clients. + * @noimplement This interface is not intended to be implemented by clients. + */ +public interface IBuildObject { + // Schema element names + public static final String ID = "id"; //$NON-NLS-1$ + public static final String NAME = "name"; //$NON-NLS-1$ + + public String getId(); + + public String getName(); + + /** + * @return id of the object this class was based on during creation or id of the object itself. + */ + public String getBaseId(); + + /** @since 8.0 */ + //public Version getVersion(); + + /** @since 8.0 */ + //public void setVersion(Version version); + + public String getManagedBuildRevision(); +} diff --git a/io.sloeber.ManagedBuild/src/io/sloeber/managedBuild/api/IBuildPathResolver.java b/io.sloeber.ManagedBuild/src/io/sloeber/managedBuild/api/IBuildPathResolver.java new file mode 100644 index 000000000..673211574 --- /dev/null +++ b/io.sloeber.ManagedBuild/src/io/sloeber/managedBuild/api/IBuildPathResolver.java @@ -0,0 +1,34 @@ +/******************************************************************************* + * Copyright (c) 2005, 2012 Intel Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Intel Corporation - Initial API and implementation + *******************************************************************************/ +package io.sloeber.managedBuild.api; + +/** + * This interface is to be implemented by the tool-integrator to provide some specific + * logic for resolving the build path variable values to the build paths. + *

+ * See extension point {@code org.eclipse.cdt.managedbuilder.core.buildDefinitions}, + * element {@code envVarBuildPath} attribute {@code buildPathResolver}. + * + * @since 3.0 + */ +public interface IBuildPathResolver { + /** + * @param pathType one of the IEnvVarBuildPath.BUILDPATH _xxx + * @param variableName represents the name of the variable that holds the build paths + * @param variableValue represents the value of the value specified with the + * variableName argument + * @param configuration represents configuration for which the build paths are requested + */ + String[] resolveBuildPaths(int pathType, String variableName, String variableValue, IConfiguration configuration); +} diff --git a/io.sloeber.ManagedBuild/src/io/sloeber/managedBuild/api/IBuilder.java b/io.sloeber.ManagedBuild/src/io/sloeber/managedBuild/api/IBuilder.java new file mode 100644 index 000000000..c2e86c534 --- /dev/null +++ b/io.sloeber.ManagedBuild/src/io/sloeber/managedBuild/api/IBuilder.java @@ -0,0 +1,316 @@ +/******************************************************************************* + * Copyright (c) 2004, 2011 Intel Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Intel Corporation - Initial API and implementation + * James Blackburn (Broadcom Corp.) + *******************************************************************************/ +package io.sloeber.managedBuild.api; + +import org.eclipse.cdt.core.ICommandLauncher; +import org.eclipse.cdt.core.settings.model.extension.CBuildData; +import org.eclipse.cdt.managedbuilder.macros.IFileContextBuildMacroValues; +import org.eclipse.cdt.managedbuilder.macros.IReservedMacroNameSupplier; +import org.eclipse.cdt.managedbuilder.makegen.IManagedBuilderMakefileGenerator; +import org.eclipse.cdt.newmake.core.IMakeBuilderInfo; +import org.eclipse.core.runtime.CoreException; + +/** + * This class represents the utility that drives the build process + * (typically, but not necessarily, a variant of "make"). It defines + * the command needed to invoke the build utility in the command attribute. + * Any special flags that need to be passed to the builder are defined + * in the arguments attribute. The builder can specify the error parser(s) + * to be used to parse its output. The builder also specifies a Java class + * that generates the build file. + * + * @since 2.1 + * @noextend This class is not intended to be subclassed by clients. + * @noimplement This interface is not intended to be implemented by clients. + */ +public interface IBuilder extends IHoldsOptions, IMakeBuilderInfo { + public static final String ARGUMENTS = "arguments"; //$NON-NLS-1$ + public static final String BUILDER_ELEMENT_NAME = "builder"; //$NON-NLS-1$ + public static final String BUILDFILEGEN_ID = "buildfileGenerator"; //$NON-NLS-1$ + public static final String COMMAND = "command"; //$NON-NLS-1$ + + public static final String VERSIONS_SUPPORTED = "versionsSupported"; //$NON-NLS-1$ + public static final String CONVERT_TO_ID = "convertToId"; //$NON-NLS-1$ + + public static final String VARIABLE_FORMAT = "variableFormat"; //$NON-NLS-1$ + public static final String RESERVED_MACRO_NAMES = "reservedMacroNames"; //$NON-NLS-1$ + public static final String RESERVED_MACRO_NAME_SUPPLIER = "reservedMacroNameSupplier"; //$NON-NLS-1$ + public static final String IS_SYSTEM = "isSystem"; //$NON-NLS-1$ + + // static final String BUILD_COMMAND = "buildCommand"; //$NON-NLS-1$ + static final String ATTRIBUTE_BUILD_PATH = "buildPath"; //$NON-NLS-1$ + // static final String USE_DEFAULT_BUILD_CMD = "useDefaultBuildCmd"; //$NON-NLS-1$ + static final String ATTRIBUTE_TARGET_AUTO = "autoBuildTarget"; //$NON-NLS-1$ + static final String ATTRIBUTE_TARGET_INCREMENTAL = "incrementalBuildTarget"; //$NON-NLS-1$ + // static final String BUILD_TARGET_FULL = "fullBuildTarget"; //$NON-NLS-1$ + static final String ATTRIBUTE_TARGET_CLEAN = "cleanBuildTarget"; //$NON-NLS-1$ + // static final String BUILD_FULL_ENABLED = "enableFullBuild"; //$NON-NLS-1$ + static final String ATTRIBUTE_CLEAN_ENABLED = "enableCleanBuild"; //$NON-NLS-1$ + static final String ATTRIBUTE_INCREMENTAL_ENABLED = "enabledIncrementalBuild"; //$NON-NLS-1$ + static final String ATTRIBUTE_AUTO_ENABLED = "enableAutoBuild"; //$NON-NLS-1$ + // static final String BUILD_ARGUMENTS = "buildArguments"; //$NON-NLS-1$ + static final String ATTRIBUTE_ENVIRONMENT = "environment"; //$NON-NLS-1$ + static final String ATTRIBUTE_APPEND_ENVIRONMENT = "appendEnvironment"; //$NON-NLS-1$ + // public final static String BUILD_TARGET_INCREMENTAL = "build.target.inc"; //$NON-NLS-1$ + // public final static String BUILD_TARGET_AUTO = "build.target.auto"; //$NON-NLS-1$ + // public final static String BUILD_TARGET_CLEAN = "build.target.clean"; //$NON-NLS-1$ + // public final static String BUILD_LOCATION = "build.location"; //$NON-NLS-1$ + // public final static String BUILD_COMMAND = "build.command"; //$NON-NLS-1$ + // public final static String BUILD_ARGUMENTS = "build.arguments"; //$NON-NLS-1$ + + static final String ATTRIBUTE_MANAGED_BUILD_ON = "managedBuildOn"; //$NON-NLS-1$ + static final String ATTRIBUTE_KEEP_ENV = "keepEnvironmentInBuildfile"; //$NON-NLS-1$ + static final String ATTRIBUTE_SUPORTS_MANAGED_BUILD = "supportsManagedBuild"; //$NON-NLS-1$ + + static final String ATTRIBUTE_CUSTOMIZED_ERROR_PARSERS = "customizedErrorParsers"; //$NON-NLS-1$ + static final String ATTRIBUTE_CUSTOM_PROPS = "customBuilderProperties"; //$NON-NLS-1$ + + static final String ATTRIBUTE_IGNORE_ERR_CMD = "ignoreErrCmd"; //$NON-NLS-1$ + static final String ATTRIBUTE_STOP_ON_ERR = "stopOnErr"; //$NON-NLS-1$ + + static final String ATTRIBUTE_PARALLEL_BUILD_CMD = "parallelBuildCmd"; //$NON-NLS-1$ + static final String ATTRIBUTE_PARALLEL_BUILD_ON = "parallelBuildOn"; //$NON-NLS-1$ + static final String ATTRIBUTE_PARALLELIZATION_NUMBER = "parallelizationNumber"; //$NON-NLS-1$ + /** @since 8.1 */ + static final String VALUE_OPTIMAL = "optimal"; //$NON-NLS-1$ + /** @since 8.1 */ + static final String VALUE_UNLIMITED = "unlimited"; //$NON-NLS-1$ + static final String PARALLEL_PATTERN_NUM = "*"; //$NON-NLS-1$ + static final String PARALLEL_PATTERN_NUM_START = "["; //$NON-NLS-1$ + static final String PARALLEL_PATTERN_NUM_END = "]"; //$NON-NLS-1$ + + static final String OUTPUT_ENTRIES = "outputEntries"; //$NON-NLS-1$ + + static final String DEFAULT_TARGET_INCREMENTAL = "all"; //$NON-NLS-1$ + static final String DEFAULT_TARGET_CLEAN = "clean"; //$NON-NLS-1$ + static final String DEFAULT_TARGET_AUTO = "all"; //$NON-NLS-1$ + /** @since 6.0 */ + static final String ATTRIBUTE_COMMAND_LAUNCHER = "commandLauncher"; //$NON-NLS-1$ + /** @since 8.0 */ + static final String ATTRIBUTE_BUILD_RUNNER = "buildRunner"; //$NON-NLS-1$ + + /** + * Returns the command line arguments to pass to the build/make utility used + * to build a configuration. + * + * @return String + */ + public String getArguments(); + + + + /** + * Returns the BuildfileGenerator used to generate buildfiles for this builder + * + * @return IManagedBuilderMakefileGenerator + */ + IManagedBuilderMakefileGenerator getBuildFileGenerator(); + + /** + * Returns the name of the build/make utility for the configuration. + * + * @return String + */ + public String getCommand(); + + /** + * Returns the semicolon separated list of unique IDs of the error parsers associated + * with the builder. + * + * @return String + */ + public String getErrorParserIds(); + + /** + * Returns the ordered list of unique IDs of the error parsers associated with the + * builder. + * + * @return String[] + */ + public String[] getErrorParserList(); + + /** + * Returns the tool-chain that is the parent of this builder. + * + * @return IToolChain + */ + public IToolChain getParent(); + + /** + * Returns the IBuilder that is the superclass of this + * target platform, or null if the attribute was not specified. + * + * @return IBuilder + */ + public IBuilder getSuperClass(); + + /** + * Returns a semi-colon delimited list of child Ids of the superclass' + * children that should not be automatically inherited by this element. + * Returns an empty string if the attribute was not specified. + * @return String + */ + public String getUnusedChildren(); + + /** + * Returns whether this element is abstract. Returns false + * if the attribute was not specified. + * + * @return boolean + */ + public boolean isAbstract(); + + /** + * Returns true if this element has changes that need to + * be saved in the project file, else false. + * + * @return boolean + */ + public boolean isDirty(); + + /** + * Returns true if this builder was loaded from a manifest file, + * and false if it was loaded from a project (.cdtbuild) file. + * + * @return boolean + */ + public boolean isExtensionElement(); + + /** + * Sets the arguments to be passed to the build utility used by the + * receiver to produce a build goal. + */ + public void setArguments(String makeArgs); + + + + /** + * Sets the build command for the receiver to the value in the argument. + */ + public void setCommand(String command); + + /** + * Sets the element's "dirty" (have I been modified?) flag. + */ + public void setDirty(boolean isDirty); + + /** + * Sets the semicolon separated list of error parser ids + */ + public void setErrorParserIds(String ids); + + /** + * Sets the isAbstract attribute of the builder. + */ + public void setIsAbstract(boolean b); + + /** + * Returns the 'versionsSupported' of this builder + * + * @return String + */ + + public String getVersionsSupported(); + + /** + * Returns the 'convertToId' of this builder + * + * @return String + */ + + public String getConvertToId(); + + /** + * Sets the 'versionsSupported' attribute of the builder. + */ + + public void setVersionsSupported(String versionsSupported); + + /** + * Sets the 'convertToId' attribute of the builder. + */ + public void setConvertToId(String convertToId); + + /** + * Returns the IFileContextBuildMacroValues interface reference that specifies + * the file-context macro-values provided by the tool-integrator + * + * @return IFileContextBuildMacroValues + */ + public IFileContextBuildMacroValues getFileContextBuildMacroValues(); + + /** + * Returns String representing the build variable pattern to be used while makefile generation + * + * @return String + */ + public String getBuilderVariablePattern(); + + /** + * Returns an array of Strings representing the patterns of the builder/buildfile-generator + * reserved variables + * + * @return String[] + */ + public String[] getReservedMacroNames(); + + /** + * Returns the tool-integrator defined implementation of the IReservedMacroNameSupplier + * to be used for detecting the builder/buildfile-generator reserved variables + * @return IReservedMacroNameSupplier + */ + public IReservedMacroNameSupplier getReservedMacroNameSupplier(); + + public CBuildData getBuildData(); + + public boolean isCustomBuilder(); + + public boolean supportsCustomizedBuild(); + + public boolean keepEnvironmentVariablesInBuildfile(); + + public void setKeepEnvironmentVariablesInBuildfile(boolean keep); + + public boolean canKeepEnvironmentVariablesInBuildfile(); + + void setBuildPath(String path); + + String getBuildPath(); + + boolean isInternalBuilder(); + + boolean matches(IBuilder builder); + + boolean isSystemObject(); + + String getUniqueRealName(); + + /** + * Returns the ICommandLauncher which should be used to launch the builder command. + * + * @return ICommandLauncher + * @since 6.0 + */ + public ICommandLauncher getCommandLauncher(); + + /** + * Returns the build runner for this builder. + * + * @return build runner + * @since 8.0 + */ + public AbstractBuildRunner getBuildRunner() throws CoreException; + +} diff --git a/io.sloeber.ManagedBuild/src/io/sloeber/managedBuild/api/IConfiguration.java b/io.sloeber.ManagedBuild/src/io/sloeber/managedBuild/api/IConfiguration.java new file mode 100644 index 000000000..8f654a4bd --- /dev/null +++ b/io.sloeber.ManagedBuild/src/io/sloeber/managedBuild/api/IConfiguration.java @@ -0,0 +1,616 @@ +/******************************************************************************* + * Copyright (c) 2003, 2012 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM - Initial API and implementation + * Dmitry Kozlov (CodeSourcery) - Save build output preferences (bug 294106) + * Andrew Gvozdev (Quoin Inc) - Saving build output implemented in different way (bug 306222) + *******************************************************************************/ +package io.sloeber.managedBuild.api; + +import org.eclipse.cdt.core.settings.model.ICSourceEntry; +import org.eclipse.cdt.core.settings.model.extension.CBuildData; +import org.eclipse.cdt.core.settings.model.extension.CConfigurationData; +import org.eclipse.cdt.managedbuilder.buildproperties.IBuildPropertyValue; +//import org.eclipse.cdt.managedbuilder.core.IFileInfo; +//import org.eclipse.cdt.managedbuilder.core.IFolderInfo; +import org.eclipse.cdt.managedbuilder.envvar.IConfigurationEnvironmentVariableSupplier; +import org.eclipse.cdt.managedbuilder.macros.IConfigurationBuildMacroSupplier; +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.runtime.IPath; + +/** + * A tool-integrator defines default configurations as children of the project type. + * These provide a template for the configurations added to the user's project, + * which are stored in the project's .cproject file. + *

+ * The configuration contains one child of type tool-chain. This describes how the + * project's resources are transformed into the build artifact. The configuration can + * contain one or more children of type resourceConfiguration. These describe build + * settings of individual resources that are different from the configuration as a whole. + * + * @since 2.1 + * @noextend This class is not intended to be subclassed by clients. + * @noimplement This interface is not intended to be implemented by clients. + */ +public interface IConfiguration + extends IBuildObject, IBuildObjectPropertiesContainer, IOptionalBuildObjectPropertiesContainer { + public static final String ARTIFACT_NAME = "artifactName"; //$NON-NLS-1$ + public static final String CLEAN_COMMAND = "cleanCommand"; //$NON-NLS-1$ + public static final String PREBUILD_STEP = "prebuildStep"; //$NON-NLS-1$ + public static final String POSTBUILD_STEP = "postbuildStep"; //$NON-NLS-1$ + public static final String PREANNOUNCEBUILD_STEP = "preannouncebuildStep"; //$NON-NLS-1$ + public static final String POSTANNOUNCEBUILD_STEP = "postannouncebuildStep"; //$NON-NLS-1$ + // Schema element names + public static final String CONFIGURATION_ELEMENT_NAME = "configuration"; //$NON-NLS-1$ + public static final String ERROR_PARSERS = "errorParsers"; //$NON-NLS-1$ + /** @since 8.1 */ + public static final String LANGUAGE_SETTINGS_PROVIDERS = "languageSettingsProviders"; //$NON-NLS-1$ + public static final String EXTENSION = "artifactExtension"; //$NON-NLS-1$ + public static final String PARENT = "parent"; //$NON-NLS-1$ + + public static final String DESCRIPTION = "description"; //$NON-NLS-1$ + + public static final String BUILD_PROPERTIES = "buildProperties"; //$NON-NLS-1$ + /** + * @since 8.6 + */ + public static final String OPTIONAL_BUILD_PROPERTIES = "optionalBuildProperties"; //$NON-NLS-1$ + public static final String BUILD_ARTEFACT_TYPE = "buildArtefactType"; //$NON-NLS-1$ + public static final String IS_SYSTEM = "isSystem"; //$NON-NLS-1$ + + public static final String SOURCE_ENTRIES = "sourceEntries"; //$NON-NLS-1$ + + /** + * Returns the description of the configuration. + * + * @return String + */ + public String getDescription(); + + /** + * Sets the description of the receiver to the value specified in the argument + */ + public void setDescription(String description); + + /** + * Creates a child resource configuration corresponding to the passed in file. + */ + public IResourceConfiguration createResourceConfiguration(IFile file); + + /** + * Creates the IToolChain child of this configuration. + * + * @param superClass - The superClass, if any + * @param Id - The id for the new tool chain + * @param name - The name for the new tool chain + * @param isExtensionElement - set {@code true} if the toolchain being created + * represents extension point toolchain + * + * @return IToolChain + */ + public IToolChain createToolChain(IToolChain superClass, String Id, String name, boolean isExtensionElement); + + /** + * Returns the extension that should be applied to build artifacts created by + * this configuration. + * + * @return String + */ + public String getArtifactExtension(); + + /** + * Returns the name of the final build artifact. + * + * @return String + */ + public String getArtifactName(); + + /** + * Returns the build arguments from this configuration's builder + * + * @return String + */ + public String getBuildArguments(); + + /** + * Returns the build command from this configuration's builder + * + * @return String + */ + public String getBuildCommand(); + + /** + * Returns the prebuild step command + * + * @return String + */ + public String getPrebuildStep(); + + /** + * Returns the postbuild step command + * + * @return String + */ + public String getPostbuildStep(); + + /** + * Returns the display string associated with the prebuild step + * + * @return String + */ + public String getPreannouncebuildStep(); + + /** + * Returns the display string associated with the postbuild step + * + * @return String + */ + public String getPostannouncebuildStep(); + + /** + * Answers the OS-specific command to remove files created by the build + * of this configuration. + * + * @return String + */ + public String getCleanCommand(); + + /** + * Answers the semicolon separated list of unique IDs of the error parsers associated + * with this configuration. + * + * @return String + */ + public String getErrorParserIds(); + + /** + * Answers the ordered list of unique IDs of the error parsers associated + * with this configuration. + * + * @return String[] + */ + public String[] getErrorParserList(); + + /** + * Returns default language settings providers IDs specified for the configuration. + * @return default language settings providers IDs or {@code null}. + * + * @since 8.1 + */ + public String[] getDefaultLanguageSettingsProviderIds(); + + /** + * Projects have C or CC natures. Tools can specify a filter so they are not + * misapplied to a project. This method allows the caller to retrieve a list + * of tools from a project that are correct for a project's nature. + * + * @return an array of ITools that have compatible filters + * for this configuration. + */ + ITool[] getFilteredTools(); + + /** + * Returns the managed-project parent of this configuration, if this is a + * project configuration. Otherwise, returns null. + * + * @return IManagedProject + */ + //public IManagedProject getManagedProject(); + + /** + * Returns the Eclipse project that owns the configuration. + * + * @return IResource + */ + public IResource getOwner(); + + /** + * Returns the configuration that this configuration is based on. + * + * @return IConfiguration + */ + public IConfiguration getParent(); + + /** + * Returns the project-type parent of this configuration, if this is an + * extension configuration. Otherwise, returns null. + * + * @return IProjectType + */ + //public IProjectType getProjectType(); + + /** + * @param path - path of the resource + * + * @return the resource configuration child of this configuration + * that is associated with the project resource, or null if none. + */ + public IResourceConfiguration getResourceConfiguration(String path); + + /** + * Returns the resource configuration children of this configuration. + * + * @return IResourceConfigurations[] + */ + public IResourceConfiguration[] getResourceConfigurations(); + + /** + * Returns the ITool in this configuration's tool-chain with + * the same id as the argument, or null. + * + * @param id unique identifier to search for + * @return ITool + */ + public ITool getTool(String id); + + /** + * Returns the ITool in this configuration's tool-chain with + * the specified ID, or the tool(s) with a superclass with this id. + * + *

If the tool-chain does not have a tool with that ID, the method + * returns an empty array. It is the responsibility of the caller to + * verify the return value. + * + * @param id unique identifier of the tool to search for + * @return ITool[] + * @since 3.0.2 + */ + public ITool[] getToolsBySuperClassId(String id); + + /** + * Returns the IToolChain child of this configuration. + * + * @return IToolChain + */ + public IToolChain getToolChain(); + + /** + * Returns the command-line invocation command for the specified tool. + * + * @param tool The tool that will have its command retrieved. + * @return String The command + */ + public String getToolCommand(ITool tool); + + /** + * Returns the tools that are used in this configuration's tool-chain. + * + * @return ITool[] + */ + public ITool[] getTools(); + + /** + * Returns the tool in this configuration specified with + * the toolChain#targetTool attribute that creates the build artifact + * + * NOTE: This method returns null in case the toolChain definition + * does not have the targetTool attribute or if the attribute does not + * refer to the appropriate tool. + * For the target tool calculation the IConfiguration#calculateTargetTool() + * method should be used + * + * @see IConfiguration#calculateTargetTool() + * + * @return ITool + */ + public ITool getTargetTool(); + + /** + * Returns true if this configuration has overridden the default build + * build command in this configuration, otherwise false. + * + * @return boolean + */ + public boolean hasOverriddenBuildCommand(); + + /** + * Returns true if the extension matches one of the special + * file extensions the tools for the configuration consider to be a header file. + * + * @param ext the file extension of the resource + * @return boolean + */ + public boolean isHeaderFile(String ext); + + /** + * Returns true if this configuration has changes that need to + * be saved in the project file, else false. + * Should not be called for an extension configuration. + * + * @return boolean + */ + public boolean isDirty(); + + /** + * Returns true if this configuration was loaded from a manifest file, + * and false if it was loaded from a project (.cdtbuild) file. + * + * @return boolean + */ + public boolean isExtensionElement(); + + /** + * Returns whether this configuration has been changed and requires the + * project to be rebuilt. + * + * @return true if the configuration contains a change + * that needs the project to be rebuilt. + * Should not be called for an extension configuration. + */ + public boolean needsRebuild(); + + /** + * Removes a resource configuration from the configuration's list. + * + * @param resConfig - resource configuration to remove + */ + //public void removeResourceConfiguration(IResourceInfo resConfig); + + public void removeResourceInfo(IPath path); + + /** + * Set (override) the extension that should be appended to the build artifact + * for the receiver. + */ + public void setArtifactExtension(String extension); + + /** + * Set the name of the artifact that will be produced when the receiver + * is built. + */ + public void setArtifactName(String name); + + /** + * Sets the arguments to be passed to the build utility used by the + * receiver to produce a build goal. + */ + public void setBuildArguments(String makeArgs); + + /** + * Sets the build command for the receiver to the value in the argument. + */ + public void setBuildCommand(String command); + + /** + * Sets the prebuild step for the receiver to the value in the argument. + */ + public void setPrebuildStep(String step); + + /** + * Sets the postbuild step for the receiver to the value in the argument. + */ + public void setPostbuildStep(String step); + + /** + * Sets the prebuild step display string for the receiver to the value in the argument. + */ + public void setPreannouncebuildStep(String announceStep); + + /** + * Sets the postbuild step display string for the receiver to the value in the argument. + */ + public void setPostannouncebuildStep(String announceStep); + + /** + * Sets the command used to clean the outputs of this configuration. + * @param command - the command to clean outputs + */ + public void setCleanCommand(String command); + + /** + * Sets the element's "dirty" (have I been modified?) flag. + */ + public void setDirty(boolean isDirty); + + /** + * Sets the semicolon separated list of error parser ids + */ + public void setErrorParserIds(String ids); + + public void setErrorParserList(String ids[]); + + /** + * Sets the name of the receiver to the value specified in the argument + */ + public void setName(String name); + + /** + * Sets the value of a boolean option for this configuration. + * + * @param parent The holder/parent of the option. + * @param option The option to change. + * @param value The value to apply to the option. + * + * @return IOption The modified option. This can be the same option or a newly created option. + * + * @since 3.0 - The type of parent has changed from ITool to IHoldsOptions. + * Code assuming ITool as type, will continue to work unchanged. + */ + public IOption setOption(IHoldsOptions parent, IOption option, boolean value) throws BuildException; + + /** + * Sets the value of a string option for this configuration. + * + * @param parent The holder/parent of the option. + * @param option The option that will be effected by change. + * @param value The value to apply to the option. + * + * @return IOption The modified option. This can be the same option or a newly created option. + * + * @since 3.0 - The type of parent has changed from ITool to IHoldsOptions. + * Code assuming ITool as type, will continue to work unchanged. + */ + public IOption setOption(IHoldsOptions parent, IOption option, String value) throws BuildException; + + /** + * Sets the value of a list option for this configuration. + * + * @param parent The holder/parent of the option. + * @param option The option to change. + * @param value The values to apply to the option. + * + * @return IOption The modified option. This can be the same option or a newly created option. + * + * @since 3.0 - The type of parent has changed from ITool to IHoldsOptions. + * Code assuming ITool as type, will continue to work unchanged. + */ + public IOption setOption(IHoldsOptions parent, IOption option, String[] value) throws BuildException; + + /** + * Sets the rebuild state in this configuration. + * + * @param rebuild true will force a rebuild the next time the project builds + * @see org.eclipse.cdt.managedbuilder.core.IManagedBuildInfo#setRebuildState(boolean) + */ + void setRebuildState(boolean rebuild); + + /** + * Overrides the tool command for a tool defined in this configuration's tool-chain. + * + * @param tool The tool that will have its command modified. + * @param command The command + */ + public void setToolCommand(ITool tool, String command); + + /** + * Returns true if the configuration's tool-chain is supported on the system + * otherwise returns false + * + * @return boolean + */ + public boolean isSupported(); + + /** + * Returns the implementation of the IConfigurationEnvironmentVariableSupplier provided + * by the tool-integrator or null if none. + * + * @return IConfigurationEnvironmentVariableSupplier + */ + public IConfigurationEnvironmentVariableSupplier getEnvironmentVariableSupplier(); + + /** + * Returns the tool-integrator provided implementation of the configuration build macro supplier + * or null if none. + * + * @return IConfigurationBuildMacroSupplier + */ + public IConfigurationBuildMacroSupplier getBuildMacroSupplier(); + + /** + * answers true if the configuration is temporary, otherwise - false + * @return boolean + */ + public boolean isTemporary(); + + /** + * Returns whether this configuration requires a full rebuild + * + * @return boolean + */ + public boolean needsFullRebuild(); + + /** + * Calculates the configuration target tool. + * + * @return ITool or null if not found + * + * @since 3.1 + */ + public ITool calculateTargetTool(); + + /** + * Returns a ITool for the tool associated with the + * output extension. + * + * @param extension the file extension of the output file + * @return ITool + * + * @since 3.1 + */ + public ITool getToolFromOutputExtension(String extension); + + /** + * Returns a ITool for the tool associated with the + * input extension. + * + * @param sourceExtension the file extension of the input file + * @return ITool + * + * @since 3.1 + */ + public ITool getToolFromInputExtension(String sourceExtension); + + IResourceInfo getResourceInfo(IPath path, boolean exactPath); + + IResourceInfo[] getResourceInfos(); + + IResourceInfo getResourceInfoById(String id); + + IFolderInfo getRootFolderInfo(); + + IFileInfo createFileInfo(IPath path); + + IFileInfo createFileInfo(IPath path, String id, String name); + + IFileInfo createFileInfo(IPath path, IFolderInfo base, ITool baseTool, String id, String name); + + IFileInfo createFileInfo(IPath path, IFileInfo base, String id, String name); + + IFolderInfo createFolderInfo(IPath path); + + IFolderInfo createFolderInfo(IPath path, String id, String name); + + IFolderInfo createFolderInfo(IPath path, IFolderInfo base, String id, String name); + + CConfigurationData getConfigurationData(); + + ICSourceEntry[] getSourceEntries(); + + void setSourceEntries(ICSourceEntry[] entries); + + CBuildData getBuildData(); + + IBuilder getBuilder(); + + IBuilder getEditableBuilder(); + + String getOutputPrefix(String outputExtension); + + boolean isSystemObject(); + + String getOutputExtension(String resourceExtension); + + String getOutputFlag(String outputExt); + + IManagedCommandLineInfo generateToolCommandLineInfo(String sourceExtension, String[] flags, String outputFlag, + String outputPrefix, String outputName, String[] inputResources, IPath inputLocation, IPath outputLocation); + + String[] getUserObjects(String extension); + + String[] getLibs(String extension); + + boolean buildsFileType(String srcExt); + + boolean supportsBuild(boolean managed); + + boolean isManagedBuildOn(); + + void setManagedBuildOn(boolean on) throws BuildException; + + boolean isBuilderCompatible(IBuilder builder); + + void changeBuilder(IBuilder newBuilder, String id, String name); + + IBuildPropertyValue getBuildArtefactType(); + + void setBuildArtefactType(String id) throws BuildException; +} diff --git a/io.sloeber.ManagedBuild/src/io/sloeber/managedBuild/api/IEnvVarBuildPath.java b/io.sloeber.ManagedBuild/src/io/sloeber/managedBuild/api/IEnvVarBuildPath.java new file mode 100644 index 000000000..be19379df --- /dev/null +++ b/io.sloeber.ManagedBuild/src/io/sloeber/managedBuild/api/IEnvVarBuildPath.java @@ -0,0 +1,64 @@ +/******************************************************************************* + * Copyright (c) 2005, 2010 Intel Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Intel Corporation - Initial API and implementation + *******************************************************************************/ +package io.sloeber.managedBuild.api; + +/** + * @since 3.0 + * @noextend This class is not intended to be subclassed by clients. + * @noimplement This interface is not intended to be implemented by clients. + */ +public interface IEnvVarBuildPath { + public static final int BUILDPATH_INCLUDE = 1; + public static final int BUILDPATH_LIBRARY = 2; + + public static final String BUILD_PATH_ELEMENT_NAME = "envVarBuildPath"; //$NON-NLS-1$ + public static final String TYPE = "pathType"; //$NON-NLS-1$ + public static final String LIST = "variableList"; //$NON-NLS-1$ + public static final String PATH_DELIMITER = "pathDelimiter"; //$NON-NLS-1$ + public static final String BUILD_PATH_RESOLVER = "buildPathResolver"; //$NON-NLS-1$ + + public static final String TYPE_INCLUDE = "buildpathInclude"; //$NON-NLS-1$ + public static final String TYPE_LIBRARY = "buildpathLibrary"; //$NON-NLS-1$ + + public static final String NAME_SEPARATOR = ","; //$NON-NLS-1$ + + /** + * + * @return one of the ITool.BUILDPATH _xxx + */ + public int getType(); + + /** + * + * @return the array of String representing the build variable names + */ + public String[] getVariableNames(); + + /** + * + * @return the String representing the path delimiter used in the variables returned by + * the getVariableNames() method + */ + public String getPathDelimiter(); + + /** + * + * @return the IBuildPathResolver interface implementation provided by the tool-integrator + * in order to specify his/her own logic of resolving the variable values to the build paths + * (see also the "Specifying the Includes and Library paths environment variables" and + * the "IBuildPathResolver" sections for more detail and for explanation why this callback + * might be needed) + */ + public IBuildPathResolver getBuildPathResolver(); +} diff --git a/io.sloeber.ManagedBuild/src/io/sloeber/managedBuild/api/IFileInfo.java b/io.sloeber.ManagedBuild/src/io/sloeber/managedBuild/api/IFileInfo.java new file mode 100644 index 000000000..729f44ece --- /dev/null +++ b/io.sloeber.ManagedBuild/src/io/sloeber/managedBuild/api/IFileInfo.java @@ -0,0 +1,27 @@ +/******************************************************************************* + * Copyright (c) 2007, 2010 Intel Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Intel Corporation - Initial API and implementation + *******************************************************************************/ +package io.sloeber.managedBuild.api; + +import org.eclipse.cdt.core.settings.model.extension.CFileData; + +/** + * @noextend This class is not intended to be subclassed by clients. + * @noimplement This interface is not intended to be implemented by clients. + */ +public interface IFileInfo extends IResourceConfiguration { + public static final String FILE_INFO_ELEMENT_NAME = "fileInfo"; //$NON-NLS-1$ + + CFileData getFileData(); + +} diff --git a/io.sloeber.ManagedBuild/src/io/sloeber/managedBuild/api/IFolderInfo.java b/io.sloeber.ManagedBuild/src/io/sloeber/managedBuild/api/IFolderInfo.java new file mode 100644 index 000000000..493283c8b --- /dev/null +++ b/io.sloeber.ManagedBuild/src/io/sloeber/managedBuild/api/IFolderInfo.java @@ -0,0 +1,70 @@ +/******************************************************************************* + * Copyright (c) 2007, 2010 Intel Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Intel Corporation - Initial API and implementation + *******************************************************************************/ +package io.sloeber.managedBuild.api; + +import org.eclipse.cdt.core.settings.model.extension.CFolderData; + +/** + * @noextend This class is not intended to be subclassed by clients. + * @noimplement This interface is not intended to be implemented by clients. + */ +public interface IFolderInfo extends IResourceInfo { + public final static String FOLDER_INFO_ELEMENT_NAME = "folderInfo"; //$NON-NLS-1$ + + ITool[] getFilteredTools(); + + IToolChain getToolChain(); + + ITool getTool(String id); + + ITool[] getToolsBySuperClassId(String id); + + CFolderData getFolderData(); + + /** + * Returns a ITool for the tool associated with the + * output extension. + * + * @param extension the file extension of the output file + * @return ITool + * + * @since 3.1 + */ + ITool getToolFromOutputExtension(String extension); + + /** + * Returns a ITool for the tool associated with the + * input extension. + * + * @param sourceExtension the file extension of the input file + * @return ITool + * + * @since 3.1 + */ + ITool getToolFromInputExtension(String sourceExtension); + + boolean buildsFileType(String srcExt); + + IModificationStatus getToolChainModificationStatus(ITool[] removed, ITool[] added); + + void modifyToolChain(ITool[] removed, ITool[] added) throws BuildException; + + IToolChain changeToolChain(IToolChain newSuperClass, String Id, String name) throws BuildException; + + boolean isToolChainCompatible(IToolChain tCh); + + String getOutputExtension(String resourceExtension); + + boolean isHeaderFile(String ext); +} diff --git a/io.sloeber.ManagedBuild/src/io/sloeber/managedBuild/api/IHoldsOptions.java b/io.sloeber.ManagedBuild/src/io/sloeber/managedBuild/api/IHoldsOptions.java new file mode 100644 index 000000000..bc1a846ff --- /dev/null +++ b/io.sloeber.ManagedBuild/src/io/sloeber/managedBuild/api/IHoldsOptions.java @@ -0,0 +1,173 @@ +/******************************************************************************* + * Copyright (c) 2005, 2010 Symbian Ltd and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Symbian Ltd - Initial API and implementation + *******************************************************************************/ +package io.sloeber.managedBuild.api; + +/** + * Implements the functionality that is needed to hold options and option + * categories. The functionality has been moved from ITool to here in CDT 3.0. + * Backwards compatibility of interfaces has been maintained because ITool + * extends IHoldOptions. + * + * @since 3.0 + * @noextend This class is not intended to be subclassed by clients. + * @noimplement This interface is not intended to be implemented by clients. + */ +public interface IHoldsOptions extends IBuildObject { + + public static final String OPTION = "option"; //$NON-NLS-1$ + public static final String OPTION_CAT = "optionCategory"; //$NON-NLS-1$ + public static final String OPTION_REF = "optionReference"; //$NON-NLS-1$ + /* + * M E T H O D S M O V E D F R O M I T O O L I N 3 . 0 + */ + + /** + * Creates a child Option + * + * @param superClass The superClass, if any + * @param Id The id for the new option + * @param name The name for the new option + * @param isExtensionElement Indicates whether this is an extension element or a managed project element + * + * @return IOption + */ + public IOption createOption(IOption superClass, String Id, String name, boolean isExtensionElement); + + /** + * Removes an option. + */ + public void removeOption(IOption option); + + /** + * This is a deprecated method for retrieving an IOption from + * the receiver based on an ID. It is preferred that you use the newer method + * getOptionById + * @see IHoldsOptions#getOptionById(java.lang.String) + * + * @param id unique identifier of the option to search for + * @return IOption + * @deprecated use getOptionById() instead + */ + @Deprecated + public IOption getOption(String id); + + /** + * Get the IOption in the receiver with the specified + * ID. This is an efficient search in the receiver. + * + *

If the receiver does not have an option with that ID, the method + * returns null. It is the responsibility of the caller to + * verify the return value. + * + * @param id unique identifier of the option to search for + * @return IOption + * @since 2.0 + */ + public IOption getOptionById(String id); + + /** + * Get the IOption in the receiver with the specified + * ID, or an option with a superclass with this id. + * + *

If the receiver does not have an option with that ID, the method + * returns null. It is the responsibility of the caller to + * verify the return value. + * + * @param id unique identifier of the option to search for + * @return IOption + * @since 3.0 + */ + public IOption getOptionBySuperClassId(String id); + + /** + * Returns the complete list of options that are available for this object. + * The list is a merging of the options specified for this object with the + * options of its superclasses. The lowest option instance in the hierarchy + * takes precedence. + * + * @return IOption[] + */ + public IOption[] getOptions(); + + /** + * Returns the option category children of this tool. + * + * @return IOptionCategory[] + */ + public IOptionCategory[] getChildCategories(); + + /* + * M E T H O D S M O V E D F R O M T O O L I N 3 . 0 + */ + + /** + * Adds the IOptionCategory to this Option Holder's + * list of Option Categories. + * + * @param category The option category to be added + */ + public void addOptionCategory(IOptionCategory category); + + /* + * N E W M E T H O D S A D D E D I N 3 . 0 + */ + + /** + * Answers the IOptionCategory that has the unique identifier + * specified in the argument. + * + * @param id The unique identifier of the option category + * @return IOptionCategory with the id specified in the argument + * @since 3.0 + */ + public IOptionCategory getOptionCategory(String id); + + /** + * Creates options from the superclass and adds it to this class. + * Each individual option in superclass, will become the superclass for + * the new option. + * + * @param superClass The superClass + * @since 3.0 + */ + public void createOptions(IHoldsOptions superClass); + + /** + + * This method should be called in order to obtain the option whose value and attributes could be directly changed/adjusted + * + * @param option -the option to be modified + * @param adjustExtension - if false, modifications are to be made for the non-extension element + * (only for some particular configuration associated with some eclipse project) + * This is the most common use of this method. + * + * True is allowed only while while handling the LOAD value handler event. + * In this case modifications are to be made for the extension element. + * This could be used for adjusting extension options + * Note: changing this option will affect all non-extension configurations using this option! + */ + IOption getOptionToSet(IOption option, boolean adjustExtension) throws BuildException; + + /** + * specifies whether the option holder is modified and needs rebuild + * + * @return boolean + */ + public boolean needsRebuild(); + + /** + * sets the holder rebuild state + */ + public void setRebuildState(boolean rebuild); +} diff --git a/io.sloeber.ManagedBuild/src/io/sloeber/managedBuild/api/IInputOrder.java b/io.sloeber.ManagedBuild/src/io/sloeber/managedBuild/api/IInputOrder.java new file mode 100644 index 000000000..daa7c091c --- /dev/null +++ b/io.sloeber.ManagedBuild/src/io/sloeber/managedBuild/api/IInputOrder.java @@ -0,0 +1,98 @@ +/******************************************************************************* + * Copyright (c) 2005, 2010 Intel Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Intel Corporation - Initial API and implementation + *******************************************************************************/ +package io.sloeber.managedBuild.api; + +/** + * This interface represents an inputOrder instance in the managed build system. + * This element is only present if the user or a tool integrator needs to define + * the specific order of input files to a tool, or needs to exclude one or more + * input files from being used by a tool. An inputType element can have + * multiple inputOrder children. + * + * @since 3.0 + * @noextend This class is not intended to be subclassed by clients. + * @noimplement This interface is not intended to be implemented by clients. + */ +public interface IInputOrder { + public static final String INPUT_ORDER_ELEMENT_NAME = "inputOrder"; //$NON-NLS-1$ + public static final String PATH = "path"; //$NON-NLS-1$ + public static final String ORDER = "order"; //$NON-NLS-1$ + public static final String EXCLUDED = "excluded"; //$NON-NLS-1$ + + /** + * Returns the InputType parent of this InputOrder. + * + * @return IInputType + */ + public IInputType getParent(); + + /** + * Returns the relative or absolute path of the resource to which this element applies. + * The resource must be a member of the project, or the output from another tool in the + * tool-chain. + * + * @return String + */ + public String getPath(); + + /** + * Sets the relative or absolute path of the resource to which this element applies. + */ + public void setPath(String path); + + /** + * Returns a comma-separated list of integer values that specify the order of this resource. + * In most cases, only a single integer value will be specified. A list is supported + * for the case where a single input file needs to be specified multiple times on the + * command line. The order numbers begin at 1. Not all values need to be specified. + * Unordered resources will fill the first "gap". For example: + * - To specify the first input file, use 1. + * - To specify the last input file, without specifying an order for any other input file, use 2. + * - To specify only the first two input files and last input file, use 1, 2 & 4. + * + * @return String + */ + public String getOrder(); + + /** + * Sets the comma-separated list of integer values that specify the order of this resource. + */ + public void setOrder(String order); + + /** + * Returns true if this resource is not used as an input for the tool. + * + * @return boolean + */ + public boolean getExcluded(); + + /** + * Sets whether this resource is not used as an input for the tool. + */ + public void setExcluded(boolean excluded); + + /** + * Returns true if this element has changes that need to + * be saved in the project file, else false. + * + * @return boolean + */ + public boolean isDirty(); + + /** + * Sets the element's "dirty" (have I been modified?) flag. + */ + public void setDirty(boolean isDirty); + +} diff --git a/io.sloeber.ManagedBuild/src/io/sloeber/managedBuild/api/IInputType.java b/io.sloeber.ManagedBuild/src/io/sloeber/managedBuild/api/IInputType.java new file mode 100644 index 000000000..70fa441eb --- /dev/null +++ b/io.sloeber.ManagedBuild/src/io/sloeber/managedBuild/api/IInputType.java @@ -0,0 +1,420 @@ +/******************************************************************************* + * Copyright (c) 2005, 2010 Intel Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Intel Corporation - Initial API and implementation + *******************************************************************************/ +package io.sloeber.managedBuild.api; + + +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.content.IContentType; + +/** + * This interface represents an inputType instance in the managed build system. + * It describes one category of input files to a Tool. A tool can have + * multiple inputType children. + * + * @since 3.0 + * @noextend This class is not intended to be subclassed by clients. + * @noimplement This interface is not intended to be implemented by clients. + */ +public interface IInputType extends IBuildObject { + public static final String INPUT_TYPE_ELEMENT_NAME = "inputType"; //$NON-NLS-1$ + public static final String SOURCE_CONTENT_TYPE = "sourceContentType"; //$NON-NLS-1$ + public static final String HEADER_CONTENT_TYPE = "headerContentType"; //$NON-NLS-1$ + public static final String SOURCES = "sources"; //$NON-NLS-1$ + public static final String HEADERS = "headers"; //$NON-NLS-1$ + public static final String DEPENDENCY_CONTENT_TYPE = "dependencyContentType"; //$NON-NLS-1$ + public static final String DEPENDENCY_EXTENSIONS = "dependencyExtensions"; //$NON-NLS-1$ + public static final String OPTION = "option"; //$NON-NLS-1$ + public static final String ASSIGN_TO_OPTION = "assignToOption"; //$NON-NLS-1$ + public static final String MULTIPLE_OF_TYPE = "multipleOfType"; //$NON-NLS-1$ + public static final String PRIMARY_INPUT = "primaryInput"; //$NON-NLS-1$ + public static final String BUILD_VARIABLE = "buildVariable"; //$NON-NLS-1$ + public static final String LANGUAGE_ID = "languageId"; //$NON-NLS-1$ + public static final String LANGUAGE_NAME = "languageName"; //$NON-NLS-1$ + public static final String LANGUAGE_INFO_CALCULATOR = "languageInfoCalculator"; //$NON-NLS-1$ + + // The attribute name for the scanner info collector + public static final String SCANNER_CONFIG_PROFILE_ID = "scannerConfigDiscoveryProfileId"; //$NON-NLS-1$ + + /** + * Creates an inputOrder child for this InputType. + * + * @param path The path associated with the InputOrder element + * @return IInputOrder of the new element + */ + public IInputOrder createInputOrder(String path); + + /** + * Removes the InputOrder element with the path specified in the argument. + * + * @param path The path associated with the InputOrder element + */ + public void removeInputOrder(String path); + + /** + * Removes the InputOrder element specified in the argument. + * + * @param element The InputOrder element + */ + public void removeInputOrder(IInputOrder element); + + /** + * Returns all of the InputOrder children of this InputType + * + * @return IInputOrder[] + */ + public IInputOrder[] getInputOrders(); + + /** + * Returns the InputOrder element with the path specified in the argument. + * + * @param path The path associated with the InputOrder element + * @return IInputOrder + */ + public IInputOrder getInputOrder(String path); + + /** + * Creates an additionalInput child for this InputType. + * + * @param path The path associated with the AdditionalInput element + * @return IAdditionalInput of the new element + */ + public IAdditionalInput createAdditionalInput(String path); + + /** + * Removes the AdditionalInput element with the path specified in the argument. + * + * @param path The path associated with the AdditionalInput element + */ + public void removeAdditionalInput(String path); + + /** + * Removes the AdditionalInput element specified in the argument. + * + * @param element The AdditionalInput element + */ + public void removeAdditionalInput(IAdditionalInput element); + + /** + * Returns all of the AdditionalInput children of this InputType + * + * @return IAdditionalInput[] + */ + public IAdditionalInput[] getAdditionalInputs(); + + /** + * Returns the AdditionalInput element with the path specified in the argument. + * + * @param path The path associated with the AdditionalInput element + * @return IAdditionalInput + */ + public IAdditionalInput getAdditionalInput(String path); + + /** + * Returns all of the additional input resources of this InputType. + * Note: This does not include additional dependencies. + * + * @return IPath[] + */ + public IPath[] getAdditionalResources(); + + /** + * Returns all of the additional dependency resources of this InputType. + * Note: This does not include additional inputs. + * + * @return IPath[] + */ + public IPath[] getAdditionalDependencies(); + + /** + * Returns the tool parent of this InputType. + * + * @return ITool + */ + public ITool getParent(); + + /** + * Returns the IInputType that is the superclass of this + * InputType, or null if the attribute was not specified. + * + * @return IInputType + */ + public IInputType getSuperClass(); + + /** + * Returns the Eclipse IContentType that describes this + * input type. If both the sources attribute and the sourceContentType + * attribute are specified, the sourceContentType will be used if it + * is registered in Eclipse. + * + * @return IContentType + */ + public IContentType getSourceContentType(); + + public IContentType[] getSourceContentTypes(); + + public IContentType[] getHeaderContentTypes(); + + public String[] getSourceContentTypeIds(); + + public String[] getHeaderContentTypeIds(); + + public String[] getHeaderExtensions(ITool tool); + + public String[] getHeaderExtensionsAttribute(); + + public void setSourceContentTypeIds(String[] ids); + + public void setHeaderContentTypeIds(String[] ids); + + public void setSourceExtensionsAttribute(String[] extensions); + + public void setHeaderExtensionsAttribute(String[] extensions); + + /** + * Sets the Eclipse IContentType that describes this + * input type. + * + * @param contentType The Eclipse content type + */ + public void setSourceContentType(IContentType contentType); + + /** + * Returns the list of valid source extensions from the + * sourceExtensions attribute. Note that this value is not used + * if source content type is specified and registered with Eclipse. + * Also, the user will not be able to modify the set of file + * extensions as they can when sourceContentType is specified. + * + * @return String[] + */ + public String[] getSourceExtensionsAttribute(); + + /** + * Sets the list of valid source extensions for this input type. + * NOTE: The value of this attribute will NOT be used if a + * source content type is specified and is registered with + * Eclipse. + * + * @param extensions The comma-separated list of valid file extensions + * - not including the separator period. + */ + public void setSourceExtensionsAttribute(String extensions); + + /** + * Returns the list of valid source extensions for this input type. + * Note that the list will come from the sourceContentType if it + * is specified and registered with Eclipse. Otherwise the + * sourceExtensions attribute will be used. + * + * @param tool the tool that contains the input-type + * @return String[] + */ + public String[] getSourceExtensions(ITool tool); + + /** + * Answers true if the input type considers the file extension to be + * one associated with a source file. + * + * @param tool the tool that contains the input-type + * @param ext file extension of the source + * @return boolean + */ + public boolean isSourceExtension(ITool tool, String ext); + + /** + * Returns the Eclipse IContentType that describes the + * dependency files of this input type. If both the dependencyExtensions + * attribute and the dependencyContentType attribute are specified, + * the dependencyContentType will be used if it is defined in Eclipse. + * + * @return IContentType + */ + public IContentType getDependencyContentType(); + + /** + * Sets the Eclipse IContentType that describes the + * dependency files of this input type. + */ + public void setDependencyContentType(IContentType type); + + /** + * Returns the list of valid dependency extensions from the + * dependencyExtensions attribute. Note that this value is not used + * if dependency content type is specified and registered with Eclipse. + * Also, the user will not be able to modify the set of file + * extensions as they can when dependencyContentType is specified. + * + * @return String[] + */ + public String[] getDependencyExtensionsAttribute(); + + /** + * Sets the list of valid dependency extensions for this input type. + * NOTE: The value of this attribute will NOT be used if a + * dependency content type is specified and is registered with + * Eclipse. + * + * @param extensions The comma-separated list of valid dependency extensions + * - not including the separator period. + */ + public void setDependencyExtensionsAttribute(String extensions); + + /** + * Returns the list of valid dependency extensions for this input type. + * Note that the list will come from the dependencyContentType if it + * is specified and registered with Eclipse. Otherwise the + * dependencyExtensions attribute will be used. + * + * @param tool the tool that contains the input-type + * @return String[] + */ + public String[] getDependencyExtensions(ITool tool); + + /** + * Answers true if the input type considers the file extension to be + * one associated with a dependency file. + * + * @param tool the tool that contains the input-type + * @param ext file extension of the source + * @return boolean + */ + public boolean isDependencyExtension(ITool tool, String ext); + + /** + * Returns the id of the option that is associated with this input + * type on the command line. If specified, the name(s) of the input + * files for this input type are taken from the value specified + * for the option. + * + * @return String + */ + public String getOptionId(); + + /** + * Sets the id of the option that is associated with this input type on + * the command line. If specified, the name(s) of the input files for + * this input type are taken from the value specified for the option. + */ + public void setOptionId(String optionId); + + /** + * Returns the id of the option whose value is to be assigned to the + * file(s) calculated for this input type. The default is not to + * assign the input file(s) to a command line option but to assign the + * files to the ${Inputs} part of the command line. Note that the + * option value is only updated during build file generation and therefore + * could be out of sync with the project until build file generation + * occurs. + * + * @return String + */ + public String getAssignToOptionId(); + + /** + * Sets the id of the option whose value is to be assigned to the + * file(s) calculated for this input type. The default is not to + * assign the input file(s) to a command line option but to assign the + * files to the ${Inputs} part of the command line. Note that the + * option value is only updated during build file generation and therefore + * could be out of sync with the project until build file generation + * occurs. + */ + public void setAssignToOptionId(String optionId); + + /** + * Returns true if this inputType can contain multiple input + * resources, else false. The inputs can be project resources, + * or the outputs of other tools in the tool-chain. + * + * @return boolean + */ + public boolean getMultipleOfType(); + + /** + * Sets whether this inputType can contain multiple input resources + */ + public void setMultipleOfType(boolean multiple); + + /** + * Returns true if this inputType is considered the primary input + * of the tool, else false. + * + * @return boolean + */ + public boolean getPrimaryInput(); + + /** + * Sets whether this inputType is considered the primary input of the tool + */ + public void setPrimaryInput(boolean primary); + + /** + * Returns a class instance that implements an interface to generate + * source-level dependencies for this input type. + * This method may return null in which case, the receiver + * should assume that the input type does not require dependency information + * when the project is built. + * + * @return IManagedDependencyGeneratorType + */ + //public IManagedDependencyGeneratorType getDependencyGenerator(); + + /** + * Returns the name of the build variable associated this this input type's resources + * The build variable used in the build file to represent the list of input files when + * multipleOfType is True. The same variable name can be used by an outputType to + * identify a set of output files that contribute to this tool's input + * (i.e., those using the same buildVariable name). The default name is chosen by MBS. + * + * @return String + */ + public String getBuildVariable(); + + /** + * Sets the name of the build variable associated this this input type's resources + */ + public void setBuildVariable(String variableName); + + /** + * Returns true if this element has changes that need to + * be saved in the project file, else false. + * + * @return boolean + */ + public boolean isDirty(); + + /** + * Returns true if this InputType was loaded from a manifest file, + * and false if it was loaded from a project (.cdtbuild) file. + * + * @return boolean + */ + public boolean isExtensionElement(); + + /** + * Sets the element's "dirty" (have I been modified?) flag. + */ + public void setDirty(boolean isDirty); + + String getLanguageId(ITool tool); + + String getLanguageName(ITool tool); + + String getDiscoveryProfileId(ITool tool); + + void setLanguageIdAttribute(String id); + + void setLanguageNameAttribute(String name); + +} diff --git a/io.sloeber.ManagedBuild/src/io/sloeber/managedBuild/api/IManagedBuildInfo.java b/io.sloeber.ManagedBuild/src/io/sloeber/managedBuild/api/IManagedBuildInfo.java new file mode 100644 index 000000000..ab8186078 --- /dev/null +++ b/io.sloeber.ManagedBuild/src/io/sloeber/managedBuild/api/IManagedBuildInfo.java @@ -0,0 +1,375 @@ +/******************************************************************************* + * Copyright (c) 2003, 2010 Rational Software Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Rational Software - Initial API and implementation + *******************************************************************************/ +package io.sloeber.managedBuild.api; + +//import org.eclipse.cdt.managedbuilder.internal.core.ManagedBuildInfo; +//import org.eclipse.cdt.managedbuilder.makegen.IManagedDependencyGeneratorType; +import org.eclipse.core.runtime.IPath; + +/** + * There is a ManagedBuildInfo per CDT managed build project. Here are + * some notes on their usage: + * o You can look up the managed build info associated with a CDT + * project by using ManagedBuildManager.getBuildInfo(IProject). + * o Given a ManagedBuildInfo, you can retrieve the associated CDT + * managed build system project by using getManagedProject. + * o The usage model of a ManagedBuildInfo is: + * 1. Call setDefaultConfiguration to set the context + * 2. Call other methods (e.g. getBuildArtifactName) which get + * information from the default configuration, and the other managed + * build system model elements that can be reached from the + * configuration. + * + * @noextend This class is not intended to be subclassed by clients. + * @noimplement This interface is not intended to be implemented by clients. + */ +public interface IManagedBuildInfo { + public static final String DEFAULT_CONFIGURATION = "defaultConfig"; //$NON-NLS-1$ + public static final String DEFAULT_TARGET = "defaultTarget"; //$NON-NLS-1$ + + /* + * Note: "Target" routines are only currently applicable when loading a CDT 2.0 + * or earlier managed build project file (.cdtbuild) + */ + + + /** + * Returns IManagedCommandLineInfo for source with extension + * The command line info contains values with + * build macros resolved to the makefile format. + * That is if a user has chosen to expand all macros in the buildfile, + * command line info contains values contain all macro references resolved, otherwise, if a user has + * chosen to keep the environment build macros unresolved, the command line info contains values contain + * the environment macro references converted to the buildfile variable format, + * all other macro references are resolved + */ + public IManagedCommandLineInfo generateToolCommandLineInfo(String sourceExtension, String[] flags, + String outputFlag, String outputPrefix, String outputName, String[] inputResources, IPath inputLocation, + IPath outputLocation); + + /** + * Answers a String containing the arguments to be passed to make. + * For example, if the user has selected a build that keeps going on error, the + * answer would contain {"-k"}. + * + * @return String + */ + public String getBuildArguments(); + + /** + * Answers the file extension for the receivers build goal without a separator. + * + * @return the extension or an empty string if none is defined + */ + public String getBuildArtifactExtension(); + + /** + * Returns the name of the artifact to build for the receiver. + * + * @return Name of the build artifact + */ + public String getBuildArtifactName(); + + /** + * Answers a String containing the make command invocation + * for the default configuration. + * @return build command + */ + public String getBuildCommand(); + + /** + * Answers the prebuild step for the default configuration + * + * @return String + */ + public String getPrebuildStep(); + + /** + * Answers the postbuild step for the default configuration + * + * @return String + */ + public String getPostbuildStep(); + + /** + * Answers the display string associated with the prebuild step for the default configuration + * + * @return String + */ + public String getPreannouncebuildStep(); + + /** + * Answers the display string associated with the postbuild step for the default configuration + * + * @return String + */ + public String getPostannouncebuildStep(); + + /** + * Answers the command needed to remove files on the build machine + */ + public String getCleanCommand(); + + /** + * Answers the name of the default configuration, for example Debug + * or Release. + * + * @return String name of default configuration + */ + public String getConfigurationName(); + + /** + * Answers a String array containing the names of all the configurations + * defined for the project. + * + * @return String[] of configuration names + */ + public String[] getConfigurationNames(); + + /** + * Get the default configuration associated with the receiver + * + * @return IConfiguration default + */ + public IConfiguration getDefaultConfiguration(); + +// public IManagedDependencyGeneratorType getDependencyGenerator(String sourceExtension); + + + + /** + * Returns a String containing the flags, including + * those overridden by the user, for the tool in the configuration + * defined by the argument. + * The string contains build macros resolved to the makefile format. + * That is if a user has chosen to expand all macros in the buildfile, + * the string contains all macro references resolved, otherwise, if a user has + * chosen to keep the environment build macros unresolved, the string contains + * the environment macro references converted to the buildfile variable format, + * all other macro references are resolved + */ + public String getToolFlagsForConfiguration(String extension, IPath inputLocation, IPath outputLocation); + + + + /** + * Returns a String containing the flags, including + * those overridden by the user, for the tool that handles the + * type of source file defined by the argument. + * The string contains build macros resolved to the makefile format. + * That is if a user has chosen to expand all macros in the buildfile, + * the string contains all macro references resolved, otherwise, if a user has + * chosen to keep the environment build macros unresolved, the string contains + * the environment macro references converted to the buildfile variable format, + * all other macro references are resolved + */ + public String getToolFlagsForSource(String extension, IPath inputLocation, IPath outputLocation); + + /** + * Answers the libraries the project links in. + */ + public String[] getLibsForConfiguration(String extension); + + /** + * Returns the ManagedProject associated with this build info + * + * @return IManagedProject + */ + public IManagedProject getManagedProject(); + + /** + * Answers the extension that will be built by the current configuration + * for the extension passed in the argument or null. + */ + public String getOutputExtension(String resourceExtension); + + /** + * Answers the flag to be passed to the build tool to produce a specific output + * or an empty String 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 + */ + public String getOutputFlag(String outputExt); + + /** + * Answers the prefix that should be prepended to the name of the build + * artifact. For example, a library foo, should have the prefix 'lib' and + * the extension '.a', so the final goal would be 'libfoo.a' + * + * @return the prefix or an empty string + */ + public String getOutputPrefix(String outputExtension); + + /** + * Returns the currently selected configuration. This is used while the project + * property pages are displayed + * + * @return IConfiguration + */ + public IConfiguration getSelectedConfiguration(); + + + /** + * Returns a String containing the command-line invocation + * for the tool associated with the output extension. + * + * @param extension the file extension of the output file + * @return a String containing the command line invocation for the tool + */ + public String getToolForConfiguration(String extension); + + /** + * Returns a String containing the command-line invocation + * for the tool associated with the source extension. + * + * @param sourceExtension the file extension of the file to be built + * @return a String containing the command line invocation for the tool + */ + public String getToolForSource(String sourceExtension); + + /** + * Returns a ITool for the tool associated with the + * input extension. + * + * @param extension the file extension of the input file + * @return ITool + */ + public ITool getToolFromInputExtension(String extension); + + /** + * Returns a ITool for the tool associated with the + * output extension. + * + * @param extension the file extension of the output file + * @return ITool + */ + public ITool getToolFromOutputExtension(String extension); + + /** + * @param extension the file extension of the build target + * + * @return a String array containing the contents of the + * user objects option, if one is defined for the target. + */ + public String[] getUserObjectsForConfiguration(String extension); + + /** + * Answers the version of the build information in the format + * @return a String containing the build information + * version + */ + public String getVersion(); + + /** + * Answers true if the build model has been changed by the user. + * + * @return boolean + */ + public boolean isDirty(); + + /** + * Answers true if the extension matches one of the special + * file extensions the tools for the configuration consider to be a header file. + * + * @param ext the file extension of the resource + * @return boolean + */ + public boolean isHeaderFile(String ext); + + /** + * Gets the read only status of Managed Build Info + * + * @return true if Managed Build Info is read only + * otherwise returns false + */ + public boolean isReadOnly(); + + /** + * Gets the "valid" status of Managed Build Info. Managed Build Info is invalid + * if the loading of, or conversion to, the Managed Build Info failed. + * + * @return true if Managed Build Info is valid, + * otherwise returns false + */ + public boolean isValid(); + + /** + * Answers whether the receiver has been changed and requires the + * project to be rebuilt. When a project is first created, it is + * assumed that the user will need it to be fully rebuilt. However + * only option and tool command changes will trigger the build + * information for an existing project to require a rebuild. + *

+ * Clients can reset the state to force or clear the rebuild status + * using setRebuildState() + * @see ManagedBuildInfo#setRebuildState(boolean) + * + * @return true if the resource managed by the + * receiver needs to be rebuilt + */ + public boolean needsRebuild(); + + public void removeTarget(String id); + + /** + * Set the primary configuration for the receiver. + * + * @param configuration The IConfiguration that will be used as the default + * for all building. + */ + public void setDefaultConfiguration(IConfiguration configuration); + + /** + * @return boolean indicating if setDefaultConfiguration was successful + */ + public boolean setDefaultConfiguration(String configName); + + /** + * Sets the dirty flag for the build model to the value of the argument. + */ + public void setDirty(boolean isDirty); + + /** + * Sets the valid flag for the build model to the value of the argument. + */ + public void setValid(boolean isValid); + + /** + * Sets the ManagedProject associated with this build info + */ + public void setManagedProject(IManagedProject project); + + /** + * sets the read only status of Managed Build Info + */ + public void setReadOnly(boolean readOnly); + + /** + * Sets the rebuild state in the receiver to the value of the argument. + * This is a potentially expensive option, so setting it to true should + * only be done if a project resource or setting has been modified in a + * way that would invalidate the previous build. + * + * @param rebuild true will force a rebuild the next time the project builds + */ + public void setRebuildState(boolean rebuild); + + /** + * Sets the currently selected configuration. This is used while the project + * property pages are displayed + * + * @param configuration the user selection + */ + public void setSelectedConfiguration(IConfiguration configuration); +} diff --git a/io.sloeber.ManagedBuild/src/io/sloeber/managedBuild/api/IManagedBuilderMakefileGenerator.java b/io.sloeber.ManagedBuild/src/io/sloeber/managedBuild/api/IManagedBuilderMakefileGenerator.java new file mode 100644 index 000000000..37dad5173 --- /dev/null +++ b/io.sloeber.ManagedBuild/src/io/sloeber/managedBuild/api/IManagedBuilderMakefileGenerator.java @@ -0,0 +1,108 @@ +/******************************************************************************* + * Copyright (c) 2004, 2010 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM - Initial API and implementation + *******************************************************************************/ +package io.sloeber.managedBuild.api; + +//import org.eclipse.cdt.managedbuilder.core.IManagedBuildInfo; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.resources.IResourceDelta; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.MultiStatus; + +/** + * @since 2.0 + * + * TODO: isGeneratedResource should take an IPath rather than an IResource, + * because an output file can be generated outside of the project directory. + * This will require a new interface. + */ +public interface IManagedBuilderMakefileGenerator { + + public final String AT = "@"; //$NON-NLS-1$ + public final String COLON = ":"; //$NON-NLS-1$ + public final int COLS_PER_LINE = 80; + public final String COMMENT_SYMBOL = "#"; //$NON-NLS-1$ + public final String DOLLAR_SYMBOL = "$"; //$NON-NLS-1$ + public final String DEP_EXT = "d"; //$NON-NLS-1$ + public final String DEPFILE_NAME = "subdir.dep"; //$NON-NLS-1$ + public final String DOT = "."; //$NON-NLS-1$ + public final String DASH = "-"; //$NON-NLS-1$ + public final String ECHO = "echo"; //$NON-NLS-1$ + public final String IN_MACRO = "$<"; //$NON-NLS-1$ + public final String LINEBREAK = "\\\n"; //$NON-NLS-1$ + public final String LOGICAL_AND = "&&"; //$NON-NLS-1$ + public final String MAKEFILE_DEFS = "makefile.defs"; //$NON-NLS-1$ + public final String MAKEFILE_INIT = "makefile.init"; //$NON-NLS-1$ + public final String MAKEFILE_NAME = "makefile"; //$NON-NLS-1$ + public final String MAKEFILE_TARGETS = "makefile.targets"; //$NON-NLS-1$ + public final String MAKE = "$(MAKE)"; //$NON-NLS-1$ + public final String NO_PRINT_DIR = "--no-print-directory"; //$NON-NLS-1$ + + public final String MODFILE_NAME = "subdir.mk"; //$NON-NLS-1$ + public final String NEWLINE = System.getProperty("line.separator"); //$NON-NLS-1$ + public final String OBJECTS_MAKFILE = "objects.mk"; //$NON-NLS-1$ + public final String OUT_MACRO = "$@"; //$NON-NLS-1$ + public final String ROOT = ".."; //$NON-NLS-1$ + public final String SEPARATOR = "/"; //$NON-NLS-1$ + public final String SINGLE_QUOTE = "'"; //$NON-NLS-1$ + public final String SRCSFILE_NAME = "sources.mk"; //$NON-NLS-1$ + public final String TAB = "\t"; //$NON-NLS-1$ + public final String WHITESPACE = " "; //$NON-NLS-1$ + public final String WILDCARD = "%"; //$NON-NLS-1$ + + // Generation error codes + public static final int SPACES_IN_PATH = 0; + public static final int NO_SOURCE_FOLDERS = 1; + + public void generateDependencies() throws CoreException; + + /** + * Clients call this method when an incremental rebuild is required. The argument + * contains a set of resource deltas that will be used to determine which + * subdirectories need a new makefile and dependency list (if any). + */ + public MultiStatus generateMakefiles(IResourceDelta delta) throws CoreException; + + /** + * Answers the path of the top directory generated for the build + * output, or null if none has been generated. + * + * @return IPath to the working directory of the build + */ + public IPath getBuildWorkingDir(); + + /** + * Answers the name of the top-level makefile generated by the receiver. + * + * @return name of the makefile. + */ + public String getMakefileName(); + + /** + * This method initializes the makefile generator + */ + public void initialize(IProject project, IManagedBuildInfo info, IProgressMonitor monitor); + + /** + * Answers true if the argument is a resource created by the generator + */ + public boolean isGeneratedResource(IResource resource); + + public void regenerateDependencies(boolean force) throws CoreException; + + public MultiStatus regenerateMakefiles() throws CoreException; + +} diff --git a/io.sloeber.ManagedBuild/src/io/sloeber/managedBuild/api/IManagedCommandLineGenerator.java b/io.sloeber.ManagedBuild/src/io/sloeber/managedBuild/api/IManagedCommandLineGenerator.java new file mode 100644 index 000000000..2938ccbdc --- /dev/null +++ b/io.sloeber.ManagedBuild/src/io/sloeber/managedBuild/api/IManagedCommandLineGenerator.java @@ -0,0 +1,20 @@ +/******************************************************************************* + * Copyright (c) 2004, 2010 Intel Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Intel Corporation - Initial API and implementation + *******************************************************************************/ +package io.sloeber.managedBuild.api; + +public interface IManagedCommandLineGenerator { + public IManagedCommandLineInfo generateCommandLineInfo(ITool tool, String commandName, String[] flags, + String outputFlag, String outputPrefix, String outputName, String[] inputResources, + String commandLinePattern); +} diff --git a/io.sloeber.ManagedBuild/src/io/sloeber/managedBuild/api/IManagedCommandLineInfo.java b/io.sloeber.ManagedBuild/src/io/sloeber/managedBuild/api/IManagedCommandLineInfo.java new file mode 100644 index 000000000..090908cd4 --- /dev/null +++ b/io.sloeber.ManagedBuild/src/io/sloeber/managedBuild/api/IManagedCommandLineInfo.java @@ -0,0 +1,58 @@ +/******************************************************************************* + * Copyright (c) 2004, 2010 Intel Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Intel Corporation - Initial API and implementation + *******************************************************************************/ +package io.sloeber.managedBuild.api; + +/** + * @noextend This class is not intended to be subclassed by clients. + * @noimplement This interface is not intended to be implemented by clients. + */ +public interface IManagedCommandLineInfo { + /** + * provide fully qualified command line string for tool invocation + * @return command line + */ + public String getCommandLine(); + + /** + * give command line pattern + */ + public String getCommandLinePattern(); + + /** + * provide tool name + */ + public String getCommandName(); + + /** + * give command flags + */ + public String getFlags(); + + + + /** + * return output file name + */ + public String getOutput(); + + /** + * give command flag to generate output + */ + public String getOutputFlag(); + + /** + * return output prefix + */ + public String getOutputPrefix(); +} diff --git a/io.sloeber.ManagedBuild/src/io/sloeber/managedBuild/api/IManagedConfigElement.java b/io.sloeber.ManagedBuild/src/io/sloeber/managedBuild/api/IManagedConfigElement.java new file mode 100644 index 000000000..34dd6a0b0 --- /dev/null +++ b/io.sloeber.ManagedBuild/src/io/sloeber/managedBuild/api/IManagedConfigElement.java @@ -0,0 +1,48 @@ +/******************************************************************************* + * Copyright (c) 2004, 2010 TimeSys Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * TimeSys Corporation - Initial API and implementation + *******************************************************************************/ +package io.sloeber.managedBuild.api; + +/** + * This class represents a configuration element for loading the managed build + * model objects. They can either be loaded from the ManagedBuildInfo extension + * point, or from an instance of IManagedConfigProvider. + * + * @noextend This class is not intended to be subclassed by clients. + * @noimplement This interface is not intended to be implemented by clients. + */ +public interface IManagedConfigElement { + + /** + * @return the name of this config element (i.e. tag name of the + * corresponding xml element) + */ + String getName(); + + /** + * @return the value of the attribute with the given name, or null + * if the attribute is unset. + */ + String getAttribute(String name); + + /** + * @return all child elements of the current config element. + */ + IManagedConfigElement[] getChildren(); + + /** + * @return all child elements of the current config element, such that + * child.getName().equals(elementName). + */ + IManagedConfigElement[] getChildren(String elementName); +} diff --git a/io.sloeber.ManagedBuild/src/io/sloeber/managedBuild/api/IManagedOptionValueHandler.java b/io.sloeber.ManagedBuild/src/io/sloeber/managedBuild/api/IManagedOptionValueHandler.java new file mode 100644 index 000000000..40189567a --- /dev/null +++ b/io.sloeber.ManagedBuild/src/io/sloeber/managedBuild/api/IManagedOptionValueHandler.java @@ -0,0 +1,132 @@ +/******************************************************************************* + * Copyright (c) 2005, 2009 Symbian Ltd and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Symbian Ltd - Initial API and implementation + *******************************************************************************/ +package io.sloeber.managedBuild.api; + +/** + * This interface represents an option value handler in the managed build + * system. It is used to enable a tool integrator to use the MBS configuration + * GUI, while linking to an alternative back-end. + * + * @since 3.0 + */ +public interface IManagedOptionValueHandler { + + /** + * The option is opened, i.e. its UI element is created. The valueHandler + * can override the value of the option. If it does not, the last persisted + * value is used. + */ + public final int EVENT_OPEN = 1; + + /** + * The option is closed. i.e. its value has been destroyed when a + * configuration/resource gets deleted. The value handler can do various + * things associated with destroying the option such as freeing the memory + * associated with this option callback, if needed. + */ + public final int EVENT_CLOSE = 2; + + /** + * The default value option::defaultValue has been set. The handleValue + * callback is called afterwards to give the handler a chance to override + * the value or to update the value in its back-end. Typically this event + * will be called when the Restore Defaults button is pressed. + */ + public final int EVENT_SETDEFAULT = 3; + + /** + * The option has been set by pressing the Apply button (or the OK button). + * The valueHandler can transfer the value of the option to its own + * back-end. + */ + public final int EVENT_APPLY = 4; + + /** + * Posted when the managed build extensions (defined in the manifest files) + * are loaded. The handler is allowed to adjust the extension elements + */ + public final int EVENT_LOAD = 5; + + /** + * Handles transfer between values between UI element and back-end in + * different circumstances. + * + * @param configuration + * build configuration of option (may be IConfiguration or + * IResourceConfiguration) + * @param holder + * contains the holder of the option + * @param option + * the option that is handled + * @param extraArgument + * extra argument for handler + * @param event + * event to be handled + * + * @return True when the event was handled, false otherwise. This enables + * default event handling can take place. + */ + boolean handleValue(IBuildObject configuration, IHoldsOptions holder, IOption option, String extraArgument, + int event); + + /** + * Checks whether the value of an option is its default value. + * + * @param configuration + * build configuration of option (may be IConfiguration or + * IResourceConfiguration) + * @param holder + * contains the holder of the option + * @param option + * the option that is handled + * @param extraArgument + * extra argument for handler + * + * The additional options besides configuration are supplied to + * provide enough information for querying the default value from + * a potential data storage back-end. + * + * @return True if the options value is its default value and False + * otherwise. This enables that default event handling can take + * place. + */ + boolean isDefaultValue(IBuildObject configuration, IHoldsOptions holder, IOption option, String extraArgument); + + /** + * Checks whether an enumeration value of an option is currently a valid + * choice. The use-case for this method is the case, where the set of valid + * enumerations in the plugin.xml file changes. The UI will remove entries + * from selection lists if the value returns false. + * + * @param configuration + * build configuration of option (may be IConfiguration or + * IResourceConfiguration) + * @param holder + * contains the holder of the option + * @param option + * the option that is handled + * @param extraArgument + * extra argument for handler + * @param enumValue + * enumeration value that is to be checked + * + * The additional options besides configuration are supplied to + * provide enough information for querying information from a a + * potential data storage back-end. + * + * @return True if the enumeration value is valid and False otherwise. + */ + boolean isEnumValueAppropriate(IBuildObject configuration, IHoldsOptions holder, IOption option, + String extraArgument, String enumValue); +} diff --git a/io.sloeber.ManagedBuild/src/io/sloeber/managedBuild/api/IManagedProject.java b/io.sloeber.ManagedBuild/src/io/sloeber/managedBuild/api/IManagedProject.java new file mode 100644 index 000000000..fad30b2fc --- /dev/null +++ b/io.sloeber.ManagedBuild/src/io/sloeber/managedBuild/api/IManagedProject.java @@ -0,0 +1,166 @@ +/******************************************************************************* + * Copyright (c) 2004, 2010 Intel Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Intel Corporation - Initial API and implementation + *******************************************************************************/ +package io.sloeber.managedBuild.api; + +import org.eclipse.core.resources.IResource; + +/** + * This class represents a project instance in the managed build system. + * Project instances are stored in the .cdtbuild file. Note that there + * is no reason to define a project element in a manifest file - it + * would never be used. + *

+ * The following steps occur when a CDT user creates a new Managed Build + * project: + * 1. A new project element is created. Its projectType attribute is set + * to the projectType that the user selected. Its name attribute is + * set to the project name that the user entered. + * 2. When the user adds a default configuration, a configuration + * element is created as a child of the project element created in + * step 1. + * 3. Add a tool-chain element that specifies as its superClass the + * tool-chain that is the child of the selected configuration element. + * 4. For each tool element child of the tool-chain that is the child of + * the selected configuration element, create a tool element child of + * the cloned configuration's tool-chain element that specifies the + * original tool element as its superClass. + * This prepares the new project/configurations for modification by the user. + * + * @since 2.1 + * @noextend This class is not intended to be subclassed by clients. + * @noimplement This interface is not intended to be implemented by clients. + */ +public interface IManagedProject + extends IBuildObject, IBuildObjectPropertiesContainer, IOptionalBuildObjectPropertiesContainer { + public static final String MANAGED_PROJECT_ELEMENT_NAME = "project"; //$NON-NLS-1$ + public static final String PROJECTTYPE = "projectType"; //$NON-NLS-1$ + public static final String BUILD_PROPERTIES = "buildProperties"; //$NON-NLS-1$ + /** + * @since 8.6 + */ + public static final String OPTIONAL_BUILD_PROPERTIES = "optionalBuildProperties"; //$NON-NLS-1$ + public static final String BUILD_ARTEFACT_TYPE = "buildArtefactType"; //$NON-NLS-1$ + + /** + * Creates a configuration for this project populated with the tools + * and options settings from the parent configuration. As options and + * tools change in the parent, unoverridden values are updated in the + * child configuration as well. + *

+ * This method performs steps 3 & 4 described above. + * + * @param parent The IConfiguration to use as a settings template + * @param id The unique id the new configuration will have + * @return IConfiguration of the new configuration + */ + public IConfiguration createConfiguration(IConfiguration parent, String id); + + /** + * Creates a configuration for this project populated with the tools + * and options settings from the parent configuration. As opposed to the + * createConfiguration method, this method creates a configuration + * from an existing configuration in the project. + *

+ * In this case, the new configuration is cloned from the existing configuration, + * and does not retain a pointer to the existing configuration. + * + * @param parent The IConfiguration to clone + * @param id The unique id the new configuration will have + * @return IConfiguration of the new configuration + */ + public IConfiguration createConfigurationClone(IConfiguration parent, String id); + + /** + * Removes the configuration with the ID specified in the argument. + * + * @param id The unique id of the configuration + */ + public void removeConfiguration(String id); + + /** + * Returns all of the configurations defined by this project-type. + * + * @return IConfiguration[] + */ + public IConfiguration[] getConfigurations(); + + /** + * Returns the configuration with the given id, or null if not found. + * + * @param id The unique id of the configuration + * @return IConfiguration + */ + public IConfiguration getConfiguration(String id); + + /** + * Answers the IProjectType that is the superclass of this + * project-type, or null if the attribute was not specified. + * + * @return IProjectType + */ + //public IProjectType getProjectType(); + + /** + * Returns the owner of the managed project (an IProject). + * + * @return IResource + */ + public IResource getOwner(); + + /** + * Sets the owner of the managed project. + */ + public void updateOwner(IResource resource); + + /** + * Returns true if this project has changes that need to + * be saved in the project file, else false. + * + * @return boolean + */ + public boolean isDirty(); + + /** + * Sets the element's "dirty" (have I been modified?) flag. + */ + public void setDirty(boolean isDirty); + + /** + * Returns true if this project is valid + * else false. + * + * @return boolean + */ + public boolean isValid(); + + /** + * Sets the element's "Valid" flag. + */ + public void setValid(boolean isValid); + + // /** + // * Persist the managed project to the project file (.cdtbuild). + // * + // * @param doc + // * @param element + // */ + // public void serialize(Document doc, Element element); + + /** + * Returns the default build artifact name for the project + * + * @return String + */ + public String getDefaultArtifactName(); +} diff --git a/io.sloeber.ManagedBuild/src/io/sloeber/managedBuild/api/IModificationStatus.java b/io.sloeber.ManagedBuild/src/io/sloeber/managedBuild/api/IModificationStatus.java new file mode 100644 index 000000000..6e8421de2 --- /dev/null +++ b/io.sloeber.ManagedBuild/src/io/sloeber/managedBuild/api/IModificationStatus.java @@ -0,0 +1,69 @@ +/******************************************************************************* + * Copyright (c) 2007, 2011 Intel Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Intel Corporation - Initial API and implementation + *******************************************************************************/ +package io.sloeber.managedBuild.api; + +import java.util.Map; +import java.util.Set; + +import org.eclipse.core.runtime.IStatus; + +/** + * @noextend This class is not intended to be subclassed by clients. + * @noimplement This interface is not intended to be implemented by clients. + */ +public interface IModificationStatus extends IStatus { + /** + * flags should be obtained via {@link IStatus#getCode()} + */ + + public static final int TOOLS_CONFLICT = 1; + public static final int PROPS_NOT_SUPPORTED = 1 << 1; + public static final int REQUIRED_PROPS_NOT_SUPPORTED = 1 << 2; + + /** + * some properties used in the toolChain are not defined in the System + */ + public static final int PROPS_NOT_DEFINED = 1 << 3; + + /** + * some tools do not support Managed Build Mode + */ + public static final int TOOLS_DONT_SUPPORT_MANAGED_BUILD = 1 << 4; + + /** + * + * @return Map containing property Id to property Value associations. + * If value is not null then the given value is not supported + * If Value is not null then the fiven property is not supported + */ + Map getUnsupportedProperties(); + + /** + * + * @return Map containing property Id to property Value associations. + * If value is not null then the given value is not supported + * If Value is not null then the fiven property is not supported + */ + Map getUnsupportedRequiredProperties(); + + /** + * + * @return Set containing undefined property IDs + */ + Set getUndefinedProperties(); + + ITool[][] getToolsConflicts(); + + ITool[] getNonManagedBuildTools(); +} diff --git a/io.sloeber.ManagedBuild/src/io/sloeber/managedBuild/api/INewManagedOutputNameProvider.java b/io.sloeber.ManagedBuild/src/io/sloeber/managedBuild/api/INewManagedOutputNameProvider.java new file mode 100644 index 000000000..862eb8ca4 --- /dev/null +++ b/io.sloeber.ManagedBuild/src/io/sloeber/managedBuild/api/INewManagedOutputNameProvider.java @@ -0,0 +1,8 @@ +package io.sloeber.managedBuild.api; + +import org.eclipse.core.resources.IProject; +import org.eclipse.core.runtime.IPath; + +public interface INewManagedOutputNameProvider { + public IPath getOutputName(IProject project, IConfiguration cConf, ITool tool, IPath inputName); +} diff --git a/io.sloeber.ManagedBuild/src/io/sloeber/managedBuild/api/IOption.java b/io.sloeber.ManagedBuild/src/io/sloeber/managedBuild/api/IOption.java new file mode 100644 index 000000000..1d6e20089 --- /dev/null +++ b/io.sloeber.ManagedBuild/src/io/sloeber/managedBuild/api/IOption.java @@ -0,0 +1,740 @@ +/******************************************************************************* + * Copyright (c) 2003, 2013 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM - Initial API and implementation + * ARM Ltd. - basic tooltip support + * James Blackburn (Broadcom Corp.) + * Petri Tuononen - [321040] Get Library Search Paths + * Baltasar Belyavsky (Texas Instruments) - [279633] Custom command-generator support + * cartu38 opendev (STMicroelectronics) - [514385] Custom defaultValue-generator support + *******************************************************************************/ +package io.sloeber.managedBuild.api; + +import org.eclipse.cdt.managedbuilder.macros.IOptionContextData; + +/** + * Basic Tool / Tool-chain Option type. + * + * @noextend This class is not intended to be subclassed by clients. + * @noimplement This interface is not intended to be implemented by clients. + */ +public interface IOption extends IBuildObject { + // Type for the value of the option + public static final int BOOLEAN = 0; + public static final int ENUMERATED = 1; + public static final int STRING = 2; + public static final int STRING_LIST = 3; + public static final int INCLUDE_PATH = 4; + public static final int PREPROCESSOR_SYMBOLS = 5; + /** + * String list of library names to link against searched for + * via LIBRARY_PATHS by the linker. In the GNU + * tool-chain these correspond to -l{lib_name}.
+ * This option type is persisted / referenced by the name + * {@link IOption#TYPE_LIB} + */ + public static final int LIBRARIES = 6; + public static final int OBJECTS = 7; + public static final int INCLUDE_FILES = 8; + /** + * String list of library search paths
+ * This option type is persisted / referenced by the name + * {@link IOption#TYPE_LIB_PATHS} + */ + public static final int LIBRARY_PATHS = 9; + /** + * String list of absolute path to libraries. + * Not currently used by the GNU integration
+ * This option type is persisted / referenced by the name 'libFiles' + * {@link IOption#TYPE_LIB_FILES} + */ + public static final int LIBRARY_FILES = 10; + public static final int MACRO_FILES = 11; + + /** + * Tree of items to select one from. + * @since 8.1 + */ + public static final int TREE = 12; + + public static final int UNDEF_INCLUDE_PATH = -INCLUDE_PATH; + public static final int UNDEF_PREPROCESSOR_SYMBOLS = -PREPROCESSOR_SYMBOLS; + public static final int UNDEF_INCLUDE_FILES = -INCLUDE_FILES; + public static final int UNDEF_LIBRARY_PATHS = -LIBRARY_PATHS; + public static final int UNDEF_LIBRARY_FILES = -LIBRARY_FILES; + public static final int UNDEF_MACRO_FILES = -MACRO_FILES; + + // Browse type + public static final int BROWSE_NONE = 0; + public static final String NONE = "none"; //$NON-NLS-1$ + public static final int BROWSE_FILE = 1; + public static final String FILE = "file"; //$NON-NLS-1$ + public static final int BROWSE_DIR = 2; + public static final String DIR = "directory"; //$NON-NLS-1$ + + // Resource Filter type + public static final int FILTER_ALL = 0; + public static final String ALL = "all"; //$NON-NLS-1$ + public static final int FILTER_FILE = 1; + public static final int FILTER_PROJECT = 2; + public static final String PROJECT = "project"; //$NON-NLS-1$ + + // Schema attribute names for option elements + public static final String BROWSE_TYPE = "browseType"; //$NON-NLS-1$ + /** @since 7.0 */ + public static final String BROWSE_FILTER_PATH = "browseFilterPath"; //$NON-NLS-1$ + /** @since 7.0 */ + public static final String BROWSE_FILTER_EXTENSIONS = "browseFilterExtensions"; //$NON-NLS-1$ + public static final String CATEGORY = "category"; //$NON-NLS-1$ + /** + * @since 8.1 + */ + public static final String ICON = "icon"; //$NON-NLS-1$ + /** + * @since 8.1 + */ + public static final String ORDER = "order"; //$NON-NLS-1$ + public static final String COMMAND = "command"; //$NON-NLS-1$ + public static final String COMMAND_FALSE = "commandFalse"; //$NON-NLS-1$ + /** @since 8.3 */ + public static final String USE_BY_SCANNER_DISCOVERY = "useByScannerDiscovery"; //$NON-NLS-1$ + /** @since 8.0 */ + public static final String COMMAND_GENERATOR = "commandGenerator"; //$NON-NLS-1$ + public static final String TOOL_TIP = "tip"; //$NON-NLS-1$ + public static final String CONTEXT_ID = "contextId"; //$NON-NLS-1$ + public static final String DEFAULT_VALUE = "defaultValue"; //$NON-NLS-1$ + /** + * @since 8.5 + */ + public static final String DEFAULTVALUE_GENERATOR = "defaultValueGenerator"; //$NON-NLS-1$ + public static final String ENUM_VALUE = "enumeratedOptionValue"; //$NON-NLS-1$ + /** + * @since 8.1 + */ + public static final String TREE_ROOT = "treeOptionRoot"; //$NON-NLS-1$ + /** + * @since 8.1 + */ + public static final String SELECT_LEAF_ONLY = "selectLeafOnly"; //$NON-NLS-1$ + /** + * @since 8.1 + */ + public static final String TREE_VALUE = "treeOption"; //$NON-NLS-1$ + /** + * @since 8.1 + */ + public static final String DESCRIPTION = "description"; //$NON-NLS-1$ + public static final String IS_DEFAULT = "isDefault"; //$NON-NLS-1$ + public static final String LIST_VALUE = "listOptionValue"; //$NON-NLS-1$ + public static final String RESOURCE_FILTER = "resourceFilter"; //$NON-NLS-1$ + public static final String APPLICABILITY_CALCULATOR = "applicabilityCalculator"; //$NON-NLS-1$ + public static final String TYPE_BOOL = "boolean"; //$NON-NLS-1$ + public static final String TYPE_ENUM = "enumerated"; //$NON-NLS-1$ + public static final String TYPE_INC_PATH = "includePath"; //$NON-NLS-1$ + public static final String TYPE_LIB = "libs"; //$NON-NLS-1$ + public static final String TYPE_STRING = "string"; //$NON-NLS-1$ + public static final String TYPE_STR_LIST = "stringList"; //$NON-NLS-1$ + public static final String TYPE_USER_OBJS = "userObjs"; //$NON-NLS-1$ + public static final String TYPE_DEFINED_SYMBOLS = "definedSymbols"; //$NON-NLS-1$ + public static final String TYPE_LIB_PATHS = "libPaths"; //$NON-NLS-1$ + public static final String TYPE_LIB_FILES = "libFiles"; //$NON-NLS-1$ + public static final String TYPE_INC_FILES = "includeFiles"; //$NON-NLS-1$ + public static final String TYPE_SYMBOL_FILES = "symbolFiles"; //$NON-NLS-1$ + public static final String TYPE_UNDEF_INC_PATH = "undefIncludePath"; //$NON-NLS-1$ + public static final String TYPE_UNDEF_DEFINED_SYMBOLS = "undefDefinedSymbols"; //$NON-NLS-1$ + public static final String TYPE_UNDEF_LIB_PATHS = "undefLibPaths"; //$NON-NLS-1$ + public static final String TYPE_UNDEF_LIB_FILES = "undefLibFiles"; //$NON-NLS-1$ + public static final String TYPE_UNDEF_INC_FILES = "undefIncludeFiles"; //$NON-NLS-1$ + public static final String TYPE_UNDEF_SYMBOL_FILES = "undefSymbolFiles"; //$NON-NLS-1$ + /** + * @since 8.1 + */ + public static final String TYPE_TREE = "tree"; //$NON-NLS-1$ + + public static final String VALUE = "value"; //$NON-NLS-1$ + public static final String VALUE_TYPE = "valueType"; //$NON-NLS-1$ + public static final String VALUE_HANDLER = "valueHandler"; //$NON-NLS-1$ + public static final String VALUE_HANDLER_EXTRA_ARGUMENT = "valueHandlerExtraArgument"; //$NON-NLS-1$ + + /** @since 8.0 */ + public static final String FIELD_EDITOR_ID = "fieldEditor"; //$NON-NLS-1$ + /** @since 8.0 */ + public static final String FIELD_EDITOR_EXTRA_ARGUMENT = "fieldEditorExtraArgument"; //$NON-NLS-1$ + + // Schema attribute names for listOptionValue elements + public static final String LIST_ITEM_VALUE = "value"; //$NON-NLS-1$ + public static final String LIST_ITEM_BUILTIN = "builtIn"; //$NON-NLS-1$ + public static final String EMPTY_STRING = ""; + + /** + * @return the parent of this option. This is an object implementing ITool + * or IToolChain. + * + * @since 3.0 - changed return type from ITool to IBuildObject. The method returns + * the same object as getOptionHolder(). It is included as a convenience for clients. + */ + public IBuildObject getParent(); + + /** + * @return the holder (parent) of this option. This may be an object + * implementing ITool or IToolChain, which both extend IHoldsOptions + * + * @since 3.0 + */ + public IHoldsOptions getOptionHolder(); + + /** + * @return the IOption that is the superclass of this + * option, or null if the attribute was not specified. + */ + public IOption getSuperClass(); + + /** + * @param holder - the actual option-holder for the context-data. This holder + * is usually a subclass of this option's {@link #getOptionHolder() holder}. + * @return the option context-data to be used for macro resolution. + * @since 7.0 + */ + public IOptionContextData getOptionContextData(IHoldsOptions holder); + + /** + * @return If this option is defined as an enumeration, this function returns + * the list of possible values for that enum. + * + * If this option is not defined as an enumeration, it returns null. + */ + public String[] getApplicableValues(); + + /** + * @return the value for a boolean option. + */ + public boolean getBooleanValue() throws BuildException; + + /** + * @return the setting of the browseType attribute + */ + public int getBrowseType(); + + /** + * Sets the browseType attribute. + * + * @param type - browseType attribute + */ + public void setBrowseType(int type); + + /** + * @return the setting of the browseFilterPath attribute. For options of {@link #BROWSE_FILE} and {@link #BROWSE_DIR} types. + * @since 7.0 + */ + public String getBrowseFilterPath(); + + /** + * Sets the browseFilterPath attribute. For options of {@link #BROWSE_FILE} and {@link #BROWSE_DIR} types. + * @param path - default filter-path for the underlying browse dialog + * @since 7.0 + */ + public void setBrowseFilterPath(String path); + + /** + * @return the setting of the browseFilterExtensions attribute. For options of {@link #BROWSE_FILE} type. + * @since 7.0 + */ + public String[] getBrowseFilterExtensions(); + + /** + * Sets the browseFilterExtensions attribute. For options of {@link #BROWSE_FILE} type. + * @param extensions - file extensions to show in browse files dialog + * + * @since 7.0 + */ + public void setBrowseFilterExtensions(String[] extensions); + + /** + * @return the setting of the resourceFilter attribute + */ + public int getResourceFilter(); + + /** + * Sets the resourceFilter attribute. + * + * @param filter - resourceFilter attribute + */ + public void setResourceFilter(int filter); + + /** + * @return an instance of the class that calculates whether the option is visible, + * enabled, and used in command line generation + */ + public IOptionApplicability getApplicabilityCalculator(); + + /** + * @return an array of strings containing the built-in values + * defined for a stringList, includePaths, definedSymbols, or libs + * option. If none have been defined, the array will be empty but + * never null. + */ + public String[] getBuiltIns(); + + /** + * @return the category for this option. + */ + public IOptionCategory getCategory(); + + /** + * Sets the category for this option. + */ + public void setCategory(IOptionCategory category); + + /** + * @return a String containing the actual command line + * option associated with the option + */ + public String getCommand(); + + /** + * @return an instance of the class that overrides the default command generation for the option + * @since 8.0 + */ + public IOptionCommandGenerator getCommandGenerator(); + + /** + * Sets a String containing the actual command line + * option associated with the option + * + * @param command - the actual command line option + */ + public void setCommand(String command); + + /** + * @return {@code String} containing the actual command line + * option associated with a Boolean option when the value is {@code false} + */ + public String getCommandFalse(); + + /** + * Sets a String containing the actual command line + * option associated with a Boolean option when the value is {@code false} + * + * @param commandFalse - the actual command line option associated + * with a Boolean option when the value is {@code false} + */ + public void setCommandFalse(String commandFalse); + + /** + * @return a String containing the tooltip + * associated with the option + */ + public String getToolTip(); + + /** + * Sets a String containing the tooltip associated with the option + * + * @param tooltip - the tooltip associated with the option + */ + public void setToolTip(String tooltip); + + /** + * @return a String containing the contextId + * associated with the option + */ + public String getContextId(); + + /** + * Sets a String containing the contextId associated with the option + * + * @param id - the contextId associated with the option + */ + public void setContextId(String id); + + /** + * @return the user-defined preprocessor symbols. + */ + public String[] getDefinedSymbols() throws BuildException; + + /** + * + * @param id - enumeration id + * @return the command associated with the enumeration id. For + * example, if the enumeration id was gnu.debug.level.default + * for the debug level option of the Gnu compiler, and the plugin + * manifest defined that as -g, then the return value would be the + * String "-g" + */ + public String getEnumCommand(String id) throws BuildException; + + /** + * Returns the command associated with the child of this option + * with the given id. Applies to options of types that has children + * for example {@link #TREE} or {@link #ENUMERATED} + * + * @param id - child id + * @return the command associated with the child id. For + * example, if the child id was gnu.debug.level.default + * for the debug level option of the Gnu compiler, and the plugin + * manifest defined that as -g, then the return value would be the + * String "-g" + * + * @throws BuildException if this option is not of type {@link #TREE} or {@link #ENUMERATED} + * @since 8.1 + */ + public String getCommand(String id) throws BuildException; + + /** + * @param id - enumeration id + * @return the "name" associated with the enumeration id. + */ + public String getEnumName(String id) throws BuildException; + + /** + * Returns the name associated with the child of this option + * with the given id. Applies to options of types that has children + * for example {@link #TREE} or {@link #ENUMERATED} + * + * @param id The id to look for + * @return Name of the child with the passed id or null if not found. + * @throws BuildException if any issue happened while searching. + * @since 8.1 + */ + public abstract String getName(String id) throws BuildException; + + /** + * @param name - a "name" associated with enumeration id + * @return enumeration id + */ + public String getEnumeratedId(String name) throws BuildException; + + /** + * Returns the id associated with the child of this option + * with the given name. Applies to options of types that has children + * for example {@link #TREE} or {@link #ENUMERATED} + * + * @param name the name of the child to look for. + * @return The id of the found child or null if not found. + * @throws BuildException if any error happened while searching + * @since 8.1 + */ + public abstract String getId(String name) throws BuildException; + + /** + * @return an array of String containing the includes paths + * defined in the build model. + */ + public String[] getIncludePaths() throws BuildException; + + /** + * @return an array or Strings containing the libraries + * that must be linked into the project. + */ + public String[] getLibraries() throws BuildException; + + /** + * @return an array or Strings containing the library files + * that must be linked into the project. + * + * @since 7.0 + */ + public String[] getLibraryFiles() throws BuildException; + + /** + * @return an array or Strings containing the library paths + * passed to the linker. + * + * @throws BuildException if the option isn't of type IOption#LIBRARY_PATHS + * @since 8.0 + */ + public String[] getLibraryPaths() throws BuildException; + + /** + * @return a String containing the unique ID of the selected + * enumeration in an enumerated option. For an option that has not been + * changed by the user, the receiver will answer with the default defined + * in the plugin manifest. If the user has modified the selection, the + * receiver will answer with the overridden selection. + * + * @throws BuildException if the option type is not an enumeration + */ + public String getSelectedEnum() throws BuildException; + + /** + * @return the current value for this option if it is a List of Strings. + */ + public String[] getStringListValue() throws BuildException; + + /** + * @return the current value for this option if it is a String + */ + public String getStringValue() throws BuildException; + + /** + * @return all of the user-defined object files that must be linked with + * the final build target. + */ + public String[] getUserObjects() throws BuildException; + + /** + * @return the raw value of this option which is the Object that contains the raw value of the option. + * The type of Object is specific to the option type. + */ + public Object getValue(); + + /** + * @return the raw default value of this option which is the Object that contains the raw default value of the option. + * The type of Object is specific to the option type. + */ + public Object getDefaultValue(); + + /** + * @return an instance of the class that overrides the default defaultValue generation for the option + * @since 8.5 + */ + public IOptionDefaultValueGenerator getDefaultValueGenerator(); + + /** + * @return the type for the value of the option. + */ + public int getValueType() throws BuildException; + + /** + * Sets the boolean value of the receiver to the value specified in the argument. + * If the receiver is not a reference to a boolean option, method will throw an + * exception. + */ + public void setValue(boolean value) throws BuildException; + + /** + * Sets the string value of the receiver to the value specified in the argument. + */ + public void setValue(String value) throws BuildException; + + /** + * Sets the value of the receiver to be an array of strings. + * + * @param value An array of strings to place in the option reference. + */ + public void setValue(String[] value) throws BuildException; + + /** + * Sets the raw value of this option. + * + * @param v The Object that contains the raw value of the option. The type + * of Object is specific to the option type. + */ + public void setValue(Object v); + + /** + * Sets the default value of this option. + * + * @param v The Object that contains the default value of the option. The type + * of Object is specific to the option type. + */ + public void setDefaultValue(Object v); + + /** + * Sets the value-type of this option. Use with care. + */ + public void setValueType(int type); + + /** + * @return the value handler specified for this tool. + * @since 3.0 + */ + public IManagedOptionValueHandler getValueHandler(); + + /** + * @return the value handlers extra argument specified for this tool + * @since 3.0 + */ + public String getValueHandlerExtraArgument(); + + /** + * Sets the value handlers extra argument specified for this tool + * @since 3.0 + */ + public void setValueHandlerExtraArgument(String extraArgument); + + /** + * @return the custom field-editor ID for this build-option. This ID should match a custom-field editor + * contributed through the {@code } element of the + * {@code org.eclipse.cdt.managedbuilder.ui.buildDefinitionsUI} extension-point. + * @since 8.0 + */ + public String getFieldEditorId(); + + /** + * @return an optional extra argument for the {@link #getFieldEditorId() field-editor}. + * @since 8.0 + */ + public String getFieldEditorExtraArgument(); + + /** + * Sets the optional extra argument for the field-editor. + * @param extraArgument free-form extra argument to be interpreted by the {@link #getFieldEditorId() field-editor} + * @since 8.0 + */ + public void setFieldEditorExtraArgument(String extraArgument); + + /** + * @return true if this option was loaded from a manifest file, + * and false if it was loaded from a project (.cdtbuild) file. + */ + public boolean isExtensionElement(); + + /** + * @return true if this option is valid and false + * if the option cannot be safely used due to an error in the MBS grammar. + * + * @since 3.0 + * + * @pre Can only be used after Ids in MBS grammar have been resolved by pointers. + */ + public boolean isValid(); + + /** + * @return the type of the option value, i.e. whether it is string, boolean, + * string list or enumeration. As opposed to the getValueType() method, + * the returned type does not specifies the "sense" of the value, e.g. whether it represents the list of includes or not. + * + *
Possible return values: + *

  • {@link IOption#BOOLEAN} + *
  • {@link IOption#STRING} + *
  • {@link IOption#ENUMERATED} + *
  • {@link IOption#TREE} + *
  • {@link IOption#STRING_LIST} - corresponds to + * {@link IOption#INCLUDE_PATH}, {@link IOption#PREPROCESSOR_SYMBOLS}, {@link IOption#LIBRARIES}, + * {@link IOption#OBJECTS}, {@link IOption#INCLUDE_FILES}, {@link IOption#LIBRARY_PATHS}, + * {@link IOption#LIBRARY_FILES}, {@link IOption#MACRO_FILES} + */ + int getBasicValueType() throws BuildException; + + /** + * @return in case the option basic value type is STRING_LIST, returns the String list value, + * throws BuildException otherwise + */ + String[] getBasicStringListValue() throws BuildException; + + public OptionStringValue[] getBasicStringListValueElements() throws BuildException; + + /** + * Flag to indicate whether the option is also used by scanner discovery. + * @return {@code true} if the option is intended to be passed to scanner discovery command + * or {@code false} otherwise. + * + * @since 8.3 + */ + public boolean isForScannerDiscovery(); + + /** + * Returns the tree root of this option if it is of type {@link #TREE} + * @return tree root of this option or null if not found. + * @throws BuildException if this option is not of type {@link #TREE} + * @since 8.1 + */ + public ITreeRoot getTreeRoot() throws BuildException; + + /** + * Represents the root of the tree of values in options of + * type {@link IOption#TREE} + * @author mhussein + * @since 8.1 + * + */ + public interface ITreeRoot extends ITreeOption { + /** + * Determines whether this tree allows selecting leaf nodes + * only or any nodes. + * @return true if only leaf nodes are allowed. + * false if all child nodes could be selected. + * @see ITreeOption#isContainer() + */ + boolean isSelectLeafsOnly(); + + /** + * Locates the node with the given id anywhere in the tree. + * @param id the id to search for + * @return the found child or null if not found. + */ + ITreeOption findNode(String id); + + /** + * Adds a new node to the tree. + * @param id The id of the new child. + * @param name The name of the new child. + * @param category The category of the new child.category is a '.' + * separated string representing hierarchical path + * of the child from the root of the tree. + * can cause other nodes to be created to construct the + * full path to the new child. + * @param order The order of the newly created node among its peers. + * see {@link ITreeOption#getOrder()} for more information. + * Note: this order will apply to any parents auto-created + * according to the passed category. + * if null the {@link ITreeOption#DEFAULT_ORDER} + * will be used. + * @return the newly added node. + */ + ITreeOption addNode(String id, String name, String category, Integer order); + } + + /** + * Represents a one of the possible values for options of type + * {@link IOption#TREE} + * @author mhussein + * @since 8.1 + * + */ + public interface ITreeOption { + /** + * The default order for tree nodes without order specified. + * Tree options with Orders smaller than this should appear above + * tree options with no order specified and vice versa. + */ + public static final int DEFAULT_ORDER = 1000; + + String getName(); + + String getID(); + + String getDescription(); + + /** + * The order that determines UI appearance of the tree node, + * not necessarily its position in {@link #getChildren()} + * @return The order of this tree option relative to its peers. + * Smaller number means it should appear above peers. + * @see #DEFAULT_ORDER + */ + int getOrder(); + + void setOrder(int order); + + ITreeOption[] getChildren(); + + ITreeOption getParent(); + + boolean isContainer(); + + String getCommand(); + + ITreeOption getChild(String name); + + /** + * Adds a new child directly under this node. + * @param id The id of the new child. + * @param name The name of the new child. + * @return The added child. + */ + ITreeOption addChild(String id, String name); + + void remove(); + + String getIcon(); + } +} diff --git a/io.sloeber.ManagedBuild/src/io/sloeber/managedBuild/api/IOptionApplicability.java b/io.sloeber.ManagedBuild/src/io/sloeber/managedBuild/api/IOptionApplicability.java new file mode 100644 index 000000000..21e5417dc --- /dev/null +++ b/io.sloeber.ManagedBuild/src/io/sloeber/managedBuild/api/IOptionApplicability.java @@ -0,0 +1,65 @@ +/******************************************************************************* + * Copyright (c) 2005 Texas Instruments Inc. and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Texas Instruments Inc. - initial API and implementation + *******************************************************************************/ +package io.sloeber.managedBuild.api; + +/** + * This interface determines whether or not the option is currently displayed, + * enabled, and used in command-line generation. + */ +public interface IOptionApplicability { + /** + * This method is queried whenever a makefile or makefile fragment is + * generated which uses this option, and in the C/C++ Build property + * pages when displaying the current command line. + * + * @param configuration build configuration of option + * (may be IConfiguration or IResourceConfiguration) + * @param holder contains the holder of the option + * @param option the option itself + * + * @return true if this option is to be used in command line + * generation, false otherwise + */ + public boolean isOptionUsedInCommandLine(IBuildObject configuration, IHoldsOptions holder, IOption option); + + /** + * This method is queried whenever a new option category is displayed. + * + * @param configuration build configuration of option + * (may be IConfiguration or IResourceConfiguration) + * @param holder contains the holder of the option + * @param option the option itself + * + * @return true if this option should be visible in the build options page, + * false otherwise + */ + public boolean isOptionVisible(IBuildObject configuration, IHoldsOptions holder, IOption option); + + /** + * Whenever the value of an option changes in the GUI, this method is + * queried on all other visible options for the same category. Note that + * this occurs when the GUI changes - the user may opt to cancel these + * changes. + * + * @param configuration build configuration of option + * (may be IConfiguration or IResourceConfiguration) + * @param holder contains the holder of the option + * @param option the option itself + * + * @return true if this option should be enabled in the build options page, + * or false if it should be disabled (grayed out) + */ + public boolean isOptionEnabled(IBuildObject configuration, IHoldsOptions holder, IOption option); + +} diff --git a/io.sloeber.ManagedBuild/src/io/sloeber/managedBuild/api/IOptionCategory.java b/io.sloeber.ManagedBuild/src/io/sloeber/managedBuild/api/IOptionCategory.java new file mode 100644 index 000000000..21ce02602 --- /dev/null +++ b/io.sloeber.ManagedBuild/src/io/sloeber/managedBuild/api/IOptionCategory.java @@ -0,0 +1,118 @@ +/******************************************************************************* + * Copyright (c) 2003, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM - Initial API and implementation + * Miwako Tokugawa (Intel Corporation) - bug 222817 (OptionCategoryApplicability) + *******************************************************************************/ +package io.sloeber.managedBuild.api; + +import java.net.URL; + +/** + * @noextend This class is not intended to be subclassed by clients. + * @noimplement This interface is not intended to be implemented by clients. + */ +public interface IOptionCategory extends IBuildObject { + + // Schema element names + public static final String OWNER = "owner"; //$NON-NLS-1$ + public static final String ICON = "icon"; //$NON-NLS-1$ + + // Resource Filter type + public static final int FILTER_ALL = 0; + public static final String ALL = "all"; //$NON-NLS-1$ + public static final int FILTER_FILE = 1; + public static final int FILTER_PROJECT = 2; + public static final String PROJECT = "project"; //$NON-NLS-1$ + + /** + * Returns the list of children of this node in the option category tree + */ + public IOptionCategory[] getChildCategories(); + + /** + * Returns an array of ITool/IOption pairs for the options in this category + * for a given configuration. + * + * @since 3.1 + */ + public Object[][] getOptions(IConfiguration configuration, IHoldsOptions optHolder); + + + + // /** + // * Returns an array of ITool/IOption pairs for the options in this category + // * for a given resource configuration. + // * + // * @since 3.1 + // */ + // public Object[][] getOptions(IResourceConfiguration resConfig, IHoldsOptions optHolder); + + /** + * Returns an array of ITool/IOption pairs for the options in this category + * for a given resource configuration. + * + * @since 3.1 + */ + public Object[][] getOptions(IResourceInfo resInfo, IHoldsOptions optHolder); + + + + /** + * Returns the category that owns this category, or null if this is the + * top category for a tool. + */ + public IOptionCategory getOwner(); + + + + /** + * Returns the holder (parent) of this category. This may be an object + * implementing ITool or IToolChain, which both extend IHoldsOptions. + * The call can return null, for example the top option category of a tool + * will return null. + * + * Note that the name getOptionHolder() has been choosen, because Tool implements + * both ITool and IOptionCategory and ITool.getParent() exists already. + * + * @return IHoldsOptions + * @since 3.0 + */ + public IHoldsOptions getOptionHolder(); + + /** + * Get the path name of an alternative icon for the option group. + * Or null if no alternative icon was defined. + * + * @return URL + * @since 3.0 + */ + public URL getIconPath(); + + /** + * Returns true if this element has changes that need to + * be saved in the project file, else false. + * + * @return boolean + */ + public boolean isDirty(); + + /** + * Sets the element's "dirty" (have I been modified?) flag. + */ + public void setDirty(boolean isDirty); + + /** + * @return an instance of the class that calculates whether the option category is visible. + * @since 8.0 + */ + public IOptionCategoryApplicability getApplicabilityCalculator(); +} diff --git a/io.sloeber.ManagedBuild/src/io/sloeber/managedBuild/api/IOptionCategoryApplicability.java b/io.sloeber.ManagedBuild/src/io/sloeber/managedBuild/api/IOptionCategoryApplicability.java new file mode 100644 index 000000000..31685e845 --- /dev/null +++ b/io.sloeber.ManagedBuild/src/io/sloeber/managedBuild/api/IOptionCategoryApplicability.java @@ -0,0 +1,38 @@ +/******************************************************************************* + * Copyright (c) 2011 Intel Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Miwako Tokugawa (Intel Corporation) - initial API and implementation + *******************************************************************************/ +package io.sloeber.managedBuild.api; + +/** + * This interface determines whether or not the option category is currently displayed. + * + * @noextend This class is not intended to be subclassed by clients. + * @noimplement This interface is not intended to be implemented by clients. + * + * @since 8.0 + */ +public interface IOptionCategoryApplicability { + /** + * This method is queried whenever a new option category is displayed. + * + * @param configuration build configuration of option + * (may be IConfiguration or IResourceConfiguration) + * @param optHolder contains the holder of the option + * @param category the option category itself + * + * @return true if this option should be visible in the build options page, + * false otherwise + */ + public boolean isOptionCategoryVisible(IBuildObject configuration, IHoldsOptions optHolder, + IOptionCategory category); +} diff --git a/io.sloeber.ManagedBuild/src/io/sloeber/managedBuild/api/IOptionCommandGenerator.java b/io.sloeber.ManagedBuild/src/io/sloeber/managedBuild/api/IOptionCommandGenerator.java new file mode 100644 index 000000000..5b338560f --- /dev/null +++ b/io.sloeber.ManagedBuild/src/io/sloeber/managedBuild/api/IOptionCommandGenerator.java @@ -0,0 +1,39 @@ +/***************************************************************** + * Copyright (c) 2010, 2011 Texas Instruments and others + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Texas Instruments - Initial API and implementation + *****************************************************************/ + +package io.sloeber.managedBuild.api; + +import org.eclipse.cdt.utils.cdtvariables.IVariableSubstitutor; + +/** + * This interface can be implemented by clients to contribute custom command-generator + * for a build-option. + * + * The custom command-generator class should be referenced in the
  • Pattern 1 (supports "-j*"): "text*text" -> "text#text"
  • + *
  • Pattern 2 (supports "-[j*]"): "text[text*text]text" -> + * "texttext#texttext
  • + *
    + * Where # is num or empty if {@code empty} is {@code true}) + */ + private String processParallelPattern(String pattern, boolean empty, int num) { + Assert.isTrue(num > 0); + + int start = pattern.indexOf(PARALLEL_PATTERN_NUM_START); + int end = -1; + boolean hasStartChar = false; + String result; + if (start != -1) { + end = pattern.indexOf(PARALLEL_PATTERN_NUM_END); + if (end != -1) { + hasStartChar = true; + } else { + start = -1; + } + } + if (start == -1) { + start = pattern.indexOf(PARALLEL_PATTERN_NUM); + if (start != -1) { + end = start + PARALLEL_PATTERN_NUM.length(); + } + } + if (start == -1) { + result = pattern; + } else { + String prefix; + String suffix; + String numStr; + prefix = pattern.substring(0, start); + suffix = pattern.substring(end); + numStr = pattern.substring(start, end); + if (empty) { + result = prefix + suffix; + } else { + String resolvedNum; + if (hasStartChar) { + String numPrefix, numSuffix; + numStr = numStr.substring(0, PARALLEL_PATTERN_NUM_START.length()); + numStr = numStr.substring(numStr.length() - PARALLEL_PATTERN_NUM_END.length()); + int numStart = pattern.indexOf(PARALLEL_PATTERN_NUM); + if (numStart != -1) { + int numEnd = numStart + PARALLEL_PATTERN_NUM.length(); + numPrefix = numStr.substring(0, numStart); + numSuffix = numStr.substring(numEnd); + resolvedNum = numPrefix + Integer.toString(num) + numSuffix; + } else { + resolvedNum = EMPTY_STRING; + } + } else { + resolvedNum = Integer.toString(num); + } + result = prefix + resolvedNum + suffix; + } + } + return result; + } + + public String getArgumentsAttribute() { + if (args == null) { + // If I have a superClass, ask it + if (superClass != null) { + return ((Builder) superClass).getArgumentsAttribute(); + } + return EMPTY_STRING; + } + return args; + } + + @Override + public String getErrorParserIds() { + String ids = errorParserIds; + if (ids == null) { + // If I have a superClass, ask it + if (superClass != null) { + ids = getSuperClass().getErrorParserIds(); + } + } + return ids; + } + + @Override + public String[] getErrorParserList() { + String parserIDs = getErrorParserIds(); + String[] errorParsers = null; + if (parserIDs != null) { + // Check for an empty string + if (parserIDs.length() == 0) { + errorParsers = new String[0]; + } else { + StringTokenizer tok = new StringTokenizer(parserIDs, ";"); //$NON-NLS-1$ + List list = new ArrayList<>(tok.countTokens()); + while (tok.hasMoreElements()) { + list.add(tok.nextToken()); + } + String[] strArr = { "" }; //$NON-NLS-1$ + errorParsers = list.toArray(strArr); + } + } else { + errorParsers = new String[0]; + } + return errorParsers; + } + + @Override + public void setCommand(String cmd) { + if (getCommand().equals(cmd)) + return; + if (cmd == null && command == null) + return; + if (command == null || cmd == null || !cmd.equals(command)) { + command = cmd; + setDirty(true); + } + } + + @Override + public void setArguments(String newArgs) { + setArgumentsAttribute(newArgs); + } + + public void setArgumentsAttribute(String newArgs) { + if (newArgs == null && args == null) + return; + if (args == null || newArgs == null || !newArgs.equals(args)) { + args = newArgs; + setDirty(true); + } + } + + @Override + public void setErrorParserIds(String ids) { + String currentIds = getErrorParserIds(); + if (ids == null && currentIds == null) + return; + if (currentIds == null || ids == null || !(currentIds.equals(ids))) { + errorParserIds = ids; + setDirty(true); + } + } + + @Override + public void setIsAbstract(boolean b) { + isAbstract = b; + setDirty(true); + } + + //@Override + public IConfigurationElement getBuildFileGeneratorElement() { + if (buildFileGeneratorElement == null) { + if (superClass != null) { + return ((Builder) superClass).getBuildFileGeneratorElement(); + } + } + return buildFileGeneratorElement; + } + + @Override + public IManagedBuilderMakefileGenerator getBuildFileGenerator() { + IConfigurationElement element = getBuildFileGeneratorElement(); + if (element != null) { + try { + if (element.getName().equalsIgnoreCase("target")) { //$NON-NLS-1$ + if (element.getAttribute(Activator.MAKEGEN_ID) != null) { + return (IManagedBuilderMakefileGenerator) element + .createExecutableExtension(Activator.MAKEGEN_ID); + } + } else { + if (element.getAttribute(IBuilder.BUILDFILEGEN_ID) != null) { + return (IManagedBuilderMakefileGenerator) element + .createExecutableExtension(IBuilder.BUILDFILEGEN_ID); + } + } + } catch (CoreException e) { + } catch (ClassCastException e) { + } + + } + return null; + //return new GnuMakefileGenerator(); + } + + //@Override + public void setBuildFileGeneratorElement(IConfigurationElement element) { + buildFileGeneratorElement = element; + setDirty(true); + } + + /* + * O B J E C T S T A T E M A I N T E N A N C E + */ + + @Override + public boolean isExtensionElement() { + return isExtensionBuilder; + } + + @Override + public boolean isDirty() { + // This shouldn't be called for an extension Builder + if (isExtensionBuilder) + return false; + return super.isDirty(); + } + + @Override + public void setDirty(boolean isDirty) { + super.setDirty(isDirty); + } + + @Override + public void resolveReferences() { + if (!resolved) { + resolved = true; + // Resolve superClass + if (superClassId != null && superClassId.length() > 0) { + superClass = ManagedBuildManager.getExtensionBuilder(superClassId); + if (superClass == null) { + // Report error + ManagedBuildManager.outputResolveError("superClass", //$NON-NLS-1$ + superClassId, "builder", //$NON-NLS-1$ + getId()); + } + } + } + } + + @Override + public String getConvertToId() { + if (convertToId == null) { + // If I have a superClass, ask it + if (superClass != null) { + return getSuperClass().getConvertToId(); + } else { + return EMPTY_STRING; + } + } + return convertToId; + } + + @Override + public void setConvertToId(String convertToId) { + if (convertToId == null && this.convertToId == null) + return; + if (convertToId == null || this.convertToId == null || !convertToId.equals(this.convertToId)) { + this.convertToId = convertToId; + setDirty(true); + } + return; + } + + @Override + public String getVersionsSupported() { + if (versionsSupported == null) { + // If I have a superClass, ask it + if (superClass != null) { + return getSuperClass().getVersionsSupported(); + } else { + return EMPTY_STRING; + } + } + return versionsSupported; + } + + @Override + public void setVersionsSupported(String versionsSupported) { + if (versionsSupported == null && this.versionsSupported == null) + return; + if (versionsSupported == null || this.versionsSupported == null + || !versionsSupported.equals(this.versionsSupported)) { + this.versionsSupported = versionsSupported; + setDirty(true); + } + return; + } + + @Override + public IFileContextBuildMacroValues getFileContextBuildMacroValues() { + return null; + // if (fileContextBuildMacroValues == null && superClass != null) + // return getSuperClass().getFileContextBuildMacroValues(); + // return fileContextBuildMacroValues; + } + + @Override + public String getBuilderVariablePattern() { + if (builderVariablePattern == null && superClass != null) + return getSuperClass().getBuilderVariablePattern(); + return builderVariablePattern; + } + + @Override + public String[] getReservedMacroNames() { + if (reservedMacroNames == null && superClass != null) + return getSuperClass().getReservedMacroNames(); + return reservedMacroNames; + } + + @Override + public IReservedMacroNameSupplier getReservedMacroNameSupplier() { + if (reservedMacroNameSupplier == null && reservedMacroNameSupplierElement != null) { + try { + reservedMacroNameSupplier = (IReservedMacroNameSupplier) reservedMacroNameSupplierElement + .createExecutableExtension(RESERVED_MACRO_NAME_SUPPLIER); + } catch (CoreException e) { + } + } + if (reservedMacroNameSupplier == null && superClass != null) + return getSuperClass().getReservedMacroNameSupplier(); + return reservedMacroNameSupplier; + } + + /* + * This function checks for migration support for the builder, while + * loading. If migration support is needed, looks for the available + * converters and stores them. + */ + + public void checkForMigrationSupport() { + + // String tmpId = null; + boolean isExists = false; + + if (getSuperClass() == null) { + // If 'superClass' is null, then there is no builder available in + // plugin manifest file with the same 'id' & version. + // Look for the 'versionsSupported' attribute + String high = ManagedBuildManager.getExtensionBuilderMap().lastKey(); + + SortedMap subMap = null; + if (superClassId.compareTo(high) <= 0) { + subMap = ManagedBuildManager.getExtensionBuilderMap().subMap(superClassId, high + "\0"); //$NON-NLS-1$ + } else { + // It means there are no entries in the map for the given id. + // make the project is invalid + + IToolChain parent = getParent(); + IConfiguration parentConfig = parent.getParent(); + IManagedProject managedProject = parentConfig.getManagedProject(); + if (managedProject != null) { + managedProject.setValid(false); + } + return; + } + + // for each element in the 'subMap', + // check the 'versionsSupported' attribute whether the given + // builder version is supported + + String baseId = ManagedBuildManager.getIdFromIdAndVersion(superClassId); + String version = ManagedBuildManager.getVersionFromIdAndVersion(superClassId); + + Collection c = subMap.values(); + IBuilder[] builderElements = c.toArray(new IBuilder[c.size()]); + + for (int i = 0; i < builderElements.length; i++) { + IBuilder builderElement = builderElements[i]; + + if (ManagedBuildManager.getIdFromIdAndVersion(builderElement.getId()).compareTo(baseId) > 0) + break; + // First check if both base ids are equal + if (ManagedBuildManager.getIdFromIdAndVersion(builderElement.getId()).equals(baseId)) { + + // Check if 'versionsSupported' attribute is available' + String versionsSupported = builderElement.getVersionsSupported(); + + if ((versionsSupported != null) && (!versionsSupported.isEmpty())) { + String[] tmpVersions = versionsSupported.split(","); //$NON-NLS-1$ + + for (int j = 0; j < tmpVersions.length; j++) { + if (new Version(version).equals(new Version(tmpVersions[j]))) { + // version is supported. + // Do the automatic conversion without + // prompting the user. + // Get the supported version + String supportedVersion = ManagedBuildManager + .getVersionFromIdAndVersion(builderElement.getId()); + setId(ManagedBuildManager.getIdFromIdAndVersion(getId()) + "_" + supportedVersion); //$NON-NLS-1$ + + // If control comes here means that 'superClass' is null + // So, set the superClass to this builder element + superClass = builderElement; + superClassId = superClass.getId(); + isExists = true; + break; + } + } + if (isExists) + break; // break the outer for loop if 'isExists' is true + } + } + } + } + if (getSuperClass() != null) { + // If 'getSuperClass()' is not null, look for 'convertToId' attribute in plugin + // manifest file for this builder. + String convertToId = getSuperClass().getConvertToId(); + if ((convertToId == null) || (convertToId.isEmpty())) { + // It means there is no 'convertToId' attribute available and + // the version is still actively + // supported by the tool integrator. So do nothing, just return + return; + } else { + // Incase the 'convertToId' attribute is available, + // it means that Tool integrator currently does not support this + // version of builder. + // Look for the converters available for this builder version. + + getConverter(convertToId); + } + + } else { + // make the project is invalid + // + IToolChain parent = getParent(); + IConfiguration parentConfig = parent.getParent(); + IManagedProject managedProject = parentConfig.getManagedProject(); + if (managedProject != null) { + managedProject.setValid(false); + } + } + return; + } + + private void getConverter(String convertToId) { + + String fromId = null; + String toId = null; + + // Get the Converter Extension Point + IExtensionPoint extensionPoint = Platform.getExtensionRegistry().getExtensionPoint( + "org.eclipse.cdt.managedbuilder.core", //$NON-NLS-1$ + "projectConverter"); //$NON-NLS-1$ + if (extensionPoint != null) { + // Get the extensions + IExtension[] extensions = extensionPoint.getExtensions(); + for (int i = 0; i < extensions.length; i++) { + // Get the configuration elements of each extension + IConfigurationElement[] configElements = extensions[i].getConfigurationElements(); + for (int j = 0; j < configElements.length; j++) { + + IConfigurationElement element = configElements[j]; + + if (element.getName().equals("converter")) { //$NON-NLS-1$ + + fromId = element.getAttribute("fromId"); //$NON-NLS-1$ + toId = element.getAttribute("toId"); //$NON-NLS-1$ + // Check whether the current converter can be used for + // the selected builder + + if (fromId.equals(getSuperClass().getId()) && toId.equals(convertToId)) { + // If it matches + String mbsVersion = element.getAttribute("mbsVersion"); //$NON-NLS-1$ + Version currentMbsVersion = ManagedBuildManager.getBuildInfoVersion(); + + // set the converter element based on the MbsVersion + if (currentMbsVersion.compareTo(new Version(mbsVersion)) > 0) { + previousMbsVersionConversionElement = element; + } else { + currentMbsVersionConversionElement = element; + } + return; + } + } + } + } + } + + // If control comes here, it means 'Tool Integrator' specified + // 'convertToId' attribute in toolchain definition file, but + // has not provided any converter. + // So, make the project is invalid + + IToolChain parent = getParent(); + IConfiguration parentConfig = parent.getParent(); + IManagedProject managedProject = parentConfig.getManagedProject(); + if (managedProject != null) { + managedProject.setValid(false); + } + } + + public IConfigurationElement getPreviousMbsVersionConversionElement() { + return previousMbsVersionConversionElement; + } + + public IConfigurationElement getCurrentMbsVersionConversionElement() { + return currentMbsVersionConversionElement; + } + + @Override + public CBuildData getBuildData() { + // return fBuildData; + return null; + } + + // public String[] getCustomizedErrorParserIds(){ + // if(customizedErrorParserIds != null) + // return (String[])customizedErrorParserIds.clone(); + // return null; + // } + + @Override + public String[] getErrorParsers() { + if (isCustomBuilder() && customizedErrorParserIds != null) + return customizedErrorParserIds.clone(); + + IToolChain parent = getParent(); + IConfiguration parentConfig = parent.getParent(); + return parentConfig.getErrorParserList(); + } + + public String[] getCustomizedErrorParserIds() { + if (customizedErrorParserIds != null) + return customizedErrorParserIds.clone(); + return null; + } + + public void setCustomizedErrorParserIds(String[] ids) { + customizedErrorParserIds = ids != null ? (String[]) ids.clone() : ids; + } + + // @Override + public void setErrorParsers(String[] parsers) throws CoreException { + if (isCustomBuilder()) { + customizedErrorParserIds = (parsers != null && parsers.length != 0) ? (String[]) parsers.clone() : parsers; + } else { + IToolChain parent = getParent(); + IConfiguration parentConfig = parent.getParent(); + parentConfig.setErrorParserList(parsers); + } + } + + private Object getMacroContextData() { + return this;//!isExtensionBuilder ? (Object)this : (Object)getParent().getParent(); + } + + //@Override + public String getBuildArguments() { + String args = getArguments(); + IBuildMacroProvider provider = ManagedBuildManager.getBuildMacroProvider(); + + try { + args = provider.resolveValue(args, "", " ", IBuildMacroProvider.CONTEXT_CONFIGURATION, //$NON-NLS-1$//$NON-NLS-2$ + getMacroContextData()); + } catch (BuildMacroException e) { + } + + return args; + } + + @Override + public IPath getBuildCommand() { + String command = getCommand(); + IBuildMacroProvider provider = ManagedBuildManager.getBuildMacroProvider(); + + try { + command = provider.resolveValue(command, "", " ", IBuildMacroProvider.CONTEXT_CONFIGURATION, //$NON-NLS-1$//$NON-NLS-2$ + getMacroContextData()); + } catch (BuildMacroException e) { + } + + return new Path(command); + } + + public String getBuildPathAttribute() { + return getBuildPathAttribute(true); + } + + public String getBuildPathAttribute(boolean querySuperClass) { + if (buildPath == null) { + if (querySuperClass && superClass != null) { + return ((Builder) superClass).getBuildPathAttribute(true); + } + } + return buildPath; + } + + @Override + public void setBuildPath(String path) { + setBuildPathAttribute(path); + } + + public void setBuildPathAttribute(String path) { + buildPath = path; + setDirty(true); + } + + @Override + public String getBuildPath() { + if (isManagedBuildOn()) + return getDefaultBuildPath(); + + String path = getBuildPathAttribute(); + if (path == null) { + path = getDefaultBuildPath(); + // if(isManagedBuildOn() && !isExtensionElement()) { + // buildPath = path; + // } + } + return path; + } + + private boolean isBuildPathEditable() { + return !isManagedBuildOn(); + } + + public String getDefaultBuildPath() { + Configuration cfg = (Configuration) getConfguration(); + IPath buildPath; + String result; + + // Builder extBuilder = (Builder)ManagedBuildManager.getExtensionBuilder(this); + // String attr = extBuilder.getBuildPathAttribute(); + if (cfg != null) { + if (!isExtensionElement() && !cfg.isPreference()) { + IProject project = cfg.getOwner().getProject(); + // if(attr == null){ + if (isManagedBuildOn()) { + IManagedBuilderMakefileGenerator gen = getBuildFileGenerator(); + if (gen instanceof IManagedBuilderMakefileGenerator2) { + ((IManagedBuilderMakefileGenerator2) gen).initialize(IncrementalProjectBuilder.FULL_BUILD, cfg, + this, new NullProgressMonitor()); + } else { + gen.initialize(project, ManagedBuildManager.getBuildInfo(project), new NullProgressMonitor()); + } + + buildPath = gen.getBuildWorkingDir(); + if (buildPath == null) + buildPath = new Path(cfg.getName()); + } else { + buildPath = Path.EMPTY; + } + // } else { + // buildPath = new Path(attr); + // } + + if (!buildPath.isAbsolute()) { + IStringVariableManager mngr = VariablesPlugin.getDefault().getStringVariableManager(); + // build dir may not exist yet and non-existent paths will resolve to empty string by VariablesPlugin + // so append relative part outside of expression, i.e. ${workspace_loc:/Project}/BuildDir + result = mngr.generateVariableExpression("workspace_loc", project.getFullPath().toString()) //$NON-NLS-1$ + + Path.SEPARATOR + buildPath.toString(); + } else { + result = buildPath.toString(); + } + } else { + if (isManagedBuildOn()) { + result = cfg.getName(); + if (result == null) + result = ""; //$NON-NLS-1$ + } else { + result = ""; //$NON-NLS-1$ + } + } + } else { + result = ""; //$NON-NLS-1$ + } + + return result; + } + + /* public boolean isWorkspaceBuildPath(){ + String path = getBuildPathAttribute(); + if(path == null) + return true; + if(isWorkspaceBuildPath == null){ + if(superClass != null) + return superClass.isWorkspaceBuildPath(); + return true; + } + return isWorkspaceBuildPath.booleanValue(); + } + */ + @Override + public IPath getBuildLocation() { + String path = getBuildPath(); + + IBuildMacroProvider provider = ManagedBuildManager.getBuildMacroProvider(); + + try { + path = provider.resolveValue(path, "", " ", IBuildMacroProvider.CONTEXT_CONFIGURATION, //$NON-NLS-1$//$NON-NLS-2$ + getMacroContextData()); + } catch (BuildMacroException e) { + } + + return new Path(path); + } + + @Override + public boolean isDefaultBuildCmd() { + return isExtensionBuilder || (command == null + && args == null /*&& stopOnErr == null && parallelBuildOn == null && parallelNum == null */ + && superClass != null); + } + + @Override + public boolean isDefaultBuildCmdOnly() { + return isExtensionBuilder || (command == null && superClass != null); + } + + @Override + public boolean isDefaultBuildArgsOnly() { + return isExtensionBuilder || (args == null && superClass != null); + } + + @Override + public boolean isStopOnError() { + if (stopOnErr == null) { + if (superClass != null) { + return getSuperClass().isStopOnError(); + } + return true; + } + return stopOnErr.booleanValue(); + } + + @Override + public void setBuildArguments(String args) throws CoreException { + setArguments(args); + } + + @Override + public void setBuildCommand(IPath command) throws CoreException { + String cmd = command != null ? command.toString() : null; + setCommand(cmd); + } + + @Override + public void setBuildLocation(IPath location) throws CoreException { + String path = location != null ? location.toString() : null; + setBuildPath(path); + } + + @Override + public void setStopOnError(boolean on) throws CoreException { + if (isStopOnError() == on) + return; + + if (supportsStopOnError(on)) { + String curCmd = getStopOnErrCmd(isStopOnError()); + String args = getArgumentsAttribute(); + String updatedArgs = removeCmd(args, curCmd); + if (!updatedArgs.equals(args)) + setArgumentsAttribute(updatedArgs); + stopOnErr = on; + } + setDirty(true); + } + + @Override + public void setUseDefaultBuildCmd(boolean on) throws CoreException { + if (!isExtensionBuilder && superClass != null) { + if (on) { + command = null; + args = null; + // stopOnErr = null; + // parallelBuildOn = null; + // parallelNum = null; + } else { + command = getCommand(); + } + } + } + + @Override + public void setUseDefaultBuildCmdOnly(boolean on) throws CoreException { + if (!isExtensionBuilder && superClass != null) { + if (on) { + command = null; + } else { + command = getCommand(); + } + } + } + + @Override + public void setUseDefaultBuildArgsOnly(boolean on) throws CoreException { + if (!isExtensionBuilder && superClass != null) { + if (on) { + args = null; + } else { + args = EMPTY_STRING; + } + } + } + + public String getAutoBuildTargetAttribute() { + if (autoBuildTarget == null) { + if (superClass != null) + return ((Builder) superClass).getAutoBuildTargetAttribute(); + return null; + } + return autoBuildTarget; + } + + @Override + public String getAutoBuildTarget() { + String attr = getAutoBuildTargetAttribute(); + + if (attr != null) { + IBuildMacroProvider provider = ManagedBuildManager.getBuildMacroProvider(); + + try { + attr = provider.resolveValue(attr, "", " ", IBuildMacroProvider.CONTEXT_CONFIGURATION, //$NON-NLS-1$//$NON-NLS-2$ + getMacroContextData()); + } catch (BuildMacroException e) { + } + } + if (attr == null) { + attr = DEFAULT_TARGET_AUTO; + } + + return attr; + } + + public String getCleanBuildTargetAttribute() { + if (cleanBuildTarget == null) { + if (superClass != null) + return ((Builder) superClass).getCleanBuildTargetAttribute(); + return null; + } + return cleanBuildTarget; + } + + @Override + public String getCleanBuildTarget() { + String attr = getCleanBuildTargetAttribute(); + + if (attr != null) { + IBuildMacroProvider provider = ManagedBuildManager.getBuildMacroProvider(); + + try { + attr = provider.resolveValue(attr, "", " ", IBuildMacroProvider.CONTEXT_CONFIGURATION, //$NON-NLS-1$//$NON-NLS-2$ + getMacroContextData()); + } catch (BuildMacroException e) { + } + } + if (attr == null) { + attr = DEFAULT_TARGET_CLEAN; + } + + return attr; + } + + @Override + public String getFullBuildTarget() { + return getIncrementalBuildTarget(); + } + + public String getIncrementalBuildTargetAttribute() { + if (incrementalBuildTarget == null) { + if (superClass != null) + return ((Builder) superClass).getIncrementalBuildTargetAttribute(); + return null; + } + return incrementalBuildTarget; + } + + @Override + public String getIncrementalBuildTarget() { + String attr = getIncrementalBuildTargetAttribute(); + + if (attr != null) { + IBuildMacroProvider provider = ManagedBuildManager.getBuildMacroProvider(); + + try { + attr = provider.resolveValue(attr, "", " ", IBuildMacroProvider.CONTEXT_CONFIGURATION, //$NON-NLS-1$//$NON-NLS-2$ + getMacroContextData()); + } catch (BuildMacroException e) { + } + } + if (attr == null) { + attr = DEFAULT_TARGET_INCREMENTAL; + } + + return attr; + } + + @Override + public boolean isAutoBuildEnable() { + if (autoBuildEnabled == null) { + if (superClass != null) + return getSuperClass().isAutoBuildEnable(); + return false; + } + return autoBuildEnabled.booleanValue(); + } + + @Override + public boolean isCleanBuildEnabled() { + if (cleanBuildEnabled == null) { + if (superClass != null) + return getSuperClass().isCleanBuildEnabled(); + return true; + } + return cleanBuildEnabled.booleanValue(); + } + + @Override + public boolean isFullBuildEnabled() { + return isIncrementalBuildEnabled(); + } + + @Override + public boolean isIncrementalBuildEnabled() { + if (incrementalBuildEnabled == null) { + if (superClass != null) + return getSuperClass().isIncrementalBuildEnabled(); + return true; + } + return incrementalBuildEnabled.booleanValue(); + } + + @Override + public void setAutoBuildEnable(boolean enabled) throws CoreException { + autoBuildEnabled = enabled; + } + + @Override + public void setAutoBuildTarget(String target) throws CoreException { + autoBuildTarget = target; + } + + @Override + public void setCleanBuildEnable(boolean enabled) throws CoreException { + cleanBuildEnabled = enabled; + } + + @Override + public void setCleanBuildTarget(String target) throws CoreException { + cleanBuildTarget = target; + } + + @Override + public void setFullBuildEnable(boolean enabled) throws CoreException { + setIncrementalBuildEnable(enabled); + } + + // @Override + public void setFullBuildTarget(String target) throws CoreException { + setIncrementalBuildTarget(target); + } + + //@Override + public void setIncrementalBuildEnable(boolean enabled) throws CoreException { + incrementalBuildEnabled = enabled; + } + + //@Override + public void setIncrementalBuildTarget(String target) throws CoreException { + incrementalBuildTarget = target; + } + + //@Override + // public boolean appendEnvironment() { + // if (appendEnvironment == null) { + // if (superClass != null) { + // return getSuperClass().appendEnvironment(); + // } + // return true; + // } + // return appendEnvironment.booleanValue(); + // } + + //@Override + public String getBuildAttribute(String name, String defaultValue) { + String result = null; + if (BUILD_TARGET_INCREMENTAL.equals(name)) { + result = getIncrementalBuildTargetAttribute(); + } else if (BUILD_TARGET_AUTO.equals(name)) { + result = getAutoBuildTargetAttribute(); + } else if (BUILD_TARGET_CLEAN.equals(name)) { + result = getCleanBuildTargetAttribute(); + } else if (BUILD_LOCATION.equals(name)) { + result = getBuildPathAttribute(); + } else if (BUILD_COMMAND.equals(name)) { + result = getCommand(); + } else if (BUILD_ARGUMENTS.equals(name)) { + result = getArguments(); + // } else if (BuilderFactory.BUILD_COMMAND.equals(name)) { + // result = getCommand(); + // } else if (BuilderFactory.BUILD_LOCATION.equals(name)) { + // result = getBuildPathAttribute(); + // } else if (BuilderFactory.STOP_ON_ERROR.equals(name)) { + // result = String.valueOf(isStopOnError()); + // } else if (BuilderFactory.USE_DEFAULT_BUILD_CMD.equals(name)) { + // result = String.valueOf(isDefaultBuildCmd()); + // } else if (BuilderFactory.BUILD_TARGET_AUTO.equals(name)) { + // result = getAutoBuildTargetAttribute(); + // } else if (BuilderFactory.BUILD_TARGET_INCREMENTAL.equals(name)) { + // result = getIncrementalBuildTargetAttribute(); + // } else if (BuilderFactory.BUILD_TARGET_FULL.equals(name)) { + // result = getIncrementalBuildTargetAttribute(); + // } else if (BuilderFactory.BUILD_TARGET_CLEAN.equals(name)) { + // result = getCleanBuildTargetAttribute(); + // } else if (BuilderFactory.BUILD_FULL_ENABLED.equals(name)) { + // result = String.valueOf(isFullBuildEnabled()); + // } else if (BuilderFactory.BUILD_CLEAN_ENABLED.equals(name)) { + // result = String.valueOf(isCleanBuildEnabled()); + // } else if (BuilderFactory.BUILD_INCREMENTAL_ENABLED.equals(name)) { + // result = String.valueOf(isIncrementalBuildEnabled()); + // } else if (BuilderFactory.BUILD_AUTO_ENABLED.equals(name)) { + // result = String.valueOf(isAutoBuildEnable()); + // } else if (BuilderFactory.BUILD_ARGUMENTS.equals(name)) { + // result = getArguments(); + // } else if (BuilderFactory.ENVIRONMENT.equals(name)) { + // result = customizedEnvironment != null ? MapStorageElement.encodeMap(customizedEnvironment) : null; + // } else if (BuilderFactory.BUILD_APPEND_ENVIRONMENT.equals(name)) { + // result = String.valueOf(appendEnvironment()); + } else if (customBuildProperties != null) { + result = customBuildProperties.get(name); + } + + if (result == null) + return defaultValue; + return result; + } + + public static String[] toBuildAttributes(String name) { + + // if (ATTRIBUTE_TARGET_INCREMENTAL.equals(name)) { + // return new String[] { BUILD_TARGET_INCREMENTAL, BuilderFactory.BUILD_TARGET_INCREMENTAL, BUILD_TARGET_FULL, + // BuilderFactory.BUILD_TARGET_FULL }; + // } else if (ATTRIBUTE_TARGET_AUTO.equals(name)) { + // return new String[] { BUILD_TARGET_AUTO, BuilderFactory.BUILD_TARGET_AUTO }; + // } else if (ATTRIBUTE_TARGET_CLEAN.equals(name)) { + // return new String[] { BUILD_TARGET_CLEAN, BuilderFactory.BUILD_TARGET_CLEAN }; + // } else if (ATTRIBUTE_BUILD_PATH.equals(name)) { + // return new String[] { BUILD_LOCATION, BuilderFactory.BUILD_LOCATION }; + // } else if (COMMAND.equals(name)) { + // return new String[] { BUILD_COMMAND, BuilderFactory.BUILD_COMMAND }; + // } else if (ARGUMENTS.equals(name)) { + // return new String[] { BUILD_ARGUMENTS, BuilderFactory.BUILD_ARGUMENTS }; + // } else if (ATTRIBUTE_STOP_ON_ERR.equals(name)) { + // return new String[] { BuilderFactory.STOP_ON_ERROR }; + // } //TODO else if(BuilderFactory.USE_DEFAULT_BUILD_CMD.equals(name)){ + // // return getCommand(); + // //} + // else if (ATTRIBUTE_INCREMENTAL_ENABLED.equals(name)) { + // return new String[] { BuilderFactory.BUILD_INCREMENTAL_ENABLED, BuilderFactory.BUILD_FULL_ENABLED }; + // } else if (ATTRIBUTE_CLEAN_ENABLED.equals(name)) { + // return new String[] { BuilderFactory.BUILD_CLEAN_ENABLED }; + // } else if (ATTRIBUTE_AUTO_ENABLED.equals(name)) { + // return new String[] { BuilderFactory.BUILD_AUTO_ENABLED }; + // } else if (ATTRIBUTE_ENVIRONMENT.equals(name)) { + // return new String[] { BuilderFactory.ENVIRONMENT }; + // } else if (ATTRIBUTE_APPEND_ENVIRONMENT.equals(name)) { + // return new String[] { BuilderFactory.BUILD_APPEND_ENVIRONMENT }; + // } else if (ATTRIBUTE_CUSTOMIZED_ERROR_PARSERS.equals(name)) { + // return new String[] { ErrorParserManager.PREF_ERROR_PARSER }; + // } + + return new String[0]; + } + + public static String toBuilderAttribute(String name) { + + // if (BUILD_TARGET_INCREMENTAL.equals(name) || BuilderFactory.BUILD_TARGET_INCREMENTAL.equals(name) + // || BUILD_TARGET_FULL.equals(name) || BuilderFactory.BUILD_TARGET_FULL.equals(name)) { + // return ATTRIBUTE_TARGET_INCREMENTAL; + // } else if (BUILD_TARGET_AUTO.equals(name) || BuilderFactory.BUILD_TARGET_AUTO.equals(name)) { + // return ATTRIBUTE_TARGET_AUTO; + // } else if (BUILD_TARGET_CLEAN.equals(name) || BuilderFactory.BUILD_TARGET_CLEAN.equals(name)) { + // return ATTRIBUTE_TARGET_CLEAN; + // } else if (BUILD_LOCATION.equals(name) || BuilderFactory.BUILD_LOCATION.equals(name)) { + // return ATTRIBUTE_BUILD_PATH; + // } else if (BUILD_COMMAND.equals(name) || BuilderFactory.BUILD_COMMAND.equals(name)) { + // return COMMAND; + // } else if (BUILD_ARGUMENTS.equals(name) || BuilderFactory.BUILD_ARGUMENTS.equals(name)) { + // return ARGUMENTS; + // } else if (BuilderFactory.STOP_ON_ERROR.equals(name)) { + // return ATTRIBUTE_STOP_ON_ERR; + // } //TODO else if(BuilderFactory.USE_DEFAULT_BUILD_CMD.equals(name)){ + // // return getCommand(); + // //} + // else if (BuilderFactory.BUILD_INCREMENTAL_ENABLED.equals(name) + // || BuilderFactory.BUILD_FULL_ENABLED.equals(name)) { + // return ATTRIBUTE_INCREMENTAL_ENABLED; + // } else if (BuilderFactory.BUILD_CLEAN_ENABLED.equals(name)) { + // return ATTRIBUTE_CLEAN_ENABLED; + // } else if (BuilderFactory.BUILD_AUTO_ENABLED.equals(name)) { + // return ATTRIBUTE_AUTO_ENABLED; + // } else if (BuilderFactory.ENVIRONMENT.equals(name)) { + // return ATTRIBUTE_ENVIRONMENT; + // } else if (BuilderFactory.BUILD_APPEND_ENVIRONMENT.equals(name)) { + // return ATTRIBUTE_APPEND_ENVIRONMENT; + // } else if (ErrorParserManager.PREF_ERROR_PARSER.equals(name)) { + // return ATTRIBUTE_CUSTOMIZED_ERROR_PARSERS; + // } + return null; + } + + @Override + public Map getEnvironment() { + if (customizedEnvironment != null) + return cloneMap(customizedEnvironment); + return null; + } + + @Override + public Map getExpandedEnvironment() throws CoreException { + if (customizedEnvironment != null) { + Map expanded = cloneMap(customizedEnvironment); + ICdtVariableManager mngr = CCorePlugin.getDefault().getCdtVariableManager(); + String separator = CCorePlugin.getDefault().getBuildEnvironmentManager().getDefaultDelimiter(); + ICConfigurationDescription cfgDes = ManagedBuildManager + .getDescriptionForConfiguration(getParent().getParent()); + Set> entrySet = expanded.entrySet(); + for (Entry entry : entrySet) { + String value = entry.getValue(); + try { + value = mngr.resolveValue(value, "", separator, cfgDes); //$NON-NLS-1$ + entry.setValue(value); + } catch (CdtVariableException e) { + } + } + + return expanded; + } + return null; + } + + @Override + public void setAppendEnvironment(boolean append) throws CoreException { + appendEnvironment = append; + } + + @Override + public void setBuildAttribute(String name, String value) throws CoreException { + // if (BUILD_TARGET_INCREMENTAL.equals(name)) { + // incrementalBuildTarget = value; + // } else if (BUILD_TARGET_AUTO.equals(name)) { + // autoBuildTarget = value; + // } else if (BUILD_TARGET_CLEAN.equals(name)) { + // cleanBuildTarget = value; + // } else if (BUILD_LOCATION.equals(name)) { + // buildPath = value; + // } else if (BUILD_COMMAND.equals(name)) { + // command = value; + // } else if (BUILD_ARGUMENTS.equals(name)) { + // args = value; + // } else if (BuilderFactory.BUILD_COMMAND.equals(name)) { + // command = value; + // } else if (BuilderFactory.BUILD_LOCATION.equals(name)) { + // buildPath = value; + // } else if (BuilderFactory.STOP_ON_ERROR.equals(name)) { + // stopOnErr = Boolean.valueOf(value); + // } else if (BuilderFactory.USE_DEFAULT_BUILD_CMD.equals(name)) { + // if (value == null || Boolean.parseBoolean(value)) { + // if (superClass != null) + // command = null; + // } + // } else if (BuilderFactory.BUILD_TARGET_AUTO.equals(name)) { + // autoBuildTarget = value; + // } else if (BuilderFactory.BUILD_TARGET_INCREMENTAL.equals(name)) { + // incrementalBuildTarget = value; + // } else if (BuilderFactory.BUILD_TARGET_FULL.equals(name)) { + // autoBuildTarget = value; + // } else if (BuilderFactory.BUILD_TARGET_CLEAN.equals(name)) { + // cleanBuildTarget = value; + // } else if (BuilderFactory.BUILD_FULL_ENABLED.equals(name)) { + // autoBuildEnabled = value != null ? Boolean.valueOf(value) : null; + // } else if (BuilderFactory.BUILD_CLEAN_ENABLED.equals(name)) { + // cleanBuildEnabled = value != null ? Boolean.valueOf(value) : null; + // } else if (BuilderFactory.BUILD_INCREMENTAL_ENABLED.equals(name)) { + // incrementalBuildEnabled = value != null ? Boolean.valueOf(value) : null; + // } else if (BuilderFactory.BUILD_AUTO_ENABLED.equals(name)) { + // autoBuildEnabled = value != null ? Boolean.valueOf(value) : null; + // } else if (BuilderFactory.BUILD_ARGUMENTS.equals(name)) { + // args = value; + // } else if (BuilderFactory.ENVIRONMENT.equals(name)) { + // if (value == null) { + // customizedEnvironment = null; + // } else { + // customizedEnvironment = MapStorageElement.decodeMap(value); + // } + // } else if (BuilderFactory.BUILD_APPEND_ENVIRONMENT.equals(name)) { + // appendEnvironment = value != null ? Boolean.valueOf(value) : null; + // } else { + // getCustomBuildPropertiesMap().put(name, value); + // } + } + + private Map getCustomBuildPropertiesMap() { + if (customBuildProperties == null) { + customBuildProperties = new HashMap<>(); + } + return customBuildProperties; + } + + @Override + public void setEnvironment(Map env) throws CoreException { + customizedEnvironment = new HashMap<>(env); + } + + @Override + public boolean isCustomBuilder() { + if (!isExtensionBuilder && getParent().getBuilder() != this) + return true; + return false; + } + + public IConfiguration getConfguration() { + if (getParent() != null) + return getParent().getParent(); + return null; + } + + @Override + public boolean isManagedBuildOn() { + IConfiguration cfg = getConfguration(); + if (cfg != null) { + if (!cfg.supportsBuild(true)) + return false; + else if (!cfg.supportsBuild(false)) + return true; + } + + Boolean attr = getManagedBuildOnAttribute(); + if (attr != null) + return attr.booleanValue(); + return true; + } + + public Boolean getManagedBuildOnAttribute() { + if (managedBuildOn == null) { + if (superClass != null) + return ((Builder) superClass).getManagedBuildOnAttribute(); + return null; + } + return managedBuildOn; + } + + @Override + public void setManagedBuildOn(boolean on) { + managedBuildOn = on; + } + + @Override + public boolean canKeepEnvironmentVariablesInBuildfile() { + return BuildMacroProvider.canKeepMacrosInBuildfile(this); + } + + @Override + public boolean keepEnvironmentVariablesInBuildfile() { + if (keepEnvVarInBuildfile == null) { + if (superClass != null) + return getSuperClass().keepEnvironmentVariablesInBuildfile(); + return false; + } + return keepEnvVarInBuildfile.booleanValue(); + } + + @Override + public void setKeepEnvironmentVariablesInBuildfile(boolean keep) { + keepEnvVarInBuildfile = keep; + } + + @Override + public boolean supportsCustomizedBuild() { + if (fSupportsCustomizedBuild == null) { + IManagedBuilderMakefileGenerator makeGen = getBuildFileGenerator(); + if (makeGen instanceof IManagedBuilderMakefileGenerator2) + fSupportsCustomizedBuild = true; + else + fSupportsCustomizedBuild = false; + } + return fSupportsCustomizedBuild.booleanValue(); + } + + @Override + public boolean supportsBuild(boolean managed) { + if (supportsManagedBuild == null) { + if (superClass != null) + return getSuperClass().supportsBuild(managed); + return managed || !isInternalBuilder(); + } + return supportsManagedBuild.booleanValue(); + } + + public void setParent(IToolChain toolChain) { + parent = toolChain; + } + + @Override + public boolean matches(IBuilder builder) { + if (builder == this) + return true; + + IBuilder rBld = ManagedBuildManager.getRealBuilder(this); + if (rBld == null) + return false; + + return rBld == ManagedBuildManager.getRealBuilder(builder); + } + + @Override + public MatchKey getMatchKey() { + if (isAbstract()) + return null; + if (!isExtensionBuilder) + return null; + return new MatchKey<>(this); + } + + @Override + public void setIdenticalList(List list) { + identicalList = list; + } + + public String getNameAndVersion() { + String name = getName(); + String version = ManagedBuildManager.getVersionFromIdAndVersion(getId()); + if (version != null && version.length() != 0) { + return new StringBuilder().append(name).append(" (").append(version).append("").toString(); //$NON-NLS-1$ //$NON-NLS-2$ + } + return name; + } + + @Override + public List getIdenticalList() { + return identicalList; + } + + @Override + public boolean isInternalBuilder() { + IBuilder internalBuilder = ManagedBuildManager.getInternalBuilder(); + for (IBuilder builder = this; builder != null; builder = builder.getSuperClass()) { + if (internalBuilder == builder) + return true; + } + return false; + } + + /** + * Returns the optimal number of parallel jobs. + * The number is the number of available processors on the machine. + * + * The function never returns number smaller than 1. + */ + public int getOptimalParallelJobNum() { + // Bug 398426: On my Mac running parallel builds at full tilt hangs the desktop. + // Need to pull it back one. + int j = Runtime.getRuntime().availableProcessors(); + if (j > 1 && Platform.getOS().equals(Platform.OS_MACOSX)) + return j - 1; + else + return j; + } + + /** + * Returns the internal representation of maximum number of parallel jobs + * to be used for a build. + * Note that negative number represents "optimal" value. + * + * The value of the number is encoded as follows: + * + *
    +     *  Status       Returns
    +     * No parallel      1
    +     * Optimal       -CPU# (negative number of processors)
    +     * Specific        >0  (positive number)
    +     * Unlimited    Builder.UNLIMITED_JOBS
    +     * 
    + */ + public int getParallelizationNumAttribute() { + if (!isParallelBuildOn()) + return 1; + + if (parallelNumberAttribute == null) { + if (superClass != null) { + return ((Builder) superClass).getParallelizationNumAttribute(); + } + return 1; + } + return parallelNumberAttribute.intValue(); + } + + private void setParallelizationNumAttribute(int parallelNumber) { + isParallelBuildEnabled = (parallelNumber != 1); + if (parallelNumber > 0) { + parallelNumberAttribute = parallelNumber; + } else { + // "optimal" + parallelNumberAttribute = -getOptimalParallelJobNum(); + } + } + + @Override + public int getParallelizationNum() { + return Math.abs(getParallelizationNumAttribute()); + } + + /** + * {@inheritDoc} + * + * @param jobs + * - maximum number of jobs. There are 2 special cases: + *
    + * - any number <=0 is interpreted as setting "optimal" property, + * the value of the number itself is ignored in this case + *
    + * - value 1 will turn parallel mode off. + */ + @Override + public void setParallelizationNum(int jobs) throws CoreException { + if (!supportsParallelBuild()) + return; + + if (parallelNumberAttribute == null || parallelNumberAttribute != jobs) { + String curCmd = getParallelizationCmd(getParallelizationNum()); + String args = getArgumentsAttribute(); + String updatedArgs = removeCmd(args, curCmd); + if (!updatedArgs.equals(args)) { + setArgumentsAttribute(updatedArgs); + } + + setParallelizationNumAttribute(jobs); + setDirty(true); + } + } + + @Override + public boolean supportsParallelBuild() { + if (isInternalBuilder()) + return true; + return getParrallelBuildCmd().length() != 0; + } + + @Override + public boolean supportsStopOnError(boolean on) { + if (isInternalBuilder()) + return true; + + if (!on) + return getIgnoreErrCmdAttribute().length() != 0; + return true; + } + + public String getStopOnErrCmd(boolean stop) { + if (!stop) + return getIgnoreErrCmdAttribute(); + return EMPTY_STRING; + } + + public String getIgnoreErrCmdAttribute() { + if (ignoreErrCmd == null) { + if (superClass != null) { + return ((Builder) superClass).getIgnoreErrCmdAttribute(); + } + return EMPTY_STRING; + } + return ignoreErrCmd; + } + + public String getParrallelBuildCmd() { + if (parallelBuildCmd == null) { + if (superClass != null) { + return ((Builder) superClass).getParrallelBuildCmd(); + } + return EMPTY_STRING; + } + return parallelBuildCmd; + } + + @Override + public boolean isParallelBuildOn() { + if (!supportsParallelBuild()) { + return false; + } + if (isParallelBuildEnabled == null) { + if (superClass != null) { + return getSuperClass().isParallelBuildOn(); + } + return false; + } + return isParallelBuildEnabled.booleanValue(); + } + + /** + * {@inheritDoc} + * + * @param on + * - the flag to enable or disable parallel mode. + *
    + * {@code true} to enable, in this case the maximum number of jobs + * will be set to "optimal" number, see + * {@link #getOptimalParallelJobNum()}. + *
    + * {@code false} to disable, the number of jobs will be set to 1. + */ + @Override + public void setParallelBuildOn(boolean on) throws CoreException { + if (on) { + // set "optimal" jobs by default when enabling parallel build + setParallelizationNum(-1); + } else { + setParallelizationNum(1); + } + } + + public Set contributeErrorParsers(Set set) { + if (getErrorParserIds() != null) { + if (set == null) + set = new HashSet<>(); + + String ids[] = getErrorParserList(); + if (ids.length != 0) + set.addAll(Arrays.asList(ids)); + } + return set; + } + + public void resetErrorParsers() { + errorParserIds = null; + } + + void removeErrorParsers(Set set) { + Set oldSet = contributeErrorParsers(null); + if (oldSet == null) + oldSet = new HashSet<>(); + oldSet.removeAll(set); + setErrorParserList(oldSet.toArray(new String[oldSet.size()])); + } + + public void setErrorParserList(String[] ids) { + if (ids == null) { + errorParserIds = null; + } else if (ids.length == 0) { + errorParserIds = EMPTY_STRING; + } else { + StringBuilder buf = new StringBuilder(); + buf.append(ids[0]); + for (int i = 1; i < ids.length; i++) { + buf.append(";").append(ids[i]); //$NON-NLS-1$ + } + errorParserIds = buf.toString(); + } + } + + @Override + public boolean isSystemObject() { + if (isTest) + return true; + + if (getConvertToId().length() != 0) + return true; + + if (getParent() != null) + return getParent().isSystemObject(); + return false; + } + + @Override + public String getUniqueRealName() { + String name = getName(); + if (name == null) { + name = getId(); + } else { + String version = ManagedBuildManager.getVersionFromIdAndVersion(getId()); + if (version != null) { + StringBuilder buf = new StringBuilder(); + buf.append(name); + buf.append(" (v").append(version).append(")"); //$NON-NLS-1$ //$NON-NLS-2$ + name = buf.toString(); + } + } + return name; + } + + public ICOutputEntry[] getOutputEntries() { + if (isManagedBuildOn()) { + return getDefaultOutputSettings(); + } + ICOutputEntry[] entries = getOutputEntrySettings(); + if (entries == null || entries.length == 0) { + entries = getDefaultOutputSettings(); + } + return entries; + } + + private ICOutputEntry[] getDefaultOutputSettings() { + Configuration cfg = (Configuration) getConfguration(); + if (cfg == null || cfg.isPreference() || cfg.isExtensionElement()) { + return new ICOutputEntry[] { new COutputEntry(Path.EMPTY, null, + ICLanguageSettingEntry.VALUE_WORKSPACE_PATH | ICLanguageSettingEntry.RESOLVED) }; + } + + IPath path = ManagedBuildManager.getBuildFullPath(cfg, this); + IProject proj = cfg.getOwner().getProject(); + IPath projFullPath = proj.getFullPath(); + if (path != null && projFullPath.isPrefixOf(path)) { + path = path.removeFirstSegments(projFullPath.segmentCount()).makeRelative(); + } else { + path = Path.EMPTY; + } + + return new ICOutputEntry[] { new COutputEntry(path, null, + ICLanguageSettingEntry.VALUE_WORKSPACE_PATH | ICLanguageSettingEntry.RESOLVED) }; + } + + public ICOutputEntry[] getOutputEntrySettings() { + if (outputEntries == null) { + if (superClass != null) { + return ((Builder) superClass).getOutputEntrySettings(); + } + return null; + + } + return outputEntries.clone(); + } + + public void setOutputEntries(ICOutputEntry[] entries) { + if (entries != null) + outputEntries = entries.clone(); + else + outputEntries = null; + } + + private int getSuperClassNum() { + int num = 0; + for (IBuilder superTool = getSuperClass(); superTool != null; superTool = superTool.getSuperClass()) { + num++; + } + return num; + } + + @Override + public int compareTo(Builder other) { + if (other.isSystemObject() != isSystemObject()) + return isSystemObject() ? 1 : -1; + + return getSuperClassNum() - other.getSuperClassNum(); + } + + @Override + public IRealBuildObjectAssociation getExtensionObject() { + return (Builder) ManagedBuildManager.getExtensionBuilder(this); + } + + @Override + public IRealBuildObjectAssociation[] getIdenticBuildObjects() { + return null; + //return (IRealBuildObjectAssociation[]) ManagedBuildManager.findIdenticalBuilders(this); + } + + @Override + public IRealBuildObjectAssociation getRealBuildObject() { + return (Builder) ManagedBuildManager.getRealBuilder(this); + } + + @Override + public IRealBuildObjectAssociation getSuperClassObject() { + return (Builder) getSuperClass(); + } + + @Override + public final int getType() { + return OBJECT_BUILDER; + } + + @Override + public boolean isRealBuildObject() { + return ManagedBuildManager.getRealBuilder(this) == this; + } + + @Override + public boolean isExtensionBuildObject() { + return isExtensionElement(); + } + + @Override + public String toString() { + return getUniqueRealName(); + } + + @Override + public ICommandLauncher getCommandLauncher() { + if (fCommandLauncherElement != null) { + try { + return (ICommandLauncher) fCommandLauncherElement.createExecutableExtension(ATTRIBUTE_COMMAND_LAUNCHER); + } catch (CoreException e) { + e.printStackTrace(); + } + } + if (superClass != null) + return getSuperClass().getCommandLauncher(); + + // catch all for backwards compatibility + return CommandLauncherManager.getInstance().getCommandLauncher(); + } + + @Override + public AbstractBuildRunner getBuildRunner() throws CoreException { + // Already defined + if (fBuildRunner != null) + return fBuildRunner; + + // Instantiate from model + if (fBuildRunnerElement != null) { + fBuildRunner = (AbstractBuildRunner) fBuildRunnerElement.createExecutableExtension(ATTRIBUTE_BUILD_RUNNER); + return fBuildRunner; + } + + // Check with superClass + if (superClass != null) + return getSuperClass().getBuildRunner(); + + // Default internal or external builder + if (isInternalBuilder()) + return new InternalBuildRunner(); + + //return new ExternalBuildRunner(); + return null; + } + + @Override + protected IResourceInfo getParentResourceInfo() { + // There are no resources associated with builders + return null; + } + + @Override + public boolean appendEnvironment() { + // TODO Auto-generated method stub + return false; + } + +} diff --git a/io.sloeber.ManagedBuild/src/io/sloeber/autoBuild/Internal/BuildfileMacroSubstitutor.java b/io.sloeber.ManagedBuild/src/io/sloeber/autoBuild/Internal/BuildfileMacroSubstitutor.java new file mode 100644 index 000000000..7acd574f3 --- /dev/null +++ b/io.sloeber.ManagedBuild/src/io/sloeber/autoBuild/Internal/BuildfileMacroSubstitutor.java @@ -0,0 +1,302 @@ +/******************************************************************************* + * Copyright (c) 2005, 2011 Intel Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Intel Corporation - Initial API and implementation + *******************************************************************************/ +package io.sloeber.autoBuild.Internal; + +import java.util.HashSet; +import java.util.Set; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.eclipse.cdt.core.CCorePlugin; +import org.eclipse.cdt.core.cdtvariables.CdtVariableException; +import org.eclipse.cdt.core.cdtvariables.ICdtVariable; +import org.eclipse.cdt.core.cdtvariables.ICdtVariableManager; +import org.eclipse.cdt.core.settings.model.ICConfigurationDescription; +//import org.eclipse.cdt.managedbuilder.core.IBuildObject; +//import org.eclipse.cdt.managedbuilder.core.IBuilder; +//import org.eclipse.cdt.managedbuilder.core.IConfiguration; +//import org.eclipse.cdt.managedbuilder.core.IInputType; +//import org.eclipse.cdt.managedbuilder.core.IManagedBuildInfo; +//import org.eclipse.cdt.managedbuilder.core.IManagedProject; +//import org.eclipse.cdt.managedbuilder.core.IOutputType; +//import org.eclipse.cdt.managedbuilder.core.IResourceInfo; +//import org.eclipse.cdt.managedbuilder.core.ITool; +//import org.eclipse.cdt.managedbuilder.core.ManagedBuildManager; +//import org.eclipse.cdt.managedbuilder.macros.IBuildMacroProvider; +//import org.eclipse.cdt.managedbuilder.macros.IReservedMacroNameSupplier; +import org.eclipse.cdt.utils.cdtvariables.CdtVariableResolver; +import org.eclipse.cdt.utils.cdtvariables.IVariableContextInfo; +import org.eclipse.cdt.utils.cdtvariables.SupplierBasedCdtVariableSubstitutor; +import org.eclipse.cdt.utils.envvar.EnvVarOperationProcessor; +import org.eclipse.core.resources.IResource; + +import io.sloeber.autoBuild.api.IBuildMacroProvider; +import io.sloeber.autoBuild.api.IBuildObject; +import io.sloeber.autoBuild.api.IBuilder; +import io.sloeber.autoBuild.api.IConfiguration; +import io.sloeber.autoBuild.api.IInputType; +import io.sloeber.autoBuild.api.IManagedBuildInfo; +import io.sloeber.autoBuild.api.IManagedProject; +import io.sloeber.autoBuild.api.IOutputType; +import io.sloeber.autoBuild.api.IReservedMacroNameSupplier; +import io.sloeber.autoBuild.api.IResourceInfo; +import io.sloeber.autoBuild.api.ITool; + +/** + * This substitutor resolves all macro references except for the environment + * macro references + * If a user has chosen to keep those macros in the buildfile, the environment + * macro references + * are converted to the buildfile variable references, otherwise those macros + * are also resolved + * + * @see org.eclipse.cdt.managedbuilder.internal.macros#IMacroSubstitutor + * @since 3.0 + */ +public class BuildfileMacroSubstitutor extends SupplierBasedCdtVariableSubstitutor { + private static final String PATTERN_MACRO_NAME = "="; //$NON-NLS-1$ + private IConfiguration fConfiguration; + private IBuilder fBuilder; + private ICdtVariableManager fVarMngr; + private ICConfigurationDescription fCfgDes; + + private class DefaultReservedMacroNameSupplier implements IReservedMacroNameSupplier { + String fReservedNames[]; + + public DefaultReservedMacroNameSupplier(IConfiguration configuration) { + IBuilder builder = configuration.getToolChain().getBuilder(); + String reservedNames[] = builder.getReservedMacroNames(); + String buildVars[] = getConfigurationReservedNames(configuration); + + if (reservedNames == null || reservedNames.length == 0) + fReservedNames = buildVars; + else if (buildVars == null || buildVars.length == 0) + fReservedNames = reservedNames; + else { + fReservedNames = new String[reservedNames.length + buildVars.length]; + System.arraycopy(reservedNames, 0, fReservedNames, 0, reservedNames.length); + System.arraycopy(buildVars, 0, fReservedNames, reservedNames.length, buildVars.length); + } + } + + /* (non-Javadoc) + * @see org.eclipse.cdt.managedbuilder.macros.IReservedMacroNameSupplier#isReservedName(java.lang.String, org.eclipse.cdt.managedbuilder.core.IConfiguration) + */ + @Override + public boolean isReservedName(String macroName, IConfiguration configuration) { + if (fReservedNames != null && fReservedNames.length > 0) { + for (int i = 0; i < fReservedNames.length; i++) { + Pattern p = Pattern.compile(fReservedNames[i]); + Matcher m = p.matcher(macroName); + if (m.matches()) + return true; + } + } + return false; + } + + protected String[] getConfigurationReservedNames(IConfiguration configuration) { + ITool tools[] = configuration.getFilteredTools(); + if (tools != null) { + Set set = new HashSet<>(); + for (int i = 0; i < tools.length; i++) { + IOutputType ots[] = tools[i].getOutputTypes(); + if (ots != null) { + for (int j = 0; j < ots.length; j++) { + String varName = ots[j].getBuildVariable(); + if (varName != null) { + set.add(varName); + } + } + } + + IInputType its[] = tools[i].getInputTypes(); + if (its != null) { + for (int j = 0; j < its.length; j++) { + String varName = its[j].getBuildVariable(); + if (varName != null) { + set.add(varName); + } + } + } + + } + + return set.toArray(new String[set.size()]); + } + return null; + } + } + + // public BuildfileMacroSubstitutor(int contextType, Object contextData, String inexistentMacroValue, String listDelimiter){ + // super(contextType, contextData, inexistentMacroValue, listDelimiter); + // init(); + // } + + public BuildfileMacroSubstitutor(IBuilder builder, IMacroContextInfo contextInfo, String inexistentMacroValue, + String listDelimiter) { + super(contextInfo, inexistentMacroValue, listDelimiter); + init(builder, contextInfo); + } + + public BuildfileMacroSubstitutor(IMacroContextInfo contextInfo, String inexistentMacroValue, String listDelimiter) { + this(null, contextInfo, inexistentMacroValue, listDelimiter); + } + + private void init(IBuilder builder, IMacroContextInfo contextInfo) { + if (contextInfo == null) + return; + + fVarMngr = CCorePlugin.getDefault().getCdtVariableManager(); + + if (builder != null) { + fBuilder = builder; + fConfiguration = builder.getParent().getParent(); + } else { + IBuildObject[] bos = findConfigurationAndBuilderFromContext(contextInfo); + if (bos != null) { + fConfiguration = (IConfiguration) bos[0]; + fBuilder = (IBuilder) bos[1]; + } + } + + if (fConfiguration != null) { + fCfgDes = ManagedBuildManager.getDescriptionForConfiguration(fConfiguration); + } + } + + static IBuildObject[] findConfigurationAndBuilderFromContext(IMacroContextInfo contextInfo) { + int type = contextInfo.getContextType(); + IConfiguration cfg = null; + IBuilder builder = null; + switch (type) { + case IBuildMacroProvider.CONTEXT_FILE: + contextInfo = (IMacroContextInfo) contextInfo.getNext(); + if (contextInfo == null) + break; + case IBuildMacroProvider.CONTEXT_OPTION: + contextInfo = (IMacroContextInfo) contextInfo.getNext(); + if (contextInfo == null) + break; + case IBuildMacroProvider.CONTEXT_CONFIGURATION: { + Object contextData = contextInfo.getContextData(); + if (contextData instanceof IConfiguration) { + cfg = (IConfiguration) contextData; + builder = cfg.getBuilder(); + } else if (contextData instanceof IBuilder) { + builder = (IBuilder) contextData; + cfg = builder.getParent().getParent(); + } else if (contextData instanceof ITool) { + ITool tool = (ITool) contextData; + IResourceInfo rcInfo = tool.getParentResourceInfo(); + if (rcInfo != null) { + cfg = rcInfo.getParent(); + if (cfg != null) { + builder = cfg.getBuilder(); + } + } + } + } + break; + case IBuildMacroProvider.CONTEXT_PROJECT: { + Object contextData = contextInfo.getContextData(); + if (contextData instanceof IManagedProject) { + IResource rc = ((IManagedProject) contextData).getOwner(); + if (rc != null) { + IManagedBuildInfo info = ManagedBuildManager.getBuildInfo(rc); + cfg = info.getDefaultConfiguration(); + builder = cfg.getBuilder(); + } + } + } + break; + } + + if (cfg != null && builder != null) + return new IBuildObject[] { cfg, builder }; + return null; + } + + /* (non-Javadoc) + * @see org.eclipse.cdt.managedbuilder.internal.macros.DefaultMacroSubstitutor#resolveMacro(org.eclipse.cdt.managedbuilder.macros.IBuildMacro) + */ + @Override + protected ResolvedMacro resolveMacro(ICdtVariable macro) throws CdtVariableException { + ResolvedMacro resolved = null; + + if (fConfiguration != null && fBuilder != null && fBuilder.keepEnvironmentVariablesInBuildfile() + && fVarMngr.isEnvironmentVariable(macro, fCfgDes) + && (!CdtVariableResolver.isStringListVariable(macro.getValueType()) + || size(macro.getStringListValue()) < 2)) { + String ref = getMacroReference(macro); + if (ref != null) + resolved = new ResolvedMacro(macro.getName(), ref); + + } + if (resolved != null) + return resolved; + return super.resolveMacro(macro); + } + + private static int size(String[] value) { + return value != null ? value.length : 0; + } + + public IConfiguration getConfiguration() { + return fConfiguration; + } + + protected IReservedMacroNameSupplier getReservedMacroNameSupplier() { + if (fBuilder == null) + return null; + IReservedMacroNameSupplier supplier = fBuilder.getReservedMacroNameSupplier(); + if (supplier == null) + supplier = new DefaultReservedMacroNameSupplier(fConfiguration); + + return supplier; + } + + protected String getMacroReference(ICdtVariable macro) { + String macroName = macro.getName(); + String ref = null; + IReservedMacroNameSupplier supplier = getReservedMacroNameSupplier(); + macroName = EnvVarOperationProcessor.normalizeName(macroName); + if (supplier == null || !supplier.isReservedName(macroName, fConfiguration)) { + String pattern = fBuilder.getBuilderVariablePattern(); + if (pattern != null && pattern.indexOf(PATTERN_MACRO_NAME) != -1) { + ref = pattern.replaceAll(PATTERN_MACRO_NAME, macroName); + } + } + return ref; + } + + /* (non-Javadoc) + * @see org.eclipse.cdt.managedbuilder.internal.macros.DefaultMacroSubstitutor#setMacroContextInfo(org.eclipse.cdt.managedbuilder.internal.macros.IMacroContextInfo) + */ + @Override + public void setMacroContextInfo(IVariableContextInfo info) throws CdtVariableException { + super.setMacroContextInfo(info); + if (info instanceof IMacroContextInfo) + init(null, (IMacroContextInfo) info); + } + + /* (non-Javadoc) + * @see org.eclipse.cdt.managedbuilder.internal.macros.IMacroSubstitutor#setMacroContextInfo(int, java.lang.Object) + */ + // public void setMacroContextInfo(int contextType, Object contextData) throws BuildMacroException{ + // super.setMacroContextInfo(contextType, contextData); + // init(); + // } + +} diff --git a/io.sloeber.ManagedBuild/src/io/sloeber/autoBuild/Internal/CompositeExpression.java b/io.sloeber.ManagedBuild/src/io/sloeber/autoBuild/Internal/CompositeExpression.java new file mode 100644 index 000000000..602582c08 --- /dev/null +++ b/io.sloeber.ManagedBuild/src/io/sloeber/autoBuild/Internal/CompositeExpression.java @@ -0,0 +1,98 @@ +/******************************************************************************* + * Copyright (c) 2005, 2010 Intel Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Intel Corporation - Initial API and implementation + *******************************************************************************/ +package io.sloeber.autoBuild.Internal; + +import java.util.Map; +import java.util.Set; + +import io.sloeber.autoBuild.api.IManagedConfigElement; + +//import org.eclipse.cdt.managedbuilder.core.IManagedConfigElement; + +public abstract class CompositeExpression implements IBooleanExpression { + private IBooleanExpression fChildren[]; + + protected CompositeExpression(IManagedConfigElement element) { + IManagedConfigElement childElement[] = element.getChildren(); + IBooleanExpression children[] = new IBooleanExpression[childElement.length]; + int num = 0; + for (int i = 0; i < childElement.length; i++) { + IBooleanExpression child = createExpression(childElement[i]); + if (child != null) + children[num++] = child; + } + + if (num < children.length) { + IBooleanExpression tmp[] = new IBooleanExpression[num]; + System.arraycopy(children, 0, tmp, 0, num); + children = tmp; + } + fChildren = children; + } + + protected IBooleanExpression createExpression(IManagedConfigElement element) { + String name = element.getName(); + //TOFIX this code should not be removerd but treplaced + // if (AndExpression.NAME.equals(name)) + // return new AndExpression(element); + // else if (OrExpression.NAME.equals(name)) + // return new OrExpression(element); + // else if (NotExpression.NAME.equals(name)) + // return new NotExpression(element); + // else if (CheckOptionExpression.NAME.equals(name)) + // return new CheckOptionExpression(element); + // else if (CheckStringExpression.NAME.equals(name)) + // return new CheckStringExpression(element); + // else if (FalseExpression.NAME.equals(name)) + // return new FalseExpression(element); + // else if (CheckHolderExpression.NAME.equals(name)) + // return new CheckHolderExpression(element); + // else if (CheckBuildPropertyExpression.NAME.equals(name)) + // return new CheckBuildPropertyExpression(element); + // else if (HasNatureExpression.NAME.equals(name)) + // return new HasNatureExpression(element); + return null; + } + + public IBooleanExpression[] getChildren() { + return fChildren; + } + + public Map> getReferencedProperties(Map> map) { + //TOFIX implement something + // IBooleanExpression children[] = getChildren(); + // if (map == null) + // map = new HashMap<>(); + // + // for (int i = 0; i < children.length; i++) { + // IBooleanExpression child = children[i]; + // if (child instanceof CompositeExpression) { + // ((CompositeExpression) child).getReferencedProperties(map); + // } else if (child instanceof CheckBuildPropertyExpression) { + // CheckBuildPropertyExpression bp = (CheckBuildPropertyExpression) child; + // String prop = bp.getPropertyId(); + // String val = bp.getValueId(); + // if (prop != null && prop.length() != 0 && val != null && val.length() != 0) { + // Set set = map.get(prop); + // if (set == null) { + // set = new HashSet<>(); + // map.put(prop, set); + // } + // set.add(val); + // } + // } + // } + return map; + } +} diff --git a/io.sloeber.ManagedBuild/src/io/sloeber/autoBuild/Internal/Configuration.java b/io.sloeber.ManagedBuild/src/io/sloeber/autoBuild/Internal/Configuration.java new file mode 100644 index 000000000..57663173c --- /dev/null +++ b/io.sloeber.ManagedBuild/src/io/sloeber/autoBuild/Internal/Configuration.java @@ -0,0 +1,3225 @@ +/******************************************************************************* + * Copyright (c) 2003, 2016 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM - Initial API and implementation + * James Blackburn (Broadcom Corp.) + * Dmitry Kozlov (CodeSourcery) - Save build output preferences (bug 294106) + * Andrew Gvozdev (Quoin Inc) - Saving build output implemented in different way (bug 306222) + *******************************************************************************/ +package io.sloeber.autoBuild.Internal; + +import static io.sloeber.autoBuild.core.Messages.*; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.StringTokenizer; +import java.util.Vector; + +//import org.eclipse.cdt.build.core.scannerconfig.ICfgScannerConfigBuilderInfo2Set; +//import org.eclipse.cdt.build.internal.core.scannerconfig.CfgDiscoveredPathManager.PathInfoCache; +import org.eclipse.cdt.core.ErrorParserManager; +import org.eclipse.cdt.core.cdtvariables.CdtVariableException; +import org.eclipse.cdt.core.settings.model.CSourceEntry; +import org.eclipse.cdt.core.settings.model.ICConfigurationDescription; +import org.eclipse.cdt.core.settings.model.ICExternalSetting; +import org.eclipse.cdt.core.settings.model.ICLibraryPathEntry; +import org.eclipse.cdt.core.settings.model.ICOutputEntry; +import org.eclipse.cdt.core.settings.model.ICSettingBase; +import org.eclipse.cdt.core.settings.model.ICSettingEntry; +import org.eclipse.cdt.core.settings.model.ICSourceEntry; +import org.eclipse.cdt.core.settings.model.ICStorageElement; +import org.eclipse.cdt.core.settings.model.extension.CBuildData; +import org.eclipse.cdt.core.settings.model.extension.CConfigurationData; +import org.eclipse.cdt.core.settings.model.util.CDataUtil; +import org.eclipse.cdt.core.settings.model.util.LanguageSettingEntriesSerializer; +import org.eclipse.cdt.core.settings.model.util.PathSettingsContainer; +import org.eclipse.cdt.internal.core.SafeStringInterner; +//import org.eclipse.cdt.managedbuilder.buildproperties.IBuildProperty; +//import org.eclipse.cdt.managedbuilder.buildproperties.IBuildPropertyType; +//import org.eclipse.cdt.managedbuilder.buildproperties.IBuildPropertyValue; +//import org.eclipse.cdt.managedbuilder.buildproperties.IOptionalBuildProperties; +//import org.eclipse.cdt.managedbuilder.core.BuildException; +//import org.eclipse.cdt.managedbuilder.core.IBuildObject; +//import org.eclipse.cdt.managedbuilder.core.IBuildObjectProperties; +//import org.eclipse.cdt.managedbuilder.core.IBuildPropertiesRestriction; +//import org.eclipse.cdt.managedbuilder.core.IBuilder; +//import org.eclipse.cdt.managedbuilder.core.IConfiguration; +//import org.eclipse.cdt.managedbuilder.core.IFileInfo; +//import org.eclipse.cdt.managedbuilder.core.IFolderInfo; +//import org.eclipse.cdt.managedbuilder.core.IHoldsOptions; +//import org.eclipse.cdt.managedbuilder.core.IManagedCommandLineGenerator; +//import org.eclipse.cdt.managedbuilder.core.IManagedCommandLineInfo; +//import org.eclipse.cdt.managedbuilder.core.IManagedConfigElement; +//import org.eclipse.cdt.managedbuilder.core.IManagedOptionValueHandler; +//import org.eclipse.cdt.managedbuilder.core.IManagedProject; +//import org.eclipse.cdt.managedbuilder.core.IOption; +//import org.eclipse.cdt.managedbuilder.core.IOptionApplicability; +//import org.eclipse.cdt.managedbuilder.core.IOptionCommandGenerator; +//import org.eclipse.cdt.managedbuilder.core.IProjectType; +//import org.eclipse.cdt.managedbuilder.core.IResourceConfiguration; +//import org.eclipse.cdt.managedbuilder.core.IResourceInfo; +//import org.eclipse.cdt.managedbuilder.core.ITargetPlatform; +//import org.eclipse.cdt.managedbuilder.core.ITool; +//import org.eclipse.cdt.managedbuilder.core.IToolChain; +//import org.eclipse.cdt.managedbuilder.core.ManagedBuildManager; +//import org.eclipse.cdt.managedbuilder.core.ManagedBuilderCorePlugin; +//import org.eclipse.cdt.managedbuilder.envvar.IConfigurationEnvironmentVariableSupplier; +//import org.eclipse.cdt.managedbuilder.internal.dataprovider.BuildConfigurationData; +//import org.eclipse.cdt.managedbuilder.internal.enablement.OptionEnablementExpression; +//import org.eclipse.cdt.managedbuilder.internal.macros.BuildMacroProvider; +//import org.eclipse.cdt.managedbuilder.internal.macros.BuildfileMacroSubstitutor; +//import org.eclipse.cdt.managedbuilder.internal.macros.FileContextData; +//import org.eclipse.cdt.managedbuilder.internal.macros.IMacroContextInfo; +//import org.eclipse.cdt.managedbuilder.internal.macros.IMacroContextInfoProvider; +//import org.eclipse.cdt.managedbuilder.internal.macros.OptionContextData; +//import org.eclipse.cdt.managedbuilder.macros.BuildMacroException; +//import org.eclipse.cdt.managedbuilder.macros.IBuildMacroProvider; +//import org.eclipse.cdt.managedbuilder.macros.IConfigurationBuildMacroSupplier; +import org.eclipse.cdt.utils.cdtvariables.SupplierBasedCdtVariableSubstitutor; +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.resources.IResourceDelta; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.Path; +import org.eclipse.core.runtime.Platform; +//import org.eclipse.core.runtime.Platform; +import org.eclipse.osgi.util.NLS; +import org.osgi.framework.Version; + +import io.sloeber.autoBuild.api.BuildException; +import io.sloeber.autoBuild.api.BuildMacroException; +import io.sloeber.autoBuild.api.IBuildMacroProvider; +import io.sloeber.autoBuild.api.IBuildObject; +import io.sloeber.autoBuild.api.IBuildObjectProperties; +import io.sloeber.autoBuild.api.IBuildPropertiesRestriction; +import io.sloeber.autoBuild.api.IBuildProperty; +import io.sloeber.autoBuild.api.IBuildPropertyType; +import io.sloeber.autoBuild.api.IBuildPropertyValue; +import io.sloeber.autoBuild.api.IBuilder; +import io.sloeber.autoBuild.api.IConfiguration; +import io.sloeber.autoBuild.api.IConfigurationBuildMacroSupplier; +import io.sloeber.autoBuild.api.IConfigurationEnvironmentVariableSupplier; +import io.sloeber.autoBuild.api.IFileInfo; +import io.sloeber.autoBuild.api.IFolderInfo; +import io.sloeber.autoBuild.api.IHoldsOptions; +import io.sloeber.autoBuild.api.IManagedCommandLineGenerator; +import io.sloeber.autoBuild.api.IManagedCommandLineInfo; +import io.sloeber.autoBuild.api.IManagedConfigElement; +import io.sloeber.autoBuild.api.IManagedOptionValueHandler; +import io.sloeber.autoBuild.api.IManagedProject; +import io.sloeber.autoBuild.api.IOption; +import io.sloeber.autoBuild.api.IOptionApplicability; +import io.sloeber.autoBuild.api.IOptionCommandGenerator; +import io.sloeber.autoBuild.api.IOptionalBuildProperties; +import io.sloeber.autoBuild.api.IProjectType; +import io.sloeber.autoBuild.api.IResourceConfiguration; +import io.sloeber.autoBuild.api.IResourceInfo; +import io.sloeber.autoBuild.api.ITargetPlatform; +import io.sloeber.autoBuild.api.ITool; +import io.sloeber.autoBuild.api.IToolChain; +import io.sloeber.autoBuild.core.Activator; +import io.sloeber.buildProperties.BuildObjectProperties; +import io.sloeber.buildProperties.OptionalBuildProperties; +import io.sloeber.buildProperties.PropertyManager; + +public class Configuration extends BuildObject implements IConfiguration, IBuildPropertiesRestriction, + IBuildPropertyChangeListener, IRealBuildObjectAssociation { + + private static final String WHITE_SPACE = " "; //$NON-NLS-1$ + private static final String EMPTY_STRING = ""; //$NON-NLS-1$ + private static final String EMPTY_CFG_ID = "org.eclipse.cdt.build.core.emptycfg"; //$NON-NLS-1$ + private static final String LANGUAGE_SETTINGS_PROVIDER_DELIMITER = ";"; //$NON-NLS-1$ + private static final String LANGUAGE_SETTINGS_PROVIDER_NEGATION_SIGN = "-"; //$NON-NLS-1$ + private static final String $TOOLCHAIN = "${Toolchain}"; //$NON-NLS-1$ + + // Parent and children + private String parentId; + private IConfiguration parent; + private ProjectType projectType; + private ManagedProject managedProject; + private String artifactName; + private String cleanCommand; + private String artifactExtension; + private String errorParserIds; + private String defaultLanguageSettingsProvidersAttribute; + private String[] defaultLanguageSettingsProviderIds; + private String prebuildStep; + private String postbuildStep; + private String preannouncebuildStep; + private String postannouncebuildStep; + private String description; + private ICSourceEntry[] sourceEntries; + private BuildObjectProperties buildProperties; + private OptionalBuildProperties optionalBuildProperties; + private boolean isTest; + private SupportedProperties supportedProperties; + + // Miscellaneous + private boolean isExtensionConfig = false; + private boolean isDirty = false; + private boolean rebuildNeeded = false; + private boolean resolved = true; + private boolean isTemporary = false; + + private PathSettingsContainer pathSettings = PathSettingsContainer.createRootContainer(); + private ResourceInfoContainer rcInfos = new ResourceInfoContainer(pathSettings, true); + private BooleanExpressionApplicabilityCalculator booleanExpressionCalculator; + + private FolderInfo rootFolderInfo; + // private BuildConfigurationData fCfgData; + private ICConfigurationDescription fCfgDes; + // private IScannerConfigBuilderInfo2 scannerCfgBuilderInfo; + // private IDiscoveredPathManager.IDiscoveredPathInfo discoveredInfo; + // private Boolean isPerResourceDiscovery; + // private ICfgScannerConfigBuilderInfo2Set cfgScannerInfo; + private boolean isPreferenceConfig; + private List excludeList; + + //property name for holding the rebuild state + private static final String REBUILD_STATE = "rebuildState"; //$NON-NLS-1$ + + //The resource delta passed to the builder is not always up-to-date + //for the given configuration because between two builds of the same configuration + //any number of other configuration builds may occur + //that is why we need to keep some information regarding what happened + //with the resource tree between the two configuration builds + // + //The trivial approach implemented currently is to hold + //the general information of whether some resources were + //removed,changed,etc. and detect whether the rebuild is needed + //based upon this information + // + //In the future we might implement some more smart mechanism + //for tracking delta, e.g calculate the pre-cinfiguration resource delta, etc. + // + //property for holding the resource change state + private static final String RC_CHANGE_STATE = "rcState"; //$NON-NLS-1$ + //resource change state + private int resourceChangeState = -1; + + //Internal Builder state + //NOTE: these are temporary properties + //In the future we are going present the Internal Builder + //as a special Builder object of the tool-chain and implement the internal + //builder enabling/disabling as the Builder substitution functionality + // + // private static final String INTERNAL_BUILDER = "internalBuilder"; //$NON-NLS-1$ + //preference key that holds the Internal Builder enable state + // private static final String INTERNAL_BUILDER_ENABLED = "enabled"; //$NON-NLS-1$ + //preference key that holds the internal builder mode + // private static final String INTERNAL_BUILDER_IGNORE_ERR = "ignoreErr"; //$NON-NLS-1$ + //preference key that holds the internal builder mode + // private static final String INTERNAL_BUILDER_PARALLEL = "parallel"; //$NON-NLS-1$ + //preference key that holds the internal builder mode + // private static final String INTERNAL_BUILDER_PARALLEL_DEF = "paralleldef"; //$NON-NLS-1$ + //preference key that holds the internal builder mode + // private static final String INTERNAL_BUILDER_PARALLELNUMBER = "parallelnumber"; //$NON-NLS-1$ + //Internal Builder enable state + // private boolean internalBuilderEnabled; + //Internal Builder mode + // private boolean internalBuilderIgnoreErr = true; + //Internal Builder parallel mode + // private boolean internalBuilderParallel = true; + //Internal Builder parallel mode - default jobs # + // private boolean internalBuilderParallelDef = true; + //Number of parallel threads + // private int internalBuilderParallelNumber = 1; // default value + /* + * C O N S T R U C T O R S + */ + + /** + * Create an extension configuration from the project manifest file element. + * + * @param projectType + * The ProjectType the configuration will be added to. + * @param element + * The element from the manifest that contains the configuration + * information. + */ + public Configuration(ProjectType projectType, IManagedConfigElement element, String managedBuildRevision) { + this.projectType = projectType; + isExtensionConfig = true; + + // setup for resolving + resolved = false; + + setManagedBuildRevision(managedBuildRevision); + + // Initialize from the XML attributes + loadFromManifest(element); + + // Hook me up to the Managed Build Manager + ManagedBuildManager.addExtensionConfiguration(this); + + // Hook me up to the ProjectType + if (projectType != null) { + projectType.addConfiguration(this); + } + + IManagedConfigElement enablements[] = element.getChildren(OptionEnablementExpression.NAME); + if (enablements.length > 0) + booleanExpressionCalculator = new BooleanExpressionApplicabilityCalculator(enablements); + + // Load the children + IManagedConfigElement[] configElements = element.getChildren(); + List srcPathList = new ArrayList<>(); + excludeList = new ArrayList<>(); + for (int l = 0; l < configElements.length; ++l) { + IManagedConfigElement configElement = configElements[l]; + if (configElement.getName().equals(IToolChain.TOOL_CHAIN_ELEMENT_NAME)) { + rootFolderInfo = new FolderInfo(this, configElement, managedBuildRevision, false); + addResourceConfiguration(rootFolderInfo); + } else if (IFolderInfo.FOLDER_INFO_ELEMENT_NAME.equals(configElement.getName())) { + FolderInfo resConfig = new FolderInfo(this, configElement, managedBuildRevision, true); + addResourceConfiguration(resConfig); + } else if (IFileInfo.FILE_INFO_ELEMENT_NAME.equals(configElement.getName()) + || IResourceConfiguration.RESOURCE_CONFIGURATION_ELEMENT_NAME.equals(configElement.getName())) { + ResourceConfiguration resConfig = new ResourceConfiguration(this, configElement, managedBuildRevision); + addResourceConfiguration(resConfig); + } else if (SourcePath.ELEMENT_NAME.equals(configElement.getName())) { + SourcePath p = new SourcePath(configElement); + if (p.getPath() != null) + srcPathList.add(p.getPath()); + } else if (configElement.getName().equals(SupportedProperties.SUPPORTED_PROPERTIES)) { + loadProperties(configElement); + } else if (SOURCE_ENTRIES.equals(configElement.getName())) { + // List seList = LanguageSettingEntriesSerializer + // .loadEntriesList(new ManagedConfigStorageElement(configElement), ICSettingEntry.SOURCE_PATH); + // sourceEntries = seList.toArray(new ICSourceEntry[seList.size()]); + } + } + + sourceEntries = createSourceEntries(sourceEntries, srcPathList, excludeList); + + excludeList = null; + + if (rootFolderInfo == null) + createRootFolderInfo(); + + String props = SafeStringInterner.safeIntern(element.getAttribute(BUILD_PROPERTIES)); + if (props != null) + buildProperties = new BuildObjectProperties(props, this, this); + + String optionalProps = SafeStringInterner.safeIntern(element.getAttribute(OPTIONAL_BUILD_PROPERTIES)); + if (optionalProps != null) + optionalBuildProperties = new OptionalBuildProperties(optionalProps); + + String artType = SafeStringInterner.safeIntern(element.getAttribute(BUILD_ARTEFACT_TYPE)); + if (artType != null) { + if (buildProperties == null) + buildProperties = new BuildObjectProperties(this, this); + + try { + buildProperties.setProperty(ManagedBuildManager.BUILD_ARTEFACT_TYPE_PROPERTY_ID, artType, true); + } catch (CoreException e) { + Activator.log(e); + } + } + + if (projectType != null && projectType.buildProperties != null) { + if (buildProperties == null) { + buildProperties = new BuildObjectProperties(projectType.buildProperties, this, this); + } else { + IBuildProperty properties[] = projectType.buildProperties.getProperties(); + for (int i = 0; i < properties.length; i++) { + try { + buildProperties.internalSetProperty(properties[i].getPropertyType().getId(), + properties[i].getValue().getId()); + } catch (CoreException e) { + } + } + } + } + + setDirty(false); + } + + private static ICSourceEntry[] createSourceEntries(ICSourceEntry[] curEntries, List pathList, + List excludeList) { + for (int i = 0; i < excludeList.size(); i++) { + IPath path = excludeList.get(i); + if (path.segmentCount() == 0) + excludeList.remove(i); + } + if (pathList.size() == 0) + pathList.add(Path.EMPTY); + + if (pathList.size() == 1 && pathList.get(0).equals(Path.EMPTY) && excludeList.size() == 0) + return curEntries; + + int pathSize = pathList.size(); + Map map = new LinkedHashMap<>(); + + for (int i = 0; i < pathSize; i++) { + IPath path = pathList.get(i); + ICSourceEntry entry = map.get(path); + if (entry == null) + entry = new CSourceEntry(path, null, ICSettingEntry.VALUE_WORKSPACE_PATH | ICSettingEntry.RESOLVED); + + entry = CDataUtil.addExcludePaths(entry, excludeList, true); + if (entry != null) + map.put(path, entry); + } + + return map.values().toArray(new ICSourceEntry[map.size()]); + } + + /** + * Create a new extension configuration based on one already defined. + * + * @param projectType + * The ProjectType the configuration will be added to. + * @param parentConfig + * The IConfiguration that is the parent configuration + * of this configuration + * @param id + * A unique ID for the new configuration. + */ + public Configuration(ProjectType projectType, IConfiguration parentConfig, String id) { + setId(id); + this.projectType = projectType; + isExtensionConfig = true; + + // setup for resolving + resolved = false; + + if (parentConfig != null) { + name = parentConfig.getName(); + // If this constructor is called to clone an existing + // configuration, the parent of the parent should be stored. + // As of 2.1, there is still one single level of inheritance to + // worry about + parent = parentConfig.getParent() == null ? parentConfig : parentConfig.getParent(); + } + + // Hook me up to the Managed Build Manager + ManagedBuildManager.addExtensionConfiguration(this); + + // Hook me up to the ProjectType + if (projectType != null) { + projectType.addConfiguration(this); + // set managedBuildRevision + setManagedBuildRevision(projectType.getManagedBuildRevision()); + } + } + + /** + * Create a new extension configuration and fill in the attributes and childen + * later. + * + * @param projectType + * The ProjectType the configuration will be added to. + * @param parentConfig + * The IConfiguration that is the parent configuration + * of this configuration + * @param id + * A unique ID for the new configuration. + * @param name + * A name for the new configuration. + */ + public Configuration(ProjectType projectType, IConfiguration parentConfig, String id, String name) { + setId(id); + setName(name); + this.projectType = projectType; + parent = parentConfig; + isExtensionConfig = true; + + // Hook me up to the Managed Build Manager + ManagedBuildManager.addExtensionConfiguration(this); + + // Hook me up to the ProjectType + if (projectType != null) { + projectType.addConfiguration(this); + setManagedBuildRevision(projectType.getManagedBuildRevision()); + } + } + + /** + * Create a Configuration based on the specification stored in the + * project file (.cdtbuild). + * + * @param managedProject + * The ManagedProject the configuration will be added + * to. + * @param element + * The XML element that contains the configuration settings. + * + */ + public Configuration(ManagedProject managedProject, ICStorageElement element, String managedBuildRevision, + boolean isPreference) { + this.managedProject = managedProject; + this.isPreferenceConfig = isPreference; + isExtensionConfig = false; + // fCfgData = new BuildConfigurationData(this); + + setManagedBuildRevision(managedBuildRevision); + + // Initialize from the XML attributes + loadFromProject(element); + + // Hook me up + if (managedProject != null) + managedProject.addConfiguration(this); + + ICStorageElement configElements[] = element.getChildren(); + List srcPathList = new ArrayList<>(); + excludeList = new ArrayList<>(); + for (int i = 0; i < configElements.length; ++i) { + ICStorageElement configElement = configElements[i]; + if (configElement.getName().equals(IToolChain.TOOL_CHAIN_ELEMENT_NAME)) { + rootFolderInfo = new FolderInfo(this, configElement, managedBuildRevision, false); + addResourceConfiguration(rootFolderInfo); + } else if (IFolderInfo.FOLDER_INFO_ELEMENT_NAME.equals(configElement.getName())) { + FolderInfo resConfig = new FolderInfo(this, configElement, managedBuildRevision, true); + addResourceConfiguration(resConfig); + } else if (IFileInfo.FILE_INFO_ELEMENT_NAME.equals(configElement.getName()) + || IResourceConfiguration.RESOURCE_CONFIGURATION_ELEMENT_NAME.equals(configElement.getName())) { + ResourceConfiguration resConfig = new ResourceConfiguration(this, configElement, managedBuildRevision); + addResourceConfiguration(resConfig); + } else if (SourcePath.ELEMENT_NAME.equals(configElement.getName())) { + SourcePath p = new SourcePath(configElement); + if (p.getPath() != null) + srcPathList.add(p.getPath()); + } else if (SOURCE_ENTRIES.equals(configElement.getName())) { + List seList = LanguageSettingEntriesSerializer.loadEntriesList(configElement, + ICSettingEntry.SOURCE_PATH); + sourceEntries = seList.toArray(new ICSourceEntry[seList.size()]); + } + } + + resolveProjectReferences(true); + + sourceEntries = createSourceEntries(sourceEntries, srcPathList, excludeList); + + excludeList = null; + + PropertyManager mngr = PropertyManager.getInstance(); + String rebuild = mngr.getProperty(this, REBUILD_STATE); + if (rebuild == null || Boolean.valueOf(rebuild).booleanValue()) + rebuildNeeded = true; + + String rcChangeState = mngr.getProperty(this, RC_CHANGE_STATE); + if (rcChangeState == null) + resourceChangeState = ~0; + else { + try { + resourceChangeState = Integer.parseInt(rcChangeState); + } catch (NumberFormatException e) { + resourceChangeState = ~0; + } + } + + setDirty(false); + + // Preferences prefs = getPreferences(INTERNAL_BUILDER); + // + // internalBuilderEnabled = prefs != null ? + // prefs.getBoolean(INTERNAL_BUILDER_ENABLED, false) : false; + // internalBuilderIgnoreErr = prefs != null ? + // prefs.getBoolean(INTERNAL_BUILDER_IGNORE_ERR, true) : true; + } + + public Configuration(ManagedProject managedProject, IToolChain tCh, String id, String name) { + setId(id); + setName(name); + + // this.description = cloneConfig.getDescription(); + this.managedProject = managedProject; + isExtensionConfig = false; + + if (tCh == null) { + //create configuration based upon the preference config + IConfiguration cfg = ManagedBuildManager.getPreferenceConfiguration(false); + if (cfg != null) + copySettingsFrom((Configuration) cfg, true); + } else { + Configuration baseCfg = (Configuration) ManagedBuildManager.getExtensionConfiguration(EMPTY_CFG_ID); + // this.isTemporary = temporary; + // fCfgData = new BuildConfigurationData(this); + if (baseCfg.buildProperties != null) + this.buildProperties = new BuildObjectProperties(baseCfg.buildProperties, this, this); + + if (baseCfg.optionalBuildProperties != null) + this.optionalBuildProperties = new OptionalBuildProperties(baseCfg.optionalBuildProperties); + + // set managedBuildRevision + setManagedBuildRevision(baseCfg.getManagedBuildRevision()); + + // if(!baseCfg.isExtensionConfig) + // cloneChildren = true; + // If this constructor is called to clone an existing + // configuration, the parent of the cloning config should be stored. + parent = baseCfg.isExtensionConfig || baseCfg.getParent() == null ? baseCfg : baseCfg.getParent(); + + // Copy the remaining attributes + projectType = baseCfg.projectType; + artifactName = baseCfg.artifactName; + cleanCommand = baseCfg.cleanCommand; + artifactExtension = baseCfg.artifactExtension; + errorParserIds = baseCfg.errorParserIds; + prebuildStep = baseCfg.prebuildStep; + postbuildStep = baseCfg.postbuildStep; + preannouncebuildStep = baseCfg.preannouncebuildStep; + postannouncebuildStep = baseCfg.postannouncebuildStep; + + if (baseCfg.sourceEntries != null) + sourceEntries = baseCfg.sourceEntries.clone(); + + defaultLanguageSettingsProvidersAttribute = baseCfg.defaultLanguageSettingsProvidersAttribute; + if (baseCfg.defaultLanguageSettingsProviderIds != null) { + defaultLanguageSettingsProviderIds = baseCfg.defaultLanguageSettingsProviderIds.clone(); + } + + // enableInternalBuilder(baseCfg.isInternalBuilderEnabled()); + // setInternalBuilderIgnoreErr(baseCfg.getInternalBuilderIgnoreErr()); + // setInternalBuilderParallel(baseCfg.getInternalBuilderParallel()); + // setParallelDef(baseCfg.getParallelDef()); + // setParallelNumber(baseCfg.getParallelNumber()); + // internalBuilderEnabled = cloneConfig.internalBuilderEnabled; + // internalBuilderIgnoreErr = cloneConfig.internalBuilderIgnoreErr; + + // Clone the configuration's children + // Tool Chain + + String tcId = ManagedBuildManager.calculateChildId(tCh.getId(), null); + + IToolChain newChain = createToolChain(tCh, tcId, tCh.getName(), false); + + // For each option/option category child of the tool-chain that is + // the child of the selected configuration element, create an option/ + // option category child of the cloned configuration's tool-chain element + // that specifies the original tool element as its superClass. + newChain.createOptions(tCh); + + // For each tool element child of the tool-chain that is the child of + // the selected configuration element, create a tool element child of + // the cloned configuration's tool-chain element that specifies the + // original tool element as its superClass. + String subId; + ITool[] tools = tCh.getTools(); + for (int i = 0; i < tools.length; i++) { + Tool toolChild = (Tool) tools[i]; + subId = ManagedBuildManager.calculateChildId(toolChild.getId(), null); + newChain.createTool(toolChild, subId, toolChild.getName(), false); + } + + ITargetPlatform tpBase = tCh.getTargetPlatform(); + ITargetPlatform extTp = tpBase; + for (; extTp != null && !extTp.isExtensionElement(); extTp = extTp.getSuperClass()) { + } + + TargetPlatform tp; + if (extTp != null) { + int nnn = ManagedBuildManager.getRandomNumber(); + subId = extTp.getId() + "." + nnn; //$NON-NLS-1$ + // subName = tpBase.getName(); + tp = new TargetPlatform(newChain, subId, tpBase.getName(), (TargetPlatform) tpBase); + } else { + subId = ManagedBuildManager.calculateChildId(getId(), null); + String subName = EMPTY_STRING; + tp = new TargetPlatform((ToolChain) newChain, null, subId, subName, false); + } + + ((ToolChain) newChain).setTargetPlatform(tp); + + // if(cloneChildren){ + //copy expand build macros setting + // BuildMacroProvider macroProvider = (BuildMacroProvider)ManagedBuildManager.getBuildMacroProvider(); + // macroProvider.expandMacrosInBuildfile(this, + // macroProvider.areMacrosExpandedInBuildfile(baseCfg)); + + //copy user-defined build macros + /* UserDefinedMacroSupplier userMacros = BuildMacroProvider.fUserDefinedMacroSupplier; + userMacros.setMacros( + userMacros.getMacros(BuildMacroProvider.CONTEXT_CONFIGURATION,cloneConfig), + BuildMacroProvider.CONTEXT_CONFIGURATION, + this); + */ + //copy user-defined environment + // UserDefinedEnvironmentSupplier userEnv = EnvironmentVariableProvider.fUserSupplier; + // userEnv.setVariables( + // userEnv.getVariables(cloneConfig), this); + + // } + + // Hook me up + managedProject.addConfiguration(this); + + IBuilder builder = getEditableBuilder(); + builder.setManagedBuildOn(false); + + propertiesChanged(); + } + setDirty(true); + setRebuildState(true); + } + + public Configuration(ManagedProject managedProject, Configuration cloneConfig, String id, boolean cloneChildren, + boolean temporary) { + this(managedProject, cloneConfig, id, cloneChildren, temporary, false); + } + + /** + * Create a new project, non-extension, configuration based on one already + * defined. + * + * @param managedProject + * The ManagedProject the configuration will be added + * to. + * @param cloneConfig + * The IConfiguration to copy the settings from. + * @param id + * A unique ID for the new configuration. + * @param cloneChildren + * If true, the configuration's tools are cloned + */ + public Configuration(ManagedProject managedProject, Configuration cloneConfig, String id, boolean cloneChildren, + boolean temporary, boolean isPreferenceConfig) { + setId(id); + setName(cloneConfig.getName()); + this.isPreferenceConfig = isPreferenceConfig; + this.managedProject = managedProject; + isExtensionConfig = false; + this.isTemporary = temporary; + + copySettingsFrom(cloneConfig, cloneChildren); + } + + private void copySettingsFrom(Configuration cloneConfig, boolean cloneChildren) { + // fCfgData = new BuildConfigurationData(this); + if (cloneConfig.buildProperties != null) { + this.buildProperties = new BuildObjectProperties(cloneConfig.buildProperties, this, this); + } + + if (cloneConfig.optionalBuildProperties != null) { + this.optionalBuildProperties = new OptionalBuildProperties(cloneConfig.optionalBuildProperties); + } + + this.description = cloneConfig.getDescription(); + + // set managedBuildRevision + setManagedBuildRevision(cloneConfig.getManagedBuildRevision()); + + if (!cloneConfig.isExtensionConfig) + cloneChildren = true; + // If this constructor is called to clone an existing + // configuration, the parent of the cloning config should be stored. + parent = cloneConfig.isExtensionConfig || cloneConfig.getParent() == null ? cloneConfig + : cloneConfig.getParent(); + parentId = parent.getId(); + + // Copy the remaining attributes + projectType = cloneConfig.projectType; + artifactName = cloneConfig.artifactName; + cleanCommand = cloneConfig.cleanCommand; + artifactExtension = cloneConfig.artifactExtension; + errorParserIds = cloneConfig.errorParserIds; + prebuildStep = cloneConfig.prebuildStep; + postbuildStep = cloneConfig.postbuildStep; + preannouncebuildStep = cloneConfig.preannouncebuildStep; + postannouncebuildStep = cloneConfig.postannouncebuildStep; + if (cloneConfig.sourceEntries != null) { + sourceEntries = cloneConfig.sourceEntries.clone(); + } + defaultLanguageSettingsProvidersAttribute = cloneConfig.defaultLanguageSettingsProvidersAttribute; + if (cloneConfig.defaultLanguageSettingsProviderIds != null) { + defaultLanguageSettingsProviderIds = cloneConfig.defaultLanguageSettingsProviderIds.clone(); + } + + // enableInternalBuilder(cloneConfig.isInternalBuilderEnabled()); + // setInternalBuilderIgnoreErr(cloneConfig.getInternalBuilderIgnoreErr()); + // setInternalBuilderParallel(cloneConfig.getInternalBuilderParallel()); + // setParallelDef(cloneConfig.getParallelDef()); + // setParallelNumber(cloneConfig.getParallelNumber()); + // internalBuilderEnabled = cloneConfig.internalBuilderEnabled; + // internalBuilderIgnoreErr = cloneConfig.internalBuilderIgnoreErr; + + // Clone the configuration's children + // Tool Chain + boolean copyIds = cloneConfig.getId().equals(id); + String subId; + // Resource Configurations + Map> toolIdMap = new HashMap<>(); + IResourceInfo infos[] = cloneConfig.rcInfos.getResourceInfos(); + for (int i = 0; i < infos.length; i++) { + if (infos[i] instanceof FolderInfo) { + FolderInfo folderInfo = (FolderInfo) infos[i]; + subId = copyIds ? folderInfo.getId() + : ManagedBuildManager.calculateChildId(getId(), folderInfo.getPath().toString()); + FolderInfo newFolderInfo = new FolderInfo(this, folderInfo, subId, toolIdMap, cloneChildren); + addResourceConfiguration(newFolderInfo); + } else { + ResourceConfiguration fileInfo = (ResourceConfiguration) infos[i]; + subId = copyIds ? fileInfo.getId() + : ManagedBuildManager.calculateChildId(getId(), fileInfo.getPath().toString()); + ResourceConfiguration newResConfig = new ResourceConfiguration(this, fileInfo, subId, toolIdMap, + cloneChildren); + addResourceConfiguration(newResConfig); + + } + } + + resolveProjectReferences(false); + + if (cloneChildren) { + //copy expand build macros setting + BuildMacroProvider macroProvider = (BuildMacroProvider) ManagedBuildManager.getBuildMacroProvider(); + macroProvider.expandMacrosInBuildfile(this, macroProvider.areMacrosExpandedInBuildfile(cloneConfig)); + + //copy user-defined build macros + /* UserDefinedMacroSupplier userMacros = BuildMacroProvider.fUserDefinedMacroSupplier; + userMacros.setMacros( + userMacros.getMacros(BuildMacroProvider.CONTEXT_CONFIGURATION,cloneConfig), + BuildMacroProvider.CONTEXT_CONFIGURATION, + this); + */ + //copy user-defined environment + // UserDefinedEnvironmentSupplier userEnv = EnvironmentVariableProvider.fUserSupplier; + // userEnv.setVariables( + // userEnv.getVariables(cloneConfig), this); + + } + + // Hook me up + if (managedProject != null) { + managedProject.addConfiguration(this); + } + + if (cloneConfig.isExtensionConfig) { + propertiesChanged(); + } + + if (copyIds) { + rebuildNeeded = cloneConfig.rebuildNeeded; + resourceChangeState = cloneConfig.resourceChangeState; + isDirty = cloneConfig.isDirty; + } else { + if (cloneConfig.isExtensionConfig) + exportArtifactInfo(); + setDirty(true); + setRebuildState(true); + } + + } + + public void applyToManagedProject(ManagedProject mProj) { + managedProject = mProj; + isPreferenceConfig = false; + isTemporary = false; + managedProject.addConfiguration(this); + } + + /* + * E L E M E N T A T T R I B U T E R E A D E R S A N D W R I T E R S + */ + + /** + * Initialize the configuration information from an element in the + * manifest file or provided by a dynamicElementProvider + * + * @param element + * An obejct implementing IManagedConfigElement + */ + protected void loadFromManifest(IManagedConfigElement element) { + ManagedBuildManager.putConfigElement(this, element); + + // id + setId(SafeStringInterner.safeIntern(element.getAttribute(IBuildObject.ID))); + + // name + name = SafeStringInterner.safeIntern(element.getAttribute(IBuildObject.NAME)); + + // description + description = SafeStringInterner.safeIntern(element.getAttribute(IConfiguration.DESCRIPTION)); + + // parent + parentId = SafeStringInterner.safeIntern(element.getAttribute(IConfiguration.PARENT)); + + // if (parentID != null) { + // // Lookup the parent configuration by ID + // parent = ManagedBuildManager.getExtensionConfiguration(parentID); + // } + + // Get the name of the build artifact associated with configuration + artifactName = SafeStringInterner.safeIntern(element.getAttribute(ARTIFACT_NAME)); + + // Get the semicolon separated list of IDs of the error parsers + errorParserIds = SafeStringInterner.safeIntern(element.getAttribute(ERROR_PARSERS)); + + // Get the initial/default language settings providers IDs + defaultLanguageSettingsProvidersAttribute = SafeStringInterner + .safeIntern(element.getAttribute(LANGUAGE_SETTINGS_PROVIDERS)); + + // Get the artifact extension + artifactExtension = SafeStringInterner.safeIntern(element.getAttribute(EXTENSION)); + + // Get the clean command + cleanCommand = SafeStringInterner.safeIntern(element.getAttribute(CLEAN_COMMAND)); + + // Get the pre-build and post-build commands + prebuildStep = SafeStringInterner.safeIntern(element.getAttribute(PREBUILD_STEP)); + postbuildStep = SafeStringInterner.safeIntern(element.getAttribute(POSTBUILD_STEP)); + + // Get the pre-build and post-build announcements + preannouncebuildStep = SafeStringInterner.safeIntern(element.getAttribute(PREANNOUNCEBUILD_STEP)); + postannouncebuildStep = SafeStringInterner.safeIntern(element.getAttribute(POSTANNOUNCEBUILD_STEP)); + + String tmp = element.getAttribute(IS_SYSTEM); + if (tmp != null) + isTest = Boolean.valueOf(tmp).booleanValue(); + } + + /** + * Initialize the configuration information from the XML element + * specified in the argument + * + * @param element + * An XML element containing the configuration information + */ + protected void loadFromProject(ICStorageElement element) { + + // id + // note: IDs are unique so no benefit to intern them + setId(element.getAttribute(IBuildObject.ID)); + + // name + if (element.getAttribute(IBuildObject.NAME) != null) + setName(SafeStringInterner.safeIntern(element.getAttribute(IBuildObject.NAME))); + + // description + if (element.getAttribute(IConfiguration.DESCRIPTION) != null) + description = SafeStringInterner.safeIntern(element.getAttribute(IConfiguration.DESCRIPTION)); + + String props = element.getAttribute(BUILD_PROPERTIES); + if (props != null) + buildProperties = new BuildObjectProperties(props, this, this); + + String optionalProps = element.getAttribute(OPTIONAL_BUILD_PROPERTIES); + if (optionalProps != null) + optionalBuildProperties = new OptionalBuildProperties(optionalProps); + + String artType = SafeStringInterner.safeIntern(element.getAttribute(BUILD_ARTEFACT_TYPE)); + if (artType != null) { + if (buildProperties == null) + buildProperties = new BuildObjectProperties(this, this); + + try { + buildProperties.setProperty(ManagedBuildManager.BUILD_ARTEFACT_TYPE_PROPERTY_ID, artType, true); + } catch (CoreException e) { + Activator.log(e); + } + } + + if (element.getAttribute(IConfiguration.PARENT) != null) { + // See if the parent belongs to the same project + if (managedProject != null) + parent = managedProject.getConfiguration(element.getAttribute(IConfiguration.PARENT)); + // If not, then try the extension configurations + if (parent == null) { + parent = ManagedBuildManager.getExtensionConfiguration(element.getAttribute(IConfiguration.PARENT)); + if (parent == null) { + String message = NLS.bind(Configuration_orphaned, getId(), //$NON-NLS-1$ + element.getAttribute(IConfiguration.PARENT)); + Activator.error(message); + } + } + } + + // Get the name of the build artifact associated with target (usually + // in the plugin specification). + if (element.getAttribute(ARTIFACT_NAME) != null) { + artifactName = SafeStringInterner.safeIntern(element.getAttribute(ARTIFACT_NAME)); + } + + // Get the semicolon separated list of IDs of the error parsers + if (element.getAttribute(ERROR_PARSERS) != null) { + errorParserIds = SafeStringInterner.safeIntern(element.getAttribute(ERROR_PARSERS)); + } + + // Get the artifact extension + if (element.getAttribute(EXTENSION) != null) { + artifactExtension = SafeStringInterner.safeIntern(element.getAttribute(EXTENSION)); + } + + // Get the clean command + if (element.getAttribute(CLEAN_COMMAND) != null) { + cleanCommand = SafeStringInterner.safeIntern(element.getAttribute(CLEAN_COMMAND)); + } + + // Get the pre-build and post-build commands + if (element.getAttribute(PREBUILD_STEP) != null) { + prebuildStep = SafeStringInterner.safeIntern(element.getAttribute(PREBUILD_STEP)); + } + + if (element.getAttribute(POSTBUILD_STEP) != null) { + postbuildStep = SafeStringInterner.safeIntern(element.getAttribute(POSTBUILD_STEP)); + } + + // Get the pre-build and post-build announcements + if (element.getAttribute(PREANNOUNCEBUILD_STEP) != null) { + preannouncebuildStep = SafeStringInterner.safeIntern(element.getAttribute(PREANNOUNCEBUILD_STEP)); + } + + if (element.getAttribute(POSTANNOUNCEBUILD_STEP) != null) { + postannouncebuildStep = SafeStringInterner.safeIntern(element.getAttribute(POSTANNOUNCEBUILD_STEP)); + } + } + + /** + * Persist this configuration to project file. + */ + public void serialize(ICStorageElement element) { + element.setAttribute(IBuildObject.ID, id); + + if (name != null) + element.setAttribute(IBuildObject.NAME, name); + + if (description != null) + element.setAttribute(IConfiguration.DESCRIPTION, description); + + if (buildProperties != null) { + element.setAttribute(BUILD_PROPERTIES, buildProperties.toString()); + + IBuildProperty prop = buildProperties.getProperty(ManagedBuildManager.BUILD_ARTEFACT_TYPE_PROPERTY_ID); + if (prop != null) { + IBuildPropertyValue val = prop.getValue(); + element.setAttribute(BUILD_ARTEFACT_TYPE, val.getId()); + } + } + + if (optionalBuildProperties != null) { + element.setAttribute(OPTIONAL_BUILD_PROPERTIES, optionalBuildProperties.toString()); + } + + if (parent != null) + element.setAttribute(IConfiguration.PARENT, parent.getId()); + + if (artifactName != null) + element.setAttribute(ARTIFACT_NAME, artifactName); + + if (errorParserIds != null) + element.setAttribute(ERROR_PARSERS, errorParserIds); + + if (artifactExtension != null) + element.setAttribute(EXTENSION, artifactExtension); + + if (cleanCommand != null) + element.setAttribute(CLEAN_COMMAND, cleanCommand); + + if (prebuildStep != null) + element.setAttribute(PREBUILD_STEP, prebuildStep); + + if (postbuildStep != null) + element.setAttribute(POSTBUILD_STEP, postbuildStep); + + if (preannouncebuildStep != null) + element.setAttribute(PREANNOUNCEBUILD_STEP, preannouncebuildStep); + + if (postannouncebuildStep != null) + element.setAttribute(POSTANNOUNCEBUILD_STEP, postannouncebuildStep); + + // Serialize my children + IResourceInfo infos[] = rcInfos.getResourceInfos(); + for (int i = 0; i < infos.length; i++) { + String elementName = infos[i].getKind() == ICSettingBase.SETTING_FILE ? IFileInfo.FILE_INFO_ELEMENT_NAME + : IFolderInfo.FOLDER_INFO_ELEMENT_NAME; + + ICStorageElement resElement = element.createChild(elementName); + ((ResourceInfo) infos[i]).serialize(resElement); + } + + PropertyManager.getInstance().serialize(this); + + if (sourceEntries != null && sourceEntries.length > 0) { + ICStorageElement el = element.createChild(SOURCE_ENTRIES); + LanguageSettingEntriesSerializer.serializeEntries(sourceEntries, el); + } + // I am clean now + setDirty(false); + } + + /* + * P A R E N T A N D C H I L D H A N D L I N G + */ + + @Override + public IConfiguration getParent() { + return parent; + } + + @Override + public IResource getOwner() { + if (managedProject != null) + return managedProject.getOwner(); + else { + return null; // Extension configurations don't have an "owner" + } + } + + //@Override + public IProjectType getProjectType() { + return projectType; + } + + @Override + public IManagedProject getManagedProject() { + return managedProject; + } + + @Override + public IToolChain createToolChain(IToolChain superClass, String Id, String name, boolean isExtensionElement) { + if (rootFolderInfo == null) { + createRootFolderInfo(); + } + + return rootFolderInfo.createToolChain(superClass, Id, name, isExtensionElement); + } + + private IFolderInfo createRootFolderInfo() { + String id = ManagedBuildManager.calculateChildId(this.id, null); + String name = "/"; //$NON-NLS-1$ + + rootFolderInfo = new FolderInfo(this, new Path(name), id, name, isExtensionConfig); + addResourceConfiguration(rootFolderInfo); + return rootFolderInfo; + } + + /* + public IFolderInfo createFolderInfo(IPath path, IToolChain superClass, String Id, String name){ + + } + + public IFolderInfo createFolderInfo(IPath path, IFolderInfo baseFolderInfo, String Id, String name){ + + } + */ + @Override + public IToolChain getToolChain() { + return rootFolderInfo.getToolChain(); + } + + @Override + public IResourceConfiguration[] getResourceConfigurations() { + return (IResourceConfiguration[]) rcInfos.getResourceInfos(ICSettingBase.SETTING_FILE, + IResourceConfiguration.class); + } + + @Override + public IResourceConfiguration getResourceConfiguration(String resPath) { + return rcInfos.getFileInfo(new Path(resPath).removeFirstSegments(1)); + } + + @Override + public ITool[] getFilteredTools() { + return rootFolderInfo.getFilteredTools(); + } + + @Override + public ITool[] getTools() { + return rootFolderInfo.getTools(); + } + + @Override + public ITool getTool(String id) { + return rootFolderInfo.getTool(id); + } + + @Override + public ITool[] getToolsBySuperClassId(String id) { + return rootFolderInfo.getToolsBySuperClassId(id); + } + + @Override + public ITool getTargetTool() { + String[] targetToolIds = rootFolderInfo.getToolChain().getTargetToolList(); + if (targetToolIds == null || targetToolIds.length == 0) + return null; + + // For each target tool id, in list order, + // look for a tool with this ID, or a tool with a superclass with this id. + // Stop when we find a match + ITool[] tools = getFilteredTools(); + for (int i = 0; i < targetToolIds.length; i++) { + String targetToolId = targetToolIds[i]; + for (int j = 0; j < tools.length; j++) { + ITool targetTool = tools[j]; + ITool tool = targetTool; + do { + if (targetToolId.equals(tool.getId())) { + return targetTool; + } + tool = tool.getSuperClass(); + } while (tool != null); + } + } + return null; + } + + @Override + public String getToolCommand(ITool tool) { + // TODO: Do we need to verify that the tool is part of the configuration? + return tool.getToolCommand(); + } + + @Override + public void setToolCommand(ITool tool, String command) { + // TODO: Do we need to verify that the tool is part of the configuration? + tool.setToolCommand(command); + } + + @Override + public IOption setOption(IHoldsOptions holder, IOption option, boolean value) throws BuildException { + return getRootFolderInfo().setOption(holder, option, value); + } + + @Override + public IOption setOption(IHoldsOptions holder, IOption option, String value) throws BuildException { + return getRootFolderInfo().setOption(holder, option, value); + } + + @Override + public IOption setOption(IHoldsOptions holder, IOption option, String[] value) throws BuildException { + return getRootFolderInfo().setOption(holder, option, value); + } + + /** + * Adds the Resource Configuration to the Resource Configuration list and map + */ + void addResourceConfiguration(IResourceInfo resConfig) { + if (resConfig.getPath().segmentCount() == 0) + rootFolderInfo = (FolderInfo) resConfig; + rcInfos.addResourceInfo(resConfig); + isDirty = true; + // rebuildNeeded = true; + } + + //@Override + public void removeResourceConfiguration(IResourceInfo resConfig) { + ManagedBuildManager.performValueHandlerEvent(resConfig, IManagedOptionValueHandler.EVENT_CLOSE); + ITool tools[] = resConfig.getTools(); + rcInfos.removeResourceInfo(resConfig.getPath()); + ((ResourceInfo) resConfig).removed(); + BuildSettingsUtil.disconnectDepentents(this, tools); + isDirty = true; + rebuildNeeded = true; + } + /* + * M O D E L A T T R I B U T E A C C E S S O R S + */ + + @Override + public String getName() { + return (name == null && parent != null) ? parent.getName() : name; + } + + @Override + public String getArtifactExtension() { + String ext = getArtifactExtensionAttribute(true); + return ext != null ? ext : EMPTY_STRING; + } + + public String getArtifactExtensionAttribute(boolean querySuperClass) { + if (artifactExtension == null) { + // Ask my parent first + if (parent != null) { + return parent.getArtifactExtension(); + } + return null; + } + return artifactExtension; + } + + @Override + public String getArtifactName() { + if (artifactName == null) { + // If I have a parent, ask it + if (parent != null) { + return parent.getArtifactName(); + } else { + // I'm it and this is not good! + return EMPTY_STRING; + } + } else { + return artifactName; + } + } + + @Override + public String getBuildArguments() { + IToolChain tc = getToolChain(); + IBuilder builder = tc.getBuilder(); + if (builder != null) { + return builder.getArguments(); + } + return "-k"; //$NON-NLS-1$ + } + + @Override + public String getBuildCommand() { + IToolChain tc = getToolChain(); + IBuilder builder = tc.getBuilder(); + if (builder != null) { + return builder.getCommand(); + } + return "make"; //$NON-NLS-1$ + } + + @Override + public String getPrebuildStep() { + if (prebuildStep == null) { + // If I have a parent, ask it + if (parent != null) { + return parent.getPrebuildStep(); + } else { + // I'm it + return EMPTY_STRING; + } + } else { + return prebuildStep; + } + } + + @Override + public String getPostbuildStep() { + if (postbuildStep == null) { + // If I have a parent, ask it + if (parent != null) { + return parent.getPostbuildStep(); + } else { + // I'm it + return EMPTY_STRING; + } + } else { + return postbuildStep; + } + } + + @Override + public String getPreannouncebuildStep() { + if (preannouncebuildStep == null) { + // If I have a parent, ask it + if (parent != null) { + return parent.getPreannouncebuildStep(); + } else { + // I'm it + return EMPTY_STRING; + } + } else { + return preannouncebuildStep; + } + } + + @Override + public String getPostannouncebuildStep() { + if (postannouncebuildStep == null) { + // If I have a parent, ask it + if (parent != null) { + return parent.getPostannouncebuildStep(); + } else { + // I'm it + return EMPTY_STRING; + } + } else { + return postannouncebuildStep; + } + } + + @Override + public String getCleanCommand() { + // Return the command used to remove files + if (cleanCommand == null) { + if (parent != null) { + return parent.getCleanCommand(); + } else { + // User forgot to specify it. Guess based on OS. + if (Platform.getOS().equals(Platform.OS_WIN32)) { + return "del"; //$NON-NLS-1$ + } else { + return "rm"; //$NON-NLS-1$ + } + } + } else { + // This was spec'd in the manifest + return cleanCommand; + } + } + + @Override + public String getDescription() { + if (description == null) { + // If I have a parent, ask it + if (parent != null) { + return parent.getDescription(); + } else { + // I'm it + return EMPTY_STRING; + } + } else { + return description; + } + } + + @Override + public String getErrorParserIds() { + if (errorParserIds != null) { + return errorParserIds; + } + // If I have a parent, ask it + String errorParsers = null; + if (parent != null) { + errorParsers = parent.getErrorParserIds(); + } + // If no error parsers are specified by the configuration, the default + // is + // the error parsers from the tool-chain + //TODO + if (errorParsers == null && rootFolderInfo != null) { + errorParsers = rootFolderInfo.getErrorParserIds(); + } + return errorParsers; + } + + public String getErrorParserIdsAttribute() { + if (errorParserIds != null) { + return errorParserIds; + } + // If I have a parent, ask it + String errorParsers = null; + if (parent != null) { + errorParsers = ((Configuration) parent).getErrorParserIdsAttribute(); + } + + return errorParsers; + } + + @Override + public String[] getErrorParserList() { + Set set = contributeErrorParsers(null, true); + if (set != null) { + String result[] = new String[set.size()]; + set.toArray(result); + return result; + } + return ErrorParserManager.getErrorParserAvailableIdsInContext(ErrorParserManager.BUILD_CONTEXT); + } + + public Set contributeErrorParsers(Set set, boolean includeChildren) { + String parserIDs = getErrorParserIdsAttribute(); + if (parserIDs != null) { + if (set == null) + set = new LinkedHashSet<>(); + if (parserIDs.length() != 0) { + StringTokenizer tok = new StringTokenizer(parserIDs, ";"); //$NON-NLS-1$ + while (tok.hasMoreElements()) { + set.add(tok.nextToken()); + } + } + } + + if (includeChildren) { + IResourceInfo[] rcInfos = getResourceInfos(); + for (int i = 0; i < rcInfos.length; i++) { + ResourceInfo rcInfo = (ResourceInfo) rcInfos[i]; + set = rcInfo.contributeErrorParsers(set); + } + } + return set; + } + + /** + * Get value of attribute {@link IConfiguration#LANGUAGE_SETTINGS_PROVIDERS} + * It not defined, it will try to pull the attribute from the parent + * configuration. + */ + private String getDefaultLanguageSettingsProvidersAttribute() { + if (defaultLanguageSettingsProvidersAttribute == null && parent instanceof Configuration) { + defaultLanguageSettingsProvidersAttribute = ((Configuration) parent) + .getDefaultLanguageSettingsProvidersAttribute(); + } + + return defaultLanguageSettingsProvidersAttribute; + } + + /** + * {@inheritDoc} + * + * This function will try to find default provider Ids specified in this + * instance. + * It none defined, it will try to pull Ids from the parent configuration. + */ + @Override + public String[] getDefaultLanguageSettingsProviderIds() { + if (defaultLanguageSettingsProviderIds == null) { + defaultLanguageSettingsProvidersAttribute = getDefaultLanguageSettingsProvidersAttribute(); + if (defaultLanguageSettingsProvidersAttribute != null) { + List ids = new ArrayList<>(); + String[] defaultIds = defaultLanguageSettingsProvidersAttribute + .split(LANGUAGE_SETTINGS_PROVIDER_DELIMITER); + for (String id : defaultIds) { + if (id != null && !id.isEmpty()) { + if (id.startsWith(LANGUAGE_SETTINGS_PROVIDER_NEGATION_SIGN)) { + id = id.substring(1); + ids.remove(id); + } else if (!ids.contains(id)) { + if (id.contains($TOOLCHAIN)) { + IToolChain toolchain = getToolChain(); + if (toolchain != null) { + String toolchainProvidersIds = toolchain.getDefaultLanguageSettingsProviderIds(); + if (toolchainProvidersIds != null) { + ids.addAll(Arrays.asList( + toolchainProvidersIds.split(LANGUAGE_SETTINGS_PROVIDER_DELIMITER))); + } + } + } else { + ids.add(id); + } + } + } + + } + defaultLanguageSettingsProviderIds = ids.toArray(new String[ids.size()]); + } else if (parent != null) { + defaultLanguageSettingsProviderIds = parent.getDefaultLanguageSettingsProviderIds(); + } + } + + return defaultLanguageSettingsProviderIds; + } + + @Override + public void setArtifactExtension(String extension) { + if (extension == null && artifactExtension == null) + return; + if (artifactExtension == null || extension == null || !artifactExtension.equals(extension)) { + artifactExtension = extension; + // rebuildNeeded = true; + if (!isExtensionElement()) { + ITool tool = calculateTargetTool(); + if (tool != null) { + tool.setRebuildState(true); + } else { + setRebuildState(true); + } + } + isDirty = true; + // exportArtifactInfo(); + } + } + + @Override + public void setArtifactName(String name) { + if (name == null && artifactName == null) + return; + if (artifactName == null || name == null || !artifactName.equals(name)) { + if (canExportedArtifactInfo()) { + // Remove existing exported library, if it exists + ICConfigurationDescription des = ManagedBuildManager.getDescriptionForConfiguration(this); + ICSettingEntry[] unresolved = new ICSettingEntry[] { + CDataUtil.createCLibraryFileEntry(getArtifactName(), 0) }; + ICSettingEntry[] libs = CDataUtil.resolveEntries(unresolved, des); + if (libs.length > 0) { + for (ICExternalSetting setting : des.getExternalSettings()) { + Set entries = new LinkedHashSet<>(Arrays.asList(setting.getEntries())); + for (ICSettingEntry lib : libs) { + if (entries.contains(lib)) { + entries.remove(lib); + des.removeExternalSetting(setting); + des.createExternalSetting(setting.getCompatibleLanguageIds(), + setting.getCompatibleContentTypeIds(), setting.getCompatibleExtensions(), + entries.toArray(new ICSettingEntry[entries.size()])); + } + } + } + } + } + + artifactName = name; + if (!isExtensionElement()) { + ITool tool = calculateTargetTool(); + if (tool != null) { + tool.setRebuildState(true); + } else { + setRebuildState(true); + } + } + // rebuildNeeded = true; + isDirty = true; + exportArtifactInfo(); + } + } + + @Override + public void setErrorParserIds(String ids) { + String currentIds = getErrorParserIds(); + if (ids == null && currentIds == null) + return; + if (currentIds == null || ids == null || !(currentIds.equals(ids))) { + errorParserIds = ids; + isDirty = true; + } + } + + @Override + public void setCleanCommand(String command) { + if (command == null && cleanCommand == null) + return; + if (cleanCommand == null || command == null || !cleanCommand.equals(command)) { + cleanCommand = command; + isDirty = true; + } + } + + @Override + public void setDescription(String description) { + if (description == null && this.description == null) + return; + if (this.description == null || description == null || !description.equals(this.description)) { + this.description = description; + isDirty = true; + } + } + + @Override + public void setBuildArguments(String makeArgs) { + IToolChain tc = getToolChain(); + IBuilder builder = tc.getBuilder(); + if (makeArgs == null) { //resetting the build arguments + if (!builder.isExtensionElement()) { + builder.setArguments(makeArgs); + // rebuildNeeded = true; + } + } else if (!makeArgs.equals(builder.getArguments())) { + if (builder.isExtensionElement()) { + String subId = ManagedBuildManager.calculateChildId(builder.getId(), null); + String builderName = builder.getName() + "." + getName(); //$NON-NLS-1$ + builder = getToolChain().createBuilder(builder, subId, builderName, false); + } + builder.setArguments(makeArgs); + // rebuildNeeded = true; + } + } + + @Override + public void setBuildCommand(String command) { + IToolChain tc = getToolChain(); + IBuilder builder = tc.getBuilder(); + if (command == null) { //resetting the build command + if (!builder.isExtensionElement()) { + builder.setCommand(command); + // rebuildNeeded = true; + } + } else if (!command.equals(builder.getCommand())) { + if (builder.isExtensionElement()) { + String subId = ManagedBuildManager.calculateChildId(builder.getId(), null); + String builderName = builder.getName() + "." + getName(); //$NON-NLS-1$ + builder = getToolChain().createBuilder(builder, subId, builderName, false); + } + builder.setCommand(command); + // rebuildNeeded = true; + } + } + + @Override + public void setPrebuildStep(String step) { + String currentPrebuildStep = getPrebuildStep(); + if (step == null && prebuildStep == null) + return; + if (currentPrebuildStep == null || step == null || !currentPrebuildStep.equals(step)) { + prebuildStep = step; + // rebuildNeeded = true; + isDirty = true; + } + } + + @Override + public void setPostbuildStep(String step) { + String currentPostbuildStep = getPostbuildStep(); + if (step == null && postbuildStep == null) + return; + if (currentPostbuildStep == null || step == null || !currentPostbuildStep.equals(step)) { + postbuildStep = step; + // rebuildNeeded = true; + isDirty = true; + } + } + + @Override + public void setPreannouncebuildStep(String announceStep) { + String currentPreannouncebuildStep = getPreannouncebuildStep(); + if (announceStep == null && preannouncebuildStep == null) + return; + if (currentPreannouncebuildStep == null || announceStep == null + || !currentPreannouncebuildStep.equals(announceStep)) { + preannouncebuildStep = announceStep; + // rebuildNeeded = true; + isDirty = true; + } + } + + @Override + public void setPostannouncebuildStep(String announceStep) { + String currentAnnounceStep = getPostannouncebuildStep(); + if (announceStep == null && postannouncebuildStep == null) + return; + if (currentAnnounceStep == null || announceStep == null || !currentAnnounceStep.equals(announceStep)) { + postannouncebuildStep = announceStep; + // rebuildNeeded = true; + isDirty = true; + } + } + + @Override + public boolean isSupported() { + IFolderInfo foInfo = getRootFolderInfo(); + if (foInfo != null) + return foInfo.isSupported(); + return false; + } + + @Override + public boolean isHeaderFile(String ext) { + return getRootFolderInfo().isHeaderFile(ext); + } + + /* + * O B J E C T S T A T E M A I N T E N A N C E + */ + + @Override + public boolean isExtensionElement() { + return isExtensionConfig; + } + + @Override + public boolean isDirty() { + // This shouldn't be called for an extension configuration + if (isExtensionConfig) + return false; + + // If I need saving, just say yes + if (isDirty) + return true; + + // Otherwise see if any children need saving + IResourceInfo infos[] = rcInfos.getResourceInfos(); + + for (int i = 0; i < infos.length; i++) { + if (infos[i].isDirty()) + return true; + } + return isDirty; + } + + @Override + public boolean needsRebuild() { + return needsRebuild(true); + } + + @Override + public boolean needsFullRebuild() { + return needsRebuild(false); + } + + public boolean needsRebuild(boolean checkChildren) { + boolean needRebuild = rebuildNeeded || resourceChangesRequireRebuild(); + + if (needRebuild || !checkChildren) + return needRebuild; + + IResourceInfo infos[] = rcInfos.getResourceInfos(); + + for (int i = 0; i < infos.length; i++) { + if (infos[i].needsRebuild()) + return true; + } + + return false; + } + + @Override + public void setDirty(boolean isDirty) { + // Override the dirty flag + this.isDirty = isDirty; + // Propagate "false" to the children + if (!isDirty) { + IResourceInfo infos[] = rcInfos.getResourceInfos(); + + for (int i = 0; i < infos.length; i++) { + infos[i].setDirty(false); + } + } + } + + @Override + public void setRebuildState(boolean rebuild) { + if (isExtensionElement() && rebuild) + return; + + if (rebuildNeeded != rebuild) { + rebuildNeeded = rebuild; + saveRebuildState(); + } + + if (!rebuildNeeded) { + setResourceChangeState(0); + + IResourceInfo infos[] = rcInfos.getResourceInfos(); + + for (int i = 0; i < infos.length; i++) { + infos[i].setRebuildState(false); + } + } + } + + @Override + public boolean hasOverriddenBuildCommand() { + IBuilder builder = getToolChain().getBuilder(); + if (builder != null) { + IBuilder superB = builder.getSuperClass(); + if (superB != null) { + String command = builder.getCommand(); + if (command != null) { + String superC = superB.getCommand(); + if (superC != null) { + if (!command.equals(superC)) { + return true; + } + } + } + String args = builder.getArguments(); + if (args != null) { + String superA = superB.getArguments(); + if (superA != null) { + if (!args.equals(superA)) { + return true; + } + } + } + } + } + return false; + } + + public void resolveReferences() { + if (!resolved) { + resolved = true; + + // call resolve references on any children + ResourceInfo infos[] = (ResourceInfo[]) rcInfos.getResourceInfos(ResourceInfo.class); + + for (int i = 0; i < infos.length; i++) { + infos[i].resolveReferences(); + } + + if (parentId != null) { + // Lookup the parent configuration by ID + parent = ManagedBuildManager.getExtensionConfiguration(parentId); + } + + } + } + + /** + * Reset the configuration's, tools', options + */ + public void reset() { + ((FolderInfo) getRootFolderInfo()).resetOptionSettings(); + } + + /** + * Create a resource configuration object for the passed-in file + */ + @Override + public IResourceConfiguration createResourceConfiguration(IFile file) { + return createFileInfo(file.getFullPath().removeFirstSegments(1)); + + } + + @Override + public IFileInfo createFileInfo(IPath path) { + String resourceName = path.lastSegment(); + String id = ManagedBuildManager.calculateChildId(getId(), path.toString()); + return createFileInfo(path, id, resourceName); + } + + @Override + public IFileInfo createFileInfo(IPath path, String id, String name) { + IResourceInfo info = getResourceInfo(path, false); + IFileInfo fileInfo = null; + if (info instanceof IFileInfo) { + fileInfo = (IFileInfo) info; + } else if (info instanceof IFolderInfo) { + IFolderInfo base = (IFolderInfo) info; + fileInfo = createFileInfo(path, base, null, id, name); + } + return fileInfo; + } + + @Override + public IFileInfo createFileInfo(IPath path, IFolderInfo base, ITool baseTool, String id, String name) { + if (base.getPath().equals(path)) + return null; + + IFileInfo fileInfo = new ResourceConfiguration((FolderInfo) base, baseTool, id, name, path); + addResourceConfiguration(fileInfo); + ManagedBuildManager.performValueHandlerEvent(fileInfo, IManagedOptionValueHandler.EVENT_OPEN); + + return fileInfo; + } + + @Override + public IFileInfo createFileInfo(IPath path, IFileInfo base, String id, String name) { + if (base.getPath().equals(path)) + return null; + + IFileInfo fileInfo = new ResourceConfiguration((ResourceConfiguration) base, path, id, name); + addResourceConfiguration(fileInfo); + ManagedBuildManager.performValueHandlerEvent(fileInfo, IManagedOptionValueHandler.EVENT_OPEN); + + return fileInfo; + } + + @Override + public IConfigurationEnvironmentVariableSupplier getEnvironmentVariableSupplier() { + IToolChain toolChain = getToolChain(); + if (toolChain != null) + return toolChain.getEnvironmentVariableSupplier(); + return null; + } + + /** + * @return Returns the version. + */ + @Override + public Version getVersion() { + if (version == null) { + if (rootFolderInfo.getToolChain() != null) { + return rootFolderInfo.getToolChain().getVersion(); + } + } + return version; + } + + @Override + public void setVersion(Version version) { + // Do nothing + } + + @Override + public IConfigurationBuildMacroSupplier getBuildMacroSupplier() { + IToolChain toolChain = getToolChain(); + if (toolChain != null) + return toolChain.getBuildMacroSupplier(); + return null; + + } + + @Override + public boolean isTemporary() { + return isTemporary; + } + + @Override + public void updateManagedBuildRevision(String revision) { + super.updateManagedBuildRevision(revision); + + ResourceInfo infos[] = (ResourceInfo[]) rcInfos.getResourceInfos(ResourceInfo.class); + + for (int i = 0; i < infos.length; i++) { + infos[i].updateManagedBuildRevision(revision); + } + } + + public void setParent(IConfiguration parent) { + if (this.parent != parent) { + this.parent = parent; + if (!isExtensionElement()) + setDirty(true); + } + } + + @Override + public ITool calculateTargetTool() { + ITool tool = getTargetTool(); + + if (tool == null) { + tool = getToolFromOutputExtension(getArtifactExtension()); + } + + if (tool == null) { + IConfiguration extCfg; + for (extCfg = this; extCfg != null && !extCfg.isExtensionElement(); extCfg = extCfg.getParent()) { + } + + if (extCfg != null) { + tool = getToolFromOutputExtension(extCfg.getArtifactExtension()); + } + } + + return tool; + } + + @Override + public ITool getToolFromOutputExtension(String extension) { + return getRootFolderInfo().getToolFromOutputExtension(extension); + } + + @Override + public ITool getToolFromInputExtension(String sourceExtension) { + return getRootFolderInfo().getToolFromInputExtension(sourceExtension); + } + + /** + * The resource delta passed to the builder is not always up-to-date + * for the given configuration because between two builds of the same + * configuration + * any number of other configuration builds may occur + * that is why we need to keep some information regarding what happened + * with the resource tree between the two configuration builds + * + * The trivial approach implemented currently is to hold + * the general information of whether some resources were + * removed,changed,etc. and detect whether the rebuild is needed + * based upon this information + * + * This method adds the resource change state for the configuration + * specifying the resource change type performed on the project + * reported while building another configuration + * The method is not exported to the public API since delta handling + * mechanism will likely to be changed in the future + * + * In the future we might implement some more smart mechanism + * for tracking delta, e.g calculate the pre-cinfiguration resource delta, etc. + * + */ + @Override + public void addResourceChangeState(int state) { + setResourceChangeState(state | resourceChangeState); + } + + private void setResourceChangeState(int state) { + if (resourceChangeState != state) { + resourceChangeState = state; + saveResourceChangeState(); + } + } + + private boolean resourceChangesRequireRebuild() { + return isInternalBuilderEnabled() ? resourceChangeState != 0 + : (resourceChangeState & IResourceDelta.REMOVED) == IResourceDelta.REMOVED; + } + + private void saveRebuildState() { + PropertyManager.getInstance().setProperty(this, REBUILD_STATE, Boolean.toString(rebuildNeeded)); + } + + private void saveResourceChangeState() { + PropertyManager.getInstance().setProperty(this, RC_CHANGE_STATE, Integer.toString(resourceChangeState)); + } + + /* + * Internal Builder state API + * NOTE: this is a temporary API + * In the future we are going present the Internal Builder + * as a special Builder object of the tool-chain and implement the internal + * builder enabling/disabling as the Builder substitution functionality + * + */ + + /* public void setInternalBuilderBoolean(boolean value, String pref) { + Preferences prefs = getPreferences(INTERNAL_BUILDER); + if(prefs != null){ + prefs.putBoolean(pref, value); + try { + prefs.flush(); + } catch (BackingStoreException e) {} + } + } + */ + /* public boolean getInternalBuilderBoolean(String pref, boolean defaultValue) { + Preferences prefs = getPreferences(INTERNAL_BUILDER); + return prefs != null ? + prefs.getBoolean(pref, false) : defaultValue; + } + */ + /** + * this method is used for enabling/disabling the internal builder + * for the given configuration + * + * @param enable + * boolean + */ + public void enableInternalBuilder(boolean enable) { + if (enable == isInternalBuilderEnabled()) + return; + + IBuilder builder = getBuilderForInternalBuilderEnablement(enable, true); + if (builder != null) { + if (enable) { + savePrevBuilderId(getBuilder()); + } + + changeBuilder(builder, ManagedBuildManager.calculateChildId(builder.getId(), null), builder.getName(), + true); + + if (enable) { + try { + setManagedBuildOn(true); + } catch (BuildException e) { + } + } + } + } + + public boolean canEnableInternalBuilder(boolean enable) { + return getBuilderForInternalBuilderEnablement(enable, true) != null; + } + + private IBuilder getBuilderForInternalBuilderEnablement(boolean enable, boolean checkCompatibility) { + IBuilder newBuilder = null; + if (enable) { + if (supportsBuild(true, false)) { + IBuilder b = ManagedBuildManager.getInternalBuilder(); + if (b != null) { + if (!checkCompatibility || isBuilderCompatible(b)) + newBuilder = b; + } + } + } else { + String id = getPrevBuilderId(); + if (id != null) { + IBuilder b = ManagedBuildManager.getExtensionBuilder(id); + if (b != null) { + if (!checkCompatibility || isBuilderCompatible(b)) + newBuilder = b; + } + } + if (newBuilder == null) { + for (IToolChain tc = getToolChain(); tc != null; tc = tc.getSuperClass()) { + IBuilder b = tc.getBuilder(); + if (b.isInternalBuilder()) + continue; + + for (; b != null && !b.isExtensionElement(); b = b.getSuperClass()) { + } + + if (b != null) { + if (!checkCompatibility || isBuilderCompatible(b)) { + newBuilder = b; + break; + } + } + } + } + + // if(newBuilder == null){ + // IBuilder builders[] = ManagedBuildManager.getRealBuilders(); + // IBuilder tmpB = null; + // for(int i = 0; i < builders.length; i++){ + // IBuilder b = builders[i]; + // if(b.isInternalBuilder()) + // continue; + // + // + // if(isBuilderCompatible(b)){ + // newBuilder = b; + // break; + // } else if(!checkCompatibility){ + // tmpB = b; + // } + // } + // + // if(newBuilder == null){ + // if(tmpB != null) + // newBuilder = tmpB; + // } + // } + + } + + return newBuilder; + } + + private void savePrevBuilderId(IBuilder builder) { + IBuilder b = builder; + for (; b != null && !b.isExtensionElement(); b = b.getSuperClass()) { + } + + if (b == null) + b = builder; + + ToolChain tc = (ToolChain) getToolChain(); + if (tc != null) + tc.setNonInternalBuilderId(b.getId()); + } + + private String getPrevBuilderId() { + ToolChain tc = (ToolChain) getToolChain(); + if (tc != null) + return tc.getNonInternalBuilderId(); + return null; + } + + /** + * returns whether the internal builder is enabled + * + * @return boolean + */ + public boolean isInternalBuilderEnabled() { + return getBuilder().isInternalBuilder(); + } + + /** + * + * sets the Internal Builder mode + * + * @param ignore + * if true, internal builder will ignore + * build errors while building, + * otherwise it will stop at the first build error + */ + public void setInternalBuilderIgnoreErr(boolean ignore) { + try { + getEditableBuilder().setStopOnError(!ignore); + } catch (CoreException e) { + } + } + + /** + * returns the Internal Builder mode + * if true, internal builder will ignore build errors while building, + * otherwise it will stop at the first build error + * + * @return boolean + */ + public boolean getInternalBuilderIgnoreErr() { + return !getBuilder().isStopOnError(); + } + + /** + * sets the Internal Builder Parallel mode + * + * @param parallel + * if true, internal builder will use parallel mode + * + * @deprecated since CDT 9.0. Use {@link #setParallelDef(boolean)} + */ + @Deprecated + public void setInternalBuilderParallel(boolean parallel) { + setParallelDef(parallel); + } + + /** + * returns the Internal Builder parallel mode + * if true, internal builder will work in parallel mode + * otherwise it will use only one thread + * + * @return boolean + * + * @deprecated since CDT 9.0. Use {@link #getParallelDef()} + */ + @Deprecated + public boolean getInternalBuilderParallel() { + return getParallelDef(); + } + + /** + * Set parallel execution mode for the configuration's builder. + * + * @see Builder#setParallelBuildOn(boolean) + * + * @param parallel + * - the flag to enable or disable parallel mode. + */ + public void setParallelDef(boolean parallel) { + if (getParallelDef() == parallel) + return; + + try { + getEditableBuilder().setParallelBuildOn(parallel); + } catch (CoreException e) { + Activator.log(e); + } + } + + /** + * Check if the configuration's builder is operating in parallel mode. + * + * @return {@code true} if parallel mode is enabled, {@code false} otherwise. + */ + public boolean getParallelDef() { + return getBuilder().isParallelBuildOn(); + } + + /** + * Sets maximum number of parallel threads/jobs to be used by builder. + * + * @param jobs + * - maximum number of jobs or threads. For details how + * the number is interpreted see + * {@link Builder#setParallelizationNum(int)}. + */ + public void setParallelNumber(int jobs) { + try { + getEditableBuilder().setParallelizationNum(jobs); + } catch (CoreException e) { + Activator.log(e); + } + } + + /** + * Returns maximum number of parallel threads/jobs used by the configuration's + * builder. + * + * @see #setParallelDef(boolean) + * + * @return - maximum number of parallel threads or jobs used by the builder. + */ + public int getParallelNumber() { + return getBuilder().getParallelizationNum(); + } + + // private Preferences getPreferences(String name){ + // if(isTemporary) + // return null; + // + // IProject project = (IProject)getOwner(); + // + // if(project == null || !project.exists() || !project.isOpen()) + // return null; + // + // Preferences prefs = new ProjectScope(project).getNode(ManagedBuilderCorePlugin.getUniqueIdentifier()); + // if(prefs != null){ + // prefs = prefs.node(getId()); + // if(prefs != null && name != null) + // prefs = prefs.node(name); + // } + // return prefs; + // } + + @Override + public IResourceInfo[] getResourceInfos() { + return rcInfos.getResourceInfos(); + } + + @Override + public IResourceInfo getResourceInfo(IPath path, boolean exactPath) { + return rcInfos.getResourceInfo(path, exactPath); + } + + @Override + public IResourceInfo getResourceInfoById(String id) { + IResourceInfo infos[] = rcInfos.getResourceInfos(); + for (int i = 0; i < infos.length; i++) { + if (id.equals(infos[i].getId())) + return infos[i]; + } + return null; + } + + @Override + public IFolderInfo getRootFolderInfo() { + return rootFolderInfo; + } + + ResourceInfoContainer getRcInfoContainer(IResourceInfo rcInfo) { + PathSettingsContainer cr = pathSettings.getChildContainer(rcInfo.getPath(), true, true); + return new ResourceInfoContainer(cr, false); + } + + @Override + public CConfigurationData getConfigurationData() { + // return fCfgData; + return null; + } + + @Override + public void removeResourceInfo(IPath path) { + IResourceInfo info = getResourceInfo(path, true); + if (info != null) + removeResourceConfiguration(info); + } + + @Override + public IFolderInfo createFolderInfo(IPath path) { + String resourceName = path.lastSegment(); + String id = ManagedBuildManager.calculateChildId(getId(), path.toString()); + return createFolderInfo(path, id, resourceName); + } + + @Override + public IFolderInfo createFolderInfo(IPath path, String id, String name) { + IResourceInfo info = getResourceInfo(path, false); + IFolderInfo folderInfo = null; + if (info instanceof IFileInfo) { + // folderInfo = null; + } else if (info instanceof IFolderInfo) { + IFolderInfo base = (IFolderInfo) info; + folderInfo = createFolderInfo(path, base, id, name); + } + return folderInfo; + } + + @Override + public IFolderInfo createFolderInfo(IPath path, IFolderInfo base, String id, String name) { + if (base.getPath().equals(path)) + return null; + + FolderInfo folderInfo = new FolderInfo((FolderInfo) base, id, name, path); + addResourceConfiguration(folderInfo); + folderInfo.propertiesChanged(); + ManagedBuildManager.performValueHandlerEvent(folderInfo, IManagedOptionValueHandler.EVENT_OPEN); + + return folderInfo; + } + + @Override + public ICSourceEntry[] getSourceEntries() { + if (sourceEntries == null || sourceEntries.length == 0) { + if (parent != null && sourceEntries == null) + return parent.getSourceEntries(); + return new ICSourceEntry[] { + new CSourceEntry(Path.EMPTY, null, ICSettingEntry.VALUE_WORKSPACE_PATH | ICSettingEntry.RESOLVED) }; + + } + return sourceEntries.clone(); + } + + @Override + public void setSourceEntries(ICSourceEntry[] entries) { + setSourceEntries(entries, true); + } + + public void setSourceEntries(ICSourceEntry[] entries, boolean setRebuildState) { + exportArtifactInfo(); + if (Arrays.equals(getSourceEntries(), entries)) + return; + sourceEntries = entries != null ? (ICSourceEntry[]) entries.clone() : null; + // for(int i = 0; i < sourcePaths.length; i++){ + // sourcePaths[i] = sourcePaths[i].makeRelative(); + // } + if (setRebuildState) { + setDirty(true); + setRebuildState(true); + } + } + + public void setErrorParserAttribute(String[] ids) { + if (ids == null) { + setErrorParserIds(null); + } else if (ids.length == 0) { + setErrorParserIds(EMPTY_STRING); + } else { + StringBuilder buf = new StringBuilder(); + buf.append(ids[0]); + for (int i = 1; i < ids.length; i++) { + buf.append(";").append(ids[i]); //$NON-NLS-1$ + } + setErrorParserIds(buf.toString()); + } + } + + @Override + public void setErrorParserList(String[] ids) { + if (ids == null) { + //reset + resetErrorParsers(); + } else { + setErrorParserAttribute(ids); + } + } + + public void resetErrorParsers() { + errorParserIds = null; + IResourceInfo rcInfos[] = getResourceInfos(); + for (int i = 0; i < rcInfos.length; i++) { + ResourceInfo rcInfo = (ResourceInfo) rcInfos[i]; + rcInfo.resetErrorParsers(); + } + } + + void removeErrorParsers(Set set) { + if (set != null && set.isEmpty()) { + Set oldSet = contributeErrorParsers(null, false); + if (oldSet == null) + oldSet = new LinkedHashSet<>(); + + oldSet.removeAll(set); + setErrorParserAttribute(oldSet.toArray(new String[oldSet.size()])); + + IResourceInfo rcInfos[] = getResourceInfos(); + for (int i = 0; i < rcInfos.length; i++) { + ResourceInfo rcInfo = (ResourceInfo) rcInfos[i]; + rcInfo.removeErrorParsers(set); + } + } + } + + @Override + public CBuildData getBuildData() { + return getEditableBuilder().getBuildData(); + } + + @Override + public IBuilder getEditableBuilder() { + IToolChain tc = getToolChain(); + IBuilder builder = tc.getBuilder(); + if (builder.isExtensionElement()) { + String subId = ManagedBuildManager.calculateChildId(builder.getId(), null); + String builderName = builder.getName() + "." + getName(); //$NON-NLS-1$ + builder = getToolChain().createBuilder(builder, subId, builderName, false); + } + return builder; + } + + @Override + public IBuilder getBuilder() { + return getToolChain().getBuilder(); + } + + @Override + public String getOutputPrefix(String outputExtension) { + // Treat null extensions as empty string + String ext = outputExtension == null ? EMPTY_STRING : outputExtension; + + // Get all the tools for the current config + String flags = EMPTY_STRING; + ITool[] tools = getFilteredTools(); + for (int index = 0; index < tools.length; index++) { + ITool tool = tools[index]; + if (tool.producesFileType(ext)) { + flags = tool.getOutputPrefix(); + } + } + return flags; + } + + public ICConfigurationDescription getConfigurationDescription() { + return fCfgDes; + } + + public void setConfigurationDescription(ICConfigurationDescription cfgDes) { + fCfgDes = cfgDes; + } + + @Override + public IBuildObjectProperties getBuildProperties() { + if (buildProperties == null) { + BuildObjectProperties parentProps = findBuildProperties(); + if (parentProps != null) + buildProperties = new BuildObjectProperties(parentProps, this, this); + else + buildProperties = new BuildObjectProperties(this, this); + } + return buildProperties; + } + + @Override + public IOptionalBuildProperties getOptionalBuildProperties() { + if (optionalBuildProperties == null) { + OptionalBuildProperties parentProps = findOptionalBuildProperties(); + if (parentProps != null) + optionalBuildProperties = new OptionalBuildProperties(parentProps); + else + optionalBuildProperties = new OptionalBuildProperties(); + } + return optionalBuildProperties; + } + + private BuildObjectProperties findBuildProperties() { + if (buildProperties == null) { + if (parent != null) { + return ((Configuration) parent).findBuildProperties(); + } + return null; + } + return buildProperties; + } + + private OptionalBuildProperties findOptionalBuildProperties() { + if (optionalBuildProperties == null) { + if (parent != null) { + return ((Configuration) parent).findOptionalBuildProperties(); + } + return null; + } + return optionalBuildProperties; + } + + public boolean supportsType(IBuildPropertyType type) { + return supportsType(type.getId()); + } + + public boolean supportsValue(IBuildPropertyType type, IBuildPropertyValue value) { + return supportsValue(type.getId(), value.getId()); + } + + @Override + public void propertiesChanged() { + if (isExtensionConfig) + return; + + BooleanExpressionApplicabilityCalculator calculator = getBooleanExpressionCalculator(); + if (calculator != null) + calculator.adjustConfiguration(this, false); + + IResourceInfo infos[] = getResourceInfos(); + for (int i = 0; i < infos.length; i++) { + ((ResourceInfo) infos[i]).propertiesChanged(); + } + } + + public BooleanExpressionApplicabilityCalculator getBooleanExpressionCalculator() { + if (booleanExpressionCalculator == null) { + if (parent != null) { + return ((Configuration) parent).getBooleanExpressionCalculator(); + } + } + return booleanExpressionCalculator; + } + + @Override + public boolean isSystemObject() { + if (isTest) + return true; + + if (getProjectType() != null) + return getProjectType().isSystemObject(); + + return false; + } + + @Override + public String getOutputExtension(String resourceExtension) { + return getRootFolderInfo().getOutputExtension(resourceExtension); + } + + @Override + public String getOutputFlag(String outputExt) { + // Treat null extension as an empty string + String ext = outputExt == null ? EMPTY_STRING : outputExt; + + // Get all the tools for the current config + String flags = EMPTY_STRING; + ITool[] tools = getFilteredTools(); + for (int index = 0; index < tools.length; index++) { + ITool tool = tools[index]; + // It's OK + if (tool.producesFileType(ext)) { + flags = tool.getOutputFlag(); + } + } + return flags; + } + + @Override + public IManagedCommandLineInfo generateToolCommandLineInfo(String sourceExtension, String[] flags, + String outputFlag, String outputPrefix, String outputName, String[] inputResources, IPath inputLocation, + IPath outputLocation) { + ITool[] tools = getFilteredTools(); + for (int index = 0; index < tools.length; index++) { + ITool tool = tools[index]; + if (tool.buildsFileType(sourceExtension)) { + String cmd = tool.getToolCommand(); + //try to resolve the build macros in the tool command + try { + String resolvedCommand = null; + + if ((inputLocation != null && inputLocation.toString().indexOf(" ") != -1) || //$NON-NLS-1$ + (outputLocation != null && outputLocation.toString().indexOf(" ") != -1)) //$NON-NLS-1$ + { + resolvedCommand = ManagedBuildManager.getBuildMacroProvider().resolveValue(cmd, "", //$NON-NLS-1$ + " ", //$NON-NLS-1$ + IBuildMacroProvider.CONTEXT_FILE, + new FileContextData(inputLocation, outputLocation, null, tool)); + } + + else { + resolvedCommand = ManagedBuildManager.getBuildMacroProvider().resolveValueToMakefileFormat(cmd, + "", //$NON-NLS-1$ + " ", //$NON-NLS-1$ + IBuildMacroProvider.CONTEXT_FILE, + new FileContextData(inputLocation, outputLocation, null, tool)); + } + if ((resolvedCommand = resolvedCommand.trim()).length() > 0) + cmd = resolvedCommand; + + } catch (BuildMacroException e) { + } + + IManagedCommandLineGenerator gen = tool.getCommandLineGenerator(); + return gen.generateCommandLineInfo(tool, cmd, flags, outputFlag, outputPrefix, outputName, + inputResources, tool.getCommandLinePattern()); + } + } + return null; + } + + @Override + public String[] getUserObjects(String extension) { + Vector objs = new Vector<>(); + ITool tool = calculateTargetTool(); + if (tool == null) + tool = getToolFromOutputExtension(extension); + + if (tool != null) { + IOption[] opts = tool.getOptions(); + // Look for the user object option type + for (int i = 0; i < opts.length; i++) { + IOption option = opts[i]; + try { + if (option.getValueType() == IOption.OBJECTS) { + // check to see if the option has an applicability calculator + IOptionApplicability applicabilityCalculator = option.getApplicabilityCalculator(); + + if (applicabilityCalculator == null + || applicabilityCalculator.isOptionUsedInCommandLine(this, tool, option)) { + boolean generateDefaultCommand = true; + IOptionCommandGenerator commandGenerator = option.getCommandGenerator(); + if (commandGenerator != null) { + SupplierBasedCdtVariableSubstitutor macroSubstitutor = new BuildfileMacroSubstitutor( + null, EMPTY_STRING, WHITE_SPACE); + IMacroContextInfoProvider provider = BuildMacroProvider.getDefault(); + IMacroContextInfo info = provider.getMacroContextInfo(BuildMacroProvider.CONTEXT_OPTION, + new OptionContextData(option, tool)); + if (info != null) { + macroSubstitutor.setMacroContextInfo(info); + String command = commandGenerator.generateCommand(option, macroSubstitutor); + if (command != null) { + objs.add(command); + generateDefaultCommand = false; + } + } + } + + if (generateDefaultCommand) { + String unresolved[] = option.getUserObjects(); + if (unresolved != null && unresolved.length > 0) { + for (int k = 0; k < unresolved.length; k++) { + try { + String resolved[] = ManagedBuildManager.getBuildMacroProvider() + .resolveStringListValueToMakefileFormat(unresolved[k], "", //$NON-NLS-1$ + " ", //$NON-NLS-1$ + IBuildMacroProvider.CONTEXT_OPTION, + new OptionContextData(option, tool)); + if (resolved != null && resolved.length > 0) + objs.addAll(Arrays.asList(resolved)); + } catch (BuildMacroException e) { + // TODO: report error + continue; + } + } + } + } + } + } + } catch (BuildException | CdtVariableException e) { + // TODO: report error + continue; + } + } + } + return objs.toArray(new String[objs.size()]); + } + + @Override + public String[] getLibs(String extension) { + Vector libs = new Vector<>(); + ITool tool = calculateTargetTool(); + if (tool == null) + tool = getToolFromOutputExtension(extension); + + if (tool != null) { + IOption[] opts = tool.getOptions(); + // Look for the lib option type + for (int i = 0; i < opts.length; i++) { + IOption option = opts[i]; + try { + if (option.getValueType() == IOption.LIBRARIES) { + + // check to see if the option has an applicability calculator + IOptionApplicability applicabilityCalculator = option.getApplicabilityCalculator(); + + if (applicabilityCalculator == null + || applicabilityCalculator.isOptionUsedInCommandLine(this, tool, option)) { + boolean generateDefaultCommand = true; + IOptionCommandGenerator commandGenerator = option.getCommandGenerator(); + if (commandGenerator != null) { + SupplierBasedCdtVariableSubstitutor macroSubstitutor = new BuildfileMacroSubstitutor( + null, EMPTY_STRING, WHITE_SPACE); + IMacroContextInfoProvider provider = BuildMacroProvider.getDefault(); + IMacroContextInfo info = provider.getMacroContextInfo(BuildMacroProvider.CONTEXT_OPTION, + new OptionContextData(option, tool)); + if (info != null) { + macroSubstitutor.setMacroContextInfo(info); + String command = commandGenerator.generateCommand(option, macroSubstitutor); + if (command != null) { + libs.add(command); + generateDefaultCommand = false; + } + } + } + + if (generateDefaultCommand) { + String command = option.getCommand(); + String[] allLibs = option.getLibraries(); + for (int j = 0; j < allLibs.length; j++) { + try { + String resolved[] = ManagedBuildManager.getBuildMacroProvider() + .resolveStringListValueToMakefileFormat(allLibs[j], " ", //$NON-NLS-1$ + " ", //$NON-NLS-1$ + IBuildMacroProvider.CONTEXT_OPTION, + new OptionContextData(option, tool)); + if (resolved != null && resolved.length > 0) { + for (int k = 0; k < resolved.length; k++) { + String string = resolved[k]; + if (string.length() > 0) + libs.add(command + string); + } + } + } catch (BuildMacroException e) { + // TODO: report error + continue; + } + } + } + } + } + } catch (BuildException | CdtVariableException e) { + // TODO: report error + continue; + } + } + } + return libs.toArray(new String[libs.size()]); + } + + @Override + public boolean buildsFileType(String srcExt) { + return getRootFolderInfo().buildsFileType(srcExt); + } + + /** + * @return whether this Configuration exports settings to other referenced + * configurations + */ + public boolean canExportedArtifactInfo() { + if (isExtensionConfig) + return false; + + IBuildObjectProperties props = getBuildProperties(); + IBuildProperty prop = props.getProperty(ManagedBuildManager.BUILD_ARTEFACT_TYPE_PROPERTY_ID); + if (prop == null) + return false; + String valueId = prop.getValue().getId(); + if (!ManagedBuildManager.BUILD_ARTEFACT_TYPE_PROPERTY_SHAREDLIB.equals(valueId) + && !ManagedBuildManager.BUILD_ARTEFACT_TYPE_PROPERTY_STATICLIB.equals(valueId)) + return false; + ICConfigurationDescription des = ManagedBuildManager.getDescriptionForConfiguration(this); + return des != null && !des.isReadOnly(); + } + + /** + * Responsible for contributing 'external' settings back to the core for use + * by referenced projects. + * + * In this case it returns Include, Library path & Library File settings + * to be used be references for linking the output of this library project + */ + public void exportArtifactInfo() { + if (!canExportedArtifactInfo()) + return; + + ICConfigurationDescription des = ManagedBuildManager.getDescriptionForConfiguration(this); + if (des != null && !des.isReadOnly()) { + ICOutputEntry entries[] = getConfigurationData().getBuildData().getOutputDirectories(); + IPath path = getOwner().getFullPath(); + + List list = new ArrayList<>(entries.length + 1); + + // Add project level include path + list.add(CDataUtil.createCIncludePathEntry(path.toString(), ICSettingEntry.VALUE_WORKSPACE_PATH)); + + // Add Build output path as an exported library path + entries = CDataUtil.resolveEntries(entries, des); + for (int i = 0; i < entries.length; i++) { + ICOutputEntry out = entries[i]; + String value = out.getValue(); + + IPath p = new Path(value); + if (!p.isAbsolute()) + value = getOwner().getFullPath().append(value).toString(); + ICLibraryPathEntry lib = CDataUtil.createCLibraryPathEntry(value, + out.getFlags() & (~ICSettingEntry.RESOLVED)); + list.add(lib); + } + + // Add 'libs' artifact names themselves + ICSettingEntry[] unresolved = new ICSettingEntry[] { + CDataUtil.createCLibraryFileEntry(getArtifactName(), 0) }; + ICSettingEntry[] libFiles = CDataUtil.resolveEntries(unresolved, des); + list.add(libFiles[0]); + + // Contribute the settings back as 'exported' + des.createExternalSetting(null, null, null, list.toArray(new ICSettingEntry[list.size()])); + } + } + + @Override + public boolean supportsBuild(boolean managed) { + return supportsBuild(managed, true); + } + + public boolean supportsBuild(boolean managed, boolean checkBuilder) { + IResourceInfo[] rcs = getResourceInfos(); + for (int i = 0; i < rcs.length; i++) { + if (!rcs[i].supportsBuild(managed)) + return false; + } + + if (checkBuilder) { + IBuilder builder = getBuilder(); + if (builder != null && !builder.supportsBuild(managed)) + return false; + } + + return true; + } + + @Override + public boolean supportsType(String typeId) { + SupportedProperties props = findSupportedProperties(); + boolean supports = false; + if (props != null) { + supports = props.supportsType(typeId); + } + + if (!supports) + supports = ((ToolChain) getToolChain()).supportsType(typeId); + + return supports; + } + + @Override + public boolean supportsValue(String typeId, String valueId) { + SupportedProperties props = findSupportedProperties(); + boolean supports = false; + if (props != null) { + supports = props.supportsValue(typeId, valueId); + } + + if (!supports) + supports = ((ToolChain) getToolChain()).supportsValue(typeId, valueId); + + return supports; + } + + private SupportedProperties findSupportedProperties() { + if (supportedProperties == null) { + if (parent != null) { + return ((Configuration) parent).findSupportedProperties(); + } + } + return supportedProperties; + } + + private void loadProperties(IManagedConfigElement el) { + supportedProperties = new SupportedProperties(el); + } + + @Override + public String[] getRequiredTypeIds() { + SupportedProperties props = findSupportedProperties(); + List list = new ArrayList<>(); + if (props != null) { + list.addAll(Arrays.asList(props.getRequiredTypeIds())); + } + + list.addAll(Arrays.asList(((ToolChain) getToolChain()).getRequiredTypeIds())); + + return list.toArray(new String[list.size()]); + } + + @Override + public String[] getSupportedTypeIds() { + SupportedProperties props = findSupportedProperties(); + List list = new ArrayList<>(); + if (props != null) { + list.addAll(Arrays.asList(props.getSupportedTypeIds())); + } + + list.addAll(Arrays.asList(((ToolChain) getToolChain()).getSupportedTypeIds())); + + return list.toArray(new String[list.size()]); + } + + @Override + public String[] getSupportedValueIds(String typeId) { + SupportedProperties props = findSupportedProperties(); + List list = new ArrayList<>(); + if (props != null) { + list.addAll(Arrays.asList(props.getSupportedValueIds(typeId))); + } + + list.addAll(Arrays.asList(((ToolChain) getToolChain()).getSupportedValueIds(typeId))); + + return list.toArray(new String[list.size()]); + } + + @Override + public boolean requiresType(String typeId) { + SupportedProperties props = findSupportedProperties(); + boolean requires = false; + if (props != null) { + requires = props.requiresType(typeId); + } + + if (!requires) + requires = ((ToolChain) getToolChain()).requiresType(typeId); + + return requires; + } + + @Override + public boolean isManagedBuildOn() { + return getBuilder().isManagedBuildOn(); + } + + @Override + public void setManagedBuildOn(boolean on) throws BuildException { + getEditableBuilder().setManagedBuildOn(on); + } + + @Override + public void changeBuilder(IBuilder newBuilder, String id, String name) { + changeBuilder(newBuilder, id, name, false); + } + + public void changeBuilder(IBuilder newBuilder, String id, String name, boolean allBuildSettings) { + ToolChain tc = (ToolChain) getToolChain(); + Builder cur = (Builder) getEditableBuilder(); + Builder newCfgBuilder = null; + if (newBuilder.getParent() == tc) { + newCfgBuilder = (Builder) newBuilder; + } else { + IBuilder curReal = ManagedBuildManager.getRealBuilder(cur); + IBuilder newReal = ManagedBuildManager.getRealBuilder(newBuilder); + if (newReal != curReal) { + IBuilder extBuilder = newBuilder; + for (; extBuilder != null + && !extBuilder.isExtensionElement(); extBuilder = extBuilder.getSuperClass()) { + } + if (extBuilder == null) + extBuilder = newBuilder; + + newCfgBuilder = new Builder(tc, extBuilder, id, name, false); + newCfgBuilder.copySettings(cur, allBuildSettings); + } + } + + if (newCfgBuilder != null) { + tc.setBuilder(newCfgBuilder); + } + } + + @Override + public boolean isBuilderCompatible(IBuilder builder) { + return builder.supportsBuild(isManagedBuildOn()); + } + + ITool findToolById(String id) { + IResourceInfo[] rcInfos = getResourceInfos(); + ITool tool = null; + for (int i = 0; i < rcInfos.length; i++) { + ResourceInfo info = (ResourceInfo) rcInfos[i]; + tool = info.getToolById(id); + if (tool != null) + break; + } + return tool; + } + + void resolveProjectReferences(boolean onLoad) { + IResourceInfo[] rcInfos = getResourceInfos(); + for (int i = 0; i < rcInfos.length; i++) { + ResourceInfo info = (ResourceInfo) rcInfos[i]; + info.resolveProjectReferences(onLoad); + } + } + + public boolean isPerRcTypeDiscovery() { + ToolChain tc = (ToolChain) getRootFolderInfo().getToolChain(); + return tc.isPerRcTypeDiscovery(); + } + + public void setPerRcTypeDiscovery(boolean on) { + ToolChain tc = (ToolChain) getRootFolderInfo().getToolChain(); + tc.setPerRcTypeDiscovery(on); + } + + // public IScannerConfigBuilderInfo2 getScannerConfigInfo(){ + // ToolChain tc = (ToolChain)getRootFolderInfo().getToolChain(); + // return tc.getScannerConfigBuilderInfo(); + // } + + // public IScannerConfigBuilderInfo2 setScannerConfigInfo(IScannerConfigBuilderInfo2 info){ + // ToolChain tc = (ToolChain)getRootFolderInfo().getToolChain(); + // return tc.setScannerConfigBuilderInfo(info); + // } + + public PathInfoCache setDiscoveredPathInfo(PathInfoCache info) { + ToolChain tc = (ToolChain) getRootFolderInfo().getToolChain(); + return tc.setDiscoveredPathInfo(info); + } + + public PathInfoCache getDiscoveredPathInfo() { + ToolChain tc = (ToolChain) getRootFolderInfo().getToolChain(); + return tc.getDiscoveredPathInfo(); + } + + public String getDiscoveryProfileId() { + ToolChain tc = (ToolChain) getRootFolderInfo().getToolChain(); + return tc.getScannerConfigDiscoveryProfileId(); + } + + public PathInfoCache clearDiscoveredPathInfo() { + ToolChain tc = (ToolChain) getRootFolderInfo().getToolChain(); + return tc.clearDiscoveredPathInfo(); + } + + // public ICfgScannerConfigBuilderInfo2Set getCfgScannerConfigInfo() { + // return cfgScannerInfo; + // } + + // public void setCfgScannerConfigInfo(ICfgScannerConfigBuilderInfo2Set info) { + // cfgScannerInfo = info; + // } + // + // public void clearCachedData() { + // cfgScannerInfo = null; + // } + + public boolean isPreference() { + return isPreferenceConfig; + } + + @Override + public IBuildPropertyValue getBuildArtefactType() { + IBuildObjectProperties props = findBuildProperties(); + if (props != null) { + IBuildProperty prop = props.getProperty(ManagedBuildManager.BUILD_ARTEFACT_TYPE_PROPERTY_ID); + if (prop != null) + return prop.getValue(); + } + return null; + } + + @Override + public void setBuildArtefactType(String id) throws BuildException { + IBuildObjectProperties props = getBuildProperties(); + try { + props.setProperty(ManagedBuildManager.BUILD_ARTEFACT_TYPE_PROPERTY_ID, id); + } catch (CoreException e) { + throw new BuildException(e.getLocalizedMessage()); + } + // May need to update the exports paths & symbols after artifact type change + exportArtifactInfo(); + } + + boolean isExcluded(IPath path) { + // if(path.segmentCount() == 0) + // return false; + ICSourceEntry[] entries = getSourceEntries(); + return CDataUtil.isExcluded(path, entries); + } + + void setExcluded(IPath path, boolean isFolder, boolean excluded) { + // if(path.segmentCount() == 0) + // return; + if (excludeList == null) { + ICSourceEntry[] newEntries = getUpdatedEntries(path, isFolder, excluded); + if (newEntries != null) + setSourceEntries(newEntries, false); + } else { + if (excluded) + excludeList.add(path); + } + } + + private ICSourceEntry[] getUpdatedEntries(IPath path, boolean isFolder, boolean excluded) { + try { + ICSourceEntry[] entries = getSourceEntries(); + return CDataUtil.setExcluded(path, isFolder, excluded, entries, false); + } catch (CoreException e) { + Activator.log(e); + } + return null; + } + + boolean canExclude(IPath path, boolean isFolder, boolean excluded) { + if (excludeList == null) { + ICSourceEntry[] newEntries = getUpdatedEntries(path, isFolder, excluded); + return newEntries != null; + } else { + if (excluded) + excludeList.add(path); + return true; + } + } + + @Override + public IRealBuildObjectAssociation getExtensionObject() { + return isExtensionConfig ? this : (Configuration) getParent(); + } + + @Override + public IRealBuildObjectAssociation[] getIdenticBuildObjects() { + return new Configuration[] { (Configuration) getExtensionObject() }; + } + + @Override + public IRealBuildObjectAssociation getRealBuildObject() { + return getExtensionObject(); + } + + @Override + public IRealBuildObjectAssociation getSuperClassObject() { + return (IRealBuildObjectAssociation) getParent(); + } + + @Override + public int getType() { + return OBJECT_CONFIGURATION; + } + + @Override + public boolean isRealBuildObject() { + return getRealBuildObject() == this; + } + + @Override + public String getUniqueRealName() { + return getName(); + } + + @Override + public boolean isExtensionBuildObject() { + return isExtensionElement(); + } +} diff --git a/io.sloeber.ManagedBuild/src/io/sloeber/autoBuild/Internal/CoreMacrosSupplier.java b/io.sloeber.ManagedBuild/src/io/sloeber/autoBuild/Internal/CoreMacrosSupplier.java new file mode 100644 index 000000000..97f0b2a65 --- /dev/null +++ b/io.sloeber.ManagedBuild/src/io/sloeber/autoBuild/Internal/CoreMacrosSupplier.java @@ -0,0 +1,11 @@ +package io.sloeber.autoBuild.Internal; + +import org.eclipse.cdt.core.settings.model.ICConfigurationDescription; + +public class CoreMacrosSupplier { + + public CoreMacrosSupplier(ICConfigurationDescription cfgDes) { + // TODO Auto-generated constructor stub + } + +} diff --git a/io.sloeber.ManagedBuild/src/io/sloeber/autoBuild/Internal/DefaultMacroContextInfo.java b/io.sloeber.ManagedBuild/src/io/sloeber/autoBuild/Internal/DefaultMacroContextInfo.java new file mode 100644 index 000000000..b0d270422 --- /dev/null +++ b/io.sloeber.ManagedBuild/src/io/sloeber/autoBuild/Internal/DefaultMacroContextInfo.java @@ -0,0 +1,36 @@ +package io.sloeber.autoBuild.Internal; + +import org.eclipse.cdt.utils.cdtvariables.ICdtVariableSupplier; +import org.eclipse.cdt.utils.cdtvariables.IVariableContextInfo; + +public class DefaultMacroContextInfo implements IMacroContextInfo { + + public DefaultMacroContextInfo(int contextType, Object contextData) { + // TODO Auto-generated constructor stub + } + + @Override + public ICdtVariableSupplier[] getSuppliers() { + // TODO Auto-generated method stub + return null; + } + + @Override + public IVariableContextInfo getNext() { + // TODO Auto-generated method stub + return null; + } + + @Override + public int getContextType() { + // TODO Auto-generated method stub + return 0; + } + + @Override + public Object getContextData() { + // TODO Auto-generated method stub + return null; + } + +} diff --git a/io.sloeber.ManagedBuild/src/io/sloeber/autoBuild/Internal/DefaultManagedConfigElement.java b/io.sloeber.ManagedBuild/src/io/sloeber/autoBuild/Internal/DefaultManagedConfigElement.java new file mode 100644 index 000000000..8508da855 --- /dev/null +++ b/io.sloeber.ManagedBuild/src/io/sloeber/autoBuild/Internal/DefaultManagedConfigElement.java @@ -0,0 +1,93 @@ +/******************************************************************************* + * Copyright (c) 2004, 2011 TimeSys Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * TimeSys Corporation - Initial API and implementation + *******************************************************************************/ +package io.sloeber.autoBuild.Internal; + +//import org.eclipse.cdt.managedbuilder.core.IManagedConfigElement; +import org.eclipse.core.runtime.IConfigurationElement; +import org.eclipse.core.runtime.IExtension; + +import io.sloeber.autoBuild.api.IManagedConfigElement; + +/** + * Implements the ManagedConfigElement by delegate all calls to an + * IConfigurationElement instance. This is used to load configuration + * information from the extension point. + */ +public class DefaultManagedConfigElement implements IManagedConfigElement { + + private IConfigurationElement element; + private IExtension extension; + + public DefaultManagedConfigElement(IConfigurationElement element, IExtension extension) { + this.element = element; + this.extension = extension; + } + + /* (non-Javadoc) + * @see org.eclipse.cdt.managedbuilder.core.IManagedConfigElement#getName() + */ + @Override + public String getName() { + return element.getName(); + } + + /* (non-Javadoc) + * @see org.eclipse.cdt.managedbuilder.core.IManagedConfigElement#getAttribute(java.lang.String) + */ + @Override + public String getAttribute(String name) { + return element.getAttribute(name); + } + + /* (non-Javadoc) + * @see org.eclipse.cdt.managedbuilder.core.IManagedConfigElement#getChildren() + */ + @Override + public IManagedConfigElement[] getChildren() { + return convertArray(element.getChildren(), extension); + } + + /* (non-Javadoc) + * @see org.eclipse.cdt.managedbuilder.core.IManagedConfigElement#getChildren(java.lang.String) + */ + @Override + public IManagedConfigElement[] getChildren(String elementName) { + return convertArray(element.getChildren(elementName), extension); + } + + /* (non-Javadoc) + * @see org.eclipse.cdt.managedbuilder.core.IManagedConfigElement#getExtension(java.lang.String) + */ + public IExtension getExtension() { + return extension; + } + + public IConfigurationElement getConfigurationElement() { + return element; + } + + /** + * Convenience method for converting an array of IConfigurationElements + * into an array of IManagedConfigElements. + */ + public static IManagedConfigElement[] convertArray(IConfigurationElement[] elements, IExtension extension) { + + IManagedConfigElement[] ret = new IManagedConfigElement[elements.length]; + for (int i = 0; i < elements.length; i++) { + ret[i] = new DefaultManagedConfigElement(elements[i], extension); + } + return ret; + } + +} diff --git a/io.sloeber.ManagedBuild/src/io/sloeber/autoBuild/Internal/EnvVarBuildPath.java b/io.sloeber.ManagedBuild/src/io/sloeber/autoBuild/Internal/EnvVarBuildPath.java new file mode 100644 index 000000000..35272b181 --- /dev/null +++ b/io.sloeber.ManagedBuild/src/io/sloeber/autoBuild/Internal/EnvVarBuildPath.java @@ -0,0 +1,130 @@ +/******************************************************************************* + * Copyright (c) 2005, 2018 Intel Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Intel Corporation - Initial API and implementation + * IBM Corporation + *******************************************************************************/ +package io.sloeber.autoBuild.Internal; + +import org.eclipse.cdt.internal.core.SafeStringInterner; +//import org.eclipse.cdt.managedbuilder +//import org.eclipse.cdt.managedbuilder.core.IEnvVarBuildPath; +//import org.eclipse.cdt.managedbuilder.core.IManagedConfigElement; +//import org.eclipse.cdt.managedbuilder.core.ITool; +//import org.eclipse.cdt.managedbuilder.core.ManagedBuildManager; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IConfigurationElement; + +import io.sloeber.autoBuild.api.IBuildPathResolver; +import io.sloeber.autoBuild.api.IEnvVarBuildPath; +import io.sloeber.autoBuild.api.IManagedConfigElement; +import io.sloeber.autoBuild.api.ITool; + +public class EnvVarBuildPath implements IEnvVarBuildPath { + + private int fType; + private String fVariableNames[]; + private String fPathDelimiter; + private IBuildPathResolver fBuildPathResolver; + private IConfigurationElement fBuildPathResolverElement; + + /** + * Constructor to create an EnvVarBuildPath based on an element from the plugin + * manifest. + * + * @param element + * The element containing the information about the tool. + */ + public EnvVarBuildPath(ITool tool, IManagedConfigElement element) { + loadFromManifest(element); + } + + /* (non-Javadoc) + * Load the EnvVarBuildPath information from the XML element specified in the + * argument + * @param element An XML element containing the tool information + */ + protected void loadFromManifest(IManagedConfigElement element) { + + setType(convertPathTypeToInt(element.getAttribute(TYPE))); + + setVariableNames(SafeStringInterner.safeIntern(element.getAttribute(LIST))); + + setPathDelimiter(SafeStringInterner.safeIntern(element.getAttribute(PATH_DELIMITER))); + + // Store the configuration element IFF there is a build path resolver defined + String buildPathResolver = element.getAttribute(BUILD_PATH_RESOLVER); + if (buildPathResolver != null && element instanceof DefaultManagedConfigElement) { + fBuildPathResolverElement = ((DefaultManagedConfigElement) element).getConfigurationElement(); + } + } + + @Override + public int getType() { + return fType; + } + + public void setType(int type) { + this.fType = type; + } + + @Override + public String[] getVariableNames() { + return fVariableNames; + } + + public void setVariableNames(String names[]) { + fVariableNames = names; + fVariableNames = SafeStringInterner.safeIntern(fVariableNames); + } + + public void setVariableNames(String names) { + setVariableNames(getNamesFromString(names)); + } + + public String[] getNamesFromString(String names) { + if (names == null) + return null; + return names.split(NAME_SEPARATOR); + } + + @Override + public String getPathDelimiter() { + return fPathDelimiter; + } + + public void setPathDelimiter(String delimiter) { + // if (delimiter == null) + // delimiter = ManagedBuildManager.getEnvironmentVariableProvider().getDefaultDelimiter(); + fPathDelimiter = SafeStringInterner.safeIntern(delimiter); + } + + private int convertPathTypeToInt(String pathType) { + if (pathType != null && TYPE_LIBRARY.equals(pathType)) + return BUILDPATH_LIBRARY; + return BUILDPATH_INCLUDE; + } + + @Override + public IBuildPathResolver getBuildPathResolver() { + if (fBuildPathResolver == null && fBuildPathResolverElement != null) { + try { + if (fBuildPathResolverElement.getAttribute(BUILD_PATH_RESOLVER) != null) { + fBuildPathResolver = (IBuildPathResolver) fBuildPathResolverElement + .createExecutableExtension(BUILD_PATH_RESOLVER); + } + } catch (CoreException e) { + } + } + return fBuildPathResolver; + } + +} diff --git a/io.sloeber.ManagedBuild/src/io/sloeber/autoBuild/Internal/EnvironmentVariableProvider.java b/io.sloeber.ManagedBuild/src/io/sloeber/autoBuild/Internal/EnvironmentVariableProvider.java new file mode 100644 index 000000000..6e67fb4d1 --- /dev/null +++ b/io.sloeber.ManagedBuild/src/io/sloeber/autoBuild/Internal/EnvironmentVariableProvider.java @@ -0,0 +1,392 @@ +/******************************************************************************* + * Copyright (c) 2005, 2016 Intel Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Intel Corporation - Initial API and implementation + *******************************************************************************/ +package io.sloeber.autoBuild.Internal; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +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.internal.core.envvar.EnvVarCollector; +//import org.eclipse.cdt.managedbuilder.core.IBuildPathResolver; +//import org.eclipse.cdt.managedbuilder.core.IConfiguration; +//import org.eclipse.cdt.managedbuilder.core.IEnvVarBuildPath; +//import org.eclipse.cdt.managedbuilder.core.ITool; +//import org.eclipse.cdt.managedbuilder.core.ManagedBuildManager; +//import org.eclipse.cdt.managedbuilder.envvar.IBuildEnvironmentVariable; +//import org.eclipse.cdt.managedbuilder.envvar.IEnvironmentBuildPathsChangeListener; +//import org.eclipse.cdt.managedbuilder.envvar.IEnvironmentVariableProvider; +//import org.eclipse.cdt.managedbuilder.envvar.IEnvironmentVariableSupplier; +import org.eclipse.cdt.utils.envvar.EnvVarOperationProcessor; + +import io.sloeber.autoBuild.api.IBuildEnvironmentVariable; +import io.sloeber.autoBuild.api.IBuildPathResolver; +import io.sloeber.autoBuild.api.IConfiguration; +import io.sloeber.autoBuild.api.IEnvVarBuildPath; +import io.sloeber.autoBuild.api.IEnvironmentVariableProvider; +import io.sloeber.autoBuild.api.IEnvironmentVariableSupplier; +import io.sloeber.autoBuild.api.ITool; + +/** + * This class implements the IEnvironmentVariableProvider interface and provides + * all + * build environment functionality to the MBS + * + * @since 3.0 + */ +public class EnvironmentVariableProvider implements IEnvironmentVariableProvider { + // private static final QualifiedName fBuildPathVarProperty = new QualifiedName(ManagedBuilderCorePlugin.getUniqueIdentifier(), "buildPathVar"); //$NON-NLS-1$ + + // private static final String DELIMITER_WIN32 = ";"; //$NON-NLS-1$ + // private static final String DELIMITER_UNIX = ":"; //$NON-NLS-1$ + + private static EnvironmentVariableProvider fInstance = null; + private List fListeners = null; + private IEnvironmentVariableManager fMngr; + private boolean fBuildPathVarCheckAllowed; + + // private StoredBuildPathEnvironmentContainer fIncludeStoredBuildPathVariables; + // private StoredBuildPathEnvironmentContainer fLibraryStoredBuildPathVariables; + + /** + * This class is used by the EnvironmentVariableProvider to calculate the build + * paths + * in case a tool-integrator did not provide the special logic for obtaining the + * build + * paths from environment variable values + * + * @since 3.0 + */ + static public class DefaultBuildPathResolver implements IBuildPathResolver { + private String fDelimiter; + + public DefaultBuildPathResolver(String delimiter) { + fDelimiter = delimiter; + } + + @Override + public String[] resolveBuildPaths(int pathType, String variableName, String variableValue, + IConfiguration configuration) { + if (fDelimiter == null || fDelimiter.isEmpty()) + return new String[] { variableValue }; + + List list = EnvVarOperationProcessor.convertToList(variableValue, fDelimiter); + return list.toArray(new String[list.size()]); + } + + } + + protected EnvironmentVariableProvider(IEnvironmentVariableManager mngr) { + fMngr = mngr; + } + + public static EnvironmentVariableProvider getDefault() { + if (fInstance == null) { + fInstance = new EnvironmentVariableProvider(CCorePlugin.getDefault().getBuildEnvironmentManager()); + fInstance.fBuildPathVarCheckAllowed = true; + } + return fInstance; + } + + // @Override + // public IBuildEnvironmentVariable getVariable(String variableName, Object level, boolean includeParentLevels, + // boolean resolveMacros) { + // // if (variableName == null || variableName.isEmpty()) + // // return null; + // // + // // if (level instanceof IConfiguration) { + // // return wrap(getVariable(variableName, (IConfiguration) level, resolveMacros)); + // // } + // return null; + // } + + @Override + public IEnvironmentVariable getVariable(String variableName, IConfiguration cfg, boolean resolveMacros) { + return getVariable(variableName, cfg, resolveMacros, true); + } + + public IEnvironmentVariable getVariable(String variableName, IConfiguration cfg, boolean resolveMacros, + boolean checkBuildPaths) { + ICConfigurationDescription des = ManagedBuildManager.getDescriptionForConfiguration(cfg); + if (des != null) { + IEnvironmentVariable variable = fMngr.getVariable(variableName, des, resolveMacros); + if (checkBuildPaths && resolveMacros && fBuildPathVarCheckAllowed) + checkBuildPathVariable(cfg, variableName, variable); + return variable; + } + return null; + } + + @Override + public IEnvironmentVariable[] getVariables(IConfiguration cfg, boolean resolveMacros) { + return getVariables(cfg, resolveMacros, true); + } + + public IEnvironmentVariable[] getVariables(IConfiguration cfg, boolean resolveMacros, boolean checkBuildPaths) { + ICConfigurationDescription des = ManagedBuildManager.getDescriptionForConfiguration(cfg); + if (des != null) { + IEnvironmentVariable vars[] = fMngr.getVariables(des, resolveMacros); + if (checkBuildPaths && resolveMacros && fBuildPathVarCheckAllowed) + checkBuildPathVariables(cfg, vars); + return vars; + } + return new IBuildEnvironmentVariable[0]; + } + + // public static IBuildEnvironmentVariable wrap(IEnvironmentVariable var) { + // if (var == null) + // return null; + // if (var instanceof IBuildEnvironmentVariable) + // return (IBuildEnvironmentVariable) var; + // return new BuildEnvVar(var); + // } + + public static IBuildEnvironmentVariable[] wrap(IEnvironmentVariable vars[]) { + if (vars == null) + return null; + if (vars instanceof IBuildEnvironmentVariable[]) + return (IBuildEnvironmentVariable[]) vars; + + IBuildEnvironmentVariable[] buildVars = new IBuildEnvironmentVariable[vars.length]; + // for (int i = 0; i < vars.length; i++) { + // buildVars[i] = wrap(vars[i]); + // } + return buildVars; + } + + /* protected ICConfigurationDescription getDescription(IConfiguration cfg) { + IProject project = cfg.getOwner().getProject(); + ICProjectDescription des = CoreModel.getDefault().getProjectDescription(project, false); + if (des != null) { + return des.getConfigurationById(cfg.getId()); + } + return null; + } + */ + // @Override + // public IBuildEnvironmentVariable[] getVariables(Object level, boolean includeParentLevels, boolean resolveMacros) { + // if (level instanceof IConfiguration) { + // return wrap(getVariables((IConfiguration) level, resolveMacros)); + // } + // return new IBuildEnvironmentVariable[0]; + // } + + @Override + public String getDefaultDelimiter() { + return fMngr.getDefaultDelimiter(); + } + + @Override + public IEnvironmentVariableSupplier[] getSuppliers(Object level) { + return null; + } + + @Override + public String[] getBuildPaths(IConfiguration configuration, int buildPathType) { + ITool tools[] = configuration.getFilteredTools(); + List list = new ArrayList<>(); + + for (ITool tool : tools) { + IEnvVarBuildPath pathDescriptors[] = tool.getEnvVarBuildPaths(); + + if (pathDescriptors == null || pathDescriptors.length == 0) + continue; + + for (IEnvVarBuildPath curPathDes : pathDescriptors) { + if (curPathDes.getType() != buildPathType) + continue; + + String vars[] = curPathDes.getVariableNames(); + if (vars == null || vars.length == 0) + continue; + + IBuildPathResolver pathResolver = curPathDes.getBuildPathResolver(); + if (pathResolver == null) { + String delimiter = curPathDes.getPathDelimiter(); + if (delimiter == null) + delimiter = getDefaultDelimiter(); + pathResolver = new DefaultBuildPathResolver(delimiter); + } + + for (String varName : vars) { + IEnvironmentVariable var = getVariable(varName, configuration, true, false); + if (var == null) + continue; + + String varValue = var.getValue(); + String paths[] = pathResolver.resolveBuildPaths(buildPathType, varName, varValue, configuration); + if (paths != null && paths.length != 0) + list.addAll(Arrays.asList(paths)); + } + } + } + + return list.toArray(new String[list.size()]); + } + + /** + * @return a list of registered listeners + */ + private List getListeners() { + if (fListeners == null) + fListeners = new ArrayList<>(); + return fListeners; + } + + /** + * notifies registered listeners + */ + private void notifyListeners(IConfiguration configuration, int buildPathType) { + List listeners = getListeners(); + for (IEnvironmentBuildPathsChangeListener listener : listeners) { + listener.buildPathsChanged(configuration, buildPathType); + } + } + + @Override + public synchronized void subscribe(IEnvironmentBuildPathsChangeListener listener) { + if (listener == null) + return; + + List listeners = getListeners(); + + if (!listeners.contains(listener)) + listeners.add(listener); + } + + @Override + public synchronized void unsubscribe(IEnvironmentBuildPathsChangeListener listener) { + if (listener == null) + return; + + List listeners = getListeners(); + + listeners.remove(listener); + } + + /** + * performs a check of the build path variables for the given configuration + * If the build variables are changed, the notification is sent + */ + public void checkBuildPathVariables(IConfiguration configuration) { + checkBuildPathVariables(configuration, getVariables(configuration, true, false)); + } + + /** + * performs a check of the build path variables of the specified type + * for the given configuration + * If the build variables are changed, the notification is sent + */ + public void checkBuildPathVariables(IConfiguration configuration, int buildPathType) { + EnvVarCollector cr = new EnvVarCollector(); + cr.add(getVariables(configuration, true, false)); + checkBuildPathVariables(configuration, buildPathType, cr); + } + + /** + * performs a check of the build path variables + * for the given configuration given the set of the variables + * defined for this configuration + * If the build variables are changed, the notification is sent + */ + protected void checkBuildPathVariables(IConfiguration configuration, IEnvironmentVariable vars[]) { + EnvVarCollector cr = new EnvVarCollector(); + cr.add(vars); + checkBuildPathVariables(configuration, IEnvVarBuildPath.BUILDPATH_INCLUDE, cr); + checkBuildPathVariables(configuration, IEnvVarBuildPath.BUILDPATH_LIBRARY, cr); + } + + /** + * performs a check of whether the given variable is the build path variable + * and if true checks whether it is changed. + * In the case of it is changed all other build path variables are checked + * and notification is sent. + * If it is not changed, other build path variables are not checked + * In the case of the given variable is not the build path one, this method does + * nothing + */ + protected void checkBuildPathVariable(IConfiguration configuration, String varName, IEnvironmentVariable var) { + checkBuildPathVariable(configuration, IEnvVarBuildPath.BUILDPATH_INCLUDE, varName, var); + checkBuildPathVariable(configuration, IEnvVarBuildPath.BUILDPATH_LIBRARY, varName, var); + } + + /** + * performs a check of whether the given variable is the build path variable + * of the specified type and if true checks whether it is changed. + * In the case of it is changed all other build path variables of that type are + * checked + * and notification is sent. + * If it is not changed, other build path variables are not checked + * In the case of the given variable is not the build path one, this method does + * nothing + */ + protected void checkBuildPathVariable(IConfiguration configuration, int buildPathType, String varName, + IEnvironmentVariable var) { + // StoredBuildPathEnvironmentContainer buildPathVars = getStoredBuildPathVariables(buildPathType); + // if (buildPathVars == null) + // return; + // if (buildPathVars.isVariableChanged(varName, var, configuration)) { + // EnvVarCollector cr = new EnvVarCollector(); + // cr.add(getVariables(configuration, true, false)); + // buildPathVars.synchronize(cr, configuration); + // notifyListeners(configuration, buildPathType); + // } + } + + /** + * performs a check of the build path variables of the specified type + * for the given configuration given the set of the variables + * defined for this configuration. + * If the build variables are changed, the notification is sent + */ + protected void checkBuildPathVariables(IConfiguration configuration, int buildPathType, EnvVarCollector varSet) { + // StoredBuildPathEnvironmentContainer buildPathVars = getStoredBuildPathVariables(buildPathType); + // if (buildPathVars == null) + // return; + // if (buildPathVars.checkBuildPathChange(varSet, configuration)) { + // notifyListeners(configuration, buildPathType); + // } + } + + /** + * returns the container of the build variables of the specified type + */ + // protected StoredBuildPathEnvironmentContainer getStoredBuildPathVariables(int buildPathType) { + // return buildPathType == IEnvVarBuildPath.BUILDPATH_LIBRARY ? getStoredLibraryBuildPathVariables() + // : getStoredIncludeBuildPathVariables(); + // } + + /** + * returns the container of the Include path variables + */ + // protected StoredBuildPathEnvironmentContainer getStoredIncludeBuildPathVariables() { + // if (fIncludeStoredBuildPathVariables == null) + // fIncludeStoredBuildPathVariables = new StoredBuildPathEnvironmentContainer( + // IEnvVarBuildPath.BUILDPATH_INCLUDE); + // return fIncludeStoredBuildPathVariables; + // } + + /** + * returns the container of the Library path variables + */ + // protected StoredBuildPathEnvironmentContainer getStoredLibraryBuildPathVariables() { + // if (fLibraryStoredBuildPathVariables == null) + // fLibraryStoredBuildPathVariables = new StoredBuildPathEnvironmentContainer( + // IEnvVarBuildPath.BUILDPATH_LIBRARY); + // return fLibraryStoredBuildPathVariables; + // } +} diff --git a/io.sloeber.ManagedBuild/src/io/sloeber/autoBuild/Internal/ExplicitFileMacroCollector.java b/io.sloeber.ManagedBuild/src/io/sloeber/autoBuild/Internal/ExplicitFileMacroCollector.java new file mode 100644 index 000000000..40d1f2078 --- /dev/null +++ b/io.sloeber.ManagedBuild/src/io/sloeber/autoBuild/Internal/ExplicitFileMacroCollector.java @@ -0,0 +1,76 @@ +/******************************************************************************* + * Copyright (c) 2005, 2010 Intel Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Intel Corporation - Initial API and implementation + *******************************************************************************/ +package io.sloeber.autoBuild.Internal; + +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.cdt.core.cdtvariables.CdtVariableException; +import org.eclipse.cdt.core.cdtvariables.ICdtVariable; +import org.eclipse.cdt.utils.cdtvariables.SupplierBasedCdtVariableSubstitutor; + +import io.sloeber.autoBuild.api.IBuildMacro; + +/** + * This class is used by the MacroResolver to collect and present + * the explicit file macros referenced in the given expression + * + * @since 3.0 + */ +public class ExplicitFileMacroCollector extends SupplierBasedCdtVariableSubstitutor { + private static final String EMPTY_STRING = ""; //$NON-NLS-1$ + + private List fMacrosList = new ArrayList<>(); + + /* public ExplicitFileMacroCollector(int contextType, Object contextData){ + super(contextType, contextData, EMPTY_STRING, EMPTY_STRING); + } + */ + public ExplicitFileMacroCollector(IMacroContextInfo contextInfo) { + super(contextInfo, EMPTY_STRING, EMPTY_STRING); + } + + /* + public ExplicitFileMacroCollector(ITool tool){ + super(null, EMPTY_STRING, EMPTY_STRING); + IBuildObject bo = tool.getParent(); + IConfiguration cfg = null; + if(bo instanceof IResourceConfiguration) + cfg = ((IResourceConfiguration)bo).getParent(); + else if (bo instanceof IToolChain) + cfg = ((IToolChain)bo).getParent(); + try{ + setMacroContextInfo(IBuildMacroProvider.CONTEXT_CONFIGURATION,cfg); + }catch (BuildMacroException e){ + } + } + */ + /* (non-Javadoc) + */ + @Override + protected ResolvedMacro resolveMacro(ICdtVariable macro) throws CdtVariableException { + // if (macro instanceof MbsMacroSupplier.FileContextMacro) { + // MbsMacroSupplier.FileContextMacro fileMacro = (MbsMacroSupplier.FileContextMacro) macro; + // if (fileMacro.isExplicit()) + // fMacrosList.add(macro); + // return null; + // } + return super.resolveMacro(macro); + } + + public IBuildMacro[] getExplicisFileMacros() { + return fMacrosList.toArray(new IBuildMacro[fMacrosList.size()]); + } + +} diff --git a/io.sloeber.ManagedBuild/src/io/sloeber/autoBuild/Internal/FileContextData.java b/io.sloeber.ManagedBuild/src/io/sloeber/autoBuild/Internal/FileContextData.java new file mode 100644 index 000000000..3ed75d9ec --- /dev/null +++ b/io.sloeber.ManagedBuild/src/io/sloeber/autoBuild/Internal/FileContextData.java @@ -0,0 +1,71 @@ +/******************************************************************************* + * Copyright (c) 2005, 2011 Intel Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Intel Corporation - Initial API and implementation + *******************************************************************************/ +package io.sloeber.autoBuild.Internal; + +//import org.eclipse.cdt.managedbuilder.core.IBuildObject; +//import org.eclipse.cdt.managedbuilder.core.IOption; +//import org.eclipse.cdt.managedbuilder.macros.IFileContextData; +//import org.eclipse.cdt.managedbuilder.macros.IOptionContextData; +import org.eclipse.core.runtime.IPath; + +import io.sloeber.autoBuild.api.IBuildObject; +import io.sloeber.autoBuild.api.IOption; + +/** + * This is a trivial implementation of the IFileContextData used internaly by + * the MBS + * + * @since 3.0 + */ +public class FileContextData implements IFileContextData { + private IPath fInputFileLocation; + private IPath fOutputFileLocation; + private IOptionContextData fOptionContextData; + + public FileContextData(IPath inputFileLocation, IPath outputFileLocation, IOption option, + IBuildObject optionParent) { + this(inputFileLocation, outputFileLocation, new OptionContextData(option, optionParent)); + } + + public FileContextData(IPath inputFileLocation, IPath outputFileLocation, IOptionContextData optionContextData) { + fInputFileLocation = inputFileLocation; + fOutputFileLocation = outputFileLocation; + fOptionContextData = optionContextData; + } + + /* (non-Javadoc) + * @see org.eclipse.cdt.managedbuilder.macros.IFileContextData#getInputFileLocation() + */ + @Override + public IPath getInputFileLocation() { + return fInputFileLocation; + } + + /* (non-Javadoc) + * @see org.eclipse.cdt.managedbuilder.macros.IFileContextData#getOutputFileLocation() + */ + @Override + public IPath getOutputFileLocation() { + return fOutputFileLocation; + } + + /* (non-Javadoc) + * @see org.eclipse.cdt.managedbuilder.macros.IFileContextData#getOption() + */ + @Override + public IOptionContextData getOptionContextData() { + return fOptionContextData; + } + +} diff --git a/io.sloeber.ManagedBuild/src/io/sloeber/autoBuild/Internal/FolderInfo.java b/io.sloeber.ManagedBuild/src/io/sloeber/autoBuild/Internal/FolderInfo.java new file mode 100644 index 000000000..b847807c9 --- /dev/null +++ b/io.sloeber.ManagedBuild/src/io/sloeber/autoBuild/Internal/FolderInfo.java @@ -0,0 +1,1475 @@ +/******************************************************************************* + * Copyright (c) 2007, 2016 Intel Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Intel Corporation - Initial API and implementation + * cartu38 opendev (STMicroelectronics) - [514385] Custom defaultValue-generator support + *******************************************************************************/ +package io.sloeber.autoBuild.Internal; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.Vector; + +import org.eclipse.cdt.core.CCProjectNature; +import org.eclipse.cdt.core.CProjectNature; +import org.eclipse.cdt.core.settings.model.ICSettingBase; +import org.eclipse.cdt.core.settings.model.ICStorageElement; +import org.eclipse.cdt.core.settings.model.extension.CFolderData; +import org.eclipse.cdt.core.settings.model.extension.CLanguageData; +import org.eclipse.cdt.core.settings.model.util.CDataUtil; +//import org.eclipse.cdt.managedb +//import org.eclipse.cdt.managedbuilder.buildproperties.IBuildPropertyType; +//import org.eclipse.cdt.managedbuilder.core.BuildException; +//import org.eclipse.cdt.managedbuilder.core.IBuildObject; +//import org.eclipse.cdt.managedbuilder.core.IBuildObjectProperties; +//import org.eclipse.cdt.managedbuilder.core.IBuildPropertiesRestriction; +//import org.eclipse.cdt.managedbuilder.core.IConfiguration; +//import org.eclipse.cdt.managedbuilder.core.IFolderInfo; +//import org.eclipse.cdt.managedbuilder.core.IHoldsOptions; +//import org.eclipse.cdt.managedbuilder.core.IInputType; +//import org.eclipse.cdt.managedbuilder.core.IManagedConfigElement; +//import org.eclipse.cdt.managedbuilder.core.IManagedProject; +//import org.eclipse.cdt.managedbuilder.core.IModificationStatus; +//import org.eclipse.cdt.managedbuilder.core.IOption; +//import org.eclipse.cdt.managedbuilder.core.IOutputType; +//import org.eclipse.cdt.managedbuilder.core.IResourceInfo; +//import org.eclipse.cdt.managedbuilder.core.ITargetPlatform; +//import org.eclipse.cdt.managedbuilder.core.ITool; +//import org.eclipse.cdt.managedbuilder.core.IToolChain; +//import org.eclipse.cdt.managedbuilder.core.ManagedBuildManager; +//import org.eclipse.cdt.managedbuilder.core.ManagedBuilderCorePlugin; +//import org.eclipse.cdt.managedbuilder.internal.buildproperties.BuildPropertyManager; +//import org.eclipse.cdt.managedbuilder.internal.dataprovider.BuildFolderData; +//import org.eclipse.cdt.managedbuilder.internal.dataprovider.BuildLanguageData; +//import org.eclipse.cdt.managedbuilder.internal.dataprovider.ConfigurationDataProvider; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IConfigurationElement; +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.Path; + +import io.sloeber.autoBuild.api.BuildException; +import io.sloeber.autoBuild.api.IBuildObjectProperties; +import io.sloeber.autoBuild.api.IBuildPropertiesRestriction; +import io.sloeber.autoBuild.api.IBuildProperty; +import io.sloeber.autoBuild.api.IBuildPropertyType; +import io.sloeber.autoBuild.api.IConfiguration; +import io.sloeber.autoBuild.api.IFolderInfo; +import io.sloeber.autoBuild.api.IHoldsOptions; +import io.sloeber.autoBuild.api.IInputType; +import io.sloeber.autoBuild.api.IManagedConfigElement; +import io.sloeber.autoBuild.api.IManagedProject; +import io.sloeber.autoBuild.api.IModificationStatus; +import io.sloeber.autoBuild.api.IOption; +import io.sloeber.autoBuild.api.IOutputType; +import io.sloeber.autoBuild.api.ITargetPlatform; +import io.sloeber.autoBuild.api.ITool; +import io.sloeber.autoBuild.api.IToolChain; +import io.sloeber.autoBuild.core.Activator; +import io.sloeber.buildProperties.BuildPropertyManager; + +public class FolderInfo extends ResourceInfo implements IFolderInfo { + private ToolChain toolChain; + private boolean isExtensionElement; + private boolean containsDiscoveredScannerInfo = true; + + public FolderInfo(FolderInfo folderInfo, String id, String resourceName, IPath path) { + super(folderInfo, path, id, resourceName); + + isExtensionElement = folderInfo.isExtensionElement(); + // if (!isExtensionElement) + // setResourceData(new BuildFolderData(this)); + + if (folderInfo.getParent() != null) + setManagedBuildRevision(folderInfo.getParent().getManagedBuildRevision()); + + IToolChain parTc = folderInfo.getToolChain(); + IToolChain extTc = ManagedBuildManager.getExtensionToolChain(parTc); + if (extTc == null) + extTc = parTc; + + String tcId = ManagedBuildManager.calculateChildId(extTc.getId(), null); + createToolChain(extTc, tcId, parTc.getName(), false); + + toolChain.createOptions(parTc); + toolChain.setUnusedChildren(parTc.getUnusedChildren()); + + ITool tools[] = parTc.getTools(); + String subId = ""; //$NON-NLS-1$ + for (ITool tool : tools) { + ITool extTool = ManagedBuildManager.getExtensionTool(tool); + if (extTool == null) + extTool = tool; + + subId = ManagedBuildManager.calculateChildId(extTool.getId(), null); + toolChain.createTool(tool, subId, tool.getName(), false); + } + setDirty(true); + setRebuildState(true); + } + + public FolderInfo(IConfiguration parent, IManagedConfigElement element, String managedBuildRevision, + boolean hasBody) { + super(parent, element, hasBody); + + isExtensionElement = true; + IManagedConfigElement tcEl = null; + if (!hasBody) { + setPath(Path.ROOT); + setId(ManagedBuildManager.calculateChildId(parent.getId(), null)); + setName("/"); //$NON-NLS-1$ + tcEl = element; + } else { + IManagedConfigElement children[] = element.getChildren(IToolChain.TOOL_CHAIN_ELEMENT_NAME); + if (children.length > 0) + tcEl = children[0]; + } + + if (tcEl != null) + toolChain = new ToolChain(this, tcEl, managedBuildRevision); + + } + + public FolderInfo(IConfiguration parent, ICStorageElement element, String managedBuildRevision, boolean hasBody) { + super(parent, element, hasBody); + + isExtensionElement = false; + // setResourceData(new BuildFolderData(this)); + ICStorageElement tcEl = null; + if (!hasBody) { + setPath(Path.ROOT); + setId(ManagedBuildManager.calculateChildId(parent.getId(), null)); + setName("/"); //$NON-NLS-1$ + tcEl = element; + } else { + ICStorageElement nodes[] = element.getChildren(); + for (ICStorageElement node : nodes) { + if (IToolChain.TOOL_CHAIN_ELEMENT_NAME.equals(node.getName())) + tcEl = node; + } + } + + if (tcEl != null) + toolChain = new ToolChain(this, tcEl, managedBuildRevision); + } + + /*TODO + public FolderInfo(FolderInfo base, IPath path, String id, String name) { + super(base, path, id, name); + } + */ + public FolderInfo(IConfiguration parent, IPath path, String id, String name, boolean isExtensionElement) { + super(parent, path, id, name); + + this.isExtensionElement = isExtensionElement; + // if (!isExtensionElement) + // setResourceData(new BuildFolderData(this)); + + } + + public FolderInfo(IConfiguration cfg, FolderInfo cloneInfo, String id, Map> superIdMap, + boolean cloneChildren) { + super(cfg, cloneInfo, id); + + isExtensionElement = cfg.isExtensionElement(); + // if (!isExtensionElement) + // setResourceData(new BuildFolderData(this)); + + String subName; + if (!cloneInfo.isExtensionElement) + cloneChildren = true; + + boolean copyIds = cloneChildren && id.equals(cloneInfo.id); + + IToolChain cloneToolChain = cloneInfo.getToolChain(); + IToolChain extToolChain = ManagedBuildManager.getExtensionToolChain(cloneToolChain); + if (extToolChain == null) + extToolChain = cloneToolChain; + + subName = cloneToolChain.getName(); + + if (cloneChildren) { + String subId = copyIds ? cloneToolChain.getId() + : ManagedBuildManager.calculateChildId(extToolChain.getId(), null); + toolChain = new ToolChain(this, subId, subName, superIdMap, (ToolChain) cloneToolChain); + + } else { + // Add a tool-chain element that specifies as its superClass the + // tool-chain that is the child of the configuration. + String subId = ManagedBuildManager.calculateChildId(extToolChain.getId(), null); + IToolChain newChain = createToolChain(extToolChain, subId, extToolChain.getName(), false); + + // For each option/option category child of the tool-chain that is + // the child of the selected configuration element, create an option/ + // option category child of the cloned configuration's tool-chain element + // that specifies the original tool element as its superClass. + newChain.createOptions(extToolChain); + + // For each tool element child of the tool-chain that is the child of + // the selected configuration element, create a tool element child of + // the cloned configuration's tool-chain element that specifies the + // original tool element as its superClass. + ITool[] tools = extToolChain.getTools(); + for (ITool tool : tools) { + Tool toolChild = (Tool) tool; + subId = ManagedBuildManager.calculateChildId(toolChild.getId(), null); + newChain.createTool(toolChild, subId, toolChild.getName(), false); + } + + ITargetPlatform tpBase = cloneInfo.getToolChain().getTargetPlatform(); + ITargetPlatform extTp = tpBase; + for (; extTp != null && !extTp.isExtensionElement(); extTp = extTp.getSuperClass()) { + // empty body, loop is to find extension element only + } + + TargetPlatform tp; + if (extTp != null) { + int nnn = ManagedBuildManager.getRandomNumber(); + subId = copyIds ? tpBase.getId() : extTp.getId() + "." + nnn; //$NON-NLS-1$ + tp = new TargetPlatform(newChain, subId, tpBase.getName(), (TargetPlatform) tpBase); + } else { + subId = copyIds ? tpBase.getId() : ManagedBuildManager.calculateChildId(getId(), null); + subName = tpBase != null ? tpBase.getName() : ""; //$NON-NLS-1$ + tp = new TargetPlatform((ToolChain) newChain, null, subId, subName, false); + } + + ((ToolChain) newChain).setTargetPlatform(tp); + } + + if (isRoot()) + containsDiscoveredScannerInfo = cloneInfo.containsDiscoveredScannerInfo; + + if (copyIds) { + isDirty = cloneInfo.isDirty; + needsRebuild = cloneInfo.needsRebuild; + } else { + setDirty(true); + setRebuildState(true); + } + + } + + private boolean conflictsWithRootTools(ITool tool) { + IFolderInfo rf = getParent().getRootFolderInfo(); + ITool[] rootTools = rf.getFilteredTools(); + ITool tt = getParent().getTargetTool(); + for (ITool rootTool : rootTools) { + if (rootTool == tt || getMultipleOfType(rootTool) != null) { + if (getConflictingInputExts(rootTool, tool).length != 0) + return true; + } + } + return false; + } + + private IInputType getMultipleOfType(ITool tool) { + IInputType[] types = tool.getInputTypes(); + IInputType mType = null; + boolean foundNonMultiplePrimary = false; + for (IInputType type : types) { + if (type.getMultipleOfType()) { + if (type.getPrimaryInput() == true) { + foundNonMultiplePrimary = false; + mType = type; + break; + } else if (mType == null) { + mType = type; + } + } else { + if (type.getPrimaryInput() == true) { + foundNonMultiplePrimary = true; + } + } + } + + return foundNonMultiplePrimary ? null : mType; + } + + public ITool[] filterTools(ITool localTools[], IManagedProject manProj) { + if (manProj == null) { + // If this is not associated with a project, then there is nothing to filter with + return localTools; + } + IProject project = (IProject) manProj.getOwner(); + Vector tools = new Vector<>(localTools.length); + for (ITool t : localTools) { + Tool tool = (Tool) t; + if (!tool.isEnabled(this)) + continue; + + if (!isRoot() && conflictsWithRootTools(tool)) + continue; + + try { + // Make sure the tool is right for the project + switch (tool.getNatureFilter()) { + case ITool.FILTER_C: + if (project.hasNature(CProjectNature.C_NATURE_ID) + && !project.hasNature(CCProjectNature.CC_NATURE_ID)) { + tools.add(tool); + } + break; + case ITool.FILTER_CC: + if (project.hasNature(CCProjectNature.CC_NATURE_ID)) { + tools.add(tool); + } + break; + case ITool.FILTER_BOTH: + tools.add(tool); + break; + default: + break; + } + } catch (CoreException e) { + continue; + } + } + + // Answer the filtered tools as an array + return tools.toArray(new Tool[tools.size()]); + } + + @Override + public ITool[] getFilteredTools() { + if (toolChain == null) { + return new ITool[0]; + } + ITool[] localTools = toolChain.getTools(); + IManagedProject manProj = getParent().getManagedProject(); + return filterTools(localTools, manProj); + } + + @Override + public final int getKind() { + return ICSettingBase.SETTING_FOLDER; + } + + @Override + public boolean isDirty() { + if (super.isDirty()) + return true; + + if (toolChain.isDirty()) + return true; + + return false; + } + + @Override + public boolean needsRebuild() { + if (super.needsRebuild() || toolChain.needsRebuild()) + return true; + else + return false; + } + + @Override + public void setRebuildState(boolean rebuild) { + super.setRebuildState(rebuild); + + if (!rebuild) + toolChain.setRebuildState(false); + } + + @Override + public IToolChain getToolChain() { + return toolChain; + } + + @Override + public ITool[] getTools() { + return toolChain.getTools(); + } + + @Override + public ITool getTool(String id) { + return toolChain.getTool(id); + } + + @Override + public ITool[] getToolsBySuperClassId(String id) { + return toolChain.getToolsBySuperClassId(id); + } + + ToolChain createToolChain(IToolChain superClass, String Id, String name, boolean isExtensionElement) { + toolChain = new ToolChain(this, superClass, Id, name, isExtensionElement); + setDirty(true); + return toolChain; + } + + @Override + void serialize(ICStorageElement element) { + super.serialize(element); + + ICStorageElement toolChainElement = element.createChild(IToolChain.TOOL_CHAIN_ELEMENT_NAME); + toolChain.serialize(toolChainElement); + } + + @Override + void resolveReferences() { + if (toolChain != null) + toolChain.resolveReferences(); + } + + @Override + public void updateManagedBuildRevision(String revision) { + super.updateManagedBuildRevision(revision); + + if (toolChain != null) + toolChain.updateManagedBuildRevision(revision); + } + + @Override + public boolean isExtensionElement() { + return isExtensionElement; + } + + public String getErrorParserIds() { + if (toolChain != null) + return toolChain.getErrorParserIds(getParent()); + return null; + } + + @Override + public CFolderData getFolderData() { + return (CFolderData) getResourceData(); + } + + @Override + public CLanguageData[] getCLanguageDatas() { + List list = new ArrayList<>(); + for (ITool t : getFilteredTools()) + for (CLanguageData d : t.getCLanguageDatas()) + list.add(d); + return list.toArray(new BuildLanguageData[list.size()]); + } + + @Override + public ITool getToolFromOutputExtension(String extension) { + // Treat a null argument as an empty string + String ext = extension == null ? "" : extension; //$NON-NLS-1$ + // Get all the tools for the current config + ITool[] tools = getFilteredTools(); + for (ITool tool : tools) { + if (tool.producesFileType(ext)) { + return tool; + } + } + return null; + } + + @Override + public ITool getToolFromInputExtension(String sourceExtension) { + // Get all the tools for the current config + ITool[] tools = getFilteredTools(); + for (ITool tool : tools) { + if (tool.buildsFileType(sourceExtension)) { + return tool; + } + } + return null; + } + + @Override + public void propertiesChanged() { + if (isExtensionElement) + return; + toolChain.propertiesChanged(); + super.propertiesChanged(); + } + + @Override + public void setDirty(boolean isDirty) { + if (isExtensionElement && isDirty) + return; + + super.setDirty(isDirty); + + // Propagate "false" to the children + if (!isDirty) { + if (toolChain != null) + toolChain.setDirty(false); + } + } + + private Map typeIdsToMap(String[] ids, IBuildObjectProperties props) { + Map map = new HashMap<>(ids.length); + for (String id : ids) { + IBuildProperty prop = props.getProperty(id); + map.put(id, prop.getValue().getId()); + } + return map; + } + + private Map propsToMap(IBuildProperty props[]) { + Map map = new HashMap<>(props.length); + for (IBuildProperty p : props) + map.put(p.getPropertyType().getId(), p.getValue().getId()); + return map; + } + + private boolean checkPropertiesModificationCompatibility(IBuildPropertiesRestriction r, + Map unspecifiedRequiredProps, Map unspecifiedProps, + Set undefinedSet) { + IBuildObjectProperties props = null; + IConfiguration cfg = getParent(); + if (cfg != null) { + props = cfg.getBuildProperties(); + } + + unspecifiedProps.clear(); + unspecifiedRequiredProps.clear(); + + if (props != null && props.getSupportedTypeIds().length != 0) { + String[] requiredIds = props.getRequiredTypeIds(); + + IBuildPropertyType[] supportedTypes = props.getSupportedTypes(); + if (supportedTypes.length != 0 || requiredIds.length != 0) { + if (requiredIds.length == 0) { + if (props.getProperty(ManagedBuildManager.BUILD_ARTEFACT_TYPE_PROPERTY_ID) != null) { + requiredIds = new String[] { ManagedBuildManager.BUILD_ARTEFACT_TYPE_PROPERTY_ID }; + } + } + + Map requiredMap = typeIdsToMap(requiredIds, props); + getUnsupportedProperties(requiredMap, r, unspecifiedRequiredProps, undefinedSet); + unspecifiedProps.putAll(unspecifiedRequiredProps); + + IBuildProperty[] ps = props.getProperties(); + Map propsMap = propsToMap(ps); + getUnsupportedProperties(propsMap, r, unspecifiedProps, undefinedSet); + } + return unspecifiedRequiredProps.size() == 0; + } + return false; + } + + private void getUnsupportedProperties(Map props, IBuildPropertiesRestriction restriction, + Map unsupported, Set inexistent) { + BuildPropertyManager mngr = BuildPropertyManager.getInstance(); + for (Map.Entry entry : props.entrySet()) { + String propId = entry.getKey(); + String valueId = entry.getValue(); + IBuildPropertyType type = mngr.getPropertyType(propId); + if (type == null) { + if (inexistent != null) { + inexistent.add(propId); + } + } + + if (!restriction.supportsType(propId)) { + unsupported.put(propId, null); + } else if (!restriction.supportsValue(propId, valueId)) { + unsupported.put(propId, valueId); + } + } + } + + public void checkPropertiesModificationCompatibility(final ITool tools[], + Map unspecifiedRequiredProps, Map unspecifiedProps, + Set undefinedSet) { + final ToolChain tc = (ToolChain) getToolChain(); + IBuildPropertiesRestriction r = new IBuildPropertiesRestriction() { + @Override + public boolean supportsType(String typeId) { + if (tc.supportsType(typeId, false)) + return true; + + for (ITool tool : tools) { + if (((Tool) tool).supportsType(typeId)) + return true; + } + return false; + } + + @Override + public boolean supportsValue(String typeId, String valueId) { + if (tc.supportsValue(typeId, valueId, false)) + return true; + + for (ITool tool : tools) { + if (((Tool) tool).supportsValue(typeId, valueId)) + return true; + } + return false; + } + + @Override + public String[] getRequiredTypeIds() { + List list = new ArrayList<>(); + + list.addAll(Arrays.asList(tc.getRequiredTypeIds(false))); + + for (ITool tool : tools) { + list.addAll(Arrays.asList(((Tool) tool).getRequiredTypeIds())); + } + + return list.toArray(new String[list.size()]); + } + + @Override + public String[] getSupportedTypeIds() { + List list = new ArrayList<>(); + + list.addAll(Arrays.asList(tc.getSupportedTypeIds(false))); + + for (ITool tool : tools) { + list.addAll(Arrays.asList(((Tool) tool).getSupportedTypeIds())); + } + + return list.toArray(new String[list.size()]); + } + + @Override + public String[] getSupportedValueIds(String typeId) { + List list = new ArrayList<>(); + + list.addAll(Arrays.asList(tc.getSupportedValueIds(typeId, false))); + + for (ITool tool : tools) { + list.addAll(Arrays.asList(((Tool) tool).getSupportedValueIds(typeId))); + } + + return list.toArray(new String[list.size()]); + } + + @Override + public boolean requiresType(String typeId) { + if (tc.requiresType(typeId, false)) + return true; + + for (ITool tool : tools) { + if (((Tool) tool).requiresType(typeId)) + return true; + } + return false; + } + }; + + checkPropertiesModificationCompatibility(r, unspecifiedRequiredProps, unspecifiedProps, undefinedSet); + } + + public boolean checkPropertiesModificationCompatibility(IToolChain tc, Map unspecifiedRequiredProps, + Map unspecifiedProps, Set undefinedSet) { + return checkPropertiesModificationCompatibility((IBuildPropertiesRestriction) tc, unspecifiedRequiredProps, + unspecifiedProps, undefinedSet); + } + + public boolean isPropertiesModificationCompatible(IToolChain tc) { + Map requiredMap = new HashMap<>(); + Map unsupportedMap = new HashMap<>(); + Set undefinedSet = new HashSet<>(); + if (!checkPropertiesModificationCompatibility(tc, requiredMap, unsupportedMap, undefinedSet)) + return false; + return true; + } + + private Set getRequiredUnspecifiedProperties() { + IBuildObjectProperties props = null; + Set set = new HashSet<>(); + IConfiguration cfg = getParent(); + + if (cfg != null) + props = cfg.getBuildProperties(); + + if (props != null) + for (String s : props.getRequiredTypeIds()) + if (props.getProperty(s) == null) + set.add(s); + return set; + } + + @Override + public boolean isToolChainCompatible(IToolChain tCh) { + return isToolChainCompatible(toolChain, tCh); + } + + public boolean isToolChainCompatible(ToolChain fromTc, IToolChain tCh) { + boolean compatible = false; + if (tCh == fromTc) + return true; + + // if (tCh == null) { + // tCh = ManagedBuildManager.getExtensionToolChain(ConfigurationDataProvider.PREF_TC_ID); + // } + + if (tCh == null) + return false; + + IToolChain curReal = ManagedBuildManager.getRealToolChain(fromTc); + IToolChain newReal = ManagedBuildManager.getRealToolChain(tCh); + + if (curReal == newReal) + return true; + + // if (getToolChainConverterInfo(fromTc, tCh) != null) + // compatible = true; + + if (!compatible) + compatible = isPropertiesModificationCompatible(tCh); + + return compatible; + } + + @Override + public IToolChain changeToolChain(IToolChain newSuperClass, String Id, String name) throws BuildException { + boolean usePrefTc = false; + // if (newSuperClass == null) { + // newSuperClass = ManagedBuildManager.getExtensionToolChain(ConfigurationDataProvider.PREF_TC_ID); + // usePrefTc = true; + // } + + if (newSuperClass == null) + return toolChain; + + IToolChain curReal = ManagedBuildManager.getRealToolChain(toolChain); + IToolChain newReal = ManagedBuildManager.getRealToolChain(newSuperClass); + + if (Id == null) { + Id = ManagedBuildManager.calculateChildId(newSuperClass.getId(), null); + } + + if (name == null) { + name = newSuperClass.getName(); + } + + if (newReal != curReal) { + IToolChain extTc = ManagedBuildManager.getExtensionToolChain(newSuperClass); + if (extTc != null) + newSuperClass = extTc; + ToolChain oldToolChain = toolChain; + // ConverterInfo cInfo = getToolChainConverterInfo(toolChain, newSuperClass); + // ITool oldTools[] = oldToolChain.getTools(); + // + // if (cInfo != null) { + // updateToolChainWithConverter(cInfo, Id, name); + // } else { + // updateToolChainWithProperties(usePrefTc ? null : newSuperClass, Id, name); + // } + // BuildSettingsUtil.disconnectDepentents(getParent(), oldTools); + } + return toolChain; + } + + void updateToolChainWithProperties(IToolChain newSuperClass, String Id, String name) { + ToolChain oldTc = (ToolChain) getToolChain(); + Configuration cfg = null; + if (newSuperClass != null) { + createToolChain(newSuperClass, Id, name, false); + + // For each option/option category child of the tool-chain that is + // the child of the selected configuration element, create an option/ + // option category child of the cloned configuration's tool-chain element + // that specifies the original tool element as its superClass. + toolChain.createOptions(newSuperClass); + + // For each tool element child of the tool-chain that is the child of + // the selected configuration element, create a tool element child of + // the cloned configuration's tool-chain element that specifies the + // original tool element as its superClass. + String subId; + ITool[] tools = newSuperClass.getTools(); + for (ITool tool : tools) { + Tool toolChild = (Tool) tool; + subId = ManagedBuildManager.calculateChildId(toolChild.getId(), null); + toolChain.createTool(toolChild, subId, toolChild.getName(), false); + } + } else { + //Configuration cfg = ConfigurationDataProvider.getClearPreference(null); + ToolChain prefTch = (ToolChain) cfg.getRootFolderInfo().getToolChain(); + + toolChain = new ToolChain(this, ManagedBuildManager.calculateChildId(prefTch.getSuperClass().getId(), null), + prefTch.getName(), new HashMap>(), prefTch); + } + + if (isRoot()) { + Builder oldBuilder = (Builder) oldTc.getBuilder(); + Builder newBuilder = (Builder) getParent().getEditableBuilder(); + newBuilder.copySettings(oldBuilder, false); + } + + IManagedProject mProj = getParent().getManagedProject(); + ITool[] filteredTools = getFilteredTools(); + ITool[] oldFilteredTools = filterTools(oldTc.getTools(), mProj); + + copySettings(oldFilteredTools, filteredTools); + + toolChain.propertiesChanged(); + } + + private void copySettings(ITool[] fromTools, ITool[] toTools) { + // ITool[][] matches = getBestMatches(fromTools, toTools); + // for (ITool[] match : matches) { + // BuildSettingsUtil.copyCommonSettings(match[0], match[1]); + // } + } + + private ITool[][] getBestMatches(ITool[] tools1, ITool[] tools2) { + HashSet set = new HashSet<>(Arrays.asList(tools2)); + List list = new ArrayList<>(tools1.length); + for (ITool tool1 : tools1) { + ITool bestMatchTool = null; + int num = 0; + for (ITool tool2 : set) { + int extsNum = getConflictingInputExts(tool1, tool2).length; + if (extsNum > num) { + bestMatchTool = tool2; + num = extsNum; + } + } + + if (bestMatchTool != null) { + list.add(new ITool[] { tool1, bestMatchTool }); + set.remove(bestMatchTool); + } + } + return list.toArray(new ITool[list.size()][]); + } + + // void updateToolChainWithConverter(ConverterInfo cInfo, String Id, String name) throws BuildException { + // IBuildObject bo = cInfo.getConvertedFromObject(); + // ToolChain updatedToolChain = null; + // if (bo instanceof Configuration) { + // Configuration cfg = (Configuration) bo; + // if (cfg != getParent()) { + // IResourceInfo rcInfo = cfg.getResourceInfo(getPath(), true); + // if (rcInfo instanceof FolderInfo) { + // IToolChain tc = ((FolderInfo) rcInfo).getToolChain(); + // IToolChain realToToolChain = ManagedBuildManager.getRealToolChain((IToolChain) cInfo.getToObject()); + // if (ManagedBuildManager.getRealToolChain(tc) == realToToolChain) { + // updatedToolChain = (ToolChain) tc; + // } + // } + // + // if (updatedToolChain == null) { + // updatedToolChain = (ToolChain) cfg.getRootFolderInfo().getToolChain(); + // } + // } else { + // updatedToolChain = toolChain; + // } + // } else if (bo instanceof ToolChain) { + // updatedToolChain = (ToolChain) bo; + // } else { + // throw new BuildException(ManagedMakeMessages.getResourceString("FolderInfo.4")); //$NON-NLS-1$ + // } + // + // if (updatedToolChain != null && toolChain != updatedToolChain) { + // setUpdatedToolChain(updatedToolChain); + // } + // + // toolChain.setName(name); + // } + + void setUpdatedToolChain(ToolChain tch) { + tch.copyNonoverriddenSettings(toolChain); + toolChain = tch; + tch.updateParentFolderInfo(this); + } + + // private ConverterInfo getToolChainConverterInfo(ToolChain fromTc, IToolChain toTc) { + // IConfigurationElement el = getToolChainConverterElement(fromTc, toTc); + // IToolChain foundToTc = toTc; + // if (el == null) { + // IToolChain[] tcs = ManagedBuildManager.findIdenticalToolChains(toTc); + // for (IToolChain tc : tcs) { + // foundToTc = tc; + // if (foundToTc == toTc) + // continue; + // + // el = getToolChainConverterElement(fromTc, foundToTc); + // if (el != null) + // break; + // } + // } + // + // if (el != null) + // return new ConverterInfo(this, getToolChain(), foundToTc, el); + // return null; + // } + + private IConfigurationElement getToolChainConverterElement(ToolChain fromTc, IToolChain tCh) { + if (tCh == null) + return null; + + if (fromTc != null) + return fromTc.getConverterModificationElement(tCh); + else + return null; + } + + @SuppressWarnings("unchecked") + private ITool[][] checkDups(ITool[] removed, ITool[] added) { + LinkedHashMap removedMap = createRealToExtToolMap(removed, false); + LinkedHashMap addedMap = createRealToExtToolMap(added, true); + LinkedHashMap rmCopy = (LinkedHashMap) removedMap.clone(); + + removedMap.keySet().removeAll(addedMap.keySet()); + addedMap.keySet().removeAll(rmCopy.keySet()); + + if (removedMap.size() != 0) { + LinkedHashMap curMap = createRealToExtToolMap(getTools(), false); + for (Iterator> iter = removedMap.entrySet().iterator(); iter.hasNext();) { + Map.Entry entry = iter.next(); + Object key = entry.getKey(); + Object curTool = curMap.get(key); + if (curTool != null) + entry.setValue((ITool) curTool); + else + iter.remove(); + } + } + ITool[][] result = new Tool[2][]; + result[0] = removedMap.values().toArray(new Tool[removedMap.size()]); + result[1] = addedMap.values().toArray(new Tool[addedMap.size()]); + return result; + } + + private LinkedHashMap createRealToExtToolMap(ITool[] tools, boolean extValues) { + LinkedHashMap map = new LinkedHashMap<>(); + for (ITool t : tools) { + Tool realTool = (Tool) ManagedBuildManager.getRealTool(t); + MatchKey key = realTool.getMatchKey(); + ITool toolValue = extValues ? ManagedBuildManager.getExtensionTool(t) : t; + if (toolValue != null) + map.put(key, toolValue); + } + return map; + } + + @Override + public void modifyToolChain(ITool[] removed, ITool[] added) { + // ToolListModificationInfo info = ToolChainModificationHelper.getModificationInfo(this, getTools(), added, + // removed); + // info.apply(); + return; + + // ITool[][] checked = checkDups(removed, added); + // removed = checked[0]; + // added = checked[1]; + // if(added.length == 0 && removed.length == 0) + // return; + // + // List remainingRemoved = new ArrayList(); + // List remainingAdded = new ArrayList(); + // Map converterMap = + // calculateConverterTools(removed, added, remainingRemoved, remainingAdded); + // invokeConverters(converterMap); + // List newTools = new ArrayList(added.length); + // for(ConverterInfo info : converterMap.values()){ + // if(info.getConvertedFromObject() instanceof Tool){ + // Tool newTool = (Tool)info.getConvertedFromObject(); + // newTool.updateParent(getToolChain()); + // newTools.add(newTool); + // } else { + // remainingAdded.add((ITool)info.getToObject()); + // } + // } + // + // for(ITool t : remainingAdded){ + // newTools.add( + // new Tool( + // toolChain, + // t, + // ManagedBuildManager.calculateChildId(t.getId(), null), + // t.getName(), + // false) + // ); + // } + // + // performToolChainModification(removed, newTools.toArray(new Tool[newTools.size()])); + } + + // private void performToolChainModification(ITool removed[], ITool[] added){ + // BuildSettingsUtil.disconnectDepentents(getParent(), removed); + // + // for (ITool tool : removed) { + // toolChain.removeTool((Tool)tool); + // } + // + // for (ITool tool : added) { + // toolChain.addTool((Tool)tool); + // } + // + // adjustTargetTools(removed, added); + // + // toolChain.propertiesChanged(); + // } + + private void adjustTargetTools(ITool removed[], ITool added[]) { + if (!isRoot()) + return; + + Set set = new HashSet<>(); + String[] ids = toolChain.getTargetToolList(); + boolean targetToolsModified = false; + set.addAll(Arrays.asList(ids)); + + for (ITool tool : removed) { + Object[] tInfo = getTargetTool(tool); + + if (tInfo == null) + continue; + + ITool target = (ITool) tInfo[0]; + String tId = (String) tInfo[1]; + + // if (BuildSettingsUtil.calcDependentTools(added, target, null).size() != 0) + // continue; + + ITool newTargetTool = findCompatibleTargetTool(target, added); + if (newTargetTool == null) + continue; + + newTargetTool = ManagedBuildManager.getExtensionTool(newTargetTool); + if (newTargetTool == null) + continue; + + set.remove(tId); + set.add(newTargetTool.getId()); + targetToolsModified = true; + } + + if (targetToolsModified) { + toolChain.setTargetToolIds(CDataUtil.arrayToString(set.toArray(new String[set.size()]), ";")); //$NON-NLS-1$ + } + } + + private ITool findCompatibleTargetTool(ITool tool, ITool allTools[]) { + IProject project = getParent().getOwner().getProject(); + String exts[] = ((Tool) tool).getAllOutputExtensions(project); + Set extsSet = new HashSet<>(Arrays.asList(exts)); + ITool compatibleTool = null; + for (ITool t : allTools) { + String otherExts[] = ((Tool) t).getAllOutputExtensions(project); + for (String otherExt : otherExts) { + if (extsSet.contains(otherExt)) { + compatibleTool = t; + break; + } + } + if (compatibleTool != null) + break; + } + + if (compatibleTool == null) { + //try to match build output variable + Set set = getToolOutputVars(tool); + for (ITool t : allTools) { + IOutputType types[] = t.getOutputTypes(); + for (IOutputType type : types) { + String var = type.getBuildVariable(); + if (var != null && set.contains(var)) { + compatibleTool = t; + break; + } + + } + + if (compatibleTool != null) + break; + } + } + + return compatibleTool; + } + + private Set getToolOutputVars(ITool tool) { + Set set = new HashSet<>(); + + IOutputType types[] = tool.getOutputTypes(); + for (IOutputType type : types) { + String var = type.getBuildVariable(); + if (var != null) + set.add(var); + + } + + return set; + } + + private Object[] getTargetTool(ITool tool) { + String[] ids = toolChain.getTargetToolList(); + + for (String id : ids) { + ITool target = tool; + for (; target != null; target = target.getSuperClass()) { + if (id.equals(target.getId())) + break; + } + if (target != null) + return new Object[] { target, id }; + + } + return null; + } + + // private List invokeConverters(Map converterMap){ + // List failed = new ArrayList(); + // for(ConverterInfo info : converterMap.values()){ + // IBuildObject converted = info.getConvertedFromObject(); + // if(converted == null || + // !converted.getClass().equals(info.getFromObject().getClass())){ + // failed.add(info); + // } + // } + // return failed; + // } + + // private Map calculateConverterTools(ITool[] removed, ITool[] added, List remainingRemoved, List remainingAdded){ + // if(remainingAdded == null) + // remainingAdded = new ArrayList(added.length); + // if(remainingRemoved == null) + // remainingRemoved = new ArrayList(removed.length); + // + // remainingAdded.clear(); + // remainingRemoved.clear(); + // + // remainingAdded.addAll(Arrays.asList(added)); + // remainingRemoved.addAll(Arrays.asList(removed)); + // + // Map resultMap = new HashMap(); + // + // for(Iterator rIter = remainingRemoved.iterator(); rIter.hasNext();){ + // ITool r = rIter.next(); + // + // if(r.getParentResourceInfo() != this) + // continue; + // + // if(ManagedBuildManager.getConversionElements(r).size() == 0) + // continue; + // + // for(Iterator aIter = remainingAdded.iterator(); aIter.hasNext();){ + // ITool a = aIter.next(); + // + // if(a.getParentResourceInfo() == this) + // continue; + // + // IConfigurationElement el = getToolConverterElement(r, a); + // if(el != null){ + // resultMap.put(r, new ConverterInfo(this, r, a, el)); + // rIter.remove(); + // aIter.remove(); + // break; + // } + // } + // } + // + // return resultMap; + // } + + private ITool[] calculateToolsArray(ITool[] removed, ITool[] added) { + LinkedHashMap map = createRealToExtToolMap(getTools(), false); + LinkedHashMap removedMap = createRealToExtToolMap(removed, false); + + map.keySet().removeAll(removedMap.keySet()); + map.putAll(createRealToExtToolMap(added, true)); + + return map.values().toArray(new ITool[map.size()]); + } + + @SuppressWarnings("unchecked") + private ITool[][] calculateConflictingTools(ITool[] newTools) { + HashSet set = new HashSet<>(); + set.addAll(Arrays.asList(newTools)); + List result = new ArrayList<>(); + for (Iterator iter = set.iterator(); iter.hasNext();) { + ITool t = iter.next(); + iter.remove(); + HashSet tmp = (HashSet) set.clone(); + List list = new ArrayList<>(); + for (Iterator tmpIt = tmp.iterator(); tmpIt.hasNext();) { + ITool other = tmpIt.next(); + String conflicts[] = getConflictingInputExts(t, other); + if (conflicts.length != 0) { + list.add(other); + tmpIt.remove(); + } + } + + if (list.size() != 0) { + list.add(t); + result.add(list.toArray(new Tool[list.size()])); + } + set = tmp; + iter = set.iterator(); + } + + return result.toArray(new ITool[result.size()][]); + } + + private String[] getConflictingInputExts(ITool tool1, ITool tool2) { + IProject project = getParent().getOwner().getProject(); + String ext1[] = ((Tool) tool1).getAllInputExtensions(project); + String ext2[] = ((Tool) tool2).getAllInputExtensions(project); + Set set1 = new HashSet<>(Arrays.asList(ext1)); + Set result = new HashSet<>(); + for (String e : ext2) { + if (set1.remove(e)) + result.add(e); + } + return result.toArray(new String[result.size()]); + } + + @Override + public IModificationStatus getToolChainModificationStatus(ITool[] removed, ITool[] added) { + return null; + // ITool[][] checked = checkDups(removed, added); + // removed = checked[0]; + // added = checked[1]; + // ITool newTools[] = calculateToolsArray(removed, added); + // ITool[][] conflicting = calculateConflictingTools(filterTools(newTools, getParent().getManagedProject())); + // Map unspecifiedRequiredProps = new HashMap<>(); + // Map unspecifiedProps = new HashMap<>(); + // Set undefinedSet = new HashSet<>(); + // IConfiguration cfg = getParent(); + // ITool[] nonManagedTools = null; + // if (cfg.isManagedBuildOn() && cfg.supportsBuild(true)) { + // List list = new ArrayList<>(); + // for (ITool t : newTools) + // if (!t.supportsBuild(true)) + // list.add(t); + // if (list.size() != 0) + // nonManagedTools = list.toArray(new Tool[list.size()]); + // } + // return new ModificationStatus(unspecifiedRequiredProps, unspecifiedProps, undefinedSet, conflicting, + // nonManagedTools); + } + + @Override + public boolean supportsBuild(boolean managed) { + if (getRequiredUnspecifiedProperties().size() != 0) + return false; + + ToolChain tCh = (ToolChain) getToolChain(); + if (tCh == null || !tCh.getSupportsManagedBuildAttribute()) + return !managed; + + ITool tools[] = getFilteredTools(); + for (int i = 0; i < tools.length; i++) { + if (!tools[i].supportsBuild(managed)) + return false; + } + + return true; + } + + @Override + public boolean buildsFileType(String srcExt) { + // Check to see if there is a rule to build a file with this extension + ITool[] tools = getFilteredTools(); + for (ITool tool : tools) { + if (tool != null && tool.buildsFileType(srcExt)) { + return true; + } + } + return false; + } + + @Override + public String getOutputExtension(String resourceExtension) { + String outputExtension = null; + ITool[] tools = getFilteredTools(); + for (ITool tool : tools) { + outputExtension = tool.getOutputExtension(resourceExtension); + if (outputExtension != null) { + return outputExtension; + } + } + return null; + } + + @Override + public boolean isHeaderFile(String ext) { + // Check to see if there is a rule to build a file with this extension + IManagedProject manProj = getParent().getManagedProject(); + IProject project = null; + if (manProj != null) { + project = (IProject) manProj.getOwner(); + } + ITool[] tools = getFilteredTools(); + for (ITool tool : tools) { + try { + if (project != null) { + // Make sure the tool is right for the project + switch (tool.getNatureFilter()) { + case ITool.FILTER_C: + if (project.hasNature(CProjectNature.C_NATURE_ID) + && !project.hasNature(CCProjectNature.CC_NATURE_ID)) { + return tool.isHeaderFile(ext); + } + break; + case ITool.FILTER_CC: + if (project.hasNature(CCProjectNature.CC_NATURE_ID)) { + return tool.isHeaderFile(ext); + } + break; + case ITool.FILTER_BOTH: + return tool.isHeaderFile(ext); + } + } else { + return tool.isHeaderFile(ext); + } + } catch (CoreException e) { + continue; + } + } + return false; + } + + @Override + public Set contributeErrorParsers(Set set) { + if (toolChain != null) + set = toolChain.contributeErrorParsers(this, set, true); + return set; + } + + @Override + public void resetErrorParsers() { + if (toolChain != null) + toolChain.resetErrorParsers(this); + } + + @Override + void removeErrorParsers(Set set) { + if (toolChain != null) + toolChain.removeErrorParsers(this, set); + } + + @Override + public ITool getToolById(String id) { + if (toolChain != null) + return toolChain.getTool(id); + return null; + } + + @Override + void resolveProjectReferences(boolean onLoad) { + if (toolChain != null) + toolChain.resolveProjectReferences(onLoad); + } + + /** + * Reset the options of the given holder to the default values + */ + private void resetOptionSettings(IHoldsOptions holder) { + IOption[] opts = holder.getOptions(); + for (IOption opt : opts) { + Object val = opt.getDefaultValue(); + + if (opt.getDefaultValueGenerator() != null) { + val = opt.getDefaultValueGenerator().generateDefaultValue(opt); + } + + if (val instanceof Boolean) { + ManagedBuildManager.setOption(toolChain.getParent(), holder, opt, (Boolean) val); + } else if (val instanceof String[]) { + ManagedBuildManager.setOption(toolChain.getParent(), holder, opt, (String[]) val); + } else if (val instanceof String) { + ManagedBuildManager.setOption(toolChain.getParent(), holder, opt, (String) val); + } else if (val == null) { + holder.removeOption(opt); + } else { + Activator.error("Unknown type of value " + val + " for " + opt); //$NON-NLS-1$ //$NON-NLS-2$ + } + } + } + + public void resetOptionSettings() { + // (Bug 438367) Removing all the options and relying on automatic creating when modifying/using the option + // will result in problems in the following cases: + // - When changing an option affects values of other options. + // - When the option has a FieldEditor that holds an instance of the option, that + // will result on having multiple copies of the option in some cases. + // Instead, will reset the value of each option to its default value. + ITool[] tools = getTools(); + IToolChain toolChain = getToolChain(); + for (ITool tool : tools) { + resetOptionSettings(tool); + } + resetOptionSettings(toolChain); + + // Send out the event to notify the options that they are about to be removed. + // Do not do this for the child resource configurations as they are handled when + // the configuration itself is destroyed. + // ManagedBuildManager.performValueHandlerEvent(this, IManagedOptionValueHandler.EVENT_CLOSE, false); + // rebuildNeeded = true; + } + + @Override + public boolean hasCustomSettings() { + IFolderInfo parentFo = getParentFolderInfo(); + if (parentFo == null) + return true; + return toolChain.hasCustomSettings((ToolChain) parentFo.getToolChain()); + } + + public boolean containsDiscoveredScannerInfo() { + if (!isRoot()) + return true; + + return containsDiscoveredScannerInfo; + } + + public void setContainsDiscoveredScannerInfo(boolean contains) { + containsDiscoveredScannerInfo = contains; + } + + @Override + public boolean isFolderInfo() { + return true; + } + + @Override + void performPostModificationAdjustments(ToolListModificationInfo info) { + adjustTargetTools(info.getRemovedTools(), info.getAddedTools(true)); + + super.performPostModificationAdjustments(info); + } + + @Override + void applyToolsInternal(ITool[] resultingTools, ToolListModificationInfo info) { + ITool[] removedTools = info.getRemovedTools(); + + for (ITool tool : removedTools) { + ITool extTool = ManagedBuildManager.getExtensionTool(tool); + if (extTool.getParent() == toolChain.getSuperClass()) + toolChain.addUnusedChild(extTool); + } + + toolChain.setToolsInternal(resultingTools); + + adjustTargetTools(removedTools, info.getAddedTools(true)); + + setRebuildState(true); + } + + @Override + public boolean isSupported() { + if (toolChain != null) + return toolChain.isSupported(); + return false; + } + + // private IConfigurationElement getToolConverterElement(ITool fromTool, ITool toTool){ + // ToolChain curTc = (ToolChain)getToolChain(); + // if(curTc != null){ + // return curTc.getConverterModificationElement(fromTool, toTool); + // } + // return null; + // } +} diff --git a/io.sloeber.ManagedBuild/src/io/sloeber/autoBuild/Internal/GeneratedMakefileBuilder.java b/io.sloeber.ManagedBuild/src/io/sloeber/autoBuild/Internal/GeneratedMakefileBuilder.java new file mode 100644 index 000000000..8db91e94c --- /dev/null +++ b/io.sloeber.ManagedBuild/src/io/sloeber/autoBuild/Internal/GeneratedMakefileBuilder.java @@ -0,0 +1,1700 @@ +/******************************************************************************* + * Copyright (c) 2002, 2016 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Rational Software - Initial API and implementation + *******************************************************************************/ +package io.sloeber.autoBuild.Internal; + +import static io.sloeber.autoBuild.Internal.ManagebBuildCommon.*; +import static io.sloeber.autoBuild.core.Messages.*; + +import java.io.IOException; +import java.io.OutputStream; +import java.net.URI; +import java.text.MessageFormat; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.Vector; + +import org.eclipse.cdt.core.CCorePlugin; +import org.eclipse.cdt.core.ConsoleOutputStream; +import org.eclipse.cdt.core.ErrorParserManager; +import org.eclipse.cdt.core.ICommandLauncher; +import org.eclipse.cdt.core.IMarkerGenerator; +import org.eclipse.cdt.core.envvar.IEnvironmentVariable; +import org.eclipse.cdt.core.model.ICModelMarker; +import org.eclipse.cdt.core.resources.ACBuilder; +import org.eclipse.cdt.core.resources.IConsole; +import org.eclipse.cdt.core.resources.RefreshScopeManager; +import org.eclipse.cdt.internal.core.BuildRunnerHelper; +import org.eclipse.cdt.internal.errorparsers.FixitManager; +//import org.eclipse.cdt.managedbuilder.buildmodel.BuildDescriptionManager; +//import org.eclipse.cdt.managedbuilder.buildmodel.IBuildDescription; +//import org.eclipse.cdt.managedbuilder.buildmodel.IBuildIOType; +//import org.eclipse.cdt.managedbuilder.buildmodel.IBuildResource; +//import org.eclipse.cdt.managedbuilder.buildmodel.IBuildStep; +//import org.eclipse.cdt.managedbuilder.core.IBuilder; +//import org.eclipse.cdt.managedbuilder.core.IConfiguration; +//import org.eclipse.cdt.managedbuilder.core.IManagedBuildInfo; +//import org.eclipse.cdt.managedbuilder.core.ManagedBuildManager; +//import org.eclipse.cdt.managedbuilder.core.ManagedBuilderCorePlugin; +//import org.eclipse.cdt.managedbuilder.internal.buildmodel.DescriptionBuilder; +//import org.eclipse.cdt.managedbuilder.internal.buildmodel.IBuildModelBuilder; +//import org.eclipse.cdt.managedbuilder.internal.buildmodel.ParallelBuilder; +//import org.eclipse.cdt.managedbuilder.internal.buildmodel.StepBuilder; +//import org.eclipse.cdt.managedbuilder.macros.BuildMacroException; +//import org.eclipse.cdt.managedbuilder.macros.IBuildMacroProvider; +//import org.eclipse.cdt.managedbuilder.makegen.IManagedBuilderMakefileGenerator; +import org.eclipse.cdt.utils.EFSExtensionManager; +import org.eclipse.core.resources.IContainer; +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IMarker; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.resources.IResourceDelta; +import org.eclipse.core.resources.IResourceDeltaVisitor; +import org.eclipse.core.resources.IWorkspace; +import org.eclipse.core.resources.IWorkspaceRoot; +import org.eclipse.core.resources.IWorkspaceRunnable; +import org.eclipse.core.resources.IncrementalProjectBuilder; +import org.eclipse.core.resources.ResourcesPlugin; +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.MultiStatus; +import org.eclipse.core.runtime.NullProgressMonitor; +import org.eclipse.core.runtime.OperationCanceledException; +import org.eclipse.core.runtime.Path; +import org.eclipse.core.runtime.Status; +import org.eclipse.core.runtime.SubProgressMonitor; + +import io.sloeber.autoBuild.api.BuildMacroException; +import io.sloeber.autoBuild.api.IBuildMacroProvider; +import io.sloeber.autoBuild.api.IBuilder; +import io.sloeber.autoBuild.api.IConfiguration; +import io.sloeber.autoBuild.api.IManagedBuildInfo; +import io.sloeber.autoBuild.api.IManagedBuilderMakefileGenerator; +import io.sloeber.autoBuild.core.Activator; + +/** + * This is the incremental builder associated with a managed build project. It + * dynamically + * decides the makefile generator it wants to use for a specific target. + * + * @since 1.2 + */ +public class GeneratedMakefileBuilder extends ACBuilder { + /** + * @since 1.2 + */ + public class ResourceDeltaVisitor implements IResourceDeltaVisitor { + private String buildGoalName; + private IManagedBuildInfo buildInfo; + private boolean incrBuildNeeded = false; + private boolean fullBuildNeeded = false; + private List reservedNames; + + public ResourceDeltaVisitor(IManagedBuildInfo info) { + buildInfo = info; + String ext = buildInfo.getBuildArtifactExtension(); + //try to resolve build macros in the build artifact extension + ext = resolveValueToMakefileFormat(ext, "", //$NON-NLS-1$ + " ", //$NON-NLS-1$ + IBuildMacroProvider.CONTEXT_CONFIGURATION, info.getDefaultConfiguration()); + + String name = buildInfo.getBuildArtifactName(); + //try to resolve build macros in the build artifact name + String resolved = resolveValueToMakefileFormat(name, "", //$NON-NLS-1$ + " ", //$NON-NLS-1$ + IBuildMacroProvider.CONTEXT_CONFIGURATION, info.getDefaultConfiguration()); + if ((resolved = resolved.trim()).length() > 0) + name = resolved; + + if (ext.length() > 0) { + buildGoalName = buildInfo.getOutputPrefix(ext) + name + IManagedBuilderMakefileGenerator.DOT + ext; + } else { + buildGoalName = name; + } + reservedNames = Arrays.asList(new String[] { ".cdtbuild", ".cdtproject", ".project" }); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + } + + private boolean isGeneratedResource(IResource resource) { + // Is this a generated directory ... + IPath path = resource.getProjectRelativePath(); + String[] configNames = buildInfo.getConfigurationNames(); + for (int i = 0; i < configNames.length; i++) { + String name = configNames[i]; + IPath root = new Path(name); + // It is if it is a root of the resource pathname + if (root.isPrefixOf(path)) + return true; + } + return false; + } + + private boolean isProjectFile(IResource resource) { + return reservedNames.contains(resource.getName()); + } + + public boolean shouldBuildIncr() { + return incrBuildNeeded; + } + + public boolean shouldBuildFull() { + return fullBuildNeeded; + } + + @Override + public boolean visit(IResourceDelta delta) throws CoreException { + IResource resource = delta.getResource(); + // If the project has changed, then a build is needed and we can stop + if (resource != null && resource.getProject() == getProject()) { + switch (resource.getType()) { + case IResource.FILE: + String name = resource.getName(); + if ((!name.equals(buildGoalName) && + // TODO: Also need to check for secondary outputs + (resource.isDerived() || (isProjectFile(resource)) || (isGeneratedResource(resource))))) { + // The resource that changed has attributes which make it uninteresting, + // so don't do anything + } else { + // TODO: Should we do extra checks here to determine if a build is really needed, + // or do you just do exclusion checks like above? + // We could check for: + // o The build goal name + // o A secondary output + // o An input file to a tool: + // o Has an extension of a source file used by a tool + // o Has an extension of a header file used by a tool + // o Has the name of an input file specified in an InputType via: + // o An Option + // o An AdditionalInput + // + //if (resourceName.equals(buildGoalName) || + // (buildInfo.buildsFileType(ext) || buildInfo.isHeaderFile(ext))) { + + // We need to do an incremental build, at least + incrBuildNeeded = true; + if (delta.getKind() == IResourceDelta.REMOVED) { + // If a meaningful resource was removed, then force a full build + // This is required because an incremental build will trigger make to + // do nothing for a missing source, since the state after the file + // removal is uptodate, as far as make is concerned + // A full build will clean, and ultimately trigger a relink without + // the object generated from the deleted source, which is what we want + fullBuildNeeded = true; + // There is no point in checking anything else since we have + // decided to do a full build anyway + break; + } + + //} + } + + return false; + } + } + return true; + } + } + + private static class OtherConfigVerifier implements IResourceDeltaVisitor { + IConfiguration config; + IConfiguration configs[]; + Set otherConfigs; + int resourceChangeState; + + private static final IPath[] ignoreList = { new Path(".cdtproject"), //$NON-NLS-1$ + new Path(".cproject"), //$NON-NLS-1$ + new Path(".cdtbuild"), //$NON-NLS-1$ + new Path(".settings"), //$NON-NLS-1$ + }; + + OtherConfigVerifier(IConfiguration cfg) { + config = cfg; + configs = cfg.getManagedProject().getConfigurations(); + otherConfigs = new HashSet(); + int counter = 0; + for (IConfiguration curConfig : configs) { + if (curConfig != config) + otherConfigs.add((Configuration) curConfig); + } + } + + @Override + public boolean visit(IResourceDelta delta) throws CoreException { + + IResource rc = delta.getResource(); + if (rc.getType() == IResource.FILE) { + if (isResourceValuable(rc)) + resourceChangeState |= delta.getKind(); + return false; + } + return !isGeneratedForConfig(rc, config) && isResourceValuable(rc); + } + + public void updateOtherConfigs(IResourceDelta delta) { + if (delta == null) + resourceChangeState = ~0; + else { + try { + delta.accept(this); + } catch (CoreException e) { + resourceChangeState = ~0; + } + } + + setResourceChangeStateForOtherConfigs(); + } + + private void setResourceChangeStateForOtherConfigs() { + for (IConfiguration curConfig : otherConfigs) { + curConfig.addResourceChangeState(resourceChangeState); + } + } + + private boolean isGeneratedForConfig(IResource resource, IConfiguration cfg) { + // Is this a generated directory ... + IPath path = resource.getProjectRelativePath(); + IPath root = new Path(cfg.getName()); + // It is if it is a root of the resource pathname + if (root.isPrefixOf(path)) + return true; + return false; + } + + private boolean isResourceValuable(IResource rc) { + IPath path = rc.getProjectRelativePath(); + for (int i = 0; i < ignoreList.length; i++) { + if (ignoreList[i].equals(path)) + return false; + } + return true; + } + } + + // String constants + //private static final String BUILD_ERROR = "ManagedMakeBuilder_message_error"; //$NON-NLS-1$ + //private static final String BUILD_FINISHED = "ManagedMakeBuilder_message_finished"; //$NON-NLS-1$ + //private static final String CONSOLE_HEADER = "ManagedMakeBuilder_message_console_header"; //$NON-NLS-1$ + private static final String ERROR_HEADER = "GeneratedmakefileBuilder error ["; //$NON-NLS-1$ + //private static final String MAKE = "ManagedMakeBuilder.message.make"; //$NON-NLS-1$ + // private static final String MARKERS = "ManagedMakeBuilder_message_creating_markers"; //$NON-NLS-1$ + private static final String NEWLINE = System.getProperty("line.separator", "\n"); //$NON-NLS-1$ //$NON-NLS-2$ + // private static final String NOTHING_BUILT = "ManagedMakeBuilder_message_no_build"; //$NON-NLS-1$ + // private static final String REFRESH = "ManagedMakeBuilder.message.updating"; //$NON-NLS-1$ + //private static final String REFRESH_ERROR = "ManagedMakeBuilder_message_error_refresh"; //$NON-NLS-1$ + private static final String TRACE_FOOTER = "]: "; //$NON-NLS-1$ + private static final String TRACE_HEADER = "GeneratedmakefileBuilder trace ["; //$NON-NLS-1$ + //private static final String TYPE_CLEAN = "ManagedMakeBuilder.type.clean"; //$NON-NLS-1$ + //private static final String TYPE_INC = "ManagedMakeBuider.type.incremental"; //$NON-NLS-1$ + private static final String WARNING_UNSUPPORTED_CONFIGURATION = "ManagedMakeBuilder.warning.unsupported.configuration"; //$NON-NLS-1$ + //private static final String BUILD_CANCELLED = "ManagedMakeBuilder_message_cancelled"; //$NON-NLS-1$ + //private static final String BUILD_FINISHED_WITH_ERRS = "ManagedMakeBuilder_message_finished_with_errs"; //$NON-NLS-1$ + // private static final String BUILD_FAILED_ERR = "ManagedMakeBuilder_message_internal_builder_error"; //$NON-NLS-1$ + //private static final String BUILD_STOPPED_ERR = "ManagedMakeBuilder_message_stopped_error"; //$NON-NLS-1$ + // private static final String INTERNAL_BUILDER_HEADER_NOTE = "ManagedMakeBuilder_message_internal_builder_header_note"; //$NON-NLS-1$ + //private static final String TYPE_REBUILD = "ManagedMakeBuider_type_rebuild"; //$NON-NLS-1$ + //private static final String INTERNAL_BUILDER = "ManagedMakeBuilder_message_internal_builder"; //$NON-NLS-1$ + + private static final int PROGRESS_MONITOR_SCALE = 100; + private static final int TICKS_STREAM_PROGRESS_MONITOR = 1 * PROGRESS_MONITOR_SCALE; + private static final int TICKS_DELETE_MARKERS = 1 * PROGRESS_MONITOR_SCALE; + + public static boolean VERBOSE = false; + + // Local variables + protected Vector generationProblems; + protected IProject[] referencedProjects; + protected List resourcesToBuild; + private IConsole console; + + public static void outputTrace(String resourceName, String message) { + if (VERBOSE) { + System.out.println(TRACE_HEADER + resourceName + TRACE_FOOTER + message + NEWLINE); + } + } + + public static void outputError(String resourceName, String message) { + if (VERBOSE) { + System.err.println(ERROR_HEADER + resourceName + TRACE_FOOTER + message + NEWLINE); + } + } + + /** + * Zero-argument constructor needed to fulfill the contract of an + * incremental builder. + */ + public GeneratedMakefileBuilder() { + } + + private void addBuilderMarkers(ErrorParserManager epm) { + IWorkspaceRoot root = CCorePlugin.getWorkspace().getRoot(); + Iterator iter = getGenerationProblems().iterator(); + while (iter.hasNext()) { + IStatus stat = iter.next(); + IResource location = root.findMember(stat.getMessage()); + if (stat.getCode() == IManagedBuilderMakefileGenerator.SPACES_IN_PATH) { + epm.generateMarker(location, -1, MakefileGenerator_error_spaces, //$NON-NLS-1$ + IMarkerGenerator.SEVERITY_WARNING, null); + } + } + } + + /* (non-javadoc) + * Emits a message to the console indicating that there were no source files to build + * @param buildType + * @param status + * @param configName + */ + private void emitNoSourceMessage(int buildType, IStatus status, String configName) throws CoreException { + try { + StringBuilder buf = new StringBuilder(); + IConsole console = CCorePlugin.getDefault().getConsole(); + console.start(getProject()); + ConsoleOutputStream consoleOutStream = console.getOutputStream(); + // Report a successful clean + String[] consoleHeader = new String[3]; + if (buildType == FULL_BUILD || buildType == INCREMENTAL_BUILD) { + consoleHeader[0] = ManagedMakeBuider_type_incremental; + } else { + consoleHeader[0] = ""; //$NON-NLS-1$ + outputError(getProject().getName(), "The given build type is not supported in this context"); //$NON-NLS-1$ + } + consoleHeader[1] = configName; + consoleHeader[2] = getProject().getName(); + buf.append(NEWLINE); + buf.append(MessageFormat.format(ManagedMakeBuilder_message_console_header, consoleHeader)).append(NEWLINE); + buf.append(NEWLINE); + buf.append(status.getMessage()).append(NEWLINE); + consoleOutStream.write(buf.toString().getBytes()); + consoleOutStream.flush(); + consoleOutStream.close(); + } catch (CoreException e) { + // Throw the exception back to the builder + throw e; + } catch (IOException io) { // Ignore console failures... + } + } + + /** + * + * This method has been created so that subclasses can override how the builder + * obtains its + * build info. The default implementation retrieves the info from the build + * manager. + * + * @return An IManagedBuildInfo object representing the build info. + */ + protected IManagedBuildInfo getBuildInfo() { + return ManagedBuildManager.getBuildInfo(getProject()); + } + + /* (non-Javadoc) + * @see org.eclipse.core.internal.events.InternalBuilder#build(int, java.util.Map, org.eclipse.core.runtime.IProgressMonitor) + */ + @Override + protected IProject[] build(int kind, @SuppressWarnings("rawtypes") Map argsMap, IProgressMonitor monitor) + throws CoreException { + @SuppressWarnings("unchecked") + Map args = argsMap; + if (DEBUG_EVENTS) + printEvent(kind, args); + + // We should always tell the build system what projects we reference + referencedProjects = getProject().getReferencedProjects(); + + // Get the build information + IManagedBuildInfo info = getBuildInfo(); + if (info == null) { + outputError(getProject().getName(), "Build information was not found"); //$NON-NLS-1$ + return referencedProjects; + } + if (!info.isValid()) { + outputError(getProject().getName(), "Build information is not valid"); //$NON-NLS-1$ + return referencedProjects; + } + + IConfiguration[] cfgs = null; + if (needAllConfigBuild()) { + cfgs = info.getManagedProject().getConfigurations(); + } else { + cfgs = new IConfiguration[] { info.getDefaultConfiguration() }; + } + + for (IConfiguration cfg : cfgs) { + updateOtherConfigs(cfg, kind); + + if (((Configuration) cfg).isInternalBuilderEnabled()) { + invokeInternalBuilder(cfg, kind != FULL_BUILD, ((Configuration) cfg).getInternalBuilderIgnoreErr(), + monitor); + + // Scrub the build info the project + info.setRebuildState(false); + return referencedProjects; + } + + // Create a makefile generator for the build + IManagedBuilderMakefileGenerator generator = ManagedBuildManager + .getBuildfileGenerator(info.getDefaultConfiguration()); + generator.initialize(getProject(), info, monitor); + + //perform necessary cleaning and build type calculation + if (cfg.needsFullRebuild()) { + //configuration rebuild state is set to true, + //full rebuild is needed in any case + //clean first, then make a full build + outputTrace(getProject().getName(), "config rebuild state is set to true, making a full rebuild"); //$NON-NLS-1$ + clean(new SubProgressMonitor(monitor, IProgressMonitor.UNKNOWN)); + fullBuild(info, generator, monitor); + } else { + // boolean fullBuildNeeded = info.needsRebuild(); + // IBuildDescription des = null; + // + // IResourceDelta delta = kind == FULL_BUILD ? null : getDelta(getProject()); + // if (delta == null) + // fullBuildNeeded = true; + // if (cfg.needsRebuild() || delta != null) { + // //use a build description model to calculate the resources to be cleaned + // //only in case there are some changes to the project sources or build information + // try { + // int flags = BuildDescriptionManager.REBUILD | BuildDescriptionManager.DEPFILES + // | BuildDescriptionManager.DEPS; + // if (delta != null) + // flags |= BuildDescriptionManager.REMOVED; + // + // outputTrace(getProject().getName(), "using a build description.."); //$NON-NLS-1$ + // + // des = BuildDescriptionManager.createBuildDescription(info.getDefaultConfiguration(), + // getDelta(getProject()), flags); + // + // BuildDescriptionManager.cleanGeneratedRebuildResources(des); + // } catch (Throwable e) { + // //TODO: log error + // outputError(getProject().getName(), + // "error occured while build description calculation: " + e.getLocalizedMessage()); //$NON-NLS-1$ + // //in case an error occured, make it behave in the old stile: + // if (info.needsRebuild()) { + // //make a full clean if an info needs a rebuild + // clean(new SubProgressMonitor(monitor, IProgressMonitor.UNKNOWN)); + // fullBuildNeeded = true; + // } else if (delta != null && !fullBuildNeeded) { + // // Create a delta visitor to detect the build type + // ResourceDeltaVisitor visitor = new ResourceDeltaVisitor(info); + // delta.accept(visitor); + // if (visitor.shouldBuildFull()) { + // clean(new SubProgressMonitor(monitor, IProgressMonitor.UNKNOWN)); + // fullBuildNeeded = true; + // } + // } + // } + } + + boolean fullBuildNeeded = true; + if (fullBuildNeeded) { + outputTrace(getProject().getName(), "performing a full build"); //$NON-NLS-1$ + fullBuild(info, generator, monitor); + } else { + outputTrace(getProject().getName(), "performing an incremental build"); //$NON-NLS-1$ + incrementalBuild(getDelta(getProject()), info, generator, monitor); + } + } + /* + // So let's figure out why we got called + if (kind == FULL_BUILD) { + outputTrace(getProject().getName(), "Full build needed/requested"); //$NON-NLS-1$ + fullBuild(info, generator, monitor); + } + else if (kind == AUTO_BUILD && info.needsRebuild()) { + outputTrace(getProject().getName(), "Autobuild requested, full build needed"); //$NON-NLS-1$ + fullBuild(info, generator, monitor); + } + else { + // Create a delta visitor to make sure we should be rebuilding + ResourceDeltaVisitor visitor = new ResourceDeltaVisitor(info); + IResourceDelta delta = getDelta(getProject()); + if (delta == null) { + outputTrace(getProject().getName(), "Incremental build requested, full build needed"); //$NON-NLS-1$ + fullBuild(info, generator, monitor); + } + else { + delta.accept(visitor); + if (visitor.shouldBuildFull()) { + outputTrace(getProject().getName(), "Incremental build requested, full build needed"); //$NON-NLS-1$ + fullBuild(info, generator, monitor); + } else if (visitor.shouldBuildIncr()) { + outputTrace(getProject().getName(), "Incremental build requested"); //$NON-NLS-1$ + incrementalBuild(delta, info, generator, monitor); + } + else if (referencedProjects != null) { + // Also check to see is any of the dependent projects changed + for (int i=0; iOperationCanceledException. + * + * @see org.eclipse.core.runtime.OperationCanceledException#OperationCanceledException() + */ + public void checkCancel(IProgressMonitor monitor) { + if (monitor != null && monitor.isCanceled()) { + outputTrace(getProject().getName(), "Build cancelled"); //$NON-NLS-1$ + forgetLastBuiltState(); + throw new OperationCanceledException(); + } + } + + /* (non-Javadoc) + * @see org.eclipse.core.resources.IncrementalProjectBuilder#clean(org.eclipse.core.runtime.IProgressMonitor) + */ + @Override + protected void clean(IProgressMonitor monitor) throws CoreException { + if (DEBUG_EVENTS) + printEvent(IncrementalProjectBuilder.CLEAN_BUILD, null); + + referencedProjects = getProject().getReferencedProjects(); + outputTrace(getProject().getName(), "Clean build requested"); //$NON-NLS-1$ + IManagedBuildInfo info = getBuildInfo(); + if (info == null) { + outputError(getProject().getName(), "Build information was not found"); //$NON-NLS-1$ + return; + } + if (!info.isValid()) { + outputError(getProject().getName(), "Build information is not valid"); //$NON-NLS-1$ + return; + } + IPath buildDirPath = getProject().getLocation().append(info.getConfigurationName()); + IWorkspace workspace = CCorePlugin.getWorkspace(); + IContainer buildDir = workspace.getRoot().getContainerForLocation(buildDirPath); + if (buildDir == null || !buildDir.isAccessible()) { + outputError(buildDir == null ? "null" : buildDir.getName(), "Could not delete the build directory"); //$NON-NLS-1$ //$NON-NLS-2$ + return; + } + String status; + try { + // try the brute force approach first + status = MessageFormat.format(ManagedMakeBuilder_message_clean_deleting_output, buildDir.getName()); + monitor.subTask(status); + workspace.delete(new IResource[] { buildDir }, true, monitor); + StringBuilder buf = new StringBuilder(); + // write to the console + IConsole console = CCorePlugin.getDefault().getConsole(); + console.start(getProject()); + ConsoleOutputStream consoleOutStream = console.getOutputStream(); + String[] consoleHeader = new String[3]; + consoleHeader[0] = ManagedMakeBuilder_type_clean; + consoleHeader[1] = info.getConfigurationName(); + consoleHeader[2] = getProject().getName(); + buf.append(NEWLINE); + buf.append(MessageFormat.format(ManagedMakeBuilder_message_console_header, consoleHeader)).append(NEWLINE); + consoleOutStream.write(buf.toString().getBytes()); + consoleOutStream.flush(); + buf = new StringBuilder(); + // Report a successful clean + String successMsg = MessageFormat.format(ManagedMakeBuilder_message_finished, getProject().getName()); + buf.append(successMsg).append(NEWLINE); + consoleOutStream.write(buf.toString().getBytes()); + consoleOutStream.flush(); + consoleOutStream.close(); + } catch (CoreException e) { + // Create a makefile generator for the build + status = MessageFormat.format(ManagedMakeBuilder_message_clean_build_clean, buildDir.getName()); + monitor.subTask(status); + IManagedBuilderMakefileGenerator generator = ManagedBuildManager + .getBuildfileGenerator(info.getDefaultConfiguration()); + generator.initialize(getProject(), info, monitor); + cleanBuild(info, generator, monitor); + } catch (IOException io) { + } // Ignore console failures... + } + + /* (non-Javadoc) + * @param info + * @param generator + * @param monitor + */ + protected void cleanBuild(IManagedBuildInfo info, IManagedBuilderMakefileGenerator generator, + IProgressMonitor monitor) { + // Make sure that there is a top level directory and a set of makefiles + IPath buildDir = generator.getBuildWorkingDir(); + if (buildDir == null) { + buildDir = new Path(info.getConfigurationName()); + } + IPath makefilePath = getProject().getLocation().append(buildDir.append(generator.getMakefileName())); + IWorkspaceRoot root = CCorePlugin.getWorkspace().getRoot(); + IFile makefile = root.getFileForLocation(makefilePath); + + if (makefile != null && makefile.isAccessible()) { + // invoke make with the clean argument + String statusMsg = MessageFormat.format(ManagedMakeBuilder_message_starting, getProject().getName()); + monitor.subTask(statusMsg); + checkCancel(monitor); + invokeMake(CLEAN_BUILD, buildDir, info, generator, monitor); + } + } + + /* (non-Javadoc) + * @param info + * @param generator + * @param monitor + */ + protected void fullBuild(IManagedBuildInfo info, IManagedBuilderMakefileGenerator generator, + IProgressMonitor monitor) throws CoreException { + // Always need one of these bad boys + if (monitor == null) { + monitor = new NullProgressMonitor(); + } + + checkCancel(monitor); + //If the previous builder invocation was cancelled, generated files might be corrupted + //in case one or more of the generated makefiles (e.g. dep files) are corrupted, + //the builder invocation might fail because of the possible syntax errors, so e.g. "make clean" will not work + //we need to explicitly clean the generated directories + // clean(new SubProgressMonitor(monitor, IProgressMonitor.UNKNOWN)); + + // Regenerate the makefiles for this project + checkCancel(monitor); + String statusMsg = MessageFormat.format(ManagedMakeBuilder_message_rebuild_makefiles, getProject().getName()); + monitor.subTask(statusMsg); + //generator = ManagedBuildManager.getBuildfileGenerator(info.getDefaultConfiguration()); + generator.initialize(getProject(), info, monitor); + MultiStatus result = generator.regenerateMakefiles(); + if (result.getCode() == IStatus.WARNING || result.getCode() == IStatus.INFO) { + IStatus[] kids = result.getChildren(); + for (int index = 0; index < kids.length; ++index) { + // One possibility is that there is nothing to build + IStatus status = kids[index]; + if (status.getCode() == IManagedBuilderMakefileGenerator.NO_SOURCE_FOLDERS) { + // Inform the user, via the console, that there is nothing to build + // either because there are no buildable sources files or all potentially + // buildable files have been excluded from build + try { + emitNoSourceMessage(FULL_BUILD, status, info.getConfigurationName()); + } catch (CoreException e) { + // Throw the exception back to the builder + throw e; + } + // Dude, we're done + return; + } else { + // Stick this in the list of stuff to warn the user about + getGenerationProblems().add(status); + } + } + } + + // Now call make + checkCancel(monitor); + statusMsg = MessageFormat.format(ManagedMakeBuilder_message_starting, getProject().getName()); + monitor.subTask(statusMsg); + IPath topBuildDir = generator.getBuildWorkingDir(); + if (topBuildDir != null) { + invokeMake(FULL_BUILD, topBuildDir, info, generator, monitor); + } else { + statusMsg = MessageFormat.format(ManagedMakeBuilder_message_no_build, getProject().getName()); + monitor.subTask(statusMsg); + return; + } + + // Now regenerate the dependencies + checkCancel(monitor); + statusMsg = MessageFormat.format(ManagedMakeBuilder_message_regen_deps, getProject().getName()); + monitor.subTask(statusMsg); + try { + generator.regenerateDependencies(false); + } catch (CoreException e) { + // Throw the exception back to the builder + throw e; + } + + // Build finished message + statusMsg = MessageFormat.format(ManagedMakeBuilder_message_finished, getProject().getName()); + monitor.subTask(statusMsg); + } + + /* (non-Javadoc) + * + * @return + */ + private Vector getGenerationProblems() { + if (generationProblems == null) { + generationProblems = new Vector<>(); + } + return generationProblems; + } + + /* (non-javadoc) + * Answers an array of strings with the proper make targets + * for a build with no custom prebuild/postbuild steps + * + * @param fullBuild + * @return + */ + protected String[] getMakeTargets(int buildType) { + List args = new ArrayList<>(); + switch (buildType) { + case CLEAN_BUILD: + args.add("clean"); //$NON-NLS-1$ + break; + case FULL_BUILD: + case INCREMENTAL_BUILD: + args.add("all"); //$NON-NLS-1$ + break; + } + return args.toArray(new String[args.size()]); + } + + protected List getResourcesToBuild() { + if (resourcesToBuild == null) { + resourcesToBuild = new ArrayList<>(); + } + return resourcesToBuild; + } + + /* (non-Javadoc) + * @see org.eclipse.cdt.core.resources.ACBuilder#getWorkingDirectory() + */ + public IPath getWorkingDirectory() { + return getProject().getLocation(); + } + + /* (non-Javadoc) + * @param delta + * @param info + * @param monitor + * @throws CoreException + */ + protected void incrementalBuild(IResourceDelta delta, IManagedBuildInfo info, + IManagedBuilderMakefileGenerator generator, IProgressMonitor monitor) throws CoreException { + // Need to report status to the user + if (monitor == null) { + monitor = new NullProgressMonitor(); + } + + // Ask the makefile generator to generate any makefiles needed to build delta + checkCancel(monitor); + String statusMsg = MessageFormat.format(ManagedMakeBuilder_message_update_makefiles, getProject().getName()); + monitor.subTask(statusMsg); + MultiStatus result = generator.generateMakefiles(delta); + if (result.getCode() == IStatus.WARNING || result.getCode() == IStatus.INFO) { + IStatus[] kids = result.getChildren(); + for (int index = 0; index < kids.length; ++index) { + // One possibility is that there is nothing to build + IStatus status = kids[index]; + if (status.getCode() == IManagedBuilderMakefileGenerator.NO_SOURCE_FOLDERS) { + // Inform the user, via the console, that there is nothing to build + // either because there are no buildable sources files or all potentially + // buildable files have been excluded from build + try { + emitNoSourceMessage(INCREMENTAL_BUILD, status, info.getConfigurationName()); + } catch (CoreException e) { + // Throw the exception back to the builder + throw e; + } + // Dude, we're done + return; + } else { + // Stick this in the list of stuff to warn the user about + getGenerationProblems().add(status); + } + } + } + + // Run the build + checkCancel(monitor); + statusMsg = MessageFormat.format(ManagedMakeBuilder_message_starting, getProject().getName()); + monitor.subTask(statusMsg); + IPath buildDir = generator.getBuildWorkingDir(); + if (buildDir != null) { + invokeMake(INCREMENTAL_BUILD, buildDir, info, generator, monitor); + } else { + statusMsg = MessageFormat.format(ManagedMakeBuilder_message_no_build, getProject().getName()); + monitor.subTask(statusMsg); + return; + } + + // Generate the dependencies for all changes + checkCancel(monitor); + statusMsg = MessageFormat.format(ManagedMakeBuilder_message_updating_deps, getProject().getName()); + monitor.subTask(statusMsg); + try { + generator.generateDependencies(); + } catch (CoreException e) { + throw e; + } + + // Build finished message + statusMsg = MessageFormat.format(ManagedMakeBuilder_message_finished, getProject().getName()); + monitor.subTask(statusMsg); + } + + /* (non-Javadoc) + * @param buildType + * @param buildDir + * @param info + * @param generator + * @param monitor + */ + protected void invokeMake(int buildType, IPath buildDir, IManagedBuildInfo info, + IManagedBuilderMakefileGenerator generator, IProgressMonitor monitor) { + // Get the project and make sure there's a monitor to cancel the build + IProject project = getProject(); + if (monitor == null) { + monitor = new NullProgressMonitor(); + } + + try { + // Figure out the working directory for the build and make sure there is a makefile there + final URI workingDirectoryURI = getProject().getFolder(buildDir).getLocationURI(); + final String pathFromURI = EFSExtensionManager.getDefault().getPathFromURI(workingDirectoryURI); + if (pathFromURI == null) { + throw new CoreException( + new Status(IStatus.ERROR, Activator.getId(), ManagedMakeBuilder_message_error, null)); + } + + IPath workingDirectory = new Path(pathFromURI); + + IWorkspace workspace = project.getWorkspace(); + if (workspace == null) { + return; + } + IWorkspaceRoot root = workspace.getRoot(); + if (root == null) { + return; + } + IPath makefile = workingDirectory.append(generator.getMakefileName()); + if (root.getFileForLocation(makefile) == null) { + return; + } + + // Flag to the user that make is about to be called + String makeCmd = info.getBuildCommand(); + //try to resolve the build macros in the builder command + try { + String resolved = ManagedBuildManager.getBuildMacroProvider().resolveValueToMakefileFormat(makeCmd, "", //$NON-NLS-1$ + " ", //$NON-NLS-1$ + IBuildMacroProvider.CONTEXT_CONFIGURATION, info.getDefaultConfiguration()); + if ((resolved = resolved.trim()).length() > 0) + makeCmd = resolved; + } catch (BuildMacroException e) { + } + + IPath makeCommand = new Path(makeCmd); + String[] msgs = new String[2]; + msgs[0] = makeCommand.toString(); + msgs[1] = project.getName(); + monitor.subTask(MessageFormat.format(ManagedMakeBuilder_message_make, msgs)); + + // Get a build console for the project + StringBuilder buf = new StringBuilder(); + IConsole console = CCorePlugin.getDefault().getConsole(); + console.start(project); + ConsoleOutputStream consoleOutStream = console.getOutputStream(); + String[] consoleHeader = new String[3]; + switch (buildType) { + case FULL_BUILD: + case INCREMENTAL_BUILD: + consoleHeader[0] = ManagedMakeBuider_type_incremental; + break; + case CLEAN_BUILD: + consoleHeader[0] = ManagedMakeBuilder_type_clean; + break; + } + + consoleHeader[1] = info.getConfigurationName(); + consoleHeader[2] = project.getName(); + buf.append(NEWLINE); + buf.append(MessageFormat.format(ManagedMakeBuilder_message_console_header, consoleHeader)).append(NEWLINE); + buf.append(NEWLINE); + + IConfiguration cfg = info.getDefaultConfiguration(); + if (!cfg.isSupported()) { + String msg = MessageFormat.format(WARNING_UNSUPPORTED_CONFIGURATION, + new String[] { cfg.getName(), cfg.getToolChain().getName() }); + buf.append(msg).append(NEWLINE); + buf.append(NEWLINE); + } + consoleOutStream.write(buf.toString().getBytes()); + consoleOutStream.flush(); + + // Remove all markers for this project + removeAllMarkers(project); + + // Get a launcher for the make command + String errMsg = null; + IBuilder builder = info.getDefaultConfiguration().getBuilder(); + ICommandLauncher launcher = builder.getCommandLauncher(); + launcher.setProject(project); + launcher.showCommand(true); + + // Set the environmennt + IEnvironmentVariable[] variables = ManagedBuildManager.getEnvironmentVariableProvider().getVariables(cfg, + true); + String[] envp = null; + ArrayList envList = new ArrayList<>(); + if (variables != null) { + for (int i = 0; i < variables.length; i++) { + envList.add(variables[i].getName() + "=" + variables[i].getValue()); //$NON-NLS-1$ + } + envp = envList.toArray(new String[envList.size()]); + } + + // Hook up an error parser manager + String[] errorParsers = info.getDefaultConfiguration().getErrorParserList(); + ErrorParserManager epm = new ErrorParserManager(getProject(), workingDirectoryURI, this, errorParsers); + epm.setOutputStream(consoleOutStream); + // This variable is necessary to ensure that the EPM stream stay open + // until we explicitly close it. See bug#123302. + OutputStream epmOutputStream = epm.getOutputStream(); + + // Get the arguments to be passed to make from build model + ArrayList makeArgs = new ArrayList<>(); + String arg = info.getBuildArguments(); + if (arg.length() > 0) { + String[] args = arg.split("\\s"); //$NON-NLS-1$ + for (int i = 0; i < args.length; ++i) { + makeArgs.add(args[i]); + } + } + + String[] makeTargets; + String prebuildStep = info.getPrebuildStep(); + //try to resolve the build macros in the prebuildStep + try { + prebuildStep = ManagedBuildManager.getBuildMacroProvider().resolveValueToMakefileFormat(prebuildStep, + "", //$NON-NLS-1$ + " ", //$NON-NLS-1$ + IBuildMacroProvider.CONTEXT_CONFIGURATION, cfg); + } catch (BuildMacroException e) { + } + boolean prebuildStepPresent = (prebuildStep.length() > 0); + Process proc = null; + boolean isuptodate = false; + + if (prebuildStepPresent) { + @SuppressWarnings("unchecked") + ArrayList premakeArgs = (ArrayList) makeArgs.clone(); + String[] premakeTargets; + switch (buildType) { + case INCREMENTAL_BUILD: { + // For an incremental build with a prebuild step: + // Check the status of the main build with "make -q main-build" + // If up to date: + // then: don't invoke the prebuild step, which should be run only if + // something needs to be built in the main build + // else: invoke the prebuild step and the main build step + premakeArgs.add("-q"); //$NON-NLS-1$ + premakeArgs.add("main-build"); //$NON-NLS-1$ + premakeTargets = premakeArgs.toArray(new String[premakeArgs.size()]); + proc = launcher.execute(makeCommand, premakeTargets, envp, workingDirectory, monitor); + if (proc != null) { + try { + // Close the input of the process since we will never write to it + proc.getOutputStream().close(); + } catch (IOException e) { + } + if (launcher.waitAndRead(epm.getOutputStream(), epm.getOutputStream(), + new SubProgressMonitor(monitor, IProgressMonitor.UNKNOWN)) != ICommandLauncher.OK) { + errMsg = launcher.getErrorMessage(); + } + } else { + errMsg = launcher.getErrorMessage(); + } + + if ((errMsg != null && errMsg.length() > 0) || proc == null) { + // Can't tell if the build is needed, so assume it is, and let any errors be triggered + // when the "real" build is invoked below + makeArgs.add("pre-build"); //$NON-NLS-1$ + makeArgs.add("main-build"); //$NON-NLS-1$ + } else { + // The "make -q" command launch was successful + if (proc.exitValue() == 0) { + // If the status value returned from "make -q" is 0, then the build state is up-to-date + isuptodate = true; + // Report that the build was up to date, and thus nothing needs to be built + String uptodateMsg = MessageFormat.format(ManagedMakeBuilder_message_no_build, + project.getName()); + buf = new StringBuilder(); + buf.append(NEWLINE); + buf.append(uptodateMsg).append(NEWLINE); + // Write message on the console + consoleOutStream.write(buf.toString().getBytes()); + consoleOutStream.flush(); + epmOutputStream.close(); + consoleOutStream.close(); + } else { + // The status value was other than 0, so press on with the build process + makeArgs.add("pre-build"); //$NON-NLS-1$ + makeArgs.add("main-build"); //$NON-NLS-1$ + } + } + break; + } + case FULL_BUILD: { + // makeArgs.add("clean"); //$NON-NLS-1$ + makeArgs.add("pre-build"); //$NON-NLS-1$ + makeArgs.add("main-build"); //$NON-NLS-1$ + break; + } + case CLEAN_BUILD: { + makeArgs.add("clean"); //$NON-NLS-1$ + break; + } + } + + } else { + // No prebuild step + // + makeArgs.addAll(Arrays.asList(getMakeTargets(buildType))); + } + + makeTargets = makeArgs.toArray(new String[makeArgs.size()]); + + // Launch make - main invocation + if (!isuptodate) { + proc = launcher.execute(makeCommand, makeTargets, envp, workingDirectory, monitor); + if (proc != null) { + try { + // Close the input of the process since we will never write to it + proc.getOutputStream().close(); + } catch (IOException e) { + } + + int state = launcher.waitAndRead(epm.getOutputStream(), epm.getOutputStream(), + new SubProgressMonitor(monitor, IProgressMonitor.UNKNOWN)); + if (state != ICommandLauncher.OK) { + errMsg = launcher.getErrorMessage(); + + if (state == ICommandLauncher.COMMAND_CANCELED) { + //TODO: the better way of handling cancel is needed + //currently the rebuild state is set to true forcing the full rebuild + //on the next builder invocation + info.getDefaultConfiguration().setRebuildState(true); + } + } + + // Force a resync of the projects without allowing the user to cancel. + // This is probably unkind, but short of this there is no way to insure + // the UI is up-to-date with the build results + monitor.subTask(ManagedMakeBuilder_message_updating); + try { + //currentProject.refreshLocal(IResource.DEPTH_INFINITE, null); + + // use the refresh scope manager to refresh + RefreshScopeManager refreshManager = RefreshScopeManager.getInstance(); + IWorkspaceRunnable runnable = refreshManager.getRefreshRunnable(project, cfg.getName()); + ResourcesPlugin.getWorkspace().run(runnable, null, IWorkspace.AVOID_UPDATE, null); + } catch (CoreException e) { + monitor.subTask(ManagedMakeBuilder_message_error_refresh); + } + } else { + errMsg = launcher.getErrorMessage(); + } + + // Report either the success or failure of our mission + buf = new StringBuilder(); + if (errMsg != null && errMsg.length() > 0) { + buf.append(errMsg).append(NEWLINE); + } else { + // Report a successful build + String successMsg = MessageFormat.format(ManagedMakeBuilder_message_finished, project.getName()); + buf.append(successMsg).append(NEWLINE); + } + + // Write message on the console + consoleOutStream.write(buf.toString().getBytes()); + consoleOutStream.flush(); + epmOutputStream.close(); + + // Generate any error markers that the build has discovered + monitor.subTask(ManagedMakeBuilder_message_creating_markers); + addBuilderMarkers(epm); + consoleOutStream.close(); + } + } catch (Exception e) { + forgetLastBuiltState(); + } finally { + getGenerationProblems().clear(); + } + } + + /* (non-Javadoc) + * Removes the IMarkers for the project specified in the argument if the + * project exists, and is open. + * + * @param project + */ + @SuppressWarnings("restriction") + private void removeAllMarkers(IProject project) { + if (project == null || !project.isAccessible()) + return; + + // Clear out the problem markers + IWorkspace workspace = project.getWorkspace(); + IMarker[] markers; + try { + markers = project.findMarkers(ICModelMarker.C_MODEL_PROBLEM_MARKER, true, IResource.DEPTH_INFINITE); + } catch (CoreException e) { + // Handled just about every case in the sanity check + return; + } + if (markers != null) { + try { + workspace.deleteMarkers(markers); + FixitManager.getInstance().deleteMarkers(markers); + } catch (CoreException e) { + // The only situation that might cause this is some sort of resource change event + return; + } + } + } + + /** + * called to invoke the MBS Internal Builder for building the given + * configuration + * + * @param cfg + * configuration to be built + * @param buildIncrementaly + * if true, incremental build will be performed, + * only files that need rebuild will be built. + * If false, full rebuild will be performed + * @param resumeOnErr + * if true, build will continue in case of error while building. + * If false the build will stop on the first error + * @param monitor + * monitor + */ + protected void invokeInternalBuilder(IConfiguration cfg, boolean buildIncrementaly, boolean resumeOnErr, + IProgressMonitor monitor) { + + boolean isParallel = ((Configuration) cfg).getParallelDef(); + + // Get the project and make sure there's a monitor to cancel the build + IProject project = cfg.getOwner().getProject(); + IFile buildFolder = project.getFile(cfg.getName()); + if (monitor == null) { + monitor = new NullProgressMonitor(); + } + + String[] msgs = new String[2]; + msgs[0] = ManagedMakeBuilder_message_internal_builder; + msgs[1] = project.getName(); + + ConsoleOutputStream consoleOutStream = null; + IConsole console = null; + OutputStream epmOutputStream = null; + try { + int flags = 0; + IResourceDelta delta = null; + + if (buildIncrementaly) { + // flags = BuildDescriptionManager.REBUILD | BuildDescriptionManager.REMOVED + // | BuildDescriptionManager.DEPS; + delta = getDelta(project); + } + + // IBuildDescription des = BuildDescriptionManager.createBuildDescription(cfg, delta, flags); + + // DescriptionBuilder builder = null; + // if (!isParallel) + // builder = new DescriptionBuilder(des, buildIncrementaly, resumeOnErr, null); + + // Get a build console for the project + StringBuilder buf = new StringBuilder(); + console = CCorePlugin.getDefault().getConsole(); + console.start(project); + consoleOutStream = console.getOutputStream(); + String[] consoleHeader = new String[3]; + if (buildIncrementaly) + consoleHeader[0] = ManagedMakeBuider_type_incremental; + else + consoleHeader[0] = ManagedMakeBuider_type_rebuild; + + consoleHeader[1] = cfg.getName(); + consoleHeader[2] = project.getName(); + buf.append(NEWLINE); + buf.append(MessageFormat.format(ManagedMakeBuilder_message_console_header, consoleHeader)).append(NEWLINE); + buf.append(NEWLINE); + + buf.append(ManagedMakeBuilder_message_internal_builder_header_note); + buf.append("\n"); //$NON-NLS-1$ + + if (!cfg.isSupported()) { + String msg = MessageFormat.format(WARNING_UNSUPPORTED_CONFIGURATION, + new String[] { cfg.getName(), cfg.getToolChain().getName() }); + buf.append(msg).append(NEWLINE); + buf.append(NEWLINE); + } + consoleOutStream.write(buf.toString().getBytes()); + consoleOutStream.flush(); + + //if (isParallel || builder.getNumCommands() > 0) { + if (isParallel) { + // Remove all markers for this project + removeAllMarkers(project); + + // Hook up an error parser manager + String[] errorParsers = cfg.getErrorParserList(); + ErrorParserManager epm = new ErrorParserManager(getProject(), buildFolder.getLocationURI(), this, + errorParsers); + epm.setOutputStream(consoleOutStream); + // This variable is necessary to ensure that the EPM stream stay open + // until we explicitly close it. See bug#123302. + epmOutputStream = epm.getOutputStream(); + + int status = 0; + + long t1 = System.currentTimeMillis(); + // if (isParallel) + // status = ParallelBuilder.build(des, null, null, epmOutputStream, epmOutputStream, monitor, + // resumeOnErr, buildIncrementaly); + // else + // status = builder.build(epmOutputStream, epmOutputStream, monitor); + long t2 = System.currentTimeMillis(); + + // Report either the success or failure of our mission + buf = new StringBuilder(); + + switch (status) { + // case IBuildModelBuilder.STATUS_OK: + // buf.append(MessageFormat.format(ManagedMakeBuilder_message_finished, project.getName())); + // break; + // case IBuildModelBuilder.STATUS_CANCELLED: + // buf.append(ManagedMakeBuilder_message_cancelled); + // break; + // case IBuildModelBuilder.STATUS_ERROR_BUILD: + // String msg = resumeOnErr ? ManagedMakeBuilder_message_finished_with_errs + // : ManagedMakeBuilder_message_stopped_error; + // buf.append(msg); + // break; + // case IBuildModelBuilder.STATUS_ERROR_LAUNCH: + default: + buf.append(ManagedMakeBuilder_message_internal_builder_error); + break; + } + buf.append(NEWLINE); + + // Report time and number of threads used + // buf.append("Time consumed: "); + // buf.append(t2 - t1); + // buf.append(" ms. "); + // if (isParallel) { + // buf.append("Parallel threads used: "); + // buf.append(ParallelBuilder.lastThreadsUsed); + // } + // buf.append("\n"); + + // Report time and number of threads used + buf.append(MessageFormat.format(CommonBuilder_6, Integer.toString((int) (t2 - t1)))); + // buf.append(t2 - t1); + // buf.append(" ms. "); + // if (isParallel) { + // buf.append( + // MessageFormat.format(CommonBuilder_7, Integer.toString(ParallelBuilder.lastThreadsUsed))); + // // buf.append(ParallelBuilder.lastThreadsUsed); + // } + buf.append(NEWLINE); + + // Write message on the console + consoleOutStream.write(buf.toString().getBytes()); + consoleOutStream.flush(); + epmOutputStream.close(); + epmOutputStream = null; + // Generate any error markers that the build has discovered + monitor.subTask(ManagedMakeBuilder_message_creating_markers); + addBuilderMarkers(epm); + } else { + buf = new StringBuilder(); + buf.append(MessageFormat.format(ManagedMakeBuilder_message_no_build, getProject().getName())) + .append(NEWLINE); + consoleOutStream.write(buf.toString().getBytes()); + consoleOutStream.flush(); + } + + } catch (Exception e) { + if (consoleOutStream != null) { + StringBuilder buf = new StringBuilder(); + buf.append(ManagedMakeBuilder_message_error).append(NEWLINE); + buf.append("(").append(e.getLocalizedMessage()).append(")").append(NEWLINE); //$NON-NLS-1$ //$NON-NLS-2$ + + try { + consoleOutStream.write(buf.toString().getBytes()); + consoleOutStream.flush(); + } catch (IOException e1) { + } + } + forgetLastBuiltState(); + } finally { + if (epmOutputStream != null) { + try { + epmOutputStream.close(); + } catch (IOException e) { + } + } + if (consoleOutStream != null) { + try { + consoleOutStream.close(); + } catch (IOException e) { + } + } + getGenerationProblems().clear(); + monitor.done(); + } + } + + private Map> arrangeFilesByProject(List files) { + Map> projectMap = new HashMap<>(); + for (IFile file : files) { + IProject project = file.getProject(); + List filesInProject = projectMap.get(project); + if (filesInProject == null) { + filesInProject = new ArrayList<>(); + projectMap.put(project, filesInProject); + } + filesInProject.add(file); + } + return projectMap; + } + + /** + * Called to invoke the MBS Internal Builder for building the given resources + * + * @param files + * - list of files to build. + * @param monitor + * - progress monitor to report progress to user. + * @return status of the operation. Can be {@link Status#OK_STATUS} or + * {@link Status#CANCEL_STATUS}. + */ + public IStatus invokeInternalBuilder(List files, IProgressMonitor monitor) { + // Make sure there's a monitor to cancel the build + if (monitor == null) { + monitor = new NullProgressMonitor(); + } + + try { + Map> projectMap = arrangeFilesByProject(files); + monitor.beginTask("", projectMap.size() * PROGRESS_MONITOR_SCALE); //$NON-NLS-1$ + + for (List filesInProject : projectMap.values()) { + IProject project = filesInProject.get(0).getProject(); + setCurrentProject(project); + monitor.subTask(MessageFormat.format(GeneratedMakefileBuilder_buildingProject, project.getName())); + invokeInternalBuilderForOneProject(filesInProject, new SubProgressMonitor(monitor, + 1 * PROGRESS_MONITOR_SCALE, SubProgressMonitor.PREPEND_MAIN_LABEL_TO_SUBTASK)); + } + } finally { + if (monitor.isCanceled()) { + return Status.CANCEL_STATUS; + } + monitor.done(); + } + return Status.OK_STATUS; + } + + private void invokeInternalBuilderForOneProject(List files, IProgressMonitor monitor) { + IProject project = files.get(0).getProject(); + BuildRunnerHelper buildRunnerHelper = new BuildRunnerHelper(project); + + try { + monitor.beginTask(MessageFormat.format(GeneratedMakefileBuilder_buildingProject, project.getName()) + ':', + TICKS_STREAM_PROGRESS_MONITOR + files.size() * PROGRESS_MONITOR_SCALE); + + // Get a build console for the project + console = CCorePlugin.getDefault().getConsole(); + console.start(project); + + IManagedBuildInfo buildInfo = ManagedBuildManager.getBuildInfo(project); + IConfiguration configuration = buildInfo.getDefaultConfiguration(); + + String cfgName = configuration.getName(); + String toolchainName = configuration.getToolChain().getName(); + IFile buildFolder = project.getFile(cfgName); + + boolean isSupported = configuration.isSupported(); + + //IBuildDescription des = BuildDescriptionManager.createBuildDescription(configuration, null, 0); + + String[] errorParsers = configuration.getErrorParserList(); + ErrorParserManager epm = new ErrorParserManager(project, buildFolder.getLocationURI(), this, errorParsers); + + buildRunnerHelper.prepareStreams(epm, null, console, + new SubProgressMonitor(monitor, TICKS_STREAM_PROGRESS_MONITOR)); + OutputStream stdout = buildRunnerHelper.getOutputStream(); + OutputStream stderr = buildRunnerHelper.getErrorStream(); + + buildRunnerHelper.greeting(GeneratedMakefileBuilder_buildingSelectedFiles, cfgName, toolchainName, + isSupported); + buildRunnerHelper.printLine(ManagedMakeBuilder_message_internal_builder_header_note); + + // Build artifacts for each file in the project + for (IFile file : files) { + if (monitor.isCanceled()) { + break; + } + String filePath = file.getProjectRelativePath().toString(); + + try { + // IBuildResource buildResource = des.getBuildResource(file); + // + // Set dependentSteps = new HashSet<>(); + // IBuildIOType depTypes[] = buildResource.getDependentIOTypes(); + // for (IBuildIOType btype : depTypes) { + // if (btype != null && btype.getStep() != null) + // dependentSteps.add(btype.getStep()); + // } + + SubProgressMonitor monitor2 = new SubProgressMonitor(monitor, 1 * PROGRESS_MONITOR_SCALE, + SubProgressMonitor.PREPEND_MAIN_LABEL_TO_SUBTASK); + try { + monitor2.beginTask("", TICKS_DELETE_MARKERS + PROGRESS_MONITOR_SCALE); //$NON-NLS-1$ + + // Remove problem markers for the file + monitor2.subTask( + MessageFormat.format(GeneratedMakefileBuilder_removingResourceMarkers, filePath)); + buildRunnerHelper.removeOldMarkers(file, new SubProgressMonitor(monitor2, TICKS_DELETE_MARKERS, + SubProgressMonitor.SUPPRESS_SUBTASK_LABEL)); + + // Build dependent steps + // for (IBuildStep step : dependentSteps) { + // if (monitor2.isCanceled()) { + // break; + // } + // + // monitor2.subTask(filePath); + // StepBuilder stepBuilder = new StepBuilder(step, null); + // stepBuilder.build(stdout, stderr, new SubProgressMonitor(monitor2, + // 1 * PROGRESS_MONITOR_SCALE, SubProgressMonitor.SUPPRESS_SUBTASK_LABEL)); + // + // monitor2.subTask( + // MessageFormat.format(GeneratedMakefileBuilder_refreshingArtifacts, filePath)); + // IBuildIOType[] outputIOTypes = step.getOutputIOTypes(); + // for (IBuildIOType type : outputIOTypes) { + // for (IBuildResource outResource : type.getResources()) { + // IFile outFile = project.getFile(outResource.getLocation()); + // // Refresh the output resource without allowing the user to cancel. + // outFile.refreshLocal(IResource.DEPTH_INFINITE, null); + // } + // } + // } + } finally { + monitor2.done(); + } + + } catch (Exception e) { + Activator + .log(new CoreException(new Status(IStatus.ERROR, Activator.getId(), "CDT Build Error", e))); //$NON-NLS-1$ + } + + } + buildRunnerHelper.close(); + buildRunnerHelper.goodbye(); + + } catch (Exception e) { + Activator.log(new CoreException(new Status(IStatus.ERROR, Activator.getId(), "CDT Build Error", e))); //$NON-NLS-1$ + forgetLastBuiltState(); + } finally { + getGenerationProblems().clear(); + try { + buildRunnerHelper.close(); + } catch (IOException e) { + Activator.log(new CoreException(new Status(IStatus.ERROR, Activator.getId(), "CDT Build Error", e))); //$NON-NLS-1$ + } + monitor.done(); + } + } + + public IStatus cleanFiles(List files, IProgressMonitor monitor) { + // Make sure there's a monitor to cancel the build + if (monitor == null) { + monitor = new NullProgressMonitor(); + } + + try { + Map> projectMap = arrangeFilesByProject(files); + monitor.beginTask("", projectMap.size() * PROGRESS_MONITOR_SCALE); //$NON-NLS-1$ + + for (List filesInProject : projectMap.values()) { + IProject project = filesInProject.get(0).getProject(); + monitor.subTask(MessageFormat.format(GeneratedMakefileBuilder_cleaningProject, project.getName())); + cleanFilesForOneProject(filesInProject, new SubProgressMonitor(monitor, 1 * PROGRESS_MONITOR_SCALE, + SubProgressMonitor.PREPEND_MAIN_LABEL_TO_SUBTASK)); + } + } finally { + if (monitor.isCanceled()) { + return Status.CANCEL_STATUS; + } + monitor.done(); + } + return Status.OK_STATUS; + } + + public void cleanFilesForOneProject(List files, IProgressMonitor monitor) { + IProject project = files.get(0).getProject(); + BuildRunnerHelper buildRunnerHelper = new BuildRunnerHelper(project); + int countDeleted = 0; + + try { + monitor.beginTask(MessageFormat.format(GeneratedMakefileBuilder_cleaningProject, project.getName()) + ':', + TICKS_STREAM_PROGRESS_MONITOR + files.size() * PROGRESS_MONITOR_SCALE); + + // Get a build console for the project + console = CCorePlugin.getDefault().getConsole(); + console.start(project); + + IManagedBuildInfo buildInfo = ManagedBuildManager.getBuildInfo(project); + IConfiguration configuration = buildInfo.getDefaultConfiguration(); + + String cfgName = configuration.getName(); + IFile buildLocation = project.getFile(cfgName); + String toolchainName = configuration.getToolChain().getName(); + boolean isSupported = configuration.isSupported(); + + //int flags = BuildDescriptionManager.REBUILD | BuildDescriptionManager.REMOVED; + IResourceDelta delta = getDelta(project); + + //IBuildDescription des = BuildDescriptionManager.createBuildDescription(configuration, delta, flags); + + String[] errorParsers = configuration.getErrorParserList(); + ErrorParserManager epm = new ErrorParserManager(project, buildLocation.getLocationURI(), this, + errorParsers); + buildRunnerHelper.prepareStreams(epm, null, console, + new SubProgressMonitor(monitor, TICKS_STREAM_PROGRESS_MONITOR)); + + buildRunnerHelper.greeting(GeneratedMakefileBuilder_cleanSelectedFiles, cfgName, toolchainName, + isSupported); + buildRunnerHelper.printLine(ManagedMakeBuilder_message_internal_builder_header_note); + + for (IFile file : files) { + if (monitor.isCanceled()) { + break; + } + String filePath = file.getProjectRelativePath().toString(); + + try { + // IBuildResource buildResource = des.getBuildResource(file); + // if (buildResource != null) { + // Set dependentSteps = new HashSet<>(); + // IBuildIOType depTypes[] = buildResource.getDependentIOTypes(); + // for (IBuildIOType btype : depTypes) { + // if (btype != null && btype.getStep() != null) + // dependentSteps.add(btype.getStep()); + // } + + SubProgressMonitor monitor2 = new SubProgressMonitor(monitor, 1 * PROGRESS_MONITOR_SCALE, + SubProgressMonitor.PREPEND_MAIN_LABEL_TO_SUBTASK); + try { + monitor2.beginTask("", //$NON-NLS-1$ + TICKS_DELETE_MARKERS + PROGRESS_MONITOR_SCALE); + + // Remove problem markers for the file + monitor2.subTask( + MessageFormat.format(GeneratedMakefileBuilder_removingResourceMarkers, filePath)); + buildRunnerHelper.removeOldMarkers(file, new SubProgressMonitor(monitor2, TICKS_DELETE_MARKERS, + SubProgressMonitor.SUPPRESS_SUBTASK_LABEL)); + + // iterate through all build steps + // for (IBuildStep step : dependentSteps) { + // if (monitor2.isCanceled()) { + // break; + // } + // + // monitor2.subTask(filePath); + // // Delete the output resources + // IBuildIOType[] outputIOTypes = step.getOutputIOTypes(); + // + // for (IBuildIOType ioType : outputIOTypes) { + // for (IBuildResource rc : ioType.getResources()) { + // IResource outputFile = project + // .findMember(rc.getFullPath().removeFirstSegments(1)); // strip project name + // if (outputFile != null) { + // outputFile.delete(true, null); + // countDeleted++; + // buildRunnerHelper.printLine( + // MessageFormat.format(GeneratedMakefileBuilder_fileDeleted, + // outputFile.getProjectRelativePath().toString())); + // } + // } + // } + // + // monitor2.worked(1 * PROGRESS_MONITOR_SCALE); + // } + } finally { + monitor2.done(); + } + // } + } catch (Exception e) { + Activator + .log(new CoreException(new Status(IStatus.ERROR, Activator.getId(), "CDT Build Error", e))); //$NON-NLS-1$ + } + + } + if (countDeleted == 0) { + buildRunnerHelper.printLine(GeneratedMakefileBuilder_nothingToClean); + } + buildRunnerHelper.close(); + buildRunnerHelper.goodbye(); + + } catch (Exception e) { + Activator.log(new CoreException(new Status(IStatus.ERROR, Activator.getId(), "CDT Build Error", e))); //$NON-NLS-1$ + } finally { + try { + buildRunnerHelper.close(); + } catch (IOException e) { + Activator.log(new CoreException(new Status(IStatus.ERROR, Activator.getId(), "CDT Build Error", e))); //$NON-NLS-1$ + } + monitor.done(); + } + } +} diff --git a/io.sloeber.ManagedBuild/src/io/sloeber/autoBuild/Internal/HoldsOptions.java b/io.sloeber.ManagedBuild/src/io/sloeber/autoBuild/Internal/HoldsOptions.java new file mode 100644 index 000000000..1627c95cb --- /dev/null +++ b/io.sloeber.ManagedBuild/src/io/sloeber/autoBuild/Internal/HoldsOptions.java @@ -0,0 +1,787 @@ +/******************************************************************************* + * Copyright (c) 2005, 2016 Symbian Ltd and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Symbian Ltd - Initial API and implementation + * Baltasar Belyavsky (Texas Instruments) - [405643] HoldsOptions performance improvements + *******************************************************************************/ +package io.sloeber.autoBuild.Internal; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Vector; + +import org.eclipse.cdt.core.settings.model.ICStorageElement; +//import org.eclipse.cdt.managedbuilder.buildproperties.IBuildPropertyType; +//import org.eclipse.cdt.managedbuilder.buildproperties.IBuildPropertyValue; +//import org.eclipse.cdt.managedbuilder.core.BuildException; +//import org.eclipse.cdt.managedbuilder.core.IBuildPropertiesRestriction; +//import org.eclipse.cdt.managedbuilder.core.IHoldsOptions; +//import org.eclipse.cdt.managedbuilder.core.IManagedConfigElement; +//import org.eclipse.cdt.managedbuilder.core.IOption; +//import org.eclipse.cdt.managedbuilder.core.IOptionCategory; +//import org.eclipse.cdt.managedbuilder.core.IResourceInfo; +//import org.eclipse.cdt.managedbuilder.core.ManagedBuildManager; +//import org.eclipse.cdt.managedbuilder.core.ManagedBuilderCorePlugin; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; + +import io.sloeber.autoBuild.api.BuildException; +import io.sloeber.autoBuild.api.IBuildPropertiesRestriction; +import io.sloeber.autoBuild.api.IBuildPropertyType; +import io.sloeber.autoBuild.api.IBuildPropertyValue; +import io.sloeber.autoBuild.api.IHoldsOptions; +import io.sloeber.autoBuild.api.IManagedConfigElement; +import io.sloeber.autoBuild.api.IOption; +import io.sloeber.autoBuild.api.IOptionCategory; +import io.sloeber.autoBuild.api.IResourceInfo; +import io.sloeber.autoBuild.core.Activator; + +/** + * Implements the functionality that is needed to hold options and option + * categories. In CDT 3.0, the functionality has been moved from ITool and + * Tool to this class. + * + * This class is intended to be used as base class for all MBS grammar + * elements that can hold Options and Option Categories. These are currently + * Tool and ToolChain. + * + * Note that the member superClass must be shared with the + * derived class. This requires to wrap this member by access functions + * in the derived class or frequent casts, because the type of + * superClass + * in HoldsOptions must be IHoldOptions. Further + * note that the member resolved must inherit the value of its + * derived class. This achieved through the constructor. + * + * @since 3.0 + */ +public abstract class HoldsOptions extends BuildObject + implements IHoldsOptions, IBuildPropertiesRestriction, IBuildPropertyChangeListener { + + private static final IOptionCategory[] EMPTY_CATEGORIES = new IOptionCategory[0]; + + // Members that are to be shared with the derived class + protected IHoldsOptions superClass; + // Members that must have the same values on creation as the derived class + private boolean resolved; + // Parent and children + private Vector categoryIds; + private Map categoryMap; + private List childOptionCategories; + private Map optionMap; + // Miscellaneous + private boolean isDirty = false; + private boolean rebuildState; + + /* + * C O N S T R U C T O R S + */ + + @SuppressWarnings("unused") + private HoldsOptions() { + // prevent accidental construction of class without setting up + // resolved + } + + protected HoldsOptions(boolean resolved) { + this.resolved = resolved; + } + + /** + * Copies children of HoldsOptions. Helper function for + * derived constructors. + * + * @param source + * The children of the source will be cloned and added + * to the class itself. + */ + protected void copyChildren(HoldsOptions source) { + + // Note: This function ignores OptionCategories since they should not be + // found on an non-extension tools + + boolean copyIds = id.equals(source.id); + if (source.optionMap != null) { + for (Option option : source.getOptionCollection()) { + int nnn = ManagedBuildManager.getRandomNumber(); + String subId; + String subName; + if (option.getSuperClass() != null) { + subId = copyIds ? option.getId() : option.getSuperClass().getId() + "." + nnn; //$NON-NLS-1$ + subName = option.getSuperClass().getName(); + } else { + subId = copyIds ? option.getId() : option.getId() + "." + nnn; //$NON-NLS-1$ + subName = option.getName(); + } + Option newOption = new Option(this, subId, subName, option); + addOption(newOption); + } + } + + if (copyIds) { + isDirty = source.isDirty; + rebuildState = source.rebuildState; + } + } + + void copyNonoverriddenSettings(HoldsOptions ho) { + if (ho.optionMap == null || ho.optionMap.size() == 0) + return; + + IOption options[] = getOptions(); + for (int i = 0; i < options.length; i++) { + if (!options[i].getParent().equals(ho)) + continue; + + Option option = (Option) options[i]; + int nnn = ManagedBuildManager.getRandomNumber(); + String subId; + String subName; + if (option.getSuperClass() != null) { + subId = option.getSuperClass().getId() + "." + nnn; //$NON-NLS-1$ + subName = option.getSuperClass().getName(); + } else { + subId = option.getId() + "." + nnn; //$NON-NLS-1$ + subName = option.getName(); + } + Option newOption = new Option(this, subId, subName, option); + addOption(newOption); + + } + } + + /* + * E L E M E N T A T T R I B U T E R E A D E R S A N D W R I T E R S + */ + + /** + * Load child element from XML element if it is of the correct type + * + * @param element + * which is loaded as child only iff it is of the correct type + * @return true when a child has been loaded, false otherwise + */ + protected boolean loadChild(ICStorageElement element) { + if (element.getName().equals(IHoldsOptions.OPTION)) { + Option option = new Option(this, element); + addOption(option); + return true; + } else if (element.getName().equals(IHoldsOptions.OPTION_CAT)) { + new OptionCategory(this, element); + return true; + } + return false; + } + + /** + * Load child element from configuration element if it is of the correct type + * + * @param element + * which is loaded as child only iff it is of the correct type + * @return true when a child has been loaded, false otherwise + */ + protected boolean loadChild(IManagedConfigElement element) { + if (element.getName().equals(IHoldsOptions.OPTION)) { + Option option = new Option(this, element); + addOption(option); + return true; + } else if (element.getName().equals(IHoldsOptions.OPTION_CAT)) { + new OptionCategory(this, element); + return true; + } + return false; + } + + /** + * Persist the tool to the XML storage element. Intended to be called by derived + * class only, thus do not handle exceptions. + * + * @param element + * where to serialize the tool + */ + protected void serialize(ICStorageElement element) throws BuildException { + if (childOptionCategories != null) { + for (IOptionCategory optCat : childOptionCategories) { + ICStorageElement optCatElement = element.createChild(OPTION); + ((OptionCategory) optCat).serialize(optCatElement); + } + } + + Collection