[Clang] Use virtual FS in processing config files

Clang has support of virtual file system for the purpose of testing, but
treatment of config files did not use it. This change enables VFS in it
as well.

Differential Revision: https://reviews.llvm.org/D132867
This commit is contained in:
Serge Pavlov 2022-09-09 18:23:52 +07:00
parent 4ab77d1677
commit 7b9fae05b4
6 changed files with 107 additions and 30 deletions

View File

@ -93,6 +93,8 @@ Bug Fixes
`Issue 57516 <https://github.com/llvm/llvm-project/issues/57516>`_
- Fix ``__builtin_assume_aligned`` crash when the 1st arg is array type. This fixes
`Issue 57169 <https://github.com/llvm/llvm-project/issues/57169>`_
- Clang configuration files are now read through the virtual file system
rather than the physical one, if these are different.
Improvements to Clang's diagnostics

View File

@ -911,7 +911,8 @@ void Driver::CreateOffloadingDeviceToolChains(Compilation &C,
/// by Dirs.
///
static bool searchForFile(SmallVectorImpl<char> &FilePath,
ArrayRef<StringRef> Dirs, StringRef FileName) {
ArrayRef<StringRef> Dirs, StringRef FileName,
llvm::vfs::FileSystem &FS) {
SmallString<128> WPath;
for (const StringRef &Dir : Dirs) {
if (Dir.empty())
@ -919,7 +920,8 @@ static bool searchForFile(SmallVectorImpl<char> &FilePath,
WPath.clear();
llvm::sys::path::append(WPath, Dir, FileName);
llvm::sys::path::native(WPath);
if (llvm::sys::fs::is_regular_file(WPath)) {
auto Status = FS.status(WPath);
if (Status && Status->getType() == llvm::sys::fs::file_type::regular_file) {
FilePath = std::move(WPath);
return true;
}
@ -930,7 +932,7 @@ static bool searchForFile(SmallVectorImpl<char> &FilePath,
bool Driver::readConfigFile(StringRef FileName) {
// Try reading the given file.
SmallVector<const char *, 32> NewCfgArgs;
if (!llvm::cl::readConfigFile(FileName, Saver, NewCfgArgs)) {
if (!llvm::cl::readConfigFile(FileName, Saver, NewCfgArgs, getVFS())) {
Diag(diag::err_drv_cannot_read_config_file) << FileName;
return true;
}
@ -970,7 +972,7 @@ bool Driver::loadConfigFile() {
SmallString<128> CfgDir;
CfgDir.append(
CLOptions->getLastArgValue(options::OPT_config_system_dir_EQ));
if (CfgDir.empty() || llvm::sys::fs::make_absolute(CfgDir))
if (CfgDir.empty() || getVFS().makeAbsolute(CfgDir))
SystemConfigDir.clear();
else
SystemConfigDir = static_cast<std::string>(CfgDir);
@ -979,7 +981,7 @@ bool Driver::loadConfigFile() {
SmallString<128> CfgDir;
CfgDir.append(
CLOptions->getLastArgValue(options::OPT_config_user_dir_EQ));
if (CfgDir.empty() || llvm::sys::fs::make_absolute(CfgDir))
if (CfgDir.empty() || getVFS().makeAbsolute(CfgDir))
UserConfigDir.clear();
else
UserConfigDir = static_cast<std::string>(CfgDir);
@ -1004,13 +1006,16 @@ bool Driver::loadConfigFile() {
// If argument contains directory separator, treat it as a path to
// configuration file.
if (llvm::sys::path::has_parent_path(CfgFileName)) {
SmallString<128> CfgFilePath;
if (llvm::sys::path::is_relative(CfgFileName))
llvm::sys::fs::current_path(CfgFilePath);
llvm::sys::path::append(CfgFilePath, CfgFileName);
if (!llvm::sys::fs::is_regular_file(CfgFilePath)) {
Diag(diag::err_drv_config_file_not_exist) << CfgFilePath;
return true;
SmallString<128> CfgFilePath(CfgFileName);
if (llvm::sys::path::is_relative(CfgFilePath)) {
if (getVFS().makeAbsolute(CfgFilePath))
return true;
auto Status = getVFS().status(CfgFilePath);
if (!Status ||
Status->getType() != llvm::sys::fs::file_type::regular_file) {
Diag(diag::err_drv_config_file_not_exist) << CfgFilePath;
return true;
}
}
return readConfigFile(CfgFilePath);
}
@ -1069,17 +1074,19 @@ bool Driver::loadConfigFile() {
// Try to find config file. First try file with corrected architecture.
llvm::SmallString<128> CfgFilePath;
if (!FixedConfigFile.empty()) {
if (searchForFile(CfgFilePath, CfgFileSearchDirs, FixedConfigFile))
if (searchForFile(CfgFilePath, CfgFileSearchDirs, FixedConfigFile,
getVFS()))
return readConfigFile(CfgFilePath);
// If 'x86_64-clang.cfg' was not found, try 'x86_64.cfg'.
FixedConfigFile.resize(FixedArchPrefixLen);
FixedConfigFile.append(".cfg");
if (searchForFile(CfgFilePath, CfgFileSearchDirs, FixedConfigFile))
if (searchForFile(CfgFilePath, CfgFileSearchDirs, FixedConfigFile,
getVFS()))
return readConfigFile(CfgFilePath);
}
// Then try original file name.
if (searchForFile(CfgFilePath, CfgFileSearchDirs, CfgFileName))
if (searchForFile(CfgFilePath, CfgFileSearchDirs, CfgFileName, getVFS()))
return readConfigFile(CfgFilePath);
// Finally try removing driver mode part: 'x86_64-clang.cfg' -> 'x86_64.cfg'.
@ -1087,7 +1094,7 @@ bool Driver::loadConfigFile() {
!ClangNameParts.TargetPrefix.empty()) {
CfgFileName.assign(ClangNameParts.TargetPrefix);
CfgFileName.append(".cfg");
if (searchForFile(CfgFilePath, CfgFileSearchDirs, CfgFileName))
if (searchForFile(CfgFilePath, CfgFileSearchDirs, CfgFileName, getVFS()))
return readConfigFile(CfgFilePath);
}

View File

@ -484,4 +484,61 @@ TEST(ToolChainTest, Toolsets) {
}
}
TEST(ToolChainTest, ConfigFileSearch) {
IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
struct TestDiagnosticConsumer : public DiagnosticConsumer {};
DiagnosticsEngine Diags(DiagID, &*DiagOpts, new TestDiagnosticConsumer);
IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> FS(
new llvm::vfs::InMemoryFileSystem);
#ifdef _WIN32
const char *TestRoot = "C:\\";
#else
const char *TestRoot = "/";
#endif
FS->setCurrentWorkingDirectory(TestRoot);
FS->addFile(
"/opt/sdk/root.cfg", 0,
llvm::MemoryBuffer::getMemBuffer("--sysroot=/opt/sdk/platform0\n"));
FS->addFile(
"/home/test/sdk/root.cfg", 0,
llvm::MemoryBuffer::getMemBuffer("--sysroot=/opt/sdk/platform1\n"));
FS->addFile(
"/home/test/bin/root.cfg", 0,
llvm::MemoryBuffer::getMemBuffer("--sysroot=/opt/sdk/platform2\n"));
{
Driver TheDriver("/home/test/bin/clang", "arm-linux-gnueabi", Diags,
"clang LLVM compiler", FS);
std::unique_ptr<Compilation> C(TheDriver.BuildCompilation(
{"/home/test/bin/clang", "--config", "root.cfg",
"--config-system-dir=/opt/sdk", "--config-user-dir=/home/test/sdk"}));
ASSERT_TRUE(C);
ASSERT_FALSE(C->containsError());
EXPECT_EQ("/opt/sdk/platform1", TheDriver.SysRoot);
}
{
Driver TheDriver("/home/test/bin/clang", "arm-linux-gnueabi", Diags,
"clang LLVM compiler", FS);
std::unique_ptr<Compilation> C(TheDriver.BuildCompilation(
{"/home/test/bin/clang", "--config", "root.cfg",
"--config-system-dir=/opt/sdk", "--config-user-dir="}));
ASSERT_TRUE(C);
ASSERT_FALSE(C->containsError());
EXPECT_EQ("/opt/sdk/platform0", TheDriver.SysRoot);
}
{
Driver TheDriver("/home/test/bin/clang", "arm-linux-gnueabi", Diags,
"clang LLVM compiler", FS);
std::unique_ptr<Compilation> C(TheDriver.BuildCompilation(
{"/home/test/bin/clang", "--config", "root.cfg",
"--config-system-dir=", "--config-user-dir="}));
ASSERT_TRUE(C);
ASSERT_FALSE(C->containsError());
EXPECT_EQ("/opt/sdk/platform2", TheDriver.SysRoot);
}
}
} // end anonymous namespace.

View File

@ -2078,7 +2078,8 @@ void tokenizeConfigFile(StringRef Source, StringSaver &Saver,
/// current config file.
///
bool readConfigFile(StringRef CfgFileName, StringSaver &Saver,
SmallVectorImpl<const char *> &Argv);
SmallVectorImpl<const char *> &Argv,
llvm::vfs::FileSystem &FS);
/// Expand response files on a command line recursively using the given
/// StringSaver and tokenization strategy. Argv should contain the command line
@ -2099,7 +2100,7 @@ bool readConfigFile(StringRef CfgFileName, StringSaver &Saver,
/// the current response file.
/// \param [in] FS File system used for all file access when running the tool.
/// \param [in] CurrentDir Path used to resolve relative rsp files. If set to
/// None, process' cwd is used instead.
/// None, the file system current directory is used instead.
/// \return true if all @files were expanded successfully or there were none.
bool ExpandResponseFiles(StringSaver &Saver, TokenizerCallback Tokenizer,
SmallVectorImpl<const char *> &Argv, bool MarkEOLs,

View File

@ -1264,10 +1264,17 @@ bool cl::ExpandResponseFiles(StringSaver &Saver, TokenizerCallback Tokenizer,
// always have an absolute path deduced from the containing file.
SmallString<128> CurrDir;
if (llvm::sys::path::is_relative(FName)) {
if (!CurrentDir)
llvm::sys::fs::current_path(CurrDir);
else
if (!CurrentDir) {
if (auto CWD = FS.getCurrentWorkingDirectory()) {
CurrDir = *CWD;
} else {
// TODO: The error should be propagated up the stack.
llvm::consumeError(llvm::errorCodeToError(CWD.getError()));
return false;
}
} else {
CurrDir = *CurrentDir;
}
llvm::sys::path::append(CurrDir, FName);
FName = CurrDir.c_str();
}
@ -1357,24 +1364,26 @@ bool cl::expandResponseFiles(int Argc, const char *const *Argv,
}
bool cl::readConfigFile(StringRef CfgFile, StringSaver &Saver,
SmallVectorImpl<const char *> &Argv) {
SmallVectorImpl<const char *> &Argv,
llvm::vfs::FileSystem &FS) {
SmallString<128> AbsPath;
if (sys::path::is_relative(CfgFile)) {
llvm::sys::fs::current_path(AbsPath);
llvm::sys::path::append(AbsPath, CfgFile);
AbsPath.assign(CfgFile);
if (std::error_code EC = FS.makeAbsolute(AbsPath))
return false;
CfgFile = AbsPath.str();
}
if (llvm::Error Err = ExpandResponseFile(
CfgFile, Saver, cl::tokenizeConfigFile, Argv,
/*MarkEOLs=*/false, /*RelativeNames=*/true, /*ExpandBasePath=*/true,
*llvm::vfs::getRealFileSystem())) {
if (llvm::Error Err =
ExpandResponseFile(CfgFile, Saver, cl::tokenizeConfigFile, Argv,
/*MarkEOLs=*/false, /*RelativeNames=*/true,
/*ExpandBasePath=*/true, FS)) {
// TODO: The error should be propagated up the stack.
llvm::consumeError(std::move(Err));
return false;
}
return ExpandResponseFiles(Saver, cl::tokenizeConfigFile, Argv,
/*MarkEOLs=*/false, /*RelativeNames=*/true,
/*ExpandBasePath=*/true, llvm::None);
/*ExpandBasePath=*/true, llvm::None, FS);
}
static void initCommonOptions();

View File

@ -1126,7 +1126,8 @@ TEST(CommandLineTest, ReadConfigFile) {
llvm::BumpPtrAllocator A;
llvm::StringSaver Saver(A);
bool Result = llvm::cl::readConfigFile(ConfigFile.path(), Saver, Argv);
bool Result = llvm::cl::readConfigFile(ConfigFile.path(), Saver, Argv,
*llvm::vfs::getRealFileSystem());
EXPECT_TRUE(Result);
EXPECT_EQ(Argv.size(), 13U);