mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2025-04-09 01:11:53 +00:00

lib dir and move all the libraries into it. This follows the main llvm tree, and allows the libraries to be built in parallel. The top level now enforces that all the libs are built before Driver, but we don't care what order the libs are built in. This speeds up parallel builds, particularly incremental ones. llvm-svn: 48402
276 lines
9.0 KiB
C++
276 lines
9.0 KiB
C++
///===--- FileManager.cpp - File System Probing and Caching ----------------===//
|
|
//
|
|
// The LLVM Compiler Infrastructure
|
|
//
|
|
// This file is distributed under the University of Illinois Open Source
|
|
// License. See LICENSE.TXT for details.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This file implements the FileManager interface.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// TODO: This should index all interesting directories with dirent calls.
|
|
// getdirentries ?
|
|
// opendir/readdir_r/closedir ?
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "clang/Basic/FileManager.h"
|
|
#include "llvm/ADT/SmallString.h"
|
|
#include "llvm/Bitcode/Serialize.h"
|
|
#include "llvm/Bitcode/Deserialize.h"
|
|
#include "llvm/Support/Streams.h"
|
|
#include "llvm/Config/config.h"
|
|
using namespace clang;
|
|
|
|
// FIXME: Enhance libsystem to support inode and other fields.
|
|
#include <sys/stat.h>
|
|
|
|
#if defined(_MSC_VER)
|
|
#define S_ISDIR(s) (_S_IFDIR & s)
|
|
#endif
|
|
|
|
/// NON_EXISTENT_DIR - A special value distinct from null that is used to
|
|
/// represent a dir name that doesn't exist on the disk.
|
|
#define NON_EXISTENT_DIR reinterpret_cast<DirectoryEntry*>((intptr_t)-1)
|
|
|
|
#ifdef LLVM_ON_WIN32
|
|
|
|
#define IS_DIR_SEPARATOR_CHAR(x) ((x) == '/' || (x) == '\\')
|
|
|
|
namespace {
|
|
static std::string GetFullPath(const char *relPath)
|
|
{
|
|
char *absPathStrPtr = _fullpath(NULL, relPath, 0);
|
|
assert(absPathStrPtr && "_fullpath() returned NULL!");
|
|
|
|
std::string absPath(absPathStrPtr);
|
|
|
|
free(absPathStrPtr);
|
|
return absPath;
|
|
}
|
|
}
|
|
|
|
class FileManager::UniqueDirContainer {
|
|
/// UniqueDirs - Cache from full path to existing directories/files.
|
|
///
|
|
llvm::StringMap<DirectoryEntry> UniqueDirs;
|
|
|
|
public:
|
|
DirectoryEntry &getDirectory(const char *Name, struct stat &StatBuf) {
|
|
std::string FullPath(GetFullPath(Name));
|
|
return UniqueDirs.GetOrCreateValue(
|
|
FullPath.c_str(),
|
|
FullPath.c_str() + FullPath.size()
|
|
).getValue();
|
|
}
|
|
|
|
size_t size() { return UniqueDirs.size(); }
|
|
};
|
|
|
|
class FileManager::UniqueFileContainer {
|
|
/// UniqueFiles - Cache from full path to existing directories/files.
|
|
///
|
|
llvm::StringMap<FileEntry> UniqueFiles;
|
|
|
|
public:
|
|
FileEntry &getFile(const char *Name, struct stat &StatBuf) {
|
|
std::string FullPath(GetFullPath(Name));
|
|
return UniqueFiles.GetOrCreateValue(
|
|
FullPath.c_str(),
|
|
FullPath.c_str() + FullPath.size()
|
|
).getValue();
|
|
}
|
|
|
|
size_t size() { return UniqueFiles.size(); }
|
|
};
|
|
|
|
#else
|
|
|
|
#define IS_DIR_SEPARATOR_CHAR(x) ((x) == '/')
|
|
|
|
class FileManager::UniqueDirContainer {
|
|
/// UniqueDirs - Cache from ID's to existing directories/files.
|
|
///
|
|
std::map<std::pair<dev_t, ino_t>, DirectoryEntry> UniqueDirs;
|
|
|
|
public:
|
|
DirectoryEntry &getDirectory(const char *Name, struct stat &StatBuf) {
|
|
return UniqueDirs[std::make_pair(StatBuf.st_dev, StatBuf.st_ino)];
|
|
}
|
|
|
|
size_t size() { return UniqueDirs.size(); }
|
|
};
|
|
|
|
class FileManager::UniqueFileContainer {
|
|
/// UniqueFiles - Cache from ID's to existing directories/files.
|
|
///
|
|
std::set<FileEntry> UniqueFiles;
|
|
|
|
public:
|
|
FileEntry &getFile(const char *Name, struct stat &StatBuf) {
|
|
return
|
|
const_cast<FileEntry&>(
|
|
*UniqueFiles.insert(FileEntry(StatBuf.st_dev,
|
|
StatBuf.st_ino)).first);
|
|
}
|
|
|
|
size_t size() { return UniqueFiles.size(); }
|
|
};
|
|
|
|
#endif
|
|
|
|
|
|
FileManager::FileManager() : UniqueDirs(*new UniqueDirContainer),
|
|
UniqueFiles(*new UniqueFileContainer),
|
|
DirEntries(64), FileEntries(64), NextFileUID(0)
|
|
{
|
|
NumDirLookups = NumFileLookups = 0;
|
|
NumDirCacheMisses = NumFileCacheMisses = 0;
|
|
}
|
|
|
|
FileManager::~FileManager() {
|
|
delete &UniqueDirs;
|
|
delete &UniqueFiles;
|
|
}
|
|
|
|
|
|
/// getDirectory - Lookup, cache, and verify the specified directory. This
|
|
/// returns null if the directory doesn't exist.
|
|
///
|
|
const DirectoryEntry *FileManager::getDirectory(const char *NameStart,
|
|
const char *NameEnd) {
|
|
++NumDirLookups;
|
|
llvm::StringMapEntry<DirectoryEntry *> &NamedDirEnt =
|
|
DirEntries.GetOrCreateValue(NameStart, NameEnd);
|
|
|
|
// See if there is already an entry in the map.
|
|
if (NamedDirEnt.getValue())
|
|
return NamedDirEnt.getValue() == NON_EXISTENT_DIR
|
|
? 0 : NamedDirEnt.getValue();
|
|
|
|
++NumDirCacheMisses;
|
|
|
|
// By default, initialize it to invalid.
|
|
NamedDirEnt.setValue(NON_EXISTENT_DIR);
|
|
|
|
// Get the null-terminated directory name as stored as the key of the
|
|
// DirEntries map.
|
|
const char *InterndDirName = NamedDirEnt.getKeyData();
|
|
|
|
// Check to see if the directory exists.
|
|
struct stat StatBuf;
|
|
if (stat(InterndDirName, &StatBuf) || // Error stat'ing.
|
|
!S_ISDIR(StatBuf.st_mode)) // Not a directory?
|
|
return 0;
|
|
|
|
// It exists. See if we have already opened a directory with the same inode.
|
|
// This occurs when one dir is symlinked to another, for example.
|
|
DirectoryEntry &UDE = UniqueDirs.getDirectory(InterndDirName, StatBuf);
|
|
|
|
NamedDirEnt.setValue(&UDE);
|
|
if (UDE.getName()) // Already have an entry with this inode, return it.
|
|
return &UDE;
|
|
|
|
// Otherwise, we don't have this directory yet, add it. We use the string
|
|
// key from the DirEntries map as the string.
|
|
UDE.Name = InterndDirName;
|
|
return &UDE;
|
|
}
|
|
|
|
/// NON_EXISTENT_FILE - A special value distinct from null that is used to
|
|
/// represent a filename that doesn't exist on the disk.
|
|
#define NON_EXISTENT_FILE reinterpret_cast<FileEntry*>((intptr_t)-1)
|
|
|
|
/// getFile - Lookup, cache, and verify the specified file. This returns null
|
|
/// if the file doesn't exist.
|
|
///
|
|
const FileEntry *FileManager::getFile(const char *NameStart,
|
|
const char *NameEnd) {
|
|
++NumFileLookups;
|
|
|
|
// See if there is already an entry in the map.
|
|
llvm::StringMapEntry<FileEntry *> &NamedFileEnt =
|
|
FileEntries.GetOrCreateValue(NameStart, NameEnd);
|
|
|
|
// See if there is already an entry in the map.
|
|
if (NamedFileEnt.getValue())
|
|
return NamedFileEnt.getValue() == NON_EXISTENT_FILE
|
|
? 0 : NamedFileEnt.getValue();
|
|
|
|
++NumFileCacheMisses;
|
|
|
|
// By default, initialize it to invalid.
|
|
NamedFileEnt.setValue(NON_EXISTENT_FILE);
|
|
|
|
// Figure out what directory it is in. If the string contains a / in it,
|
|
// strip off everything after it.
|
|
// FIXME: this logic should be in sys::Path.
|
|
const char *SlashPos = NameEnd-1;
|
|
while (SlashPos >= NameStart && !IS_DIR_SEPARATOR_CHAR(SlashPos[0]))
|
|
--SlashPos;
|
|
|
|
const DirectoryEntry *DirInfo;
|
|
if (SlashPos < NameStart) {
|
|
// Use the current directory if file has no path component.
|
|
const char *Name = ".";
|
|
DirInfo = getDirectory(Name, Name+1);
|
|
} else if (SlashPos == NameEnd-1)
|
|
return 0; // If filename ends with a /, it's a directory.
|
|
else
|
|
DirInfo = getDirectory(NameStart, SlashPos);
|
|
|
|
if (DirInfo == 0) // Directory doesn't exist, file can't exist.
|
|
return 0;
|
|
|
|
// Get the null-terminated file name as stored as the key of the
|
|
// FileEntries map.
|
|
const char *InterndFileName = NamedFileEnt.getKeyData();
|
|
|
|
// FIXME: Use the directory info to prune this, before doing the stat syscall.
|
|
// FIXME: This will reduce the # syscalls.
|
|
|
|
// Nope, there isn't. Check to see if the file exists.
|
|
struct stat StatBuf;
|
|
//llvm::cerr << "STATING: " << Filename;
|
|
if (stat(InterndFileName, &StatBuf) || // Error stat'ing.
|
|
S_ISDIR(StatBuf.st_mode)) { // A directory?
|
|
// If this file doesn't exist, we leave a null in FileEntries for this path.
|
|
//llvm::cerr << ": Not existing\n";
|
|
return 0;
|
|
}
|
|
//llvm::cerr << ": exists\n";
|
|
|
|
// It exists. See if we have already opened a file with the same inode.
|
|
// This occurs when one dir is symlinked to another, for example.
|
|
FileEntry &UFE = UniqueFiles.getFile(InterndFileName, StatBuf);
|
|
|
|
NamedFileEnt.setValue(&UFE);
|
|
if (UFE.getName()) // Already have an entry with this inode, return it.
|
|
return &UFE;
|
|
|
|
// Otherwise, we don't have this directory yet, add it.
|
|
// FIXME: Change the name to be a char* that points back to the 'FileEntries'
|
|
// key.
|
|
UFE.Name = InterndFileName;
|
|
UFE.Size = StatBuf.st_size;
|
|
UFE.ModTime = StatBuf.st_mtime;
|
|
UFE.Dir = DirInfo;
|
|
UFE.UID = NextFileUID++;
|
|
return &UFE;
|
|
}
|
|
|
|
void FileManager::PrintStats() const {
|
|
llvm::cerr << "\n*** File Manager Stats:\n";
|
|
llvm::cerr << UniqueFiles.size() << " files found, "
|
|
<< UniqueDirs.size() << " dirs found.\n";
|
|
llvm::cerr << NumDirLookups << " dir lookups, "
|
|
<< NumDirCacheMisses << " dir cache misses.\n";
|
|
llvm::cerr << NumFileLookups << " file lookups, "
|
|
<< NumFileCacheMisses << " file cache misses.\n";
|
|
|
|
//llvm::cerr << PagesMapped << BytesOfPagesMapped << FSLookups;
|
|
}
|