In -spec and -exe mode, accept multiple object files and link them
together internally to find the undefined symbols.
In -glue mode, accept multiple C files and generate a single glue
file for all of them.

diff --git a/tools/winebuild/build.h b/tools/winebuild/build.h
index 9758ed6..ab52cec 100644
--- a/tools/winebuild/build.h
+++ b/tools/winebuild/build.h
@@ -139,6 +139,8 @@
 extern void fatal_perror( const char *msg, ... );
 extern void warning( const char *msg, ... );
 extern void output_standard_file_header( FILE *outfile );
+extern FILE *open_input_file( const char *srcdir, const char *name );
+extern void close_input_file( FILE *file );
 extern void dump_bytes( FILE *outfile, const unsigned char *data, int len,
                         const char *label, int constant );
 extern const char *make_c_identifier( const char *str );
@@ -146,6 +148,7 @@
 
 extern void add_import_dll( const char *name, int delay );
 extern void add_ignore_symbol( const char *name );
+extern void read_undef_symbols( char **argv );
 extern int resolve_imports( void );
 extern int output_imports( FILE *outfile );
 extern void load_res32_file( const char *name );
@@ -156,13 +159,13 @@
 extern void output_dll_init( FILE *outfile, const char *constructor, const char *destructor );
 extern void parse_debug_channels( const char *srcdir, const char *filename );
 
-extern void BuildGlue( FILE *outfile, FILE *infile );
+extern void BuildGlue( FILE *outfile, const char *srcdir, char **argv );
 extern void BuildRelays16( FILE *outfile );
 extern void BuildRelays32( FILE *outfile );
 extern void BuildSpec16File( FILE *outfile );
 extern void BuildSpec32File( FILE *outfile );
 extern void BuildDef32File( FILE *outfile );
-extern void BuildDebugFile( FILE *outfile );
+extern void BuildDebugFile( FILE *outfile, const char *srcdir, char **argv );
 extern SPEC_TYPE ParseTopLevel( FILE *file, int def_only );
 
 /* global variables */
@@ -184,7 +187,7 @@
 extern char DLLFileName[80];
 extern char owner_name[80];
 extern char *init_func;
-extern const char *input_file_name;
+extern char *input_file_name;
 extern const char *output_file_name;
 extern char **debug_channels;
 extern char **lib_path;
diff --git a/tools/winebuild/import.c b/tools/winebuild/import.c
index 61246a1..054e885 100644
--- a/tools/winebuild/import.c
+++ b/tools/winebuild/import.c
@@ -26,6 +26,7 @@
 #include <fcntl.h>
 #include <stdio.h>
 #include <string.h>
+#include <unistd.h>
 
 #include "build.h"
 
@@ -55,6 +56,8 @@
 static int nb_ignore_symbols;
 static int ignore_size;
 
+static const char *ld_tmp_file;  /* ld temp file name */
+
 static struct import **dll_imports = NULL;
 static int nb_imports = 0;      /* number of imported dlls (delayed or not) */
 static int nb_delayed = 0;      /* number of delayed dlls */
@@ -103,6 +106,12 @@
         qsort( table, size, sizeof(*table), name_cmp );
 }
 
+/* remove the temp file at exit */
+static void remove_ld_tmp_file(void)
+{
+    if (ld_tmp_file) unlink( ld_tmp_file );
+}
+
 /* open the .so library for a given dll in a specified path */
 static char *try_library_path( const char *path, const char *name )
 {
@@ -385,15 +394,46 @@
     current_line = curline;
 }
 
+/* combine a list of object files with ld into a single object file */
+/* returns the name of the combined file */
+static const char *ldcombine_files( char **argv )
+{
+    int i, len = 0;
+    char *cmd;
+    int fd, err;
+    char buffer[] = "/tmp/winebuild.tmp.XXXXXX";
+
+    if ((fd = mkstemp( buffer ) == -1)) fatal_error( "could not generate a temp file\n" );
+    close( fd );
+    ld_tmp_file = xstrdup( buffer );
+    atexit( remove_ld_tmp_file );
+
+    for (i = 0; argv[i]; i++) len += strlen(argv[i]) + 1;
+    cmd = xmalloc( len + strlen(ld_tmp_file) + 10 );
+    sprintf( cmd, "ld -r -o %s", ld_tmp_file );
+    for (i = 0; argv[i]; i++) sprintf( cmd + strlen(cmd), " %s", argv[i] );
+    err = system( cmd );
+    if (err) fatal_error( "ld -r failed with status %d\n", err );
+    free( cmd );
+    return ld_tmp_file;
+}
+
 /* read in the list of undefined symbols */
