https://github.com/mati865 created 
https://github.com/llvm/llvm-project/pull/182062

This implementation differs from GCC, but arguably more in line with Unix 
systems, because it stops linking of default Win32 system libraries.

On GCC it works like this:
```
❯ /ucrt64/bin/gcc -### /dev/null -nolibc 2>&1 | tr ' ' '\n' | rg '^\-l' | sort 
-u
-lgcc
-lgcc_eh
-lkernel32
-lmingw32
-lmingwex
-lmsvcrt

❯ /ucrt64/bin/gcc -### /dev/null 2>&1 | tr ' ' '\n' | rg '^\-l' | sort -u
-ladvapi32
-lgcc
-lgcc_eh
-lkernel32
-lmingw32
-lmingwex
-lmsvcrt
-lpthread
-lshell32
-luser32
```
Clang with this PR:
```
❯ ./bin/clang -### /dev/null -nolibc 2>&1 | tr ' ' '\n' | rg '^"\-l' | sort -u
"-lgcc"
"-lgcc_eh"
```

The motivation for supporting this argument comes from Rust, which wants to 
control what is linked, but still utilize compiler builtins. With GCC that is 
done by supplying `-nodefaultlibs` and `-lgcc`, but LLVM's compiler-rt cannot 
be added back as easily.
`-nolibc --unwindlib=none` that skips Win32 libs would give the parity with 
GCC's `-nodefaultlibs -lgcc`.

From 558200c1d15490e83dbfb4a4edb1ecd307096dfc Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Mateusz=20Miku=C5=82a?= <[email protected]>
Date: Wed, 18 Feb 2026 16:32:55 +0100
Subject: [PATCH] [Clang] [MinGW] Handle `-nolibc` argument

This implementation differs from GCC, but arguably
more in line with Unix systems, because it stops
linking of default Win32 system libraries.
---
 clang/lib/Driver/ToolChains/MinGW.cpp | 37 +++++++++++++++------------
 clang/test/Driver/mingw.cpp           | 10 ++++++++
 2 files changed, 31 insertions(+), 16 deletions(-)

