diff --git a/build/org.eclipse.cdt.make.core/src/org/eclipse/cdt/make/internal/core/scannerconfig/util/CygpathTranslator.java b/build/org.eclipse.cdt.make.core/src/org/eclipse/cdt/make/internal/core/scannerconfig/util/CygpathTranslator.java index 820df07aac7..3dca63cf0c0 100644 --- a/build/org.eclipse.cdt.make.core/src/org/eclipse/cdt/make/internal/core/scannerconfig/util/CygpathTranslator.java +++ b/build/org.eclipse.cdt.make.core/src/org/eclipse/cdt/make/internal/core/scannerconfig/util/CygpathTranslator.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2004, 2011 IBM Corporation and others. + * Copyright (c) 2004, 2013 IBM 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 @@ -20,8 +20,14 @@ import java.util.List; import org.eclipse.cdt.core.CCorePlugin; import org.eclipse.cdt.core.IBinaryParser; +import org.eclipse.cdt.core.envvar.IEnvironmentVariable; +import org.eclipse.cdt.core.envvar.IEnvironmentVariableManager; import org.eclipse.cdt.core.model.CoreModelUtil; import org.eclipse.cdt.core.settings.model.ICConfigExtensionReference; +import org.eclipse.cdt.core.settings.model.ICConfigurationDescription; +import org.eclipse.cdt.core.settings.model.ICProjectDescription; +import org.eclipse.cdt.internal.core.Cygwin; +import org.eclipse.cdt.make.core.MakeCorePlugin; import org.eclipse.cdt.utils.CygPath; import org.eclipse.cdt.utils.ICygwinToolsFactroy; import org.eclipse.core.resources.IProject; @@ -32,125 +38,135 @@ import org.eclipse.core.runtime.Platform; /** * Use binary parser's 'cygpath' command to translate cygpaths to absolute paths. + * Note that this class does not support build configurations. * * @author vhirsl */ public class CygpathTranslator { - /** Default Cygwin root dir */ - private static final String DEFAULT_CYGWIN_ROOT= "C:\\cygwin"; //$NON-NLS-1$ - // private static final String CYGPATH_ERROR_MESSAGE = "CygpathTranslator.NotAvailableErrorMessage"; //$NON-NLS-1$ - private CygPath cygPath = null; - private boolean isAvailable = false; - - public CygpathTranslator(IProject project) { - try { - ICConfigExtensionReference[] parserRef = CCorePlugin.getDefault().getDefaultBinaryParserExtensions(project); - for (int i = 0; i < parserRef.length; i++) { - try { - IBinaryParser parser = CoreModelUtil.getBinaryParser(parserRef[i]); - ICygwinToolsFactroy cygwinToolFactory = (ICygwinToolsFactroy) parser.getAdapter(ICygwinToolsFactroy.class); - if (cygwinToolFactory != null) { - cygPath = cygwinToolFactory.getCygPath(); - if (cygPath != null) { - isAvailable = true; - break; - } - } - } catch (ClassCastException e) { - } - } - // No CygPath specified in BinaryParser page or not supported. - // Hoping that cygpath is on the path. - if (cygPath == null && Platform.getOS().equals(Platform.OS_WIN32)) { - if (new File(DEFAULT_CYGWIN_ROOT).exists()) { - cygPath = new CygPath(DEFAULT_CYGWIN_ROOT + "\\bin\\cygpath.exe"); //$NON-NLS-1$ - } else { - cygPath = new CygPath("cygpath"); //$NON-NLS-1$ - } - isAvailable = cygPath.getFileName("test").equals("test"); //$NON-NLS-1$ //$NON-NLS-2$ - } - } - catch (CoreException e) { - } - catch (IOException e) { - isAvailable = false; - // Removing markers. if cygpath isn't in your path then you aren't using cygwin. - // Then why are we calling this.... -// scMarkerGenerator.addMarker(project, -1, -// MakeMessages.getString(CYGPATH_ERROR_MESSAGE), -// IMarkerGenerator.SEVERITY_WARNING, null); - } - } - - public static List translateIncludePaths(IProject project, List sumIncludes) { - // first check if cygpath translation is needed at all - boolean translationNeeded = false; - if (Platform.getOS().equals(Platform.OS_WIN32)) { - for (Iterator i = sumIncludes.iterator(); i.hasNext(); ) { + private static final String ENV_PATH = "PATH"; //$NON-NLS-1$ + + private CygPath cygPath = null; + + public CygpathTranslator(IProject project) { + try { + ICConfigExtensionReference[] parserRef = CCorePlugin.getDefault().getDefaultBinaryParserExtensions(project); + for (int i = 0; i < parserRef.length; i++) { + try { + IBinaryParser parser = CoreModelUtil.getBinaryParser(parserRef[i]); + ICygwinToolsFactroy cygwinToolFactory = (ICygwinToolsFactroy) parser.getAdapter(ICygwinToolsFactroy.class); + if (cygwinToolFactory != null) { + cygPath = cygwinToolFactory.getCygPath(); + } + } catch (ClassCastException e) { + } + } + } + catch (CoreException e) { + } + } + + public static List translateIncludePaths(IProject project, List sumIncludes) { + // first check if cygpath translation is needed at all + boolean translationNeeded = false; + if (Platform.getOS().equals(Platform.OS_WIN32)) { + for (Iterator i = sumIncludes.iterator(); i.hasNext(); ) { String include = i.next(); if (include.startsWith("/")) { //$NON-NLS-1$ translationNeeded = true; break; } } - } - if (!translationNeeded) { - return sumIncludes; - } - - CygpathTranslator cygpath = new CygpathTranslator(project); - - List translatedIncludePaths = new ArrayList(); - for (Iterator i = sumIncludes.iterator(); i.hasNext(); ) { - String includePath = i.next(); - IPath realPath = new Path(includePath); - // only allow native pathes if they have a device prefix - // to avoid matches on the current drive, e.g. /usr/bin = C:\\usr\\bin - if (realPath.getDevice() != null && realPath.toFile().exists()) { - translatedIncludePaths.add(includePath); - } - else { - String translatedPath = includePath; - if (cygpath.isAvailable) { - try { - translatedPath = cygpath.cygPath.getFileName(includePath); - } - catch (IOException e) { - TraceUtil.outputError("CygpathTranslator unable to translate path: ", includePath); //$NON-NLS-1$ - } - } else if (realPath.segmentCount() >= 2) { - // try default conversions - // /cygdrive/x/ --> X:\ - if ("cygdrive".equals(realPath.segment(0))) { //$NON-NLS-1$ - String drive= realPath.segment(1); - if (drive.length() == 1) { - translatedPath= realPath.removeFirstSegments(2).makeAbsolute().setDevice(drive.toUpperCase() + ':').toOSString(); - } - } - } - if (!translatedPath.equals(includePath)) { - // Check if the translated path exists - if (new File(translatedPath).exists()) { - translatedIncludePaths.add(translatedPath); - } - else if (cygpath.isAvailable) { - // TODO VMIR for now add even if it does not exist - translatedIncludePaths.add(translatedPath); - } - else { - translatedIncludePaths.add(includePath); - } - } - else { - // TODO VMIR for now add even if it does not exist - translatedIncludePaths.add(translatedPath); - } - } - } - if (cygpath.cygPath != null) { - cygpath.cygPath.dispose(); - } - return translatedIncludePaths; - } + } + if (!translationNeeded) { + return sumIncludes; + } + + CygpathTranslator cygpath = new CygpathTranslator(project); + boolean useCygPathExtension = cygpath.cygPath != null; + boolean useCygwinFromPath = !useCygPathExtension; + + String envPath = null; + if (useCygwinFromPath) { + IEnvironmentVariableManager mngr = CCorePlugin.getDefault().getBuildEnvironmentManager(); + ICProjectDescription prjDes = CCorePlugin.getDefault().getProjectDescription(project, false); + if (prjDes != null) { + // we don't know for sure which configuration needs to be used here, so betting on "DefaultSettingConfiguration" + // considering that scanner discovery uses "DefaultSettingConfiguration" rather than "Active" configuration, + // see org.eclipse.cdt.build.core.scannerconfig.ScannerConfigBuilder.build(CfgInfoContext context, ...) + ICConfigurationDescription cfgDes = prjDes.getDefaultSettingConfiguration(); + IEnvironmentVariable envVar = mngr.getVariable(ENV_PATH, cfgDes, true); + if (envVar != null) { + envPath = envVar.getValue(); + } + } + if (envPath == null) { + IEnvironmentVariable envVar = mngr.getVariable(ENV_PATH, null, true); + if (envVar != null) { + envPath = envVar.getValue(); + } + } + + useCygwinFromPath = Cygwin.isAvailable(envPath); + } + + List translatedIncludePaths = new ArrayList(); + for (Iterator i = sumIncludes.iterator(); i.hasNext(); ) { + String includePath = i.next(); + IPath realPath = new Path(includePath); + // only allow native pathes if they have a device prefix + // to avoid matches on the current drive, e.g. /usr/bin = C:\\usr\\bin + if (realPath.getDevice() != null && realPath.toFile().exists()) { + translatedIncludePaths.add(includePath); + } + else { + String translatedPath = includePath; + + if (useCygPathExtension) { + try { + translatedPath = cygpath.cygPath.getFileName(includePath); + } + catch (IOException e) { + TraceUtil.outputError("CygpathTranslator unable to translate path: ", includePath); //$NON-NLS-1$ + } + } else if (useCygwinFromPath) { + try { + translatedPath = Cygwin.cygwinToWindowsPath(includePath, envPath); + } catch (Exception e) { + MakeCorePlugin.log(e); + } + } else if (realPath.segmentCount() >= 2) { + // try default conversions + // /cygdrive/x/ --> X:\ + if ("cygdrive".equals(realPath.segment(0))) { //$NON-NLS-1$ + String drive= realPath.segment(1); + if (drive.length() == 1) { + translatedPath= realPath.removeFirstSegments(2).makeAbsolute().setDevice(drive.toUpperCase() + ':').toOSString(); + } + } + } + if (!translatedPath.equals(includePath)) { + // Check if the translated path exists + if (new File(translatedPath).exists()) { + translatedIncludePaths.add(translatedPath); + } + else if (useCygPathExtension || useCygwinFromPath) { + // TODO VMIR for now add even if it does not exist + translatedIncludePaths.add(translatedPath); + } + else { + translatedIncludePaths.add(includePath); + } + } + else { + // TODO VMIR for now add even if it does not exist + translatedIncludePaths.add(translatedPath); + } + } + } + if (useCygPathExtension) { + cygpath.cygPath.dispose(); + } + return translatedIncludePaths; + } } diff --git a/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/envvar/EnvironmentVariableManagerToolChain.java b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/envvar/EnvironmentVariableManagerToolChain.java new file mode 100644 index 00000000000..5072fc95c50 --- /dev/null +++ b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/envvar/EnvironmentVariableManagerToolChain.java @@ -0,0 +1,220 @@ +/******************************************************************************* + * Copyright (c) 2012, 2012 Andrew Gvozdev 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: + * Andrew Gvozdev - Initial API and implementation + *******************************************************************************/ +package org.eclipse.cdt.managedbuilder.internal.envvar; + +import org.eclipse.cdt.core.cdtvariables.ICdtVariable; +import org.eclipse.cdt.core.envvar.IEnvironmentVariable; +import org.eclipse.cdt.core.settings.model.ICConfigurationDescription; +import org.eclipse.cdt.internal.core.cdtvariables.DefaultVariableContextInfo; +import org.eclipse.cdt.internal.core.cdtvariables.EnvironmentVariableSupplier; +import org.eclipse.cdt.internal.core.cdtvariables.ICoreVariableContextInfo; +import org.eclipse.cdt.internal.core.envvar.DefaultEnvironmentContextInfo; +import org.eclipse.cdt.internal.core.envvar.EnvVarDescriptor; +import org.eclipse.cdt.internal.core.envvar.EnvironmentVariableManager; +import org.eclipse.cdt.internal.core.envvar.ICoreEnvironmentVariableSupplier; +import org.eclipse.cdt.internal.core.envvar.IEnvironmentContextInfo; +import org.eclipse.cdt.managedbuilder.core.IConfiguration; +import org.eclipse.cdt.managedbuilder.core.IToolChain; +import org.eclipse.cdt.managedbuilder.core.ManagedBuildManager; +import org.eclipse.cdt.managedbuilder.envvar.IConfigurationEnvironmentVariableSupplier; +import org.eclipse.cdt.managedbuilder.envvar.IEnvironmentVariableProvider; +import org.eclipse.cdt.utils.cdtvariables.ICdtVariableSupplier; +import org.eclipse.cdt.utils.cdtvariables.IVariableContextInfo; + + +/** + * Helper class to resolve environment variables directly from toolchain. The intention is + * to use that in New Project Wizard scenarios when no configuration is available yet. + */ +public class EnvironmentVariableManagerToolChain extends EnvironmentVariableManager { + private static EnvironmentVariableManagerToolChain fInstance = null; + + /** + * Basically, converter from IEnvironmentVariable to ICdtVariable (build macros) which + * is used by EnvironmentVariableManager implementation to resolve variables/macros. + */ + private final class CoreVariableContextInfoToolChain implements ICoreVariableContextInfo { + public final static int CONTEXT_TOOLCHAIN = 1009; // arbitrary value different from ICoreVariableContextInfo.CONTEXT_XXX + + private final IToolChain toolChain; + private final IConfigurationEnvironmentVariableSupplier mbsSupplier; + + private CoreVariableContextInfoToolChain(IToolChain toolChain) { + this.toolChain = toolChain; + this.mbsSupplier = toolChain.getEnvironmentVariableSupplier(); + } + + @Override + public ICdtVariableSupplier[] getSuppliers() { + ICdtVariableSupplier sup = new ICdtVariableSupplier() { + @Override + public ICdtVariable getVariable(String macroName, IVariableContextInfo context) { + IEnvironmentVariable var = mbsSupplier.getVariable(macroName, null, ManagedBuildManager.getEnvironmentVariableProvider()); + return EnvironmentVariableSupplier.getInstance().createBuildMacro(var); + } + @Override + public ICdtVariable[] getVariables(IVariableContextInfo context) { + IEnvironmentVariable[] vars = mbsSupplier.getVariables(null, ManagedBuildManager.getEnvironmentVariableProvider()); + if (vars != null) { + ICdtVariable[] cdtVars = new ICdtVariable[vars.length]; + for (int i = 0; i < vars.length; i++) { + cdtVars[i] = EnvironmentVariableSupplier.getInstance().createBuildMacro(vars[i]); + } + } + return null; + } + + }; + return new ICdtVariableSupplier[] { sup }; + } + + @Override + public IVariableContextInfo getNext() { + return new DefaultVariableContextInfo(ICoreVariableContextInfo.CONTEXT_WORKSPACE, null); + } + + @Override + public int getContextType() { + return CONTEXT_TOOLCHAIN; + } + + @Override + public Object getContextData() { + return toolChain; + } + } + + private final class EnvironmentContextInfoToolChain implements IEnvironmentContextInfo { + private final IToolChain toolChain; + + private EnvironmentContextInfoToolChain(IToolChain toolChain) { + this.toolChain = toolChain; + } + + @Override + public IEnvironmentContextInfo getNext() { + return new DefaultEnvironmentContextInfo(null); + } + + @Override + public ICoreEnvironmentVariableSupplier[] getSuppliers() { + final IConfigurationEnvironmentVariableSupplier cevSupplier = toolChain.getEnvironmentVariableSupplier(); + + ICoreEnvironmentVariableSupplier toolchainSupplier = new ICoreEnvironmentVariableSupplier() { + @Override + public IEnvironmentVariable getVariable(String name, Object context) { + IEnvironmentVariableProvider provider = ManagedBuildManager.getEnvironmentVariableProvider(); + return cevSupplier.getVariable(name, null, provider); + } + @Override + public IEnvironmentVariable[] getVariables(Object context) { + return cevSupplier.getVariables(null, ManagedBuildManager.getEnvironmentVariableProvider()); + } + @Override + public boolean appendEnvironment(Object context) { + // Arbitrary value, it did not appear being used in tested scenarios + return false; + } + }; + return new ICoreEnvironmentVariableSupplier[] { EnvironmentVariableManagerToolChain.fUserSupplier, toolchainSupplier }; + } + + @Override + public Object getContext() { + return toolChain; + } + } + + public static EnvironmentVariableManagerToolChain getDefault() { + if (fInstance == null) + fInstance = new EnvironmentVariableManagerToolChain(); + return fInstance; + } + + @Override + public IEnvironmentContextInfo getContextInfo(Object level) { + if (level instanceof IToolChain) { + return new EnvironmentContextInfoToolChain((IToolChain) level); + } + + return super.getContextInfo(level); + } + + @Override + protected int getMacroContextTypeFromContext(Object context) { + if (context instanceof IToolChain) { + return CoreVariableContextInfoToolChain.CONTEXT_TOOLCHAIN; + } + + return super.getMacroContextTypeFromContext(context); + } + + @Override + public ICoreVariableContextInfo getMacroContextInfoForContext(Object context) { + if (context instanceof IToolChain) { + return new CoreVariableContextInfoToolChain((IToolChain) context); + } + + return super.getMacroContextInfoForContext(context); + } + + /** + * Get environment variable value from toolchain definition. + * + * @param name - name of the variable. + * @param toolChain - toolchain. + * @param resolveMacros - {@code true} to expand macros, {@code false} otherwise. + * + * @return value of the variable. + */ + public IEnvironmentVariable getVariable(String name, IToolChain toolChain, boolean resolveMacros) { + if (name == null || name.isEmpty()) + return null; + + IEnvironmentContextInfo info = getContextInfo(toolChain); + EnvVarDescriptor var = EnvironmentVariableManagerToolChain.getVariable(name,info,true); + + if (var != null && var.getOperation() != IEnvironmentVariable.ENVVAR_REMOVE) { + return resolveMacros ? calculateResolvedVariable(var,info) : var; + } + return null; + } + + /** + * Get environment variable value resolved in context of configuration. + * If no configuration available use toolchain definition. + * + * @param name - name of the variable. + * @param toolChain - toolchain. + * @param resolveMacros - {@code true} to expand macros, {@code false} otherwise. + * + * @return value of the variable. + */ + public String getVariableInConfigurationContext(String name, IToolChain toolChain, boolean resolveMacros) { + if (toolChain == null) { + return null; + } + + IConfiguration cfg = toolChain.getParent(); + ICConfigurationDescription cfgDescription = cfg != null ? ManagedBuildManager.getDescriptionForConfiguration(cfg) : null; + + IEnvironmentVariable var = null; + if (cfgDescription != null) { + var = getVariable(name, cfgDescription, resolveMacros); + } else { + var = getVariable(name, toolChain, resolveMacros); + } + + String value = var != null ? var.getValue() : null; + return value; + } + +} diff --git a/build/org.eclipse.cdt.managedbuilder.gnu.ui/src/org/eclipse/cdt/managedbuilder/gnu/cygwin/CygwinPathResolver.java b/build/org.eclipse.cdt.managedbuilder.gnu.ui/src/org/eclipse/cdt/managedbuilder/gnu/cygwin/CygwinPathResolver.java index 8f2b5b7e781..f3e5dc9e034 100644 --- a/build/org.eclipse.cdt.managedbuilder.gnu.ui/src/org/eclipse/cdt/managedbuilder/gnu/cygwin/CygwinPathResolver.java +++ b/build/org.eclipse.cdt.managedbuilder.gnu.ui/src/org/eclipse/cdt/managedbuilder/gnu/cygwin/CygwinPathResolver.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2005, 2010 Intel Corporation and others. + * Copyright (c) 2005, 2013 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 @@ -9,6 +9,7 @@ * Intel Corporation - Initial API and implementation * Enrico Ehrich - http://bugs.eclipse.org/233866 * Marc-Andre Laperle - fix for Cygwin GCC is Not detected (bug 303900) + * Andrew Gvozdev - changes to recognize $CYGWIN_HOME *******************************************************************************/ package org.eclipse.cdt.managedbuilder.gnu.cygwin; @@ -19,9 +20,8 @@ import java.io.InputStream; import java.io.InputStreamReader; import java.util.ArrayList; -import org.eclipse.cdt.core.CCorePlugin; import org.eclipse.cdt.core.envvar.IEnvironmentVariable; -import org.eclipse.cdt.core.settings.model.util.CDataUtil; +import org.eclipse.cdt.internal.core.Cygwin; import org.eclipse.cdt.managedbuilder.core.IBuildPathResolver; import org.eclipse.cdt.managedbuilder.core.IConfiguration; import org.eclipse.cdt.managedbuilder.core.ManagedBuildManager; @@ -30,40 +30,35 @@ import org.eclipse.cdt.utils.PathUtil; import org.eclipse.cdt.utils.WindowsRegistry; import org.eclipse.cdt.utils.spawner.ProcessFactory; import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; /** * @noextend This class is not intended to be subclassed by clients. */ public class CygwinPathResolver implements IBuildPathResolver { - private static final String DEFAULT_ROOT = "C:\\cygwin"; //$NON-NLS-1$ - private static final String TOOL = "/cygpath -w -p "; //$NON-NLS-1$ - private static final char BS = '\\'; - private static final char SLASH = '/'; + private static final String ENV_PATH = "PATH"; //$NON-NLS-1$ + private static final String DELIMITER_UNIX = ":"; //$NON-NLS-1$ + private static final String DELIMITER_WIN = ";"; //$NON-NLS-1$ + private static final String PROPERTY_OS_NAME = "os.name"; //$NON-NLS-1$ - private static final String PROPERTY_OS_VALUE = "windows";//$NON-NLS-1$ - private static final String SP = " "; //$NON-NLS-1$ - private static final String REGISTRY_KEY_SETUP = "SOFTWARE\\Cygwin\\setup"; //$NON-NLS-1$ - private static final String REGISTRY_KEY_SETUP_WIN64 = "SOFTWARE\\Wow6432Node\\Cygwin\\setup"; //$NON-NLS-1$ + private static final String OS_WINDOWS = "windows";//$NON-NLS-1$ + private static final char SLASH = '/'; + private static final char BACKSLASH = '\\'; + + private static final String CYGPATH_PATH_LIST_TO_WINDOWS = "cygpath -w -p "; //$NON-NLS-1$ + // note that in Cygwin 1.7 the mount point storage has been moved out of the registry private static final String REGISTRY_KEY_MOUNTS = "SOFTWARE\\Cygnus Solutions\\Cygwin\\mounts v2\\"; //$NON-NLS-1$ private static final String PATH_NAME = "native"; //$NON-NLS-1$ - private static final String SSLASH = "/"; //$NON-NLS-1$ - private static final String BSLASH = "\\\\"; //$NON-NLS-1$ private static final String BINPATTERN = "/usr/bin"; //$NON-NLS-1$ private static final String BINPATTERN_ALTERNATE = "/bin"; //$NON-NLS-1$ private static final String ETCPATTERN = "/etc"; //$NON-NLS-1$ - private static final String ROOTPATTERN = SSLASH; - private static final String DELIMITER_UNIX = ":"; //$NON-NLS-1$ - private static final String DELIMITER_WIN = ";"; //$NON-NLS-1$ + private static final String GCC_VERSION_CMD = "gcc --version"; //$NON-NLS-1$ private static final String MINGW_SPECIAL = "mingw "; //$NON-NLS-1$ private static final String CYGWIN_SPECIAL = "cygwin "; //$NON-NLS-1$ - private static String envPathValueCached = null; - private static String binCygwin = null; - private static String rootCygwin = null; - private static String etcCygwin = null; - @Override public String[] resolveBuildPaths(int pathType, String variableName, String variableValue, IConfiguration configuration) { if(!isWindows()) { @@ -72,58 +67,66 @@ public class CygwinPathResolver implements IBuildPathResolver { return variableValue.split(DELIMITER_WIN); } - String[] result = variableValue.split(DELIMITER_UNIX); - String exePath = getBinPath(); - if (exePath == null) { - return result; // no changes - } - File file = new File(exePath); - if (!file.exists() || !file.isDirectory()) { - return result; // no changes - } - String s = exePath + TOOL + variableValue; - String[] lines = exec(s, configuration); + String[] lines = executeInConfigurationContext(CYGPATH_PATH_LIST_TO_WINDOWS + variableValue, configuration); if (lines != null && lines.length > 0) { - result = lines[0].replace(BS,SLASH).split(DELIMITER_WIN); + String pathList = lines[0].replace(BACKSLASH, SLASH); + return pathList.split(DELIMITER_WIN); } - return result; + + return variableValue.split(DELIMITER_UNIX); } /** - * returns "/etc" path in Windows format + * @return "/etc" path in Windows format for workspace. + * @deprecated. Deprecated as of CDT 8.2. Note that Cygwin root path in general may depend on configuration. * * If you use this do not cache results to ensure user preferences are accounted for. * Please rely on internal caching. */ + @Deprecated public static String getEtcPath() { - findPaths(); + String etcCygwin = getPathFromRoot(ETCPATTERN); + // Try to find the paths in SOFTWARE\\Cygnus Solutions + if(etcCygwin == null) { + etcCygwin = readValueFromRegistry(REGISTRY_KEY_MOUNTS + ETCPATTERN, PATH_NAME); + } return etcCygwin; } /** - * returns "/usr/bin" path in Windows format + * @return "/usr/bin" path in Windows format for workspace. + * @deprecated. Deprecated as of CDT 8.2. Note that Cygwin root path in general may depend on configuration. * * If you use this do not cache results to ensure user preferences are accounted for. * Please rely on internal caching. */ + @Deprecated public static String getBinPath() { - findPaths(); + String binCygwin = getPathFromRoot(BINPATTERN); + if(binCygwin == null) { + binCygwin = getPathFromRoot(BINPATTERN_ALTERNATE); + } + // Try to find the paths in SOFTWARE\\Cygnus Solutions + if(binCygwin == null) { + binCygwin = readValueFromRegistry(REGISTRY_KEY_MOUNTS + BINPATTERN, PATH_NAME); + } return binCygwin; } /** - * returns Cygwin root ("/") path in Windows format + * @return Cygwin root ("/") path in Windows format for workspace. + * @deprecated. Deprecated as of CDT 8.2. Note that Cygwin root path in general may depend on configuration. * * If you use this do not cache results to ensure user preferences are accounted for. * Please rely on internal caching. */ + @Deprecated public static String getRootPath() { - findPaths(); - return rootCygwin; + return Cygwin.getCygwinHome(); } public static boolean isWindows() { - return (System.getProperty(PROPERTY_OS_NAME).toLowerCase().startsWith(PROPERTY_OS_VALUE)); + return (System.getProperty(PROPERTY_OS_NAME).toLowerCase().startsWith(OS_WINDOWS)); } /** @@ -136,146 +139,117 @@ public class CygwinPathResolver implements IBuildPathResolver { */ private static String readValueFromRegistry(String key, String name) { WindowsRegistry registry = WindowsRegistry.getRegistry(); - if (null != registry) { - String s = registry.getCurrentUserValue(key, name); - if(s == null) - s = registry.getLocalMachineValue(key, name); - - if (s != null) - return (s.replaceAll(BSLASH, SSLASH)); - } - return null; - } - - /** - * Returns the absolute path of the pattern by - * simply appending the pattern to the root - * - * @param pattern The pattern to find - * @return The absolute path to the pattern or null if pattern is not found - */ - private static String getValueFromRoot(String pattern) { - if (rootCygwin != null) { - String path = rootCygwin + pattern; - File file = new File(path); - if (file.exists() && file.isDirectory()) - return (path.replaceAll(BSLASH, SSLASH)); - else - return null; - } - - return null; - } - - /** - * Returns the absolute path to cygwin's root - * - * @return The absolute path to cygwin's root or null if not found - */ - private static String findRoot(String paths) { - String rootValue = null; - - // 1. Look in PATH values. Look for bin\cygwin1.dll - IPath location = PathUtil.findProgramLocation("cygwin1.dll", paths); //$NON-NLS-1$ - if (location!=null) { - rootValue = location.removeLastSegments(2).toOSString(); - } - - // 2. Try to find the root dir in SOFTWARE\Cygwin\setup - if(rootValue == null) { - rootValue = readValueFromRegistry(REGISTRY_KEY_SETUP, "rootdir"); //$NON-NLS-1$ - } - - // 3. Try to find the root dir in SOFTWARE\Wow6432Node\Cygwin\setup - if(rootValue == null) { - rootValue = readValueFromRegistry(REGISTRY_KEY_SETUP_WIN64, "rootdir"); //$NON-NLS-1$ - } - - // 4. Try to find the root dir in SOFTWARE\Cygnus Solutions - if (rootValue == null) { - rootValue = readValueFromRegistry(REGISTRY_KEY_MOUNTS + ROOTPATTERN, PATH_NAME); - } - - // 5. Try the default Cygwin install dir - if(rootValue == null) { - File file = new File(DEFAULT_ROOT); - if (file.exists() && file.isDirectory()) - rootValue = DEFAULT_ROOT; - } - - if(rootValue != null) - rootValue = rootValue.replaceAll(BSLASH, SSLASH); - - return rootValue; - } - - /** - * Finds Cygwin's paths and sets corresponding properties. - */ - private static synchronized void findPaths() { - if (!isWindows()) { - return; - } - - IEnvironmentVariable varPath = CCorePlugin.getDefault().getBuildEnvironmentManager().getVariable("PATH", null, true); //$NON-NLS-1$ - String envPathValue = varPath != null ? varPath.getValue() : null; - - if (CDataUtil.objectsEqual(envPathValue, envPathValueCached)) { - return; - } - - etcCygwin = null; - binCygwin = null; - rootCygwin = null; - - rootCygwin = findRoot(envPathValue); - - // 1. Try to find the paths by appending the patterns to the root dir - etcCygwin = getValueFromRoot(ETCPATTERN); - binCygwin = getValueFromRoot(BINPATTERN); - if(binCygwin == null) - binCygwin = getValueFromRoot(BINPATTERN_ALTERNATE); - - // 2. Try to find the paths in SOFTWARE\\Cygnus Solutions - if(etcCygwin == null) - etcCygwin = readValueFromRegistry(REGISTRY_KEY_MOUNTS + ETCPATTERN, PATH_NAME); - if(binCygwin == null) - binCygwin = readValueFromRegistry(REGISTRY_KEY_MOUNTS + BINPATTERN, PATH_NAME); - - envPathValueCached = envPathValue; - } - - private static String[] exec(String cmd, IConfiguration cfg) { - try { - IEnvironmentVariable vars[] = ManagedBuildManager.getEnvironmentVariableProvider().getVariables(cfg,true); - String env[] = new String[vars.length]; - for(int i = 0; i < env.length; i++) { - env[i] = vars[i].getName() + "="; //$NON-NLS-1$ - String value = vars[i].getValue(); - if(value != null) - env[i] += value; + if (registry != null) { + String value = registry.getCurrentUserValue(key, name); + if (value == null) { + value = registry.getLocalMachineValue(key, name); } - Process proc = ProcessFactory.getFactory().exec(cmd.split(SP), env); - if (proc != null) { + if (value != null) { + return value.replace(BACKSLASH, SLASH); + } + } + return null; + } - InputStream ein = proc.getInputStream(); - BufferedReader d1 = new BufferedReader(new InputStreamReader(ein)); - ArrayList ls = new ArrayList(10); - String s; - while ((s = d1.readLine() ) != null ) { - ls.add(s); + /** + * Returns the absolute path of the pattern by simply appending the relativePath to the root. + * + * @param relativePath - the pattern to find. + * @return The absolute path to the pattern or {@code null} if path does not exist. + */ + private static String getPathFromRoot(String relativePath) { + String rootCygwin = Cygwin.getCygwinHome(); + if (rootCygwin != null) { + String path = rootCygwin + relativePath; + File file = new File(path); + if (file.exists() && file.isDirectory()) { + return path.replace(BACKSLASH, SLASH); + } + } + return null; + } + + /** + * Resolve and return full path to program in context of configuration. + * + * @param program - program to resolve. + * @param cfg - configuration context. + * @return absolute path to program. + */ + private static String resolveProgram(String program, IConfiguration cfg) { + String envPathValue = null; + try { + IEnvironmentVariable envPathVar = ManagedBuildManager.getEnvironmentVariableProvider().getVariable(ENV_PATH, cfg, true); + if (envPathVar != null) { + envPathValue = envPathVar.getValue(); + IPath progPath = PathUtil.findProgramLocation(program, envPathValue); + if (progPath != null) { + program = progPath.toOSString(); + } + // this resolves cygwin symbolic links + program = Cygwin.cygwinToWindowsPath(program, envPathValue); + } + } catch (Exception e) { + GnuUIPlugin.getDefault().log(new Status(IStatus.WARNING, GnuUIPlugin.PLUGIN_ID, "Problem trying to find program [" + program + "] in $PATH=[" + envPathValue + "]", e)); + } + return program; + } + + /** + * Return environment in envp format, see {@link Runtime#exec(String, String[])}. + * + * @param cfg - configuration. + * @return environment as array of strings in format name=value. + */ + private static String[] getEnvp(IConfiguration cfg) { + IEnvironmentVariable vars[] = ManagedBuildManager.getEnvironmentVariableProvider().getVariables(cfg,true); + String envp[] = new String[vars.length]; + for(int i = 0; i < envp.length; i++) { + envp[i] = vars[i].getName() +'='; + String value = vars[i].getValue(); + if(value != null) + envp[i] += value; + } + return envp; + } + + /** + * Execute command taking in account configuration environment. + * + * @param cmd - command to execute. + * @param cfg - configuration context. + * @return command output as string array. + */ + private static String[] executeInConfigurationContext(String cmd, IConfiguration cfg) { + String[] args = cmd.split(" "); //$NON-NLS-1$ + args[0] = resolveProgram(args[0], cfg); + + String[] result = null; + try { + String[] envp = getEnvp(cfg); + Process proc = ProcessFactory.getFactory().exec(args, envp); + if (proc != null) { + InputStream ein = proc.getInputStream(); + try { + BufferedReader d1 = new BufferedReader(new InputStreamReader(ein)); + ArrayList ls = new ArrayList(10); + String s; + while ((s = d1.readLine()) != null ) { + ls.add(s); + } + result = ls.toArray(new String[0]); + } finally { + ein.close(); } - ein.close(); - return ls.toArray(new String[0]); } } catch (IOException e) { - GnuUIPlugin.getDefault().log(e); + GnuUIPlugin.getDefault().log(new Status(IStatus.ERROR, GnuUIPlugin.PLUGIN_ID, "Error executing program [" +cmd + "]", e)); } - return null; + return result; } public static boolean isMinGW(IConfiguration cfg) { - String versionInfo[] = exec(GCC_VERSION_CMD, cfg); + String versionInfo[] = executeInConfigurationContext(GCC_VERSION_CMD, cfg); if(versionInfo != null) { for(int i = 0; i < versionInfo.length; i++) { if(versionInfo[i].indexOf(MINGW_SPECIAL) != -1) diff --git a/build/org.eclipse.cdt.managedbuilder.gnu.ui/src/org/eclipse/cdt/managedbuilder/gnu/cygwin/GnuCygwinConfigurationEnvironmentSupplier.java b/build/org.eclipse.cdt.managedbuilder.gnu.ui/src/org/eclipse/cdt/managedbuilder/gnu/cygwin/GnuCygwinConfigurationEnvironmentSupplier.java index ae08fcf841d..5b659ead2d2 100644 --- a/build/org.eclipse.cdt.managedbuilder.gnu.ui/src/org/eclipse/cdt/managedbuilder/gnu/cygwin/GnuCygwinConfigurationEnvironmentSupplier.java +++ b/build/org.eclipse.cdt.managedbuilder.gnu.ui/src/org/eclipse/cdt/managedbuilder/gnu/cygwin/GnuCygwinConfigurationEnvironmentSupplier.java @@ -1,33 +1,38 @@ /******************************************************************************* - * Copyright (c) 2005, 2011 Intel Corporation and others. + * Copyright (c) 2005, 2012 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 + * Intel Corporation - Initial API and implementation + * Andrew Gvozdev - Ability to use different Cygwin versions in different cfg *******************************************************************************/ package org.eclipse.cdt.managedbuilder.gnu.cygwin; +import org.eclipse.cdt.core.CCorePlugin; +import org.eclipse.cdt.core.envvar.IEnvironmentVariable; +import org.eclipse.cdt.internal.core.Cygwin; import org.eclipse.cdt.managedbuilder.core.IConfiguration; import org.eclipse.cdt.managedbuilder.envvar.IBuildEnvironmentVariable; import org.eclipse.cdt.managedbuilder.envvar.IConfigurationEnvironmentVariableSupplier; import org.eclipse.cdt.managedbuilder.envvar.IEnvironmentVariableProvider; import org.eclipse.cdt.managedbuilder.internal.envvar.BuildEnvVar; +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.Path; /** * @noextend This class is not intended to be subclassed by clients. */ public class GnuCygwinConfigurationEnvironmentSupplier implements IConfigurationEnvironmentVariableSupplier { - private static final String PATH = "PATH"; //$NON-NLS-1$ - private static final String DELIMITER_UNIX = ":"; //$NON-NLS-1$ - private static final String PROPERTY_DELIMITER = "path.separator"; //$NON-NLS-1$ - private static final String PROPERTY_OSNAME = "os.name"; //$NON-NLS-1$ + private static final String ENV_PATH = "PATH"; //$NON-NLS-1$ + private static final String ENV_LANG = "LANG"; //$NON-NLS-1$ + private static final String ENV_LC_ALL = "LC_ALL"; //$NON-NLS-1$ + private static final String ENV_LC_MESSAGES = "LC_MESSAGES"; //$NON-NLS-1$ - private static final String LANG = "LANG"; //$NON-NLS-1$ - private static final String LC_ALL = "LC_ALL"; //$NON-NLS-1$ - private static final String LC_MESSAGES = "LC_MESSAGES"; //$NON-NLS-1$ + private static final String PROPERTY_OSNAME = "os.name"; //$NON-NLS-1$ + private static final String BACKSLASH = java.io.File.separator; @Override public IBuildEnvironmentVariable getVariable(String variableName, IConfiguration configuration, IEnvironmentVariableProvider provider) { @@ -39,19 +44,33 @@ public class GnuCygwinConfigurationEnvironmentSupplier implements IConfiguration return null; } - if (variableName.equalsIgnoreCase(PATH)) { - String p = CygwinPathResolver.getBinPath(); - if (p != null) { - return new BuildEnvVar(PATH, p.replace('/','\\'), IBuildEnvironmentVariable.ENVVAR_PREPEND, System.getProperty(PROPERTY_DELIMITER, DELIMITER_UNIX)); + if (variableName.equalsIgnoreCase(ENV_PATH)) { + @SuppressWarnings("nls") + String path = "${" + Cygwin.ENV_CYGWIN_HOME + "}" + BACKSLASH + "bin"; + return new BuildEnvVar(ENV_PATH, path, IBuildEnvironmentVariable.ENVVAR_PREPEND); + + } else if (variableName.equals(Cygwin.ENV_CYGWIN_HOME)) { + String home = Cygwin.getCygwinHome(); + // If the variable is not defined still show it in the environment variables list as a hint to user + if (home == null) { + home = ""; //$NON-NLS-1$ } - } else if (variableName.equalsIgnoreCase(LANG)) { + IPath homePath = new Path(home); + IEnvironmentVariable varCygwinHome = CCorePlugin.getDefault().getBuildEnvironmentManager().getVariable(Cygwin.ENV_CYGWIN_HOME, null, false); + if (varCygwinHome == null || (!homePath.equals(new Path(varCygwinHome.getValue())))) { + // Contribute if the variable does not already come from workspace environment + return new BuildEnvVar(Cygwin.ENV_CYGWIN_HOME, homePath.toOSString()); + } + return null; + + } else if (variableName.equalsIgnoreCase(ENV_LANG)) { // Workaround for not being able to select encoding for CDT console -> change codeset to Latin1 - String langValue = System.getenv(LANG); + String langValue = System.getenv(ENV_LANG); if (langValue == null || langValue.length() == 0) { - langValue = System.getenv(LC_ALL); + langValue = System.getenv(ENV_LC_ALL); } if (langValue == null || langValue.length() == 0) { - langValue = System.getenv(LC_MESSAGES); + langValue = System.getenv(ENV_LC_MESSAGES); } if (langValue != null && langValue.length() > 0) { // langValue is [language[_territory][.codeset][@modifier]], i.e. "en_US.UTF-8@dict" @@ -61,21 +80,17 @@ public class GnuCygwinConfigurationEnvironmentSupplier implements IConfiguration } else { langValue = "C.ISO-8859-1"; //$NON-NLS-1$ } - - return new BuildEnvVar(LANG, langValue); + return new BuildEnvVar(ENV_LANG, langValue); } return null; } @Override public IBuildEnvironmentVariable[] getVariables(IConfiguration configuration, IEnvironmentVariableProvider provider) { - IBuildEnvironmentVariable varLang = getVariable(LANG, configuration, provider); - IBuildEnvironmentVariable varPath = getVariable(PATH, configuration, provider); + IBuildEnvironmentVariable varHome = getVariable(Cygwin.ENV_CYGWIN_HOME, configuration, provider); + IBuildEnvironmentVariable varLang = getVariable(ENV_LANG, configuration, provider); + IBuildEnvironmentVariable varPath = getVariable(ENV_PATH, configuration, provider); - if (varPath != null) { - return new IBuildEnvironmentVariable[] {varLang, varPath}; - } else { - return new IBuildEnvironmentVariable[] {varLang}; - } + return new IBuildEnvironmentVariable[] {varHome, varLang, varPath}; } } diff --git a/build/org.eclipse.cdt.managedbuilder.gnu.ui/src/org/eclipse/cdt/managedbuilder/gnu/cygwin/IsGnuCygwinToolChainSupported.java b/build/org.eclipse.cdt.managedbuilder.gnu.ui/src/org/eclipse/cdt/managedbuilder/gnu/cygwin/IsGnuCygwinToolChainSupported.java index a2d2050338a..9a2fd648827 100644 --- a/build/org.eclipse.cdt.managedbuilder.gnu.ui/src/org/eclipse/cdt/managedbuilder/gnu/cygwin/IsGnuCygwinToolChainSupported.java +++ b/build/org.eclipse.cdt.managedbuilder.gnu.ui/src/org/eclipse/cdt/managedbuilder/gnu/cygwin/IsGnuCygwinToolChainSupported.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2005, 2010 Intel Corporation and others. + * Copyright (c) 2005, 2013 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 @@ -7,85 +7,28 @@ * * Contributors: * Intel Corporation - Initial API and implementation + * Andrew Gvozdev - Ability to use different Cygwin versions in different configurations *******************************************************************************/ package org.eclipse.cdt.managedbuilder.gnu.cygwin; -import java.io.BufferedReader; -import java.io.File; -import java.io.FileNotFoundException; -import java.io.FileReader; -import java.io.IOException; - -import org.eclipse.cdt.core.settings.model.util.CDataUtil; +import org.eclipse.cdt.internal.core.Cygwin; import org.eclipse.cdt.managedbuilder.core.IManagedIsToolChainSupported; import org.eclipse.cdt.managedbuilder.core.IToolChain; +import org.eclipse.cdt.managedbuilder.internal.envvar.EnvironmentVariableManagerToolChain; import org.osgi.framework.Version; /** * This class implements the IManagedIsToolChainSupported for the Gnu Cygwin tool-chain - * The class is NOT used currently, because currently the gnu cygwin tool-chain - * is intended to be used not only with Cygwin, but with MinGW also, and there is no - * correct way of determining whether the appropriate packages are installed for MinGW. - * - * For the future MBS/CDT versions we might create the separate tool-chain/configuration/project-type - * for the MinGW and define a set of converters using the tool-chain converter mechanism that MBS will provide, - * that would convert the CygWin to the MinGW projects/tool-chains, and vice a versa. * * @noextend This class is not intended to be subclassed by clients. */ public class IsGnuCygwinToolChainSupported implements IManagedIsToolChainSupported { - private static final String[] CHECKED_NAMES = {"gcc", "binutils", "make"}; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + private static final String ENV_PATH = "PATH"; //$NON-NLS-1$ - private static String etcCygwinCached = null; - private static boolean toolchainIsSupported = false; - - /** - * @since 8.0 - */ @Override public boolean isSupported(IToolChain toolChain, Version version, String instance) { - String etcCygwin = CygwinPathResolver.getEtcPath(); - if (CDataUtil.objectsEqual(etcCygwin, etcCygwinCached)) { - return toolchainIsSupported; - } - - toolchainIsSupported = etcCygwin != null && arePackagesInstalled(etcCygwin); - etcCygwinCached = etcCygwin; - - return toolchainIsSupported; + String envPath = EnvironmentVariableManagerToolChain.getDefault().getVariableInConfigurationContext(ENV_PATH, toolChain, true); + return Cygwin.isAvailable(envPath); } - /** - * Returns true if all required packages are installed, see CHECKED_NAMES for a list of packages. Cygwin - * maintains a list of packages in /etc/setup/installed.db so we look for packages in this file. - * - * @param etcCygwin the absolute path of /etc containing /setup/installed.db - * @return true if the packages specified in CHECKED_NAMES are installed - */ - private boolean arePackagesInstalled(String etcCygwin) { - boolean arePackagesInstalled = false; - File file = new File(etcCygwin + "/setup/installed.db"); //$NON-NLS-1$ - try { - BufferedReader data = new BufferedReader(new FileReader(file)); - - // All required package names should be found - boolean[] found = new boolean[CHECKED_NAMES.length]; - String s; - while ((s = data.readLine()) != null ) { - for (int j = 0; j < CHECKED_NAMES.length; j++) { - if (s.startsWith(CHECKED_NAMES[j])) { - found[j] = true; - } - } - } - arePackagesInstalled = true; - for (int j = 0; j < CHECKED_NAMES.length; j++) { - arePackagesInstalled &= found[j]; - } - data.close(); - } catch (FileNotFoundException e) { - } catch (IOException e) { - } - return arePackagesInstalled; - } } diff --git a/core/org.eclipse.cdt.core/utils/org/eclipse/cdt/internal/core/Cygwin.java b/core/org.eclipse.cdt.core/utils/org/eclipse/cdt/internal/core/Cygwin.java index e0b770d87c9..bd878b12cd7 100644 --- a/core/org.eclipse.cdt.core/utils/org/eclipse/cdt/internal/core/Cygwin.java +++ b/core/org.eclipse.cdt.core/utils/org/eclipse/cdt/internal/core/Cygwin.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2012, 2012 Andrew Gvozdev and others. + * Copyright (c) 2012, 2013 Andrew Gvozdev 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 @@ -11,24 +11,74 @@ package org.eclipse.cdt.internal.core; import java.io.BufferedReader; +import java.io.File; import java.io.IOException; import java.io.InputStreamReader; +import java.util.Collections; +import java.util.Map; +import org.eclipse.cdt.core.CCorePlugin; +import org.eclipse.cdt.core.envvar.IEnvironmentVariable; +import org.eclipse.cdt.core.settings.model.util.CDataUtil; import org.eclipse.cdt.utils.PathUtil; +import org.eclipse.cdt.utils.WindowsRegistry; import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.Path; import org.eclipse.core.runtime.Platform; /** * A collection of cygwin-related utilities. */ public class Cygwin { + public static final String ENV_CYGWIN_HOME = "CYGWIN_HOME"; //$NON-NLS-1$ + private static final String ENV_PATH = "PATH"; //$NON-NLS-1$ - private static IPath findCygpathLocation(String envPath) { - return PathUtil.findProgramLocation("cygpath", envPath); //$NON-NLS-1$ + private static final String CYGPATH = "cygpath"; //$NON-NLS-1$ + private static final String DEFAULT_ROOT = "C:\\cygwin"; //$NON-NLS-1$ + private static final String CYGWIN_DLL = "cygwin1.dll"; //$NON-NLS-1$ + private static final String REGISTRY_KEY_SETUP = "SOFTWARE\\Cygwin\\setup"; //$NON-NLS-1$ + private static final String REGISTRY_KEY_SETUP_WIN64 = "SOFTWARE\\Wow6432Node\\Cygwin\\setup"; //$NON-NLS-1$ + // note that in Cygwin 1.7 the mount point storage has been moved out of the registry + private static final String REGISTRY_KEY_MOUNTS = "SOFTWARE\\Cygnus Solutions\\Cygwin\\mounts v2\\"; //$NON-NLS-1$ + private static final String PATH_NAME = "native"; //$NON-NLS-1$ + private static final String ROOTPATTERN = "/"; //$NON-NLS-1$ + private static final char SLASH = '/'; + private static final char BACKSLASH = '\\'; + + private static final boolean isWindowsPlatform = Platform.getOS().equals(Platform.OS_WIN32); + + private static String envPathValueCached = null; + private static String envCygwinHomeValueCached = null; + private static String cygwinLocation = null; + private static boolean isCygwinLocationCached = false; + + private final static Map cygpathLocationCache = Collections.synchronizedMap(new LRUCache(1,20)); + private final static Map translatedPathsCache = Collections.synchronizedMap(new LRUCache(10,500)); + + /** + * Find location of "cygpath" utility on the file system. + */ + private static String findCygpathLocation(String envPath) { + if (envPath == null) { + // $PATH from user preferences + IEnvironmentVariable varPath = CCorePlugin.getDefault().getBuildEnvironmentManager().getVariable(ENV_PATH, null, true); + if (varPath != null) { + envPath = varPath.getValue(); + } + } + + String cygpathLocation = cygpathLocationCache.get(envPath); + if (cygpathLocation == null) { + IPath loc = PathUtil.findProgramLocation(CYGPATH, envPath); + cygpathLocation = loc != null ? loc.toOSString() : null; + cygpathLocationCache.put(envPath, cygpathLocation); + } + return cygpathLocation; } /** * Check if cygwin path conversion utilities are available in the path. + * Tells whether cygwin is installed in the path. * * @param envPath - list of directories to search for cygwin utilities separated * by path separator (format of environment variable $PATH) @@ -36,22 +86,60 @@ public class Cygwin { * @return {@code true} if cygwin is available, {@code false} otherwise. */ public static boolean isAvailable(String envPath) { - return Platform.getOS().equals(Platform.OS_WIN32) && findCygpathLocation(envPath) != null; + return isWindowsPlatform && findCygpathLocation(envPath) != null; } /** * Check if cygwin path conversion utilities are available in $PATH. + * Tells whether cygwin is installed in the path. * * @return {@code true} if cygwin is available, {@code false} otherwise. */ public static boolean isAvailable() { - return Platform.getOS().equals(Platform.OS_WIN32) && findCygpathLocation(null) != null; + return isWindowsPlatform && findCygpathLocation(null) != null; + } + + /** + * Run program (assuming cygpath) and return the translated path which is the first line of output. + */ + private static String runCygpath(String[] args) throws IOException { + String command = getCommand(args); + String translatedPath = translatedPathsCache.get(command); + if (translatedPath == null) { + Process cygpathProcess = Runtime.getRuntime().exec(args); + BufferedReader stdout = new BufferedReader(new InputStreamReader(cygpathProcess.getInputStream())); + String firstLine = null; + try { + firstLine = stdout.readLine(); + } finally { + stdout.close(); + } + if (firstLine == null) { + throw new IOException("Unable read output from command=[" + command + "]"); //$NON-NLS-1$ //$NON-NLS-2$ + } + translatedPath = firstLine.trim(); + translatedPathsCache.put(command, translatedPath); + } + + return translatedPath; + } + + /** + * Construct a command from arguments array. + */ + private static String getCommand(String[] args) { + String command = ""; //$NON-NLS-1$ + for (String arg : args) { + command = command + arg + ' '; + } + return command.trim(); } /** * Conversion from Cygwin path to Windows path. + * Note that there is no need to cache results, they are already cached internally. * - * @param cygwinPath - Cygwin path. + * @param cygwinPath - cygwin path. * @param envPath - list of directories to search for cygwin utilities separated * by path separator (format of environment variable $PATH). * @return Windows style converted path. Note that that also converts cygwin links to their targets. @@ -63,31 +151,24 @@ public class Cygwin { if (cygwinPath == null || cygwinPath.trim().length() == 0) return cygwinPath; - if (!Platform.getOS().equals(Platform.OS_WIN32)) { - // Don't run this on non-windows platforms + if (!isWindowsPlatform) { throw new UnsupportedOperationException("Not a Windows system, Cygwin is unavailable."); //$NON-NLS-1$ } - IPath cygpathLocation = findCygpathLocation(envPath); + String cygpathLocation = findCygpathLocation(envPath); if (cygpathLocation == null) { - throw new UnsupportedOperationException("Cygwin utility cygpath is not in the system search path."); //$NON-NLS-1$ + throw new UnsupportedOperationException(CYGPATH + " is not in the system search path."); //$NON-NLS-1$ } - String[] args = {cygpathLocation.toOSString(), "-w", cygwinPath}; //$NON-NLS-1$ - Process cygpathProcess = Runtime.getRuntime().exec(args); - BufferedReader stdout = new BufferedReader(new InputStreamReader(cygpathProcess.getInputStream())); - - String windowsPath = stdout.readLine(); - if (windowsPath == null) { - throw new IOException("Unexpected output from Cygwin utility cygpath."); //$NON-NLS-1$ - } - return windowsPath.trim(); + String windowsPath = runCygpath(new String[] {cygpathLocation, "-w", cygwinPath}); //$NON-NLS-1$ + return windowsPath; } /** * Conversion from Cygwin path to Windows path. + * Note that there is no need to cache results, they are already cached internally. * - * @param cygwinPath - Cygwin path. + * @param cygwinPath - cygwin path. * @return Windows style converted path. Note that that also converts cygwin links to their targets. * * @throws UnsupportedOperationException if Cygwin is unavailable. @@ -99,6 +180,7 @@ public class Cygwin { /** * Conversion from Windows path to Cygwin path. + * Note that there is no need to cache results, they are already cached internally. * * @param windowsPath - Windows path. * @param envPath - list of directories to search for cygwin utilities (value of environment variable $PATH). @@ -111,28 +193,22 @@ public class Cygwin { if (windowsPath == null || windowsPath.trim().length() == 0) return windowsPath; - if (!Platform.getOS().equals(Platform.OS_WIN32)) { - // Don't run this on non-windows platforms + if (!isWindowsPlatform) { throw new UnsupportedOperationException("Not a Windows system, Cygwin is unavailable."); //$NON-NLS-1$ } - IPath cygpathLocation = findCygpathLocation(envPath); + + String cygpathLocation = findCygpathLocation(envPath); if (cygpathLocation == null) { - throw new UnsupportedOperationException("Cygwin utility cygpath is not in the system search path."); //$NON-NLS-1$ + throw new UnsupportedOperationException(CYGPATH + " is not in the system search path."); //$NON-NLS-1$ } - String[] args = {cygpathLocation.toOSString(), "-u", windowsPath}; //$NON-NLS-1$ - Process cygpath = Runtime.getRuntime().exec(args); - BufferedReader stdout = new BufferedReader(new InputStreamReader(cygpath.getInputStream())); - - String cygwinPath = stdout.readLine(); - if (cygwinPath == null) { - throw new IOException("Unexpected output from Cygwin utility cygpath."); //$NON-NLS-1$ - } - return cygwinPath.trim(); + String cygwinPath = runCygpath(new String[] {cygpathLocation, "-u", windowsPath}); //$NON-NLS-1$ + return cygwinPath; } /** * Conversion from Windows path to Cygwin path. + * Note that there is no need to cache results, they are already cached internally. * * @param windowsPath - Windows path. * @return Cygwin style converted path. @@ -143,4 +219,114 @@ public class Cygwin { public static String windowsToCygwinPath(String windowsPath) throws IOException, UnsupportedOperationException { return windowsToCygwinPath(windowsPath, null); } + + /** + * Find location where Cygwin is installed. A number of locations is being checked, + * such as environment variable $CYGWIN_HOME, $PATH, Windows registry et al. + *

+ * If you use this do not cache results to ensure user preferences are accounted for. + * Please rely on internal caching. + * + * @return Location of Cygwin root folder "/" on file system in Windows format. + */ + public static String getCygwinHome() { + if (!isWindowsPlatform) { + return null; + } + + IEnvironmentVariable varPath = CCorePlugin.getDefault().getBuildEnvironmentManager().getVariable(ENV_PATH, null, true); + String envPathValue = varPath != null ? varPath.getValue() : null; + IEnvironmentVariable varCygwinHome = CCorePlugin.getDefault().getBuildEnvironmentManager().getVariable(ENV_CYGWIN_HOME, null, true); + String envCygwinHomeValue = varCygwinHome != null ? varCygwinHome.getValue() : null; + + // isCygwinLocationCached is used to figure fact of caching when all cached objects are null + if (isCygwinLocationCached && CDataUtil.objectsEqual(envPathValue, envPathValueCached) && CDataUtil.objectsEqual(envCygwinHomeValue, envCygwinHomeValueCached)) { + return cygwinLocation; + } + + cygwinLocation = findCygwinRoot(envPathValue, envCygwinHomeValue); + + envPathValueCached = envPathValue; + envCygwinHomeValueCached = envCygwinHomeValue; + isCygwinLocationCached = true; + + return cygwinLocation; + } + + /** + * Reads required value from registry. Looks in both + * HKEY_CURRENT_USER and HKEY_LOCAL_MACHINE + * + * @param key Registry key + * @param name Registry value to read + * @return corresponding string value or null if nothing found + */ + private static String readValueFromRegistry(String key, String name) { + WindowsRegistry registry = WindowsRegistry.getRegistry(); + if (registry != null) { + String s = registry.getCurrentUserValue(key, name); + if(s == null) { + s = registry.getLocalMachineValue(key, name); + } + + if (s != null) { + return (s.replace(BACKSLASH, SLASH)); + } + } + return null; + } + + /** + * @return The absolute path to cygwin's root or null if not found + */ + private static String findCygwinRoot(String envPathValue, String envCygwinHomeValue) { + String rootValue = null; + + // Check $CYGWIN_HOME + if (envCygwinHomeValue != null && !envCygwinHomeValue.isEmpty()) { + IPath location = new Path(envCygwinHomeValue + "/bin/" + CYGWIN_DLL); //$NON-NLS-1$ + if (location.toFile().exists()) { + // get rootValue from "rootValue\bin\cygwin1.dll" + rootValue = location.removeLastSegments(2).toOSString(); + } + } + + // Look in PATH values. Look for cygwin1.dll + if(rootValue == null) { + IPath location = PathUtil.findProgramLocation(CYGWIN_DLL, envPathValue); + if (location != null) { + // get rootValue from "rootValue\bin\cygwin1.dll" + rootValue = location.removeLastSegments(2).toOSString(); + } + } + + // Try to find the root dir in SOFTWARE\Cygwin\setup + if(rootValue == null) { + rootValue = readValueFromRegistry(REGISTRY_KEY_SETUP, "rootdir"); //$NON-NLS-1$ + } + + // Try to find the root dir in SOFTWARE\Wow6432Node\Cygwin\setup + if(rootValue == null) { + rootValue = readValueFromRegistry(REGISTRY_KEY_SETUP_WIN64, "rootdir"); //$NON-NLS-1$ + } + + // Try to find the root dir in SOFTWARE\Cygnus Solutions + if (rootValue == null) { + rootValue = readValueFromRegistry(REGISTRY_KEY_MOUNTS + ROOTPATTERN, PATH_NAME); + } + + // Try the default Cygwin install dir + if(rootValue == null) { + File file = new File(DEFAULT_ROOT); + if (file.exists() && file.isDirectory()) + rootValue = DEFAULT_ROOT; + } + + if(rootValue != null) { + rootValue = rootValue.replace(BACKSLASH, SLASH); + } + + return rootValue; + } + } diff --git a/core/org.eclipse.cdt.core/utils/org/eclipse/cdt/internal/core/LRUCache.java b/core/org.eclipse.cdt.core/utils/org/eclipse/cdt/internal/core/LRUCache.java new file mode 100644 index 00000000000..817613c6406 --- /dev/null +++ b/core/org.eclipse.cdt.core/utils/org/eclipse/cdt/internal/core/LRUCache.java @@ -0,0 +1,50 @@ +/******************************************************************************* + * Copyright (c) 2013 Andrew Gvozdev 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: + * Andrew Gvozdev - initial API and implementation + *******************************************************************************/ + +package org.eclipse.cdt.internal.core; + +import java.util.LinkedHashMap; +import java.util.Map.Entry; + +/** + * A simple cache with limited number of items in the cache. LRUCache discards the Least Recently Used items first. + * Based on {@link LinkedHashMap}. Note that {@link LinkedHashMap} has built-in facility to support cache like that + * which is described in its JavaDoc. + */ +public class LRUCache extends LinkedHashMap { + private int fLimit; + + /** + * Constructs an empty LRUCache with the specified limit on the number of items in the cache. + * + * @param limit - the maximum number of items to keep in the cache. + */ + public LRUCache(int limit) { + super(limit, 0.75f, true); + fLimit= limit; + } + + /** + * Constructs an empty LRUCache with the specified initial capacity and limit on the number of items in the cache. + * + * @param initialCapacity - initial capacity. + * @param limit - the maximum number of items to keep in the cache. + */ + public LRUCache(int initialCapacity, int limit) { + super(initialCapacity, 0.75f, true); + fLimit= limit; + } + + @Override + protected boolean removeEldestEntry(Entry eldest) { + return size() >= fLimit; + } +} \ No newline at end of file diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/newui/AbstractPage.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/newui/AbstractPage.java index 61270ae07d4..cf9f9f73299 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/newui/AbstractPage.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/newui/AbstractPage.java @@ -979,8 +979,11 @@ implements } protected void cfgChanged(ICConfigurationDescription _cfgd) { - CConfigurationStatus st = _cfgd.getConfigurationStatus(); + if (st.getCode() == CConfigurationStatus.TOOLCHAIN_NOT_SUPPORTED) { + // Re-check, maybe user got the problem fixed + st = _cfgd.getConfigurationData().getStatus(); + } if (errPane != null && errMessage != null) { if (st.isOK()) { errPane.setVisible(false);