-void read_undef_symbols( const char *name )
+void read_undef_symbols( char **argv )
 {
     FILE *f;
     char buffer[1024];
     int err;
+    const char *name;
+
+    if (!argv[0]) return;
 
     undef_size = nb_undef_symbols = 0;
 
+    /* if we have multiple object files, link them together */
+    if (argv[1]) name = ldcombine_files( argv );
+    else name = argv[0];
+
     sprintf( buffer, "nm -u %s", name );
     if (!(f = popen( buffer, "r" )))
         fatal_error( "Cannot execute '%s'\n", buffer );
diff --git a/tools/winebuild/main.c b/tools/winebuild/main.c
index 40d5fdf..9851edd 100644
--- a/tools/winebuild/main.c
+++ b/tools/winebuild/main.c
@@ -62,8 +62,8 @@
 char **debug_channels = NULL;
 char **lib_path = NULL;
 
-const char *input_file_name;
-const char *output_file_name;
+char *input_file_name = NULL;
+const char *output_file_name = NULL;
 
 static FILE *input_file;
 static FILE *output_file;
@@ -82,17 +82,6 @@
     MODE_RELAY32
 } exec_mode = MODE_NONE;
 
-/* open the input file */
-static void open_input( const char *name )
-{
-    input_file_name = name;
-    if (!(input_file = fopen( name, "r" )))
-    {
-        fprintf( stderr, "Cannot open input file '%s'\n", name );
-        exit(1);
-    }
-}
-
 /* set the dll file name from the input file name */
 static void set_dll_file_name( const char *name )
 {
@@ -135,11 +124,11 @@
 static void do_spec( const char *arg );
 static void do_def( const char *arg );
 static void do_exe( const char *arg );
-static void do_glue( const char *arg );
+static void do_glue(void);
 static void do_relay16(void);
 static void do_relay32(void);
 static void do_debug(void);
-static void do_sym( const char *arg );
+static void do_sym(void);
 static void do_chdir( const char *arg );
 static void do_lib( const char *arg );
 static void do_import( const char *arg );
@@ -161,13 +150,13 @@
     { "-l",       1, do_import,  "-l lib.dll       Import the specified library" },
     { "-dl",      1, do_dimport, "-dl lib.dll      Delay-import the specified library" },
     { "-res",     1, do_rsrc,    "-res rsrc.res    Load resources from rsrc.res" },
-    { "-o",       1, do_output,  "-o name          Set the output file name (default: stdout)" },
-    { "-sym",     1, do_sym,     "-sym file.o      Read the list of undefined symbols from 'file.o'\n" },
+    { "-o",       1, do_output,  "-o name          Set the output file name (default: stdout)\n" },
+    { "-sym",     0, do_sym,     NULL },  /* ignored for backwards compatibility */
     { "-spec",    1, do_spec,    "-spec file.spec  Build a .c file from a spec file" },
     { "-def",     1, do_def,     "-def file.spec   Build a .def file from a spec file" },
     { "-exe",     1, do_exe,     "-exe name        Build a .c file from the named executable" },
     { "-debug",   0, do_debug,   "-debug [files]   Build a .c file containing debug channels declarations" },
-    { "-glue",    1, do_glue,    "-glue file.c     Build the 16-bit glue for a .c file" },
+    { "-glue",    0, do_glue,    "-glue [files]    Build the 16-bit glue for the source files" },
     { "-relay16", 0, do_relay16, "-relay16         Build the 16-bit relay assembly routines" },
     { "-relay32", 0, do_relay32, "-relay32         Build the 32-bit relay assembly routines" },
     { NULL,       0, NULL,      NULL }
@@ -194,7 +183,9 @@
     const struct option_descr *opt;
     fprintf( stderr, "Usage: winebuild [options]\n\n" );
     fprintf( stderr, "Options:\n" );
-    for (opt = option_table; opt->name; opt++) fprintf( stderr, "   %s\n", opt->usage );
+    for (opt = option_table; opt->name; opt++)
+        if (opt->usage) fprintf( stderr, "   %s\n", opt->usage );
+
     fprintf( stderr, "\nExactly one of -spec, -def, -exe, -debug, -glue, -relay16 or -relay32 must be specified.\n\n" );
     exit(1);
 }
@@ -231,7 +222,7 @@
 {
     if (exec_mode != MODE_NONE || !arg[0]) do_usage();
     exec_mode = MODE_SPEC;
-    open_input( arg );
+    input_file = open_input_file( NULL, arg );
     set_dll_file_name( arg );
 }
 
