[PATCH 0/9] MR10273: vcruntime140: Initial C++ support.
From: Jacek Caban <jacek@codeweavers.com> This distinguishes -windows-gnu from -w64-mingw32 based on what Wine tools expect from the compiler. It is now assumed that the underlying toolchain is LLVM and, similarly to the MSVC -windows target, the -target argument is always passed instead of requiring $(CC) to be configured for a specific target. That this does not affect --with-mingw=llvm-mingw builds, which, like other typical mingw distributions, use -w64-mingw32. Those still do not use the -target argument in winebuild and rely on target-specific compiler driver aliases anyway. --- tools/tools.h | 12 ++++++++++-- tools/winebuild/import.c | 4 ++-- tools/winebuild/spec32.c | 1 + tools/winebuild/utils.c | 34 ++++++++++++++++++++++------------ tools/winegcc/winegcc.c | 3 ++- 5 files changed, 37 insertions(+), 17 deletions(-) diff --git a/tools/tools.h b/tools/tools.h index be569f801d5..5cbe6bc5d42 100644 --- a/tools/tools.h +++ b/tools/tools.h @@ -110,6 +110,7 @@ struct target PLATFORM_FREEBSD, PLATFORM_SOLARIS, PLATFORM_WINDOWS, + PLATFORM_WINDOWS_GNU, PLATFORM_MINGW, PLATFORM_CYGWIN } platform; @@ -617,9 +618,16 @@ static inline void set_target_ptr_size( struct target *target, unsigned int size } +static inline bool is_llvm_pe_target( struct target target ) +{ + return target.platform == PLATFORM_WINDOWS || + target.platform == PLATFORM_WINDOWS_GNU; +} + + static inline bool is_pe_target( struct target target ) { - return (target.platform == PLATFORM_WINDOWS || + return (is_llvm_pe_target( target ) || target.platform == PLATFORM_MINGW || target.platform == PLATFORM_CYGWIN); } @@ -668,7 +676,7 @@ static inline int get_platform_from_name( const char *name ) { "freebsd", PLATFORM_FREEBSD }, { "solaris", PLATFORM_SOLARIS }, { "mingw32", PLATFORM_MINGW }, - { "windows-gnu", PLATFORM_MINGW }, + { "windows-gnu", PLATFORM_WINDOWS_GNU }, { "winnt", PLATFORM_MINGW }, { "windows", PLATFORM_WINDOWS }, { "cygwin", PLATFORM_CYGWIN }, diff --git a/tools/winebuild/import.c b/tools/winebuild/import.c index 2d7caa0883e..a2ed34667df 100644 --- a/tools/winebuild/import.c +++ b/tools/winebuild/import.c @@ -1210,7 +1210,7 @@ void output_static_lib( const char *output_name, struct strarray files, int crea { struct strarray args; - if (!create || target.platform != PLATFORM_WINDOWS) + if (!create || !is_llvm_pe_target( target )) { args = find_tool( "ar", NULL ); strarray_add( &args, create ? "rc" : "r" ); @@ -1228,7 +1228,7 @@ void output_static_lib( const char *output_name, struct strarray files, int crea if (create) unlink( output_name ); spawn( args ); - if (target.platform != PLATFORM_WINDOWS) + if (!is_llvm_pe_target( target )) { struct strarray ranlib = find_tool( "ranlib", NULL ); strarray_add( &ranlib, output_name ); diff --git a/tools/winebuild/spec32.c b/tools/winebuild/spec32.c index 9d99850f887..11ec69ef446 100644 --- a/tools/winebuild/spec32.c +++ b/tools/winebuild/spec32.c @@ -751,6 +751,7 @@ void output_module( DLLSPEC *spec ) { case PLATFORM_MINGW: case PLATFORM_WINDOWS: + case PLATFORM_WINDOWS_GNU: return; /* nothing to do */ case PLATFORM_APPLE: output( "\t.text\n" ); diff --git a/tools/winebuild/utils.c b/tools/winebuild/utils.c index 5492de99c90..d91c2d7a930 100644 --- a/tools/winebuild/utils.c +++ b/tools/winebuild/utils.c @@ -345,6 +345,7 @@ struct strarray get_ld_command(void) break; case PLATFORM_MINGW: case PLATFORM_WINDOWS: + case PLATFORM_WINDOWS_GNU: strarray_add( &args, "-m" ); strarray_add( &args, (force_pointer_size == 8) ? "i386pep" : "i386pe" ); break; @@ -747,6 +748,7 @@ const char *asm_name( const char *sym ) { case PLATFORM_MINGW: case PLATFORM_WINDOWS: + case PLATFORM_WINDOWS_GNU: if (target.cpu != CPU_i386) return sym; if (sym[0] == '@') return sym; /* fastcall */ /* fall through */ @@ -779,6 +781,7 @@ void output_function_header( const char *func, int global ) break; case PLATFORM_MINGW: case PLATFORM_WINDOWS: + case PLATFORM_WINDOWS_GNU: if (target.cpu == CPU_ARM64EC) output( ".section .text,\"xr\",discard,%s\n\t", name ); output( "\t.def %s\n\t.scl 2\n\t.type 32\n\t.endef\n", name ); if (global) output( "\t.globl %s\n", name ); @@ -800,6 +803,7 @@ void output_function_size( const char *name ) case PLATFORM_APPLE: case PLATFORM_MINGW: case PLATFORM_WINDOWS: + case PLATFORM_WINDOWS_GNU: break; default: output( "\t.size %s, .-%s\n", name, name ); @@ -891,6 +895,7 @@ void output_gnu_stack_note(void) { case PLATFORM_MINGW: case PLATFORM_WINDOWS: + case PLATFORM_WINDOWS_GNU: case PLATFORM_APPLE: break; default: @@ -908,6 +913,7 @@ const char *asm_globl( const char *func ) return strmake( "\t.globl _%s\n\t.private_extern _%s\n_%s:", func, func, func ); case PLATFORM_MINGW: case PLATFORM_WINDOWS: + case PLATFORM_WINDOWS_GNU: { const char *name = asm_name( func ); return strmake( "\t.globl %s\n%s:", name, name ); @@ -943,10 +949,11 @@ const char *get_asm_export_section(void) { switch (target.platform) { - case PLATFORM_APPLE: return ".data"; + case PLATFORM_APPLE: return ".data"; case PLATFORM_MINGW: - case PLATFORM_WINDOWS: return ".section .edata"; - default: return ".section .data"; + case PLATFORM_WINDOWS: + case PLATFORM_WINDOWS_GNU: return ".section .edata"; + default: return ".section .data"; } } @@ -954,10 +961,11 @@ const char *get_asm_rodata_section(void) { switch (target.platform) { - case PLATFORM_APPLE: return ".const"; + case PLATFORM_APPLE: return ".const"; case PLATFORM_MINGW: - case PLATFORM_WINDOWS: return ".section .rdata"; - default: return ".section .rodata"; + case PLATFORM_WINDOWS: + case PLATFORM_WINDOWS_GNU: return ".section .rdata"; + default: return ".section .rodata"; } } @@ -965,10 +973,11 @@ const char *get_asm_rsrc_section(void) { switch (target.platform) { - case PLATFORM_APPLE: return ".data"; + case PLATFORM_APPLE: return ".data"; case PLATFORM_MINGW: - case PLATFORM_WINDOWS: return ".section .rsrc"; - default: return ".section .data"; + case PLATFORM_WINDOWS: + case PLATFORM_WINDOWS_GNU: return ".section .rsrc"; + default: return ".section .data"; } } @@ -976,9 +985,10 @@ const char *get_asm_string_section(void) { switch (target.platform) { - case PLATFORM_APPLE: return ".cstring"; + case PLATFORM_APPLE: return ".cstring"; case PLATFORM_MINGW: - case PLATFORM_WINDOWS: return ".section .rdata"; - default: return ".section .rodata"; + case PLATFORM_WINDOWS: + case PLATFORM_WINDOWS_GNU: return ".section .rdata"; + default: return ".section .rodata"; } } diff --git a/tools/winegcc/winegcc.c b/tools/winegcc/winegcc.c index 76b9663bffa..6b48a75082a 100644 --- a/tools/winegcc/winegcc.c +++ b/tools/winegcc/winegcc.c @@ -424,7 +424,7 @@ static struct strarray build_tool_name( const char *target_name, struct tool_nam if (cc_cmd && !strncmp( tool.llvm_base, "clang", 5 )) { ret = strarray_fromstring( cc_cmd, " " ); - if (target.platform == PLATFORM_WINDOWS) add_clang_options( target_name, &ret ); + if (is_llvm_pe_target( target )) add_clang_options( target_name, &ret ); return ret; } @@ -543,6 +543,7 @@ static struct strarray get_link_args( const char *output_name ) case PLATFORM_MINGW: case PLATFORM_CYGWIN: + case PLATFORM_WINDOWS_GNU: strarray_add( &link_args, "-nodefaultlibs" ); strarray_add( &link_args, "-nostartfiles" ); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10273
From: Jacek Caban <jacek@codeweavers.com> --- configure | 8 ++++++-- configure.ac | 8 ++++++-- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/configure b/configure index ed9c961efcc..6ffc2a8e580 100755 --- a/configure +++ b/configure @@ -7703,9 +7703,13 @@ fi target_strip=${target:-llvm}-strip if test "$wine_try_msvc" = yes -o -z "$target" then - llvm_target="$mingw_cpu-windows" + case $wine_arch in + arm) llvm_target="$mingw_cpu-windows-gnu" + llvm_cflags="-mconsole -Wl,--fatal-warnings" ;; + *) llvm_target="$mingw_cpu-windows" + llvm_cflags="-Wl,-subsystem:console -Wl,-WX" ;; + esac llvm_extra_cflags="-target $llvm_target -fuse-ld=lld" - llvm_cflags="-Wl,-subsystem:console -Wl,-WX" else llvm_target=$target llvm_extra_cflags="-fuse-ld=lld" diff --git a/configure.ac b/configure.ac index f63669df192..78364d27346 100644 --- a/configure.ac +++ b/configure.ac @@ -469,9 +469,13 @@ do target_strip=${target:-llvm}-strip if test "$wine_try_msvc" = yes -o -z "$target" then - llvm_target="$mingw_cpu-windows" + case $wine_arch in + arm) llvm_target="$mingw_cpu-windows-gnu" + llvm_cflags="-mconsole -Wl,--fatal-warnings" ;; + *) llvm_target="$mingw_cpu-windows" + llvm_cflags="-Wl,-subsystem:console -Wl,-WX" ;; + esac llvm_extra_cflags="-target $llvm_target -fuse-ld=lld" - llvm_cflags="-Wl,-subsystem:console -Wl,-WX" else llvm_target=$target llvm_extra_cflags="-fuse-ld=lld" -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10273
From: Alexandre Julliard <julliard@winehq.org> With help from Jacek Caban. --- configure | 366 ++++++++++++++++++++++++------------------- configure.ac | 15 +- tools/make_makefiles | 8 +- tools/makedep.c | 76 +++++++-- 4 files changed, 288 insertions(+), 177 deletions(-) diff --git a/configure b/configure index 6ffc2a8e580..02649853799 100755 --- a/configure +++ b/configure @@ -807,8 +807,11 @@ x86_64_STRIP x86_64_TARGET x86_64_DEBUG x86_64_LDFLAGS +x86_64_EXTRACXXFLAGS x86_64_EXTRACFLAGS +x86_64_CXXFLAGS x86_64_CFLAGS +x86_64_CXX x86_64_CC i386_DISABLED_SUBDIRS i386_DELAYLOADFLAG @@ -816,8 +819,11 @@ i386_STRIP i386_TARGET i386_DEBUG i386_LDFLAGS +i386_EXTRACXXFLAGS i386_EXTRACFLAGS +i386_CXXFLAGS i386_CFLAGS +i386_CXX i386_CC arm64ec_DISABLED_SUBDIRS arm64ec_DELAYLOADFLAG @@ -825,8 +831,11 @@ arm64ec_STRIP arm64ec_TARGET arm64ec_DEBUG arm64ec_LDFLAGS +arm64ec_EXTRACXXFLAGS arm64ec_EXTRACFLAGS +arm64ec_CXXFLAGS arm64ec_CFLAGS +arm64ec_CXX arm64ec_CC arm_DISABLED_SUBDIRS arm_DELAYLOADFLAG @@ -834,8 +843,11 @@ arm_STRIP arm_TARGET arm_DEBUG arm_LDFLAGS +arm_EXTRACXXFLAGS arm_EXTRACFLAGS +arm_CXXFLAGS arm_CFLAGS +arm_CXX arm_CC aarch64_DISABLED_SUBDIRS aarch64_DELAYLOADFLAG @@ -843,8 +855,11 @@ aarch64_STRIP aarch64_TARGET aarch64_DEBUG aarch64_LDFLAGS +aarch64_EXTRACXXFLAGS aarch64_EXTRACFLAGS +aarch64_CXXFLAGS aarch64_CFLAGS +aarch64_CXX aarch64_CC HOST_ARCH toolsext @@ -7680,6 +7695,20 @@ then : else case e in #( e) eval "${wine_arch}_LDFLAGS=\$CROSSLDFLAGS" ;; esac +fi + if eval test \${${wine_arch}_CXX+y} +then : + +else case e in #( + e) eval ${wine_arch}_CXX=\$${wine_arch}_CC ;; +esac +fi + if eval test \${${wine_arch}_CXXFLAGS+y} +then : + +else case e in #( + e) eval ${wine_arch}_CXXFLAGS=\$${wine_arch}_CFLAGS ;; +esac fi eval CC=\$${wine_arch}_CC eval CFLAGS=\$${wine_arch}_CFLAGS @@ -8175,46 +8204,6 @@ printf "%s\n" "$ac_res" >&6; } if eval test \"x\$"$as_ac_var"\" = x"yes" then : CFLAGS="$CFLAGS -Werror=unsupported-floating-point-opt" -fi } - { as_ac_var=`printf "%s\n" "ac_cv_${wine_arch}_cflags_-Wdeclaration-after-statement" | sed "$as_sed_sh"` -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC supports -Wdeclaration-after-statement" >&5 -printf %s "checking whether $CC supports -Wdeclaration-after-statement... " >&6; } -if eval test \${$as_ac_var+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_wine_try_cflags_saved=$CFLAGS -ac_wine_try_cflags_saved_exeext=$ac_exeext -CFLAGS="$CFLAGS -nostdlib -nodefaultlibs -Wdeclaration-after-statement" -ac_exeext=".exe" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -void *__os_arm64x_dispatch_ret = 0; -const unsigned int _load_config_used[0x50] = { sizeof(_load_config_used) }; -#if defined(__clang_major__) && defined(MIN_CLANG_VERSION) && __clang_major__ < MIN_CLANG_VERSION -#error Too old clang version -#endif -int __cdecl mainCRTStartup(void) { return 0; } -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval "$as_ac_var=yes" -else case e in #( - e) eval "$as_ac_var=no" ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CFLAGS=$ac_wine_try_cflags_saved -ac_exeext=$ac_wine_try_cflags_saved_exeext ;; -esac -fi -eval ac_res=\$$as_ac_var - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -printf "%s\n" "$ac_res" >&6; } -if eval test \"x\$"$as_ac_var"\" = x"yes" -then : - as_fn_append ${wine_arch}_EXTRACFLAGS " -Wdeclaration-after-statement" fi } { as_ac_var=`printf "%s\n" "ac_cv_${wine_arch}_cflags_-Wempty-body" | sed "$as_sed_sh"` { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC supports -Wempty-body" >&5 @@ -8455,46 +8444,6 @@ printf "%s\n" "$ac_res" >&6; } if eval test \"x\$"$as_ac_var"\" = x"yes" then : as_fn_append ${wine_arch}_EXTRACFLAGS " -Wshift-overflow=2" -fi } - { as_ac_var=`printf "%s\n" "ac_cv_${wine_arch}_cflags_-Wstrict-prototypes" | sed "$as_sed_sh"` -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC supports -Wstrict-prototypes" >&5 -printf %s "checking whether $CC supports -Wstrict-prototypes... " >&6; } -if eval test \${$as_ac_var+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_wine_try_cflags_saved=$CFLAGS -ac_wine_try_cflags_saved_exeext=$ac_exeext -CFLAGS="$CFLAGS -nostdlib -nodefaultlibs -Wstrict-prototypes" -ac_exeext=".exe" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -void *__os_arm64x_dispatch_ret = 0; -const unsigned int _load_config_used[0x50] = { sizeof(_load_config_used) }; -#if defined(__clang_major__) && defined(MIN_CLANG_VERSION) && __clang_major__ < MIN_CLANG_VERSION -#error Too old clang version -#endif -int __cdecl mainCRTStartup(void) { return 0; } -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval "$as_ac_var=yes" -else case e in #( - e) eval "$as_ac_var=no" ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CFLAGS=$ac_wine_try_cflags_saved -ac_exeext=$ac_wine_try_cflags_saved_exeext ;; -esac -fi -eval ac_res=\$$as_ac_var - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -printf "%s\n" "$ac_res" >&6; } -if eval test \"x\$"$as_ac_var"\" = x"yes" -then : - as_fn_append ${wine_arch}_EXTRACFLAGS " -Wstrict-prototypes" fi } { as_ac_var=`printf "%s\n" "ac_cv_${wine_arch}_cflags_-Wtype-limits" | sed "$as_sed_sh"` { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC supports -Wtype-limits" >&5 @@ -8735,46 +8684,6 @@ printf "%s\n" "$ac_res" >&6; } if eval test \"x\$"$as_ac_var"\" = x"yes" then : as_fn_append ${wine_arch}_EXTRACFLAGS " -Wlogical-op" -fi } - { as_ac_var=`printf "%s\n" "ac_cv_${wine_arch}_cflags_-Wabsolute-value" | sed "$as_sed_sh"` -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC supports -Wabsolute-value" >&5 -printf %s "checking whether $CC supports -Wabsolute-value... " >&6; } -if eval test \${$as_ac_var+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_wine_try_cflags_saved=$CFLAGS -ac_wine_try_cflags_saved_exeext=$ac_exeext -CFLAGS="$CFLAGS -nostdlib -nodefaultlibs -Wabsolute-value" -ac_exeext=".exe" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -void *__os_arm64x_dispatch_ret = 0; -const unsigned int _load_config_used[0x50] = { sizeof(_load_config_used) }; -#if defined(__clang_major__) && defined(MIN_CLANG_VERSION) && __clang_major__ < MIN_CLANG_VERSION -#error Too old clang version -#endif -int __cdecl mainCRTStartup(void) { return 0; } -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval "$as_ac_var=yes" -else case e in #( - e) eval "$as_ac_var=no" ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CFLAGS=$ac_wine_try_cflags_saved -ac_exeext=$ac_wine_try_cflags_saved_exeext ;; -esac -fi -eval ac_res=\$$as_ac_var - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -printf "%s\n" "$ac_res" >&6; } -if eval test \"x\$"$as_ac_var"\" = x"yes" -then : - as_fn_append ${wine_arch}_EXTRACFLAGS " -Wabsolute-value" fi } { as_ac_var=`printf "%s\n" "ac_cv_${wine_arch}_cflags_-Wenum-enum-conversion" | sed "$as_sed_sh"` { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC supports -Wenum-enum-conversion" >&5 @@ -8897,46 +8806,6 @@ printf "%s\n" "$ac_res" >&6; } if eval test \"x\$"$as_ac_var"\" = x"yes" then : as_fn_append ${wine_arch}_EXTRACFLAGS " -ffunction-sections" -fi } - { as_ac_var=`printf "%s\n" "ac_cv_${wine_arch}_cflags_-fasync-exceptions -DMIN_CLANG_VERSION=19" | sed "$as_sed_sh"` -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC supports -fasync-exceptions -DMIN_CLANG_VERSION=19" >&5 -printf %s "checking whether $CC supports -fasync-exceptions -DMIN_CLANG_VERSION=19... " >&6; } -if eval test \${$as_ac_var+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_wine_try_cflags_saved=$CFLAGS -ac_wine_try_cflags_saved_exeext=$ac_exeext -CFLAGS="$CFLAGS -nostdlib -nodefaultlibs -fasync-exceptions -DMIN_CLANG_VERSION=19" -ac_exeext=".exe" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -void *__os_arm64x_dispatch_ret = 0; -const unsigned int _load_config_used[0x50] = { sizeof(_load_config_used) }; -#if defined(__clang_major__) && defined(MIN_CLANG_VERSION) && __clang_major__ < MIN_CLANG_VERSION -#error Too old clang version -#endif -int __cdecl mainCRTStartup(void) { return 0; } -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval "$as_ac_var=yes" -else case e in #( - e) eval "$as_ac_var=no" ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CFLAGS=$ac_wine_try_cflags_saved -ac_exeext=$ac_wine_try_cflags_saved_exeext ;; -esac -fi -eval ac_res=\$$as_ac_var - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -printf "%s\n" "$ac_res" >&6; } -if eval test \"x\$"$as_ac_var"\" = x"yes" -then : - as_fn_append ${wine_arch}_EXTRACFLAGS " -fasync-exceptions" fi } { as_ac_var=`printf "%s\n" "ac_cv_${wine_arch}_cflags_-ffp-exception-behavior=maytrap" | sed "$as_sed_sh"` { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC supports -ffp-exception-behavior=maytrap" >&5 @@ -9621,6 +9490,168 @@ then : fi } test "x$enable_build_id" != xyes || as_fn_append ${wine_arch}_LDFLAGS " -Wl,--build-id" + eval ${wine_arch}_EXTRACXXFLAGS=\$${wine_arch}_EXTRACFLAGS + { as_ac_var=`printf "%s\n" "ac_cv_${wine_arch}_cflags_-Wdeclaration-after-statement" | sed "$as_sed_sh"` +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC supports -Wdeclaration-after-statement" >&5 +printf %s "checking whether $CC supports -Wdeclaration-after-statement... " >&6; } +if eval test \${$as_ac_var+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) ac_wine_try_cflags_saved=$CFLAGS +ac_wine_try_cflags_saved_exeext=$ac_exeext +CFLAGS="$CFLAGS -nostdlib -nodefaultlibs -Wdeclaration-after-statement" +ac_exeext=".exe" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +void *__os_arm64x_dispatch_ret = 0; +const unsigned int _load_config_used[0x50] = { sizeof(_load_config_used) }; +#if defined(__clang_major__) && defined(MIN_CLANG_VERSION) && __clang_major__ < MIN_CLANG_VERSION +#error Too old clang version +#endif +int __cdecl mainCRTStartup(void) { return 0; } +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + eval "$as_ac_var=yes" +else case e in #( + e) eval "$as_ac_var=no" ;; +esac +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +CFLAGS=$ac_wine_try_cflags_saved +ac_exeext=$ac_wine_try_cflags_saved_exeext ;; +esac +fi +eval ac_res=\$$as_ac_var + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +printf "%s\n" "$ac_res" >&6; } +if eval test \"x\$"$as_ac_var"\" = x"yes" +then : + as_fn_append ${wine_arch}_EXTRACFLAGS " -Wdeclaration-after-statement" +fi } + { as_ac_var=`printf "%s\n" "ac_cv_${wine_arch}_cflags_-Wstrict-prototypes" | sed "$as_sed_sh"` +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC supports -Wstrict-prototypes" >&5 +printf %s "checking whether $CC supports -Wstrict-prototypes... " >&6; } +if eval test \${$as_ac_var+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) ac_wine_try_cflags_saved=$CFLAGS +ac_wine_try_cflags_saved_exeext=$ac_exeext +CFLAGS="$CFLAGS -nostdlib -nodefaultlibs -Wstrict-prototypes" +ac_exeext=".exe" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +void *__os_arm64x_dispatch_ret = 0; +const unsigned int _load_config_used[0x50] = { sizeof(_load_config_used) }; +#if defined(__clang_major__) && defined(MIN_CLANG_VERSION) && __clang_major__ < MIN_CLANG_VERSION +#error Too old clang version +#endif +int __cdecl mainCRTStartup(void) { return 0; } +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + eval "$as_ac_var=yes" +else case e in #( + e) eval "$as_ac_var=no" ;; +esac +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +CFLAGS=$ac_wine_try_cflags_saved +ac_exeext=$ac_wine_try_cflags_saved_exeext ;; +esac +fi +eval ac_res=\$$as_ac_var + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +printf "%s\n" "$ac_res" >&6; } +if eval test \"x\$"$as_ac_var"\" = x"yes" +then : + as_fn_append ${wine_arch}_EXTRACFLAGS " -Wstrict-prototypes" +fi } + { as_ac_var=`printf "%s\n" "ac_cv_${wine_arch}_cflags_-Wabsolute-value" | sed "$as_sed_sh"` +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC supports -Wabsolute-value" >&5 +printf %s "checking whether $CC supports -Wabsolute-value... " >&6; } +if eval test \${$as_ac_var+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) ac_wine_try_cflags_saved=$CFLAGS +ac_wine_try_cflags_saved_exeext=$ac_exeext +CFLAGS="$CFLAGS -nostdlib -nodefaultlibs -Wabsolute-value" +ac_exeext=".exe" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +void *__os_arm64x_dispatch_ret = 0; +const unsigned int _load_config_used[0x50] = { sizeof(_load_config_used) }; +#if defined(__clang_major__) && defined(MIN_CLANG_VERSION) && __clang_major__ < MIN_CLANG_VERSION +#error Too old clang version +#endif +int __cdecl mainCRTStartup(void) { return 0; } +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + eval "$as_ac_var=yes" +else case e in #( + e) eval "$as_ac_var=no" ;; +esac +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +CFLAGS=$ac_wine_try_cflags_saved +ac_exeext=$ac_wine_try_cflags_saved_exeext ;; +esac +fi +eval ac_res=\$$as_ac_var + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +printf "%s\n" "$ac_res" >&6; } +if eval test \"x\$"$as_ac_var"\" = x"yes" +then : + as_fn_append ${wine_arch}_EXTRACFLAGS " -Wabsolute-value" +fi } + { as_ac_var=`printf "%s\n" "ac_cv_${wine_arch}_cflags_-fasync-exceptions -DMIN_CLANG_VERSION=19" | sed "$as_sed_sh"` +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC supports -fasync-exceptions -DMIN_CLANG_VERSION=19" >&5 +printf %s "checking whether $CC supports -fasync-exceptions -DMIN_CLANG_VERSION=19... " >&6; } +if eval test \${$as_ac_var+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) ac_wine_try_cflags_saved=$CFLAGS +ac_wine_try_cflags_saved_exeext=$ac_exeext +CFLAGS="$CFLAGS -nostdlib -nodefaultlibs -fasync-exceptions -DMIN_CLANG_VERSION=19" +ac_exeext=".exe" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +void *__os_arm64x_dispatch_ret = 0; +const unsigned int _load_config_used[0x50] = { sizeof(_load_config_used) }; +#if defined(__clang_major__) && defined(MIN_CLANG_VERSION) && __clang_major__ < MIN_CLANG_VERSION +#error Too old clang version +#endif +int __cdecl mainCRTStartup(void) { return 0; } +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + eval "$as_ac_var=yes" +else case e in #( + e) eval "$as_ac_var=no" ;; +esac +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +CFLAGS=$ac_wine_try_cflags_saved +ac_exeext=$ac_wine_try_cflags_saved_exeext ;; +esac +fi +eval ac_res=\$$as_ac_var + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +printf "%s\n" "$ac_res" >&6; } +if eval test \"x\$"$as_ac_var"\" = x"yes" +then : + as_fn_append ${wine_arch}_EXTRACFLAGS " -fasync-exceptions" +fi } + done CC=$saved_CC @@ -24455,8 +24486,11 @@ TARGETFLAGS = $TARGETFLAGS toolsext = $toolsext HOST_ARCH = $HOST_ARCH aarch64_CC = $aarch64_CC +aarch64_CXX = $aarch64_CXX aarch64_CFLAGS = $aarch64_CFLAGS +aarch64_CXXFLAGS = $aarch64_CXXFLAGS aarch64_EXTRACFLAGS = $aarch64_EXTRACFLAGS +aarch64_EXTRACXXFLAGS = $aarch64_EXTRACXXFLAGS aarch64_LDFLAGS = $aarch64_LDFLAGS aarch64_DEBUG = $aarch64_DEBUG aarch64_TARGET = $aarch64_TARGET @@ -24464,8 +24498,11 @@ aarch64_STRIP = $aarch64_STRIP aarch64_DELAYLOADFLAG = $aarch64_DELAYLOADFLAG aarch64_DISABLED_SUBDIRS = $aarch64_DISABLED_SUBDIRS arm_CC = $arm_CC +arm_CXX = $arm_CXX arm_CFLAGS = $arm_CFLAGS +arm_CXXFLAGS = $arm_CXXFLAGS arm_EXTRACFLAGS = $arm_EXTRACFLAGS +arm_EXTRACXXFLAGS = $arm_EXTRACXXFLAGS arm_LDFLAGS = $arm_LDFLAGS arm_DEBUG = $arm_DEBUG arm_TARGET = $arm_TARGET @@ -24473,8 +24510,11 @@ arm_STRIP = $arm_STRIP arm_DELAYLOADFLAG = $arm_DELAYLOADFLAG arm_DISABLED_SUBDIRS = $arm_DISABLED_SUBDIRS arm64ec_CC = $arm64ec_CC +arm64ec_CXX = $arm64ec_CXX arm64ec_CFLAGS = $arm64ec_CFLAGS +arm64ec_CXXFLAGS = $arm64ec_CXXFLAGS arm64ec_EXTRACFLAGS = $arm64ec_EXTRACFLAGS +arm64ec_EXTRACXXFLAGS = $arm64ec_EXTRACXXFLAGS arm64ec_LDFLAGS = $arm64ec_LDFLAGS arm64ec_DEBUG = $arm64ec_DEBUG arm64ec_TARGET = $arm64ec_TARGET @@ -24482,8 +24522,11 @@ arm64ec_STRIP = $arm64ec_STRIP arm64ec_DELAYLOADFLAG = $arm64ec_DELAYLOADFLAG arm64ec_DISABLED_SUBDIRS = $arm64ec_DISABLED_SUBDIRS i386_CC = $i386_CC +i386_CXX = $i386_CXX i386_CFLAGS = $i386_CFLAGS +i386_CXXFLAGS = $i386_CXXFLAGS i386_EXTRACFLAGS = $i386_EXTRACFLAGS +i386_EXTRACXXFLAGS = $i386_EXTRACXXFLAGS i386_LDFLAGS = $i386_LDFLAGS i386_DEBUG = $i386_DEBUG i386_TARGET = $i386_TARGET @@ -24491,8 +24534,11 @@ i386_STRIP = $i386_STRIP i386_DELAYLOADFLAG = $i386_DELAYLOADFLAG i386_DISABLED_SUBDIRS = $i386_DISABLED_SUBDIRS x86_64_CC = $x86_64_CC +x86_64_CXX = $x86_64_CXX x86_64_CFLAGS = $x86_64_CFLAGS +x86_64_CXXFLAGS = $x86_64_CXXFLAGS x86_64_EXTRACFLAGS = $x86_64_EXTRACFLAGS +x86_64_EXTRACXXFLAGS = $x86_64_EXTRACXXFLAGS x86_64_LDFLAGS = $x86_64_LDFLAGS x86_64_DEBUG = $x86_64_DEBUG x86_64_TARGET = $x86_64_TARGET diff --git a/configure.ac b/configure.ac index 78364d27346..a05f3e31e12 100644 --- a/configure.ac +++ b/configure.ac @@ -174,7 +174,7 @@ case "$host_cpu" in x86_64) HOST_ARCH=x86_64 ;; esac m4_set_add_all([_AC_SUBST_VARS],[HOST_ARCH]m4_foreach([cpu],[aarch64,arm,arm64ec,i386,x86_64], - [m4_foreach([var],[CC,CFLAGS,EXTRACFLAGS,LDFLAGS,DEBUG,TARGET,STRIP,DELAYLOADFLAG,DISABLED_SUBDIRS],[,cpu[_]var])])) + [m4_foreach([var],[CC,CXX,CFLAGS,CXXFLAGS,EXTRACFLAGS,EXTRACXXFLAGS,LDFLAGS,DEBUG,TARGET,STRIP,DELAYLOADFLAG,DISABLED_SUBDIRS],[,cpu[_]var])])) case $host_os in darwin*) @@ -446,6 +446,8 @@ do CPPFLAGS="" AS_VAR_SET_IF([${wine_arch}_CFLAGS],[],[AS_VAR_SET([${wine_arch}_CFLAGS],[${CROSSCFLAGS:-"-g -O2"}])]) AS_VAR_SET_IF([${wine_arch}_LDFLAGS],[],[AS_VAR_SET([${wine_arch}_LDFLAGS],[$CROSSLDFLAGS])]) + AS_VAR_SET_IF([${wine_arch}_CXX],[],[AS_VAR_COPY([${wine_arch}_CXX],[${wine_arch}_CC])]) + AS_VAR_SET_IF([${wine_arch}_CXXFLAGS],[],[AS_VAR_COPY([${wine_arch}_CXXFLAGS],[${wine_arch}_CFLAGS])]) AS_VAR_COPY([CC],[${wine_arch}_CC]) AS_VAR_COPY([CFLAGS],[${wine_arch}_CFLAGS]) AS_VAR_COPY([LDFLAGS],[${wine_arch}_LDFLAGS]) @@ -559,24 +561,20 @@ This is an error since --enable-archs=$wine_arch was requested.])]) WINE_TRY_PE_CFLAGS([-Werror=unused-command-line-argument],[CFLAGS="$CFLAGS -Werror=unused-command-line-argument"]) WINE_TRY_PE_CFLAGS([-Werror=ignored-optimization-argument],[CFLAGS="$CFLAGS -Werror=ignored-optimization-argument"]) WINE_TRY_PE_CFLAGS([-Werror=unsupported-floating-point-opt],[CFLAGS="$CFLAGS -Werror=unsupported-floating-point-opt"]) - WINE_TRY_PE_CFLAGS([-Wdeclaration-after-statement]) WINE_TRY_PE_CFLAGS([-Wempty-body]) WINE_TRY_PE_CFLAGS([-Wignored-qualifiers]) WINE_TRY_PE_CFLAGS([-Winit-self]) WINE_TRY_PE_CFLAGS([-Wpacked-not-aligned],[AS_VAR_APPEND(${wine_arch}_EXTRACFLAGS,[" -Wno-packed-not-aligned"])]) WINE_TRY_PE_CFLAGS([-Wmicrosoft-enum-forward-reference],[AS_VAR_APPEND(${wine_arch}_EXTRACFLAGS,[" -Wno-microsoft-enum-forward-reference"])]) WINE_TRY_PE_CFLAGS([-Wshift-overflow=2]) - WINE_TRY_PE_CFLAGS([-Wstrict-prototypes]) WINE_TRY_PE_CFLAGS([-Wtype-limits]) WINE_TRY_PE_CFLAGS([-Wunused-but-set-parameter]) WINE_TRY_PE_CFLAGS([-Wvla]) WINE_TRY_PE_CFLAGS([-Wwrite-strings]) WINE_TRY_PE_CFLAGS([-Wpointer-arith]) WINE_TRY_PE_CFLAGS([-Wlogical-op]) - WINE_TRY_PE_CFLAGS([-Wabsolute-value]) WINE_TRY_PE_CFLAGS([-Wenum-enum-conversion],[:],WINE_TRY_PE_CFLAGS([-Wenum-conversion])) WINE_TRY_PE_CFLAGS([-ffunction-sections]) - WINE_TRY_PE_CFLAGS([-fasync-exceptions -DMIN_CLANG_VERSION=19], AS_VAR_APPEND([${wine_arch}_EXTRACFLAGS],[" -fasync-exceptions"])) WINE_TRY_PE_CFLAGS([-ffp-exception-behavior=maytrap]) dnl clang had broken -fms-hotpatch support before version 18 (https://github.com/llvm/llvm-project/pull/77245) @@ -644,6 +642,13 @@ This is an error since --enable-archs=$wine_arch was requested.])]) dnl don't bother testing flags, compilation will fail afterwards test "x$enable_build_id" != xyes || AS_VAR_APPEND([${wine_arch}_LDFLAGS],[" -Wl,--build-id"]) + dnl Options that differ between C and C++ + AS_VAR_COPY([${wine_arch}_EXTRACXXFLAGS],[${wine_arch}_EXTRACFLAGS]) + WINE_TRY_PE_CFLAGS([-Wdeclaration-after-statement]) + WINE_TRY_PE_CFLAGS([-Wstrict-prototypes]) + WINE_TRY_PE_CFLAGS([-Wabsolute-value]) + WINE_TRY_PE_CFLAGS([-fasync-exceptions -DMIN_CLANG_VERSION=19], AS_VAR_APPEND([${wine_arch}_EXTRACFLAGS],[" -fasync-exceptions"])) + done CC=$saved_CC diff --git a/tools/make_makefiles b/tools/make_makefiles index 5e925855d55..48c390fca1d 100755 --- a/tools/make_makefiles +++ b/tools/make_makefiles @@ -252,7 +252,7 @@ sub assign_sources_to_makefiles(@) my $subdir = $dir; while ($dir && !defined $makefiles{"$dir/Makefile.in"}) { $dir = dirname( $dir ); } - $subdir =~ s/^$dir\/?//; + $subdir =~ s/^\Q$dir\E\/?//; next unless $dir; die "no makefile found for $file\n" unless defined $makefiles{"$dir/Makefile.in"}; @@ -291,7 +291,11 @@ sub assign_sources_to_makefiles(@) { next unless $dir eq "dlls/winewayland.drv"; } - elsif ($name !~ /\.(S|c|desktop|in|inl|l|m|mc|po|rc|rh|sfd|svg|ver|x|y)$/) + elsif ($name =~ /^msvcrt\/[^.]+$/) # C++ header without extension + { + next unless $dir eq "include"; + } + elsif ($name !~ /\.(S|c|cpp|desktop|in|inl|l|m|mc|po|rc|rh|sfd|svg|ver|x|y)$/) { next; } diff --git a/tools/makedep.c b/tools/makedep.c index 8c6d8d58b58..bc099c6f6cb 100644 --- a/tools/makedep.c +++ b/tools/makedep.c @@ -97,7 +97,8 @@ struct incl_file #define FLAG_SFD_FONTS 0x00400000 /* sfd file generated bitmap fonts */ #define FLAG_C_IMPLIB 0x01000000 /* file is part of an import library */ #define FLAG_C_UNIX 0x02000000 /* file is part of a Unix library */ -#define FLAG_ARM64EC_X64 0x04000000 /* use x86_64 object on ARM64EC */ +#define FLAG_C_CXX 0x04000000 /* file uses C++ */ +#define FLAG_ARM64EC_X64 0x08000000 /* use x86_64 object on ARM64EC */ static const struct { @@ -181,7 +182,7 @@ static const char *delay_load_flags[MAX_ARCHS]; static struct strarray debug_flags[MAX_ARCHS]; static struct strarray target_flags[MAX_ARCHS]; static struct strarray extra_cflags[MAX_ARCHS]; -static struct strarray extra_cflags_extlib[MAX_ARCHS]; +static struct strarray extra_cxxflags[MAX_ARCHS]; static struct strarray disabled_dirs[MAX_ARCHS]; static unsigned int native_archs[MAX_ARCHS]; static unsigned int hybrid_archs[MAX_ARCHS]; @@ -1140,6 +1141,16 @@ static void parse_c_file( struct file *source, FILE *file ) } +/******************************************************************* + * parse_cxx_file + */ +static void parse_cxx_file( struct file *source, FILE *file ) +{ + source->flags |= FLAG_C_CXX; + parse_c_file( source, file ); +} + + /******************************************************************* * parse_rc_file */ @@ -1256,6 +1267,9 @@ static const struct { ".x", parse_c_file }, { ".y", parse_c_file }, { ".idl", parse_idl_file }, + { ".cpp", parse_cxx_file }, + { ".hpp", parse_cxx_file }, + { ".ipp", parse_cxx_file }, { ".rc", parse_rc_file }, { ".ver", parse_rc_file }, { ".in", parse_in_file }, @@ -1287,6 +1301,12 @@ static struct file *load_file( const char *name ) parse_functions[i].parse( file, f ); break; } + if (i == ARRAY_SIZE(parse_functions)) + { + /* check for C++ header with no extension */ + char *dir = strstr( name, "/msvcrt/" ); + if (dir && !strchr( dir, '.' )) parse_cxx_file( file, f ); + } fclose( f ); input_file_name = NULL; @@ -1658,7 +1678,7 @@ static void parse_file( struct makefile *make, struct incl_file *source, bool sr if (strendswith( file->name, ".m" )) file->flags |= FLAG_C_UNIX; if (file->flags & FLAG_C_UNIX) source->use_msvcrt = false; - else if (file->flags & FLAG_C_IMPLIB) source->use_msvcrt = true; + else if (file->flags & (FLAG_C_IMPLIB | FLAG_C_CXX)) source->use_msvcrt = true; if (source->sourcename) { @@ -2128,6 +2148,10 @@ static void get_dependencies( struct incl_file *file, struct incl_file *source ) if (file != source) { if (file->owner == source) return; /* already processed */ + if (!(source->file->flags & FLAG_C_CXX)) /* ignore C++ dependencies for non-C++ sources */ + { + if (file->file && (file->file->flags & FLAG_C_CXX)) return; + } if (file->type == INCL_IMPORTLIB) { if (!(source->file->flags & (FLAG_IDL_TYPELIB | FLAG_IDL_REGTYPELIB))) @@ -3489,6 +3513,10 @@ static void output_source_one_arch( struct makefile *make, struct incl_file *sou { if (!unix_lib_supported) return; } + else if (source->file->flags & FLAG_C_CXX) + { + return; + } else if (archs.count > 1 && is_using_msvcrt( make )) { if (!so_dll_supported) return; @@ -3517,11 +3545,23 @@ static void output_source_one_arch( struct makefile *make, struct incl_file *sou strarray_add( &cflags, "-D__arm64ec_x64__" ); strarray_addall( &cflags, get_expanded_make_var_array( top_makefile, "x86_64_EXTRACFLAGS" )); } + else if (source->file->flags & FLAG_C_CXX) + { + var_cc = arch_make_variable( "CXX", arch ); + var_cflags = arch_make_variable( "CXXFLAGS", arch ); + if (make->external) + strarray_addall( &cflags, remove_warning_flags( extra_cxxflags[arch] )); + else + strarray_addall( &cflags, extra_cxxflags[arch] ); + } else { var_cc = arch_make_variable( "CC", arch ); var_cflags = arch_make_variable( "CFLAGS", arch ); - strarray_addall( &cflags, make->external ? extra_cflags_extlib[arch] : extra_cflags[arch] ); + if (make->external) + strarray_addall( &cflags, remove_warning_flags( extra_cflags[arch] )); + else + strarray_addall( &cflags, extra_cflags[arch] ); } if (!arch) @@ -3604,6 +3644,12 @@ static void output_source_one_arch( struct makefile *make, struct incl_file *sou cmd->cmd = get_expanded_make_variable( make, "x86_64_CC" ); if (cflags) strarray_add( &cmd->args, cflags ); } + else if (source->file->flags & FLAG_C_CXX) + { + char *cflags = get_expanded_arch_var( make, "CXXFLAGS", arch ); + cmd->cmd = get_expanded_arch_var( make, "CXX", arch ); + if (cflags) strarray_add( &cmd->args, cflags ); + } else { char *cflags = get_expanded_arch_var( make, "CFLAGS", arch ); @@ -4168,13 +4214,23 @@ static void output_sources( struct makefile *make ) char *obj = xstrdup( source->name ); char *ext = get_extension( obj ); - if (!ext) fatal_error( "unsupported file type %s\n", source->name ); - *ext++ = 0; + if (ext) + { + *ext++ = 0; - for (j = 0; output_source_funcs[j].ext; j++) - if (!strcmp( ext, output_source_funcs[j].ext )) break; + for (j = 0; output_source_funcs[j].ext; j++) + if (!strcmp( ext, output_source_funcs[j].ext )) break; + + output_source_funcs[j].fn( make, source, obj ); + } + else + { + if (source->file->flags & FLAG_C_CXX) + output_source_h( make, source, obj ); + else + fatal_error( "unsupported file type %s\n", source->name ); + } - output_source_funcs[j].fn( make, source, obj ); strarray_addall_uniq( &make->dependencies, source->dependencies ); } @@ -4950,7 +5006,7 @@ int main( int argc, char *argv[] ) { arch_pe_dirs[arch] = strmake( "%s-windows", archs.str[arch] ); extra_cflags[arch] = get_expanded_arch_var_array( top_makefile, "EXTRACFLAGS", arch ); - extra_cflags_extlib[arch] = remove_warning_flags( extra_cflags[arch] ); + extra_cxxflags[arch] = get_expanded_arch_var_array( top_makefile, "EXTRACXXFLAGS", arch ); disabled_dirs[arch] = get_expanded_arch_var_array( top_makefile, "DISABLED_SUBDIRS", arch ); if (!is_multiarch( arch )) continue; delay_load_flags[arch] = get_expanded_arch_var( top_makefile, "DELAYLOADFLAG", arch ); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10273
From: Alexandre Julliard <julliard@winehq.org> With help from Jacek Caban. --- aclocal.m4 | 884 ++++++++++++++++++++++++++++++++++++++++++++++++++- configure | 823 +++++++++++++++++++++++++++++++++++++++++++++++ configure.ac | 36 +++ 3 files changed, 1740 insertions(+), 3 deletions(-) diff --git a/aclocal.m4 b/aclocal.m4 index 873c707b657..11f8c855697 100644 --- a/aclocal.m4 +++ b/aclocal.m4 @@ -391,6 +391,884 @@ for msg in $wine_warnings; do done IFS="$ac_save_IFS"]) -dnl Local Variables: -dnl compile-command: "autoreconf --warnings=all" -dnl End: + +# C++ version tests copied from https://www.gnu.org/software/autoconf-archive/ax_cxx_compile_stdcxx.html +# +# LICENSE +# +# Copyright (c) 2008 Benjamin Kosnik <bkoz@redhat.com> +# Copyright (c) 2012 Zack Weinberg <zackw@panix.com> +# Copyright (c) 2013 Roy Stogner <roystgnr@ices.utexas.edu> +# Copyright (c) 2014, 2015 Google Inc.; contributed by Alexey Sokolov <sokolov@google.com> +# Copyright (c) 2015 Paul Norman <penorman@mac.com> +# Copyright (c) 2015 Moritz Klammler <moritz@klammler.eu> +# Copyright (c) 2016, 2018 Krzesimir Nowak <qdlacz@gmail.com> +# Copyright (c) 2019 Enji Cooper <yaneurabeya@gmail.com> +# Copyright (c) 2020 Jason Merrill <jason@redhat.com> +# Copyright (c) 2021, 2024 Jörn Heusipp <osmanx@problemloesungsmaschine.de> +# Copyright (c) 2015, 2022, 2023, 2024 Olly Betts +# +# Copying and distribution of this file, with or without modification, are +# permitted in any medium without royalty provided the copyright notice +# and this notice are preserved. This file is offered as-is, without any +# warranty. + +dnl Test body for checking C++11 support + +m4_define([_AX_CXX_COMPILE_STDCXX_testbody_11], + [_AX_CXX_COMPILE_STDCXX_testbody_new_in_11] +) + +dnl Test body for checking C++14 support + +m4_define([_AX_CXX_COMPILE_STDCXX_testbody_14], + [_AX_CXX_COMPILE_STDCXX_testbody_new_in_11 + _AX_CXX_COMPILE_STDCXX_testbody_new_in_14] +) + +dnl Test body for checking C++17 support + +m4_define([_AX_CXX_COMPILE_STDCXX_testbody_17], + [_AX_CXX_COMPILE_STDCXX_testbody_new_in_11 + _AX_CXX_COMPILE_STDCXX_testbody_new_in_14 + _AX_CXX_COMPILE_STDCXX_testbody_new_in_17] +) + +dnl Test body for checking C++20 support + +m4_define([_AX_CXX_COMPILE_STDCXX_testbody_20], + [_AX_CXX_COMPILE_STDCXX_testbody_new_in_11 + _AX_CXX_COMPILE_STDCXX_testbody_new_in_14 + _AX_CXX_COMPILE_STDCXX_testbody_new_in_17 + _AX_CXX_COMPILE_STDCXX_testbody_new_in_20] +) + +dnl Test body for checking C++23 support + +m4_define([_AX_CXX_COMPILE_STDCXX_testbody_23], + [_AX_CXX_COMPILE_STDCXX_testbody_new_in_11 + _AX_CXX_COMPILE_STDCXX_testbody_new_in_14 + _AX_CXX_COMPILE_STDCXX_testbody_new_in_17 + _AX_CXX_COMPILE_STDCXX_testbody_new_in_20 + _AX_CXX_COMPILE_STDCXX_testbody_new_in_23] +) + + +dnl Tests for new features in C++11 + +m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_11], [[ + +// If the compiler admits that it is not ready for C++11, why torture it? +// Hopefully, this will speed up the test. + +#ifndef __cplusplus + +#error "This is not a C++ compiler" + +// MSVC always sets __cplusplus to 199711L in older versions; newer versions +// only set it correctly if /Zc:__cplusplus is specified as well as a +// /std:c++NN switch: +// +// https://devblogs.microsoft.com/cppblog/msvc-now-correctly-reports-__cplusplu... +// +// The value __cplusplus ought to have is available in _MSVC_LANG since +// Visual Studio 2015 Update 3: +// +// https://learn.microsoft.com/en-us/cpp/preprocessor/predefined-macros +// +// This was also the first MSVC version to support C++14 so we can't use the +// value of either __cplusplus or _MSVC_LANG to quickly rule out MSVC having +// C++11 or C++14 support, but we can check _MSVC_LANG for C++17 and later. +#elif __cplusplus < 201103L && !defined _MSC_VER + +#error "This is not a C++11 compiler" + +#else + +namespace cxx11 +{ + + namespace test_static_assert + { + + template <typename T> + struct check + { + static_assert(sizeof(int) <= sizeof(T), "not big enough"); + }; + + } + + namespace test_final_override + { + + struct Base + { + virtual ~Base() {} + virtual void f() {} + }; + + struct Derived : public Base + { + virtual ~Derived() override {} + virtual void f() override {} + }; + + } + + namespace test_double_right_angle_brackets + { + + template < typename T > + struct check {}; + + typedef check<void> single_type; + typedef check<check<void>> double_type; + typedef check<check<check<void>>> triple_type; + typedef check<check<check<check<void>>>> quadruple_type; + + } + + namespace test_decltype + { + + int + f() + { + int a = 1; + decltype(a) b = 2; + return a + b; + } + + } + + namespace test_type_deduction + { + + template < typename T1, typename T2 > + struct is_same + { + static const bool value = false; + }; + + template < typename T > + struct is_same<T, T> + { + static const bool value = true; + }; + + template < typename T1, typename T2 > + auto + add(T1 a1, T2 a2) -> decltype(a1 + a2) + { + return a1 + a2; + } + + int + test(const int c, volatile int v) + { + static_assert(is_same<int, decltype(0)>::value == true, ""); + static_assert(is_same<int, decltype(c)>::value == false, ""); + static_assert(is_same<int, decltype(v)>::value == false, ""); + auto ac = c; + auto av = v; + auto sumi = ac + av + 'x'; + auto sumf = ac + av + 1.0; + static_assert(is_same<int, decltype(ac)>::value == true, ""); + static_assert(is_same<int, decltype(av)>::value == true, ""); + static_assert(is_same<int, decltype(sumi)>::value == true, ""); + static_assert(is_same<int, decltype(sumf)>::value == false, ""); + static_assert(is_same<int, decltype(add(c, v))>::value == true, ""); + return (sumf > 0.0) ? sumi : add(c, v); + } + + } + + namespace test_noexcept + { + + int f() { return 0; } + int g() noexcept { return 0; } + + static_assert(noexcept(f()) == false, ""); + static_assert(noexcept(g()) == true, ""); + + } + + namespace test_constexpr + { + + template < typename CharT > + unsigned long constexpr + strlen_c_r(const CharT *const s, const unsigned long acc) noexcept + { + return *s ? strlen_c_r(s + 1, acc + 1) : acc; + } + + template < typename CharT > + unsigned long constexpr + strlen_c(const CharT *const s) noexcept + { + return strlen_c_r(s, 0UL); + } + + static_assert(strlen_c("") == 0UL, ""); + static_assert(strlen_c("1") == 1UL, ""); + static_assert(strlen_c("example") == 7UL, ""); + static_assert(strlen_c("another\0example") == 7UL, ""); + + } + + namespace test_rvalue_references + { + + template < int N > + struct answer + { + static constexpr int value = N; + }; + + answer<1> f(int&) { return answer<1>(); } + answer<2> f(const int&) { return answer<2>(); } + answer<3> f(int&&) { return answer<3>(); } + + void + test() + { + int i = 0; + const int c = 0; + static_assert(decltype(f(i))::value == 1, ""); + static_assert(decltype(f(c))::value == 2, ""); + static_assert(decltype(f(0))::value == 3, ""); + } + + } + + namespace test_uniform_initialization + { + + struct test + { + static const int zero {}; + static const int one {1}; + }; + + static_assert(test::zero == 0, ""); + static_assert(test::one == 1, ""); + + } + + namespace test_lambdas + { + + void + test1() + { + auto lambda1 = [](){}; + auto lambda2 = lambda1; + lambda1(); + lambda2(); + } + + int + test2() + { + auto a = [](int i, int j){ return i + j; }(1, 2); + auto b = []() -> int { return '0'; }(); + auto c = [=](){ return a + b; }(); + auto d = [&](){ return c; }(); + auto e = [a, &b](int x) mutable { + const auto identity = [](int y){ return y; }; + for (auto i = 0; i < a; ++i) + a += b--; + return x + identity(a + b); + }(0); + return a + b + c + d + e; + } + + int + test3() + { + const auto nullary = [](){ return 0; }; + const auto unary = [](int x){ return x; }; + using nullary_t = decltype(nullary); + using unary_t = decltype(unary); + const auto higher1st = [](nullary_t f){ return f(); }; + const auto higher2nd = [unary](nullary_t f1){ + return [unary, f1](unary_t f2){ return f2(unary(f1())); }; + }; + return higher1st(nullary) + higher2nd(nullary)(unary); + } + + } + + namespace test_variadic_templates + { + + template <int...> + struct sum; + + template <int N0, int... N1toN> + struct sum<N0, N1toN...> + { + static constexpr auto value = N0 + sum<N1toN...>::value; + }; + + template <> + struct sum<> + { + static constexpr auto value = 0; + }; + + static_assert(sum<>::value == 0, ""); + static_assert(sum<1>::value == 1, ""); + static_assert(sum<23>::value == 23, ""); + static_assert(sum<1, 2>::value == 3, ""); + static_assert(sum<5, 5, 11>::value == 21, ""); + static_assert(sum<2, 3, 5, 7, 11, 13>::value == 41, ""); + + } + + // http://stackoverflow.com/questions/13728184/template-aliases-and-sfinae + // Clang 3.1 fails with headers of libstd++ 4.8.3 when using std::function + // because of this. + namespace test_template_alias_sfinae + { + + struct foo {}; + + template<typename T> + using member = typename T::member_type; + + template<typename T> + void func(...) {} + + template<typename T> + void func(member<T>*) {} + + void test(); + + void test() { func<foo>(0); } + + } + +} // namespace cxx11 + +#endif // __cplusplus >= 201103L + +]]) + + +dnl Tests for new features in C++14 + +m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_14], [[ + +// If the compiler admits that it is not ready for C++14, why torture it? +// Hopefully, this will speed up the test. + +#ifndef __cplusplus + +#error "This is not a C++ compiler" + +#elif __cplusplus < 201402L && !defined _MSC_VER + +#error "This is not a C++14 compiler" + +#else + +namespace cxx14 +{ + + namespace test_polymorphic_lambdas + { + + int + test() + { + const auto lambda = [](auto&&... args){ + const auto istiny = [](auto x){ + return (sizeof(x) == 1UL) ? 1 : 0; + }; + const int aretiny[] = { istiny(args)... }; + return aretiny[0]; + }; + return lambda(1, 1L, 1.0f, '1'); + } + + } + + namespace test_binary_literals + { + + constexpr auto ivii = 0b0000000000101010; + static_assert(ivii == 42, "wrong value"); + + } + + namespace test_generalized_constexpr + { + + template < typename CharT > + constexpr unsigned long + strlen_c(const CharT *const s) noexcept + { + auto length = 0UL; + for (auto p = s; *p; ++p) + ++length; + return length; + } + + static_assert(strlen_c("") == 0UL, ""); + static_assert(strlen_c("x") == 1UL, ""); + static_assert(strlen_c("test") == 4UL, ""); + static_assert(strlen_c("another\0test") == 7UL, ""); + + } + + namespace test_lambda_init_capture + { + + int + test() + { + auto x = 0; + const auto lambda1 = [a = x](int b){ return a + b; }; + const auto lambda2 = [a = lambda1(x)](){ return a; }; + return lambda2(); + } + + } + + namespace test_digit_separators + { + + constexpr auto ten_million = 100'000'000; + static_assert(ten_million == 100000000, ""); + + } + + namespace test_return_type_deduction + { + + auto f(int& x) { return x; } + decltype(auto) g(int& x) { return x; } + + template < typename T1, typename T2 > + struct is_same + { + static constexpr auto value = false; + }; + + template < typename T > + struct is_same<T, T> + { + static constexpr auto value = true; + }; + + int + test() + { + auto x = 0; + static_assert(is_same<int, decltype(f(x))>::value, ""); + static_assert(is_same<int&, decltype(g(x))>::value, ""); + return x; + } + + } + +} // namespace cxx14 + +#endif // __cplusplus >= 201402L + +]]) + + +dnl Tests for new features in C++17 + +m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_17], [[ + +// If the compiler admits that it is not ready for C++17, why torture it? +// Hopefully, this will speed up the test. + +#ifndef __cplusplus + +#error "This is not a C++ compiler" + +#elif (defined _MSVC_LANG ? _MSVC_LANG : __cplusplus) < 201703L + +#error "This is not a C++17 compiler" + +#else + +namespace cxx17 +{ + + namespace test_constexpr_lambdas + { + + constexpr int foo = [](){return 42;}(); + + } + + namespace test::nested_namespace::definitions + { + + } + + namespace test_fold_expression + { + + template<typename... Args> + int multiply(Args... args) + { + return (args * ... * 1); + } + + template<typename... Args> + bool all(Args... args) + { + return (args && ...); + } + + } + + namespace test_extended_static_assert + { + + static_assert (true); + + } + + namespace test_typename_in_template_template_parameter + { + + template<template<typename> typename X> struct D; + + } + + namespace test_fallthrough_nodiscard_maybe_unused_attributes + { + + int f1() + { + return 42; + } + + [[nodiscard]] int f2() + { + [[maybe_unused]] auto unused = f1(); + + switch (f1()) + { + case 17: + f1(); + [[fallthrough]]; + case 42: + f1(); + } + return f1(); + } + + } + + namespace test_extended_aggregate_initialization + { + + struct base1 + { + int b1, b2 = 42; + }; + + struct base2 + { + base2() { + b3 = 42; + } + int b3; + }; + + struct derived : base1, base2 + { + int d; + }; + + derived d1 {{1, 2}, {}, 4}; // full initialization + derived d2 {{}, {}, 4}; // value-initialized bases + + } + + namespace test_general_range_based_for_loop + { + + struct iter + { + int i; + + int& operator* () + { + return i; + } + + const int& operator* () const + { + return i; + } + + iter& operator++() + { + ++i; + return *this; + } + }; + + struct sentinel + { + int i; + }; + + bool operator== (const iter& i, const sentinel& s) + { + return i.i == s.i; + } + + bool operator!= (const iter& i, const sentinel& s) + { + return !(i == s); + } + + struct range + { + iter begin() const + { + return {0}; + } + + sentinel end() const + { + return {5}; + } + }; + + void f() + { + range r {}; + + for (auto i : r) + { + [[maybe_unused]] auto v = i; + } + } + + } + + namespace test_lambda_capture_asterisk_this_by_value + { + + struct t + { + int i; + int foo() + { + return [*this]() + { + return i; + }(); + } + }; + + } + + namespace test_enum_class_construction + { + + enum class byte : unsigned char + {}; + + byte foo {42}; + + } + + namespace test_constexpr_if + { + + template <bool cond> + int f () + { + if constexpr(cond) + { + return 13; + } + else + { + return 42; + } + } + + } + + namespace test_selection_statement_with_initializer + { + + int f() + { + return 13; + } + + int f2() + { + if (auto i = f(); i > 0) + { + return 3; + } + + switch (auto i = f(); i + 4) + { + case 17: + return 2; + + default: + return 1; + } + } + + } + + namespace test_template_argument_deduction_for_class_templates + { + + template <typename T1, typename T2> + struct pair + { + pair (T1 p1, T2 p2) + : m1 {p1}, + m2 {p2} + {} + + T1 m1; + T2 m2; + }; + + void f() + { + [[maybe_unused]] auto p = pair{13, 42u}; + } + + } + + namespace test_non_type_auto_template_parameters + { + + template <auto n> + struct B + {}; + + B<5> b1; + B<'a'> b2; + + } + + namespace test_exception_spec_type_system + { + + struct Good {}; + struct Bad {}; + + void g1() noexcept; + void g2(); + + template<typename T> + Bad + f(T*, T*); + + template<typename T1, typename T2> + Good + f(T1*, T2*); + + } + + namespace test_inline_variables + { + + template<class T> void f(T) + {} + + template<class T> inline T g(T) + { + return T{}; + } + + template<> inline void f<>(int) + {} + + template<> int g<>(int) + { + return 5; + } + + } + +} // namespace cxx17 + +#endif // (defined _MSVC_LANG ? _MSVC_LANG : __cplusplus) < 201703L + +]]) + + +dnl Tests for new features in C++20 + +m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_20], [[ + +#ifndef __cplusplus + +#error "This is not a C++ compiler" + +#elif (defined _MSVC_LANG ? _MSVC_LANG : __cplusplus) < 202002L + +#error "This is not a C++20 compiler" + +#else + +#include <version> + +namespace cxx20 +{ + +// As C++20 supports feature test macros in the standard, there is no +// immediate need to actually test for feature availability on the +// Autoconf side. + +} // namespace cxx20 + +#endif // (defined _MSVC_LANG ? _MSVC_LANG : __cplusplus) < 202002L + +]]) + + +dnl Tests for new features in C++23 + +m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_23], [[ + +#ifndef __cplusplus + +#error "This is not a C++ compiler" + +#elif (defined _MSVC_LANG ? _MSVC_LANG : __cplusplus) < 202302L + +#error "This is not a C++23 compiler" + +#else + +#include <version> + +namespace cxx23 +{ + +// As C++23 supports feature test macros in the standard, there is no +// immediate need to actually test for feature availability on the +// Autoconf side. + +} // namespace cxx23 + +#endif // (defined _MSVC_LANG ? _MSVC_LANG : __cplusplus) < 202302L + +]]) diff --git a/configure b/configure index 02649853799..23249d70e21 100755 --- a/configure +++ b/configure @@ -7390,8 +7390,10 @@ then : fi saved_CC=$CC +saved_CXX=$CXX saved_CFLAGS=$CFLAGS saved_CPPFLAGS=$CPPFLAGS +saved_CXXFLAGS=$CXXFLAGS saved_LDFLAGS=$LDFLAGS { extra_arch=; unset extra_arch;} @@ -7711,7 +7713,9 @@ else case e in #( esac fi eval CC=\$${wine_arch}_CC + eval CXX=\$${wine_arch}_CXX eval CFLAGS=\$${wine_arch}_CFLAGS + eval CXXFLAGS=\$${wine_arch}_CXXFLAGS eval LDFLAGS=\$${wine_arch}_LDFLAGS eval "${wine_arch}_EXTRACFLAGS=\"-D__WINE_PE_BUILD -Wall\"" @@ -7837,6 +7841,7 @@ fi } as_fn_append ${wine_arch}_EXTRACFLAGS " $llvm_extra_cflags" as_fn_append ${wine_arch}_LDFLAGS " $llvm_extra_ldflags" CFLAGS="$CFLAGS $llvm_extra_cflags $llvm_cflags" + CXXFLAGS="$CXXFLAGS $llvm_extra_cflags $llvm_cflags" else as_wine_cv_crosscc=`printf "%s\n" "wine_cv_${wine_arch}_crosscc" | sed "$as_sed_sh"` @@ -7944,6 +7949,822 @@ printf "%s\n" "$res" >&6; } as_fn_append ${wine_arch}_CC " $res" ;; esac + as_wine_cv_crosscxx_cxx17=`printf "%s\n" "ac_cv_${wine_arch}_crosscxx_cxx17" | sed "$as_sed_sh"` + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CXX option to enable C++17 features" >&5 +printf %s "checking for $CXX option to enable C++17 features... " >&6; } + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + +if eval test \${$as_wine_cv_crosscxx_cxx17+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) eval "$as_wine_cv_crosscxx_cxx17=no" + for arg in '' '-std=gnu++17' + do + test -z "$arg" || CXX="$CXX $arg" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + +// If the compiler admits that it is not ready for C++11, why torture it? +// Hopefully, this will speed up the test. + +#ifndef __cplusplus + +#error "This is not a C++ compiler" + +// MSVC always sets __cplusplus to 199711L in older versions; newer versions +// only set it correctly if /Zc:__cplusplus is specified as well as a +// /std:c++NN switch: +// +// https://devblogs.microsoft.com/cppblog/msvc-now-correctly-reports-__cplusplu... +// +// The value __cplusplus ought to have is available in _MSVC_LANG since +// Visual Studio 2015 Update 3: +// +// https://learn.microsoft.com/en-us/cpp/preprocessor/predefined-macros +// +// This was also the first MSVC version to support C++14 so we can't use the +// value of either __cplusplus or _MSVC_LANG to quickly rule out MSVC having +// C++11 or C++14 support, but we can check _MSVC_LANG for C++17 and later. +#elif __cplusplus < 201103L && !defined _MSC_VER + +#error "This is not a C++11 compiler" + +#else + +namespace cxx11 +{ + + namespace test_static_assert + { + + template <typename T> + struct check + { + static_assert(sizeof(int) <= sizeof(T), "not big enough"); + }; + + } + + namespace test_final_override + { + + struct Base + { + virtual ~Base() {} + virtual void f() {} + }; + + struct Derived : public Base + { + virtual ~Derived() override {} + virtual void f() override {} + }; + + } + + namespace test_double_right_angle_brackets + { + + template < typename T > + struct check {}; + + typedef check<void> single_type; + typedef check<check<void>> double_type; + typedef check<check<check<void>>> triple_type; + typedef check<check<check<check<void>>>> quadruple_type; + + } + + namespace test_decltype + { + + int + f() + { + int a = 1; + decltype(a) b = 2; + return a + b; + } + + } + + namespace test_type_deduction + { + + template < typename T1, typename T2 > + struct is_same + { + static const bool value = false; + }; + + template < typename T > + struct is_same<T, T> + { + static const bool value = true; + }; + + template < typename T1, typename T2 > + auto + add(T1 a1, T2 a2) -> decltype(a1 + a2) + { + return a1 + a2; + } + + int + test(const int c, volatile int v) + { + static_assert(is_same<int, decltype(0)>::value == true, ""); + static_assert(is_same<int, decltype(c)>::value == false, ""); + static_assert(is_same<int, decltype(v)>::value == false, ""); + auto ac = c; + auto av = v; + auto sumi = ac + av + 'x'; + auto sumf = ac + av + 1.0; + static_assert(is_same<int, decltype(ac)>::value == true, ""); + static_assert(is_same<int, decltype(av)>::value == true, ""); + static_assert(is_same<int, decltype(sumi)>::value == true, ""); + static_assert(is_same<int, decltype(sumf)>::value == false, ""); + static_assert(is_same<int, decltype(add(c, v))>::value == true, ""); + return (sumf > 0.0) ? sumi : add(c, v); + } + + } + + namespace test_noexcept + { + + int f() { return 0; } + int g() noexcept { return 0; } + + static_assert(noexcept(f()) == false, ""); + static_assert(noexcept(g()) == true, ""); + + } + + namespace test_constexpr + { + + template < typename CharT > + unsigned long constexpr + strlen_c_r(const CharT *const s, const unsigned long acc) noexcept + { + return *s ? strlen_c_r(s + 1, acc + 1) : acc; + } + + template < typename CharT > + unsigned long constexpr + strlen_c(const CharT *const s) noexcept + { + return strlen_c_r(s, 0UL); + } + + static_assert(strlen_c("") == 0UL, ""); + static_assert(strlen_c("1") == 1UL, ""); + static_assert(strlen_c("example") == 7UL, ""); + static_assert(strlen_c("another\0example") == 7UL, ""); + + } + + namespace test_rvalue_references + { + + template < int N > + struct answer + { + static constexpr int value = N; + }; + + answer<1> f(int&) { return answer<1>(); } + answer<2> f(const int&) { return answer<2>(); } + answer<3> f(int&&) { return answer<3>(); } + + void + test() + { + int i = 0; + const int c = 0; + static_assert(decltype(f(i))::value == 1, ""); + static_assert(decltype(f(c))::value == 2, ""); + static_assert(decltype(f(0))::value == 3, ""); + } + + } + + namespace test_uniform_initialization + { + + struct test + { + static const int zero {}; + static const int one {1}; + }; + + static_assert(test::zero == 0, ""); + static_assert(test::one == 1, ""); + + } + + namespace test_lambdas + { + + void + test1() + { + auto lambda1 = [](){}; + auto lambda2 = lambda1; + lambda1(); + lambda2(); + } + + int + test2() + { + auto a = [](int i, int j){ return i + j; }(1, 2); + auto b = []() -> int { return '0'; }(); + auto c = [=](){ return a + b; }(); + auto d = [&](){ return c; }(); + auto e = [a, &b](int x) mutable { + const auto identity = [](int y){ return y; }; + for (auto i = 0; i < a; ++i) + a += b--; + return x + identity(a + b); + }(0); + return a + b + c + d + e; + } + + int + test3() + { + const auto nullary = [](){ return 0; }; + const auto unary = [](int x){ return x; }; + using nullary_t = decltype(nullary); + using unary_t = decltype(unary); + const auto higher1st = [](nullary_t f){ return f(); }; + const auto higher2nd = [unary](nullary_t f1){ + return [unary, f1](unary_t f2){ return f2(unary(f1())); }; + }; + return higher1st(nullary) + higher2nd(nullary)(unary); + } + + } + + namespace test_variadic_templates + { + + template <int...> + struct sum; + + template <int N0, int... N1toN> + struct sum<N0, N1toN...> + { + static constexpr auto value = N0 + sum<N1toN...>::value; + }; + + template <> + struct sum<> + { + static constexpr auto value = 0; + }; + + static_assert(sum<>::value == 0, ""); + static_assert(sum<1>::value == 1, ""); + static_assert(sum<23>::value == 23, ""); + static_assert(sum<1, 2>::value == 3, ""); + static_assert(sum<5, 5, 11>::value == 21, ""); + static_assert(sum<2, 3, 5, 7, 11, 13>::value == 41, ""); + + } + + // http://stackoverflow.com/questions/13728184/template-aliases-and-sfinae + // Clang 3.1 fails with headers of libstd++ 4.8.3 when using std::function + // because of this. + namespace test_template_alias_sfinae + { + + struct foo {}; + + template<typename T> + using member = typename T::member_type; + + template<typename T> + void func(...) {} + + template<typename T> + void func(member<T>*) {} + + void test(); + + void test() { func<foo>(0); } + + } + +} // namespace cxx11 + +#endif // __cplusplus >= 201103L + + + + +// If the compiler admits that it is not ready for C++14, why torture it? +// Hopefully, this will speed up the test. + +#ifndef __cplusplus + +#error "This is not a C++ compiler" + +#elif __cplusplus < 201402L && !defined _MSC_VER + +#error "This is not a C++14 compiler" + +#else + +namespace cxx14 +{ + + namespace test_polymorphic_lambdas + { + + int + test() + { + const auto lambda = [](auto&&... args){ + const auto istiny = [](auto x){ + return (sizeof(x) == 1UL) ? 1 : 0; + }; + const int aretiny[] = { istiny(args)... }; + return aretiny[0]; + }; + return lambda(1, 1L, 1.0f, '1'); + } + + } + + namespace test_binary_literals + { + + constexpr auto ivii = 0b0000000000101010; + static_assert(ivii == 42, "wrong value"); + + } + + namespace test_generalized_constexpr + { + + template < typename CharT > + constexpr unsigned long + strlen_c(const CharT *const s) noexcept + { + auto length = 0UL; + for (auto p = s; *p; ++p) + ++length; + return length; + } + + static_assert(strlen_c("") == 0UL, ""); + static_assert(strlen_c("x") == 1UL, ""); + static_assert(strlen_c("test") == 4UL, ""); + static_assert(strlen_c("another\0test") == 7UL, ""); + + } + + namespace test_lambda_init_capture + { + + int + test() + { + auto x = 0; + const auto lambda1 = [a = x](int b){ return a + b; }; + const auto lambda2 = [a = lambda1(x)](){ return a; }; + return lambda2(); + } + + } + + namespace test_digit_separators + { + + constexpr auto ten_million = 100'000'000; + static_assert(ten_million == 100000000, ""); + + } + + namespace test_return_type_deduction + { + + auto f(int& x) { return x; } + decltype(auto) g(int& x) { return x; } + + template < typename T1, typename T2 > + struct is_same + { + static constexpr auto value = false; + }; + + template < typename T > + struct is_same<T, T> + { + static constexpr auto value = true; + }; + + int + test() + { + auto x = 0; + static_assert(is_same<int, decltype(f(x))>::value, ""); + static_assert(is_same<int&, decltype(g(x))>::value, ""); + return x; + } + + } + +} // namespace cxx14 + +#endif // __cplusplus >= 201402L + + + + +// If the compiler admits that it is not ready for C++17, why torture it? +// Hopefully, this will speed up the test. + +#ifndef __cplusplus + +#error "This is not a C++ compiler" + +#elif (defined _MSVC_LANG ? _MSVC_LANG : __cplusplus) < 201703L + +#error "This is not a C++17 compiler" + +#else + +namespace cxx17 +{ + + namespace test_constexpr_lambdas + { + + constexpr int foo = [](){return 42;}(); + + } + + namespace test::nested_namespace::definitions + { + + } + + namespace test_fold_expression + { + + template<typename... Args> + int multiply(Args... args) + { + return (args * ... * 1); + } + + template<typename... Args> + bool all(Args... args) + { + return (args && ...); + } + + } + + namespace test_extended_static_assert + { + + static_assert (true); + + } + + namespace test_typename_in_template_template_parameter + { + + template<template<typename> typename X> struct D; + + } + + namespace test_fallthrough_nodiscard_maybe_unused_attributes + { + + int f1() + { + return 42; + } + + [[nodiscard]] int f2() + { + [[maybe_unused]] auto unused = f1(); + + switch (f1()) + { + case 17: + f1(); + [[fallthrough]]; + case 42: + f1(); + } + return f1(); + } + + } + + namespace test_extended_aggregate_initialization + { + + struct base1 + { + int b1, b2 = 42; + }; + + struct base2 + { + base2() { + b3 = 42; + } + int b3; + }; + + struct derived : base1, base2 + { + int d; + }; + + derived d1 {{1, 2}, {}, 4}; // full initialization + derived d2 {{}, {}, 4}; // value-initialized bases + + } + + namespace test_general_range_based_for_loop + { + + struct iter + { + int i; + + int& operator* () + { + return i; + } + + const int& operator* () const + { + return i; + } + + iter& operator++() + { + ++i; + return *this; + } + }; + + struct sentinel + { + int i; + }; + + bool operator== (const iter& i, const sentinel& s) + { + return i.i == s.i; + } + + bool operator!= (const iter& i, const sentinel& s) + { + return !(i == s); + } + + struct range + { + iter begin() const + { + return {0}; + } + + sentinel end() const + { + return {5}; + } + }; + + void f() + { + range r {}; + + for (auto i : r) + { + [[maybe_unused]] auto v = i; + } + } + + } + + namespace test_lambda_capture_asterisk_this_by_value + { + + struct t + { + int i; + int foo() + { + return [*this]() + { + return i; + }(); + } + }; + + } + + namespace test_enum_class_construction + { + + enum class byte : unsigned char + {}; + + byte foo {42}; + + } + + namespace test_constexpr_if + { + + template <bool cond> + int f () + { + if constexpr(cond) + { + return 13; + } + else + { + return 42; + } + } + + } + + namespace test_selection_statement_with_initializer + { + + int f() + { + return 13; + } + + int f2() + { + if (auto i = f(); i > 0) + { + return 3; + } + + switch (auto i = f(); i + 4) + { + case 17: + return 2; + + default: + return 1; + } + } + + } + + namespace test_template_argument_deduction_for_class_templates + { + + template <typename T1, typename T2> + struct pair + { + pair (T1 p1, T2 p2) + : m1 {p1}, + m2 {p2} + {} + + T1 m1; + T2 m2; + }; + + void f() + { + [[maybe_unused]] auto p = pair{13, 42u}; + } + + } + + namespace test_non_type_auto_template_parameters + { + + template <auto n> + struct B + {}; + + B<5> b1; + B<'a'> b2; + + } + + namespace test_exception_spec_type_system + { + + struct Good {}; + struct Bad {}; + + void g1() noexcept; + void g2(); + + template<typename T> + Bad + f(T*, T*); + + template<typename T1, typename T2> + Good + f(T1*, T2*); + + } + + namespace test_inline_variables + { + + template<class T> void f(T) + {} + + template<class T> inline T g(T) + { + return T{}; + } + + template<> inline void f<>(int) + {} + + template<> int g<>(int) + { + return 5; + } + + } + +} // namespace cxx17 + +#endif // (defined _MSVC_LANG ? _MSVC_LANG : __cplusplus) < 201703L + + + +_ACEOF +if ac_fn_cxx_try_compile "$LINENO" +then : + eval "$as_wine_cv_crosscxx_cxx17=\$arg" +else case e in #( + e) eval "$as_wine_cv_crosscxx_cxx17=no" ;; +esac +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + eval CXX=\$${wine_arch}_CXX + if eval test \"x\$"$as_wine_cv_crosscxx_cxx17"\" = x"no" +then : + +else case e in #( + e) break ;; +esac +fi + done ;; +esac +fi + + eval res=\$$as_wine_cv_crosscxx_cxx17 + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + + case "x$res" in + x) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 +printf "%s\n" "none needed" >&6; } ;; + xno) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 +printf "%s\n" "unsupported" >&6; } + if test ${enable_archs+y} +then : + as_fn_error $? "$wine_arch PE cross-compiler supporting C++17 not found. +This is an error since --enable-archs=$wine_arch was requested." "$LINENO" 5 +fi + continue + ;; + x*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $res" >&5 +printf "%s\n" "$res" >&6; } + as_fn_append ${wine_arch}_CXX " $res" ;; + esac + if test "x$wine_arch" = xi386 then : @@ -9655,8 +10476,10 @@ fi } done CC=$saved_CC +CXX=$saved_CXX CFLAGS=$saved_CFLAGS CPPFLAGS=$saved_CPPFLAGS +CXXFLAGS=$saved_CXXFLAGS LDFLAGS=$saved_LDFLAGS case $HOST_ARCH in diff --git a/configure.ac b/configure.ac index a05f3e31e12..72b9a85929a 100644 --- a/configure.ac +++ b/configure.ac @@ -396,8 +396,10 @@ AS_VAR_SET_IF([enable_archs], AS_VAR_IF([PE_ARCHS],[none],[cross_archs=]) saved_CC=$CC +saved_CXX=$CXX saved_CFLAGS=$CFLAGS saved_CPPFLAGS=$CPPFLAGS +saved_CXXFLAGS=$CXXFLAGS saved_LDFLAGS=$LDFLAGS AS_UNSET(extra_arch) @@ -449,7 +451,9 @@ do AS_VAR_SET_IF([${wine_arch}_CXX],[],[AS_VAR_COPY([${wine_arch}_CXX],[${wine_arch}_CC])]) AS_VAR_SET_IF([${wine_arch}_CXXFLAGS],[],[AS_VAR_COPY([${wine_arch}_CXXFLAGS],[${wine_arch}_CFLAGS])]) AS_VAR_COPY([CC],[${wine_arch}_CC]) + AS_VAR_COPY([CXX],[${wine_arch}_CXX]) AS_VAR_COPY([CFLAGS],[${wine_arch}_CFLAGS]) + AS_VAR_COPY([CXXFLAGS],[${wine_arch}_CXXFLAGS]) AS_VAR_COPY([LDFLAGS],[${wine_arch}_LDFLAGS]) AS_VAR_SET([${wine_arch}_EXTRACFLAGS],["-D__WINE_PE_BUILD -Wall"]) @@ -495,6 +499,7 @@ do AS_VAR_APPEND([${wine_arch}_EXTRACFLAGS],[" $llvm_extra_cflags"]) AS_VAR_APPEND([${wine_arch}_LDFLAGS],[" $llvm_extra_ldflags"]) CFLAGS="$CFLAGS $llvm_extra_cflags $llvm_cflags" + CXXFLAGS="$CXXFLAGS $llvm_extra_cflags $llvm_cflags" else AS_VAR_PUSHDEF([wine_cv_crosscc], [wine_cv_${wine_arch}_crosscc]) AC_CACHE_CHECK([whether $CC works], wine_cv_crosscc, @@ -540,6 +545,35 @@ This is an error since --enable-archs=$wine_arch was requested.])]) AS_VAR_APPEND([${wine_arch}_CC],[" $res"]) ;; esac + AS_VAR_PUSHDEF([wine_cv_crosscxx_cxx17],[ac_cv_${wine_arch}_crosscxx_cxx17]) + AC_MSG_CHECKING([for $CXX option to enable C++17 features]) + AC_LANG_PUSH([C++]) + AC_CACHE_VAL([wine_cv_crosscxx_cxx17], + [AS_VAR_SET([wine_cv_crosscxx_cxx17],[no]) + for arg in '' '-std=gnu++17' + do + test -z "$arg" || CXX="$CXX $arg" + AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_17])], + [AS_VAR_SET([wine_cv_crosscxx_cxx17],[$arg])], + [AS_VAR_SET([wine_cv_crosscxx_cxx17],[no])]) + AS_VAR_COPY([CXX],[${wine_arch}_CXX]) + AS_VAR_IF([wine_cv_crosscxx_cxx17],[no],[],[break]) + done]) + AS_VAR_COPY([res],[wine_cv_crosscxx_cxx17]) + AC_LANG_POP([C++]) + AS_VAR_POPDEF([wine_cv_crosscxx_cxx17]) + case "x$res" in + x) AC_MSG_RESULT([none needed]) ;; + xno) AC_MSG_RESULT([unsupported]) + AS_VAR_SET_IF([enable_archs], + [AC_MSG_ERROR([$wine_arch PE cross-compiler supporting C++17 not found. +This is an error since --enable-archs=$wine_arch was requested.])]) + continue + ;; + x*) AC_MSG_RESULT([$res]) + AS_VAR_APPEND([${wine_arch}_CXX],[" $res"]) ;; + esac + AS_VAR_IF([wine_arch],[i386],[], [AS_VAR_PUSHDEF([wine_cv_seh_support],[ac_cv_${wine_arch}_seh_support]) AC_CACHE_CHECK([whether $CC supports SEH directives], wine_cv_seh_support, @@ -652,8 +686,10 @@ This is an error since --enable-archs=$wine_arch was requested.])]) done CC=$saved_CC +CXX=$saved_CXX CFLAGS=$saved_CFLAGS CPPFLAGS=$saved_CPPFLAGS +CXXFLAGS=$saved_CXXFLAGS LDFLAGS=$saved_LDFLAGS case $HOST_ARCH in -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10273
From: Jacek Caban <jacek@codeweavers.com> Based on libcxxabi. --- dlls/vcruntime140/Makefile.in | 3 +- dlls/vcruntime140/new.cpp | 170 ++++++++++++++++++++++++++++++++++ 2 files changed, 172 insertions(+), 1 deletion(-) create mode 100644 dlls/vcruntime140/new.cpp diff --git a/dlls/vcruntime140/Makefile.in b/dlls/vcruntime140/Makefile.in index 1f99225ffe8..715242c80ad 100644 --- a/dlls/vcruntime140/Makefile.in +++ b/dlls/vcruntime140/Makefile.in @@ -2,4 +2,5 @@ MODULE = vcruntime140.dll IMPORTLIB = vcruntime140 SOURCES = \ - misc.c + misc.c \ + new.cpp diff --git a/dlls/vcruntime140/new.cpp b/dlls/vcruntime140/new.cpp new file mode 100644 index 00000000000..ef3ce48f415 --- /dev/null +++ b/dlls/vcruntime140/new.cpp @@ -0,0 +1,170 @@ +//===--------------------- stdlib_new_delete.cpp --------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +// +// This file implements the new and delete operators. +//===----------------------------------------------------------------------===// + +#include <new.h> +#include <vcruntime_exception.h> +#include <malloc.h> + +#if 0 +#pragma makedep implib +#endif + +void *operator new(size_t size) +{ + if (size == 0) + size = 1; + void* p; + while ((p = ::malloc(size)) == 0) + { + if (!_callnewh(size)) + throw std::bad_alloc(); + } + return p; +} + +void *operator new(size_t size, const std::nothrow_t&) noexcept +{ + void* p = 0; + try + { + p = ::operator new(size); + } + catch (...) + { + } + return p; +} + +void *operator new[](size_t size) +{ + return ::operator new(size); +} + +void *operator new[](size_t size, const std::nothrow_t&) noexcept +{ + void* p = 0; + try + { + p = ::operator new[](size); + } + catch (...) + { + } + return p; +} + +void operator delete(void* ptr) noexcept +{ + if (ptr) + ::free(ptr); +} + +void operator delete(void* ptr, const std::nothrow_t&) noexcept +{ + ::operator delete(ptr); +} + +void operator delete(void* ptr, size_t) noexcept +{ + ::operator delete(ptr); +} + +void operator delete[] (void* ptr) noexcept +{ + ::operator delete(ptr); +} + +void operator delete[] (void* ptr, const std::nothrow_t&) noexcept +{ + ::operator delete[](ptr); +} + +void operator delete[] (void* ptr, size_t) noexcept +{ + ::operator delete[](ptr); +} + +void *operator new(size_t size, std::align_val_t alignment) +{ + if (size == 0) + size = 1; + if (static_cast<size_t>(alignment) < sizeof(void*)) + alignment = std::align_val_t(sizeof(void*)); + void* p; + while ((p = _aligned_malloc(size, static_cast<size_t>(alignment))) == nullptr) + { + if (!_callnewh(size)) + throw std::bad_alloc(); + } + return p; +} + +void *operator new(size_t size, std::align_val_t alignment, const std::nothrow_t&) noexcept +{ + void* p = 0; + try + { + p = ::operator new(size, alignment); + } + catch (...) + { + } + return p; +} + +void *operator new[](size_t size, std::align_val_t alignment) +{ + return ::operator new(size, alignment); +} + +void *operator new[](size_t size, std::align_val_t alignment, const std::nothrow_t&) noexcept +{ + void* p = 0; + try + { + p = ::operator new[](size, alignment); + } + catch (...) + { + } + return p; +} + +void operator delete(void* ptr, std::align_val_t) noexcept +{ + if (ptr) + ::_aligned_free(ptr); +} + +void operator delete(void* ptr, std::align_val_t alignment, const std::nothrow_t&) noexcept +{ + ::operator delete(ptr, alignment); +} + +void operator delete(void* ptr, size_t, std::align_val_t alignment) noexcept +{ + ::operator delete(ptr, alignment); +} + +void operator delete[] (void* ptr, std::align_val_t alignment) noexcept +{ + ::operator delete(ptr, alignment); +} + +void operator delete[] (void* ptr, std::align_val_t alignment, const std::nothrow_t&) noexcept +{ + ::operator delete[](ptr, alignment); +} + +void operator delete[] (void* ptr, size_t, std::align_val_t alignment) noexcept +{ + ::operator delete[](ptr, alignment); +} -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10273
From: Jacek Caban <jacek@codeweavers.com> --- dlls/vcruntime140/Makefile.in | 3 +- dlls/vcruntime140/typeinfo_root.cpp | 45 +++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+), 1 deletion(-) create mode 100644 dlls/vcruntime140/typeinfo_root.cpp diff --git a/dlls/vcruntime140/Makefile.in b/dlls/vcruntime140/Makefile.in index 715242c80ad..30231e1b074 100644 --- a/dlls/vcruntime140/Makefile.in +++ b/dlls/vcruntime140/Makefile.in @@ -3,4 +3,5 @@ IMPORTLIB = vcruntime140 SOURCES = \ misc.c \ - new.cpp + new.cpp \ + typeinfo_root.cpp diff --git a/dlls/vcruntime140/typeinfo_root.cpp b/dlls/vcruntime140/typeinfo_root.cpp new file mode 100644 index 00000000000..018c292ee3f --- /dev/null +++ b/dlls/vcruntime140/typeinfo_root.cpp @@ -0,0 +1,45 @@ +/* + * Copyright 2026 Jacek Caban for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#if 0 +#pragma makedep implib +#endif + +#ifdef _MSC_VER + +#include "windef.h" +#include "winnt.h" +#include "wine/asm.h" + +struct __type_info_node +{ + SLIST_HEADER list; +}; + +__type_info_node __type_info_root_node = {}; + +extern "C" void __cdecl __std_type_info_destroy_list(SLIST_HEADER*); + +extern "C" void __cdecl __wine_destroy_type_info_list(void) +{ + __std_type_info_destroy_list(&__type_info_root_node.list); +} + +__ASM_SECTION_POINTER( ".section .CRT$XTY", __wine_destroy_type_info_list ) + +#endif -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10273
From: Jacek Caban <jacek@codeweavers.com> --- dlls/vcruntime140/Makefile.in | 1 + dlls/vcruntime140/init_thread.c | 83 +++++++++++++++++++++++++++++++++ 2 files changed, 84 insertions(+) create mode 100644 dlls/vcruntime140/init_thread.c diff --git a/dlls/vcruntime140/Makefile.in b/dlls/vcruntime140/Makefile.in index 30231e1b074..a0004e52af6 100644 --- a/dlls/vcruntime140/Makefile.in +++ b/dlls/vcruntime140/Makefile.in @@ -2,6 +2,7 @@ MODULE = vcruntime140.dll IMPORTLIB = vcruntime140 SOURCES = \ + init_thread.c \ misc.c \ new.cpp \ typeinfo_root.cpp diff --git a/dlls/vcruntime140/init_thread.c b/dlls/vcruntime140/init_thread.c new file mode 100644 index 00000000000..6d73f85785f --- /dev/null +++ b/dlls/vcruntime140/init_thread.c @@ -0,0 +1,83 @@ +/* + * Thread-safe static constructor support functions. + * + * Copyright 2026 Jacek Caban for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#if 0 +#pragma makedep implib +#endif + +#ifdef __WINE_PE_BUILD + +#include <stdarg.h> +#include <limits.h> +#include "windef.h" +#include "winbase.h" + +static SRWLOCK init_lock; +static CONDITION_VARIABLE init_cv; + +int _Init_global_epoch = INT_MIN; +__thread int _Init_thread_epoch = INT_MIN; + +void _Init_thread_lock(void) +{ + AcquireSRWLockExclusive( &init_lock ); +} + +void _Init_thread_unlock(void) +{ + ReleaseSRWLockExclusive( &init_lock ); +} + +void _Init_thread_wait( DWORD timeout ) +{ + SleepConditionVariableSRW( &init_cv, &init_lock, timeout, 0 ); +} + +void _Init_thread_notify(void) +{ + WakeAllConditionVariable( &init_cv ); +} + +void _Init_thread_header( int *once ) +{ + _Init_thread_lock(); + while (*once == -1) _Init_thread_wait( INFINITE ); + if (*once) _Init_thread_epoch = _Init_global_epoch; + else *once = -1; + _Init_thread_unlock(); +} + +void _Init_thread_footer( int *once ) +{ + _Init_thread_lock(); + _Init_thread_epoch = *once = ++_Init_global_epoch; + _Init_thread_unlock(); + _Init_thread_notify(); +} + +void _Init_thread_abort( int *once ) +{ + _Init_thread_lock(); + *once = 0; + _Init_thread_unlock(); + _Init_thread_notify(); +} + +#endif -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10273
From: Jacek Caban <jacek@codeweavers.com> Clang does not generate RTTI/vtbl for this type. The vtable is referenced by ther classes’ RTTI. On MSVC, it is provided by the statically linked portion of vcruntime. --- dlls/vcruntime140/Makefile.in | 1 + dlls/vcruntime140/typeinfo.c | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+) create mode 100644 dlls/vcruntime140/typeinfo.c diff --git a/dlls/vcruntime140/Makefile.in b/dlls/vcruntime140/Makefile.in index a0004e52af6..f38bc1df6e5 100644 --- a/dlls/vcruntime140/Makefile.in +++ b/dlls/vcruntime140/Makefile.in @@ -5,4 +5,5 @@ SOURCES = \ init_thread.c \ misc.c \ new.cpp \ + typeinfo.c \ typeinfo_root.cpp diff --git a/dlls/vcruntime140/typeinfo.c b/dlls/vcruntime140/typeinfo.c new file mode 100644 index 00000000000..e5b59d85e29 --- /dev/null +++ b/dlls/vcruntime140/typeinfo.c @@ -0,0 +1,34 @@ +/* + * Copyright 2026 Jacek Caban for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#if 0 +#pragma makedep implib +#endif + +#ifdef __WINE_PE_BUILD + +#include <stdarg.h> +#include "../msvcrt/cxx.h" +#include "wine/asm.h" + +CREATE_TYPE_INFO_VTABLE + +asm( ".globl \"??_7type_info@@6B@\"\n" + "\"??_7type_info@@6B@\"=" __ASM_NAME("type_info_vtable") "\n" ); + +#endif -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10273
Martin Storsjö (@mstorsjo) commented about configure.ac:
target_strip=${target:-llvm}-strip if test "$wine_try_msvc" = yes -o -z "$target" then - llvm_target="$mingw_cpu-windows" + case $wine_arch in + arm) llvm_target="$mingw_cpu-windows-gnu" + llvm_cflags="-mconsole -Wl,--fatal-warnings" ;;
What's the reason for wanting to do this specifically only for 32 bit arm? Previously (up until a year ago), 32 bit arm builds in msvc mode didn't really work due to missing the compiler-rt libraries, but since those have been imported now, msvc mode builds should work equally fine there. Is there another reason involved here that I don't see? (It would be nice with motivation for changes like this in the commit messages.) -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10273#note_131571
Martin Storsjö (@mstorsjo) commented about tools/makedep.c:
+ else if (source->file->flags & FLAG_C_CXX) + { + var_cc = arch_make_variable( "CXX", arch ); + var_cflags = arch_make_variable( "CXXFLAGS", arch ); + if (make->external) + strarray_addall( &cflags, remove_warning_flags( extra_cxxflags[arch] )); + else + strarray_addall( &cflags, extra_cxxflags[arch] ); + } else { var_cc = arch_make_variable( "CC", arch ); var_cflags = arch_make_variable( "CFLAGS", arch ); - strarray_addall( &cflags, make->external ? extra_cflags_extlib[arch] : extra_cflags[arch] ); + if (make->external) + strarray_addall( &cflags, remove_warning_flags( extra_cflags[arch] )); If this would be a project that I maintain, I would request that a change like this (removing `extra_cflags_extlib` and changing how the warning flags are handled wrt that) would be split out into a separate patch - it seems like a slightly different change than the plain C++ support.
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/10273#note_131572
Martin Storsjö (@mstorsjo) commented about tools/make_makefiles:
my $subdir = $dir;
while ($dir && !defined $makefiles{"$dir/Makefile.in"}) { $dir = dirname( $dir ); } - $subdir =~ s/^$dir\/?//; + $subdir =~ s/^\Q$dir\E\/?//;
What does this change do, and is it strictly related to the C++ support? It seems like a different topic than the rest. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10273#note_131573
Martin Storsjö (@mstorsjo) commented about dlls/vcruntime140/new.cpp:
+// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +// +// This file implements the new and delete operators. +//===----------------------------------------------------------------------===// + +#include <new.h> +#include <vcruntime_exception.h> +#include <malloc.h> + +#if 0 +#pragma makedep implib +#endif + +void *operator new(size_t size) How does this change work, with respect to the external ABI of the DLLs? I see that msvcrt already exports e.g. `??_U@YAPEAX_K@Z` based on the implementation in `operator_new`, providing the MSVC C++ ABI interface, regardless of the build mode of the wine source. But if I understand this correctly, for vcruntime140, the operator new symbols are always linked statically - and this implementation matches the C++ ABI mode (mingw or msvc) of the PE build, suitable for static linking into the other PE build DLLs, but not visible on the external ABI surfaces. Is that the correct understanding? :-)
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/10273#note_131575
On Mon Mar 9 10:38:31 2026 +0000, Martin Storsjö wrote:
What does this change do, and is it strictly related to the C++ support? It seems like a different topic than the rest. It's to allow a directory name to contain wildcard chars, like `c++`.
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/10273#note_131576
On Mon Mar 9 10:47:34 2026 +0000, Martin Storsjö wrote:
How does this change work, with respect to the external ABI of the DLLs? I see that msvcrt already exports e.g. `??_U@YAPEAX_K@Z` based on the implementation in `operator_new`, providing the MSVC C++ ABI interface, regardless of the build mode of the wine source. But if I understand this correctly, for vcruntime140, the operator new symbols are always linked statically - and this implementation matches the C++ ABI mode (mingw or msvc) of the PE build, suitable for static linking into the other PE build DLLs, but not visible on the external ABI surfaces. Is that the correct understanding? :-) The plan is to only support MSVC mode for C++ Winelib builds. Mingw mode is already handled by Mingw.
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/10273#note_131577
On Mon Mar 9 10:32:07 2026 +0000, Martin Storsjö wrote:
What's the reason for wanting to do this specifically only for 32 bit arm? Previously (up until a year ago), 32 bit arm builds in msvc mode didn't really work due to missing the compiler-rt libraries, but since those have been imported now, msvc mode builds should work equally fine there. Is there another reason involved here that I don't see? (It would be nice with motivation for changes like this in the commit messages.) C++ exceptions are broken in MSVC mode on this target (even a trivial test case crashes the compiler), so at least in the current LLVM state, C++ is problematic there, while it seems to work fine in mingw mode.
Back then, one motivation for defaulting to msvc mode was to make it easier for packages to build, while using mingw target depended on a full llvm-mingw build. We have recently started building compiler-rt for mingw targets as well, so this change should not be a problem in that regard. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10273#note_131578
On Mon Mar 9 11:00:36 2026 +0000, Jacek Caban wrote:
C++ exceptions are broken in MSVC mode on this target (even a trivial test case crashes the compiler), so at least in the current LLVM state, C++ is problematic there, while it seems to work fine in mingw mode. Back then, one motivation for defaulting to msvc mode was to make it easier for packages to build, while using mingw target depended on a full llvm-mingw build. We have recently started building compiler-rt for mingw targets as well, so this change should not be a problem in that regard. Oh, right, that's true. Yes, the arm target is incomplete in msvc mode.
It would be nice to have this explained in the commit message. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10273#note_131582
On Mon Mar 9 10:38:31 2026 +0000, Martin Storsjö wrote:
If this would be a project that I maintain, I would request that a change like this (removing `extra_cflags_extlib` and changing how the warning flags are handled wrt that) would be split out into a separate patch - it seems like a slightly different change than the plain C++ support. It's a noop, it's just to make the code symmetric with the C++ case above it.
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/10273#note_131584
On Mon Mar 9 10:58:18 2026 +0000, Alexandre Julliard wrote:
The plan is to only support MSVC mode for C++ Winelib builds. Mingw mode is already handled by Mingw. To elaborate on that, some msvcrt versions export those operators, but modern MSVC provides them in a statically linked form, like this patch does. Cross-module ABI compatibility depends on using compatible versions of these operators in the participating modules. It helps that the actual work is delegated to the C runtime, using the malloc/free allocators and _callnewh for the new handler (although that part would also require something like https://github.com/llvm/llvm-project/pull/150182 on the libc++ side to be fully correct).
With this solution, it would not be possible to use Wine built in mingw mode to build C++ code in MSVC mode, or the other way around. We support that for the C runtime, but unfortunately C++ makes it impossible. Then, as Alexandre said, there is little reason to use Winelib in mingw mode. We will still need to support mingw mode for building Wine itself, but there are good open source mingw toolchains available for non-Wine code. An open source solution for MSVC mode is not available, so allowing that with Winelib seems worth it. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10273#note_131604
FWIW, the CI build failure seems to be caused by the configure cache. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10273#note_131605
This merge request was approved by Jacek Caban. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10273
On Mon Mar 9 21:20:25 2026 +0000, Jacek Caban wrote:
To elaborate on that, some msvcrt versions export those operators, but modern MSVC provides them in a statically linked form, like this patch does. Cross-module ABI compatibility depends on using compatible versions of these operators in the participating modules. It helps that the actual work is delegated to the C runtime, using the malloc/free allocators and _callnewh for the new handler (although that part would also require something like https://github.com/llvm/llvm-project/pull/150182 on the libc++ side to be fully correct). With this solution, it would not be possible to use Wine built in mingw mode to build C++ code in MSVC mode, or the other way around. We support that for the C runtime, but unfortunately C++ makes it impossible. Then, as Alexandre said, there is little reason to use Winelib in mingw mode. We will still need to support mingw mode for building Wine itself, but there are good open source mingw toolchains available for non-Wine code. An open source solution for MSVC mode is not available, so allowing that with Winelib seems worth it. Yeah, this sounds very reasonable to me. FWIW, I don't really have winelib use cases in mind at all (I barely remember that exists), just about what it means to potential build configurations of wine itself. And that winelib C++ usecases only works for the same build mode as wine itself sounds totally reasonable.
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/10273#note_131630
participants (5)
-
Alexandre Julliard -
Alexandre Julliard (@julliard) -
Jacek Caban -
Jacek Caban (@jacek) -
Martin Storsjö