[Lex] Add support for 'user specified system frameworks' (see test case).

- Developers of system frameworks need a way for their framework to be treated as a "system framework" during development. Otherwise, they are unable to properly test how their framework behaves when installed because of the semantic changes (in warning behavior) applied to system frameworks.

llvm-svn: 154105
This commit is contained in:
Daniel Dunbar 2012-04-05 17:10:06 +00:00
parent 17138613b1
commit 3c9bc4dbdb
8 changed files with 89 additions and 9 deletions

View File

@ -30,6 +30,7 @@
<li><a href="#vectors">Vectors and Extended Vectors</a></li>
<li><a href="#deprecated">Messages on <tt>deprecated</tt> and <tt>unavailable</tt> attributes</a></li>
<li><a href="#attributes-on-enumerators">Attributes on enumerators</a></li>
<li><a href="#user_specified_system_framework">'User-Specified' System Frameworks</a></li>
<li><a href="#availability">Availability attribute</a></li>
<li><a href="#checking_language_features">Checks for Standard Language Features</a>
<ul>
@ -625,6 +626,34 @@ individual enumerators.</p>
<p>Query for this feature with <tt>__has_extension(enumerator_attributes)</tt>.</p>
<!-- ======================================================================= -->
<h2 id="user_specified_system_framework">'User-Specified' System Frameworks</h2>
<!-- ======================================================================= -->
<p>Clang provides a mechanism by which frameworks can be built in such a way
that they will always be treated as being 'system frameworks', even if they are
not present in a system framework directory. This can be useful to system
framework developers who want to be able to test building other applications
with development builds of their framework, including the manner in which the
compiler changes warning behavior for system headers.</p>
<p>Framework developers can opt-in to this mechanism by creating a
'.system_framework' file at the top-level of their framework. That is, the
framework should have contents like:</p>
<pre>
.../TestFramework.framework
.../TestFramework.framework/.system_framework
.../TestFramework.framework/Headers
.../TestFramework.framework/Headers/TestFramework.h
...
</pre>
<p>Clang will treat the presence of this file as an indicator that the framework
should be treated as a system framework, regardless of how it was found in the
framework search path. For consistency, we recommend that such files never be
included in installed versions of the framework.</p>
<!-- ======================================================================= -->
<h2 id="availability">Availability attribute</h2
<!-- ======================================================================= -->

View File

@ -145,17 +145,23 @@ public:
/// \param SuggestedModule If non-null, and the file found is semantically
/// part of a known module, this will be set to the module that should
/// be imported instead of preprocessing/parsing the file found.
///
/// \param InUserSpecifiedSystemHeader [out] If the file is found, set to true
/// if the file is located in a framework that has been user-specified to be
/// treated as a system framework.
const FileEntry *LookupFile(StringRef Filename, HeaderSearch &HS,
SmallVectorImpl<char> *SearchPath,
SmallVectorImpl<char> *RelativePath,
Module **SuggestedModule) const;
Module **SuggestedModule,
bool &InUserSpecifiedSystemHeader) const;
private:
const FileEntry *DoFrameworkLookup(
StringRef Filename, HeaderSearch &HS,
SmallVectorImpl<char> *SearchPath,
SmallVectorImpl<char> *RelativePath,
Module **SuggestedModule) const;
Module **SuggestedModule,
bool &InUserSpecifiedSystemHeader) const;
};

View File

