Skip to content

Commit 8d7ee46

Browse files
authored
[clang] Move CCC_OVERRIDE_OPTIONS implementation to Driver (llvm#85425)
Move CCC_OVERRIDE_OPTIONS support to clangDriver so that it may be used outside of the clang driver binary. The override functionality will be used in LLDB, to apply adjustments to ClangImporter flags. This will be useful as an escape hatch when there are issues that can be fixed by adding or removing clang flags. The only thing changed is the name, from `ApplyQAOverride` to `applyOverrideOptions`.
1 parent 4da2b54 commit 8d7ee46

File tree

3 files changed

+144
-135
lines changed

3 files changed

+144
-135
lines changed

clang/include/clang/Driver/Driver.h

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,8 @@
2828
#include "llvm/Option/ArgList.h"
2929
#include "llvm/Support/StringSaver.h"
3030

31-
#include <list>
3231
#include <map>
32+
#include <set>
3333
#include <string>
3434
#include <vector>
3535

@@ -839,6 +839,13 @@ llvm::Error expandResponseFiles(SmallVectorImpl<const char *> &Args,
839839
bool ClangCLMode, llvm::BumpPtrAllocator &Alloc,
840840
llvm::vfs::FileSystem *FS = nullptr);
841841

842+
/// Apply a space separated list of edits to the input argument lists.
843+
/// See applyOneOverrideOption.
844+
void applyOverrideOptions(SmallVectorImpl<const char *> &Args,
845+
const char *OverrideOpts,
846+
llvm::StringSet<> &SavedStrings,
847+
raw_ostream *OS = nullptr);
848+
842849
} // end namespace driver
843850
} // end namespace clang
844851

