work is still in progress.
todo: - ensure that all affected sources (i.e. C sources with any kind of assembly) are listed in either way for all architectures - test Wine built with LTO
relevant bug reports: - https://bugs.winehq.org/show_bug.cgi?id=41712 - https://bugs.winehq.org/show_bug.cgi?id=51051
-- v3: fixups for LTO enabled build preliminary LTO support
From: Konstantin Demin rockdrilla@gmail.com
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=41712 Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=51051
Signed-off-by: Konstantin Demin rockdrilla@gmail.com --- configure.ac | 12 ++++ tools/makedep.c | 139 +++++++++++++++++++++++++++++++++++++++ tools/tools.h | 75 +++++++++++++++++++++ tools/winebuild/build.h | 1 + tools/winebuild/import.c | 39 ++++++++++- tools/winebuild/main.c | 6 +- tools/winebuild/utils.c | 22 ++++++- tools/winegcc/winegcc.c | 20 ++++++ 8 files changed, 308 insertions(+), 6 deletions(-)
diff --git a/configure.ac b/configure.ac index 5f9e63b6f9f..9774a8c29ba 100644 --- a/configure.ac +++ b/configure.ac @@ -24,6 +24,7 @@ AC_ARG_ENABLE(maintainer-mode, AS_HELP_STRING([--enable-maintainer-mode],[enable AC_ARG_ENABLE(sast, AS_HELP_STRING([--enable-sast],[enable static application security testing using Clang])) AC_ARG_ENABLE(silent-rules, AS_HELP_STRING([--enable-silent-rules],[use silent build rules (override: "make V=1")])) AC_ARG_ENABLE(werror, AS_HELP_STRING([--enable-werror],[treat compilation warnings as errors])) +AC_ARG_ENABLE(lto, AS_HELP_STRING([--enable-lto],[build with LTO (EXPERIMENTAL)]))
AC_ARG_WITH(alsa, AS_HELP_STRING([--without-alsa],[do not use the Alsa sound support])) AC_ARG_WITH(capi, AS_HELP_STRING([--without-capi],[do not use CAPI (ISDN support)])) @@ -803,6 +804,11 @@ do esac done
+if test "x$enable_lto" = xyes +then + AS_VAR_APPEND([EXTRACFLAGS],[" -D__WINE_LTO_BUILD"]) +fi + for wine_arch in $cross_archs $extra_arch do case "x$with_mingw" in @@ -837,6 +843,11 @@ do AS_VAR_COPY([LDFLAGS],[${wine_arch}_LDFLAGS]) AS_VAR_SET([${wine_arch}_EXTRACFLAGS],["-D__WINE_PE_BUILD -Wall"])
+ if test "x$enable_lto" = xyes + then + AS_VAR_APPEND([${wine_arch}_EXTRACFLAGS],[" -D__WINE_LTO_BUILD"]) + fi + target="" set x $CC shift @@ -2377,6 +2388,7 @@ AS_ECHO_N("creating Makefile rules...") >&AS_MESSAGE_FD
makedep_flags=" -C" test "x$enable_silent_rules" = xyes && makedep_flags="$makedep_flags -S" +test "x$enable_lto" = xyes && makedep_flags="$makedep_flags -L"
wine_srcdir= test "$srcdir" = . || wine_srcdir="$srcdir/" diff --git a/tools/makedep.c b/tools/makedep.c index c1937363c39..7c58e8b1c43 100644 --- a/tools/makedep.c +++ b/tools/makedep.c @@ -175,6 +175,7 @@ static struct strarray disabled_dirs[MAX_ARCHS]; static unsigned int native_archs[MAX_ARCHS]; static unsigned int hybrid_archs[MAX_ARCHS]; static struct strarray hybrid_target_flags[MAX_ARCHS]; +static struct strarray global_lto_skip[MAX_ARCHS];
struct makefile { @@ -229,6 +230,8 @@ struct makefile struct strarray res_files[MAX_ARCHS]; struct strarray all_targets[MAX_ARCHS]; struct strarray install_rules[NB_INSTALL_RULES]; + int lto_skip[MAX_ARCHS]; + struct strarray lto_skip_src[MAX_ARCHS]; };
static struct makefile *top_makefile; @@ -242,6 +245,7 @@ static const char *output_file_name; static const char *temp_file_name; static int compile_commands_mode; static int silent_rules; +static int with_lto = 0; static int input_line; static int output_column; static FILE *output_file; @@ -270,6 +274,13 @@ static void fatal_perror( const char *msg, ... ) __attribute__ ((__format__ (__p static void output( const char *format, ... ) __attribute__ ((__format__ (__printf__, 1, 2))); static char *strmake( const char* fmt, ... ) __attribute__ ((__format__ (__printf__, 1, 2)));
+static void parse_global_lto_skip_lists( void ); +static int is_lto_enabled_source( struct makefile *make, struct incl_file *source, unsigned int arch ); +static int is_lto_enabled_target( struct makefile *make, unsigned int arch ); +static void output_lto_flags( int use_lto, int use_env ); +static void output_lto_flags_source( struct makefile *make, struct incl_file *source, unsigned int arch, int use_env ); +static void output_lto_flags_target( struct makefile *make, unsigned int arch, int use_env ); + /******************************************************************* * fatal_error */ @@ -2439,6 +2450,7 @@ static const char *cmd_prefix( const char *cmd ) static void output_winegcc_command( struct makefile *make, unsigned int arch ) { output( "\t%s%s -o $@", cmd_prefix( "CCLD" ), tools_path( make, "winegcc" )); + output_lto_flags_target( make, arch, 0 /* use_env = FALSE */ ); output_filename( "--wine-objdir ." ); if (tools_dir) { @@ -3271,6 +3283,7 @@ static void output_source_one_arch( struct makefile *make, struct incl_file *sou output_filenames( defines ); output_filenames( cflags ); output_filename( var_cflags ); + output_lto_flags_source( make, source, arch, 1 /* use_env = TRUE */ ); output( "\n" );
if (make->testdll && strendswith( source->name, ".c" ) && @@ -3545,6 +3558,7 @@ static void output_import_lib( struct makefile *make, unsigned int arch ) if (hybrid_arch) output_filenames_obj_dir( make, make->implib_files[hybrid_arch] ); output( "\n" ); output( "\t%s%s -w --implib -o $@", cmd_prefix( "BUILD" ), tools_path( make, "winebuild" ) ); + output_lto_flags_target( make, arch, 0 /* use_env = FALSE */ ); if (!delay_load_flags[arch]) output_filename( "--without-dlltool" ); output_filenames( target_flags[hybrid_arch ? hybrid_arch : arch] ); if (make->is_win16) output_filename( "-m16" ); @@ -3579,6 +3593,7 @@ static void output_unix_lib( struct makefile *make ) output_filenames( unix_deps ); output( "\n" ); output( "\t%s$(CC) -o $@", cmd_prefix( "CCLD" )); + output_lto_flags_target( make, arch, 1 /* use_env = TRUE */ ); output_filenames( get_expanded_make_var_array( make, "UNIXLDFLAGS" )); output_filenames_obj_dir( make, make->unixobj_files ); output_filenames( unix_libs ); @@ -3604,6 +3619,7 @@ static void output_static_lib( struct makefile *make, unsigned int arch ) if (!arch) output_filenames_obj_dir( make, make->unixobj_files ); output( "\n" ); output( "\t%s%s -w --staticlib -o $@", cmd_prefix( "BUILD" ), tools_path( make, "winebuild" )); + output_lto_flags_target( make, arch, 0 /* use_env = FALSE */ ); output_filenames( target_flags[hybrid_arch ? hybrid_arch : arch] ); output_filenames_obj_dir( make, make->object_files[arch] ); if (hybrid_arch) output_filenames_obj_dir( make, make->object_files[hybrid_arch] ); @@ -3730,6 +3746,7 @@ static void output_programs( struct makefile *make ) output_filenames( deps ); output( "\n" ); output( "\t%s$(CC) -o $@", cmd_prefix( "CCLD" )); + output_lto_flags_target( make, arch, 1 /* use_env = TRUE */ ); output_filenames_obj_dir( make, objs ); output_filenames( all_libs ); output_filename( "$(LDFLAGS)" ); @@ -4490,6 +4507,22 @@ static void load_sources( struct makefile *make )
for (i = 0; i < make->delayimports.count; i++) strarray_add_uniq( &delay_import_libs, get_base_name( make->delayimports.str[i] )); + + if (with_lto) + { + for (arch = 0; arch < archs.count; arch++) + { + const char * lto_skip; + lto_skip = get_expanded_arch_var( make, "LTO_SKIP", arch ); + + make->lto_skip[arch] = var_to_bool(lto_skip); + + memset( &make->lto_skip_src[arch], 0, sizeof(struct strarray) ); + value = get_expanded_arch_var_array( make, "LTO_SKIP_SRC", arch ); + for (i = 0; i < value.count; i++) + strarray_add( &make->lto_skip_src[arch], xstrdup( value.str[i] )); + } + } }
@@ -4537,6 +4570,9 @@ static int parse_option( const char *opt ) case 'S': silent_rules = 1; break; + case 'L': + with_lto = 1; + break; default: fprintf( stderr, "Unknown option '%s'\n%s", opt, Usage ); exit(1); @@ -4679,6 +4715,7 @@ int main( int argc, char *argv[] )
for (i = 0; i < subdirs.count; i++) submakes[i] = parse_makefile( subdirs.str[i] );
+ parse_global_lto_skip_lists(); load_sources( top_makefile ); load_sources( include_makefile ); for (i = 0; i < subdirs.count; i++) @@ -4691,3 +4728,105 @@ int main( int argc, char *argv[] )
return 0; } + + +static void parse_global_lto_skip_lists( void ) +{ + unsigned int arch; + char *buffer; + FILE *file; + + if (!with_lto) return; + + for (arch = 0; arch < archs.count; arch++) + { + memset( &global_lto_skip[arch], 0, sizeof(struct strarray) ); + + input_file_name = root_src_dir_path( arch ? strmake( "tools/makedep.lto-skip.%s.list", archs.str[arch] ) : "tools/makedep.lto-skip.any.list" ); + input_line = 0; + if (!(file = fopen( input_file_name, "r" ))) + { + /* skip nonexistent files */ + input_file_name = NULL; + continue; + } + + while ((buffer = get_line( file ))) + { + if (*buffer == '#') continue; /* comment */ + buffer = skip_spaces( buffer ); + strarray_add( &global_lto_skip[arch], xstrdup( buffer )); + } + fclose( file ); + input_file_name = NULL; + } +} + +static int is_lto_enabled_source( struct makefile *make, struct incl_file *source, unsigned int arch ) +{ + if (!with_lto) return 0; + + /* target config */ + if (strarray_exists( &make->lto_skip_src[0], source->name )) + return 0; + + if (arch) + { + /* target config */ + if (strarray_exists( &make->lto_skip_src[arch], source->name )) + return 0; + + /* global config */ + if (strarray_exists( &global_lto_skip[arch], source->filename )) + return 0; + } + + /* global config */ + if (strarray_exists( &global_lto_skip[0], source->filename )) + return 0; + + return 1; +} + + +static int is_lto_enabled_target( struct makefile *make, unsigned int arch ) +{ + if (!with_lto) return 0; + + if (make->lto_skip[0]) return 0; + + if (arch && make->lto_skip[arch]) + return 0; + + return 1; +} + + +static void output_lto_flags( int use_lto, int use_env ) +{ + struct strarray lto_flags = empty_strarray; + append_lto_flags( <o_flags, use_lto, use_env ); + output_filenames( lto_flags ); +} + + +static void output_lto_flags_source( struct makefile *make, struct incl_file *source, unsigned int arch, int use_env ) +{ + int use_lto = 0; + + if (!with_lto) return; + + use_lto = is_lto_enabled_target( make, arch ) && is_lto_enabled_source( make, source, arch ); + output_lto_flags( use_lto, use_env ); +} + + +static void output_lto_flags_target( struct makefile *make, unsigned int arch, int use_env ) +{ + int use_lto = 0; + + if (!with_lto) return; + + use_lto = is_lto_enabled_target( make, arch ); + output_lto_flags( use_lto, use_env ); +} diff --git a/tools/tools.h b/tools/tools.h index b840a85b2e5..2a93938117f 100644 --- a/tools/tools.h +++ b/tools/tools.h @@ -949,4 +949,79 @@ static inline struct strarray parse_options( int argc, char **argv, const char * #undef OPT_ERR }
+__attribute__((used)) +static int var_to_bool( const char *var ) +{ + if (!var) return 0; + if (!( var[0] )) return 0; + + switch (var[0]) + { + /* "1" */ + case '1': + if (!var[1]) return 1; + break; + + /* "[Tt]", "[Tt][Rr][Uu][Ee]" */ + case 'T': /* -fallthrough */ + case 't': + if (!var[1]) return 1; + + if (strlen( var ) != 4) break; + if ((var[1] != 'R') && (var[1] != 'r')) break; + if ((var[2] != 'U') && (var[2] != 'u')) break; + if ((var[3] != 'E') && (var[3] != 'e')) break; + return 1; + + break; + + /* "[Yy]", "[Yy][Ee][Ss]" */ + case 'Y': /* -fallthrough */ + case 'y': + if (!var[1]) return 1; + + if (strlen( var ) != 3) break; + if ((var[1] != 'E') && (var[1] != 'e')) break; + if ((var[2] != 'S') && (var[2] != 's')) break; + return 1; + + break; + } + + return 0; +} + +__attribute__((used)) +static int adjust_verbose_lto( int with_lto, int verbose ) +{ + const char* lto_debug; + + if (with_lto < 1) return verbose; + if (verbose) return verbose; + + lto_debug = getenv("WINE_LTO_DEBUG"); + if (!lto_debug) return verbose; + if (!strlen( lto_debug )) return verbose; + + return var_to_bool(lto_debug); +} + +__attribute__((used)) +static void append_lto_flags( struct strarray *args, int with_lto, int use_env ) +{ + if (with_lto < 0) return; + + while (use_env > 0) + { + const char *flags = getenv( (with_lto) ? "WINE_LTO_FLAGS" : "WINE_LTO_SKIP_FLAGS" ); + if (!flags) break; + if (!strlen( flags )) break; + + strarray_addall( args, strarray_fromstring( flags, " " ) ); + return; + } + + strarray_add( args, with_lto ? "-flto" : "-fno-lto" ); +} + #endif /* __WINE_TOOLS_H */ diff --git a/tools/winebuild/build.h b/tools/winebuild/build.h index e5ede93425b..f6a57db1a2e 100644 --- a/tools/winebuild/build.h +++ b/tools/winebuild/build.h @@ -363,6 +363,7 @@ extern void put_pword( unsigned int val );
extern int current_line; extern int UsePIC; +extern int UseLTO; extern int nb_errors; extern int display_warnings; extern int kill_at; diff --git a/tools/winebuild/import.c b/tools/winebuild/import.c index 6aee0fa98f8..3223795e430 100644 --- a/tools/winebuild/import.c +++ b/tools/winebuild/import.c @@ -1241,11 +1241,27 @@ static const char *get_target_machine(void) /* build a library from the current asm files and any additional object files in argv */ void output_static_lib( const char *output_name, struct strarray files, int create ) { - struct strarray args; + struct strarray args = empty_strarray;
if (!create || target.platform != PLATFORM_WINDOWS) { - args = find_tool( "ar", NULL ); + while (UseLTO) + { + static const char * _cmd[2] = { 0 }; + if (!_cmd[0]) + { + const char *_ar = getenv( "WINE_LTO_AR" ); + if (!_ar) break; + if (!strlen( _ar )) break; + _cmd[0] = _ar; + } + args = find_tool( "ar", _cmd ); + break; + } + if (!args.count) + { + args = find_tool( "ar", NULL ); + } strarray_add( &args, create ? "rc" : "r" ); strarray_add( &args, output_name ); } @@ -1263,7 +1279,24 @@ void output_static_lib( const char *output_name, struct strarray files, int crea
if (target.platform != PLATFORM_WINDOWS) { - struct strarray ranlib = find_tool( "ranlib", NULL ); + struct strarray ranlib = empty_strarray; + while (UseLTO) + { + static const char * _cmd[2] = { 0 }; + if (!_cmd[0]) + { + const char *_ranlib = getenv( "WINE_LTO_RANLIB" ); + if (!_ranlib) break; + if (!strlen( _ranlib )) break; + _cmd[0] = _ranlib; + } + ranlib = find_tool( "ranlib", _cmd ); + break; + } + if (!ranlib.count) + { + ranlib = find_tool( "ranlib", NULL ); + } strarray_add( &ranlib, output_name ); spawn( ranlib ); } diff --git a/tools/winebuild/main.c b/tools/winebuild/main.c index 63d65e7bcd0..49331544822 100644 --- a/tools/winebuild/main.c +++ b/tools/winebuild/main.c @@ -34,6 +34,7 @@ #include "build.h"
int UsePIC = 0; +int UseLTO = -1; int nb_errors = 0; int display_warnings = 0; int native_arch = -1; @@ -185,7 +186,7 @@ static const char usage_str[] = " -e, --entry=FUNC Set the DLL entry point function (default: DllMain)\n" " -E, --export=FILE Export the symbols defined in the .spec or .def file\n" " --external-symbols Allow linking to external symbols\n" -" -f FLAGS Compiler flags (-fPIC and -fasynchronous-unwind-tables are supported)\n" +" -f FLAGS Compiler flags (-flto, -fPIC and -fasynchronous-unwind-tables are supported)\n" " -F, --filename=DLLFILE Set the DLL filename (default: from input file name)\n" " --fake-module Create a fake binary module\n" " -h, --help Display this help message\n" @@ -405,6 +406,8 @@ static void option_callback( int optc, char *optarg ) if (!strcmp( optarg, "PIC") || !strcmp( optarg, "pic")) UsePIC = 1; else if (!strcmp( optarg, "asynchronous-unwind-tables")) unwind_tables = 1; else if (!strcmp( optarg, "no-asynchronous-unwind-tables")) unwind_tables = 0; + else if (!strcmp( optarg, "lto" )) UseLTO = 1; + else if (!strcmp( optarg, "no-lto" )) UseLTO = 0; /* ignore all other flags */ break; case 'h': @@ -569,6 +572,7 @@ int main(int argc, char **argv) if (is_pe()) unwind_tables = 1;
files = parse_options( argc, argv, short_options, long_options, 0, option_callback ); + verbose = adjust_verbose_lto( UseLTO, verbose );
atexit( cleanup ); /* make sure we remove the output file on exit */
diff --git a/tools/winebuild/utils.c b/tools/winebuild/utils.c index 05595f86d37..bd016107232 100644 --- a/tools/winebuild/utils.c +++ b/tools/winebuild/utils.c @@ -303,6 +303,7 @@ struct strarray get_as_command(void)
if (using_cc) { + append_lto_flags( &args, (UseLTO == -1) ? -1 : 0, 1 /* use_env = TRUE */ ); strarray_add( &args, "-xassembler" ); strarray_add( &args, "-c" ); if (force_pointer_size) @@ -345,6 +346,7 @@ struct strarray get_ld_command(void) }
strarray_addall( &args, ld_command ); + append_lto_flags( &args, UseLTO, 1 /* use_env = TRUE */ );
if (force_pointer_size) { @@ -380,8 +382,24 @@ const char *get_nm_command(void) { if (!nm_command.count) { - static const char * const commands[] = { "nm", "gnm", NULL }; - nm_command = find_tool( "nm", commands ); + while (UseLTO) + { + static const char * _cmd[2] = { 0 }; + if (!_cmd[0]) + { + const char *_nm = getenv( "WINE_LTO_NM" ); + if (!_nm) break; + if (!strlen( _nm )) break; + _cmd[0] = _nm; + } + nm_command = find_tool( "nm", _cmd ); + break; + } + if (!nm_command.count) + { + static const char * const commands[] = { "nm", "gnm", NULL }; + nm_command = find_tool( "nm", commands ); + } } if (nm_command.count > 1) fatal_error( "multiple arguments in nm command not supported yet\n" ); diff --git a/tools/winegcc/winegcc.c b/tools/winegcc/winegcc.c index 5b60c57daf7..45f1cbd5c36 100644 --- a/tools/winegcc/winegcc.c +++ b/tools/winegcc/winegcc.c @@ -177,6 +177,7 @@ struct options int unwind_tables; int strip; int pic; + int lto; int no_default_config; int build_id; const char* wine_objdir; @@ -364,6 +365,7 @@ static struct strarray get_link_args( struct options *opts, const char *output_n struct strarray flags = empty_strarray;
strarray_addall( &link_args, opts->linker_args ); + append_lto_flags( &link_args, opts->lto, 1 /* use_env = TRUE */ );
if (verbose > 1) strarray_add( &flags, "-v" );
@@ -653,6 +655,17 @@ static void compile(struct options* opts, const char* lang) break; }
+ switch(opts->processor) + { + case proc_cc: /* -fallthrough */ + case proc_cxx: + append_lto_flags( &comp_args, opts->lto, 1 /* use_env = TRUE */ ); + break; + case proc_cpp: /* -fallthrough */ + case proc_as: + break; + } + if (opts->target.platform == PLATFORM_WINDOWS || opts->target.platform == PLATFORM_CYGWIN || opts->target.platform == PLATFORM_MINGW) @@ -835,6 +848,7 @@ static struct strarray get_winebuild_args( struct options *opts, const char *tar strarray_add( &spec_args, binary ); if (verbose) strarray_add( &spec_args, "-v" ); if (keep_generated) strarray_add( &spec_args, "--save-temps" ); + append_lto_flags( &spec_args, opts->lto, 0 /* use_env = FALSE */ ); if (target) { strarray_add( &spec_args, "--target" ); @@ -1502,6 +1516,7 @@ int main(int argc, char **argv) memset(&opts, 0, sizeof(opts)); opts.target = init_argv0_target( argv[0] ); opts.pic = 1; + opts.lto = -1;
/* determine the processor type */ if (strendswith(argv[0], "winecpp")) opts.processor = proc_cpp; @@ -1653,6 +1668,10 @@ int main(int argc, char **argv) opts.pic = 1; else if (!strcmp("-fno-PIC", opts.args.str[i]) || !strcmp("-fno-pic", opts.args.str[i])) opts.pic = 0; + else if (!strcmp( "-flto", opts.args.str[i] )) + opts.lto = 1; + else if (!strcmp( "-fno-lto", opts.args.str[i] )) + opts.lto = 0; break; case 'i': if (!strcmp( "-isysroot", opts.args.str[i] )) opts.isysroot = opts.args.str[i + 1]; @@ -1942,6 +1961,7 @@ int main(int argc, char **argv) strarray_add( &opts.files, opts.args.str[i] ); } } + verbose = adjust_verbose_lto( opts.lto, verbose );
if (opts.force_pointer_size) set_target_ptr_size( &opts.target, opts.force_pointer_size ); if (opts.processor == proc_cpp) linking = 0;
From: Konstantin Demin rockdrilla@gmail.com
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=41712 Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=51051
Signed-off-by: Konstantin Demin rockdrilla@gmail.com --- dlls/d3d8/Makefile.in | 3 +++ dlls/d3d9/Makefile.in | 3 +++ dlls/dbghelp/Makefile.in | 2 ++ dlls/ddraw/Makefile.in | 3 +++ dlls/hal/Makefile.in | 2 ++ dlls/hidclass.sys/Makefile.in | 2 ++ dlls/kernel32/Makefile.in | 4 ++++ dlls/kernelbase/Makefile.in | 5 +++++ dlls/krnl386.exe16/Makefile.in | 2 ++ dlls/mmsystem.dll16/Makefile.in | 2 ++ dlls/mshtml/Makefile.in | 3 +++ dlls/msi/Makefile.in | 2 ++ dlls/msvcirt/Makefile.in | 2 ++ dlls/msvcp60/Makefile.in | 2 ++ dlls/msvcp90/Makefile.in | 2 ++ dlls/ntoskrnl.exe/Makefile.in | 2 ++ dlls/ole32/Makefile.in | 2 ++ dlls/oleaut32/Makefile.in | 4 ++++ dlls/riched20/Makefile.in | 2 ++ dlls/rpcrt4/Makefile.in | 2 ++ dlls/system.drv16/Makefile.in | 2 ++ dlls/user32/Makefile.in | 2 ++ dlls/vcomp/Makefile.in | 4 ++++ dlls/win32u/Makefile.in | 4 ++++ dlls/win87em.dll16/Makefile.in | 2 ++ dlls/winebus.sys/Makefile.in | 2 ++ dlls/winecrt0/Makefile.in | 5 +++++ dlls/wineusb.sys/Makefile.in | 2 ++ dlls/winex11.drv/Makefile.in | 2 ++ dlls/winexinput.sys/Makefile.in | 2 ++ dlls/wow64/Makefile.in | 2 ++ dlls/wow64cpu/Makefile.in | 2 ++ dlls/xaudio2_7/Makefile.in | 2 ++ loader/Makefile.in | 3 +++ programs/rundll32/Makefile.in | 2 ++ programs/wineboot/Makefile.in | 3 +++ tools/makedep.lto-skip.any.list | 17 +++++++++++++++++ tools/makedep.lto-skip.i386.list | 11 +++++++++++ tools/makedep.lto-skip.x86_64.list | 3 +++ 39 files changed, 123 insertions(+) create mode 100644 tools/makedep.lto-skip.any.list create mode 100644 tools/makedep.lto-skip.i386.list create mode 100644 tools/makedep.lto-skip.x86_64.list
diff --git a/dlls/d3d8/Makefile.in b/dlls/d3d8/Makefile.in index 5a718b2d22d..1a2ec0c3357 100644 --- a/dlls/d3d8/Makefile.in +++ b/dlls/d3d8/Makefile.in @@ -14,3 +14,6 @@ SOURCES = \ version.rc \ vertexdeclaration.c \ volume.c + +i386_LTO_SKIP_SRC = device.c +x86_64_LTO_SKIP_SRC = device.c diff --git a/dlls/d3d9/Makefile.in b/dlls/d3d9/Makefile.in index 5a717b11863..d200933e3d1 100644 --- a/dlls/d3d9/Makefile.in +++ b/dlls/d3d9/Makefile.in @@ -16,3 +16,6 @@ SOURCES = \ version.rc \ vertexdeclaration.c \ volume.c + +i386_LTO_SKIP_SRC = device.c +x86_64_LTO_SKIP_SRC = device.c diff --git a/dlls/dbghelp/Makefile.in b/dlls/dbghelp/Makefile.in index 152ef80611a..1d3b1b163da 100644 --- a/dlls/dbghelp/Makefile.in +++ b/dlls/dbghelp/Makefile.in @@ -27,3 +27,5 @@ SOURCES = \ symbol.c \ type.c \ version.rc + +i386_LTO_SKIP_SRC = minidump.c diff --git a/dlls/ddraw/Makefile.in b/dlls/ddraw/Makefile.in index e6d6dddddef..c919424f588 100644 --- a/dlls/ddraw/Makefile.in +++ b/dlls/ddraw/Makefile.in @@ -17,3 +17,6 @@ SOURCES = \ version.rc \ vertexbuffer.c \ viewport.c + +i386_LTO_SKIP_SRC = device.c +x86_64_LTO_SKIP_SRC = device.c diff --git a/dlls/hal/Makefile.in b/dlls/hal/Makefile.in index 7e9928f0e57..12ead12f877 100644 --- a/dlls/hal/Makefile.in +++ b/dlls/hal/Makefile.in @@ -5,3 +5,5 @@ IMPORTS = ntoskrnl SOURCES = \ hal.c \ version.rc + +i386_LTO_SKIP = yes diff --git a/dlls/hidclass.sys/Makefile.in b/dlls/hidclass.sys/Makefile.in index 57a8fd79297..5179cc13193 100644 --- a/dlls/hidclass.sys/Makefile.in +++ b/dlls/hidclass.sys/Makefile.in @@ -6,3 +6,5 @@ SOURCES = \ device.c \ hidclass.rc \ pnp.c + +i386_LTO_SKIP_SRC = pnp.c diff --git a/dlls/kernel32/Makefile.in b/dlls/kernel32/Makefile.in index ca5bb437e24..d4782e01596 100644 --- a/dlls/kernel32/Makefile.in +++ b/dlls/kernel32/Makefile.in @@ -32,3 +32,7 @@ SOURCES = \ version.rc \ virtual.c \ volume.c + +i386_LTO_SKIP_SRC = process.c sync.c thread.c +x86_64_LTO_SKIP_SRC = module.c +arm64ec_LTO_SKIP_SRC = module.c diff --git a/dlls/kernelbase/Makefile.in b/dlls/kernelbase/Makefile.in index 081e9bfbb64..212c329415b 100644 --- a/dlls/kernelbase/Makefile.in +++ b/dlls/kernelbase/Makefile.in @@ -26,3 +26,8 @@ SOURCES = \ version.c \ volume.c \ winerror.mc + +LTO_SKIP_SRC = debug.c thread.c +i386_LTO_SKIP_SRC = sync.c +x86_64_LTO_SKIP_SRC = loader.c +arm64ec_LTO_SKIP_SRC = loader.c diff --git a/dlls/krnl386.exe16/Makefile.in b/dlls/krnl386.exe16/Makefile.in index 4251c83e158..38cf42bd9ce 100644 --- a/dlls/krnl386.exe16/Makefile.in +++ b/dlls/krnl386.exe16/Makefile.in @@ -35,3 +35,5 @@ SOURCES = \ version.rc \ vxd.c \ wowthunk.c + +LTO_SKIP_SRC = instr.c ne_module.c relay.c selector.c thunk.c wowthunk.c diff --git a/dlls/mmsystem.dll16/Makefile.in b/dlls/mmsystem.dll16/Makefile.in index 08334cb8f83..7638a7bbca7 100644 --- a/dlls/mmsystem.dll16/Makefile.in +++ b/dlls/mmsystem.dll16/Makefile.in @@ -9,3 +9,5 @@ SOURCES = \ message16.c \ mmio16.c \ mmsystem.c + +LTO_SKIP_SRC = mmsystem.c diff --git a/dlls/mshtml/Makefile.in b/dlls/mshtml/Makefile.in index bc712a202c5..957c60b5190 100644 --- a/dlls/mshtml/Makefile.in +++ b/dlls/mshtml/Makefile.in @@ -67,3 +67,6 @@ SOURCES = \ xmlhttprequest.c
nsembed_EXTRADEFS = -DINSTALL_DATADIR=""${datadir}"" + +i386_LTO_SKIP_SRC = ifacewrap.c nsembed.c +x86_64_LTO_SKIP_SRC = ifacewrap.c diff --git a/dlls/msi/Makefile.in b/dlls/msi/Makefile.in index 21420909a92..1c5c0cc9627 100644 --- a/dlls/msi/Makefile.in +++ b/dlls/msi/Makefile.in @@ -49,3 +49,5 @@ SOURCES = \ upgrade.c \ where.c \ winemsi.idl + +i386_LTO_SKIP_SRC = custom.c diff --git a/dlls/msvcirt/Makefile.in b/dlls/msvcirt/Makefile.in index 4f60ea36b3e..c0483368e50 100644 --- a/dlls/msvcirt/Makefile.in +++ b/dlls/msvcirt/Makefile.in @@ -6,3 +6,5 @@ IMPORTS = msvcrt SOURCES = \ exception.c \ msvcirt.c + +i386_LTO_SKIP_SRC = msvcirt.c diff --git a/dlls/msvcp60/Makefile.in b/dlls/msvcp60/Makefile.in index d7beeb0f989..cb4b828dd84 100644 --- a/dlls/msvcp60/Makefile.in +++ b/dlls/msvcp60/Makefile.in @@ -14,3 +14,5 @@ SOURCES = \ memory.c \ misc.c \ string.c + +i386_LTO_SKIP_SRC = main.c diff --git a/dlls/msvcp90/Makefile.in b/dlls/msvcp90/Makefile.in index 5438b518260..63281c4739f 100644 --- a/dlls/msvcp90/Makefile.in +++ b/dlls/msvcp90/Makefile.in @@ -12,3 +12,5 @@ SOURCES = \ misc.c \ msvcp_main.c \ string.c + +i386_LTO_SKIP_SRC = exception.c msvcp_main.c diff --git a/dlls/ntoskrnl.exe/Makefile.in b/dlls/ntoskrnl.exe/Makefile.in index a04a75e7f52..b69f8d49528 100644 --- a/dlls/ntoskrnl.exe/Makefile.in +++ b/dlls/ntoskrnl.exe/Makefile.in @@ -10,3 +10,5 @@ SOURCES = \ plugplay.idl \ pnp.c \ sync.c + +LTO_SKIP_SRC = instr.c ntoskrnl.c diff --git a/dlls/ole32/Makefile.in b/dlls/ole32/Makefile.in index ee0fcc41f7d..0132d1f8e9f 100644 --- a/dlls/ole32/Makefile.in +++ b/dlls/ole32/Makefile.in @@ -44,3 +44,5 @@ SOURCES = \ usrmarshal.c
dlldata_EXTRADEFS = -DENTRY_PREFIX=OLE32_ -DPROXY_CLSID=CLSID_PSFactoryBuffer -DWINE_REGISTER_DLL + +i386_LTO_SKIP_SRC = stg_prop.c diff --git a/dlls/oleaut32/Makefile.in b/dlls/oleaut32/Makefile.in index 1e85c4bd299..badaa07b559 100644 --- a/dlls/oleaut32/Makefile.in +++ b/dlls/oleaut32/Makefile.in @@ -25,3 +25,7 @@ SOURCES = \ vartype.c
dlldata_EXTRADEFS = -DENTRY_PREFIX=OLEAUTPS_ -DPROXY_DELEGATION -DWINE_REGISTER_DLL -DPROXY_CLSID=CLSID_PSFactoryBuffer + +LTO_SKIP_SRC = thunks.c +i386_LTO_SKIP_SRC = vartype.c +x86_64_LTO_SKIP_SRC = vartype.c diff --git a/dlls/riched20/Makefile.in b/dlls/riched20/Makefile.in index cd9d5ff63b1..808934144cc 100644 --- a/dlls/riched20/Makefile.in +++ b/dlls/riched20/Makefile.in @@ -27,3 +27,5 @@ SOURCES = \ version.rc \ wrap.c \ writer.c + +i386_LTO_SKIP_SRC = txthost.c txtsrv.c diff --git a/dlls/rpcrt4/Makefile.in b/dlls/rpcrt4/Makefile.in index 69f6961eff3..f0ebbc7b162 100644 --- a/dlls/rpcrt4/Makefile.in +++ b/dlls/rpcrt4/Makefile.in @@ -28,3 +28,5 @@ SOURCES = \ rpcrt4_main.c \ thunks.c \ version.rc + +LTO_SKIP_SRC = ndr_stubless.c thunks.c diff --git a/dlls/system.drv16/Makefile.in b/dlls/system.drv16/Makefile.in index 260bf957f10..26346994bb6 100644 --- a/dlls/system.drv16/Makefile.in +++ b/dlls/system.drv16/Makefile.in @@ -3,3 +3,5 @@ EXTRADLLFLAGS = -m16
SOURCES = \ system.c + +LTO_SKIP = yes diff --git a/dlls/user32/Makefile.in b/dlls/user32/Makefile.in index 69e1fa24e15..6006ef28825 100644 --- a/dlls/user32/Makefile.in +++ b/dlls/user32/Makefile.in @@ -68,3 +68,5 @@ SOURCES = \ winproc.c \ winstation.c \ wsprintf.c + +i386_LTO_SKIP_SRC = hook.c sysparams.c win.c winproc.c diff --git a/dlls/vcomp/Makefile.in b/dlls/vcomp/Makefile.in index ec1f82cc33b..d3dfb6e984c 100644 --- a/dlls/vcomp/Makefile.in +++ b/dlls/vcomp/Makefile.in @@ -3,3 +3,7 @@ MODULE = vcomp.dll SOURCES = \ fork.c \ main.c + +LTO_SKIP_SRC = fork.c +i386_LTO_SKIP = yes +x86_64_LTO_SKIP = yes diff --git a/dlls/win32u/Makefile.in b/dlls/win32u/Makefile.in index 6326a3cd302..9c1912ab3c8 100644 --- a/dlls/win32u/Makefile.in +++ b/dlls/win32u/Makefile.in @@ -56,3 +56,7 @@ SOURCES = \ vulkan.c \ window.c \ winstation.c + +LTO_SKIP_SRC = main.c +i386_LTO_SKIP_SRC = dibdrv/primitives.c winstation.c +x86_64_LTO_SKIP_SRC = dibdrv/primitives.c winstation.c diff --git a/dlls/win87em.dll16/Makefile.in b/dlls/win87em.dll16/Makefile.in index 03bf1b5853b..2636f3e1205 100644 --- a/dlls/win87em.dll16/Makefile.in +++ b/dlls/win87em.dll16/Makefile.in @@ -3,3 +3,5 @@ EXTRADLLFLAGS = -m16
SOURCES = \ win87em.c + +LTO_SKIP = yes diff --git a/dlls/winebus.sys/Makefile.in b/dlls/winebus.sys/Makefile.in index db32faee5b3..a24aa9ba97e 100644 --- a/dlls/winebus.sys/Makefile.in +++ b/dlls/winebus.sys/Makefile.in @@ -14,3 +14,5 @@ SOURCES = \ main.c \ unixlib.c \ winebus.rc + +i386_LTO_SKIP_SRC = main.c diff --git a/dlls/winecrt0/Makefile.in b/dlls/winecrt0/Makefile.in index 863e5ed4190..df8818a31d5 100644 --- a/dlls/winecrt0/Makefile.in +++ b/dlls/winecrt0/Makefile.in @@ -21,3 +21,8 @@ SOURCES = \ setjmp.c \ stub.c \ unix_lib.c + +LTO_SKIP_SRC = setjmp.c +i386_LTO_SKIP_SRC = exception.c +x86_64_LTO_SKIP_SRC = exception.c +arm64ec_LTO_SKIP_SRC = arm64ec.c unix_lib.c diff --git a/dlls/wineusb.sys/Makefile.in b/dlls/wineusb.sys/Makefile.in index 0c6bb77f143..d4d58d5554b 100644 --- a/dlls/wineusb.sys/Makefile.in +++ b/dlls/wineusb.sys/Makefile.in @@ -10,3 +10,5 @@ SOURCES = \ unixlib.c \ wineusb.c \ wineusb.rc + +i386_LTO_SKIP_SRC = wineusb.c diff --git a/dlls/winex11.drv/Makefile.in b/dlls/winex11.drv/Makefile.in index 9806dd350e9..1e814929d37 100644 --- a/dlls/winex11.drv/Makefile.in +++ b/dlls/winex11.drv/Makefile.in @@ -29,3 +29,5 @@ SOURCES = \ xrandr.c \ xrender.c \ xvidmode.c + +i386_LTO_SKIP_SRC = opengl.c diff --git a/dlls/winexinput.sys/Makefile.in b/dlls/winexinput.sys/Makefile.in index 64241631552..c07b7b8bd9f 100644 --- a/dlls/winexinput.sys/Makefile.in +++ b/dlls/winexinput.sys/Makefile.in @@ -5,3 +5,5 @@ EXTRADLLFLAGS = -Wl,--subsystem,native SOURCES = \ main.c \ winexinput.rc + +i386_LTO_SKIP = yes diff --git a/dlls/wow64/Makefile.in b/dlls/wow64/Makefile.in index b58b6eb803a..76a3cae7290 100644 --- a/dlls/wow64/Makefile.in +++ b/dlls/wow64/Makefile.in @@ -13,3 +13,5 @@ SOURCES = \ syscall.c \ system.c \ virtual.c + +LTO_SKIP_SRC = syscall.c diff --git a/dlls/wow64cpu/Makefile.in b/dlls/wow64cpu/Makefile.in index b06fc8f9f64..26b1d61087f 100644 --- a/dlls/wow64cpu/Makefile.in +++ b/dlls/wow64cpu/Makefile.in @@ -5,3 +5,5 @@ EXTRADLLFLAGS = -nodefaultlibs -Wl,--image-base,0x7a400000
SOURCES = \ cpu.c + +LTO_SKIP = yes diff --git a/dlls/xaudio2_7/Makefile.in b/dlls/xaudio2_7/Makefile.in index 0d88bfe6dd3..6ae757c9c47 100644 --- a/dlls/xaudio2_7/Makefile.in +++ b/dlls/xaudio2_7/Makefile.in @@ -10,3 +10,5 @@ SOURCES = \ xaudio_allocator.c \ xaudio_classes.idl \ xaudio_dll.c + +i386_LTO_SKIP_SRC = xaudio_dll.c diff --git a/loader/Makefile.in b/loader/Makefile.in index 191ab81e1d2..f9fde87d669 100644 --- a/loader/Makefile.in +++ b/loader/Makefile.in @@ -33,3 +33,6 @@ wine_preloader_LDFLAGS = $(WINEPRELOADER_LDFLAGS) wine64_preloader_OBJS = preloader.o preloader_mac.o wine64_preloader_DEPS = $(WINELOADER_DEPENDS) wine64_preloader_LDFLAGS = $(WINEPRELOADER_LDFLAGS) + +# LTO_SKIP_SRC = preloader.c preloader_mac.c +LTO_SKIP = yes diff --git a/programs/rundll32/Makefile.in b/programs/rundll32/Makefile.in index f2aa9742e36..d2ddc87cc02 100644 --- a/programs/rundll32/Makefile.in +++ b/programs/rundll32/Makefile.in @@ -5,3 +5,5 @@ EXTRADLLFLAGS = -mwindows -municode
SOURCES = \ rundll32.c + +i386_LTO_SKIP = yes diff --git a/programs/wineboot/Makefile.in b/programs/wineboot/Makefile.in index 0983420a91f..81f31dc945d 100644 --- a/programs/wineboot/Makefile.in +++ b/programs/wineboot/Makefile.in @@ -9,3 +9,6 @@ SOURCES = \ wineboot.c \ wineboot.man.in \ wineboot.rc + +i386_LTO_SKIP_SRC = wineboot.c +x86_64_LTO_SKIP_SRC = wineboot.c diff --git a/tools/makedep.lto-skip.any.list b/tools/makedep.lto-skip.any.list new file mode 100644 index 00000000000..e24fec819e0 --- /dev/null +++ b/tools/makedep.lto-skip.any.list @@ -0,0 +1,17 @@ +dlls/msvcrt/except_arm.c +dlls/msvcrt/except_arm64.c +dlls/msvcrt/except_arm64ec.c +dlls/msvcrt/except_i386.c +dlls/msvcrt/except_x86_64.c +dlls/msvcrt/math.c +dlls/ntdll/relay.c +dlls/ntdll/signal_arm.c +dlls/ntdll/signal_arm64.c +dlls/ntdll/signal_arm64ec.c +dlls/ntdll/signal_i386.c +dlls/ntdll/signal_x86_64.c +dlls/ntdll/unix/signal_arm.c +dlls/ntdll/unix/signal_arm64.c +dlls/ntdll/unix/signal_i386.c +dlls/ntdll/unix/signal_x86_64.c +dlls/ntdll/unix/system.c diff --git a/tools/makedep.lto-skip.i386.list b/tools/makedep.lto-skip.i386.list new file mode 100644 index 00000000000..2147073a594 --- /dev/null +++ b/tools/makedep.lto-skip.i386.list @@ -0,0 +1,11 @@ +dlls/dinput/dinput.c +dlls/msvcrt/exception_ptr.c +dlls/msvcrt/file.c +dlls/msvcrt/misc.c +dlls/msvcrt/string.c +dlls/ntdll/large_int.c +dlls/ntdll/loader.c +dlls/ntdll/math.c +dlls/ntdll/resource.c +dlls/ntdll/rtl.c +dlls/ntdll/unix/loader.c diff --git a/tools/makedep.lto-skip.x86_64.list b/tools/makedep.lto-skip.x86_64.list new file mode 100644 index 00000000000..2edd78cfab4 --- /dev/null +++ b/tools/makedep.lto-skip.x86_64.list @@ -0,0 +1,3 @@ +dlls/msvcrt/string.c +dlls/ntdll/loader.c +dlls/ntdll/process.c
@insn I'd prefer to fix existing code instead of quirking build chain but it's very sophisticated.
E.g. I'm unable to build working/sane object file from `dlls/winecrt0/setjmp.c` with LTO enabled due to further linking issues like `undefined reference to '__wine_setjmpex'`.
Proposed change (doesn't work though): ```diff --- a/dlls/winecrt0/setjmp.c +++ b/dlls/winecrt0/setjmp.c @@ -25,6 +25,22 @@
#if defined(__GNUC__) || defined(__clang__)
+#if (defined(__i386__) || defined(__x86_64__) || defined(__arm__) || defined(__aarch64__)) && !defined(__arm64ec__) +__attribute__((used)) +extern int __cdecl __wine_setjmpex( __wine_jmp_buf *buf, EXCEPTION_REGISTRATION_RECORD *frame ); +__attribute__((used)) +extern void __cdecl __wine_longjmp( __wine_jmp_buf *buf, int retval ); +#endif + +#ifdef __WINE_LTO_BUILD +__attribute__((used)) +static void __wine_lto_fixup( void ) +{ + (void) __wine_setjmpex( NULL, NULL ); + __wine_longjmp( NULL, 0 ); +} +#endif + #if defined(__i386__)
__ASM_GLOBAL_FUNC( __wine_setjmpex, ```
On Thu Jan 23 20:01:19 2025 +0000, Konstantin Demin wrote:
@insn I'd prefer to fix existing code instead of quirking build chain but it's very sophisticated. E.g. I'm unable to build working/sane object file from `dlls/winecrt0/setjmp.c` with LTO enabled due to further linking issues like `undefined reference to '__wine_setjmpex'`. Proposed change (doesn't work though):
--- a/dlls/winecrt0/setjmp.c +++ b/dlls/winecrt0/setjmp.c @@ -25,6 +25,22 @@ #if defined(__GNUC__) || defined(__clang__) +#if (defined(__i386__) || defined(__x86_64__) || defined(__arm__) || defined(__aarch64__)) && !defined(__arm64ec__) +__attribute__((used)) +extern int __cdecl __wine_setjmpex( __wine_jmp_buf *buf, EXCEPTION_REGISTRATION_RECORD *frame ); +__attribute__((used)) +extern void __cdecl __wine_longjmp( __wine_jmp_buf *buf, int retval ); +#endif + +#ifdef __WINE_LTO_BUILD +__attribute__((used)) +static void __wine_lto_fixup( void ) +{ + (void) __wine_setjmpex( NULL, NULL ); + __wine_longjmp( NULL, 0 ); +} +#endif + #if defined(__i386__) __ASM_GLOBAL_FUNC( __wine_setjmpex,
Yeah, LTO is broken with ASM_GLOBAL_FUNC. GCC doesn't parse the asm, so it doesn't know they're defined. When importing a library with an API having same name, it will pull it from the library since it can't find it defined yet. Later, when it actually assembles and links the code (the real link stage, not LTO), it will find two definitions of the API: the ASM_GLOBAL_FUNC one and the one imported.
The issue with winecrt0 is different. When importing a static library it looks to see if any imports are needed from one of its object files. But setjmp.o contains some ASM_GLOBAL_FUNCs so it won't import it because it can't "see" them, so it thinks it's not needed. That's why it gives undefined reference.
I think it's OK to remove LTO for specific object files. But you used it way too much, it should only be needed for like 3-4 modules AFAIK, those with ASM_GLOBAL_FUNC only. The others can be fixed in the code.
On Thu Jan 23 20:01:19 2025 +0000, Gabriel Ivăncescu wrote:
Yeah, LTO is broken with ASM_GLOBAL_FUNC. GCC doesn't parse the asm, so it doesn't know they're defined. When importing a library with an API having same name, it will pull it from the library since it can't find it defined yet. Later, when it actually assembles and links the code (the real link stage, not LTO), it will find two definitions of the API: the ASM_GLOBAL_FUNC one and the one imported. The issue with winecrt0 is different. When importing a static library it looks to see if any imports are needed from one of its object files. But setjmp.o contains some ASM_GLOBAL_FUNCs so it won't import it because it can't "see" them, so it thinks it's not needed. That's why it gives undefined reference. I think it's OK to remove LTO for specific object files. But you used it way too much, it should only be needed for like 3-4 modules AFAIK, those with ASM_GLOBAL_FUNC only. The others can be fixed in the code.
To be fair, I mean ASM_GLOBAL_FUNC **exports** (or in static libraries, which are implicit exports). If the function is not exported, it's not necessary to disable LTO.
On Thu Jan 23 20:02:19 2025 +0000, Gabriel Ivăncescu wrote:
To be fair, I mean ASM_GLOBAL_FUNC **exports** (or in static libraries, which are implicit exports). If the function is not exported, it's not necessary to disable LTO.
Also see MR !7119
On Thu Jan 23 20:04:20 2025 +0000, Gabriel Ivăncescu wrote:
Also see MR !7119
@insn thanks, I've seen !7119 that's why I've tried once more to fix some parts of code in order to increase LTO "coverage".