Hi rnk,

This patch adds support for building DLLs (the /LD and /LDd flags). It 
basically does two things: runtime selection and passing -dll and -implib to 
the linker.

http://llvm-reviews.chandlerc.com/D1632

Files:
  include/clang/Driver/CLCompatOptions.td
  include/clang/Driver/Types.def
  lib/Driver/Driver.cpp
  lib/Driver/Tools.cpp
  test/Driver/cl-link.c
  test/Driver/cl-outputs.c
  test/Driver/cl-runtime-flags.c
Index: include/clang/Driver/CLCompatOptions.td
===================================================================
--- include/clang/Driver/CLCompatOptions.td
+++ include/clang/Driver/CLCompatOptions.td
@@ -99,6 +99,8 @@
 def _SLASH_Fo : CLJoined<"Fo">,
   HelpText<"Set output object file, or directory (ends in / or \\)">,
   MetaVarName<"<file or directory>">;
+def _SLASH_LD : CLFlag<"LD">, HelpText<"Create DLL">;
+def _SLASH_LDd : CLFlag<"LDd">, HelpText<"Create debug DLL">;
 def _SLASH_link : CLRemainingArgs<"link">,
   HelpText<"Forward options to the linker">, MetaVarName<"<options>">;
 def _SLASH_MD : CLFlag<"MD">,
Index: include/clang/Driver/Types.def
===================================================================
--- include/clang/Driver/Types.def
+++ include/clang/Driver/Types.def
@@ -90,5 +90,6 @@
 TYPE("treelang",                 Treelang,     INVALID,         0,       "u")
 TYPE("image",                    Image,        INVALID,         "out",   "")
 TYPE("dSYM",                     dSYM,         INVALID,         "dSYM",  "A")
+TYPE("dll",                      dll,          INVALID,         "dll",   "")
 TYPE("dependencies",             Dependencies, INVALID,         "d",     "")
 TYPE("none",                     Nothing,      INVALID,         0,       "u")
Index: lib/Driver/Driver.cpp
===================================================================
--- lib/Driver/Driver.cpp
+++ lib/Driver/Driver.cpp
@@ -1263,8 +1263,12 @@
   }
 
   // Add a link action if necessary.
-  if (!LinkerInputs.empty())
-    Actions.push_back(new LinkJobAction(LinkerInputs, types::TY_Image));
+  if (!LinkerInputs.empty()) {
+    bool DLL = Args.hasArg(options::OPT__SLASH_LD) ||
+               Args.hasArg(options::OPT__SLASH_LDd);
+    Actions.push_back(new LinkJobAction(LinkerInputs, DLL ? types::TY_dll
+                                                          : types::TY_Image));
+  }
 
   // If we are linking, claim any options which are obviously only used for
   // compilation.
@@ -1650,17 +1654,20 @@
     StringRef Val = C.getArgs().getLastArg(options::OPT__SLASH_Fo)->getValue();
     NamedOutput = MakeCLOutputFilename(C.getArgs(), Val, BaseName,
                                        types::TY_Object);
