blob: 7c981ae9750d81019c73790f68dbcc4800a300d3 [file] [log] [blame]
//===--- IndexUnitWriter.cpp - Index unit serialization -------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "clang/Index/IndexUnitWriter.h"
#include "IndexDataStoreUtils.h"
#include "clang/Basic/FileManager.h"
#include "llvm/ADT/APInt.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/Hashing.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/Bitcode/BitstreamWriter.h"
#include "llvm/Support/Allocator.h"
#include "llvm/Support/Errc.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/raw_ostream.h"
using namespace clang;
using namespace clang::index;
using namespace clang::index::store;
using namespace llvm;
class IndexUnitWriter::PathStorage {
std::string WorkDir;
std::string SysrootPath;
SmallString<512> PathsBuf;
StringMap<DirBitPath, BumpPtrAllocator> Dirs;
std::vector<FileBitPath> FileBitPaths;
DenseMap<const FileEntry *, size_t> FileToIndex;
public:
PathStorage(StringRef workDir, StringRef sysrootPath) {
WorkDir = workDir;
if (sysrootPath == "/")
sysrootPath = StringRef();
SysrootPath = sysrootPath;
}
StringRef getPathsBuffer() const { return PathsBuf.str(); }
ArrayRef<FileBitPath> getBitPaths() const { return FileBitPaths; }
int getPathIndex(const FileEntry *FE) {
if (!FE)
return -1;
auto Pair = FileToIndex.insert(std::make_pair(FE, FileBitPaths.size()));
bool IsNew = Pair.second;
size_t Index = Pair.first->getSecond();
if (IsNew) {
StringRef Filename = sys::path::filename(FE->getName());
DirBitPath Dir = getDirBitPath(sys::path::parent_path(FE->getName()));
FileBitPaths.emplace_back(Dir.PrefixKind, Dir.Dir,
BitPathComponent(getPathOffset(Filename),
Filename.size()));
}
return Index;
}
size_t getPathOffset(StringRef Path) {
if (Path.empty())
return 0;
size_t offset = PathsBuf.size();
PathsBuf += Path;
return offset;
}
private:
DirBitPath getDirBitPath(StringRef dirStr) {
auto pair = Dirs.insert(std::make_pair(dirStr, DirBitPath()));
bool isNew = pair.second;
auto &dirPath = pair.first->second;
if (isNew) {
if (isPathInDir(SysrootPath, dirStr)) {
dirPath.PrefixKind = UNIT_PATH_PREFIX_SYSROOT;
dirStr = dirStr.drop_front(SysrootPath.size());
while (!dirStr.empty() && dirStr[0] == '/')
dirStr = dirStr.drop_front();
} else if (isPathInDir(WorkDir, dirStr)) {
dirPath.PrefixKind = UNIT_PATH_PREFIX_WORKDIR;
dirStr = dirStr.drop_front(WorkDir.size());
while (!dirStr.empty() && dirStr[0] == '/')
dirStr = dirStr.drop_front();
}
dirPath.Dir.Offset = getPathOffset(dirStr);
dirPath.Dir.Size = dirStr.size();
}
return dirPath;
}
static bool isPathInDir(StringRef dir, StringRef path) {
if (dir.empty() || !path.startswith(dir))
return false;
StringRef rest = path.drop_front(dir.size());
return !rest.empty() && sys::path::is_separator(rest.front());
}
};
IndexUnitWriter::IndexUnitWriter(FileManager &FileMgr,
StringRef StorePath,
StringRef ProviderIdentifier,
StringRef ProviderVersion,
StringRef OutputFile,
StringRef ModuleName,
const FileEntry *MainFile,
bool IsSystem,
bool IsModuleUnit,
bool IsDebugCompilation,
StringRef TargetTriple,
StringRef SysrootPath,
writer::ModuleInfoWriterCallback GetInfoForModule)
: FileMgr(FileMgr) {
this->UnitsPath = StorePath;
store::appendUnitSubDir(this->UnitsPath);
this->ProviderIdentifier = ProviderIdentifier;
this->ProviderVersion = ProviderVersion;
this->OutputFile = OutputFile;
this->ModuleName = ModuleName;
this->MainFile = MainFile;
this->IsSystemUnit = IsSystem;
this->IsModuleUnit = IsModuleUnit;
this->IsDebugCompilation = IsDebugCompilation;
this->TargetTriple = TargetTriple;
this->SysrootPath = SysrootPath;
this->GetInfoForModuleFn = GetInfoForModule;
}
IndexUnitWriter::~IndexUnitWriter() {}
int IndexUnitWriter::addModule(writer::OpaqueModule Mod) {
if (!Mod)
return -1;
auto Pair = IndexByModule.insert(std::make_pair(Mod, Modules.size()));
bool WasInserted = Pair.second;
if (WasInserted) {
Modules.push_back(Mod);
}
return Pair.first->second;
}
int IndexUnitWriter::addFileDependency(const FileEntry *File, bool IsSystem,
writer::OpaqueModule Mod) {
assert(File);
auto Pair = IndexByFile.insert(std::make_pair(File, Files.size()));
bool WasInserted = Pair.second;
if (WasInserted) {
Files.push_back(FileEntryData{File, IsSystem, addModule(Mod), {}});
}
return Pair.first->second;
}
void IndexUnitWriter::addRecordFile(StringRef RecordFile, const FileEntry *File,
bool IsSystem, writer::OpaqueModule Mod) {
int Dep = File ? addFileDependency(File, IsSystem, /*module=*/nullptr) : -1;
Records.push_back(RecordOrUnitData{RecordFile, Dep, addModule(Mod), IsSystem});
}
void IndexUnitWriter::addASTFileDependency(const FileEntry *File, bool IsSystem,
writer::OpaqueModule Mod,
bool withoutUnitName) {
assert(File);
if (!SeenASTFiles.insert(File).second)
return;
SmallString<64> UnitName;
if (!withoutUnitName)
getUnitNameForOutputFile(File->getName(), UnitName);
addUnitDependency(UnitName.str(), File, IsSystem, Mod);
}
void IndexUnitWriter::addUnitDependency(StringRef UnitFile,
const FileEntry *File, bool IsSystem,
writer::OpaqueModule Mod) {
int Dep = File ? addFileDependency(File, IsSystem, /*module=*/nullptr) : -1;
ASTFileUnits.emplace_back(RecordOrUnitData{UnitFile, Dep, addModule(Mod), IsSystem});
}
bool IndexUnitWriter::addInclude(const FileEntry *Source, unsigned Line,
const FileEntry *Target) {
// FIXME: This will ignore includes of headers that resolve to module imports
// because the 'target' header has not been added as a file dependency earlier
// so it is missing from \c IndexByFile.
auto It = IndexByFile.find(Source);
if (It == IndexByFile.end())
return false;
int SourceIndex = It->getSecond();
It = IndexByFile.find(Target);
if (It == IndexByFile.end())
return false;
int TargetIndex = It->getSecond();
Files[SourceIndex].Includes.emplace_back(FileInclude{TargetIndex, Line});
return true;
};
void IndexUnitWriter::getUnitNameForOutputFile(StringRef FilePath,
SmallVectorImpl<char> &Str) {
SmallString<256> AbsPath(FilePath);
FileMgr.makeAbsolutePath(AbsPath);
return getUnitNameForAbsoluteOutputFile(AbsPath, Str);
}
void IndexUnitWriter::getUnitPathForOutputFile(StringRef FilePath,
SmallVectorImpl<char> &Str) {
Str.append(UnitsPath.begin(), UnitsPath.end());
Str.push_back('/');
return getUnitNameForOutputFile(FilePath, Str);
}
Optional<bool> IndexUnitWriter::isUnitUpToDateForOutputFile(StringRef FilePath,
Optional<StringRef> TimeCompareFilePath,
std::string &Error) {
SmallString<256> UnitPath;
getUnitPathForOutputFile(FilePath, UnitPath);
llvm::sys::fs::file_status UnitStat;
if (std::error_code EC = llvm::sys::fs::status(UnitPath.c_str(), UnitStat)) {
if (EC != llvm::errc::no_such_file_or_directory) {
llvm::raw_string_ostream Err(Error);
Err << "could not access path '" << UnitPath
<< "': " << EC.message();
return None;
}
return false;
}
if (!TimeCompareFilePath.hasValue())
return true;
llvm::sys::fs::file_status CompareStat;
if (std::error_code EC = llvm::sys::fs::status(*TimeCompareFilePath, CompareStat)) {
if (EC != llvm::errc::no_such_file_or_directory) {
llvm::raw_string_ostream Err(Error);
Err << "could not access path '" << *TimeCompareFilePath
<< "': " << EC.message();
return None;
}
return true;
}
// Return true (unit is up-to-date) if the file to compare is older than the
// unit file.
return CompareStat.getLastModificationTime() <= UnitStat.getLastModificationTime();
}
void IndexUnitWriter::getUnitNameForAbsoluteOutputFile(StringRef FilePath,
SmallVectorImpl<char> &Str) {
StringRef Fname = sys::path::filename(FilePath);
Str.append(Fname.begin(), Fname.end());
Str.push_back('-');
llvm::hash_code PathHashVal = llvm::hash_value(FilePath);
llvm::APInt(64, PathHashVal).toString(Str, 36, /*Signed=*/false);
}
static void writeBlockInfo(BitstreamWriter &Stream) {
RecordData Record;
Stream.EnterBlockInfoBlock();
#define BLOCK(X) emitBlockID(X ## _ID, #X, Stream, Record)
#define RECORD(X) emitRecordID(X, #X, Stream, Record)
BLOCK(UNIT_VERSION_BLOCK);
RECORD(UNIT_VERSION);
BLOCK(UNIT_INFO_BLOCK);
RECORD(UNIT_INFO);
BLOCK(UNIT_DEPENDENCIES_BLOCK);
RECORD(UNIT_DEPENDENCY);
BLOCK(UNIT_INCLUDES_BLOCK);
RECORD(UNIT_INCLUDE);
BLOCK(UNIT_PATHS_BLOCK);
RECORD(UNIT_PATH);
RECORD(UNIT_PATH_BUFFER);
BLOCK(UNIT_MODULES_BLOCK);
RECORD(UNIT_MODULE);
RECORD(UNIT_MODULE_BUFFER);
#undef RECORD
#undef BLOCK
Stream.ExitBlock();
}
static void writeVersionInfo(BitstreamWriter &Stream) {
using namespace llvm::sys;
Stream.EnterSubblock(UNIT_VERSION_BLOCK_ID, 3);
auto Abbrev = std::make_shared<BitCodeAbbrev>();
Abbrev->Add(BitCodeAbbrevOp(UNIT_VERSION));
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Store format version
unsigned AbbrevCode = Stream.EmitAbbrev(std::move(Abbrev));
RecordData Record;
Record.push_back(UNIT_VERSION);
Record.push_back(STORE_FORMAT_VERSION);
Stream.EmitRecordWithAbbrev(AbbrevCode, Record);
Stream.ExitBlock();
}
bool IndexUnitWriter::write(std::string &Error) {
using namespace llvm::sys;
// Determine the working directory.
SmallString<128> CWDPath;
if (!FileMgr.getFileSystemOpts().WorkingDir.empty()) {
CWDPath = FileMgr.getFileSystemOpts().WorkingDir;
if (!path::is_absolute(CWDPath)) {
fs::make_absolute(CWDPath);
}
} else {
std::error_code EC = sys::fs::current_path(CWDPath);
if (EC) {
llvm::raw_string_ostream Err(Error);
Err << "failed to determine current working directory: " << EC.message();
return true;
}
}
WorkDir = CWDPath.str();
SmallString<512> Buffer;
BitstreamWriter Stream(Buffer);
Stream.Emit('I', 8);
Stream.Emit('D', 8);
Stream.Emit('X', 8);
Stream.Emit('U', 8);
PathStorage PathStore(WorkDir, SysrootPath);
writeBlockInfo(Stream);
writeVersionInfo(Stream);
writeUnitInfo(Stream, PathStore);
writeDependencies(Stream, PathStore);
writeIncludes(Stream, PathStore);
writePaths(Stream, PathStore);
writeModules(Stream);
SmallString<256> UnitPath;
getUnitPathForOutputFile(OutputFile, UnitPath);
SmallString<128> TempPath;
TempPath = path::parent_path(UnitsPath);
TempPath += '/';
TempPath += path::filename(UnitPath);
TempPath += "-%%%%%%%%";
int TempFD;
if (llvm::sys::fs::createUniqueFile(TempPath.str(), TempFD, TempPath)) {
llvm::raw_string_ostream Err(Error);
Err << "failed to create temporary file: " << TempPath;
return true;
}
raw_fd_ostream OS(TempFD, /*shouldClose=*/true);
OS.write(Buffer.data(), Buffer.size());
OS.close();
std::error_code EC = fs::rename(/*from=*/TempPath.c_str(), /*to=*/UnitPath.c_str());
if (EC) {
llvm::raw_string_ostream Err(Error);
Err << "failed to rename '" << TempPath << "' to '" << UnitPath << "': " << EC.message();
return true;
}
return false;
}
void IndexUnitWriter::writeUnitInfo(llvm::BitstreamWriter &Stream,
PathStorage &PathStore) {
Stream.EnterSubblock(UNIT_INFO_BLOCK_ID, 3);
auto Abbrev = std::make_shared<BitCodeAbbrev>();
Abbrev->Add(BitCodeAbbrevOp(UNIT_INFO));
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // IsSystemUnit
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 10)); // WorkDir offset
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // WorkDir size
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 10)); // OutputFile offset
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // OutputFile size
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 10)); // Sysroot offset
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // Sysroot size
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 10)); // Main path id
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // IsDebugCompilation
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // IsModuleUnit
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 5)); // Module name size
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 5)); // ProviderIdentifier size
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 5)); // ProviderVersion size
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 5)); // ProviderDataVersion
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Module name + ProviderIdentifier + ProviderVersion + target triple
unsigned AbbrevCode = Stream.EmitAbbrev(std::move(Abbrev));
RecordData Record;
Record.push_back(UNIT_INFO);
Record.push_back(IsSystemUnit);
Record.push_back(PathStore.getPathOffset(WorkDir));
Record.push_back(WorkDir.size());
Record.push_back(PathStore.getPathOffset(OutputFile));
Record.push_back(OutputFile.size());
Record.push_back(PathStore.getPathOffset(SysrootPath));
Record.push_back(SysrootPath.size());
Record.push_back(PathStore.getPathIndex(MainFile) + 1); // Make 1-based with 0=invalid
Record.push_back(IsDebugCompilation);
Record.push_back(IsModuleUnit);
Record.push_back(ModuleName.size());
Record.push_back(ProviderIdentifier.size());
Record.push_back(ProviderVersion.size());
// ProviderDataVersion is reserved. Not sure it is a good to idea to have
// clients consider the specifics of a 'provider data version', but reserving
// to avoid store format version change in case there is a use case in the
// future.
Record.push_back(0); // ProviderDataVersion
SmallString<128> InfoStrings;
InfoStrings += ModuleName;
InfoStrings += ProviderIdentifier;
InfoStrings += ProviderVersion;
InfoStrings += TargetTriple;
Stream.EmitRecordWithBlob(AbbrevCode, Record, InfoStrings);
Stream.ExitBlock();
}
void IndexUnitWriter::writeDependencies(llvm::BitstreamWriter &Stream,
PathStorage &PathStore) {
std::vector<bool> FileUsedForRecordOrUnit;
FileUsedForRecordOrUnit.resize(Files.size());
Stream.EnterSubblock(UNIT_DEPENDENCIES_BLOCK_ID, 3);
auto Abbrev = std::make_shared<BitCodeAbbrev>();
Abbrev->Add(BitCodeAbbrevOp(UNIT_DEPENDENCY));
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, UnitDependencyKindBitNum)); // Dependency kind
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // IsSystem
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 10)); // PathIndex (1-based, 0 = none)
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // ModuleIndex (1-based, 0 = none)
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 32)); // time_t
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 16)); // file size
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Name
unsigned AbbrevCode = Stream.EmitAbbrev(std::move(Abbrev));
RecordData Record;
auto addRecordOrUnitData = [&](UnitDependencyKind K, const RecordOrUnitData &Data) {
Record.push_back(UNIT_DEPENDENCY);
Record.push_back(K);
Record.push_back(Data.IsSystem);
if (Data.FileIndex != -1) {
Record.push_back(PathStore.getPathIndex(Files[Data.FileIndex].File) + 1);
FileUsedForRecordOrUnit[Data.FileIndex] = true;
} else {
Record.push_back(0);
}
if (Data.ModuleIndex != -1) {
Record.push_back(Data.ModuleIndex + 1);
} else {
Record.push_back(0);
}
if (Data.FileIndex != -1) {
Record.push_back(Files[Data.FileIndex].File->getModificationTime());
Record.push_back(Files[Data.FileIndex].File->getSize());
} else {
Record.push_back(0);
Record.push_back(0);
}
Stream.EmitRecordWithBlob(AbbrevCode, Record, Data.Name);
};
for (auto &ASTData : ASTFileUnits) {
Record.clear();
addRecordOrUnitData(UNIT_DEPEND_KIND_UNIT, ASTData);
}
for (auto &recordData : Records) {
Record.clear();
addRecordOrUnitData(UNIT_DEPEND_KIND_RECORD, recordData);
}
size_t FileIndex = 0;
for (auto &File : Files) {
if (FileUsedForRecordOrUnit[FileIndex++])
continue;
Record.clear();
Record.push_back(UNIT_DEPENDENCY);
Record.push_back(UNIT_DEPEND_KIND_FILE);
Record.push_back(File.IsSystem);
Record.push_back(PathStore.getPathIndex(File.File) + 1);
if (File.ModuleIndex != -1) {
Record.push_back(File.ModuleIndex + 1);
} else {
Record.push_back(0);
}
Record.push_back(File.File->getModificationTime());
Record.push_back(File.File->getSize());
Stream.EmitRecordWithBlob(AbbrevCode, Record, StringRef());
}
Stream.ExitBlock();
}
void IndexUnitWriter::writeIncludes(llvm::BitstreamWriter &Stream,
PathStorage &PathStore) {
Stream.EnterSubblock(UNIT_INCLUDES_BLOCK_ID, 3);
auto Abbrev = std::make_shared<BitCodeAbbrev>();
Abbrev->Add(BitCodeAbbrevOp(UNIT_INCLUDE));
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 10)); // source path index (1-based, 0 = no path)
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 12)); // source include line
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 10)); // target path index (1-based, 0 = no path)
unsigned AbbrevCode = Stream.EmitAbbrev(std::move(Abbrev));
RecordData Record;
for (auto &Including : Files) {
for(auto &Included: Including.Includes) {
Record.clear();
Record.push_back(UNIT_INCLUDE);
Record.push_back(PathStore.getPathIndex(Including.File) + 1);
Record.push_back(Included.Line);
Record.push_back(PathStore.getPathIndex(Files[Included.Index].File) + 1);
Stream.EmitRecordWithAbbrev(AbbrevCode, Record);
}
}
Stream.ExitBlock();
}
void IndexUnitWriter::writePaths(llvm::BitstreamWriter &Stream,
PathStorage &PathStore) {
Stream.EnterSubblock(UNIT_PATHS_BLOCK_ID, 3);
auto PathAbbrev = std::make_shared<BitCodeAbbrev>();
PathAbbrev->Add(BitCodeAbbrevOp(UNIT_PATH));
PathAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, UnitFilePathPrefixKindBitNum)); // Path prefix kind
PathAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 10)); // DirPath offset
PathAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // DirPath size
PathAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 10)); // Filename offset
PathAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Filename size
unsigned PathAbbrevCode = Stream.EmitAbbrev(std::move(PathAbbrev));
auto PathBufferAbbrev = std::make_shared<BitCodeAbbrev>();
PathBufferAbbrev->Add(BitCodeAbbrevOp(UNIT_PATH_BUFFER));
PathBufferAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Paths buffer
unsigned PathBufferAbbrevCode = Stream.EmitAbbrev(PathBufferAbbrev);
RecordData Record;
for(auto &BitPath: PathStore.getBitPaths()) {
Record.push_back(UNIT_PATH);
Record.push_back(BitPath.PrefixKind);
Record.push_back(BitPath.Dir.Offset);
Record.push_back(BitPath.Dir.Size);
Record.push_back(BitPath.Filename.Offset);
Record.push_back(BitPath.Filename.Size);
Stream.EmitRecordWithAbbrev(PathAbbrevCode, Record);
Record.clear();
}
Record.push_back(UNIT_PATH_BUFFER);
Stream.EmitRecordWithBlob(PathBufferAbbrevCode, Record, PathStore.getPathsBuffer());
Stream.ExitBlock();
}
void IndexUnitWriter::writeModules(llvm::BitstreamWriter &Stream) {
Stream.EnterSubblock(UNIT_MODULES_BLOCK_ID, 3);
auto Abbrev = std::make_shared<BitCodeAbbrev>();
Abbrev->Add(BitCodeAbbrevOp(UNIT_MODULE));
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 9)); // Module name offset
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Module name size
unsigned AbbrevCode = Stream.EmitAbbrev(std::move(Abbrev));
auto BufferAbbrev = std::make_shared<BitCodeAbbrev>();
BufferAbbrev->Add(BitCodeAbbrevOp(UNIT_MODULE_BUFFER));
BufferAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Module names buffer
unsigned BufferAbbrevCode = Stream.EmitAbbrev(BufferAbbrev);
SmallString<512> ModuleNamesBuf;
RecordData Record;
for (auto &Mod : Modules) {
SmallString<64> ModuleName;
StringRef name = GetInfoForModuleFn(Mod, ModuleName).Name;
size_t offset = ModuleNamesBuf.size();
ModuleNamesBuf += name;
Record.push_back(UNIT_MODULE);
Record.push_back(offset);
Record.push_back(name.size());
Stream.EmitRecordWithAbbrev(AbbrevCode, Record);
Record.clear();
}
Record.push_back(UNIT_MODULE_BUFFER);
Stream.EmitRecordWithBlob(BufferAbbrevCode, Record, ModuleNamesBuf.str());
Stream.ExitBlock();
}
bool IndexUnitWriter::initIndexDirectory(StringRef StorePath,
std::string &Error) {
using namespace llvm::sys;
SmallString<128> SubPath = StorePath;
store::appendRecordSubDir(SubPath);
std::error_code EC = fs::create_directories(SubPath);
if (EC) {
llvm::raw_string_ostream Err(Error);
Err << "failed to create directory '" << SubPath << "': " << EC.message();
return true;
}
SubPath = StorePath;
store::appendUnitSubDir(SubPath);
EC = fs::create_directory(SubPath);
if (EC) {
llvm::raw_string_ostream Err(Error);
Err << "failed to create directory '" << SubPath << "': " << EC.message();
return true;
}
return false;
}