diff --git a/clang/lib/Driver/ToolChains/MinGW.cpp 
b/clang/lib/Driver/ToolChains/MinGW.cpp
index 2c9a174069f70..7c01d49dd778e 100644
--- a/clang/lib/Driver/ToolChains/MinGW.cpp
+++ b/clang/lib/Driver/ToolChains/MinGW.cpp
@@ -60,9 +60,11 @@ void tools::MinGW::Assembler::ConstructJob(Compilation &C, 
const JobAction &JA,
 
 void tools::MinGW::Linker::AddLibGCC(const ArgList &Args,
                                      ArgStringList &CmdArgs) const {
+  bool NoLibc = Args.hasArg(options::OPT_nolibc);
   if (Args.hasArg(options::OPT_mthreads))
     CmdArgs.push_back("-lmingwthrd");
-  CmdArgs.push_back("-lmingw32");
+  if (!NoLibc)
+    CmdArgs.push_back("-lmingw32");
 
   // Make use of compiler-rt if --rtlib option is used
   ToolChain::RuntimeLibType RLT = getToolChain().GetRuntimeLibType(Args);
@@ -83,21 +85,23 @@ void tools::MinGW::Linker::AddLibGCC(const ArgList &Args,
     AddRunTimeLibs(getToolChain(), getToolChain().getDriver(), CmdArgs, Args);
   }
 
-  CmdArgs.push_back("-lmoldname");
-  CmdArgs.push_back("-lmingwex");
-  for (auto Lib : Args.getAllArgValues(options::OPT_l)) {
-    if (StringRef(Lib).starts_with("msvcr") ||
-        StringRef(Lib).starts_with("ucrt") ||
-        StringRef(Lib).starts_with("crtdll")) {
-      std::string CRTLib = (llvm::Twine("-l") + Lib).str();
-      // Respect the user's chosen crt variant, but still provide it
-      // again as the last linker argument, because some of the libraries
-      // we added above may depend on it.
-      CmdArgs.push_back(Args.MakeArgStringRef(CRTLib));
-      return;
+  if (!NoLibc) {
+    CmdArgs.push_back("-lmoldname");
+    CmdArgs.push_back("-lmingwex");
+    for (auto Lib : Args.getAllArgValues(options::OPT_l)) {
+      if (StringRef(Lib).starts_with("msvcr") ||
+          StringRef(Lib).starts_with("ucrt") ||
+          StringRef(Lib).starts_with("crtdll")) {
+        std::string CRTLib = (llvm::Twine("-l") + Lib).str();
+        // Respect the user's chosen crt variant, but still provide it
+        // again as the last linker argument, because some of the libraries
+        // we added above may depend on it.
+        CmdArgs.push_back(Args.MakeArgStringRef(CRTLib));
+        return;
+      }
     }
+    CmdArgs.push_back("-lmsvcrt");
   }
-  CmdArgs.push_back("-lmsvcrt");
 }
 
 void tools::MinGW::Linker::ConstructJob(Compilation &C, const JobAction &JA,
@@ -289,6 +293,7 @@ void tools::MinGW::Linker::ConstructJob(Compilation &C, 
const JobAction &JA,
     }
   }
 
+  bool NoLibc = Args.hasArg(options::OPT_nolibc);
   if (!Args.hasArg(options::OPT_nostdlib)) {
     if (!Args.hasArg(options::OPT_nodefaultlibs)) {
       if (Args.hasArg(options::OPT_static))
@@ -347,7 +352,7 @@ void tools::MinGW::Linker::ConstructJob(Compilation &C, 
const JobAction &JA,
 
       TC.addProfileRTLibs(Args, CmdArgs);
 
-      if (!HasWindowsApp) {
+      if (!HasWindowsApp && !NoLibc) {
         // Add system libraries. If linking to libwindowsapp.a, that import
         // library replaces all these and we shouldn't accidentally try to
         // link to the normal desktop mode dlls.
@@ -365,7 +370,7 @@ void tools::MinGW::Linker::ConstructJob(Compilation &C, 
const JobAction &JA,
         CmdArgs.push_back("--end-group");
       } else {
         AddLibGCC(Args, CmdArgs);
-        if (!HasWindowsApp)
+        if (!HasWindowsApp && !NoLibc)
           CmdArgs.push_back("-lkernel32");
       }
     }
diff --git a/clang/test/Driver/mingw.cpp b/clang/test/Driver/mingw.cpp
index f43fa177e2905..9affd3ba6d5db 100644
--- a/clang/test/Driver/mingw.cpp
+++ b/clang/test/Driver/mingw.cpp
@@ -96,3 +96,13 @@
 // RUN: %clang --target=i686-windows-gnu -fms-hotpatch -### -- %s 2>&1 \
 // RUN:    | FileCheck %s --check-prefix=FUNCTIONPADMIN
 // FUNCTIONPADMIN: "--functionpadmin"
+
+// RUN: %clang --target=x86_64-pc-windows-gnu -nolibc -### %s 2>&1 | FileCheck 
-check-prefix=CHECK_MINGW_NOLIBC %s
+// CHECK_MINGW_NOLIBC-NOT: "-ladvapi32"
+// CHECK_MINGW_NOLIBC-NOT: "-lkernel32"
+// CHECK_MINGW_NOLIBC-NOT: "-lmingw32"
+// CHECK_MINGW_NOLIBC-NOT: "-lmingwex"
+// CHECK_MINGW_NOLIBC-NOT: "-lmoldname"
+// CHECK_MINGW_NOLIBC-NOT: "-lmsvcrt"
+// CHECK_MINGW_NOLIBC-NOT: "-lshell32"
+// CHECK_MINGW_NOLIBC-NOT: "-luser32"

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

Reply via email to