From 755b2055197d2bfa4c4952ac6d292848282f6bf2 Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Thu, 17 Nov 2011 22:09:43 +0000 Subject: [PATCH] Add the notion of "framework" modules to module maps. Framework modules (obviously) describe frameworks, and understand the header layout of frameworks. llvm-svn: 144921 --- .../include/clang/Basic/DiagnosticLexKinds.td | 2 +- clang/include/clang/Lex/ModuleMap.h | 24 ++++++-- clang/lib/Lex/ModuleMap.cpp | 58 ++++++++++++++++--- .../DependsOnModule.framework/Headers/other.h | 1 + .../DependsOnModule.framework/module.map | 4 ++ 5 files changed, 75 insertions(+), 14 deletions(-) create mode 100644 clang/test/Modules/Inputs/DependsOnModule.framework/Headers/other.h create mode 100644 clang/test/Modules/Inputs/DependsOnModule.framework/module.map diff --git a/clang/include/clang/Basic/DiagnosticLexKinds.td b/clang/include/clang/Basic/DiagnosticLexKinds.td index 5925ef8bd6d0..0f9a8214c550 100644 --- a/clang/include/clang/Basic/DiagnosticLexKinds.td +++ b/clang/include/clang/Basic/DiagnosticLexKinds.td @@ -392,7 +392,7 @@ def note_mmap_prev_definition : Note<"previously defined here">; def err_mmap_header_conflict : Error< "header '%0' is already part of module '%1'">; def err_mmap_header_not_found : Error< - "%select{|umbrella }0 header '%1' not found">; + "%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< diff --git a/clang/include/clang/Lex/ModuleMap.h b/clang/include/clang/Lex/ModuleMap.h index b1eaebddb20a..f4eb773e704e 100644 --- a/clang/include/clang/Lex/ModuleMap.h +++ b/clang/include/clang/Lex/ModuleMap.h @@ -59,19 +59,23 @@ public: /// \brief The headers that are part of this module. llvm::SmallVector Headers; + /// \brief Whether this is a framework module. + bool IsFramework; + /// \brief Whether this is an explicit submodule. bool IsExplicit; /// \brief Construct a top-level module. - explicit Module(StringRef Name, SourceLocation DefinitionLoc) + explicit Module(StringRef Name, SourceLocation DefinitionLoc, + bool IsFramework) : Name(Name), DefinitionLoc(DefinitionLoc), Parent(0), UmbrellaHeader(0), - IsExplicit(false) { } + IsFramework(IsFramework), IsExplicit(false) { } /// \brief Construct a new module or submodule. Module(StringRef Name, SourceLocation DefinitionLoc, Module *Parent, - bool IsExplicit) + bool IsFramework, bool IsExplicit) : Name(Name), DefinitionLoc(DefinitionLoc), Parent(Parent), - UmbrellaHeader(0), IsExplicit(IsExplicit) { + UmbrellaHeader(0), IsFramework(IsFramework), IsExplicit(IsExplicit) { } ~Module(); @@ -79,6 +83,18 @@ public: /// \brief Determine whether this module is a submodule. bool isSubModule() const { return Parent != 0; } + /// \brief Determine whether this module is a part of a framework, + /// either because it is a framework module or because it is a submodule + /// of a framework module. + bool isPartOfFramework() const { + for (const Module *Mod = this; Mod; Mod = Mod->Parent) + if (Mod->IsFramework) + return true; + + return false; + } + + /// \brief Retrieve the full name of this module, including the path from /// its top-level module. std::string getFullModuleName() const; diff --git a/clang/lib/Lex/ModuleMap.cpp b/clang/lib/Lex/ModuleMap.cpp index 393118110aff..b8068cc05d8a 100644 --- a/clang/lib/Lex/ModuleMap.cpp +++ b/clang/lib/Lex/ModuleMap.cpp @@ -162,7 +162,8 @@ ModuleMap::inferFrameworkModule(StringRef ModuleName, if (!UmbrellaHeader) return 0; - Module *Result = new Module(ModuleName, SourceLocation()); + Module *Result = new Module(ModuleName, SourceLocation(), + /*IsFramework=*/true); Result->UmbrellaHeader = UmbrellaHeader; Headers[UmbrellaHeader] = Result; UmbrellaDirs[FrameworkDir] = Result; @@ -177,6 +178,8 @@ static void indent(llvm::raw_ostream &OS, unsigned Spaces) { static void dumpModule(llvm::raw_ostream &OS, ModuleMap::Module *M, unsigned Indent) { indent(OS, Indent); + if (M->IsFramework) + OS << "framework "; if (M->IsExplicit) OS << "explicit "; OS << M->Name << " {\n"; @@ -230,6 +233,7 @@ namespace clang { HeaderKeyword, Identifier, ExplicitKeyword, + FrameworkKeyword, ModuleKeyword, UmbrellaKeyword, StringLiteral, @@ -333,6 +337,7 @@ retry: Tok.Kind = llvm::StringSwitch(Tok.getString()) .Case("header", MMToken::HeaderKeyword) .Case("explicit", MMToken::ExplicitKeyword) + .Case("framework", MMToken::FrameworkKeyword) .Case("module", MMToken::ModuleKeyword) .Case("umbrella", MMToken::UmbrellaKeyword) .Default(MMToken::Identifier); @@ -416,18 +421,26 @@ void ModuleMapParser::skipUntil(MMToken::TokenKind K) { /// \brief Parse a module declaration. /// /// module-declaration: -/// 'module' identifier { module-member* } +/// 'framework'[opt] 'module' identifier { module-member* } /// /// module-member: /// umbrella-declaration /// header-declaration /// 'explicit'[opt] module-declaration void ModuleMapParser::parseModuleDecl() { - assert(Tok.is(MMToken::ExplicitKeyword) || Tok.is(MMToken::ModuleKeyword)); - - // Parse 'explicit' keyword, if present. + assert(Tok.is(MMToken::ExplicitKeyword) || Tok.is(MMToken::ModuleKeyword) || + Tok.is(MMToken::FrameworkKeyword)); + + // Parse 'framework' or 'explicit' keyword, if present. + bool Framework = false; bool Explicit = false; - if (Tok.is(MMToken::ExplicitKeyword)) { + + if (Tok.is(MMToken::FrameworkKeyword)) { + consumeToken(); + Framework = true; + } + // Parse 'explicit' keyword, if present. + else if (Tok.is(MMToken::ExplicitKeyword)) { consumeToken(); Explicit = true; } @@ -481,7 +494,8 @@ void ModuleMapParser::parseModuleDecl() { } // Start defining this module. - ActiveModule = new Module(ModuleName, ModuleNameLoc, ActiveModule, Explicit); + ActiveModule = new Module(ModuleName, ModuleNameLoc, ActiveModule, Framework, + Explicit); ModuleSpace[ModuleName] = ActiveModule; bool Done = false; @@ -562,11 +576,32 @@ void ModuleMapParser::parseUmbrellaDecl() { // Look for this file. llvm::SmallString<128> PathName; PathName += Directory->getName(); - llvm::sys::path::append(PathName, FileName); + unsigned PathLength = PathName.size(); + const FileEntry *File = 0; + if (ActiveModule->isPartOfFramework()) { + // Check whether this file is in the public headers. + llvm::sys::path::append(PathName, "Headers"); + llvm::sys::path::append(PathName, FileName); + File = SourceMgr.getFileManager().getFile(PathName); + + if (!File) { + // Check whether this file is in the private headers. + PathName.resize(PathLength); + llvm::sys::path::append(PathName, "PrivateHeaders"); + 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); + File = SourceMgr.getFileManager().getFile(PathName); + } // FIXME: We shouldn't be eagerly stat'ing every file named in a module map. // Come up with a lazy way to do this. - if (const FileEntry *File = SourceMgr.getFileManager().getFile(PathName)) { + if (File) { if (const Module *OwningModule = Map.Headers[File]) { Diags.Report(FileNameLoc, diag::err_mmap_header_conflict) << FileName << OwningModule->getFullModuleName(); @@ -609,6 +644,10 @@ void ModuleMapParser::parseHeaderDecl() { // Look for this file. llvm::SmallString<128> PathName; PathName += Directory->getName(); + + if (ActiveModule->isPartOfFramework()) + llvm::sys::path::append(PathName, "Headers"); + llvm::sys::path::append(PathName, FileName); // FIXME: We shouldn't be eagerly stat'ing every file named in a module map. @@ -641,6 +680,7 @@ bool ModuleMapParser::parseModuleMapFile() { return HadError; case MMToken::ModuleKeyword: + case MMToken::FrameworkKeyword: parseModuleDecl(); break; diff --git a/clang/test/Modules/Inputs/DependsOnModule.framework/Headers/other.h b/clang/test/Modules/Inputs/DependsOnModule.framework/Headers/other.h new file mode 100644 index 000000000000..5ee3f9274282 --- /dev/null +++ b/clang/test/Modules/Inputs/DependsOnModule.framework/Headers/other.h @@ -0,0 +1 @@ +int depends_on_module_other; diff --git a/clang/test/Modules/Inputs/DependsOnModule.framework/module.map b/clang/test/Modules/Inputs/DependsOnModule.framework/module.map new file mode 100644 index 000000000000..99ecac8bccd2 --- /dev/null +++ b/clang/test/Modules/Inputs/DependsOnModule.framework/module.map @@ -0,0 +1,4 @@ +framework module DependsOnModule { + umbrella "DependsOnModule.h" + header "other.h" +}