winebuild: Add a --resources mode that compiles multiple resource files into a single object.
This commit is contained in:
parent
a37b8f79af
commit
a328834f5b
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue