Index: clang/test/Driver/clang-offload-bundler.c =================================================================== --- clang/test/Driver/clang-offload-bundler.c +++ clang/test/Driver/clang-offload-bundler.c @@ -68,12 +68,12 @@ // RUN: not clang-offload-bundler -type=i -targets=host-%itanium_abi_triple,openmp-powerpc64le-ibm-linux-gnu,openmp-x86_64-pc-linux-gnu -outputs=%t.i,%t.tgt1 -inputs=%t.bundle.i -unbundle 2>&1 | FileCheck %s --check-prefix CK-ERR4 // CK-ERR4: error: number of output files and targets should match in unbundling mode. -// RUN: not clang-offload-bundler -type=i -targets=host-%itanium_abi_triple,openmp-powerpc64le-ibm-linux-gnu,openmp-x86_64-pc-linux-gnu -inputs=%t.i,%t.tgt1,%t.tgt2.notexist -outputs=%t.bundle.i 2>&1 | FileCheck %s --check-prefix CK-ERR5 -// RUN: not clang-offload-bundler -type=i -targets=host-%itanium_abi_triple,openmp-powerpc64le-ibm-linux-gnu,openmp-x86_64-pc-linux-gnu -outputs=%t.i,%t.tgt1,%t.tgt2 -inputs=%t.bundle.i.notexist -unbundle 2>&1 | FileCheck %s --check-prefix CK-ERR5 -// CK-ERR5: error: Can't open file {{.+}}.notexist: {{N|n}}o such file or directory +// RUN: not clang-offload-bundler -type=i -targets=host-%itanium_abi_triple,openmp-powerpc64le-ibm-linux-gnu,openmp-x86_64-pc-linux-gnu -inputs=%t.i,%t.tgt1,%t.tgt2.notexist -outputs=%t.bundle.i 2>&1 | FileCheck %s -DFILE=%t.tgt2.notexist --check-prefix CK-ERR5 +// RUN: not clang-offload-bundler -type=i -targets=host-%itanium_abi_triple,openmp-powerpc64le-ibm-linux-gnu,openmp-x86_64-pc-linux-gnu -outputs=%t.i,%t.tgt1,%t.tgt2 -inputs=%t.bundle.i.notexist -unbundle 2>&1 | FileCheck %s -DFILE=%t.bundle.i.notexist --check-prefix CK-ERR5 +// CK-ERR5: error: '[[FILE]]': {{N|n}}o such file or directory -// RUN: not clang-offload-bundler -type=invalid -targets=host-%itanium_abi_triple,openmp-powerpc64le-ibm-linux-gnu,openmp-x86_64-pc-linux-gnu -inputs=%t.i,%t.tgt1,%t.tgt2 -outputs=%t.bundle.i 2>&1 | FileCheck %s --check-prefix CK-ERR6 -// CK-ERR6: error: invalid file type specified. +// RUN: not clang-offload-bundler -type=invalid -targets=host-%itanium_abi_triple,openmp-powerpc64le-ibm-linux-gnu,openmp-x86_64-pc-linux-gnu -inputs=%t.i,%t.tgt1,%t.tgt2 -outputs=%t.bundle.i 2>&1 | FileCheck %s -DTYPE=invalid --check-prefix CK-ERR6 +// CK-ERR6: error: '[[TYPE]]': invalid file type specified. // RUN: not clang-offload-bundler 2>&1 | FileCheck %s --check-prefix CK-ERR7 // CK-ERR7-DAG: clang-offload-bundler: for the --type option: must be specified at least once! Index: clang/tools/clang-offload-bundler/ClangOffloadBundler.cpp =================================================================== --- clang/tools/clang-offload-bundler/ClangOffloadBundler.cpp +++ clang/tools/clang-offload-bundler/ClangOffloadBundler.cpp @@ -17,6 +17,7 @@ #include "clang/Basic/Version.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/SmallString.h" +#include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringSwitch.h" @@ -25,23 +26,23 @@ #include "llvm/Object/ObjectFile.h" #include "llvm/Support/Casting.h" #include "llvm/Support/CommandLine.h" +#include "llvm/Support/Errc.h" #include "llvm/Support/Error.h" #include "llvm/Support/ErrorOr.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/Path.h" #include "llvm/Support/Program.h" -#include "llvm/Support/raw_ostream.h" #include "llvm/Support/Signals.h" #include "llvm/Support/StringSaver.h" -#include +#include "llvm/Support/WithColor.h" +#include "llvm/Support/raw_ostream.h" #include -#include #include #include #include #include -#include +#include using namespace llvm; using namespace llvm::object; @@ -98,6 +99,9 @@ /// Path to the current binary. static std::string BundlerExecutable; +/// Saved argv[0]. +static StringRef Argv0; + /// Obtain the offload kind and real machine triple out of the target /// information specified by the user. static void getOffloadKindAndTriple(StringRef Target, StringRef &OffloadKind, @@ -113,6 +117,15 @@ return OffloadKind == "host"; } +/// Error reporting functions. +static void reportError(Error E) { + logAllUnhandledErrors(std::move(E), WithColor::error(errs(), Argv0)); +} + +static void reportFileError(StringRef File, std::error_code EC) { + reportError(createFileError(File, EC)); +} + /// Generic file handler interface. class FileHandler { public: @@ -146,7 +159,6 @@ /// Write the marker that closes a bundle for the triple \a TargetTriple to \a /// OS. Return true if any error was found. - virtual bool WriteBundleEnd(raw_fd_ostream &OS, StringRef TargetTriple) = 0; /// Write the bundle from \a Input into \a OS. @@ -327,7 +339,7 @@ unsigned Idx = 0; for (auto &T : TargetNames) { - MemoryBuffer &MB = *Inputs[Idx++].get(); + MemoryBuffer &MB = *Inputs[Idx++]; // Bundle offset. Write8byteIntegerToBuffer(OS, HeaderSize); // Size of the bundle (adds to the next bundle's offset) @@ -467,7 +479,8 @@ ErrorOr Objcopy = sys::findProgramByName( "llvm-objcopy", sys::path::parent_path(BundlerExecutable)); if (!Objcopy) { - errs() << "error: unable to find 'llvm-objcopy' in path.\n"; + reportError(createStringError(Objcopy.getError(), + "unable to find 'llvm-objcopy' in path.")); return true; } @@ -489,13 +502,14 @@ // If the user asked for the commands to be printed out, we do that instead // of executing it. if (PrintExternalCommands) { - errs() << "\"" << Objcopy.get() << "\""; + errs() << "\"" << *Objcopy << "\""; for (StringRef Arg : drop_begin(ObjcopyArgs, 1)) errs() << " \"" << Arg << "\""; errs() << "\n"; } else { - if (sys::ExecuteAndWait(Objcopy.get(), ObjcopyArgs)) { - errs() << "error: llvm-objcopy tool failed.\n"; + if (sys::ExecuteAndWait(*Objcopy, ObjcopyArgs)) { + reportError(createStringError(inconvertibleErrorCode(), + "'llvm-objcopy' tool failed.")); return true; } } @@ -622,13 +636,11 @@ // We only support regular object files. If this is not an object file, // default to the binary handler. The handler will be owned by the client of // this function. - std::unique_ptr Obj( - dyn_cast(BinaryOrErr.get().release())); - - if (!Obj) - return new BinaryFileHandler(); - - return new ObjectFileHandler(std::move(Obj)); + if (auto *Obj = dyn_cast(BinaryOrErr->get())) { + BinaryOrErr->release(); + return new ObjectFileHandler(std::unique_ptr(Obj)); + } + return new BinaryFileHandler(); } /// Return an appropriate handler given the input files and options. @@ -650,7 +662,10 @@ if (FilesType == "ast") return new BinaryFileHandler(); - errs() << "error: invalid file type specified.\n"; + reportError( + createStringError(errc::invalid_argument, + "'" + FilesType + "': invalid file type specified.")); + return nullptr; } @@ -662,44 +677,42 @@ raw_fd_ostream OutputFile(OutputFileNames.front(), EC, sys::fs::OF_None); if (EC) { - errs() << "error: Can't open file " << OutputFileNames.front() << ".\n"; + reportFileError(OutputFileNames.front(), EC); return true; } // Open input files. - std::vector> InputBuffers( - InputFileNames.size()); - - unsigned Idx = 0; + SmallVector, 8u> InputBuffers; + InputBuffers.reserve(InputFileNames.size()); for (auto &I : InputFileNames) { ErrorOr> CodeOrErr = MemoryBuffer::getFileOrSTDIN(I); if (std::error_code EC = CodeOrErr.getError()) { - errs() << "error: Can't open file " << I << ": " << EC.message() << "\n"; + reportFileError(I, EC); return true; } - InputBuffers[Idx++] = std::move(CodeOrErr.get()); + InputBuffers.emplace_back(std::move(*CodeOrErr)); } // Get the file handler. We use the host buffer as reference. assert(HostInputIndex != ~0u && "Host input index undefined??"); std::unique_ptr FH; - FH.reset(CreateFileHandler(*InputBuffers[HostInputIndex].get())); + FH.reset(CreateFileHandler(*InputBuffers[HostInputIndex])); // Quit if we don't have a handler. - if (!FH.get()) + if (!FH) return true; // Write header. - FH.get()->WriteHeader(OutputFile, InputBuffers); + FH->WriteHeader(OutputFile, InputBuffers); // Write all bundles along with the start/end markers. If an error was found // writing the end of the bundle component, abort the bundle writing. auto Input = InputBuffers.begin(); for (auto &Triple : TargetNames) { - FH.get()->WriteBundleStart(OutputFile, Triple); - FH.get()->WriteBundle(OutputFile, *Input->get()); - if (FH.get()->WriteBundleEnd(OutputFile, Triple)) + FH->WriteBundleStart(OutputFile, Triple); + FH->WriteBundle(OutputFile, **Input); + if (FH->WriteBundleEnd(OutputFile, Triple)) return true; ++Input; } @@ -712,23 +725,22 @@ ErrorOr> CodeOrErr = MemoryBuffer::getFileOrSTDIN(InputFileNames.front()); if (std::error_code EC = CodeOrErr.getError()) { - errs() << "error: Can't open file " << InputFileNames.front() << ": " - << EC.message() << "\n"; + reportFileError(InputFileNames.front(), EC); return true; } - MemoryBuffer &Input = *CodeOrErr.get(); + MemoryBuffer &Input = **CodeOrErr; // Select the right files handler. std::unique_ptr FH; FH.reset(CreateFileHandler(Input)); // Quit if we don't have a handler. - if (!FH.get()) + if (!FH) return true; // Read the header of the bundled file. - FH.get()->ReadHeader(Input); + FH->ReadHeader(Input); // Create a work list that consist of the map triple/output file. StringMap Worklist; @@ -742,7 +754,7 @@ // assume the file is meant for the host target. bool FoundHostBundle = false; while (!Worklist.empty()) { - StringRef CurTriple = FH.get()->ReadBundleStart(Input); + StringRef CurTriple = FH->ReadBundleStart(Input); // We don't have more bundles. if (CurTriple.empty()) @@ -759,12 +771,11 @@ std::error_code EC; raw_fd_ostream OutputFile(Output->second, EC, sys::fs::OF_None); if (EC) { - errs() << "error: Can't open file " << Output->second << ": " - << EC.message() << "\n"; + reportFileError(Output->second, EC); return true; } - FH.get()->ReadBundle(OutputFile, Input); - FH.get()->ReadBundleEnd(Input); + FH->ReadBundle(OutputFile, Input); + FH->ReadBundleEnd(Input); Worklist.erase(Output); // Record if we found the host bundle. @@ -779,8 +790,7 @@ std::error_code EC; raw_fd_ostream OutputFile(E.second, EC, sys::fs::OF_None); if (EC) { - errs() << "error: Can't open file " << E.second << ": " << EC.message() - << "\n"; + reportFileError(E.second, EC); return true; } @@ -794,7 +804,8 @@ // If we found elements, we emit an error if none of those were for the host // in case host bundle name was provided in command line. if (!FoundHostBundle && HostInputIndex != ~0u) { - errs() << "error: Can't find bundle for the host target\n"; + reportError(createStringError(inconvertibleErrorCode(), + "Can't find bundle for the host target.")); return true; } @@ -803,8 +814,7 @@ std::error_code EC; raw_fd_ostream OutputFile(E.second, EC, sys::fs::OF_None); if (EC) { - errs() << "error: Can't open file " << E.second << ": " << EC.message() - << "\n"; + reportFileError(E.second, EC); return true; } } @@ -817,6 +827,7 @@ } int main(int argc, const char **argv) { + Argv0 = argv[0]; sys::PrintStackTraceOnErrorSignal(argv[0]); cl::HideUnrelatedOptions(ClangOffloadBundlerCategory); @@ -837,22 +848,28 @@ if (Unbundle) { if (InputFileNames.size() != 1) { Error = true; - errs() << "error: only one input file supported in unbundling mode.\n"; + reportError(createStringError( + errc::invalid_argument, + "only one input file supported in unbundling mode.")); } if (OutputFileNames.size() != TargetNames.size()) { Error = true; - errs() << "error: number of output files and targets should match in " - "unbundling mode.\n"; + reportError(createStringError(errc::invalid_argument, + "number of output files and targets should " + "match in unbundling mode.")); } } else { if (OutputFileNames.size() != 1) { Error = true; - errs() << "error: only one output file supported in bundling mode.\n"; + reportError(createStringError( + errc::invalid_argument, + "only one output file supported in bundling mode.")); } if (InputFileNames.size() != TargetNames.size()) { Error = true; - errs() << "error: number of input files and targets should match in " - "bundling mode.\n"; + reportError(createStringError( + errc::invalid_argument, + "number of input files and targets should match in bundling mode.")); } } @@ -878,13 +895,15 @@ if (!KindIsValid || !TripleIsValid) { Error = true; - errs() << "error: invalid target '" << Target << "'"; + SmallVector Buf; + raw_svector_ostream Msg(Buf); + Msg << "invalid target '" << Target << "'"; if (!KindIsValid) - errs() << ", unknown offloading kind '" << Kind << "'"; + Msg << ", unknown offloading kind '" << Kind << "'"; if (!TripleIsValid) - errs() << ", unknown target triple '" << Triple << "'"; - errs() << ".\n"; + Msg << ", unknown target triple '" << Triple << "'"; + reportError(createStringError(errc::invalid_argument, Msg.str() + ".")); } if (KindIsValid && Kind == "host") { @@ -900,8 +919,9 @@ // treat missing host triple as error if we do unbundling. if ((Unbundle && HostTargetNum > 1) || (!Unbundle && HostTargetNum != 1)) { Error = true; - errs() << "error: expecting exactly one host target but got " - << HostTargetNum << ".\n"; + reportError(createStringError(errc::invalid_argument, + "expecting exactly one host target but got " + + Twine(HostTargetNum) + ".")); } if (Error)