Commit a328834f authored by Alexandre Julliard's avatar Alexandre Julliard

winebuild: Add a --resources mode that compiles multiple resource files into a single object.

parent a37b8f79
......@@ -205,6 +205,7 @@ extern int output( const char *format, ... )
extern const char *get_as_command(void);
extern const char *get_ld_command(void);
extern const char *get_nm_command(void);
extern const char *get_windres_command(void);
extern char *get_temp_file_name( const char *prefix, const char *suffix );
extern void output_standard_file_header(void);
extern FILE *open_input_file( const char *srcdir, const char *name );
......@@ -250,6 +251,7 @@ extern void load_res16_file( const char *name, DLLSPEC *spec );
extern void output_res16_data( DLLSPEC *spec );
extern void output_res16_directory( DLLSPEC *spec );
extern void output_spec16_file( DLLSPEC *spec );
extern void output_res_o_file( DLLSPEC *spec );
extern void BuildRelays16(void);
extern void BuildRelays32(void);
......
......@@ -96,7 +96,8 @@ enum exec_mode_values
MODE_EXE,
MODE_DEF,
MODE_RELAY16,
MODE_RELAY32
MODE_RELAY32,
MODE_RESOURCES
};
static enum exec_mode_values exec_mode = MODE_NONE;
......@@ -243,6 +244,7 @@ static const char usage_str[] =
" --exe Build a .c file for an executable\n"
" --relay16 Build the 16-bit relay assembly routines\n"
" --relay32 Build the 32-bit relay assembly routines\n\n"
" --resources Build a .o file for the resource files\n\n"
"The mode options are mutually exclusive; you must specify one and only one.\n\n";
enum long_options_values
......@@ -257,6 +259,7 @@ enum long_options_values
LONG_OPT_NXCOMPAT,
LONG_OPT_RELAY16,
LONG_OPT_RELAY32,
LONG_OPT_RESOURCES,
LONG_OPT_SAVE_TEMPS,
LONG_OPT_SUBSYSTEM,
LONG_OPT_VERSION
......@@ -276,6 +279,7 @@ static const struct option long_options[] =
{ "nxcompat", 1, 0, LONG_OPT_NXCOMPAT },
{ "relay16", 0, 0, LONG_OPT_RELAY16 },
{ "relay32", 0, 0, LONG_OPT_RELAY32 },
{ "resources", 0, 0, LONG_OPT_RESOURCES },
{ "save-temps", 0, 0, LONG_OPT_SAVE_TEMPS },
{ "subsystem", 1, 0, LONG_OPT_SUBSYSTEM },
{ "version", 0, 0, LONG_OPT_VERSION },
......@@ -463,6 +467,9 @@ static char **parse_options( int argc, char **argv, DLLSPEC *spec )
case LONG_OPT_RELAY32:
set_exec_mode( MODE_RELAY32 );
break;
case LONG_OPT_RESOURCES:
set_exec_mode( MODE_RESOURCES );
break;
case LONG_OPT_SAVE_TEMPS:
save_temps = 1;
break;
......@@ -621,6 +628,10 @@ int main(int argc, char **argv)
if (argv[0]) fatal_error( "file argument '%s' not allowed in this mode\n", argv[0] );
BuildRelays32();
break;
case MODE_RESOURCES:
load_resources( argv, spec );
output_res_o_file( spec );
break;
default:
usage(1);
break;
......
......@@ -21,6 +21,7 @@
#include "config.h"
#include "wine/port.h"
#include <assert.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
......@@ -55,6 +56,7 @@ struct resource
struct string_id name;
const void *data;
unsigned int data_size;
unsigned short mem_options;
unsigned short lang;
};
......@@ -89,6 +91,9 @@ static const unsigned char *file_pos; /* current position in resource file */
static const unsigned char *file_end; /* end of resource file */
static const char *file_name; /* current resource file name */
static unsigned char *file_out_pos; /* current position in output resource file */
static unsigned char *file_out_end; /* end of output buffer */
/* size of a resource directory with n entries */
#define RESOURCE_DIR_SIZE (4 * sizeof(unsigned int))
#define RESOURCE_DIR_ENTRY_SIZE (2 * sizeof(unsigned int))
......@@ -178,6 +183,41 @@ static void get_string( struct string_id *str )
}
}
/* put a word into the resource file */
static void put_word( unsigned short val )
{
if (byte_swapped) val = (val << 8) | (val >> 8);
*(unsigned short *)file_out_pos = val;
file_out_pos += sizeof(unsigned short);
assert( file_out_pos <= file_out_end );
}
/* put a dword into the resource file */
static void put_dword( unsigned int val )
{
if (byte_swapped)
val = ((val << 24) | ((val << 8) & 0x00ff0000) | ((val >> 8) & 0x0000ff00) | (val >> 24));
*(unsigned int *)file_out_pos = val;
file_out_pos += sizeof(unsigned int);
assert( file_out_pos <= file_out_end );
}
/* put a string into the resource file */
static void put_string( const struct string_id *str )
{
if (str->str)
{
const WCHAR *p = str->str;
while (*p) put_word( *p++ );
put_word( 0 );
}
else
{
put_word( 0xffff );
put_word( str->id );
}
}
/* check the file header */
/* all values must be zero except header size */
static int check_header(void)
......@@ -204,7 +244,7 @@ static void load_next_resource( DLLSPEC *spec )
unsigned int hdr_size;
struct resource *res = add_resource( spec );
res->data_size = (get_dword() + 3) & ~3;
res->data_size = get_dword();
hdr_size = get_dword();
if (hdr_size & 3) fatal_error( "%s header size not aligned\n", file_name );
......@@ -213,12 +253,12 @@ static void load_next_resource( DLLSPEC *spec )
get_string( &res->name );
if ((unsigned long)file_pos & 2) get_word(); /* align to dword boundary */
get_dword(); /* skip data version */
get_word(); /* skip mem options */
res->mem_options = get_word();
res->lang = get_word();
get_dword(); /* skip version */
get_dword(); /* skip characteristics */
file_pos = (const unsigned char *)res->data + res->data_size;
file_pos = (const unsigned char *)res->data + ((res->data_size + 3) & ~3);
if (file_pos > file_end) fatal_error( "%s is a truncated file\n", file_name );
}
......@@ -441,7 +481,7 @@ void output_resources( DLLSPEC *spec )
for (i = 0, res = spec->resources; i < spec->nb_resources; i++, res++)
output( "\t.long .L__wine_spec_res_%d-.L__wine_spec_rva_base,%u,0,0\n",
i, res->data_size );
i, (res->data_size + 3) & ~3 );
/* dump the name strings */
......@@ -458,10 +498,98 @@ void output_resources( DLLSPEC *spec )
{
output( "\n\t.align %d\n", get_alignment(get_ptr_size()) );
output( ".L__wine_spec_res_%d:\n", i );
dump_bytes( res->data, res->data_size );
dump_bytes( res->data, (res->data_size + 3) & ~3 );
}
output( ".L__wine_spec_resources_end:\n" );
output( "\t.byte 0\n" );
free_resource_tree( tree );
}
static unsigned int get_resource_header_size( const struct resource *res )
{
unsigned int size = 5 * sizeof(unsigned int) + 2 * sizeof(unsigned short);
if (!res->type.str) size += 2 * sizeof(unsigned short);
else size += (strlenW(res->type.str) + 1) * sizeof(WCHAR);
if (!res->name.str) size += 2 * sizeof(unsigned short);
else size += (strlenW(res->name.str) + 1) * sizeof(WCHAR);
return size;
}
/* output the resources into a .o file */
void output_res_o_file( DLLSPEC *spec )
{
unsigned int i, total_size;
unsigned char *data;
char *res_file, *cmd;
const char *prog;
int fd, err;
if (!spec->nb_resources) fatal_error( "--resources mode needs at least one resource file as input\n" );
if (!output_file_name) fatal_error( "No output file name specified\n" );
total_size = 32; /* header */
for (i = 0; i < spec->nb_resources; i++)
{
total_size += (get_resource_header_size( &spec->resources[i] ) + 3) & ~3;
total_size += (spec->resources[i].data_size + 3) & ~3;
}
data = xmalloc( total_size );
byte_swapped = 0;
file_out_pos = data;
file_out_end = data + total_size;
put_dword( 0 ); /* ResSize */
put_dword( 32 ); /* HeaderSize */
put_word( 0xffff ); /* ResType */
put_word( 0x0000 );
put_word( 0xffff ); /* ResName */
put_word( 0x0000 );
put_dword( 0 ); /* DataVersion */
put_word( 0 ); /* Memory options */
put_word( 0 ); /* Language */
put_dword( 0 ); /* Version */
put_dword( 0 ); /* Characteristics */
for (i = 0; i < spec->nb_resources; i++)
{
unsigned int header_size = get_resource_header_size( &spec->resources[i] );
put_dword( spec->resources[i].data_size );
put_dword( header_size );
put_string( &spec->resources[i].type );
put_string( &spec->resources[i].name );
if ((unsigned long)file_out_pos & 2) put_word( 0 );
put_dword( 0 );
put_word( spec->resources[i].mem_options );
put_word( spec->resources[i].lang );
put_dword( 0 );
put_dword( 0 );
memcpy( file_out_pos, spec->resources[i].data, spec->resources[i].data_size );
file_out_pos += spec->resources[i].data_size;
while ((unsigned long)file_out_pos & 3) *file_out_pos++ = 0;
}
assert( file_out_pos == file_out_end );
res_file = get_temp_file_name( output_file_name, ".res" );
if ((fd = open( res_file, O_WRONLY|O_CREAT|O_TRUNC, 0600 )) == -1)
fatal_error( "Cannot create %s\n", res_file );
if (write( fd, data, total_size ) != total_size)
fatal_error( "Error writing to %s\n", res_file );
close( fd );
free( data );
prog = get_windres_command();
cmd = xmalloc( strlen(prog) + strlen(res_file) + strlen(output_file_name) + 9 );
sprintf( cmd, "%s -i %s -o %s", prog, res_file, output_file_name );
if (verbose) fprintf( stderr, "%s\n", cmd );
err = system( cmd );
if (err) fatal_error( "%s failed with status %d\n", prog, err );
free( cmd );
output_file_name = NULL; /* so we don't try to assemble it */
}
......@@ -319,6 +319,27 @@ const char *get_nm_command(void)
return nm_command;
}
const char *get_windres_command(void)
{
static char *windres_command;
if (!windres_command)
{
if (target_alias)
{
windres_command = xmalloc( strlen(target_alias) + sizeof("-windres") );
strcpy( windres_command, target_alias );
strcat( windres_command, "-windres" );
}
else
{
static const char * const commands[] = { "windres", NULL };
if (!(windres_command = find_tool( commands ))) windres_command = xstrdup("windres");
}
}
return windres_command;
}
/* get a name for a temp file, automatically cleaned up on exit */
char *get_temp_file_name( const char *prefix, const char *suffix )
{
......
......@@ -53,6 +53,13 @@ Wine internal usage only, you should never need to use this option.
.B \--relay32
Generate the assembly code for the 32-bit relay routines. This is for
Wine internal usage only, you should never need to use this option.
.TP
.B \--resources
Generate a .o file containing all the input resources. This is useful
when building with a PE compiler, since the PE binutils cannot handle
multiple resource files as input. For a standard Unix build, the
resource files are automatically included when building the spec file,
so there's no need for an intermediate .o file.
.SH OPTIONS
.TP
.BI \--as-cmd= as-command
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment