Using clang on windows without using MSVC link

Hello,

I’ve been looking into using clang to build and link on windows, however it seems that clang tries to run MSVC link instead of lld.

clang++: warning: unable to find a Visual Studio installation; try running Clang from a developer command prompt [-Wmsvc-not-found]

Is there any way to use the MSVC libraries and includes, as specified in LIB and INCLUDE variables, but link using LLVM?

Well, you could use lld-link.exe which comes with the official Clang/LLVM setup for Windows (i.e. from here).

You do this by passing -fuse-ld=lld-link to your compiler driver (e.g. clang or clang++). If you want to see what exactly is going on, you can add a -v for increased verbosity.

Still, the outcome will most likely be that some static or import libs are missing as those don’t seem to come with the official installer (but you could get those from a Windows SDK or the older Windows WDKs which even came with compilers and linkers).

Suppose we have a trivial program not depending on any external header (dummy.cpp):

int main()
{
	return 0;
}

If we attempt to compile this without MSVC toolchains in their usual paths (think vswhere or other means of “detecting” MSVC incapacitated) we’ll get:

Z:\test>clang++ -v -fuse-ld=lld-link dummy.cpp
clang version 12.0.0
Target: x86_64-pc-windows-msvc
Thread model: posix
InstalledDir: C:\Program Files\LLVM\bin
 "C:\\Program Files\\LLVM\\bin\\clang++.exe" -cc1 -triple x86_64-pc-windows-msvc19.11.0 -emit-obj -mrelax-all -mincremental-linker-compatible --mrelax-relocations -disable-free -disable-llvm-verifier -discard-value-names -main-file-name dummy.cpp -mrelocation-model pic -pic-level 2 -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -tune-cpu generic -v -resource-dir "C:\\Program Files\\LLVM\\lib\\clang\\12.0.0" -internal-isystem "C:\\Program Files\\LLVM\\lib\\clang\\12.0.0\\include" -internal-isystem "C:/Program Files/Microsoft Visual Studio 10.0/VC/include" -internal-isystem "C:/Program Files/Microsoft Visual Studio 9.0/VC/include" -internal-isystem "C:/Program Files/Microsoft Visual Studio 9.0/VC/PlatformSDK/Include" -internal-isystem "C:/Program Files/Microsoft Visual Studio 8/VC/include" -internal-isystem "C:/Program Files/Microsoft Visual Studio 8/VC/PlatformSDK/Include" -fdeprecated-macro -fdebug-compilation-dir "Z:\\test" -ferror-limit 19 -fmessage-length=188 -fno-use-cxa-atexit -fms-extensions -fms-compatibility -fms-compatibility-version=19.11 -std=c++14 -fdelayed-template-parsing -fcxx-exceptions -fexceptions -fcolor-diagnostics -faddrsig -o "C:\\Users\\Joe\\AppData\\Local\\Temp\\dummy-e464fb.o" -x c++ dummy.cpp
clang -cc1 version 12.0.0 based upon LLVM 12.0.0 default target x86_64-pc-windows-msvc
ignoring nonexistent directory "C:/Program Files/Microsoft Visual Studio 10.0/VC/include"
ignoring nonexistent directory "C:/Program Files/Microsoft Visual Studio 9.0/VC/include"
ignoring nonexistent directory "C:/Program Files/Microsoft Visual Studio 9.0/VC/PlatformSDK/Include"
ignoring nonexistent directory "C:/Program Files/Microsoft Visual Studio 8/VC/include"
ignoring nonexistent directory "C:/Program Files/Microsoft Visual Studio 8/VC/PlatformSDK/Include"
#include "..." search starts here:
#include <...> search starts here:
 C:\Program Files\LLVM\lib\clang\12.0.0\include
End of search list.
 "C:\\Program Files\\LLVM\\bin\\lld-link" -out:a.exe -defaultlib:libcmt -defaultlib:oldnames "-libpath:lib\\amd64" "-libpath:atlmfc\\lib\\amd64" "-libpath:C:\\Program Files\\LLVM\\lib\\clang\\12.0.0\\lib\\windows" -nologo "C:\\Users\\Joe\\AppData\\Local\\Temp\\dummy-e464fb.o"
lld-link: error: could not open 'libcmt.lib': no such file or directory
lld-link: error: could not open 'oldnames.lib': no such file or directory
clang++: error: linker command failed with exit code 1 (use -v to see invocation)

