Add a new spelling for module map files 'module.modulemap'
authorBen Langmuir <blangmuir@apple.com>
Wed, 19 Mar 2014 20:23:34 +0000 (20:23 +0000)
committerBen Langmuir <blangmuir@apple.com>
Wed, 19 Mar 2014 20:23:34 +0000 (20:23 +0000)
This name, while more verbose, plays more nicely with tools that use
file extensions to determine file types. The existing spelling
'module.map' will continue to work, but the new spelling will take
precedence.

In frameworks, this new filename will only go in a new 'Modules'
sub-directory.

Similarly, add a module.private.modulemap corresponding to
module_private.map.

llvm-svn: 204261

21 files changed:
clang/docs/Modules.rst
clang/include/clang/Lex/HeaderSearch.h
clang/lib/Lex/HeaderSearch.cpp
clang/lib/Lex/ModuleMap.cpp
clang/test/Modules/Inputs/ModuleMapLocations/Both/a.h [new file with mode: 0644]
clang/test/Modules/Inputs/ModuleMapLocations/Both/b.h [new file with mode: 0644]
clang/test/Modules/Inputs/ModuleMapLocations/Both/module.map [new file with mode: 0644]
clang/test/Modules/Inputs/ModuleMapLocations/Both/module.modulemap [new file with mode: 0644]
clang/test/Modules/Inputs/ModuleMapLocations/Both_F.framework/Headers/a.h [new file with mode: 0644]
clang/test/Modules/Inputs/ModuleMapLocations/Both_F.framework/Headers/b.h [new file with mode: 0644]
clang/test/Modules/Inputs/ModuleMapLocations/Both_F.framework/Modules/module.modulemap [new file with mode: 0644]
clang/test/Modules/Inputs/ModuleMapLocations/Both_F.framework/module.map [new file with mode: 0644]
clang/test/Modules/Inputs/ModuleMapLocations/Inferred.framework/Headers/Inferred.h [new file with mode: 0644]
clang/test/Modules/Inputs/ModuleMapLocations/Module_ModuleMap/a.h [new file with mode: 0644]
clang/test/Modules/Inputs/ModuleMapLocations/Module_ModuleMap/module.modulemap [new file with mode: 0644]
clang/test/Modules/Inputs/ModuleMapLocations/Module_ModuleMap_F.framework/Headers/a.h [new file with mode: 0644]
clang/test/Modules/Inputs/ModuleMapLocations/Module_ModuleMap_F.framework/Modules/module.modulemap [new file with mode: 0644]
clang/test/Modules/Inputs/ModuleMapLocations/Module_ModuleMap_F.framework/Modules/module.private.modulemap [new file with mode: 0644]
clang/test/Modules/Inputs/ModuleMapLocations/Module_ModuleMap_F.framework/PrivateHeaders/private.h [new file with mode: 0644]
clang/test/Modules/Inputs/ModuleMapLocations/module.modulemap [new file with mode: 0644]
clang/test/Modules/modulemap-locations.m [new file with mode: 0644]

index 7545bf0..611a5ed 100644 (file)
@@ -144,7 +144,7 @@ Module maps
 -----------
 The crucial link between modules and headers is described by a *module map*, which describes how a collection of existing headers maps on to the (logical) structure of a module. For example, one could imagine a module ``std`` covering the C standard library. Each of the C standard library headers (``<stdio.h>``, ``<stdlib.h>``, ``<math.h>``, etc.) would contribute to the ``std`` module, by placing their respective APIs into the corresponding submodule (``std.io``, ``std.lib``, ``std.math``, etc.). Having a list of the headers that are part of the ``std`` module allows the compiler to build the ``std`` module as a standalone entity, and having the mapping from header names to (sub)modules allows the automatic translation of ``#include`` directives to module imports.
 
