1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-04-29 19:45:01 +02:00

Bug 519190 - Get CMake working with MSVC toolchain

Adds in Core Build support for the MSVC toolchain. Fixes issue
with PATH in the core build configuration since on Windows it's often
Path.

Change-Id: I3eb201bc22bf42341207e8f3bbef999d4d174f05
(cherry picked from commit 7f3745c765)
This commit is contained in:
dschaefer 2017-07-04 21:40:52 -04:00 committed by Doug Schaefer
parent dd07cba37b
commit c4990122ac
4 changed files with 378 additions and 1 deletions

View file

@ -435,7 +435,14 @@ public abstract class CBuildConfiguration extends PlatformObject
Map<String, String> env = new HashMap<>(System.getenv());
setBuildEnvironment(env);
String[] path = env.get("PATH").split(File.pathSeparator); //$NON-NLS-1$
String pathStr = env.get("PATH"); //$NON-NLS-1$
if (pathStr == null) {
pathStr = env.get("Path"); // for Windows //$NON-NLS-1$
if (pathStr == null) {
return null; // no idea
}
}
String[] path = pathStr.split(File.pathSeparator);
for (String dir : path) {
Path commandPath = Paths.get(dir, command);
if (Files.exists(commandPath)) {
@ -635,6 +642,7 @@ public abstract class CBuildConfiguration extends PlatformObject
String[] compileCommands = toolChain.getCompileCommands();
loop:
for (String arg : command) {
// TODO we should really ask the toolchain, not all args start with '-'
if (arg.startsWith("-")) { //$NON-NLS-1$
// option found, missed our command
return false;

View file

@ -735,5 +735,12 @@
</toolChain>
</template>
</extension>
<extension
point="org.eclipse.cdt.core.toolChainProvider">
<provider
class="org.eclipse.cdt.msw.build.core.MSVCToolChainProvider"
id="org.eclipse.cdt.msw.build">
</provider>
</extension>
</plugin>

View file

@ -0,0 +1,281 @@
/*******************************************************************************
* Copyright (c) 2017 QNX Software Systems 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
*******************************************************************************/
package org.eclipse.cdt.msw.build.core;
import java.io.File;
import java.net.URI;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.eclipse.cdt.core.CCorePlugin;
import org.eclipse.cdt.core.build.IToolChain;
import org.eclipse.cdt.core.build.IToolChainProvider;
import org.eclipse.cdt.core.envvar.EnvironmentVariable;
import org.eclipse.cdt.core.envvar.IEnvironmentVariable;
import org.eclipse.cdt.core.model.ILanguage;
import org.eclipse.cdt.core.parser.ExtendedScannerInfo;
import org.eclipse.cdt.core.parser.IExtendedScannerInfo;
import org.eclipse.core.resources.IBuildConfiguration;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IWorkspaceRoot;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.PlatformObject;
import org.osgi.framework.Version;
public class MSVCToolChain extends PlatformObject implements IToolChain {
private final IToolChainProvider provider;
private final Path path;
private final Map<String, String> properties = new HashMap<>();
private final String id;
private final String arch;
private final String version;
private final IEnvironmentVariable pathVar;
private final IEnvironmentVariable includeVar;
private final IEnvironmentVariable libVar;
private final String[] includeDirs;
private final Map<String, String> symbols;
public MSVCToolChain(IToolChainProvider provider, Path path) {
this.provider = provider;
this.path = path;
// path = <version>/bin/<hostArch>/<targetArch>
String targetArch = path.getFileName().toString();
this.arch = targetArch.equalsIgnoreCase("x86") ? Platform.ARCH_X86 : Platform.ARCH_X86_64; //$NON-NLS-1$
this.id = "msvc." + arch; //$NON-NLS-1$
this.version = path.getParent().getParent().getParent().getFileName().toString();
Path kitRoot = Paths.get("C:", "Program Files (x86)", "Windows Kits", "10"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
List<String> versions = Arrays.asList(kitRoot.resolve("lib").toFile().list()); //$NON-NLS-1$
Collections.sort(versions, (v1, v2) -> {
Version ver1;
try {
ver1 = new Version(v1);
} catch (IllegalArgumentException e) {
return 1;
}
Version ver2;
try {
ver2 = new Version(v2);
} catch (IllegalArgumentException e) {
return -1;
}
return ver2.compareTo(ver1);
});
String sdkVersion = versions.iterator().next();
pathVar = new EnvironmentVariable("Path", String.join(File.pathSeparator, //$NON-NLS-1$
path.toString(),
kitRoot.resolve("bin").resolve(sdkVersion).resolve(targetArch).toString() //$NON-NLS-1$
), IEnvironmentVariable.ENVVAR_PREPEND, File.pathSeparator);
this.includeDirs = new String[] {
path.getParent().getParent().getParent().resolve("include").toString(), //$NON-NLS-1$
kitRoot.resolve("include").resolve(sdkVersion).resolve("ucrt").toString(), //$NON-NLS-1$ //$NON-NLS-2$
kitRoot.resolve("include").resolve(sdkVersion).resolve("shared").toString(), //$NON-NLS-1$ //$NON-NLS-2$
kitRoot.resolve("include").resolve(sdkVersion).resolve("um").toString(), //$NON-NLS-1$ //$NON-NLS-2$
kitRoot.resolve("include").resolve(sdkVersion).resolve("winrt").toString() //$NON-NLS-1$ //$NON-NLS-2$
};
includeVar = new EnvironmentVariable("INCLUDE", String.join(File.pathSeparator, this.includeDirs), //$NON-NLS-1$
IEnvironmentVariable.ENVVAR_REPLACE, File.pathSeparator);
libVar = new EnvironmentVariable("LIB", String.join(File.pathSeparator, //$NON-NLS-1$
path.getParent().getParent().getParent().resolve("lib").resolve(targetArch).toString(), //$NON-NLS-1$
kitRoot.resolve("lib").resolve(sdkVersion).resolve("ucrt").resolve(targetArch).toString(), //$NON-NLS-1$ //$NON-NLS-2$
kitRoot.resolve("lib").resolve(sdkVersion).resolve("um").resolve(targetArch).toString() //$NON-NLS-1$ //$NON-NLS-2$
), IEnvironmentVariable.ENVVAR_REPLACE, File.pathSeparator);
symbols = new HashMap<>();
symbols.put("_WIN32", "1"); //$NON-NLS-1$ //$NON-NLS-2$
if (this.arch.equals(Platform.ARCH_X86)) {
symbols.put("_M_IX86", "600"); //$NON-NLS-1$ //$NON-NLS-2$
} else {
symbols.put("_WIN64", "1"); //$NON-NLS-1$ //$NON-NLS-2$
symbols.put("_M_X64", "100"); //$NON-NLS-1$ //$NON-NLS-2$
}
// TODO make this more dynamic to actual version
symbols.put("_MSC_VER", "1900"); //$NON-NLS-1$ //$NON-NLS-2$
// Microsoft specific modifiers that can be ignored
symbols.put("__cdecl", ""); //$NON-NLS-1$ //$NON-NLS-2$
symbols.put("__fastcall", ""); //$NON-NLS-1$ //$NON-NLS-2$
symbols.put("__restrict", ""); //$NON-NLS-1$ //$NON-NLS-2$
symbols.put("__sptr", ""); //$NON-NLS-1$ //$NON-NLS-2$
symbols.put("__stdcall", ""); //$NON-NLS-1$ //$NON-NLS-2$
symbols.put("__unaligned", ""); //$NON-NLS-1$ //$NON-NLS-2$
symbols.put("__uptr", ""); //$NON-NLS-1$ //$NON-NLS-2$
symbols.put("__w64", ""); //$NON-NLS-1$ //$NON-NLS-2$
// Redefine some things so that the CDT parser can handle them, until there is a VC specific parser
symbols.put("__forceinline", "__inline"); //$NON-NLS-1$ //$NON-NLS-2$
symbols.put("__int8", "char"); //$NON-NLS-1$ //$NON-NLS-2$
symbols.put("__int16", "short"); //$NON-NLS-1$ //$NON-NLS-2$
symbols.put("__int32", "int"); //$NON-NLS-1$ //$NON-NLS-2$
symbols.put("__int64", "long long"); //$NON-NLS-1$ //$NON-NLS-2$
}
@Override
public IToolChainProvider getProvider() {
return provider;
}
@Override
public String getId() {
return id;
}
@Override
public String getVersion() {
return version;
}
@Override
public String getName() {
return "Visual C++";
}
@Override
public String getProperty(String key) {
String value = properties.get(key);
if (value != null) {
return value;
}
// By default, we're a local GCC
switch (key) {
case ATTR_OS:
return Platform.OS_WIN32;
case ATTR_ARCH:
return arch;
}
return null;
}
@Override
public void setProperty(String key, String value) {
properties.put(key, value);
}
@Override
public IEnvironmentVariable[] getVariables() {
return new IEnvironmentVariable[] { pathVar, includeVar, libVar };
}
@Override
public IEnvironmentVariable getVariable(String name) {
switch (name) {
case "PATH": //$NON-NLS-1$
case "Path": //$NON-NLS-1$
return pathVar;
default:
return null;
}
}
@Override
public String[] getErrorParserIds() {
return new String[] { CCorePlugin.PLUGIN_ID + ".VCErrorParser" //$NON-NLS-1$
};
}
@Override
public String getBinaryParserId() {
return CCorePlugin.PLUGIN_ID + ".PE"; //$NON-NLS-1$
}
@Override
public Path getCommandPath(Path command) {
if (command.isAbsolute()) {
return command;
} else {
return this.path.resolve(command);
}
}
@Override
public String[] getCompileCommands() {
return new String[] { "cl", "cl.exe" //$NON-NLS-1$ //$NON-NLS-2$
};
}
@Override
public IExtendedScannerInfo getDefaultScannerInfo(IBuildConfiguration buildConfig,
IExtendedScannerInfo baseScannerInfo, ILanguage language, URI buildDirectoryURI) {
return new ExtendedScannerInfo(symbols, includeDirs);
}
@Override
public IExtendedScannerInfo getScannerInfo(IBuildConfiguration buildConfig, List<String> command,
IExtendedScannerInfo baseScannerInfo, IResource resource, URI buildDirectoryURI) {
Map<String, String> symbols = new HashMap<>(this.symbols);
List<String> includeDirs = new ArrayList<>(Arrays.asList(this.includeDirs));
for (String arg : command) {
if (arg.startsWith("-") || arg.startsWith("/")) { //$NON-NLS-1$ //$NON-NLS-2$
if (arg.charAt(1) == 'I') {
includeDirs.add(arg.substring(2));
} else if (arg.charAt(1) == 'D') {
String[] define = arg.substring(2).split("="); //$NON-NLS-1$
if (define.length == 1) {
symbols.put(define[0], "1"); //$NON-NLS-1$
} else {
symbols.put(define[0], define[1]);
}
}
}
}
return new ExtendedScannerInfo(symbols, includeDirs.toArray(new String[includeDirs.size()]));
}
@Override
public IResource[] getResourcesFromCommand(List<String> command, URI buildDirectoryURI) {
// Start at the back looking for arguments
// TODO this was copied from the GCCToolChain, good candidate for the default implementation
List<IResource> resources = new ArrayList<>();
IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
for (int i = command.size() - 1; i >= 0; --i) {
String arg = command.get(i);
if (arg.startsWith("-") || arg.startsWith("/")) { //$NON-NLS-1$ //$NON-NLS-2$
// ran into an option, we're done.
break;
}
Path srcPath = Paths.get(arg);
URI uri;
if (srcPath.isAbsolute()) {
uri = srcPath.toUri();
} else {
try {
uri = buildDirectoryURI.resolve(arg);
} catch (IllegalArgumentException e) {
// Bad URI
continue;
}
}
for (IFile resource : root.findFilesForLocationURI(uri)) {
resources.add(resource);
}
}
return resources.toArray(new IResource[resources.size()]);
}
}

View file

@ -0,0 +1,81 @@
/*******************************************************************************
* Copyright (c) 2017 QNX Software Systems 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
*******************************************************************************/
package org.eclipse.cdt.msw.build.core;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import org.eclipse.cdt.core.build.IToolChain;
import org.eclipse.cdt.core.build.IToolChainManager;
import org.eclipse.cdt.core.build.IToolChainProvider;
import org.eclipse.cdt.msw.build.Activator;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.Status;
/**
* Toolchain provider for Microsoft's Visual C++ Compiler (MSVC).
*
* This implementation only supports Microsoft Build Tools 2017 and
* the Windows 10 SDK (Kit).
*/
public class MSVCToolChainProvider implements IToolChainProvider {
public MSVCToolChainProvider() {
// TODO Auto-generated constructor stub
}
@Override
public String getId() {
return "org.eclipse.cdt.msw.build"; //$NON-NLS-1$
}
@Override
public void init(IToolChainManager manager) throws CoreException {
// See if cl is installed
Path vsPath = Paths.get("C:", "Program Files (x86)", "Microsoft Visual Studio"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
if (!Files.exists(vsPath)) {
return;
}
Path vs2017Path = vsPath.resolve("2017"); //$NON-NLS-1$
if (!Files.exists(vs2017Path)) {
return;
}
Path msvcPath = vs2017Path.resolve("BuildTools").resolve("VC").resolve("Tools").resolve("MSVC"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
if (!Files.exists(msvcPath)) {
return;
}
String hostPath = Platform.getOSArch().equals(Platform.ARCH_X86) ? "HostX86" : "HostX64"; //$NON-NLS-1$ //$NON-NLS-2$
String archPath = Platform.getOSArch().equals(Platform.ARCH_X86) ? "x86" : "x64"; //$NON-NLS-1$ //$NON-NLS-2$
try {
Files.find(msvcPath, 6, (path, attr) -> {
return path.getFileName().toString().equalsIgnoreCase("cl.exe") //$NON-NLS-1$
&& path.getParent().getParent().getFileName().toString().equalsIgnoreCase(hostPath)
&& path.getParent().getFileName().toString().equalsIgnoreCase(archPath);
}).forEach((path) -> {
manager.addToolChain(new MSVCToolChain(this, path.getParent()));
});
} catch (IOException e) {
throw new CoreException(new Status(IStatus.ERROR, Activator.PLUGIN_ID, "Finding cl.exe", e)); //$NON-NLS-1$
}
}
@Override
public IToolChain getToolChain(String id, String version) throws CoreException {
// TODO Auto-generated method stub
return IToolChainProvider.super.getToolChain(id, version);
}
}