//===-- clang-offload-packager/ClangOffloadPackager.cpp - file bundler ---===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===---------------------------------------------------------------------===// // // This tool takes several device object files and bundles them into a single // binary image using a custom binary format. This is intended to be used to // embed many device files into an application to create a fat binary. // //===---------------------------------------------------------------------===// #include "clang/Basic/Version.h" #include "llvm/Object/Binary.h" #include "llvm/Object/ObjectFile.h" #include "llvm/Object/OffloadBinary.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/FileOutputBuffer.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/Path.h" #include "llvm/Support/Signals.h" #include "llvm/Support/StringSaver.h" #include "llvm/Support/WithColor.h" using namespace llvm; using namespace llvm::object; static cl::opt Help("h", cl::desc("Alias for -help"), cl::Hidden); static cl::OptionCategory ClangOffloadPackagerCategory("clang-offload-packager options"); static cl::opt OutputFile("o", cl::Required, cl::desc("Write output to ."), cl::value_desc("file"), cl::cat(ClangOffloadPackagerCategory)); static cl::list DeviceImages("image", cl::desc("List of key and value arguments. Required keywords " "are 'file' and 'triple'."), cl::value_desc("=,..."), cl::cat(ClangOffloadPackagerCategory)); static void PrintVersion(raw_ostream &OS) { OS << clang::getClangToolFullVersion("clang-offload-packager") << '\n'; } int main(int argc, const char **argv) { sys::PrintStackTraceOnErrorSignal(argv[0]); cl::HideUnrelatedOptions(ClangOffloadPackagerCategory); cl::SetVersionPrinter(PrintVersion); cl::ParseCommandLineOptions( argc, argv, "A utility for bundling several object files into a single binary.\n" "The output binary can then be embedded into the host section table\n" "to create a fatbinary containing offloading code.\n"); if (Help) { cl::PrintHelpMessage(); return EXIT_SUCCESS; } auto reportError = [argv](Error E) { logAllUnhandledErrors(std::move(E), WithColor::error(errs(), argv[0])); return EXIT_FAILURE; }; SmallVector BinaryData; raw_svector_ostream OS(BinaryData); for (StringRef Image : DeviceImages) { BumpPtrAllocator Alloc; StringSaver Saver(Alloc); StringMap Args; for (StringRef Arg : llvm::split(Image, ",")) { auto KeyAndValue = Arg.split("="); if (Args.count(KeyAndValue.first)) Args[KeyAndValue.first] = Saver.save(Args[KeyAndValue.first] + "," + KeyAndValue.second); else Args[KeyAndValue.first] = KeyAndValue.second; } if (!Args.count("triple") || !Args.count("file")) return reportError(createStringError( inconvertibleErrorCode(), "'file' and 'triple' are required image arguments")); OffloadBinary::OffloadingImage ImageBinary{}; std::unique_ptr DeviceImage; for (const auto &KeyAndValue : Args) { StringRef Key = KeyAndValue.getKey(); if (Key == "file") { llvm::ErrorOr> ObjectOrErr = llvm::MemoryBuffer::getFileOrSTDIN(KeyAndValue.getValue()); if (std::error_code EC = ObjectOrErr.getError()) return reportError(errorCodeToError(EC)); // Clang uses the '.o' suffix for LTO bitcode. if (identify_magic((*ObjectOrErr)->getBuffer()) == file_magic::bitcode) ImageBinary.TheImageKind = object::IMG_Bitcode; else ImageBinary.TheImageKind = getImageKind( sys::path::extension(KeyAndValue.getValue()).drop_front()); ImageBinary.Image = std::move(*ObjectOrErr); } else if (Key == "kind") { ImageBinary.TheOffloadKind = getOffloadKind(KeyAndValue.getValue()); } else { ImageBinary.StringData[Key] = KeyAndValue.getValue(); } } std::unique_ptr Buffer = OffloadBinary::write(ImageBinary); if (Buffer->getBufferSize() % OffloadBinary::getAlignment() != 0) return reportError( createStringError(inconvertibleErrorCode(), "Offload binary has invalid size alignment")); OS << Buffer->getBuffer(); } Expected> OutputOrErr = FileOutputBuffer::create(OutputFile, BinaryData.size()); if (!OutputOrErr) return reportError(OutputOrErr.takeError()); std::unique_ptr Output = std::move(*OutputOrErr); std::copy(BinaryData.begin(), BinaryData.end(), Output->getBufferStart()); if (Error E = Output->commit()) return reportError(std::move(E)); }