1 //===-- llvm-libtool-darwin.cpp - a tool for creating libraries -----------===//
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
7 //===----------------------------------------------------------------------===//
9 // A utility for creating static and dynamic libraries for Darwin.
11 //===----------------------------------------------------------------------===//
13 #include "llvm/BinaryFormat/Magic.h"
14 #include "llvm/IR/LLVMContext.h"
15 #include "llvm/Object/ArchiveWriter.h"
16 #include "llvm/Object/IRObjectFile.h"
17 #include "llvm/Object/MachO.h"
18 #include "llvm/Object/MachOUniversal.h"
19 #include "llvm/Object/MachOUniversalWriter.h"
20 #include "llvm/Object/ObjectFile.h"
21 #include "llvm/Support/CommandLine.h"
22 #include "llvm/Support/InitLLVM.h"
23 #include "llvm/Support/LineIterator.h"
24 #include "llvm/Support/VirtualFileSystem.h"
25 #include "llvm/Support/WithColor.h"
26 #include "llvm/TextAPI/Architecture.h"
28 #include <type_traits>
31 using namespace llvm::object
;
33 static LLVMContext LLVMCtx
;
35 typedef std::map
<uint64_t, std::vector
<NewArchiveMember
>>
36 MembersPerArchitectureMap
;
38 cl::OptionCategory
LibtoolCategory("llvm-libtool-darwin Options");
40 static cl::opt
<std::string
> OutputFile("o", cl::desc("Specify output filename"),
41 cl::value_desc("filename"),
42 cl::cat(LibtoolCategory
));
44 static cl::list
<std::string
> InputFiles(cl::Positional
,
45 cl::desc("<input files>"),
47 cl::cat(LibtoolCategory
));
49 static cl::opt
<std::string
> ArchType(
50 "arch_only", cl::desc("Specify architecture type for output library"),
51 cl::value_desc("arch_type"), cl::ZeroOrMore
, cl::cat(LibtoolCategory
));
53 enum class Operation
{ None
, Static
};
55 static cl::opt
<Operation
> LibraryOperation(
56 cl::desc("Library Type: "),
58 clEnumValN(Operation::Static
, "static",
59 "Produce a statically linked library from the input files")),
60 cl::init(Operation::None
), cl::cat(LibtoolCategory
));
62 static cl::opt
<bool> DeterministicOption(
63 "D", cl::desc("Use zero for timestamps and UIDs/GIDs (Default)"),
64 cl::init(false), cl::cat(LibtoolCategory
));
67 NonDeterministicOption("U", cl::desc("Use actual timestamps and UIDs/GIDs"),
68 cl::init(false), cl::cat(LibtoolCategory
));
70 static cl::opt
<std::string
>
72 cl::desc("Pass in file containing a list of filenames"),
73 cl::value_desc("listfile[,dirname]"), cl::cat(LibtoolCategory
));
75 static cl::list
<std::string
> Libraries(
78 "l<x> searches for the library libx.a in the library search path. If"
79 " the string 'x' ends with '.o', then the library 'x' is searched for"
80 " without prepending 'lib' or appending '.a'"),
81 cl::ZeroOrMore
, cl::Prefix
, cl::cat(LibtoolCategory
));
83 static cl::list
<std::string
> LibrarySearchDirs(
86 "L<dir> adds <dir> to the list of directories in which to search for"
88 cl::ZeroOrMore
, cl::Prefix
, cl::cat(LibtoolCategory
));
91 VersionOption("V", cl::desc("Print the version number and exit"),
92 cl::cat(LibtoolCategory
));
94 static cl::opt
<bool> NoWarningForNoSymbols(
95 "no_warning_for_no_symbols",
96 cl::desc("Do not warn about files that have no symbols"),
97 cl::cat(LibtoolCategory
), cl::init(false));
99 static const std::array
<std::string
, 3> StandardSearchDirs
{
106 bool Deterministic
= true; // Updated by 'D' and 'U' modifiers.
107 uint32_t ArchCPUType
;
108 uint32_t ArchCPUSubtype
;
111 static Expected
<std::string
> searchForFile(const Twine
&FileName
) {
114 [FileName
](ArrayRef
<std::string
> SearchDirs
) -> Optional
<std::string
> {
115 for (StringRef Dir
: SearchDirs
) {
116 SmallString
<128> Path
;
117 sys::path::append(Path
, Dir
, FileName
);
119 if (sys::fs::exists(Path
))
120 return std::string(Path
);
125 Optional
<std::string
> Found
= FindLib(LibrarySearchDirs
);
127 Found
= FindLib(StandardSearchDirs
);
131 return createStringError(std::errc::invalid_argument
,
132 "cannot locate file '%s'", FileName
.str().c_str());
135 static Error
processCommandLineLibraries() {
136 for (StringRef BaseName
: Libraries
) {
137 Expected
<std::string
> FullPath
= searchForFile(
138 BaseName
.endswith(".o") ? BaseName
.str() : "lib" + BaseName
+ ".a");
140 return FullPath
.takeError();
141 InputFiles
.push_back(FullPath
.get());
144 return Error::success();
147 static Error
processFileList() {
148 StringRef FileName
, DirName
;
149 std::tie(FileName
, DirName
) = StringRef(FileList
).rsplit(",");
151 ErrorOr
<std::unique_ptr
<MemoryBuffer
>> FileOrErr
=
152 MemoryBuffer::getFileOrSTDIN(FileName
, /*IsText=*/false,
153 /*RequiresNullTerminator=*/false);
154 if (std::error_code EC
= FileOrErr
.getError())
155 return createFileError(FileName
, errorCodeToError(EC
));
156 const MemoryBuffer
&Ref
= *FileOrErr
.get();
158 line_iterator
I(Ref
, /*SkipBlanks=*/false);
160 return createStringError(std::errc::invalid_argument
,
161 "file list file: '%s' is empty",
162 FileName
.str().c_str());
163 for (; !I
.is_at_eof(); ++I
) {
166 return createStringError(std::errc::invalid_argument
,
167 "file list file: '%s': filename cannot be empty",
168 FileName
.str().c_str());
170 SmallString
<128> Path
;
171 if (!DirName
.empty())
172 sys::path::append(Path
, DirName
, Line
);
174 sys::path::append(Path
, Line
);
175 InputFiles
.push_back(static_cast<std::string
>(Path
));
177 return Error::success();
180 static Error
validateArchitectureName(StringRef ArchitectureName
) {
181 if (!MachOObjectFile::isValidArch(ArchitectureName
)) {
183 raw_string_ostream
OS(Buf
);
184 for (StringRef Arch
: MachOObjectFile::getValidArchs())
187 return createStringError(
188 std::errc::invalid_argument
,
189 "invalid architecture '%s': valid architecture names are %s",
190 ArchitectureName
.str().c_str(), OS
.str().c_str());
192 return Error::success();
195 static uint64_t getCPUID(uint32_t CPUType
, uint32_t CPUSubtype
) {
197 case MachO::CPU_TYPE_ARM
:
198 case MachO::CPU_TYPE_ARM64
:
199 case MachO::CPU_TYPE_ARM64_32
:
200 case MachO::CPU_TYPE_X86_64
:
201 // We consider CPUSubtype only for the above 4 CPUTypes to match cctools'
203 return static_cast<uint64_t>(CPUType
) << 32 | CPUSubtype
;
209 // MembersData is an organized collection of members.
211 // MembersPerArchitectureMap is a mapping from CPU architecture to a list of
213 MembersPerArchitectureMap MembersPerArchitecture
;
214 std::vector
<std::unique_ptr
<MemoryBuffer
>> FileBuffers
;
216 static_assert(!std::is_copy_constructible
<NewArchiveMember
>::value
,
217 "MembersPerArchitecture has a dependency on FileBuffers so it "
218 "should not be able to be copied on its own without "
220 static_assert(!std::is_copy_assignable
<NewArchiveMember
>::value
,
221 "MembersPerArchitecture has a dependency on FileBuffers so it "
222 "should not be able to be copied on its own without "
226 // MembersBuilder collects and organizes all members from the files provided by
228 class MembersBuilder
{
230 MembersBuilder(const Config
&C
) : C(C
) {}
232 Expected
<MembersData
> build() {
233 for (StringRef FileName
: InputFiles
)
234 if (Error E
= addMember(FileName
))
237 if (!ArchType
.empty()) {
238 uint64_t ArchCPUID
= getCPUID(C
.ArchCPUType
, C
.ArchCPUSubtype
);
239 if (Data
.MembersPerArchitecture
.find(ArchCPUID
) ==
240 Data
.MembersPerArchitecture
.end())
241 return createStringError(std::errc::invalid_argument
,
242 "no library created (no object files in input "
243 "files matching -arch_only %s)",
246 return std::move(Data
);
250 // Check that a file's architecture [FileCPUType, FileCPUSubtype]
251 // matches the architecture specified under -arch_only flag.
252 bool acceptFileArch(uint32_t FileCPUType
, uint32_t FileCPUSubtype
) {
253 if (C
.ArchCPUType
!= FileCPUType
)
256 switch (C
.ArchCPUType
) {
257 case MachO::CPU_TYPE_ARM
:
258 case MachO::CPU_TYPE_ARM64_32
:
259 case MachO::CPU_TYPE_X86_64
:
260 return C
.ArchCPUSubtype
== FileCPUSubtype
;
262 case MachO::CPU_TYPE_ARM64
:
263 if (C
.ArchCPUSubtype
== MachO::CPU_SUBTYPE_ARM64_ALL
)
264 return FileCPUSubtype
== MachO::CPU_SUBTYPE_ARM64_ALL
||
265 FileCPUSubtype
== MachO::CPU_SUBTYPE_ARM64_V8
;
267 return C
.ArchCPUSubtype
== FileCPUSubtype
;
274 Error
verifyAndAddMachOObject(NewArchiveMember Member
) {
275 auto MBRef
= Member
.Buf
->getMemBufferRef();
276 Expected
<std::unique_ptr
<object::ObjectFile
>> ObjOrErr
=
277 object::ObjectFile::createObjectFile(MBRef
);
279 // Throw error if not a valid object file.
281 return createFileError(Member
.MemberName
, ObjOrErr
.takeError());
283 // Throw error if not in Mach-O format.
284 if (!isa
<object::MachOObjectFile
>(**ObjOrErr
))
285 return createStringError(std::errc::invalid_argument
,
286 "'%s': format not supported",
287 Member
.MemberName
.data());
289 auto *O
= dyn_cast
<MachOObjectFile
>(ObjOrErr
->get());
290 uint32_t FileCPUType
, FileCPUSubtype
;
291 std::tie(FileCPUType
, FileCPUSubtype
) = MachO::getCPUTypeFromArchitecture(
292 MachO::getArchitectureFromName(O
->getArchTriple().getArchName()));
294 // If -arch_only is specified then skip this file if it doesn't match
295 // the architecture specified.
296 if (!ArchType
.empty() && !acceptFileArch(FileCPUType
, FileCPUSubtype
)) {
297 return Error::success();
300 if (!NoWarningForNoSymbols
&& O
->symbols().empty())
301 WithColor::warning() << Member
.MemberName
+ " has no symbols\n";
303 uint64_t FileCPUID
= getCPUID(FileCPUType
, FileCPUSubtype
);
304 Data
.MembersPerArchitecture
[FileCPUID
].push_back(std::move(Member
));
305 return Error::success();
308 Error
verifyAndAddIRObject(NewArchiveMember Member
) {
309 auto MBRef
= Member
.Buf
->getMemBufferRef();
310 Expected
<std::unique_ptr
<object::IRObjectFile
>> IROrErr
=
311 object::IRObjectFile::create(MBRef
, LLVMCtx
);
313 // Throw error if not a valid IR object file.
315 return createFileError(Member
.MemberName
, IROrErr
.takeError());
317 Triple TT
= Triple(IROrErr
->get()->getTargetTriple());
319 Expected
<uint32_t> FileCPUTypeOrErr
= MachO::getCPUType(TT
);
320 if (!FileCPUTypeOrErr
)
321 return FileCPUTypeOrErr
.takeError();
323 Expected
<uint32_t> FileCPUSubTypeOrErr
= MachO::getCPUSubType(TT
);
324 if (!FileCPUSubTypeOrErr
)
325 return FileCPUSubTypeOrErr
.takeError();
327 // If -arch_only is specified then skip this file if it doesn't match
328 // the architecture specified.
329 if (!ArchType
.empty() &&
330 !acceptFileArch(*FileCPUTypeOrErr
, *FileCPUSubTypeOrErr
)) {
331 return Error::success();
334 uint64_t FileCPUID
= getCPUID(*FileCPUTypeOrErr
, *FileCPUSubTypeOrErr
);
335 Data
.MembersPerArchitecture
[FileCPUID
].push_back(std::move(Member
));
336 return Error::success();
339 Error
addChildMember(const object::Archive::Child
&M
) {
340 Expected
<NewArchiveMember
> NewMemberOrErr
=
341 NewArchiveMember::getOldMember(M
, C
.Deterministic
);
343 return NewMemberOrErr
.takeError();
344 auto &NewMember
= *NewMemberOrErr
;
346 file_magic Magic
= identify_magic(NewMember
.Buf
->getBuffer());
348 if (Magic
== file_magic::bitcode
)
349 return verifyAndAddIRObject(std::move(NewMember
));
351 return verifyAndAddMachOObject(std::move(NewMember
));
354 Error
processArchive(object::Archive
&Lib
, StringRef FileName
) {
355 Error Err
= Error::success();
356 for (const object::Archive::Child
&Child
: Lib
.children(Err
))
357 if (Error E
= addChildMember(Child
))
358 return createFileError(FileName
, std::move(E
));
360 return createFileError(FileName
, std::move(Err
));
362 return Error::success();
365 Error
addArchiveMembers(NewArchiveMember NewMember
, StringRef FileName
) {
366 Expected
<std::unique_ptr
<Archive
>> LibOrErr
=
367 object::Archive::create(NewMember
.Buf
->getMemBufferRef());
369 return createFileError(FileName
, LibOrErr
.takeError());
371 if (Error E
= processArchive(**LibOrErr
, FileName
))
374 // Update vector FileBuffers with the MemoryBuffers to transfer
376 Data
.FileBuffers
.push_back(std::move(NewMember
.Buf
));
377 return Error::success();
380 Error
addUniversalMembers(NewArchiveMember NewMember
, StringRef FileName
) {
381 Expected
<std::unique_ptr
<MachOUniversalBinary
>> BinaryOrErr
=
382 MachOUniversalBinary::create(NewMember
.Buf
->getMemBufferRef());
384 return createFileError(FileName
, BinaryOrErr
.takeError());
386 auto *UO
= BinaryOrErr
->get();
387 for (const MachOUniversalBinary::ObjectForArch
&O
: UO
->objects()) {
389 Expected
<std::unique_ptr
<MachOObjectFile
>> MachOObjOrErr
=
392 NewArchiveMember NewMember
=
393 NewArchiveMember(MachOObjOrErr
->get()->getMemoryBufferRef());
394 NewMember
.MemberName
= sys::path::filename(NewMember
.MemberName
);
396 if (Error E
= verifyAndAddMachOObject(std::move(NewMember
)))
401 Expected
<std::unique_ptr
<IRObjectFile
>> IRObjectOrError
=
402 O
.getAsIRObject(LLVMCtx
);
403 if (IRObjectOrError
) {
404 // A universal file member can be a MachOObjectFile, an IRObject or an
405 // Archive. In case we can successfully cast the member as an IRObject,
406 // it is safe to throw away the error generated due to casting the
407 // object as a MachOObjectFile.
408 consumeError(MachOObjOrErr
.takeError());
410 NewArchiveMember NewMember
=
411 NewArchiveMember(IRObjectOrError
->get()->getMemoryBufferRef());
412 NewMember
.MemberName
= sys::path::filename(NewMember
.MemberName
);
414 if (Error E
= verifyAndAddIRObject(std::move(NewMember
)))
419 Expected
<std::unique_ptr
<Archive
>> ArchiveOrError
= O
.getAsArchive();
420 if (ArchiveOrError
) {
421 // A universal file member can be a MachOObjectFile, an IRObject or an
422 // Archive. In case we can successfully cast the member as an Archive,
423 // it is safe to throw away the error generated due to casting the
424 // object as a MachOObjectFile.
425 consumeError(MachOObjOrErr
.takeError());
426 consumeError(IRObjectOrError
.takeError());
428 if (Error E
= processArchive(**ArchiveOrError
, FileName
))
433 Error CombinedError
= joinErrors(
434 ArchiveOrError
.takeError(),
435 joinErrors(IRObjectOrError
.takeError(), MachOObjOrErr
.takeError()));
436 return createFileError(FileName
, std::move(CombinedError
));
439 // Update vector FileBuffers with the MemoryBuffers to transfer
441 Data
.FileBuffers
.push_back(std::move(NewMember
.Buf
));
442 return Error::success();
445 Error
addMember(StringRef FileName
) {
446 Expected
<NewArchiveMember
> NewMemberOrErr
=
447 NewArchiveMember::getFile(FileName
, C
.Deterministic
);
449 return createFileError(FileName
, NewMemberOrErr
.takeError());
450 auto &NewMember
= *NewMemberOrErr
;
452 // For regular archives, use the basename of the object path for the member
454 NewMember
.MemberName
= sys::path::filename(NewMember
.MemberName
);
455 file_magic Magic
= identify_magic(NewMember
.Buf
->getBuffer());
458 if (Magic
== file_magic::archive
)
459 return addArchiveMembers(std::move(NewMember
), FileName
);
461 // Flatten universal files.
462 if (Magic
== file_magic::macho_universal_binary
)
463 return addUniversalMembers(std::move(NewMember
), FileName
);
466 if (Magic
== file_magic::bitcode
)
467 return verifyAndAddIRObject(std::move(NewMember
));
469 return verifyAndAddMachOObject(std::move(NewMember
));
476 static Expected
<SmallVector
<Slice
, 2>>
477 buildSlices(ArrayRef
<OwningBinary
<Archive
>> OutputBinaries
) {
478 SmallVector
<Slice
, 2> Slices
;
480 for (const auto &OB
: OutputBinaries
) {
481 const Archive
&A
= *OB
.getBinary();
482 Expected
<Slice
> ArchiveSlice
= Slice::create(A
, &LLVMCtx
);
484 return ArchiveSlice
.takeError();
485 Slices
.push_back(*ArchiveSlice
);
490 static Error
createStaticLibrary(const Config
&C
) {
491 MembersBuilder
Builder(C
);
492 auto DataOrError
= Builder
.build();
493 if (auto Error
= DataOrError
.takeError())
496 const auto &NewMembers
= DataOrError
->MembersPerArchitecture
;
498 if (NewMembers
.size() == 1) {
499 return writeArchive(OutputFile
, NewMembers
.begin()->second
,
500 /*WriteSymtab=*/true,
501 /*Kind=*/object::Archive::K_DARWIN
, C
.Deterministic
,
505 SmallVector
<OwningBinary
<Archive
>, 2> OutputBinaries
;
506 for (const std::pair
<const uint64_t, std::vector
<NewArchiveMember
>> &M
:
508 Expected
<std::unique_ptr
<MemoryBuffer
>> OutputBufferOrErr
=
509 writeArchiveToBuffer(M
.second
,
510 /*WriteSymtab=*/true,
511 /*Kind=*/object::Archive::K_DARWIN
,
514 if (!OutputBufferOrErr
)
515 return OutputBufferOrErr
.takeError();
516 std::unique_ptr
<MemoryBuffer
> &OutputBuffer
= OutputBufferOrErr
.get();
518 Expected
<std::unique_ptr
<Archive
>> ArchiveOrError
=
519 Archive::create(OutputBuffer
->getMemBufferRef());
521 return ArchiveOrError
.takeError();
522 std::unique_ptr
<Archive
> &A
= ArchiveOrError
.get();
524 OutputBinaries
.push_back(
525 OwningBinary
<Archive
>(std::move(A
), std::move(OutputBuffer
)));
528 Expected
<SmallVector
<Slice
, 2>> Slices
= buildSlices(OutputBinaries
);
530 return Slices
.takeError();
532 llvm::stable_sort(*Slices
);
533 return writeUniversalBinary(*Slices
, OutputFile
);
536 static Expected
<Config
> parseCommandLine(int Argc
, char **Argv
) {
538 cl::ParseCommandLineOptions(Argc
, Argv
, "llvm-libtool-darwin\n");
540 if (LibraryOperation
== Operation::None
) {
541 if (!VersionOption
) {
543 raw_string_ostream
Stream(Error
);
544 LibraryOperation
.error("must be specified", "", Stream
);
545 return createStringError(std::errc::invalid_argument
, Error
.c_str());
550 if (OutputFile
.empty()) {
552 raw_string_ostream
Stream(Error
);
553 OutputFile
.error("must be specified", "o", Stream
);
554 return createStringError(std::errc::invalid_argument
, Error
.c_str());
557 if (DeterministicOption
&& NonDeterministicOption
)
558 return createStringError(std::errc::invalid_argument
,
559 "cannot specify both -D and -U flags");
560 else if (NonDeterministicOption
)
561 C
.Deterministic
= false;
563 if (!Libraries
.empty())
564 if (Error E
= processCommandLineLibraries())
567 if (!FileList
.empty())
568 if (Error E
= processFileList())
571 if (InputFiles
.empty())
572 return createStringError(std::errc::invalid_argument
,
573 "no input files specified");
575 if (ArchType
.getNumOccurrences()) {
576 if (Error E
= validateArchitectureName(ArchType
))
579 std::tie(C
.ArchCPUType
, C
.ArchCPUSubtype
) =
580 MachO::getCPUTypeFromArchitecture(
581 MachO::getArchitectureFromName(ArchType
));
587 int main(int Argc
, char **Argv
) {
588 InitLLVM
X(Argc
, Argv
);
589 cl::HideUnrelatedOptions({&LibtoolCategory
, &getColorCategory()});
590 Expected
<Config
> ConfigOrErr
= parseCommandLine(Argc
, Argv
);
592 WithColor::defaultErrorHandler(ConfigOrErr
.takeError());
597 cl::PrintVersionMessage();
599 Config C
= *ConfigOrErr
;
600 switch (LibraryOperation
) {
601 case Operation::None
:
603 case Operation::Static
:
604 if (Error E
= createStaticLibrary(C
)) {
605 WithColor::defaultErrorHandler(std::move(E
));