This would hopefully fix some comctl32 test failures which started happening after I changed my nightly winetest runs to build Wine with Clang.
-- v3: winegcc: Force default subsystem version to MSVC modern values. user32/tests: Force console subsystem version 5.2. quartz/tests: Force console subsystem version 5.2. dxgi/tests: Force console subsystem version 5.2. comctl32/tests: Force console subsystem version 5.2. winegcc: Support subsystem version number in link.exe-style cmdline. winegcc: Set the default subsystem to console. winegcc: Consistently use the subsystem option with Clang and MinGW.
From: Rémi Bernon rbernon@codeweavers.com
Instead of the -mwindows / -mconsole flags with MinGW. --- tools/winegcc/winegcc.c | 31 +++++++++++-------------------- 1 file changed, 11 insertions(+), 20 deletions(-)
diff --git a/tools/winegcc/winegcc.c b/tools/winegcc/winegcc.c index 7322feaaf80..46a63453985 100644 --- a/tools/winegcc/winegcc.c +++ b/tools/winegcc/winegcc.c @@ -170,7 +170,6 @@ enum file_type { file_na, file_other, file_obj, file_res, file_rc, file_arh, fil static bool is_pe; static bool is_static; static bool is_shared; -static bool is_gui_app; static bool is_unicode_app; static bool is_win16_app; static bool is_arm64x; @@ -541,10 +540,9 @@ static struct strarray get_link_args( const char *output_name ) strarray_add( &flags, "-shared" ); strarray_add( &flags, "-Wl,--kill-at" ); } - else strarray_add( &flags, is_gui_app ? "-mwindows" : "-mconsole" );
if (is_unicode_app) strarray_add( &flags, "-municode" ); - if (subsystem) strarray_add( &flags, strmake("-Wl,--subsystem,%s", subsystem )); + if (subsystem) strarray_add( &flags, strmake( "-Wl,--subsystem,%s", subsystem ) );
strarray_add( &flags, "-Wl,--exclude-all-symbols" ); strarray_add( &flags, "-Wl,--nxcompat" ); @@ -600,10 +598,7 @@ static struct strarray get_link_args( const char *output_name )
if (entry_point) strarray_add( &flags, strmake( "-Wl,-entry:%s", entry_point ));
- if (subsystem) - strarray_add( &flags, strmake("-Wl,-subsystem:%s", subsystem )); - else - strarray_add( &flags, strmake("-Wl,-subsystem:%s", is_gui_app ? "windows" : "console" )); + if (subsystem) strarray_add( &flags, strmake( "-Wl,--subsystem:%s", subsystem ) );
STRARRAY_FOR_EACH( file, &output_debug_files ) { @@ -1137,13 +1132,14 @@ static void build_spec_obj( const char *spec_file, const char *output_file, strarray_add(&spec_args, output_name); }
- if (!is_shared) + if (subsystem) { - strarray_add(&spec_args, "--subsystem"); - strarray_add(&spec_args, is_gui_app ? "windows" : "console"); - if (large_address_aware) strarray_add( &spec_args, "--large-address-aware" ); + strarray_add( &spec_args, "--subsystem" ); + strarray_add( &spec_args, subsystem ); }
+ if (!is_shared && large_address_aware) strarray_add( &spec_args, "--large-address-aware" ); + if (target.platform == PLATFORM_WINDOWS && target.cpu == CPU_i386) strarray_add(&spec_args, "--safeseh");
@@ -1153,12 +1149,6 @@ static void build_spec_obj( const char *spec_file, const char *output_file, strarray_add(&spec_args, entry_point); }
- if (subsystem) - { - strarray_add(&spec_args, "--subsystem"); - strarray_add(&spec_args, subsystem); - } - if (!is_pe) STRARRAY_FOR_EACH( imp, &delayimports ) strarray_add(&spec_args, strmake("-d%s", imp));
strarray_addall( &spec_args, resources ); @@ -1318,7 +1308,7 @@ static void build(struct strarray input_files, const char *output)
if (!wine_objdir && !nodefaultlibs) { - if (is_gui_app) + if (subsystem && !strncmp( subsystem, "windows", 7 )) { add_library(lib_dirs, &files, "shell32"); add_library(lib_dirs, &files, "comdlg32"); @@ -1776,12 +1766,12 @@ int main(int argc, char **argv) } else if (strcmp("-mwindows", args.str[i]) == 0) { - is_gui_app = true; + subsystem = "windows"; raw_compiler_arg = 0; } else if (strcmp("-mconsole", args.str[i]) == 0) { - is_gui_app = false; + subsystem = "console"; raw_compiler_arg = 0; } else if (strcmp("-municode", args.str[i]) == 0) @@ -1856,6 +1846,7 @@ int main(int argc, char **argv) { is_shared = true; raw_compiler_arg = raw_linker_arg = 0; + if (!subsystem) subsystem = "console"; } else if (strcmp("-s", args.str[i]) == 0) {
From: Rémi Bernon rbernon@codeweavers.com
--- tools/winegcc/winegcc.c | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-)
diff --git a/tools/winegcc/winegcc.c b/tools/winegcc/winegcc.c index 46a63453985..65460937c54 100644 --- a/tools/winegcc/winegcc.c +++ b/tools/winegcc/winegcc.c @@ -542,7 +542,7 @@ static struct strarray get_link_args( const char *output_name ) }
if (is_unicode_app) strarray_add( &flags, "-municode" ); - if (subsystem) strarray_add( &flags, strmake( "-Wl,--subsystem,%s", subsystem ) ); + strarray_add( &flags, strmake( "-Wl,--subsystem,%s", subsystem ) );
strarray_add( &flags, "-Wl,--exclude-all-symbols" ); strarray_add( &flags, "-Wl,--nxcompat" ); @@ -598,7 +598,7 @@ static struct strarray get_link_args( const char *output_name )
if (entry_point) strarray_add( &flags, strmake( "-Wl,-entry:%s", entry_point ));
- if (subsystem) strarray_add( &flags, strmake( "-Wl,--subsystem:%s", subsystem ) ); + strarray_add( &flags, strmake( "-Wl,--subsystem:%s", subsystem ) );
STRARRAY_FOR_EACH( file, &output_debug_files ) { @@ -1132,11 +1132,8 @@ static void build_spec_obj( const char *spec_file, const char *output_file, strarray_add(&spec_args, output_name); }
- if (subsystem) - { - strarray_add( &spec_args, "--subsystem" ); - strarray_add( &spec_args, subsystem ); - } + strarray_add( &spec_args, "--subsystem" ); + strarray_add( &spec_args, subsystem );
if (!is_shared && large_address_aware) strarray_add( &spec_args, "--large-address-aware" );
@@ -1308,7 +1305,7 @@ static void build(struct strarray input_files, const char *output)
if (!wine_objdir && !nodefaultlibs) { - if (subsystem && !strncmp( subsystem, "windows", 7 )) + if (!strncmp( subsystem, "windows", 7 )) { add_library(lib_dirs, &files, "shell32"); add_library(lib_dirs, &files, "comdlg32"); @@ -1338,7 +1335,7 @@ static void build(struct strarray input_files, const char *output) /* set default entry point, if needed */ if (!entry_point) { - if (subsystem && !strcmp( subsystem, "native" )) + if (!strcmp( subsystem, "native" )) entry_point = (is_pe && target.cpu == CPU_i386) ? "DriverEntry@8" : "DriverEntry"; else if (use_msvcrt && !is_shared && !is_win16_app) entry_point = is_unicode_app ? "wmainCRTStartup" : "mainCRTStartup"; @@ -1621,6 +1618,7 @@ int main(int argc, char **argv) includedir = get_includedir( bindir ); target = init_argv0_target( argv[0] ); path_dirs = strarray_frompath( getenv( "PATH" )); + subsystem = "console";
/* setup tmp file removal at exit */ atexit(clean_temp_files); @@ -1846,7 +1844,6 @@ int main(int argc, char **argv) { is_shared = true; raw_compiler_arg = raw_linker_arg = 0; - if (!subsystem) subsystem = "console"; } else if (strcmp("-s", args.str[i]) == 0) {
From: Rémi Bernon rbernon@codeweavers.com
--- tools/winegcc/winegcc.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/tools/winegcc/winegcc.c b/tools/winegcc/winegcc.c index 65460937c54..c3618f16c21 100644 --- a/tools/winegcc/winegcc.c +++ b/tools/winegcc/winegcc.c @@ -495,6 +495,7 @@ static struct strarray get_link_args( const char *output_name ) { struct strarray link_args = get_translator(); struct strarray flags = empty_strarray; + char *version;
strarray_addall( &link_args, linker_args );
@@ -598,7 +599,9 @@ static struct strarray get_link_args( const char *output_name )
if (entry_point) strarray_add( &flags, strmake( "-Wl,-entry:%s", entry_point ));
- strarray_add( &flags, strmake( "-Wl,--subsystem:%s", subsystem ) ); + if ((version = strchr( subsystem, ':' ))) subsystem = strmake( "%.*s,%s", (int)(version - subsystem), subsystem, version + 1 ); + strarray_add( &flags, "-Xlinker" ); + strarray_add( &flags, strmake( "-subsystem:%s", subsystem ) );
STRARRAY_FOR_EACH( file, &output_debug_files ) {
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/comctl32/tests/Makefile.in | 1 + 1 file changed, 1 insertion(+)
diff --git a/dlls/comctl32/tests/Makefile.in b/dlls/comctl32/tests/Makefile.in index ee7fe6527fe..9c17acd77d7 100644 --- a/dlls/comctl32/tests/Makefile.in +++ b/dlls/comctl32/tests/Makefile.in @@ -1,5 +1,6 @@ TESTDLL = comctl32.dll IMPORTS = ole32 user32 gdi32 advapi32 imm32 uxtheme oleacc oleaut32 +EXTRADLLFLAGS = -Wl,--subsystem,console:5.2
SOURCES = \ animate.c \
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/dxgi/tests/Makefile.in | 1 + 1 file changed, 1 insertion(+)
diff --git a/dlls/dxgi/tests/Makefile.in b/dlls/dxgi/tests/Makefile.in index 43c7a55a88c..add3803ca40 100644 --- a/dlls/dxgi/tests/Makefile.in +++ b/dlls/dxgi/tests/Makefile.in @@ -1,5 +1,6 @@ TESTDLL = dxgi.dll IMPORTS = d3d10_1 dxgi user32 +EXTRADLLFLAGS = -Wl,--subsystem,console:5.2
SOURCES = \ dxgi.c
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/quartz/tests/Makefile.in | 1 + 1 file changed, 1 insertion(+)
diff --git a/dlls/quartz/tests/Makefile.in b/dlls/quartz/tests/Makefile.in index c3b96272fbf..1dd25efd19f 100644 --- a/dlls/quartz/tests/Makefile.in +++ b/dlls/quartz/tests/Makefile.in @@ -1,5 +1,6 @@ TESTDLL = quartz.dll IMPORTS = strmbase advapi32 d3d9 ddraw dsound msdmo msvfw32 ole32 oleaut32 user32 uuid winmm +EXTRADLLFLAGS = -Wl,--subsystem,console:5.2
SOURCES = \ acmwrapper.c \
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/user32/tests/Makefile.in | 1 + 1 file changed, 1 insertion(+)
diff --git a/dlls/user32/tests/Makefile.in b/dlls/user32/tests/Makefile.in index bff53de7713..4bc7172bdb9 100644 --- a/dlls/user32/tests/Makefile.in +++ b/dlls/user32/tests/Makefile.in @@ -1,5 +1,6 @@ TESTDLL = user32.dll IMPORTS = user32 gdi32 advapi32 hid imm32 setupapi +EXTRADLLFLAGS = -Wl,--subsystem,console:5.2
testdll_IMPORTS = user32
From: Rémi Bernon rbernon@codeweavers.com
--- tools/winegcc/winegcc.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-)
diff --git a/tools/winegcc/winegcc.c b/tools/winegcc/winegcc.c index c3618f16c21..2f611940030 100644 --- a/tools/winegcc/winegcc.c +++ b/tools/winegcc/winegcc.c @@ -1612,7 +1612,7 @@ int main(int argc, char **argv) int i, c, next_is_arg = 0; int raw_compiler_arg, raw_linker_arg, raw_winebuild_arg; struct strarray args = empty_strarray; - const char* option_arg; + const char* option_arg, *subsystem_version; char* str;
init_signals( exit_on_signal ); @@ -1621,7 +1621,8 @@ int main(int argc, char **argv) includedir = get_includedir( bindir ); target = init_argv0_target( argv[0] ); path_dirs = strarray_frompath( getenv( "PATH" )); - subsystem = "console"; + subsystem_version = target.cpu == CPU_i386 || target.cpu == CPU_x86_64 ? "6.0" : "6.2"; + subsystem = strmake( "console:%s", subsystem_version );
/* setup tmp file removal at exit */ atexit(clean_temp_files); @@ -1767,12 +1768,12 @@ int main(int argc, char **argv) } else if (strcmp("-mwindows", args.str[i]) == 0) { - subsystem = "windows"; + subsystem = strmake( "windows:%s", subsystem_version ); raw_compiler_arg = 0; } else if (strcmp("-mconsole", args.str[i]) == 0) { - subsystem = "console"; + subsystem = strmake( "console:%s", subsystem_version ); raw_compiler_arg = 0; } else if (strcmp("-municode", args.str[i]) == 0) @@ -1903,6 +1904,8 @@ int main(int argc, char **argv) if (!strcmp(Wl.str[j], "--subsystem") && j < Wl.count - 1) { subsystem = xstrdup( Wl.str[++j] ); + if (!strcmp( subsystem, "windows" ) || !strcmp( subsystem, "console" )) + subsystem = strmake( "%s:%s", subsystem, subsystem_version ); continue; } if (!strcmp(Wl.str[j], "--entry") && j < Wl.count - 1)
v2: Use modern MSVC subsystem version values by default, compile the broken tests with the explicit older version.
Jacek Caban (@jacek) commented about tools/winegcc/winegcc.c:
if (entry_point) strarray_add( &flags, strmake( "-Wl,-entry:%s", entry_point ));
if (subsystem)strarray_add( &flags, strmake("-Wl,-subsystem:%s", subsystem ));elsestrarray_add( &flags, strmake("-Wl,-subsystem:%s", is_gui_app ? "windows" : "console" ));
if (subsystem) strarray_add( &flags, strmake( "-Wl,--subsystem:%s", subsystem ) );
This should be `-subsystem`.
Jacek Caban (@jacek) commented about tools/winegcc/winegcc.c:
} else if (strcmp("-mwindows", args.str[i]) == 0) {
is_gui_app = true;
subsystem = "windows";
This loses version information if both `--subsystem` and `-mwindows` are used in an unfortunate order. We may be better off separating the version from the subsystem immediately and storing them separately.
Jacek Caban (@jacek) commented about tools/winegcc/winegcc.c:
includedir = get_includedir( bindir ); target = init_argv0_target( argv[0] ); path_dirs = strarray_frompath( getenv( "PATH" ));
- subsystem = "console";
- subsystem_version = target.cpu == CPU_i386 || target.cpu == CPU_x86_64 ? "6.0" : "6.2";
Can we just use a consistent value instead? For Wine usage, I suppose we’ll eventually want this to match the reported Windows version, but that might be a separate change. I’m not sure whether we’d want to adjust the defaults in winegcc or the build system for that.
On Tue Oct 21 11:00:10 2025 +0000, Jacek Caban wrote:
Can we just use a consistent value instead? For Wine usage, I suppose we’ll eventually want this to match the reported Windows version, but that might be a separate change. I’m not sure whether we’d want to adjust the defaults in winegcc or the build system for that.
Which version do you suggest should be the default? This is meant to match the table here: https://learn.microsoft.com/en-us/cpp/build/reference/subsystem-specify-subs...
On Tue Oct 21 11:00:10 2025 +0000, Jacek Caban wrote:
This loses version information if both `--subsystem` and `-mwindows` are used in an unfortunate order. We may be better off separating the version from the subsystem immediately and storing them separately.
Then what if command-line is like: `--subsystem=native:4.0 -mwindows`? Shouldn't `-mwindows` take over any previously set subsystem (which it does already) *and* its version?
On Tue Oct 21 11:36:57 2025 +0000, Rémi Bernon wrote:
Which version do you suggest should be the default? This is meant to match the table here: https://learn.microsoft.com/en-us/cpp/build/reference/subsystem-specify-subs...
Windows 10 components seem to use "10.0", so I’d be inclined to just use that. If it turns out not to work for some reason, LLD uses "6.0" on all targets anyway, so it should be fine to use that and drop the condition.
On Tue Oct 21 11:55:19 2025 +0000, Jacek Caban wrote:
Windows 10 components seem to use "10.0", so I’d be inclined to just use that. If it turns out not to work for some reason, LLD uses "6.0" on all targets anyway, so it should be fine to use that and drop the condition.
Ok, fwiw this only sets the "subsystem version" (as reported by winedump) in the PE header, not the "required OS version" or "image version". I don't know if there's compiler flags for these.
On Tue Oct 21 12:05:12 2025 +0000, Rémi Bernon wrote:
Ok, fwiw this only sets the "subsystem version" (as reported by winedump) in the PE header, not the "required OS version" or "image version". I don't know if there's compiler flags for these.
Also looks like using 10.0 causes Windows to fail to run the program with STATUS_INVALID_IMAGE_FORMAT, so I'll use 6.0 instead.