clang/lib/Driver/Driver.cpp

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@
8787
#include "llvm/Support/Process.h"
8888
#include "llvm/Support/Program.h"
8989
#include "llvm/Support/RISCVISAInfo.h"
90+
#include "llvm/Support/Regex.h"
9091
#include "llvm/Support/StringSaver.h"
9192
#include "llvm/Support/VirtualFileSystem.h"
9293
#include "llvm/Support/raw_ostream.h"
@@ -6677,3 +6678,131 @@ llvm::Error driver::expandResponseFiles(SmallVectorImpl<const char *> &Args,
66776678

66786679
return llvm::Error::success();
66796680
}
6681+
6682+
static const char *GetStableCStr(llvm::StringSet<> &SavedStrings, StringRef S) {
6683+
return SavedStrings.insert(S).first->getKeyData();
6684+
}
6685+
6686+
/// Apply a list of edits to the input argument lists.
6687+
///
6688+
/// The input string is a space separated list of edits to perform,
6689+
/// they are applied in order to the input argument lists. Edits
6690+
/// should be one of the following forms:
6691+
///
6692+
/// '#': Silence information about the changes to the command line arguments.
6693+
///
6694+
/// '^': Add FOO as a new argument at the beginning of the command line.
6695+
///
6696+
/// '+': Add FOO as a new argument at the end of the command line.
6697+
///
6698+
/// 's/XXX/YYY/': Substitute the regular expression XXX with YYY in the command
6699+
/// line.
6700+
///
6701+
/// 'xOPTION': Removes all instances of the literal argument OPTION.
6702+
///
6703+
/// 'XOPTION': Removes all instances of the literal argument OPTION,
6704+
/// and the following argument.
6705+
///
6706+
/// 'Ox': Removes all flags matching 'O' or 'O[sz0-9]' and adds 'Ox'
6707+
/// at the end of the command line.
6708+
///
6709+
/// \param OS - The stream to write edit information to.
6710+
/// \param Args - The vector of command line arguments.
6711+
/// \param Edit - The override command to perform.
6712+
/// \param SavedStrings - Set to use for storing string representations.
6713+
static void applyOneOverrideOption(raw_ostream &OS,
6714+
SmallVectorImpl<const char *> &Args,
6715+
StringRef Edit,
6716+
llvm::StringSet<> &SavedStrings) {
6717+
// This does not need to be efficient.
6718+
6719+
if (Edit[0] == '^') {
6720+
const char *Str = GetStableCStr(SavedStrings, Edit.substr(1));
6721+
OS << "### Adding argument " << Str << " at beginning\n";
6722+
Args.insert(Args.begin() + 1, Str);
6723+
} else if (Edit[0] == '+') {
6724+
const char *Str = GetStableCStr(SavedStrings, Edit.substr(1));
6725+
OS << "### Adding argument " << Str << " at end\n";
6726+
Args.push_back(Str);
6727+
} else if (Edit[0] == 's' && Edit[1] == '/' && Edit.ends_with("/") &&
6728+
Edit.slice(2, Edit.size() - 1).contains('/')) {
6729+
StringRef MatchPattern = Edit.substr(2).split('/').first;
6730+
StringRef ReplPattern = Edit.substr(2).split('/').second;
6731+
ReplPattern = ReplPattern.slice(0, ReplPattern.size() - 1);
6732+
6733+
for (unsigned i = 1, e = Args.size(); i != e; ++i) {
6734+
// Ignore end-of-line response file markers
6735+
if (Args[i] == nullptr)
6736+
continue;
6737+
std::string Repl = llvm::Regex(MatchPattern).sub(ReplPattern, Args[i]);
6738+
6739+
if (Repl != Args[i]) {
6740+
OS << "### Replacing '" << Args[i] << "' with '" << Repl << "'\n";
6741+
Args[i] = GetStableCStr(SavedStrings, Repl);
6742+
}
6743+
}
6744+
} else if (Edit[0] == 'x' || Edit[0] == 'X') {
6745+
auto Option = Edit.substr(1);
6746+
for (unsigned i = 1; i < Args.size();) {
6747+
if (Option == Args[i]) {
6748+
OS << "### Deleting argument " << Args[i] << '\n';
6749+
Args.erase(Args.begin() + i);
6750+
if (Edit[0] == 'X') {
6751+
if (i < Args.size()) {
6752+
OS << "### Deleting argument " << Args[i] << '\n';
6753+
Args.erase(Args.begin() + i);
6754+
} else
6755+
OS << "### Invalid X edit, end of command line!\n";
6756+
}
6757+
} else
6758+
++i;
6759+
}
6760+
} else if (Edit[0] == 'O') {
6761+
for (unsigned i = 1; i < Args.size();) {
6762+
const char *A = Args[i];
6763+
// Ignore end-of-line response file markers
6764+
if (A == nullptr)
6765+
continue;
6766+
if (A[0] == '-' && A[1] == 'O' &&
6767+
(A[2] == '\0' || (A[3] == '\0' && (A[2] == 's' || A[2] == 'z' ||
6768+
('0' <= A[2] && A[2] <= '9'))))) {
6769+
OS << "### Deleting argument " << Args[i] << '\n';
6770+
Args.erase(Args.begin() + i);
6771+
} else
6772+
++i;
6773+
}
6774+
OS << "### Adding argument " << Edit << " at end\n";
6775+
Args.push_back(GetStableCStr(SavedStrings, '-' + Edit.str()));
6776+
} else {
6777+
OS << "### Unrecognized edit: " << Edit << "\n";
6778+
}
6779+
}
6780+
6781+
void driver::applyOverrideOptions(SmallVectorImpl<const char *> &Args,
6782+
const char *OverrideStr,
6783+
llvm::StringSet<> &SavedStrings,
6784+
raw_ostream *OS) {
6785+
if (!OS)
6786+
OS = &llvm::nulls();
6787+
6788+
if (OverrideStr[0] == '#') {
6789+
++OverrideStr;
6790+
OS = &llvm::nulls();
6791+
}
6792+
6793+
*OS << "### CCC_OVERRIDE_OPTIONS: " << OverrideStr << "\n";
6794+
6795+
// This does not need to be efficient.
6796+
6797+
const char *S = OverrideStr;
6798+
while (*S) {
6799+
const char *End = ::strchr(S, ' ');
6800+
if (!End)
6801+
End = S + strlen(S);
6802+
if (End != S)
6803+
applyOneOverrideOption(*OS, Args, std::string(S, End), SavedStrings);
6804+
S = End;
6805+
if (*S != '\0')
6806+
++S;
6807+
}
6808+
}

clang/tools/driver/driver.cpp

