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
