Commit 492ac292 authored by Alexandre Julliard's avatar Alexandre Julliard

Added support for building a dll from a .def file for cases where we

don't want to write a full .spec. Renamed --spec option to --dll for consistency.
parent 14743a0f
......@@ -129,7 +129,7 @@ LINTS = $(C_SRCS:.c=.ln)
$(WINDRES) -i $< -o $@
.spec.spec.c:
$(WINEBUILD) $(DEFS) -o $@ --main-module $(MODULE) --spec $<
$(WINEBUILD) $(DEFS) -o $@ --main-module $(MODULE) --dll $<
.spec.spec.def:
$(WINEBUILD) $(DEFS) -o $@ --def $<
......
......@@ -27,7 +27,7 @@ all: $(MODULE)$(DLLEXT) $(SUBDIRS)
# Rules for .so files
$(MAINSPEC).c: $(MAINSPEC) $(RC_SRCS:.rc=.res) $(ALL_OBJS) $(IMPORTLIBS) $(WINEBUILD)
$(WINEBUILD) $(DEFS) $(DLLFLAGS) -o $@ --spec $(SRCDIR)/$(MAINSPEC) $(DLLMODE:%=--mode %) $(RC_SRCS:.rc=.res) $(ALL_OBJS) -L$(DLLDIR) $(DELAYIMPORTS:%=-d%) $(IMPORTS:%=-l%)
$(WINEBUILD) $(DEFS) $(DLLFLAGS) -o $@ --dll $(SRCDIR)/$(MAINSPEC) $(DLLMODE:%=--mode %) $(RC_SRCS:.rc=.res) $(ALL_OBJS) -L$(DLLDIR) $(DELAYIMPORTS:%=-d%) $(IMPORTS:%=-l%)
$(MODULE).so: $(MAINSPEC).o $(ALL_OBJS) Makefile.in
$(LDDLL) $(MAINSPEC).o $(ALL_OBJS) -o $@ -L$(DLLDIR) $(ALL_LIBS) -lc
......
......@@ -76,7 +76,7 @@ EXTRASUBDIRS = \
# Special rules for 16-bit resource and spec files
gdi.exe.spec.c: gdi.exe.spec version16.res
$(WINEBUILD) $(DEFS) $(DLLFLAGS) -o $@ --heap 65520 --main-module $(MODULE) --res version16.res --spec $(SRCDIR)/gdi.exe.spec
$(WINEBUILD) $(DEFS) $(DLLFLAGS) -o $@ --heap 65520 --main-module $(MODULE) --res version16.res --dll $(SRCDIR)/gdi.exe.spec
version16.res: version16.rc
$(LDPATH) $(RC16) $(RC16FLAGS) -fo$@ $(SRCDIR)/version16.rc
......
......@@ -113,7 +113,7 @@ relay16asm.s: $(WINEBUILD)
# Special rules for 16-bit resource and spec files
krnl386.exe.spec.c: krnl386.exe.spec version16.res
$(WINEBUILD) $(DEFS) $(DLLFLAGS) -o $@ --dll-name kernel --main-module $(MODULE) --res version16.res --spec $(SRCDIR)/krnl386.exe.spec
$(WINEBUILD) $(DEFS) $(DLLFLAGS) -o $@ --dll-name kernel --main-module $(MODULE) --res version16.res --dll $(SRCDIR)/krnl386.exe.spec
version16.res: version16.rc
$(LDPATH) $(RC16) $(RC16FLAGS) -fo$@ $(SRCDIR)/version16.rc
......
......@@ -72,10 +72,10 @@ version16.res: version16.rc
$(LDPATH) $(RC16) $(RC16FLAGS) -fo$@ $(SRCDIR)/version16.rc
shell.spec.c: shell.spec version16.res
$(WINEBUILD) $(DEFS) $(DLLFLAGS) -o $@ --main-module $(MODULE) --res version16.res --spec $(SRCDIR)/shell.spec
$(WINEBUILD) $(DEFS) $(DLLFLAGS) -o $@ --main-module $(MODULE) --res version16.res --dll $(SRCDIR)/shell.spec
authors.c: $(TOPSRCDIR)/AUTHORS
(LANG=C; echo 'const char * const SHELL_Authors[] = {' && \
(LC_ALL=C; echo 'const char * const SHELL_Authors[] = {' && \
sed -e '1,2d' -e 's/\(.*\)/ \"\1\",/' $(TOPSRCDIR)/AUTHORS && \
echo ' 0 };') >$@ || ($(RM) $@ && false)
......
......@@ -168,13 +168,13 @@ EXTRASUBDIRS = \
# Special rules for 16-bit resource and spec files
user.exe.spec.c: user.exe.spec resources/version16.res
$(WINEBUILD) $(DEFS) $(DLLFLAGS) -o $@ --heap 65520 --main-module $(MODULE) --res resources/version16.res --spec $(SRCDIR)/user.exe.spec
$(WINEBUILD) $(DEFS) $(DLLFLAGS) -o $@ --heap 65520 --main-module $(MODULE) --res resources/version16.res --dll $(SRCDIR)/user.exe.spec
display.drv.spec.c: display.drv.spec resources/display.res
$(WINEBUILD) $(DEFS) $(DLLFLAGS) -o $@ --main-module $(MODULE) --res resources/display.res --spec $(SRCDIR)/display.drv.spec
$(WINEBUILD) $(DEFS) $(DLLFLAGS) -o $@ --main-module $(MODULE) --res resources/display.res --dll $(SRCDIR)/display.drv.spec
mouse.drv.spec.c: mouse.drv.spec resources/mouse.res
$(WINEBUILD) $(DEFS) $(DLLFLAGS) -o $@ --main-module $(MODULE) --res resources/mouse.res --spec $(SRCDIR)/mouse.drv.spec
$(WINEBUILD) $(DEFS) $(DLLFLAGS) -o $@ --main-module $(MODULE) --res resources/mouse.res --dll $(SRCDIR)/mouse.drv.spec
resources/display.res: resources/display.rc
$(LDPATH) $(RC16) $(RC16FLAGS) -fo$@ $(SRCDIR)/resources/display.rc
......
......@@ -68,7 +68,6 @@ typedef struct
typedef struct
{
int n_args;
char arg_types[21];
} ORD_FUNCTION;
......@@ -170,6 +169,9 @@ 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 int remove_stdcall_decoration( char *name );
extern DLLSPEC *alloc_dll_spec(void);
extern void free_dll_spec( DLLSPEC *spec );
extern const char *make_c_identifier( const char *str );
extern int get_alignment(int alignBoundary);
......@@ -184,7 +186,6 @@ extern void load_res16_file( const char *name, DLLSPEC *spec );
extern int output_res16_data( FILE *outfile, DLLSPEC *spec );
extern int output_res16_directory( unsigned char *buffer, DLLSPEC *spec );
extern void output_dll_init( FILE *outfile, const char *constructor, const char *destructor );
extern int parse_debug_channels( const char *srcdir, const char *filename );
extern void BuildRelays16( FILE *outfile );
extern void BuildRelays32( FILE *outfile );
......@@ -192,7 +193,10 @@ extern void BuildSpec16File( FILE *outfile, DLLSPEC *spec );
extern void BuildSpec32File( FILE *outfile, DLLSPEC *spec );
extern void BuildDef32File( FILE *outfile, DLLSPEC *spec );
extern void BuildDebugFile( FILE *outfile, const char *srcdir, char **argv );
extern int ParseTopLevel( FILE *file, DLLSPEC *spec );
extern int parse_spec_file( FILE *file, DLLSPEC *spec );
extern int parse_def_file( FILE *file, DLLSPEC *spec );
extern int parse_debug_channels( const char *srcdir, const char *filename );
/* global variables */
......
/*
* DLL imports support
*
* Copyright 2000 Alexandre Julliard
* 2000 Eric Pouech
* Copyright 2000, 2004 Alexandre Julliard
* Copyright 2000 Eric Pouech
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
......@@ -32,20 +32,13 @@
#include "build.h"
struct func
{
char *name; /* function name */
int ordinal; /* function ordinal */
int ord_only; /* non-zero if function is imported by ordinal */
};
struct import
{
char *dll; /* dll name */
DLLSPEC *spec; /* description of the imported dll */
int delay; /* delay or not dll loading ? */
struct func *exports; /* functions exported from this dll */
ORDDEF **exports; /* functions exported from this dll */
int nb_exports; /* number of exported functions */
struct func *imports; /* functions we want to import from this dll */
ORDDEF **imports; /* functions we want to import from this dll */
int nb_imports; /* number of imported functions */
};
......@@ -143,7 +136,10 @@ static int name_cmp( const void *name, const void *entry )
/* compare function names; helper for resolve_imports */
static int func_cmp( const void *func1, const void *func2 )
{
return strcmp( ((struct func *)func1)->name, ((struct func *)func2)->name );
const ORDDEF *odp1 = *(const ORDDEF **)func1;
const ORDDEF *odp2 = *(const ORDDEF **)func2;
return strcmp( odp1->name ? odp1->name : odp1->export_name,
odp2->name ? odp2->name : odp2->export_name );
}
/* locate a symbol in a (sorted) list */
......@@ -159,14 +155,15 @@ inline static const char *find_symbol( const char *name, char **table, int size
}
/* locate an export in a (sorted) export list */
inline static struct func *find_export( const char *name, struct func *table, int size )
inline static ORDDEF *find_export( const char *name, ORDDEF **table, int size )
{
struct func func, *res = NULL;
ORDDEF func, *odp, **res = NULL;
func.name = (char *)name;
func.ordinal = -1;
if (table) res = bsearch( &func, table, size, sizeof(*table), func_cmp );
return res;
odp = &func;
if (table) res = bsearch( &odp, table, size, sizeof(*table), func_cmp );
return res ? *res : NULL;
}
/* sort a symbol table */
......@@ -179,13 +176,9 @@ inline static void sort_symbols( char **table, int size )
/* free an import structure */
static void free_imports( struct import *imp )
{
int i;
for (i = 0; i < imp->nb_exports; i++) free( imp->exports[i].name );
for (i = 0; i < imp->nb_imports; i++) free( imp->imports[i].name );
free( imp->exports );
free( imp->imports );
free( imp->dll );
free_dll_spec( imp->spec );
free( imp );
}
......@@ -202,7 +195,7 @@ static int is_already_imported( const char *name )
for (i = 0; i < nb_imports; i++)
{
if (!strcmp( dll_imports[i]->dll, name )) return 1;
if (!strcmp( dll_imports[i]->spec->file_name, name )) return 1;
}
return 0;
}
......@@ -241,152 +234,40 @@ static char *open_library( const char *name )
return fullname;
}
/* skip whitespace until the next token */
static char *skip_whitespace( char *p )
{
while (*p && isspace(*p)) p++;
if (!*p || *p == ';') p = NULL;
return p;
}
/* skip to the start of the next token, null terminating the current one */
static char *next_token( char *p )
{
while (*p && !isspace(*p)) p++;
if (*p) *p++ = 0;
return skip_whitespace( p );
}
/* remove the @nn suffix from stdcall names */
static char *remove_stdcall_decoration( char *buffer )
{
char *p = buffer + strlen(buffer) - 1;
while (p > buffer && isdigit(*p)) p--;
if (p > buffer && *p == '@') *p = 0;
return buffer;
}
/* read in the list of exported symbols of an import library */
static int read_import_lib( const char *name, struct import *imp )
{
FILE *f;
char buffer[1024];
char *fullname;
int size;
int i, ret;
DLLSPEC *spec = imp->spec;
imp->exports = NULL;
imp->nb_exports = size = 0;
imp->nb_exports = 0;
fullname = open_library( name );
f = open_input_file( NULL, fullname );
free( fullname );
while (fgets( buffer, sizeof(buffer), f ))
{
char *name, *flags;
int ordinal = 0, ord_only = 0;
char *p = buffer + strlen(buffer) - 1;
if (p < buffer) goto next;
if (*p == '\n') *p-- = 0;
p = buffer;
if (!(p = skip_whitespace(p))) goto next;
name = p;
p = next_token( name );
if (!strcmp( name, "LIBRARY" ))
{
if (!p)
{
error( "Expected name after LIBRARY\n" );
goto next;
}
name = p;
p = next_token( name );
if (p)
{
error( "Garbage after LIBRARY statement\n" );
goto next;
}
if (is_already_imported( name ))
{
close_input_file( f );
return 0; /* ignore this dll */
}
free( imp->dll );
imp->dll = xstrdup( name );
goto next;
}
if (!strcmp( name, "EXPORTS" )) goto next;
ret = parse_def_file( f, spec );
close_input_file( f );
if (!ret) return 0;
if (is_already_imported( spec->file_name )) return 0;
/* check for ordinal */
if (!p)
{
error( "Expected ordinal after function name\n" );
goto next;
}
if (*p != '@' || !isdigit(p[1]))
{
error( "Expected ordinal after function name '%s'\n", name );
goto next;
}
ordinal = strtol( p+1, &p, 10 );
if (ordinal >= MAX_ORDINALS)
{
error( "Invalid ordinal number %d\n", ordinal );
goto next;
}
imp->exports = xmalloc( spec->nb_entry_points * sizeof(*imp->exports) );
/* check for optional flags */
while (p && (p = skip_whitespace(p)))
{
flags = p;
p = next_token( flags );
if (!strcmp( flags, "NONAME" ))
{
ord_only = 1;
if (!ordinal)
{
error( "Invalid ordinal number %d\n", ordinal );
goto next;
}
}
else if (!strcmp( flags, "CONSTANT" ) || !strcmp( flags, "DATA" ))
{
/* we don't support importing non-function entry points */
goto next;
}
else if (!strcmp( flags, "PRIVATE" ))
{
/* function must not be imported */
goto next;
}
else
{
error( "Garbage after ordinal declaration\n" );
goto next;
}
}
for (i = 0; i < spec->nb_entry_points; i++)
{
ORDDEF *odp = &spec->entry_points[i];
if (imp->nb_exports == size)
{
size += 128;
imp->exports = xrealloc( imp->exports, size * sizeof(*imp->exports) );
}
if ((p = strchr( name, '=' ))) *p = 0;
remove_stdcall_decoration( name );
imp->exports[imp->nb_exports].name = xstrdup( name );
imp->exports[imp->nb_exports].ordinal = ordinal;
imp->exports[imp->nb_exports].ord_only = ord_only;
imp->nb_exports++;
next:
current_line++;
if (odp->type != TYPE_STDCALL && odp->type != TYPE_CDECL) continue;
if (odp->flags & FLAG_PRIVATE) continue;
imp->exports[imp->nb_exports++] = odp;
}
close_input_file( f );
imp->exports = xrealloc( imp->exports, imp->nb_exports * sizeof(*imp->exports) );
if (imp->nb_exports)
qsort( imp->exports, imp->nb_exports, sizeof(*imp->exports), func_cmp );
return !nb_errors;
return 1;
}
/* add a dll to the list of imports */
......@@ -407,11 +288,11 @@ void add_import_dll( const char *name, int delay )
}
imp = xmalloc( sizeof(*imp) );
imp->dll = fullname;
imp->delay = delay;
imp->imports = NULL;
imp->nb_imports = 0;
imp->spec = alloc_dll_spec();
imp->spec->file_name = fullname;
imp->delay = delay;
imp->imports = NULL;
imp->nb_imports = 0;
if (delay) nb_delayed++;
if (read_import_lib( name, imp ))
......@@ -489,13 +370,10 @@ void add_ignore_symbol( const char *name )
}
/* add a function to the list of imports from a given dll */
static void add_import_func( struct import *imp, const struct func *func )
static void add_import_func( struct import *imp, ORDDEF *func )
{
imp->imports = xrealloc( imp->imports, (imp->nb_imports+1) * sizeof(*imp->imports) );
imp->imports[imp->nb_imports].name = xstrdup( func->name );
imp->imports[imp->nb_imports].ordinal = func->ordinal;
imp->imports[imp->nb_imports].ord_only = func->ord_only;
imp->nb_imports++;
imp->imports[imp->nb_imports++] = func;
total_imports++;
if (imp->delay) total_delayed++;
}
......@@ -613,15 +491,16 @@ static void add_extra_undef_symbols( const DLLSPEC *spec )
static int check_unused( const struct import* imp, const DLLSPEC *spec )
{
int i;
size_t len = strlen(imp->dll);
const char *p = strchr( imp->dll, '.' );
if (p && !strcasecmp( p, ".dll" )) len = p - imp->dll;
const char *file_name = imp->spec->file_name;
size_t len = strlen( file_name );
const char *p = strchr( file_name, '.' );
if (p && !strcasecmp( p, ".dll" )) len = p - file_name;
for (i = spec->base; i <= spec->limit; i++)
{
ORDDEF *odp = spec->ordinals[i];
if (!odp || !(odp->flags & FLAG_FORWARD)) continue;
if (!strncasecmp( odp->link_name, imp->dll, len ) &&
if (!strncasecmp( odp->link_name, file_name, len ) &&
odp->link_name[len] == '.')
return 0; /* found a forward, it is used */
}
......@@ -724,10 +603,10 @@ int resolve_imports( DLLSPEC *spec )
for (j = 0; j < nb_undef_symbols; j++)
{
struct func *func = find_export( undef_symbols[j], imp->exports, imp->nb_exports );
if (func)
ORDDEF *odp = find_export( undef_symbols[j], imp->exports, imp->nb_exports );
if (odp)
{
add_import_func( imp, func );
add_import_func( imp, odp );
free( undef_symbols[j] );
undef_symbols[j] = NULL;
}
......@@ -736,7 +615,7 @@ int resolve_imports( DLLSPEC *spec )
if (!remove_symbol_holes() && check_unused( imp, spec ))
{
/* the dll is not used, get rid of it */
warning( "%s imported but no symbols used\n", imp->dll );
warning( "%s imported but no symbols used\n", imp->spec->file_name );
remove_import_dll( i );
i--;
}
......@@ -772,7 +651,7 @@ static int output_immediate_imports( FILE *outfile )
{
if (dll_imports[i]->delay) continue;
fprintf( outfile, " { 0, 0, 0, \"%s\", &imports.data[%d] },\n",
dll_imports[i]->dll, j );
dll_imports[i]->spec->file_name, j );
j += dll_imports[i]->nb_imports + 1;
}
......@@ -784,18 +663,18 @@ static int output_immediate_imports( FILE *outfile )
for (i = 0; i < nb_imports; i++)
{
if (dll_imports[i]->delay) continue;
fprintf( outfile, " /* %s */\n", dll_imports[i]->dll );
fprintf( outfile, " /* %s */\n", dll_imports[i]->spec->file_name );
for (j = 0; j < dll_imports[i]->nb_imports; j++)
{
struct func *import = &dll_imports[i]->imports[j];
if (!import->ord_only)
ORDDEF *odp = dll_imports[i]->imports[j];
if (!(odp->flags & FLAG_NONAME))
{
unsigned short ord = import->ordinal;
unsigned short ord = odp->ordinal;
fprintf( outfile, " \"\\%03o\\%03o%s\",\n",
*(unsigned char *)&ord, *((unsigned char *)&ord + 1), import->name );
*(unsigned char *)&ord, *((unsigned char *)&ord + 1), odp->name );
}
else
fprintf( outfile, " (char *)%d,\n", import->ordinal );
fprintf( outfile, " (char *)%d,\n", odp->ordinal );
}
fprintf( outfile, " 0,\n" );
}
......@@ -811,13 +690,14 @@ static int output_immediate_imports( FILE *outfile )
if (dll_imports[i]->delay) continue;
for (j = 0; j < dll_imports[i]->nb_imports; j++, pos += 4)
{
struct func *import = &dll_imports[i]->imports[j];
fprintf( outfile, " \"\\t" __ASM_FUNC("%s") "\\n\"\n", import->name );
fprintf( outfile, " \"\\t.globl " __ASM_NAME("%s") "\\n\"\n", import->name );
fprintf( outfile, " \"" __ASM_NAME("%s") ":\\n\\t", import->name);
ORDDEF *odp = dll_imports[i]->imports[j];
const char *name = odp->name ? odp->name : odp->export_name;
fprintf( outfile, " \"\\t" __ASM_FUNC("%s") "\\n\"\n", name );
fprintf( outfile, " \"\\t.globl " __ASM_NAME("%s") "\\n\"\n", name );
fprintf( outfile, " \"" __ASM_NAME("%s") ":\\n\\t", name);
#if defined(__i386__)
if (strstr( import->name, "__wine_call_from_16" ))
if (strstr( name, "__wine_call_from_16" ))
fprintf( outfile, ".byte 0x2e\\n\\tjmp *(imports+%d)\\n\\tnop\\n", pos );
else
fprintf( outfile, "jmp *(imports+%d)\\n\\tmovl %%esi,%%esi\\n", pos );
......@@ -886,8 +766,9 @@ static int output_delayed_imports( FILE *outfile, const DLLSPEC *spec )
fprintf( outfile, "static void *__wine_delay_imp_%d_hmod;\n", i);
for (j = 0; j < dll_imports[i]->nb_imports; j++)
{
fprintf( outfile, "void __wine_delay_imp_%d_%s();\n",
i, dll_imports[i]->imports[j].name );
ORDDEF *odp = dll_imports[i]->imports[j];
const char *name = odp->name ? odp->name : odp->export_name;
fprintf( outfile, "void __wine_delay_imp_%d_%s();\n", i, name );
}
}
fprintf( outfile, "\n" );
......@@ -910,31 +791,33 @@ static int output_delayed_imports( FILE *outfile, const DLLSPEC *spec )
{
if (!dll_imports[i]->delay) continue;
fprintf( outfile, " { 0, \"%s\", &__wine_delay_imp_%d_hmod, &delay_imports.IAT[%d], &delay_imports.INT[%d], 0, 0, 0 },\n",
dll_imports[i]->dll, i, j, j );
dll_imports[i]->spec->file_name, i, j, j );
j += dll_imports[i]->nb_imports;
}
fprintf( outfile, " },\n {\n" );
for (i = 0; i < nb_imports; i++)
{
if (!dll_imports[i]->delay) continue;
fprintf( outfile, " /* %s */\n", dll_imports[i]->dll );
fprintf( outfile, " /* %s */\n", dll_imports[i]->spec->file_name );
for (j = 0; j < dll_imports[i]->nb_imports; j++)
{
fprintf( outfile, " &__wine_delay_imp_%d_%s,\n", i, dll_imports[i]->imports[j].name);
ORDDEF *odp = dll_imports[i]->imports[j];
const char *name = odp->name ? odp->name : odp->export_name;
fprintf( outfile, " &__wine_delay_imp_%d_%s,\n", i, name );
}
}
fprintf( outfile, " },\n {\n" );
for (i = 0; i < nb_imports; i++)
{
if (!dll_imports[i]->delay) continue;
fprintf( outfile, " /* %s */\n", dll_imports[i]->dll );
fprintf( outfile, " /* %s */\n", dll_imports[i]->spec->file_name );
for (j = 0; j < dll_imports[i]->nb_imports; j++)
{
struct func *import = &dll_imports[i]->imports[j];
if (import->ord_only)
fprintf( outfile, " (char *)%d,\n", import->ordinal );
ORDDEF *odp = dll_imports[i]->imports[j];
if (!odp->name)
fprintf( outfile, " (char *)%d,\n", odp->ordinal );
else
fprintf( outfile, " \"%s\",\n", import->name );
fprintf( outfile, " \"%s\",\n", odp->name );
}
}
fprintf( outfile, " }\n};\n\n" );
......@@ -1059,7 +942,10 @@ static int output_delayed_imports( FILE *outfile, const DLLSPEC *spec )
for (j = 0; j < dll_imports[i]->nb_imports; j++)
{
char buffer[128];
sprintf( buffer, "__wine_delay_imp_%d_%s", i, dll_imports[i]->imports[j].name );
ORDDEF *odp = dll_imports[i]->imports[j];
const char *name = odp->name ? odp->name : odp->export_name;
sprintf( buffer, "__wine_delay_imp_%d_%s", i, name );
fprintf( outfile, " \"\\t" __ASM_FUNC("%s") "\\n\"\n", buffer );
fprintf( outfile, " \"" __ASM_NAME("%s") ":\\n\"\n", buffer );
#if defined(__i386__)
......@@ -1088,12 +974,14 @@ static int output_delayed_imports( FILE *outfile, const DLLSPEC *spec )
if (!dll_imports[i]->delay) continue;
for (j = 0; j < dll_imports[i]->nb_imports; j++, pos += 4)
{
struct func *import = &dll_imports[i]->imports[j];
fprintf( outfile, " \"\\t" __ASM_FUNC("%s") "\\n\"\n", import->name );
fprintf( outfile, " \"\\t.globl " __ASM_NAME("%s") "\\n\"\n", import->name );
fprintf( outfile, " \"" __ASM_NAME("%s") ":\\n\\t\"", import->name);
ORDDEF *odp = dll_imports[i]->imports[j];
const char *name = odp->name ? odp->name : odp->export_name;
fprintf( outfile, " \"\\t" __ASM_FUNC("%s") "\\n\"\n", name );
fprintf( outfile, " \"\\t.globl " __ASM_NAME("%s") "\\n\"\n", name );
fprintf( outfile, " \"" __ASM_NAME("%s") ":\\n\\t\"", name );
#if defined(__i386__)
if (strstr( import->name, "__wine_call_from_16" ))
if (strstr( name, "__wine_call_from_16" ))
fprintf( outfile, "\".byte 0x2e\\n\\tjmp *(delay_imports+%d)\\n\\tnop\\n\"", pos );
else
fprintf( outfile, "\"jmp *(delay_imports+%d)\\n\\tmovl %%esi,%%esi\\n\"", pos );
......
......@@ -56,17 +56,17 @@ char **lib_path = NULL;
char *input_file_name = NULL;
const char *output_file_name = NULL;
static FILE *input_file;
static FILE *output_file;
static const char *current_src_dir;
static int nb_res_files;
static char **res_files;
static char *spec_file_name;
/* execution mode */
enum exec_mode_values
{
MODE_NONE,
MODE_SPEC,
MODE_DLL,
MODE_EXE,
MODE_DEF,
MODE_DEBUG,
......@@ -87,7 +87,10 @@ static void set_dll_file_name( const char *name, DLLSPEC *spec )
if ((p = strrchr( name, '/' ))) name = p + 1;
spec->file_name = xmalloc( strlen(name) + 5 );
strcpy( spec->file_name, name );
if ((p = strrchr( spec->file_name, '.' )) && !strcmp( p, ".spec" )) *p = 0;
if ((p = strrchr( spec->file_name, '.' )))
{
if (!strcmp( p, ".spec" ) || !strcmp( p, ".def" )) *p = 0;
}
if (!strchr( spec->file_name, '.' )) strcat( spec->file_name, ".dll" );
}
......@@ -126,7 +129,7 @@ static const char usage_str[] =
" --version Print the version and exit\n"
" -w --warnings Turn on warnings\n"
"\nMode options:\n"
" --spec=FILE.SPEC Build a .c file from a spec file\n"
" --dll=FILE Build a .c file from a .spec or .def file\n"
" --def=FILE.SPEC Build a .def file from a spec file\n"
" --exe=NAME Build a .c file for the named executable\n"
" --debug [FILES] Build a .c file with the debug channels declarations\n"
......@@ -136,7 +139,7 @@ static const char usage_str[] =
enum long_options_values
{
LONG_OPT_SPEC = 1,
LONG_OPT_DLL = 1,
LONG_OPT_DEF,
LONG_OPT_EXE,
LONG_OPT_DEBUG,
......@@ -149,13 +152,14 @@ static const char short_options[] = "C:D:F:H:I:K:L:M:N:d:e:f:hi:kl:m:o:r:w";
static const struct option long_options[] =
{
{ "spec", 1, 0, LONG_OPT_SPEC },
{ "dll", 1, 0, LONG_OPT_DLL },
{ "def", 1, 0, LONG_OPT_DEF },
{ "exe", 1, 0, LONG_OPT_EXE },
{ "debug", 0, 0, LONG_OPT_DEBUG },
{ "relay16", 0, 0, LONG_OPT_RELAY16 },
{ "relay32", 0, 0, LONG_OPT_RELAY32 },
{ "version", 0, 0, LONG_OPT_VERSION },
{ "spec", 1, 0, LONG_OPT_DLL }, /* for backwards compatibility */
/* aliases for short options */
{ "source-dir", 1, 0, 'C' },
{ "delay-lib", 1, 0, 'd' },
......@@ -287,14 +291,14 @@ static char **parse_options( int argc, char **argv, DLLSPEC *spec )
case 'w':
display_warnings = 1;
break;
case LONG_OPT_SPEC:
set_exec_mode( MODE_SPEC );
input_file = open_input_file( NULL, optarg );
case LONG_OPT_DLL:
set_exec_mode( MODE_DLL );
spec_file_name = xstrdup( optarg );
set_dll_file_name( optarg, spec );
break;
case LONG_OPT_DEF:
set_exec_mode( MODE_DEF );
input_file = open_input_file( NULL, optarg );
spec_file_name = xstrdup( optarg );
set_dll_file_name( optarg, spec );
break;
case LONG_OPT_EXE:
......@@ -357,65 +361,59 @@ static void load_resources( char *argv[], DLLSPEC *spec )
}
}
static int parse_input_file( DLLSPEC *spec )
{
FILE *input_file = open_input_file( NULL, spec_file_name );
char *extension = strrchr( spec_file_name, '.' );
if (extension && !strcmp( extension, ".def" ))
return parse_def_file( input_file, spec );
else
return parse_spec_file( input_file, spec );
close_input_file( input_file );
}
/*******************************************************************
* main
*/
int main(int argc, char **argv)
{
DLLSPEC spec;
spec.file_name = NULL;
spec.dll_name = NULL;
spec.owner_name = NULL;
spec.init_func = NULL;
spec.type = SPEC_WIN32;
spec.mode = SPEC_MODE_DLL;
spec.base = MAX_ORDINALS;
spec.limit = 0;
spec.stack_size = 0;
spec.heap_size = 0;
spec.nb_entry_points = 0;
spec.alloc_entry_points = 0;
spec.nb_names = 0;
spec.nb_resources = 0;
spec.entry_points = NULL;
spec.names = NULL;
spec.ordinals = NULL;
spec.resources = NULL;
DLLSPEC *spec = alloc_dll_spec();
output_file = stdout;
argv = parse_options( argc, argv, &spec );
argv = parse_options( argc, argv, spec );
switch(exec_mode)
{
case MODE_SPEC:
load_resources( argv, &spec );
if (!ParseTopLevel( input_file, &spec )) break;
switch (spec.type)
case MODE_DLL:
load_resources( argv, spec );
if (!parse_input_file( spec )) break;
switch (spec->type)
{
case SPEC_WIN16:
if (argv[0])
fatal_error( "file argument '%s' not allowed in this mode\n", argv[0] );
BuildSpec16File( output_file, &spec );
BuildSpec16File( output_file, spec );
break;
case SPEC_WIN32:
read_undef_symbols( argv );
BuildSpec32File( output_file, &spec );
BuildSpec32File( output_file, spec );
break;
default: assert(0);
}
break;
case MODE_EXE:
if (spec.type == SPEC_WIN16) fatal_error( "Cannot build 16-bit exe files\n" );
load_resources( argv, &spec );
if (spec->type == SPEC_WIN16) fatal_error( "Cannot build 16-bit exe files\n" );
load_resources( argv, spec );
read_undef_symbols( argv );
BuildSpec32File( output_file, &spec );
BuildSpec32File( output_file, spec );
break;
case MODE_DEF:
if (argv[0]) fatal_error( "file argument '%s' not allowed in this mode\n", argv[0] );
if (spec.type == SPEC_WIN16) fatal_error( "Cannot yet build .def file for 16-bit dlls\n" );
if (!ParseTopLevel( input_file, &spec )) break;
BuildDef32File( output_file, &spec );
if (spec->type == SPEC_WIN16) fatal_error( "Cannot yet build .def file for 16-bit dlls\n" );
if (!parse_input_file( spec )) break;
BuildDef32File( output_file, spec );
break;
case MODE_DEBUG:
BuildDebugFile( output_file, current_src_dir, argv );
......
......@@ -3,7 +3,7 @@
*
* Copyright 1993 Robert J. Amstadt
* Copyright 1995 Martin von Loewis
* Copyright 1995, 1996, 1997 Alexandre Julliard
* Copyright 1995, 1996, 1997, 2004 Alexandre Julliard
* Copyright 1997 Eric Youngdale
* Copyright 1999 Ulrich Weigand
*
......@@ -43,6 +43,9 @@ static char TokenBuffer[512];
static char *ParseNext = ParseBuffer;
static FILE *input_file;
static const char *separator_chars;
static const char *comment_chars;
static const char * const TypeNames[TYPE_NBTYPES] =
{
"variable", /* TYPE_VARIABLE */
......@@ -76,7 +79,12 @@ static int IsNumberString(const char *s)
inline static int is_token_separator( char ch )
{
return (ch == '(' || ch == ')' || ch == '-');
return strchr( separator_chars, ch ) != NULL;
}
inline static int is_token_comment( char ch )
{
return strchr( comment_chars, ch ) != NULL;
}
/* get the next line from the input file, or return 0 if at eof */
......@@ -109,7 +117,7 @@ static const char * GetToken( int allow_eol )
else break;
}
if ((*p == '\0') || (*p == '#'))
if ((*p == '\0') || is_token_comment(*p))
{
if (!allow_eol) error( "Declaration not terminated properly\n" );
return NULL;
......@@ -146,11 +154,11 @@ static ORDDEF *add_entry_point( DLLSPEC *spec )
}
/*******************************************************************
* ParseVariable
* parse_spec_variable
*
* Parse a variable definition.
* Parse a variable definition in a .spec file.
*/
static int ParseVariable( ORDDEF *odp, DLLSPEC *spec )
static int parse_spec_variable( ORDDEF *odp, DLLSPEC *spec )
{
char *endptr;
int *value_array;
......@@ -208,11 +216,11 @@ static int ParseVariable( ORDDEF *odp, DLLSPEC *spec )
/*******************************************************************
* ParseExportFunction
* parse_spec_export
*
* Parse a function definition.
* Parse an exported function definition in a .spec file.
*/
static int ParseExportFunction( ORDDEF *odp, DLLSPEC *spec )
static int parse_spec_export( ORDDEF *odp, DLLSPEC *spec )
{
const char *token;
unsigned int i;
......@@ -330,11 +338,11 @@ static int ParseExportFunction( ORDDEF *odp, DLLSPEC *spec )
/*******************************************************************
* ParseEquate
* parse_spec_equate
*
* Parse an 'equate' definition.
* Parse an 'equate' definition in a .spec file.
*/
static int ParseEquate( ORDDEF *odp, DLLSPEC *spec )
static int parse_spec_equate( ORDDEF *odp, DLLSPEC *spec )
{
char *endptr;
int value;
......@@ -358,11 +366,11 @@ static int ParseEquate( ORDDEF *odp, DLLSPEC *spec )
/*******************************************************************
* ParseStub
* parse_spec_stub
*
* Parse a 'stub' definition.
* Parse a 'stub' definition in a .spec file
*/
static int ParseStub( ORDDEF *odp, DLLSPEC *spec )
static int parse_spec_stub( ORDDEF *odp, DLLSPEC *spec )
{
odp->u.func.arg_types[0] = '\0';
odp->link_name = xstrdup("");
......@@ -371,11 +379,11 @@ static int ParseStub( ORDDEF *odp, DLLSPEC *spec )
/*******************************************************************
* ParseExtern
* parse_spec_extern
*
* Parse an 'extern' definition.
* Parse an 'extern' definition in a .spec file.
*/
static int ParseExtern( ORDDEF *odp, DLLSPEC *spec )
static int parse_spec_extern( ORDDEF *odp, DLLSPEC *spec )
{
const char *token;
......@@ -403,11 +411,11 @@ static int ParseExtern( ORDDEF *odp, DLLSPEC *spec )
/*******************************************************************
* ParseFlags
* parse_spec_flags
*
* Parse the optional flags for an entry point
* Parse the optional flags for an entry point in a .spec file.
*/
static const char *ParseFlags( ORDDEF *odp )
static const char *parse_spec_flags( ORDDEF *odp )
{
unsigned int i;
const char *token;
......@@ -429,26 +437,13 @@ static const char *ParseFlags( ORDDEF *odp )
return token;
}
/*******************************************************************
* fix_export_name
*
* Fix an exported function name by removing a possible @xx suffix
*/
static void fix_export_name( char *name )
{
char *p, *end = strrchr( name, '@' );
if (!end || !end[1] || end == name) return;
/* make sure all the rest is digits */
for (p = end + 1; *p; p++) if (!isdigit(*p)) return;
*end = 0;
}
/*******************************************************************
* ParseOrdinal
* parse_spec_ordinal
*
* Parse an ordinal definition.
* Parse an ordinal definition in a .spec file.
*/
static int ParseOrdinal( int ordinal, DLLSPEC *spec )
static int parse_spec_ordinal( int ordinal, DLLSPEC *spec )
{
const char *token;
......@@ -468,32 +463,32 @@ static int ParseOrdinal( int ordinal, DLLSPEC *spec )
}
if (!(token = GetToken(0))) goto error;
if (*token == '-' && !(token = ParseFlags( odp ))) goto error;
if (*token == '-' && !(token = parse_spec_flags( odp ))) goto error;
odp->name = xstrdup( token );
fix_export_name( odp->name );
remove_stdcall_decoration( odp->name );
odp->lineno = current_line;
odp->ordinal = ordinal;
switch(odp->type)
{
case TYPE_VARIABLE:
if (!ParseVariable( odp, spec )) goto error;
if (!parse_spec_variable( odp, spec )) goto error;
break;
case TYPE_PASCAL:
case TYPE_STDCALL:
case TYPE_VARARGS:
case TYPE_CDECL:
if (!ParseExportFunction( odp, spec )) goto error;
if (!parse_spec_export( odp, spec )) goto error;
break;
case TYPE_ABS:
if (!ParseEquate( odp, spec )) goto error;
if (!parse_spec_equate( odp, spec )) goto error;
break;
case TYPE_STUB:
if (!ParseStub( odp, spec )) goto error;
if (!parse_spec_stub( odp, spec )) goto error;
break;
case TYPE_EXTERN:
if (!ParseExtern( odp, spec )) goto error;
if (!parse_spec_extern( odp, spec )) goto error;
break;
default:
assert( 0 );
......@@ -641,17 +636,20 @@ static void assign_ordinals( DLLSPEC *spec )
/*******************************************************************
* ParseTopLevel
* parse_spec_file
*
* Parse a spec file.
* Parse a .spec file.
*/
int ParseTopLevel( FILE *file, DLLSPEC *spec )
int parse_spec_file( FILE *file, DLLSPEC *spec )
{
const char *token;
input_file = file;
current_line = 0;
comment_chars = "#;";
separator_chars = "()-";
while (get_next_line())
{
if (!(token = GetToken(1))) continue;
......@@ -662,11 +660,11 @@ int ParseTopLevel( FILE *file, DLLSPEC *spec )
error( "'@' ordinals not supported for Win16\n" );
continue;
}
if (!ParseOrdinal( -1, spec )) continue;
if (!parse_spec_ordinal( -1, spec )) continue;
}
else if (IsNumberString(token))
{
if (!ParseOrdinal( atoi(token), spec )) continue;
if (!parse_spec_ordinal( atoi(token), spec )) continue;
}
else
{
......@@ -684,6 +682,243 @@ int ParseTopLevel( FILE *file, DLLSPEC *spec )
/*******************************************************************
* parse_def_library
*
* Parse a LIBRARY declaration in a .def file.
*/
static int parse_def_library( DLLSPEC *spec )
{
const char *token = GetToken(1);
if (!token) return 1;
if (strcmp( token, "BASE" ))
{
free( spec->file_name );
spec->file_name = xstrdup( token );
if (!(token = GetToken(1))) return 1;
}
if (strcmp( token, "BASE" ))
{
error( "Expected library name or BASE= declaration, got '%s'\n", token );
return 0;
}
if (!(token = GetToken(0))) return 0;
if (strcmp( token, "=" ))
{
error( "Expected '=' after BASE, got '%s'\n", token );
return 0;
}
if (!(token = GetToken(0))) return 0;
/* FIXME: do something with base address */
return 1;
}
/*******************************************************************
* parse_def_stack_heap_size
*
* Parse a STACKSIZE or HEAPSIZE declaration in a .def file.
*/
static int parse_def_stack_heap_size( int is_stack, DLLSPEC *spec )
{
const char *token = GetToken(0);
char *end;
unsigned long size;
if (!token) return 0;
size = strtoul( token, &end, 0 );
if (*end)
{
error( "Invalid number '%s'\n", token );
return 0;
}
if (is_stack) spec->stack_size = size / 1024;
else spec->heap_size = size / 1024;
if (!(token = GetToken(1))) return 1;
if (strcmp( token, "," ))
{
error( "Expected ',' after size, got '%s'\n", token );
return 0;
}
if (!(token = GetToken(0))) return 0;
/* FIXME: do something with reserve size */
return 1;
}
/*******************************************************************
* parse_def_export
*
* Parse an export declaration in a .def file.
*/
static int parse_def_export( char *name, DLLSPEC *spec )
{
int i, args;
const char *token = GetToken(1);
ORDDEF *odp = add_entry_point( spec );
memset( odp, 0, sizeof(*odp) );
odp->lineno = current_line;
odp->ordinal = -1;
odp->name = name;
args = remove_stdcall_decoration( odp->name );
if (args == -1) odp->type = TYPE_CDECL;
else
{
odp->type = TYPE_STDCALL;
args /= sizeof(int);
if (args >= sizeof(odp->u.func.arg_types))
{
error( "Too many arguments in stdcall function '%s'\n", odp->name );
return 0;
}
for (i = 0; i < args; i++) odp->u.func.arg_types[i] = 'l';
}
/* check for optional internal name */
if (token && !strcmp( token, "=" ))
{
if (!(token = GetToken(0))) goto error;
odp->link_name = xstrdup( token );
remove_stdcall_decoration( odp->link_name );
token = GetToken(1);
}
/* check for optional ordinal */
if (token && token[0] == '@')
{
int ordinal;
if (!IsNumberString( token+1 ))
{
error( "Expected number after '@', got '%s'\n", token+1 );
goto error;
}
ordinal = atoi( token+1 );
if (!ordinal)
{
error( "Ordinal 0 is not valid\n" );
goto error;
}
if (ordinal >= MAX_ORDINALS)
{
error( "Ordinal number %d too large\n", ordinal );
goto error;
}
if (ordinal > spec->limit) spec->limit = ordinal;
if (ordinal < spec->base) spec->base = ordinal;
odp->ordinal = ordinal;
token = GetToken(1);
}
/* check for other optional keywords */
if (token && !strcmp( token, "NONAME" ))
{
if (odp->ordinal == -1)
{
error( "NONAME requires an ordinal\n" );
goto error;
}
odp->export_name = odp->name;
odp->name = NULL;
odp->flags |= FLAG_NONAME;
token = GetToken(1);
}
if (token && !strcmp( token, "PRIVATE" ))
{
odp->flags |= FLAG_PRIVATE;
token = GetToken(1);
}
if (token && !strcmp( token, "DATA" ))
{
odp->type = TYPE_EXTERN;
token = GetToken(1);
}
if (token)
{
error( "Garbage text '%s' found at end of export declaration\n", token );
goto error;
}
return 1;
error:
spec->nb_entry_points--;
free( odp->name );
return 0;
}
/*******************************************************************
* parse_def_file
*
* Parse a .def file.
*/
int parse_def_file( FILE *file, DLLSPEC *spec )
{
const char *token;
int in_exports = 0;
input_file = file;
current_line = 0;
comment_chars = ";";
separator_chars = ",=";
while (get_next_line())
{
if (!(token = GetToken(1))) continue;
if (!strcmp( token, "LIBRARY" ) || !strcmp( token, "NAME" ))
{
if (!parse_def_library( spec )) continue;
goto end_of_line;
}
else if (!strcmp( token, "STACKSIZE" ))
{
if (!parse_def_stack_heap_size( 1, spec )) continue;
goto end_of_line;
}
else if (!strcmp( token, "HEAPSIZE" ))
{
if (!parse_def_stack_heap_size( 0, spec )) continue;
goto end_of_line;
}
else if (!strcmp( token, "EXPORTS" ))
{
in_exports = 1;
if (!(token = GetToken(1))) continue;
}
else if (!strcmp( token, "IMPORTS" ))
{
in_exports = 0;
if (!(token = GetToken(1))) continue;
}
else if (!strcmp( token, "SECTIONS" ))
{
in_exports = 0;
if (!(token = GetToken(1))) continue;
}
if (!in_exports) continue; /* ignore this line */
if (!parse_def_export( xstrdup(token), spec )) continue;
end_of_line:
if ((token = GetToken(1))) error( "Syntax error near '%s'\n", token );
}
current_line = 0; /* no longer parsing the input file */
assign_names( spec );
assign_ordinals( spec );
return !nb_errors;
}
/*******************************************************************
* add_debug_channel
*/
static void add_debug_channel( const char *name )
......
......@@ -210,6 +210,83 @@ void close_input_file( FILE *file )
/*******************************************************************
* remove_stdcall_decoration
*
* Remove a possible @xx suffix from a function name.
* Return the numerical value of the suffix, or -1 if none.
*/
int remove_stdcall_decoration( char *name )
{
char *p, *end = strrchr( name, '@' );
if (!end || !end[1] || end == name) return -1;
/* make sure all the rest is digits */
for (p = end + 1; *p; p++) if (!isdigit(*p)) return -1;
*end = 0;
return atoi( end + 1 );
}
/*******************************************************************
* alloc_dll_spec
*
* Create a new dll spec file descriptor
*/
DLLSPEC *alloc_dll_spec(void)
{
DLLSPEC *spec;
spec = xmalloc( sizeof(*spec) );
spec->file_name = NULL;
spec->dll_name = NULL;
spec->owner_name = NULL;
spec->init_func = NULL;
spec->type = SPEC_WIN32;
spec->mode = SPEC_MODE_DLL;
spec->base = MAX_ORDINALS;
spec->limit = 0;
spec->stack_size = 0;
spec->heap_size = 0;
spec->nb_entry_points = 0;
spec->alloc_entry_points = 0;
spec->nb_names = 0;
spec->nb_resources = 0;
spec->entry_points = NULL;
spec->names = NULL;
spec->ordinals = NULL;
spec->resources = NULL;
return spec;
}
/*******************************************************************
* free_dll_spec
*
* Free dll spec file descriptor
*/
void free_dll_spec( DLLSPEC *spec )
{
int i;
for (i = 0; i < spec->nb_entry_points; i++)
{
ORDDEF *odp = &spec->entry_points[i];
free( odp->name );
free( odp->export_name );
free( odp->link_name );
}
free( spec->file_name );
free( spec->dll_name );
free( spec->owner_name );
free( spec->init_func );
free( spec->entry_points );
free( spec->names );
free( spec->ordinals );
free( spec->resources );
free( spec );
}
/*******************************************************************
* make_c_identifier
*
* Map a string to a valid C identifier.
......
......@@ -19,10 +19,11 @@ option can be specified, as described in the \fBOPTIONS\fR section.
You have to specify exactly one of the following options, depending on
what you want winebuild to generate.
.TP
.BI \--spec=\ file.spec
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.
.BI \--dll=\ filename
Build a C file from a .spec file (see \fBSPEC FILE SYNTAX\fR for
details), or from a standard Windows .def file. The resulting C file
must be compiled and linked to the other object files to build a
working Wine dll.
.br
In that mode, the
.I input files
......@@ -34,7 +35,7 @@ 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,
the --dll 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, and all the other object files must be listed
......@@ -130,7 +131,7 @@ imported from it is actually called).
.BI \-M,\ --main-module= module
Specify that we are building a 16-bit dll, that will ultimately be
linked together with the 32-bit dll specified in \fImodule\fR. Only
meaningful in \fB--spec\fR mode.
meaningful in \fB--dll\fR mode.
.TP
.BI \-m,\ --mode= mode
Set the executable or dll mode, which can be one of the following:
......
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