Skip to content

Commit 6e491c4

Browse files
committed
[Support] Class for response file expansion (NFC)
Functions that implement expansion of response and config files depend on many options, which are passes as arguments. Extending the expansion requires new options, it in turn causes changing calls in various places making them even more bulky. This change introduces a class ExpansionContext, which represents set of options that control the expansion. Its methods implements expansion of responce files including config files. It makes extending the expansion easier. No functional changes. Differential Revision: https://reviews.llvm.org/D132379
1 parent 89e56e7 commit 6e491c4

File tree

7 files changed

+143
-128
lines changed

7 files changed

+143
-128
lines changed

clang/lib/Driver/Driver.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -956,7 +956,9 @@ static void appendOneArg(InputArgList &Args, const Arg *Opt,
956956
bool Driver::readConfigFile(StringRef FileName) {
957957
// Try reading the given file.
958958
SmallVector<const char *, 32> NewCfgArgs;
959-
if (!llvm::cl::readConfigFile(FileName, Saver, NewCfgArgs, getVFS())) {
959+
llvm::cl::ExpansionContext ExpCtx(Alloc, llvm::cl::tokenizeConfigFile);
960+
ExpCtx.setVFS(&getVFS());
961+
if (!ExpCtx.readConfigFile(FileName, NewCfgArgs)) {
960962
Diag(diag::err_drv_cannot_read_config_file) << FileName;
961963
return true;
962964
}

clang/lib/Tooling/ExpandResponseFilesCompilationDatabase.cpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -60,9 +60,10 @@ class ExpandResponseFilesDatabase : public CompilationDatabase {
6060
if (!SeenRSPFile)
6161
continue;
6262
llvm::BumpPtrAllocator Alloc;
63-
llvm::StringSaver Saver(Alloc);
64-
llvm::cl::ExpandResponseFiles(Saver, Tokenizer, Argv, false, false, false,
65-
llvm::StringRef(Cmd.Directory), *FS);
63+
llvm::cl::ExpansionContext ECtx(Alloc, Tokenizer);
64+
ECtx.setVFS(FS.get())
65+
.setCurrentDir(Cmd.Directory)
66+
.expandResponseFiles(Argv);
6667
// Don't assign directly, Argv aliases CommandLine.
6768
std::vector<std::string> ExpandedArgv(Argv.begin(), Argv.end());
6869
Cmd.CommandLine = std::move(ExpandedArgv);

clang/tools/driver/driver.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -308,9 +308,8 @@ static int ExecuteCC1Tool(SmallVectorImpl<const char *> &ArgV) {
308308
llvm::cl::ResetAllOptionOccurrences();
309309

310310
llvm::BumpPtrAllocator A;
311-
llvm::StringSaver Saver(A);
312-
llvm::cl::ExpandResponseFiles(Saver, &llvm::cl::TokenizeGNUCommandLine, ArgV,
313-
/*MarkEOLs=*/false);
311+
llvm::cl::ExpansionContext ECtx(A, llvm::cl::TokenizeGNUCommandLine);
312+
ECtx.expandResponseFiles(ArgV);
314313
StringRef Tool = ArgV[1];
315314
void *GetExecutablePathVP = (void *)(intptr_t)GetExecutablePath;
316315
if (Tool == "-cc1")
@@ -373,7 +372,8 @@ int clang_main(int Argc, char **Argv) {
373372

374373
if (MarkEOLs && Args.size() > 1 && StringRef(Args[1]).startswith("-cc1"))
375374
MarkEOLs = false;
376-
llvm::cl::ExpandResponseFiles(Saver, Tokenizer, Args, MarkEOLs);
375+
llvm::cl::ExpansionContext ECtx(A, Tokenizer);
376+
ECtx.setMarkEOLs(MarkEOLs).expandResponseFiles(Args);
377377

378378
// Handle -cc1 integrated tools, even if -cc1 was expanded from a response
379379
// file.

llvm/include/llvm/Support/CommandLine.h

Lines changed: 82 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
#include "llvm/ADT/iterator_range.h"
3232
#include "llvm/Support/ErrorHandling.h"
3333
#include "llvm/Support/ManagedStatic.h"
34+
#include "llvm/Support/StringSaver.h"
3435
#include "llvm/Support/raw_ostream.h"
3536
#include <cassert>
3637
#include <climits>
@@ -2065,56 +2066,88 @@ void tokenizeConfigFile(StringRef Source, StringSaver &Saver,
20652066
SmallVectorImpl<const char *> &NewArgv,
20662067
bool MarkEOLs = false);
20672068

2068-
/// Reads command line options from the given configuration file.
2069-
///
2070-
/// \param [in] CfgFileName Path to configuration file.
2071-
/// \param [in] Saver Objects that saves allocated strings.
2072-
/// \param [out] Argv Array to which the read options are added.
2073-
/// \return true if the file was successfully read.
2074-
///
2075-
/// It reads content of the specified file, tokenizes it and expands "@file"
2076-
/// commands resolving file names in them relative to the directory where
2077-
/// CfgFilename resides. It also expands "<CFGDIR>" to the base path of the
2078-
/// current config file.
2079-
///
2080-
bool readConfigFile(StringRef CfgFileName, StringSaver &Saver,
2081-
SmallVectorImpl<const char *> &Argv,
2082-
llvm::vfs::FileSystem &FS);
2083-
2084-
/// Expand response files on a command line recursively using the given
2085-
/// StringSaver and tokenization strategy. Argv should contain the command line
2086-
/// before expansion and will be modified in place. If requested, Argv will
2087-
/// also be populated with nullptrs indicating where each response file line
2088-
/// ends, which is useful for the "/link" argument that needs to consume all
2089-
/// remaining arguments only until the next end of line, when in a response
2090-
/// file.
2091-
///
2092-
/// \param [in] Saver Delegates back to the caller for saving parsed strings.
2093-
/// \param [in] Tokenizer Tokenization strategy. Typically Unix or Windows.
2094-
/// \param [in,out] Argv Command line into which to expand response files.
2095-
/// \param [in] MarkEOLs Mark end of lines and the end of the response file
2096-
/// with nullptrs in the Argv vector.
2097-
/// \param [in] RelativeNames true if names of nested response files must be
2098-
/// resolved relative to including file.
2099-
/// \param [in] ExpandBasePath If true, "<CFGDIR>" expands to the base path of
2100-
/// the current response file.
2101-
/// \param [in] FS File system used for all file access when running the tool.
2102-
/// \param [in] CurrentDir Path used to resolve relative rsp files. If set to
2103-
/// None, the file system current directory is used instead.
2069+
/// Contains options that control response file expansion.
2070+
class ExpansionContext {
2071+
/// Provides persistent storage for parsed strings.
2072+
StringSaver Saver;
2073+
2074+
/// Tokenization strategy. Typically Unix or Windows.
2075+
TokenizerCallback Tokenizer;
2076+
2077+
/// File system used for all file access when running the expansion.
2078+
vfs::FileSystem *FS;
2079+
2080+
/// Path used to resolve relative rsp files. If empty, the file system
2081+
/// current directory is used instead.
2082+
StringRef CurrentDir;
2083+
2084+
/// True if names of nested response files must be resolved relative to
2085+
/// including file.
2086+
bool RelativeNames = false;
2087+
2088+
/// If true, mark end of lines and the end of the response file with nullptrs
2089+
/// in the Argv vector.
2090+
bool MarkEOLs = false;
2091+
2092+
/// If true, body of config file is expanded.
2093+
bool InConfigFile = false;
2094+
2095+
llvm::Error expandResponseFile(StringRef FName,
2096+
SmallVectorImpl<const char *> &NewArgv);
2097+
2098+
public:
2099+
ExpansionContext(BumpPtrAllocator &A, TokenizerCallback T);
2100+
2101+
ExpansionContext &setMarkEOLs(bool X) {
2102+
MarkEOLs = X;
2103+
return *this;
2104+
}
2105+
2106+
ExpansionContext &setRelativeNames(bool X) {
2107+
RelativeNames = X;
2108+
return *this;
2109+
}
2110+
2111+
ExpansionContext &setCurrentDir(StringRef X) {
2112+
CurrentDir = X;
2113+
return *this;
2114+
}
2115+
2116+
ExpansionContext &setVFS(vfs::FileSystem *X) {
2117+
FS = X;
2118+
return *this;
2119+
}
2120+
2121+
/// Reads command line options from the given configuration file.
2122+
///
2123+
/// \param [in] CfgFile Path to configuration file.
2124+
/// \param [out] Argv Array to which the read options are added.
2125+
/// \return true if the file was successfully read.
2126+
///
2127+
/// It reads content of the specified file, tokenizes it and expands "@file"
2128+
/// commands resolving file names in them relative to the directory where
2129+
/// CfgFilename resides. It also expands "<CFGDIR>" to the base path of the
2130+
/// current config file.
2131+
bool readConfigFile(StringRef CfgFile, SmallVectorImpl<const char *> &Argv);
2132+
2133+
/// Expands constructs "@file" in the provided array of arguments recursively.
2134+
bool expandResponseFiles(SmallVectorImpl<const char *> &Argv);
2135+
};
2136+
2137+
/// A convenience helper which concatenates the options specified by the
2138+
/// environment variable EnvVar and command line options, then expands
2139+
/// response files recursively.
21042140
/// \return true if all @files were expanded successfully or there were none.
2105-
bool ExpandResponseFiles(StringSaver &Saver, TokenizerCallback Tokenizer,
2106-
SmallVectorImpl<const char *> &Argv, bool MarkEOLs,
2107-
bool RelativeNames, bool ExpandBasePath,
2108-
llvm::Optional<llvm::StringRef> CurrentDir,
2109-
llvm::vfs::FileSystem &FS);
2110-
2111-
/// An overload of ExpandResponseFiles() that uses
2112-
/// llvm::vfs::getRealFileSystem().
2113-
bool ExpandResponseFiles(
2114-
StringSaver &Saver, TokenizerCallback Tokenizer,
2115-
SmallVectorImpl<const char *> &Argv, bool MarkEOLs = false,
2116-
bool RelativeNames = false, bool ExpandBasePath = false,
2117-
llvm::Optional<llvm::StringRef> CurrentDir = llvm::None);
2141+
bool expandResponseFiles(int Argc, const char *const *Argv, const char *EnvVar,
2142+
SmallVectorImpl<const char *> &NewArgv);
2143+
2144+
/// A convenience helper which supports the typical use case of expansion
2145+
/// function call.
2146+
inline bool ExpandResponseFiles(StringSaver &Saver, TokenizerCallback Tokenizer,
2147+
SmallVectorImpl<const char *> &Argv) {
2148+
ExpansionContext ECtx(Saver.getAllocator(), Tokenizer);
2149+
return ECtx.expandResponseFiles(Argv);
2150+
}
21182151

21192152
/// A convenience helper which concatenates the options specified by the
21202153
/// environment variable EnvVar and command line options, then expands response

llvm/include/llvm/Support/StringSaver.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ class StringSaver final {
2424
public:
2525
StringSaver(BumpPtrAllocator &Alloc) : Alloc(Alloc) {}
2626

27+
BumpPtrAllocator &getAllocator() const { return Alloc; }
28+
2729
// All returned strings are null-terminated: *save(S).end() == 0.
2830
StringRef save(const char *S) { return save(StringRef(S)); }
2931
StringRef save(StringRef S);

llvm/lib/Support/CommandLine.cpp

Lines changed: 30 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1153,15 +1153,12 @@ static void ExpandBasePaths(StringRef BasePath, StringSaver &Saver,
11531153
}
11541154

11551155
// FName must be an absolute path.
1156-
static llvm::Error ExpandResponseFile(StringRef FName, StringSaver &Saver,
1157-
TokenizerCallback Tokenizer,
1158-
SmallVectorImpl<const char *> &NewArgv,
1159-
bool MarkEOLs, bool RelativeNames,
1160-
bool ExpandBasePath,
1161-
llvm::vfs::FileSystem &FS) {
1156+
llvm::Error
1157+
ExpansionContext::expandResponseFile(StringRef FName,
1158+
SmallVectorImpl<const char *> &NewArgv) {
11621159
assert(sys::path::is_absolute(FName));
11631160
llvm::ErrorOr<std::unique_ptr<MemoryBuffer>> MemBufOrErr =
1164-
FS.getBufferForFile(FName);
1161+
FS->getBufferForFile(FName);
11651162
if (!MemBufOrErr)
11661163
return llvm::errorCodeToError(MemBufOrErr.getError());
11671164
MemoryBuffer &MemBuf = *MemBufOrErr.get();
@@ -1196,7 +1193,7 @@ static llvm::Error ExpandResponseFile(StringRef FName, StringSaver &Saver,
11961193
continue;
11971194

11981195
// Substitute <CFGDIR> with the file's base path.
1199-
if (ExpandBasePath)
1196+
if (InConfigFile)
12001197
ExpandBasePaths(BasePath, Saver, Arg);
12011198

12021199
// Skip non-rsp file arguments.
@@ -1219,11 +1216,8 @@ static llvm::Error ExpandResponseFile(StringRef FName, StringSaver &Saver,
12191216

12201217
/// Expand response files on a command line recursively using the given
12211218
/// StringSaver and tokenization strategy.
1222-
bool cl::ExpandResponseFiles(StringSaver &Saver, TokenizerCallback Tokenizer,
1223-
SmallVectorImpl<const char *> &Argv, bool MarkEOLs,
1224-
bool RelativeNames, bool ExpandBasePath,
1225-
llvm::Optional<llvm::StringRef> CurrentDir,
1226-
llvm::vfs::FileSystem &FS) {
1219+
bool ExpansionContext::expandResponseFiles(
1220+
SmallVectorImpl<const char *> &Argv) {
12271221
bool AllExpanded = true;
12281222
struct ResponseFileRecord {
12291223
std::string File;
@@ -1264,28 +1258,28 @@ bool cl::ExpandResponseFiles(StringSaver &Saver, TokenizerCallback Tokenizer,
12641258
// always have an absolute path deduced from the containing file.
12651259
SmallString<128> CurrDir;
12661260
if (llvm::sys::path::is_relative(FName)) {
1267-
if (!CurrentDir) {
1268-
if (auto CWD = FS.getCurrentWorkingDirectory()) {
1261+
if (CurrentDir.empty()) {
1262+
if (auto CWD = FS->getCurrentWorkingDirectory()) {
12691263
CurrDir = *CWD;
12701264
} else {
12711265
// TODO: The error should be propagated up the stack.
12721266
llvm::consumeError(llvm::errorCodeToError(CWD.getError()));
12731267
return false;
12741268
}
12751269
} else {
1276-
CurrDir = *CurrentDir;
1270+
CurrDir = CurrentDir;
12771271
}
12781272
llvm::sys::path::append(CurrDir, FName);
12791273
FName = CurrDir.c_str();
12801274
}
1281-
auto IsEquivalent = [FName, &FS](const ResponseFileRecord &RFile) {
1282-
llvm::ErrorOr<llvm::vfs::Status> LHS = FS.status(FName);
1275+
auto IsEquivalent = [FName, this](const ResponseFileRecord &RFile) {
1276+
llvm::ErrorOr<llvm::vfs::Status> LHS = FS->status(FName);
12831277
if (!LHS) {
12841278
// TODO: The error should be propagated up the stack.
12851279
llvm::consumeError(llvm::errorCodeToError(LHS.getError()));
12861280
return false;
12871281
}
1288-
llvm::ErrorOr<llvm::vfs::Status> RHS = FS.status(RFile.File);
1282+
llvm::ErrorOr<llvm::vfs::Status> RHS = FS->status(RFile.File);
12891283
if (!RHS) {
12901284
// TODO: The error should be propagated up the stack.
12911285
llvm::consumeError(llvm::errorCodeToError(RHS.getError()));
@@ -1306,9 +1300,7 @@ bool cl::ExpandResponseFiles(StringSaver &Saver, TokenizerCallback Tokenizer,
13061300
// Replace this response file argument with the tokenization of its
13071301
// contents. Nested response files are expanded in subsequent iterations.
13081302
SmallVector<const char *, 0> ExpandedArgv;
1309-
if (llvm::Error Err =
1310-
ExpandResponseFile(FName, Saver, Tokenizer, ExpandedArgv, MarkEOLs,
1311-
RelativeNames, ExpandBasePath, FS)) {
1303+
if (llvm::Error Err = expandResponseFile(FName, ExpandedArgv)) {
13121304
// We couldn't read this file, so we leave it in the argument stream and
13131305
// move on.
13141306
// TODO: The error should be propagated up the stack.
@@ -1338,15 +1330,6 @@ bool cl::ExpandResponseFiles(StringSaver &Saver, TokenizerCallback Tokenizer,
13381330
return AllExpanded;
13391331
}
13401332

1341-
bool cl::ExpandResponseFiles(StringSaver &Saver, TokenizerCallback Tokenizer,
1342-
SmallVectorImpl<const char *> &Argv, bool MarkEOLs,
1343-
bool RelativeNames, bool ExpandBasePath,
1344-
llvm::Optional<StringRef> CurrentDir) {
1345-
return ExpandResponseFiles(Saver, std::move(Tokenizer), Argv, MarkEOLs,
1346-
RelativeNames, ExpandBasePath,
1347-
std::move(CurrentDir), *vfs::getRealFileSystem());
1348-
}
1349-
13501333
bool cl::expandResponseFiles(int Argc, const char *const *Argv,
13511334
const char *EnvVar, StringSaver &Saver,
13521335
SmallVectorImpl<const char *> &NewArgv) {
@@ -1360,30 +1343,30 @@ bool cl::expandResponseFiles(int Argc, const char *const *Argv,
13601343

13611344
// Command line options can override the environment variable.
13621345
NewArgv.append(Argv + 1, Argv + Argc);
1363-
return ExpandResponseFiles(Saver, Tokenize, NewArgv);
1346+
ExpansionContext ECtx(Saver.getAllocator(), Tokenize);
1347+
return ECtx.expandResponseFiles(NewArgv);
13641348
}
13651349

1366-
bool cl::readConfigFile(StringRef CfgFile, StringSaver &Saver,
1367-
SmallVectorImpl<const char *> &Argv,
1368-
llvm::vfs::FileSystem &FS) {
1350+
ExpansionContext::ExpansionContext(BumpPtrAllocator &A, TokenizerCallback T)
1351+
: Saver(A), Tokenizer(T), FS(vfs::getRealFileSystem().get()) {}
1352+
1353+
bool ExpansionContext::readConfigFile(StringRef CfgFile,
1354+
SmallVectorImpl<const char *> &Argv) {
13691355
SmallString<128> AbsPath;
13701356
if (sys::path::is_relative(CfgFile)) {
13711357
AbsPath.assign(CfgFile);
1372-
if (std::error_code EC = FS.makeAbsolute(AbsPath))
1358+
if (std::error_code EC = FS->makeAbsolute(AbsPath))
13731359
return false;
13741360
CfgFile = AbsPath.str();
13751361
}
1376-
if (llvm::Error Err =
1377-
ExpandResponseFile(CfgFile, Saver, cl::tokenizeConfigFile, Argv,
1378-
/*MarkEOLs=*/false, /*RelativeNames=*/true,
1379-
/*ExpandBasePath=*/true, FS)) {
1362+
InConfigFile = true;
1363+
RelativeNames = true;
1364+
if (llvm::Error Err = expandResponseFile(CfgFile, Argv)) {
13801365
// TODO: The error should be propagated up the stack.
13811366
llvm::consumeError(std::move(Err));
13821367
return false;
13831368
}
1384-
return ExpandResponseFiles(Saver, cl::tokenizeConfigFile, Argv,
1385-
/*MarkEOLs=*/false, /*RelativeNames=*/true,
1386-
/*ExpandBasePath=*/true, llvm::None, FS);
1369+
return expandResponseFiles(Argv);
13871370
}
13881371

13891372
static void initCommonOptions();
@@ -1441,11 +1424,10 @@ bool CommandLineParser::ParseCommandLineOptions(int argc,
14411424
// Expand response files.
14421425
SmallVector<const char *, 20> newArgv(argv, argv + argc);
14431426
BumpPtrAllocator A;
1444-
StringSaver Saver(A);
1445-
ExpandResponseFiles(Saver,
1446-
Triple(sys::getProcessTriple()).isOSWindows() ?
1447-
cl::TokenizeWindowsCommandLine : cl::TokenizeGNUCommandLine,
1448-
newArgv);
1427+
ExpansionContext ECtx(A, Triple(sys::getProcessTriple()).isOSWindows()
1428+
? cl::TokenizeWindowsCommandLine
1429+
: cl::TokenizeGNUCommandLine);
1430+
ECtx.expandResponseFiles(newArgv);
14491431
argv = &newArgv[0];
14501432
argc = static_cast<int>(newArgv.size());
14511433

0 commit comments

Comments
 (0)