[obj2yaml] Add -o to specify output filename
authorFangrui Song <i@maskray.me>
Thu, 14 Jul 2022 07:32:48 +0000 (00:32 -0700)
committerFangrui Song <i@maskray.me>
Thu, 14 Jul 2022 07:32:48 +0000 (00:32 -0700)
-o is very common among tools. yaml2obj supports -o and it surprised me that
obj2yaml doesn't support -o. Just add it which doesn't take much code.

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

llvm/test/ObjectYAML/Offload/default.yaml
llvm/test/ObjectYAML/wasm/header.yaml
llvm/test/tools/obj2yaml/Archives/regular.yaml
llvm/test/tools/obj2yaml/COFF/test-1.test
llvm/test/tools/obj2yaml/DXContainer/DXILPart.yaml
llvm/test/tools/obj2yaml/Minidump/basic.yaml
llvm/test/tools/obj2yaml/XCOFF/aix.yaml
llvm/test/tools/obj2yaml/output-file.yaml [new file with mode: 0644]
llvm/tools/obj2yaml/obj2yaml.cpp

index 7b147b8526457cfe01360fa1341436d273774cb1..ac8e89e6d04575047412ac2833e799dbe2b1bc9e 100644 (file)
@@ -1,4 +1,8 @@
-# RUN: yaml2obj %s | obj2yaml | FileCheck %s
+# RUN: yaml2obj %s -o %t
+# RUN: obj2yaml %t > %t.stdout.yaml
+# RUN: obj2yaml %t -o %t.file.yaml 2>&1 | count 0
+# RUN: FileCheck --input-file=%t.stdout.yaml %s
+# RUN: diff %t.stdout.yaml %t.file.yaml
 !Offload
 Members:
   - 
index a182d3e797ce4c1762e7cfb4fd917fd94330b7ae..7cfd6a9d0fed7cf845c0978ddef0e6cffb91d4e9 100644 (file)
@@ -1,4 +1,8 @@
-# RUN: yaml2obj %s | obj2yaml | FileCheck %s
+# RUN: yaml2obj %s -o %t
+# RUN: obj2yaml %t > %t.stdout.yaml
+# RUN: obj2yaml %t -o %t.file.yaml 2>&1 | count 0
+# RUN: FileCheck --input-file=%t.stdout.yaml %s
+# RUN: diff %t.stdout.yaml %t.file.yaml
 --- !WASM
 FileHeader:
   Version:         0x00000001
index 923d99dec812c20ef2efe5e6fa72b6853abd970a..0ad47ec410ae12dc143fef7c03a5c21b4d59ec68 100644 (file)
@@ -3,7 +3,10 @@
 ## Check how we dump an empty archive.
 
 # RUN: yaml2obj %s --docnum=1 -o %t.empty.a
-# RUN: obj2yaml %t.empty.a | FileCheck %s --check-prefix=EMPTY
+# RUN: obj2yaml %t.empty.a > %t.stdout.yaml
+# RUN: obj2yaml %t.empty.a -o %t.file.yaml 2>&1 | count 0
+# RUN: FileCheck --input-file=%t.stdout.yaml %s --check-prefix=EMPTY
+# RUN: diff %t.stdout.yaml %t.file.yaml
 
 # EMPTY:      --- !Arch
 # EMPTY-NEXT: Members: []
index 0d7880b06a372b3f222831809b5789ded56bd44f..ce05b72b97d738acd19d52a3f78e8a0b80906743 100755 (executable)
@@ -1,4 +1,7 @@
-# RUN: obj2yaml %S/Inputs/test-1.o | yaml2obj -o %t.o
+# RUN: obj2yaml %S/Inputs/test-1.o > %t.stdout.yaml
+# RUN: obj2yaml %S/Inputs/test-1.o -o %t.file.yaml 2>&1 | count 0
+# RUN: yaml2obj %t.stdout.yaml -o %t.o
 # RUN: llvm-pdbutil dump --types %t.o | FileCheck %s -check-prefix=ALL
+# RUN: diff %t.stdout.yaml %t.file.yaml
 
 # ALL: {{.*}} guid = {00C903AB-0968-4639-84F8-7D3E719A1BE1}
