LLVM 17.0.0git
LibDriver.cpp
Go to the documentation of this file.
1//===- LibDriver.cpp - lib.exe-compatible driver --------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// Defines an interface to a lib.exe-compatible driver that also understands
10// bitcode files. Used by llvm-lib and lld-link /lib.
11//
12//===----------------------------------------------------------------------===//
13
15#include "llvm/ADT/STLExtras.h"
16#include "llvm/ADT/StringSet.h"
21#include "llvm/Object/COFF.h"
23#include "llvm/Option/Arg.h"
24#include "llvm/Option/ArgList.h"
25#include "llvm/Option/Option.h"
27#include "llvm/Support/Path.h"
31#include <optional>
32
33using namespace llvm;
34
35namespace {
36
37enum {
38 OPT_INVALID = 0,
39#define OPTION(_1, _2, ID, _4, _5, _6, _7, _8, _9, _10, _11, _12) OPT_##ID,
40#include "Options.inc"
41#undef OPTION
42};
43
44#define PREFIX(NAME, VALUE) \
45 static constexpr StringLiteral NAME##_init[] = VALUE; \
46 static constexpr ArrayRef<StringLiteral> NAME(NAME##_init, \
47 std::size(NAME##_init) - 1);
48#include "Options.inc"
49#undef PREFIX
50
51static constexpr opt::OptTable::Info InfoTable[] = {
52#define OPTION(X1, X2, ID, KIND, GROUP, ALIAS, X7, X8, X9, X10, X11, X12) \
53 {X1, X2, X10, X11, OPT_##ID, opt::Option::KIND##Class, \
54 X9, X8, OPT_##GROUP, OPT_##ALIAS, X7, X12},
55#include "Options.inc"
56#undef OPTION
57};
58
59class LibOptTable : public opt::GenericOptTable {
60public:
61 LibOptTable() : opt::GenericOptTable(InfoTable, true) {}
62};
63}
64
65static std::string getDefaultOutputPath(const NewArchiveMember &FirstMember) {
66 SmallString<128> Val = StringRef(FirstMember.Buf->getBufferIdentifier());
68 return std::string(Val.str());
69}
70
71static std::vector<StringRef> getSearchPaths(opt::InputArgList *Args,
72 StringSaver &Saver) {
73 std::vector<StringRef> Ret;
74 // Add current directory as first item of the search path.
75 Ret.push_back("");
76
77 // Add /libpath flags.
78 for (auto *Arg : Args->filtered(OPT_libpath))
79 Ret.push_back(Arg->getValue());
80
81 // Add $LIB.
82 std::optional<std::string> EnvOpt = sys::Process::GetEnv("LIB");
83 if (!EnvOpt)
84 return Ret;
85 StringRef Env = Saver.save(*EnvOpt);
86 while (!Env.empty()) {
87 StringRef Path;
88 std::tie(Path, Env) = Env.split(';');
89 Ret.push_back(Path);
90 }
91 return Ret;
92}
93
94static std::string findInputFile(StringRef File, ArrayRef<StringRef> Paths) {
95 for (StringRef Dir : Paths) {
96 SmallString<128> Path = Dir;
97 sys::path::append(Path, File);
98 if (sys::fs::exists(Path))
99 return std::string(Path);
100 }
101 return "";
102}
103
104static void fatalOpenError(llvm::Error E, Twine File) {
105 if (!E)
106 return;
107 handleAllErrors(std::move(E), [&](const llvm::ErrorInfoBase &EIB) {
108 llvm::errs() << "error opening '" << File << "': " << EIB.message() << '\n';
109 exit(1);
110 });
111}
112
113static void doList(opt::InputArgList& Args) {
114 // lib.exe prints the contents of the first archive file.
115 std::unique_ptr<MemoryBuffer> B;
116 for (auto *Arg : Args.filtered(OPT_INPUT)) {
117 // Create or open the archive object.
119 Arg->getValue(), /*IsText=*/false, /*RequiresNullTerminator=*/false);
120 fatalOpenError(errorCodeToError(MaybeBuf.getError()), Arg->getValue());
121
122 if (identify_magic(MaybeBuf.get()->getBuffer()) == file_magic::archive) {
123 B = std::move(MaybeBuf.get());
124 break;
125 }
126 }
127
128 // lib.exe doesn't print an error if no .lib files are passed.
129 if (!B)
130 return;
131
132 Error Err = Error::success();
133 object::Archive Archive(B.get()->getMemBufferRef(), Err);
134 fatalOpenError(std::move(Err), B->getBufferIdentifier());
135
136 for (auto &C : Archive.children(Err)) {
137 Expected<StringRef> NameOrErr = C.getName();
138 fatalOpenError(NameOrErr.takeError(), B->getBufferIdentifier());
139 StringRef Name = NameOrErr.get();
140 llvm::outs() << Name << '\n';
141 }
142 fatalOpenError(std::move(Err), B->getBufferIdentifier());
143}
144
146 std::error_code EC;
147 auto Obj = object::COFFObjectFile::create(MB);
148 if (!Obj)
149 return Obj.takeError();
150
151 uint16_t Machine = (*Obj)->getMachine();
152 if (Machine != COFF::IMAGE_FILE_MACHINE_I386 &&
157 "unknown machine: " + std::to_string(Machine));
158 }
159
160 return static_cast<COFF::MachineTypes>(Machine);
161}
162
165 if (!TripleStr)
166 return TripleStr.takeError();
167
168 switch (Triple(*TripleStr).getArch()) {
169 case Triple::x86:
171 case Triple::x86_64:
173 case Triple::arm:
175 case Triple::aarch64:
177 default:
179 "unknown arch in target triple: " + *TripleStr);
180 }
181}
182
183static void appendFile(std::vector<NewArchiveMember> &Members,
184 COFF::MachineTypes &LibMachine,
185 std::string &LibMachineSource, MemoryBufferRef MB) {
186 file_magic Magic = identify_magic(MB.getBuffer());
187
188 if (Magic != file_magic::coff_object && Magic != file_magic::bitcode &&
192 << ": not a COFF object, bitcode, archive, import library or "
193 "resource file\n";
194 exit(1);
195 }
196
197 // If a user attempts to add an archive to another archive, llvm-lib doesn't
198 // handle the first archive file as a single file. Instead, it extracts all
199 // members from the archive and add them to the second archive. This behavior
200 // is for compatibility with Microsoft's lib command.
201 if (Magic == file_magic::archive) {
202 Error Err = Error::success();
203 object::Archive Archive(MB, Err);
204 fatalOpenError(std::move(Err), MB.getBufferIdentifier());
205
206 for (auto &C : Archive.children(Err)) {
207 Expected<MemoryBufferRef> ChildMB = C.getMemoryBufferRef();
208 if (!ChildMB) {
209 handleAllErrors(ChildMB.takeError(), [&](const ErrorInfoBase &EIB) {
210 llvm::errs() << MB.getBufferIdentifier() << ": " << EIB.message()
211 << "\n";
212 });
213 exit(1);
214 }
215
216 appendFile(Members, LibMachine, LibMachineSource, *ChildMB);
217 }
218
219 fatalOpenError(std::move(Err), MB.getBufferIdentifier());
220 return;
221 }
222
223 // Check that all input files have the same machine type.
224 // Mixing normal objects and LTO bitcode files is fine as long as they
225 // have the same machine type.
226 // Doing this here duplicates the header parsing work that writeArchive()
227 // below does, but it's not a lot of work and it's a bit awkward to do
228 // in writeArchive() which needs to support many tools, can't assume the
229 // input is COFF, and doesn't have a good way to report errors.
230 if (Magic == file_magic::coff_object || Magic == file_magic::bitcode) {
231 Expected<COFF::MachineTypes> MaybeFileMachine =
234 if (!MaybeFileMachine) {
235 handleAllErrors(MaybeFileMachine.takeError(),
236 [&](const ErrorInfoBase &EIB) {
237 llvm::errs() << MB.getBufferIdentifier() << ": "
238 << EIB.message() << "\n";
239 });
240 exit(1);
241 }
242 COFF::MachineTypes FileMachine = *MaybeFileMachine;
243
244 // FIXME: Once lld-link rejects multiple resource .obj files:
245 // Call convertResToCOFF() on .res files and add the resulting
246 // COFF file to the .lib output instead of adding the .res file, and remove
247 // this check. See PR42180.
248 if (FileMachine != COFF::IMAGE_FILE_MACHINE_UNKNOWN) {
249 if (LibMachine == COFF::IMAGE_FILE_MACHINE_UNKNOWN) {
250 LibMachine = FileMachine;
251 LibMachineSource =
252 (" (inferred from earlier file '" + MB.getBufferIdentifier() + "')")
253 .str();
254 } else if (LibMachine != FileMachine) {
255 llvm::errs() << MB.getBufferIdentifier() << ": file machine type "
256 << machineToStr(FileMachine)
257 << " conflicts with library machine type "
258 << machineToStr(LibMachine) << LibMachineSource << '\n';
259 exit(1);
260 }
261 }
262 }
263
264 Members.emplace_back(MB);
265}
266
268 BumpPtrAllocator Alloc;
269 StringSaver Saver(Alloc);
270
271 // Parse command line arguments.
272 SmallVector<const char *, 20> NewArgs(ArgsArr.begin(), ArgsArr.end());
274 ArgsArr = NewArgs;
275
276 LibOptTable Table;
277 unsigned MissingIndex;
278 unsigned MissingCount;
279 opt::InputArgList Args =
280 Table.ParseArgs(ArgsArr.slice(1), MissingIndex, MissingCount);
281 if (MissingCount) {
282 llvm::errs() << "missing arg value for \""
283 << Args.getArgString(MissingIndex) << "\", expected "
284 << MissingCount
285 << (MissingCount == 1 ? " argument.\n" : " arguments.\n");
286 return 1;
287 }
288 for (auto *Arg : Args.filtered(OPT_UNKNOWN))
289 llvm::errs() << "ignoring unknown argument: " << Arg->getAsString(Args)
290 << "\n";
291
292 // Handle /help
293 if (Args.hasArg(OPT_help)) {
294 Table.printHelp(outs(), "llvm-lib [options] file...", "LLVM Lib");
295 return 0;
296 }
297
298 // Parse /ignore:
299 llvm::StringSet<> IgnoredWarnings;
300 for (auto *Arg : Args.filtered(OPT_ignore))
301 IgnoredWarnings.insert(Arg->getValue());
302
303 // If no input files and not told otherwise, silently do nothing to match
304 // lib.exe
305 if (!Args.hasArgNoClaim(OPT_INPUT) && !Args.hasArg(OPT_llvmlibempty)) {
306 if (!IgnoredWarnings.contains("emptyoutput")) {
307 llvm::errs() << "warning: no input files, not writing output file\n";
308 llvm::errs() << " pass /llvmlibempty to write empty .lib file,\n";
309 llvm::errs() << " pass /ignore:emptyoutput to suppress warning\n";
310 if (Args.hasFlag(OPT_WX, OPT_WX_no, false)) {
311 llvm::errs() << "treating warning as error due to /WX\n";
312 return 1;
313 }
314 }
315 return 0;
316 }
317
318 if (Args.hasArg(OPT_lst)) {
319 doList(Args);
320 return 0;
321 }
322
323 std::vector<StringRef> SearchPaths = getSearchPaths(&Args, Saver);
324
326 std::string LibMachineSource;
327 if (auto *Arg = Args.getLastArg(OPT_machine)) {
328 LibMachine = getMachineType(Arg->getValue());
329 if (LibMachine == COFF::IMAGE_FILE_MACHINE_UNKNOWN) {
330 llvm::errs() << "unknown /machine: arg " << Arg->getValue() << '\n';
331 return 1;
332 }
333 LibMachineSource =
334 std::string(" (from '/machine:") + Arg->getValue() + "' flag)";
335 }
336
337 std::vector<std::unique_ptr<MemoryBuffer>> MBs;
338 StringSet<> Seen;
339 std::vector<NewArchiveMember> Members;
340
341 // Create a NewArchiveMember for each input file.
342 for (auto *Arg : Args.filtered(OPT_INPUT)) {
343 // Find a file
344 std::string Path = findInputFile(Arg->getValue(), SearchPaths);
345 if (Path.empty()) {
346 llvm::errs() << Arg->getValue() << ": no such file or directory\n";
347 return 1;
348 }
349
350 // Input files are uniquified by pathname. If you specify the exact same
351 // path more than once, all but the first one are ignored.
352 //
353 // Note that there's a loophole in the rule; you can prepend `.\` or
354 // something like that to a path to make it look different, and they are
355 // handled as if they were different files. This behavior is compatible with
356 // Microsoft lib.exe.
357 if (!Seen.insert(Path).second)
358 continue;
359
360 // Open a file.
362 Path, /*IsText=*/false, /*RequiresNullTerminator=*/false);
364 MemoryBufferRef MBRef = (*MOrErr)->getMemBufferRef();
365
366 // Append a file.
367 appendFile(Members, LibMachine, LibMachineSource, MBRef);
368
369 // Take the ownership of the file buffer to keep the file open.
370 MBs.push_back(std::move(*MOrErr));
371 }
372
373 // Create an archive file.
374 std::string OutputPath;
375 if (auto *Arg = Args.getLastArg(OPT_out)) {
376 OutputPath = Arg->getValue();
377 } else if (!Members.empty()) {
378 OutputPath = getDefaultOutputPath(Members[0]);
379 } else {
380 llvm::errs() << "no output path given, and cannot infer with no inputs\n";
381 return 1;
382 }
383 // llvm-lib uses relative paths for both regular and thin archives, unlike
384 // standard GNU ar, which only uses relative paths for thin archives and
385 // basenames for regular archives.
386 for (NewArchiveMember &Member : Members) {
387 if (sys::path::is_relative(Member.MemberName)) {
388 Expected<std::string> PathOrErr =
389 computeArchiveRelativePath(OutputPath, Member.MemberName);
390 if (PathOrErr)
391 Member.MemberName = Saver.save(*PathOrErr);
392 }
393 }
394
395 if (Error E =
396 writeArchive(OutputPath, Members,
397 /*WriteSymtab=*/true, object::Archive::K_GNU,
398 /*Deterministic*/ true, Args.hasArg(OPT_llvmlibthin))) {
399 handleAllErrors(std::move(E), [&](const ErrorInfoBase &EI) {
400 llvm::errs() << OutputPath << ": " << EI.message() << "\n";
401 });
402 return 1;
403 }
404
405 return 0;
406}
amdgpu Simplify well known AMD library false FunctionCallee Value * Arg
arm prera ldst opt
Defines the llvm::Arg class for parsed arguments.
basic Basic Alias true
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
std::string Name
static Expected< COFF::MachineTypes > getBitcodeFileMachine(MemoryBufferRef MB)
Definition: LibDriver.cpp:163
static Expected< COFF::MachineTypes > getCOFFFileMachine(MemoryBufferRef MB)
Definition: LibDriver.cpp:145
static std::string getDefaultOutputPath(const NewArchiveMember &FirstMember)
Definition: LibDriver.cpp:65
static std::string findInputFile(StringRef File, ArrayRef< StringRef > Paths)
Definition: LibDriver.cpp:94
static void doList(opt::InputArgList &Args)
Definition: LibDriver.cpp:113
static std::vector< StringRef > getSearchPaths(opt::InputArgList *Args, StringSaver &Saver)
Definition: LibDriver.cpp:71
static void appendFile(std::vector< NewArchiveMember > &Members, COFF::MachineTypes &LibMachine, std::string &LibMachineSource, MemoryBufferRef MB)
Definition: LibDriver.cpp:183
static void fatalOpenError(llvm::Error E, Twine File)
Definition: LibDriver.cpp:104
Provides a library for accessing information about this process and other processes on the operating ...
This file contains some templates that are useful if you are working with the STL at all.
StringSet - A set-like wrapper for the StringMap.
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
Definition: ArrayRef.h:41
iterator end() const
Definition: ArrayRef.h:152
iterator begin() const
Definition: ArrayRef.h:151
ArrayRef< T > slice(size_t N, size_t M) const
slice(n, m) - Chop off the first N elements of the array, and keep M elements in the array.
Definition: ArrayRef.h:193
Allocate memory in an ever growing pool, as if by bump-pointer.
Definition: Allocator.h:66
Base class for error info classes.
Definition: Error.h:47
virtual std::string message() const
Return the error message as a string.
Definition: Error.h:55
Represents either an error or a value T.
Definition: ErrorOr.h:56
reference get()
Definition: ErrorOr.h:150
std::error_code getError() const
Definition: ErrorOr.h:153
Lightweight error class with error context and mandatory checking.
Definition: Error.h:156
static ErrorSuccess success()
Create a success value.
Definition: Error.h:330
Tagged union holding either a T or a Error.
Definition: Error.h:470
Error takeError()
Take ownership of the stored error.
Definition: Error.h:597
reference get()
Returns a reference to the stored T value.
Definition: Error.h:567
StringRef getBufferIdentifier() const
StringRef getBuffer() const
static ErrorOr< std::unique_ptr< MemoryBuffer > > getFile(const Twine &Filename, bool IsText=false, bool RequiresNullTerminator=true, bool IsVolatile=false, std::optional< Align > Alignment=std::nullopt)
Open the specified file as a MemoryBuffer, returning a new MemoryBuffer if successful,...
SmallString - A SmallString is just a SmallVector with methods and accessors that make it work better...
Definition: SmallString.h:26
StringRef str() const
Explicit conversion to StringRef.
Definition: SmallString.h:261
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Definition: SmallVector.h:1200
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:50
std::pair< StringRef, StringRef > split(char Separator) const
Split into two substrings around the first occurrence of a separator character.
Definition: StringRef.h:688
constexpr bool empty() const
empty - Check if the string is empty.
Definition: StringRef.h:134
Saves strings in the provided stable storage and returns a StringRef with a stable character pointer.
Definition: StringSaver.h:21
StringRef save(const char *S)
Definition: StringSaver.h:30
StringSet - A wrapper for StringMap that provides set-like functionality.
Definition: StringSet.h:23
bool contains(StringRef key) const
Check if the set contains the given key.
Definition: StringSet.h:51
std::pair< typename Base::iterator, bool > insert(StringRef key)
Definition: StringSet.h:34
Triple - Helper class for working with autoconf configuration names.
Definition: Triple.h:44
ArchType getArch() const
Get the parsed architecture type of this triple.
Definition: Triple.h:355
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
Definition: Twine.h:81
iterator_range< child_iterator > children(Error &Err, bool SkipInternal=true) const
Definition: Archive.h:344
static Expected< std::unique_ptr< COFFObjectFile > > create(MemoryBufferRef Object)
Specialization of OptTable.
Definition: OptTable.h:267
static std::optional< std::string > GetEnv(StringRef name)
MachineTypes
Definition: COFF.h:92
@ IMAGE_FILE_MACHINE_ARM64
Definition: COFF.h:100
@ IMAGE_FILE_MACHINE_UNKNOWN
Definition: COFF.h:95
@ IMAGE_FILE_MACHINE_AMD64
Definition: COFF.h:97
@ IMAGE_FILE_MACHINE_I386
Definition: COFF.h:103
@ IMAGE_FILE_MACHINE_ARMNT
Definition: COFF.h:99
@ C
The default llvm calling convention, compatible with C.
Definition: CallingConv.h:34
bool ExpandResponseFiles(StringSaver &Saver, TokenizerCallback Tokenizer, SmallVectorImpl< const char * > &Argv)
A convenience helper which supports the typical use case of expansion function call.
void TokenizeWindowsCommandLine(StringRef Source, StringSaver &Saver, SmallVectorImpl< const char * > &NewArgv, bool MarkEOLs=false)
Tokenizes a string of Windows command line arguments, which may contain quotes and escaped quotes.
bool exists(const basic_file_status &status)
Does file exist?
Definition: Path.cpp:1077
void replace_extension(SmallVectorImpl< char > &path, const Twine &extension, Style style=Style::native)
Replace the file extension of path with extension.
Definition: Path.cpp:480
bool is_relative(const Twine &path, Style style=Style::native)
Is path relative?
Definition: Path.cpp:699
void append(SmallVectorImpl< char > &path, const Twine &a, const Twine &b="", const Twine &c="", const Twine &d="")
Append to path.
Definition: Path.cpp:456
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
file_magic identify_magic(StringRef magic)
Identify the type of a binary file based on how magical it is.
Definition: Magic.cpp:33
int libDriverMain(ArrayRef< const char * > ARgs)
Definition: LibDriver.cpp:267
void handleAllErrors(Error E, HandlerTs &&... Handlers)
Behaves the same as handleErrors, except that by contract all errors must be handled by the given han...
Definition: Error.h:966
std::error_code inconvertibleErrorCode()
The value returned by this function can be returned from convertToErrorCode for Error values where no...
Definition: Error.cpp:79
raw_fd_ostream & outs()
This returns a reference to a raw_fd_ostream for standard output.
Expected< std::string > getBitcodeTargetTriple(MemoryBufferRef Buffer)
Read the header of the specified bitcode buffer and extract just the triple information.
COFF::MachineTypes getMachineType(StringRef S)
Error createStringError(std::error_code EC, char const *Fmt, const Ts &... Vals)
Create formatted StringError object.
Definition: Error.h:1246
StringRef machineToStr(COFF::MachineTypes MT)
raw_fd_ostream & errs()
This returns a reference to a raw_ostream for standard error.
Error writeArchive(StringRef ArcName, ArrayRef< NewArchiveMember > NewMembers, bool WriteSymtab, object::Archive::Kind Kind, bool Deterministic, bool Thin, std::unique_ptr< MemoryBuffer > OldArchiveBuf=nullptr)
Expected< std::string > computeArchiveRelativePath(StringRef From, StringRef To)
Error errorCodeToError(std::error_code EC)
Helper for converting an std::error_code to a Error.
Definition: Error.cpp:92
std::unique_ptr< MemoryBuffer > Buf
Definition: ArchiveWriter.h:21
file_magic - An "enum class" enumeration of file types based on magic (the first N bytes of the file)...
Definition: Magic.h:20
@ coff_import_library
COFF import library.
Definition: Magic.h:47
@ archive
ar style archive file
Definition: Magic.h:24
@ bitcode
Bitcode file.
Definition: Magic.h:23
@ windows_resource
Windows compiled resource file (.res)
Definition: Magic.h:49
@ coff_object
COFF object file.
Definition: Magic.h:46
Entry for a single option instance in the option data table.
Definition: OptTable.h:43