1 //===-- clang-offload-bundler/ClangOffloadBundler.cpp ---------------------===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
11 /// This file implements a clang-offload-bundler that bundles different
12 /// files that relate with the same source code but different targets into a
13 /// single one. Also the implements the opposite functionality, i.e. unbundle
14 /// files previous created by this tool.
16 //===----------------------------------------------------------------------===//
18 #include "clang/Basic/Version.h"
19 #include "llvm/ADT/ArrayRef.h"
20 #include "llvm/ADT/SmallString.h"
21 #include "llvm/ADT/StringMap.h"
22 #include "llvm/ADT/StringRef.h"
23 #include "llvm/ADT/StringSwitch.h"
24 #include "llvm/ADT/Triple.h"
25 #include "llvm/Bitcode/BitcodeWriter.h"
26 #include "llvm/IR/Constant.h"
27 #include "llvm/IR/Constants.h"
28 #include "llvm/IR/GlobalVariable.h"
29 #include "llvm/IR/LLVMContext.h"
30 #include "llvm/IR/Module.h"
31 #include "llvm/Object/Binary.h"
32 #include "llvm/Object/ObjectFile.h"
33 #include "llvm/Support/Casting.h"
34 #include "llvm/Support/CommandLine.h"
35 #include "llvm/Support/Error.h"
36 #include "llvm/Support/ErrorOr.h"
37 #include "llvm/Support/FileSystem.h"
38 #include "llvm/Support/MemoryBuffer.h"
39 #include "llvm/Support/Path.h"
40 #include "llvm/Support/Program.h"
41 #include "llvm/Support/raw_ostream.h"
42 #include "llvm/Support/Signals.h"
49 #include <system_error>
53 using namespace llvm::object;
55 static cl::opt<bool> Help("h", cl::desc("Alias for -help"), cl::Hidden);
57 // Mark all our options with this category, everything else (except for -version
58 // and -help) will be hidden.
59 static cl::OptionCategory
60 ClangOffloadBundlerCategory("clang-offload-bundler options");
62 static cl::list<std::string>
63 InputFileNames("inputs", cl::CommaSeparated, cl::OneOrMore,
64 cl::desc("[<input file>,...]"),
65 cl::cat(ClangOffloadBundlerCategory));
66 static cl::list<std::string>
67 OutputFileNames("outputs", cl::CommaSeparated, cl::OneOrMore,
68 cl::desc("[<output file>,...]"),
69 cl::cat(ClangOffloadBundlerCategory));
70 static cl::list<std::string>
71 TargetNames("targets", cl::CommaSeparated, cl::OneOrMore,
72 cl::desc("[<offload kind>-<target triple>,...]"),
73 cl::cat(ClangOffloadBundlerCategory));
74 static cl::opt<std::string>
75 FilesType("type", cl::Required,
76 cl::desc("Type of the files to be bundled/unbundled.\n"
77 "Current supported types are:\n"
79 " ii - c++-cpp-output\n"
84 " gch - precompiled-header\n"
85 " ast - clang AST file"),
86 cl::cat(ClangOffloadBundlerCategory));
89 cl::desc("Unbundle bundled file into several output files.\n"),
90 cl::init(false), cl::cat(ClangOffloadBundlerCategory));
92 static cl::opt<bool> PrintExternalCommands(
94 cl::desc("Print any external commands that are to be executed "
95 "instead of actually executing them - for testing purposes.\n"),
96 cl::init(false), cl::cat(ClangOffloadBundlerCategory));
98 static cl::opt<bool> DumpTemporaryFiles(
99 "dump-temporary-files",
100 cl::desc("Dumps any temporary files created - for testing purposes.\n"),
101 cl::init(false), cl::cat(ClangOffloadBundlerCategory));
103 /// Magic string that marks the existence of offloading data.
104 #define OFFLOAD_BUNDLER_MAGIC_STR "__CLANG_OFFLOAD_BUNDLE__"
106 /// The index of the host input in the list of inputs.
107 static unsigned HostInputIndex = ~0u;
109 /// Path to the current binary.
110 static std::string BundlerExecutable;
112 /// Obtain the offload kind and real machine triple out of the target
113 /// information specified by the user.
114 static void getOffloadKindAndTriple(StringRef Target, StringRef &OffloadKind,
116 auto KindTriplePair = Target.split('-');
117 OffloadKind = KindTriplePair.first;
118 Triple = KindTriplePair.second;
120 static StringRef getTriple(StringRef Target) {
121 StringRef OffloadKind;
123 getOffloadKindAndTriple(Target, OffloadKind, Triple);
126 static bool hasHostKind(StringRef Target) {
127 StringRef OffloadKind;
129 getOffloadKindAndTriple(Target, OffloadKind, Triple);
130 return OffloadKind == "host";
133 /// Generic file handler interface.
138 virtual ~FileHandler() {}
140 /// Update the file handler with information from the header of the bundled
142 virtual void ReadHeader(MemoryBuffer &Input) = 0;
144 /// Read the marker of the next bundled to be read in the file. The triple of
145 /// the target associated with that bundle is returned. An empty string is
146 /// returned if there are no more bundles to be read.
147 virtual StringRef ReadBundleStart(MemoryBuffer &Input) = 0;
149 /// Read the marker that closes the current bundle.
150 virtual void ReadBundleEnd(MemoryBuffer &Input) = 0;
152 /// Read the current bundle and write the result into the stream \a OS.
153 virtual void ReadBundle(raw_fd_ostream &OS, MemoryBuffer &Input) = 0;
155 /// Write the header of the bundled file to \a OS based on the information
156 /// gathered from \a Inputs.
157 virtual void WriteHeader(raw_fd_ostream &OS,
158 ArrayRef<std::unique_ptr<MemoryBuffer>> Inputs) = 0;
160 /// Write the marker that initiates a bundle for the triple \a TargetTriple to
162 virtual void WriteBundleStart(raw_fd_ostream &OS, StringRef TargetTriple) = 0;
164 /// Write the marker that closes a bundle for the triple \a TargetTriple to \a
165 /// OS. Return true if any error was found.
167 virtual bool WriteBundleEnd(raw_fd_ostream &OS, StringRef TargetTriple) = 0;
169 /// Write the bundle from \a Input into \a OS.
170 virtual void WriteBundle(raw_fd_ostream &OS, MemoryBuffer &Input) = 0;
173 /// Handler for binary files. The bundled file will have the following format
174 /// (all integers are stored in little-endian format):
176 /// "OFFLOAD_BUNDLER_MAGIC_STR" (ASCII encoding of the string)
178 /// NumberOfOffloadBundles (8-byte integer)
180 /// OffsetOfBundle1 (8-byte integer)
181 /// SizeOfBundle1 (8-byte integer)
182 /// NumberOfBytesInTripleOfBundle1 (8-byte integer)
183 /// TripleOfBundle1 (byte length defined before)
187 /// OffsetOfBundleN (8-byte integer)
188 /// SizeOfBundleN (8-byte integer)
189 /// NumberOfBytesInTripleOfBundleN (8-byte integer)
190 /// TripleOfBundleN (byte length defined before)
196 /// Read 8-byte integers from a buffer in little-endian format.
197 static uint64_t Read8byteIntegerFromBuffer(StringRef Buffer, size_t pos) {
199 const char *Data = Buffer.data();
201 for (unsigned i = 0; i < 8; ++i) {
203 uint64_t Char = (uint64_t)Data[pos + 7 - i];
209 /// Write 8-byte integers to a buffer in little-endian format.
210 static void Write8byteIntegerToBuffer(raw_fd_ostream &OS, uint64_t Val) {
211 for (unsigned i = 0; i < 8; ++i) {
212 char Char = (char)(Val & 0xffu);
218 class BinaryFileHandler final : public FileHandler {
219 /// Information about the bundles extracted from the header.
220 struct BundleInfo final {
221 /// Size of the bundle.
223 /// Offset at which the bundle starts in the bundled file.
224 uint64_t Offset = 0u;
227 BundleInfo(uint64_t Size, uint64_t Offset) : Size(Size), Offset(Offset) {}
230 /// Map between a triple and the corresponding bundle information.
231 StringMap<BundleInfo> BundlesInfo;
233 /// Iterator for the bundle information that is being read.
234 StringMap<BundleInfo>::iterator CurBundleInfo;
237 BinaryFileHandler() : FileHandler() {}
239 ~BinaryFileHandler() final {}
241 void ReadHeader(MemoryBuffer &Input) final {
242 StringRef FC = Input.getBuffer();
244 // Initialize the current bundle with the end of the container.
245 CurBundleInfo = BundlesInfo.end();
247 // Check if buffer is smaller than magic string.
248 size_t ReadChars = sizeof(OFFLOAD_BUNDLER_MAGIC_STR) - 1;
249 if (ReadChars > FC.size())
252 // Check if no magic was found.
253 StringRef Magic(FC.data(), sizeof(OFFLOAD_BUNDLER_MAGIC_STR) - 1);
254 if (!Magic.equals(OFFLOAD_BUNDLER_MAGIC_STR))
257 // Read number of bundles.
258 if (ReadChars + 8 > FC.size())
261 uint64_t NumberOfBundles = Read8byteIntegerFromBuffer(FC, ReadChars);
264 // Read bundle offsets, sizes and triples.
265 for (uint64_t i = 0; i < NumberOfBundles; ++i) {
268 if (ReadChars + 8 > FC.size())
271 uint64_t Offset = Read8byteIntegerFromBuffer(FC, ReadChars);
275 if (ReadChars + 8 > FC.size())
278 uint64_t Size = Read8byteIntegerFromBuffer(FC, ReadChars);
282 if (ReadChars + 8 > FC.size())
285 uint64_t TripleSize = Read8byteIntegerFromBuffer(FC, ReadChars);
289 if (ReadChars + TripleSize > FC.size())
292 StringRef Triple(&FC.data()[ReadChars], TripleSize);
293 ReadChars += TripleSize;
295 // Check if the offset and size make sense.
296 if (!Size || !Offset || Offset + Size > FC.size())
299 assert(BundlesInfo.find(Triple) == BundlesInfo.end() &&
300 "Triple is duplicated??");
301 BundlesInfo[Triple] = BundleInfo(Size, Offset);
303 // Set the iterator to where we will start to read.
304 CurBundleInfo = BundlesInfo.begin();
307 StringRef ReadBundleStart(MemoryBuffer &Input) final {
308 if (CurBundleInfo == BundlesInfo.end())
311 return CurBundleInfo->first();
314 void ReadBundleEnd(MemoryBuffer &Input) final {
315 assert(CurBundleInfo != BundlesInfo.end() && "Invalid reader info!");
319 void ReadBundle(raw_fd_ostream &OS, MemoryBuffer &Input) final {
320 assert(CurBundleInfo != BundlesInfo.end() && "Invalid reader info!");
321 StringRef FC = Input.getBuffer();
322 OS.write(FC.data() + CurBundleInfo->second.Offset,
323 CurBundleInfo->second.Size);
326 void WriteHeader(raw_fd_ostream &OS,
327 ArrayRef<std::unique_ptr<MemoryBuffer>> Inputs) final {
328 // Compute size of the header.
329 uint64_t HeaderSize = 0;
331 HeaderSize += sizeof(OFFLOAD_BUNDLER_MAGIC_STR) - 1;
332 HeaderSize += 8; // Number of Bundles
334 for (auto &T : TargetNames) {
335 HeaderSize += 3 * 8; // Bundle offset, Size of bundle and size of triple.
336 HeaderSize += T.size(); // The triple.
339 // Write to the buffer the header.
340 OS << OFFLOAD_BUNDLER_MAGIC_STR;
342 Write8byteIntegerToBuffer(OS, TargetNames.size());
345 for (auto &T : TargetNames) {
346 MemoryBuffer &MB = *Inputs[Idx++].get();
348 Write8byteIntegerToBuffer(OS, HeaderSize);
349 // Size of the bundle (adds to the next bundle's offset)
350 Write8byteIntegerToBuffer(OS, MB.getBufferSize());
351 HeaderSize += MB.getBufferSize();
352 // Size of the triple
353 Write8byteIntegerToBuffer(OS, T.size());
359 void WriteBundleStart(raw_fd_ostream &OS, StringRef TargetTriple) final {}
361 bool WriteBundleEnd(raw_fd_ostream &OS, StringRef TargetTriple) final {
365 void WriteBundle(raw_fd_ostream &OS, MemoryBuffer &Input) final {
366 OS.write(Input.getBufferStart(), Input.getBufferSize());
370 /// Handler for object files. The bundles are organized by sections with a
373 /// In order to bundle we create an IR file with the content of each section and
374 /// use incremental linking to produce the resulting object. We also add section
375 /// with a single byte to state the name of the component the main object file
376 /// (the one we are bundling into) refers to.
378 /// To unbundle, we use just copy the contents of the designated section. If the
379 /// requested bundle refer to the main object file, we just copy it with no
381 class ObjectFileHandler final : public FileHandler {
383 /// The object file we are currently dealing with.
384 std::unique_ptr<ObjectFile> Obj;
386 /// Return the input file contents.
387 StringRef getInputFileContents() const { return Obj->getData(); }
389 /// Return true if the provided section is an offload section and return the
390 /// triple by reference.
391 static bool IsOffloadSection(SectionRef CurSection,
392 StringRef &OffloadTriple) {
393 StringRef SectionName;
394 CurSection.getName(SectionName);
396 if (SectionName.empty())
399 // If it does not start with the reserved suffix, just skip this section.
400 if (!SectionName.startswith(OFFLOAD_BUNDLER_MAGIC_STR))
403 // Return the triple that is right after the reserved prefix.
404 OffloadTriple = SectionName.substr(sizeof(OFFLOAD_BUNDLER_MAGIC_STR) - 1);
408 /// Total number of inputs.
409 unsigned NumberOfInputs = 0;
411 /// Total number of processed inputs, i.e, inputs that were already
412 /// read from the buffers.
413 unsigned NumberOfProcessedInputs = 0;
415 /// LLVM context used to create the auxiliary modules.
416 LLVMContext VMContext;
418 /// LLVM module used to create an object with all the bundle
420 std::unique_ptr<Module> AuxModule;
422 /// The current triple we are working with.
423 StringRef CurrentTriple;
425 /// The name of the main input file.
426 StringRef MainInputFileName;
428 /// Iterator of the current and next section.
429 section_iterator CurrentSection;
430 section_iterator NextSection;
433 ObjectFileHandler(std::unique_ptr<ObjectFile> ObjIn)
434 : FileHandler(), Obj(std::move(ObjIn)),
435 CurrentSection(Obj->section_begin()),
436 NextSection(Obj->section_begin()) {}
438 ~ObjectFileHandler() final {}
440 void ReadHeader(MemoryBuffer &Input) final {}
442 StringRef ReadBundleStart(MemoryBuffer &Input) final {
443 while (NextSection != Obj->section_end()) {
444 CurrentSection = NextSection;
447 StringRef OffloadTriple;
448 // Check if the current section name starts with the reserved prefix. If
449 // so, return the triple.
450 if (IsOffloadSection(*CurrentSection, OffloadTriple))
451 return OffloadTriple;
456 void ReadBundleEnd(MemoryBuffer &Input) final {}
458 void ReadBundle(raw_fd_ostream &OS, MemoryBuffer &Input) final {
459 // If the current section has size one, that means that the content we are
460 // interested in is the file itself. Otherwise it is the content of the
463 // TODO: Instead of copying the input file as is, deactivate the section
464 // that is no longer needed.
467 CurrentSection->getContents(Content);
469 if (Content.size() < 2)
470 OS.write(Input.getBufferStart(), Input.getBufferSize());
472 OS.write(Content.data(), Content.size());
475 void WriteHeader(raw_fd_ostream &OS,
476 ArrayRef<std::unique_ptr<MemoryBuffer>> Inputs) final {
477 assert(HostInputIndex != ~0u && "Host input index not defined.");
479 // Record number of inputs.
480 NumberOfInputs = Inputs.size();
482 // Create an LLVM module to have the content we need to bundle.
483 auto *M = new Module("clang-offload-bundle", VMContext);
484 M->setTargetTriple(getTriple(TargetNames[HostInputIndex]));
488 void WriteBundleStart(raw_fd_ostream &OS, StringRef TargetTriple) final {
489 ++NumberOfProcessedInputs;
491 // Record the triple we are using, that will be used to name the section we
493 CurrentTriple = TargetTriple;
496 bool WriteBundleEnd(raw_fd_ostream &OS, StringRef TargetTriple) final {
497 assert(NumberOfProcessedInputs <= NumberOfInputs &&
498 "Processing more inputs that actually exist!");
499 assert(HostInputIndex != ~0u && "Host input index not defined.");
501 // If this is not the last output, we don't have to do anything.
502 if (NumberOfProcessedInputs != NumberOfInputs)
505 // Create the bitcode file name to write the resulting code to. Keep it if
506 // save-temps is active.
507 SmallString<128> BitcodeFileName;
508 if (sys::fs::createTemporaryFile("clang-offload-bundler", "bc",
510 errs() << "error: unable to create temporary file.\n";
514 // Dump the contents of the temporary file if that was requested.
515 if (DumpTemporaryFiles) {
516 errs() << ";\n; Object file bundler IR file.\n;\n";
517 AuxModule.get()->print(errs(), nullptr,
518 /*ShouldPreserveUseListOrder=*/false,
519 /*IsForDebug=*/true);
523 // Find clang in order to create the bundle binary.
524 StringRef Dir = sys::path::parent_path(BundlerExecutable);
526 auto ClangBinary = sys::findProgramByName("clang", Dir);
527 if (ClangBinary.getError()) {
528 // Remove bitcode file.
529 sys::fs::remove(BitcodeFileName);
531 errs() << "error: unable to find 'clang' in path.\n";
535 // Do the incremental linking. We write to the output file directly. So, we
536 // close it and use the name to pass down to clang.
538 SmallString<128> TargetName = getTriple(TargetNames[HostInputIndex]);
539 std::vector<StringRef> ClangArgs = {"clang",
544 OutputFileNames.front().c_str(),
545 InputFileNames[HostInputIndex].c_str(),
546 BitcodeFileName.c_str(),
549 // If the user asked for the commands to be printed out, we do that instead
551 if (PrintExternalCommands) {
552 errs() << "\"" << ClangBinary.get() << "\"";
553 for (StringRef Arg : ClangArgs)
554 errs() << " \"" << Arg << "\"";
557 // Write the bitcode contents to the temporary file.
560 raw_fd_ostream BitcodeFile(BitcodeFileName, EC, sys::fs::F_None);
562 errs() << "error: unable to open temporary file.\n";
565 WriteBitcodeToFile(*AuxModule, BitcodeFile);
568 bool Failed = sys::ExecuteAndWait(ClangBinary.get(), ClangArgs);
570 // Remove bitcode file.
571 sys::fs::remove(BitcodeFileName);
574 errs() << "error: incremental linking by external tool failed.\n";
582 void WriteBundle(raw_fd_ostream &OS, MemoryBuffer &Input) final {
583 Module *M = AuxModule.get();
585 // Create the new section name, it will consist of the reserved prefix
586 // concatenated with the triple.
587 std::string SectionName = OFFLOAD_BUNDLER_MAGIC_STR;
588 SectionName += CurrentTriple;
590 // Create the constant with the content of the section. For the input we are
591 // bundling into (the host input), this is just a place-holder, so a single
592 // byte is sufficient.
593 assert(HostInputIndex != ~0u && "Host input index undefined??");
595 if (NumberOfProcessedInputs == HostInputIndex + 1) {
596 uint8_t Byte[] = {0};
597 Content = ConstantDataArray::get(VMContext, Byte);
599 Content = ConstantDataArray::get(
600 VMContext, ArrayRef<uint8_t>(reinterpret_cast<const uint8_t *>(
601 Input.getBufferStart()),
602 Input.getBufferSize()));
604 // Create the global in the desired section. We don't want these globals in
605 // the symbol table, so we mark them private.
606 auto *GV = new GlobalVariable(*M, Content->getType(), /*IsConstant=*/true,
607 GlobalVariable::PrivateLinkage, Content);
608 GV->setSection(SectionName);
612 /// Handler for text files. The bundled file will have the following format.
614 /// "Comment OFFLOAD_BUNDLER_MAGIC_STR__START__ triple"
616 /// "Comment OFFLOAD_BUNDLER_MAGIC_STR__END__ triple"
618 /// "Comment OFFLOAD_BUNDLER_MAGIC_STR__START__ triple"
620 /// "Comment OFFLOAD_BUNDLER_MAGIC_STR__END__ triple"
621 class TextFileHandler final : public FileHandler {
622 /// String that begins a line comment.
625 /// String that initiates a bundle.
626 std::string BundleStartString;
628 /// String that closes a bundle.
629 std::string BundleEndString;
631 /// Number of chars read from input.
632 size_t ReadChars = 0u;
635 void ReadHeader(MemoryBuffer &Input) final {}
637 StringRef ReadBundleStart(MemoryBuffer &Input) final {
638 StringRef FC = Input.getBuffer();
640 // Find start of the bundle.
641 ReadChars = FC.find(BundleStartString, ReadChars);
642 if (ReadChars == FC.npos)
645 // Get position of the triple.
646 size_t TripleStart = ReadChars = ReadChars + BundleStartString.size();
648 // Get position that closes the triple.
649 size_t TripleEnd = ReadChars = FC.find("\n", ReadChars);
650 if (TripleEnd == FC.npos)
653 // Next time we read after the new line.
656 return StringRef(&FC.data()[TripleStart], TripleEnd - TripleStart);
659 void ReadBundleEnd(MemoryBuffer &Input) final {
660 StringRef FC = Input.getBuffer();
662 // Read up to the next new line.
663 assert(FC[ReadChars] == '\n' && "The bundle should end with a new line.");
665 size_t TripleEnd = ReadChars = FC.find("\n", ReadChars + 1);
666 if (TripleEnd == FC.npos)
669 // Next time we read after the new line.
673 void ReadBundle(raw_fd_ostream &OS, MemoryBuffer &Input) final {
674 StringRef FC = Input.getBuffer();
675 size_t BundleStart = ReadChars;
677 // Find end of the bundle.
678 size_t BundleEnd = ReadChars = FC.find(BundleEndString, ReadChars);
680 StringRef Bundle(&FC.data()[BundleStart], BundleEnd - BundleStart);
684 void WriteHeader(raw_fd_ostream &OS,
685 ArrayRef<std::unique_ptr<MemoryBuffer>> Inputs) final {}
687 void WriteBundleStart(raw_fd_ostream &OS, StringRef TargetTriple) final {
688 OS << BundleStartString << TargetTriple << "\n";
691 bool WriteBundleEnd(raw_fd_ostream &OS, StringRef TargetTriple) final {
692 OS << BundleEndString << TargetTriple << "\n";
696 void WriteBundle(raw_fd_ostream &OS, MemoryBuffer &Input) final {
697 OS << Input.getBuffer();
701 TextFileHandler(StringRef Comment)
702 : FileHandler(), Comment(Comment), ReadChars(0) {
704 "\n" + Comment.str() + " " OFFLOAD_BUNDLER_MAGIC_STR "__START__ ";
706 "\n" + Comment.str() + " " OFFLOAD_BUNDLER_MAGIC_STR "__END__ ";
710 /// Return an appropriate object file handler. We use the specific object
711 /// handler if we know how to deal with that format, otherwise we use a default
712 /// binary file handler.
713 static FileHandler *CreateObjectFileHandler(MemoryBuffer &FirstInput) {
714 // Check if the input file format is one that we know how to deal with.
715 Expected<std::unique_ptr<Binary>> BinaryOrErr = createBinary(FirstInput);
717 // Failed to open the input as a known binary. Use the default binary handler.
719 // We don't really care about the error (we just consume it), if we could
720 // not get a valid device binary object we use the default binary handler.
721 consumeError(BinaryOrErr.takeError());
722 return new BinaryFileHandler();
725 // We only support regular object files. If this is not an object file,
726 // default to the binary handler. The handler will be owned by the client of
728 std::unique_ptr<ObjectFile> Obj(
729 dyn_cast<ObjectFile>(BinaryOrErr.get().release()));
732 return new BinaryFileHandler();
734 return new ObjectFileHandler(std::move(Obj));
737 /// Return an appropriate handler given the input files and options.
738 static FileHandler *CreateFileHandler(MemoryBuffer &FirstInput) {
739 if (FilesType == "i")
740 return new TextFileHandler(/*Comment=*/"//");
741 if (FilesType == "ii")
742 return new TextFileHandler(/*Comment=*/"//");
743 if (FilesType == "ll")
744 return new TextFileHandler(/*Comment=*/";");
745 if (FilesType == "bc")
746 return new BinaryFileHandler();
747 if (FilesType == "s")
748 return new TextFileHandler(/*Comment=*/"#");
749 if (FilesType == "o")
750 return CreateObjectFileHandler(FirstInput);
751 if (FilesType == "gch")
752 return new BinaryFileHandler();
753 if (FilesType == "ast")
754 return new BinaryFileHandler();
756 errs() << "error: invalid file type specified.\n";
760 /// Bundle the files. Return true if an error was found.
761 static bool BundleFiles() {
764 // Create output file.
765 raw_fd_ostream OutputFile(OutputFileNames.front(), EC, sys::fs::F_None);
768 errs() << "error: Can't open file " << OutputFileNames.front() << ".\n";
773 std::vector<std::unique_ptr<MemoryBuffer>> InputBuffers(
774 InputFileNames.size());
777 for (auto &I : InputFileNames) {
778 ErrorOr<std::unique_ptr<MemoryBuffer>> CodeOrErr =
779 MemoryBuffer::getFileOrSTDIN(I);
780 if (std::error_code EC = CodeOrErr.getError()) {
781 errs() << "error: Can't open file " << I << ": " << EC.message() << "\n";
784 InputBuffers[Idx++] = std::move(CodeOrErr.get());
787 // Get the file handler. We use the host buffer as reference.
788 assert(HostInputIndex != ~0u && "Host input index undefined??");
789 std::unique_ptr<FileHandler> FH;
790 FH.reset(CreateFileHandler(*InputBuffers[HostInputIndex].get()));
792 // Quit if we don't have a handler.
797 FH.get()->WriteHeader(OutputFile, InputBuffers);
799 // Write all bundles along with the start/end markers. If an error was found
800 // writing the end of the bundle component, abort the bundle writing.
801 auto Input = InputBuffers.begin();
802 for (auto &Triple : TargetNames) {
803 FH.get()->WriteBundleStart(OutputFile, Triple);
804 FH.get()->WriteBundle(OutputFile, *Input->get());
805 if (FH.get()->WriteBundleEnd(OutputFile, Triple))
812 // Unbundle the files. Return true if an error was found.
813 static bool UnbundleFiles() {
815 ErrorOr<std::unique_ptr<MemoryBuffer>> CodeOrErr =
816 MemoryBuffer::getFileOrSTDIN(InputFileNames.front());
817 if (std::error_code EC = CodeOrErr.getError()) {
818 errs() << "error: Can't open file " << InputFileNames.front() << ": "
819 << EC.message() << "\n";
823 MemoryBuffer &Input = *CodeOrErr.get();
825 // Select the right files handler.
826 std::unique_ptr<FileHandler> FH;
827 FH.reset(CreateFileHandler(Input));
829 // Quit if we don't have a handler.
833 // Read the header of the bundled file.
834 FH.get()->ReadHeader(Input);
836 // Create a work list that consist of the map triple/output file.
837 StringMap<StringRef> Worklist;
838 auto Output = OutputFileNames.begin();
839 for (auto &Triple : TargetNames) {
840 Worklist[Triple] = *Output;
844 // Read all the bundles that are in the work list. If we find no bundles we
845 // assume the file is meant for the host target.
846 bool FoundHostBundle = false;
847 while (!Worklist.empty()) {
848 StringRef CurTriple = FH.get()->ReadBundleStart(Input);
850 // We don't have more bundles.
851 if (CurTriple.empty())
854 auto Output = Worklist.find(CurTriple);
855 // The file may have more bundles for other targets, that we don't care
856 // about. Therefore, move on to the next triple
857 if (Output == Worklist.end()) {
861 // Check if the output file can be opened and copy the bundle to it.
863 raw_fd_ostream OutputFile(Output->second, EC, sys::fs::F_None);
865 errs() << "error: Can't open file " << Output->second << ": "
866 << EC.message() << "\n";
869 FH.get()->ReadBundle(OutputFile, Input);
870 FH.get()->ReadBundleEnd(Input);
871 Worklist.erase(Output);
873 // Record if we found the host bundle.
874 if (hasHostKind(CurTriple))
875 FoundHostBundle = true;
878 // If no bundles were found, assume the input file is the host bundle and
879 // create empty files for the remaining targets.
880 if (Worklist.size() == TargetNames.size()) {
881 for (auto &E : Worklist) {
883 raw_fd_ostream OutputFile(E.second, EC, sys::fs::F_None);
885 errs() << "error: Can't open file " << E.second << ": " << EC.message()
890 // If this entry has a host kind, copy the input file to the output file.
891 if (hasHostKind(E.first()))
892 OutputFile.write(Input.getBufferStart(), Input.getBufferSize());
897 // If we found elements, we emit an error if none of those were for the host.
898 if (!FoundHostBundle) {
899 errs() << "error: Can't find bundle for the host target\n";
903 // If we still have any elements in the worklist, create empty files for them.
904 for (auto &E : Worklist) {
906 raw_fd_ostream OutputFile(E.second, EC, sys::fs::F_None);
908 errs() << "error: Can't open file " << E.second << ": " << EC.message()
917 static void PrintVersion(raw_ostream &OS) {
918 OS << clang::getClangToolFullVersion("clang-offload-bundler") << '\n';
921 int main(int argc, const char **argv) {
922 sys::PrintStackTraceOnErrorSignal(argv[0]);
924 cl::HideUnrelatedOptions(ClangOffloadBundlerCategory);
925 cl::SetVersionPrinter(PrintVersion);
926 cl::ParseCommandLineOptions(
928 "A tool to bundle several input files of the specified type <type> \n"
929 "referring to the same source file but different targets into a single \n"
930 "one. The resulting file can also be unbundled into different files by \n"
931 "this tool if -unbundle is provided.\n");
934 cl::PrintHelpMessage();
940 if (InputFileNames.size() != 1) {
942 errs() << "error: only one input file supported in unbundling mode.\n";
944 if (OutputFileNames.size() != TargetNames.size()) {
946 errs() << "error: number of output files and targets should match in "
947 "unbundling mode.\n";
950 if (OutputFileNames.size() != 1) {
952 errs() << "error: only one output file supported in bundling mode.\n";
954 if (InputFileNames.size() != TargetNames.size()) {
956 errs() << "error: number of input files and targets should match in "
961 // Verify that the offload kinds and triples are known. We also check that we
962 // have exactly one host target.
964 unsigned HostTargetNum = 0u;
965 for (StringRef Target : TargetNames) {
968 getOffloadKindAndTriple(Target, Kind, Triple);
970 bool KindIsValid = !Kind.empty();
971 KindIsValid = KindIsValid && StringSwitch<bool>(Kind)
973 .Case("openmp", true)
977 bool TripleIsValid = !Triple.empty();
978 llvm::Triple T(Triple);
979 TripleIsValid &= T.getArch() != Triple::UnknownArch;
981 if (!KindIsValid || !TripleIsValid) {
983 errs() << "error: invalid target '" << Target << "'";
986 errs() << ", unknown offloading kind '" << Kind << "'";
988 errs() << ", unknown target triple '" << Triple << "'";
992 if (KindIsValid && Kind == "host") {
994 // Save the index of the input that refers to the host.
995 HostInputIndex = Index;
1001 if (HostTargetNum != 1) {
1003 errs() << "error: expecting exactly one host target but got "
1004 << HostTargetNum << ".\n";
1010 // Save the current executable directory as it will be useful to find other
1012 BundlerExecutable = sys::fs::getMainExecutable(argv[0], &BundlerExecutable);
1014 return Unbundle ? UnbundleFiles() : BundleFiles();