[llvm] r358921 - [dsymutil] Collect parseable Swift interfaces in the .dSYM bundle.

Adrian Prantl via llvm-commits llvm-commits at lists.llvm.org
Mon Apr 22 14:33:23 PDT 2019


Author: adrian
Date: Mon Apr 22 14:33:22 2019
New Revision: 358921

URL: http://llvm.org/viewvc/llvm-project?rev=358921&view=rev
Log:
[dsymutil] Collect parseable Swift interfaces in the .dSYM bundle.

When a Swift module built with debug info imports a library without
debug info from a textual interface, the textual interface is
necessary to reconstruct types defined in the library's interface. By
recording the Swift interface files in DWARF dsymutil can collect them
and LLDB can find them.

This patch teaches dsymutil to look for DW_TAG_imported_modules and
records all references to parseable Swift ingterfrace files and copies
them to

  a.out.dSYM/Contents/Resources/<Arch>/<ModuleName>.swiftinterface

<rdar://problem/49751748>

Added:
    llvm/trunk/test/tools/dsymutil/Inputs/swift-interface.ll
    llvm/trunk/test/tools/dsymutil/X86/swift-interface.test
Modified:
    llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFFormValue.h
    llvm/trunk/tools/dsymutil/CompileUnit.cpp
    llvm/trunk/tools/dsymutil/CompileUnit.h
    llvm/trunk/tools/dsymutil/DwarfLinker.cpp
    llvm/trunk/tools/dsymutil/DwarfLinker.h
    llvm/trunk/tools/dsymutil/LinkUtils.h
    llvm/trunk/tools/dsymutil/dsymutil.cpp

Modified: llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFFormValue.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFFormValue.h?rev=358921&r1=358920&r2=358921&view=diff
==============================================================================
--- llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFFormValue.h (original)
+++ llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFFormValue.h Mon Apr 22 14:33:22 2019
@@ -159,6 +159,19 @@ inline Optional<const char *> toString(c
   return None;
 }
 
+/// Take an optional DWARFFormValue and try to extract a string value from it.
+///
+/// \param V and optional DWARFFormValue to attempt to extract the value from.
+/// \returns an optional value that contains a value if the form value
+/// was valid and was a string.
+inline StringRef toStringRef(const Optional<DWARFFormValue> &V,
+                             StringRef Default = {}) {
+  if (V)
+    if (auto S = V->getAsCString())
+      return *S;
+  return Default;
+}
+
 /// Take an optional DWARFFormValue and extract a string value from it.
 ///
 /// \param V and optional DWARFFormValue to attempt to extract the value from.

Added: llvm/trunk/test/tools/dsymutil/Inputs/swift-interface.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/dsymutil/Inputs/swift-interface.ll?rev=358921&view=auto
==============================================================================
--- llvm/trunk/test/tools/dsymutil/Inputs/swift-interface.ll (added)
+++ llvm/trunk/test/tools/dsymutil/Inputs/swift-interface.ll Mon Apr 22 14:33:22 2019
@@ -0,0 +1,34 @@
+; This is a manually stripped empty Swift program with one import.
+source_filename = "/swift-interface.ll"
+target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-apple-macosx10.9.0"
+
+ at __swift_reflection_version = linkonce_odr hidden constant i16 3
+ at llvm.used = appending global [1 x i8*] [i8* bitcast (i16* @__swift_reflection_version to i8*)], section "llvm.metadata", align 8
+
+define i32 @main(i32, i8**) !dbg !29 {
+entry:
+  %2 = bitcast i8** %1 to i8*
+  ret i32 0, !dbg !35
+}
+
+!llvm.dbg.cu = !{!0}
+!swift.module.flags = !{!14}
+!llvm.module.flags = !{!20, !21, !24}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_Swift, file: !1, isOptimized: false, runtimeVersion: 5, emissionKind: FullDebug, enums: !2, imports: !3)
+!1 = !DIFile(filename: "ParseableInterfaceImports.swift", directory: "/")
+!2 = !{}
+!3 = !{!4}
+!4 = !DIImportedEntity(tag: DW_TAG_imported_module, scope: !1, entity: !5, file: !1)
+!5 = !DIModule(scope: null, name: "Foo", includePath: "/Foo/x86_64.swiftinterface")
+!14 = !{!"standard-library", i1 false}
+!20 = !{i32 2, !"Dwarf Version", i32 4}
+!21 = !{i32 2, !"Debug Info Version", i32 3}
+!24 = !{i32 1, !"Swift Version", i32 7}
+!29 = distinct !DISubprogram(name: "main", linkageName: "main", scope: !5, file: !1, line: 1, type: !30, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2)
+!30 = !DISubroutineType(types: !31)
+!31 = !{}
+!35 = !DILocation(line: 0, scope: !36)
+!36 = !DILexicalBlockFile(scope: !29, file: !37, discriminator: 0)
+!37 = !DIFile(filename: "<compiler-generated>", directory: "")

