Building clang (win x86-64) binaries with msvc's clang: Hurdles and sticking point

Hello.

I would like to be able to build clang tools/executables from recent source (I’m using llvm-project-llvmorg-14.0.6), initially using visual studio clang tools (v 13.0.1), but thereafter and for newer versions of clang, using these newly built clang tools themself.

However, where I may differ from others who I’ve seen asking for help with similar issues is that I’m attempting to build clang from source as explicitly as possible (i.e. avoiding the cmake machinery that flails around and attempts to automatically find latest versions among multiple installations of toolchains, winsdk and standard library header and lib locations), with as simple, self-contained, and portable/loose directory structure of tools; limiting as much as possible the need for anything to be ‘installed’ and explicitly pointing to everything (one way or another) that ends up being needed.

“Why do it this way?”, you might well ask: Well, it strikes me as a much more clean, portable, and reproducible way of going about things, to explicitly point to a complier, to system include and lib directories, and even to explicitly point to versions of cmake to use, from just one or two simple config/setup steps. There are plenty of people asking for help with issues for which the answer is frequently, “you haven’t installed X properly. Uninstall and reinstall…”, which just strikes me as a quite error prone solution, relying on a lot of ‘flail and find’ cmake build machinery. If a build needs a compiler, linker, various headers, and libs and someone knows exactly where to find them, they should be able to simply explicitly point to them. Plus, this is also a learning excercise for me and something which is not entirely well documented (that I can find).

This whole endevour has had a few hurdles that I document for the possible benefit of others at the bottom, but I also end up at a problem that I can’t get past and would be greatful for some help.

So far, I have the following general directory structure -

c:/dev/
  /cmake-3.24.1-windows-x86_64
    /bin/...
    etc.
  /llvm-project-llvmorg-14.0.6
    /build/...
    mytoolchain_msvcclang.cmake
    etc.
  /meson-0.63.1
    ninja.exe  (v 1.11.0)
  [msvc llvm x64 bin]
    clang.exe  (v 13.0.1)
    clang++.exe
    etc.
[windows sdk run-time headers]
[msvc toolchain headers]
[windows sdk libs]

I believe the cleanest way to glue the everything together for cmake is to specify a toolchain file that explicitly points to the paths of everything needed.
Where ‘mytoolchain_msvcclang.cmake’ contains the following (for now) -

set(CMAKE_SYSTEM_NAME Windows)
set(WIN32 1)
set(CMAKE_SYSTEM_PROCESSOR x64)
set(CMAKE_C_COMPILER "C:/Program Files/Microsoft Visual Studio/2022/Community/VC/Tools/Llvm/x64/bin/clang.exe")
set(CMAKE_C_COMPILER_ID "Clang")
set(CMAKE_C_COMPILER_FRONTEND_VARIANT "GNU")
set(CMAKE_CXX_COMPILER "C:/Program Files/Microsoft Visual Studio/2022/Community/VC/Tools/Llvm/x64/bin/clang++.exe")
set(CMAKE_CXX_COMPILER_ID "Clang")
set(CMAKE_CXX_COMPILER_FRONTEND_VARIANT "GNU")
set(LLVM_HOST_TRIPLE "x86_64" CACHE STRING "" FORCE)
set(LLVM_NATIVE_ARCH "x86_64" CACHE STRING "" FORCE)
set(LLVM_TARGET_ARCH "x86_64" CACHE STRING "" FORCE)
set(CMAKE_MT "C:/Program Files (x86)/Windows Kits/10/bin/10.0.20348.0/x64/mt.exe")
set(CMAKE_RC_COMPILER_INIT "C:/Program Files (x86)/Windows Kits/10/bin/10.0.20348.0/x64/rc.exe")
set(CMAKE_RC_FLAGS_INIT "/nologo")
set(MIDL_COMPILER "C:/Program Files (x86)/Windows Kits/10/bin/10.0.20348.0/x64/midl.exe")
set(MDMERGE_TOOL "C:/Program Files (x86)/Windows Kits/10/bin/10.0.20348.0/x64/mdmerge.exe")

