Skip to content

Commit 421ba7f

Browse files
authored
[llvm-config] Add new flag --quote-paths to optionally quote and escape paths (#103397)
If any of the printed paths by llvm-config contain quotes, spaces, backslashes or dollar sign characters, these paths will be quoted and escaped, but only if using `--quote-paths`. The previous behavior is retained for compatibility and `--quote-paths` is there to acknowledge the migration to the new behavior. Following discussion in #76304 Fixes #28117 Superseeds #97305 I could also do what @tothambrus11 suggests in #97305 (comment) but that makes all Windows paths quoted & escaped since they all contain backslashes.
1 parent bff2aa6 commit 421ba7f

File tree

3 files changed

+86
-21
lines changed

3 files changed

+86
-21
lines changed

llvm/docs/ReleaseNotes.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,10 @@ Changes to the LLVM tools
180180
* Some code paths for supporting Python 2.7 in `llvm-lit` have been removed.
181181
* Support for `%T` in lit has been removed.
182182

183+
* `llvm-config` gained a new flag `--quote-paths` which quotes and escapes paths
184+
emitted on stdout, to account for spaces or other special characters in path.
185+
(`#97305 <https://github.com/llvm/llvm-project/pull/97305>`_).
186+
183187
Changes to LLDB
184188
---------------------------------
185189

llvm/test/tools/llvm-config/paths.test

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,18 +4,34 @@ RUN: llvm-config --bindir 2>&1 | FileCheck --check-prefix=CHECK-BINDIR %s
44
CHECK-BINDIR: {{.*}}{{/|\\}}bin
55
CHECK-BINDIR-NOT: error:
66
CHECK-BINDIR-NOT: warning
7+
RUN: llvm-config --bindir --quote-paths 2>&1 | FileCheck --check-prefix=CHECK-BINDIR2 %s
8+
CHECK-BINDIR2: {{.*}}{{/|\\\\}}bin
9+
CHECK-BINDIR2-NOT: error:
10+
CHECK-BINDIR2-NOT: warning
711

812
RUN: llvm-config --includedir 2>&1 | FileCheck --check-prefix=CHECK-INCLUDEDIR %s
913
CHECK-INCLUDEDIR: {{.*}}{{/|\\}}include
1014
CHECK-INCLUDEDIR-NOT: error:
1115
CHECK-INCLUDEDIR-NOT: warning
16+
RUN: llvm-config --includedir --quote-paths 2>&1 | FileCheck --check-prefix=CHECK-INCLUDEDIR2 %s
17+
CHECK-INCLUDEDIR2: {{.*}}{{/|\\\\}}include
18+
CHECK-INCLUDEDIR2-NOT: error:
19+
CHECK-INCLUDEDIR2-NOT: warning
1220

1321
RUN: llvm-config --libdir 2>&1 | FileCheck --check-prefix=CHECK-LIBDIR %s
1422
CHECK-LIBDIR: {{.*}}{{/|\\}}lib{{.*}}
1523
CHECK-LIBDIR-NOT: error:
1624
CHECK-LIBDIR-NOT: warning
25+
RUN: llvm-config --libdir --quote-paths 2>&1 | FileCheck --check-prefix=CHECK-LIBDIR2 %s
26+
CHECK-LIBDIR2: {{.*}}{{/|\\\\}}lib{{.*}}
27+
CHECK-LIBDIR2-NOT: error:
28+
CHECK-LIBDIR2-NOT: warning
1729

1830
RUN: llvm-config --cmakedir 2>&1 | FileCheck --check-prefix=CHECK-CMAKEDIR %s
1931
CHECK-CMAKEDIR: {{.*}}{{/|\\}}cmake{{/|\\}}llvm
2032
CHECK-CMAKEDIR-NOT: error:
2133
CHECK-CMAKEDIR-NOT: warning
34+
RUN: llvm-config --cmakedir --quote-paths 2>&1 | FileCheck --check-prefix=CHECK-CMAKEDIR2 %s
35+
CHECK-CMAKEDIR2: {{.*}}{{/|\\\\}}cmake{{/|\\\\}}llvm
36+
CHECK-CMAKEDIR2-NOT: error:
37+
CHECK-CMAKEDIR2-NOT: warning

llvm/tools/llvm-config/llvm-config.cpp

Lines changed: 66 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include "llvm/Config/config.h"
2525
#include "llvm/Support/FileSystem.h"
2626
#include "llvm/Support/Path.h"
27+
#include "llvm/Support/Program.h"
2728
#include "llvm/Support/WithColor.h"
2829
#include "llvm/Support/raw_ostream.h"
2930
#include "llvm/TargetParser/Triple.h"
@@ -218,6 +219,7 @@ Options:\n\
218219
--components List of all possible components.\n\
219220
--cppflags C preprocessor flags for files that include LLVM headers.\n\
220221
--cxxflags C++ compiler flags for files that include LLVM headers.\n\
222+
--quote-paths Quote and escape paths when needed.\n\
221223
--has-rtti Print whether or not LLVM was built with rtti (YES or NO).\n\
222224
--help Print a summary of llvm-config arguments.\n\
223225
--host-target Target triple used to configure LLVM.\n\
@@ -324,7 +326,7 @@ int main(int argc, char **argv) {
324326
// information.
325327
std::string ActivePrefix, ActiveBinDir, ActiveIncludeDir, ActiveLibDir,
326328
ActiveCMakeDir;
327-
std::string ActiveIncludeOption;
329+
std::vector<std::string> ActiveIncludeOptions;
328330
if (IsInDevelopmentTree) {
329331
ActiveIncludeDir = std::string(LLVM_SRC_ROOT) + "/include";
330332
ActivePrefix = CurrentExecPrefix;
@@ -350,8 +352,8 @@ int main(int argc, char **argv) {
350352
}
351353

352354
// We need to include files from both the source and object trees.
353-
ActiveIncludeOption =
354-
("-I" + ActiveIncludeDir + " " + "-I" + ActiveObjRoot + "/include");
355+
ActiveIncludeOptions.push_back(ActiveIncludeDir);
356+
ActiveIncludeOptions.push_back(ActiveObjRoot + "/include");
355357
} else {
356358
ActivePrefix = CurrentExecPrefix;
357359
{
@@ -370,7 +372,7 @@ int main(int argc, char **argv) {
370372
sys::path::make_absolute(ActivePrefix, Path);
371373
ActiveCMakeDir = std::string(Path);
372374
}
373-
ActiveIncludeOption = "-I" + ActiveIncludeDir;
375+
ActiveIncludeOptions.push_back(ActiveIncludeDir);
374376
}
375377

376378
/// We only use `shared library` mode in cases where the static library form
@@ -399,7 +401,9 @@ int main(int argc, char **argv) {
399401
llvm::replace(ActiveBinDir, '/', '\\');
400402
llvm::replace(ActiveLibDir, '/', '\\');
401403
llvm::replace(ActiveCMakeDir, '/', '\\');
402-
llvm::replace(ActiveIncludeOption, '/', '\\');
404+
llvm::replace(ActiveIncludeDir, '/', '\\');
405+
for (auto &Include : ActiveIncludeOptions)
406+
llvm::replace(Include, '/', '\\');
403407
}
404408
SharedDir = ActiveBinDir;
405409
StaticDir = ActiveLibDir;
@@ -501,6 +505,32 @@ int main(int argc, char **argv) {
501505
};
502506

503507
raw_ostream &OS = outs();
508+
509+
// Check if we want quoting and escaping.
510+
bool QuotePaths = std::any_of(&argv[0], &argv[argc], [](const char *Arg) {
511+
return StringRef(Arg) == "--quote-paths";
512+
});
513+
514+
auto MaybePrintQuoted = [&](StringRef Str) {
515+
if (QuotePaths)
516+
sys::printArg(OS, Str, /*Quote=*/false); // only add quotes if necessary
517+
else
518+
OS << Str;
519+
};
520+
521+
// Render include paths and associated flags
522+
auto RenderFlags = [&](StringRef Flags) {
523+
bool First = true;
524+
for (auto &Include : ActiveIncludeOptions) {
525+
if (!First)
526+
OS << ' ';
527+
std::string FlagsStr = "-I" + Include;
528+
MaybePrintQuoted(FlagsStr);
529+
First = false;
530+
}
531+
OS << ' ' << Flags << '\n';
532+
};
533+
504534
for (int i = 1; i != argc; ++i) {
505535
StringRef Arg = argv[i];
506536

@@ -509,24 +539,32 @@ int main(int argc, char **argv) {
509539
if (Arg == "--version") {
510540
OS << PACKAGE_VERSION << '\n';
511541
} else if (Arg == "--prefix") {
512-
OS << ActivePrefix << '\n';
542+
MaybePrintQuoted(ActivePrefix);
543+
OS << '\n';
513544
} else if (Arg == "--bindir") {
514-
OS << ActiveBinDir << '\n';
545+
MaybePrintQuoted(ActiveBinDir);
546+
OS << '\n';
515547
} else if (Arg == "--includedir") {
516-
OS << ActiveIncludeDir << '\n';
548+
MaybePrintQuoted(ActiveIncludeDir);
549+
OS << '\n';
517550
} else if (Arg == "--libdir") {
518-
OS << ActiveLibDir << '\n';
551+
MaybePrintQuoted(ActiveLibDir);
552+
OS << '\n';
519553
} else if (Arg == "--cmakedir") {
520-
OS << ActiveCMakeDir << '\n';
554+
MaybePrintQuoted(ActiveCMakeDir);
555+
OS << '\n';
521556
} else if (Arg == "--cppflags") {
522-
OS << ActiveIncludeOption << ' ' << LLVM_CPPFLAGS << '\n';
557+
RenderFlags(LLVM_CPPFLAGS);
523558
} else if (Arg == "--cflags") {
524-
OS << ActiveIncludeOption << ' ' << LLVM_CFLAGS << '\n';
559+
RenderFlags(LLVM_CFLAGS);
525560
} else if (Arg == "--cxxflags") {
526-
OS << ActiveIncludeOption << ' ' << LLVM_CXXFLAGS << '\n';
561+
RenderFlags(LLVM_CXXFLAGS);
527562
} else if (Arg == "--ldflags") {
528-
OS << ((HostTriple.isWindowsMSVCEnvironment()) ? "-LIBPATH:" : "-L")
529-
<< ActiveLibDir << ' ' << LLVM_LDFLAGS << '\n';
563+
std::string LDFlags =
564+
HostTriple.isWindowsMSVCEnvironment() ? "-LIBPATH:" : "-L";
565+
LDFlags += ActiveLibDir;
566+
MaybePrintQuoted(LDFlags);
567+
OS << ' ' << LLVM_LDFLAGS << '\n';
530568
} else if (Arg == "--system-libs") {
531569
PrintSystemLibs = true;
532570
} else if (Arg == "--libs") {
@@ -580,7 +618,8 @@ int main(int argc, char **argv) {
580618
} else if (Arg == "--shared-mode") {
581619
PrintSharedMode = true;
582620
} else if (Arg == "--obj-root") {
583-
OS << ActivePrefix << '\n';
621+
MaybePrintQuoted(ActivePrefix);
622+
OS << '\n';
584623
} else if (Arg == "--ignore-libllvm") {
585624
LinkDyLib = false;
586625
LinkMode = BuiltSharedLibs ? LinkModeShared : LinkModeAuto;
@@ -590,6 +629,8 @@ int main(int argc, char **argv) {
590629
LinkMode = LinkModeStatic;
591630
} else if (Arg == "--help") {
592631
usage(false);
632+
} else if (Arg == "--quote-paths") {
633+
// Was already handled above this loop.
593634
} else {
594635
usage();
595636
}
@@ -682,26 +723,30 @@ int main(int argc, char **argv) {
682723

683724
auto PrintForLib = [&](const StringRef &Lib) {
684725
const bool Shared = LinkMode == LinkModeShared;
726+
std::string LibFileName;
685727
if (PrintLibNames) {
686-
OS << GetComponentLibraryFileName(Lib, Shared);
728+
LibFileName = GetComponentLibraryFileName(Lib, Shared);
687729
} else if (PrintLibFiles) {
688-
OS << GetComponentLibraryPath(Lib, Shared);
730+
LibFileName = GetComponentLibraryPath(Lib, Shared);
689731
} else if (PrintLibs) {
690732
// On Windows, output full path to library without parameters.
691733
// Elsewhere, if this is a typical library name, include it using -l.
692734
if (HostTriple.isWindowsMSVCEnvironment()) {
693-
OS << GetComponentLibraryPath(Lib, Shared);
735+
LibFileName = GetComponentLibraryPath(Lib, Shared);
694736
} else {
737+
LibFileName = "-l";
695738
StringRef LibName;
696739
if (GetComponentLibraryNameSlice(Lib, LibName)) {
697740
// Extract library name (remove prefix and suffix).
698-
OS << "-l" << LibName;
741+
LibFileName += LibName;
699742
} else {
700743
// Lib is already a library name without prefix and suffix.
701-
OS << "-l" << Lib;
744+
LibFileName += Lib;
702745
}
703746
}
704747
}
748+
if (!LibFileName.empty())
749+
MaybePrintQuoted(LibFileName);
705750
};
706751

707752
if (LinkMode == LinkModeShared && LinkDyLib)

0 commit comments

Comments
 (0)