https://github.com/yxsamliu updated 
https://github.com/llvm/llvm-project/pull/207798

>From 414e15bbe999530b854894349077cea36e23b14d Mon Sep 17 00:00:00 2001
From: "Yaxun (Sam) Liu" <[email protected]>
Date: Mon, 6 Jul 2026 11:48:02 -0400
Subject: [PATCH] [Driver] Print C++ standard library info

Users and tools sometimes need to know which C++ standard library Clang 
selected, and which include directories the driver added for it. Today they 
have to inspect verbose or `-###` output.

Add options to print this information directly:

`--print-cxx-stdlib`
`--print-cxx-stdlib-include-dirs`

For MSVC targets, the default printed library is `msvcstl`. Explicit `-stdlib=` 
values are still reported as requested. The include-dir query reuses toolchain 
logic, including the MSVC STL include path for the default MSVC case.
---
 clang/include/clang/Driver/ToolChain.h |  4 ++
 clang/include/clang/Options/Options.td |  8 ++++
 clang/lib/Driver/Driver.cpp            | 30 ++++++++++++++
 clang/lib/Driver/ToolChain.cpp         | 10 +++++
 clang/lib/Driver/ToolChains/MSVC.cpp   | 56 ++++++++++++++++++++------
 clang/lib/Driver/ToolChains/MSVC.h     |  8 ++++
 clang/test/Driver/print-cxx-stdlib.cpp | 56 ++++++++++++++++++++++++++
 7 files changed, 160 insertions(+), 12 deletions(-)
 create mode 100644 clang/test/Driver/print-cxx-stdlib.cpp

diff --git a/clang/include/clang/Driver/ToolChain.h 
b/clang/include/clang/Driver/ToolChain.h
index 863ba1084cb1a..c5633e10933e8 100644
--- a/clang/include/clang/Driver/ToolChain.h
+++ b/clang/include/clang/Driver/ToolChain.h
@@ -783,6 +783,10 @@ class ToolChain {
   // given compilation arguments.
   virtual CXXStdlibType GetCXXStdlibType(const llvm::opt::ArgList &Args) const;
 
+  // GetCXXStdlibName - Determine the name of the C++ standard library to use
+  // with the given compilation arguments.
+  virtual StringRef GetCXXStdlibName(const llvm::opt::ArgList &Args) const;
+
   // GetUnwindLibType - Determine the unwind library type to use with the
   // given compilation arguments.
   virtual UnwindLibType GetUnwindLibType(const llvm::opt::ArgList &Args) const;
diff --git a/clang/include/clang/Options/Options.td 
b/clang/include/clang/Options/Options.td
index 4afb089e8a51f..95f0bbada11ea 100644
--- a/clang/include/clang/Options/Options.td
+++ b/clang/include/clang/Options/Options.td
@@ -6585,6 +6585,14 @@ def print_libgcc_file_name : Flag<["-", "--"], 
"print-libgcc-file-name">,
   HelpText<"Print the library path for the currently used compiler runtime "
            "library (\"libgcc.a\" or \"libclang_rt.builtins.*.a\")">,
   Visibility<[ClangOption, CLOption]>;
+def print_cxx_stdlib : Flag<["-", "--"], "print-cxx-stdlib">,
+  HelpText<"Print the C++ standard library selected by the driver">,
+  Visibility<[ClangOption]>;
+def print_cxx_stdlib_include_dirs :
+    Flag<["-", "--"], "print-cxx-stdlib-include-dirs">,
+  HelpText<"Print the C++ standard library include directories selected by "
+           "the driver">,
+  Visibility<[ClangOption]>;
 def print_multi_directory : Flag<["-", "--"], "print-multi-directory">;
 def print_multi_lib : Flag<["-", "--"], "print-multi-lib">;
 def print_multi_flags : Flag<["-", "--"], "print-multi-flags-experimental">,
diff --git a/clang/lib/Driver/Driver.cpp b/clang/lib/Driver/Driver.cpp
index e606cdc4c1cf8..2ef9ffe0b9426 100644
--- a/clang/lib/Driver/Driver.cpp
+++ b/clang/lib/Driver/Driver.cpp
@@ -136,6 +136,26 @@ template <typename F> static bool usesInput(const ArgList 
&Args, F &&Fn) {
   });
 }
 