include_directories(SYSTEM "C:/Program Files (x86)/Windows Kits/10/Include/10.0.20348.0/ucrt")
include_directories(SYSTEM "C:/Program Files (x86)/Windows Kits/10/Include/10.0.20348.0/shared")
include_directories(SYSTEM "C:/Program Files (x86)/Windows Kits/10/Include/10.0.20348.0/um")
include_directories(SYSTEM "C:/Program Files (x86)/Windows Kits/10/Include/10.0.20348.0/winrt")
include_directories(SYSTEM "C:/Program Files (x86)/Windows Kits/10/Include/10.0.20348.0/cppwinrt")
include_directories(SYSTEM "C:/Program Files/Microsoft Visual Studio/2022/Community/VC/Tools/MSVC/14.32.31326/include")

link_directories("C:/Program Files (x86)/Windows Kits/10/Lib/10.0.20348.0/ucrt/x64")
link_directories("C:/Program Files (x86)/Windows Kits/10/Lib/10.0.20348.0/um/x64")

add_definitions(-D_CRT_SECURE_NO_WARNINGS)
add_definitions(-D_CRT_USE_BUILTIN_OFFSETOF)

I’ve arrived at this through quite a bit of flailing so suspect one or two things in here could be unnecessary and trimmed out.

I also add the following to my local/temporary PATH envroment -
> set PATH=[...path to msvc llvm x64 bin...];[...path to cmake-3.24.1-windows-x86_64\bin...];[...path to dir containing ninja.exe...];%PATH%

Then I can do -

	> cd /llvm-project-llvmorg-14.0.6
	> mkdir build
	> cd build
	> cmake -DCMAKE_TOOLCHAIN_FILE=../mytoolchain_msvcclang.cmake -DLLVM_ENABLE_PROJECTS=clang -G Ninja -DCMAKE_BUILD_TYPE=Release ../llvm

and this now seems to happily generate everything I need to then fire off -
> ninja
which happily gets running compiling and building hundreds of steps … before ultimately failing with -

...
ninja: build stopped: subcommand failed.
FAILED: NATIVE/bin/llvm-tblgen.exe C:/dev/llvm-project-llvmorg-14.0.6/build/NATIVE/bin/llvm-tblgen.exe
cmd.exe /C "cd /D C:\dev\llvm-project-llvmorg-14.0.6\build\NATIVE && C:\dev\cmake-3.24.1-windows-x86_64\bin\cmake.exe --build C:/dev/llvm-project-llvmorg-14.0.6/build/NATIVE --target llvm-tblgen --config Release"
ninja: build stopped: subcommand failed.

What’s going on here? It looks like there’s a non-ninja / explicit cmake command line step that it’s trying to run. Firstly, it’s not specifying the toolchain file that I suspect I need to use for all cmake steps. Secondly, it looks like it’s invoking cmake with options that are now obsolete.

In other words, if I manually try to run -
C:\dev\llvm-project-llvmorg-14.0.6\build\NATIVE>cmake -DCMAKE_TOOLCHAIN_FILE=../../mytoolchain_msvcclang.cmake --build C:/dev/llvm-project-llvmorg-14.0.6/build/NATIVE --target llvm-tblgen --config Release
it gives me -

CMake Warning:
  Ignoring extra path from command line:
   "Release"
CMake Error: Unknown argument --config

and ‘cmake --help’ confirms that --config (and --target and --build for that matter) are not valid arguments.

So am I missing some configuration steps that would avoid this problem or is there a bug somewhere in clang’s cmake build configurations (and a fix/workaround)?

Backing up a little bit, prior to the sticking point above, I also encountered the following issues -

  1. The initial cmake command above resulted in the error, “CMake Error at cmake/modules/CheckAtomic.cmake:53 (message): Host compiler appears to require libatomic, but cannot find it.”, which has been discussed here (c - How to solve libatomic issue in windows? - Stack Overflow) and worked around by making the suggested hack to ‘CheckAtomic.cmake’.
  2. After the hack/work-around for #1, I then hit, “CMake Warning at cmake/modules/GetHostTriple.cmake:46 (message): unable to determine host target triple”, which seems to have given others the same problem (cmake/config-ix.cmake:401 (get_host_triple) error when trying to build LLVM with CMake on Windows - Stack Overflow) and appears to be worked-around by the addition of ‘set(LLVM_HOST_TRIPLE “x86_64” CACHE STRING “” FORCE)’ to my toolchain file. I don’t know if this is expected or if this fix/work-around is likely to lead to problems later on. However it did seem to allow me to progress.
  3. The initial cmake command now completes successfully but I notice it spits out, “Native target architecture is x86” even though my toolchain file configures as much as it can to configure or point to x64. I tried adding “-A x64 -Thost=x64” to the cmake command line but that just errors, saying, “Generator Ninja does not support platform specification, but platform x64 was specified”. I hope that the rest of my toolchain configuration will be sufficient for ultimately building clang for the x86_64 target, but if not, does anyone know what addition/change might be necessary?
  4. After the eventual successful completion of the initial cmake command, the first ‘> ninja’ build failed with -
