Add /reproduce option to lld/COFF
authorRui Ueyama <ruiu@google.com>
Fri, 4 Oct 2019 07:27:38 +0000 (07:27 +0000)
committerRui Ueyama <ruiu@google.com>
Fri, 4 Oct 2019 07:27:38 +0000 (07:27 +0000)
This patch adds /reproduce:<path> option to lld/COFF. This is an
lld-specific option, so we can name it freely. I chose /reproduce
over other names (e.g. /lldlinkrepro) for consistency with other lld
ports.

Differential Revision: https://reviews.llvm.org/D68381

llvm-svn: 373704

lld/COFF/Driver.cpp
lld/COFF/Options.td
lld/test/COFF/linkrepro.test

index 24814cc..4bd9dc6 100644 (file)
@@ -603,6 +603,7 @@ static std::string createResponseFile(const opt::InputArgList &args,
   for (auto *arg : args) {
     switch (arg->getOption().getID()) {
     case OPT_linkrepro:
+    case OPT_reproduce:
     case OPT_INPUT:
     case OPT_defaultlib:
     case OPT_libpath:
@@ -1071,6 +1072,26 @@ void LinkerDriver::maybeExportMinGWSymbols(const opt::InputArgList &args) {
   });
 }
 
+// lld has a feature to create a tar file containing all input files as well as
+// all command line options, so that other people can run lld again with exactly
+// the same inputs. This feature is accessible via /linkrepro and /reproduce.
+//
+// /linkrepro and /reproduce are very similar, but /linkrepro takes a directory
+// name while /reproduce takes a full path. We have /linkrepro for compatibility
+// with Microsoft link.exe.
+Optional<std::string> getReproduceFile(const opt::InputArgList &args) {
+  if (auto *arg = args.getLastArg(OPT_reproduce))
+    return std::string(arg->getValue());
+
+  if (auto *arg = args.getLastArg(OPT_linkrepro)) {
+    SmallString<64> path = StringRef(arg->getValue());
+    sys::path::append(path, "repro.tar");
+    return path.str().str();
+  }
+
+  return None;
+}
+
 void LinkerDriver::link(ArrayRef<const char *> argsArr) {
   // Needed for LTO.
   InitializeAllTargetInfos();
@@ -1133,17 +1154,15 @@ void LinkerDriver::link(ArrayRef<const char *> argsArr) {
   // options are handled.
   config->mingw = args.hasArg(OPT_lldmingw);
 
-  if (auto *arg = args.getLastArg(OPT_linkrepro)) {
-    SmallString<64> path = StringRef(arg->getValue());
-    sys::path::append(path, "repro.tar");
-
+  // Handle /linkrepro and /reproduce.
+  if (Optional<std::string> path = getReproduceFile(args)) {
     Expected<std::unique_ptr<TarWriter>> errOrWriter =
-        TarWriter::create(path, "repro");
+        TarWriter::create(*path, sys::path::stem(*path));
 
     if (errOrWriter) {
       tar = std::move(*errOrWriter);
     } else {
-      error("/linkrepro: failed to open " + path + ": " +
+      error("/linkrepro: failed to open " + *path + ": " +
             toString(errOrWriter.takeError()));
     }
   }
index d6d2e91..9e58d92 100644 (file)
@@ -112,6 +112,8 @@ def noentry : F<"noentry">,
 def profile : F<"profile">;
 def repro : F<"Brepro">,
     HelpText<"Use a hash of the executable as the PE header timestamp">;
+def reproduce : P<"reproduce",
+    "Dump linker invocation and input files for debugging">;
 def swaprun : P<"swaprun",
   "Comma-separated list of 'cd' or 'net'">;
 def swaprun_cd : F<"swaprun:cd">, Alias<swaprun>, AliasArgs<["cd"]>,
index 8f42234..a2a9d64 100644 (file)
 # RUN: diff %p/Inputs/std32.lib repro/%:p/Inputs/std32.lib
 # RUN: FileCheck %s --check-prefix=RSP < repro/response.txt
 
+# RUN: cd %t.dir/build1
+# RUN: lld-link %t.obj %p/Inputs/std32.lib /subsystem:console \
+# RUN:   /entry:main@0 /reproduce:repro2.tar /out:%t.exe
+# RUN: tar xf repro2.tar
+# RUN: diff %t.obj repro2/%:t.obj
+# RUN: diff %p/Inputs/std32.lib repro2/%:p/Inputs/std32.lib
+# RUN: FileCheck %s --check-prefix=RSP < repro2/response.txt
+
 # RUN: cd %t.dir/build2
 # RUN: lld-link %t.obj /libpath:%p/Inputs /defaultlib:std32 /subsystem:console \
 # RUN:   /entry:main@0 /linkrepro:. /out:%t.exe