Skip to content
This repository was archived by the owner on Mar 28, 2020. It is now read-only.

Commit 038b68a

Browse files
committed
Allow resolving response file names relative to including file
If a response file included by construct @file itself includes a response file and that file is specified by relative file name, current behavior is to resolve the name relative to the current working directory. The change adds additional flag to ExpandResponseFiles that may be used to resolve nested response file names relative to including file. With the new mode a set of related response files may be kept together and reference each other with short position independent names. Differential Revision: https://reviews.llvm.org/D24917 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@285675 91177308-0d34-0410-b5e6-96231b3b80d8
1 parent aa686dd commit 038b68a

File tree

3 files changed

+91
-7
lines changed

3 files changed

+91
-7
lines changed

include/llvm/Support/CommandLine.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1803,10 +1803,12 @@ typedef void (*TokenizerCallback)(StringRef Source, StringSaver &Saver,
18031803
/// \param [in,out] Argv Command line into which to expand response files.
18041804
/// \param [in] MarkEOLs Mark end of lines and the end of the response file
18051805
/// with nullptrs in the Argv vector.
1806+
/// \param [in] RelativeNames true if names of nested response files must be
1807+
/// resolved relative to including file.
18061808
/// \return true if all @files were expanded successfully or there were none.
18071809
bool ExpandResponseFiles(StringSaver &Saver, TokenizerCallback Tokenizer,
18081810
SmallVectorImpl<const char *> &Argv,
1809-
bool MarkEOLs = false);
1811+
bool MarkEOLs = false, bool RelativeNames = false);
18101812

18111813
/// \brief Mark all options not part of this category as cl::ReallyHidden.
18121814
///

lib/Support/CommandLine.cpp

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -871,10 +871,10 @@ static bool hasUTF8ByteOrderMark(ArrayRef<char> S) {
871871
return (S.size() >= 3 && S[0] == '\xef' && S[1] == '\xbb' && S[2] == '\xbf');
872872
}
873873