@@ -239,7 +230,7 @@
 {
     if (exec_mode != MODE_NONE || !arg[0]) do_usage();
     exec_mode = MODE_DEF;
-    open_input( arg );
+    input_file = open_input_file( NULL, arg );
     set_dll_file_name( arg );
 }
 
@@ -270,11 +261,10 @@
     strcpy( owner_name, arg );
 }
 
-static void do_glue( const char *arg )
+static void do_glue(void)
 {
-    if (exec_mode != MODE_NONE || !arg[0]) do_usage();
+    if (exec_mode != MODE_NONE) do_usage();
     exec_mode = MODE_GLUE;
-    open_input( arg );
 }
 
 static void do_debug(void)
@@ -300,10 +290,9 @@
     exec_mode = MODE_RELAY32;
 }
 
-static void do_sym( const char *arg )
+static void do_sym(void)
 {
-    extern void read_undef_symbols( const char *name );
-    read_undef_symbols( arg );
+    /* nothing */
 }
 
 static void do_lib( const char *arg )
@@ -331,10 +320,10 @@
 static void parse_options( char *argv[] )
 {
     const struct option_descr *opt;
-    char * const * ptr;
+    char **ptr, **last;
     const char* arg=NULL;
 
-    for (ptr = argv + 1; *ptr; ptr++)
+    for (ptr = last = argv + 1; *ptr; ptr++)
     {
         for (opt = option_table; opt->name; opt++)
         {
@@ -355,21 +344,18 @@
             }
         }
 
-        if (!opt->name)
+        if (opt->name)
         {
-            if (exec_mode == MODE_DEBUG && **ptr != '-')
-            {
-                /* this a file name to parse for debug channels */
-                parse_debug_channels( current_src_dir, *ptr );
-                continue;
-            }
-            fprintf( stderr, "Unrecognized option '%s'\n", *ptr );
-            do_usage();
+            if (opt->has_arg && arg != NULL) opt->func( arg );
+            else opt->func( "" );
         }
-
-        if (opt->has_arg && arg!=NULL) opt->func( arg );
-        else opt->func( "" );
+        else  /* keep this argument */
+        {
+            if (last != ptr) *last = *ptr;
+            last++;
+        }
     }
+    *last = NULL;
 }
 
 
@@ -387,18 +373,23 @@
         switch (ParseTopLevel( input_file, 0 ))
         {
             case SPEC_WIN16:
+                if (argv[1])
+                    fatal_error( "file argument '%s' not allowed in this mode\n", argv[1] );
                 BuildSpec16File( output_file );
                 break;
             case SPEC_WIN32:
+                read_undef_symbols( argv + 1 );
                 BuildSpec32File( output_file );
                 break;
             default: assert(0);
         }
         break;
     case MODE_EXE:
+        read_undef_symbols( argv + 1 );
         BuildSpec32File( output_file );
         break;
     case MODE_DEF:
+        if (argv[1]) fatal_error( "file argument '%s' not allowed in this mode\n", argv[1] );
         switch (ParseTopLevel( input_file, 1 ))
         {
             case SPEC_WIN16:
@@ -411,15 +402,17 @@
         }
         break;
     case MODE_DEBUG:
-        BuildDebugFile( output_file );
+        BuildDebugFile( output_file, current_src_dir, argv + 1 );
         break;
     case MODE_GLUE:
-        BuildGlue( output_file, input_file );
+        BuildGlue( output_file, current_src_dir, argv + 1 );
         break;
     case MODE_RELAY16:
+        if (argv[1]) fatal_error( "file argument '%s' not allowed in this mode\n", argv[1] );
         BuildRelays16( output_file );
         break;
     case MODE_RELAY32:
+        if (argv[1]) fatal_error( "file argument '%s' not allowed in this mode\n", argv[1] );
         BuildRelays32( output_file );
         break;
     default:
diff --git a/tools/winebuild/parser.c b/tools/winebuild/parser.c
index 727cdb6..886bc4c 100644
--- a/tools/winebuild/parser.c
+++ b/tools/winebuild/parser.c
@@ -595,20 +595,8 @@
 {
     FILE *file;
     int eol_seen = 1;
-    char *fullname = NULL;
 
-    if (srcdir)
-    {
-        fullname = xmalloc( strlen(srcdir) + strlen(filename) + 2 );
-        strcpy( fullname, srcdir );
-        strcat( fullname, "/" );
-        strcat( fullname, filename );
-    }
-    else fullname = xstrdup( filename );
-
-    if (!(file = fopen( fullname, "r" ))) fatal_error( "Cannot open file '%s'\n", fullname );
-    input_file_name = fullname;
-    current_line = 1;
+    file = open_input_file( srcdir, filename );
     while (fgets( ParseBuffer, sizeof(ParseBuffer), file ))
     {
         char *channel, *end, *p = ParseBuffer;
@@ -645,8 +633,5 @@
         }
         current_line++;
     }