Added: llvm/trunk/test/tools/dsymutil/X86/swift-interface.test
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/dsymutil/X86/swift-interface.test?rev=358921&view=auto
==============================================================================
--- llvm/trunk/test/tools/dsymutil/X86/swift-interface.test (added)
+++ llvm/trunk/test/tools/dsymutil/X86/swift-interface.test Mon Apr 22 14:33:22 2019
@@ -0,0 +1,23 @@
+# RUN: rm -rf %t.dir
+# RUN: mkdir -p %t.dir/obj
+# RUN: mkdir -p %t.dir/Foo/x86_64
+# RUN: llc %p/../Inputs/swift-interface.ll -filetype=obj -o %t.dir/obj/1.o
+# RUN: dsymutil -oso-prepend-path %t.dir -y %s \
+# RUN:    -o %t.dir/swift-interface.dSYM 2>&1 \
+# RUN:    | FileCheck %s --check-prefix=WARNINGS
+# RUN: echo "// module Foo" >%t.dir/Foo/x86_64.swiftinterface
+# RUN: dsymutil -oso-prepend-path %t.dir -y %s \
+# RUN:    -o %t.dir/swift-interface.dSYM
+# RUN: cat %t.dir/swift-interface.dSYM/Contents/Resources/Swift/Foo.swiftinterface \
+# RUN:   | FileCheck %s --check-prefix=INTERFACE
+
+# WARNINGS: cannot copy parseable Swift interface
+# INTERFACE: module Foo
+
+---
+triple:          'x86_64-apple-darwin'
+objects:
+  - filename: obj/1.o
+    symbols:
+      - { sym: _main, objAddr: 0x0, binAddr: 0x10000, size: 0x10 }
+...

Modified: llvm/trunk/tools/dsymutil/CompileUnit.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/dsymutil/CompileUnit.cpp?rev=358921&r1=358920&r2=358921&view=diff
==============================================================================
--- llvm/trunk/tools/dsymutil/CompileUnit.cpp (original)
+++ llvm/trunk/tools/dsymutil/CompileUnit.cpp Mon Apr 22 14:33:22 2019
@@ -22,6 +22,14 @@ static bool inFunctionScope(CompileUnit
   return false;
 }
 
+uint16_t CompileUnit::getLanguage() {
+  if (!Language) {
+    DWARFDie CU = getOrigUnit().getUnitDIE();
+    Language = dwarf::toUnsigned(CU.find(dwarf::DW_AT_language), 0);
+  }
+  return Language;
+}
+
 void CompileUnit::markEverythingAsKept() {
   unsigned Idx = 0;
 

Modified: llvm/trunk/tools/dsymutil/CompileUnit.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/dsymutil/CompileUnit.h?rev=358921&r1=358920&r2=358921&view=diff
==============================================================================
--- llvm/trunk/tools/dsymutil/CompileUnit.h (original)
+++ llvm/trunk/tools/dsymutil/CompileUnit.h Mon Apr 22 14:33:22 2019
@@ -114,6 +114,8 @@ public:
 
   bool hasODR() const { return HasODR; }
   bool isClangModule() const { return !ClangModuleName.empty(); }
+  uint16_t getLanguage();
+
   const std::string &getClangModuleName() const { return ClangModuleName; }
 
   DIEInfo &getInfo(unsigned Idx) { return Info[Idx]; }
@@ -316,6 +318,9 @@ private:
   /// Did a DIE actually contain a valid reloc?
   bool HasInterestingContent;
 
+  /// The DW_AT_language of this unit.
+  uint16_t Language = 0;
+
   /// If this is a Clang module, this holds the module's name.
   std::string ClangModuleName;
 };

