This is an archive of the discontinued LLVM Phabricator instance.

[PR48898][CMake] Support MinGW Toolchain tools in llvm_ExternalProject_Add
ClosedPublic

Authored by zero9178 on Feb 25 2021, 12:36 AM.

Details

Summary

Windows is in the unique position of having two drivers, clang-cl and normal GNU clang, depending on whether a GNU or MSVC target is used. The current implementation with the USE_TOOLCHAIN argument assumes that when CMAKE_SYSTEM_NAME is set to Windows that clang-cl should be used, which is the incorrect choice when targeting a GNU environment.

This patch solves the following:

  • If the host is MinGW and USE_TOOLCHAIN is passed as an argument, the GNU style drivers should be selected instead of clang-cl
  • If one of CMAKE_(C|ASM|CXX)_COMPILER_TARGET has been passed as cmake arguments it checks whether a windows-gnu or windows-msvc target has been requested and selects accordingly

I discovered these issues when trying to do builds of the runtimes using LLVM_ENABLE_RUNTIMES while having a MinGW target as one of the LLVM_RUNTIME_TARGETS.

Diff Detail

Event Timeline

zero9178 created this revision.Feb 25 2021, 12:36 AM
zero9178 requested review of this revision.Feb 25 2021, 12:36 AM
Herald added a project: Restricted Project. · View Herald TranscriptFeb 25 2021, 12:36 AM

Windows is in the unique position of having two drivers, clang-cl and normal GNU clang, depending on whether a GNU or MSVC target is used.

