From aac69889bf1e276688895eca313dc861cab07545 Mon Sep 17 00:00:00 2001 From: Alexandre Julliard Date: Fri, 25 Mar 2016 15:32:22 +0900 Subject: [PATCH] winebuild: Add support for creating static import libraries. Signed-off-by: Alexandre Julliard --- tools/winebuild/build.h | 1 + tools/winebuild/import.c | 132 ++++++++++++++++++++++++++++--- tools/winebuild/utils.c | 7 ++ tools/winebuild/winebuild.man.in | 2 +- 4 files changed, 131 insertions(+), 11 deletions(-) diff --git a/tools/winebuild/build.h b/tools/winebuild/build.h index 5cf984b76dc..03b88faf98e 100644 --- a/tools/winebuild/build.h +++ b/tools/winebuild/build.h @@ -233,6 +233,7 @@ extern char *strmake(const char* fmt, ...) __attribute__((__format__ (__printf__ extern struct strarray strarray_fromstring( const char *str, const char *delim ); extern void strarray_add( struct strarray *array, ... ); extern void strarray_addv( struct strarray *array, char * const *argv ); +extern void strarray_addall( struct strarray *array, struct strarray args ); extern DECLSPEC_NORETURN void fatal_error( const char *msg, ... ) __attribute__ ((__format__ (__printf__, 1, 2))); extern DECLSPEC_NORETURN void fatal_perror( const char *msg, ... ) diff --git a/tools/winebuild/import.c b/tools/winebuild/import.c index 1d561c4fec3..d2d6f570fae 100644 --- a/tools/winebuild/import.c +++ b/tools/winebuild/import.c @@ -68,6 +68,10 @@ static struct strarray ext_link_imports; /* list of external symbols to link to static struct list dll_imports = LIST_INIT( dll_imports ); static struct list dll_delayed = LIST_INIT( dll_delayed ); +static struct strarray as_files; + +static const char import_func_prefix[] = "__wine$func$"; +static const char import_ord_prefix[] = "__wine$ord$"; static inline const char *ppc_reg( int reg ) { @@ -1283,16 +1287,56 @@ void output_imports( DLLSPEC *spec ) output_external_link_imports( spec ); } -/* output an import library for a Win32 module and additional object files */ -void output_import_lib( DLLSPEC *spec, char **argv ) +/* create a new asm temp file */ +static void new_output_as_file( const char *prefix ) +{ + char *name = get_temp_file_name( prefix, ".s" ); + + if (output_file) fclose( output_file ); + if (!(output_file = fopen( name, "w" ))) + fatal_error( "Unable to create output file '%s'\n", name ); + strarray_add( &as_files, name, NULL ); +} + +/* assemble all the asm files */ +static void assemble_files( const char *prefix ) +{ + unsigned int i; + + if (output_file) fclose( output_file ); + output_file = NULL; + + for (i = 0; i < as_files.count; i++) + { + char *obj = get_temp_file_name( prefix, ".o" ); + assemble_file( as_files.str[i], obj ); + as_files.str[i] = obj; + } +} + +/* build a library from the current asm files and any additional object files in argv */ +static void build_library( const char *output_name, char **argv, int create ) +{ + struct strarray args = find_tool( "ar", NULL ); + struct strarray ranlib = find_tool( "ranlib", NULL ); + + strarray_add( &args, create ? "rc" : "r", output_name, NULL ); + strarray_addall( &args, as_files ); + strarray_addv( &args, argv ); + if (create) unlink( output_name ); + spawn( args ); + + strarray_add( &ranlib, output_name, NULL ); + spawn( ranlib ); +} + +/* create a Windows-style import library */ +static void build_windows_import_lib( DLLSPEC *spec ) { struct strarray args; char *def_file; const char *as_flags, *m_flag; - if (target_platform != PLATFORM_WINDOWS) - fatal_error( "Unix-style import libraries not supported yet\n" ); - def_file = get_temp_file_name( output_file_name, ".def" ); fclose( output_file ); if (!(output_file = fopen( def_file, "w" ))) @@ -1320,13 +1364,81 @@ void output_import_lib( DLLSPEC *spec, char **argv ) if (m_flag) strarray_add( &args, "-m", m_flag, as_flags, NULL ); spawn( args ); +} - if (argv[0]) +/* create a Unix-style import library */ +static void build_unix_import_lib( DLLSPEC *spec ) +{ + static const char valid_chars[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789._@"; + int i, total; + const char *name, *prefix; + char *dll_name = xstrdup( spec->file_name ); + + if (strendswith( dll_name, ".dll" )) dll_name[strlen(dll_name) - 4] = 0; + if (strspn( dll_name, valid_chars ) < strlen( dll_name )) + fatal_error( "%s contains invalid characters\n", spec->file_name ); + + /* entry points */ + + for (i = total = 0; i < spec->nb_entry_points; i++) { - args = find_tool( "ar", NULL ); - strarray_add( &args, "rs", output_file_name, NULL ); - strarray_addv( &args, argv ); - spawn( args ); + const ORDDEF *odp = &spec->entry_points[i]; + + if (odp->name) name = odp->name; + else if (odp->export_name) name = odp->export_name; + else continue; + + if (odp->flags & FLAG_PRIVATE) continue; + total++; + + /* C++ mangled names cannot be imported */ + if (strpbrk( name, "?@" )) continue; + + switch(odp->type) + { + case TYPE_VARARGS: + case TYPE_CDECL: + case TYPE_STDCALL: + case TYPE_THISCALL: + prefix = (!odp->name || (odp->flags & FLAG_ORDINAL)) ? import_ord_prefix : import_func_prefix; + new_output_as_file( spec->file_name ); + output( "\t.text\n" ); + output( "\n\t.align %d\n", get_alignment( get_ptr_size() )); + output( "\t%s\n", func_declaration( name ) ); + output( "%s\n", asm_globl( name ) ); + output( "\t%s %s%s$%u$%s\n", get_asm_ptr_keyword(), + asm_name( prefix ), dll_name, odp->ordinal, name ); + output_function_size( name ); + break; + + default: + break; + } + } + if (!total) warning( "%s: Import library doesn't export anything\n", spec->file_name ); + + if (!as_files.count) /* create a dummy file to avoid empty import libraries */ + { + new_output_as_file( spec->file_name ); + output( "\t.text\n" ); + } + + assemble_files( spec->file_name ); + free( dll_name ); +} + +/* output an import library for a Win32 module and additional object files */ +void output_import_lib( DLLSPEC *spec, char **argv ) +{ + if (target_platform == PLATFORM_WINDOWS) + { + build_windows_import_lib( spec ); + if (argv[0]) build_library( output_file_name, argv, 0 ); + } + else + { + build_unix_import_lib( spec ); + build_library( output_file_name, argv, 1 ); } output_file_name = NULL; } diff --git a/tools/winebuild/utils.c b/tools/winebuild/utils.c index c5135658a4b..9308e83947a 100644 --- a/tools/winebuild/utils.c +++ b/tools/winebuild/utils.c @@ -182,6 +182,13 @@ void strarray_addv( struct strarray *array, char * const *argv ) while (*argv) strarray_add_one( array, *argv++ ); } +void strarray_addall( struct strarray *array, struct strarray args ) +{ + unsigned int i; + + for (i = 0; i < args.count; i++) strarray_add_one( array, args.str[i] ); +} + struct strarray strarray_fromstring( const char *str, const char *delim ) { const char *tok; diff --git a/tools/winebuild/winebuild.man.in b/tools/winebuild/winebuild.man.in index 206373857a8..d99fb5752bb 100644 --- a/tools/winebuild/winebuild.man.in +++ b/tools/winebuild/winebuild.man.in @@ -47,7 +47,7 @@ Build a .def file from a spec file. The .spec file is specified via the \fB-E\fR option. This is used when building dlls with a PE (Win32) compiler. .TP .BI \--implib -Build a PE import library from a spec file. The .spec file is +Build a .a import library from a spec file. The .spec file is specified via the \fB-E\fR option. .TP .B \--resources