Lines changed: 7 additions & 134 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
#include "llvm/ADT/ArrayRef.h"
2929
#include "llvm/ADT/SmallString.h"
3030
#include "llvm/ADT/SmallVector.h"
31+
#include "llvm/ADT/StringSet.h"
3132
#include "llvm/Option/ArgList.h"
3233
#include "llvm/Option/OptTable.h"
3334
#include "llvm/Option/Option.h"
@@ -41,7 +42,6 @@
4142
#include "llvm/Support/PrettyStackTrace.h"
4243
#include "llvm/Support/Process.h"
4344
#include "llvm/Support/Program.h"
44-
#include "llvm/Support/Regex.h"
4545
#include "llvm/Support/Signals.h"
4646
#include "llvm/Support/StringSaver.h"
4747
#include "llvm/Support/TargetSelect.h"
@@ -73,136 +73,8 @@ std::string GetExecutablePath(const char *Argv0, bool CanonicalPrefixes) {
7373
return llvm::sys::fs::getMainExecutable(Argv0, P);
7474
}
7575

76-
static const char *GetStableCStr(std::set<std::string> &SavedStrings,
77-
StringRef S) {
78-
return SavedStrings.insert(std::string(S)).first->c_str();
79-
}
80-
81-
/// ApplyOneQAOverride - Apply a list of edits to the input argument lists.
82-
///
83-
/// The input string is a space separated list of edits to perform,
84-
/// they are applied in order to the input argument lists. Edits
85-
/// should be one of the following forms:
86-
///
87-
/// '#': Silence information about the changes to the command line arguments.
88-
///
89-
/// '^': Add FOO as a new argument at the beginning of the command line.
90-
///
91-
/// '+': Add FOO as a new argument at the end of the command line.
92-
///
93-
/// 's/XXX/YYY/': Substitute the regular expression XXX with YYY in the command
94-
/// line.
95-
///
96-
/// 'xOPTION': Removes all instances of the literal argument OPTION.
97-
///
98-
/// 'XOPTION': Removes all instances of the literal argument OPTION,
99-
/// and the following argument.
100-
///
101-
/// 'Ox': Removes all flags matching 'O' or 'O[sz0-9]' and adds 'Ox'
102-
/// at the end of the command line.
103-
///
104-
/// \param OS - The stream to write edit information to.
105-
/// \param Args - The vector of command line arguments.
106-
/// \param Edit - The override command to perform.
107-
/// \param SavedStrings - Set to use for storing string representations.
108-
static void ApplyOneQAOverride(raw_ostream &OS,
109-
SmallVectorImpl<const char*> &Args,
110-
StringRef Edit,
111-
std::set<std::string> &SavedStrings) {
112-
// This does not need to be efficient.
113-
114-
if (Edit[0] == '^') {
115-
const char *Str =
116-
GetStableCStr(SavedStrings, Edit.substr(1));
117-
OS << "### Adding argument " << Str << " at beginning\n";
118-
Args.insert(Args.begin() + 1, Str);
119-
} else if (Edit[0] == '+') {
120-
const char *Str =
121-
GetStableCStr(SavedStrings, Edit.substr(1));
122-
OS << "### Adding argument " << Str << " at end\n";
123-
Args.push_back(Str);
124-
} else if (Edit[0] == 's' && Edit[1] == '/' && Edit.ends_with("/") &&
125-
Edit.slice(2, Edit.size() - 1).contains('/')) {
126-
StringRef MatchPattern = Edit.substr(2).split('/').first;
127-
StringRef ReplPattern = Edit.substr(2).split('/').second;
128-
ReplPattern = ReplPattern.slice(0, ReplPattern.size()-1);
129-
130-
for (unsigned i = 1, e = Args.size(); i != e; ++i) {
131-
// Ignore end-of-line response file markers
132-
if (Args[i] == nullptr)
133-
continue;
134-
std::string Repl = llvm::Regex(MatchPattern).sub(ReplPattern, Args[i]);
135-
136-
if (Repl != Args[i]) {
137-
OS << "### Replacing '" << Args[i] << "' with '" << Repl << "'\n";
138-
Args[i] = GetStableCStr(SavedStrings, Repl);
139-
}
140-
}
141-
} else if (Edit[0] == 'x' || Edit[0] == 'X') {
142-
auto Option = Edit.substr(1);
143-
for (unsigned i = 1; i < Args.size();) {
144-
if (Option == Args[i]) {
145-
OS << "### Deleting argument " << Args[i] << '\n';
146-
Args.erase(Args.begin() + i);
147-
if (Edit[0] == 'X') {
148-
if (i < Args.size()) {
149-
OS << "### Deleting argument " << Args[i] << '\n';
150-
Args.erase(Args.begin() + i);
151-
} else
152-
OS << "### Invalid X edit, end of command line!\n";
153-
}
154-
} else
155-
++i;
156-
}
157-
} else if (Edit[0] == 'O') {
158-
for (unsigned i = 1; i < Args.size();) {
159-
const char *A = Args[i];
160-
// Ignore end-of-line response file markers
161-
if (A == nullptr)
162-
continue;
163-
if (A[0] == '-' && A[1] == 'O' &&
164-
(A[2] == '\0' ||
165-
(A[3] == '\0' && (A[2] == 's' || A[2] == 'z' ||
166-
('0' <= A[2] && A[2] <= '9'))))) {
167-
OS << "### Deleting argument " << Args[i] << '\n';
168-
Args.erase(Args.begin() + i);
169-
} else
170-
++i;
171-
}
172-
OS << "### Adding argument " << Edit << " at end\n";
173-
Args.push_back(GetStableCStr(SavedStrings, '-' + Edit.str()));
174-
} else {
175-
OS << "### Unrecognized edit: " << Edit << "\n";
176-
}
177-
}
178-
179-
/// ApplyQAOverride - Apply a space separated list of edits to the
180-
/// input argument lists. See ApplyOneQAOverride.
181-
static void ApplyQAOverride(SmallVectorImpl<const char*> &Args,
182-
const char *OverrideStr,
183-
std::set<std::string> &SavedStrings) {
184-
raw_ostream *OS = &llvm::errs();
185-
186-
if (OverrideStr[0] == '#') {
187-
++OverrideStr;
188-
OS = &llvm::nulls();
189-
}
190-
191-
*OS << "### CCC_OVERRIDE_OPTIONS: " << OverrideStr << "\n";
192-
193-
// This does not need to be efficient.
194-
195-
const char *S = OverrideStr;
196-
while (*S) {
197-
const char *End = ::strchr(S, ' ');
198-
if (!End)
199-
End = S + strlen(S);
200-
if (End != S)
201-
ApplyOneQAOverride(*OS, Args, std::string(S, End), SavedStrings);
202-
S = End;
203-
if (*S != '\0')
204-
++S;
205-
}
76+
static const char *GetStableCStr(llvm::StringSet<> &SavedStrings, StringRef S) {
77+
return SavedStrings.insert(S).first->getKeyData();
20678
}
20779

20880
extern int cc1_main(ArrayRef<const char *> Argv, const char *Argv0,
@@ -215,7 +87,7 @@ extern int cc1gen_reproducer_main(ArrayRef<const char *> Argv,
21587

21688
static void insertTargetAndModeArgs(const ParsedClangName &NameParts,
21789
SmallVectorImpl<const char *> &ArgVector,
218-
std::set<std::string> &SavedStrings) {
90+
llvm::StringSet<> &SavedStrings) {
21991
// Put target and mode arguments at the start of argument list so that
22092
// arguments specified in command line could override them. Avoid putting
22193
// them at index 0, as an option like '-cc1' must remain the first.
@@ -419,12 +291,13 @@ int clang_main(int Argc, char **Argv, const llvm::ToolContext &ToolContext) {
419291
}
420292
}
421293

422-
std::set<std::string> SavedStrings;
294+
llvm::StringSet<> SavedStrings;
423295
// Handle CCC_OVERRIDE_OPTIONS, used for editing a command line behind the
424296
// scenes.
425297
if (const char *OverrideStr = ::getenv("CCC_OVERRIDE_OPTIONS")) {
426298
// FIXME: Driver shouldn't take extra initial argument.
427-
ApplyQAOverride(Args, OverrideStr, SavedStrings);
299+
driver::applyOverrideOptions(Args, OverrideStr, SavedStrings,
300+
&llvm::errs());
428301
}
429302

430303
std::string Path = GetExecutablePath(ToolContext.Path, CanonicalPrefixes);

0 commit comments

Comments
 (0)