Modified: llvm/trunk/tools/dsymutil/DwarfLinker.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/dsymutil/DwarfLinker.cpp?rev=358921&r1=358920&r2=358921&view=diff
==============================================================================
--- llvm/trunk/tools/dsymutil/DwarfLinker.cpp (original)
+++ llvm/trunk/tools/dsymutil/DwarfLinker.cpp Mon Apr 22 14:33:22 2019
@@ -243,18 +243,55 @@ bool DwarfLinker::createStreamer(const T
   return Streamer->init(TheTriple);
 }
 
+/// Resolve the relative path to a build artifact referenced by DWARF by
+/// applying DW_AT_comp_dir.
+static void resolveRelativeObjectPath(SmallVectorImpl<char> &Buf, DWARFDie CU) {
+  sys::path::append(Buf, dwarf::toString(CU.find(dwarf::DW_AT_comp_dir), ""));
+}
+
+/// Collect references to parseable Swift interfaces in imported
+/// DW_TAG_module blocks.
+static void analyzeImportedModule(
+    const DWARFDie &DIE, CompileUnit &CU,
+    std::map<std::string, std::string> &ParseableSwiftInterfaces,
+    std::function<void(const Twine &, const DWARFDie &)> ReportWarning) {
+  if (CU.getLanguage() != dwarf::DW_LANG_Swift)
+    return;
+
+  StringRef Path = dwarf::toStringRef(DIE.find(dwarf::DW_AT_LLVM_include_path));
+  if (!Path.endswith(".swiftinterface"))
+    return;
+  if (Optional<DWARFFormValue> Val = DIE.find(dwarf::DW_AT_name))
+    if (Optional<const char *> Name = Val->getAsCString()) {
+      auto &Entry = ParseableSwiftInterfaces[*Name];
+      // The prepend path is applied later when copying.
+      DWARFDie CUDie = CU.getOrigUnit().getUnitDIE();
+      SmallString<128> ResolvedPath;
+      if (sys::path::is_relative(Path))
+        resolveRelativeObjectPath(ResolvedPath, CUDie);
+      sys::path::append(ResolvedPath, Path);
+      if (!Entry.empty() && Entry != ResolvedPath)
+        ReportWarning(
+            Twine("Conflicting parseable interfaces for Swift Module ") +
+                *Name + ": " + Entry + " and " + Path,
+            DIE);
+      Entry = ResolvedPath.str();
+    }
+}
+
 /// Recursive helper to build the global DeclContext information and
 /// gather the child->parent relationships in the original compile unit.
 ///
 /// \return true when this DIE and all of its children are only
 /// forward declarations to types defined in external clang modules
 /// (i.e., forward declarations that are children of a DW_TAG_module).