874-
static bool ExpandResponseFile(const char *FName, StringSaver &Saver,
874+
static bool ExpandResponseFile(StringRef FName, StringSaver &Saver,
875875
TokenizerCallback Tokenizer,
876876
SmallVectorImpl<const char *> &NewArgv,
877-
bool MarkEOLs = false) {
877+
bool MarkEOLs, bool RelativeNames) {
878878
ErrorOr<std::unique_ptr<MemoryBuffer>> MemBufOrErr =
879879
MemoryBuffer::getFile(FName);
880880
if (!MemBufOrErr)
@@ -899,14 +899,33 @@ static bool ExpandResponseFile(const char *FName, StringSaver &Saver,
899899
// Tokenize the contents into NewArgv.
900900
Tokenizer(Str, Saver, NewArgv, MarkEOLs);
901901

902+
// If names of nested response files should be resolved relative to including
903+
// file, replace the included response file names with their full paths
904+
// obtained by required resolution.
905+
if (RelativeNames)
906+
for (unsigned I = 0; I < NewArgv.size(); ++I)
907+
if (NewArgv[I]) {
908+
StringRef Arg = NewArgv[I];
909+
if (Arg.front() == '@') {
910+
StringRef FileName = Arg.drop_front();
911+
if (llvm::sys::path::is_relative(FileName)) {
912+
SmallString<128> ResponseFile;
913+
ResponseFile.append(1, '@');
914+
llvm::sys::path::append(
915+
ResponseFile, llvm::sys::path::parent_path(FName), FileName);
916+
NewArgv[I] = Saver.save(ResponseFile.c_str()).data();
917+
}
918+
}
919+
}
920+
902921
return true;
903922
}
904923

905924
/// \brief Expand response files on a command line recursively using the given
906925
/// StringSaver and tokenization strategy.
907926
bool cl::ExpandResponseFiles(StringSaver &Saver, TokenizerCallback Tokenizer,
908927
SmallVectorImpl<const char *> &Argv,
909-
bool MarkEOLs) {
928+
bool MarkEOLs, bool RelativeNames) {
910929
unsigned RspFiles = 0;
911930
bool AllExpanded = true;
912931

@@ -930,11 +949,9 @@ bool cl::ExpandResponseFiles(StringSaver &Saver, TokenizerCallback Tokenizer,
930949

931950
// Replace this response file argument with the tokenization of its
932951
// contents. Nested response files are expanded in subsequent iterations.
933-
// FIXME: If a nested response file uses a relative path, is it relative to
934-
// the cwd of the process or the response file?
935952
SmallVector<const char *, 0> ExpandedArgv;
936953
if (!ExpandResponseFile(Arg + 1, Saver, Tokenizer, ExpandedArgv,
937-
MarkEOLs)) {
954+
MarkEOLs, RelativeNames)) {
938955
// We couldn't read this file, so we leave it in the argument stream and
939956
// move on.
940957
AllExpanded = false;

unittests/Support/CommandLineTest.cpp

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,15 @@
77
//
88
//===----------------------------------------------------------------------===//
99

10+
#include "llvm/ADT/SmallString.h"
1011
#include "llvm/ADT/STLExtras.h"
1112
#include "llvm/Config/config.h"
1213
#include "llvm/Support/CommandLine.h"
14+
#include "llvm/Support/FileSystem.h"
15+
#include "llvm/Support/Path.h"
1316
#include "llvm/Support/StringSaver.h"
1417
#include "gtest/gtest.h"
18+
#include <fstream>
1519
#include <stdlib.h>
1620
#include <string>
1721

@@ -505,4 +509,65 @@ TEST(CommandLineTest, GetRegisteredSubcommands) {
505509
}
506510
}
507511

512+
TEST(CommandLineTest, ResponseFiles) {
513+
llvm::SmallString<128> TestDir;
514+
std::error_code EC =
515+
llvm::sys::fs::createUniqueDirectory("unittest", TestDir);
516+
EXPECT_TRUE(!EC);
517+
518+
// Create included response file of first level.
519+
llvm::SmallString<128> IncludedFileName;
520+
llvm::sys::path::append(IncludedFileName, TestDir, "resp1");
521+
std::ofstream IncludedFile(IncludedFileName.c_str());
522+
EXPECT_TRUE(IncludedFile.is_open());
523+
IncludedFile << "-option_1 -option_2\n"
524+
"@incdir/resp2\n"
525+
"-option_3=abcd\n";
526+
IncludedFile.close();
527+
528+
// Directory for included file.
529+
llvm::SmallString<128> IncDir;
530+
llvm::sys::path::append(IncDir, TestDir, "incdir");
531+
EC = llvm::sys::fs::create_directory(IncDir);
532+
EXPECT_TRUE(!EC);
533+
534+
// Create included response file of second level.
535+
llvm::SmallString<128> IncludedFileName2;
536+
llvm::sys::path::append(IncludedFileName2, IncDir, "resp2");
537+
std::ofstream IncludedFile2(IncludedFileName2.c_str());
538+
EXPECT_TRUE(IncludedFile2.is_open());
539+
IncludedFile2 << "-option_21 -option_22\n";
540+
IncludedFile2 << "-option_23=abcd\n";
541+
IncludedFile2.close();
542+
543+
// Prepare 'file' with reference to response file.
544+
SmallString<128> IncRef;
545+
IncRef.append(1, '@');
546+
IncRef.append(IncludedFileName.c_str());
547+
llvm::SmallVector<const char *, 4> Argv =
548+
{ "test/test", "-flag_1", IncRef.c_str(), "-flag_2" };
549+
550+
// Expand response files.
551+
llvm::BumpPtrAllocator A;
552+
llvm::StringSaver Saver(A);
553+
bool Res = llvm::cl::ExpandResponseFiles(
554+
Saver, llvm::cl::TokenizeGNUCommandLine, Argv, false, true);
555+
EXPECT_TRUE(Res);
556+
EXPECT_EQ(Argv.size(), 9);
557+
EXPECT_STREQ(Argv[0], "test/test");
558+
EXPECT_STREQ(Argv[1], "-flag_1");
559+
EXPECT_STREQ(Argv[2], "-option_1");
560+
EXPECT_STREQ(Argv[3], "-option_2");
561+
EXPECT_STREQ(Argv[4], "-option_21");
562+
EXPECT_STREQ(Argv[5], "-option_22");
563+
EXPECT_STREQ(Argv[6], "-option_23=abcd");
564+
EXPECT_STREQ(Argv[7], "-option_3=abcd");
565+
EXPECT_STREQ(Argv[8], "-flag_2");
566+
567+
llvm::sys::fs::remove(IncludedFileName2);
568+
llvm::sys::fs::remove(IncDir);
569+
llvm::sys::fs::remove(IncludedFileName);
570+
llvm::sys::fs::remove(TestDir);
571+
}
572+
508573
} // anonymous namespace

0 commit comments

Comments
 (0)