index 546ebcb9cf5964ec67fb44f17fb9fd7a5f638bb4..4ee8c4282611bce64fd61c2f295df6b1a8b30ede 100644 (file)
@@ -1,4 +1,8 @@
-# RUN: yaml2obj %s | obj2yaml | FileCheck %s 
+# RUN: yaml2obj %s -o %t
+# RUN: obj2yaml %t > %t.stdout.yaml
+# RUN: obj2yaml %t -o %t.file.yaml 2>&1 | count 0
+# RUN: FileCheck --input-file=%t.stdout.yaml %s
+# RUN: diff %t.stdout.yaml %t.file.yaml
 
 --- !dxcontainer
 Header:
index 15076604309e082c9f74f3c049b8ea56dd5435e2..dfabc132d8e71c52e0a6ac36af6e0df2da130eac 100644 (file)
@@ -1,4 +1,8 @@
-# RUN: yaml2obj %s | obj2yaml - | FileCheck %s
+# RUN: yaml2obj %s -o %t
+# RUN: obj2yaml %t > %t.stdout.yaml
+# RUN: obj2yaml %t -o %t.file.yaml 2>&1 | count 0
+# RUN: FileCheck --input-file=%t.stdout.yaml %s
+# RUN: diff %t.stdout.yaml %t.file.yaml
 
 --- !minidump
 Streams:
index f49d981aaf010ed8c396449914b3be5fbb58b4ec..cd1e88dec11d29b97a8f0482ac07673374b51faa 100644 (file)
@@ -2,7 +2,8 @@
 # RUN: yaml2obj %s -DMAGIC=0x01DF -o %t-32
 # RUN: obj2yaml %t-32 | FileCheck %s --check-prefix=CHECK32
 # RUN: yaml2obj %s -DMAGIC=0x01F7 -o %t-64
-# RUN: obj2yaml %t-64 | FileCheck %s --check-prefix=CHECK64
+# RUN: obj2yaml %t-64 -o %t-64.yaml 2>&1 | count 0
+# RUN: FileCheck --input-file %t-64.yaml %s --check-prefix=CHECK64
 
 # CHECK32:      --- !XCOFF
 # CHECK32-NEXT: FileHeader:
diff --git a/llvm/test/tools/obj2yaml/output-file.yaml b/llvm/test/tools/obj2yaml/output-file.yaml
new file mode 100644 (file)
index 0000000..196999e
--- /dev/null
@@ -0,0 +1,23 @@
+## Test that -o sets the output file name.
+
+# RUN: yaml2obj %s -o %t
+# RUN: rm -f %t.yaml && obj2yaml %t -o %t.yaml
+# RUN: ls %t.yaml
+# RUN: rm -f %t.yaml && cat %t | obj2yaml -o%t.yaml
+# RUN: ls %t.yaml
+
+## In case of an error, don't create the output file.
+# RUN: rm -f %t.yaml
+# RUN: echo | not obj2yaml -o %t.yaml
+# RUN: not ls %t.yaml
+
+# RUN: not obj2yaml %t -o %p/path/does/not/exist 2>&1 | FileCheck -DMSG=%errc_ENOENT %s
+
+# CHECK: obj2yaml: error: failed to open '{{.*}}/path/does/not/exist': [[MSG]]
+
+!ELF
+FileHeader:
+  Class:   ELFCLASS64
+  Data:    ELFDATA2LSB
+  Type:    ET_REL
+  Machine: EM_NONE
index 4aa154a8d819cc60f8bcc3a8995bd5b8206a4500..4eec967d9fa6bce5a2be3a21b7e52769abae3e79 100644 (file)
 #include "llvm/Support/CommandLine.h"
 #include "llvm/Support/Errc.h"
 #include "llvm/Support/InitLLVM.h"
+#include "llvm/Support/ToolOutputFile.h"
+#include "llvm/Support/WithColor.h"
 
 using namespace llvm;
 using namespace llvm::object;
 
 static cl::opt<std::string>
     InputFilename(cl::Positional, cl::desc("<input file>"), cl::init("-"));
