Pārlūkot izejas kodu

Use export_as for autolinking frameworks

framework module SomeKitCore {
  ...
  export_as SomeKit
}

Given the module above, while generting autolink information during
codegen, clang should to emit '-framework SomeKitCore' only if SomeKit
was not imported in the relevant TU, otherwise it should use '-framework
SomeKit' instead.

rdar://problem/38269782

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@330152 91177308-0d34-0410-b5e6-96231b3b80d8
Bruno Cardoso Lopes 7 gadi atpakaļ
vecāks
revīzija
c995be9ca4

+ 4 - 0
include/clang/Basic/Module.h

@@ -331,6 +331,10 @@ public:
   /// an entity from this module is used.
   llvm::SmallVector<LinkLibrary, 2> LinkLibraries;
 
+  /// Autolinking uses the framework name for linking purposes
+  /// when this is false and the export_as name otherwise.
+  bool UseExportAsModuleLinkName = false;
+
   /// \brief The set of "configuration macros", which are macros that
   /// (intentionally) change how this module is built.
   std::vector<std::string> ConfigMacros;

+ 13 - 0
include/clang/Lex/ModuleMap.h

@@ -21,6 +21,7 @@
 #include "llvm/ADT/ArrayRef.h"
 #include "llvm/ADT/DenseMap.h"
 #include "llvm/ADT/PointerIntPair.h"
