On MSVC, building hybrid ARM64X images requires executing linker directly, with `-machine:arm64x` option, there is not way to use the compiler as a linker driver in such case.
Clang git version has `-marm64x` option now, which allows using it as a linker driver for ARM64X builds. This MR adds a similar option to winegcc and winebuild. For winegcc, we need to build spec file objects for both targets (native and EC). winebuild uses a new llvm-dlltool option `-N`, which works like MSVC lib.exe's `/defArm64Native` and allows passing .def files for both targets to generate a hybrid import library.
From: Jacek Caban jacek@codeweavers.com
--- tools/winebuild/build.h | 4 +++- tools/winebuild/import.c | 16 ++++++++++++++-- tools/winebuild/main.c | 4 +++- tools/winebuild/parser.c | 12 ++++++------ tools/winebuild/spec32.c | 5 ++--- tools/winebuild/utils.c | 2 ++ 6 files changed, 30 insertions(+), 13 deletions(-)
diff --git a/tools/winebuild/build.h b/tools/winebuild/build.h index a469a0e9042..b857e05aa14 100644 --- a/tools/winebuild/build.h +++ b/tools/winebuild/build.h @@ -162,6 +162,7 @@ typedef struct int unicode_app; /* default to unicode entry point */ ORDDEF *entry_points; /* spec entry points */ struct exports exports; /* dll exports */ + struct exports native_exports; /* dll native exports */ struct resource *resources; /* array of dll resources (format differs between Win16/Win32) */ struct apiset apiset; /* list of defined api sets */ } DLLSPEC; @@ -327,7 +328,7 @@ extern void output_bin_resources( DLLSPEC *spec, unsigned int start_rva ); extern void output_spec32_file( DLLSPEC *spec ); extern void output_fake_module( DLLSPEC *spec ); extern void output_data_module( DLLSPEC *spec ); -extern void output_def_file( DLLSPEC *spec, int import_only ); +extern void output_def_file( DLLSPEC *spec, struct exports *exports, int import_only ); extern void output_apiset_lib( DLLSPEC *spec, const struct apiset *apiset ); extern void load_res16_file( const char *name, DLLSPEC *spec ); extern void output_res16_data( DLLSPEC *spec ); @@ -372,6 +373,7 @@ extern int force_pointer_size; extern int unwind_tables; extern int use_dlltool; extern int use_msvcrt; +extern int native_arch; extern int safe_seh; extern int prefer_native; extern int data_only; diff --git a/tools/winebuild/import.c b/tools/winebuild/import.c index 9cefb2afdfe..1ca2048284b 100644 --- a/tools/winebuild/import.c +++ b/tools/winebuild/import.c @@ -1377,19 +1377,31 @@ void output_static_lib( const char *output_name, struct strarray files, int crea /* create a Windows-style import library using dlltool */ static void build_dlltool_import_lib( const char *lib_name, DLLSPEC *spec, struct strarray files ) { + const char *def_file, *native_def_file = NULL; struct strarray args; - char *def_file;
def_file = open_temp_output_file( ".def" ); - output_def_file( spec, 1 ); + output_def_file( spec, &spec->exports, 1 ); fclose( output_file );
+ if (native_arch != -1) + { + native_def_file = open_temp_output_file( ".def" ); + output_def_file( spec, &spec->native_exports, 1 ); + fclose( output_file ); + } + args = find_tool( "dlltool", NULL ); strarray_add( &args, "-k" ); strarray_add( &args, strendswith( lib_name, ".delay.a" ) ? "-y" : "-l" ); strarray_add( &args, lib_name ); strarray_add( &args, "-d" ); strarray_add( &args, def_file ); + if (native_def_file) + { + strarray_add( &args, "-N" ); + strarray_add( &args, native_def_file ); + }
switch (target.cpu) { diff --git a/tools/winebuild/main.c b/tools/winebuild/main.c index 71e61522578..dc2992b5c51 100644 --- a/tools/winebuild/main.c +++ b/tools/winebuild/main.c @@ -36,6 +36,7 @@ int UsePIC = 0; int nb_errors = 0; int display_warnings = 0; +int native_arch = -1; int kill_at = 0; int verbose = 0; int link_ext_symbols = 0; @@ -386,6 +387,7 @@ static void option_callback( int optc, char *optarg ) else if (!strcmp( optarg, "64" )) force_pointer_size = 8; else if (!strcmp( optarg, "no-cygwin" )) use_msvcrt = 1; else if (!strcmp( optarg, "unicode" )) main_spec->unicode_app = 1; + else if (!strcmp( optarg, "arm64x" )) native_arch = CPU_ARM64; else if (!strncmp( optarg, "cpu=", 4 )) cpu_option = xstrdup( optarg + 4 ); else if (!strncmp( optarg, "fpu=", 4 )) fpu_option = xstrdup( optarg + 4 ); else if (!strncmp( optarg, "arch=", 5 )) arch_option = xstrdup( optarg + 5 ); @@ -648,7 +650,7 @@ int main(int argc, char **argv) if (!spec_file_name) fatal_error( "missing .spec file\n" ); if (!parse_input_file( spec )) break; open_output_file(); - output_def_file( spec, 0 ); + output_def_file( spec, &spec->exports, 0 ); close_output_file(); break; case MODE_IMPLIB: diff --git a/tools/winebuild/parser.c b/tools/winebuild/parser.c index 5bd05e97ca9..ec42c240a0a 100644 --- a/tools/winebuild/parser.c +++ b/tools/winebuild/parser.c @@ -943,16 +943,15 @@ static void assign_ordinals( struct exports *exports ) }
-static void assign_exports( DLLSPEC *spec ) +static void assign_exports( DLLSPEC *spec, unsigned int cpu, struct exports *exports ) { - struct exports *exports = &spec->exports; unsigned int i;
exports->entry_points = xmalloc( spec->nb_entry_points * sizeof(*exports->entry_points) ); for (i = 0; i < spec->nb_entry_points; i++) { ORDDEF *entry = &spec->entry_points[i]; - if ((entry->flags & FLAG_CPU_MASK) && !(entry->flags & FLAG_CPU(target.cpu))) + if ((entry->flags & FLAG_CPU_MASK) && !(entry->flags & FLAG_CPU(cpu))) continue; exports->entry_points[exports->nb_entry_points++] = entry; } @@ -1018,7 +1017,7 @@ void add_16bit_exports( DLLSPEC *spec32, DLLSPEC *spec16 ) odp->u.func.nb_args * sizeof(odp->u.func.args[0]) ); }
- assign_exports( spec32 ); + assign_exports( spec32, target.cpu, &spec32->exports ); }
@@ -1061,7 +1060,8 @@ int parse_spec_file( FILE *file, DLLSPEC *spec ) }
current_line = 0; /* no longer parsing the input file */ - assign_exports( spec ); + assign_exports( spec, target.cpu, &spec->exports ); + if (native_arch != -1) assign_exports( spec, native_arch, &spec->native_exports ); return !nb_errors; }
@@ -1303,6 +1303,6 @@ int parse_def_file( FILE *file, DLLSPEC *spec ) }
current_line = 0; /* no longer parsing the input file */ - assign_exports( spec ); + assign_exports( spec, target.cpu, &spec->exports ); return !nb_errors; } diff --git a/tools/winebuild/spec32.c b/tools/winebuild/spec32.c index 857985cb292..718ce4666ef 100644 --- a/tools/winebuild/spec32.c +++ b/tools/winebuild/spec32.c @@ -1343,9 +1343,8 @@ void output_data_module( DLLSPEC *spec ) * * Build a Win32 def file from a spec file. */ -void output_def_file( DLLSPEC *spec, int import_only ) +void output_def_file( DLLSPEC *spec, struct exports *exports, int import_only ) { - struct exports *exports; DLLSPEC *spec32 = NULL; const char *name; int i, total; @@ -1355,8 +1354,8 @@ void output_def_file( DLLSPEC *spec, int import_only ) spec32 = alloc_dll_spec(); add_16bit_exports( spec32, spec ); spec = spec32; + exports = &spec->exports; } - exports = &spec->exports;
if (spec_file_name) output( "; File generated automatically from %s; do not edit!\n\n", diff --git a/tools/winebuild/utils.c b/tools/winebuild/utils.c index 62f05e535b6..05595f86d37 100644 --- a/tools/winebuild/utils.c +++ b/tools/winebuild/utils.c @@ -615,6 +615,7 @@ DLLSPEC *alloc_dll_spec(void) spec->subsystem_minor = 0; spec->dll_characteristics = IMAGE_DLLCHARACTERISTICS_NX_COMPAT | IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE; spec->exports.base = MAX_ORDINALS; + spec->native_exports.base = MAX_ORDINALS; return spec; }
@@ -644,6 +645,7 @@ void free_dll_spec( DLLSPEC *spec ) free( odp->link_name ); } free_exports( &spec->exports ); + free_exports( &spec->native_exports ); free( spec->file_name ); free( spec->dll_name ); free( spec->c_name );
From: Jacek Caban jacek@codeweavers.com
--- tools/winegcc/winegcc.c | 76 ++++++++++++++++++++++------------------- 1 file changed, 41 insertions(+), 35 deletions(-)
diff --git a/tools/winegcc/winegcc.c b/tools/winegcc/winegcc.c index 533fb3c519b..694242542ad 100644 --- a/tools/winegcc/winegcc.c +++ b/tools/winegcc/winegcc.c @@ -255,7 +255,7 @@ static const struct { "objcopy", "llvm-objcopy" }, };
-static struct strarray build_tool_name( struct options *opts, enum tool tool ) +static struct strarray build_tool_name( struct options *opts, const char *target, enum tool tool ) { const char *base = tool_names[tool].base; const char *llvm_base = tool_names[tool].llvm_base; @@ -264,13 +264,13 @@ static struct strarray build_tool_name( struct options *opts, enum tool tool ) struct strarray ret = empty_strarray; char* str;
- if (opts->target_alias && opts->version) + if (target && opts->version) { - str = strmake("%s-%s-%s", opts->target_alias, base, opts->version); + str = strmake( "%s-%s-%s", target, base, opts->version ); } - else if (opts->target_alias) + else if (target) { - str = strmake("%s-%s", opts->target_alias, base); + str = strmake( "%s-%s", target, base ); } else if (opts->version) { @@ -293,10 +293,10 @@ static struct strarray build_tool_name( struct options *opts, enum tool tool ) ret = strarray_fromstring( path, " " ); if (!strncmp( llvm_base, "clang", 5 )) { - if (opts->target_alias) + if (target) { strarray_add( &ret, "-target" ); - strarray_add( &ret, opts->target_alias ); + strarray_add( &ret, target ); } strarray_add( &ret, "-Wno-unused-command-line-argument" ); strarray_add( &ret, "-fuse-ld=lld" ); @@ -310,12 +310,12 @@ static struct strarray get_translator(struct options *opts) switch(opts->processor) { case proc_cpp: - return build_tool_name( opts, TOOL_CPP ); + return build_tool_name( opts, opts->target_alias, TOOL_CPP ); case proc_cc: case proc_as: - return build_tool_name( opts, TOOL_CC ); + return build_tool_name( opts, opts->target_alias, TOOL_CC ); case proc_cxx: - return build_tool_name( opts, TOOL_CXX ); + return build_tool_name( opts, opts->target_alias, TOOL_CXX ); } assert(0); return empty_strarray; @@ -635,8 +635,8 @@ static void compile(struct options* opts, const char* lang) /* mixing different C and C++ compilers isn't supported in configure anyway */ case proc_cc: case proc_cxx: - gcc = build_tool_name(opts, TOOL_CC); - gpp = build_tool_name(opts, TOOL_CXX); + gcc = build_tool_name( opts, opts->target_alias, TOOL_CC ); + gpp = build_tool_name( opts, opts->target_alias, TOOL_CXX ); for ( j = 0; !gcc_defs && j < comp_args.count; j++ ) { const char *cc = comp_args.str[j]; @@ -810,7 +810,7 @@ static const char* compile_to_object(struct options* opts, const char* file, con }
/* return the initial set of options needed to run winebuild */ -static struct strarray get_winebuild_args(struct options *opts) +static struct strarray get_winebuild_args( struct options *opts, const char *target ) { const char* winebuild = getenv("WINEBUILD"); const char *binary = NULL; @@ -831,10 +831,10 @@ static struct strarray get_winebuild_args(struct options *opts) strarray_add( &spec_args, binary ); if (verbose) strarray_add( &spec_args, "-v" ); if (keep_generated) strarray_add( &spec_args, "--save-temps" ); - if (opts->target_alias) + if (target) { strarray_add( &spec_args, "--target" ); - strarray_add( &spec_args, opts->target_alias ); + strarray_add( &spec_args, target ); } if (opts->force_pointer_size) strarray_add(&spec_args, strmake("-m%u", 8 * opts->force_pointer_size )); @@ -846,7 +846,7 @@ static struct strarray get_winebuild_args(struct options *opts)
static void fixup_constructors( struct options *opts, const char *file ) { - struct strarray args = get_winebuild_args( opts ); + struct strarray args = get_winebuild_args( opts, opts->target_alias );
strarray_add( &args, "--fixup-ctors" ); strarray_add( &args, file ); @@ -855,7 +855,7 @@ static void fixup_constructors( struct options *opts, const char *file )
static void make_wine_builtin( struct options *opts, const char *file ) { - struct strarray args = get_winebuild_args( opts ); + struct strarray args = get_winebuild_args( opts, opts->target_alias );
strarray_add( &args, "--builtin" ); strarray_add( &args, file ); @@ -943,23 +943,24 @@ static void add_library( struct options *opts, struct strarray lib_dirs, }
/* run winebuild to generate the .spec.o file */ -static const char *build_spec_obj( struct options *opts, const char *spec_file, const char *output_file, - struct strarray files, struct strarray lib_dirs, const char *entry_point ) +static void build_spec_obj( struct options *opts, const char *spec_file, const char *output_file, + const char *target, struct strarray files, struct strarray resources, + struct strarray lib_dirs, const char *entry_point, struct strarray *spec_objs ) { unsigned int i; int is_pe = is_pe_target( opts ); - struct strarray spec_args = get_winebuild_args( opts ); + struct strarray spec_args = get_winebuild_args( opts, target ); struct strarray tool; const char *spec_o_name, *output_name;
/* get the filename from the path */ output_name = get_basename( output_file );
- tool = build_tool_name( opts, TOOL_CC ); + tool = build_tool_name( opts, target, TOOL_CC ); strarray_add( &spec_args, strmake( "--cc-cmd=%s", strarray_tostring( tool, " " ))); if (!is_pe) { - tool = build_tool_name( opts, TOOL_LD ); + tool = build_tool_name( opts, target, TOOL_LD ); strarray_add( &spec_args, strmake( "--ld-cmd=%s", strarray_tostring( tool, " " ))); }
@@ -1021,9 +1022,7 @@ static const char *build_spec_obj( struct options *opts, const char *spec_file, strarray_add(&spec_args, strmake("-d%s", opts->delayimports.str[i])); }
- /* add resource files */ - for (i = 0; i < files.count; i++) - if (files.str[i][1] == 'r') strarray_add(&spec_args, files.str[i]); + strarray_addall( &spec_args, resources );
/* add other files */ strarray_add(&spec_args, "--"); @@ -1040,14 +1039,14 @@ static const char *build_spec_obj( struct options *opts, const char *spec_file, }
spawn(opts->prefix, spec_args, 0); - return spec_o_name; + strarray_add( spec_objs, spec_o_name ); }
/* run winebuild to generate a data-only library */ static void build_data_lib( struct options *opts, const char *spec_file, const char *output_file, struct strarray files ) { unsigned int i; - struct strarray spec_args = get_winebuild_args( opts ); + struct strarray spec_args = get_winebuild_args( opts, opts->target_alias );
strarray_add(&spec_args, opts->shared ? "--dll" : "--exe"); strarray_add(&spec_args, "-o"); @@ -1067,16 +1066,18 @@ static void build_data_lib( struct options *opts, const char *spec_file, const c
static void build(struct options* opts) { + struct strarray resources = empty_strarray; + struct strarray spec_objs = empty_strarray; struct strarray lib_dirs = empty_strarray; struct strarray files = empty_strarray; struct strarray link_args; char *output_file, *output_path; - const char *spec_o_name = NULL, *libgcc = NULL; const char *output_name, *spec_file, *lang; + const char *libgcc = NULL; int generate_app_loader = 1; const char *crt_lib = NULL, *entry_point = NULL; int is_pe = is_pe_target( opts ); - unsigned int j; + unsigned int i, j;
/* NOTE: for the files array we'll use the following convention: * -axxx: xxx is an archive (.a) @@ -1225,7 +1226,12 @@ static void build(struct options* opts) build_data_lib( opts, spec_file, output_file, files ); return; } - spec_o_name = build_spec_obj( opts, spec_file, output_file, files, lib_dirs, entry_point ); + + for (i = 0; i < files.count; i++) + if (files.str[i][1] == 'r') strarray_add( &resources, files.str[i] ); + + build_spec_obj( opts, spec_file, output_file, opts->target_alias, files, resources, lib_dirs, + entry_point, &spec_objs );
if (opts->fake_module) return; /* nothing else to do */
@@ -1265,7 +1271,7 @@ static void build(struct options* opts) entry_point)); }
- if (spec_o_name) strarray_add(&link_args, spec_o_name); + strarray_addall( &link_args, spec_objs );
if (is_pe) { @@ -1341,7 +1347,7 @@ static void build(struct options* opts)
if (opts->debug_file && !strendswith(opts->debug_file, ".pdb")) { - struct strarray tool, objcopy = build_tool_name(opts, TOOL_OBJCOPY); + struct strarray tool, objcopy = build_tool_name(opts, opts->target_alias, TOOL_OBJCOPY);
tool = empty_strarray; strarray_addall( &tool, objcopy ); @@ -1371,10 +1377,10 @@ static void build(struct options* opts) if (!spec_file) error("--out-implib requires a .spec or .def file\n");
- implib_args = get_winebuild_args( opts ); - tool = build_tool_name( opts, TOOL_CC ); + implib_args = get_winebuild_args( opts, opts->target_alias ); + tool = build_tool_name( opts, opts->target_alias, TOOL_CC ); strarray_add( &implib_args, strmake( "--cc-cmd=%s", strarray_tostring( tool, " " ))); - tool = build_tool_name( opts, TOOL_LD ); + tool = build_tool_name( opts, opts->target_alias, TOOL_LD ); strarray_add( &implib_args, strmake( "--ld-cmd=%s", strarray_tostring( tool, " " )));
strarray_add(&implib_args, "--implib");
From: Jacek Caban jacek@codeweavers.com
--- tools/winegcc/winegcc.c | 13 +++++++++++++ 1 file changed, 13 insertions(+)
diff --git a/tools/winegcc/winegcc.c b/tools/winegcc/winegcc.c index 694242542ad..fb759063da9 100644 --- a/tools/winegcc/winegcc.c +++ b/tools/winegcc/winegcc.c @@ -191,6 +191,7 @@ struct options const char* entry_point; const char* debug_file; const char* out_implib; + const char* native_arch; struct strarray prefix; struct strarray lib_dirs; struct strarray args; @@ -1232,6 +1233,13 @@ static void build(struct options* opts)
build_spec_obj( opts, spec_file, output_file, opts->target_alias, files, resources, lib_dirs, entry_point, &spec_objs ); + if (opts->native_arch) + { + const char *suffix = strchr( opts->target_alias, '-' ); + if (!suffix) suffix = ""; + build_spec_obj( opts, spec_file, output_file, strmake( "%s%s", opts->native_arch, suffix ), + files, empty_strarray, lib_dirs, entry_point, &spec_objs ); + }
if (opts->fake_module) return; /* nothing else to do */
@@ -1707,6 +1715,11 @@ int main(int argc, char **argv) { raw_linker_arg = 1; } + else if (!strcmp("-marm64x", opts.args.str[i] )) + { + raw_linker_arg = 1; + opts.native_arch = "aarch64"; + } else if (!strncmp("-mcpu=", opts.args.str[i], 6) || !strncmp("-mfpu=", opts.args.str[i], 6) || !strncmp("-march=", opts.args.str[i], 7))