FWIW, the normal GNU frontend also works for the MSVC target; some finer details are omitted in that case, but it rougly does work (and if the default target of the build is an msvc target, that's what targeted when calling that frontend too).

Also FWIW, I haven't really used the runtimes build mechanism at all, because I primarily bootstrap everything from scratch in a cross compile setup, i.e. with no preexisting build tools; first building the compiler, then building the base mingw crt, the compiler-rt builtins on top of that, and then other runtimes like libunwind, libcxxabi and libcxx on top of that. In such cases, afaik the runtimes build is a bit tricky, because I'd need to build other bits (e.g. the mingw crt) between building the compiler and the rest of the llvm provided runtimes. For now I just build all of those subprojects individually afterwards.

So therefore all of this is a bit of uncharted territory for me.

There's also a separate contender for how to build runtimes (still not entirely formally supported), as a middle ground - see https://github.com/llvm/llvm-project/blob/main/libcxx/utils/ci/runtimes/CMakeLists.txt. With that one, you configure building the runtimes just like a normal standalone project (i.e. you set the cmake configuration yourself, instead of instructing the machinery to figure it out based on a target triple), but you can add a series of projects to build as e.g. -DLLVM_ENABLE_PROJECTS="libunwind;libcxxabi;libcxx". That setup has worked fine for me in some initial testing.

llvm/cmake/modules/LLVMExternalProjectUtils.cmake
65

Technically, you can have triples in other forms too, like x86_64-win32; win32 is an alias for windows, and if the -msvc suffix is omitted it defaults to the msvc variant.

If this only deals with canonicalized triples it should be fine. And for other cases, I guess it might be fine as well (as you'd get proper results if you pass triples in the expected form at least and we can't expect to mimic all the quirks handled by the llvm internal triple parser).

85

I'm not quite sure I follow the logic of this condition (parentheses might help?) - is it not (aix or mingw) or (not aix) or mingw? And why doesn't the current default logic work for the mingw case? At worst it might build an unnecessary llvm-lib frontend?

zero9178 marked an inline comment as done.Feb 25 2021, 2:14 AM

Windows is in the unique position of having two drivers, clang-cl and normal GNU clang, depending on whether a GNU or MSVC target is used.

FWIW, the normal GNU frontend also works for the MSVC target; some finer details are omitted in that case, but it rougly does work (and if the default target of the build is an msvc target, that's what targeted when calling that frontend too).

Also FWIW, I haven't really used the runtimes build mechanism at all, because I primarily bootstrap everything from scratch in a cross compile setup, i.e. with no preexisting build tools; first building the compiler, then building the base mingw crt, the compiler-rt builtins on top of that, and then other runtimes like libunwind, libcxxabi and libcxx on top of that. In such cases, afaik the runtimes build is a bit tricky, because I'd need to build other bits (e.g. the mingw crt) between building the compiler and the rest of the llvm provided runtimes. For now I just build all of those subprojects individually afterwards.

So therefore all of this is a bit of uncharted territory for me.

There's also a separate contender for how to build runtimes (still not entirely formally supported), as a middle ground - see https://github.com/llvm/llvm-project/blob/main/libcxx/utils/ci/runtimes/CMakeLists.txt. With that one, you configure building the runtimes just like a normal standalone project (i.e. you set the cmake configuration yourself, instead of instructing the machinery to figure it out based on a target triple), but you can add a series of projects to build as e.g. -DLLVM_ENABLE_PROJECTS="libunwind;libcxxabi;libcxx". That setup has worked fine for me in some initial testing.

I use a MinGW sysroot that is already prebuilt (with GCC in my case) therefore only needing all the other runtimes to be built by clang. Additionally I also build sanitizers and others with clang-cl for i386,x86 and aarch64. I do all of this natively from Windows and being able to simply add LLVM_ENABLE_RUNTIMES to the normal cmake config makes it a lot easier and I only use a single cmake cache file containing all variables, nothing else.

I took heavy inspiration from some of Fuchsia build caches as seen here https://github.com/llvm/llvm-project/blob/d748908fa02b11c7840a7f03c7a52223126bdba9/clang/cmake/caches/Fuchsia.cmake.
I then created my own script (https://gist.github.com/zero9178/cb992f102597f591dc7ed91449f77743) allowing me to just do cmake .. -GNinja -C build.cmake and it'll build a vast array of configurations.

The fact that it worked in LLVM 11 and before was more luck than anything. Since LLVM 12 this has been broken for mingw triples however, so I am trying to fix it.

llvm/cmake/modules/LLVMExternalProjectUtils.cmake
65

I was checking around if there were any functions in other cmake modules or so that could parse or canonicalize triples. I was thinking that for now only supporting canonicalized triples should be fine. Other patterns could technically be added in the future. As far as I am aware, clang would also accept eg. GCC style triple for mingw as well I believe.

85

That's true, that was a mistake of mine. Not a lot that can go wrong here but I'll only conditionally add llvm-lib anyway for the sake of it. Will fix shortly

zero9178 updated this revision to Diff 326328.Feb 25 2021, 2:15 AM
zero9178 marked an inline comment as done.

Addressed reviewers comments:
Corrected appending the correct tools to ARG_TOOLCHAIN_TOOLS in the case when use_mingw_toolchain_tools is set.

rnk added inline comments.Mar 1 2021, 11:25 AM
llvm/cmake/modules/LLVMExternalProjectUtils.cmake
65

This string matching of the cmake argument list makes me feel like we should be passing the target as a proper function argument, and then have llvm_ExternalProject_Add be responsible for appending all three DCMAKE_(C|CXX|ASM)_COMPILER_TARGET variants to the argument list. Do you mind making that happen? It should be a net savings in lines of code. I see only the test-suite caller of llvm_ExternalProject_add doesn't pass these arguments.

I share the concern that cmake doesn't know how to normalize mingw/gnu/msvc triples, but let's factor the decision out into some kind of "is_msvc_triple" utility, and then later we can teach it to match any of the patterns really matter.

zero9178 updated this revision to Diff 327419.Mar 2 2021, 5:43 AM

Added new option argument to llvm_ExternalProject_Add called TARGET_TRIPLE. When set, passes the various CMAKE_<LANG>_COMPILER_TARGET as cmake argument.
Additionally a helper function called is_msvc_triple is used to determine whether the target triple (either set by TARGET_TRIPLE or LLVM_DEFAULT_TARGET_TRIPLE) refers to an msvc target. If that is the case and the just-built toolchain is to be used, it will select clang-cl as well as other MSVC specific tools over the GNU style ones.

Also updated usages of llvm_ExternProject_Add accordingly

rnk accepted this revision.Mar 2 2021, 1:25 PM
This revision is now accepted and ready to land.Mar 2 2021, 1:25 PM
zero9178 closed this revision.Mar 2 2021, 2:02 PM