-    fclose( file );
-    input_file_name = NULL;
-    current_line = 0;
-    free( fullname );
+    close_input_file( file );
 }
diff --git a/tools/winebuild/spec16.c b/tools/winebuild/spec16.c
index 811a971..80720ca 100644
--- a/tools/winebuild/spec16.c
+++ b/tools/winebuild/spec16.c
@@ -458,10 +458,7 @@
 
     if (!strncmp( "word_", profile, 5 )) short_ret = 1;
     else if (strncmp( "long_", profile, 5 ))
-    {
-        fprintf( stderr, "Invalid function name '%s'.\n", profile );
-        exit(1);
-    }
+        fatal_error( "Invalid function name '%s'\n", profile );
 
     fprintf( outfile, "unsigned %s __stdcall %s_CallTo16_%s( void (*proc)()",
              short_ret? "short" : "int", prefix, profile );
@@ -473,6 +470,7 @@
         {
         case 'w': fprintf( outfile, "unsigned short" ); argsize += 2; break;
         case 'l': fprintf( outfile, "unsigned int" ); argsize += 4; break;
+        default: fatal_error( "Invalid letter '%c' in function name '%s'\n", args[i], profile );
         }
         fprintf( outfile, " arg%d", i+1 );
     }
@@ -907,7 +905,7 @@
  *
  * Build the 16-bit-to-Wine/Wine-to-16-bit callback glue code
  */
-void BuildGlue( FILE *outfile, FILE *infile )
+void BuildGlue( FILE *outfile, const char *srcdir, char **argv )
 {
     char buffer[1024];
 
@@ -924,26 +922,33 @@
 
     /* Build the callback glue functions */
 
-    while (fgets( buffer, sizeof(buffer), infile ))
+    while (*argv)
     {
-        if (strstr( buffer, "### start build ###" )) break;
-    }
-    while (fgets( buffer, sizeof(buffer), infile ))
-    {
-        char *p;
-        if ( (p = strstr( buffer, "CallTo16_" )) != NULL )
-        {
-            char *q, *profile = p + strlen( "CallTo16_" );
-            for (q = profile; (*q == '_') || isalpha(*q); q++ )
-                ;
-            *q = '\0';
-            for (q = p-1; q > buffer && ((*q == '_') || isalnum(*q)); q-- )
-                ;
-            if ( ++q < p ) p[-1] = '\0'; else q = "";
-            BuildCallTo16Func( outfile, profile, q );
-        }
-        if (strstr( buffer, "### stop build ###" )) break;
-    }
+        FILE *infile = open_input_file( srcdir, *argv );
 
-    fclose( infile );
+        while (fgets( buffer, sizeof(buffer), infile ))
+        {
+            current_line++;
+            if (strstr( buffer, "### start build ###" )) break;
+        }
+        while (fgets( buffer, sizeof(buffer), infile ))
+        {
+            char *p;
+            if ( (p = strstr( buffer, "CallTo16_" )) != NULL )
+            {
+                char *q, *profile = p + strlen( "CallTo16_" );
+                for (q = profile; (*q == '_') || isalpha(*q); q++ )
+                    ;
+                *q = '\0';
+                for (q = p-1; q > buffer && ((*q == '_') || isalnum(*q)); q-- )
+                    ;
+                if ( ++q < p ) p[-1] = '\0'; else q = "";
+                BuildCallTo16Func( outfile, profile, q );
+            }
+            current_line++;
+            if (strstr( buffer, "### stop build ###" )) break;
+        }
+        close_input_file( infile );
+        argv++;
+    }
 }
diff --git a/tools/winebuild/spec32.c b/tools/winebuild/spec32.c
index 25fd253..01f19f3 100644
--- a/tools/winebuild/spec32.c
+++ b/tools/winebuild/spec32.c
@@ -894,11 +894,13 @@
  *
  * Build the debugging channels source file.
  */
