Implement modules support for subframeworks (aka embedded

frameworks). A submodule can now be labeled as a "framework", and
header search will look into the appropriate Headers/PrivateHeaders
subdirectories for named headers.



git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@145941 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Douglas Gregor 2011-12-06 17:16:41 +00:00
parent 8075ce62f7
commit d620a84a01
6 changed files with 61 additions and 21 deletions

View File

@ -395,8 +395,6 @@ def err_mmap_header_not_found : Error<
"%select{|umbrella }0header '%1' not found">;
def err_mmap_umbrella_header_conflict : Error<
"module '%0' already has an umbrella header ('%1')">;
def err_mmap_umbrella_header_submodule : Error<
"submodule '%0' can not have an umbrella header">;
def err_mmap_umbrella_clash : Error<
"umbrella header for module '%0' already covers this directory">;
def err_mmap_export_module_id : Error<

View File

@ -251,6 +251,8 @@ ModuleMap::inferFrameworkModule(StringRef ModuleName,
Result->InferSubmodules = true;
Result->InferExportWildcard = true;
// FIXME: Look for subframeworks.
Modules[ModuleName] = Result;
return Result;
}
@ -559,19 +561,21 @@ void ModuleMapParser::parseModuleDecl() {
assert(Tok.is(MMToken::ExplicitKeyword) || Tok.is(MMToken::ModuleKeyword) ||
Tok.is(MMToken::FrameworkKeyword));
// Parse 'framework' or 'explicit' keyword, if present.
bool Framework = false;
// Parse 'explicit' or 'framework' keyword, if present.
bool Explicit = false;
bool Framework = false;
// Parse 'explicit' keyword, if present.
if (Tok.is(MMToken::ExplicitKeyword)) {
consumeToken();
Explicit = true;
}
// Parse 'framework' keyword, if present.
if (Tok.is(MMToken::FrameworkKeyword)) {
consumeToken();
Framework = true;
}
// Parse 'explicit' keyword, if present.
else if (Tok.is(MMToken::ExplicitKeyword)) {
consumeToken();
Explicit = true;
}
// Parse 'module' keyword.
if (!Tok.is(MMToken::ModuleKeyword)) {
@ -640,6 +644,7 @@ void ModuleMapParser::parseModuleDecl() {
break;
case MMToken::ExplicitKeyword:
case MMToken::FrameworkKeyword:
case MMToken::ModuleKeyword:
parseModuleDecl();
break;
@ -674,7 +679,27 @@ void ModuleMapParser::parseModuleDecl() {
// We're done parsing this module. Pop back to our parent scope.
ActiveModule = ActiveModule->Parent;
}
/// \brief Append to \p Paths the set of paths needed to get to the
/// subframework in which the given module lives.
void appendSubframeworkPaths(Module *Mod, llvm::SmallVectorImpl<char> &Path) {
// Collect the framework names from the given module to the top-level module.
llvm::SmallVector<StringRef, 2> Paths;
for (; Mod; Mod = Mod->Parent) {
if (Mod->IsFramework)
Paths.push_back(Mod->Name);
}
if (Paths.empty())
return;
// Add Frameworks/Name.framework for each subframework.
for (unsigned I = Paths.size() - 1; I != 0; --I) {
llvm::sys::path::append(Path, "Frameworks");
llvm::sys::path::append(Path, Paths[I-1] + ".framework");
}
}
/// \brief Parse an umbrella header declaration.
///
/// umbrella-declaration:
@ -702,14 +727,6 @@ void ModuleMapParser::parseUmbrellaDecl() {
return;
}
// Only top-level modules can have umbrella headers.
if (ActiveModule->Parent) {
Diags.Report(UmbrellaLoc, diag::err_mmap_umbrella_header_submodule)
<< ActiveModule->getFullModuleName();
HadError = true;
return;
}
// Look for this file.
llvm::SmallString<128> PathName;
const FileEntry *File = 0;
@ -721,7 +738,10 @@ void ModuleMapParser::parseUmbrellaDecl() {
// Search for the header file within the search directory.
PathName += Directory->getName();
unsigned PathLength = PathName.size();
if (ActiveModule->isPartOfFramework()) {
appendSubframeworkPaths(ActiveModule, PathName);
// Check whether this file is in the public headers.
llvm::sys::path::append(PathName, "Headers");
llvm::sys::path::append(PathName, FileName);
@ -734,8 +754,6 @@ void ModuleMapParser::parseUmbrellaDecl() {
llvm::sys::path::append(PathName, FileName);
File = SourceMgr.getFileManager().getFile(PathName);
}
// FIXME: Deal with subframeworks.
} else {
// Lookup for normal headers.
llvm::sys::path::append(PathName, FileName);
@ -797,8 +815,10 @@ void ModuleMapParser::parseHeaderDecl() {
// FIXME: Change this search to also look for private headers!
PathName += Directory->getName();
if (ActiveModule->isPartOfFramework())
if (ActiveModule->isPartOfFramework()) {
appendSubframeworkPaths(ActiveModule, PathName);
llvm::sys::path::append(PathName, "Headers");
}
}
llvm::sys::path::append(PathName, FileName);

View File

@ -0,0 +1 @@
double *sub_framework_other;

View File

@ -0,0 +1,2 @@
#include "SubFramework/Other.h"
float *sub_framework;

View File

@ -4,4 +4,7 @@ framework module DependsOnModule {
module * {
export *
}
explicit framework module SubFramework {
umbrella "SubFramework.h"
}
}

View File

@ -0,0 +1,16 @@
// RUN: rm -rf %t
// RUN: %clang_cc1 -Wauto-import -fmodule-cache-path %t -fauto-module-import -F %S/Inputs %s -verify
__import_module__ DependsOnModule;
void testSubFramework() {
float *sf1 = sub_framework; // expected-error{{use of undeclared identifier 'sub_framework'}}
}
__import_module__ DependsOnModule.SubFramework;
void testSubFrameworkAgain() {
float *sf2 = sub_framework;
double *sfo1 = sub_framework_other;
}