[docs] Add LICENSE.txt to the root of the mono-repo
[llvm-project.git] / clang / lib / Driver / OffloadBundler.cpp
blob4a73d2c02120981c69a35082ec0cb544fc335536
1 //===- OffloadBundler.cpp - File Bundling and Unbundling ------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 ///
9 /// \file
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.
14 ///
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"
46 #include <algorithm>
47 #include <cassert>
48 #include <cstddef>
49 #include <cstdint>
50 #include <forward_list>
51 #include <memory>
52 #include <set>
53 #include <string>
54 #include <system_error>
55 #include <utility>
57 using namespace llvm;
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)
66 : BundlerConfig(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));
78 } else {
79 auto KindTriple = TargetFeatures.first.split('-');
80 this->OffloadKind = KindTriple.first;
81 this->Triple = llvm::Triple(KindTriple.second);
82 this->GPUArch = "";
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)
98 return true;
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;
108 return false;
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"))
128 return ".bc";
129 if (Device.contains("sm_"))
130 return ".cubin";
131 return sys::path::extension(BundleFileName);
134 static std::string getDeviceLibraryFileName(StringRef BundleFileName,
135 StringRef Device) {
136 StringRef LibName = sys::path::stem(BundleFileName);
137 StringRef Extension = getDeviceFileExtension(Device, BundleFileName);
139 std::string Result;
140 Result += LibName;
141 Result += Extension;
142 return Result;
145 /// Generic file handler interface.
146 class FileHandler {
147 public:
148 struct BundleInfo {
149 StringRef BundleID;
152 FileHandler() {}
154 virtual ~FileHandler() {}
156 /// Update the file handler with information from the header of the bundled
157 /// file.
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
178 /// \a OS.
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
183 /// OS.
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))
192 return Err;
193 return forEachBundle(Input, [&](const BundleInfo &Info) -> Error {
194 llvm::outs() << Info.BundleID << '\n';
195 Error Err = listBundleIDsCallback(Input, Info);
196 if (Err)
197 return Err;
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) {
205 while (true) {
206 Expected<Optional<StringRef>> CurTripleOrErr = ReadBundleStart(Input);
207 if (!CurTripleOrErr)
208 return CurTripleOrErr.takeError();
210 // No more bundles.
211 if (!*CurTripleOrErr)
212 break;
214 StringRef CurTriple = **CurTripleOrErr;
215 assert(!CurTriple.empty());
217 BundleInfo Info{CurTriple};
218 if (Error Err = Func(Info))
219 return Err;
221 return Error::success();
224 protected:
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)
243 /// ...
245 /// OffsetOfBundleN (8-byte integer)
246 /// SizeOfBundleN (8-byte integer)
247 /// NumberOfBytesInTripleOfBundleN (8-byte integer)
248 /// TripleOfBundleN (byte length defined before)
250 /// Bundle1
251 /// ...
252 /// BundleN
254 /// Read 8-byte integers from a buffer in little-endian format.
255 static uint64_t Read8byteIntegerFromBuffer(StringRef Buffer, size_t pos) {
256 uint64_t Res = 0;
257 const char *Data = Buffer.data();
259 for (unsigned i = 0; i < 8; ++i) {
260 Res <<= 8;
261 uint64_t Char = (uint64_t)Data[pos + 7 - i];
262 Res |= 0xffu & Char;
264 return Res;
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);
271 OS.write(&Char, 1);
272 Val >>= 8;
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.
280 uint64_t Size = 0u;
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;
302 public:
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);
329 ReadChars += 8;
331 // Read bundle offsets, sizes and triples.
332 for (uint64_t i = 0; i < NumberOfBundles; ++i) {
334 // Read offset.
335 if (ReadChars + 8 > FC.size())
336 return Error::success();
338 uint64_t Offset = Read8byteIntegerFromBuffer(FC, ReadChars);
339 ReadChars += 8;
341 // Read size.
342 if (ReadChars + 8 > FC.size())
343 return Error::success();
345 uint64_t Size = Read8byteIntegerFromBuffer(FC, ReadChars);
346 ReadChars += 8;
348 // Read triple size.
349 if (ReadChars + 8 > FC.size())
350 return Error::success();
352 uint64_t TripleSize = Read8byteIntegerFromBuffer(FC, ReadChars);
353 ReadChars += 8;
355 // Read triple.
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())
378 return None;
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());
415 unsigned Idx = 0;
416 for (auto &T : BundlerConfig.TargetNames) {
417 MemoryBuffer &MB = *Inputs[Idx++];
418 HeaderSize = alignTo(HeaderSize, BundlerConfig.BundleAlignment);
419 // Bundle offset.
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());
427 // Triple
428 OS << T;
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];
444 OS.seek(BI.Offset);
445 OS.write(Input.getBufferStart(), Input.getBufferSize());
446 return Error::success();
450 namespace {
452 // This class implements a list of temporary files that are removed upon
453 // object destruction.
454 class TempFileHandlerRAII {
455 public:
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);
469 if (Contents) {
470 std::error_code EC;
471 raw_fd_ostream OS(File, EC);
472 if (EC)
473 return createFileError(File, EC);
474 OS.write(Contents->data(), Contents->size());
476 return Files.front().str();
479 private:
480 std::forward_list<SmallString<128u>> Files;
483 } // end anonymous namespace
485 /// Handler for object files. The bundles are organized by sections with a
486 /// designated name.
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
498 /// section.
499 static Expected<Optional<StringRef>> IsOffloadSection(SectionRef CurSection) {
500 Expected<StringRef> NameOrErr = CurSection.getName();
501 if (!NameOrErr)
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))
506 return None;
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;
526 public:
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;
540 ++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);
546 if (!TripleOrErr)
547 return TripleOrErr.takeError();
548 if (*TripleOrErr)
549 return **TripleOrErr;
551 return None;
554 Error ReadBundleEnd(MemoryBuffer &Input) final { return Error::success(); }
556 Error ReadBundle(raw_ostream &OS, MemoryBuffer &Input) final {
557 Expected<StringRef> ContentOrErr = CurrentSection->getContents();
558 if (!ContentOrErr)
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
598 // shared library.
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.
605 OS.close();
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));
624 if (!TempFileOrErr)
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] +
632 "=" + InputFile));
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))
644 return Err;
646 return Error::success();
649 Error WriteBundle(raw_fd_ostream &OS, MemoryBuffer &Input) final {
650 return Error::success();
653 private:
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 << "\"";
661 errs() << "\n";
662 } else {
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"
674 /// Bundle 1
675 /// "Comment OFFLOAD_BUNDLER_MAGIC_STR__END__ triple"
676 /// ...
677 /// "Comment OFFLOAD_BUNDLER_MAGIC_STR__START__ triple"
678 /// Bundle N
679 /// "Comment OFFLOAD_BUNDLER_MAGIC_STR__END__ triple"
680 class TextFileHandler final : public FileHandler {
681 /// String that begins a line comment.
682 StringRef 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;
693 protected:
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)
702 return None;
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)
710 return None;
712 // Next time we read after the new line.
713 ++ReadChars;
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.
727 ++ReadChars;
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);
740 OS << Bundle;
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();
765 public:
766 TextFileHandler(StringRef Comment) : Comment(Comment), ReadChars(0) {
767 BundleStartString =
768 "\n" + Comment.str() + " " OFFLOAD_BUNDLER_MAGIC_STR "__START__ ";
769 BundleEndString =
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
778 // important.
779 ReadChars = Input.getBuffer().find(BundleEndString, ReadChars);
780 if (Error Err = ReadBundleEnd(Input))
781 return Err;
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())),
804 BundlerConfig);
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) {
845 // Open Input file.
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;
860 assert(FH);
861 return FH->listBundleIDs(Input);
864 /// Bundle the files. Return true if an error was found.
865 Error OffloadBundler::BundleFiles() {
866 std::error_code EC;
868 // Create output file.
869 raw_fd_ostream OutputFile(BundlerConfig.OutputFileNames.front(),
870 EC, sys::fs::OF_None);
871 if (EC)
872 return createFileError(BundlerConfig.OutputFileNames.front(), EC);
874 // Open input files.
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],
891 BundlerConfig);
892 if (!FileHandlerOrErr)
893 return FileHandlerOrErr.takeError();
895 std::unique_ptr<FileHandler> &FH = *FileHandlerOrErr;
896 assert(FH);
898 // Write header.
899 if (Error Err = FH->WriteHeader(OutputFile, InputBuffers))
900 return Err;
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))
907 return Err;
908 if (Error Err = FH->WriteBundle(OutputFile, **Input))
909 return Err;
910 if (Error Err = FH->WriteBundleEnd(OutputFile, Triple))
911 return Err;
912 ++Input;
914 return Error::success();
917 // Unbundle the files. Return true if an error was found.
918 Error OffloadBundler::UnbundleFiles() {
919 // Open Input file.
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;
934 assert(FH);
936 // Read the header of the bundled file.
937 if (Error Err = FH->ReadHeader(Input))
938 return Err;
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;
945 ++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);
953 if (!CurTripleOrErr)
954 return CurTripleOrErr.takeError();
956 // We don't have more bundles.
957 if (!*CurTripleOrErr)
958 break;
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())
967 continue;
969 // Check if the output file can be opened and copy the bundle to it.
970 std::error_code EC;
971 raw_fd_ostream OutputFile(Output->second, EC, sys::fs::OF_None);
972 if (EC)
973 return createFileError(Output->second, EC);
974 if (Error Err = FH->ReadBundle(OutputFile, Input))
975 return Err;
976 if (Error Err = FH->ReadBundleEnd(Input))
977 return Err;
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());
991 unsigned I = 0;
992 unsigned Last = Sorted.size() - 1;
993 for (auto &E : Sorted) {
994 if (I != 0 && Last > 1)
995 ErrMsg += ",";
996 ErrMsg += " ";
997 if (I == Last && I != 0)
998 ErrMsg += "and ";
999 ErrMsg += E.str();
1000 ++I;
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) {
1009 std::error_code EC;
1010 raw_fd_ostream OutputFile(E.second, EC, sys::fs::OF_None);
1011 if (EC)
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) {
1030 std::error_code EC;
1031 raw_fd_ostream OutputFile(E.second, EC, sys::fs::OF_None);
1032 if (EC)
1033 return createFileError(E.second, EC);
1036 return Error::success();
1039 static Archive::Kind getDefaultArchiveKindForHost() {
1040 return Triple(sys::getDefaultTargetTriple()).isOSDarwin() ? Archive::K_DARWIN
1041 : Archive::K_GNU;
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");
1056 return true;
1059 // Incompatible if Kinds or Triples mismatch.
1060 if (!CodeObjectInfo.isOffloadKindCompatible(TargetInfo.OffloadKind) ||
1061 !CodeObjectInfo.Triple.isCompatibleWith(TargetInfo.Triple)) {
1062 DEBUG_WITH_TYPE(
1063 "CodeObjectCompatibility",
1064 dbgs() << "Incompatible: Kind/Triple mismatch \t[CodeObject: "
1065 << CodeObjectInfo.str() << "]\t:\t[Target: " << TargetInfo.str()
1066 << "]\n");
1067 return false;
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");
1076 return false;
1079 DEBUG_WITH_TYPE(
1080 "CodeObjectCompatibility",
1081 dbgs() << "Compatible: Code Objects are compatible \t[CodeObject: "
1082 << CodeObjectInfo.str() << "]\t:\t[Target: " << TargetInfo.str()
1083 << "]\n");
1084 return true;
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
1091 /// given targets
1092 /// @return false, if no compatible target is found.
1093 static bool
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");
1100 return false;
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;
1130 ++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());
1143 if (!LibOrErr)
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) {
1154 if (ArchiveErr)
1155 return ArchiveErr;
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))
1179 return ReadErr;
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)
1189 continue;
1190 StringRef CodeObject = *OptionalCurBundleID;
1192 // Process all bundle entries (CodeObjects) found in this child of input
1193 // archive.
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,
1200 CompatibleTargets,
1201 BundlerConfig)) {
1202 std::string BundleData;
1203 raw_string_ostream DataStream(BundleData);
1204 if (Error Err =
1205 FileHandler.get()->ReadBundle(DataStream, *CodeObjectBuffer))
1206 return Err;
1208 for (auto &CompatibleTarget : CompatibleTargets) {
1209 SmallString<128> BundledObjectFileName;
1210 BundledObjectFileName.assign(BundledObjectFile);
1211 auto OutputBundleName =
1212 Twine(llvm::sys::path::stem(BundledObjectFileName) + "-" +
1213 CodeObject +
1214 getDeviceLibraryFileName(BundledObjectFileName,
1215 CodeObjectInfo.GPUArch))
1216 .str();
1217 // Replace ':' in optional target feature list with '_' to ensure
1218 // cross-platform validity.
1219 std::replace(OutputBundleName.begin(), OutputBundleName.end(), ':',
1220 '_');
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));
1237 } else {
1238 OutputArchivesMap[CompatibleTarget].push_back(
1239 NewArchiveMember(MemBufRef));
1244 if (Error Err = FileHandler.get()->ReadBundleEnd(*CodeObjectBuffer))
1245 return Err;
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))
1267 return WriteErr;
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)
1272 .str();
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,
1282 false, nullptr))
1283 return WriteErr;
1287 return Error::success();