+static bool isIncludeDirArg(StringRef Arg) {
+  return Arg == "-internal-isystem" || Arg == "-internal-externc-isystem" ||
+         Arg == "-isystem" || Arg == "-cxx-isystem" || Arg == "-idirafter";
+}
+
+static void printCXXStdlibIncludeDirs(const ToolChain &TC,
+                                      const ArgList &Args) {
+  ArgStringList CC1Args;
+  if (Args.hasArg(options::OPT_stdlibxx_isystem))
+    TC.AddClangCXXStdlibIsystemArgs(Args, CC1Args);
+  else
+    TC.AddClangCXXStdlibIncludeArgs(Args, CC1Args);
+
+  for (size_t I = 0; I < CC1Args.size(); ++I) {
+    StringRef Arg(CC1Args[I]);
+    if (isIncludeDirArg(Arg) && I + 1 < CC1Args.size())
+      llvm::outs() << CC1Args[++I] << '\n';
+  }
+}
+
 CUIDOptions::CUIDOptions(llvm::opt::DerivedArgList &Args, const Driver &D)
     : UseCUID(Kind::Hash) {
   if (Arg *A = Args.getLastArg(options::OPT_fuse_cuid_EQ)) {
@@ -2674,6 +2694,16 @@ bool Driver::HandleImmediateArgs(Compilation &C) {
     return false;
   }
 
+  if (C.getArgs().hasArg(options::OPT_print_cxx_stdlib)) {
+    llvm::outs() << TC.GetCXXStdlibName(C.getArgs()) << '\n';
+    return false;
+  }
+
+  if (C.getArgs().hasArg(options::OPT_print_cxx_stdlib_include_dirs)) {
+    printCXXStdlibIncludeDirs(TC, C.getArgs());
+    return false;
+  }
+
   if (C.getArgs().hasArg(options::OPT_print_std_module_manifest_path)) {
     llvm::outs() << GetStdModuleManifestPath(C, C.getDefaultToolChain())
                  << '\n';
diff --git a/clang/lib/Driver/ToolChain.cpp b/clang/lib/Driver/ToolChain.cpp
index 0002d40bf1aa3..6a928890df7c4 100644
--- a/clang/lib/Driver/ToolChain.cpp
+++ b/clang/lib/Driver/ToolChain.cpp
@@ -1629,6 +1629,16 @@ ToolChain::CXXStdlibType 
ToolChain::GetCXXStdlibType(const ArgList &Args) const{
   return *cxxStdlibType;
 }
 
+StringRef ToolChain::GetCXXStdlibName(const ArgList &Args) const {
+  switch (GetCXXStdlibType(Args)) {
+  case ToolChain::CST_Libcxx:
+    return "libc++";
+  case ToolChain::CST_Libstdcxx:
+    return "libstdc++";
+  }
+  llvm_unreachable("unknown C++ standard library type");
+}
+
 ToolChain::CStdlibType ToolChain::GetCStdlibType(const ArgList &Args) const {
   if (cStdlibType)
     return *cStdlibType;
diff --git a/clang/lib/Driver/ToolChains/MSVC.cpp 
b/clang/lib/Driver/ToolChains/MSVC.cpp
index 2aa69ec62cfba..07ad9215fc029 100644
--- a/clang/lib/Driver/ToolChains/MSVC.cpp
+++ b/clang/lib/Driver/ToolChains/MSVC.cpp
@@ -776,6 +776,37 @@ void MSVCToolChain::AddSystemIncludeWithSubfolder(
   addSystemInclude(DriverArgs, CC1Args, path);
 }
 
+void MSVCToolChain::AddMSVCStdlibMultilibIncludeArgs(
+    const ArgList &DriverArgs, ArgStringList &CC1Args,
+    bool HonorNostdincxx) const {
+  if (DriverArgs.hasArg(options::OPT_nostdinc, options::OPT_nostdlibinc) ||
+      (HonorNostdincxx && DriverArgs.hasArg(options::OPT_nostdincxx)))
+    return;
+
+  // Add multilib variant include paths in priority order.
+  for (const Multilib &M : getOrderedMultilibs()) {
+    if (M.isDefault())
+      continue;
+    if (std::optional<std::string> StdlibIncDir = getStdlibIncludePath()) {
+      SmallString<128> Dir(*StdlibIncDir);
+      llvm::sys::path::append(Dir, M.includeSuffix());
+      if (getDriver().getVFS().exists(Dir))
+        addSystemInclude(DriverArgs, CC1Args, Dir);
+    }
+  }
+}
+
+void MSVCToolChain::AddMSVCStdlibIncludeArgs(const ArgList &DriverArgs,
+                                             ArgStringList &CC1Args) const {
+  AddMSVCStdlibMultilibIncludeArgs(DriverArgs, CC1Args,
+                                   /*HonorNostdincxx=*/true);
+
+  if (!DriverArgs.hasArg(options::OPT_nostdinc, options::OPT_nostdlibinc) &&
+      !DriverArgs.hasArg(options::OPT_nostdincxx) && !VCToolChainPath.empty())
+    addSystemInclude(DriverArgs, CC1Args,
+                     getSubDirectoryPath(llvm::SubDirectoryType::Include));
+}
+
 void MSVCToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
                                               ArgStringList &CC1Args) const {
   if (DriverArgs.hasArg(options::OPT_nostdinc))
@@ -824,17 +855,8 @@ void MSVCToolChain::AddClangSystemIncludeArgs(const 
ArgList &DriverArgs,
   if (DriverArgs.hasArg(options::OPT_nostdlibinc))
     return;
 
-  // Add multilib variant include paths in priority order.
-  for (const Multilib &M : getOrderedMultilibs()) {
-    if (M.isDefault())
-      continue;
-    if (std::optional<std::string> StdlibIncDir = getStdlibIncludePath()) {
-      SmallString<128> Dir(*StdlibIncDir);
-      llvm::sys::path::append(Dir, M.includeSuffix());
-      if (getDriver().getVFS().exists(Dir))
-        addSystemInclude(DriverArgs, CC1Args, Dir);
-    }
-  }
+  AddMSVCStdlibMultilibIncludeArgs(DriverArgs, CC1Args,
+                                   /*HonorNostdincxx=*/false);
 
   // Honor %INCLUDE% and %EXTERNAL_INCLUDE%. It should have essential search
   // paths set by vcvarsall.bat. Skip if the user expressly set any of the
@@ -929,7 +951,17 @@ void MSVCToolChain::AddClangSystemIncludeArgs(const 
ArgList &DriverArgs,
 
 void MSVCToolChain::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs,
                                                  ArgStringList &CC1Args) const 
{
-  // FIXME: There should probably be logic here to find libc++ on Windows.
+  // MSVC STL paths are added from AddClangSystemIncludeArgs during normal
+  // compilation to preserve clang-cl header search order.
+  if (DriverArgs.hasArg(options::OPT_print_cxx_stdlib_include_dirs) &&
+      !DriverArgs.hasArg(options::OPT_stdlib_EQ))
+    AddMSVCStdlibIncludeArgs(DriverArgs, CC1Args);
+}
+
+StringRef MSVCToolChain::GetCXXStdlibName(const ArgList &DriverArgs) const {
+  if (!DriverArgs.hasArg(options::OPT_stdlib_EQ))
+    return "msvcstl";
+  return ToolChain::GetCXXStdlibName(DriverArgs);
 }
 
 VersionTuple MSVCToolChain::computeMSVCVersion(const Driver *D,
diff --git a/clang/lib/Driver/ToolChains/MSVC.h 
b/clang/lib/Driver/ToolChains/MSVC.h
index 6878d6a195d78..8ff8b2815d8df 100644
--- a/clang/lib/Driver/ToolChains/MSVC.h
+++ b/clang/lib/Driver/ToolChains/MSVC.h
@@ -101,6 +101,8 @@ class LLVM_LIBRARY_VISIBILITY MSVCToolChain : public 
ToolChain {
   void
   AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs,
                             llvm::opt::ArgStringList &CC1Args) const override;
+  llvm::StringRef
+  GetCXXStdlibName(const llvm::opt::ArgList &DriverArgs) const override;
   void AddClangCXXStdlibIncludeArgs(
       const llvm::opt::ArgList &DriverArgs,
       llvm::opt::ArgStringList &CC1Args) const override;
@@ -143,6 +145,12 @@ class LLVM_LIBRARY_VISIBILITY MSVCToolChain : public 
ToolChain {
                         Action::OffloadKind DeviceOffloadKind) const override;
 
 protected:
+  void AddMSVCStdlibMultilibIncludeArgs(const llvm::opt::ArgList &DriverArgs,
+                                        llvm::opt::ArgStringList &CC1Args,
+                                        bool HonorNostdincxx) const;
+  void AddMSVCStdlibIncludeArgs(const llvm::opt::ArgList &DriverArgs,
+                                llvm::opt::ArgStringList &CC1Args) const;
+
   void AddSystemIncludeWithSubfolder(const llvm::opt::ArgList &DriverArgs,
                                      llvm::opt::ArgStringList &CC1Args,
                                      const std::string &folder,
diff --git a/clang/test/Driver/print-cxx-stdlib.cpp 
b/clang/test/Driver/print-cxx-stdlib.cpp
new file mode 100644
index 0000000000000..58620e7ee34dc
--- /dev/null
+++ b/clang/test/Driver/print-cxx-stdlib.cpp
@@ -0,0 +1,56 @@
+// RUN: %clangxx -print-cxx-stdlib -stdlib=libc++ \
+// RUN:   --target=x86_64-unknown-linux-gnu | FileCheck %s 
--check-prefix=LIBCXX
+// RUN: %clangxx --print-cxx-stdlib -stdlib=libstdc++ \
+// RUN:   --target=x86_64-unknown-linux-gnu | FileCheck %s 
--check-prefix=LIBSTDCXX
+// RUN: %clangxx --print-cxx-stdlib --target=x86_64-pc-windows-msvc \
+// RUN:   | FileCheck %s --check-prefix=MSVC-STL
+// RUN: %clangxx --print-cxx-stdlib -stdlib=libc++ \
+// RUN:   --target=x86_64-pc-windows-msvc | FileCheck %s --check-prefix=LIBCXX
+
+// RUN: mkdir -p %t/bin
+// RUN: mkdir -p %t/include/c++/v1
+// RUN: %clangxx -print-cxx-stdlib-include-dirs -stdlib=libc++ \
+// RUN:   --target=x86_64-unknown-linux-gnu -ccc-install-dir %t/bin \
+// RUN:   | FileCheck %s --check-prefix=LIBCXX-INCLUDES
+
+// RUN: %clangxx --print-cxx-stdlib-include-dirs -stdlib++-isystem /tmp/foo \
+// RUN:   -stdlib++-isystem /tmp/bar --target=x86_64-unknown-linux-gnu \
+// RUN:   | FileCheck %s --check-prefix=STDLIBXX-ISYSTEM
+// RUN: %clangxx --print-cxx-stdlib-include-dirs -stdlib++-isystem /tmp/foo \
+// RUN:   -stdlib++-isystem /tmp/bar -nostdinc++ \
+// RUN:   --target=x86_64-unknown-linux-gnu \
+// RUN:   | FileCheck %s --check-prefix=NO-INCLUDES --allow-empty
+
+// RUN: %clangxx --print-cxx-stdlib-include-dirs -stdlib=libstdc++ \
+// RUN:   --gcc-toolchain=%S/Inputs/gcc_version_parsing_rt_libs \
+// RUN:   --target=x86_64-redhat-linux \
+// RUN:   | FileCheck %s --check-prefix=LIBSTDCXX-INCLUDES
+// RUN: %clangxx --print-cxx-stdlib-include-dirs \
+// RUN:   --target=x86_64-pc-windows-msvc \
+// RUN:   -Xmicrosoft-visualc-tools-root %t/VC/Tools/MSVC/27.1828.18284 \
+// RUN:   | FileCheck %s --check-prefix=MSVC-INCLUDES
+// RUN: %clangxx --print-cxx-stdlib-include-dirs \
+// RUN:   --target=x86_64-pc-windows-msvc \
+// RUN:   -Xmicrosoft-visualc-tools-root %t/VC/Tools/MSVC/27.1828.18284 \
+// RUN:   -nostdinc++ \
+// RUN:   | FileCheck %s --check-prefix=NO-INCLUDES --allow-empty
+// RUN: %clangxx --print-cxx-stdlib-include-dirs -stdlib=libc++ \
+// RUN:   --target=x86_64-pc-windows-msvc \
+// RUN:   -Xmicrosoft-visualc-tools-root %t/VC/Tools/MSVC/27.1828.18284 \
+// RUN:   | FileCheck %s --check-prefix=NO-INCLUDES --allow-empty
+
+// LIBCXX: libc++
+// LIBSTDCXX: libstdc++
+// MSVC-STL: msvcstl
+
+// LIBCXX-INCLUDES: {{.*}}{{/|\\}}include{{/|\\}}c++{{/|\\}}v1
+
+// STDLIBXX-ISYSTEM: /tmp/foo
+// STDLIBXX-ISYSTEM-NEXT: /tmp/bar
+
+// NO-INCLUDES-NOT: {{.}}
+
+// LIBSTDCXX-INCLUDES: 
{{.*}}gcc_version_parsing_rt_libs{{/|\\}}lib{{/|\\}}gcc{{/|\\}}x86_64-redhat-linux{{/|\\}}10.2.0{{/|\\}}..{{/|\\}}..{{/|\\}}..{{/|\\}}gcc{{/|\\}}x86_64-redhat-linux{{/|\\}}10.2.0{{/|\\}}include{{/|\\}}c++
+
+// MSVC-INCLUDES: 
{{.*}}VC{{/|\\}}Tools{{/|\\}}MSVC{{/|\\}}27.1828.18284{{/|\\}}include
+// MSVC-INCLUDES-NOT: atlmfc

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to