COFF: Fix default output file path.
authorRui Ueyama <ruiu@google.com>
Sun, 7 Jun 2015 00:20:32 +0000 (00:20 +0000)
committerRui Ueyama <ruiu@google.com>
Sun, 7 Jun 2015 00:20:32 +0000 (00:20 +0000)
Default output filename is the same as the first object file's
name with its extension replaced with ".exe".

llvm-svn: 239238

lld/COFF/Config.h
lld/COFF/Driver.cpp
lld/test/COFF/out.test [new file with mode: 0644]

index a49906c..34fec7f 100644 (file)
@@ -29,6 +29,7 @@ public:
   bool Verbose = false;
   WindowsSubsystem Subsystem = llvm::COFF::IMAGE_SUBSYSTEM_UNKNOWN;
   StringRef EntryName;
+  std::string OutputFile;
 
   // Symbols in this set are considered as live by the garbage collector.
   std::set<StringRef> GCRoots;
index 0700f1a..b40a3a7 100644 (file)
@@ -49,17 +49,11 @@ bool link(int Argc, const char *Argv[]) {
   return Driver->link(Argc, Argv);
 }
 
-static std::string getOutputPath(llvm::opt::InputArgList *Args) {
-  if (auto *Arg = Args->getLastArg(OPT_out))
-    return Arg->getValue();
-  for (auto *Arg : Args->filtered(OPT_INPUT)) {
-    if (!StringRef(Arg->getValue()).endswith_lower(".obj"))
-      continue;
-    SmallString<128> Val = StringRef(Arg->getValue());
-    llvm::sys::path::replace_extension(Val, ".exe");
-    return Val.str();
-  }
-  llvm_unreachable("internal error");
+// Drop directory components and replace extension with ".exe".
+static std::string getOutputPath(StringRef Path) {
+  auto P = Path.find_last_of("\\/");
+  StringRef S = (P == StringRef::npos) ? Path : Path.substr(P + 1);
+  return (S.substr(0, S.rfind('.')) + ".exe").str();
 }
 
 // Opens a file. Path has to be resolved already.
@@ -78,6 +72,8 @@ ErrorOr<std::unique_ptr<InputFile>> LinkerDriver::openFile(StringRef Path) {
     return std::unique_ptr<InputFile>(new ArchiveFile(MBRef));
   if (Magic == file_magic::bitcode)
     return std::unique_ptr<InputFile>(new BitcodeFile(MBRef));
+  if (Config->OutputFile == "")
+    Config->OutputFile = getOutputPath(Path);
   return std::unique_ptr<InputFile>(new ObjectFile(MBRef));
 }
 
@@ -226,6 +222,10 @@ bool LinkerDriver::link(int Argc, const char *Argv[]) {
     return false;
   }
 
+  // Handle /out
+  if (auto *Arg = Args->getLastArg(OPT_out))
+    Config->OutputFile = Arg->getValue();
+
   // Handle /verbose
   if (Args->hasArg(OPT_verbose))
     Config->Verbose = true;
@@ -412,7 +412,7 @@ bool LinkerDriver::link(int Argc, const char *Argv[]) {
 
   // Write the result.
   Writer Out(&Symtab);
-  if (auto EC = Out.write(getOutputPath(Args.get()))) {
+  if (auto EC = Out.write(Config->OutputFile)) {
     llvm::errs() << EC.message() << "\n";
     return false;
   }
diff --git a/lld/test/COFF/out.test b/lld/test/COFF/out.test
new file mode 100644 (file)
index 0000000..84a8282
--- /dev/null
@@ -0,0 +1,16 @@
+# RUN: yaml2obj < %p/Inputs/ret42.yaml > %t.obj
+
+# RUN: mkdir -p %T/out/tmp
+# RUN: cp %t.obj %T/out/out1.obj
+# RUN: cp %t.obj %T/out/tmp/out2
+# RUN: cp %t.obj %T/out/tmp/out3.xyz
+
+# RUN: lld -flavor link2 %T/out/out1.obj
+# RUN: lld -flavor link2 %T/out/tmp/out2
+# RUN: lld -flavor link2 %T/out/tmp/out3.xyz
+
+# RUN: llvm-readobj out1.exe | FileCheck %s
+# RUN: llvm-readobj out2.exe | FileCheck %s
+# RUN: llvm-readobj out3.exe | FileCheck %s
+
+CHECK: File: