/******************************************************************************* * Copyright (c) 2005, 2011 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 * Miwako Tokugawa (Intel Corporation) - bug 222817 (OptionCategoryApplicability) *******************************************************************************/ package org.eclipse.cdt.managedbuilder.internal.macros; import java.util.ArrayList; import java.util.List; 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.IResourceConfiguration; 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.internal.core.Tool; import org.eclipse.cdt.managedbuilder.macros.BuildMacroException; import org.eclipse.cdt.managedbuilder.macros.IBuildMacro; import org.eclipse.cdt.managedbuilder.macros.IBuildMacroProvider; import org.eclipse.cdt.managedbuilder.macros.IBuildMacroSupplier; import org.eclipse.cdt.utils.cdtvariables.CdtVariableResolver; import org.eclipse.cdt.utils.cdtvariables.ICdtVariableSupplier; import org.eclipse.cdt.utils.cdtvariables.IVariableSubstitutor; import org.eclipse.cdt.utils.cdtvariables.SupplierBasedCdtVariableManager; import org.eclipse.cdt.utils.cdtvariables.SupplierBasedCdtVariableSubstitutor; import org.eclipse.core.variables.IDynamicVariable; import org.eclipse.core.variables.IStringVariable; /** * The default IBuildMacroProvider implementation * @since 3.0 */ public class BuildMacroProvider implements IBuildMacroProvider, IMacroContextInfoProvider { private static final String PATTERN_MACRO_NAME = "="; //$NON-NLS-1$ static private BuildMacroProvider fDefault; public static MbsMacroSupplier fMbsMacroSupplier = MbsMacroSupplier.getInstance(); protected BuildMacroProvider(){ } public static BuildMacroProvider getDefault(){ if(fDefault == null) fDefault = new BuildMacroProvider(); return fDefault; } /* (non-Javadoc) * @see org.eclipse.cdt.managedbuilder.macros.IBuildMacroProvider#getMacro(java.lang.String, int, java.lang.Object, boolean) */ @Override public IBuildMacro getMacro(String macroName, int contextType, Object contextData, boolean includeParentContexts) { ICdtVariable var = getVariable(macroName, contextType, contextData, includeParentContexts); if(var != null) return wrap(var); return null; } /* (non-Javadoc) * @see org.eclipse.cdt.managedbuilder.macros.IBuildMacroProvider#getMacros(int, java.lang.Object, boolean) */ @Override public IBuildMacro[] getMacros(int contextType, Object contextData, boolean includeParentContexts) { ICdtVariable[] vars = getVariables(contextType, contextData, includeParentContexts); if(vars != null) return wrap(vars); return null; } public static CoreMacrosSupplier createCoreSupplier(IConfiguration cfg){ ICConfigurationDescription cfgDes = ManagedBuildManager.getDescriptionForConfiguration(cfg); if(cfgDes != null){ return new CoreMacrosSupplier(cfgDes); } return null; } @Override public ICdtVariable getVariable(String macroName, int contextType, Object contextData, boolean includeParentContexts) { return SupplierBasedCdtVariableManager.getVariable(macroName, getMacroContextInfo(contextType,contextData),includeParentContexts); } @Override public ICdtVariable[] getVariables(int contextType, Object contextData, boolean includeParentContexts) { return SupplierBasedCdtVariableManager.getVariables(getMacroContextInfo(contextType,contextData),includeParentContexts); } /* (non-Javadoc) * @see org.eclipse.cdt.managedbuilder.macros.IBuildMacroProvider#getSuppliers(int, java.lang.Object) */ @Override public IBuildMacroSupplier[] getSuppliers(int contextType, Object contextData) { IMacroContextInfo info = getMacroContextInfo(contextType,contextData); if(info != null){ ICdtVariableSupplier suppliers[] = info.getSuppliers(); if(suppliers != null) return filterMacroSuppliers(suppliers); } return null; } private static IBuildMacroSupplier[] filterMacroSuppliers(ICdtVariableSupplier suppliers[]){ List<ICdtVariableSupplier> list = new ArrayList<ICdtVariableSupplier>(suppliers.length); for(int i = 0; i < suppliers.length; i++){ if(suppliers[i] instanceof IBuildMacroSupplier) list.add(suppliers[i]); } return list.toArray(new IBuildMacroSupplier[list.size()]); } @Override public IMacroContextInfo getMacroContextInfo( int contextType, Object contextData){ DefaultMacroContextInfo info = new DefaultMacroContextInfo(contextType,contextData); if(info.getSuppliers() != null) return info; return null; } /* (non-Javadoc) * @see org.eclipse.cdt.managedbuilder.macros.IBuildMacroProvider#convertStringListToString(java.lang.String[], java.lang.String) */ @Override public String convertStringListToString(String[] value, String listDelimiter) { return CdtVariableResolver.convertStringListToString(value,listDelimiter); } private static class VariableWrapper implements IBuildMacro { private ICdtVariable fVariable; public VariableWrapper(ICdtVariable var){ if(var == null) throw new NullPointerException(); fVariable = var; } // public ICdtVariable getVariable(){ // return fVariable; // } @Override public int getMacroValueType() { return fVariable.getValueType(); } @Override public String[] getStringListValue() throws BuildMacroException { try { return fVariable.getStringListValue(); } catch (CdtVariableException e) { throw new BuildMacroException(e); } } @Override public String getStringValue() throws BuildMacroException { try { return fVariable.getStringValue(); } catch (CdtVariableException e) { throw new BuildMacroException(e); } } @Override public String getName() { return fVariable.getName(); } @Override public int getValueType() { return fVariable.getValueType(); } } public static IBuildMacro wrap(ICdtVariable var){ if(var == null) return null; if(var instanceof IBuildMacro) return (IBuildMacro)var; return new VariableWrapper(var); } public static IBuildMacro[] wrap(ICdtVariable vars[]){ if(vars instanceof IBuildMacro[]) return (IBuildMacro[])vars; IBuildMacro macros[] = new IBuildMacro[vars.length]; for(int i = 0; i < macros.length; i++){ macros[i] = wrap(vars[i]); } return macros; } /* (non-Javadoc) * @see org.eclipse.cdt.managedbuilder.macros.IBuildMacroProvider#resolveValue(java.lang.String, java.lang.String, java.lang.String, int, java.lang.Object) */ @Override public String resolveValue(String value, String nonexistentMacrosValue, String listDelimiter, int contextType, Object contextData) throws BuildMacroException { IMacroContextInfo info = getMacroContextInfo(contextType,contextData); if(info != null){ try { return CdtVariableResolver.resolveToString(value, getMacroSubstitutor(info,nonexistentMacrosValue, listDelimiter)); } catch (CdtVariableException e) { throw new BuildMacroException(e); } } return value; } /* (non-Javadoc) * @see org.eclipse.cdt.managedbuilder.macros.IBuildMacroProvider#resolveStringListValue(java.lang.String, java.lang.String, int, java.lang.Object) */ @Override public String[] resolveStringListValue(String value, String nonexistentMacrosValue, String listDelimiter, int contextType, Object contextData) throws BuildMacroException { IMacroContextInfo info = getMacroContextInfo(contextType,contextData); if(info != null){ try { return CdtVariableResolver.resolveToStringList(value,getMacroSubstitutor(info,nonexistentMacrosValue, listDelimiter)); } catch (CdtVariableException e) { throw new BuildMacroException(e); } } return null; } /* (non-Javadoc) * @see org.eclipse.cdt.managedbuilder.macros.IBuildMacroProvider#resolveValueToMakefileFormat(java.lang.String, java.lang.String, java.lang.String, int, java.lang.Object) */ @Override public String resolveValueToMakefileFormat(String value, String nonexistentMacrosValue, String listDelimiter, int contextType, Object contextData) throws BuildMacroException { IMacroContextInfo info = getMacroContextInfo(contextType,contextData); if(info != null){ try { return CdtVariableResolver.resolveToString(value, getBuildfileMacroSubstitutor(info,nonexistentMacrosValue, listDelimiter)); } catch (CdtVariableException e) { throw new BuildMacroException(e); } } return null; } /* (non-Javadoc) * @see org.eclipse.cdt.managedbuilder.macros.IBuildMacroProvider#resolveStringListValueToMakefileFormat(java.lang.String, java.lang.String, int, java.lang.Object) */ @Override public String[] resolveStringListValueToMakefileFormat(String value, String nonexistentMacrosValue, String listDelimiter, int contextType, Object contextData) throws BuildMacroException { IMacroContextInfo info = getMacroContextInfo(contextType,contextData); if(info != null){ try { return CdtVariableResolver.resolveToStringList(value,getBuildfileMacroSubstitutor(info,nonexistentMacrosValue, listDelimiter)); } catch (CdtVariableException e) { throw new BuildMacroException(e); } } return null; } /* (non-Javadoc) * @see org.eclipse.cdt.managedbuilder.macros.IBuildMacroProvider#isStringListValue(java.lang.String) */ @Override public boolean isStringListValue(String value, int contextType, Object contextData) throws BuildMacroException { try { CdtVariableResolver.resolveToStringList(value,getMacroSubstitutor(getMacroContextInfo(contextType,contextData)," ",null)); //$NON-NLS-1$ }catch(CdtVariableException e){ return false; } return true; } /* (non-Javadoc) * @see org.eclipse.cdt.managedbuilder.macros.IBuildMacroProvider#checkIntegrity(int, java.lang.Object) */ @Override public void checkIntegrity(int contextType, Object contextData) throws BuildMacroException { final ICdtVariableManager mngr = CCorePlugin.getDefault().getCdtVariableManager(); IMacroContextInfo info = getMacroContextInfo(contextType,contextData); IVariableSubstitutor subst = new SupplierBasedCdtVariableSubstitutor(info,null,""){ //$NON-NLS-1$ @Override protected ResolvedMacro resolveMacro(ICdtVariable macro) throws CdtVariableException { IStringVariable var = mngr.toEclipseVariable(macro, null); if(var instanceof IDynamicVariable) return new ResolvedMacro(macro.getName(),""); //$NON-NLS-1$ return super.resolveMacro(macro); } }; if(info != null){ try { CdtVariableResolver.checkIntegrity(info,subst); } catch (CdtVariableException e) { throw new BuildMacroException(e); } } } public SupplierBasedCdtVariableSubstitutor getMacroSubstitutor(IMacroContextInfo info, String inexistentMacroValue, String listDelimiter){ return new SupplierBasedCdtVariableSubstitutor(info, inexistentMacroValue, listDelimiter); } public IVariableSubstitutor getBuildfileMacroSubstitutor(IMacroContextInfo info, String inexistentMacroValue, String listDelimiter){ return new BuildfileMacroSubstitutor(info, inexistentMacroValue, listDelimiter); } /** * @return whether the environment macros are to be expanded in the buildfile */ public boolean areMacrosExpandedInBuildfile(IConfiguration cfg){ IBuilder builder = cfg.getBuilder(); boolean expanded = !builder.keepEnvironmentVariablesInBuildfile(); if(expanded || canKeepMacrosInBuildfile(cfg)) return expanded; return true; } /** * sets whether the environment macros are to be expanded in the buildfile or not * If a builder does not support treating environment variables as its own ones this method * has no effect * Returns the result of this set operation. That is whether the environment macros are to be expanded in the buildfile * * @return whether the environment macros are to be expanded in the buildfile */ public boolean expandMacrosInBuildfile(IConfiguration cfg, boolean expand){ if(expand || canKeepMacrosInBuildfile(cfg)){ IBuilder builder = cfg.getEditableBuilder(); builder.setKeepEnvironmentVariablesInBuildfile(!expand); return expand; } return true; } /* (non-Javadoc) * @see org.eclipse.cdt.managedbuilder.macros.IBuildMacroProvider#resolveStringListValues(java.lang.String[], java.lang.String, java.lang.String, int, java.lang.Object) */ @Override public String[] resolveStringListValues(String[] value, String nonexistentMacrosValue, String listDelimiter, int contextType, Object contextData) throws BuildMacroException { IMacroContextInfo info = getMacroContextInfo(contextType,contextData); if(info != null){ try { return CdtVariableResolver.resolveStringListValues(value, getMacroSubstitutor(info,nonexistentMacrosValue, listDelimiter), true); } catch (CdtVariableException e) { throw new BuildMacroException(e); } } return null; } /* (non-Javadoc) * @see org.eclipse.cdt.managedbuilder.macros.IBuildMacroProvider#resolveStringListValuesToMakefileFormat(java.lang.String[], java.lang.String, java.lang.String, int, java.lang.Object) */ @Override public String[] resolveStringListValuesToMakefileFormat(String[] value, String nonexistentMacrosValue, String listDelimiter, int contextType, Object contextData) throws BuildMacroException { IMacroContextInfo info = getMacroContextInfo(contextType,contextData); if(info != null){ try { return CdtVariableResolver.resolveStringListValues(value, getBuildfileMacroSubstitutor(info,nonexistentMacrosValue, listDelimiter), true); } catch (CdtVariableException e) { throw new BuildMacroException(e); } } return null; } /** * @return whether the builder used for the given configuration is capable * of handling macros in the buildfile */ public static boolean canKeepMacrosInBuildfile(IConfiguration cfg){ if(cfg != null){ IToolChain toolChain = cfg.getToolChain(); if(toolChain != null) return canKeepMacrosInBuildfile(toolChain.getBuilder()); } return false; } /** * @return whether the given builder is capable * of handling macros in the buildfile */ public static boolean canKeepMacrosInBuildfile(IBuilder builder){ if(builder != null){ String pattern = builder.getBuilderVariablePattern(); if(pattern != null && pattern.indexOf(PATTERN_MACRO_NAME) != -1) return true; } return false; } /** * creates a macro reference in the buildfile format for the given builder. * If the builder can not treat macros, returns null */ public static String createBuildfileMacroReference(String name, IBuilder builder){ String ref = null; if(builder != null){ String pattern = builder.getBuilderVariablePattern(); if(pattern != null && pattern.indexOf(PATTERN_MACRO_NAME) != -1) ref = pattern.replaceAll(PATTERN_MACRO_NAME,name); } return ref; } /** * creates a macro reference in the buildfile format for the builder used for * the given configuration. * If the builder can not treat macros, returns null */ public static String createBuildfileMacroReference(String name, IConfiguration cfg){ String ref = null; if(cfg != null){ IToolChain toolChain = cfg.getToolChain(); if(toolChain != null) ref = createBuildfileMacroReference(name,toolChain.getBuilder()); } return ref; } /** * @return the array of the explicit file macros, referenced in the tool's options * (Explicit file macros are the file-specific macros, whose values are not provided * by the tool-integrator. As a result these macros contain explicit values, but not the values * specified in the format of the builder automatic variables and text functions) */ public static IBuildMacro[] getReferencedExplitFileMacros(ITool tool){ if(tool instanceof Tool){ Tool t = (Tool)tool; ExplicitFileMacroCollector collector = new ExplicitFileMacroCollector(null); t.getToolCommandFlags(null,null,collector, getDefault()); return collector.getExplicisFileMacros(); } return new IBuildMacro[0]; } static IConfiguration getConfiguration(ITool tool){ IBuildObject bo = tool.getParent(); if(bo instanceof IResourceConfiguration) return ((IResourceConfiguration)bo).getParent(); else if (bo instanceof IToolChain) return ((IToolChain)bo).getParent(); return null; } /** * @return the array of the explicit file macros, referenced in the given string * (Explicit file macros are the file-specific macros, whose values are not provided * by the tool-integrator. As a result these macros contain explicit values, but not the values * specified in the format of the builder automatic variables and text functions) */ public static IBuildMacro[] getReferencedExplitFileMacros(String expression, int contextType, Object contextData){ ExplicitFileMacroCollector collector = new ExplicitFileMacroCollector(getDefault().getMacroContextInfo(contextType, contextData)); try { CdtVariableResolver.resolveToString(expression,collector); } catch (CdtVariableException e){ } return collector.getExplicisFileMacros(); } }