llvm-mingw
llvm-mingw copied to clipboard
wrappers: add CMake toolchain files
Those toolchain files greatly simplify configuring a project to use the llvm-mingw toolchain.
The toolchain file will:
- Configure CMake to look for libraries and headers in the correct directories
- Configure Clang for the architecture,
libc++andlld - Locate the primary Compiler executable
CMake has some quite complete and complex machinery to detect further tools and configuration. Whatever supported in your CMake version should "just work" (eg. C++ Modules one day).
The lookup uses the system clang toolchain as fallback, and does not require any of the wrappers / symlinks in bin.
ie. Its possible to delete the bin directory if a matching clang/llvm toolchain is installed.
still needs some work
Had to fix some issues, mostly on windows (needs to convert to native paths) and some quoting.
Something of note is, that CMake does locate matching tools by searching first for the version-qualified name. For example it will look for llvm-ranlib-18 then llvm-ranlib. Means that is available, a system llvm-ranlib-18 will be used.
This is not optimal but is unlikely to cause big trouble.
Still, ideally llvm-mingw could provide llvm-ranlib-18, making these lookup schemes more robust.
i dropped the support of using a system clang/llvm installation. its pretty hard to get right on windows, i am not even sure if its bc if bugs or if some antivirus/company it policies intervene in my testing.
I added some more stuff in another branch, primary to add some unit tests:
https://github.com/nolange/llvm-mingw/commits/new_toolchainfile/
There is a subdirectory test/cmake/tests building the existing tests. I am probably biased but this should be way cleaner than the Makefile and offers integration with ctest and all the benefits that come with CMake (like just opening the directory in vscode and have everything setup automatically).
And another test/cmake/template which should serve as a basic project that works with llvm, msvc and a series of IDEs (Visual Studio).
Ping?
So, I'm quite undecided about this (as I think I had mentioned in some other discussion, where you mentioned that you were going to submit this).
The primary way of using the llvm-mingw tools is via the triple prefixed wrappers - this is easy to set up and use with all build systems, and matches how many other cross toolchains work. We probably don't want to ship config files for all build systems out there.
Merging this, even if I'm not a fan of using toolchain files, would cost us a bit more files to maintain and test. (I did see that you had ported all my smoke tests to run on cmake - not sure if I'd go with that or just something smaller. In any case, I'm pretty sure I want to keep the original plain makefile based test setup anyway.) For people using CMake, it would indeed make things simpler to use though.
Regarding getting the right defaults for -stdlib=libc++ and such, for other tools than the plain compiler - that is also possible by using clang config files; see https://github.com/mstorsjo/llvm-mingw/commits/clang-cfg - I'm pondering merging something like that. (Unfortunately, that doesn't work for the UWP defaults, as clang normalizes -mingw32uwp triples into the same windows-gnu as regular triples, so the UWP additions still need to be supplied somewhere.)
So, I'm undecided for now.
The primary way of using the llvm-mingw tools is via the triple prefixed wrappers - this is easy to set up and use with all build systems, and matches how many other cross toolchains work. We probably don't want to ship config files for all build systems out there.
I don't agree with "easy to setup with all build systems", but I don't want to remove the wrappers. CMake is wildy popular (so is QT), so that's a reason to add support. Using CMake + toolchain file it further is also easy to setup with IDEs, package-managers like Conan, static analyzers like CodeChecker, etc. Most of the time you don't need to configure anything for a correctly setup CMake Project.
Merging this, even if I'm not a fan of using toolchain files, would cost us a bit more files to maintain and test.
It saves many more people work if the CMake support is central, and you save documenting/answering on how to use the toolchain with CMake. I could add a sample project for illustration.
Regarding getting the right defaults for -stdlib=libc++ and such, for other tools than the plain compiler - that is also possible by using clang config files.
Yes, I played with that but its completely irrelevant here (could replace the ugly Windows wrappers potentially). I see you have some problems with a separate uwp configuration, AFAIR you could use clang -v -target x86_64-w64_uwp-windows-gnu then it will search for x86_64-w64_uwp-windows-gnu.cfg. I got the branch stowed somewhere, need to dig it up.
Also these default-things typically are quite fragile and inflexible regarding typical workflows. For ex. building QT dependencies in a STAGING prefix, then QT itself and installing it to the toolchain (or creating an additional sysroot) are all quite nicely abstracted by setting a few CMake variables. Using raw commandline is alot more complicated and the wrappers make this worse not better.
Regarding getting the right defaults for -stdlib=libc++ and such, for other tools than the plain compiler - that is also possible by using clang config files.
Yes, I played with that but its completely irrelevant here
It's relevant to the point whether using toolchain files solves a technical issue (getting the right defaults flags for -stdlib=libc++ to clang-tidy or similar) or just a convenience issue.
I see you have some problems with a separate
uwpconfiguration, AFAIR you could useclang -v -target x86_64-w64_uwp-windows-gnuthen it will search forx86_64-w64_uwp-windows-gnu.cfg.
Right, that could work, but feels a bit ugly and would also deviate even more from earlier conventions. And having a differing vendor field may trip up a number of other cases (we may potentially use the "per-target runtime" install layout for compiler-rt and/or libcxx at some point, and at that point, changing the vendor field would make it fail to find all those runtimes). But thanks for the idea!
It's relevant to the point whether using toolchain files solves a technical issue (getting the right defaults flags for
-stdlib=libc++to clang-tidy or similar) or just a convenience issue.
toolchain files solves a technical issue, namely configuring CMake so that Projects can do the right decisions, including building dependencies with the toolchain file (or passing it to a package manager for the same reason). The toolchain file is then a single parameter defining the target system.
Personally I switched to CMake at work many years ago, having projects dealing with Barebones RTOS on microcontrollers, Emdedded Linux to currently also the Microsoft abominations. Now you don't have to care for the target or project, you can open it in one of the many IDEs supporting CMake and everything works including all the tools expecting to find the used flags in the commandline (compile_commands.json). Cause you cant expect the used compiler/wrapper itself being relevant - tools often want to know what the meaning of the command is without invoking the compiler/wrapper then do something entirely different with this information.
Of course you could argue it could be done differently, but that's almost equivalent to saying don't use CMake and all the integration it provides.
I updated the branch with the CMake Testsuite: https://github.com/nolange/llvm-mingw/commits/new_toolchainfile/
Now should work (almost) out of the Box with Editors supporting CMake Projects. Likely will need to setup the path to the toolchain.
The Project itself should compile with llvm-mingw, gcc-mingw and even with (wine-)msvc. Running tests is supported if wine is available, but some might have trouble finding DLLs without help.
Hope this illustrates why providing toolchain-files allows a ton of integrations that are difficult to impossible without.
I think I can agree that these toolchain files could be useful to some people, even if it is not how I use cmake. So perhaps we can aim towards trying to get this merged sometime during the LLVM 19.x releases.
As for the testsuite, I appreciate your effort in trying to wrap that up in cmake. I don't think I would like to merge those changes though.
I'll try to have a look around and see what kind of testing I'd like to have, within the scope of this project - if I go with a really bare-bones cmake test file like https://github.com/mstorsjo/msvc-wine/blob/master/test/CMakeLists.txt or something else, and how I would like it to be hooked up in the CI environment.
So sure, we probably can do this, but give me some time to integrate it in a way I'm comfortable with.
I think I can agree that these toolchain files could be useful to some people, even if it is not how I use cmake. So perhaps we can aim towards trying to get this merged sometime during the LLVM 19.x releases.
That is my hope
As for the testsuite, I appreciate your effort in trying to wrap that up in cmake. I don't think I would like to merge those changes though.
I haven't done a merge request?
Its both for illustrating a point, namely if you use CMake more thoroughly then a toolchain gets pretty important. But then things get easier using a different compiler (https://github.com/mstorsjo/msvc-wine/pull/132).
The other point was to ease your concern of maintenance (testing) of the toolchain files... but I guess now you have more concerns about maintaining the CMakeFiles.txt ;)
As for the testsuite, I appreciate your effort in trying to wrap that up in cmake. I don't think I would like to merge those changes though.
I haven't done a merge request? Its both for illustrating a point, namely if you use CMake more thoroughly then a toolchain gets pretty important. But then things get easier using a different compiler (mstorsjo/msvc-wine#132). The other point was to ease your concern of maintenance (testing) of the toolchain files... but I guess now you have more concerns about maintaining the
CMakeFiles.txt;)
Yes, you haven't done a PR for those bits, but I was just proactively mentioning that I don't think I'd want to maintain that bit, even if it can serve as a useful example.
Did alot more tests, was able to build and later find openssl3 + qt6 via pkgconf and cmake. Needed some fixes.
Hmm, come to think of it - I would really like if those files could be indiscriminately used and abused as templates, without any licensing concerns. Your project has a lengthy Apache2 license, I marked them as Public Domain. Hope that's fine with you
Hmm, come to think of it - I would really like if those files could be indiscriminately used and abused as templates, without any licensing concerns. Your project has a lengthy Apache2 license, I marked them as Public Domain. Hope that's fine with you
It's not apache2, it's the ISC license (which is equivalent with simplified BSD and MIT) for the build scripts etc. It's meant as the simplest and least restrictive license that still is a proper license.
I've heard that some people have concerns around "public domain" (which isn't really a thing in all jurisdictions), but I guess it should be fine for these files, especially if users are meant to copy and adapt them. (And if someone has a problem with it, we can add the same ISC license header as the other files.)
It's not apache2, it's the ISC license (which is equivalent with simplified BSD and MIT) for the build scripts etc. It's meant as the simplest and least restrictive license that still is a proper license.
My bad I looked at the release Archive which ships apparently with LLVM's LICENSE.TXT (?).
I would definitely add a Header since otherwise its not apparent, to me those files are just a bit more complex but still "obvious" config files. Still would prefer no license (less hassle with updating authors), but I am not terrible against MIT/BSD.
It's not apache2, it's the ISC license (which is equivalent with simplified BSD and MIT) for the build scripts etc. It's meant as the simplest and least restrictive license that still is a proper license.
My bad I looked at the release Archive which ships apparently with LLVM's
LICENSE.TXT(?).
Yep - the build scripts themselves don't ship in the distributable release packages, so the license of llvm-mingw isn't really visible there, it's mainly the LLVM and mingw-w64 licenses.
I would definitely add a Header since otherwise its not apparent, to me those files are just a bit more complex but still "obvious" config files. Still would prefer no license (less hassle with updating authors), but I am not terrible against MIT/BSD.
Ok, let's go with this public domain form for now, and we can always revisit it if someone else is against it.
So, I have integrated some smoke testing of these files, and tested it on github actions. See https://github.com/mstorsjo/llvm-mingw/commits/cmake-toolchain-files for what I could consider to merge.
There's two changes on top of your toolchain files; we don't want to set CMAKE_SYSROOT, because on the Windows toolchain, we have includes in <prefix>/include, and if we pass --sysroot pointing at the <arch>-w64-mingw32 subdir, it won't find the headers.
Secondly, cmake does weird things, reincluding the toolchain file many times. After concluding that we're not cross compiling, it gets reincluded, with CMAKE_SYSTEM_PROCESSOR reset to the default CMAKE_HOST_SYSTEM_PROCESSOR, so we end up with it set to AMD64 - so I had to extend the condition for when we fetch our default value for this.
With these changes in place, the smoke tests run as desired, both in full cross compilation mode, and with the toolchain default native arch.
I could go ahead and merge these changes soon (after the LLVM 19.1.0 RC 3 package gets completed, which is running in CI right now) if you don't have anything extra in mind right now.
So, I have integrated some smoke testing of these files, and tested it on github actions. See https://github.com/mstorsjo/llvm-mingw/commits/cmake-toolchain-files for what I could consider to merge.
There's two changes on top of your toolchain files; we don't want to set
CMAKE_SYSROOT, because on the Windows toolchain, we have includes in<prefix>/include, and if we pass--sysrootpointing at the<arch>-w64-mingw32subdir, it won't find the headers.
CMAKE_SYSROOT is essential because that's what CMake and other tools will use - this ithe point of this PR.
I will look at how I best add this path to the FLAGS, but it will take a while to retest everything =/.
Secondly, cmake does weird things, reincluding the toolchain file many times. After concluding that we're not cross compiling, it gets reincluded, with
CMAKE_SYSTEM_PROCESSORreset to the defaultCMAKE_HOST_SYSTEM_PROCESSOR, so we end up with it set toAMD64- so I had to extend the condition for when we fetch our default value for this.
Yes it does funny things, including spawning separate CMake-Processes during try_compile using only a part of the information and I bet the version always using CMAKE_HOST_SYSTEM_PROCESSOR will cause less trouble while making only a difference in corner cases no one should care about.
With these changes in place, the smoke tests run as desired, both in full cross compilation mode, and with the toolchain default native arch.
I could go ahead and merge these changes soon (after the LLVM 19.1.0 RC 3 package gets completed, which is running in CI right now) if you don't have anything extra in mind right now.
Well, this tc won't work for me, and I am gonna find some time finding a fix and retesting stuff.
Secondly, cmake does weird things, reincluding the toolchain file many times. After concluding that we're not cross compiling, it gets reincluded, with
CMAKE_SYSTEM_PROCESSORreset to the defaultCMAKE_HOST_SYSTEM_PROCESSOR, so we end up with it set toAMD64- so I had to extend the condition for when we fetch our default value for this.Yes it does funny things, including spawning separate CMake-Processes during
try_compileusing only a part of the information and I bet the version always usingCMAKE_HOST_SYSTEM_PROCESSORwill cause less trouble while making only a difference in corner cases no one should care about.
Sorry, but re-repeating that this is a corner case that nobody should care about will render this PR closed. Get over it.
So, I have integrated some smoke testing of these files, and tested it on github actions. See https://github.com/mstorsjo/llvm-mingw/commits/cmake-toolchain-files for what I could consider to merge. There's two changes on top of your toolchain files; we don't want to set
CMAKE_SYSROOT, because on the Windows toolchain, we have includes in<prefix>/include, and if we pass--sysrootpointing at the<arch>-w64-mingw32subdir, it won't find the headers.
CMAKE_SYSROOTis essential because that's what CMake and other tools will use - this ithe point of thisPR. I will look at how I best add this path to theFLAGS, but it will take a while to retest everything =/.
FWIW, for quicker iteration with testing, I did testing with a separate patch on top, that skips actually building the toolchain and just adds the files on top of an existing toolchain release: https://github.com/mstorsjo/llvm-mingw/commit/cmake-toolchain-files-testing
So, I have integrated some smoke testing of these files, and tested it on github actions. See https://github.com/mstorsjo/llvm-mingw/commits/cmake-toolchain-files for what I could consider to merge. There's two changes on top of your toolchain files; we don't want to set
CMAKE_SYSROOT, because on the Windows toolchain, we have includes in<prefix>/include, and if we pass--sysrootpointing at the<arch>-w64-mingw32subdir, it won't find the headers.
CMAKE_SYSROOTis essential because that's what CMake and other tools will use - this ithe point of thisPR. I will look at how I best add this path to theFLAGS, but it will take a while to retest everything =/.FWIW, for quicker iteration with testing, I did testing with a separate patch on top, that skips actually building the toolchain and just adds the files on top of an existing toolchain release: cmake-toolchain-files-testing
No, the problem is building several CMake projects, see if they resolve the correct paths vie CMake and pkg-conf and if IDE and tools like clangd (not the binary from llvm-mingw) that solely depend on compile_commands.json fully work.
that includes the stuff like multiple implicit invocations of CMake and multiple passes over the toolchain file. I am not confident until I used it for a while.
Adopted TC passes the compile tests: https://github.com/nolange/llvm-mingw/tree/test_tc
Still need to see if there's fallout when using more... CMake
It would be nice to see this merged, anything still blocking it?
I was cross-compiling a Windows Qt project from macos and setting up my own CMake toolchains was a bit of a pain in the ass. Based on my own toolchains you might be missing the following:
set(CMAKE_AR "<todo>")
set(CMAKE_RANLIB "<todo>")
These are used for add_library(OBJECT and add_library(STATIC, although I am not 100% sure if they are necessary when the target platform is set to Windows.
It would be nice to see this merged, anything still blocking it?
I had expected some more followup after the last post above.
The main blocking issue was that the suggested toolchain file uses CMAKE_SYSROOT, which doesn't work on Windows (because headers are in <toolchain>/include rather than <toolchain>/<triple>/include). I suggested just dropping setting CMAKE_SYSROOT, as there is no proper coherent sysroot directory in the windows based toolchains. @nolange didn't like this, started an experiment in order to be able to still set CMAKE_SYSROOT, but I never got any trigger to pick it up again, as the last comment was "still need to see...".
From looking at the linked repos, the attempt to be able to keep setting CMAKE_SYSROOT amounts to manually adding include directories like <toolchain>/include/c++/v1 to the list of include directories to the compiler. I disagree with that solution - I think simply not setting CMAKE_SYSROOT would be much preferrable. I don't think we should duplicate the logic of the compiler driver like that; manually setting those directories breaks how things behave e.g. if passing options like -nostdinc++.
I was cross-compiling a Windows Qt project from macos and setting up my own CMake toolchains was a bit of a pain in the ass. Based on my own toolchains you might be missing the following:
set(CMAKE_AR "<todo>") set(CMAKE_RANLIB "<todo>")These are used for
add_library(OBJECTandadd_library(STATIC, although I am not 100% sure if they are necessary when the target platform is set to Windows.
While using cmake with llvm-mingw, I usually get by without needing to set those - cmake deduces them from the names of the other tools, when using triple-prefixed tool names. Perhaps it may be necessary when the cmake toolchain file points directly at the clang binary though.
The toolchain in the MR doesnt work for Windows, the one in https://github.com/nolange/llvm-mingw/tree/test_tc seems to be.
On Linux it should be fine, on MacOS too.
Setting CMAKE_SYSROOT is relevant since CMake itself and Tools parsing the command-line need to know the full paths as they don't get the builtin information from the compiler(-driver).
ie. if you made the effort to add QT5 to llvm-mingw, find_package(Qt5) will not do its job.
I am not using Windows at home, so testing is slow and given that I made this technical argument atleast twice already and its likely just to be ignored again (see "I disagree with that solution" above), I have little motivation to continue.
It requires a hack with CMAKE_PROJECT_INCLUDE and you need a few Qt tools compiled for the host platform:
llvm-mingw.cmake
set(LLVM_MINGW /Users/admin/llvm-mingw-ucrt)
set(CMAKE_PREFIX_PATH /Users/admin/Qt5.6.3-msvc2015/msvc2015_64)
set(CMAKE_SYSTEM_PROCESSOR x86_64)
set(CMAKE_C_COMPILER_TARGET ${CMAKE_SYSTEM_PROCESSOR}-w64-mingw32)
set(CMAKE_C_COMPILER ${LLVM_MINGW}/bin/x86_64-w64-mingw32-clang)
set(CMAKE_CXX_COMPILER ${LLVM_MINGW}/bin/x86_64-w64-mingw32-clang++)
set(CMAKE_SYSTEM_NAME Windows)
set(CMAKE_SYSTEM_VERSION 1)
# This is working (thanks to Simon for finding this trick)
set(CMAKE_AR ${LLVM_MINGW}/bin/llvm-ar)
set(CMAKE_RANLIB ${LLVM_MINGW}/bin/x86_64-w64-mingw32-ranlib)
set(CMAKE_RC_COMPILER ${LLVM_MINGW}/bin/llvm-rc)
set(CMAKE_RC_COMPILER /Users/admin/Projects/zig-cross/cmake/zig-rc)
set(CMAKE_PROJECT_INCLUDE ${CMAKE_CURRENT_LIST_DIR}/qt-cross.cmake)
set(CMAKE_CXX_FLAGS_INIT "-stdlib=libc++ -mlzcnt")
set(CMAKE_EXE_LINKER_FLAGS_INIT "--start-no-unused-arguments -rtlib=compiler-rt -unwindlib=libunwind --end-no-unused-arguments")
set(CMAKE_MODULE_LINKER_FLAGS_INIT "${CMAKE_EXE_LINKER_FLAGS_INIT}")
set(CMAKE_SHARED_LINKER_FLAGS_INIT "${CMAKE_EXE_LINKER_FLAGS_INIT}")
qt-cross.cmake:
include_guard()
message(STATUS "Configuring Qt for cross-compilation...")
# Qt
set(QT_HOST_BIN_DIR /Users/admin/Projects/qtbase-wasm32-wasi/bin)
function(qt5_host_tool name)
if (NOT TARGET Qt5::${name})
add_executable(Qt5::${name} IMPORTED)
if(CMAKE_HOST_SYSTEM_NAME STREQUAL "Windows")
set(imported_location ${QT_HOST_BIN_DIR}/${name}.exe)
else()
set(imported_location ${QT_HOST_BIN_DIR}/${name})
endif()
if(NOT EXISTS ${imported_location})
message(FATAL_ERROR "Qt5 tool not found: ${imported_location}")
endif()
set_target_properties(Qt5::${name} PROPERTIES
IMPORTED_LOCATION ${imported_location}
)
endif()
endfunction()
qt5_host_tool(qmake)
qt5_host_tool(moc)
qt5_host_tool(rcc)
qt5_host_tool(uic)
My changes requires for compiling Qt 5.6 (and other Qt 5 versions) with the latest Clang on the host are here: https://github.com/mrexodia/qtbase-wasm32-wasi/commit/20ed9e5c19a0e868921884fee8d924d5d08bd2e2. I built the host tools with the following command:
./configure -opensource -confirm-license -static -nomake examples -no-widgets -no-iconv -no-icu -qt-zlib -no-accessibility -no-warnings-are-errors -prefix Qt5.6
Setting
CMAKE_SYSROOTis relevant since CMake itself and Tools parsing the command-line need to know the full paths as they don't get the builtin information from the compiler(-driver).ie. if you made the effort to add QT5 to llvm-mingw,
find_package(Qt5)will not do its job.
Can you elaborate and substantiate this issue, with a fully reproducible build sequence that requires this?
What do you mean with "add qt5 to llvm-mingw"? I've built and used Qt (both 5 and 6) just fine with this toolchain - you need to be more specific about what you have in mind. Installing the built qt libraries into the llvm-mingw toolchain and expecting them to be found within the toolchain sysroots?
given that I made this technical argument atleast twice already
I do remember that you have mentioned that CMAKE_SYSROOT is required for some cases, yes, but I don't remember seeing any more concrete details about this, either about exactly where/how it is required or the full procedure to need this; "build and use some libraries" isn't really actionable as there's at least three dozen different ways of doing that.
Can you elaborate and substantiate this issue, with a fully reproducible build sequence that requires this?
I'm not sure about his specific usecase, but CMAKE_SYSROOT is often necessary if you have a build server with multiple gcc installations, for example I have a ingle Linux build server which compiles projects for Windows mingw 64 and 32, Linux native, and Emscripten Web assembly. In such cases it's a good thing to have.
As for the tool chain file itself, I don't think it should be included as part of the project, since most users will have their custom tools in special places which will require them to write their own tool chain file separately anyway... If anything, it ahould only be a template which requires setting by the users.