I have a cross platform project (Windows/macOS) that uses Clang for compilation. On macOS it is native. On Windows I use the Visual Studio Build Tools + Clang toolchain.
I was able to boil down the issue to the following small example:
#include <iostream>
int main()
{
std::cout << "Hello, World!" << std::endl;
auto foo = 3;
auto fn = [foo]() { std::cout << foo << "\n"; };
fn();
return 0;
}
cmake_minimum_required(VERSION 3.24)
if(WIN32)
# this is the "magic" that enables the Clang toolchain
set(CMAKE_GENERATOR_TOOLSET "ClangCL")
endif()
project(windows_clang_toolchain)
set(CMAKE_CXX_STANDARD 17)
add_executable(windows_clang_toolchain main.cpp)
target_compile_options(windows_clang_toolchain PUBLIC "-Wall")
This is the output of the compilation command line generated by CMake:
C:\Program Files (x86)\Microsoft Visual Studio\2019\BuildTools\VC\Tools\Llvm\x64\bin\clang-cl.exe /c /Z7 /nologo /Wall /WX- /diagnostics:column /Od /Ob0 /D _MBCS /D WIN32 /D _WINDOWS /D "CMAKE_INTDIR=\"Debug\"" /EHsc /MDd /GS /fp:precise /std:c++17 /Fo"windows_clang_toolchain.dir\Debug\\" /Gd /TP -m64 "D:\Work\test\windows-clang-toolchain\main.cpp"
D:\Work\test\windows-clang-toolchain\main.cpp(6,3): warning : 'auto' type specifier is incompatible with C++98 [-Wc++98-compat] [D:\Work\test\windows-clang-toolchain\cmake-build-debug-visual-studio-amd64\windows_clang_toolchain.vcxproj]
D:\Work\test\windows-clang-toolchain\main.cpp(7,3): warning : 'auto' type specifier is incompatible with C++98 [-Wc++98-compat] [D:\Work\test\windows-clang-toolchain\cmake-build-debug-visual-studio-amd64\windows_clang_toolchain.vcxproj]
D:\Work\test\windows-clang-toolchain\main.cpp(7,13): warning : lambda expressions are incompatible with C++98 [-Wc++98-compat] [D:\Work\test\windows-clang-toolchain\cmake-build-debug-visual-studio-amd64\windows_clang_toolchain.vcxproj]
I think the issue is that -Wall gets turned into /Wall and according to the “help” from clang:
/Wall is equivalent to -Weverything and not -Wall which then leads to completely irrelevant warnings (it’s a c++17 project and yes I am using auto and lambda…).
On macOS -Wall works fine.
If you do not use the Clang toolchain, then the MSVC compiler behaves like Clang on macOS.
I can certainly use an if() statement to use a different warning level depending on which toolchain/platform is being used, but wanted to report it here because IMO it is a bug from CMake to not generate the right flag.
I don’t exactly understand what your question is but, IMOH, /Wall indeed gives too many false positive to be of any use (actually most “warnings” are mere informations).
I personally uses /W4 for msvc and a if statement in order to differentiate my warnings with respect to the compiler.
As different compilers have quite different warnings, it’s hard for CMake to abstract that.
You should put this logic into a single .cmake file that you will include into your projects CMakeLists.txt.
I guess my question was not clear, but I wanted to report what I noticed and figure out whether this is normal or a bug that I should file as a ticket.
I am not writing /Wall in my CMakeLists.txt file, I am writing -Wall. So it is CMake which is doing this transformation. It seems to me that in the case of “Visual Studio + Clang” this transformation is not right.
So the question is, shall I file this issue as a ticket?
May I reformulate.
You’re observing that -Wall is mapped, by CMake, to /Wall for msvc and -Wall for clang.
I thus agree with you that it’s not the closer match according to the clang “help” you are quoting.
(yet the clang mapping /Wx <=> -Wall for x in {1;2;3} seems a bit extrem)
So:
1- IMOH it is relevant to file an issue
2- I think that default strategies won’t be OK for all kind of needs and you will have to if() things up and have finer strategies (on gcc/clang side, I’m personnaly using more warning flags)
No, I am observing that -Wall is mapped by CMake to /Wallboth for MSVC and Clang. The issue is that, as per my original message, /Wall is equivalent to -Weverything for Clang, hence the useless/irrelevant warnings.
I will file a ticket then. Worst case, it can be closed with no action if it’s not considered to be a bug.
I also agree with you that at some points if() might be required in some instances.
by looking closer to your example, it seems that there is an issue with your cmakelist:
the warning are leggit and should even be errors => your language level is not the good one. You should set it explicitely to C++>=11.
Still, /Wall for cl is not the same as -Wall for clang but, in your case, the compiler is clang-cl which I don’t know, maybe that Wall is OK for clang-cl.
Can you first set your standard to C++ >= 11 and see what’s happening?
I see indeed the C++17 (I missed it the first time, sorry).
Thus, either there is an additional warning that is added at some other step or there is an issue but from clang-cl? Is it implicitely set by /Wall?
Have you a way to check this?
I am 99% sure that -Weverything is what turns on -Wc++98-compat and as the help page of Clang (for Windows) describes this is what /Wall does (which to be honest does not make a lot of sense to me…)
OK, so I would advise the if solution and if Jakub is right and there is no “smart” translation of warning flags, then it’s not a cmake issue (it’s a msvc one…).
I think what may be happening is that when making the Visual Studio project CMake attempts to set the WarningLevel property in the ClCompile node in the project based on the option and for -Wall it appears it will set that to “EnableAllWarnings”. I wonder if something could be done with the flag tables to have a different mapping in the case the generator toolset was ClangCL.
I wouldn’t consider this a CMake bug, but an incorrect setting by the project.
Compiler options always depend on the compiler used. If you would use another compiler (like Borland), it would be even an “unknown switch”. The same is true for older MSVC versions AFAIK.
In fact you’re mixing GCC and MSVC settings, just because they have the same name.
If you use clang with it’s native frontend, it behaves similar to GCC.
But you do use “ClangCL”, which uses a frontend that understand/emulates MSVC cl.exe switches.
Also on the real cl.exe, you normally never want to enable /Wall, just /W4.
MS implemented that switch for cl.exe as “enable every known message”. And the correct mapping for “ClangCL” is what it does: also enable every message.
Compiler switches should be in a compiler specific toolchain file, or needs some Generator Expressions like COMPILE_LANG_AND_ID to select the right compiler and maybe language. Because if you use NASM or so, it will also not understand what -Wall is.
So - is this a Cmake issue that cmake adds W3 even though I specify -t ClangCL to cmake?
Or is it a clang-cl issue that they don’t faithfully emulate cl’s command line arguments? Or has this been fixed in a newer cmake?
In share/cmake-3.30/Modules/Platform/Windows-MSVC.cmake
There are tests specifically for clang…which looks mostly like swapping ‘/’ to ‘-’.
Edit: Looking at this further, I guess I’m not really setting the right option? even though the projects get built and load with (LLVM - clang-cl) after them… so it uses the second option which builds with _W3 variable set to /W3 … sigh no, it’s even worse if I force that path…
… Okay enabled CMP0092 NEW (which sets _WALL and _W3 to blank) and now the error isn’t the fault of CMake… but the project still fails because masm.targets (visual studio thing) still adds a /W3. Looks like really this should be deferred to Clang-CL.
Final Edit: 1) sorry I keep thinking it’s still 2023, sorry for the necropost, 2) the -T option specified above is probably wrong for cmake, I’m actually using cmake-js which is a wrapper around cmake, with its own argument syntax unfortunatly.