Introduce the notion of "Relocatable" precompiled headers, which are built

with a particular system root directory and can be used with a different
system root directory when the headers it depends on have been installed.
Relocatable precompiled headers rewrite the file names of the headers used
when generating the PCH file into the corresponding file names of the 
headers available when using the PCH file.

Addresses <rdar://problem/7001604>.



git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@74885 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Douglas Gregor 2009-07-07 00:12:59 +00:00
Родитель 169077dde4
Коммит e650c8c3bc
14 изменённых файлов: 325 добавлений и 64 удалений

Просмотреть файл

@ -465,6 +465,50 @@ for headers that are directly included within a source file. For example:</p>
<tt>test.h</tt> since <tt>test.h</tt> was included directly in the source file
and not specified on the command line using <tt>-include</tt>.</p>
<h4>Relocatable PCH Files</h4>
<p>It is sometimes necessary to build a precompiled header from headers that
are not yet in their final, installed locations. For example, one might build a
precompiled header within the build tree that is then meant to be installed
alongside the headers. Clang permits the creation of "relocatable" precompiled
headers, which are built with a given path (into the build directory) and can
later be used from an installed location.</p>
<p>To build a relocatable precompiled header, place your headers into a
subdirectory whose structure mimics the installed location. For example, if you
want to build a precompiled header for the header <code>mylib.h</code> that
will be installed into <code>/usr/include</code>, create a subdirectory
<code>build/usr/include</code> and place the header <code>mylib.h</code> into
that subdirectory. If <code>mylib.h</code> depends on other headers, then
they can be stored within <code>build/usr/include</code> in a way that mimics
the installed location.</p>
<p>Building a relocatable precompiled header requires two additional arguments.
First, pass the <code>--relocatable-pch</code> flag to indicate that the
resulting PCH file should be relocatable. Second, pass
<code>-isysroot /path/to/build</code>, which makes all includes for your
library relative to the build directory. For example:</p>
<pre>
# clang -x c-header --relocatable-pch -isysroot /path/to/build /path/to/build/mylib.h mylib.h.pch
</pre>
<p>When loading the relocatable PCH file, the various headers used in the PCH
file are found from the system header root. For example, <code>mylib.h</code>
can be found in <code>/usr/include/mylib.h</code>. If the headers are installed
in some other system root, the <code>-isysroot</code> option can be used provide
a different system root from which the headers will be based. For example,
<code>-isysroot /Developer/SDKs/MacOSX10.4u.sdk</code> will look for
<code>mylib.h</code> in
<code>/Developer/SDKs/MacOSX10.4u.sdk/usr/include/mylib.h</code>.</p>
<p>Relocatable precompiled headers are intended to be used in a limited number
of cases where the compilation environment is tightly controlled and the
precompiled header cannot be generated after headers have been installed.
Relocatable precompiled headers also have some performance impact, because
the difference in location between the header locations at PCH build time vs.
at the time of PCH use requires one of the PCH optimizations,
<code>stat()</code> caching, to be disabled. However, this change is only
likely to affect PCH files that reference a large number of headers.</p>
<!-- ======================================================================= -->
<h2 id="c">C Language Features</h2>

Просмотреть файл

@ -24,6 +24,9 @@ def warn_fixit_no_changes : Note<
"FIX-IT detected errors it could not fix; no output will be generated">;
// PCH reader
def err_relocatable_without_without_isysroot : Error<
"must specify system root with -isysroot when building a relocatable "
"PCH file">;
def warn_pch_target_triple : Error<
"PCH file was compiled for the target '%0' but the current translation "
"unit is being compiled for target '%1'">;

Просмотреть файл

