From 2fda3d6a179c0f2c74cc5d7530eccba260f87697 Mon Sep 17 00:00:00 2001
From: Alexandre Julliard <julliard@winehq.org>
Date: Wed, 30 Dec 2009 11:51:19 +0100
Subject: [PATCH] winebuild: Add support for building Windows import libraries.

---
 tools/winebuild/build.h          |  1 +
 tools/winebuild/import.c         | 49 ++++++++++++++++++++++++++++++++
 tools/winebuild/main.c           | 12 ++++++++
 tools/winebuild/winebuild.man.in |  4 +++
 4 files changed, 66 insertions(+)

diff --git a/tools/winebuild/build.h b/tools/winebuild/build.h
index 7dca2d81b96..0543eb1d3af 100644
--- a/tools/winebuild/build.h
+++ b/tools/winebuild/build.h
@@ -251,6 +251,7 @@ extern void output_get_pc_thunk(void);
 extern void output_module( DLLSPEC *spec );
 extern void output_stubs( DLLSPEC *spec );
 extern void output_imports( DLLSPEC *spec );
+extern void output_import_lib( DLLSPEC *spec, char **argv );
 extern void output_exports( DLLSPEC *spec );
 extern int load_res32_file( const char *name, DLLSPEC *spec );
 extern void output_resources( DLLSPEC *spec );
diff --git a/tools/winebuild/import.c b/tools/winebuild/import.c
index 0caaffde6be..648d29f71be 100644
--- a/tools/winebuild/import.c
+++ b/tools/winebuild/import.c
@@ -1304,3 +1304,52 @@ void output_imports( DLLSPEC *spec )
     if (nb_imports || ext_link_imports.count || has_stubs(spec) || has_relays(spec))
         output_get_pc_thunk();
 }
+
+/* output an import library for a Win32 module and additional object files */
+void output_import_lib( DLLSPEC *spec, char **argv )
+{
+    char *dlltool, *def_file;
+    char *cmd;
+    int err;
+
+    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" )))
+        fatal_error( "Unable to create output file '%s'\n", def_file );
+    BuildDef32File( spec );
+    fclose( output_file );
+    output_file = NULL;
+
+    dlltool = find_tool( "dlltool", NULL );
+    cmd = xmalloc( strlen(dlltool) + strlen(output_file_name) + strlen(def_file) + 12 );
+    sprintf( cmd, "%s -k -l %s -d %s", dlltool, output_file_name, def_file );
+    if (verbose) fprintf( stderr, "%s\n", cmd );
+    err = system( cmd );
+    if (err) fatal_error( "%s failed with status %d\n", dlltool, err );
+    free( cmd );
+    free( dlltool );
+
+    if (argv[0])
+    {
+        char *ar = find_tool( "ar", NULL );
+        int i, len;
+
+        for (i = len = 0; argv[i]; i++) len += strlen(argv[i]) + 1;
+        cmd = xmalloc( strlen(ar) + strlen(output_file_name) + len + 5 );
+        sprintf( cmd, "%s rs %s", ar, output_file_name );
+        for (i = 0; argv[i]; i++)
+        {
+            strcat( cmd, " " );
+            strcat( cmd, argv[i] );
+        }
+        if (verbose) fprintf( stderr, "%s\n", cmd );
+        err = system( cmd );
+        if (err) fatal_error( "%s failed with status %d\n", dlltool, err );
+        free( cmd );
+        free( ar );
+    }
+    output_file_name = NULL;
+}
diff --git a/tools/winebuild/main.c b/tools/winebuild/main.c
index e81f88fd9b1..138ec68c39a 100644
--- a/tools/winebuild/main.c
+++ b/tools/winebuild/main.c
@@ -100,6 +100,7 @@ enum exec_mode_values
     MODE_DLL,
     MODE_EXE,
     MODE_DEF,
+    MODE_IMPLIB,
     MODE_RELAY16,
     MODE_RELAY32,
     MODE_RESOURCES
@@ -268,6 +269,7 @@ static const char usage_str[] =
 "       --dll                 Build a .c file from a .spec or .def file\n"
 "       --def                 Build a .def file from a .spec file\n"
 "       --exe                 Build a .c file for an executable\n"
+"       --implib              Build an import library\n"
 "       --relay16             Build the 16-bit relay assembly routines\n"
 "       --relay32             Build the 32-bit relay assembly routines\n"
 "       --resources           Build a .o file for the resource files\n\n"
@@ -278,6 +280,7 @@ enum long_options_values
     LONG_OPT_DLL = 1,
     LONG_OPT_DEF,
     LONG_OPT_EXE,
+    LONG_OPT_IMPLIB,
     LONG_OPT_ASCMD,
     LONG_OPT_EXTERNAL_SYMS,
     LONG_OPT_FAKE_MODULE,
@@ -300,6 +303,7 @@ static const struct option long_options[] =
     { "dll",           0, 0, LONG_OPT_DLL },
     { "def",           0, 0, LONG_OPT_DEF },
     { "exe",           0, 0, LONG_OPT_EXE },
+    { "implib",        0, 0, LONG_OPT_IMPLIB },
     { "as-cmd",        1, 0, LONG_OPT_ASCMD },
     { "external-symbols", 0, 0, LONG_OPT_EXTERNAL_SYMS },
     { "fake-module",   0, 0, LONG_OPT_FAKE_MODULE },
@@ -475,6 +479,9 @@ static char **parse_options( int argc, char **argv, DLLSPEC *spec )
             set_exec_mode( MODE_EXE );
             if (!spec->subsystem) spec->subsystem = IMAGE_SUBSYSTEM_WINDOWS_GUI;
             break;
+        case LONG_OPT_IMPLIB:
+            set_exec_mode( MODE_IMPLIB );
+            break;
         case LONG_OPT_ASCMD:
             as_command = xstrdup( optarg );
             break;
@@ -662,6 +669,11 @@ int main(int argc, char **argv)
         if (!parse_input_file( spec )) break;
         BuildDef32File( spec );
         break;
+    case MODE_IMPLIB:
+        if (!spec_file_name) fatal_error( "missing .spec file\n" );
+        if (!parse_input_file( spec )) break;
+        output_import_lib( spec, argv );
+        break;
     case MODE_RELAY16:
         if (argv[0]) fatal_error( "file argument '%s' not allowed in this mode\n", argv[0] );
         BuildRelays16();
diff --git a/tools/winebuild/winebuild.man.in b/tools/winebuild/winebuild.man.in
index d41fae7a8c9..e0dd72b14ed 100644
--- a/tools/winebuild/winebuild.man.in
+++ b/tools/winebuild/winebuild.man.in
@@ -46,6 +46,10 @@ executable, and all the other object files must be listed as
 Build a .def file from a spec file. The .spec file is specified via the
 -E 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
+specified via the -E option.
+.TP
 .B \--relay16
 Generate the assembly code for the 16-bit relay routines. This is for
 Wine internal usage only, you should never need to use this option.
-- 
GitLab