-  } else if (JA.getType() == types::TY_Image &&
+  } else if ((JA.getType() == types::TY_Image ||
+              JA.getType() == types::TY_dll) &&
              C.getArgs().hasArg(options::OPT__SLASH_Fe)) {
     // The /Fe flag names the linked file.
     StringRef Val = C.getArgs().getLastArg(options::OPT__SLASH_Fe)->getValue();
     NamedOutput = MakeCLOutputFilename(C.getArgs(), Val, BaseName,
-                                       types::TY_Image);
-  } else if (JA.getType() == types::TY_Image) {    
+                                       JA.getType());
+  } else if (JA.getType() == types::TY_Image ||
+             JA.getType() == types::TY_dll) {    
     if (IsCLMode()) {
       // clang-cl uses BaseName for the executable name.
       SmallString<128> Filename = BaseName;
-      llvm::sys::path::replace_extension(Filename, "exe");
+      const char *Extension = types::getTypeTempSuffix(JA.getType(), true);
+      llvm::sys::path::replace_extension(Filename, Extension);
       NamedOutput = C.getArgs().MakeArgString(Filename.c_str());
     } else if (MultipleArchs && BoundArch) {
       SmallString<128> Output(DefaultImageName.c_str());
Index: lib/Driver/Tools.cpp
===================================================================
--- lib/Driver/Tools.cpp
+++ lib/Driver/Tools.cpp
@@ -3714,6 +3714,11 @@
 void Clang::AddClangCLArgs(const ArgList &Args, ArgStringList &CmdArgs) const {
   unsigned RTOptionID = options::OPT__SLASH_MT;
 
+  if (Args.hasArg(options::OPT__SLASH_LDd))
+    // The /LDd option implies /MTd. The dependent lib part can be overridden,
+    // but defining _DEBUG is sticky.
+    RTOptionID = options::OPT__SLASH_MTd;
+
   if (Arg *A = Args.getLastArg(options::OPT__SLASH_MD,
                                options::OPT__SLASH_MDd,
                                options::OPT__SLASH_MT,
@@ -3723,6 +3728,8 @@
 
   switch(RTOptionID) {
     case options::OPT__SLASH_MD:
+      if (Args.hasArg(options::OPT__SLASH_LDd))
+        CmdArgs.push_back("-D_DEBUG");
       CmdArgs.push_back("-D_MT");
       CmdArgs.push_back("-D_DLL");
       CmdArgs.push_back("--dependent-lib=msvcrt");
@@ -3734,6 +3741,8 @@
       CmdArgs.push_back("--dependent-lib=msvcrtd");
       break;
     case options::OPT__SLASH_MT:
+      if (Args.hasArg(options::OPT__SLASH_LDd))
+        CmdArgs.push_back("-D_DEBUG");
       CmdArgs.push_back("-D_MT");
       CmdArgs.push_back("--dependent-lib=libcmt");
       break;
@@ -6579,13 +6588,30 @@
 
   CmdArgs.push_back("-nologo");
 
+  bool DLL = Args.hasArg(options::OPT__SLASH_LD) ||
+             Args.hasArg(options::OPT__SLASH_LDd);
+
+  if (DLL) {
+    CmdArgs.push_back(Args.MakeArgString("-dll"));
+
+    SmallString<128> ImplibName(Output.getFilename());
+    llvm::sys::path::replace_extension(ImplibName, "lib");
+    CmdArgs.push_back(Args.MakeArgString(std::string("-implib:") +
+                                         ImplibName.str()));
+  }
+
   if (getToolChain().getDriver().getOrParseSanitizerArgs(Args).needsAsanRt()) {
     CmdArgs.push_back(Args.MakeArgString("-debug"));
     CmdArgs.push_back(Args.MakeArgString("-incremental:no"));
     SmallString<128> LibSanitizer(getToolChain().getDriver().ResourceDir);
-    // FIXME: Handle 64-bit. Use asan_dll_thunk.dll when building a DLL.
-    llvm::sys::path::append(
-        LibSanitizer, "lib", "windows", "clang_rt.asan-i386.lib");
+    llvm::sys::path::append(LibSanitizer, "lib", "windows");
+    if (DLL) {
+      // FIXME: Not sure what the final name of the thunk lib is.
+      llvm::sys::path::append(LibSanitizer, "clang_rt.asan-i386-dll_thunk.lib");
+    } else {
+      llvm::sys::path::append(LibSanitizer, "clang_rt.asan-i386.lib");
+    }
+    // FIXME: Handle 64-bit.
     CmdArgs.push_back(Args.MakeArgString(LibSanitizer));
   }
 
Index: test/Driver/cl-link.c
===================================================================
--- test/Driver/cl-link.c
+++ test/Driver/cl-link.c
@@ -17,3 +17,17 @@
 // ASAN: "-incremental:no"
 // ASAN: "{{.*}}clang_rt.asan-i386.lib"
 // ASAN: "{{.*}}cl-link{{.*}}.obj"
+
+// RUN: %clang_cl /LD -### %s 2>&1 | FileCheck --check-prefix=DLL %s
+// RUN: %clang_cl /LDd -### %s 2>&1 | FileCheck --check-prefix=DLL %s
+// DLL: link.exe
+// "-dll"
+
+// RUN: %clang_cl /LD /Tc%s -### -fsanitize=address 2>&1 | FileCheck --check-prefix=ASAN-DLL %s
+// RUN: %clang_cl /LDd /Tc%s -### -fsanitize=address 2>&1 | FileCheck --check-prefix=ASAN-DLL %s
+// ASAN-DLL: link.exe
+// ASAN-DLL: "-dll"
+// ASAN-DLL: "-debug"
+// ASAN-DLL: "-incremental:no"
+// ASAN-DLL: "{{.*}}clang_rt.asan-i386-dll_thunk.lib"
+// ASAN-DLL: "{{.*}}cl-link{{.*}}.obj"
Index: test/Driver/cl-outputs.c
===================================================================
--- test/Driver/cl-outputs.c
+++ test/Driver/cl-outputs.c
@@ -39,24 +39,54 @@
 // RUN: %clang_cl -### -- %s 2>&1 | FileCheck -check-prefix=DEFAULTEXE %s
 // DEFAULTEXE: cl-outputs.exe
 
+// RUN: %clang_cl /LD -### -- %s 2>&1 | FileCheck -check-prefix=DEFAULTDLL %s
+// RUN: %clang_cl /LDd -### -- %s 2>&1 | FileCheck -check-prefix=DEFAULTDLL %s
+// DEFAULTDLL: "-out:cl-outputs.dll"
+// DEFAULTDLL: "-implib:cl-outputs.lib"
+
 // RUN: %clang_cl /Fefoo -### -- %s 2>&1 | FileCheck -check-prefix=FeNOEXT %s
-// FeNOEXT: foo.exe
+// FeNOEXT: "-out:foo.exe"
+
+// RUN: %clang_cl /Fefoo /LD -### -- %s 2>&1 | FileCheck -check-prefix=FeNOEXTDLL %s
+// RUN: %clang_cl /Fefoo /LDd -### -- %s 2>&1 | FileCheck -check-prefix=FeNOEXTDLL %s
+// FeNOEXTDLL: "-out:foo.dll"
+// FeNOEXTDLL: "-implib:foo.lib"
 
 // RUN: %clang_cl /Fefoo.ext -### -- %s 2>&1 | FileCheck -check-prefix=FeEXT %s
-// FeEXT: foo.ext
+// FeEXT: "-out:foo.ext"
+
+// RUN: %clang_cl /LD /Fefoo.ext -### -- %s 2>&1 | FileCheck -check-prefix=FeEXTDLL %s
+// RUN: %clang_cl /LDd /Fefoo.ext -### -- %s 2>&1 | FileCheck -check-prefix=FeEXTDLL %s
+// FeEXTDLL: "-out:foo.ext"
+// FeEXTDLL: "-implib:foo.lib"
 
 // RUN: %clang_cl /Fefoo.dir/ -### -- %s 2>&1 | FileCheck -check-prefix=FeDIR %s
-// FeDIR: foo.dir{{[/\\]+}}cl-outputs.exe
+// FeDIR: "-out:foo.dir{{[/\\]+}}cl-outputs.exe"
+
+// RUN: %clang_cl /LD /Fefoo.dir/ -### -- %s 2>&1 | FileCheck -check-prefix=FeDIRDLL %s
+// RUN: %clang_cl /LDd /Fefoo.dir/ -### -- %s 2>&1 | FileCheck -check-prefix=FeDIRDLL %s
+// FeDIRDLL: "-out:foo.dir{{[/\\]+}}cl-outputs.dll"
+// FeDIRDLL: "-implib:foo.dir{{[/\\]+}}cl-outputs.lib"
 
 // RUN: %clang_cl /Fefoo.dir/a -### -- %s 2>&1 | FileCheck -check-prefix=FeDIRNAME %s
-// FeDIRNAME: foo.dir{{[/\\]+}}a.exe
+// FeDIRNAME: "-out:foo.dir{{[/\\]+}}a.exe"
+
+// RUN: %clang_cl /LD /Fefoo.dir/a -### -- %s 2>&1 | FileCheck -check-prefix=FeDIRNAMEDLL %s
+// RUN: %clang_cl /LDd /Fefoo.dir/a -### -- %s 2>&1 | FileCheck -check-prefix=FeDIRNAMEDLL %s
+// FeDIRNAMEDLL: "-out:foo.dir{{[/\\]+}}a.dll"
+// FeDIRNAMEDLL: "-implib:foo.dir{{[/\\]+}}a.lib"
 
 // RUN: %clang_cl /Fefoo.dir/a.ext -### -- %s 2>&1 | FileCheck -check-prefix=FeDIRNAMEEXT %s
-// FeDIRNAMEEXT: foo.dir{{[/\\]+}}a.ext
+// FeDIRNAMEEXT: "-out:foo.dir{{[/\\]+}}a.ext"
+
+// RUN: %clang_cl /LD /Fefoo.dir/a.ext -### -- %s 2>&1 | FileCheck -check-prefix=FeDIRNAMEEXTDLL %s
+// RUN: %clang_cl /LDd /Fefoo.dir/a.ext -### -- %s 2>&1 | FileCheck -check-prefix=FeDIRNAMEEXTDLL %s
+// FeDIRNAMEEXTDLL: "-out:foo.dir{{[/\\]+}}a.ext"
+// FeDIRNAMEEXTDLL: "-implib:foo.dir{{[/\\]+}}a.lib"
 
 // RUN: %clang_cl /Fe -### 2>&1 | FileCheck -check-prefix=FeMISSINGARG %s
 // FeMISSINGARG: error: argument to '/Fe' is missing (expected 1 value)
 
 // RUN: %clang_cl /Fefoo /Febar -### -- %s 2>&1 | FileCheck -check-prefix=FeOVERRIDE %s
 // FeOVERRIDE: warning: overriding '/Fefoo' option with '/Febar'
-// FeOVERRIDE: bar.exe
+// FeOVERRIDE: "-out:bar.exe"
Index: test/Driver/cl-runtime-flags.c
===================================================================
--- test/Driver/cl-runtime-flags.c
+++ test/Driver/cl-runtime-flags.c
@@ -20,6 +20,7 @@
 // CHECK-MT: "--dependent-lib=oldnames"
 
 // RUN: %clang_cl -### /MTd -- %s 2>&1 | FileCheck -check-prefix=CHECK-MTd %s
+// RUN: %clang_cl -### /LD /MTd -- %s 2>&1 | FileCheck -check-prefix=CHECK-MTd %s
 // CHECK-MTd: "-D_DEBUG"
 // CHECK-MTd: "-D_MT"
 // CHECK-MTd-NOT: "-D_DLL"
@@ -39,3 +40,47 @@
 // CHECK-MDd: "-D_DLL"
 // CHECK-MDd: "--dependent-lib=msvcrtd"
 // CHECK-MDd: "--dependent-lib=oldnames"
+
+// RUN: %clang_cl -### /LD -- %s 2>&1 | FileCheck -check-prefix=CHECK-LD %s
+// RUN: %clang_cl -### /LD /MT -- %s 2>&1 | FileCheck -check-prefix=CHECK-LD %s
+// CHECK-LD-NOT: "-D_DEBUG"
+// CHECK-LD: "-D_MT"
+// CHECK-LD-NOT: "-D_DLL"
+// CHECK-LD: "--dependent-lib=libcmt"
+
+// RUN: %clang_cl -### /LDd -- %s 2>&1 | FileCheck -check-prefix=CHECK-LDd %s
+// RUN: %clang_cl -### /LDd /MTd -- %s 2>&1 | FileCheck -check-prefix=CHECK-LDd %s
+// CHECK-LDd: "-D_DEBUG"
+// CHECK-LDd: "-D_MT"
+// CHECK-LDd-NOT: "-D_DLL"
+// CHECK-LDd: "--dependent-lib=libcmtd"
+
+// RUN: %clang_cl -### /LDd /MT -- %s 2>&1 | FileCheck -check-prefix=CHECK-LDdMT %s
+// RUN: %clang_cl -### /MT /LDd -- %s 2>&1 | FileCheck -check-prefix=CHECK-LDdMT %s
+// CHECK-LDdMT: "-D_DEBUG"
+// CHECK-LDdMT: "-D_MT"
+// CHECK-LDdMT-NOT: "-D_DLL"
+// CHECK-LDdMT: "--dependent-lib=libcmt"
+
+// RUN: %clang_cl -### /LD /MD -- %s 2>&1 | FileCheck -check-prefix=CHECK-LDMD %s
+// RUN: %clang_cl -### /MD /LD -- %s 2>&1 | FileCheck -check-prefix=CHECK-LDMD %s
+// CHECK-LDMD-NOT: "-D_DEBUG"
+// CHECK-LDMD: "-D_MT"
+// CHECK-LDMD: "-D_DLL"
+// CHECK-LDMD: "--dependent-lib=msvcrt"
+
+// RUN: %clang_cl -### /LDd /MD -- %s 2>&1 | FileCheck -check-prefix=CHECK-LDdMD %s
+// RUN: %clang_cl -### /MD /LDd -- %s 2>&1 | FileCheck -check-prefix=CHECK-LDdMD %s
+// CHECK-LDdMD: "-D_DEBUG"
+// CHECK-LDdMD: "-D_MT"
+// CHECK-LDdMD: "-D_DLL"
+// CHECK-LDdMD: "--dependent-lib=msvcrt"
+
+// RUN: %clang_cl -### /LD /MDd -- %s 2>&1 | FileCheck -check-prefix=CHECK-LDMDd %s
+// RUN: %clang_cl -### /MDd /LD -- %s 2>&1 | FileCheck -check-prefix=CHECK-LDMDd %s
+// RUN: %clang_cl -### /LDd /MDd -- %s 2>&1 | FileCheck -check-prefix=CHECK-LDMDd %s
+// RUN: %clang_cl -### /MDd /LDd -- %s 2>&1 | FileCheck -check-prefix=CHECK-LDMDd %s
+// CHECK-LDMDd: "-D_DEBUG"
+// CHECK-LDMDd: "-D_MT"
+// CHECK-LDMDd: "-D_DLL"
+// CHECK-LDMDd: "--dependent-lib=msvcrtd"
_______________________________________________
cfe-commits mailing list
cfe-commits@cs.uiuc.edu
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits

Reply via email to