-void BuildDebugFile( FILE *outfile )
+void BuildDebugFile( FILE *outfile, const char *srcdir, char **argv )
 {
     int nr_debug;
     char *prefix, *p;
 
+    while (*argv) parse_debug_channels( srcdir, *argv++ );
+
     output_standard_file_header( outfile );
     nr_debug = output_debug( outfile );
     if (!nr_debug)
diff --git a/tools/winebuild/utils.c b/tools/winebuild/utils.c
index 68b6e31..cbc8e51 100644
--- a/tools/winebuild/utils.c
+++ b/tools/winebuild/utils.c
@@ -153,6 +153,46 @@
 
 
 /*******************************************************************
+ *         open_input_file
+ *
+ * Open a file in the given srcdir and set the input_file_name global variable.
+ */
+FILE *open_input_file( const char *srcdir, const char *name )
+{
+    char *fullname;
+    FILE *file;
+
+    if (srcdir)
+    {
+        fullname = xmalloc( strlen(srcdir) + strlen(name) + 2 );
+        strcpy( fullname, srcdir );
+        strcat( fullname, "/" );
+        strcat( fullname, name );
+    }
+    else fullname = xstrdup( name );
+
+    if (!(file = fopen( fullname, "r" ))) fatal_error( "Cannot open file '%s'\n", fullname );
+    input_file_name = fullname;
+    current_line = 1;
+    return file;
+}
+
+
+/*******************************************************************
+ *         close_input_file
+ *
+ * Close the current input file (must have been opened with open_input_file).
+ */
+void close_input_file( FILE *file )
+{
+    fclose( file );
+    free( input_file_name );
+    input_file_name = NULL;
+    current_line = 0;
+}
+
+
+/*******************************************************************
  *         make_c_identifier
  *
  * Map a string to a valid C identifier.
diff --git a/tools/winebuild/winebuild.man.in b/tools/winebuild/winebuild.man.in
index 5db4125..0a40daf 100644
--- a/tools/winebuild/winebuild.man.in
+++ b/tools/winebuild/winebuild.man.in
@@ -3,7 +3,7 @@
 .SH NAME
 winebuild \- Wine dll builder
 .SH SYNOPSIS
-.BI "winebuild " "[options] " "[inputfile]"
+.BI winebuild\  [options]\ [input\ files]
 .SH DESCRIPTION
 .B winebuild
 generates the C and assembly files that are necessary to build a Wine
@@ -23,29 +23,42 @@
 Build a C file from a spec file (see \fBSPEC FILE SYNTAX\fR for
 details). The resulting C file must be compiled and linked to the
 other object files to build a working Wine dll.
-.TP
-.BI \-def\  file.spec
-Build a .def file from a spec file. This is used when building dlls
-with a PE (Win32) compiler.
+.br
+In that mode, the
+.I input files
+should be the list of all object files that will be linked into the
+final dll, to allow
+.B winebuild
+to get the list of all undefined symbols that need to be imported from
+other dlls.
 .TP
 .BI \-exe\  name
 Build a C file for the named executable. This is basically the same as
 the -spec mode except that it doesn't require a .spec file as input,
 since an executable doesn't export functions. The resulting C file
 must be compiled and linked to the other object files to build a
-working Wine executable.
+working Wine executable, and all the other object files must be listed
+as
+.I input files.
 .TP
-.BI \-debug\  [files]
-Build a C file containing the definitions for debugging channels. The
-\fIfiles\fR argument is a list of C files to search for debug channel
+.BI \-def\  file.spec
+Build a .def file from a spec file. This is used when building dlls
+with a PE (Win32) compiler.
+.TP
+.B \-debug
+Build a C file containing the definitions for debugging channels. In
+that mode the
+.I input files
+should be a list of C files to search for debug channel
 definitions. The resulting C file must be compiled and linked with the
 dll.
 .TP
-.BI \-glue\  file.c
+.B \-glue
 Build a C file containing the glue code for the 16-bit calls contained
-in the \fIfile.c\fR source. These calls must be specified in the
-source file using special markers, as described in the \fBGLUE
-FUNCTIONS\fR section.
+in the
+.I input files.
+These calls must be specified in the source files using special
+markers, as described in the \fBGLUE FUNCTIONS\fR section.
 .TP
 .B \-relay16
 Generate the assembly code for the 16-bit relay routines. This is for
@@ -58,7 +71,8 @@
 .TP
 .BI \-C\  directory
 Change to the specified directory before reading source files. Only
-meaningful in \fB-debug\fR mode.
+meaningful in
+.BR \-debug\  and\  -glue\  modes.
 .TP
 .BI \-D\  symbol
 Ignored for compatibility with the C compiler.
@@ -125,8 +139,6 @@
 \fIrsrc.res\fR can be produced from a source resource file with
 .BR wrc(1)
 (or with a Windows resource compiler).
-.BI \-sym\  file.o
-Read the list of undefined symbols from the object file file.o.
 .TP
 .B \-w
 Turn on warnings.