1 //===- OffloadBundler.cpp - File Bundling and Unbundling ------------------===//
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 //===----------------------------------------------------------------------===//
10 /// This file implements an offload bundling API that bundles different files
11 /// that relate with the same source code but different targets into a single
12 /// one. Also the implements the opposite functionality, i.e. unbundle files
13 /// previous created by this API.
15 //===----------------------------------------------------------------------===//
17 #include "clang/Basic/Cuda.h"
18 #include "clang/Basic/Version.h"
19 #include "clang/Driver/OffloadBundler.h"
20 #include "llvm/ADT/ArrayRef.h"
21 #include "llvm/ADT/SmallString.h"
22 #include "llvm/ADT/SmallVector.h"
23 #include "llvm/ADT/StringMap.h"
24 #include "llvm/ADT/StringRef.h"
25 #include "llvm/ADT/Triple.h"
26 #include "llvm/Object/Archive.h"
27 #include "llvm/Object/ArchiveWriter.h"
28 #include "llvm/Object/Binary.h"
29 #include "llvm/Object/ObjectFile.h"
30 #include "llvm/Support/Casting.h"
31 #include "llvm/Support/CommandLine.h"
32 #include "llvm/Support/Debug.h"
33 #include "llvm/Support/Errc.h"
34 #include "llvm/Support/Error.h"
35 #include "llvm/Support/ErrorOr.h"
36 #include "llvm/Support/FileSystem.h"
37 #include "llvm/Support/Host.h"
38 #include "llvm/Support/MemoryBuffer.h"
39 #include "llvm/Support/Path.h"
40 #include "llvm/Support/Program.h"
41 #include "llvm/Support/Signals.h"
42 #include "llvm/Support/StringSaver.h"
43 #include "llvm/Support/WithColor.h"
44 #include "llvm/Support/raw_ostream.h"
49 #include <forward_list>
53 #include <system_error>
57 using namespace llvm::object
;
58 using namespace clang
;
60 /// Magic string that marks the existence of offloading data.
61 #define OFFLOAD_BUNDLER_MAGIC_STR "__CLANG_OFFLOAD_BUNDLE__"
63 OffloadTargetInfo::OffloadTargetInfo(const StringRef Target
,
64 const OffloadBundlerConfig
&BC
)
67 // TODO: Add error checking from ClangOffloadBundler.cpp
68 auto TargetFeatures
= Target
.split(':');
69 auto TripleOrGPU
= TargetFeatures
.first
.rsplit('-');
71 if (clang::StringToCudaArch(TripleOrGPU
.second
) !=
72 clang::CudaArch::UNKNOWN
) {
73 auto KindTriple
= TripleOrGPU
.first
.split('-');
74 this->OffloadKind
= KindTriple
.first
;
75 this->Triple
= llvm::Triple(KindTriple
.second
);
76 this->GPUArch
= Target
.substr(Target
.find(TripleOrGPU
.second
));
78 auto KindTriple
= TargetFeatures
.first
.split('-');
79 this->OffloadKind
= KindTriple
.first
;
80 this->Triple
= llvm::Triple(KindTriple
.second
);
85 bool OffloadTargetInfo::hasHostKind() const {
86 return this->OffloadKind
== "host";
89 bool OffloadTargetInfo::isOffloadKindValid() const {
90 return OffloadKind
== "host" || OffloadKind
== "openmp" ||
91 OffloadKind
== "hip" || OffloadKind
== "hipv4";
94 bool OffloadTargetInfo::isOffloadKindCompatible(
95 const StringRef TargetOffloadKind
) const {
96 if (OffloadKind
== TargetOffloadKind
)
98 if (BundlerConfig
.HipOpenmpCompatible
) {
99 bool HIPCompatibleWithOpenMP
=
100 OffloadKind
.startswith_insensitive("hip") &&
101 TargetOffloadKind
== "openmp";
102 bool OpenMPCompatibleWithHIP
=
103 OffloadKind
== "openmp" &&
104 TargetOffloadKind
.startswith_insensitive("hip");
105 return HIPCompatibleWithOpenMP
|| OpenMPCompatibleWithHIP
;
110 bool OffloadTargetInfo::isTripleValid() const {
111 return !Triple
.str().empty() && Triple
.getArch() != Triple::UnknownArch
;
114 bool OffloadTargetInfo::operator==(const OffloadTargetInfo
&Target
) const {
115 return OffloadKind
== Target
.OffloadKind
&&
116 Triple
.isCompatibleWith(Target
.Triple
) &&
117 GPUArch
== Target
.GPUArch
;
120 std::string
OffloadTargetInfo::str() {
121 return Twine(OffloadKind
+ "-" + Triple
.str() + "-" + GPUArch
).str();
124 static StringRef
getDeviceFileExtension(StringRef Device
,
125 StringRef BundleFileName
) {
126 if (Device
.contains("gfx"))
128 if (Device
.contains("sm_"))
130 return sys::path::extension(BundleFileName
);
133 static std::string
getDeviceLibraryFileName(StringRef BundleFileName
,
135 StringRef LibName
= sys::path::stem(BundleFileName
);
136 StringRef Extension
= getDeviceFileExtension(Device
, BundleFileName
);
144 /// Generic file handler interface.
153 virtual ~FileHandler() {}
155 /// Update the file handler with information from the header of the bundled
157 virtual Error
ReadHeader(MemoryBuffer
&Input
) = 0;
159 /// Read the marker of the next bundled to be read in the file. The bundle
160 /// name is returned if there is one in the file, or `None` if there are no
161 /// more bundles to be read.
162 virtual Expected
<Optional
<StringRef
>>
163 ReadBundleStart(MemoryBuffer
&Input
) = 0;
165 /// Read the marker that closes the current bundle.
166 virtual Error
ReadBundleEnd(MemoryBuffer
&Input
) = 0;
168 /// Read the current bundle and write the result into the stream \a OS.
169 virtual Error
ReadBundle(raw_ostream
&OS
, MemoryBuffer
&Input
) = 0;
171 /// Write the header of the bundled file to \a OS based on the information
172 /// gathered from \a Inputs.
173 virtual Error
WriteHeader(raw_fd_ostream
&OS
,
174 ArrayRef
<std::unique_ptr
<MemoryBuffer
>> Inputs
) = 0;
176 /// Write the marker that initiates a bundle for the triple \a TargetTriple to
178 virtual Error
WriteBundleStart(raw_fd_ostream
&OS
,
179 StringRef TargetTriple
) = 0;
181 /// Write the marker that closes a bundle for the triple \a TargetTriple to \a
183 virtual Error
WriteBundleEnd(raw_fd_ostream
&OS
, StringRef TargetTriple
) = 0;
185 /// Write the bundle from \a Input into \a OS.
186 virtual Error
WriteBundle(raw_fd_ostream
&OS
, MemoryBuffer
&Input
) = 0;
188 /// List bundle IDs in \a Input.
189 virtual Error
listBundleIDs(MemoryBuffer
&Input
) {
190 if (Error Err
= ReadHeader(Input
))
192 return forEachBundle(Input
, [&](const BundleInfo
&Info
) -> Error
{
193 llvm::outs() << Info
.BundleID
<< '\n';
194 Error Err
= listBundleIDsCallback(Input
, Info
);
197 return Error::success();
201 /// For each bundle in \a Input, do \a Func.
202 Error
forEachBundle(MemoryBuffer
&Input
,
203 std::function
<Error(const BundleInfo
&)> Func
) {
205 Expected
<Optional
<StringRef
>> CurTripleOrErr
= ReadBundleStart(Input
);
207 return CurTripleOrErr
.takeError();
210 if (!*CurTripleOrErr
)
213 StringRef CurTriple
= **CurTripleOrErr
;
214 assert(!CurTriple
.empty());
216 BundleInfo Info
{CurTriple
};
217 if (Error Err
= Func(Info
))
220 return Error::success();
224 virtual Error
listBundleIDsCallback(MemoryBuffer
&Input
,
225 const BundleInfo
&Info
) {
226 return Error::success();
230 /// Handler for binary files. The bundled file will have the following format
231 /// (all integers are stored in little-endian format):
233 /// "OFFLOAD_BUNDLER_MAGIC_STR" (ASCII encoding of the string)
235 /// NumberOfOffloadBundles (8-byte integer)
237 /// OffsetOfBundle1 (8-byte integer)
238 /// SizeOfBundle1 (8-byte integer)
239 /// NumberOfBytesInTripleOfBundle1 (8-byte integer)
240 /// TripleOfBundle1 (byte length defined before)
244 /// OffsetOfBundleN (8-byte integer)
245 /// SizeOfBundleN (8-byte integer)
246 /// NumberOfBytesInTripleOfBundleN (8-byte integer)
247 /// TripleOfBundleN (byte length defined before)
253 /// Read 8-byte integers from a buffer in little-endian format.
254 static uint64_t Read8byteIntegerFromBuffer(StringRef Buffer
, size_t pos
) {
256 const char *Data
= Buffer
.data();
258 for (unsigned i
= 0; i
< 8; ++i
) {
260 uint64_t Char
= (uint64_t)Data
[pos
+ 7 - i
];
266 /// Write 8-byte integers to a buffer in little-endian format.
267 static void Write8byteIntegerToBuffer(raw_fd_ostream
&OS
, uint64_t Val
) {
268 for (unsigned i
= 0; i
< 8; ++i
) {
269 char Char
= (char)(Val
& 0xffu
);
275 class BinaryFileHandler final
: public FileHandler
{
276 /// Information about the bundles extracted from the header.
277 struct BinaryBundleInfo final
: public BundleInfo
{
278 /// Size of the bundle.
280 /// Offset at which the bundle starts in the bundled file.
281 uint64_t Offset
= 0u;
283 BinaryBundleInfo() {}
284 BinaryBundleInfo(uint64_t Size
, uint64_t Offset
)
285 : Size(Size
), Offset(Offset
) {}
288 /// Map between a triple and the corresponding bundle information.
289 StringMap
<BinaryBundleInfo
> BundlesInfo
;
291 /// Iterator for the bundle information that is being read.
292 StringMap
<BinaryBundleInfo
>::iterator CurBundleInfo
;
293 StringMap
<BinaryBundleInfo
>::iterator NextBundleInfo
;
295 /// Current bundle target to be written.
296 std::string CurWriteBundleTarget
;
298 /// Configuration options and arrays for this bundler job
299 const OffloadBundlerConfig
&BundlerConfig
;
302 // TODO: Add error checking from ClangOffloadBundler.cpp
303 BinaryFileHandler(const OffloadBundlerConfig
&BC
) : BundlerConfig(BC
) {}
305 ~BinaryFileHandler() final
{}
307 Error
ReadHeader(MemoryBuffer
&Input
) final
{
308 StringRef FC
= Input
.getBuffer();
310 // Initialize the current bundle with the end of the container.
311 CurBundleInfo
= BundlesInfo
.end();
313 // Check if buffer is smaller than magic string.
314 size_t ReadChars
= sizeof(OFFLOAD_BUNDLER_MAGIC_STR
) - 1;
315 if (ReadChars
> FC
.size())
316 return Error::success();
318 // Check if no magic was found.
319 StringRef
Magic(FC
.data(), sizeof(OFFLOAD_BUNDLER_MAGIC_STR
) - 1);
320 if (!Magic
.equals(OFFLOAD_BUNDLER_MAGIC_STR
))
321 return Error::success();
323 // Read number of bundles.
324 if (ReadChars
+ 8 > FC
.size())
325 return Error::success();
327 uint64_t NumberOfBundles
= Read8byteIntegerFromBuffer(FC
, ReadChars
);
330 // Read bundle offsets, sizes and triples.
331 for (uint64_t i
= 0; i
< NumberOfBundles
; ++i
) {
334 if (ReadChars
+ 8 > FC
.size())
335 return Error::success();
337 uint64_t Offset
= Read8byteIntegerFromBuffer(FC
, ReadChars
);
341 if (ReadChars
+ 8 > FC
.size())
342 return Error::success();
344 uint64_t Size
= Read8byteIntegerFromBuffer(FC
, ReadChars
);
348 if (ReadChars
+ 8 > FC
.size())
349 return Error::success();
351 uint64_t TripleSize
= Read8byteIntegerFromBuffer(FC
, ReadChars
);
355 if (ReadChars
+ TripleSize
> FC
.size())
356 return Error::success();
358 StringRef
Triple(&FC
.data()[ReadChars
], TripleSize
);
359 ReadChars
+= TripleSize
;
361 // Check if the offset and size make sense.
362 if (!Offset
|| Offset
+ Size
> FC
.size())
363 return Error::success();
365 assert(BundlesInfo
.find(Triple
) == BundlesInfo
.end() &&
366 "Triple is duplicated??");
367 BundlesInfo
[Triple
] = BinaryBundleInfo(Size
, Offset
);
369 // Set the iterator to where we will start to read.
370 CurBundleInfo
= BundlesInfo
.end();
371 NextBundleInfo
= BundlesInfo
.begin();
372 return Error::success();
375 Expected
<Optional
<StringRef
>> ReadBundleStart(MemoryBuffer
&Input
) final
{
376 if (NextBundleInfo
== BundlesInfo
.end())
378 CurBundleInfo
= NextBundleInfo
++;
379 return CurBundleInfo
->first();
382 Error
ReadBundleEnd(MemoryBuffer
&Input
) final
{
383 assert(CurBundleInfo
!= BundlesInfo
.end() && "Invalid reader info!");
384 return Error::success();
387 Error
ReadBundle(raw_ostream
&OS
, MemoryBuffer
&Input
) final
{
388 assert(CurBundleInfo
!= BundlesInfo
.end() && "Invalid reader info!");
389 StringRef FC
= Input
.getBuffer();
390 OS
.write(FC
.data() + CurBundleInfo
->second
.Offset
,
391 CurBundleInfo
->second
.Size
);
392 return Error::success();
395 Error
WriteHeader(raw_fd_ostream
&OS
,
396 ArrayRef
<std::unique_ptr
<MemoryBuffer
>> Inputs
) final
{
398 // Compute size of the header.
399 uint64_t HeaderSize
= 0;
401 HeaderSize
+= sizeof(OFFLOAD_BUNDLER_MAGIC_STR
) - 1;
402 HeaderSize
+= 8; // Number of Bundles
404 for (auto &T
: BundlerConfig
.TargetNames
) {
405 HeaderSize
+= 3 * 8; // Bundle offset, Size of bundle and size of triple.
406 HeaderSize
+= T
.size(); // The triple.
409 // Write to the buffer the header.
410 OS
<< OFFLOAD_BUNDLER_MAGIC_STR
;
412 Write8byteIntegerToBuffer(OS
, BundlerConfig
.TargetNames
.size());
415 for (auto &T
: BundlerConfig
.TargetNames
) {
416 MemoryBuffer
&MB
= *Inputs
[Idx
++];
417 HeaderSize
= alignTo(HeaderSize
, BundlerConfig
.BundleAlignment
);
419 Write8byteIntegerToBuffer(OS
, HeaderSize
);
420 // Size of the bundle (adds to the next bundle's offset)
421 Write8byteIntegerToBuffer(OS
, MB
.getBufferSize());
422 BundlesInfo
[T
] = BinaryBundleInfo(MB
.getBufferSize(), HeaderSize
);
423 HeaderSize
+= MB
.getBufferSize();
424 // Size of the triple
425 Write8byteIntegerToBuffer(OS
, T
.size());
429 return Error::success();
432 Error
WriteBundleStart(raw_fd_ostream
&OS
, StringRef TargetTriple
) final
{
433 CurWriteBundleTarget
= TargetTriple
.str();
434 return Error::success();
437 Error
WriteBundleEnd(raw_fd_ostream
&OS
, StringRef TargetTriple
) final
{
438 return Error::success();
441 Error
WriteBundle(raw_fd_ostream
&OS
, MemoryBuffer
&Input
) final
{
442 auto BI
= BundlesInfo
[CurWriteBundleTarget
];
444 OS
.write(Input
.getBufferStart(), Input
.getBufferSize());
445 return Error::success();
451 // This class implements a list of temporary files that are removed upon
452 // object destruction.
453 class TempFileHandlerRAII
{
455 ~TempFileHandlerRAII() {
456 for (const auto &File
: Files
)
457 sys::fs::remove(File
);
460 // Creates temporary file with given contents.
461 Expected
<StringRef
> Create(Optional
<ArrayRef
<char>> Contents
) {
462 SmallString
<128u> File
;
463 if (std::error_code EC
=
464 sys::fs::createTemporaryFile("clang-offload-bundler", "tmp", File
))
465 return createFileError(File
, EC
);
466 Files
.push_front(File
);
470 raw_fd_ostream
OS(File
, EC
);
472 return createFileError(File
, EC
);
473 OS
.write(Contents
->data(), Contents
->size());
475 return Files
.front().str();
479 std::forward_list
<SmallString
<128u>> Files
;
482 } // end anonymous namespace
484 /// Handler for object files. The bundles are organized by sections with a
487 /// To unbundle, we just copy the contents of the designated section.
488 class ObjectFileHandler final
: public FileHandler
{
490 /// The object file we are currently dealing with.
491 std::unique_ptr
<ObjectFile
> Obj
;
493 /// Return the input file contents.
494 StringRef
getInputFileContents() const { return Obj
->getData(); }
496 /// Return bundle name (<kind>-<triple>) if the provided section is an offload
498 static Expected
<Optional
<StringRef
>> IsOffloadSection(SectionRef CurSection
) {
499 Expected
<StringRef
> NameOrErr
= CurSection
.getName();
501 return NameOrErr
.takeError();
503 // If it does not start with the reserved suffix, just skip this section.
504 if (!NameOrErr
->startswith(OFFLOAD_BUNDLER_MAGIC_STR
))
507 // Return the triple that is right after the reserved prefix.
508 return NameOrErr
->substr(sizeof(OFFLOAD_BUNDLER_MAGIC_STR
) - 1);
511 /// Total number of inputs.
512 unsigned NumberOfInputs
= 0;
514 /// Total number of processed inputs, i.e, inputs that were already
515 /// read from the buffers.
516 unsigned NumberOfProcessedInputs
= 0;
518 /// Iterator of the current and next section.
519 section_iterator CurrentSection
;
520 section_iterator NextSection
;
522 /// Configuration options and arrays for this bundler job
523 const OffloadBundlerConfig
&BundlerConfig
;
526 // TODO: Add error checking from ClangOffloadBundler.cpp
527 ObjectFileHandler(std::unique_ptr
<ObjectFile
> ObjIn
,
528 const OffloadBundlerConfig
&BC
)
529 : Obj(std::move(ObjIn
)), CurrentSection(Obj
->section_begin()),
530 NextSection(Obj
->section_begin()), BundlerConfig(BC
) {}
532 ~ObjectFileHandler() final
{}
534 Error
ReadHeader(MemoryBuffer
&Input
) final
{ return Error::success(); }
536 Expected
<Optional
<StringRef
>> ReadBundleStart(MemoryBuffer
&Input
) final
{
537 while (NextSection
!= Obj
->section_end()) {
538 CurrentSection
= NextSection
;
541 // Check if the current section name starts with the reserved prefix. If
542 // so, return the triple.
543 Expected
<Optional
<StringRef
>> TripleOrErr
=
544 IsOffloadSection(*CurrentSection
);
546 return TripleOrErr
.takeError();
548 return **TripleOrErr
;
553 Error
ReadBundleEnd(MemoryBuffer
&Input
) final
{ return Error::success(); }
555 Error
ReadBundle(raw_ostream
&OS
, MemoryBuffer
&Input
) final
{
556 Expected
<StringRef
> ContentOrErr
= CurrentSection
->getContents();
558 return ContentOrErr
.takeError();
559 StringRef Content
= *ContentOrErr
;
561 // Copy fat object contents to the output when extracting host bundle.
562 if (Content
.size() == 1u && Content
.front() == 0)
563 Content
= StringRef(Input
.getBufferStart(), Input
.getBufferSize());
565 OS
.write(Content
.data(), Content
.size());
566 return Error::success();
569 Error
WriteHeader(raw_fd_ostream
&OS
,
570 ArrayRef
<std::unique_ptr
<MemoryBuffer
>> Inputs
) final
{
571 assert(BundlerConfig
.HostInputIndex
!= ~0u &&
572 "Host input index not defined.");
574 // Record number of inputs.
575 NumberOfInputs
= Inputs
.size();
576 return Error::success();
579 Error
WriteBundleStart(raw_fd_ostream
&OS
, StringRef TargetTriple
) final
{
580 ++NumberOfProcessedInputs
;
581 return Error::success();
584 Error
WriteBundleEnd(raw_fd_ostream
&OS
, StringRef TargetTriple
) final
{
585 assert(NumberOfProcessedInputs
<= NumberOfInputs
&&
586 "Processing more inputs that actually exist!");
587 assert(BundlerConfig
.HostInputIndex
!= ~0u &&
588 "Host input index not defined.");
590 // If this is not the last output, we don't have to do anything.
591 if (NumberOfProcessedInputs
!= NumberOfInputs
)
592 return Error::success();
594 // We will use llvm-objcopy to add target objects sections to the output
595 // fat object. These sections should have 'exclude' flag set which tells
596 // link editor to remove them from linker inputs when linking executable or
599 assert(BundlerConfig
.ObjcopyPath
!= "" &&
600 "llvm-objcopy path not specified");
602 // We write to the output file directly. So, we close it and use the name
603 // to pass down to llvm-objcopy.
606 // Temporary files that need to be removed.
607 TempFileHandlerRAII TempFiles
;
609 // Compose llvm-objcopy command line for add target objects' sections with
610 // appropriate flags.
611 BumpPtrAllocator Alloc
;
612 StringSaver SS
{Alloc
};
613 SmallVector
<StringRef
, 8u> ObjcopyArgs
{"llvm-objcopy"};
615 for (unsigned I
= 0; I
< NumberOfInputs
; ++I
) {
616 StringRef InputFile
= BundlerConfig
.InputFileNames
[I
];
617 if (I
== BundlerConfig
.HostInputIndex
) {
618 // Special handling for the host bundle. We do not need to add a
619 // standard bundle for the host object since we are going to use fat
620 // object as a host object. Therefore use dummy contents (one zero byte)
621 // when creating section for the host bundle.
622 Expected
<StringRef
> TempFileOrErr
= TempFiles
.Create(ArrayRef
<char>(0));
624 return TempFileOrErr
.takeError();
625 InputFile
= *TempFileOrErr
;
628 ObjcopyArgs
.push_back(SS
.save(Twine("--add-section=") +
629 OFFLOAD_BUNDLER_MAGIC_STR
+
630 BundlerConfig
.TargetNames
[I
] +
632 ObjcopyArgs
.push_back(SS
.save(Twine("--set-section-flags=") +
633 OFFLOAD_BUNDLER_MAGIC_STR
+
634 BundlerConfig
.TargetNames
[I
] +
635 "=readonly,exclude"));
637 ObjcopyArgs
.push_back("--");
638 ObjcopyArgs
.push_back(
639 BundlerConfig
.InputFileNames
[BundlerConfig
.HostInputIndex
]);
640 ObjcopyArgs
.push_back(BundlerConfig
.OutputFileNames
.front());
642 if (Error Err
= executeObjcopy(BundlerConfig
.ObjcopyPath
, ObjcopyArgs
))
645 return Error::success();
648 Error
WriteBundle(raw_fd_ostream
&OS
, MemoryBuffer
&Input
) final
{
649 return Error::success();
653 Error
executeObjcopy(StringRef Objcopy
, ArrayRef
<StringRef
> Args
) {
654 // If the user asked for the commands to be printed out, we do that
655 // instead of executing it.
656 if (BundlerConfig
.PrintExternalCommands
) {
657 errs() << "\"" << Objcopy
<< "\"";
658 for (StringRef Arg
: drop_begin(Args
, 1))
659 errs() << " \"" << Arg
<< "\"";
662 if (sys::ExecuteAndWait(Objcopy
, Args
))
663 return createStringError(inconvertibleErrorCode(),
664 "'llvm-objcopy' tool failed");
666 return Error::success();
670 /// Handler for text files. The bundled file will have the following format.
672 /// "Comment OFFLOAD_BUNDLER_MAGIC_STR__START__ triple"
674 /// "Comment OFFLOAD_BUNDLER_MAGIC_STR__END__ triple"
676 /// "Comment OFFLOAD_BUNDLER_MAGIC_STR__START__ triple"
678 /// "Comment OFFLOAD_BUNDLER_MAGIC_STR__END__ triple"
679 class TextFileHandler final
: public FileHandler
{
680 /// String that begins a line comment.
683 /// String that initiates a bundle.
684 std::string BundleStartString
;
686 /// String that closes a bundle.
687 std::string BundleEndString
;
689 /// Number of chars read from input.
690 size_t ReadChars
= 0u;
693 Error
ReadHeader(MemoryBuffer
&Input
) final
{ return Error::success(); }
695 Expected
<Optional
<StringRef
>> ReadBundleStart(MemoryBuffer
&Input
) final
{
696 StringRef FC
= Input
.getBuffer();
698 // Find start of the bundle.
699 ReadChars
= FC
.find(BundleStartString
, ReadChars
);
700 if (ReadChars
== FC
.npos
)
703 // Get position of the triple.
704 size_t TripleStart
= ReadChars
= ReadChars
+ BundleStartString
.size();
706 // Get position that closes the triple.
707 size_t TripleEnd
= ReadChars
= FC
.find("\n", ReadChars
);
708 if (TripleEnd
== FC
.npos
)
711 // Next time we read after the new line.
714 return StringRef(&FC
.data()[TripleStart
], TripleEnd
- TripleStart
);
717 Error
ReadBundleEnd(MemoryBuffer
&Input
) final
{
718 StringRef FC
= Input
.getBuffer();
720 // Read up to the next new line.
721 assert(FC
[ReadChars
] == '\n' && "The bundle should end with a new line.");
723 size_t TripleEnd
= ReadChars
= FC
.find("\n", ReadChars
+ 1);
724 if (TripleEnd
!= FC
.npos
)
725 // Next time we read after the new line.
728 return Error::success();
731 Error
ReadBundle(raw_ostream
&OS
, MemoryBuffer
&Input
) final
{
732 StringRef FC
= Input
.getBuffer();
733 size_t BundleStart
= ReadChars
;
735 // Find end of the bundle.
736 size_t BundleEnd
= ReadChars
= FC
.find(BundleEndString
, ReadChars
);
738 StringRef
Bundle(&FC
.data()[BundleStart
], BundleEnd
- BundleStart
);
741 return Error::success();
744 Error
WriteHeader(raw_fd_ostream
&OS
,
745 ArrayRef
<std::unique_ptr
<MemoryBuffer
>> Inputs
) final
{
746 return Error::success();
749 Error
WriteBundleStart(raw_fd_ostream
&OS
, StringRef TargetTriple
) final
{
750 OS
<< BundleStartString
<< TargetTriple
<< "\n";
751 return Error::success();
754 Error
WriteBundleEnd(raw_fd_ostream
&OS
, StringRef TargetTriple
) final
{
755 OS
<< BundleEndString
<< TargetTriple
<< "\n";
756 return Error::success();
759 Error
WriteBundle(raw_fd_ostream
&OS
, MemoryBuffer
&Input
) final
{
760 OS
<< Input
.getBuffer();
761 return Error::success();
765 TextFileHandler(StringRef Comment
) : Comment(Comment
), ReadChars(0) {
767 "\n" + Comment
.str() + " " OFFLOAD_BUNDLER_MAGIC_STR
"__START__ ";
769 "\n" + Comment
.str() + " " OFFLOAD_BUNDLER_MAGIC_STR
"__END__ ";
772 Error
listBundleIDsCallback(MemoryBuffer
&Input
,
773 const BundleInfo
&Info
) final
{
774 // TODO: To list bundle IDs in a bundled text file we need to go through
775 // all bundles. The format of bundled text file may need to include a
776 // header if the performance of listing bundle IDs of bundled text file is
778 ReadChars
= Input
.getBuffer().find(BundleEndString
, ReadChars
);
779 if (Error Err
= ReadBundleEnd(Input
))
781 return Error::success();
785 /// Return an appropriate object file handler. We use the specific object
786 /// handler if we know how to deal with that format, otherwise we use a default
787 /// binary file handler.
788 static std::unique_ptr
<FileHandler
>
789 CreateObjectFileHandler(MemoryBuffer
&FirstInput
,
790 const OffloadBundlerConfig
&BundlerConfig
) {
791 // Check if the input file format is one that we know how to deal with.
792 Expected
<std::unique_ptr
<Binary
>> BinaryOrErr
= createBinary(FirstInput
);
794 // We only support regular object files. If failed to open the input as a
795 // known binary or this is not an object file use the default binary handler.
796 if (errorToBool(BinaryOrErr
.takeError()) || !isa
<ObjectFile
>(*BinaryOrErr
))
797 return std::make_unique
<BinaryFileHandler
>(BundlerConfig
);
799 // Otherwise create an object file handler. The handler will be owned by the
800 // client of this function.
801 return std::make_unique
<ObjectFileHandler
>(
802 std::unique_ptr
<ObjectFile
>(cast
<ObjectFile
>(BinaryOrErr
->release())),
806 /// Return an appropriate handler given the input files and options.
807 static Expected
<std::unique_ptr
<FileHandler
>>
808 CreateFileHandler(MemoryBuffer
&FirstInput
,
809 const OffloadBundlerConfig
&BundlerConfig
) {
810 std::string FilesType
= BundlerConfig
.FilesType
;
812 if (FilesType
== "i")
813 return std::make_unique
<TextFileHandler
>(/*Comment=*/"//");
814 if (FilesType
== "ii")
815 return std::make_unique
<TextFileHandler
>(/*Comment=*/"//");
816 if (FilesType
== "cui")
817 return std::make_unique
<TextFileHandler
>(/*Comment=*/"//");
818 // TODO: `.d` should be eventually removed once `-M` and its variants are
819 // handled properly in offload compilation.
820 if (FilesType
== "d")
821 return std::make_unique
<TextFileHandler
>(/*Comment=*/"#");
822 if (FilesType
== "ll")
823 return std::make_unique
<TextFileHandler
>(/*Comment=*/";");
824 if (FilesType
== "bc")
825 return std::make_unique
<BinaryFileHandler
>(BundlerConfig
);
826 if (FilesType
== "s")
827 return std::make_unique
<TextFileHandler
>(/*Comment=*/"#");
828 if (FilesType
== "o")
829 return CreateObjectFileHandler(FirstInput
, BundlerConfig
);
830 if (FilesType
== "a")
831 return CreateObjectFileHandler(FirstInput
, BundlerConfig
);
832 if (FilesType
== "gch")
833 return std::make_unique
<BinaryFileHandler
>(BundlerConfig
);
834 if (FilesType
== "ast")
835 return std::make_unique
<BinaryFileHandler
>(BundlerConfig
);
837 return createStringError(errc::invalid_argument
,
838 "'" + FilesType
+ "': invalid file type specified");
841 // List bundle IDs. Return true if an error was found.
842 Error
OffloadBundler::ListBundleIDsInFile(StringRef InputFileName
,
843 const OffloadBundlerConfig
&BundlerConfig
) {
845 ErrorOr
<std::unique_ptr
<MemoryBuffer
>> CodeOrErr
=
846 MemoryBuffer::getFileOrSTDIN(InputFileName
);
847 if (std::error_code EC
= CodeOrErr
.getError())
848 return createFileError(InputFileName
, EC
);
850 MemoryBuffer
&Input
= **CodeOrErr
;
852 // Select the right files handler.
853 Expected
<std::unique_ptr
<FileHandler
>> FileHandlerOrErr
=
854 CreateFileHandler(Input
, BundlerConfig
);
855 if (!FileHandlerOrErr
)
856 return FileHandlerOrErr
.takeError();
858 std::unique_ptr
<FileHandler
> &FH
= *FileHandlerOrErr
;
860 return FH
->listBundleIDs(Input
);
863 /// Bundle the files. Return true if an error was found.
864 Error
OffloadBundler::BundleFiles() {
867 // Create output file.
868 raw_fd_ostream
OutputFile(BundlerConfig
.OutputFileNames
.front(),
869 EC
, sys::fs::OF_None
);
871 return createFileError(BundlerConfig
.OutputFileNames
.front(), EC
);
874 SmallVector
<std::unique_ptr
<MemoryBuffer
>, 8u> InputBuffers
;
875 InputBuffers
.reserve(BundlerConfig
.InputFileNames
.size());
876 for (auto &I
: BundlerConfig
.InputFileNames
) {
877 ErrorOr
<std::unique_ptr
<MemoryBuffer
>> CodeOrErr
=
878 MemoryBuffer::getFileOrSTDIN(I
);
879 if (std::error_code EC
= CodeOrErr
.getError())
880 return createFileError(I
, EC
);
881 InputBuffers
.emplace_back(std::move(*CodeOrErr
));
884 // Get the file handler. We use the host buffer as reference.
885 assert((BundlerConfig
.HostInputIndex
!= ~0u || BundlerConfig
.AllowNoHost
) &&
886 "Host input index undefined??");
887 Expected
<std::unique_ptr
<FileHandler
>> FileHandlerOrErr
=
888 CreateFileHandler(*InputBuffers
[BundlerConfig
.AllowNoHost
? 0
889 : BundlerConfig
.HostInputIndex
],
891 if (!FileHandlerOrErr
)
892 return FileHandlerOrErr
.takeError();
894 std::unique_ptr
<FileHandler
> &FH
= *FileHandlerOrErr
;
898 if (Error Err
= FH
->WriteHeader(OutputFile
, InputBuffers
))
901 // Write all bundles along with the start/end markers. If an error was found
902 // writing the end of the bundle component, abort the bundle writing.
903 auto Input
= InputBuffers
.begin();
904 for (auto &Triple
: BundlerConfig
.TargetNames
) {
905 if (Error Err
= FH
->WriteBundleStart(OutputFile
, Triple
))
907 if (Error Err
= FH
->WriteBundle(OutputFile
, **Input
))
909 if (Error Err
= FH
->WriteBundleEnd(OutputFile
, Triple
))
913 return Error::success();
916 // Unbundle the files. Return true if an error was found.
917 Error
OffloadBundler::UnbundleFiles() {
919 ErrorOr
<std::unique_ptr
<MemoryBuffer
>> CodeOrErr
=
920 MemoryBuffer::getFileOrSTDIN(BundlerConfig
.InputFileNames
.front());
921 if (std::error_code EC
= CodeOrErr
.getError())
922 return createFileError(BundlerConfig
.InputFileNames
.front(), EC
);
924 MemoryBuffer
&Input
= **CodeOrErr
;
926 // Select the right files handler.
927 Expected
<std::unique_ptr
<FileHandler
>> FileHandlerOrErr
=
928 CreateFileHandler(Input
, BundlerConfig
);
929 if (!FileHandlerOrErr
)
930 return FileHandlerOrErr
.takeError();
932 std::unique_ptr
<FileHandler
> &FH
= *FileHandlerOrErr
;
935 // Read the header of the bundled file.
936 if (Error Err
= FH
->ReadHeader(Input
))
939 // Create a work list that consist of the map triple/output file.
940 StringMap
<StringRef
> Worklist
;
941 auto Output
= BundlerConfig
.OutputFileNames
.begin();
942 for (auto &Triple
: BundlerConfig
.TargetNames
) {
943 Worklist
[Triple
] = *Output
;
947 // Read all the bundles that are in the work list. If we find no bundles we
948 // assume the file is meant for the host target.
949 bool FoundHostBundle
= false;
950 while (!Worklist
.empty()) {
951 Expected
<Optional
<StringRef
>> CurTripleOrErr
= FH
->ReadBundleStart(Input
);
953 return CurTripleOrErr
.takeError();
955 // We don't have more bundles.
956 if (!*CurTripleOrErr
)
959 StringRef CurTriple
= **CurTripleOrErr
;
960 assert(!CurTriple
.empty());
962 auto Output
= Worklist
.find(CurTriple
);
963 // The file may have more bundles for other targets, that we don't care
964 // about. Therefore, move on to the next triple
965 if (Output
== Worklist
.end())
968 // Check if the output file can be opened and copy the bundle to it.
970 raw_fd_ostream
OutputFile(Output
->second
, EC
, sys::fs::OF_None
);
972 return createFileError(Output
->second
, EC
);
973 if (Error Err
= FH
->ReadBundle(OutputFile
, Input
))
975 if (Error Err
= FH
->ReadBundleEnd(Input
))
977 Worklist
.erase(Output
);
979 // Record if we found the host bundle.
980 auto OffloadInfo
= OffloadTargetInfo(CurTriple
, BundlerConfig
);
981 if (OffloadInfo
.hasHostKind())
982 FoundHostBundle
= true;
985 if (!BundlerConfig
.AllowMissingBundles
&& !Worklist
.empty()) {
986 std::string ErrMsg
= "Can't find bundles for";
987 std::set
<StringRef
> Sorted
;
988 for (auto &E
: Worklist
)
989 Sorted
.insert(E
.first());
991 unsigned Last
= Sorted
.size() - 1;
992 for (auto &E
: Sorted
) {
993 if (I
!= 0 && Last
> 1)
996 if (I
== Last
&& I
!= 0)
1001 return createStringError(inconvertibleErrorCode(), ErrMsg
);
1004 // If no bundles were found, assume the input file is the host bundle and
1005 // create empty files for the remaining targets.
1006 if (Worklist
.size() == BundlerConfig
.TargetNames
.size()) {
1007 for (auto &E
: Worklist
) {
1009 raw_fd_ostream
OutputFile(E
.second
, EC
, sys::fs::OF_None
);
1011 return createFileError(E
.second
, EC
);
1013 // If this entry has a host kind, copy the input file to the output file.
1014 auto OffloadInfo
= OffloadTargetInfo(E
.getKey(), BundlerConfig
);
1015 if (OffloadInfo
.hasHostKind())
1016 OutputFile
.write(Input
.getBufferStart(), Input
.getBufferSize());
1018 return Error::success();
1021 // If we found elements, we emit an error if none of those were for the host
1022 // in case host bundle name was provided in command line.
1023 if (!FoundHostBundle
&& BundlerConfig
.HostInputIndex
!= ~0u)
1024 return createStringError(inconvertibleErrorCode(),
1025 "Can't find bundle for the host target");
1027 // If we still have any elements in the worklist, create empty files for them.
1028 for (auto &E
: Worklist
) {
1030 raw_fd_ostream
OutputFile(E
.second
, EC
, sys::fs::OF_None
);
1032 return createFileError(E
.second
, EC
);
1035 return Error::success();
1038 static Archive::Kind
getDefaultArchiveKindForHost() {
1039 return Triple(sys::getDefaultTargetTriple()).isOSDarwin() ? Archive::K_DARWIN
1043 /// @brief Checks if a code object \p CodeObjectInfo is compatible with a given
1044 /// target \p TargetInfo.
1045 /// @link https://clang.llvm.org/docs/ClangOffloadBundler.html#bundle-entry-id
1046 bool isCodeObjectCompatible(OffloadTargetInfo
&CodeObjectInfo
,
1047 OffloadTargetInfo
&TargetInfo
) {
1049 // Compatible in case of exact match.
1050 if (CodeObjectInfo
== TargetInfo
) {
1051 DEBUG_WITH_TYPE("CodeObjectCompatibility",
1052 dbgs() << "Compatible: Exact match: \t[CodeObject: "
1053 << CodeObjectInfo
.str()
1054 << "]\t:\t[Target: " << TargetInfo
.str() << "]\n");
1058 // Incompatible if Kinds or Triples mismatch.
1059 if (!CodeObjectInfo
.isOffloadKindCompatible(TargetInfo
.OffloadKind
) ||
1060 !CodeObjectInfo
.Triple
.isCompatibleWith(TargetInfo
.Triple
)) {
1062 "CodeObjectCompatibility",
1063 dbgs() << "Incompatible: Kind/Triple mismatch \t[CodeObject: "
1064 << CodeObjectInfo
.str() << "]\t:\t[Target: " << TargetInfo
.str()
1069 // Incompatible if GPUArch mismatch.
1070 if (CodeObjectInfo
.GPUArch
!= TargetInfo
.GPUArch
) {
1071 DEBUG_WITH_TYPE("CodeObjectCompatibility",
1072 dbgs() << "Incompatible: GPU Arch mismatch \t[CodeObject: "
1073 << CodeObjectInfo
.str()
1074 << "]\t:\t[Target: " << TargetInfo
.str() << "]\n");
1079 "CodeObjectCompatibility",
1080 dbgs() << "Compatible: Code Objects are compatible \t[CodeObject: "
1081 << CodeObjectInfo
.str() << "]\t:\t[Target: " << TargetInfo
.str()
1086 /// @brief Computes a list of targets among all given targets which are
1087 /// compatible with this code object
1088 /// @param [in] CodeObjectInfo Code Object
1089 /// @param [out] CompatibleTargets List of all compatible targets among all
1091 /// @return false, if no compatible target is found.
1093 getCompatibleOffloadTargets(OffloadTargetInfo
&CodeObjectInfo
,
1094 SmallVectorImpl
<StringRef
> &CompatibleTargets
,
1095 const OffloadBundlerConfig
&BundlerConfig
) {
1096 if (!CompatibleTargets
.empty()) {
1097 DEBUG_WITH_TYPE("CodeObjectCompatibility",
1098 dbgs() << "CompatibleTargets list should be empty\n");
1101 for (auto &Target
: BundlerConfig
.TargetNames
) {
1102 auto TargetInfo
= OffloadTargetInfo(Target
, BundlerConfig
);
1103 if (isCodeObjectCompatible(CodeObjectInfo
, TargetInfo
))
1104 CompatibleTargets
.push_back(Target
);
1106 return !CompatibleTargets
.empty();
1109 /// UnbundleArchive takes an archive file (".a") as input containing bundled
1110 /// code object files, and a list of offload targets (not host), and extracts
1111 /// the code objects into a new archive file for each offload target. Each
1112 /// resulting archive file contains all code object files corresponding to that
1113 /// particular offload target. The created archive file does not
1114 /// contain an index of the symbols and code object files are named as
1115 /// <<Parent Bundle Name>-<CodeObject's GPUArch>>, with ':' replaced with '_'.
1116 Error
OffloadBundler::UnbundleArchive() {
1117 std::vector
<std::unique_ptr
<MemoryBuffer
>> ArchiveBuffers
;
1119 /// Map of target names with list of object files that will form the device
1120 /// specific archive for that target
1121 StringMap
<std::vector
<NewArchiveMember
>> OutputArchivesMap
;
1123 // Map of target names and output archive filenames
1124 StringMap
<StringRef
> TargetOutputFileNameMap
;
1126 auto Output
= BundlerConfig
.OutputFileNames
.begin();
1127 for (auto &Target
: BundlerConfig
.TargetNames
) {
1128 TargetOutputFileNameMap
[Target
] = *Output
;
1132 StringRef IFName
= BundlerConfig
.InputFileNames
.front();
1134 ErrorOr
<std::unique_ptr
<MemoryBuffer
>> BufOrErr
=
1135 MemoryBuffer::getFileOrSTDIN(IFName
, true, false);
1136 if (std::error_code EC
= BufOrErr
.getError())
1137 return createFileError(BundlerConfig
.InputFileNames
.front(), EC
);
1139 ArchiveBuffers
.push_back(std::move(*BufOrErr
));
1140 Expected
<std::unique_ptr
<llvm::object::Archive
>> LibOrErr
=
1141 Archive::create(ArchiveBuffers
.back()->getMemBufferRef());
1143 return LibOrErr
.takeError();
1145 auto Archive
= std::move(*LibOrErr
);
1147 Error ArchiveErr
= Error::success();
1148 auto ChildEnd
= Archive
->child_end();
1150 /// Iterate over all bundled code object files in the input archive.
1151 for (auto ArchiveIter
= Archive
->child_begin(ArchiveErr
);
1152 ArchiveIter
!= ChildEnd
; ++ArchiveIter
) {
1155 auto ArchiveChildNameOrErr
= (*ArchiveIter
).getName();
1156 if (!ArchiveChildNameOrErr
)
1157 return ArchiveChildNameOrErr
.takeError();
1159 StringRef BundledObjectFile
= sys::path::filename(*ArchiveChildNameOrErr
);
1161 auto CodeObjectBufferRefOrErr
= (*ArchiveIter
).getMemoryBufferRef();
1162 if (!CodeObjectBufferRefOrErr
)
1163 return CodeObjectBufferRefOrErr
.takeError();
1165 auto CodeObjectBuffer
=
1166 MemoryBuffer::getMemBuffer(*CodeObjectBufferRefOrErr
, false);
1168 Expected
<std::unique_ptr
<FileHandler
>> FileHandlerOrErr
=
1169 CreateFileHandler(*CodeObjectBuffer
, BundlerConfig
);
1170 if (!FileHandlerOrErr
)
1171 return FileHandlerOrErr
.takeError();
1173 std::unique_ptr
<FileHandler
> &FileHandler
= *FileHandlerOrErr
;
1174 assert(FileHandler
&&
1175 "FileHandle creation failed for file in the archive!");
1177 if (Error ReadErr
= FileHandler
.get()->ReadHeader(*CodeObjectBuffer
))
1180 Expected
<Optional
<StringRef
>> CurBundleIDOrErr
=
1181 FileHandler
->ReadBundleStart(*CodeObjectBuffer
);
1182 if (!CurBundleIDOrErr
)
1183 return CurBundleIDOrErr
.takeError();
1185 Optional
<StringRef
> OptionalCurBundleID
= *CurBundleIDOrErr
;
1186 // No device code in this child, skip.
1187 if (!OptionalCurBundleID
)
1189 StringRef CodeObject
= *OptionalCurBundleID
;
1191 // Process all bundle entries (CodeObjects) found in this child of input
1193 while (!CodeObject
.empty()) {
1194 SmallVector
<StringRef
> CompatibleTargets
;
1195 auto CodeObjectInfo
= OffloadTargetInfo(CodeObject
, BundlerConfig
);
1196 if (CodeObjectInfo
.hasHostKind()) {
1197 // Do nothing, we don't extract host code yet.
1198 } else if (getCompatibleOffloadTargets(CodeObjectInfo
,
1201 std::string BundleData
;
1202 raw_string_ostream
DataStream(BundleData
);
1204 FileHandler
.get()->ReadBundle(DataStream
, *CodeObjectBuffer
))
1207 for (auto &CompatibleTarget
: CompatibleTargets
) {
1208 SmallString
<128> BundledObjectFileName
;
1209 BundledObjectFileName
.assign(BundledObjectFile
);
1210 auto OutputBundleName
=
1211 Twine(llvm::sys::path::stem(BundledObjectFileName
) + "-" +
1213 getDeviceLibraryFileName(BundledObjectFileName
,
1214 CodeObjectInfo
.GPUArch
))
1216 // Replace ':' in optional target feature list with '_' to ensure
1217 // cross-platform validity.
1218 std::replace(OutputBundleName
.begin(), OutputBundleName
.end(), ':',
1221 std::unique_ptr
<MemoryBuffer
> MemBuf
= MemoryBuffer::getMemBufferCopy(
1222 DataStream
.str(), OutputBundleName
);
1223 ArchiveBuffers
.push_back(std::move(MemBuf
));
1224 llvm::MemoryBufferRef MemBufRef
=
1225 MemoryBufferRef(*(ArchiveBuffers
.back()));
1227 // For inserting <CompatibleTarget, list<CodeObject>> entry in
1228 // OutputArchivesMap.
1229 if (OutputArchivesMap
.find(CompatibleTarget
) ==
1230 OutputArchivesMap
.end()) {
1232 std::vector
<NewArchiveMember
> ArchiveMembers
;
1233 ArchiveMembers
.push_back(NewArchiveMember(MemBufRef
));
1234 OutputArchivesMap
.insert_or_assign(CompatibleTarget
,
1235 std::move(ArchiveMembers
));
1237 OutputArchivesMap
[CompatibleTarget
].push_back(
1238 NewArchiveMember(MemBufRef
));
1243 if (Error Err
= FileHandler
.get()->ReadBundleEnd(*CodeObjectBuffer
))
1246 Expected
<Optional
<StringRef
>> NextTripleOrErr
=
1247 FileHandler
->ReadBundleStart(*CodeObjectBuffer
);
1248 if (!NextTripleOrErr
)
1249 return NextTripleOrErr
.takeError();
1251 CodeObject
= ((*NextTripleOrErr
).has_value()) ? **NextTripleOrErr
: "";
1252 } // End of processing of all bundle entries of this child of input archive.
1253 } // End of while over children of input archive.
1255 assert(!ArchiveErr
&& "Error occurred while reading archive!");
1257 /// Write out an archive for each target
1258 for (auto &Target
: BundlerConfig
.TargetNames
) {
1259 StringRef FileName
= TargetOutputFileNameMap
[Target
];
1260 StringMapIterator
<std::vector
<llvm::NewArchiveMember
>> CurArchiveMembers
=
1261 OutputArchivesMap
.find(Target
);
1262 if (CurArchiveMembers
!= OutputArchivesMap
.end()) {
1263 if (Error WriteErr
= writeArchive(FileName
, CurArchiveMembers
->getValue(),
1264 true, getDefaultArchiveKindForHost(),
1265 true, false, nullptr))
1267 } else if (!BundlerConfig
.AllowMissingBundles
) {
1268 std::string ErrMsg
=
1269 Twine("no compatible code object found for the target '" + Target
+
1270 "' in heterogeneous archive library: " + IFName
)
1272 return createStringError(inconvertibleErrorCode(), ErrMsg
);
1273 } else { // Create an empty archive file if no compatible code object is
1274 // found and "allow-missing-bundles" is enabled. It ensures that
1275 // the linker using output of this step doesn't complain about
1276 // the missing input file.
1277 std::vector
<llvm::NewArchiveMember
> EmptyArchive
;
1278 EmptyArchive
.clear();
1279 if (Error WriteErr
= writeArchive(FileName
, EmptyArchive
, true,
1280 getDefaultArchiveKindForHost(), true,
1286 return Error::success();