[docs] Fix build-docs.sh
[llvm-project.git] / clang / lib / Driver / OffloadBundler.cpp
blob4a87942934ff9310eefa08b933551198ff4699d1
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/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"
45 #include <algorithm>
46 #include <cassert>
47 #include <cstddef>
48 #include <cstdint>
49 #include <forward_list>
50 #include <memory>
51 #include <set>
52 #include <string>
53 #include <system_error>
54 #include <utility>
56 using namespace llvm;
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)
65 : BundlerConfig(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));
77 } else {
78 auto KindTriple = TargetFeatures.first.split('-');
79 this->OffloadKind = KindTriple.first;
80 this->Triple = llvm::Triple(KindTriple.second);
81 this->GPUArch = "";
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)
97 return true;
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;
107 return false;
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"))
127 return ".bc";
128 if (Device.contains("sm_"))
129 return ".cubin";
130 return sys::path::extension(BundleFileName);
133 static std::string getDeviceLibraryFileName(StringRef BundleFileName,
134 StringRef Device) {
135 StringRef LibName = sys::path::stem(BundleFileName);
136 StringRef Extension = getDeviceFileExtension(Device, BundleFileName);
138 std::string Result;
139 Result += LibName;
140 Result += Extension;
141 return Result;
144 /// Generic file handler interface.
145 class FileHandler {
146 public:
147 struct BundleInfo {
148 StringRef BundleID;
151 FileHandler() {}
153 virtual ~FileHandler() {}
155 /// Update the file handler with information from the header of the bundled
156 /// file.
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
177 /// \a OS.
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
182 /// OS.
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))
191 return Err;
192 return forEachBundle(Input, [&](const BundleInfo &Info) -> Error {
193 llvm::outs() << Info.BundleID << '\n';
194 Error Err = listBundleIDsCallback(Input, Info);
195 if (Err)
196 return Err;
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) {
204 while (true) {
205 Expected<Optional<StringRef>> CurTripleOrErr = ReadBundleStart(Input);
206 if (!CurTripleOrErr)
207 return CurTripleOrErr.takeError();
209 // No more bundles.
210 if (!*CurTripleOrErr)
211 break;
213 StringRef CurTriple = **CurTripleOrErr;
214 assert(!CurTriple.empty());
216 BundleInfo Info{CurTriple};
217 if (Error Err = Func(Info))
218 return Err;
220 return Error::success();
223 protected:
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)
242 /// ...
244 /// OffsetOfBundleN (8-byte integer)
245 /// SizeOfBundleN (8-byte integer)
246 /// NumberOfBytesInTripleOfBundleN (8-byte integer)
247 /// TripleOfBundleN (byte length defined before)
249 /// Bundle1
250 /// ...
251 /// BundleN
253 /// Read 8-byte integers from a buffer in little-endian format.
254 static uint64_t Read8byteIntegerFromBuffer(StringRef Buffer, size_t pos) {
255 uint64_t Res = 0;
256 const char *Data = Buffer.data();
258 for (unsigned i = 0; i < 8; ++i) {
259 Res <<= 8;
260 uint64_t Char = (uint64_t)Data[pos + 7 - i];
261 Res |= 0xffu & Char;
263 return Res;
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);
270 OS.write(&Char, 1);
271 Val >>= 8;
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.
279 uint64_t Size = 0u;
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;
301 public:
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);
328 ReadChars += 8;
330 // Read bundle offsets, sizes and triples.
331 for (uint64_t i = 0; i < NumberOfBundles; ++i) {
333 // Read offset.
334 if (ReadChars + 8 > FC.size())
335 return Error::success();
337 uint64_t Offset = Read8byteIntegerFromBuffer(FC, ReadChars);
338 ReadChars += 8;
340 // Read size.
341 if (ReadChars + 8 > FC.size())
342 return Error::success();
344 uint64_t Size = Read8byteIntegerFromBuffer(FC, ReadChars);
345 ReadChars += 8;
347 // Read triple size.
348 if (ReadChars + 8 > FC.size())
349 return Error::success();
351 uint64_t TripleSize = Read8byteIntegerFromBuffer(FC, ReadChars);
352 ReadChars += 8;
354 // Read triple.
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())
377 return None;
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());
414 unsigned Idx = 0;
415 for (auto &T : BundlerConfig.TargetNames) {
416 MemoryBuffer &MB = *Inputs[Idx++];
417 HeaderSize = alignTo(HeaderSize, BundlerConfig.BundleAlignment);
418 // Bundle offset.
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());
426 // Triple
427 OS << T;
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];
443 OS.seek(BI.Offset);
444 OS.write(Input.getBufferStart(), Input.getBufferSize());
445 return Error::success();
449 namespace {
451 // This class implements a list of temporary files that are removed upon
452 // object destruction.
453 class TempFileHandlerRAII {
454 public:
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);
468 if (Contents) {
469 std::error_code EC;
470 raw_fd_ostream OS(File, EC);
471 if (EC)
472 return createFileError(File, EC);
473 OS.write(Contents->data(), Contents->size());
475 return Files.front().str();
478 private:
479 std::forward_list<SmallString<128u>> Files;
482 } // end anonymous namespace
484 /// Handler for object files. The bundles are organized by sections with a
485 /// designated name.
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
497 /// section.
498 static Expected<Optional<StringRef>> IsOffloadSection(SectionRef CurSection) {
499 Expected<StringRef> NameOrErr = CurSection.getName();
500 if (!NameOrErr)
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))
505 return None;
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;
525 public:
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;
539 ++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);
545 if (!TripleOrErr)
546 return TripleOrErr.takeError();
547 if (*TripleOrErr)
548 return **TripleOrErr;
550 return None;
553 Error ReadBundleEnd(MemoryBuffer &Input) final { return Error::success(); }
555 Error ReadBundle(raw_ostream &OS, MemoryBuffer &Input) final {
556 Expected<StringRef> ContentOrErr = CurrentSection->getContents();
557 if (!ContentOrErr)
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
597 // shared library.
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.
604 OS.close();
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));
623 if (!TempFileOrErr)
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] +
631 "=" + InputFile));
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))
643 return Err;
645 return Error::success();
648 Error WriteBundle(raw_fd_ostream &OS, MemoryBuffer &Input) final {
649 return Error::success();
652 private:
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 << "\"";
660 errs() << "\n";
661 } else {
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"
673 /// Bundle 1
674 /// "Comment OFFLOAD_BUNDLER_MAGIC_STR__END__ triple"
675 /// ...
676 /// "Comment OFFLOAD_BUNDLER_MAGIC_STR__START__ triple"
677 /// Bundle N
678 /// "Comment OFFLOAD_BUNDLER_MAGIC_STR__END__ triple"
679 class TextFileHandler final : public FileHandler {
680 /// String that begins a line comment.
681 StringRef 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;
692 protected:
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)
701 return None;
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)
709 return None;
711 // Next time we read after the new line.
712 ++ReadChars;
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.
726 ++ReadChars;
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);
739 OS << Bundle;
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();
764 public:
765 TextFileHandler(StringRef Comment) : Comment(Comment), ReadChars(0) {
766 BundleStartString =
767 "\n" + Comment.str() + " " OFFLOAD_BUNDLER_MAGIC_STR "__START__ ";
768 BundleEndString =
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
777 // important.
778 ReadChars = Input.getBuffer().find(BundleEndString, ReadChars);
779 if (Error Err = ReadBundleEnd(Input))
780 return Err;
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())),
803 BundlerConfig);
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) {
844 // Open Input file.
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;
859 assert(FH);
860 return FH->listBundleIDs(Input);
863 /// Bundle the files. Return true if an error was found.
864 Error OffloadBundler::BundleFiles() {
865 std::error_code EC;
867 // Create output file.
868 raw_fd_ostream OutputFile(BundlerConfig.OutputFileNames.front(),
869 EC, sys::fs::OF_None);
870 if (EC)
871 return createFileError(BundlerConfig.OutputFileNames.front(), EC);
873 // Open input files.
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],
890 BundlerConfig);
891 if (!FileHandlerOrErr)
892 return FileHandlerOrErr.takeError();
894 std::unique_ptr<FileHandler> &FH = *FileHandlerOrErr;
895 assert(FH);
897 // Write header.
898 if (Error Err = FH->WriteHeader(OutputFile, InputBuffers))
899 return Err;
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))
906 return Err;
907 if (Error Err = FH->WriteBundle(OutputFile, **Input))
908 return Err;
909 if (Error Err = FH->WriteBundleEnd(OutputFile, Triple))
910 return Err;
911 ++Input;
913 return Error::success();
916 // Unbundle the files. Return true if an error was found.
917 Error OffloadBundler::UnbundleFiles() {
918 // Open Input file.
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;
933 assert(FH);
935 // Read the header of the bundled file.
936 if (Error Err = FH->ReadHeader(Input))
937 return Err;
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;
944 ++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);
952 if (!CurTripleOrErr)
953 return CurTripleOrErr.takeError();
955 // We don't have more bundles.
956 if (!*CurTripleOrErr)
957 break;
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())
966 continue;
968 // Check if the output file can be opened and copy the bundle to it.
969 std::error_code EC;
970 raw_fd_ostream OutputFile(Output->second, EC, sys::fs::OF_None);
971 if (EC)
972 return createFileError(Output->second, EC);
973 if (Error Err = FH->ReadBundle(OutputFile, Input))
974 return Err;
975 if (Error Err = FH->ReadBundleEnd(Input))
976 return Err;
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());
990 unsigned I = 0;
991 unsigned Last = Sorted.size() - 1;
992 for (auto &E : Sorted) {
993 if (I != 0 && Last > 1)
994 ErrMsg += ",";
995 ErrMsg += " ";
996 if (I == Last && I != 0)
997 ErrMsg += "and ";
998 ErrMsg += E.str();
999 ++I;
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) {
1008 std::error_code EC;
1009 raw_fd_ostream OutputFile(E.second, EC, sys::fs::OF_None);
1010 if (EC)
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) {
1029 std::error_code EC;
1030 raw_fd_ostream OutputFile(E.second, EC, sys::fs::OF_None);
1031 if (EC)
1032 return createFileError(E.second, EC);
1035 return Error::success();
1038 static Archive::Kind getDefaultArchiveKindForHost() {
1039 return Triple(sys::getDefaultTargetTriple()).isOSDarwin() ? Archive::K_DARWIN
1040 : Archive::K_GNU;
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");
1055 return true;
1058 // Incompatible if Kinds or Triples mismatch.
1059 if (!CodeObjectInfo.isOffloadKindCompatible(TargetInfo.OffloadKind) ||
1060 !CodeObjectInfo.Triple.isCompatibleWith(TargetInfo.Triple)) {
1061 DEBUG_WITH_TYPE(
1062 "CodeObjectCompatibility",
1063 dbgs() << "Incompatible: Kind/Triple mismatch \t[CodeObject: "
1064 << CodeObjectInfo.str() << "]\t:\t[Target: " << TargetInfo.str()
1065 << "]\n");
1066 return false;
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");
1075 return false;
1078 DEBUG_WITH_TYPE(
1079 "CodeObjectCompatibility",
1080 dbgs() << "Compatible: Code Objects are compatible \t[CodeObject: "
1081 << CodeObjectInfo.str() << "]\t:\t[Target: " << TargetInfo.str()
1082 << "]\n");
1083 return true;
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
1090 /// given targets
1091 /// @return false, if no compatible target is found.
1092 static bool
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");
1099 return false;
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;
1129 ++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());
1142 if (!LibOrErr)
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) {
1153 if (ArchiveErr)
1154 return ArchiveErr;
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))
1178 return ReadErr;
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)
1188 continue;
1189 StringRef CodeObject = *OptionalCurBundleID;
1191 // Process all bundle entries (CodeObjects) found in this child of input
1192 // archive.
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,
1199 CompatibleTargets,
1200 BundlerConfig)) {
1201 std::string BundleData;
1202 raw_string_ostream DataStream(BundleData);
1203 if (Error Err =
1204 FileHandler.get()->ReadBundle(DataStream, *CodeObjectBuffer))
1205 return Err;
1207 for (auto &CompatibleTarget : CompatibleTargets) {
1208 SmallString<128> BundledObjectFileName;
1209 BundledObjectFileName.assign(BundledObjectFile);
1210 auto OutputBundleName =
1211 Twine(llvm::sys::path::stem(BundledObjectFileName) + "-" +
1212 CodeObject +
1213 getDeviceLibraryFileName(BundledObjectFileName,
1214 CodeObjectInfo.GPUArch))
1215 .str();
1216 // Replace ':' in optional target feature list with '_' to ensure
1217 // cross-platform validity.
1218 std::replace(OutputBundleName.begin(), OutputBundleName.end(), ':',
1219 '_');
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));
1236 } else {
1237 OutputArchivesMap[CompatibleTarget].push_back(
1238 NewArchiveMember(MemBufRef));
1243 if (Error Err = FileHandler.get()->ReadBundleEnd(*CodeObjectBuffer))
1244 return Err;
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))
1266 return WriteErr;
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)
1271 .str();
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,
1281 false, nullptr))
1282 return WriteErr;
1286 return Error::success();