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

llvm-svn: 330152
This commit is contained in:
Bruno Cardoso Lopes 2018-04-16 19:42:32 +00:00
parent 1c3bd2ff0c
commit a3b5f71eaa
17 changed files with 128 additions and 0 deletions

View File

@ -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;

View File

@ -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.

View File

@ -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.

View File

@ -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;

View File

@ -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();
}

View File

@ -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;
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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