Index: ELF/Driver.h =================================================================== --- ELF/Driver.h +++ ELF/Driver.h @@ -27,6 +27,7 @@ public: void main(ArrayRef Args); void addFile(StringRef Path); + void addLibrary(StringRef Name); private: void readConfigs(llvm::opt::InputArgList &Args); Index: ELF/Driver.cpp =================================================================== --- ELF/Driver.cpp +++ ELF/Driver.cpp @@ -55,23 +55,34 @@ if (S == "aarch64linux") return {ELF64LEKind, EM_AARCH64}; if (S == "i386pe" || S == "i386pep" || S == "thumb2pe") - fatal("Windows targets are not supported on the ELF frontend: " + S); - fatal("Unknown emulation: " + S); + error("Windows targets are not supported on the ELF frontend: " + S); + else + error("Unknown emulation: " + S); + return {ELFNoneKind, 0}; } // Returns slices of MB by parsing MB as an archive file. // Each slice consists of a member file in the archive. static std::vector getArchiveMembers(MemoryBufferRef MB) { ErrorOr> FileOrErr = Archive::create(MB); - fatal(FileOrErr, "Failed to parse archive"); + if (!FileOrErr) { + error(FileOrErr, "Failed to parse archive"); + return {}; + } std::unique_ptr File = std::move(*FileOrErr); std::vector V; for (const ErrorOr &C : File->children()) { - fatal(C, "Could not get the child of the archive " + File->getFileName()); + if (!C) { + error(C, "Could not get the child of the archive " + File->getFileName()); + return {}; + } ErrorOr MbOrErr = C->getMemoryBufferRef(); - fatal(MbOrErr, "Could not get the buffer for a child of the archive " + - File->getFileName()); + if (!MbOrErr) { + error(MbOrErr, "Could not get the buffer for a child of the archive " + + File->getFileName()); + return {}; + } V.push_back(*MbOrErr); } return V; @@ -84,7 +95,10 @@ if (Config->Verbose) llvm::outs() << Path << "\n"; auto MBOrErr = MemoryBuffer::getFile(Path); - fatal(MBOrErr, "cannot open " + Path); + if (!MBOrErr) { + error(MBOrErr, "cannot open " + Path); + return; + } std::unique_ptr &MB = *MBOrErr; MemoryBufferRef MBRef = MB->getMemBufferRef(); OwningMBs.push_back(std::move(MB)); // take MB ownership @@ -109,6 +123,15 @@ } } +// Add a given library by searching it from input search paths. +void LinkerDriver::addLibrary(StringRef Name) { + StringRef Path = searchLibrary(Name); + if (Path.empty()) + error("Unable to find library -l" + Name); + else + addFile(Path); +} + // Some command line options or some combinations of them are not allowed. // This function checks for such fatals. static void checkOptions(opt::InputArgList &Args) { @@ -116,15 +139,15 @@ // of executables or DSOs. We don't support that since the feature // does not seem to provide more value than the static archiver. if (Args.hasArg(OPT_relocatable)) - fatal("-r option is not supported. Use 'ar' command instead."); + error("-r option is not supported. Use 'ar' command instead."); // The MIPS ABI as of 2016 does not support the GNU-style symbol lookup // table which is a relatively new feature. if (Config->EMachine == EM_MIPS && Config->GnuHash) - fatal("The .gnu.hash section is not compatible with the MIPS target."); + error("The .gnu.hash section is not compatible with the MIPS target."); if (Config->EMachine == EM_AMDGPU && !Config->Entry.empty()) - fatal("-e option is not valid for AMDGPU."); + error("-e option is not valid for AMDGPU."); } static StringRef @@ -148,6 +171,8 @@ readConfigs(Args); createFiles(Args); checkOptions(Args); + if (HasError) + return; switch (Config->EKind) { case ELF32LEKind: @@ -163,7 +188,7 @@ link(Args); return; default: - fatal("-m or at least a .o file required"); + error("-m or at least a .o file required"); } } @@ -219,7 +244,7 @@ if (auto *Arg = Args.getLastArg(OPT_O)) { StringRef Val = Arg->getValue(); if (Val.getAsInteger(10, Config->Optimize)) - fatal("Invalid optimization level"); + error("Invalid optimization level"); } if (auto *Arg = Args.getLastArg(OPT_hash_style)) { @@ -230,7 +255,7 @@ } else if (S == "both") { Config->GnuHash = true; } else if (S != "sysv") - fatal("Unknown hash style: " + S); + error("Unknown hash style: " + S); } for (auto *Arg : Args.filtered(OPT_undefined)) @@ -241,7 +266,7 @@ for (auto *Arg : Args) { switch (Arg->getOption().getID()) { case OPT_l: - addFile(searchLibrary(Arg->getValue())); + addLibrary(Arg->getValue()); break; case OPT_INPUT: case OPT_script: @@ -268,8 +293,8 @@ } } - if (Files.empty()) - fatal("no input files."); + if (Files.empty() && !HasError) + error("no input files."); } template void LinkerDriver::link(opt::InputArgList &Args) { Index: ELF/DriverUtils.cpp =================================================================== --- ELF/DriverUtils.cpp +++ ELF/DriverUtils.cpp @@ -66,7 +66,7 @@ // Parse options and then do fatal checking. opt::InputArgList Args = Table.ParseArgs(Vec, MissingIndex, MissingCount); if (MissingCount) - fatal(Twine("missing arg value for \"") + Args.getArgString(MissingIndex) + + error(Twine("missing arg value for \"") + Args.getArgString(MissingIndex) + "\", expected " + Twine(MissingCount) + (MissingCount == 1 ? " argument.\n" : " arguments")); @@ -74,8 +74,7 @@ for (auto *Arg : Unknowns) warning("warning: unknown argument: " + Arg->getSpelling()); if (Unknowns.begin() != Unknowns.end()) - fatal("unknown argument(s) found"); - + error("unknown argument(s) found"); return Args; } @@ -104,7 +103,7 @@ if (!S.empty()) return S; } - fatal("Unable to find library -l" + Path); + return ""; } // Makes a path by concatenating Dir and File. Index: ELF/LinkerScript.cpp =================================================================== --- ELF/LinkerScript.cpp +++ ELF/LinkerScript.cpp @@ -178,7 +178,7 @@ else Driver->addFile(Saver.save(Config->Sysroot + "/" + S.substr(1))); } else if (S.startswith("-l")) { - Driver->addFile(searchLibrary(S.substr(2))); + Driver->addLibrary(S.substr(2)); } else if (sys::fs::exists(S)) { Driver->addFile(S); } else { Index: test/ELF/driver.test =================================================================== --- /dev/null +++ test/ELF/driver.test @@ -0,0 +1,9 @@ +# RUN: not ld.lld -unknown1 -unknown2 -m foo /no/such/file -lnosuchlib \ +# RUN: 2>&1 | FileCheck %s + +# CHECK: warning: unknown argument: -unknown1 +# CHECK: warning: unknown argument: -unknown2 +# CHECK: unknown argument(s) found +# CHECK: Unknown emulation: foo +# CHECK: cannot open /no/such/file +# CHECK: Unable to find library -lnosuchlib