@ -223,6 +223,8 @@ OPTION("--print-prog-name", _print_prog_name, Separate, INVALID, print_prog_name
OPTION("--print-search-dirs", _print_search_dirs, Flag, INVALID, print_search_dirs, "", 0, 0, 0)
OPTION("--profile-blocks", _profile_blocks, Flag, INVALID, a, "", 0, 0, 0)
OPTION("--profile", _profile, Flag, INVALID, p, "", 0, 0, 0)
OPTION("--relocatable-pch", _relocatable_pch, Flag, INVALID, INVALID, "", 0,
"Build a relocatable precompiled header", 0)
OPTION("--resource=", _resource_EQ, Joined, INVALID, fcompile_resource_EQ, "", 0, 0, 0)
OPTION("--resource", _resource, Separate, INVALID, fcompile_resource_EQ, "J", 0, 0, 0)
OPTION("--save-temps", _save_temps, Flag, INVALID, save_temps, "", 0, 0, 0)

Просмотреть файл

@ -92,7 +92,8 @@ ASTConsumer* CreateHTMLPrinter(llvm::raw_ostream *OS, Diagnostic &D,
// used later with the PCHReader (clang-cc option -include-pch)
// to speed up compile times.
ASTConsumer *CreatePCHGenerator(const Preprocessor &PP,
llvm::raw_ostream *OS);
llvm::raw_ostream *OS,
const char *isysroot = 0);
// Block rewriter: rewrites code using the Apple blocks extension to pure
// C code. Output is always sent to stdout.

Просмотреть файл

@ -310,6 +310,13 @@ private:
/// file.
std::string OriginalFileName;
/// \brief Whether this precompiled header is a relocatable PCH file.
bool RelocatablePCH;
/// \brief The system include root to be used when loading the
/// precompiled header.
const char *isysroot;
/// \brief Mapping from switch-case IDs in the PCH file to
/// switch-case statements.
std::map<unsigned, SwitchCase *> SwitchCaseStmts;
@ -428,10 +435,13 @@ private:
/// predefines buffer may contain additional definitions.
std::string SuggestedPredefines;
void MaybeAddSystemRootToFilename(std::string &Filename);
PCHReadResult ReadPCHBlock();
bool CheckPredefinesBuffer(const char *PCHPredef,
unsigned PCHPredefLen,
FileID PCHBufferID);
bool ParseLineTable(llvm::SmallVectorImpl<uint64_t> &Record);
PCHReadResult ReadSourceManagerBlock();
PCHReadResult ReadSLocEntryRecord(unsigned ID);
@ -448,19 +458,42 @@ private:
PCHReader(const PCHReader&); // do not implement
PCHReader &operator=(const PCHReader &); // do not implement
public:
typedef llvm::SmallVector<uint64_t, 64> RecordData;
/// \brief Load the PCH file and validate its contents against the given
/// Preprocessor.
PCHReader(Preprocessor &PP, ASTContext *Context);
///
/// \param PP the preprocessor associated with the context in which this
/// precompiled header will be loaded.
///
/// \param Context the AST context that this precompiled header will be
/// loaded into.
///
/// \param isysroot If non-NULL, the system include path specified by the
/// user. This is only used with relocatable PCH files. If non-NULL,
/// a relocatable PCH file will use the default path "/".
PCHReader(Preprocessor &PP, ASTContext *Context, const char *isysroot = 0);
/// \brief Load the PCH file without using any pre-initialized Preprocessor.
///
/// The necessary information to initialize a Preprocessor later can be
/// obtained by setting a PCHReaderListener.
PCHReader(SourceManager &SourceMgr, FileManager &FileMgr, Diagnostic &Diags);
///
/// \param SourceMgr the source manager into which the precompiled header
/// will be loaded.
///
/// \param FileMgr the file manager into which the precompiled header will
/// be loaded.
///
/// \param Diags the diagnostics system to use for reporting errors and
/// warnings relevant to loading the precompiled header.
///
/// \param isysroot If non-NULL, the system include path specified by the
/// user. This is only used with relocatable PCH files. If non-NULL,
/// a relocatable PCH file will use the default path "/".
PCHReader(SourceManager &SourceMgr, FileManager &FileMgr,
Diagnostic &Diags, const char *isysroot = 0);
~PCHReader();
/// \brief Load the precompiled header designated by the given file

Просмотреть файл

@ -160,11 +160,12 @@ private:
unsigned NumVisibleDeclContexts;
void WriteBlockInfoBlock();
void WriteMetadata(ASTContext &Context);
void WriteMetadata(ASTContext &Context, const char *isysroot);
void WriteLanguageOptions(const LangOptions &LangOpts);
void WriteStatCache(MemorizeStatCalls &StatCalls);
void WriteStatCache(MemorizeStatCalls &StatCalls, const char* isysroot);
void WriteSourceManagerBlock(SourceManager &SourceMgr,
const Preprocessor &PP);
const Preprocessor &PP,
const char* isysroot);
void WritePreprocessor(const Preprocessor &PP);
void WriteComments(ASTContext &Context);
void WriteType(const Type *T);
@ -186,7 +187,17 @@ public:
PCHWriter(llvm::BitstreamWriter &Stream);
/// \brief Write a precompiled header for the given semantic analysis.
void WritePCH(Sema &SemaRef, MemorizeStatCalls *StatCalls);
///
/// \param SemaRef a reference to the semantic analysis object that processed
/// the AST to be written into the precompiled header.
///
/// \param StatCalls the object that cached all of the stat() calls made while
/// searching for source files and headers.
///
/// \param isysroot if non-NULL, write a relocatable PCH file whose headers
/// are relative to the given system root.
void WritePCH(Sema &SemaRef, MemorizeStatCalls *StatCalls,
const char* isysroot);
/// \brief Emit a source location.
void AddSourceLocation(SourceLocation Loc, RecordData &Record);

