Added support in winebuild for specifying import libraries directly on the command line without the -l option. Changed the -d option to only mark the library as delayed, the actual loading is now done separately.
diff --git a/dlls/Makedll.rules.in b/dlls/Makedll.rules.in index b7fe639..ae3c02b 100644 --- a/dlls/Makedll.rules.in +++ b/dlls/Makedll.rules.in
@@ -16,9 +16,10 @@ MAINSPEC = $(MODULE:%.dll=%).spec SPEC_DEF = $(MAINSPEC).def WIN16_FILES = $(SPEC_SRCS16:.spec=.spec.o) $(C_SRCS16:.c=.o) $(EXTRA_OBJS16) -ALL_OBJS = @WIN16_FILES@ $(OBJS) $(MODULE).dbg.o +ALL_OBJS = @WIN16_FILES@ $(OBJS) $(MODULE).dbg.o $(RC_SRCS:.rc=.res) ALL_LIBS = $(LIBWINE) $(EXTRALIBS) $(LIBPORT) $(LDFLAGS) $(LIBS) -IMPORTLIBS = $(DELAYIMPORTS:%=$(DLLDIR)/lib%.$(IMPLIBEXT)) $(IMPORTS:%=$(DLLDIR)/lib%.$(IMPLIBEXT)) +ALL_IMPORTS = $(DELAYIMPORTS) $(IMPORTS) +IMPORTLIBS = $(ALL_IMPORTS:%=$(DLLDIR)/lib%.$(IMPLIBEXT)) all: $(MODULE)$(DLLEXT) $(SUBDIRS) @@ -26,13 +27,13 @@ # Rules for .so files -$(MODULE).so: $(MAINSPEC) $(RC_SRCS:.rc=.res) $(ALL_OBJS) $(IMPORTLIBS) Makefile.in - $(WINEGCC) -B$(TOOLSDIR)/tools/winebuild -shared $(SRCDIR)/$(MAINSPEC) $(ALL_OBJS) $(RC_SRCS:.rc=.res) $(SUBSYSTEM:%=-Wb,--subsystem,%) -o $@ -L$(DLLDIR) $(DELAYIMPORTS:%=-Wb,-d%) $(IMPORTS:%=-l%) $(ALL_LIBS) +$(MODULE).so: $(MAINSPEC) $(ALL_OBJS) $(IMPORTLIBS) Makefile.in + $(WINEGCC) -B$(TOOLSDIR)/tools/winebuild -shared $(SRCDIR)/$(MAINSPEC) $(ALL_OBJS) $(SUBSYSTEM:%=-Wb,--subsystem,%) -o $@ -L$(DLLDIR) $(ALL_IMPORTS:%=-l%) $(DELAYIMPORTS:%=-Wb,-d%) $(ALL_LIBS) # Rules for .dll files $(MODULE): $(RCOBJS) $(OBJS) $(MODULE).dbg.o $(SPEC_DEF) $(IMPORTLIBS) Makefile.in - $(DLLWRAP) -k --def $(SPEC_DEF) -o $@ $(RCOBJS) $(OBJS) $(MODULE).dbg.o -L$(DLLDIR) $(DELAYIMPORTS:%=-l%) $(IMPORTS:%=-l%) $(ALL_LIBS) + $(DLLWRAP) -k --def $(SPEC_DEF) -o $@ $(RCOBJS) $(OBJS) $(MODULE).dbg.o -L$(DLLDIR) $(ALL_IMPORTS:%=-l%) $(ALL_LIBS) $(SPEC_DEF): $(WINEBUILD) @@ -55,8 +56,8 @@ # Rule to explicitly generate the .spec.c for debugging -$(MAINSPEC).c: $(MAINSPEC) $(RC_SRCS:.rc=.res) $(ALL_OBJS) $(IMPORTLIBS) $(WINEBUILD) - $(WINEBUILD) $(DEFS) $(DLLFLAGS) --dll -o $@ --export $(SRCDIR)/$(MAINSPEC) $(SUBSYSTEM:%=--subsystem %) $(RC_SRCS:.rc=.res) $(ALL_OBJS) -L$(DLLDIR) $(DELAYIMPORTS:%=-d%) $(IMPORTS:%=-l%) +$(MAINSPEC).c: $(MAINSPEC) $(ALL_OBJS) $(IMPORTLIBS) $(WINEBUILD) + $(WINEBUILD) $(DEFS) $(DLLFLAGS) --dll -o $@ --export $(SRCDIR)/$(MAINSPEC) $(SUBSYSTEM:%=--subsystem %) $(ALL_OBJS) -L$(DLLDIR) $(ALL_IMPORTS:%=-l%) $(DELAYIMPORTS:%=-d%) # Rules for auto documentation
diff --git a/programs/Makeprog.rules.in b/programs/Makeprog.rules.in index b6089b2..0e94df5 100644 --- a/programs/Makeprog.rules.in +++ b/programs/Makeprog.rules.in
@@ -13,9 +13,9 @@ DLLFLAGS = @DLLFLAGS@ DEFS = $(DLLDEFS) $(EXTRADEFS) ALL_OBJS = $(OBJS) $(MODULE).dbg.o -ALL_LIBS = $(IMPORTS:%=-l%) $(LIBWINE) $(EXTRALIBS) $(LIBPORT) $(LDFLAGS) $(LIBS) +ALL_IMPORTS = $(DELAYIMPORTS) $(IMPORTS) +ALL_LIBS = $(ALL_IMPORTS:%=-l%) $(LIBWINE) $(EXTRALIBS) $(LIBPORT) $(LDFLAGS) $(LIBS) BASEMODULE = $(MODULE:.exe=) -TESTIMPORTS = $(DELAYIMPORTS) $(IMPORTS) RUNTESTFLAGS= -q -P wine -T $(TOPOBJDIR) @MAKE_RULES@ @@ -25,7 +25,7 @@ # Rules for .so main module $(MODULE).so: $(ALL_OBJS) $(RC_SRCS:.rc=.res) Makefile.in - $(WINEGCC) -B$(TOOLSDIR)/tools/winebuild $(APPMODE) $(ALL_OBJS) $(RC_SRCS:.rc=.res) -o $@ -L$(DLLDIR) $(DELAYIMPORTS:%=-Wb,-d%) $(ALL_LIBS) + $(WINEGCC) -B$(TOOLSDIR)/tools/winebuild $(APPMODE) $(ALL_OBJS) $(RC_SRCS:.rc=.res) -o $@ -L$(DLLDIR) $(ALL_LIBS) $(DELAYIMPORTS:%=-Wb,-d%) $(BASEMODULE): $(WINEWRAPPER) $(RM) $@ && $(LN_S) $(WINEWRAPPER) $@ @@ -33,7 +33,7 @@ # Rules for .exe main module $(MODULE): $(ALL_OBJS) $(RCOBJS) Makefile.in - $(CC) $(APPMODE) $(ALL_OBJS) $(RCOBJS) -o $@ $(DELAYIMPORTS:%=-l%) $(ALL_LIBS) + $(CC) $(APPMODE) $(ALL_OBJS) $(RCOBJS) -o $@ $(ALL_LIBS) # Rules for testing
diff --git a/tools/winebuild/build.h b/tools/winebuild/build.h index 99d8cab..4109831 100644 --- a/tools/winebuild/build.h +++ b/tools/winebuild/build.h
@@ -148,6 +148,7 @@ extern void *xrealloc (void *ptr, size_t size); extern char *xstrdup( const char *str ); extern char *strupper(char *s); +extern int strendswith(const char* str, const char* end); extern void fatal_error( const char *msg, ... ) __attribute__ ((__format__ (__printf__, 1, 2))); extern void fatal_perror( const char *msg, ... ) @@ -167,7 +168,8 @@ extern const char *make_c_identifier( const char *str ); extern int get_alignment(int alignBoundary); -extern void add_import_dll( const char *name, int delay ); +extern void add_import_dll( const char *name, const char *filename ); +extern void add_delayed_import( const char *name ); extern void add_ignore_symbol( const char *name ); extern void read_undef_symbols( char **argv ); extern int resolve_imports( DLLSPEC *spec );
diff --git a/tools/winebuild/import.c b/tools/winebuild/import.c index ec17fe8..9c94ca0 100644 --- a/tools/winebuild/import.c +++ b/tools/winebuild/import.c
@@ -27,6 +27,9 @@ #include <stdio.h> #include <string.h> #include <stdarg.h> +#ifdef HAVE_SYS_STAT_H +# include <sys/stat.h> +#endif #ifdef HAVE_UNISTD_H # include <unistd.h> #endif @@ -37,7 +40,10 @@ struct import { - DLLSPEC *spec; /* description of the imported dll */ + DLLSPEC *spec; /* description of the imported dll */ + char *full_name; /* full name of the input file */ + dev_t dev; /* device/inode of the input file */ + ino_t ino; int delay; /* delay or not dll loading ? */ ORDDEF **exports; /* functions exported from this dll */ int nb_exports; /* number of exported functions */ @@ -60,6 +66,8 @@ static int nb_delayed = 0; /* number of delayed dlls */ static int total_imports = 0; /* total number of imported functions */ static int total_delayed = 0; /* total number of imported functions in delayed DLLs */ +static char **delayed_imports; /* names of delayed import dlls */ +static int nb_delayed_imports; /* size of the delayed_imports array */ /* list of symbols that are ignored by default */ static const char * const default_ignored_symbols[] = @@ -189,6 +197,7 @@ free( imp->exports ); free( imp->imports ); free_dll_spec( imp->spec ); + free( imp->full_name ); free( imp ); } @@ -198,16 +207,28 @@ if (ld_tmp_file) unlink( ld_tmp_file ); } +/* check whether a given dll is imported in delayed mode */ +static int is_delayed_import( const char *name ) +{ + int i; + + for (i = 0; i < nb_delayed_imports; i++) + { + if (!strcmp( delayed_imports[i], name )) return 1; + } + return 0; +} + /* check whether a given dll has already been imported */ -static int is_already_imported( const char *name ) +static struct import *is_already_imported( const char *name ) { int i; for (i = 0; i < nb_imports; i++) { - if (!strcmp( dll_imports[i]->spec->file_name, name )) return 1; + if (!strcmp( dll_imports[i]->spec->file_name, name )) return dll_imports[i]; } - return 0; + return NULL; } /* open the .so library for a given dll in a specified path */ @@ -229,8 +250,8 @@ return NULL; } -/* open the .so library for a given dll */ -static char *open_library( const char *name ) +/* find the .def import library for a given dll */ +static char *find_library( const char *name ) { char *fullname; int i; @@ -244,24 +265,36 @@ } /* read in the list of exported symbols of an import library */ -static int read_import_lib( const char *name, struct import *imp ) +static int read_import_lib( struct import *imp ) { FILE *f; - char *fullname; int i, ret; + struct stat stat; + struct import *prev_imp; DLLSPEC *spec = imp->spec; - imp->exports = NULL; - imp->nb_exports = 0; - - fullname = open_library( name ); - f = open_input_file( NULL, fullname ); - free( fullname ); - + f = open_input_file( NULL, imp->full_name ); + fstat( fileno(f), &stat ); + imp->dev = stat.st_dev; + imp->ino = stat.st_ino; ret = parse_def_file( f, spec ); close_input_file( f ); if (!ret) return 0; - if (is_already_imported( spec->file_name )) return 0; + + /* check if we already imported that library from a different file */ + if ((prev_imp = is_already_imported( spec->file_name ))) + { + if (prev_imp->dev != imp->dev || prev_imp->ino != imp->ino) + fatal_error( "%s and %s have the same export name '%s'\n", + prev_imp->full_name, imp->full_name, spec->file_name ); + return 0; /* the same file was already loaded, ignore this one */ + } + + if (is_delayed_import( spec->file_name )) + { + imp->delay = 1; + nb_delayed++; + } imp->exports = xmalloc( spec->nb_entry_points * sizeof(*imp->exports) ); @@ -279,32 +312,47 @@ return 1; } -/* add a dll to the list of imports */ -void add_import_dll( const char *name, int delay ) +/* build the dll exported name from the import lib name or path */ +static char *get_dll_name( const char *name, const char *filename ) { - struct import *imp; - char *fullname; + char *ret; - fullname = xmalloc( strlen(name) + 5 ); - strcpy( fullname, name ); - if (!strchr( fullname, '.' )) strcat( fullname, ".dll" ); - - /* check if we already imported it */ - if (is_already_imported( fullname )) + if (filename) { - free( fullname ); - return; + const char *basename = strrchr( filename, '/' ); + if (!basename) basename = filename; + else basename++; + if (!strncmp( basename, "lib", 3 )) basename += 3; + ret = xmalloc( strlen(basename) + 5 ); + strcpy( ret, basename ); + if (strendswith( ret, ".def" )) ret[strlen(ret)-4] = 0; } + else + { + ret = xmalloc( strlen(name) + 5 ); + strcpy( ret, name ); + } + if (!strchr( ret, '.' )) strcat( ret, ".dll" ); + return ret; +} - imp = xmalloc( sizeof(*imp) ); +/* add a dll to the list of imports */ +void add_import_dll( const char *name, const char *filename ) +{ + struct import *imp = xmalloc( sizeof(*imp) ); + imp->spec = alloc_dll_spec(); - imp->spec->file_name = fullname; - imp->delay = delay; + imp->spec->file_name = get_dll_name( name, filename ); + imp->delay = 0; imp->imports = NULL; imp->nb_imports = 0; - if (delay) nb_delayed++; + imp->exports = NULL; + imp->nb_exports = 0; - if (read_import_lib( name, imp )) + if (filename) imp->full_name = xstrdup( filename ); + else imp->full_name = find_library( name ); + + if (read_import_lib( imp )) { dll_imports = xrealloc( dll_imports, (nb_imports+1) * sizeof(*dll_imports) ); dll_imports[nb_imports++] = imp; @@ -316,6 +364,21 @@ } } +/* add a library to the list of delayed imports */ +void add_delayed_import( const char *name ) +{ + struct import *imp; + char *fullname = get_dll_name( name, NULL ); + + delayed_imports = xrealloc( delayed_imports, (nb_delayed_imports+1) * sizeof(*delayed_imports) ); + delayed_imports[nb_delayed_imports++] = fullname; + if ((imp = is_already_imported( fullname )) && !imp->delay) + { + imp->delay = 1; + nb_delayed++; + } +} + /* remove an imported dll, based on its index in the dll_imports array */ static void remove_import_dll( int index ) { @@ -477,8 +540,8 @@ ntdll_imports += add_extra_symbol( extras, &count, "RtlRaiseException", spec ); /* make sure we import the dlls that contain these functions */ - if (kernel_imports) add_import_dll( "kernel32", 0 ); - if (ntdll_imports) add_import_dll( "ntdll", 0 ); + if (kernel_imports) add_import_dll( "kernel32", NULL ); + if (ntdll_imports) add_import_dll( "ntdll", NULL ); if (count) {
diff --git a/tools/winebuild/main.c b/tools/winebuild/main.c index 0755a2a..ebd4051 100644 --- a/tools/winebuild/main.c +++ b/tools/winebuild/main.c
@@ -281,7 +281,7 @@ spec->dll_name = xstrdup( optarg ); break; case 'd': - add_import_dll( optarg, 1 ); + add_delayed_import( optarg ); break; case 'e': spec->init_func = xstrdup( optarg ); @@ -310,7 +310,7 @@ kill_at = 1; break; case 'l': - add_import_dll( optarg, 0 ); + add_import_dll( optarg, NULL ); break; case 'o': if (unlink( optarg ) == -1 && errno != ENOENT) @@ -401,6 +401,21 @@ } } +/* add input files that look like import libs to the import list */ +static void load_import_libs( char *argv[] ) +{ + char **ptr, **last; + + for (ptr = last = argv; *ptr; ptr++) + { + if (strendswith( *ptr, ".def" )) + add_import_dll( NULL, *ptr ); + else + *last++ = *ptr; /* not an import dll, keep it in the list */ + } + *last = NULL; +} + static int parse_input_file( DLLSPEC *spec ) { FILE *input_file = open_input_file( NULL, spec_file_name ); @@ -437,6 +452,7 @@ case MODE_DLL: spec->characteristics |= IMAGE_FILE_DLL; load_resources( argv, spec ); + load_import_libs( argv ); if (!spec_file_name) fatal_error( "missing .spec file\n" ); if (!parse_input_file( spec )) break; switch (spec->type) @@ -457,6 +473,7 @@ if (spec->type == SPEC_WIN16) fatal_error( "Cannot build 16-bit exe files\n" ); if (!spec->file_name) fatal_error( "executable must be named via the -F option\n" ); load_resources( argv, spec ); + load_import_libs( argv ); if (spec_file_name && !parse_input_file( spec )) break; read_undef_symbols( argv ); BuildSpec32File( output_file, spec );
diff --git a/tools/winebuild/utils.c b/tools/winebuild/utils.c index 0bdd0a3..c66c8dc 100644 --- a/tools/winebuild/utils.c +++ b/tools/winebuild/utils.c
@@ -71,6 +71,13 @@ return s; } +int strendswith(const char* str, const char* end) +{ + int l = strlen(str); + int m = strlen(end); + return l >= m && strcmp(str + l - m, end) == 0; +} + void fatal_error( const char *msg, ... ) { va_list valist;
diff --git a/tools/winebuild/winebuild.man.in b/tools/winebuild/winebuild.man.in index cca9dcf..108a879 100644 --- a/tools/winebuild/winebuild.man.in +++ b/tools/winebuild/winebuild.man.in
@@ -69,6 +69,12 @@ meaningful in .BR \--debug\ mode. .TP +.BI \-d,\ --delay-lib= name +Set the delayed import mode for the specified library, which must be +one of the libraries imported with the \fB-l\fR option. Delayed mode +means that the library won't be loaded until a function imported from +it is actually called. +.TP .BI \-D\ symbol Ignored for compatibility with the C compiler. .TP @@ -138,11 +144,6 @@ \fIlibname.def\fR file in the directories specified with the \fB-L\fR option. .TP -.BI \-d,\ --delay-lib= name -Same as the \fB-l\fR option, but import the specified library in -delayed mode (i.e. the library won't be loaded until a function -imported from it is actually called). -.TP .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