C:/dev/llvm-project-llvmorg-14.0.6/third-party/benchmark/src/benchmark.cc:172:17: error: static_assert expression is not an integral constant expression
  static_assert(offsetof(State, error_occurred_) <=
				^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
C:/Program Files (x86)/Windows Kits/10/Include/10.0.20348.0/ucrt\stddef.h:47:31: note: expanded from macro 'offsetof'
		#define offsetof(s,m) ((::size_t)&reinterpret_cast<char const volatile&>((((s*)0)->m)))
							  ^
C:/dev/llvm-project-llvmorg-14.0.6/third-party/benchmark/src/benchmark.cc:172:17: note: cast that performs the conversions of a reinterpret_cast is not allowed in a constant expression

which prompted me to add “add_definitions(-D_CRT_USE_BUILTIN_OFFSETOF)” to my toolchain file (along with “add_definitions(-D_CRT_SECURE_NO_WARNINGS)” to silence the thousands of warnings relating to using the non-msvc-secure flavour of many standard functions) :roll_eyes:

You’re setting LLVM_HOST_TRIPLE incorrectly, and that might cause you issues. The correct triple is something like “x86_64-pc-windows-msvc”. Also, for builds using the Windows SDK, if you want to stay on a well-tested path, you should set the compiler to “clang-cl.exe”, not “clang.exe”.

For the tblgen thing, I’m not exactly sure what’s happening; somehow the CMake configuration thinks you’re cross-compiling, but the cross-compile machinery is getting confused. Maybe related to the LLVM_HOST_TRIPLE thing.

For the offsetof thing, probably you’re confusing clang by setting the include paths to something it isn’t expecting. If you want to force clang-cl to use a particular SDK, there’s a “/winsdkdir” flag, which should do the right thing without trying to manually specify the include paths the way clang wants.

Thanks for the suggestions. I really appreciate the help.

I’m starting to wonder if the build machinery is overly complicated (and possibly fragile or problematic as a consequence) through defensive try, guess, or find-like behaviours, or maybe even conflict with and overwrite explicit user-supplied settings (e.g. the errors I’ve mentioned above and below appear to ignore thing’s I’ve explicitly specified, and possibly other problems like Using lld-link with MSVC compiler on Windows - #2 by marstaik - Usage - CMake Discourse) and stumble onward instead of simply stopping with a clear error, indicating a required tool, setting, path, or file can’t be found or needs to be explicitly specified by the user, which I would have thought is trivial for most users to locate and specify through just a few toolchain file settings.

Regarding your first point: Changing -
set(LLVM_HOST_TRIPLE "x86_64" CACHE STRING "" FORCE)
to -
set(LLVM_HOST_TRIPLE "x86_64-pc-windows-msvc" CACHE STRING "" FORCE)
appears to have no actual effect (other than changing this define value string throughout the cmake cache and generated .ninja build file) and still ultimately fails in the ninja build at the strange ‘llvm-tblgen’ cmake invocation.

Next, changing -

	set(CMAKE_C_COMPILER "C:/Program Files/Microsoft Visual Studio/2022/Community/VC/Tools/Llvm/x64/bin/clang.exe")
	set(CMAKE_C_COMPILER_ID "Clang")
	set(CMAKE_C_COMPILER_FRONTEND_VARIANT "GNU")
	set(CMAKE_CXX_COMPILER "C:/Program Files/Microsoft Visual Studio/2022/Community/VC/Tools/Llvm/x64/bin/clang++.exe")
	set(CMAKE_CXX_COMPILER_ID "Clang")
	set(CMAKE_CXX_COMPILER_FRONTEND_VARIANT "GNU")

to -

	set(CMAKE_C_COMPILER "C:/Program Files/Microsoft Visual Studio/2022/Community/VC/Tools/Llvm/x64/bin/clang-cl.exe")
	set(CMAKE_C_COMPILER_ID "Clang")
	set(CMAKE_C_COMPILER_FRONTEND_VARIANT "MSVC")
	set(CMAKE_CXX_COMPILER "C:/Program Files/Microsoft Visual Studio/2022/Community/VC/Tools/Llvm/x64/bin/clang-cl.exe")
	set(CMAKE_CXX_COMPILER_ID "Clang")
	set(CMAKE_CXX_COMPILER_FRONTEND_VARIANT "MSVC")

then cleaning out the ‘build’ directory and re-running -
cmake -DCMAKE_TOOLCHAIN_FILE=../mytoolchain_msvcclang.cmake -DLLVM_ENABLE_PROJECTS=clang -G Ninja -DCMAKE_BUILD_TYPE=Release ../llvm
immediately fails the inital cmake command with -

The C compiler
	"C:/Program Files/Microsoft Visual Studio/2022/Community/VC/Tools/Llvm/x64/bin/clang-cl.exe"
is not able to compile a simple test program.
It fails with the following output:
	Change Dir: C:/dev/llvm-project-llvmorg-14.0.6/build/CMakeFiles/CMakeTmp
	Run Build Command(s):C:/dev/workspaces/pkg_meson/ninja.EXE cmTC_28c6c && [1/2] Building C object CMakeFiles\cmTC_28c6c.dir\testCCompiler.c.obj
	[2/2] Linking C executable cmTC_28c6c.exe
	FAILED: cmTC_28c6c.exe
	cmd.exe /C "cd . && C:\dev\cmake-3.24.1-windows-x86_64\bin\cmake.exe -E vs_link_exe --intdir=CMakeFiles\cmTC_28c6c.dir --rc=C:\PROGRA~2\WI3CF2~1\10\bin\100203~1.0\x64\rc.exe --mt=C:\PROGRA~2\WI3CF2~1\10\bin\100203~1.0\x64\mt.exe --manifests  -- C:\PROGRA~1\MICROS~2\2022\COMMUN~1\VC\Tools\Llvm\x64\bin\lld-link.exe /nologo CMakeFiles\cmTC_28c6c.dir\testCCompiler.c.obj  /out:cmTC_28c6c.exe /implib:cmTC_28c6c.lib /pdb:cmTC_28c6c.pdb /version:0.0 /machine:x64  /debug /INCREMENTAL /subsystem:console -LIBPATH:C:\PROGRA~2\WI3CF2~1\10\Lib\100203~1.0\ucrt\x64   -LIBPATH:C:\PROGRA~2\WI3CF2~1\10\Lib\100203~1.0\um\x64 kernel32.lib user32.lib gdi32.lib winspool.lib shell32.lib ole32.lib oleaut32.lib uuid.lib comdlg32.lib advapi32.lib && cd ."
	LINK Pass 1: command "C:\PROGRA~1\MICROS~2\2022\COMMUN~1\VC\Tools\Llvm\x64\bin\lld-link.exe /nologo CMakeFiles\cmTC_28c6c.dir\testCCompiler.c.obj /out:cmTC_28c6c.exe /implib:cmTC_28c6c.lib /pdb:cmTC_28c6c.pdb /version:0.0 /machine:x64 /debug /INCREMENTAL /subsystem:console -LIBPATH:C:\PROGRA~2\WI3CF2~1\10\Lib\100203~1.0\ucrt\x64 -LIBPATH:C:\PROGRA~2\WI3CF2~1\10\Lib\100203~1.0\um\x64 kernel32.lib user32.lib gdi32.lib winspool.lib shell32.lib ole32.lib oleaut32.lib uuid.lib comdlg32.lib advapi32.lib /MANIFEST /MANIFESTFILE:CMakeFiles\cmTC_28c6c.dir/intermediate.manifest CMakeFiles\cmTC_28c6c.dir/manifest.res" failed (exit code 1) with the following output:
	lld-link: error: could not open 'msvcrtd.lib': no such file or directory
	lld-link: error: could not open 'oldnames.lib': no such file or directory

which is straightforward; msvcrtd.lib isn’t on any of the libpaths I had in my toolchain config. Adding -
link_directories("C:/Program Files/Microsoft Visual Studio/2022/Community/VC/Tools/MSVC/14.32.31326/lib/x64")
to my toolchain config now results in success.

Next,
> ninja
produces -

[48/4492] Configuring NATIVE LLVM...
FAILED: NATIVE/CMakeCache.txt C:/dev/llvm-project-llvmorg-14.0.6/build/NATIVE/CMakeCache.txt
cmd.exe /C "cd /D C:\dev\llvm-project-llvmorg-14.0.6\build\NATIVE && C:\dev\cmake-3.24.1-windows-x86_64\bin\cmake.exe -G Ninja -DCMAKE_MAKE_PROGRAM="C:/dev/workspaces/pkg_meson/ninja.EXE" -DCMAKE_C_COMPILER_LAUNCHER="" -DCMAKE_CXX_COMPILER_LAUNCHER="" "-DCMAKE_C_COMPILER=C:/Program Files/Microsoft Visual Studio/2022/Community/VC/Tools/Llvm/x64/bin/clang-cl.exe" "-DCMAKE_CXX_COMPILER=C:/Program Files/Microsoft Visual Studio/2022/Community/VC/Tools/Llvm/x64/bin/clang-cl.exe" C:/dev/llvm-project-llvmorg-14.0.6/llvm -DLLVM_TARGET_IS_CROSSCOMPILE_HOST=TRUE -DLLVM_TARGETS_TO_BUILD="AArch64;AMDGPU;ARM;AVR;BPF;Hexagon;Lanai;Mips;MSP430;NVPTX;PowerPC;RISCV;Sparc;SystemZ;VE;WebAssembly;X86;XCore" -DLLVM_EXPERIMENTAL_TARGETS_TO_BUILD="" -DLLVM_DEFAULT_TARGET_TRIPLE="x86_64-pc-windows-msvc" -DLLVM_TARGET_ARCH="x86_64" -DLLVM_ENABLE_PROJECTS="clang" -DLLVM_EXTERNAL_PROJECTS="" -DLLVM_ENABLE_RUNTIMES="" -DLLVM_TEMPORARILY_ALLOW_OLD_TOOLCHAIN="OFF" -DCMAKE_BUILD_TYPE=Release -DLLVM_EXTERNAL_CLANG_SOURCE_DIR=C:/dev/llvm-project-llvmorg-14.0.6/llvm/../clang"
-- The C compiler identification is Clang 13.0.1 with MSVC-like command-line
-- The CXX compiler identification is Clang 13.0.1 with MSVC-like command-line
-- The ASM compiler identification is Clang with MSVC-like command-line
-- Found assembler: C:/Program Files/Microsoft Visual Studio/2022/Community/VC/Tools/Llvm/x64/bin/clang-cl.exe
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - failed
-- Check for working C compiler: C:/Program Files/Microsoft Visual Studio/2022/Community/VC/Tools/Llvm/x64/bin/clang-cl.exe
-- Check for working C compiler: C:/Program Files/Microsoft Visual Studio/2022/Community/VC/Tools/Llvm/x64/bin/clang-cl.exe - broken
CMake Error at C:/dev/cmake-3.24.1-windows-x86_64/share/cmake-3.24/Modules/CMakeTestCCompiler.cmake:69 (message):
  The C compiler
	"C:/Program Files/Microsoft Visual Studio/2022/Community/VC/Tools/Llvm/x64/bin/clang-cl.exe"
  is not able to compile a simple test program.
  It fails with the following output:
	Change Dir: C:/dev/llvm-project-llvmorg-14.0.6/build/NATIVE/CMakeFiles/CMakeTmp
	Run Build Command(s):C:/dev/workspaces/pkg_meson/ninja.EXE cmTC_4b470 && [1/2] Building C object CMakeFiles\cmTC_4b470.dir\testCCompiler.c.obj
	[2/2] Linking C executable cmTC_4b470.exe
	FAILED: cmTC_4b470.exe
	cmd.exe /C "cd . && C:\dev\cmake-3.24.1-windows-x86_64\bin\cmake.exe -E vs_link_exe --intdir=CMakeFiles\cmTC_4b470.dir --rc=C:\PROGRA~1\MICROS~2\2022\COMMUN~1\VC\Tools\Llvm\x64\bin\llvm-rc.exe --mt=CMAKE_MT-NOTFOUND --manifests  -- C:\PROGRA~1\MICROS~2\2022\COMMUN~1\VC\Tools\Llvm\x64\bin\lld-link.exe /nologo CMakeFiles\cmTC_4b470.dir\testCCompiler.c.obj  /out:cmTC_4b470.exe /implib:cmTC_4b470.lib /pdb:cmTC_4b470.pdb /version:0.0 /machine:x64  /debug /INCREMENTAL /subsystem:console  kernel32.lib user32.lib gdi32.lib winspool.lib shell32.lib ole32.lib oleaut32.lib uuid.lib comdlg32.lib advapi32.lib && cd ."
	LINK Pass 1: command "C:\PROGRA~1\MICROS~2\2022\COMMUN~1\VC\Tools\Llvm\x64\bin\lld-link.exe /nologo CMakeFiles\cmTC_4b470.dir\testCCompiler.c.obj /out:cmTC_4b470.exe /implib:cmTC_4b470.lib /pdb:cmTC_4b470.pdb /version:0.0 /machine:x64 /debug /INCREMENTAL /subsystem:console kernel32.lib user32.lib gdi32.lib winspool.lib shell32.lib ole32.lib oleaut32.lib uuid.lib comdlg32.lib advapi32.lib /MANIFEST /MANIFESTFILE:CMakeFiles\cmTC_4b470.dir/intermediate.manifest CMakeFiles\cmTC_4b470.dir/manifest.res" failed (exit code 1) with the following output:
	lld-link: error: could not open 'kernel32.lib': no such file or directory
	lld-link: error: could not open 'user32.lib': no such file or directory
	...

So this is invoking lld-link.exe and referencing libs without full paths (fair enough) but is omitting the lib paths that I’ve explicitly specified in the toolchain file; if it would only respect -
link_directories("C:/Program Files (x86)/Windows Kits/10/Lib/10.0.20348.0/um/x64")
from my toolchain file, this would execute just fine… which to me has the hint of a bug, but I’m not proficient in all the cmake build machinery to identify exactly where this is going wrong.

Finally, attempting yet another bit of hacky work-around/flail, I add the lib paths from my toolchain config file to the PATH environment variable (and confirm that ‘where kernel32.lib’ succeeds from any CWD)… but the exact same command fails in exactly the same way.

Update: Poking around for the source of this ‘Linking C executable …’ message in this failing step would suggest it’s coming from the recently generated “/llvm-project-llvmorg-14.0.6/build/cmakefiles/rules.ninja”, which contains the lines -

#############################################
# Rule for linking C executable.
rule C_EXECUTABLE_LINKER__count_Release
  command = cmd.exe /C "$PRE_LINK && C:\dev\cmake-3.24.1-windows-x86_64\bin\cmake.exe -E vs_link_exe --intdir=$OBJECT_DIR --rc=C:\PROGRA~2\WI3CF2~1\10\bin\100203~1.0\x64\rc.exe --mt=C:\PROGRA~2\WI3CF2~1\10\bin\100203~1.0\x64\mt.exe --manifests $MANIFESTS -- C:\PROGRA~1\MICROS~2\2022\COMMUN~1\VC\Tools\Llvm\x64\bin\lld-link.exe /nologo $in  /out:$TARGET_FILE /implib:$TARGET_IMPLIB /pdb:$TARGET_PDB /version:0.0 $LINK_FLAGS $LINK_PATH $LINK_LIBRARIES && $POST_BUILD"
  description = Linking C executable $TARGET_FILE
  restat = $RESTAT

which makes reference to a $LINK_PATH value but, from the output in the error, it would seem that $LINK_PATH is empty or not set for this failing ‘CMakeTestCCompiler.cmake’ / ‘testCCompiler.c’ step.

Now, looking in the newly generated ‘/llvm-project-llvmorg-14.0.6/build/build.ninja’, I can see many instances of defining LINK_PATH, all with the correct set of LIBPATH values. E.g. -

# Link the executable bin\llvm-tblgen.exe
build bin\llvm-tblgen.exe: CXX_EXECUTABLE_LINKER...
  FLAGS = /DWIN32 /D_WINDOWS  ...
  LINK_FLAGS = /machine:x64 ...
  LINK_LIBRARIES = lib\LLVMSupport.lib  ...
  LINK_PATH = -LIBPATH:C:\PROGRA~2\WI3CF2~1\10\Lib\100203~1.0\ucrt\x64   -LIBPATH:C:\PROGRA
...
# Link the executable bin\FileCheck.exe
build bin\FileCheck.exe: ...
  LINK_PATH = -LIBPATH:C:\PROGRA...
  ...
# Link the executable bin\count.exe
build bin\count.exe: ...
  ...
  LINK_PATH = -LIBPATH:C:\PROGRA...
  ...
# Link the executable bin\llvm-ar.exe
build bin\llvm-ar.exe: ...
  ...
  LINK_PATH = -LIBPATH:C:\PROGRA...
  ...
# Link the executable bin\clang.exe

build bin\clang.exe: ...
  ...
  LINK_PATH = -LIBPATH:C:\PROGRA...
  ...

In fact the only place I can see any assigning values to LINK_PATH is this one ‘build.ninja’ file, but no sign of LINK_PATH being correctly set up for this ‘testccompiler’ step.

Is this ‘testccompiler’ phase being run as a special-case, defensive work-around, perhaps as a result of an unhelpfully quiet issue/failure earlier on in the setup? And if so, might it be invoking build steps with special-case settings that overlook the need to set and respect the explicitly specified link paths and other values from the toolchain?

I wonder whether this could be a case of a problem that could be far more simply identified and resolved if the build machinery simply said, “I don’t know [property X/Y/Z] of the compiler you specified” and stop there, leaving me to set the necessary value in the toolchain settings file.

Looking in the ninja build output, just before this ‘CMakeTestCCompiler’ shenanigans, I see -

-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - failed
-- Check for working C compiler: C:/Program Files/Microsoft Visual Studio/2022/Community/VC/Tools/Llvm/x64/bin/clang-cl.exe
-- Check for working C compiler: C:/Program Files/Microsoft Visual Studio/2022/Community/VC/Tools/Llvm/x64/bin/clang-cl.exe - broken
CMake Error at C:/dev/cmake-3.24.1-windows-x86_64/share/cmake-3.24/Modules/CMakeTestCCompiler.cmake:69 (message):
  The C compiler
    "C:/Program Files/Microsoft Visual Studio/2022/Community/VC/Tools/Llvm/x64/bin/clang-cl.exe"
  is not able to compile a simple test program.
  ...

Aside from having this seemingly problematic ‘CMakeTestCCompiler.cmake’ stuff fix the issue of it invoking lld-link.exe without suitably setting up the LINK_PATH as it appears to be done elsewhere, given that figuring out a proper cmake fix is beyond me at the moment, would it be reasonable to circumvent this test (and its consequences) in this ‘cmaketestccompiler.cmake’ file -

if(NOT CMAKE_C_COMPILER_WORKS)
  ...
  message(FATAL_ERROR "The C compiler\n  \"${CMAKE_C_COMPILER}\"\n"

by chucking in -

set(CMAKE_C_COMPILER_WORKS TRUE)
set(CMAKE_CXX_COMPILER_WORKS TRUE)

into my toolchain file?

Update edit: More searching has revealed others running in to what looks to be a similar problem -

… and their solution seems to be to attempt a similar toolchain hack to what I suggest above, but it’s really unsatisfactory for 2 reasons -

  1. Like the second stack overflow post mentions, this burdens the toolchain config file owner with having to set other internal compiler state values that might be needed in current and future versions of the cmake build machinery.
  2. I can easily manually compile and link the .c / .cpp test code and run the exe by using the suitable paths and flags that the toolchain specifies but which are mysteriously omitted for these compiler checks. Why don’t these steps use appropriate compile/link flags and paths? It seems fixing this would properly resolve a not uncommon problem and help a few people out and avoid work-around hacks. (Because I’m new to all of this, I’m not really in a position to diagnose and attempt it myself… at least yet)