We detect this compatibility mode with a flag and based on argv[0]
ending in "cl" for clang-cl.exe or just cl.exe.
Once we've detected this mode, we try to parse arguments as MSVC style
arguments before falling back to parsing gcc style arguments.
Conflicting options can be passed using an -Xclang-driver escape.
High level discussion is on cfe-dev:
http://lists.cs.uiuc.edu/pipermail/cfe-dev/2013-June/030404.html
http://llvm-reviews.chandlerc.com/D1048
Files:
include/clang/Driver/Driver.h
include/clang/Driver/MSVCOptions.td
include/clang/Driver/Options.h
include/clang/Driver/Options.td
lib/Driver/Driver.cpp
lib/Driver/DriverOptions.cpp
lib/Driver/ToolChains.h
lib/Driver/WindowsToolChain.cpp
lib/Headers/CMakeLists.txt
lib/Headers/msvcrt_picker.h
test/Driver/ccc-msvc.cpp
tools/driver/CMakeLists.txt
tools/driver/clang_symlink.cmake
tools/driver/driver.cpp
Index: include/clang/Driver/Driver.h
===================================================================
--- include/clang/Driver/Driver.h
+++ include/clang/Driver/Driver.h
@@ -387,6 +387,12 @@
const ToolChain &getToolChain(const llvm::opt::ArgList &Args,
StringRef DarwinArchName = "") const;
+ /// \brief Parse the given list of strings into an ArgList while giving
+ /// precedence to MSVC options if there is a conflict.
+ llvm::opt::InputArgList *ParseMSVCArgs(ArrayRef<const char *> ArgList,
+ unsigned &MissingArgIndex,
+ unsigned &MissingArgCount);
+
/// @}
public:
Index: include/clang/Driver/MSVCOptions.td
===================================================================
--- /dev/null
+++ include/clang/Driver/MSVCOptions.td
@@ -0,0 +1,111 @@
+//===--- MSVCOptions.td - Options for clang-cl ----------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the options accepted by clang-cl.
+//
+//===----------------------------------------------------------------------===//
+
+// Define special MSVC option kinds with higher precedence (-1) than the normal
+// options. If there is a conflict on the command line, it can be resolved by
+// escaping it with -Xclang or -Xclang-driver.
+// FIXME: Add some new escape to let the driver interpret it?
+
+class MSVCFlag<string name> : Option<["/", "-"], name, KIND_FLAG>;
+class MSVCJoined<string name> : Option<["/", "-"], name, KIND_JOINED>;
+class MSVCJoinedOrSeparate<string name> :
+ Option<["/", "-"], name, KIND_JOINED_OR_SEPARATE>;
+
+// MSVC compatible options. These are only enabled when clang is invoked as
+// clang-cl, or when it is passed -ccc-msvc. Always put the "/" prefix first so
+// the help text renders with it.
+
+// Escape for any gcc-style driver options that conflict with MSVC options,
+// such as -MD.
+// FIXME: Should -Xclang-driver always go to the driver, even on non-Windows?
+// If so, remove the MSVCOption flag.
+def Xclang_driver : Separate<["-"], "Xclang-driver">, Flags<[MSVCOption]>;
+
+let Flags = [MSVCOption, DriverOption] in {
+
+def _QUESTION : MSVCFlag<"?">,
+ HelpText<"Print help for MSVC options">;
+def showIncludes : MSVCFlag<"showIncludes">,
+ HelpText<"Print include paths to stdout">;
+def Fo : MSVCJoined<"Fo">,
+ HelpText<"Output file or directory for multiple source files">;
+
+// We can't accept -MD or -MT since they are already used for depfiles. Even
+// though -MDd and -MTd don't conflict, don't accept them for consistency.
+def _SLASH_MD : MSVCFlag<"MD">, HelpText<"Use the dynamic, release Visual C runtime">;
+def _SLASH_MT : MSVCFlag<"MT">, HelpText<"Use the static, release Visual C runtime">;
+def _SLASH_MDd : MSVCFlag<"MDd">, HelpText<"Use the dynamic, debug Visual C runtime">;
+def _SLASH_MTd : MSVCFlag<"MTd">, HelpText<"Use the static, debug Visual C runtime">;
+
+// Optimization aliases. We can't alias many of these because -O is joined and
+// these are not.
+def _SLASH_O : MSVCJoined<"O">, Alias<O>,
+ HelpText<"Optimization level">;
+def Ob0 : MSVCFlag<"Ob0">, Alias<fno_inline_functions>,
+ HelpText<"Disables all inlining aside from __forceinline">;
+def Ob : MSVCJoined<"Ob">,
+ HelpText<"Controls inlining, unsupported">;
+def Ox : MSVCFlag<"Ox">,
+ HelpText<"Maximum optimizations (-O3)">;
+def Od : MSVCFlag<"Od">,
+ HelpText<"Disable optimizations">;
+def Ot : MSVCFlag<"Ot">,
+ HelpText<"Optimize for speed">;
+def Oy : MSVCFlag<"Oy">, Alias<fomit_frame_pointer>,
+ HelpText<"Enable frame pointer omission">;
+def Oy_ : MSVCFlag<"Oy-">, Alias<fno_omit_frame_pointer>,
+ HelpText<"Disable frame pointer omission">;
+// Not implemented:
+// /Og - global optimizations
+// /Oi[-] - enable/disable intrinsics
+
+// Language options. These should mostly be aliases.
+def GR : MSVCFlag<"GR">, Alias<frtti>, HelpText<"Enable RTTI">;
+def GR_ : MSVCFlag<"GR-">, Alias<fno_rtti>, HelpText<"Disable RTTI">;
+
+// Simple aliases.
+def _SLASH_c : MSVCFlag<"c">, Alias<c>;
+def _SLASH_I : MSVCJoined<"I">, Alias<I>;
+def _SLASH_D : MSVCJoinedOrSeparate<"D">, Alias<D>;
+def _SLASH_U : MSVCJoinedOrSeparate<"U">, Alias<U>;
+def _SLASH_W1 : MSVCFlag<"W1">; // -Wall
+def _SLASH_W2 : MSVCFlag<"W2">; // -Wall
+def _SLASH_W3 : MSVCFlag<"W3">; // -Wall
+def _SLASH_WX : MSVCFlag<"WX">; // -Werror
+def _SLASH_WX_ : MSVCFlag<"WX-">; // -Wno-error
+
+// Compatibility no-ops.
+
+def nologo : MSVCFlag<"nologo">;
+def analyze_ : MSVCFlag<"analyze-">;
+
+// Unsupported
+
+def Zi : MSVCFlag<"Zi">;
+def Zc_ : MSVCJoined<"Zc:">;
+def fp_ : MSVCJoined<"fp:">;
+def Fd : MSVCJoined<"Fd">;
+def GS : MSVCFlag<"GS">;
+def EH : MSVCJoined<"EH">;
+def Gd : MSVCFlag<"Gd">;
+def Gz : MSVCFlag<"Gz">;
+def Gr : MSVCFlag<"Gr">;
+def Gm : MSVCFlag<"Gm">;
+def Gm_ : MSVCFlag<"Gm-">;
+def GZ : MSVCFlag<"GZ">;
+def RTC : MSVCJoined<"RTC">;
+def TP : MSVCFlag<"TP">, HelpText<"Compile all files as C++">;
+def TC : MSVCFlag<"TC">, HelpText<"Compile all files as C">;
+def errorReport_ : MSVCJoined<"errorReport:">;
+
+} // let Flags = [MSVCOption, DriverOption]
Index: include/clang/Driver/Options.h
===================================================================
--- include/clang/Driver/Options.h
+++ include/clang/Driver/Options.h
@@ -29,7 +29,8 @@
NoForward = (1 << 7),
Unsupported = (1 << 8),
CC1Option = (1 << 9),
- NoDriverOption = (1 << 10)
+ NoDriverOption = (1 << 10),
+ MSVCOption = (1 << 11)
};
enum ID {
Index: include/clang/Driver/Options.td
===================================================================
--- include/clang/Driver/Options.td
+++ include/clang/Driver/Options.td
@@ -42,6 +42,10 @@
// NoDriverOption - This option should not be accepted by the driver.
def NoDriverOption : OptionFlag;
+// MSVCOption - This option should only be accepted for compatiblity with
+// MSVC's frontend cl.exe.
+def MSVCOption : OptionFlag;
+
/////////
// Groups
@@ -97,8 +101,10 @@
// substitutions:
// _ => __
// - => _
+// / => _SLASH_
// # => _HASH
// , => _COMMA
+// ? => _QUESTION
// = => _EQ
// C++ => CXX
// . => _
@@ -114,6 +120,8 @@
class CCCDriverOpt : Group<ccc_driver_Group>, Flags<[DriverOption, HelpHidden]>;
def ccc_cxx : Flag<["-"], "ccc-cxx">, CCCDriverOpt,
HelpText<"Act as a C++ driver">;
+def ccc_msvc : Flag<["-"], "ccc-msvc">, CCCDriverOpt,
+ HelpText<"Act as Microsoft's cl.exe compiler. Must be the first argument.">;
def ccc_echo : Flag<["-"], "ccc-echo">, CCCDriverOpt,
HelpText<"Echo commands before running them">;
def ccc_gcc_name : Separate<["-"], "ccc-gcc-name">, CCCDriverOpt,
@@ -1306,3 +1314,5 @@
Flags<[LinkerInput, NoArgumentUnused, Unsupported]>, Group<reserved_lib_Group>;
include "CC1Options.td"
+
+include "MSVCOptions.td"
Index: lib/Driver/Driver.cpp
===================================================================
--- lib/Driver/Driver.cpp
+++ lib/Driver/Driver.cpp
@@ -81,11 +81,63 @@
delete I->second;
}
+InputArgList *Driver::ParseMSVCArgs(ArrayRef<const char *> ArgList,
+ unsigned &MissingArgIndex,
+ unsigned &MissingArgCount) {
+ InputArgList *Args = new InputArgList(ArgList.begin(), ArgList.end());
+
+ MissingArgIndex = MissingArgCount = 0;
+ unsigned Index = 0, End = ArgList.size();
+ while (Index < End) {
+ // Ignore empty arguments (other things may still take them as arguments).
+ if (Args->getArgString(Index)[0] == '\0') {
+ ++Index;
+ continue;
+ }
+
+ // Try to parse as if it's an MSVC arg and fall back to non-MSVC.
+ unsigned Next = Index;
+ Arg *A = getOpts().ParseOneArg(*Args, Next, options::MSVCOption);
+ assert(Next > Index && "Parser failed to consume argument.");
+
+ if (A && A->getOption().getKind() == Option::UnknownClass) {
+ delete A; // FIXME: Avoid useless mallocs.
+ Next = Index;
+ A = getOpts().ParseOneArg(*Args, Next, ~options::MSVCOption);
+ assert(Next > Index && "Parser failed to consume argument.");
+ }
+
+ if (!A) {
+ MissingArgIndex = Index;
+ MissingArgCount = Next - Index - 1;
+ break;
+ }
+
+ Args->append(A);
+ Index = Next;
+ }
+ assert(Index >= End && "Unexpected parser error.");
+
+ return Args;
+}
+
InputArgList *Driver::ParseArgStrings(ArrayRef<const char *> ArgList) {
llvm::PrettyStackTraceString CrashInfo("Command line argument parsing");
+
+ // If -ccc-msvc is the first argument, use a two-pass parse: do the initial
+ // parse with only MSVC flags, and then reparse every arg that we didn't match
+ // an MSVC option. This ensures that conflicting flags like -MD get
+ // interpreted as MSVC options without imposing tough sorting requirements on
+ // the option table.
+ bool IsMSVC = !ArgList.empty() && StringRef(ArgList[0]) == "-ccc-msvc";
+
unsigned MissingArgIndex, MissingArgCount;
- InputArgList *Args = getOpts().ParseArgs(ArgList.begin(), ArgList.end(),
- MissingArgIndex, MissingArgCount);
+ InputArgList *Args;
+ if (IsMSVC)
+ Args = ParseMSVCArgs(ArgList, MissingArgIndex, MissingArgCount);
+ else
+ Args = getOpts().ParseArgs(ArgList.begin(), ArgList.end(), MissingArgIndex,
+ MissingArgCount, 0, options::MSVCOption);
// Check for missing argument error.
if (MissingArgCount)
@@ -582,8 +634,9 @@
void Driver::PrintHelp(bool ShowHidden) const {
getOpts().PrintHelp(
- llvm::outs(), Name.c_str(), DriverTitle.c_str(), /*Include*/ 0,
- /*Exclude*/ options::NoDriverOption | (ShowHidden ? 0 : HelpHidden));
+ llvm::outs(), Name.c_str(), DriverTitle.c_str(), /*Include*/0,
+ /*Exclude*/options::NoDriverOption | options::MSVCOption |
+ (ShowHidden ? 0 : HelpHidden));
}
void Driver::PrintVersion(const Compilation &C, raw_ostream &OS) const {
@@ -639,6 +692,12 @@
return false;
}
+ if (C.getArgs().hasArg(options::OPT__QUESTION)) {
+ getOpts().PrintHelp(llvm::outs(), Name.c_str(), DriverTitle.c_str(),
+ options::MSVCOption, 0);
+ return false;
+ }
+
if (C.getArgs().hasArg(options::OPT__version)) {
// Follow gcc behavior and use stdout for --version and stderr for -v.
PrintVersion(C, llvm::outs());
Index: lib/Driver/DriverOptions.cpp
===================================================================
--- lib/Driver/DriverOptions.cpp
+++ lib/Driver/DriverOptions.cpp
@@ -15,7 +15,7 @@
using namespace clang::driver::options;
using namespace llvm::opt;
-#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE;
+#define PREFIX(NAME, VALUE) static const char *const NAME[] = VALUE;
#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, FLAGS, PARAM, \
HELPTEXT, METAVAR)
#include "clang/Driver/Options.inc"
Index: lib/Driver/ToolChains.h
===================================================================
--- lib/Driver/ToolChains.h
+++ lib/Driver/ToolChains.h
@@ -626,6 +626,13 @@
AddClangCXXStdlibIncludeArgs(const llvm::opt::ArgList &DriverArgs,
llvm::opt::ArgStringList &CC1Args) const;
+ /// \brief Translates any MSVC arguments that can be easily rewritten as
+ /// clang/gcc style arguments. Some, like /showIncludes, cannot be rewritten
+ /// and require support from clang -cc1.
+ virtual llvm::opt::DerivedArgList *
+ TranslateArgs(const llvm::opt::DerivedArgList &Args,
+ const char *BoundArch) const;
+
protected:
virtual Tool *buildLinker() const;
virtual Tool *buildAssembler() const;
Index: lib/Driver/WindowsToolChain.cpp
===================================================================
--- lib/Driver/WindowsToolChain.cpp
+++ lib/Driver/WindowsToolChain.cpp
@@ -340,3 +340,126 @@
ArgStringList &CC1Args) const {
// FIXME: There should probably be logic here to find libc++ on Windows.
}
+
+static bool TranslateMSVCRTFlag(const ToolChain *TC, const Arg *A,
+ DerivedArgList *DAL, const OptTable &Opts,
+ unsigned OptId) {
+ switch (OptId) {
+ case options::OPT__SLASH_MDd:
+ DAL->AddJoinedArg(A, Opts.getOption(options::OPT_D), "_DEBUG");
+ DAL->AddJoinedArg(A, Opts.getOption(options::OPT_D), "_DLL");
+ break;
+ case options::OPT__SLASH_MD:
+ DAL->AddJoinedArg(A, Opts.getOption(options::OPT_D), "_DLL");
+ break;
+ case options::OPT__SLASH_MTd:
+ DAL->AddJoinedArg(A, Opts.getOption(options::OPT_D), "_DEBUG");
+ break;
+ case options::OPT__SLASH_MT:
+ break;
+ default:
+ return false;
+ }
+ // Hack: include a header that uses pragmas to auto-link the default CRT.
+ DAL->AddSeparateArg(A, Opts.getOption(options::OPT_include),
+ TC->GetFilePath("include/msvcrt_picker.h"));
+ return true;
+}
+
+// Optimization aliases. We can't alias these in tablegen because clang's -O
+// option is joined.
+static bool TranslateOptimizationFlag(const Arg *A, DerivedArgList *DAL,
+ const OptTable &Opts, unsigned OptId) {
+ const char *Alias;
+ switch (OptId) {
+ case options::OPT_Od: Alias = "0"; break;
+ case options::OPT_Ot: Alias = "2"; break;
+ case options::OPT_Ox: Alias = "3"; break;
+ case options::OPT__SLASH_O: Alias = A->getValue(); break;
+ default:
+ return false;
+ }
+ DAL->AddJoinedArg(A, Opts.getOption(options::OPT_O), Alias);
+ return true;
+}
+
+static bool TranslateWarningFlag(const Arg *A, DerivedArgList *DAL,
+ const OptTable &Opts, unsigned OptId) {
+ const char *Alias;
+ switch (OptId) {
+ case options::OPT__SLASH_W1:
+ case options::OPT__SLASH_W2:
+ case options::OPT__SLASH_W3:
+ // Just use -Wall, since that's a pretty good default.
+ Alias = "all";
+ break;
+ case options::OPT__SLASH_WX:
+ Alias = "error";
+ break;
+ case options::OPT__SLASH_WX_:
+ Alias = "no-error";
+ break;
+ default:
+ return false;
+ }
+ DAL->AddJoinedArg(A, Opts.getOption(options::OPT_O), Alias);
+ return true;
+}
+
+DerivedArgList *Windows::TranslateArgs(const DerivedArgList &Args,
+ const char *BoundArch) const {
+ // We could be using the windows toolchain without MSVC argument emulation.
+ if (!Args.hasArg(options::OPT_ccc_msvc))
+ return 0;
+
+ DerivedArgList *DAL = new DerivedArgList(Args.getBaseArgs());
+ const OptTable &Opts = getDriver().getOpts();
+
+ for (ArgList::const_iterator it = Args.begin(),
+ ie = Args.end(); it != ie; ++it) {
+ Arg *A = *it;
+ Option Opt = A->getOption();
+
+ // Pass through all non-MSVC args.
+ if (!Opt.hasFlag(options::MSVCOption)) {
+ DAL->append(A);
+ continue;
+ }
+
+ unsigned ID = Opt.getID();
+
+ // Re-parse escaped arguments
+ // FIXME: Should -Xclang-driver always go to the driver, even on
+ // non-Windows?
+ if (ID == options::OPT_Xclang_driver) {
+ unsigned Index = Args.getBaseArgs().MakeIndex(A->getValue());
+ unsigned Prev = Index;
+ Arg *NewArg = Opts.ParseOneArg(Args, Index);
+ if (!NewArg || Index > Prev + 1) {
+ // FIXME: Passing separated options with values to the driver is
+ // unsupported. Fortunately, all known conflicts are for flag or joined
+ // style options.
+ getDriver().Diag(diag::err_drv_unknown_argument)
+ << A->getAsString(Args);
+ } else {
+ NewArg->setBaseArg(A);
+ DAL->append(NewArg);
+ }
+ continue;
+ }
+
+ if (TranslateMSVCRTFlag(this, A, DAL, Opts, ID))
+ continue;
+
+ if (TranslateOptimizationFlag(A, DAL, Opts, ID))
+ continue;
+
+ if (TranslateWarningFlag(A, DAL, Opts, ID))
+ continue;
+
+ // We may have this option in tablegen, but we can't yet translate it.
+ // Ignore it and leave it unclaimed so the driver warns.
+ }
+
+ return DAL;
+}
Index: lib/Headers/CMakeLists.txt
===================================================================
--- lib/Headers/CMakeLists.txt
+++ lib/Headers/CMakeLists.txt
@@ -41,6 +41,7 @@
xopintrin.h
cpuid.h
unwind.h
+ msvcrt_picker.h
module.map
)
Index: lib/Headers/msvcrt_picker.h
===================================================================
--- /dev/null
+++ lib/Headers/msvcrt_picker.h
@@ -0,0 +1,50 @@
+/*===---- msvcrt_picker.h - C runtime picker -------------------------------===
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ *===-----------------------------------------------------------------------===
+ */
+
+#ifndef __MSVCRT_PICKER_H
+#define __MSVCRT_PICKER_H
+
+/* This will cause link.exe to automatically link the usual C runtime. */
+#ifdef _DLL
+# ifdef _DEBUG
+# pragma comment(lib, "msvcrtd")
+# else
+# pragma comment(lib, "msvcrt")
+# endif
+#else
+# ifdef _DEBUG
+# pragma comment(lib, "libcmtd")
+# else
+# pragma comment(lib, "libcmt")
+# endif
+#endif
+
+/* FIXME: Check if we need to auto-link the C++ runtime. */
+
+/* This provides POSIX compatibility (maps 'open' to '_open'), which most users
+ * want. MSVC has a switch to turn off this autolinking, but it's not
+ * implemented in clang yet.
+ */
+#pragma comment(lib, "OLDNAMES")
+
+#endif /* __MSVCRT_PICKER_H */
Index: test/Driver/ccc-msvc.cpp
===================================================================
--- /dev/null
+++ test/Driver/ccc-msvc.cpp
@@ -0,0 +1,26 @@
+// Test some simple aliases. Constructing the compile job re-orders the
+// arguments, hence -DAG.
+//
+// RUN: %clang -ccc-msvc /Ox /Oy- /Ob0 /GR- /MDd -c %s -### 2>&1 | FileCheck %s
+// CHECK-DAG: "-O3"
+// CHECK-DAG: "-mdisable-fp-elim"
+// CHECK-DAG: "-fno-inline-functions"
+// CHECK-DAG: "-fno-rtti"
+// CHECK-DAG: "-D" "_DLL"
+// CHECK-DAG: "-D" "_DEBUG"
+// CHECK-DAG: "-include" "{{.*}}msvcrt_picker.h"
+
+// By default (no -ccc-msvc arg), the driver should not try to emulate MSVC.
+//
+// RUN: %clang /Od /GR- /MDd -c %s -### 2>&1 | FileCheck -check-prefix=NOTMSVC %s
+// NOTMSVC: error: no such file or directory: '/Od'
+// NOTMSVC: error: no such file or directory: '/GR-'
+
+// Test escaping with -Xclang-driver.
+//
+// RUN: %clang -ccc-msvc -MD -c %s -### 2>&1 | FileCheck -check-prefix=MDMSVC %s
+// MDMSVC-DAG: "-D" "_DLL"
+// MDMSVC-DAG: "-include" "{{.*}}msvcrt_picker.h"
+// RUN: %clang -ccc-msvc -Xclang-driver -MD -c %s -### 2>&1 | FileCheck -check-prefix=MDGCC %s
+// MDGCC-NOT: Xclang-driver
+// MDGCC: "-dependency-file"
Index: tools/driver/CMakeLists.txt
===================================================================
--- tools/driver/CMakeLists.txt
+++ tools/driver/CMakeLists.txt
@@ -73,8 +73,13 @@
add_custom_command(TARGET clang POST_BUILD
COMMAND ${CMAKE_COMMAND} -E ${CLANGXX_LINK_OR_COPY} "${clang_binary}" "${clang_pp}")
+# Create the clang++ symlink in the build directory.
+set(clang_cl "${LLVM_BINARY_DIR}/bin/${CMAKE_CFG_INTDIR}/clang-cl${CMAKE_EXECUTABLE_SUFFIX}")
+add_custom_command(TARGET clang POST_BUILD
+ COMMAND ${CMAKE_COMMAND} -E ${CLANGXX_LINK_OR_COPY} "${clang_binary}" "${clang_cl}")
+
set_property(DIRECTORY APPEND
- PROPERTY ADDITIONAL_MAKE_CLEAN_FILES ${clang_pp})
+ PROPERTY ADDITIONAL_MAKE_CLEAN_FILES ${clang_pp} ${clang_cl})
install(TARGETS clang
RUNTIME DESTINATION bin)
Index: tools/driver/clang_symlink.cmake
===================================================================
--- tools/driver/clang_symlink.cmake
+++ tools/driver/clang_symlink.cmake
@@ -19,9 +19,13 @@
set(bindir "${CLANGXX_DESTDIR}${CMAKE_INSTALL_PREFIX}/bin/")
set(clang "clang${EXECUTABLE_SUFFIX}")
set(clangxx "clang++${EXECUTABLE_SUFFIX}")
+set(clang_cl "clang-cl${EXECUTABLE_SUFFIX}")
message("Creating clang++ executable based on ${clang}")
execute_process(
COMMAND "${CMAKE_COMMAND}" -E ${CLANGXX_LINK_OR_COPY} "${clang}" "${clangxx}"
WORKING_DIRECTORY "${bindir}")
+execute_process(
+ COMMAND "${CMAKE_COMMAND}" -E ${CLANGXX_LINK_OR_COPY} "${clang}" "${clang_cl}"
+ WORKING_DIRECTORY "${bindir}")
Index: tools/driver/driver.cpp
===================================================================
--- tools/driver/driver.cpp
+++ tools/driver/driver.cpp
@@ -28,6 +28,7 @@
#include "llvm/Option/ArgList.h"
#include "llvm/Option/OptTable.h"
#include "llvm/Option/Option.h"
+#include "llvm/Support/ConvertUTF.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Host.h"
@@ -39,6 +40,7 @@
#include "llvm/Support/Program.h"
#include "llvm/Support/Regex.h"
#include "llvm/Support/Signals.h"
+#include "llvm/Support/SwapByteOrder.h"
#include "llvm/Support/TargetRegistry.h"
#include "llvm/Support/TargetSelect.h"
#include "llvm/Support/Timer.h"
@@ -296,6 +298,10 @@
{ "++", true, false },
};
std::string ProgName(llvm::sys::path::stem(ArgVector[0]));
+#ifdef LLVM_ON_WIN32
+ // Windows paths are case insensitive.
+ std::transform(ProgName.begin(), ProgName.end(), ProgName.begin(), ::tolower);
+#endif
StringRef ProgNameRef(ProgName);
StringRef Prefix;
@@ -314,6 +320,11 @@
}
}
+ // If we were invoked as cl.exe, add the flag that makes us accept MSVC
+ // arguments.
+ if (ProgNameRef.endswith("cl"))
+ ArgVector.insert(ArgVector.begin() + 1, "-ccc-msvc");
+
if (FoundMatch) {
StringRef::size_type LastComponent = ProgNameRef.rfind('-',
ProgNameRef.size() - strlen(suffixes[i].Suffix));
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits