diff options
| author | Andrew Gvozdev | 2012-07-11 21:56:33 +0000 |
|---|---|---|
| committer | Andrew Gvozdev | 2013-02-01 15:32:41 +0000 |
| commit | 4b5b30fe150c8ba54ebf4a6c156fd8aae007f6d8 (patch) | |
| tree | 8f30e1ce55ad0b479e4e55b74c87bedc3563d91d | |
| parent | a3783e3f840a9bc2fa8d13fe05585d85ffa2d388 (diff) | |
| download | org.eclipse.cdt-4b5b30fe150c8ba54ebf4a6c156fd8aae007f6d8.tar.gz org.eclipse.cdt-4b5b30fe150c8ba54ebf4a6c156fd8aae007f6d8.tar.xz org.eclipse.cdt-4b5b30fe150c8ba54ebf4a6c156fd8aae007f6d8.zip | |
bug 357442: Added $CYGWIN_HOME to cygwin toolchain detection algorithm
8 files changed, 790 insertions, 383 deletions
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<String> translateIncludePaths(IProject project, List<String> sumIncludes) { - // first check if cygpath translation is needed at all - boolean translationNeeded = false; - if (Platform.getOS().equals(Platform.OS_WIN32)) { - for (Iterator<String> 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<String> translateIncludePaths(IProject project, List<String> sumIncludes) { + // first check if cygpath translation is needed at all + boolean translationNeeded = false; + if (Platform.getOS().equals(Platform.OS_WIN32)) { + for (Iterator<String> 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<String> translatedIncludePaths = new ArrayList<String>(); - for (Iterator<String> 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<String> translatedIncludePaths = new ArrayList<String>(); + for (Iterator<String> 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)); + if (registry != null) { + String value = registry.getCurrentUserValue(key, name); + if (value == null) { + value = registry.getLocalMachineValue(key, name); + } + if (value != null) { + return value.replace(BACKSLASH, SLASH); + } } return null; } /** - * Returns the absolute path of the pattern by - * simply appending the pattern to the root + * Returns the absolute path of the pattern by simply appending the relativePath to the root. * - * @param pattern The pattern to find - * @return The absolute path to the pattern or null if pattern is not found + * @param relativePath - the pattern to find. + * @return The absolute path to the pattern or {@code null} if path does not exist. */ - private static String getValueFromRoot(String pattern) { + private static String getPathFromRoot(String relativePath) { + String rootCygwin = Cygwin.getCygwinHome(); if (rootCygwin != null) { - String path = rootCygwin + pattern; + String path = rootCygwin + relativePath; File file = new File(path); - if (file.exists() && file.isDirectory()) - return (path.replaceAll(BSLASH, SSLASH)); - else - return null; + if (file.exists() && file.isDirectory()) { + return path.replace(BACKSLASH, SLASH); + } } - return null; } /** - * Returns the absolute path to cygwin's root + * Resolve and return full path to program in context of configuration. * - * @return The absolute path to cygwin's root or null if not found + * @param program - program to resolve. + * @param cfg - configuration context. + * @return absolute path to program. */ - 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; + 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)); } - - if(rootValue != null) - rootValue = rootValue.replaceAll(BSLASH, SSLASH); - - return rootValue; + return program; } /** - * Finds Cygwin's paths and sets corresponding properties. + * 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 synchronized void findPaths() { - if (!isWindows()) { - return; + 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; } - - 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; + return envp; } - private static String[] exec(String cmd, IConfiguration cfg) { + /** + * 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 { - 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; - } - Process proc = ProcessFactory.getFactory().exec(cmd.split(SP), env); + String[] envp = getEnvp(cfg); + Process proc = ProcessFactory.getFactory().exec(args, envp); if (proc != null) { - InputStream ein = proc.getInputStream(); - BufferedReader d1 = new BufferedReader(new InputStreamReader(ein)); - ArrayList<String> ls = new ArrayList<String>(10); - String s; - while ((s = d1.readLine() ) != null ) { - ls.add(s); + try { + BufferedReader d1 = new BufferedReader(new InputStreamReader(ein)); + ArrayList<String> ls = new ArrayList<String>(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$ + } + 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()); } - } else if (variableName.equalsIgnoreCase(LANG)) { + 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<String/*envPath*/, String /*cygpathLocation*/> cygpathLocationCache = Collections.synchronizedMap(new LRUCache<String, String>(1,20));
+ private final static Map<String/*command*/, String /*translatedPath*/> translatedPathsCache = Collections.synchronizedMap(new LRUCache<String, String>(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.
+ * <br><br>
+ * 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<K, V> extends LinkedHashMap<K, V> {
+ 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<K, V> 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); |
