[llvm] 421ba7f - [llvm-config] Add new flag `--quote-paths` to optionally quote and escape paths (#103397)
via llvm-commits
llvm-commits at lists.llvm.org
Sat Nov 1 10:19:26 PDT 2025
Author: Alexandre Ganea
Date: 2025-11-01T17:19:21Z
New Revision: 421ba7fbb582f2bedcdf46d5afc03367d229bc31
URL: https://github.com/llvm/llvm-project/commit/421ba7fbb582f2bedcdf46d5afc03367d229bc31
DIFF: https://github.com/llvm/llvm-project/commit/421ba7fbb582f2bedcdf46d5afc03367d229bc31.diff
LOG: [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 https://github.com/llvm/llvm-project/pull/97305
I could also do what @tothambrus11 suggests in
https://github.com/llvm/llvm-project/pull/97305#issuecomment-2282847990
but that makes all Windows paths quoted & escaped since they all contain
backslashes.
Added:
Modified:
llvm/docs/ReleaseNotes.md
llvm/test/tools/llvm-config/paths.test
llvm/tools/llvm-config/llvm-config.cpp
Removed:
################################################################################
diff --git a/llvm/docs/ReleaseNotes.md b/llvm/docs/ReleaseNotes.md
index 49158fb4217b6..bfe68274eae3f 100644
--- a/llvm/docs/ReleaseNotes.md
+++ b/llvm/docs/ReleaseNotes.md
@@ -180,6 +180,10 @@ Changes to the LLVM tools
* Some code paths for supporting Python 2.7 in `llvm-lit` have been removed.
* Support for `%T` in lit has been removed.
+* `llvm-config` gained a new flag `--quote-paths` which quotes and escapes paths
+ emitted on stdout, to account for spaces or other special characters in path.
+ (`#97305 <https://github.com/llvm/llvm-project/pull/97305>`_).
+
Changes to LLDB
---------------------------------
diff --git a/llvm/test/tools/llvm-config/paths.test b/llvm/test/tools/llvm-config/paths.test
index 419f155ae1f83..61d86f7eb0ba1 100644
--- a/llvm/test/tools/llvm-config/paths.test
+++ b/llvm/test/tools/llvm-config/paths.test
@@ -4,18 +4,34 @@ RUN: llvm-config --bindir 2>&1 | FileCheck --check-prefix=CHECK-BINDIR %s
CHECK-BINDIR: {{.*}}{{/|\\}}bin
CHECK-BINDIR-NOT: error:
CHECK-BINDIR-NOT: warning
+RUN: llvm-config --bindir --quote-paths 2>&1 | FileCheck --check-prefix=CHECK-BINDIR2 %s
+CHECK-BINDIR2: {{.*}}{{/|\\\\}}bin
+CHECK-BINDIR2-NOT: error:
+CHECK-BINDIR2-NOT: warning
RUN: llvm-config --includedir 2>&1 | FileCheck --check-prefix=CHECK-INCLUDEDIR %s
CHECK-INCLUDEDIR: {{.*}}{{/|\\}}include
CHECK-INCLUDEDIR-NOT: error:
CHECK-INCLUDEDIR-NOT: warning
+RUN: llvm-config --includedir --quote-paths 2>&1 | FileCheck --check-prefix=CHECK-INCLUDEDIR2 %s
+CHECK-INCLUDEDIR2: {{.*}}{{/|\\\\}}include
+CHECK-INCLUDEDIR2-NOT: error:
+CHECK-INCLUDEDIR2-NOT: warning
RUN: llvm-config --libdir 2>&1 | FileCheck --check-prefix=CHECK-LIBDIR %s
CHECK-LIBDIR: {{.*}}{{/|\\}}lib{{.*}}
CHECK-LIBDIR-NOT: error:
CHECK-LIBDIR-NOT: warning
+RUN: llvm-config --libdir --quote-paths 2>&1 | FileCheck --check-prefix=CHECK-LIBDIR2 %s
+CHECK-LIBDIR2: {{.*}}{{/|\\\\}}lib{{.*}}
+CHECK-LIBDIR2-NOT: error:
+CHECK-LIBDIR2-NOT: warning
RUN: llvm-config --cmakedir 2>&1 | FileCheck --check-prefix=CHECK-CMAKEDIR %s
CHECK-CMAKEDIR: {{.*}}{{/|\\}}cmake{{/|\\}}llvm
CHECK-CMAKEDIR-NOT: error:
CHECK-CMAKEDIR-NOT: warning
+RUN: llvm-config --cmakedir --quote-paths 2>&1 | FileCheck --check-prefix=CHECK-CMAKEDIR2 %s
+CHECK-CMAKEDIR2: {{.*}}{{/|\\\\}}cmake{{/|\\\\}}llvm
+CHECK-CMAKEDIR2-NOT: error:
+CHECK-CMAKEDIR2-NOT: warning
diff --git a/llvm/tools/llvm-config/llvm-config.cpp b/llvm/tools/llvm-config/llvm-config.cpp
index 020b1b5e093d5..36cd7913eda82 100644
--- a/llvm/tools/llvm-config/llvm-config.cpp
+++ b/llvm/tools/llvm-config/llvm-config.cpp
@@ -24,6 +24,7 @@
#include "llvm/Config/config.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Path.h"
+#include "llvm/Support/Program.h"
#include "llvm/Support/WithColor.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/TargetParser/Triple.h"
@@ -218,6 +219,7 @@ Options:\n\
--components List of all possible components.\n\
--cppflags C preprocessor flags for files that include LLVM headers.\n\
--cxxflags C++ compiler flags for files that include LLVM headers.\n\
+ --quote-paths Quote and escape paths when needed.\n\
--has-rtti Print whether or not LLVM was built with rtti (YES or NO).\n\
--help Print a summary of llvm-config arguments.\n\
--host-target Target triple used to configure LLVM.\n\
@@ -324,7 +326,7 @@ int main(int argc, char **argv) {
// information.
std::string ActivePrefix, ActiveBinDir, ActiveIncludeDir, ActiveLibDir,
ActiveCMakeDir;
- std::string ActiveIncludeOption;
+ std::vector<std::string> ActiveIncludeOptions;
if (IsInDevelopmentTree) {
ActiveIncludeDir = std::string(LLVM_SRC_ROOT) + "/include";
ActivePrefix = CurrentExecPrefix;
@@ -350,8 +352,8 @@ int main(int argc, char **argv) {
}
// We need to include files from both the source and object trees.
- ActiveIncludeOption =
- ("-I" + ActiveIncludeDir + " " + "-I" + ActiveObjRoot + "/include");
+ ActiveIncludeOptions.push_back(ActiveIncludeDir);
+ ActiveIncludeOptions.push_back(ActiveObjRoot + "/include");
} else {
ActivePrefix = CurrentExecPrefix;
{
@@ -370,7 +372,7 @@ int main(int argc, char **argv) {
sys::path::make_absolute(ActivePrefix, Path);
ActiveCMakeDir = std::string(Path);
}
- ActiveIncludeOption = "-I" + ActiveIncludeDir;
+ ActiveIncludeOptions.push_back(ActiveIncludeDir);
}
/// We only use `shared library` mode in cases where the static library form
@@ -399,7 +401,9 @@ int main(int argc, char **argv) {
llvm::replace(ActiveBinDir, '/', '\\');
llvm::replace(ActiveLibDir, '/', '\\');
llvm::replace(ActiveCMakeDir, '/', '\\');
- llvm::replace(ActiveIncludeOption, '/', '\\');
+ llvm::replace(ActiveIncludeDir, '/', '\\');
+ for (auto &Include : ActiveIncludeOptions)
+ llvm::replace(Include, '/', '\\');
}
SharedDir = ActiveBinDir;
StaticDir = ActiveLibDir;
@@ -501,6 +505,32 @@ int main(int argc, char **argv) {
};
raw_ostream &OS = outs();
+
+ // Check if we want quoting and escaping.
+ bool QuotePaths = std::any_of(&argv[0], &argv[argc], [](const char *Arg) {
+ return StringRef(Arg) == "--quote-paths";
+ });
+
+ auto MaybePrintQuoted = [&](StringRef Str) {
+ if (QuotePaths)
+ sys::printArg(OS, Str, /*Quote=*/false); // only add quotes if necessary
+ else
+ OS << Str;
+ };
+
+ // Render include paths and associated flags
+ auto RenderFlags = [&](StringRef Flags) {
+ bool First = true;
+ for (auto &Include : ActiveIncludeOptions) {
+ if (!First)
+ OS << ' ';
+ std::string FlagsStr = "-I" + Include;
+ MaybePrintQuoted(FlagsStr);
+ First = false;
+ }
+ OS << ' ' << Flags << '\n';
+ };
+
for (int i = 1; i != argc; ++i) {
StringRef Arg = argv[i];
@@ -509,24 +539,32 @@ int main(int argc, char **argv) {
if (Arg == "--version") {
OS << PACKAGE_VERSION << '\n';
} else if (Arg == "--prefix") {
- OS << ActivePrefix << '\n';
+ MaybePrintQuoted(ActivePrefix);
+ OS << '\n';
} else if (Arg == "--bindir") {
- OS << ActiveBinDir << '\n';
+ MaybePrintQuoted(ActiveBinDir);
+ OS << '\n';
} else if (Arg == "--includedir") {
- OS << ActiveIncludeDir << '\n';
+ MaybePrintQuoted(ActiveIncludeDir);
+ OS << '\n';
} else if (Arg == "--libdir") {
- OS << ActiveLibDir << '\n';
+ MaybePrintQuoted(ActiveLibDir);
+ OS << '\n';
} else if (Arg == "--cmakedir") {
- OS << ActiveCMakeDir << '\n';
+ MaybePrintQuoted(ActiveCMakeDir);
+ OS << '\n';
} else if (Arg == "--cppflags") {
- OS << ActiveIncludeOption << ' ' << LLVM_CPPFLAGS << '\n';
+ RenderFlags(LLVM_CPPFLAGS);
} else if (Arg == "--cflags") {
- OS << ActiveIncludeOption << ' ' << LLVM_CFLAGS << '\n';
+ RenderFlags(LLVM_CFLAGS);
} else if (Arg == "--cxxflags") {
- OS << ActiveIncludeOption << ' ' << LLVM_CXXFLAGS << '\n';
+ RenderFlags(LLVM_CXXFLAGS);
} else if (Arg == "--ldflags") {
- OS << ((HostTriple.isWindowsMSVCEnvironment()) ? "-LIBPATH:" : "-L")
- << ActiveLibDir << ' ' << LLVM_LDFLAGS << '\n';
+ std::string LDFlags =
+ HostTriple.isWindowsMSVCEnvironment() ? "-LIBPATH:" : "-L";
+ LDFlags += ActiveLibDir;
+ MaybePrintQuoted(LDFlags);
+ OS << ' ' << LLVM_LDFLAGS << '\n';
} else if (Arg == "--system-libs") {
PrintSystemLibs = true;
} else if (Arg == "--libs") {
@@ -580,7 +618,8 @@ int main(int argc, char **argv) {
} else if (Arg == "--shared-mode") {
PrintSharedMode = true;
} else if (Arg == "--obj-root") {
- OS << ActivePrefix << '\n';
+ MaybePrintQuoted(ActivePrefix);
+ OS << '\n';
} else if (Arg == "--ignore-libllvm") {
LinkDyLib = false;
LinkMode = BuiltSharedLibs ? LinkModeShared : LinkModeAuto;
@@ -590,6 +629,8 @@ int main(int argc, char **argv) {
LinkMode = LinkModeStatic;
} else if (Arg == "--help") {
usage(false);
+ } else if (Arg == "--quote-paths") {
+ // Was already handled above this loop.
} else {
usage();
}
@@ -682,26 +723,30 @@ int main(int argc, char **argv) {
auto PrintForLib = [&](const StringRef &Lib) {
const bool Shared = LinkMode == LinkModeShared;
+ std::string LibFileName;
if (PrintLibNames) {
- OS << GetComponentLibraryFileName(Lib, Shared);
+ LibFileName = GetComponentLibraryFileName(Lib, Shared);
} else if (PrintLibFiles) {
- OS << GetComponentLibraryPath(Lib, Shared);
+ LibFileName = GetComponentLibraryPath(Lib, Shared);
} else if (PrintLibs) {
// On Windows, output full path to library without parameters.
// Elsewhere, if this is a typical library name, include it using -l.
if (HostTriple.isWindowsMSVCEnvironment()) {
- OS << GetComponentLibraryPath(Lib, Shared);
+ LibFileName = GetComponentLibraryPath(Lib, Shared);
} else {
+ LibFileName = "-l";
StringRef LibName;
if (GetComponentLibraryNameSlice(Lib, LibName)) {
// Extract library name (remove prefix and suffix).
- OS << "-l" << LibName;
+ LibFileName += LibName;
} else {
// Lib is already a library name without prefix and suffix.
- OS << "-l" << Lib;
+ LibFileName += Lib;
}
}
}
+ if (!LibFileName.empty())
+ MaybePrintQuoted(LibFileName);
};
if (LinkMode == LinkModeShared && LinkDyLib)
More information about the llvm-commits
mailing list