+#include "llvm/ADT/StringSet.h"
 #include "llvm/ADT/SmallPtrSet.h"
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/ADT/StringMap.h"
@@ -104,7 +105,19 @@ class ModuleMap {
   /// \brief The number of modules we have created in total.
   unsigned NumCreatedModules = 0;
 
+  /// In case a module has a export_as entry, it might have a pending link
+  /// name to be determined if that module is imported.
+  llvm::StringMap<llvm::StringSet<>> PendingLinkAsModule;
+
 public:
+  /// Use PendingLinkAsModule information to mark top level link names that
+  /// are going to be replaced by export_as aliases.
+  void resolveLinkAsDependencies(Module *Mod);
+
+  /// Make module to use export_as as the link dependency name if enough
+  /// information is available or add it to a pending list otherwise.
+  void addLinkAsDependency(Module *Mod);
+
   /// \brief Flags describing the role of a module header.
   enum ModuleHeaderRole {
     /// \brief This header is normally included in the module.

+ 6 - 0
lib/CodeGen/CodeGenModule.cpp

@@ -1556,6 +1556,12 @@ static void addLinkOptionsPostorder(CodeGenModule &CGM, Module *Mod,
   // Add linker options to link against the libraries/frameworks
   // described by this module.
   llvm::LLVMContext &Context = CGM.getLLVMContext();
+
+  // For modules that use export_as for linking, use that module
+  // name instead.
+  if (Mod->UseExportAsModuleLinkName)
+    return;
+
   for (unsigned I = Mod->LinkLibraries.size(); I > 0; --I) {
     // Link against a framework.  Frameworks are currently Darwin only, so we
     // don't to ask TargetCodeGenInfo for the spelling of the linker option.

+ 6 - 0
lib/Frontend/CompilerInstance.cpp

@@ -1979,6 +1979,12 @@ CompilerInstance::loadModule(SourceLocation ImportLoc,
                      Module, ImportLoc);
   }
 
+  // Resolve any remaining module using export_as for this one.
+  getPreprocessor()
+      .getHeaderSearchInfo()
+      .getModuleMap()
+      .resolveLinkAsDependencies(TopModule);
+
   LastModuleImportLoc = ImportLoc;
   LastModuleImportResult = ModuleLoadResult(Module);
   return LastModuleImportResult;

+ 20 - 0
lib/Lex/ModuleMap.cpp

@@ -54,6 +54,24 @@
 
 using namespace clang;
 
+void ModuleMap::resolveLinkAsDependencies(Module *Mod) {
+  auto PendingLinkAs = PendingLinkAsModule.find(Mod->Name);
+  if (PendingLinkAs != PendingLinkAsModule.end()) {
+    for (auto &Name : PendingLinkAs->second) {
+      auto *M = findModule(Name.getKey());
+      if (M)
+        M->UseExportAsModuleLinkName = true;
+    }
+  }
+}
+
+void ModuleMap::addLinkAsDependency(Module *Mod) {
+  if (findModule(Mod->ExportAsModule))
+    Mod->UseExportAsModuleLinkName = true;
+  else
+    PendingLinkAsModule[Mod->ExportAsModule].insert(Mod->Name);
+}
+
 Module::HeaderKind ModuleMap::headerRoleToKind(ModuleHeaderRole Role) {
   switch ((int)Role) {
   default: llvm_unreachable("unknown header role");
@@ -2412,6 +2430,8 @@ void ModuleMapParser::parseExportAsDecl() {
   }
   
   ActiveModule->ExportAsModule = Tok.getString();
+  Map.addLinkAsDependency(ActiveModule);
+
   consumeToken();
 }
 

+ 2 - 0
lib/Serialization/ASTReader.cpp

@@ -5171,6 +5171,7 @@ ASTReader::ReadSubmoduleBlock(ModuleFile &F, unsigned ClientLoadCapabilities) {
       break;
 
     case SUBMODULE_LINK_LIBRARY:
+      ModMap.resolveLinkAsDependencies(CurrentModule);
       CurrentModule->LinkLibraries.push_back(
                                          Module::LinkLibrary(Blob, Record[0]));
       break;
@@ -5203,6 +5204,7 @@ ASTReader::ReadSubmoduleBlock(ModuleFile &F, unsigned ClientLoadCapabilities) {
 
     case SUBMODULE_EXPORT_AS:
       CurrentModule->ExportAsModule = Blob.str();
+      ModMap.addLinkAsDependency(CurrentModule);
       break;
     }
   }

+ 6 - 0
test/Modules/Inputs/exportas-link/OtherKit.framework/Headers/OtherKit.h

@@ -0,0 +1,6 @@
+#import <SomeKitCore/SomeKitCore.h>
+
+#ifdef F
+#import <SomeKit/SomeKit.h>
+#endif
+

+ 5 - 0
test/Modules/Inputs/exportas-link/OtherKit.framework/Modules/module.modulemap

@@ -0,0 +1,5 @@
+
+framework module OtherKit {
+  header "OtherKit.h"
+  export *
+}

+ 1 - 0
test/Modules/Inputs/exportas-link/SomeKit.framework/Headers/SKWidget.h

@@ -0,0 +1 @@
+#import <SomeKitCore/SKWidget.h>

+ 1 - 0
test/Modules/Inputs/exportas-link/SomeKit.framework/Headers/SomeKit.h

@@ -0,0 +1 @@
+#import <SomeKit/SKWidget.h>

+ 6 - 0
test/Modules/Inputs/exportas-link/SomeKit.framework/Modules/module.modulemap

@@ -0,0 +1,6 @@
+framework module SomeKit {
+  umbrella header "SomeKit.h"
+  module * {
+    export *
+  }
+}

+ 1 - 0
test/Modules/Inputs/exportas-link/SomeKit.framework/SomeKit.tbd

@@ -0,0 +1 @@
+dummy tbd file

+ 4 - 0
test/Modules/Inputs/exportas-link/SomeKitCore.framework/Headers/SKWidget.h

@@ -0,0 +1,4 @@
+@interface SKWidget
+- (void)someObjCMethod;
+@end
+

+ 1 - 0
test/Modules/Inputs/exportas-link/SomeKitCore.framework/Headers/SomeKitCore.h

@@ -0,0 +1 @@
+#import <SomeKitCore/SKWidget.h>

+ 7 - 0
test/Modules/Inputs/exportas-link/SomeKitCore.framework/Modules/module.modulemap

@@ -0,0 +1,7 @@
+framework module SomeKitCore {
+  umbrella header "SomeKitCore.h"
+  export_as SomeKit
+  module * {
+    export *
+  }
+}

+ 1 - 0
test/Modules/Inputs/exportas-link/SomeKitCore.framework/SomeKitCore.tbd

@@ -0,0 +1 @@
+dummy tbd file

+ 44 - 0
test/Modules/use-exportas-for-link.m

@@ -0,0 +1,44 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -emit-llvm -o - -fmodules-cache-path=%t -DA -fmodules -fimplicit-module-maps -F %S/Inputs/exportas-link %s | FileCheck --check-prefix=CHECK_A %s
+// CHECK_A: !llvm.linker.options = !{![[MODULE:[0-9]+]]}
+// CHECK_A: ![[MODULE]] = !{!"-framework", !"SomeKit"}
+#ifdef A
+@import SomeKitCore;
+@import SomeKit;
+#endif
+
+// RUN: %clang_cc1 -emit-llvm -o - -fmodules-cache-path=%t -DB -fmodules -fimplicit-module-maps -F %S/Inputs/exportas-link %s | FileCheck --check-prefix=CHECK_B %s
+// CHECK_B: !llvm.linker.options = !{![[MODULE:[0-9]+]]}
+// CHECK_B: ![[MODULE]] = !{!"-framework", !"SomeKit"}
+#ifdef B
+@import SomeKit;
+@import SomeKitCore;
+#endif
+
+// RUN: %clang_cc1 -emit-llvm -o - -fmodules-cache-path=%t -DC -fmodules -fimplicit-module-maps -F %S/Inputs/exportas-link %s | FileCheck --check-prefix=CHECK_C %s
+// CHECK_C: !llvm.linker.options = !{![[MODULE:[0-9]+]]}
+// CHECK_C: ![[MODULE]] = !{!"-framework", !"SomeKitCore"}
+#ifdef C
+@import SomeKitCore;
+#endif
+
+// RUN: %clang_cc1 -emit-llvm -o - -fmodules-cache-path=%t -DD -fmodules -fimplicit-module-maps -F %S/Inputs/exportas-link %s | FileCheck --check-prefix=CHECK_D %s
+// CHECK_D: !llvm.linker.options = !{![[MODULE:[0-9]+]]}
+// CHECK_D: ![[MODULE]] = !{!"-framework", !"SomeKit"}
+#ifdef D
+@import SomeKit;
+#endif
+
+// RUN: %clang_cc1 -emit-llvm -o - -fmodules-cache-path=%t -DE -fmodules -fimplicit-module-maps -F %S/Inputs/exportas-link %s | FileCheck --check-prefix=CHECK_E %s
+// CHECK_E: !llvm.linker.options = !{![[MODULE:[0-9]+]]}
+// CHECK_E: ![[MODULE]] = !{!"-framework", !"SomeKitCore"}
+#ifdef E
+@import OtherKit;
+#endif
+
+// RUN: %clang_cc1 -emit-llvm -o - -fmodules-cache-path=%t -DF -fmodules -fimplicit-module-maps -F %S/Inputs/exportas-link %s | FileCheck --check-prefix=CHECK_F %s
+// CHECK_F: !llvm.linker.options = !{![[MODULE:[0-9]+]]}
+// CHECK_F: ![[MODULE]] = !{!"-framework", !"SomeKit"}
+#ifdef F
+@import OtherKit;
+#endif