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/StringSwitch.h"
26 #include "llvm/ADT/Triple.h"
27 #include "llvm/Object/Archive.h"
28 #include "llvm/Object/ArchiveWriter.h"
29 #include "llvm/Object/Binary.h"
30 #include "llvm/Object/ObjectFile.h"
31 #include "llvm/Support/Casting.h"
32 #include "llvm/Support/CommandLine.h"
33 #include "llvm/Support/Debug.h"
34 #include "llvm/Support/Errc.h"
35 #include "llvm/Support/Error.h"
36 #include "llvm/Support/ErrorOr.h"
37 #include "llvm/Support/FileSystem.h"
38 #include "llvm/Support/Host.h"
39 #include "llvm/Support/MemoryBuffer.h"
40 #include "llvm/Support/Path.h"
41 #include "llvm/Support/Program.h"
42 #include "llvm/Support/Signals.h"
43 #include "llvm/Support/StringSaver.h"
44 #include "llvm/Support/WithColor.h"
45 #include "llvm/Support/raw_ostream.h"
50 #include <forward_list>
54 #include <system_error>
58 using namespace llvm::object
;
59 using namespace clang
;
61 /// Magic string that marks the existence of offloading data.
62 #define OFFLOAD_BUNDLER_MAGIC_STR "__CLANG_OFFLOAD_BUNDLE__"
64 OffloadTargetInfo::OffloadTargetInfo(const StringRef Target
,
65 const OffloadBundlerConfig
&BC
)
68 // TODO: Add error checking from ClangOffloadBundler.cpp
69 auto TargetFeatures
= Target
.split(':');
70 auto TripleOrGPU
= TargetFeatures
.first
.rsplit('-');
72 if (clang::StringToCudaArch(TripleOrGPU
.second
) !=
73 clang::CudaArch::UNKNOWN
) {
74 auto KindTriple
= TripleOrGPU
.first
.split('-');
75 this->OffloadKind
= KindTriple
.first
;
76 this->Triple
= llvm::Triple(KindTriple
.second
);
77 this->GPUArch
= Target
.substr(Target
.find(TripleOrGPU
.second
));
79 auto KindTriple
= TargetFeatures
.first
.split('-');
80 this->OffloadKind
= KindTriple
.first
;
81 this->Triple
= llvm::Triple(KindTriple
.second
);
86 bool OffloadTargetInfo::hasHostKind() const {
87 return this->OffloadKind
== "host";
90 bool OffloadTargetInfo::isOffloadKindValid() const {
91 return OffloadKind
== "host" || OffloadKind
== "openmp" ||
92 OffloadKind
== "hip" || OffloadKind
== "hipv4";
95 bool OffloadTargetInfo::isOffloadKindCompatible(
96 const StringRef TargetOffloadKind
) const {
97 if (OffloadKind
== TargetOffloadKind
)
99 if (BundlerConfig
.HipOpenmpCompatible
) {
100 bool HIPCompatibleWithOpenMP
=
101 OffloadKind
.startswith_insensitive("hip") &&
102 TargetOffloadKind
== "openmp";
103 bool OpenMPCompatibleWithHIP
=
104 OffloadKind
== "openmp" &&
105 TargetOffloadKind
.startswith_insensitive("hip");
106 return HIPCompatibleWithOpenMP
|| OpenMPCompatibleWithHIP
;
111 bool OffloadTargetInfo::isTripleValid() const {
112 return !Triple
.str().empty() && Triple
.getArch() != Triple::UnknownArch
;
115 bool OffloadTargetInfo::operator==(const OffloadTargetInfo
&Target
) const {
116 return OffloadKind
== Target
.OffloadKind
&&
117 Triple
.isCompatibleWith(Target
.Triple
) &&
118 GPUArch
== Target
.GPUArch
;
121 std::string
OffloadTargetInfo::str() {
122 return Twine(OffloadKind
+ "-" + Triple
.str() + "-" + GPUArch
).str();
125 static StringRef
getDeviceFileExtension(StringRef Device
,
126 StringRef BundleFileName
) {
127 if (Device
.contains("gfx"))
129 if (Device
.contains("sm_"))
131 return sys::path::extension(BundleFileName
);
134 static std::string
getDeviceLibraryFileName(StringRef BundleFileName
,
136 StringRef LibName
= sys::path::stem(BundleFileName
);
137 StringRef Extension
= getDeviceFileExtension(Device
, BundleFileName
);
145 /// Generic file handler interface.
154 virtual ~FileHandler() {}
156 /// Update the file handler with information from the header of the bundled
158 virtual Error
ReadHeader(MemoryBuffer
&Input
) = 0;
160 /// Read the marker of the next bundled to be read in the file. The bundle
161 /// name is returned if there is one in the file, or `None` if there are no
162 /// more bundles to be read.
163 virtual Expected
<Optional
<StringRef
>>
164 ReadBundleStart(MemoryBuffer
&Input
) = 0;
166 /// Read the marker that closes the current bundle.
167 virtual Error
ReadBundleEnd(MemoryBuffer
&Input
) = 0;
169 /// Read the current bundle and write the result into the stream \a OS.
170 virtual Error
ReadBundle(raw_ostream
&OS
, MemoryBuffer
&Input
) = 0;
172 /// Write the header of the bundled file to \a OS based on the information
173 /// gathered from \a Inputs.
174 virtual Error
WriteHeader(raw_fd_ostream
&OS
,
175 ArrayRef
<std::unique_ptr
<MemoryBuffer
>> Inputs
) = 0;
177 /// Write the marker that initiates a bundle for the triple \a TargetTriple to
179 virtual Error
WriteBundleStart(raw_fd_ostream
&OS
,
180 StringRef TargetTriple
) = 0;
182 /// Write the marker that closes a bundle for the triple \a TargetTriple to \a
184 virtual Error
WriteBundleEnd(raw_fd_ostream
&OS
, StringRef TargetTriple
) = 0;
186 /// Write the bundle from \a Input into \a OS.
187 virtual Error
WriteBundle(raw_fd_ostream
&OS
, MemoryBuffer
&Input
) = 0;
189 /// List bundle IDs in \a Input.
190 virtual Error
listBundleIDs(MemoryBuffer
&Input
) {
191 if (Error Err
= ReadHeader(Input
))
193 return forEachBundle(Input
, [&](const BundleInfo
&Info
) -> Error
{
194 llvm::outs() << Info
.BundleID
<< '\n';
195 Error Err
= listBundleIDsCallback(Input
, Info
);
198 return Error::success();
202 /// For each bundle in \a Input, do \a Func.
203 Error
forEachBundle(MemoryBuffer
&Input
,
204 std::function
<Error(const BundleInfo
&)> Func
) {
206 Expected
<Optional
<StringRef
>> CurTripleOrErr
= ReadBundleStart(Input
);
208 return CurTripleOrErr
.takeError();
211 if (!*CurTripleOrErr
)
214 StringRef CurTriple
= **CurTripleOrErr
;
215 assert(!CurTriple
.empty());
217 BundleInfo Info
{CurTriple
};
218 if (Error Err
= Func(Info
))
221 return Error::success();
225 virtual Error
listBundleIDsCallback(MemoryBuffer
&Input
,
226 const BundleInfo
&Info
) {
227 return Error::success();
231 /// Handler for binary files. The bundled file will have the following format
232 /// (all integers are stored in little-endian format):
234 /// "OFFLOAD_BUNDLER_MAGIC_STR" (ASCII encoding of the string)
236 /// NumberOfOffloadBundles (8-byte integer)
238 /// OffsetOfBundle1 (8-byte integer)
239 /// SizeOfBundle1 (8-byte integer)
240 /// NumberOfBytesInTripleOfBundle1 (8-byte integer)
241 /// TripleOfBundle1 (byte length defined before)
245 /// OffsetOfBundleN (8-byte integer)
246 /// SizeOfBundleN (8-byte integer)
247 /// NumberOfBytesInTripleOfBundleN (8-byte integer)
248 /// TripleOfBundleN (byte length defined before)
254 /// Read 8-byte integers from a buffer in little-endian format.
255 static uint64_t Read8byteIntegerFromBuffer(StringRef Buffer
, size_t pos
) {
257 const char *Data
= Buffer
.data();
259 for (unsigned i
= 0; i
< 8; ++i
) {
261 uint64_t Char
= (uint64_t)Data
[pos
+ 7 - i
];
267 /// Write 8-byte integers to a buffer in little-endian format.
268 static void Write8byteIntegerToBuffer(raw_fd_ostream
&OS
, uint64_t Val
) {
269 for (unsigned i
= 0; i
< 8; ++i
) {
270 char Char
= (char)(Val
& 0xffu
);
276 class BinaryFileHandler final
: public FileHandler
{
277 /// Information about the bundles extracted from the header.
278 struct BinaryBundleInfo final
: public BundleInfo
{
279 /// Size of the bundle.
281 /// Offset at which the bundle starts in the bundled file.
282 uint64_t Offset
= 0u;
284 BinaryBundleInfo() {}
285 BinaryBundleInfo(uint64_t Size
, uint64_t Offset
)
286 : Size(Size
), Offset(Offset
) {}
289 /// Map between a triple and the corresponding bundle information.
290 StringMap
<BinaryBundleInfo
> BundlesInfo
;
292 /// Iterator for the bundle information that is being read.
293 StringMap
<BinaryBundleInfo
>::iterator CurBundleInfo
;
294 StringMap
<BinaryBundleInfo
>::iterator NextBundleInfo
;
296 /// Current bundle target to be written.
297 std::string CurWriteBundleTarget
;
299 /// Configuration options and arrays for this bundler job
300 const OffloadBundlerConfig
&BundlerConfig
;
303 // TODO: Add error checking from ClangOffloadBundler.cpp
304 BinaryFileHandler(const OffloadBundlerConfig
&BC
) : BundlerConfig(BC
) {}
306 ~BinaryFileHandler() final
{}
308 Error
ReadHeader(MemoryBuffer
&Input
) final
{
309 StringRef FC
= Input
.getBuffer();
311 // Initialize the current bundle with the end of the container.
312 CurBundleInfo
= BundlesInfo
.end();
314 // Check if buffer is smaller than magic string.
315 size_t ReadChars
= sizeof(OFFLOAD_BUNDLER_MAGIC_STR
) - 1;
316 if (ReadChars
> FC
.size())
317 return Error::success();
319 // Check if no magic was found.
320 StringRef
Magic(FC
.data(), sizeof(OFFLOAD_BUNDLER_MAGIC_STR
) - 1);
321 if (!Magic
.equals(OFFLOAD_BUNDLER_MAGIC_STR
))
322 return Error::success();
324 // Read number of bundles.
325 if (ReadChars
+ 8 > FC
.size())
326 return Error::success();
328 uint64_t NumberOfBundles
= Read8byteIntegerFromBuffer(FC
, ReadChars
);
331 // Read bundle offsets, sizes and triples.
332 for (uint64_t i
= 0; i
< NumberOfBundles
; ++i
) {
335 if (ReadChars
+ 8 > FC
.size())
336 return Error::success();
338 uint64_t Offset
= Read8byteIntegerFromBuffer(FC
, ReadChars
);
342 if (ReadChars
+ 8 > FC
.size())
343 return Error::success();
345 uint64_t Size
= Read8byteIntegerFromBuffer(FC
, ReadChars
);
349 if (ReadChars
+ 8 > FC
.size())
350 return Error::success();
352 uint64_t TripleSize
= Read8byteIntegerFromBuffer(FC
, ReadChars
);
356 if (ReadChars
+ TripleSize
> FC
.size())
357 return Error::success();
359 StringRef
Triple(&FC
.data()[ReadChars
], TripleSize
);
360 ReadChars
+= TripleSize
;
362 // Check if the offset and size make sense.
363 if (!Offset
|| Offset
+ Size
> FC
.size())
364 return Error::success();
366 assert(BundlesInfo
.find(Triple
) == BundlesInfo
.end() &&
367 "Triple is duplicated??");
368 BundlesInfo
[Triple
] = BinaryBundleInfo(Size
, Offset
);
370 // Set the iterator to where we will start to read.
371 CurBundleInfo
= BundlesInfo
.end();
372 NextBundleInfo
= BundlesInfo
.begin();
373 return Error::success();
376 Expected
<Optional
<StringRef
>> ReadBundleStart(MemoryBuffer
&Input
) final
{
377 if (NextBundleInfo
== BundlesInfo
.end())
379 CurBundleInfo
= NextBundleInfo
++;
380 return CurBundleInfo
->first();
383 Error
ReadBundleEnd(MemoryBuffer
&Input
) final
{
384 assert(CurBundleInfo
!= BundlesInfo
.end() && "Invalid reader info!");
385 return Error::success();
388 Error
ReadBundle(raw_ostream
&OS
, MemoryBuffer
&Input
) final
{
389 assert(CurBundleInfo
!= BundlesInfo
.end() && "Invalid reader info!");
390 StringRef FC
= Input
.getBuffer();
391 OS
.write(FC
.data() + CurBundleInfo
->second
.Offset
,
392 CurBundleInfo
->second
.Size
);
393 return Error::success();
396 Error
WriteHeader(raw_fd_ostream
&OS
,
397 ArrayRef
<std::unique_ptr
<MemoryBuffer
>> Inputs
) final
{
399 // Compute size of the header.
400 uint64_t HeaderSize
= 0;
402 HeaderSize
+= sizeof(OFFLOAD_BUNDLER_MAGIC_STR
) - 1;
403 HeaderSize
+= 8; // Number of Bundles
405 for (auto &T
: BundlerConfig
.TargetNames
) {
406 HeaderSize
+= 3 * 8; // Bundle offset, Size of bundle and size of triple.
407 HeaderSize
+= T
.size(); // The triple.
410 // Write to the buffer the header.
411 OS
<< OFFLOAD_BUNDLER_MAGIC_STR
;
413 Write8byteIntegerToBuffer(OS
, BundlerConfig
.TargetNames
.size());
416 for (auto &T
: BundlerConfig
.TargetNames
) {
417 MemoryBuffer
&MB
= *Inputs
[Idx
++];
418 HeaderSize
= alignTo(HeaderSize
, BundlerConfig
.BundleAlignment
);
420 Write8byteIntegerToBuffer(OS
, HeaderSize
);
421 // Size of the bundle (adds to the next bundle's offset)
422 Write8byteIntegerToBuffer(OS
, MB
.getBufferSize());
423 BundlesInfo
[T
] = BinaryBundleInfo(MB
.getBufferSize(), HeaderSize
);
424 HeaderSize
+= MB
.getBufferSize();
425 // Size of the triple
426 Write8byteIntegerToBuffer(OS
, T
.size());
430 return Error::success();
433 Error
WriteBundleStart(raw_fd_ostream
&OS
, StringRef TargetTriple
) final
{
434 CurWriteBundleTarget
= TargetTriple
.str();
435 return Error::success();
438 Error
WriteBundleEnd(raw_fd_ostream
&OS
, StringRef TargetTriple
) final
{
439 return Error::success();
442 Error
WriteBundle(raw_fd_ostream
&OS
, MemoryBuffer
&Input
) final
{
443 auto BI
= BundlesInfo
[CurWriteBundleTarget
];
445 OS
.write(Input
.getBufferStart(), Input
.getBufferSize());
446 return Error::success();
452 // This class implements a list of temporary files that are removed upon
453 // object destruction.
454 class TempFileHandlerRAII
{
456 ~TempFileHandlerRAII() {
457 for (const auto &File
: Files
)
458 sys::fs::remove(File
);
461 // Creates temporary file with given contents.
462 Expected
<StringRef
> Create(Optional
<ArrayRef
<char>> Contents
) {
463 SmallString
<128u> File
;
464 if (std::error_code EC
=
465 sys::fs::createTemporaryFile("clang-offload-bundler", "tmp", File
))
466 return createFileError(File
, EC
);
467 Files
.push_front(File
);
471 raw_fd_ostream
OS(File
, EC
);
473 return createFileError(File
, EC
);
474 OS
.write(Contents
->data(), Contents
->size());
476 return Files
.front().str();
480 std::forward_list
<SmallString
<128u>> Files
;
483 } // end anonymous namespace
485 /// Handler for object files. The bundles are organized by sections with a
488 /// To unbundle, we just copy the contents of the designated section.
489 class ObjectFileHandler final
: public FileHandler
{
491 /// The object file we are currently dealing with.
492 std::unique_ptr
<ObjectFile
> Obj
;
494 /// Return the input file contents.
495 StringRef
getInputFileContents() const { return Obj
->getData(); }
497 /// Return bundle name (<kind>-<triple>) if the provided section is an offload
499 static Expected
<Optional
<StringRef
>> IsOffloadSection(SectionRef CurSection
) {
500 Expected
<StringRef
> NameOrErr
= CurSection
.getName();
502 return NameOrErr
.takeError();
504 // If it does not start with the reserved suffix, just skip this section.
505 if (!NameOrErr
->startswith(OFFLOAD_BUNDLER_MAGIC_STR
))
508 // Return the triple that is right after the reserved prefix.
509 return NameOrErr
->substr(sizeof(OFFLOAD_BUNDLER_MAGIC_STR
) - 1);
512 /// Total number of inputs.
513 unsigned NumberOfInputs
= 0;
515 /// Total number of processed inputs, i.e, inputs that were already
516 /// read from the buffers.
517 unsigned NumberOfProcessedInputs
= 0;
519 /// Iterator of the current and next section.
520 section_iterator CurrentSection
;
521 section_iterator NextSection
;
523 /// Configuration options and arrays for this bundler job
524 const OffloadBundlerConfig
&BundlerConfig
;
527 // TODO: Add error checking from ClangOffloadBundler.cpp
528 ObjectFileHandler(std::unique_ptr
<ObjectFile
> ObjIn
,
529 const OffloadBundlerConfig
&BC
)
530 : Obj(std::move(ObjIn
)), CurrentSection(Obj
->section_begin()),
531 NextSection(Obj
->section_begin()), BundlerConfig(BC
) {}
533 ~ObjectFileHandler() final
{}
535 Error
ReadHeader(MemoryBuffer
&Input
) final
{ return Error::success(); }
537 Expected
<Optional
<StringRef
>> ReadBundleStart(MemoryBuffer
&Input
) final
{
538 while (NextSection
!= Obj
->section_end()) {
539 CurrentSection
= NextSection
;
542 // Check if the current section name starts with the reserved prefix. If
543 // so, return the triple.
544 Expected
<Optional
<StringRef
>> TripleOrErr
=
545 IsOffloadSection(*CurrentSection
);
547 return TripleOrErr
.takeError();
549 return **TripleOrErr
;
554 Error
ReadBundleEnd(MemoryBuffer
&Input
) final
{ return Error::success(); }
556 Error
ReadBundle(raw_ostream
&OS
, MemoryBuffer
&Input
) final
{
557 Expected
<StringRef
> ContentOrErr
= CurrentSection
->getContents();
559 return ContentOrErr
.takeError();
560 StringRef Content
= *ContentOrErr
;
562 // Copy fat object contents to the output when extracting host bundle.
563 if (Content
.size() == 1u && Content
.front() == 0)
564 Content
= StringRef(Input
.getBufferStart(), Input
.getBufferSize());
566 OS
.write(Content
.data(), Content
.size());
567 return Error::success();
570 Error
WriteHeader(raw_fd_ostream
&OS
,
571 ArrayRef
<std::unique_ptr
<MemoryBuffer
>> Inputs
) final
{
572 assert(BundlerConfig
.HostInputIndex
!= ~0u &&
573 "Host input index not defined.");
575 // Record number of inputs.
576 NumberOfInputs
= Inputs
.size();
577 return Error::success();
580 Error
WriteBundleStart(raw_fd_ostream
&OS
, StringRef TargetTriple
) final
{
581 ++NumberOfProcessedInputs
;
582 return Error::success();
585 Error
WriteBundleEnd(raw_fd_ostream
&OS
, StringRef TargetTriple
) final
{
586 assert(NumberOfProcessedInputs
<= NumberOfInputs
&&
587 "Processing more inputs that actually exist!");
588 assert(BundlerConfig
.HostInputIndex
!= ~0u &&
589 "Host input index not defined.");
591 // If this is not the last output, we don't have to do anything.
592 if (NumberOfProcessedInputs
!= NumberOfInputs
)
593 return Error::success();
595 // We will use llvm-objcopy to add target objects sections to the output
596 // fat object. These sections should have 'exclude' flag set which tells
597 // link editor to remove them from linker inputs when linking executable or
600 assert(BundlerConfig
.ObjcopyPath
!= "" &&
601 "llvm-objcopy path not specified");
603 // We write to the output file directly. So, we close it and use the name
604 // to pass down to llvm-objcopy.
607 // Temporary files that need to be removed.
608 TempFileHandlerRAII TempFiles
;
610 // Compose llvm-objcopy command line for add target objects' sections with
611 // appropriate flags.
612 BumpPtrAllocator Alloc
;
613 StringSaver SS
{Alloc
};
614 SmallVector
<StringRef
, 8u> ObjcopyArgs
{"llvm-objcopy"};
616 for (unsigned I
= 0; I
< NumberOfInputs
; ++I
) {
617 StringRef InputFile
= BundlerConfig
.InputFileNames
[I
];
618 if (I
== BundlerConfig
.HostInputIndex
) {
619 // Special handling for the host bundle. We do not need to add a
620 // standard bundle for the host object since we are going to use fat
621 // object as a host object. Therefore use dummy contents (one zero byte)
622 // when creating section for the host bundle.
623 Expected
<StringRef
> TempFileOrErr
= TempFiles
.Create(ArrayRef
<char>(0));
625 return TempFileOrErr
.takeError();
626 InputFile
= *TempFileOrErr
;
629 ObjcopyArgs
.push_back(SS
.save(Twine("--add-section=") +
630 OFFLOAD_BUNDLER_MAGIC_STR
+
631 BundlerConfig
.TargetNames
[I
] +
633 ObjcopyArgs
.push_back(SS
.save(Twine("--set-section-flags=") +
634 OFFLOAD_BUNDLER_MAGIC_STR
+
635 BundlerConfig
.TargetNames
[I
] +
636 "=readonly,exclude"));
638 ObjcopyArgs
.push_back("--");
639 ObjcopyArgs
.push_back(
640 BundlerConfig
.InputFileNames
[BundlerConfig
.HostInputIndex
]);
641 ObjcopyArgs
.push_back(BundlerConfig
.OutputFileNames
.front());
643 if (Error Err
= executeObjcopy(BundlerConfig
.ObjcopyPath
, ObjcopyArgs
))
646 return Error::success();
649 Error
WriteBundle(raw_fd_ostream
&OS
, MemoryBuffer
&Input
) final
{
650 return Error::success();
654 Error
executeObjcopy(StringRef Objcopy
, ArrayRef
<StringRef
> Args
) {
655 // If the user asked for the commands to be printed out, we do that
656 // instead of executing it.
657 if (BundlerConfig
.PrintExternalCommands
) {
658 errs() << "\"" << Objcopy
<< "\"";
659 for (StringRef Arg
: drop_begin(Args
, 1))
660 errs() << " \"" << Arg
<< "\"";
663 if (sys::ExecuteAndWait(Objcopy
, Args
))
664 return createStringError(inconvertibleErrorCode(),
665 "'llvm-objcopy' tool failed");
667 return Error::success();
671 /// Handler for text files. The bundled file will have the following format.
673 /// "Comment OFFLOAD_BUNDLER_MAGIC_STR__START__ triple"
675 /// "Comment OFFLOAD_BUNDLER_MAGIC_STR__END__ triple"
677 /// "Comment OFFLOAD_BUNDLER_MAGIC_STR__START__ triple"
679 /// "Comment OFFLOAD_BUNDLER_MAGIC_STR__END__ triple"
680 class TextFileHandler final
: public FileHandler
{
681 /// String that begins a line comment.
684 /// String that initiates a bundle.
685 std::string BundleStartString
;
687 /// String that closes a bundle.
688 std::string BundleEndString
;
690 /// Number of chars read from input.
691 size_t ReadChars
= 0u;
694 Error
ReadHeader(MemoryBuffer
&Input
) final
{ return Error::success(); }
696 Expected
<Optional
<StringRef
>> ReadBundleStart(MemoryBuffer
&Input
) final
{
697 StringRef FC
= Input
.getBuffer();
699 // Find start of the bundle.
700 ReadChars
= FC
.find(BundleStartString
, ReadChars
);
701 if (ReadChars
== FC
.npos
)
704 // Get position of the triple.
705 size_t TripleStart
= ReadChars
= ReadChars
+ BundleStartString
.size();
707 // Get position that closes the triple.
708 size_t TripleEnd
= ReadChars
= FC
.find("\n", ReadChars
);
709 if (TripleEnd
== FC
.npos
)
712 // Next time we read after the new line.
715 return StringRef(&FC
.data()[TripleStart
], TripleEnd
- TripleStart
);
718 Error
ReadBundleEnd(MemoryBuffer
&Input
) final
{
719 StringRef FC
= Input
.getBuffer();
721 // Read up to the next new line.
722 assert(FC
[ReadChars
] == '\n' && "The bundle should end with a new line.");
724 size_t TripleEnd
= ReadChars
= FC
.find("\n", ReadChars
+ 1);
725 if (TripleEnd
!= FC
.npos
)
726 // Next time we read after the new line.
729 return Error::success();
732 Error
ReadBundle(raw_ostream
&OS
, MemoryBuffer
&Input
) final
{
733 StringRef FC
= Input
.getBuffer();
734 size_t BundleStart
= ReadChars
;
736 // Find end of the bundle.
737 size_t BundleEnd
= ReadChars
= FC
.find(BundleEndString
, ReadChars
);
739 StringRef
Bundle(&FC
.data()[BundleStart
], BundleEnd
- BundleStart
);
742 return Error::success();
745 Error
WriteHeader(raw_fd_ostream
&OS
,
746 ArrayRef
<std::unique_ptr
<MemoryBuffer
>> Inputs
) final
{
747 return Error::success();
750 Error
WriteBundleStart(raw_fd_ostream
&OS
, StringRef TargetTriple
) final
{
751 OS
<< BundleStartString
<< TargetTriple
<< "\n";
752 return Error::success();
755 Error
WriteBundleEnd(raw_fd_ostream
&OS
, StringRef TargetTriple
) final
{
756 OS
<< BundleEndString
<< TargetTriple
<< "\n";
757 return Error::success();
760 Error
WriteBundle(raw_fd_ostream
&OS
, MemoryBuffer
&Input
) final
{
761 OS
<< Input
.getBuffer();
762 return Error::success();
766 TextFileHandler(StringRef Comment
) : Comment(Comment
), ReadChars(0) {
768 "\n" + Comment
.str() + " " OFFLOAD_BUNDLER_MAGIC_STR
"__START__ ";
770 "\n" + Comment
.str() + " " OFFLOAD_BUNDLER_MAGIC_STR
"__END__ ";
773 Error
listBundleIDsCallback(MemoryBuffer
&Input
,
774 const BundleInfo
&Info
) final
{
775 // TODO: To list bundle IDs in a bundled text file we need to go through
776 // all bundles. The format of bundled text file may need to include a
777 // header if the performance of listing bundle IDs of bundled text file is
779 ReadChars
= Input
.getBuffer().find(BundleEndString
, ReadChars
);
780 if (Error Err
= ReadBundleEnd(Input
))
782 return Error::success();
786 /// Return an appropriate object file handler. We use the specific object
787 /// handler if we know how to deal with that format, otherwise we use a default
788 /// binary file handler.
789 static std::unique_ptr
<FileHandler
>
790 CreateObjectFileHandler(MemoryBuffer
&FirstInput
,
791 const OffloadBundlerConfig
&BundlerConfig
) {
792 // Check if the input file format is one that we know how to deal with.
793 Expected
<std::unique_ptr
<Binary
>> BinaryOrErr
= createBinary(FirstInput
);
795 // We only support regular object files. If failed to open the input as a
796 // known binary or this is not an object file use the default binary handler.
797 if (errorToBool(BinaryOrErr
.takeError()) || !isa
<ObjectFile
>(*BinaryOrErr
))
798 return std::make_unique
<BinaryFileHandler
>(BundlerConfig
);
800 // Otherwise create an object file handler. The handler will be owned by the
801 // client of this function.
802 return std::make_unique
<ObjectFileHandler
>(
803 std::unique_ptr
<ObjectFile
>(cast
<ObjectFile
>(BinaryOrErr
->release())),
807 /// Return an appropriate handler given the input files and options.
808 static Expected
<std::unique_ptr
<FileHandler
>>
809 CreateFileHandler(MemoryBuffer
&FirstInput
,
810 const OffloadBundlerConfig
&BundlerConfig
) {
811 std::string FilesType
= BundlerConfig
.FilesType
;
813 if (FilesType
== "i")
814 return std::make_unique
<TextFileHandler
>(/*Comment=*/"//");
815 if (FilesType
== "ii")
816 return std::make_unique
<TextFileHandler
>(/*Comment=*/"//");
817 if (FilesType
== "cui")
818 return std::make_unique
<TextFileHandler
>(/*Comment=*/"//");
819 // TODO: `.d` should be eventually removed once `-M` and its variants are
820 // handled properly in offload compilation.
821 if (FilesType
== "d")
822 return std::make_unique
<TextFileHandler
>(/*Comment=*/"#");
823 if (FilesType
== "ll")
824 return std::make_unique
<TextFileHandler
>(/*Comment=*/";");
825 if (FilesType
== "bc")
826 return std::make_unique
<BinaryFileHandler
>(BundlerConfig
);
827 if (FilesType
== "s")
828 return std::make_unique
<TextFileHandler
>(/*Comment=*/"#");
829 if (FilesType
== "o")
830 return CreateObjectFileHandler(FirstInput
, BundlerConfig
);
831 if (FilesType
== "a")
832 return CreateObjectFileHandler(FirstInput
, BundlerConfig
);
833 if (FilesType
== "gch")
834 return std::make_unique
<BinaryFileHandler
>(BundlerConfig
);
835 if (FilesType
== "ast")
836 return std::make_unique
<BinaryFileHandler
>(BundlerConfig
);
838 return createStringError(errc::invalid_argument
,
839 "'" + FilesType
+ "': invalid file type specified");
842 // List bundle IDs. Return true if an error was found.
843 Error
OffloadBundler::ListBundleIDsInFile(StringRef InputFileName
,
844 const OffloadBundlerConfig
&BundlerConfig
) {
846 ErrorOr
<std::unique_ptr
<MemoryBuffer
>> CodeOrErr
=
847 MemoryBuffer::getFileOrSTDIN(InputFileName
);
848 if (std::error_code EC
= CodeOrErr
.getError())
849 return createFileError(InputFileName
, EC
);
851 MemoryBuffer
&Input
= **CodeOrErr
;
853 // Select the right files handler.
854 Expected
<std::unique_ptr
<FileHandler
>> FileHandlerOrErr
=
855 CreateFileHandler(Input
, BundlerConfig
);
856 if (!FileHandlerOrErr
)
857 return FileHandlerOrErr
.takeError();
859 std::unique_ptr
<FileHandler
> &FH
= *FileHandlerOrErr
;
861 return FH
->listBundleIDs(Input
);
864 /// Bundle the files. Return true if an error was found.
865 Error
OffloadBundler::BundleFiles() {
868 // Create output file.
869 raw_fd_ostream
OutputFile(BundlerConfig
.OutputFileNames
.front(),
870 EC
, sys::fs::OF_None
);
872 return createFileError(BundlerConfig
.OutputFileNames
.front(), EC
);
875 SmallVector
<std::unique_ptr
<MemoryBuffer
>, 8u> InputBuffers
;
876 InputBuffers
.reserve(BundlerConfig
.InputFileNames
.size());
877 for (auto &I
: BundlerConfig
.InputFileNames
) {
878 ErrorOr
<std::unique_ptr
<MemoryBuffer
>> CodeOrErr
=
879 MemoryBuffer::getFileOrSTDIN(I
);
880 if (std::error_code EC
= CodeOrErr
.getError())
881 return createFileError(I
, EC
);
882 InputBuffers
.emplace_back(std::move(*CodeOrErr
));
885 // Get the file handler. We use the host buffer as reference.
886 assert((BundlerConfig
.HostInputIndex
!= ~0u || BundlerConfig
.AllowNoHost
) &&
887 "Host input index undefined??");
888 Expected
<std::unique_ptr
<FileHandler
>> FileHandlerOrErr
=
889 CreateFileHandler(*InputBuffers
[BundlerConfig
.AllowNoHost
? 0
890 : BundlerConfig
.HostInputIndex
],
892 if (!FileHandlerOrErr
)
893 return FileHandlerOrErr
.takeError();
895 std::unique_ptr
<FileHandler
> &FH
= *FileHandlerOrErr
;
899 if (Error Err
= FH
->WriteHeader(OutputFile
, InputBuffers
))
902 // Write all bundles along with the start/end markers. If an error was found
903 // writing the end of the bundle component, abort the bundle writing.
904 auto Input
= InputBuffers
.begin();
905 for (auto &Triple
: BundlerConfig
.TargetNames
) {
906 if (Error Err
= FH
->WriteBundleStart(OutputFile
, Triple
))
908 if (Error Err
= FH
->WriteBundle(OutputFile
, **Input
))
910 if (Error Err
= FH
->WriteBundleEnd(OutputFile
, Triple
))
914 return Error::success();
917 // Unbundle the files. Return true if an error was found.
918 Error
OffloadBundler::UnbundleFiles() {
920 ErrorOr
<std::unique_ptr
<MemoryBuffer
>> CodeOrErr
=
921 MemoryBuffer::getFileOrSTDIN(BundlerConfig
.InputFileNames
.front());
922 if (std::error_code EC
= CodeOrErr
.getError())
923 return createFileError(BundlerConfig
.InputFileNames
.front(), EC
);
925 MemoryBuffer
&Input
= **CodeOrErr
;
927 // Select the right files handler.
928 Expected
<std::unique_ptr
<FileHandler
>> FileHandlerOrErr
=
929 CreateFileHandler(Input
, BundlerConfig
);
930 if (!FileHandlerOrErr
)
931 return FileHandlerOrErr
.takeError();
933 std::unique_ptr
<FileHandler
> &FH
= *FileHandlerOrErr
;
936 // Read the header of the bundled file.
937 if (Error Err
= FH
->ReadHeader(Input
))
940 // Create a work list that consist of the map triple/output file.
941 StringMap
<StringRef
> Worklist
;
942 auto Output
= BundlerConfig
.OutputFileNames
.begin();
943 for (auto &Triple
: BundlerConfig
.TargetNames
) {
944 Worklist
[Triple
] = *Output
;
948 // Read all the bundles that are in the work list. If we find no bundles we
949 // assume the file is meant for the host target.
950 bool FoundHostBundle
= false;
951 while (!Worklist
.empty()) {
952 Expected
<Optional
<StringRef
>> CurTripleOrErr
= FH
->ReadBundleStart(Input
);
954 return CurTripleOrErr
.takeError();
956 // We don't have more bundles.
957 if (!*CurTripleOrErr
)
960 StringRef CurTriple
= **CurTripleOrErr
;
961 assert(!CurTriple
.empty());
963 auto Output
= Worklist
.find(CurTriple
);
964 // The file may have more bundles for other targets, that we don't care
965 // about. Therefore, move on to the next triple
966 if (Output
== Worklist
.end())
969 // Check if the output file can be opened and copy the bundle to it.
971 raw_fd_ostream
OutputFile(Output
->second
, EC
, sys::fs::OF_None
);
973 return createFileError(Output
->second
, EC
);
974 if (Error Err
= FH
->ReadBundle(OutputFile
, Input
))
976 if (Error Err
= FH
->ReadBundleEnd(Input
))
978 Worklist
.erase(Output
);
980 // Record if we found the host bundle.
981 auto OffloadInfo
= OffloadTargetInfo(CurTriple
, BundlerConfig
);
982 if (OffloadInfo
.hasHostKind())
983 FoundHostBundle
= true;
986 if (!BundlerConfig
.AllowMissingBundles
&& !Worklist
.empty()) {
987 std::string ErrMsg
= "Can't find bundles for";
988 std::set
<StringRef
> Sorted
;
989 for (auto &E
: Worklist
)
990 Sorted
.insert(E
.first());
992 unsigned Last
= Sorted
.size() - 1;
993 for (auto &E
: Sorted
) {
994 if (I
!= 0 && Last
> 1)
997 if (I
== Last
&& I
!= 0)
1002 return createStringError(inconvertibleErrorCode(), ErrMsg
);
1005 // If no bundles were found, assume the input file is the host bundle and
1006 // create empty files for the remaining targets.
1007 if (Worklist
.size() == BundlerConfig
.TargetNames
.size()) {
1008 for (auto &E
: Worklist
) {
1010 raw_fd_ostream
OutputFile(E
.second
, EC
, sys::fs::OF_None
);
1012 return createFileError(E
.second
, EC
);
1014 // If this entry has a host kind, copy the input file to the output file.
1015 auto OffloadInfo
= OffloadTargetInfo(E
.getKey(), BundlerConfig
);
1016 if (OffloadInfo
.hasHostKind())
1017 OutputFile
.write(Input
.getBufferStart(), Input
.getBufferSize());
1019 return Error::success();
1022 // If we found elements, we emit an error if none of those were for the host
1023 // in case host bundle name was provided in command line.
1024 if (!FoundHostBundle
&& BundlerConfig
.HostInputIndex
!= ~0u)
1025 return createStringError(inconvertibleErrorCode(),
1026 "Can't find bundle for the host target");
1028 // If we still have any elements in the worklist, create empty files for them.
1029 for (auto &E
: Worklist
) {
1031 raw_fd_ostream
OutputFile(E
.second
, EC
, sys::fs::OF_None
);
1033 return createFileError(E
.second
, EC
);
1036 return Error::success();
1039 static Archive::Kind
getDefaultArchiveKindForHost() {
1040 return Triple(sys::getDefaultTargetTriple()).isOSDarwin() ? Archive::K_DARWIN
1044 /// @brief Checks if a code object \p CodeObjectInfo is compatible with a given
1045 /// target \p TargetInfo.
1046 /// @link https://clang.llvm.org/docs/ClangOffloadBundler.html#bundle-entry-id
1047 bool isCodeObjectCompatible(OffloadTargetInfo
&CodeObjectInfo
,
1048 OffloadTargetInfo
&TargetInfo
) {
1050 // Compatible in case of exact match.
1051 if (CodeObjectInfo
== TargetInfo
) {
1052 DEBUG_WITH_TYPE("CodeObjectCompatibility",
1053 dbgs() << "Compatible: Exact match: \t[CodeObject: "
1054 << CodeObjectInfo
.str()
1055 << "]\t:\t[Target: " << TargetInfo
.str() << "]\n");
1059 // Incompatible if Kinds or Triples mismatch.
1060 if (!CodeObjectInfo
.isOffloadKindCompatible(TargetInfo
.OffloadKind
) ||
1061 !CodeObjectInfo
.Triple
.isCompatibleWith(TargetInfo
.Triple
)) {
1063 "CodeObjectCompatibility",
1064 dbgs() << "Incompatible: Kind/Triple mismatch \t[CodeObject: "
1065 << CodeObjectInfo
.str() << "]\t:\t[Target: " << TargetInfo
.str()
1070 // Incompatible if GPUArch mismatch.
1071 if (CodeObjectInfo
.GPUArch
!= TargetInfo
.GPUArch
) {
1072 DEBUG_WITH_TYPE("CodeObjectCompatibility",
1073 dbgs() << "Incompatible: GPU Arch mismatch \t[CodeObject: "
1074 << CodeObjectInfo
.str()
1075 << "]\t:\t[Target: " << TargetInfo
.str() << "]\n");
1080 "CodeObjectCompatibility",
1081 dbgs() << "Compatible: Code Objects are compatible \t[CodeObject: "
1082 << CodeObjectInfo
.str() << "]\t:\t[Target: " << TargetInfo
.str()
1087 /// @brief Computes a list of targets among all given targets which are
1088 /// compatible with this code object
1089 /// @param [in] CodeObjectInfo Code Object
1090 /// @param [out] CompatibleTargets List of all compatible targets among all
1092 /// @return false, if no compatible target is found.
1094 getCompatibleOffloadTargets(OffloadTargetInfo
&CodeObjectInfo
,
1095 SmallVectorImpl
<StringRef
> &CompatibleTargets
,
1096 const OffloadBundlerConfig
&BundlerConfig
) {
1097 if (!CompatibleTargets
.empty()) {
1098 DEBUG_WITH_TYPE("CodeObjectCompatibility",
1099 dbgs() << "CompatibleTargets list should be empty\n");
1102 for (auto &Target
: BundlerConfig
.TargetNames
) {
1103 auto TargetInfo
= OffloadTargetInfo(Target
, BundlerConfig
);
1104 if (isCodeObjectCompatible(CodeObjectInfo
, TargetInfo
))
1105 CompatibleTargets
.push_back(Target
);
1107 return !CompatibleTargets
.empty();
1110 /// UnbundleArchive takes an archive file (".a") as input containing bundled
1111 /// code object files, and a list of offload targets (not host), and extracts
1112 /// the code objects into a new archive file for each offload target. Each
1113 /// resulting archive file contains all code object files corresponding to that
1114 /// particular offload target. The created archive file does not
1115 /// contain an index of the symbols and code object files are named as
1116 /// <<Parent Bundle Name>-<CodeObject's GPUArch>>, with ':' replaced with '_'.
1117 Error
OffloadBundler::UnbundleArchive() {
1118 std::vector
<std::unique_ptr
<MemoryBuffer
>> ArchiveBuffers
;
1120 /// Map of target names with list of object files that will form the device
1121 /// specific archive for that target
1122 StringMap
<std::vector
<NewArchiveMember
>> OutputArchivesMap
;
1124 // Map of target names and output archive filenames
1125 StringMap
<StringRef
> TargetOutputFileNameMap
;
1127 auto Output
= BundlerConfig
.OutputFileNames
.begin();
1128 for (auto &Target
: BundlerConfig
.TargetNames
) {
1129 TargetOutputFileNameMap
[Target
] = *Output
;
1133 StringRef IFName
= BundlerConfig
.InputFileNames
.front();
1135 ErrorOr
<std::unique_ptr
<MemoryBuffer
>> BufOrErr
=
1136 MemoryBuffer::getFileOrSTDIN(IFName
, true, false);
1137 if (std::error_code EC
= BufOrErr
.getError())
1138 return createFileError(BundlerConfig
.InputFileNames
.front(), EC
);
1140 ArchiveBuffers
.push_back(std::move(*BufOrErr
));
1141 Expected
<std::unique_ptr
<llvm::object::Archive
>> LibOrErr
=
1142 Archive::create(ArchiveBuffers
.back()->getMemBufferRef());
1144 return LibOrErr
.takeError();
1146 auto Archive
= std::move(*LibOrErr
);
1148 Error ArchiveErr
= Error::success();
1149 auto ChildEnd
= Archive
->child_end();
1151 /// Iterate over all bundled code object files in the input archive.
1152 for (auto ArchiveIter
= Archive
->child_begin(ArchiveErr
);
1153 ArchiveIter
!= ChildEnd
; ++ArchiveIter
) {
1156 auto ArchiveChildNameOrErr
= (*ArchiveIter
).getName();
1157 if (!ArchiveChildNameOrErr
)
1158 return ArchiveChildNameOrErr
.takeError();
1160 StringRef BundledObjectFile
= sys::path::filename(*ArchiveChildNameOrErr
);
1162 auto CodeObjectBufferRefOrErr
= (*ArchiveIter
).getMemoryBufferRef();
1163 if (!CodeObjectBufferRefOrErr
)
1164 return CodeObjectBufferRefOrErr
.takeError();
1166 auto CodeObjectBuffer
=
1167 MemoryBuffer::getMemBuffer(*CodeObjectBufferRefOrErr
, false);
1169 Expected
<std::unique_ptr
<FileHandler
>> FileHandlerOrErr
=
1170 CreateFileHandler(*CodeObjectBuffer
, BundlerConfig
);
1171 if (!FileHandlerOrErr
)
1172 return FileHandlerOrErr
.takeError();
1174 std::unique_ptr
<FileHandler
> &FileHandler
= *FileHandlerOrErr
;
1175 assert(FileHandler
&&
1176 "FileHandle creation failed for file in the archive!");
1178 if (Error ReadErr
= FileHandler
.get()->ReadHeader(*CodeObjectBuffer
))
1181 Expected
<Optional
<StringRef
>> CurBundleIDOrErr
=
1182 FileHandler
->ReadBundleStart(*CodeObjectBuffer
);
1183 if (!CurBundleIDOrErr
)
1184 return CurBundleIDOrErr
.takeError();
1186 Optional
<StringRef
> OptionalCurBundleID
= *CurBundleIDOrErr
;
1187 // No device code in this child, skip.
1188 if (!OptionalCurBundleID
)
1190 StringRef CodeObject
= *OptionalCurBundleID
;
1192 // Process all bundle entries (CodeObjects) found in this child of input
1194 while (!CodeObject
.empty()) {
1195 SmallVector
<StringRef
> CompatibleTargets
;
1196 auto CodeObjectInfo
= OffloadTargetInfo(CodeObject
, BundlerConfig
);
1197 if (CodeObjectInfo
.hasHostKind()) {
1198 // Do nothing, we don't extract host code yet.
1199 } else if (getCompatibleOffloadTargets(CodeObjectInfo
,
1202 std::string BundleData
;
1203 raw_string_ostream
DataStream(BundleData
);
1205 FileHandler
.get()->ReadBundle(DataStream
, *CodeObjectBuffer
))
1208 for (auto &CompatibleTarget
: CompatibleTargets
) {
1209 SmallString
<128> BundledObjectFileName
;
1210 BundledObjectFileName
.assign(BundledObjectFile
);
1211 auto OutputBundleName
=
1212 Twine(llvm::sys::path::stem(BundledObjectFileName
) + "-" +
1214 getDeviceLibraryFileName(BundledObjectFileName
,
1215 CodeObjectInfo
.GPUArch
))
1217 // Replace ':' in optional target feature list with '_' to ensure
1218 // cross-platform validity.
1219 std::replace(OutputBundleName
.begin(), OutputBundleName
.end(), ':',
1222 std::unique_ptr
<MemoryBuffer
> MemBuf
= MemoryBuffer::getMemBufferCopy(
1223 DataStream
.str(), OutputBundleName
);
1224 ArchiveBuffers
.push_back(std::move(MemBuf
));
1225 llvm::MemoryBufferRef MemBufRef
=
1226 MemoryBufferRef(*(ArchiveBuffers
.back()));
1228 // For inserting <CompatibleTarget, list<CodeObject>> entry in
1229 // OutputArchivesMap.
1230 if (OutputArchivesMap
.find(CompatibleTarget
) ==
1231 OutputArchivesMap
.end()) {
1233 std::vector
<NewArchiveMember
> ArchiveMembers
;
1234 ArchiveMembers
.push_back(NewArchiveMember(MemBufRef
));
1235 OutputArchivesMap
.insert_or_assign(CompatibleTarget
,
1236 std::move(ArchiveMembers
));
1238 OutputArchivesMap
[CompatibleTarget
].push_back(
1239 NewArchiveMember(MemBufRef
));
1244 if (Error Err
= FileHandler
.get()->ReadBundleEnd(*CodeObjectBuffer
))
1247 Expected
<Optional
<StringRef
>> NextTripleOrErr
=
1248 FileHandler
->ReadBundleStart(*CodeObjectBuffer
);
1249 if (!NextTripleOrErr
)
1250 return NextTripleOrErr
.takeError();
1252 CodeObject
= ((*NextTripleOrErr
).has_value()) ? **NextTripleOrErr
: "";
1253 } // End of processing of all bundle entries of this child of input archive.
1254 } // End of while over children of input archive.
1256 assert(!ArchiveErr
&& "Error occurred while reading archive!");
1258 /// Write out an archive for each target
1259 for (auto &Target
: BundlerConfig
.TargetNames
) {
1260 StringRef FileName
= TargetOutputFileNameMap
[Target
];
1261 StringMapIterator
<std::vector
<llvm::NewArchiveMember
>> CurArchiveMembers
=
1262 OutputArchivesMap
.find(Target
);
1263 if (CurArchiveMembers
!= OutputArchivesMap
.end()) {
1264 if (Error WriteErr
= writeArchive(FileName
, CurArchiveMembers
->getValue(),
1265 true, getDefaultArchiveKindForHost(),
1266 true, false, nullptr))
1268 } else if (!BundlerConfig
.AllowMissingBundles
) {
1269 std::string ErrMsg
=
1270 Twine("no compatible code object found for the target '" + Target
+
1271 "' in heterogeneous archive library: " + IFName
)
1273 return createStringError(inconvertibleErrorCode(), ErrMsg
);
1274 } else { // Create an empty archive file if no compatible code object is
1275 // found and "allow-missing-bundles" is enabled. It ensures that
1276 // the linker using output of this step doesn't complain about
1277 // the missing input file.
1278 std::vector
<llvm::NewArchiveMember
> EmptyArchive
;
1279 EmptyArchive
.clear();
1280 if (Error WriteErr
= writeArchive(FileName
, EmptyArchive
, true,
1281 getDefaultArchiveKindForHost(), true,
1287 return Error::success();