1c6f07c42SPeter Collingbourne //===- LibDriver.cpp - lib.exe-compatible driver --------------------------===//
2c6f07c42SPeter Collingbourne //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6c6f07c42SPeter Collingbourne //
7c6f07c42SPeter Collingbourne //===----------------------------------------------------------------------===//
8c6f07c42SPeter Collingbourne //
9c6f07c42SPeter Collingbourne // Defines an interface to a lib.exe-compatible driver that also understands
10c6f07c42SPeter Collingbourne // bitcode files. Used by llvm-lib and lld-link /lib.
11c6f07c42SPeter Collingbourne //
12c6f07c42SPeter Collingbourne //===----------------------------------------------------------------------===//
13c6f07c42SPeter Collingbourne
14c6f07c42SPeter Collingbourne #include "llvm/ToolDrivers/llvm-lib/LibDriver.h"
15c6f07c42SPeter Collingbourne #include "llvm/ADT/STLExtras.h"
1660e9df33SRui Ueyama #include "llvm/ADT/StringSet.h"
17d546b505SNico Weber #include "llvm/BinaryFormat/COFF.h"
18264b5d9eSZachary Turner #include "llvm/BinaryFormat/Magic.h"
19d546b505SNico Weber #include "llvm/Bitcode/BitcodeReader.h"
20c6f07c42SPeter Collingbourne #include "llvm/Object/ArchiveWriter.h"
21d546b505SNico Weber #include "llvm/Object/COFF.h"
221dc2123dSNico Weber #include "llvm/Object/WindowsMachineFlag.h"
23c6f07c42SPeter Collingbourne #include "llvm/Option/Arg.h"
24c6f07c42SPeter Collingbourne #include "llvm/Option/ArgList.h"
25c6f07c42SPeter Collingbourne #include "llvm/Option/Option.h"
26c6f07c42SPeter Collingbourne #include "llvm/Support/CommandLine.h"
27c6f07c42SPeter Collingbourne #include "llvm/Support/Path.h"
28c6f07c42SPeter Collingbourne #include "llvm/Support/Process.h"
296bda14b3SChandler Carruth #include "llvm/Support/StringSaver.h"
30c6f07c42SPeter Collingbourne #include "llvm/Support/raw_ostream.h"
31c6f07c42SPeter Collingbourne
32c6f07c42SPeter Collingbourne using namespace llvm;
33c6f07c42SPeter Collingbourne
34c6f07c42SPeter Collingbourne namespace {
35c6f07c42SPeter Collingbourne
36c6f07c42SPeter Collingbourne enum {
37c6f07c42SPeter Collingbourne OPT_INVALID = 0,
38ba5d4af4SYuka Takahashi #define OPTION(_1, _2, ID, _4, _5, _6, _7, _8, _9, _10, _11, _12) OPT_##ID,
39c6f07c42SPeter Collingbourne #include "Options.inc"
40c6f07c42SPeter Collingbourne #undef OPTION
41c6f07c42SPeter Collingbourne };
42c6f07c42SPeter Collingbourne
43c6f07c42SPeter Collingbourne #define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE;
44c6f07c42SPeter Collingbourne #include "Options.inc"
45c6f07c42SPeter Collingbourne #undef PREFIX
46c6f07c42SPeter Collingbourne
47f2f4e033SRui Ueyama static const opt::OptTable::Info InfoTable[] = {
48cc82cdffSMartell Malone #define OPTION(X1, X2, ID, KIND, GROUP, ALIAS, X7, X8, X9, X10, X11, X12) \
49f2f4e033SRui Ueyama {X1, X2, X10, X11, OPT_##ID, opt::Option::KIND##Class, \
50cc82cdffSMartell Malone X9, X8, OPT_##GROUP, OPT_##ALIAS, X7, X12},
51c6f07c42SPeter Collingbourne #include "Options.inc"
52c6f07c42SPeter Collingbourne #undef OPTION
53c6f07c42SPeter Collingbourne };
54c6f07c42SPeter Collingbourne
55f2f4e033SRui Ueyama class LibOptTable : public opt::OptTable {
56c6f07c42SPeter Collingbourne public:
LibOptTable()57cc82cdffSMartell Malone LibOptTable() : OptTable(InfoTable, true) {}
58c6f07c42SPeter Collingbourne };
59c6f07c42SPeter Collingbourne
60c6f07c42SPeter Collingbourne }
61c6f07c42SPeter Collingbourne
getDefaultOutputPath(const NewArchiveMember & FirstMember)621428f86cSEric Astor static std::string getDefaultOutputPath(const NewArchiveMember &FirstMember) {
63c6f07c42SPeter Collingbourne SmallString<128> Val = StringRef(FirstMember.Buf->getBufferIdentifier());
64f2f4e033SRui Ueyama sys::path::replace_extension(Val, ".lib");
65adcd0268SBenjamin Kramer return std::string(Val.str());
66c6f07c42SPeter Collingbourne }
67c6f07c42SPeter Collingbourne
getSearchPaths(opt::InputArgList * Args,StringSaver & Saver)68f2f4e033SRui Ueyama static std::vector<StringRef> getSearchPaths(opt::InputArgList *Args,
69c6f07c42SPeter Collingbourne StringSaver &Saver) {
70c6f07c42SPeter Collingbourne std::vector<StringRef> Ret;
71c6f07c42SPeter Collingbourne // Add current directory as first item of the search path.
72c6f07c42SPeter Collingbourne Ret.push_back("");
73c6f07c42SPeter Collingbourne
74c6f07c42SPeter Collingbourne // Add /libpath flags.
75c6f07c42SPeter Collingbourne for (auto *Arg : Args->filtered(OPT_libpath))
76c6f07c42SPeter Collingbourne Ret.push_back(Arg->getValue());
77c6f07c42SPeter Collingbourne
78c6f07c42SPeter Collingbourne // Add $LIB.
79c6f07c42SPeter Collingbourne Optional<std::string> EnvOpt = sys::Process::GetEnv("LIB");
80*e0e687a6SKazu Hirata if (!EnvOpt)
81c6f07c42SPeter Collingbourne return Ret;
82c6f07c42SPeter Collingbourne StringRef Env = Saver.save(*EnvOpt);
83c6f07c42SPeter Collingbourne while (!Env.empty()) {
84c6f07c42SPeter Collingbourne StringRef Path;
85c6f07c42SPeter Collingbourne std::tie(Path, Env) = Env.split(';');
86c6f07c42SPeter Collingbourne Ret.push_back(Path);
87c6f07c42SPeter Collingbourne }
88c6f07c42SPeter Collingbourne return Ret;
89c6f07c42SPeter Collingbourne }
90c6f07c42SPeter Collingbourne
findInputFile(StringRef File,ArrayRef<StringRef> Paths)91f2f4e033SRui Ueyama static std::string findInputFile(StringRef File, ArrayRef<StringRef> Paths) {
92f2f4e033SRui Ueyama for (StringRef Dir : Paths) {
93c6f07c42SPeter Collingbourne SmallString<128> Path = Dir;
94c6f07c42SPeter Collingbourne sys::path::append(Path, File);
95c6f07c42SPeter Collingbourne if (sys::fs::exists(Path))
96b2924d99SJonas Devlieghere return std::string(Path);
97c6f07c42SPeter Collingbourne }
98f2f4e033SRui Ueyama return "";
99c6f07c42SPeter Collingbourne }
100c6f07c42SPeter Collingbourne
fatalOpenError(llvm::Error E,Twine File)101a2f60933SNico Weber static void fatalOpenError(llvm::Error E, Twine File) {
102a2f60933SNico Weber if (!E)
103a2f60933SNico Weber return;
104a2f60933SNico Weber handleAllErrors(std::move(E), [&](const llvm::ErrorInfoBase &EIB) {
105a2f60933SNico Weber llvm::errs() << "error opening '" << File << "': " << EIB.message() << '\n';
106a2f60933SNico Weber exit(1);
107a2f60933SNico Weber });
108a2f60933SNico Weber }
109a2f60933SNico Weber
doList(opt::InputArgList & Args)110a2f60933SNico Weber static void doList(opt::InputArgList& Args) {
111a2f60933SNico Weber // lib.exe prints the contents of the first archive file.
112a2f60933SNico Weber std::unique_ptr<MemoryBuffer> B;
113a2f60933SNico Weber for (auto *Arg : Args.filtered(OPT_INPUT)) {
114a2f60933SNico Weber // Create or open the archive object.
115c83cd8feSAbhina Sreeskantharajan ErrorOr<std::unique_ptr<MemoryBuffer>> MaybeBuf = MemoryBuffer::getFile(
116c83cd8feSAbhina Sreeskantharajan Arg->getValue(), /*IsText=*/false, /*RequiresNullTerminator=*/false);
117a2f60933SNico Weber fatalOpenError(errorCodeToError(MaybeBuf.getError()), Arg->getValue());
118a2f60933SNico Weber
119a2f60933SNico Weber if (identify_magic(MaybeBuf.get()->getBuffer()) == file_magic::archive) {
120a2f60933SNico Weber B = std::move(MaybeBuf.get());
121a2f60933SNico Weber break;
122a2f60933SNico Weber }
123a2f60933SNico Weber }
124a2f60933SNico Weber
125a2f60933SNico Weber // lib.exe doesn't print an error if no .lib files are passed.
126a2f60933SNico Weber if (!B)
127a2f60933SNico Weber return;
128a2f60933SNico Weber
129a2f60933SNico Weber Error Err = Error::success();
130a2f60933SNico Weber object::Archive Archive(B.get()->getMemBufferRef(), Err);
131a2f60933SNico Weber fatalOpenError(std::move(Err), B->getBufferIdentifier());
132a2f60933SNico Weber
133a2f60933SNico Weber for (auto &C : Archive.children(Err)) {
134a2f60933SNico Weber Expected<StringRef> NameOrErr = C.getName();
135a2f60933SNico Weber fatalOpenError(NameOrErr.takeError(), B->getBufferIdentifier());
136a2f60933SNico Weber StringRef Name = NameOrErr.get();
137a2f60933SNico Weber llvm::outs() << Name << '\n';
138a2f60933SNico Weber }
139a2f60933SNico Weber fatalOpenError(std::move(Err), B->getBufferIdentifier());
140a2f60933SNico Weber }
141a2f60933SNico Weber
getCOFFFileMachine(MemoryBufferRef MB)142f3c9687aSNico Weber static Expected<COFF::MachineTypes> getCOFFFileMachine(MemoryBufferRef MB) {
14364a362e7SRui Ueyama std::error_code EC;
14439772063SReid Kleckner auto Obj = object::COFFObjectFile::create(MB);
145f3c9687aSNico Weber if (!Obj)
146f3c9687aSNico Weber return Obj.takeError();
14764a362e7SRui Ueyama
14839772063SReid Kleckner uint16_t Machine = (*Obj)->getMachine();
14964a362e7SRui Ueyama if (Machine != COFF::IMAGE_FILE_MACHINE_I386 &&
15064a362e7SRui Ueyama Machine != COFF::IMAGE_FILE_MACHINE_AMD64 &&
15164a362e7SRui Ueyama Machine != COFF::IMAGE_FILE_MACHINE_ARMNT &&
15264a362e7SRui Ueyama Machine != COFF::IMAGE_FILE_MACHINE_ARM64) {
153f3c9687aSNico Weber return createStringError(inconvertibleErrorCode(),
154f3c9687aSNico Weber "unknown machine: " + std::to_string(Machine));
15564a362e7SRui Ueyama }
15664a362e7SRui Ueyama
15764a362e7SRui Ueyama return static_cast<COFF::MachineTypes>(Machine);
15864a362e7SRui Ueyama }
15964a362e7SRui Ueyama
getBitcodeFileMachine(MemoryBufferRef MB)160f3c9687aSNico Weber static Expected<COFF::MachineTypes> getBitcodeFileMachine(MemoryBufferRef MB) {
16164a362e7SRui Ueyama Expected<std::string> TripleStr = getBitcodeTargetTriple(MB);
162f3c9687aSNico Weber if (!TripleStr)
163f3c9687aSNico Weber return TripleStr.takeError();
16464a362e7SRui Ueyama
16564a362e7SRui Ueyama switch (Triple(*TripleStr).getArch()) {
16664a362e7SRui Ueyama case Triple::x86:
16764a362e7SRui Ueyama return COFF::IMAGE_FILE_MACHINE_I386;
16864a362e7SRui Ueyama case Triple::x86_64:
16964a362e7SRui Ueyama return COFF::IMAGE_FILE_MACHINE_AMD64;
17064a362e7SRui Ueyama case Triple::arm:
17164a362e7SRui Ueyama return COFF::IMAGE_FILE_MACHINE_ARMNT;
17264a362e7SRui Ueyama case Triple::aarch64:
17364a362e7SRui Ueyama return COFF::IMAGE_FILE_MACHINE_ARM64;
17464a362e7SRui Ueyama default:
175f3c9687aSNico Weber return createStringError(inconvertibleErrorCode(),
176f3c9687aSNico Weber "unknown arch in target triple: " + *TripleStr);
17764a362e7SRui Ueyama }
17864a362e7SRui Ueyama }
17964a362e7SRui Ueyama
appendFile(std::vector<NewArchiveMember> & Members,COFF::MachineTypes & LibMachine,std::string & LibMachineSource,MemoryBufferRef MB)18064a362e7SRui Ueyama static void appendFile(std::vector<NewArchiveMember> &Members,
18164a362e7SRui Ueyama COFF::MachineTypes &LibMachine,
18264a362e7SRui Ueyama std::string &LibMachineSource, MemoryBufferRef MB) {
18364a362e7SRui Ueyama file_magic Magic = identify_magic(MB.getBuffer());
18464a362e7SRui Ueyama
18564a362e7SRui Ueyama if (Magic != file_magic::coff_object && Magic != file_magic::bitcode &&
1864d09ed95SMartin Storsjö Magic != file_magic::archive && Magic != file_magic::windows_resource &&
1874d09ed95SMartin Storsjö Magic != file_magic::coff_import_library) {
18864a362e7SRui Ueyama llvm::errs() << MB.getBufferIdentifier()
1894d09ed95SMartin Storsjö << ": not a COFF object, bitcode, archive, import library or "
1904d09ed95SMartin Storsjö "resource file\n";
19164a362e7SRui Ueyama exit(1);
19264a362e7SRui Ueyama }
19364a362e7SRui Ueyama
19464a362e7SRui Ueyama // If a user attempts to add an archive to another archive, llvm-lib doesn't
19564a362e7SRui Ueyama // handle the first archive file as a single file. Instead, it extracts all
196f3c9687aSNico Weber // members from the archive and add them to the second archive. This behavior
19764a362e7SRui Ueyama // is for compatibility with Microsoft's lib command.
19864a362e7SRui Ueyama if (Magic == file_magic::archive) {
19964a362e7SRui Ueyama Error Err = Error::success();
20064a362e7SRui Ueyama object::Archive Archive(MB, Err);
20164a362e7SRui Ueyama fatalOpenError(std::move(Err), MB.getBufferIdentifier());
20264a362e7SRui Ueyama
20364a362e7SRui Ueyama for (auto &C : Archive.children(Err)) {
20464a362e7SRui Ueyama Expected<MemoryBufferRef> ChildMB = C.getMemoryBufferRef();
20564a362e7SRui Ueyama if (!ChildMB) {
20664a362e7SRui Ueyama handleAllErrors(ChildMB.takeError(), [&](const ErrorInfoBase &EIB) {
20764a362e7SRui Ueyama llvm::errs() << MB.getBufferIdentifier() << ": " << EIB.message()
20864a362e7SRui Ueyama << "\n";
20964a362e7SRui Ueyama });
21064a362e7SRui Ueyama exit(1);
21164a362e7SRui Ueyama }
21264a362e7SRui Ueyama
21364a362e7SRui Ueyama appendFile(Members, LibMachine, LibMachineSource, *ChildMB);
21464a362e7SRui Ueyama }
21564a362e7SRui Ueyama
21664a362e7SRui Ueyama fatalOpenError(std::move(Err), MB.getBufferIdentifier());
21764a362e7SRui Ueyama return;
21864a362e7SRui Ueyama }
21964a362e7SRui Ueyama
22064a362e7SRui Ueyama // Check that all input files have the same machine type.
22164a362e7SRui Ueyama // Mixing normal objects and LTO bitcode files is fine as long as they
22264a362e7SRui Ueyama // have the same machine type.
22364a362e7SRui Ueyama // Doing this here duplicates the header parsing work that writeArchive()
22464a362e7SRui Ueyama // below does, but it's not a lot of work and it's a bit awkward to do
22564a362e7SRui Ueyama // in writeArchive() which needs to support many tools, can't assume the
22664a362e7SRui Ueyama // input is COFF, and doesn't have a good way to report errors.
22764a362e7SRui Ueyama if (Magic == file_magic::coff_object || Magic == file_magic::bitcode) {
228f3c9687aSNico Weber Expected<COFF::MachineTypes> MaybeFileMachine =
229f3c9687aSNico Weber (Magic == file_magic::coff_object) ? getCOFFFileMachine(MB)
23064a362e7SRui Ueyama : getBitcodeFileMachine(MB);
231f3c9687aSNico Weber if (!MaybeFileMachine) {
23275196b99SNico Weber handleAllErrors(MaybeFileMachine.takeError(),
23375196b99SNico Weber [&](const ErrorInfoBase &EIB) {
23475196b99SNico Weber llvm::errs() << MB.getBufferIdentifier() << ": "
23575196b99SNico Weber << EIB.message() << "\n";
236f3c9687aSNico Weber });
237f3c9687aSNico Weber exit(1);
238f3c9687aSNico Weber }
239f3c9687aSNico Weber COFF::MachineTypes FileMachine = *MaybeFileMachine;
24064a362e7SRui Ueyama
24164a362e7SRui Ueyama // FIXME: Once lld-link rejects multiple resource .obj files:
24264a362e7SRui Ueyama // Call convertResToCOFF() on .res files and add the resulting
24364a362e7SRui Ueyama // COFF file to the .lib output instead of adding the .res file, and remove
24464a362e7SRui Ueyama // this check. See PR42180.
24564a362e7SRui Ueyama if (FileMachine != COFF::IMAGE_FILE_MACHINE_UNKNOWN) {
24664a362e7SRui Ueyama if (LibMachine == COFF::IMAGE_FILE_MACHINE_UNKNOWN) {
24764a362e7SRui Ueyama LibMachine = FileMachine;
24864a362e7SRui Ueyama LibMachineSource =
24964a362e7SRui Ueyama (" (inferred from earlier file '" + MB.getBufferIdentifier() + "')")
25064a362e7SRui Ueyama .str();
25164a362e7SRui Ueyama } else if (LibMachine != FileMachine) {
25264a362e7SRui Ueyama llvm::errs() << MB.getBufferIdentifier() << ": file machine type "
25364a362e7SRui Ueyama << machineToStr(FileMachine)
25464a362e7SRui Ueyama << " conflicts with library machine type "
25564a362e7SRui Ueyama << machineToStr(LibMachine) << LibMachineSource << '\n';
25664a362e7SRui Ueyama exit(1);
25764a362e7SRui Ueyama }
25864a362e7SRui Ueyama }
25964a362e7SRui Ueyama }
26064a362e7SRui Ueyama
26164a362e7SRui Ueyama Members.emplace_back(MB);
26264a362e7SRui Ueyama }
26364a362e7SRui Ueyama
libDriverMain(ArrayRef<const char * > ArgsArr)264f2f4e033SRui Ueyama int llvm::libDriverMain(ArrayRef<const char *> ArgsArr) {
265c6f07c42SPeter Collingbourne BumpPtrAllocator Alloc;
266c6f07c42SPeter Collingbourne StringSaver Saver(Alloc);
267f2f4e033SRui Ueyama
268f2f4e033SRui Ueyama // Parse command line arguments.
269f2f4e033SRui Ueyama SmallVector<const char *, 20> NewArgs(ArgsArr.begin(), ArgsArr.end());
270c6f07c42SPeter Collingbourne cl::ExpandResponseFiles(Saver, cl::TokenizeWindowsCommandLine, NewArgs);
271c6f07c42SPeter Collingbourne ArgsArr = NewArgs;
272c6f07c42SPeter Collingbourne
273c6f07c42SPeter Collingbourne LibOptTable Table;
274c6f07c42SPeter Collingbourne unsigned MissingIndex;
275c6f07c42SPeter Collingbourne unsigned MissingCount;
276f2f4e033SRui Ueyama opt::InputArgList Args =
277c6f07c42SPeter Collingbourne Table.ParseArgs(ArgsArr.slice(1), MissingIndex, MissingCount);
278c6f07c42SPeter Collingbourne if (MissingCount) {
279c6f07c42SPeter Collingbourne llvm::errs() << "missing arg value for \""
280c6f07c42SPeter Collingbourne << Args.getArgString(MissingIndex) << "\", expected "
281c6f07c42SPeter Collingbourne << MissingCount
282c6f07c42SPeter Collingbourne << (MissingCount == 1 ? " argument.\n" : " arguments.\n");
283c6f07c42SPeter Collingbourne return 1;
284c6f07c42SPeter Collingbourne }
285c6f07c42SPeter Collingbourne for (auto *Arg : Args.filtered(OPT_UNKNOWN))
286a7802763SNico Weber llvm::errs() << "ignoring unknown argument: " << Arg->getAsString(Args)
287a7802763SNico Weber << "\n";
288c6f07c42SPeter Collingbourne
28917172c6bSNico Weber // Handle /help
29017172c6bSNico Weber if (Args.hasArg(OPT_help)) {
291f1e2d585SFangrui Song Table.printHelp(outs(), "llvm-lib [options] file...", "LLVM Lib");
29217172c6bSNico Weber return 0;
29317172c6bSNico Weber }
29417172c6bSNico Weber
29575196b99SNico Weber // Parse /ignore:
29675196b99SNico Weber llvm::StringSet<> IgnoredWarnings;
29775196b99SNico Weber for (auto *Arg : Args.filtered(OPT_ignore))
29875196b99SNico Weber IgnoredWarnings.insert(Arg->getValue());
29975196b99SNico Weber
300e9827f0bSEric Astor // If no input files and not told otherwise, silently do nothing to match
301e9827f0bSEric Astor // lib.exe
30275196b99SNico Weber if (!Args.hasArgNoClaim(OPT_INPUT) && !Args.hasArg(OPT_llvmlibempty)) {
30375196b99SNico Weber if (!IgnoredWarnings.contains("emptyoutput")) {
30475196b99SNico Weber llvm::errs() << "warning: no input files, not writing output file\n";
30575196b99SNico Weber llvm::errs() << " pass /llvmlibempty to write empty .lib file,\n";
30675196b99SNico Weber llvm::errs() << " pass /ignore:emptyoutput to suppress warning\n";
30775196b99SNico Weber if (Args.hasFlag(OPT_WX, OPT_WX_no, false)) {
30875196b99SNico Weber llvm::errs() << "treating warning as error due to /WX\n";
30975196b99SNico Weber return 1;
31075196b99SNico Weber }
31175196b99SNico Weber }
312c6f07c42SPeter Collingbourne return 0;
31375196b99SNico Weber }
314c6f07c42SPeter Collingbourne
315a2f60933SNico Weber if (Args.hasArg(OPT_lst)) {
316a2f60933SNico Weber doList(Args);
317a2f60933SNico Weber return 0;
318a2f60933SNico Weber }
319a2f60933SNico Weber
320c6f07c42SPeter Collingbourne std::vector<StringRef> SearchPaths = getSearchPaths(&Args, Saver);
321c6f07c42SPeter Collingbourne
322b941fa88SNico Weber COFF::MachineTypes LibMachine = COFF::IMAGE_FILE_MACHINE_UNKNOWN;
323b941fa88SNico Weber std::string LibMachineSource;
324b941fa88SNico Weber if (auto *Arg = Args.getLastArg(OPT_machine)) {
325b941fa88SNico Weber LibMachine = getMachineType(Arg->getValue());
326b941fa88SNico Weber if (LibMachine == COFF::IMAGE_FILE_MACHINE_UNKNOWN) {
327b941fa88SNico Weber llvm::errs() << "unknown /machine: arg " << Arg->getValue() << '\n';
328b941fa88SNico Weber return 1;
329b941fa88SNico Weber }
330b941fa88SNico Weber LibMachineSource =
331b941fa88SNico Weber std::string(" (from '/machine:") + Arg->getValue() + "' flag)";
332b941fa88SNico Weber }
333b941fa88SNico Weber
33464a362e7SRui Ueyama std::vector<std::unique_ptr<MemoryBuffer>> MBs;
33560e9df33SRui Ueyama StringSet<> Seen;
336f2f4e033SRui Ueyama std::vector<NewArchiveMember> Members;
33764a362e7SRui Ueyama
33864a362e7SRui Ueyama // Create a NewArchiveMember for each input file.
339c6f07c42SPeter Collingbourne for (auto *Arg : Args.filtered(OPT_INPUT)) {
34064a362e7SRui Ueyama // Find a file
341f2f4e033SRui Ueyama std::string Path = findInputFile(Arg->getValue(), SearchPaths);
342f2f4e033SRui Ueyama if (Path.empty()) {
343c6f07c42SPeter Collingbourne llvm::errs() << Arg->getValue() << ": no such file or directory\n";
344c6f07c42SPeter Collingbourne return 1;
345c6f07c42SPeter Collingbourne }
346f2f4e033SRui Ueyama
34760e9df33SRui Ueyama // Input files are uniquified by pathname. If you specify the exact same
34860e9df33SRui Ueyama // path more than once, all but the first one are ignored.
34960e9df33SRui Ueyama //
35060e9df33SRui Ueyama // Note that there's a loophole in the rule; you can prepend `.\` or
35160e9df33SRui Ueyama // something like that to a path to make it look different, and they are
35260e9df33SRui Ueyama // handled as if they were different files. This behavior is compatible with
35360e9df33SRui Ueyama // Microsoft lib.exe.
35460e9df33SRui Ueyama if (!Seen.insert(Path).second)
35560e9df33SRui Ueyama continue;
35660e9df33SRui Ueyama
35764a362e7SRui Ueyama // Open a file.
358c83cd8feSAbhina Sreeskantharajan ErrorOr<std::unique_ptr<MemoryBuffer>> MOrErr = MemoryBuffer::getFile(
359c83cd8feSAbhina Sreeskantharajan Path, /*IsText=*/false, /*RequiresNullTerminator=*/false);
36064a362e7SRui Ueyama fatalOpenError(errorCodeToError(MOrErr.getError()), Path);
36164a362e7SRui Ueyama MemoryBufferRef MBRef = (*MOrErr)->getMemBufferRef();
362f2f4e033SRui Ueyama
36364a362e7SRui Ueyama // Append a file.
36464a362e7SRui Ueyama appendFile(Members, LibMachine, LibMachineSource, MBRef);
365d546b505SNico Weber
36664a362e7SRui Ueyama // Take the ownership of the file buffer to keep the file open.
36764a362e7SRui Ueyama MBs.push_back(std::move(*MOrErr));
368c6f07c42SPeter Collingbourne }
369c6f07c42SPeter Collingbourne
370f2f4e033SRui Ueyama // Create an archive file.
3711428f86cSEric Astor std::string OutputPath;
3721428f86cSEric Astor if (auto *Arg = Args.getLastArg(OPT_out)) {
3731428f86cSEric Astor OutputPath = Arg->getValue();
3741428f86cSEric Astor } else if (!Members.empty()) {
3751428f86cSEric Astor OutputPath = getDefaultOutputPath(Members[0]);
3761428f86cSEric Astor } else {
3771428f86cSEric Astor llvm::errs() << "no output path given, and cannot infer with no inputs\n";
3781428f86cSEric Astor return 1;
3791428f86cSEric Astor }
380451c2ef1SJordan Rupprecht // llvm-lib uses relative paths for both regular and thin archives, unlike
381451c2ef1SJordan Rupprecht // standard GNU ar, which only uses relative paths for thin archives and
382451c2ef1SJordan Rupprecht // basenames for regular archives.
3835d5078e3SOwen Reynolds for (NewArchiveMember &Member : Members) {
3845d5078e3SOwen Reynolds if (sys::path::is_relative(Member.MemberName)) {
3855d5078e3SOwen Reynolds Expected<std::string> PathOrErr =
3865d5078e3SOwen Reynolds computeArchiveRelativePath(OutputPath, Member.MemberName);
3875d5078e3SOwen Reynolds if (PathOrErr)
3885d5078e3SOwen Reynolds Member.MemberName = Saver.save(*PathOrErr);
3895d5078e3SOwen Reynolds }
3905d5078e3SOwen Reynolds }
391451c2ef1SJordan Rupprecht
39225cbdf25SRafael Espindola if (Error E =
393f2f4e033SRui Ueyama writeArchive(OutputPath, Members,
394c6f07c42SPeter Collingbourne /*WriteSymtab=*/true, object::Archive::K_GNU,
39525cbdf25SRafael Espindola /*Deterministic*/ true, Args.hasArg(OPT_llvmlibthin))) {
39625cbdf25SRafael Espindola handleAllErrors(std::move(E), [&](const ErrorInfoBase &EI) {
39725cbdf25SRafael Espindola llvm::errs() << OutputPath << ": " << EI.message() << "\n";
39825cbdf25SRafael Espindola });
399c6f07c42SPeter Collingbourne return 1;
400c6f07c42SPeter Collingbourne }
401c6f07c42SPeter Collingbourne
402c6f07c42SPeter Collingbourne return 0;
403c6f07c42SPeter Collingbourne }
404