/******************************************************************************* * Copyright (c) 2005, 2010 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 * Enrico Ehrich - http://bugs.eclipse.org/233866 * Marc-Andre Laperle - fix for Cygwin GCC is Not detected (bug 303900) *******************************************************************************/ package org.eclipse.cdt.managedbuilder.gnu.cygwin; import java.io.BufferedReader; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.util.ArrayList; import org.eclipse.cdt.core.envvar.IEnvironmentVariable; import org.eclipse.cdt.managedbuilder.core.IBuildPathResolver; import org.eclipse.cdt.managedbuilder.core.IConfiguration; import org.eclipse.cdt.managedbuilder.core.ManagedBuildManager; import org.eclipse.cdt.managedbuilder.gnu.ui.GnuUIPlugin; 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; /** * @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 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$ // 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 boolean checked = false; private static String binCygwin = null; private static String rootCygwin = null; private static String etcCygwin = null; /* (non-Javadoc) * @see org.eclipse.cdt.managedbuilder.core.IBuildPathResolver#resolveBuildPaths(int, java.lang.String, java.lang.String, org.eclipse.cdt.managedbuilder.core.IConfiguration) */ public String[] resolveBuildPaths(int pathType, String variableName, String variableValue, IConfiguration configuration) { if(!isWindows()){ return variableValue.split(DELIMITER_UNIX); } else if(isMinGW(configuration)){ 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); if (lines != null && lines.length > 0) { result = lines[0].replace(BS,SLASH).split(DELIMITER_WIN); } return result; } /* * returns "/etc" path in Windows format */ public static String getEtcPath() { if (!checked) findPaths(); return etcCygwin; } /* * returns "/usr/bin" path in Windows format */ public static String getBinPath() { if (!checked) findPaths(); return binCygwin; } /* * returns Cygwin root ("/") path in Windows format */ public static String getRootPath() { if (!checked) findPaths(); return rootCygwin; } public static boolean isWindows() { return (System.getProperty(PROPERTY_OS_NAME).toLowerCase().startsWith(PROPERTY_OS_VALUE)); } /** * 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 (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 rootValue = null; // 1. Look in PATH values. Look for bin\cygwin1.dll IPath location = PathUtil.findProgramLocation("cygwin1.dll"); //$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 (checked) return; etcCygwin = null; binCygwin = null; rootCygwin = null; if (!isWindows()) return; rootCygwin = findRoot(); // 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); checked = true; } 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; } Process proc = ProcessFactory.getFactory().exec(cmd.split(SP), env); 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); } ein.close(); return ls.toArray(new String[0]); } } catch (IOException e) { GnuUIPlugin.getDefault().log(e); } return null; } public static boolean isMinGW(IConfiguration cfg){ String versionInfo[] = exec(GCC_VERSION_CMD, cfg); if(versionInfo != null) { for(int i = 0; i < versionInfo.length; i++){ if(versionInfo[i].indexOf(MINGW_SPECIAL) != -1) return true; else if(versionInfo[i].indexOf(CYGWIN_SPECIAL) != -1) return false; } } return false; } }