+static cl::opt<std::string> OutputFilename("o", cl::desc("Output filename"),
+                                           cl::value_desc("filename"),
+                                           cl::init("-"), cl::Prefix);
 static cl::bits<RawSegments> RawSegment(
     "raw-segment",
     cl::desc("Mach-O: dump the raw contents of the listed segments instead of "
              "parsing them:"),
     cl::values(clEnumVal(data, "__DATA"), clEnumVal(linkedit, "__LINKEDIT")));
 
-static Error dumpObject(const ObjectFile &Obj) {
+static Error dumpObject(const ObjectFile &Obj, raw_ostream &OS) {
   if (Obj.isCOFF())
-    return errorCodeToError(coff2yaml(outs(), cast<COFFObjectFile>(Obj)));
+    return errorCodeToError(coff2yaml(OS, cast<COFFObjectFile>(Obj)));
 
   if (Obj.isXCOFF())
-    return xcoff2yaml(outs(), cast<XCOFFObjectFile>(Obj));
+    return xcoff2yaml(OS, cast<XCOFFObjectFile>(Obj));
 
   if (Obj.isELF())
-    return elf2yaml(outs(), Obj);
+    return elf2yaml(OS, Obj);
 
   if (Obj.isWasm())
-    return errorCodeToError(wasm2yaml(outs(), cast<WasmObjectFile>(Obj)));
+    return errorCodeToError(wasm2yaml(OS, cast<WasmObjectFile>(Obj)));
 
   llvm_unreachable("unexpected object file format");
 }
 
-static Error dumpInput(StringRef File) {
+static Error dumpInput(StringRef File, raw_ostream &OS) {
   ErrorOr<std::unique_ptr<MemoryBuffer>> FileOrErr =
       MemoryBuffer::getFileOrSTDIN(File, /*IsText=*/false,
                                    /*RequiresNullTerminator=*/false);
@@ -52,11 +57,11 @@ static Error dumpInput(StringRef File) {
   MemoryBufferRef MemBuf = Buffer->getMemBufferRef();
   switch (identify_magic(MemBuf.getBuffer())) {
   case file_magic::archive:
-    return archive2yaml(outs(), MemBuf);
+    return archive2yaml(OS, MemBuf);
   case file_magic::dxcontainer_object:
-    return dxcontainer2yaml(outs(), MemBuf);
+    return dxcontainer2yaml(OS, MemBuf);
   case file_magic::offload_binary:
-    return offload2yaml(outs(), MemBuf);
+    return offload2yaml(OS, MemBuf);
   default:
     break;
   }
@@ -70,11 +75,11 @@ static Error dumpInput(StringRef File) {
   // Universal MachO is not a subclass of ObjectFile, so it needs to be handled
   // here with the other binary types.
   if (Binary.isMachO() || Binary.isMachOUniversalBinary())
-    return macho2yaml(outs(), Binary, RawSegment.getBits());
+    return macho2yaml(OS, Binary, RawSegment.getBits());
   if (ObjectFile *Obj = dyn_cast<ObjectFile>(&Binary))
-    return dumpObject(*Obj);
+    return dumpObject(*Obj, OS);
   if (MinidumpFile *Minidump = dyn_cast<MinidumpFile>(&Binary))
-    return minidump2yaml(outs(), *Minidump);
+    return minidump2yaml(OS, *Minidump);
 
   return Error::success();
 }
@@ -94,10 +99,19 @@ int main(int argc, char *argv[]) {
   InitLLVM X(argc, argv);
   cl::ParseCommandLineOptions(argc, argv);
 
-  if (Error Err = dumpInput(InputFilename)) {
+  std::error_code EC;
+  std::unique_ptr<ToolOutputFile> Out(
+      new ToolOutputFile(OutputFilename, EC, sys::fs::OF_None));
+  if (EC) {
+    WithColor::error(errs(), "obj2yaml")
+        << "failed to open '" + OutputFilename + "': " + EC.message() << '\n';
+    return 1;
+  }
+  if (Error Err = dumpInput(InputFilename, Out->os())) {
     reportError(InputFilename, std::move(Err));
     return 1;
   }
+  Out->keep();
 
   return 0;
 }