2424#include " llvm/ADT/StringSwitch.h"
2525#include " llvm/ADT/Triple.h"
2626#include " llvm/Object/Archive.h"
27+ #include " llvm/Object/ArchiveWriter.h"
2728#include " llvm/Object/Binary.h"
2829#include " llvm/Object/ObjectFile.h"
2930#include " llvm/Support/Casting.h"
@@ -88,6 +89,7 @@ static cl::opt<std::string> FilesType(
8889 " oo - object; output file is a list of unbundled objects\n "
8990 " gch - precompiled-header\n "
9091 " ast - clang AST file\n "
92+ " a - archive of objects\n "
9193 " ao - archive with one object; output is an unbundled object\n "
9294 " aoo - archive; output file is a list of unbundled objects\n " ),
9395 cl::cat(ClangOffloadBundlerCategory));
@@ -161,7 +163,7 @@ class FileHandler {
161163 virtual Error ReadBundleEnd (MemoryBuffer &Input) = 0;
162164
163165 // / Read the current bundle and write the result into the stream \a OS.
164- virtual Error ReadBundle (raw_fd_ostream &OS, MemoryBuffer &Input) = 0;
166+ virtual Error ReadBundle (raw_ostream &OS, MemoryBuffer &Input) = 0;
165167
166168 // / Write the header of the bundled file to \a OS based on the information
167169 // / gathered from \a Inputs.
@@ -342,7 +344,7 @@ class BinaryFileHandler final : public FileHandler {
342344 return Error::success ();
343345 }
344346
345- Error ReadBundle (raw_fd_ostream &OS, MemoryBuffer &Input) final {
347+ Error ReadBundle (raw_ostream &OS, MemoryBuffer &Input) final {
346348 assert (CurBundleInfo != BundlesInfo.end () && " Invalid reader info!" );
347349 StringRef FC = Input.getBuffer ();
348350 OS.write (FC.data () + CurBundleInfo->second .Offset ,
@@ -624,7 +626,7 @@ class ObjectFileHandler final : public FileHandler {
624626
625627 Error ReadBundleEnd (MemoryBuffer &Input) final { return Error::success (); }
626628
627- Error ReadBundle (raw_fd_ostream &OS, MemoryBuffer &Input) final {
629+ Error ReadBundle (raw_ostream &OS, MemoryBuffer &Input) final {
628630 assert (CurBundle != TripleToBundleInfo.end () &&
629631 " all bundles have been read already" );
630632
@@ -899,7 +901,7 @@ class TextFileHandler final : public FileHandler {
899901 return Error::success ();
900902 }
901903
902- Error ReadBundle (raw_fd_ostream &OS, MemoryBuffer &Input) final {
904+ Error ReadBundle (raw_ostream &OS, MemoryBuffer &Input) final {
903905 StringRef FC = Input.getBuffer ();
904906 size_t BundleStart = ReadChars;
905907
@@ -955,11 +957,26 @@ class ArchiveFileHandler final : public FileHandler {
955957 StringMap<unsigned >::iterator CurrBundle = Bundles.end();
956958 StringMap<unsigned >::iterator NextBundle = Bundles.end();
957959
960+ // / Output mode for the archive unbundler.
961+ enum class OutputType {
962+ Unknown,
963+ FileList, // Output is a list file with extracted object file names
964+ Object, // Output is a single object file
965+ Archive // Output is an archive with extracted objects
966+ };
967+ const OutputType Mode = StringSwitch<OutputType>(FilesType)
968+ .Case(" aoo" , OutputType::FileList)
969+ .Case(" ao" , OutputType::Object)
970+ .Case(" a" , OutputType::Archive)
971+ .Default(OutputType::Unknown);
972+
958973public:
959974 ArchiveFileHandler () = default ;
960975 ~ArchiveFileHandler () = default ;
961976
962977 Error ReadHeader (MemoryBuffer &Input) override {
978+ assert (Mode != OutputType::Unknown && " unknown output mode" );
979+
963980 // Create archive instance for the given input.
964981 auto ArOrErr = Archive::create (Input);
965982 if (!ArOrErr)
@@ -1014,18 +1031,27 @@ class ArchiveFileHandler final : public FileHandler {
10141031
10151032 Error ReadBundleEnd (MemoryBuffer &Input) override { return Error::success (); }
10161033
1017- Error ReadBundle (raw_fd_ostream &OS, MemoryBuffer &Input) override {
1034+ Error ReadBundle (raw_ostream &OS, MemoryBuffer &Input) override {
10181035 assert (CurrBundle->second && " attempt to extract nonexistent bundle" );
10191036
1020- bool FileListMode = FilesType == " aoo" ;
1021-
10221037 // In single-file mode we do not expect to see bundle more than once.
1023- if (!FileListMode && CurrBundle->second > 1 )
1038+ if (Mode == OutputType::Object && CurrBundle->second > 1 )
10241039 return createStringError (
10251040 errc::invalid_argument,
10261041 " 'ao' file type is requested, but the archive contains multiple "
10271042 " device objects; use 'aoo' instead" );
10281043
1044+ // For 'host' archive bundle just copy input data to the output stream.
1045+ if (Mode == OutputType::Archive && hasHostKind (CurrBundle->first ())) {
1046+ OS << Input.getBuffer ();
1047+ return Error::success ();
1048+ }
1049+
1050+ // Extracted objects data for archive mode.
1051+ SmallVector<std::string, 8u > ArNames;
1052+ SmallVector<SmallVector<char , 0u >, 8u > ArData;
1053+ SmallVector<NewArchiveMember, 8u > ArMembers;
1054+
10291055 // Read all children.
10301056 Error Err = Error::success ();
10311057 for (auto &C : Ar->children (Err)) {
@@ -1043,6 +1069,10 @@ class ArchiveFileHandler final : public FileHandler {
10431069 auto Obj = std::unique_ptr<ObjectFile>(cast<ObjectFile>(Bin.release ()));
10441070 auto Buf = MemoryBuffer::getMemBuffer (Obj->getMemoryBufferRef (), false );
10451071
1072+ auto ChildNameOrErr = C.getName ();
1073+ if (!ChildNameOrErr)
1074+ return ChildNameOrErr.takeError ();
1075+
10461076 ObjectFileHandler OFH (std::move (Obj));
10471077 if (Error Err = OFH.ReadHeader (*Buf))
10481078 return Err;
@@ -1052,10 +1082,9 @@ class ArchiveFileHandler final : public FileHandler {
10521082 while (*NameOrErr) {
10531083 auto TT = **NameOrErr;
10541084 if (TT == CurrBundle->first ()) {
1055- // This is the bundle we are looking for. Create temporary file where
1056- // the device part will be extracted if we are in the file-list mode,
1057- // or write directly to the output file otherwise.
1058- if (FileListMode) {
1085+ // This is the bundle we are looking for.
1086+ if (Mode == OutputType::FileList) {
1087+ // Create temporary file where the device part will be extracted to.
10591088 SmallString<128u > ChildFileName;
10601089 auto EC = sys::fs::createTemporaryFile (TempFileNameBase, " o" ,
10611090 ChildFileName);
@@ -1075,8 +1104,23 @@ class ArchiveFileHandler final : public FileHandler {
10751104 // Add temporary file name with the device part to the output file
10761105 // list.
10771106 OS << ChildFileName << " \n " ;
1078- } else if (Error Err = OFH.ReadBundle (OS, *Buf))
1079- return Err;
1107+ } else if (Mode == OutputType::Object) {
1108+ // Extract the bundle to the output file in single file mode.
1109+ if (Error Err = OFH.ReadBundle (OS, *Buf))
1110+ return Err;
1111+ } else if (Mode == OutputType::Archive) {
1112+ auto &Name =
1113+ ArNames.emplace_back ((TT + " ." + *ChildNameOrErr).str ());
1114+ auto &Data = ArData.emplace_back ();
1115+ raw_svector_ostream ChildOS{Data};
1116+
1117+ // Extract the bundle.
1118+ if (Error Err = OFH.ReadBundle (ChildOS, *Buf))
1119+ return Err;
1120+
1121+ ArMembers.emplace_back (
1122+ MemoryBufferRef{StringRef (Data.data (), Data.size ()), Name});
1123+ }
10801124 if (Error Err = OFH.ReadBundleEnd (*Buf))
10811125 return Err;
10821126 }
@@ -1087,6 +1131,23 @@ class ArchiveFileHandler final : public FileHandler {
10871131 }
10881132 if (Err)
10891133 return Err;
1134+
1135+ if (Mode == OutputType::Archive) {
1136+ // Determine archive kind for the offload target.
1137+ StringRef TargetKind;
1138+ StringRef TargetTriple;
1139+ getOffloadKindAndTriple (CurrBundle->first (), TargetKind, TargetTriple);
1140+ auto ArKind = Triple (TargetTriple).isOSDarwin () ? Archive::K_DARWIN
1141+ : Archive::K_GNU;
1142+
1143+ // And write archive to the output.
1144+ Expected<std::unique_ptr<MemoryBuffer>> NewAr =
1145+ writeArchiveToBuffer (ArMembers, /* WriteSymtab=*/ true , ArKind,
1146+ /* Deterministic=*/ true , /* Thin=*/ false );
1147+ if (!NewAr)
1148+ return NewAr.takeError ();
1149+ OS << NewAr.get ()->getBuffer ();
1150+ }
10901151 return Error::success ();
10911152 }
10921153
@@ -1152,7 +1213,7 @@ CreateFileHandler(MemoryBuffer &FirstInput) {
11521213 return std::make_unique<BinaryFileHandler>();
11531214 if (FilesType == " ast" )
11541215 return std::make_unique<BinaryFileHandler>();
1155- if (FilesType == " ao" || FilesType == " aoo" )
1216+ if (FilesType == " a " || FilesType == " ao" || FilesType == " aoo" )
11561217 return std::make_unique<ArchiveFileHandler>();
11571218
11581219 return createStringError (errc::invalid_argument,
@@ -1163,7 +1224,7 @@ CreateFileHandler(MemoryBuffer &FirstInput) {
11631224static Error BundleFiles () {
11641225 std::error_code EC;
11651226
1166- if (FilesType == " ao" || FilesType == " aoo" )
1227+ if (FilesType == " a " || FilesType == " ao" || FilesType == " aoo" )
11671228 return createStringError (errc::invalid_argument,
11681229 " bundling is not supported for archives" );
11691230
0 commit comments