Now compare this with an invocation of clang++, still using lld-link as the linker, which has the MSVC libraries and headers at its disposal:

Z:\test>clang++ -v -fuse-ld=lld-link dummy.cpp
clang version 12.0.0
Target: x86_64-pc-windows-msvc
Thread model: posix
InstalledDir: C:\Program Files\LLVM\bin
 "C:\\Program Files\\LLVM\\bin\\clang++.exe" -cc1 -triple x86_64-pc-windows-msvc19.29.30133 -emit-obj -mrelax-all -mincremental-linker-compatible --mrelax-relocations -disable-free -disable-llvm-verifier -discard-value-names -main-file-name dummy.cpp -mrelocation-model pic -pic-level 2 -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -tune-cpu generic -v -resource-dir "C:\\Program Files\\LLVM\\lib\\clang\\12.0.0" -internal-isystem "C:\\Program Files\\LLVM\\lib\\clang\\12.0.0\\include" -internal-isystem "C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\Professional\\VC\\Tools\\MSVC\\14.29.30133\\include" -internal-isystem "C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\Professional\\VC\\Tools\\MSVC\\14.29.30133\\atlmfc\\include" -internal-isystem "C:\\Program Files (x86)\\Windows Kits\\10\\Include\\10.0.19041.0\\ucrt" -internal-isystem "C:\\Program Files (x86)\\Windows Kits\\10\\include\\10.0.19041.0\\shared" -internal-isystem "C:\\Program Files (x86)\\Windows Kits\\10\\include\\10.0.19041.0\\um" -internal-isystem "C:\\Program Files (x86)\\Windows Kits\\10\\include\\10.0.19041.0\\winrt" -fdeprecated-macro -fdebug-compilation-dir "Z:\\test" -ferror-limit 19 -fmessage-length=188 -fno-use-cxa-atexit -fms-extensions -fms-compatibility -fms-compatibility-version=19.29.30133 -std=c++14 -fdelayed-template-parsing -fcxx-exceptions -fexceptions -fcolor-diagnostics -faddrsig -o "C:\\Users\\Joe\\AppData\\Local\\Temp\\dummy-88e3cc.o" -x c++ dummy.cpp
clang -cc1 version 12.0.0 based upon LLVM 12.0.0 default target x86_64-pc-windows-msvc
#include "..." search starts here:
#include <...> search starts here:
 C:\Program Files\LLVM\lib\clang\12.0.0\include
 C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional\VC\Tools\MSVC\14.29.30133\include
 C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional\VC\Tools\MSVC\14.29.30133\atlmfc\include
 C:\Program Files (x86)\Windows Kits\10\Include\10.0.19041.0\ucrt
 C:\Program Files (x86)\Windows Kits\10\include\10.0.19041.0\shared
 C:\Program Files (x86)\Windows Kits\10\include\10.0.19041.0\um
 C:\Program Files (x86)\Windows Kits\10\include\10.0.19041.0\winrt
End of search list.
 "C:\\Program Files\\LLVM\\bin\\lld-link" -out:a.exe -defaultlib:libcmt -defaultlib:oldnames "-libpath:C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\Professional\\VC\\Tools\\MSVC\\14.29.30133\\lib\\x64" "-libpath:C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\Professional\\VC\\Tools\\MSVC\\14.29.30133\\atlmfc\\lib\\x64" "-libpath:C:\\Program Files (x86)\\Windows Kits\\10\\Lib\\10.0.19041.0\\ucrt\\x64" "-libpath:C:\\Program Files (x86)\\Windows Kits\\10\\Lib\\10.0.19041.0\\um\\x64" "-libpath:C:\\Program Files\\LLVM\\lib\\clang\\12.0.0\\lib\\windows" -nologo "C:\\Users\\Joe\\AppData\\Local\\Temp\\dummy-88e3cc.o"

As you can see the issue isn’t so much (or not only) about Clang defaulting to Microsoft’s link.exe as the fact that the headers and libraries are searched in “known” places or somehow auto-detected.

I haven’t tried if the environment variables have any effect on finding the respective libraries/headers, though. So perhaps you can try that and respond with your findings so we all can learn.

Minor addition. You could perhaps add /nodefaultlib so as to prevent the linker to be called with the respective default lib. But in that case you would have to provide a substitute which would have to mimic the basic aspects of what the C/C++ runtime does before (and after) main() gets called (unless, of course, you resort to overriding your entry point and providing your own … but even then some runtime checks will require a handful of helper routines that the runtime checks reference).