-Module maps are specified as separate files (each named ``module.map``) alongside the headers they describe, which allows them to be added to existing software libraries without having to change the library headers themselves (in most cases [#]_). The actual `Module map language`_ is described in a later section.
+Module maps are specified as separate files (each named ``module.modulemap``) alongside the headers they describe, which allows them to be added to existing software libraries without having to change the library headers themselves (in most cases [#]_). The actual `Module map language`_ is described in a later section.
 
 .. note::
 
@@ -237,10 +237,13 @@ Module Map Language
 
 The module map language describes the mapping from header files to the
 logical structure of modules. To enable support for using a library as
-a module, one must write a ``module.map`` file for that library. The
-``module.map`` file is placed alongside the header files themselves,
+a module, one must write a ``module.modulemap`` file for that library. The
+``module.modulemap`` file is placed alongside the header files themselves,
 and is written in the module map language described below.
 
+.. note::
+    For compatibility with previous releases, if a module map file named ``module.modulemap`` is not found, Clang will also search for a file named ``module.map``. This behavior is deprecated and we plan to eventually remove it.
+
 As an example, the module map file for the C standard library might look a bit like this:
 
 .. parsed-literal::
@@ -319,7 +322,7 @@ The ``framework`` qualifier specifies that this module corresponds to a Darwin-s
 .. parsed-literal::
 
   Name.framework/
-    module.map                Module map for the framework
+    Modules/module.modulemap  Module map for the framework
     Headers/                  Subdirectory containing framework headers
     Frameworks/               Subdirectory containing embedded frameworks
     Resources/                Subdirectory containing additional resources
index e326db7..23be927 100644 (file)
@@ -502,6 +502,12 @@ public:
   ///
   /// \returns The module with the given name.
   Module *lookupModule(StringRef ModuleName, bool AllowSearch = true);
+
+
+  /// \brief Try to find a module map file in the given directory, returning
+  /// \c nullptr if none is found.
+  const FileEntry *lookupModuleMapFile(const DirectoryEntry *Dir,
+                                       bool IsFramework);
   
   void IncrementFrameworkLookupCount() { ++NumFrameworkLookups; }
 
@@ -623,26 +629,32 @@ private:
     /// invalid.
     LMM_InvalidModuleMap
   };
-  
+
+  LoadModuleMapResult loadModuleMapFileImpl(const FileEntry *File,
+                                            bool IsSystem);
+
   /// \brief Try to load the module map file in the given directory.
   ///
   /// \param DirName The name of the directory where we will look for a module
   /// map file.
   /// \param IsSystem Whether this is a system header directory.
+  /// \param IsFramework Whether this is a framework directory.
   ///
   /// \returns The result of attempting to load the module map file from the
   /// named directory.
-  LoadModuleMapResult loadModuleMapFile(StringRef DirName, bool IsSystem);
+  LoadModuleMapResult loadModuleMapFile(StringRef DirName, bool IsSystem,
+                                        bool IsFramework);
 
   /// \brief Try to load the module map file in the given directory.
   ///
   /// \param Dir The directory where we will look for a module map file.
   /// \param IsSystem Whether this is a system header directory.
+  /// \param IsFramework Whether this is a framework directory.
   ///
   /// \returns The result of attempting to load the module map file from the
   /// named directory.
   LoadModuleMapResult loadModuleMapFile(const DirectoryEntry *Dir,
-                                        bool IsSystem);
+                                        bool IsSystem, bool IsFramework);
 
   /// \brief Return the HeaderFileInfo structure for the specified FileEntry.
   HeaderFileInfo &getFileInfo(const FileEntry *FE);
index 46d4d41..cb76923 100644 (file)
@@ -165,8 +165,8 @@ Module *HeaderSearch::lookupModule(StringRef ModuleName, bool AllowSearch) {
 
     bool IsSystem = SearchDirs[Idx].isSystemHeaderDirectory();
     // Search for a module map file in this directory.
-    if (loadModuleMapFile(SearchDirs[Idx].getDir(), IsSystem)
-          == LMM_NewlyLoaded) {
+    if (loadModuleMapFile(SearchDirs[Idx].getDir(), IsSystem,
+                          /*IsFramework*/false) == LMM_NewlyLoaded) {
       // We just loaded a module map file; check whether the module is
       // available now.
       Module = ModMap.findModule(ModuleName);
@@ -179,7 +179,8 @@ Module *HeaderSearch::lookupModule(StringRef ModuleName, bool AllowSearch) {
     SmallString<128> NestedModuleMapDirName;
     NestedModuleMapDirName = SearchDirs[Idx].getDir()->getName();
     llvm::sys::path::append(NestedModuleMapDirName, ModuleName);
-    if (loadModuleMapFile(NestedModuleMapDirName, IsSystem) == LMM_NewlyLoaded){
+    if (loadModuleMapFile(NestedModuleMapDirName, IsSystem,
+                          /*IsFramework*/false) == LMM_NewlyLoaded){
       // If we just loaded a module map file, look for the module again.
       Module = ModMap.findModule(ModuleName);
       if (Module)
@@ -1097,8 +1098,8 @@ bool HeaderSearch::hasModuleMap(StringRef FileName,
     if (!Dir)
       return false;
 
-    // Try to load the "module.map" file in this directory.
-    switch (loadModuleMapFile(Dir, IsSystem)) {
+    // Try to load the module map file in this directory.
+    switch (loadModuleMapFile(Dir, IsSystem, /*IsFramework*/false)) {
     case LMM_NewlyLoaded:
     case LMM_AlreadyLoaded:
       // Success. All of the directories we stepped through inherit this module
@@ -1132,36 +1133,84 @@ HeaderSearch::findModuleForHeader(const FileEntry *File) const {
   return ModMap.findModuleForHeader(File);
 }
 
+static const FileEntry *getPrivateModuleMap(StringRef ModuleMapPath,
+                                            const DirectoryEntry *Directory,
+                                            FileManager &FileMgr) {
+  StringRef Filename = llvm::sys::path::filename(ModuleMapPath);
+  SmallString<128>  PrivateFilename(Directory->getName());
+  if (Filename == "module.map")
+    llvm::sys::path::append(PrivateFilename, "module_private.map");
+  else if (Filename == "module.modulemap")
+    llvm::sys::path::append(PrivateFilename, "module.private.modulemap");
+  else
+    return nullptr;
+  return FileMgr.getFile(PrivateFilename);
+}
+
 bool HeaderSearch::loadModuleMapFile(const FileEntry *File, bool IsSystem) {
+  switch (loadModuleMapFileImpl(File, IsSystem)) {
+  case LMM_AlreadyLoaded:
+  case LMM_NewlyLoaded:
+    return false;
+  case LMM_NoDirectory:
+  case LMM_InvalidModuleMap:
+    return true;
+  }
+}
+
+HeaderSearch::LoadModuleMapResult
+HeaderSearch::loadModuleMapFileImpl(const FileEntry *File, bool IsSystem) {
+  assert(File && "expected FileEntry");
+
   const DirectoryEntry *Dir = File->getDir();
-  
-  llvm::DenseMap<const DirectoryEntry *, bool>::iterator KnownDir
-    = DirectoryHasModuleMap.find(Dir);
+  auto KnownDir = DirectoryHasModuleMap.find(Dir);
   if (KnownDir != DirectoryHasModuleMap.end())
-    return !KnownDir->second;
-  
-  bool Result = ModMap.parseModuleMapFile(File, IsSystem);
-  if (!Result && llvm::sys::path::filename(File->getName()) == "module.map") {
-    // If the file we loaded was a module.map, look for the corresponding
-    // module_private.map.
-    SmallString<128> PrivateFilename(Dir->getName());
-    llvm::sys::path::append(PrivateFilename, "module_private.map");
-    if (const FileEntry *PrivateFile = FileMgr.getFile(PrivateFilename))
-      Result = ModMap.parseModuleMapFile(PrivateFile, IsSystem);
+    return KnownDir->second ? LMM_AlreadyLoaded : LMM_InvalidModuleMap;
+
+  if (ModMap.parseModuleMapFile(File, IsSystem)) {
+    DirectoryHasModuleMap[Dir] = false;
+    return LMM_InvalidModuleMap;
   }
-  
-  DirectoryHasModuleMap[Dir] = !Result;  
-  return Result;
+
+  // Try to load a corresponding private module map.
+  if (const FileEntry *PMMFile =
+        getPrivateModuleMap(File->getName(), Dir, FileMgr)) {
+    if (ModMap.parseModuleMapFile(PMMFile, IsSystem)) {
+      DirectoryHasModuleMap[Dir] = false;
+      return LMM_InvalidModuleMap;
+    }
+  }
+
+  // This directory has a module map.
+  DirectoryHasModuleMap[Dir] = true;
+  return LMM_NewlyLoaded;
+}
+
+const FileEntry *
+HeaderSearch::lookupModuleMapFile(const DirectoryEntry *Dir, bool IsFramework) {
+  // For frameworks, the preferred spelling is Modules/module.modulemap, but
+  // module.map at the framework root is also accepted.
+  SmallString<128> ModuleMapFileName(Dir->getName());
+  if (IsFramework)
+    llvm::sys::path::append(ModuleMapFileName, "Modules");
+  llvm::sys::path::append(ModuleMapFileName, "module.modulemap");
+  if (const FileEntry *F = FileMgr.getFile(ModuleMapFileName))
+    return F;
+
+  // Continue to allow module.map
+  ModuleMapFileName = Dir->getName();
+  llvm::sys::path::append(ModuleMapFileName, "module.map");
+  return FileMgr.getFile(ModuleMapFileName);
 }
 
-Module *HeaderSearch::loadFrameworkModule(StringRef Name, 
+Module *HeaderSearch::loadFrameworkModule(StringRef Name,
                                           const DirectoryEntry *Dir,
                                           bool IsSystem) {
   if (Module *Module = ModMap.findModule(Name))
     return Module;
   
   // Try to load a module map file.
-  switch (loadModuleMapFile(Dir, IsSystem)) {
+  switch (loadModuleMapFile(Dir, IsSystem, /*IsFramework*/true)) {
   case LMM_InvalidModuleMap:
     break;
     
@@ -1201,53 +1250,30 @@ Module *HeaderSearch::loadFrameworkModule(StringRef Name,
 
 
 HeaderSearch::LoadModuleMapResult 
-HeaderSearch::loadModuleMapFile(StringRef DirName, bool IsSystem) {
+HeaderSearch::loadModuleMapFile(StringRef DirName, bool IsSystem,
+                                bool IsFramework) {
   if (const DirectoryEntry *Dir = FileMgr.getDirectory(DirName))
-    return loadModuleMapFile(Dir, IsSystem);
+    return loadModuleMapFile(Dir, IsSystem, IsFramework);
   
   return LMM_NoDirectory;
 }
 
 HeaderSearch::LoadModuleMapResult 
-HeaderSearch::loadModuleMapFile(const DirectoryEntry *Dir, bool IsSystem) {
-  llvm::DenseMap<const DirectoryEntry *, bool>::iterator KnownDir
-    = DirectoryHasModuleMap.find(Dir);
+HeaderSearch::loadModuleMapFile(const DirectoryEntry *Dir, bool IsSystem,
+                                bool IsFramework) {
+  auto KnownDir = DirectoryHasModuleMap.find(Dir);
   if (KnownDir != DirectoryHasModuleMap.end())
     return KnownDir->second? LMM_AlreadyLoaded : LMM_InvalidModuleMap;
-  
-  SmallString<128> ModuleMapFileName;
-  ModuleMapFileName += Dir->getName();
-  unsigned ModuleMapDirNameLen = ModuleMapFileName.size();
-  llvm::sys::path::append(ModuleMapFileName, "module.map");
-  if (const FileEntry *ModuleMapFile = FileMgr.getFile(ModuleMapFileName)) {
-    // We have found a module map file. Try to parse it.
-    if (ModMap.parseModuleMapFile(ModuleMapFile, IsSystem)) {
-      // No suitable module map.
-      DirectoryHasModuleMap[Dir] = false;
-      return LMM_InvalidModuleMap;
-    }
 
-    // This directory has a module map.
-    DirectoryHasModuleMap[Dir] = true;
-    
-    // Check whether there is a private module map that we need to load as well.
-    ModuleMapFileName.erase(ModuleMapFileName.begin() + ModuleMapDirNameLen,
-                            ModuleMapFileName.end());
-    llvm::sys::path::append(ModuleMapFileName, "module_private.map");
-    if (const FileEntry *PrivateModuleMapFile
-                                        = FileMgr.getFile(ModuleMapFileName)) {
-      if (ModMap.parseModuleMapFile(PrivateModuleMapFile, IsSystem)) {
-        // No suitable module map.
-        DirectoryHasModuleMap[Dir] = false;
-        return LMM_InvalidModuleMap;
-      }      
-    }
-    
-    return LMM_NewlyLoaded;
+  if (const FileEntry *ModuleMapFile = lookupModuleMapFile(Dir, IsFramework)) {
+    LoadModuleMapResult Result = loadModuleMapFileImpl(ModuleMapFile, IsSystem);
+    // Add Dir explicitly in case ModuleMapFile is in a subdirectory.
+    // E.g. Foo.framework/Modules/module.modulemap
+    //      ^Dir                  ^ModuleMapFile
+    if (Result == LMM_NewlyLoaded)
+      DirectoryHasModuleMap[Dir] = true;
+    return Result;
   }
-  
-  // No suitable module map.
-  DirectoryHasModuleMap[Dir] = false;
   return LMM_InvalidModuleMap;
 }
 
@@ -1285,7 +1311,7 @@ void HeaderSearch::collectAllModules(SmallVectorImpl<Module *> &Modules) {
       continue;
     
     // Try to load a module map file for the search directory.
-    loadModuleMapFile(SearchDirs[Idx].getDir(), IsSystem);
+    loadModuleMapFile(SearchDirs[Idx].getDir(), IsSystem, /*IsFramework*/false);
     
     // Try to load module map files for immediate subdirectories of this search
     // directory.
@@ -1310,7 +1336,8 @@ void HeaderSearch::loadTopLevelSystemModules() {
 
     // Try to load a module map file for the search directory.
     loadModuleMapFile(SearchDirs[Idx].getDir(),
-                      SearchDirs[Idx].isSystemHeaderDirectory());
+                      SearchDirs[Idx].isSystemHeaderDirectory(),
+                      SearchDirs[Idx].isFramework());
   }
 }
 
@@ -1323,7 +1350,8 @@ void HeaderSearch::loadSubdirectoryModuleMaps(DirectoryLookup &SearchDir) {
   llvm::sys::path::native(SearchDir.getDir()->getName(), DirNative);
   for (llvm::sys::fs::directory_iterator Dir(DirNative.str(), EC), DirEnd;
        Dir != DirEnd && !EC; Dir.increment(EC)) {
-    loadModuleMapFile(Dir->path(), SearchDir.isSystemHeaderDirectory());
+    loadModuleMapFile(Dir->path(), SearchDir.isSystemHeaderDirectory(),
+                      SearchDir.isFramework());
   }
 
   SearchDir.setSearchedAllModuleMaps(true);
index d5e8af9..e78806d 100644 (file)
@@ -594,9 +594,9 @@ ModuleMap::inferFrameworkModule(StringRef ModuleName,
         if (inferred == InferredDirectories.end()) {
           // We haven't looked here before. Load a module map, if there is
           // one.
-          SmallString<128> ModMapPath = Parent;
-          llvm::sys::path::append(ModMapPath, "module.map");
-          if (const FileEntry *ModMapFile = FileMgr.getFile(ModMapPath)) {
+          bool IsFrameworkDir = Parent.endswith(".framework");
+          if (const FileEntry *ModMapFile =
+                HeaderInfo.lookupModuleMapFile(ParentDir, IsFrameworkDir)) {
             parseModuleMapFile(ModMapFile, IsSystem);
             inferred = InferredDirectories.find(ParentDir);
           }
@@ -2219,10 +2219,21 @@ bool ModuleMap::parseModuleMapFile(const FileEntry *File, bool IsSystem) {
   const llvm::MemoryBuffer *Buffer = SourceMgr.getBuffer(ID);
   if (!Buffer)
     return ParsedModuleMap[File] = true;
+
+  // Find the directory for the module. For frameworks, that may require going
+  // up from the 'Modules' directory.
+  const DirectoryEntry *Dir = File->getDir();
+  StringRef DirName(Dir->getName());
+  if (llvm::sys::path::filename(DirName) == "Modules") {
+    DirName = llvm::sys::path::parent_path(DirName);
+    if (DirName.endswith(".framework"))
+      Dir = SourceMgr.getFileManager().getDirectory(DirName);
+    assert(Dir && "parent must exist");
+  }
   
   // Parse this module map file.
   Lexer L(ID, SourceMgr.getBuffer(ID), SourceMgr, MMapLangOpts);
-  ModuleMapParser Parser(L, SourceMgr, Target, Diags, *this, File->getDir(),
+  ModuleMapParser Parser(L, SourceMgr, Target, Diags, *this, Dir,
                          BuiltinIncludeDir, IsSystem);
   bool Result = Parser.parseModuleMapFile();
   ParsedModuleMap[File] = Result;
diff --git a/clang/test/Modules/Inputs/ModuleMapLocations/Both/a.h b/clang/test/Modules/Inputs/ModuleMapLocations/Both/a.h
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/clang/test/Modules/Inputs/ModuleMapLocations/Both/b.h b/clang/test/Modules/Inputs/ModuleMapLocations/Both/b.h
new file mode 100644 (file)
index 0000000..3abbd39
--- /dev/null
@@ -0,0 +1 @@
+void wont_be_found1(void);
diff --git a/clang/test/Modules/Inputs/ModuleMapLocations/Both/module.map b/clang/test/Modules/Inputs/ModuleMapLocations/Both/module.map
new file mode 100644 (file)
index 0000000..bf5aaed
--- /dev/null
@@ -0,0 +1,3 @@
+module both {
+  header "b.h"
+}
diff --git a/clang/test/Modules/Inputs/ModuleMapLocations/Both/module.modulemap b/clang/test/Modules/Inputs/ModuleMapLocations/Both/module.modulemap
new file mode 100644 (file)
index 0000000..0bfa096
--- /dev/null
@@ -0,0 +1,3 @@
+module both {
+  header "a.h"
+}
diff --git a/clang/test/Modules/Inputs/ModuleMapLocations/Both_F.framework/Headers/a.h b/clang/test/Modules/Inputs/ModuleMapLocations/Both_F.framework/Headers/a.h
new file mode 100644 (file)
index 0000000..9dabfc0
--- /dev/null
@@ -0,0 +1 @@
+void will_be_found2(void);
diff --git a/clang/test/Modules/Inputs/ModuleMapLocations/Both_F.framework/Headers/b.h b/clang/test/Modules/Inputs/ModuleMapLocations/Both_F.framework/Headers/b.h
new file mode 100644 (file)
index 0000000..26169fa
--- /dev/null
@@ -0,0 +1 @@
+void wont_be_found2(void);
diff --git a/clang/test/Modules/Inputs/ModuleMapLocations/Both_F.framework/Modules/module.modulemap b/clang/test/Modules/Inputs/ModuleMapLocations/Both_F.framework/Modules/module.modulemap
new file mode 100644 (file)
index 0000000..da49ba5
--- /dev/null
@@ -0,0 +1,3 @@
+framework module Both_F {
+  header "a.h"
+}
diff --git a/clang/test/Modules/Inputs/ModuleMapLocations/Both_F.framework/module.map b/clang/test/Modules/Inputs/ModuleMapLocations/Both_F.framework/module.map
new file mode 100644 (file)
index 0000000..8fc108d
--- /dev/null
@@ -0,0 +1,3 @@
+framework module Both_F {
+  header "b.h"
+}
diff --git a/clang/test/Modules/Inputs/ModuleMapLocations/Inferred.framework/Headers/Inferred.h b/clang/test/Modules/Inputs/ModuleMapLocations/Inferred.framework/Headers/Inferred.h
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/clang/test/Modules/Inputs/ModuleMapLocations/Module_ModuleMap/a.h b/clang/test/Modules/Inputs/ModuleMapLocations/Module_ModuleMap/a.h
new file mode 100644 (file)
index 0000000..d571c6e
--- /dev/null
@@ -0,0 +1 @@
+void will_be_found1(void);
diff --git a/clang/test/Modules/Inputs/ModuleMapLocations/Module_ModuleMap/module.modulemap b/clang/test/Modules/Inputs/ModuleMapLocations/Module_ModuleMap/module.modulemap
new file mode 100644 (file)
index 0000000..2ac7cc5
--- /dev/null
@@ -0,0 +1,3 @@
+module module_modulemap {
+  header "a.h"
+}
diff --git a/clang/test/Modules/Inputs/ModuleMapLocations/Module_ModuleMap_F.framework/Headers/a.h b/clang/test/Modules/Inputs/ModuleMapLocations/Module_ModuleMap_F.framework/Headers/a.h
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/clang/test/Modules/Inputs/ModuleMapLocations/Module_ModuleMap_F.framework/Modules/module.modulemap b/clang/test/Modules/Inputs/ModuleMapLocations/Module_ModuleMap_F.framework/Modules/module.modulemap
new file mode 100644 (file)
index 0000000..400f304
--- /dev/null
@@ -0,0 +1,3 @@
+framework module Module_ModuleMap_F {
+  header "a.h"
+}
diff --git a/clang/test/Modules/Inputs/ModuleMapLocations/Module_ModuleMap_F.framework/Modules/module.private.modulemap b/clang/test/Modules/Inputs/ModuleMapLocations/Module_ModuleMap_F.framework/Modules/module.private.modulemap
new file mode 100644 (file)
index 0000000..25a469d
--- /dev/null
@@ -0,0 +1,3 @@
+explicit framework module Module_ModuleMap_F.Private {
+  header "private.h"
+}
diff --git a/clang/test/Modules/Inputs/ModuleMapLocations/Module_ModuleMap_F.framework/PrivateHeaders/private.h b/clang/test/Modules/Inputs/ModuleMapLocations/Module_ModuleMap_F.framework/PrivateHeaders/private.h
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/clang/test/Modules/Inputs/ModuleMapLocations/module.modulemap b/clang/test/Modules/Inputs/ModuleMapLocations/module.modulemap
new file mode 100644 (file)
index 0000000..a8f5d1f
--- /dev/null
@@ -0,0 +1,2 @@
+framework module * {
+}
diff --git a/clang/test/Modules/modulemap-locations.m b/clang/test/Modules/modulemap-locations.m
new file mode 100644 (file)
index 0000000..9acdcd6
--- /dev/null
@@ -0,0 +1,18 @@
+// RUN: rm -rf %t 
+// RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t -I %S/Inputs/ModuleMapLocations/Module_ModuleMap -I %S/Inputs/ModuleMapLocations/Both -F %S/Inputs/ModuleMapLocations -x objective-c -fsyntax-only %s -verify
+
+// regular
+@import module_modulemap;
+@import both;
+// framework
+@import Module_ModuleMap_F;
+@import Module_ModuleMap_F.Private;
+@import Both_F;
+@import Inferred;
+
+void test() {
+  will_be_found1();
+  wont_be_found1(); // expected-warning{{implicit declaration of function 'wont_be_found1' is invalid in C99}}
+  will_be_found2();
+  wont_be_found2(); // expected-warning{{implicit declaration of function 'wont_be_found2' is invalid in C99}}
+}