Просмотреть файл

@ -474,6 +474,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back(A->getValue(Args));
}
if (Args.hasArg(options::OPT__relocatable_pch, true))
CmdArgs.push_back("--relocatable-pch");
// Forward -f options which we can pass directly.
Args.AddLastArg(CmdArgs, options::OPT_femit_all_decls);
Args.AddLastArg(CmdArgs, options::OPT_fexceptions);

Просмотреть файл

@ -32,19 +32,24 @@ using namespace llvm;
namespace {
class VISIBILITY_HIDDEN PCHGenerator : public SemaConsumer {
const Preprocessor &PP;
const char *isysroot;
llvm::raw_ostream *Out;
Sema *SemaPtr;
MemorizeStatCalls *StatCalls; // owned by the FileManager
public:
explicit PCHGenerator(const Preprocessor &PP, llvm::raw_ostream *Out);
explicit PCHGenerator(const Preprocessor &PP,
const char *isysroot,
llvm::raw_ostream *Out);
virtual void InitializeSema(Sema &S) { SemaPtr = &S; }
virtual void HandleTranslationUnit(ASTContext &Ctx);
};
}
PCHGenerator::PCHGenerator(const Preprocessor &PP, llvm::raw_ostream *OS)
: PP(PP), Out(OS), SemaPtr(0), StatCalls(0) {
PCHGenerator::PCHGenerator(const Preprocessor &PP,
const char *isysroot,
llvm::raw_ostream *OS)
: PP(PP), isysroot(isysroot), Out(OS), SemaPtr(0), StatCalls(0) {
// Install a stat() listener to keep track of all of the stat()
// calls.
@ -56,14 +61,14 @@ void PCHGenerator::HandleTranslationUnit(ASTContext &Ctx) {
if (PP.getDiagnostics().hasErrorOccurred())
return;
// Write the PCH contents into a buffer
// Write the PCH contents into a buffer
std::vector<unsigned char> Buffer;
BitstreamWriter Stream(Buffer);
PCHWriter Writer(Stream);
// Emit the PCH file
assert(SemaPtr && "No Sema?");
Writer.WritePCH(*SemaPtr, StatCalls);
Writer.WritePCH(*SemaPtr, StatCalls, isysroot);
// Write the generated bitstream to "Out".
Out->write((char *)&Buffer.front(), Buffer.size());
@ -73,6 +78,7 @@ void PCHGenerator::HandleTranslationUnit(ASTContext &Ctx) {
}
ASTConsumer *clang::CreatePCHGenerator(const Preprocessor &PP,
llvm::raw_ostream *OS) {
return new PCHGenerator(PP, OS);
llvm::raw_ostream *OS,
const char *isysroot) {
return new PCHGenerator(PP, isysroot, OS);
}

Просмотреть файл

@ -336,7 +336,8 @@ void PCHValidator::ReadCounter(unsigned Value) {
// PCH reader implementation
//===----------------------------------------------------------------------===//
PCHReader::PCHReader(Preprocessor &PP, ASTContext *Context)
PCHReader::PCHReader(Preprocessor &PP, ASTContext *Context,
const char *isysroot)
: Listener(new PCHValidator(PP, *this)), SourceMgr(PP.getSourceManager()),
FileMgr(PP.getFileManager()), Diags(PP.getDiagnostics()),
SemaObj(0), PP(&PP), Context(Context), Consumer(0),
@ -344,25 +345,31 @@ PCHReader::PCHReader(Preprocessor &PP, ASTContext *Context)
IdentifierOffsets(0),
MethodPoolLookupTable(0), MethodPoolLookupTableData(0),
TotalSelectorsInMethodPool(0), SelectorOffsets(0),
TotalNumSelectors(0), Comments(0), NumComments(0),
TotalNumSelectors(0), Comments(0), NumComments(0), isysroot(isysroot),
NumStatHits(0), NumStatMisses(0),
NumSLocEntriesRead(0), NumStatementsRead(0),
NumMacrosRead(0), NumMethodPoolSelectorsRead(0), NumMethodPoolMisses(0),
NumLexicalDeclContextsRead(0), NumVisibleDeclContextsRead(0) { }
NumLexicalDeclContextsRead(0), NumVisibleDeclContextsRead(0),
CurrentlyLoadingTypeOrDecl(0) {
RelocatablePCH = false;
}
PCHReader::PCHReader(SourceManager &SourceMgr, FileManager &FileMgr,
Diagnostic &Diags)
Diagnostic &Diags, const char *isysroot)
: SourceMgr(SourceMgr), FileMgr(FileMgr), Diags(Diags),
SemaObj(0), PP(0), Context(0), Consumer(0),
IdentifierTableData(0), IdentifierLookupTable(0),
IdentifierOffsets(0),
MethodPoolLookupTable(0), MethodPoolLookupTableData(0),
TotalSelectorsInMethodPool(0), SelectorOffsets(0),
TotalNumSelectors(0), NumStatHits(0), NumStatMisses(0),
TotalNumSelectors(0), Comments(0), NumComments(0), isysroot(isysroot),
NumStatHits(0), NumStatMisses(0),
NumSLocEntriesRead(0), NumStatementsRead(0),
NumMacrosRead(0), NumMethodPoolSelectorsRead(0), NumMethodPoolMisses(0),
NumLexicalDeclContextsRead(0), NumVisibleDeclContextsRead(0),
CurrentlyLoadingTypeOrDecl(0) { }
CurrentlyLoadingTypeOrDecl(0) {
RelocatablePCH = false;
}
PCHReader::~PCHReader() {}
@ -652,8 +659,7 @@ bool PCHReader::CheckPredefinesBuffer(const char *PCHPredef,
/// \brief Read the line table in the source manager block.
/// \returns true if ther was an error.
static bool ParseLineTable(SourceManager &SourceMgr,
llvm::SmallVectorImpl<uint64_t> &Record) {
bool PCHReader::ParseLineTable(llvm::SmallVectorImpl<uint64_t> &Record) {
unsigned Idx = 0;
LineTableInfo &LineTable = SourceMgr.getLineTable();
@ -664,6 +670,7 @@ static bool ParseLineTable(SourceManager &SourceMgr,
unsigned FilenameLen = Record[Idx++];
std::string Filename(&Record[Idx], &Record[Idx] + FilenameLen);
Idx += FilenameLen;
MaybeAddSystemRootToFilename(Filename);
FileIDs[I] = LineTable.getLineTableFilenameID(Filename.c_str(),
Filename.size());
}
@ -859,7 +866,7 @@ PCHReader::PCHReadResult PCHReader::ReadSourceManagerBlock() {
break;
case pch::SM_LINE_TABLE:
if (ParseLineTable(SourceMgr, Record))
if (ParseLineTable(Record))
return Failure;
break;
@ -912,10 +919,12 @@ PCHReader::PCHReadResult PCHReader::ReadSLocEntryRecord(unsigned ID) {
return Failure;
case pch::SM_SLOC_FILE_ENTRY: {
const FileEntry *File = FileMgr.getFile(BlobStart, BlobStart + BlobLen);
std::string Filename(BlobStart, BlobStart + BlobLen);
MaybeAddSystemRootToFilename(Filename);
const FileEntry *File = FileMgr.getFile(Filename);
if (File == 0) {
std::string ErrorStr = "could not find file '";
ErrorStr.append(BlobStart, BlobLen);
ErrorStr += Filename;
ErrorStr += "' referenced by PCH file";
Error(ErrorStr.c_str());
return Failure;
@ -1096,6 +1105,32 @@ void PCHReader::ReadMacroRecord(uint64_t Offset) {
}
}
/// \brief If we are loading a relocatable PCH file, and the filename is
/// not an absolute path, add the system root to the beginning of the file
/// name.
void PCHReader::MaybeAddSystemRootToFilename(std::string &Filename) {
// If this is not a relocatable PCH file, there's nothing to do.
if (!RelocatablePCH)
return;
if (Filename.empty() || Filename[0] == '/' || Filename[0] == '<')
return;
std::string FIXME = Filename;
if (isysroot == 0) {
// If no system root was given, default to '/'
Filename.insert(Filename.begin(), '/');
return;
}
unsigned Length = strlen(isysroot);
if (isysroot[Length - 1] != '/')
Filename.insert(Filename.begin(), '/');
Filename.insert(Filename.begin(), isysroot, isysroot + Length);
}
PCHReader::PCHReadResult
PCHReader::ReadPCHBlock() {
if (Stream.EnterSubBlock(pch::PCH_BLOCK_ID)) {
@ -1208,6 +1243,7 @@ PCHReader::ReadPCHBlock() {
return IgnorePCH;
}
RelocatablePCH = Record[4];
if (Listener) {
std::string TargetTriple(BlobStart, BlobLen);
if (Listener->ReadTargetTriple(TargetTriple))
@ -1338,6 +1374,7 @@ PCHReader::ReadPCHBlock() {
case pch::ORIGINAL_FILE_NAME:
OriginalFileName.assign(BlobStart, BlobLen);
MaybeAddSystemRootToFilename(OriginalFileName);
break;
case pch::COMMENT_RANGES:

Просмотреть файл

@ -476,11 +476,68 @@ void PCHWriter::WriteBlockInfoBlock() {
Stream.ExitBlock();
}
/// \brief Adjusts the given filename to only write out the portion of the
/// filename that is not part of the system root directory.
///
/// \param Filename the file name to adjust.
///
/// \param isysroot When non-NULL, the PCH file is a relocatable PCH file and
/// the returned filename will be adjusted by this system root.
///
/// \returns either the original filename (if it needs no adjustment) or the
/// adjusted filename (which points into the @p Filename parameter).
static const char *
adjustFilenameForRelocatablePCH(const char *Filename, const char *isysroot) {
assert(Filename && "No file name to adjust?");
if (!isysroot)
return Filename;
// Verify that the filename and the system root have the same prefix.
unsigned Pos = 0;
for (; Filename[Pos] && isysroot[Pos]; ++Pos)
if (Filename[Pos] != isysroot[Pos])
return Filename; // Prefixes don't match.
// We hit the end of the filename before we hit the end of the system root.
if (!Filename[Pos])
return Filename;
// If the file name has a '/' at the current position, skip over the '/'.
// We distinguish sysroot-based includes from absolute includes by the
// absence of '/' at the beginning of sysroot-based includes.
if (Filename[Pos] == '/')
++Pos;
return Filename + Pos;
}
/// \brief Write the PCH metadata (e.g., i686-apple-darwin9).
void PCHWriter::WriteMetadata(ASTContext &Context) {
void PCHWriter::WriteMetadata(ASTContext &Context, const char *isysroot) {
using namespace llvm;
// Metadata
const TargetInfo &Target = Context.Target;
BitCodeAbbrev *MetaAbbrev = new BitCodeAbbrev();
MetaAbbrev->Add(BitCodeAbbrevOp(pch::METADATA));
MetaAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // PCH major
MetaAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // PCH minor
MetaAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // Clang major
MetaAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // Clang minor
MetaAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Relocatable
MetaAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Target triple
unsigned MetaAbbrevCode = Stream.EmitAbbrev(MetaAbbrev);
RecordData Record;
Record.push_back(pch::METADATA);
Record.push_back(pch::VERSION_MAJOR);
Record.push_back(pch::VERSION_MINOR);
Record.push_back(CLANG_VERSION_MAJOR);
Record.push_back(CLANG_VERSION_MINOR);
Record.push_back(isysroot != 0);
const char *Triple = Target.getTargetTriple();
Stream.EmitRecordWithBlob(MetaAbbrevCode, Record, Triple, strlen(Triple));
// Original file name
SourceManager &SM = Context.getSourceManager();
if (const FileEntry *MainFile = SM.getFileEntryForID(SM.getMainFileID())) {
@ -500,31 +557,14 @@ void PCHWriter::WriteMetadata(ASTContext &Context) {
MainFileName = MainFilePath.toString();
}
const char *MainFileNameStr = MainFileName.c_str();
MainFileNameStr = adjustFilenameForRelocatablePCH(MainFileNameStr,
isysroot);
RecordData Record;
Record.push_back(pch::ORIGINAL_FILE_NAME);
Stream.EmitRecordWithBlob(FileAbbrevCode, Record, MainFileName.c_str(),
MainFileName.size());
Stream.EmitRecordWithBlob(FileAbbrevCode, Record, MainFileNameStr,
strlen(MainFileNameStr));
}
// Metadata
const TargetInfo &Target = Context.Target;
BitCodeAbbrev *MetaAbbrev = new BitCodeAbbrev();
MetaAbbrev->Add(BitCodeAbbrevOp(pch::METADATA));
MetaAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // PCH major
MetaAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // PCH minor
MetaAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // Clang major
MetaAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // Clang minor
MetaAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Target triple
unsigned MetaAbbrevCode = Stream.EmitAbbrev(MetaAbbrev);
RecordData Record;
Record.push_back(pch::METADATA);
Record.push_back(pch::VERSION_MAJOR);
Record.push_back(pch::VERSION_MINOR);
Record.push_back(CLANG_VERSION_MAJOR);
Record.push_back(CLANG_VERSION_MINOR);
const char *Triple = Target.getTargetTriple();
Stream.EmitRecordWithBlob(MetaAbbrevCode, Record, Triple, strlen(Triple));
}
/// \brief Write the LangOptions structure.
@ -649,15 +689,19 @@ public:
} // end anonymous namespace
/// \brief Write the stat() system call cache to the PCH file.
void PCHWriter::WriteStatCache(MemorizeStatCalls &StatCalls) {
void PCHWriter::WriteStatCache(MemorizeStatCalls &StatCalls,
const char *isysroot) {
// Build the on-disk hash table containing information about every
// stat() call.
OnDiskChainedHashTableGenerator<PCHStatCacheTrait> Generator;
unsigned NumStatEntries = 0;
for (MemorizeStatCalls::iterator Stat = StatCalls.begin(),
StatEnd = StatCalls.end();
Stat != StatEnd; ++Stat, ++NumStatEntries)
Generator.insert(Stat->first(), Stat->second);
Stat != StatEnd; ++Stat, ++NumStatEntries) {
const char *Filename = Stat->first();
Filename = adjustFilenameForRelocatablePCH(Filename, isysroot);
Generator.insert(Filename, Stat->second);
}
// Create the on-disk hash table in a buffer.
llvm::SmallVector<char, 4096> StatCacheData;
@ -753,7 +797,8 @@ static unsigned CreateSLocInstantiationAbbrev(llvm::BitstreamWriter &Stream) {
/// errors), we probably won't have to create file entries for any of
/// the files in the AST.
void PCHWriter::WriteSourceManagerBlock(SourceManager &SourceMgr,
const Preprocessor &PP) {
const Preprocessor &PP,
const char *isysroot) {
RecordData Record;
// Enter the source manager block.
@ -774,6 +819,7 @@ void PCHWriter::WriteSourceManagerBlock(SourceManager &SourceMgr,
for (unsigned I = 0, N = LineTable.getNumFilenames(); I != N; ++I) {
// Emit the file name
const char *Filename = LineTable.getFilename(I);
Filename = adjustFilenameForRelocatablePCH(Filename, isysroot);
unsigned FilenameLen = Filename? strlen(Filename) : 0;
Record.push_back(FilenameLen);
if (FilenameLen)
@ -850,9 +896,21 @@ void PCHWriter::WriteSourceManagerBlock(SourceManager &SourceMgr,
if (Content->Entry) {
// The source location entry is a file. The blob associated
// with this entry is the file name.
Stream.EmitRecordWithBlob(SLocFileAbbrv, Record,
Content->Entry->getName(),
strlen(Content->Entry->getName()));
// Turn the file name into an absolute path, if it isn't already.
const char *Filename = Content->Entry->getName();
llvm::sys::Path FilePath(Filename, strlen(Filename));
std::string FilenameStr;
if (!FilePath.isAbsolute()) {
llvm::sys::Path P = llvm::sys::Path::GetCurrentDirectory();
P.appendComponent(FilePath.toString());
FilenameStr = P.toString();
Filename = FilenameStr.c_str();
}
Filename = adjustFilenameForRelocatablePCH(Filename, isysroot);
Stream.EmitRecordWithBlob(SLocFileAbbrv, Record, Filename,
strlen(Filename));
// FIXME: For now, preload all file source locations, so that
// we get the appropriate File entries in the reader. This is
@ -1716,7 +1774,8 @@ PCHWriter::PCHWriter(llvm::BitstreamWriter &Stream)
NumStatements(0), NumMacros(0), NumLexicalDeclContexts(0),
NumVisibleDeclContexts(0) { }
void PCHWriter::WritePCH(Sema &SemaRef, MemorizeStatCalls *StatCalls) {
void PCHWriter::WritePCH(Sema &SemaRef, MemorizeStatCalls *StatCalls,
const char *isysroot) {
using namespace llvm;
ASTContext &Context = SemaRef.Context;
@ -1778,11 +1837,11 @@ void PCHWriter::WritePCH(Sema &SemaRef, MemorizeStatCalls *StatCalls) {
// Write the remaining PCH contents.
RecordData Record;
Stream.EnterSubblock(pch::PCH_BLOCK_ID, 4);
WriteMetadata(Context);
WriteMetadata(Context, isysroot);
WriteLanguageOptions(Context.getLangOptions());
if (StatCalls)
WriteStatCache(*StatCalls);
WriteSourceManagerBlock(Context.getSourceManager(), PP);
if (StatCalls && !isysroot)
WriteStatCache(*StatCalls, isysroot);
WriteSourceManagerBlock(Context.getSourceManager(), PP, isysroot);
WritePreprocessor(PP);
WriteComments(Context);

Просмотреть файл

@ -0,0 +1,15 @@
#ifndef RELOC_H
#define RELOC_H
#include <reloc2.h>
// Line number 13 below is important
int x = 2;
#endif // RELOC_H

Просмотреть файл

@ -0,0 +1,15 @@
#ifndef RELOC2_H
#define RELOC2_H
#include <stddef.h>
// Line number below is important!
int y = 2;
#endif // RELOC2_H

14
test/PCH/reloc.c Normal file
Просмотреть файл

@ -0,0 +1,14 @@
// RUN: clang-cc -emit-pch -o %t --relocatable-pch -isysroot `pwd`/libroot `pwd`/libroot/usr/include/reloc.h &&
// RUN: clang-cc -include-pch %t -isysroot `pwd`/libroot %s -verify
// FIXME (test harness can't do this?): not clang-cc -include-pch %t %s
#include <reloc.h>
int x = 2; // expected-error{{redefinition}}
int y = 5; // expected-error{{redefinition}}
// expected-note{{previous definition}}
// expected-note{{previous definition}}

Просмотреть файл

@ -1057,6 +1057,10 @@ static llvm::cl::opt<std::string>
ImplicitIncludePTH("include-pth", llvm::cl::value_desc("file"),
llvm::cl::desc("Include file before parsing"));
static llvm::cl::opt<bool>
RelocatablePCH("relocatable-pch",
llvm::cl::desc("Whether to build a relocatable precompiled "
"header"));
//===----------------------------------------------------------------------===//
// Preprocessor include path information.
@ -1820,8 +1824,16 @@ static void ProcessInputFile(Preprocessor &PP, PreprocessorFactory &PPF,
}
case GeneratePCH:
if (RelocatablePCH.getValue() && !isysroot.getNumOccurrences()) {
PP.Diag(SourceLocation(), diag::err_relocatable_without_without_isysroot);
RelocatablePCH.setValue(false);
}
OS.reset(ComputeOutFile(InFile, 0, true, OutPath));
Consumer.reset(CreatePCHGenerator(PP, OS.get()));
if (RelocatablePCH.getValue())
Consumer.reset(CreatePCHGenerator(PP, OS.get(), isysroot.c_str()));
else
Consumer.reset(CreatePCHGenerator(PP, OS.get()));
CompleteTranslationUnit = false;
break;
@ -1978,7 +1990,13 @@ static void ProcessInputFile(Preprocessor &PP, PreprocessorFactory &PPF,
llvm::OwningPtr<ExternalASTSource> Source;
if (!ImplicitIncludePCH.empty()) {
Reader.reset(new PCHReader(PP, ContextOwner.get()));
// If the user specified -isysroot, it will be used for relocatable PCH
// files.
const char *isysrootPCH = 0;
if (isysroot.getNumOccurrences() != 0)
isysrootPCH = isysroot.c_str();
Reader.reset(new PCHReader(PP, ContextOwner.get(), isysrootPCH));
// The user has asked us to include a precompiled header. Load
// the precompiled header into the AST context.