/******************************************************************************* * Copyright (c) 2006, 2016 Intel Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Intel Corporation - Initial API and implementation * IBM Corporation *******************************************************************************/ package org.eclipse.cdt.managedbuilder.makegen.gnu; 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.IManagedCommandLineGenerator; import org.eclipse.cdt.managedbuilder.core.IManagedCommandLineInfo; import org.eclipse.cdt.managedbuilder.core.IResourceConfiguration; 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.IManagedBuilderMakefileGenerator; import org.eclipse.cdt.managedbuilder.makegen.IManagedDependencyCommands; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResource; import org.eclipse.core.runtime.IPath; /** * This dependency calculator uses the same dependency management technique as the * DefaultGCCDependencyCalculator. That is: * * 1. An echo command creates the dependency file (.d). * 2. A second invocation of the compiler is made in order to append to the dependency file. * The additional options -MM -MG -P -w are added to the command line. * 3. The dependency files are post-processed to add the empty header rules. * * This class is used with DefaultGCCDependencyCalculator3. * * This is an example dependency calculator that is not used by the CDT GCC tool-chain. * * @since 3.1 * @noextend This class is not intended to be subclassed by clients. * @noinstantiate This class is not intended to be instantiated by clients. */ public class DefaultGCCDependencyCalculator3Commands implements IManagedDependencyCommands { private static final String EMPTY_STRING = ""; //$NON-NLS-1$ // Member variables set by the constructor IPath source; IResource resource; IBuildObject buildContext; ITool tool; IPath topBuildDirectory; // Other Member variables IProject project; IConfiguration config; private IResourceInfo resInfo; IPath sourceLocation; IPath outputLocation; boolean needExplicitRuleForFile; boolean genericCommands = true; /** * Constructor * * @param source The source file for which dependencies should be calculated * The IPath can be either relative to the project directory, or absolute in the file system. * @param buildContext The IConfiguration or IResourceConfiguration that * contains the context in which the source file will be built * @param tool The tool associated with the source file * @param topBuildDirectory The top build directory of the configuration. This is * the working directory for the tool. This IPath is relative to the project directory. */ public DefaultGCCDependencyCalculator3Commands(IPath source, IResource resource, IBuildObject buildContext, ITool tool, IPath topBuildDirectory) { this.source = source; this.resource = resource; this.buildContext = buildContext; this.tool = tool; this.topBuildDirectory = topBuildDirectory; // Compute the project if (buildContext instanceof IConfiguration) { config = (IConfiguration)buildContext; resInfo = config.getRootFolderInfo(); project = (IProject)config.getOwner(); } else if (buildContext instanceof IResourceInfo) { resInfo = (IResourceInfo)buildContext; config = resInfo.getParent(); project = (IProject)config.getOwner(); } sourceLocation = (source.isAbsolute() ? source : project.getLocation().append(source)); outputLocation = project.getLocation().append(topBuildDirectory).append(getDependencyFiles()[0]); // 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 = true; if(resource != null) { resourceNameRequiresExplicitRule = (resource.isLinked() && GnuMakefileGenerator .containsSpecialCharacters(sourceLocation.toString())) || (!resource.isLinked() && GnuMakefileGenerator .containsSpecialCharacters(resource.getProjectRelativePath().toString())); } needExplicitRuleForFile = resourceNameRequiresExplicitRule || BuildMacroProvider.getReferencedExplitFileMacros(tool).length > 0 || BuildMacroProvider.getReferencedExplitFileMacros( tool.getToolCommand(), IBuildMacroProvider.CONTEXT_FILE, new FileContextData(sourceLocation, outputLocation, null, tool)).length > 0; if (buildContext instanceof IResourceConfiguration || needExplicitRuleForFile) genericCommands = false; } /** * Constructor. This constructor calls * DefaultGCCDependencyCalculator3Commands(IPath source, IResource resource, * IBuildObject buildContext, ITool tool, IPath topBuildDirectory) with a * null resource. The net result of this is that dependency rules will * always be explicit and will never use pattern rules, as it is impossible * for the calculator to know whether the resource is linked or not. * * @param source * The source file for which dependencies should be calculated * The IPath can be either relative to the project directory, or * absolute in the file system. * @param buildContext * The IConfiguration or IResourceConfiguration that contains the * context in which the source file will be built * @param tool * The tool associated with the source file * @param topBuildDirectory * The top build directory of the configuration. This is the * working directory for the tool. This IPath is relative to the * project directory. * * @see #DefaultGCCDependencyCalculator3Commands(IPath source, IResource resource, IBuildObject buildContext, ITool tool, IPath topBuildDirectory) */ public DefaultGCCDependencyCalculator3Commands(IPath source, IBuildObject buildContext, ITool tool, IPath topBuildDirectory) { this(source, (IResource) null, buildContext, tool, topBuildDirectory); } /* * (non-Javadoc) * @see org.eclipse.cdt.managedbuilder.makegen.IManagedDependencyCommands#areCommandsGeneric() */ @Override public boolean areCommandsGeneric() { return genericCommands; } /* * (non-Javadoc) * @see org.eclipse.cdt.managedbuilder.makegen.IManagedDependencyCommands#getDependencyCommandOptions() */ @Override public String[] getDependencyCommandOptions() { // Nothing return null; } /* * (non-Javadoc) * @see org.eclipse.cdt.managedbuilder.makegen.IManagedDependencyCommands#getDependencyFiles() */ @Override public IPath[] getDependencyFiles() { // The source file is project relative and the dependency file is top build directory relative // Remove the source extension and add the dependency extension IPath depFilePath = source.removeFileExtension().addFileExtension(IManagedBuilderMakefileGenerator.DEP_EXT); // Remember that the source folder hierarchy and the build output folder hierarchy are the same // but if this is a generated resource, then it may already be under the top build directory if (!depFilePath.isAbsolute()) { if (topBuildDirectory.isPrefixOf(depFilePath)) { depFilePath = depFilePath.removeFirstSegments(1); } } IPath[] paths = new IPath[1]; paths[0] = depFilePath; return paths; } /* * (non-Javadoc) * @see org.eclipse.cdt.managedbuilder.makegen.IManagedDependencyCommands#getPostToolDependencyCommands() */ @Override public String[] getPostToolDependencyCommands() { /* * For a given input, <path>/<resource_name>.<ext>, return a string containing * echo -n $(@:%.<out_ext>=%.d) '<path>/' >> $(@:%.<out_ext>=%.d) && \ * <tool_command> -P -MM -MG <tool_flags> $< >> $(@:%.<out_ext>=%.d) * */ String[] commands = new String[2]; // Get what we need to create the dependency generation command String inputExtension = source.getFileExtension(); String outputExtension = tool.getOutputExtension(inputExtension); // Calculate the dependency rule // <path>/$(@:%.<out_ext>=%.d) String depRule = "'$(@:%." + //$NON-NLS-1$ outputExtension + "=%." + //$NON-NLS-1$ IManagedBuilderMakefileGenerator.DEP_EXT + ")'"; //$NON-NLS-1$ // Add the Echo command that will actually create the right format for the dep commands[0] = IManagedBuilderMakefileGenerator.TAB + IManagedBuilderMakefileGenerator.ECHO + IManagedBuilderMakefileGenerator.WHITESPACE + "-n" + //$NON-NLS-1$ IManagedBuilderMakefileGenerator.WHITESPACE + depRule + IManagedBuilderMakefileGenerator.WHITESPACE + "$(dir $@)" + //$NON-NLS-1$ IManagedBuilderMakefileGenerator.WHITESPACE + ">" + //$NON-NLS-1$ IManagedBuilderMakefileGenerator.WHITESPACE + depRule; // Add the line that will do the work to calculate dependencies IBuildMacroProvider provider = ManagedBuildManager.getBuildMacroProvider(); IManagedCommandLineInfo cmdLInfo = null; String buildCmd = null; String[] inputs= new String[1]; inputs[0] = IManagedBuilderMakefileGenerator.IN_MACRO; String outputFile = ""; //$NON-NLS-1$ String outflag = ""; //$NON-NLS-1$ String outputPrefix = ""; //$NON-NLS-1$ String cmd = tool.getToolCommand(); //try to resolve the build macros in the tool command try { String resolvedCommand = null; if (!needExplicitRuleForFile) { resolvedCommand = provider.resolveValueToMakefileFormat( cmd, EMPTY_STRING, IManagedBuilderMakefileGenerator.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( cmd, EMPTY_STRING, IManagedBuilderMakefileGenerator.WHITESPACE, IBuildMacroProvider.CONTEXT_FILE, new FileContextData(sourceLocation, outputLocation, null, tool)); } if((resolvedCommand = resolvedCommand.trim()).length() > 0) cmd = resolvedCommand; } catch (BuildMacroException e){ } String[] toolFlags = null; try { toolFlags = tool.getToolCommandFlags(sourceLocation, outputLocation); } catch( BuildException ex ) { toolFlags = new String[0]; } String[] flags = new String[toolFlags.length + 4]; flags[0] = "-MM"; //$NON-NLS-1$ flags[1] = "-MG"; //$NON-NLS-1$ flags[2] = "-P"; //$NON-NLS-1$ flags[3] = "-w"; //$NON-NLS-1$ for (int i=0; i<toolFlags.length; i++) { flags[4+i] = toolFlags[i]; } IManagedCommandLineGenerator cmdLGen = tool.getCommandLineGenerator(); cmdLInfo = cmdLGen.generateCommandLineInfo( tool, cmd, flags, outflag, outputPrefix, outputFile, inputs, tool.getCommandLinePattern() ); // The command to build buildCmd = cmdLInfo.getCommandLine(); // resolve any remaining macros in the command after it has been generated try { String resolvedCommand = null; if (!needExplicitRuleForFile) { resolvedCommand = provider.resolveValueToMakefileFormat( buildCmd, EMPTY_STRING, IManagedBuilderMakefileGenerator.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, IManagedBuilderMakefileGenerator.WHITESPACE, IBuildMacroProvider.CONTEXT_FILE, new FileContextData(sourceLocation, outputLocation, null, tool)); } if((resolvedCommand = resolvedCommand.trim()).length() > 0) buildCmd = resolvedCommand; } catch (BuildMacroException e){ } commands[1] = IManagedBuilderMakefileGenerator.TAB + buildCmd + IManagedBuilderMakefileGenerator.WHITESPACE + ">>" + //$NON-NLS-1$ IManagedBuilderMakefileGenerator.WHITESPACE + depRule; return commands; } /* * (non-Javadoc) * @see org.eclipse.cdt.managedbuilder.makegen.IManagedDependencyCommands#getPreToolDependencyCommands() */ @Override public String[] getPreToolDependencyCommands() { // Nothing return null; } /* * (non-Javadoc) * @see org.eclipse.cdt.managedbuilder.makegen.IManagedDependencyInfo#getBuildContext() */ @Override public IBuildObject getBuildContext() { return buildContext; } /* * (non-Javadoc) * @see org.eclipse.cdt.managedbuilder.makegen.IManagedDependencyInfo#getSource() */ @Override public IPath getSource() { return source; } /* * (non-Javadoc) * @see org.eclipse.cdt.managedbuilder.makegen.IManagedDependencyInfo#getTool() */ @Override public ITool getTool() { return tool; } /* * (non-Javadoc) * @see org.eclipse.cdt.managedbuilder.makegen.IManagedDependencyInfo#getTopBuildDirectory() */ @Override public IPath getTopBuildDirectory() { return topBuildDirectory; } }