Skip to content

Commit be2fc1d

Browse files
committed
[llvm-config] Optionally quote and escape paths with a flag
If any of the printed paths by llvm-config contains quotes, spaces, backslashes or dollar sign characters, these paths can be quoted if using --quote-paths and the corresponding characters will be escaped. Following discussion in llvm#76304 Fixes llvm#28117
1 parent e79e601 commit be2fc1d

File tree

3 files changed

+90
-22
lines changed

3 files changed

+90
-22
lines changed

llvm/docs/ReleaseNotes.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,10 @@ Changes to the Debug Info
163163
Changes to the LLVM tools
164164
---------------------------------
165165

166+
* llvm-config gained a new flag --quote-paths which quotes and escapes paths
167+
emitted on stdout, to account for spaces or other special characters in path.
168+
(`#97305 <https://github.com/llvm/llvm-project/pull/97305>`_).
169+
166170
Changes to LLDB
167171
---------------------------------
168172

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: 70 additions & 22 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"
@@ -219,6 +220,7 @@ Options:\n\
219220
--components List of all possible components.\n\
220221
--cppflags C preprocessor flags for files that include LLVM headers.\n\
221222
--cxxflags C++ compiler flags for files that include LLVM headers.\n\
223+
--quote-paths Quote and escape paths when needed.\n\
222224
--has-rtti Print whether or not LLVM was built with rtti (YES or NO).\n\
223225
--help Print a summary of llvm-config arguments.\n\
224226
--host-target Target triple used to configure LLVM.\n\
@@ -326,7 +328,7 @@ int main(int argc, char **argv) {
326328
// information.
327329
std::string ActivePrefix, ActiveBinDir, ActiveIncludeDir, ActiveLibDir,
328330
ActiveCMakeDir;
329-
std::string ActiveIncludeOption;
331+
std::vector<std::string> ActiveIncludeOptions;
330332
if (IsInDevelopmentTree) {
331333
ActiveIncludeDir = std::string(LLVM_SRC_ROOT) + "/include";
332334
ActivePrefix = CurrentExecPrefix;
@@ -352,8 +354,8 @@ int main(int argc, char **argv) {
352354
}
353355

354356
// We need to include files from both the source and object trees.
355-
ActiveIncludeOption =
356-
("-I" + ActiveIncludeDir + " " + "-I" + ActiveObjRoot + "/include");
357+
ActiveIncludeOptions.push_back(ActiveIncludeDir);
358+
ActiveIncludeOptions.push_back(ActiveObjRoot + "/include");
357359
} else {
358360
ActivePrefix = CurrentExecPrefix;
359361
{
@@ -372,7 +374,7 @@ int main(int argc, char **argv) {
372374
sys::fs::make_absolute(ActivePrefix, Path);
373375
ActiveCMakeDir = std::string(Path);
374376
}
375-
ActiveIncludeOption = "-I" + ActiveIncludeDir;
377+
ActiveIncludeOptions.push_back(ActiveIncludeDir);
376378
}
377379

378380
/// We only use `shared library` mode in cases where the static library form
@@ -401,8 +403,9 @@ int main(int argc, char **argv) {
401403
std::replace(ActiveBinDir.begin(), ActiveBinDir.end(), '/', '\\');
402404
std::replace(ActiveLibDir.begin(), ActiveLibDir.end(), '/', '\\');
403405
std::replace(ActiveCMakeDir.begin(), ActiveCMakeDir.end(), '/', '\\');
404-
std::replace(ActiveIncludeOption.begin(), ActiveIncludeOption.end(), '/',
405-
'\\');
406+
std::replace(ActiveIncludeDir.begin(), ActiveIncludeDir.end(), '/', '\\');
407+
for (auto &Include : ActiveIncludeOptions)
408+
std::replace(Include.begin(), Include.end(), '/', '\\');
406409
}
407410
SharedDir = ActiveBinDir;
408411
StaticDir = ActiveLibDir;
@@ -504,6 +507,36 @@ int main(int argc, char **argv) {
504507
};
505508

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

@@ -512,24 +545,32 @@ int main(int argc, char **argv) {
512545
if (Arg == "--version") {
513546
OS << PACKAGE_VERSION << '\n';
514547
} else if (Arg == "--prefix") {
515-
OS << ActivePrefix << '\n';
548+
MaybePrintQuoted(ActivePrefix);
549+
OS << '\n';
516550
} else if (Arg == "--bindir") {
517-
OS << ActiveBinDir << '\n';
551+
MaybePrintQuoted(ActiveBinDir);
552+
OS << '\n';
518553
} else if (Arg == "--includedir") {
519-
OS << ActiveIncludeDir << '\n';
554+
MaybePrintQuoted(ActiveIncludeDir);
555+
OS << '\n';
520556
} else if (Arg == "--libdir") {
521-
OS << ActiveLibDir << '\n';
557+
MaybePrintQuoted(ActiveLibDir);
558+
OS << '\n';
522559
} else if (Arg == "--cmakedir") {
523-
OS << ActiveCMakeDir << '\n';
560+
MaybePrintQuoted(ActiveCMakeDir);
561+
OS << '\n';
524562
} else if (Arg == "--cppflags") {
525-
OS << ActiveIncludeOption << ' ' << LLVM_CPPFLAGS << '\n';
563+
RenderFlags(LLVM_CPPFLAGS);
526564
} else if (Arg == "--cflags") {
527-
OS << ActiveIncludeOption << ' ' << LLVM_CFLAGS << '\n';
565+
RenderFlags(LLVM_CFLAGS);
528566
} else if (Arg == "--cxxflags") {
529-
OS << ActiveIncludeOption << ' ' << LLVM_CXXFLAGS << '\n';
567+
RenderFlags(LLVM_CXXFLAGS);
530568
} else if (Arg == "--ldflags") {
531-
OS << ((HostTriple.isWindowsMSVCEnvironment()) ? "-LIBPATH:" : "-L")
532-
<< ActiveLibDir << ' ' << LLVM_LDFLAGS << '\n';
569+
std::string LDFlags =
570+
HostTriple.isWindowsMSVCEnvironment() ? "-LIBPATH:" : "-L";
571+
LDFlags += ActiveLibDir;
572+
MaybePrintQuoted(LDFlags);
573+
OS << ' ' << LLVM_LDFLAGS << '\n';
533574
} else if (Arg == "--system-libs") {
534575
PrintSystemLibs = true;
535576
} else if (Arg == "--libs") {
@@ -590,7 +631,8 @@ int main(int argc, char **argv) {
590631
} else if (Arg == "--shared-mode") {
591632
PrintSharedMode = true;
592633
} else if (Arg == "--obj-root") {
593-
OS << ActivePrefix << '\n';
634+
MaybePrintQuoted(ActivePrefix);
635+
OS << '\n';
594636
} else if (Arg == "--ignore-libllvm") {
595637
LinkDyLib = false;
596638
LinkMode = BuiltSharedLibs ? LinkModeShared : LinkModeAuto;
@@ -600,6 +642,8 @@ int main(int argc, char **argv) {
600642
LinkMode = LinkModeStatic;
601643
} else if (Arg == "--help") {
602644
usage(false);
645+
} else if (Arg == "--quote-paths") {
646+
// Was already handled above this loop.
603647
} else {
604648
usage();
605649
}
@@ -695,26 +739,30 @@ int main(int argc, char **argv) {
695739

696740
auto PrintForLib = [&](const StringRef &Lib) {
697741
const bool Shared = LinkMode == LinkModeShared;
742+
std::string LibFileName;
698743
if (PrintLibNames) {
699-
OS << GetComponentLibraryFileName(Lib, Shared);
744+
LibFileName = GetComponentLibraryFileName(Lib, Shared);
700745
} else if (PrintLibFiles) {
701-
OS << GetComponentLibraryPath(Lib, Shared);
746+
LibFileName = GetComponentLibraryPath(Lib, Shared);
702747
} else if (PrintLibs) {
703748
// On Windows, output full path to library without parameters.
704749
// Elsewhere, if this is a typical library name, include it using -l.
705750
if (HostTriple.isWindowsMSVCEnvironment()) {
706-
OS << GetComponentLibraryPath(Lib, Shared);
751+
LibFileName = GetComponentLibraryPath(Lib, Shared);
707752
} else {
753+
LibFileName = "-l";
708754
StringRef LibName;
709755
if (GetComponentLibraryNameSlice(Lib, LibName)) {
710756
// Extract library name (remove prefix and suffix).
711-
OS << "-l" << LibName;
757+
LibFileName += LibName;
712758
} else {
713759
// Lib is already a library name without prefix and suffix.
714-
OS << "-l" << Lib;
760+
LibFileName += Lib;
715761
}
716762
}
717763
}
764+
if (!LibFileName.empty())
765+
MaybePrintQuoted(LibFileName);
718766
};
719767

720768
if (LinkMode == LinkModeShared && LinkDyLib) {

0 commit comments

Comments
 (0)