I recently noticed problems with building with clang in msvc mode when using my distro clang. It seems specific to its configuration, I think that it doesn't affect default clang.
One problem is that --rtlib=libgcc is specified in /etc/clang, which causes clang to produce: ``` clang-15: error: unsupported runtime library 'libgcc' for platform 'MSVC' ``` I think it's a clang bug here: https://github.com/llvm/llvm-project/blob/main/clang/lib/Driver/ToolChains/M... It should probably check for -nodefaultlibs in addition to -nostdlib. It's easy to handle on Wine side by using -nostdlib.
The other problem is that clang for some reason doesn't define `_MSV_VER` by default. I found that it's defined only if I pass `-fuse-ld=lld` to the command line. That's weird because it shouldn't affect compilation step, it should matter only for linking and that's when we pass it. I didn't track it down in clang code itself, but if we can't depend on clang providing it by default, we need to make sure to pass `-fms-compatibility-version` ourselves. The exact version doesn't really matter, we mostly need to make sure that it's defined at all so that our #ifdefs work correctly.
-- v2: configure: Use -fuse-ld=lld also for compilation targets. winegcc: Use -nostdlib instead of -nostartfiles on Clang MSVC targets. configure: Use -nostdlib instead of -nostartfiles in WINE_TRY_PE_CFLAGS.
From: Jacek Caban jacek@codeweavers.com
-nostartfiles is not enough if clang is configured with explicit default rtlib. --- aclocal.m4 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/aclocal.m4 b/aclocal.m4 index 080f782b698..f2412497067 100644 --- a/aclocal.m4 +++ b/aclocal.m4 @@ -208,7 +208,7 @@ AC_DEFUN([WINE_TRY_PE_CFLAGS], AC_CACHE_CHECK([whether $CC supports $1], ac_var, [ac_wine_try_cflags_saved=$CFLAGS ac_wine_try_cflags_saved_exeext=$ac_exeext -CFLAGS="$CFLAGS -nostartfiles -nodefaultlibs $1" +CFLAGS="$CFLAGS -nostdlib -nodefaultlibs $1" ac_exeext=".exe" AC_LINK_IFELSE([AC_LANG_SOURCE([[int __cdecl mainCRTStartup(void) { return 0; }]])], [AS_VAR_SET(ac_var,yes)], [AS_VAR_SET(ac_var,no)])
From: Jacek Caban jacek@codeweavers.com
-nostartfiles is not enough if clang is configured with explicit default rtlib. --- tools/winegcc/winegcc.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/tools/winegcc/winegcc.c b/tools/winegcc/winegcc.c index 71d2b93f0c6..a850cce765f 100644 --- a/tools/winegcc/winegcc.c +++ b/tools/winegcc/winegcc.c @@ -482,7 +482,8 @@ static struct strarray get_link_args( struct options *opts, const char *output_n } if (opts->unicode_app) strarray_add( &flags, "-municode" ); if (opts->nodefaultlibs || opts->use_msvcrt) strarray_add( &flags, "-nodefaultlibs" ); - if (opts->nostartfiles || opts->use_msvcrt) strarray_add( &flags, "-nostartfiles" ); + if (opts->nostartfiles) strarray_add( &flags, "-nostartfiles" ); + if (opts->use_msvcrt) strarray_add( &flags, "-nostdlib" ); if (opts->image_base) strarray_add( &flags, strmake("-Wl,-base:%s", opts->image_base )); if (opts->subsystem) strarray_add( &flags, strmake("-Wl,-subsystem:%s", opts->subsystem ));
From: Jacek Caban jacek@codeweavers.com
This is used by clang to distinguish between MSVC and windows-itanium targets. We override default option (usually meant for native builds) to make sure that we use the right target. --- configure.ac | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/configure.ac b/configure.ac index 7313fde9a4e..cb91c9c02b5 100644 --- a/configure.ac +++ b/configure.ac @@ -931,7 +931,6 @@ do
dnl Check if cross compiler supports -target argument llvm_target=$target - llvm_cflags="-fuse-ld=lld" if test -z "$llvm_target" then case $wine_arch in @@ -940,14 +939,15 @@ do *) llvm_target=$wine_arch-windows ;; esac fi + llvm_extra_cflags="-target $llvm_target -fuse-ld=lld" case $llvm_target in - *windows) llvm_cflags="$llvm_cflags -Wl,-subsystem:console" ;; + *windows) llvm_cflags="-Wl,-subsystem:console" ;; esac - WINE_TRY_PE_CFLAGS([-target $llvm_target $llvm_cflags], + WINE_TRY_PE_CFLAGS([$llvm_extra_cflags $llvm_cflags], [target=$llvm_target AS_VAR_SET([${wine_arch}_DELAYLOADFLAG],["-Wl,-delayload,"]) - AS_VAR_APPEND([${wine_arch}_EXTRACFLAGS],[" -target $target"]) - CFLAGS="$CFLAGS -target $target $llvm_cflags"]) + AS_VAR_APPEND([${wine_arch}_EXTRACFLAGS],[" $llvm_extra_cflags"]) + CFLAGS="$llvm_extra_cflags $llvm_cflags"]) AS_VAR_SET([${wine_arch}_TARGET],[$target])]) AS_VAR_POPDEF([wine_cv_crosscc])
On Fri Nov 25 18:56:43 2022 +0000, Jacek Caban wrote:
Interesting findings, thanks. I didn't know that such targets even exist... And I agree, it's better to always pass `-fuse-ld` in that case.
I pushed a new version that just always passes `-fuse-ld`. We can't do the same for `-rtlib`, because `-rtlib=platform` requires your commit 0a4c6c9f98a6d, which is not yet present in released clang versions. I also think that this option shouldn't really matter and -nostdlib achieves that.
On Mon Nov 28 12:57:44 2022 +0000, Jacek Caban wrote:
I pushed a new version that just always passes `-fuse-ld`. We can't do the same for `-rtlib`, because `-rtlib=platform` requires your commit 0a4c6c9f98a6d, which is not yet present in released clang versions. I also think that this option shouldn't really matter and -nostdlib achieves that.
Thanks! This looks reasonable to me now I think.
Overall I'm not a fan of needing to pass `-fuse-ld` like this, but given what the current Clang code does, this is probably the most reasonable fix.
This (mis)feature seems to have been introduced in f96bedfce301aa3ebaa14968558cfd5e9431818e in llvm-project (https://github.com/llvm/llvm-project/commit/f96bedfce301aa3ebaa14968558cfd5e...) - I disagree with that patch quite a bit, but I'm not sure if I disagree enough to try to get it reversed... (The effort could also be spent on making default config files only apply to the intended native target.)