From 6f74b45a81f8e7763d2534476e313c0774160876 Mon Sep 17 00:00:00 2001 From: Alexandre Julliard Date: Sat, 30 May 2009 15:24:07 +0200 Subject: [PATCH] winegcc: Add support for building PE executables using Mingw. --- dlls/Makedll.rules.in | 4 +- dlls/Maketest.rules.in | 2 +- programs/Makeprog.rules.in | 4 +- programs/winetest/Makefile.in | 2 +- tools/winegcc/utils.c | 34 +++---- tools/winegcc/utils.h | 12 ++- tools/winegcc/winegcc.c | 163 ++++++++++++++++++++++++++-------- 7 files changed, 163 insertions(+), 58 deletions(-) diff --git a/dlls/Makedll.rules.in b/dlls/Makedll.rules.in index 76747b6c418..29ee76a5c76 100644 --- a/dlls/Makedll.rules.in +++ b/dlls/Makedll.rules.in @@ -35,8 +35,8 @@ $(MODULE).so: $(MAINSPEC) $(ALL_OBJS) Makefile.in # Rules for .dll files -$(MODULE): $(RCOBJS) $(OBJS) $(SPEC_DEF) Makefile.in - $(DLLWRAP) -k --def $(SPEC_DEF) -o $@ $(RCOBJS) $(OBJS) $(DLL_LDPATH) $(DELAYIMPORTS:%=-l%) $(IMPORTS:%=-l%) $(LIBWINE) $(ALL_LIBS) +$(MODULE): $(MAINSPEC) $(RCOBJS) $(OBJS) Makefile.in + $(WINEGCC) -shared $(SRCDIR)/$(MAINSPEC) $(OBJS) $(RCOBJS) $(EXTRADLLFLAGS) -o $@ $(DELAYIMPORTS:%=-l%) $(IMPORTS:%=-l%) $(ALL_LIBS) # Rules for import libraries diff --git a/dlls/Maketest.rules.in b/dlls/Maketest.rules.in index 05a9774611e..58bd3a39e36 100644 --- a/dlls/Maketest.rules.in +++ b/dlls/Maketest.rules.in @@ -38,7 +38,7 @@ $(MODULE).so: $(OBJS) $(RC_SRCS:.rc=.res) Makefile.in # Rules for .exe main module $(MODULE): $(OBJS) $(RCOBJS) Makefile.in - $(CC) $(APPMODE) $(OBJS) $(RCOBJS) -o $@ -L$(DLLDIR) $(IMPORTS:%=-L$(DLLDIR)/%) $(ALL_LIBS) + $(WINEGCC) $(APPMODE) $(OBJS) $(RCOBJS) -o $@ $(LIBPORT) $(ALL_LIBS) # Rules for building test list diff --git a/programs/Makeprog.rules.in b/programs/Makeprog.rules.in index add239f59cf..95772f3d26d 100644 --- a/programs/Makeprog.rules.in +++ b/programs/Makeprog.rules.in @@ -11,7 +11,7 @@ DLLFLAGS = @DLLFLAGS@ DEFS = $(EXTRADEFS) -ALL_LIBS = $(DELAYIMPORTS:%=-l%) $(IMPORTS:%=-l%) $(EXTRALIBS) $(LIBPORT) $(LDFLAGS) $(LIBS) +ALL_LIBS = $(DELAYIMPORTS:%=-l%) $(IMPORTS:%=-l%) $(EXTRALIBS) -lwine $(LIBPORT) $(LDFLAGS) $(LIBS) RUNTESTFLAGS= -q -P wine -T $(TOPOBJDIR) INSTALLDIRS = $(DESTDIR)$(bindir) $(DESTDIR)$(dlldir) $(DESTDIR)$(mandir)/man$(prog_manext) @@ -27,7 +27,7 @@ $(MODULE).so: $(OBJS) $(RC_SRCS:.rc=.res) Makefile.in # Rules for .exe main module $(MODULE): $(OBJS) $(RCOBJS) Makefile.in - $(CC) $(APPMODE) $(OBJS) $(RCOBJS) -o $@ -L$(DLLDIR) $(IMPORTS:%=-L$(DLLDIR)/%) $(DELAYIMPORTS:%=-L$(DLLDIR)/%) $(LIBWINE) $(ALL_LIBS) + $(WINEGCC) $(APPMODE) $(OBJS) $(RCOBJS) -o $@ $(ALL_LIBS) $(DELAYIMPORTS:%=-Wb,-d%) # Rules for testing diff --git a/programs/winetest/Makefile.in b/programs/winetest/Makefile.in index 298ca1a5862..d880cabe6ab 100644 --- a/programs/winetest/Makefile.in +++ b/programs/winetest/Makefile.in @@ -50,7 +50,7 @@ winetest-dist.exe.so: $(OBJS) dist.res Makefile.in $(WINEGCC) $(APPMODE) $(OBJS) dist.res -o $@ -L$(DLLDIR) $(DELAYIMPORTS:%=-Wb,-d%) $(ALL_LIBS) winetest-dist.exe: $(OBJS) dist.res.o Makefile.in - $(CC) $(APPMODE) $(OBJS) dist.res.o -o $@ -L$(DLLDIR) $(IMPORTS:%=-L$(DLLDIR)/%) $(ALL_LIBS) + $(WINEGCC) $(APPMODE) $(OBJS) dist.res.o -o $@ -L$(DLLDIR) $(DELAYIMPORTS:%=-Wb,-d%) $(ALL_LIBS) -upx -9 -qqq $@ dist.res: winetest.rc tests.rc build.nfo winetest.ico $(TESTBINS) diff --git a/tools/winegcc/utils.c b/tools/winegcc/utils.c index 743f2e06c9e..611ec42f4aa 100644 --- a/tools/winegcc/utils.c +++ b/tools/winegcc/utils.c @@ -258,36 +258,38 @@ static char* try_lib_path(const char* dir, const char* pre, return 0; } -static file_type guess_lib_type(const char* dir, const char* library, char** file) +static file_type guess_lib_type(enum target_platform platform, const char* dir, + const char* library, char** file) { - /* Unix shared object */ - if ((*file = try_lib_path(dir, "lib", library, ".so", file_so))) - return file_so; - - /* Mach-O (Darwin/Mac OS X) Dynamic Library behaves mostly like .so */ - if ((*file = try_lib_path(dir, "lib", library, ".dylib", file_so))) - return file_so; + if (platform != PLATFORM_WINDOWS) + { + /* Unix shared object */ + if ((*file = try_lib_path(dir, "lib", library, ".so", file_so))) + return file_so; - /* Windows DLL */ - if ((*file = try_lib_path(dir, "lib", library, ".def", file_def))) - return file_dll; - if ((*file = try_lib_path(dir, "", library, ".def", file_def))) - return file_dll; + /* Mach-O (Darwin/Mac OS X) Dynamic Library behaves mostly like .so */ + if ((*file = try_lib_path(dir, "lib", library, ".dylib", file_so))) + return file_so; - /* Unix static archives */ + /* Windows DLL */ + if ((*file = try_lib_path(dir, "lib", library, ".def", file_def))) + return file_dll; + } + + /* static archives */ if ((*file = try_lib_path(dir, "lib", library, ".a", file_arh))) return file_arh; return file_na; } -file_type get_lib_type(strarray* path, const char* library, char** file) +file_type get_lib_type(enum target_platform platform, strarray* path, const char* library, char** file) { unsigned int i; for (i = 0; i < path->size; i++) { - file_type type = guess_lib_type(path->base[i], library, file); + file_type type = guess_lib_type(platform, path->base[i], library, file); if (type != file_na) return type; } return file_na; diff --git a/tools/winegcc/utils.h b/tools/winegcc/utils.h index a48bbf038c0..08c9a0f77bc 100644 --- a/tools/winegcc/utils.h +++ b/tools/winegcc/utils.h @@ -31,6 +31,16 @@ # endif #endif +enum target_cpu +{ + CPU_x86, CPU_x86_64, CPU_SPARC, CPU_ALPHA, CPU_POWERPC +}; + +enum target_platform +{ + PLATFORM_UNSPECIFIED, PLATFORM_APPLE, PLATFORM_SOLARIS, PLATFORM_WINDOWS +}; + void error(const char* s, ...) DECLSPEC_NORETURN; void* xmalloc(size_t size); @@ -62,7 +72,7 @@ typedef enum { char* get_basename(const char* file); void create_file(const char* name, int mode, const char* fmt, ...); file_type get_file_type(const char* filename); -file_type get_lib_type(strarray* path, const char* library, char** file); +file_type get_lib_type(enum target_platform platform, strarray* path, const char* library, char** file); void spawn(const strarray* prefix, const strarray* arr, int ignore_errors); extern int verbose; diff --git a/tools/winegcc/winegcc.c b/tools/winegcc/winegcc.c index 4e410330102..f64b6775803 100644 --- a/tools/winegcc/winegcc.c +++ b/tools/winegcc/winegcc.c @@ -145,16 +145,6 @@ static sigset_t signal_mask; enum processor { proc_cc, proc_cxx, proc_cpp, proc_as }; -enum target_cpu -{ - CPU_x86, CPU_x86_64, CPU_SPARC, CPU_ALPHA, CPU_POWERPC -}; - -enum target_platform -{ - PLATFORM_UNSPECIFIED, PLATFORM_APPLE, PLATFORM_SOLARIS, PLATFORM_WINDOWS -}; - static const struct { const char *name; @@ -474,6 +464,24 @@ static const char* compile_to_object(struct options* opts, const char* file, con return copts.output_name; } +/* return the initial set of options needed to run winebuild */ +static strarray *get_winebuild_args(struct options *opts) +{ + const char* winebuild = getenv("WINEBUILD"); + strarray *spec_args = strarray_alloc(); + + if (!winebuild) winebuild = "winebuild"; + strarray_add( spec_args, winebuild ); + if (verbose) strarray_add( spec_args, "-v" ); + if (keep_generated) strarray_add( spec_args, "--save-temps" ); + if (opts->target) + { + strarray_add( spec_args, "--target" ); + strarray_add( spec_args, opts->target ); + } + return spec_args; +} + /* check if there is a static lib associated to a given dll */ static char *find_static_lib( const char *dll ) { @@ -484,11 +492,11 @@ static char *find_static_lib( const char *dll ) } /* add specified library to the list of files */ -static void add_library( strarray *lib_dirs, strarray *files, const char *library ) +static void add_library( struct options *opts, strarray *lib_dirs, strarray *files, const char *library ) { char *static_lib, *fullname = 0; - switch(get_lib_type(lib_dirs, library, &fullname)) + switch(get_lib_type(opts->target_platform, lib_dirs, library, &fullname)) { case file_arh: strarray_add(files, strmake("-a%s", fullname)); @@ -518,7 +526,6 @@ static void build(struct options* opts) char *output_file; const char *spec_o_name; const char *output_name, *spec_file, *lang; - const char* winebuild = getenv("WINEBUILD"); int generate_app_loader = 1; unsigned int j; @@ -532,8 +539,6 @@ static void build(struct options* opts) * -xlll: lll is the language (c, c++, etc.) */ - if (!winebuild) winebuild = "winebuild"; - output_file = strdup( opts->output_name ? opts->output_name : "a.out" ); /* 'winegcc -o app xxx.exe.so' only creates the load script */ @@ -577,6 +582,7 @@ static void build(struct options* opts) /* mark the files with their appropriate type */ spec_file = lang = 0; files = strarray_alloc(); + link_args = strarray_alloc(); for ( j = 0; j < opts->files->size; j++ ) { const char* file = opts->files->base[j]; @@ -616,43 +622,131 @@ static void build(struct options* opts) } } else if (file[1] == 'l') - add_library( lib_dirs, files, file + 2 ); + add_library(opts, lib_dirs, files, file + 2 ); else if (file[1] == 'x') lang = file; } if (opts->shared && !spec_file) error("A spec file is currently needed in shared mode\n"); + /* building for Windows is completely different */ + + if (opts->target_platform == PLATFORM_WINDOWS) + { + if (opts->shared) + { + /* run winebuild to generate the .def file */ + char *spec_def_name = get_temp_file(output_name, ".spec.def"); + spec_args = get_winebuild_args( opts ); + strarray_add(spec_args, "--def"); + strarray_add(spec_args, "-o"); + strarray_add(spec_args, spec_def_name); + if (spec_file) + { + strarray_add(spec_args, "--export"); + strarray_add(spec_args, spec_file); + } + spawn(opts->prefix, spec_args, 0); + strarray_free(spec_args); + + if (opts->target) strarray_add(link_args, strmake("%s-dllwrap", opts->target)); + else strarray_add(link_args, "dllwrap"); + if (verbose) strarray_add(link_args, "-v"); + strarray_add(link_args, "-k"); + strarray_add(link_args, "--def"); + strarray_add(link_args, spec_def_name); + } + else + { + strarray_addall(link_args, get_translator(opts)); + strarray_add(link_args, opts->gui_app ? "-mwindows" : "-mconsole"); + if (opts->use_msvcrt) strarray_add(link_args, "-mno-cygwin"); + if (opts->nodefaultlibs) strarray_add(link_args, "-nodefaultlibs"); + } + + for ( j = 0 ; j < opts->linker_args->size ; j++ ) + strarray_add(link_args, opts->linker_args->base[j]); + + strarray_add(link_args, "-o"); + strarray_add(link_args, output_file); + + if (opts->image_base) + strarray_add(link_args, strmake("-Wl,--image-base,%s", opts->image_base)); + + for ( j = 0; j < lib_dirs->size; j++ ) + strarray_add(link_args, strmake("-L%s", lib_dirs->base[j])); + + if (opts->shared && !opts->nostdlib) add_library(opts, lib_dirs, files, "wine"); + + for ( j = 0; j < files->size; j++ ) + { + const char* name = files->base[j] + 2; + + switch(files->base[j][1]) + { + case 'l': + case 's': + case 'd': + strarray_add(link_args, strmake("-l%s", name)); + break; + case 'o': + strarray_add(link_args, name); + break; + case 'a': + if (strchr(name, '/')) + { + /* turn the path back into -Ldir -lfoo options + * this makes sure that we use the specified libs even + * when mingw adds its own import libs to the link */ + char *lib = xstrdup( name ); + char *p = strrchr( lib, '/' ); + + *p++ = 0; + if (!strncmp( p, "lib", 3 )) + { + char *ext = strrchr( p, '.' ); + + if (ext) *ext = 0; + p += 3; + strarray_add(link_args, strmake("-L%s", lib )); + strarray_add(link_args, strmake("-l%s", p )); + free( lib ); + break; + } + free( lib ); + } + strarray_add(link_args, name); + break; + } + } + + spawn(opts->prefix, link_args, 0); + strarray_free (link_args); + return; + } + /* add the default libraries, if needed */ - if (!opts->nostdlib && opts->use_msvcrt) add_library(lib_dirs, files, "msvcrt"); + if (!opts->nostdlib && opts->use_msvcrt) add_library(opts, lib_dirs, files, "msvcrt"); if (!opts->wine_objdir && !opts->nodefaultlibs) { if (opts->gui_app) { - add_library(lib_dirs, files, "shell32"); - add_library(lib_dirs, files, "comdlg32"); - add_library(lib_dirs, files, "gdi32"); + add_library(opts, lib_dirs, files, "shell32"); + add_library(opts, lib_dirs, files, "comdlg32"); + add_library(opts, lib_dirs, files, "gdi32"); } - add_library(lib_dirs, files, "advapi32"); - add_library(lib_dirs, files, "user32"); - add_library(lib_dirs, files, "kernel32"); + add_library(opts, lib_dirs, files, "advapi32"); + add_library(opts, lib_dirs, files, "user32"); + add_library(opts, lib_dirs, files, "kernel32"); } - if (!opts->nostartfiles) add_library(lib_dirs, files, "winecrt0"); - if (!opts->nostdlib) add_library(lib_dirs, files, "wine"); + if (!opts->nostartfiles) add_library(opts, lib_dirs, files, "winecrt0"); + if (!opts->nostdlib) add_library(opts, lib_dirs, files, "wine"); /* run winebuild to generate the .spec.o file */ - spec_args = strarray_alloc(); + spec_args = get_winebuild_args( opts ); spec_o_name = get_temp_file(output_name, ".spec.o"); - strarray_add(spec_args, winebuild); - if (verbose) strarray_add(spec_args, "-v"); - if (keep_generated) strarray_add(spec_args, "--save-temps"); - if (opts->target) - { - strarray_add(spec_args, "--target"); - strarray_add(spec_args, opts->target); - } if (opts->force_pointer_size) strarray_add(spec_args, strmake("-m%u", 8 * opts->force_pointer_size )); strarray_addall(spec_args, strarray_fromstring(DLLFLAGS, " ")); @@ -704,7 +798,6 @@ static void build(struct options* opts) strarray_free (spec_args); /* link everything together now */ - link_args = strarray_alloc(); strarray_addall(link_args, get_translator(opts)); strarray_addall(link_args, strarray_fromstring(LDDLLFLAGS, " "));