@ -124,6 +124,11 @@ class HeaderSearch {
struct FrameworkCacheEntry {
/// The directory entry which should be used for the cached framework.
const DirectoryEntry *Directory;
/// Whether this framework has been "user-specified" to be treated as if it
/// were a system framework (even if it was found outside a system framework
/// directory).
bool IsUserSpecifiedSystemFramework;
};
FileManager &FileMgr;

View File

@ -204,7 +204,10 @@ const FileEntry *DirectoryLookup::LookupFile(
HeaderSearch &HS,
SmallVectorImpl<char> *SearchPath,
SmallVectorImpl<char> *RelativePath,
Module **SuggestedModule) const {
Module **SuggestedModule,
bool &InUserSpecifiedSystemFramework) const {
InUserSpecifiedSystemFramework = false;
SmallString<1024> TmpDir;
if (isNormalDir()) {
// Concatenate the requested file onto the directory.
@ -239,7 +242,7 @@ const FileEntry *DirectoryLookup::LookupFile(
if (isFramework())
return DoFrameworkLookup(Filename, HS, SearchPath, RelativePath,
SuggestedModule);
SuggestedModule, InUserSpecifiedSystemFramework);
assert(isHeaderMap() && "Unknown directory lookup");
const FileEntry * const Result = getHeaderMap()->LookupFile(
@ -266,7 +269,8 @@ const FileEntry *DirectoryLookup::DoFrameworkLookup(
HeaderSearch &HS,
SmallVectorImpl<char> *SearchPath,
SmallVectorImpl<char> *RelativePath,
Module **SuggestedModule) const
Module **SuggestedModule,
bool &InUserSpecifiedSystemFramework) const
{
FileManager &FileMgr = HS.getFileMgr();
@ -303,15 +307,27 @@ const FileEntry *DirectoryLookup::DoFrameworkLookup(
HS.IncrementFrameworkLookupCount();
// If the framework dir doesn't exist, we fail.
// FIXME: It's probably more efficient to query this with FileMgr.getDir.
if (!llvm::sys::fs::exists(FrameworkName.str()))
return 0;
const DirectoryEntry *Dir = FileMgr.getDirectory(FrameworkName.str());
if (Dir == 0) return 0;
// Otherwise, if it does, remember that this is the right direntry for this
// framework.
CacheEntry.Directory = getFrameworkDir();
// If this is a user search directory, check if the framework has been
// user-specified as a system framework.
if (getDirCharacteristic() == SrcMgr::C_User) {
SmallString<1024> SystemFrameworkMarker(FrameworkName);
SystemFrameworkMarker += ".system_framework";
if (llvm::sys::fs::exists(SystemFrameworkMarker.str())) {
CacheEntry.IsUserSpecifiedSystemFramework = true;
}
}
}
// Set the 'user-specified system framework' flag.
InUserSpecifiedSystemFramework = CacheEntry.IsUserSpecifiedSystemFramework;
if (RelativePath != NULL) {
RelativePath->clear();
RelativePath->append(Filename.begin()+SlashPos+1, Filename.end());
@ -476,9 +492,10 @@ const FileEntry *HeaderSearch::LookupFile(
// Check each directory in sequence to see if it contains this file.
for (; i != SearchDirs.size(); ++i) {
bool InUserSpecifiedSystemFramework = false;
const FileEntry *FE =
SearchDirs[i].LookupFile(Filename, *this, SearchPath, RelativePath,
SuggestedModule);
SuggestedModule, InUserSpecifiedSystemFramework);
if (!FE) continue;
CurDir = &SearchDirs[i];
@ -487,6 +504,12 @@ const FileEntry *HeaderSearch::LookupFile(
HeaderFileInfo &HFI = getFileInfo(FE);
HFI.DirInfo = CurDir->getDirCharacteristic();
// If the directory characteristic is User but this framework was
// user-specified to be treated as a system framework, promote the
// characteristic.
if (HFI.DirInfo == SrcMgr::C_User && InUserSpecifiedSystemFramework)
HFI.DirInfo = SrcMgr::C_System;
// If this file is found in a header map and uses the framework style of
// includes, then this header is part of a framework we're building.
if (CurDir->isIndexHeaderMap()) {

View File

@ -0,0 +1,3 @@
static inline int another_test_framework_func(unsigned a) {
return a;
}

View File

@ -0,0 +1,6 @@
// Include a subframework header.
#include <AnotherTestFramework/AnotherTestFramework.h>
static inline int test_framework_func(unsigned a) {
return a;
}

View File

@ -0,0 +1,8 @@
// RUN: %clang -cc1 -fsyntax-only -F %S/Inputs -Wsign-conversion -verify %s
// Check that TestFramework is treated as a system header.
#include <TestFramework/TestFramework.h>
int f1() {
return test_framework_func(1) + another_test_framework_func(2);
}