I'm building a LLVM environment on Windows that can work without Microsoft compiler and SDK and without GCC compiler or GNU linker, only LLVM (the official build) and MinGW-w64 runtime.
When compiling this C program with clang
compiler and lld
linker, and with x86_64-windows-gnu
target (MinGW-w64 runtime), it works:
> type c1.c
#include <stdio.h>
int main() {
printf("hello 1\n");
return 0;
}
> clang c1.c -target x86_64-windows-gnu -fuse-ld=lld -o c1.exe
> c1
hello 1
How to achieve the same with CMake? Is there a high level option for CMake to set these flags automatically? Or, when trying to set these flags manually (with CMAKE_EXE_LINKER_FLAGS
or CMAKE_C_FLAGS
) looks like that it confuses CMake and it still passes some Visual C++ style flags (like /subsystem:console
) during linking:
> type CMakeLists.txt
project (P1 C)
cmake_minimum_required(VERSION 3.0)
set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -target x86_64-windows-gnu -fuse-ld=lld")
add_executable (c1 c1.c)
> cmake -G Ninja -B build -DCMAKE_C_COMPILER=clang
-- The C compiler identification is Clang 12.0.0 with GNU-like command-line
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: C:/Program Files/LLVM/bin/clang.exe - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Configuring done
-- Generating done
-- Build files have been written to: C:/build
> cmake --build build
[2/2] Linking C executable c1.exe
FAILED: c1.exe
cmd.exe /C "cd . && C:\PROGRA~1\LLVM\bin\clang.exe -fuse-ld=lld-link -nostartfiles -nostdlib -g -Xclang -gcodeview -O0 -D_DEBUG -D_DLL -D_MT -Xclang --dependent-lib=msvcrtd -target x86_64-windows-gnu -fuse-ld=lld -Xlinker /subsystem:console CMakeFiles/c1.dir/c1.c.obj -o c1.exe -Xlinker /implib:c1.lib -Xlinker /pdb:c1.pdb -Xlinker /version:0.0 -lkernel32 -luser32 -lgdi32 -lwinspool -lshell32 -lole32 -loleaut32 -luuid -lcomdlg32 -ladvapi32 -loldnames && cd ."
lld: error: unable to find library -loldnames
clang: error: linker command failed with
Please see the documentation on toolchains here: https://cmake.org/cmake/help/latest/manual/cmake-toolchains.7.html#cross-compiling-using-clang
Since you're overriding the default Clang target, CMake needs to know about this during compiler detection. By the time you're in the CMakeLists.txt, it is too late. The following clang-x86_64_windows_gnu.cmake
toolchain file might work (I can't test it without replicating your environment):
set(CMAKE_C_COMPILER clang)
set(CMAKE_C_COMPILER_TARGET x86_64-windows-gnu)
set(CMAKE_EXE_LINKER_FLAGS_INIT "-fuse-ld=lld")
set(CMAKE_MODULE_LINKER_FLAGS_INIT "-fuse-ld=lld")
set(CMAKE_SHARED_LINKER_FLAGS_INIT "-fuse-ld=lld")
Then your CMakeLists.txt was wrong, it should be:
cmake_minimum_required(VERSION 3.20)
project(P1 LANGUAGES C)
add_executable(c1 c1.c)
Notice the order of the cmake_minimum_required
and project
commands. They should always be the first two lines in your CMakeLists.txt, in that order.