-static bool analyzeContextInfo(const DWARFDie &DIE, unsigned ParentIdx,
-                               CompileUnit &CU, DeclContext *CurrentDeclContext,
-                               UniquingStringPool &StringPool,
-                               DeclContextTree &Contexts,
-                               uint64_t ModulesEndOffset,
-                               bool InImportedModule = false) {
+static bool analyzeContextInfo(
+    const DWARFDie &DIE, unsigned ParentIdx, CompileUnit &CU,
+    DeclContext *CurrentDeclContext, UniquingStringPool &StringPool,
+    DeclContextTree &Contexts, uint64_t ModulesEndOffset,
+    std::map<std::string, std::string> &ParseableSwiftInterfaces,
+    std::function<void(const Twine &, const DWARFDie &)> ReportWarning,
+    bool InImportedModule = false) {
   unsigned MyIdx = CU.getOrigUnit().getDIEIndex(DIE);
   CompileUnit::DIEInfo &Info = CU.getInfo(MyIdx);
 
@@ -274,6 +311,7 @@ static bool analyzeContextInfo(const DWA
       dwarf::toString(DIE.find(dwarf::DW_AT_name), "") !=
           CU.getClangModuleName()) {
     InImportedModule = true;
+    analyzeImportedModule(DIE, CU, ParseableSwiftInterfaces, ReportWarning);
   }
 
   Info.ParentIdx = ParentIdx;
@@ -294,9 +332,10 @@ static bool analyzeContextInfo(const DWA
   Info.Prune = InImportedModule;
   if (DIE.hasChildren())
     for (auto Child : DIE.children())
-      Info.Prune &=
-          analyzeContextInfo(Child, MyIdx, CU, CurrentDeclContext, StringPool,
-                             Contexts, ModulesEndOffset, InImportedModule);
+      Info.Prune &= analyzeContextInfo(Child, MyIdx, CU, CurrentDeclContext,
+                                       StringPool, Contexts, ModulesEndOffset,
+                                       ParseableSwiftInterfaces, ReportWarning,
+                                       InImportedModule);
 
   // Prune this DIE if it is either a forward declaration inside a
   // DW_TAG_module or a DW_TAG_module that contains nothing but
@@ -2106,7 +2145,7 @@ static uint64_t getDwoId(const DWARFDie
 }
 
 bool DwarfLinker::registerModuleReference(
-    const DWARFDie &CUDie, const DWARFUnit &Unit, DebugMap &ModuleMap,
+    DWARFDie CUDie, const DWARFUnit &Unit, DebugMap &ModuleMap,
     const DebugMapObject &DMO, RangesTy &Ranges, OffsetsStringPool &StringPool,
     UniquingStringPool &UniquingStringPool, DeclContextTree &ODRContexts,
     uint64_t ModulesEndOffset, unsigned &UnitID, bool IsLittleEndian,
@@ -2117,7 +2156,6 @@ bool DwarfLinker::registerModuleReferenc
     return false;
 
   // Clang module DWARF skeleton CUs abuse this for the path to the module.
-  std::string PCMpath = dwarf::toString(CUDie.find(dwarf::DW_AT_comp_dir), "");
   uint64_t DwoId = getDwoId(CUDie, Unit);
 
   std::string Name = dwarf::toString(CUDie.find(dwarf::DW_AT_name), "");
@@ -2152,7 +2190,8 @@ bool DwarfLinker::registerModuleReferenc
   // Cyclic dependencies are disallowed by Clang, but we still
   // shouldn't run into an infinite loop, so mark it as processed now.
   ClangModules.insert({PCMfile, DwoId});
-  if (Error E = loadClangModule(PCMfile, PCMpath, Name, DwoId, ModuleMap, DMO,
+
+  if (Error E = loadClangModule(CUDie, PCMfile, Name, DwoId, ModuleMap, DMO,
                                 Ranges, StringPool, UniquingStringPool,
                                 ODRContexts, ModulesEndOffset, UnitID,
                                 IsLittleEndian, Indent + 2, Quiet)) {
@@ -2185,17 +2224,16 @@ DwarfLinker::loadObject(const DebugMapOb
 }
 
 Error DwarfLinker::loadClangModule(
-    StringRef Filename, StringRef ModulePath, StringRef ModuleName,
-    uint64_t DwoId, DebugMap &ModuleMap, const DebugMapObject &DMO,
-    RangesTy &Ranges, OffsetsStringPool &StringPool,
-    UniquingStringPool &UniquingStringPool, DeclContextTree &ODRContexts,
-    uint64_t ModulesEndOffset, unsigned &UnitID, bool IsLittleEndian,
-    unsigned Indent, bool Quiet) {
-  SmallString<80> Path(Options.PrependPath);
+    DWARFDie CUDie, StringRef Filename, StringRef ModuleName, uint64_t DwoId,
+    DebugMap &ModuleMap, const DebugMapObject &DMO, RangesTy &Ranges,
+    OffsetsStringPool &StringPool, UniquingStringPool &UniquingStringPool,
+    DeclContextTree &ODRContexts, uint64_t ModulesEndOffset, unsigned &UnitID,
+    bool IsLittleEndian, unsigned Indent, bool Quiet) {
+  /// Using a SmallString<0> because loadClangModule() is recursive.
+  SmallString<0> Path(Options.PrependPath);
   if (sys::path::is_relative(Filename))
-    sys::path::append(Path, ModulePath, Filename);
-  else
-    sys::path::append(Path, Filename);
+    resolveRelativeObjectPath(Path, CUDie);
+  sys::path::append(Path, Filename);
   // Don't use the cached binary holder because we have no thread-safety
   // guarantee and the lifetime is limited.
   auto &Obj = ModuleMap.addDebugMapObject(
@@ -2282,7 +2320,11 @@ Error DwarfLinker::loadClangModule(
                                             ModuleName);
       Unit->setHasInterestingContent();
       analyzeContextInfo(CUDie, 0, *Unit, &ODRContexts.getRoot(),
-                         UniquingStringPool, ODRContexts, ModulesEndOffset);
+                         UniquingStringPool, ODRContexts, ModulesEndOffset,
+                         ParseableSwiftInterfaces,
+                         [&](const Twine &Warning, const DWARFDie &DIE) {
+                           reportWarning(Warning, DMO, &DIE);
+                         });
       // Keep everything.
       Unit->markEverythingAsKept();
     }
@@ -2449,6 +2491,43 @@ bool DwarfLinker::emitPaperTrailWarnings
   return true;
 }
 
+static Error copySwiftInterfaces(
+    const std::map<std::string, std::string> &ParseableSwiftInterfaces,
+    StringRef Architecture, const LinkOptions &Options) {
+  std::error_code EC;
+  SmallString<128> InputPath;
+  SmallString<128> Path;
+  sys::path::append(Path, *Options.ResourceDir, "Swift");
+  if ((EC = sys::fs::create_directories(Path.str(), true,
+                                        sys::fs::perms::all_all)))
+    return make_error<StringError>(
+        "cannot create directory: " + toString(errorCodeToError(EC)), EC);
+  unsigned BaseLength = Path.size();
+
+  for (auto &I : ParseableSwiftInterfaces) {
+    StringRef ModuleName = I.first;
+    StringRef InterfaceFile = I.second;
+    if (!Options.PrependPath.empty()) {
+      InputPath.clear();
+      sys::path::append(InputPath, Options.PrependPath, InterfaceFile);
+      InterfaceFile = InputPath;
+    }
+    sys::path::append(Path, ModuleName);
+    Path.append(".swiftinterface");
+    if (Options.Verbose)
+      outs() << "copy parseable Swift interface " << InterfaceFile << " -> "
+             << Path.str() << '\n';
+
+    // copy_file attempts an APFS clone first, so this should be cheap.
+    if ((EC = sys::fs::copy_file(InterfaceFile, Path.str())))
+      warn(Twine("cannot copy parseable Swift interface ") +
+           InterfaceFile + ": " +
+           toString(errorCodeToError(EC)));
+    Path.resize(BaseLength);
+  }
+  return Error::success();
+}
+
 bool DwarfLinker::link(const DebugMap &Map) {
   if (!createStreamer(Map.getTriple(), OutFile))
     return false;
@@ -2636,7 +2715,11 @@ bool DwarfLinker::link(const DebugMap &M
         continue;
       analyzeContextInfo(CurrentUnit->getOrigUnit().getUnitDIE(), 0,
                          *CurrentUnit, &ODRContexts.getRoot(),
-                         UniquingStringPool, ODRContexts, ModulesEndOffset);
+                         UniquingStringPool, ODRContexts, ModulesEndOffset,
+                         ParseableSwiftInterfaces,
+                         [&](const Twine &Warning, const DWARFDie &DIE) {
+                           reportWarning(Warning, LinkContext.DMO, &DIE);
+                         });
     }
   };
 
@@ -2749,7 +2832,17 @@ bool DwarfLinker::link(const DebugMap &M
     pool.wait();
   }
 
-  return Options.NoOutput ? true : Streamer->finish(Map, Options.Translator);
+  if (Options.NoOutput)
+    return true;
+
+  if (Options.ResourceDir && !ParseableSwiftInterfaces.empty()) {
+    StringRef ArchName = Triple::getArchTypeName(Map.getTriple().getArch());
+    if (auto E =
+            copySwiftInterfaces(ParseableSwiftInterfaces, ArchName, Options))
+      return error(toString(std::move(E)));
+  }
+  
+  return Streamer->finish(Map, Options.Translator);
 } // namespace dsymutil
 
 bool linkDwarf(raw_fd_ostream &OutFile, BinaryHolder &BinHolder,

Modified: llvm/trunk/tools/dsymutil/DwarfLinker.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/dsymutil/DwarfLinker.h?rev=358921&r1=358920&r2=358921&view=diff
==============================================================================
--- llvm/trunk/tools/dsymutil/DwarfLinker.h (original)
+++ llvm/trunk/tools/dsymutil/DwarfLinker.h Mon Apr 22 14:33:22 2019
@@ -193,7 +193,7 @@ private:
   /// A skeleton CU is a CU without children, a DW_AT_gnu_dwo_name
   /// pointing to the module, and a DW_AT_gnu_dwo_id with the module
   /// hash.
-  bool registerModuleReference(const DWARFDie &CUDie, const DWARFUnit &Unit,
+  bool registerModuleReference(DWARFDie CUDie, const DWARFUnit &Unit,
                                DebugMap &ModuleMap, const DebugMapObject &DMO,
                                RangesTy &Ranges,
                                OffsetsStringPool &OffsetsStringPool,
@@ -206,7 +206,7 @@ private:
   /// Recursively add the debug info in this clang module .pcm
   /// file (and all the modules imported by it in a bottom-up fashion)
   /// to Units.
-  Error loadClangModule(StringRef Filename, StringRef ModulePath,
+  Error loadClangModule(DWARFDie CUDie, StringRef FilePath,
                         StringRef ModuleName, uint64_t DwoId,
                         DebugMap &ModuleMap, const DebugMapObject &DMO,
                         RangesTy &Ranges, OffsetsStringPool &OffsetsStringPool,
@@ -494,6 +494,12 @@ private:
   /// Mapping the PCM filename to the DwoId.
   StringMap<uint64_t> ClangModules;
 
+  /// A list of all .swiftinterface files referenced by the debug
+  /// info, mapping Module name to path on disk. The entries need to
+  /// be uniqued and sorted and there are only few entries expected
+  /// per compile unit, which is why this is a std::map.
+  std::map<std::string, std::string> ParseableSwiftInterfaces;
+  
   bool ModuleCacheHintDisplayed = false;
   bool ArchiveHintDisplayed = false;
 };

Modified: llvm/trunk/tools/dsymutil/LinkUtils.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/dsymutil/LinkUtils.h?rev=358921&r1=358920&r2=358921&view=diff
==============================================================================
--- llvm/trunk/tools/dsymutil/LinkUtils.h (original)
+++ llvm/trunk/tools/dsymutil/LinkUtils.h Mon Apr 22 14:33:22 2019
@@ -62,6 +62,9 @@ struct LinkOptions {
   /// -oso-prepend-path
   std::string PrependPath;
 
+  /// The Resources directory in the .dSYM bundle.
+  Optional<std::string> ResourceDir;
+
   /// Symbol map translator.
   SymbolMapTranslator Translator;
 

Modified: llvm/trunk/tools/dsymutil/dsymutil.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/dsymutil/dsymutil.cpp?rev=358921&r1=358920&r2=358921&view=diff
==============================================================================
--- llvm/trunk/tools/dsymutil/dsymutil.cpp (original)
+++ llvm/trunk/tools/dsymutil/dsymutil.cpp Mon Apr 22 14:33:22 2019
@@ -278,23 +278,30 @@ static bool verify(llvm::StringRef Outpu
   return false;
 }
 
-static Expected<std::string> getOutputFileName(llvm::StringRef InputFile) {
+namespace {
+struct OutputLocation {
+  std::string DWARFFile;
+  Optional<std::string> ResourceDir;
+};
+}
+
+static Expected<OutputLocation> getOutputFileName(llvm::StringRef InputFile) {
   if (OutputFileOpt == "-")
-    return OutputFileOpt;
+    return OutputLocation{OutputFileOpt, {}};
 
   // When updating, do in place replacement.
   if (OutputFileOpt.empty() && (Update || !SymbolMap.empty()))
-    return InputFile;
+    return OutputLocation{InputFile, {}};
 
   // If a flat dSYM has been requested, things are pretty simple.
   if (FlatOut) {
     if (OutputFileOpt.empty()) {
       if (InputFile == "-")
-        return "a.out.dwarf";
-      return (InputFile + ".dwarf").str();
+        return OutputLocation{"a.out.dwarf", {}};
+      return OutputLocation{(InputFile + ".dwarf").str(), {}};
     }
 
-    return OutputFileOpt;
+    return OutputLocation{OutputFileOpt, {}};
   }
 
   // We need to create/update a dSYM bundle.
@@ -307,17 +314,18 @@ static Expected<std::string> getOutputFi
   //                <DWARF file(s)>
   std::string DwarfFile =
       InputFile == "-" ? llvm::StringRef("a.out") : InputFile;
-  llvm::SmallString<128> BundleDir(OutputFileOpt);
-  if (BundleDir.empty())
-    BundleDir = DwarfFile + ".dSYM";
-  if (auto E = createBundleDir(BundleDir))
+  llvm::SmallString<128> Path(OutputFileOpt);
+  if (Path.empty())
+    Path = DwarfFile + ".dSYM";
+  if (auto E = createBundleDir(Path))
     return std::move(E);
-  if (auto E = createPlistFile(DwarfFile, BundleDir))
+  if (auto E = createPlistFile(DwarfFile, Path))
     return std::move(E);
 
-  llvm::sys::path::append(BundleDir, "Contents", "Resources", "DWARF",
-                          llvm::sys::path::filename(DwarfFile));
-  return BundleDir.str();
+  llvm::sys::path::append(Path, "Contents", "Resources");
+  StringRef ResourceDir = Path;
+  llvm::sys::path::append(Path, "DWARF", llvm::sys::path::filename(DwarfFile));
+  return OutputLocation{Path.str(), ResourceDir.str()};
 }
 
 /// Parses the command line options into the LinkOptions struct and performs
@@ -544,13 +552,15 @@ int main(int argc, char **argv) {
       // types don't work with std::bind in the ThreadPool implementation.
       std::shared_ptr<raw_fd_ostream> OS;
 
-      Expected<std::string> OutputFileOrErr = getOutputFileName(InputFile);
-      if (!OutputFileOrErr) {
-        WithColor::error() << toString(OutputFileOrErr.takeError());
+      Expected<OutputLocation> OutputLocationOrErr =
+          getOutputFileName(InputFile);
+      if (!OutputLocationOrErr) {
+        WithColor::error() << toString(OutputLocationOrErr.takeError());
         return 1;
       }
+      OptionsOrErr->ResourceDir = OutputLocationOrErr->ResourceDir;
 
-      std::string OutputFile = *OutputFileOrErr;
+      std::string OutputFile = OutputLocationOrErr->DWARFFile;
       if (NeedsTempFiles) {
         TempFiles.emplace_back(Map->getTriple().getArchName().str());
 
@@ -597,12 +607,13 @@ int main(int argc, char **argv) {
       return 1;
 
     if (NeedsTempFiles) {
-      Expected<std::string> OutputFileOrErr = getOutputFileName(InputFile);
-      if (!OutputFileOrErr) {
-        WithColor::error() << toString(OutputFileOrErr.takeError());
+      Expected<OutputLocation> OutputLocationOrErr = getOutputFileName(InputFile);
+      if (!OutputLocationOrErr) {
+        WithColor::error() << toString(OutputLocationOrErr.takeError());
         return 1;
       }
-      if (!MachOUtils::generateUniversalBinary(TempFiles, *OutputFileOrErr,
+      if (!MachOUtils::generateUniversalBinary(TempFiles,
+                                               OutputLocationOrErr->DWARFFile,
                                                *OptionsOrErr, SDKPath))
         return 1;
     }




More information about the llvm-commits mailing list