diff --git a/build/org.eclipse.cdt.make.core.tests/src/org/eclipse/cdt/make/scannerdiscovery/GCCBuildCommandParserTest.java b/build/org.eclipse.cdt.make.core.tests/src/org/eclipse/cdt/make/scannerdiscovery/GCCBuildCommandParserTest.java index 1f71546aaca..a1aef93e593 100644 --- a/build/org.eclipse.cdt.make.core.tests/src/org/eclipse/cdt/make/scannerdiscovery/GCCBuildCommandParserTest.java +++ b/build/org.eclipse.cdt.make.core.tests/src/org/eclipse/cdt/make/scannerdiscovery/GCCBuildCommandParserTest.java @@ -1026,17 +1026,13 @@ public class GCCBuildCommandParserTest extends TestCase { // parse line parser.startup(cfgDescription); parser.processLine("gcc " - + " -IC:\\path" + + " -IX:\\path" + " file.cpp"); parser.shutdown(); // check populated entries - IPath path0 = new Path("C:\\path").setDevice(project.getLocation().getDevice()); - { - List entries = parser.getSettingEntries(cfgDescription, file, languageId); - CIncludePathEntry expected = new CIncludePathEntry(path0, 0); - assertEquals(expected, entries.get(0)); - } + List entries = parser.getSettingEntries(cfgDescription, file, languageId); + assertEquals(new CIncludePathEntry(new Path("X:\\path"), 0), entries.get(0)); } /** diff --git a/build/org.eclipse.cdt.make.core/src/org/eclipse/cdt/make/core/scannerconfig/AbstractLanguageSettingsOutputScanner.java b/build/org.eclipse.cdt.make.core/src/org/eclipse/cdt/make/core/scannerconfig/AbstractLanguageSettingsOutputScanner.java index 4f30aaba5f5..d5ad2a07fa5 100644 --- a/build/org.eclipse.cdt.make.core/src/org/eclipse/cdt/make/core/scannerconfig/AbstractLanguageSettingsOutputScanner.java +++ b/build/org.eclipse.cdt.make.core/src/org/eclipse/cdt/make/core/scannerconfig/AbstractLanguageSettingsOutputScanner.java @@ -242,18 +242,24 @@ public abstract class AbstractLanguageSettingsOutputScanner extends LanguageSett currentResource = findResource(parsedResourceName); + /** + * URI of directory where the build is happening. This URI could point to a remote filesystem + * for remote builds. Most often it is the same filesystem as for currentResource but + * it can be different filesystem (and different URI schema). + */ + URI buildDirURI = null; + /** * Where source tree starts if mapped. This kind of mapping is useful for example in cases when * the absolute path to the source file on the remote system is simulated inside a project in the * workspace. + * This URI is rooted on the same filesystem where currentResource resides. In general this filesystem + * (or even URI schema) does not have to match that of buildDirURI. */ URI mappedRootURI = null; - URI buildDirURI = null; - + if (isResolvingPaths) { - if (currentResource!=null) { - mappedRootURI = getMappedRootURI(currentResource, parsedResourceName); - } + mappedRootURI = getMappedRootURI(currentResource, parsedResourceName); buildDirURI = getBuildDirURI(mappedRootURI); } @@ -346,7 +352,7 @@ public abstract class AbstractLanguageSettingsOutputScanner extends LanguageSett ICLanguageSettingEntry entry; String resolvedPath = null; - URI uri = determineURI(parsedPath, baseURI); + URI uri = determineMappedURI(parsedPath, baseURI); IResource rc = null; if (uri != null && uri.isAbsolute()) { rc = findResourceForLocationURI(uri, optionParser.kind, currentProject); @@ -417,7 +423,7 @@ public abstract class AbstractLanguageSettingsOutputScanner extends LanguageSett return sourceFile; } - private URI getBuildDirURI(URI mappedRootURI) { + protected URI getBuildDirURI(URI mappedRootURI) { URI buildDirURI = null; URI cwdURI = null; @@ -457,13 +463,13 @@ public abstract class AbstractLanguageSettingsOutputScanner extends LanguageSett } /** - * Determine URI appending to baseURI when possible. + * Determine URI on the local filesystem considering possible mapping. * * @param pathStr - path to the resource, can be absolute or relative * @param baseURI - base {@link URI} where path to the resource is rooted * @return {@link URI} of the resource */ - private static URI determineURI(String pathStr, URI baseURI) { + private static URI determineMappedURI(String pathStr, URI baseURI) { URI uri = null; if (baseURI==null) { @@ -476,9 +482,15 @@ public abstract class AbstractLanguageSettingsOutputScanner extends LanguageSett // careful not to use Path here but 'pathStr' as String as we want to properly navigate symlinks uri = resolvePathFromBaseLocation(pathStr, baseLocation); } else { - // use canonicalized path here, in particular replace all '\' with '/' for Windows paths - Path path = new Path(pathStr); - uri = EFSExtensionManager.getDefault().append(baseURI, path.toString()); + // location on a remote filesystem + IPath path = new Path(pathStr); // use canonicalized path here, in particular replace all '\' with '/' for Windows paths + URI remoteUri = EFSExtensionManager.getDefault().append(baseURI, path.toString()); + if (remoteUri!=null) { + String localPath = EFSExtensionManager.getDefault().getMappedPath(remoteUri); + if (localPath!=null) { + uri = org.eclipse.core.filesystem.URIUtil.toURI(localPath); + } + } } if (uri == null) { @@ -642,7 +654,11 @@ public abstract class AbstractLanguageSettingsOutputScanner extends LanguageSett * @param parsedResourceName - path as appears in the output * @return mapped path as URI */ - private static URI getMappedRootURI(IResource sourceFile, String parsedResourceName) { + protected URI getMappedRootURI(IResource sourceFile, String parsedResourceName) { + if (currentResource==null) { + return null; + } + URI fileURI = sourceFile.getLocationURI(); String mappedRoot = "/"; //$NON-NLS-1$ @@ -674,17 +690,19 @@ public abstract class AbstractLanguageSettingsOutputScanner extends LanguageSett private static URI resolvePathFromBaseLocation(String name, IPath baseLocation) { String pathName = name; if (baseLocation != null && !baseLocation.isEmpty()) { - String device = new Path(pathName).getDevice(); - if (device != null && device.length() > 0) { - pathName = pathName.substring(device.length()); - } pathName = pathName.replace(File.separatorChar, '/'); - - baseLocation = baseLocation.addTrailingSeparator(); - if (pathName.startsWith("/")) { //$NON-NLS-1$ - pathName = pathName.substring(1); + String device = new Path(pathName).getDevice(); + if (device==null || device.equals(baseLocation.getDevice())) { + if (device != null && device.length() > 0) { + pathName = pathName.substring(device.length()); + } + + baseLocation = baseLocation.addTrailingSeparator(); + if (pathName.startsWith("/")) { //$NON-NLS-1$ + pathName = pathName.substring(1); + } + pathName = baseLocation.toString() + pathName; } - pathName = baseLocation.toString() + pathName; } try { diff --git a/build/org.eclipse.cdt.managedbuilder.core.tests/tests/org/eclipse/cdt/build/core/scannerconfig/tests/GCCBuiltinSpecsDetectorTest.java b/build/org.eclipse.cdt.managedbuilder.core.tests/tests/org/eclipse/cdt/build/core/scannerconfig/tests/GCCBuiltinSpecsDetectorTest.java index 21d1a22c2b7..965122671ba 100644 --- a/build/org.eclipse.cdt.managedbuilder.core.tests/tests/org/eclipse/cdt/build/core/scannerconfig/tests/GCCBuiltinSpecsDetectorTest.java +++ b/build/org.eclipse.cdt.managedbuilder.core.tests/tests/org/eclipse/cdt/build/core/scannerconfig/tests/GCCBuiltinSpecsDetectorTest.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2009 Andrew Gvozdev and others. + * Copyright (c) 2010, 2011 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 @@ -33,6 +33,7 @@ import org.eclipse.cdt.core.testplugin.ResourceHelper; import org.eclipse.cdt.internal.core.XmlUtil; import org.eclipse.cdt.managedbuilder.internal.scannerconfig.AbstractBuiltinSpecsDetector; import org.eclipse.cdt.managedbuilder.internal.scannerconfig.GCCBuiltinSpecsDetector; +import org.eclipse.cdt.managedbuilder.internal.scannerconfig.GCCBuiltinSpecsDetectorCygwin; import org.eclipse.core.resources.IProject; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; @@ -280,7 +281,6 @@ public class GCCBuiltinSpecsDetectorTest extends TestCase { String projectName = getName(); IProject project = ResourceHelper.createCDTProjectWithConfig(projectName); ICConfigurationDescription[] cfgDescriptions = getConfigurationDescriptions(project); - ICConfigurationDescription cfgDescription = cfgDescriptions[0]; AbstractBuiltinSpecsDetector detector = new GCCBuiltinSpecsDetector() { @@ -684,5 +684,63 @@ public class GCCBuiltinSpecsDetectorTest extends TestCase { assertEquals(expected, entries.get(0)); assertEquals(1, entries.size()); } + + public void testGCCBuiltinSpecsDetector_Cygwin_NoProject() throws Exception { + String windowsLocation; + String cygwinLocation = "/usr/include"; + try { + windowsLocation = ResourceHelper.cygwinToWindowsPath(cygwinLocation); + } catch (UnsupportedOperationException e) { + // Skip the test if Cygwin is not available. + return; + } + assertTrue("windowsLocation=["+windowsLocation+"]", new Path(windowsLocation).getDevice()!=null); + + AbstractBuiltinSpecsDetector detector = new GCCBuiltinSpecsDetectorCygwin(); + + detector.startup(null); + detector.processLine("#include <...> search starts here:"); + detector.processLine(" /usr/include"); + detector.processLine("End of search list."); + detector.shutdown(); + + // check populated entries + List entries = detector.getSettingEntries(null, null, null); + assertEquals(new CIncludePathEntry(new Path(windowsLocation), ICSettingEntry.BUILTIN | ICSettingEntry.READONLY), entries.get(0)); + assertEquals(1, entries.size()); + + } + + public void testGCCBuiltinSpecsDetector_Cygwin_Configuration() throws Exception { + String windowsLocation; + String cygwinLocation = "/usr/include"; + try { + windowsLocation = ResourceHelper.cygwinToWindowsPath(cygwinLocation); + } catch (UnsupportedOperationException e) { + // Skip the test if Cygwin is not available. + return; + } + assertTrue("windowsLocation=["+windowsLocation+"]", new Path(windowsLocation).getDevice()!=null); + + + // Create model project and folders to test + String projectName = getName(); + IProject project = ResourceHelper.createCDTProjectWithConfig(projectName); + ICConfigurationDescription[] cfgDescriptions = getConfigurationDescriptions(project); + ICConfigurationDescription cfgDescription = cfgDescriptions[0]; + + AbstractBuiltinSpecsDetector detector = new GCCBuiltinSpecsDetectorCygwin(); + + detector.startup(cfgDescription); + detector.processLine("#include <...> search starts here:"); + detector.processLine(" /usr/include"); + detector.processLine("End of search list."); + detector.shutdown(); + + // check populated entries + List entries = detector.getSettingEntries(null, null, null); + assertEquals(new CIncludePathEntry(new Path(windowsLocation), ICSettingEntry.BUILTIN | ICSettingEntry.READONLY), entries.get(0)); + assertEquals(1, entries.size()); + } } diff --git a/build/org.eclipse.cdt.managedbuilder.core/plugin.xml b/build/org.eclipse.cdt.managedbuilder.core/plugin.xml index fa816ec68e8..5514f2173e0 100644 --- a/build/org.eclipse.cdt.managedbuilder.core/plugin.xml +++ b/build/org.eclipse.cdt.managedbuilder.core/plugin.xml @@ -609,7 +609,7 @@ diff --git a/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/scannerconfig/AbstractBuiltinSpecsDetector.java b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/scannerconfig/AbstractBuiltinSpecsDetector.java index 4b0a3ac816e..488c155cfa7 100644 --- a/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/scannerconfig/AbstractBuiltinSpecsDetector.java +++ b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/scannerconfig/AbstractBuiltinSpecsDetector.java @@ -13,6 +13,7 @@ package org.eclipse.cdt.managedbuilder.internal.scannerconfig; import java.io.IOException; import java.io.OutputStream; +import java.net.URI; import java.net.URL; import java.util.ArrayList; import java.util.HashMap; @@ -79,6 +80,9 @@ public abstract class AbstractBuiltinSpecsDetector extends AbstractLanguageSetti protected java.io.File specFile = null; protected boolean preserveSpecFile = false; + protected URI mappedRootURI = null; + protected URI buildDirURI = null; + /** * TODO */ @@ -151,6 +155,22 @@ public abstract class AbstractBuiltinSpecsDetector extends AbstractLanguageSetti return currentLanguageId; } + @Override + protected URI getMappedRootURI(IResource sourceFile, String parsedResourceName) { + if (mappedRootURI==null) { + mappedRootURI = super.getMappedRootURI(sourceFile, parsedResourceName); + } + return mappedRootURI; + } + + @Override + protected URI getBuildDirURI(URI mappedRootURI) { + if (buildDirURI==null) { + buildDirURI = super.getBuildDirURI(mappedRootURI); + } + return buildDirURI; + } + @Override public void startup(ICConfigurationDescription cfgDescription) throws CoreException { // for workspace provider cfgDescription is used to figure out the current project for build console @@ -165,10 +185,16 @@ public abstract class AbstractBuiltinSpecsDetector extends AbstractLanguageSetti specFile = null; currentCommandResolved = resolveCommand(currentLanguageId); + + mappedRootURI = null; + buildDirURI = null; } @Override public void shutdown() { + buildDirURI = null; + mappedRootURI = null; + if (detectedSettingEntries!=null && detectedSettingEntries.size()>0) { groupEntries(detectedSettingEntries); setSettingEntries(currentCfgDescription, currentResource, currentLanguageId, detectedSettingEntries); diff --git a/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/scannerconfig/GCCBuiltinSpecsDetector.java b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/scannerconfig/GCCBuiltinSpecsDetector.java index 6b01c80d53b..b080fab86f5 100644 --- a/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/scannerconfig/GCCBuiltinSpecsDetector.java +++ b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/scannerconfig/GCCBuiltinSpecsDetector.java @@ -29,10 +29,10 @@ public class GCCBuiltinSpecsDetector extends AbstractBuiltinSpecsDetector implem private static final String GCC_TOOLCHAIN_ID = "cdt.managedbuild.toolchain.gnu.base"; //$NON-NLS-1$ private enum State {NONE, EXPECTING_LOCAL_INCLUDE, EXPECTING_SYSTEM_INCLUDE, EXPECTING_FRAMEWORKS} - State state = State.NONE; + private State state = State.NONE; @SuppressWarnings("nls") - static final AbstractOptionParser[] optionParsers = { + private static final AbstractOptionParser[] optionParsers = { new IncludePathOptionParser("#include \"(\\S.*)\"", "$1", ICSettingEntry.BUILTIN | ICSettingEntry.READONLY | ICSettingEntry.LOCAL), new IncludePathOptionParser("#include <(\\S.*)>", "$1", ICSettingEntry.BUILTIN | ICSettingEntry.READONLY), new IncludePathOptionParser("#framework <(\\S.*)>", "$1", ICSettingEntry.BUILTIN | ICSettingEntry.READONLY | ICSettingEntry.FRAMEWORKS_MAC), diff --git a/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/scannerconfig/GCCBuiltinSpecsDetectorCygwin.java b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/scannerconfig/GCCBuiltinSpecsDetectorCygwin.java new file mode 100644 index 00000000000..64389f7a5b3 --- /dev/null +++ b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/scannerconfig/GCCBuiltinSpecsDetectorCygwin.java @@ -0,0 +1,81 @@ +/******************************************************************************* + * Copyright (c) 2009, 2011 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.scannerconfig; + +import java.net.URI; +import java.net.URISyntaxException; + +import org.eclipse.cdt.core.settings.model.ICSettingEntry; +import org.eclipse.core.resources.IResource; + +/** + * Class to detect built-in compiler settings. + * The paths are converted to cygwin "filesystem" representation. Then + * + */ +public class GCCBuiltinSpecsDetectorCygwin extends GCCBuiltinSpecsDetector { + private static final URI CYGWIN_ROOT; + static { + try { + CYGWIN_ROOT = new URI("cygwin:/"); //$NON-NLS-1$ + } catch (URISyntaxException e) { + // hey we know this works + throw new IllegalStateException(e); + } + } + + @SuppressWarnings("nls") + private static final AbstractOptionParser[] optionParsers = { + new IncludePathOptionParser("#include \"(\\S.*)\"", "$1", ICSettingEntry.BUILTIN | ICSettingEntry.READONLY | ICSettingEntry.LOCAL), + new IncludePathOptionParser("#include <(\\S.*)>", "$1", ICSettingEntry.BUILTIN | ICSettingEntry.READONLY), + new MacroOptionParser("#define (\\S*\\(.*?\\)) *(.*)", "$1", "$2", ICSettingEntry.BUILTIN | ICSettingEntry.READONLY), + new MacroOptionParser("#define (\\S*) *(.*)", "$1", "$2", ICSettingEntry.BUILTIN | ICSettingEntry.READONLY), + }; + + @Override + protected AbstractOptionParser[] getOptionParsers() { + return optionParsers; + } + + @Override + protected URI getMappedRootURI(IResource sourceFile, String parsedResourceName) { + if (mappedRootURI==null) { + mappedRootURI = super.getMappedRootURI(sourceFile, parsedResourceName); + if (mappedRootURI==null) { + mappedRootURI = CYGWIN_ROOT; + } + } + return mappedRootURI; + } + + @Override + protected URI getBuildDirURI(URI mappedRootURI) { + if (buildDirURI==null) { + buildDirURI = super.getBuildDirURI(mappedRootURI); + if (buildDirURI==null) { + buildDirURI = CYGWIN_ROOT; + } + } + return buildDirURI; + } + + @Override + public GCCBuiltinSpecsDetectorCygwin cloneShallow() throws CloneNotSupportedException { + return (GCCBuiltinSpecsDetectorCygwin) super.cloneShallow(); + } + + @Override + public GCCBuiltinSpecsDetectorCygwin clone() throws CloneNotSupportedException { + return (GCCBuiltinSpecsDetectorCygwin) super.clone(); + } + +} diff --git a/core/org.eclipse.cdt.core/plugin.xml b/core/org.eclipse.cdt.core/plugin.xml index c8167c62bf1..95349032069 100644 --- a/core/org.eclipse.cdt.core/plugin.xml +++ b/core/org.eclipse.cdt.core/plugin.xml @@ -751,5 +751,12 @@ factoryClass="org.eclipse.cdt.internal.core.resources.ResourceExclusionFactory"> + + + + diff --git a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/core/resources/CygwinEFSExtensionProvider.java b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/core/resources/CygwinEFSExtensionProvider.java new file mode 100644 index 00000000000..5e78daf609b --- /dev/null +++ b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/core/resources/CygwinEFSExtensionProvider.java @@ -0,0 +1,101 @@ +/******************************************************************************* + * Copyright (c) 2011, 2011 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.resources; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.net.URI; + +import org.eclipse.cdt.core.CCorePlugin; +import org.eclipse.cdt.core.EFSExtensionProvider; +import org.eclipse.core.runtime.Platform; + +public class CygwinEFSExtensionProvider extends EFSExtensionProvider { + @Override + public String getMappedPath(URI locationURI) { + String cygwinPath = getPathFromURI(locationURI); + String windowsPath = null; + try { + windowsPath = cygwinToWindowsPath(cygwinPath); + } catch (Exception e) { + CCorePlugin.log(e); + } + return windowsPath; + } + + /** + * Conversion from Windows path to Cygwin path. + * + * @param windowsPath - Windows path. + * @return Cygwin style converted path. + * @throws UnsupportedOperationException if Cygwin is unavailable. + * @throws IOException on IO problem. + * + * See ResourceHelper.windowsToCygwinPath(...) + */ + public static String windowsToCygwinPath(String windowsPath) throws IOException, UnsupportedOperationException { + if (!Platform.getOS().equals(Platform.OS_WIN32)) { + // Don't run this on non-windows platforms + throw new UnsupportedOperationException("Not a Windows system, Cygwin is unavailable."); + } + @SuppressWarnings("nls") + String[] args = {"cygpath", "-u", windowsPath}; + Process cygpath; + try { + cygpath = Runtime.getRuntime().exec(args); + } catch (IOException ioe) { + throw new UnsupportedOperationException("Cygwin utility cygpath is not in the system search path."); + } + BufferedReader stdout = new BufferedReader(new InputStreamReader(cygpath.getInputStream())); + + String cygwinPath = stdout.readLine(); + if (cygwinPath == null) { + throw new UnsupportedOperationException("Cygwin utility cygpath is not available."); + } + return cygwinPath.trim(); + } + + /** + * Conversion from Cygwin path to Windows path. + * + * @param cygwinPath - Cygwin path. + * @return Windows style converted path. + * @throws UnsupportedOperationException if Cygwin is unavailable. + * @throws IOException on IO problem. + * + * * See ResourceHelper.cygwinToWindowsPath(...) + */ + public static String cygwinToWindowsPath(String cygwinPath) throws IOException, UnsupportedOperationException { + if (!Platform.getOS().equals(Platform.OS_WIN32)) { + // Don't run this on non-windows platforms + throw new UnsupportedOperationException("Not a Windows system, Cygwin is unavailable."); + } + @SuppressWarnings("nls") + String[] args = {"cygpath", "-w", cygwinPath}; + Process cygpath; + try { + cygpath = Runtime.getRuntime().exec(args); + } catch (IOException ioe) { + throw new UnsupportedOperationException("Cygwin utility cygpath is not in the system search path."); + } + BufferedReader stdout = new BufferedReader(new InputStreamReader(cygpath.getInputStream())); + + String windowsPath = stdout.readLine(); + if (windowsPath == null) { + throw new UnsupportedOperationException("Cygwin utility cygpath is not available."); + } + return windowsPath.trim(); + } + + +}