winegcc.c 48 KB
Newer Older
1 2 3
/*
 * MinGW wrapper: makes gcc behave like MinGW.
 *
4
 * Copyright 2000 Manuel Novoa III
5
 * Copyright 2000 Francois Gouget
6 7 8 9 10 11 12 13 14 15 16 17 18 19
 * Copyright 2002 Dimitrie O. Paun
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
20
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 22 23 24 25 26
 *
 * DESCRIPTION
 *
 * all options for gcc start with '-' and are for the most part
 * single options (no parameters as separate argument). 
 * There are of course exceptions to this rule, so here is an 
27
 * exhaustive list of options that do take parameters (potentially)
28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62
 * as a separate argument:
 *
 * Compiler:
 * -x language
 * -o filename
 * -aux-info filename
 *
 * Preprocessor:
 * -D name 
 * -U name
 * -I dir
 * -MF file
 * -MT target
 * -MQ target
 * (all -i.* arg)
 * -include file 
 * -imacros file
 * -idirafter dir
 * -iwithprefix dir
 * -iwithprefixbefore dir
 * -isystem dir
 * -A predicate=answer
 *
 * Linking:
 * -l library
 * -Xlinker option
 * -u symbol
 *
 * Misc:
 * -b machine
 * -V version
 * -G num  (see NOTES below)
 *
 * NOTES
 * There is -G option for compatibility with System V that
63 64
 * takes no parameters. This makes "-G num" parsing ambiguous.
 * This option is synonymous to -shared, and as such we will
65 66 67 68 69 70 71 72 73 74
 * not support it for now.
 *
 * Special interest options 
 *
 *      Assembler Option
 *          -Wa,option
 *
 *      Linker Options
 *          object-file-name  -llibrary -nostartfiles  -nodefaultlibs
 *          -nostdlib -s  -static  -static-libgcc  -shared  -shared-libgcc
75
 *          -symbolic -Wl,option  -Xlinker option -u symbol --image-base
76 77 78 79 80 81 82
 *
 *      Directory Options
 *          -Bprefix  -Idir  -I-  -Ldir  -specs=file
 *
 *      Target Options
 *          -b machine  -V version
 *
83 84
 * Please note that the Target Options are relevant to everything:
 *   compiler, linker, assembler, preprocessor.
85 86
 * 
 */ 
87 88 89 90

#include "config.h"
#include "wine/port.h"

91
#include <assert.h>
92
#include <stdio.h>
Alexandre Julliard's avatar
Alexandre Julliard committed
93
#include <stdlib.h>
94
#include <signal.h>
95
#include <stdarg.h>
96
#include <string.h>
97
#include <errno.h>
98

99
#include "utils.h"
100

101
static const char* app_loader_template =
102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125
    "#!/bin/sh\n"
    "\n"
    "appname=\"%s\"\n"
    "# determine the application directory\n"
    "appdir=''\n"
    "case \"$0\" in\n"
    "  */*)\n"
    "    # $0 contains a path, use it\n"
    "    appdir=`dirname \"$0\"`\n"
    "    ;;\n"
    "  *)\n"
    "    # no directory in $0, search in PATH\n"
    "    saved_ifs=$IFS\n"
    "    IFS=:\n"
    "    for d in $PATH\n"
    "    do\n"
    "      IFS=$saved_ifs\n"
    "      if [ -x \"$d/$appname\" ]; then appdir=\"$d\"; break; fi\n"
    "    done\n"
    "    ;;\n"
    "esac\n"
    "\n"
    "# figure out the full app path\n"
    "if [ -n \"$appdir\" ]; then\n"
126
    "    apppath=\"$appdir/$appname\"\n"
127 128 129
    "    WINEDLLPATH=\"$appdir:$WINEDLLPATH\"\n"
    "    export WINEDLLPATH\n"
    "else\n"
130
    "    apppath=\"$appname\"\n"
131 132 133 134 135 136
    "fi\n"
    "\n"
    "# determine the WINELOADER\n"
    "if [ ! -x \"$WINELOADER\" ]; then WINELOADER=\"wine\"; fi\n"
    "\n"
    "# and try to start the app\n"
137
    "exec \"$WINELOADER\" \"$apppath\" \"$@\"\n"
138 139
;

140
static int keep_generated = 0;
141
static strarray* tmp_files;
142
#ifdef HAVE_SIGSET_T
143
static sigset_t signal_mask;
144
#endif
145

146 147
enum processor { proc_cc, proc_cxx, proc_cpp, proc_as };

148 149 150 151 152 153 154 155 156 157 158
static const struct
{
    const char *name;
    enum target_cpu cpu;
} cpu_names[] =
{
    { "i386",    CPU_x86 },
    { "i486",    CPU_x86 },
    { "i586",    CPU_x86 },
    { "i686",    CPU_x86 },
    { "i786",    CPU_x86 },
159
    { "amd64",   CPU_x86_64 },
160 161
    { "x86_64",  CPU_x86_64 },
    { "sparc",   CPU_SPARC },
162 163
    { "powerpc", CPU_POWERPC },
    { "arm",     CPU_ARM }
164 165 166 167 168 169 170 171 172 173 174
};

static const struct
{
    const char *name;
    enum target_platform platform;
} platform_names[] =
{
    { "macos",   PLATFORM_APPLE },
    { "darwin",  PLATFORM_APPLE },
    { "solaris", PLATFORM_SOLARIS },
175
    { "cygwin",  PLATFORM_CYGWIN },
176 177 178 179 180 181
    { "mingw32", PLATFORM_WINDOWS },
    { "windows", PLATFORM_WINDOWS },
    { "winnt",   PLATFORM_WINDOWS }
};

struct options
182
{
183
    enum processor processor;
184 185
    enum target_cpu target_cpu;
    enum target_platform target_platform;
186
    const char *target;
187
    const char *version;
188
    int shared;
189 190 191
    int use_msvcrt;
    int nostdinc;
    int nostdlib;
192
    int nostartfiles;
193
    int nodefaultlibs;
194
    int noshortwchar;
195
    int gui_app;
196
    int unicode_app;
197
    int win16_app;
198
    int compile_only;
199
    int force_pointer_size;
200
    int large_address_aware;
201
    int unwind_tables;
202
    int strip;
203
    const char* wine_objdir;
204
    const char* output_name;
205
    const char* image_base;
206
    const char* section_align;
207
    const char* lib_suffix;
208
    strarray* prefix;
209
    strarray* lib_dirs;
210 211
    strarray* linker_args;
    strarray* compiler_args;
212
    strarray* winebuild_args;
213 214 215
    strarray* files;
};

216 217 218 219 220 221 222 223
#ifdef __i386__
static const enum target_cpu build_cpu = CPU_x86;
#elif defined(__x86_64__)
static const enum target_cpu build_cpu = CPU_x86_64;
#elif defined(__sparc__)
static const enum target_cpu build_cpu = CPU_SPARC;
#elif defined(__powerpc__)
static const enum target_cpu build_cpu = CPU_POWERPC;
224 225
#elif defined(__arm__)
static const enum target_cpu build_cpu = CPU_ARM;
226 227 228 229 230 231 232 233
#else
#error Unsupported CPU
#endif

#ifdef __APPLE__
static enum target_platform build_platform = PLATFORM_APPLE;
#elif defined(__sun)
static enum target_platform build_platform = PLATFORM_SOLARIS;
234 235
#elif defined(__CYGWIN__)
static enum target_platform build_platform = PLATFORM_CYGWIN;
236
#elif defined(_WIN32)
237 238 239 240 241
static enum target_platform build_platform = PLATFORM_WINDOWS;
#else
static enum target_platform build_platform = PLATFORM_UNSPECIFIED;
#endif

242
static void clean_temp_files(void)
243
{
244
    unsigned int i;
245 246 247 248 249

    if (keep_generated) return;

    for (i = 0; i < tmp_files->size; i++)
	unlink(tmp_files->base[i]);
250 251
}

252 253 254 255 256 257
/* clean things up when aborting on a signal */
static void exit_on_signal( int sig )
{
    exit(1);  /* this will call the atexit functions */
}

258
static char* get_temp_file(const char* prefix, const char* suffix)
259
{
260
    int fd;
261
    char* tmp = strmake("%s-XXXXXX%s", prefix, suffix);
262

263 264
#ifdef HAVE_SIGPROCMASK
    sigset_t old_set;
265 266
    /* block signals while manipulating the temp files list */
    sigprocmask( SIG_BLOCK, &signal_mask, &old_set );
267
#endif
268
    fd = mkstemps( tmp, strlen(suffix) );
269 270 271 272
    if (fd == -1)
    {
        /* could not create it in current directory, try in /tmp */
        free(tmp);
273
        tmp = strmake("/tmp/%s-XXXXXX%s", prefix, suffix);
274
        fd = mkstemps( tmp, strlen(suffix) );
275
        if (fd == -1) error( "could not create temp file\n" );
276 277
    }
    close( fd );
278
    strarray_add(tmp_files, tmp);
279
#ifdef HAVE_SIGPROCMASK
280
    sigprocmask( SIG_SETMASK, &old_set, NULL );
281
#endif
282 283 284
    return tmp;
}

285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305
static char* build_tool_name(struct options *opts, const char* base, const char* deflt)
{
    char* str;

    if (opts->target && opts->version)
    {
        str = strmake("%s-%s-%s", opts->target, base, opts->version);
    }
    else if (opts->target)
    {
        str = strmake("%s-%s", opts->target, base);
    }
    else if (opts->version)
    {
        str = strmake("%s-%s", base, opts->version);
    }
    else
        str = xstrdup(deflt);
    return str;
}

306
static const strarray* get_translator(struct options *opts)
307
{
308
    char *str = NULL;
309
    strarray *ret;
310

311
    switch(opts->processor)
312
    {
313
    case proc_cpp:
314
        str = build_tool_name(opts, "cpp", CPP);
315 316
        break;
    case proc_cc:
317
    case proc_as:
318
        str = build_tool_name(opts, "gcc", CC);
319 320
        break;
    case proc_cxx:
321
        str = build_tool_name(opts, "g++", CXX);
322 323 324
        break;
    default:
        assert(0);
325
    }
326
    ret = strarray_fromstring( str, " " );
327
    free(str);
328
    if (opts->force_pointer_size)
329
        strarray_add( ret, strmake("-m%u", 8 * opts->force_pointer_size ));
330
    return ret;
331 332
}

333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360
/* check that file is a library for the correct platform */
static int check_platform( struct options *opts, const char *file )
{
    int ret = 0, fd = open( file, O_RDONLY );
    if (fd != -1)
    {
        unsigned char header[16];
        if (read( fd, header, sizeof(header) ) == sizeof(header))
        {
            /* FIXME: only ELF is supported, platform is not checked beyond 32/64 */
            if (!memcmp( header, "\177ELF", 4 ))
            {
                if (header[4] == 2)  /* 64-bit */
                    ret = (opts->force_pointer_size == 8 ||
                           (!opts->force_pointer_size && opts->target_cpu == CPU_x86_64));
                else
                    ret = (opts->force_pointer_size == 4 ||
                           (!opts->force_pointer_size && opts->target_cpu != CPU_x86_64));
            }
        }
        close( fd );
    }
    return ret;
}

static char *get_lib_dir( struct options *opts )
{
    static const char *stdlibpath[] = { LIBDIR, "/usr/lib", "/usr/local/lib", "/lib" };
361
    static const char libwine[] = "/libwine.so";
362 363 364 365
    unsigned int i;

    for (i = 0; i < sizeof(stdlibpath)/sizeof(stdlibpath[0]); i++)
    {
366
        char *p, *buffer = xmalloc( strlen(stdlibpath[i]) + strlen(libwine) + 3 );
367 368 369
        strcpy( buffer, stdlibpath[i] );
        p = buffer + strlen(buffer);
        while (p > buffer && p[-1] == '/') p--;
370 371
        strcpy( p, libwine );
        if (check_platform( opts, buffer )) goto found;
372 373 374
        if (p > buffer + 2 && (!memcmp( p - 2, "32", 2 ) || !memcmp( p - 2, "64", 2 ))) p -= 2;
        if (opts->force_pointer_size == 4 || (!opts->force_pointer_size && opts->target_cpu != CPU_x86_64))
        {
375 376 377
            strcpy( p, "32" );
            strcat( p, libwine );
            if (check_platform( opts, buffer )) goto found;
378 379 380
        }
        if (opts->force_pointer_size == 8 || (!opts->force_pointer_size && opts->target_cpu == CPU_x86_64))
        {
381 382 383
            strcpy( p, "64" );
            strcat( p, libwine );
            if (check_platform( opts, buffer )) goto found;
384 385
        }
        free( buffer );
386 387 388 389 390
        continue;

    found:
        buffer[strlen(buffer) - strlen(libwine)] = 0;
        return buffer;
391 392 393 394
    }
    return xstrdup( LIBDIR );
}

395
static void compile(struct options* opts, const char* lang)
396
{
397
    strarray* comp_args = strarray_alloc();
398 399
    unsigned int j;
    int gcc_defs = 0;
400 401
    char* gcc;
    char* gpp;
402

403
    strarray_addall(comp_args, get_translator(opts));
404 405
    switch(opts->processor)
    {
406 407
	case proc_cpp: gcc_defs = 1; break;
	case proc_as:  gcc_defs = 0; break;
408 409
	/* Note: if the C compiler is gcc we assume the C++ compiler is too */
	/* mixing different C and C++ compilers isn't supported in configure anyway */
410 411
	case proc_cc:
	case proc_cxx:
412 413
            gcc = build_tool_name(opts, "gcc", CC);
            gpp = build_tool_name(opts, "g++", CXX);
414 415 416 417
            for ( j = 0; !gcc_defs && j < comp_args->size; j++ )
            {
                const char *cc = comp_args->base[j];

418
                gcc_defs = strendswith(cc, gcc) || strendswith(cc, gpp);
419
            }
420 421
            free(gcc);
            free(gpp);
422
            break;
423
    }
424

425 426
    if (opts->target_platform == PLATFORM_WINDOWS || opts->target_platform == PLATFORM_CYGWIN)
        goto no_compat_defines;
427

428
    if (opts->processor != proc_cpp)
429
    {
430
	if (gcc_defs && !opts->wine_objdir && !opts->noshortwchar)
431
	{
432
            strarray_add(comp_args, "-fshort-wchar");
433 434 435
            strarray_add(comp_args, "-DWINE_UNICODE_NATIVE");
	}
        strarray_addall(comp_args, strarray_fromstring(DLLFLAGS, " "));
436
    }
437

438 439 440 441 442 443 444 445
    if (opts->target_cpu == CPU_x86_64)
    {
        strarray_add(comp_args, "-DWIN64");
        strarray_add(comp_args, "-D_WIN64");
        strarray_add(comp_args, "-D__WIN64");
        strarray_add(comp_args, "-D__WIN64__");
    }

446 447 448 449 450 451 452
    strarray_add(comp_args, "-DWIN32");
    strarray_add(comp_args, "-D_WIN32");
    strarray_add(comp_args, "-D__WIN32");
    strarray_add(comp_args, "-D__WIN32__");
    strarray_add(comp_args, "-D__WINNT");
    strarray_add(comp_args, "-D__WINNT__");

453 454
    if (gcc_defs)
    {
455
        int fastcall_done = 0;
456 457 458 459 460 461 462 463
        if (opts->target_cpu == CPU_x86_64)
        {
            strarray_add(comp_args, "-D__stdcall=__attribute__((ms_abi))");
            strarray_add(comp_args, "-D__cdecl=__attribute__((ms_abi))");
            strarray_add(comp_args, "-D_stdcall=__attribute__((ms_abi))");
            strarray_add(comp_args, "-D_cdecl=__attribute__((ms_abi))");
            strarray_add(comp_args, "-D__fastcall=__attribute__((ms_abi))");
            strarray_add(comp_args, "-D_fastcall=__attribute__((ms_abi))");
464
            fastcall_done = 1;
465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480
        }
        else if (opts->target_platform == PLATFORM_APPLE)
        {
            /* Mac OS X uses a 16-byte aligned stack and not a 4-byte one */
            strarray_add(comp_args, "-D__stdcall=__attribute__((__stdcall__)) __attribute__((__force_align_arg_pointer__))");
            strarray_add(comp_args, "-D__cdecl=__attribute__((__cdecl__)) __attribute__((__force_align_arg_pointer__))");
            strarray_add(comp_args, "-D_stdcall=__attribute__((__stdcall__)) __attribute__((__force_align_arg_pointer__))");
            strarray_add(comp_args, "-D_cdecl=__attribute__((__cdecl__)) __attribute__((__force_align_arg_pointer__))");
        }
        else
        {
            strarray_add(comp_args, "-D__stdcall=__attribute__((__stdcall__))");
            strarray_add(comp_args, "-D__cdecl=__attribute__((__cdecl__))");
            strarray_add(comp_args, "-D_stdcall=__attribute__((__stdcall__))");
            strarray_add(comp_args, "-D_cdecl=__attribute__((__cdecl__))");
        }
481

482 483 484 485 486
	if (!fastcall_done)
        {
            strarray_add(comp_args, "-D__fastcall=__attribute__((__fastcall__))");
            strarray_add(comp_args, "-D_fastcall=__attribute__((__fastcall__))");
        }
487 488 489 490 491 492 493 494 495 496 497 498 499 500
	strarray_add(comp_args, "-D__declspec(x)=__declspec_##x");
	strarray_add(comp_args, "-D__declspec_align(x)=__attribute__((aligned(x)))");
	strarray_add(comp_args, "-D__declspec_allocate(x)=__attribute__((section(x)))");
	strarray_add(comp_args, "-D__declspec_deprecated=__attribute__((deprecated))");
	strarray_add(comp_args, "-D__declspec_dllimport=__attribute__((dllimport))");
	strarray_add(comp_args, "-D__declspec_dllexport=__attribute__((dllexport))");
	strarray_add(comp_args, "-D__declspec_naked=__attribute__((naked))");
	strarray_add(comp_args, "-D__declspec_noinline=__attribute__((noinline))");
	strarray_add(comp_args, "-D__declspec_noreturn=__attribute__((noreturn))");
	strarray_add(comp_args, "-D__declspec_nothrow=__attribute__((nothrow))");
	strarray_add(comp_args, "-D__declspec_novtable=__attribute__(())"); /* ignore it */
	strarray_add(comp_args, "-D__declspec_selectany=__attribute__((weak))");
	strarray_add(comp_args, "-D__declspec_thread=__thread");
    }
501

502 503 504
    strarray_add(comp_args, "-D__int8=char");
    strarray_add(comp_args, "-D__int16=short");
    strarray_add(comp_args, "-D__int32=int");
505 506 507 508 509 510 511
    if (opts->target_cpu == CPU_x86_64)
        strarray_add(comp_args, "-D__int64=long");
    else
        strarray_add(comp_args, "-D__int64=long long");

no_compat_defines:
    strarray_add(comp_args, "-D__WINE__");
512 513 514

    /* options we handle explicitly */
    if (opts->compile_only)
515
	strarray_add(comp_args, "-c");
516
    if (opts->output_name)
517 518 519 520
    {
	strarray_add(comp_args, "-o");
	strarray_add(comp_args, opts->output_name);
    }
521 522 523

    /* the rest of the pass-through parameters */
    for ( j = 0 ; j < opts->compiler_args->size ; j++ ) 
524
        strarray_add(comp_args, opts->compiler_args->base[j]);
525

526 527 528 529
    /* the language option, if any */
    if (lang && strcmp(lang, "-xnone"))
	strarray_add(comp_args, lang);

530 531
    /* last, but not least, the files */
    for ( j = 0; j < opts->files->size; j++ )
532 533 534 535
    {
	if (opts->files->base[j][0] != '-')
	    strarray_add(comp_args, opts->files->base[j]);
    }
536

537
    /* standard includes come last in the include search path */
538
    if (!opts->wine_objdir && !opts->nostdinc)
539 540 541
    {
        if (opts->use_msvcrt)
        {
542
            strarray_add(comp_args, gcc_defs ? "-isystem" INCLUDEDIR "/msvcrt" : "-I" INCLUDEDIR "/msvcrt" );
543 544
            strarray_add(comp_args, "-D__MSVCRT__");
        }
545
        strarray_add(comp_args, gcc_defs ? "-isystem" INCLUDEDIR "/windows" : "-I" INCLUDEDIR "/windows" );
546
    }
547 548
    else if (opts->wine_objdir)
        strarray_add(comp_args, strmake("-I%s/include", opts->wine_objdir) );
549

550
    spawn(opts->prefix, comp_args, 0);
551
    strarray_free(comp_args);
552 553
}

554
static const char* compile_to_object(struct options* opts, const char* file, const char* lang)
555 556 557
{
    struct options copts;
    char* base_name;
558

559
    /* make a copy so we don't change any of the initial stuff */
560 561 562 563 564 565 566
    /* a shallow copy is exactly what we want in this case */
    base_name = get_basename(file);
    copts = *opts;
    copts.output_name = get_temp_file(base_name, ".o");
    copts.compile_only = 1;
    copts.files = strarray_alloc();
    strarray_add(copts.files, file);
567
    compile(&copts, lang);
568 569 570 571 572 573
    strarray_free(copts.files);
    free(base_name);

    return copts.output_name;
}

574 575 576 577 578 579 580 581 582 583 584 585 586 587 588
/* 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 );
    }
589 590
    if (opts->unwind_tables) strarray_add( spec_args, "-fasynchronous-unwind-tables" );
    else strarray_add( spec_args, "-fno-asynchronous-unwind-tables" );
591 592 593
    return spec_args;
}

594 595 596 597 598 599 600 601 602 603 604 605 606 607 608
static const char* compile_resources_to_object(struct options* opts, const strarray *resources,
                                               const char *res_o_name)
{
    strarray *winebuild_args = get_winebuild_args( opts );

    strarray_add( winebuild_args, "--resources" );
    strarray_add( winebuild_args, "-o" );
    strarray_add( winebuild_args, res_o_name );
    strarray_addall( winebuild_args, resources );

    spawn( opts->prefix, winebuild_args, 0 );
    strarray_free( winebuild_args );
    return res_o_name;
}

609 610 611 612 613 614 615 616 617
/* check if there is a static lib associated to a given dll */
static char *find_static_lib( const char *dll )
{
    char *lib = strmake("%s.a", dll);
    if (get_file_type(lib) == file_arh) return lib;
    free( lib );
    return NULL;
}

618
/* add specified library to the list of files */
619
static void add_library( struct options *opts, strarray *lib_dirs, strarray *files, const char *library )
620 621 622
{
    char *static_lib, *fullname = 0;

623
    switch(get_lib_type(opts->target_platform, lib_dirs, library, opts->lib_suffix, &fullname))
624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644
    {
    case file_arh:
        strarray_add(files, strmake("-a%s", fullname));
        break;
    case file_dll:
        strarray_add(files, strmake("-d%s", fullname));
        if ((static_lib = find_static_lib(fullname)))
        {
            strarray_add(files, strmake("-a%s",static_lib));
            free(static_lib);
        }
        break;
    case file_so:
    default:
        /* keep it anyway, the linker may know what to do with it */
        strarray_add(files, strmake("-l%s", library));
        break;
    }
    free(fullname);
}

645 646 647 648 649 650
/* hack a main or WinMain function to work around Mingw's lack of Unicode support */
static const char *mingw_unicode_hack( struct options *opts )
{
    char *main_stub = get_temp_file( opts->output_name, ".c" );

    create_file( main_stub, 0644,
651 652 653 654
                 "typedef unsigned short wchar_t;\n"
                 "extern void * __stdcall LoadLibraryA(const char *);\n"
                 "extern void * __stdcall GetProcAddress(void *,const char *);\n"
                 "extern int wmain( int argc, wchar_t *argv[] );\n\n"
655
                 "int main( int argc, char *argv[] )\n{\n"
656 657
                 "    int wargc;\n"
                 "    wchar_t **wargv, **wenv;\n"
658 659 660 661
                 "    void *msvcrt = LoadLibraryA( \"msvcrt.dll\" );\n"
                 "    void (*__wgetmainargs)(int *argc, wchar_t** *wargv, wchar_t** *wenvp, int expand_wildcards,\n"
                 "                           int *new_mode) = GetProcAddress( msvcrt, \"__wgetmainargs\" );\n"
                 "    __wgetmainargs( &wargc, &wargv, &wenv, 0, 0 );\n"
662
                 "    return wmain( wargc, wargv );\n}\n" );
663 664 665
    return compile_to_object( opts, main_stub, NULL );
}

666
static void build(struct options* opts)
667
{
668
    strarray *lib_dirs, *files;
669
    strarray *spec_args, *link_args;
670
    char *output_file;
671
    const char *spec_o_name;
672
    const char *output_name, *spec_file, *lang;
673
    int generate_app_loader = 1;
674
    int fake_module = 0;
675
    unsigned int j;
676

677 678 679 680 681 682 683
    /* NOTE: for the files array we'll use the following convention:
     *    -axxx:  xxx is an archive (.a)
     *    -dxxx:  xxx is a DLL (.def)
     *    -lxxx:  xxx is an unsorted library
     *    -oxxx:  xxx is an object (.o)
     *    -rxxx:  xxx is a resource (.res)
     *    -sxxx:  xxx is a shared lib (.so)
684
     *    -xlll:  lll is the language (c, c++, etc.)
685
     */
686

687
    output_file = strdup( opts->output_name ? opts->output_name : "a.out" );
688

689
    /* 'winegcc -o app xxx.exe.so' only creates the load script */
690
    if (opts->files->size == 1 && strendswith(opts->files->base[0], ".exe.so"))
691
    {
692
	create_file(output_file, 0755, app_loader_template, opts->files->base[0]);
693 694
	return;
    }
695

696
    /* generate app loader only for .exe */
697
    if (opts->shared || strendswith(output_file, ".so"))
698 699
	generate_app_loader = 0;

700 701
    if (strendswith(output_file, ".fake")) fake_module = 1;

702 703 704
    /* normalize the filename a bit: strip .so, ensure it has proper ext */
    if (strendswith(output_file, ".so")) 
	output_file[strlen(output_file) - 3] = 0;
705 706 707 708
    if ((output_name = strrchr(output_file, '/'))) output_name++;
    else output_name = output_file;
    if (!strchr(output_name, '.'))
        output_file = strmake("%s.%s", output_file, opts->shared ? "dll" : "exe");
709

710
    /* get the filename from the path */
711 712 713
    if ((output_name = strrchr(output_file, '/'))) output_name++;
    else output_name = output_file;

714
    /* prepare the linking path */
715
    if (!opts->wine_objdir)
716
    {
717
        char *lib_dir = get_lib_dir( opts );
718
        lib_dirs = strarray_dup(opts->lib_dirs);
719 720
        strarray_add( lib_dirs, strmake( "%s/wine", lib_dir ));
        strarray_add( lib_dirs, lib_dir );
721
    }
722 723
    else
    {
724
        lib_dirs = strarray_alloc();
725 726
        strarray_add(lib_dirs, strmake("%s/dlls", opts->wine_objdir));
        strarray_add(lib_dirs, strmake("%s/libs/wine", opts->wine_objdir));
727
        strarray_addall(lib_dirs, opts->lib_dirs);
728
    }
729

730
    /* mark the files with their appropriate type */
731
    spec_file = lang = 0;
732
    files = strarray_alloc();
733
    link_args = strarray_alloc();
734
    for ( j = 0; j < opts->files->size; j++ )
735
    {
736 737
	const char* file = opts->files->base[j];
	if (file[0] != '-')
738
	{
739 740
	    switch(get_file_type(file))
	    {
741 742 743
		case file_def:
		case file_spec:
		    if (spec_file)
744
			error("Only one spec file can be specified\n");
745 746
		    spec_file = file;
		    break;
747 748
		case file_rc:
		    /* FIXME: invoke wrc to build it */
749
		    error("Can't compile .rc file at the moment: %s\n", file);
750 751 752 753 754 755 756
	            break;
	    	case file_res:
		    strarray_add(files, strmake("-r%s", file));
		    break;
		case file_obj:
		    strarray_add(files, strmake("-o%s", file));
		    break;
757 758 759 760 761 762
		case file_arh:
		    strarray_add(files, strmake("-a%s", file));
		    break;
		case file_so:
		    strarray_add(files, strmake("-s%s", file));
		    break;
763
	    	case file_na:
764
		    error("File does not exist: %s\n", file);
765 766
		    break;
	        default:
767
		    file = compile_to_object(opts, file, lang);
768 769 770 771 772
		    strarray_add(files, strmake("-o%s", file));
		    break;
	    }
	}
	else if (file[1] == 'l')
773
            add_library(opts, lib_dirs, files, file + 2 );
774 775
	else if (file[1] == 'x')
	    lang = file;
776
    }
777

778 779
    /* building for Windows is completely different */

780
    if (opts->target_platform == PLATFORM_WINDOWS || opts->target_platform == PLATFORM_CYGWIN)
781
    {
782 783 784
        strarray *resources = strarray_alloc();
        char *res_o_name = NULL;

785 786 787
        if (opts->win16_app)
            error( "Building 16-bit code is not supported for Windows\n" );

788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826
        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->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));

827 828
        if (opts->large_address_aware) strarray_add( link_args, "-Wl,--large-address-aware" );

829 830 831
        if (opts->unicode_app && !opts->shared)
            strarray_add(link_args, mingw_unicode_hack(opts));

832 833 834
        for ( j = 0; j < lib_dirs->size; j++ )
            strarray_add(link_args, strmake("-L%s", lib_dirs->base[j]));

835
        if (!opts->nodefaultlibs)
836 837
        {
            add_library(opts, lib_dirs, files, "winecrt0");
838 839
            add_library(opts, lib_dirs, files, "kernel32");
            add_library(opts, lib_dirs, files, "ntdll");
840
        }
841
        if (opts->shared && !opts->nostdlib) add_library(opts, lib_dirs, files, "wine");
842 843
        if (!opts->shared && opts->use_msvcrt && opts->target_platform == PLATFORM_CYGWIN)
            add_library(opts, lib_dirs, files, "msvcrt");
844 845 846 847 848 849 850 851 852 853 854

        for ( j = 0; j < files->size; j++ )
        {
            const char* name = files->base[j] + 2;

            switch(files->base[j][1])
            {
            case 'l':
            case 'd':
                strarray_add(link_args, strmake("-l%s", name));
                break;
855
            case 's':
856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874
            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;
875 876
                        strarray_add(link_args, strmake("-L%s", lib ));
                        strarray_add(link_args, strmake("-l%s", p ));
877 878 879 880 881 882 883
                        free( lib );
                        break;
                    }
                    free( lib );
                }
                strarray_add(link_args, name);
                break;
884 885 886 887 888 889 890 891
            case 'r':
                if (!res_o_name)
                {
                    res_o_name = get_temp_file( output_name, ".res.o" );
                    strarray_add( link_args, res_o_name );
                }
                strarray_add( resources, name );
                break;
892 893 894
            }
        }

895 896
        if (res_o_name) compile_resources_to_object( opts, resources, res_o_name );

897
        spawn(opts->prefix, link_args, 0);
898
        strarray_free (resources);
899
        strarray_free (link_args);
900 901
        strarray_free (lib_dirs);
        strarray_free (files);
902 903 904
        return;
    }

905
    /* add the default libraries, if needed */
906
    if (!opts->nostdlib && opts->use_msvcrt) add_library(opts, lib_dirs, files, "msvcrt");
907

908
    if (!opts->wine_objdir && !opts->nodefaultlibs) 
909
    {
910 911
        if (opts->gui_app) 
	{
912 913 914
	    add_library(opts, lib_dirs, files, "shell32");
	    add_library(opts, lib_dirs, files, "comdlg32");
	    add_library(opts, lib_dirs, files, "gdi32");
915
	}
916 917
        add_library(opts, lib_dirs, files, "advapi32");
        add_library(opts, lib_dirs, files, "user32");
918 919
    }

920
    if (!opts->nodefaultlibs)
921 922
    {
        add_library(opts, lib_dirs, files, "winecrt0");
923 924 925
        if (opts->win16_app) add_library(opts, lib_dirs, files, "kernel");
        add_library(opts, lib_dirs, files, "kernel32");
        add_library(opts, lib_dirs, files, "ntdll");
926
    }
927
    if (!opts->nostdlib) add_library(opts, lib_dirs, files, "wine");
928

929
    /* run winebuild to generate the .spec.o file */
930
    spec_args = get_winebuild_args( opts );
931
    spec_o_name = get_temp_file(output_name, ".spec.o");
932 933
    if (opts->force_pointer_size)
        strarray_add(spec_args, strmake("-m%u", 8 * opts->force_pointer_size ));
934
    strarray_addall(spec_args, strarray_fromstring(DLLFLAGS, " "));
935
    strarray_add(spec_args, opts->shared ? "--dll" : "--exe");
936 937 938 939 940 941 942 943 944 945 946
    if (fake_module)
    {
        strarray_add(spec_args, "--fake-module");
        strarray_add(spec_args, "-o");
        strarray_add(spec_args, output_file);
    }
    else
    {
        strarray_add(spec_args, "-o");
        strarray_add(spec_args, spec_o_name);
    }
947
    if (spec_file)
948
    {
949
        strarray_add(spec_args, "-E");
950 951
        strarray_add(spec_args, spec_file);
    }
952
    if (opts->win16_app) strarray_add(spec_args, "-m16");
953 954

    if (!opts->shared)
955
    {
956
        strarray_add(spec_args, "-F");
957
        strarray_add(spec_args, output_name);
958 959
        strarray_add(spec_args, "--subsystem");
        strarray_add(spec_args, opts->gui_app ? "windows" : "console");
960 961 962
        if (opts->unicode_app)
        {
            strarray_add(spec_args, "--entry");
963
            strarray_add(spec_args, "__wine_spec_exe_wentry");
964
        }
965
        if (opts->large_address_aware) strarray_add( spec_args, "--large-address-aware" );
966
    }
967

968 969
    for ( j = 0; j < lib_dirs->size; j++ )
	strarray_add(spec_args, strmake("-L%s", lib_dirs->base[j]));
970

971 972 973
    for ( j = 0 ; j < opts->winebuild_args->size ; j++ )
        strarray_add(spec_args, opts->winebuild_args->base[j]);

974 975 976 977 978 979
    /* add resource files */
    for ( j = 0; j < files->size; j++ )
	if (files->base[j][1] == 'r') strarray_add(spec_args, files->base[j]);

    /* add other files */
    strarray_add(spec_args, "--");
980 981 982 983
    for ( j = 0; j < files->size; j++ )
    {
	switch(files->base[j][1])
	{
984
	    case 'd':
985 986
	    case 'a':
	    case 'o':
987
		strarray_add(spec_args, files->base[j] + 2);
988 989 990
		break;
	}
    }
991

992
    spawn(opts->prefix, spec_args, 0);
993
    strarray_free (spec_args);
994
    if (fake_module) return;  /* nothing else to do */
995 996

    /* link everything together now */
997
    strarray_addall(link_args, get_translator(opts));
998
    strarray_addall(link_args, strarray_fromstring(LDDLLFLAGS, " "));
999

1000
    strarray_add(link_args, "-o");
1001
    strarray_add(link_args, strmake("%s.so", output_file));
1002 1003 1004 1005

    for ( j = 0 ; j < opts->linker_args->size ; j++ ) 
        strarray_add(link_args, opts->linker_args->base[j]);

1006
    switch (opts->target_platform)
1007
    {
1008 1009 1010 1011 1012 1013
    case PLATFORM_APPLE:
        if (opts->image_base)
        {
            strarray_add(link_args, "-image_base");
            strarray_add(link_args, opts->image_base);
        }
1014 1015
        if (opts->strip)
            strarray_add(link_args, "-Wl,-x");
1016 1017 1018 1019 1020
        break;
    case PLATFORM_SOLARIS:
        {
            char *mapfile = get_temp_file( output_name, ".map" );
            const char *align = opts->section_align ? opts->section_align : "0x1000";
1021

1022 1023 1024 1025 1026 1027 1028
            create_file( mapfile, 0644, "text = A%s;\ndata = A%s;\n", align, align );
            strarray_add(link_args, strmake("-Wl,-M,%s", mapfile));
            strarray_add(tmp_files, mapfile);
        }
        break;
    default:
        break;
1029 1030
    }

1031 1032
    for ( j = 0; j < lib_dirs->size; j++ )
	strarray_add(link_args, strmake("-L%s", lib_dirs->base[j]));
1033

1034
    strarray_add(link_args, spec_o_name);
1035

1036 1037 1038 1039 1040
    for ( j = 0; j < files->size; j++ )
    {
	const char* name = files->base[j] + 2;
	switch(files->base[j][1])
	{
1041
	    case 'l':
1042 1043
		strarray_add(link_args, strmake("-l%s", name));
		break;
1044
	    case 's':
1045 1046 1047 1048 1049 1050
	    case 'a':
	    case 'o':
		strarray_add(link_args, name);
		break;
	}
    }
1051

1052 1053 1054 1055 1056
    if (!opts->nostdlib) 
    {
	strarray_add(link_args, "-lm");
	strarray_add(link_args, "-lc");
    }
1057

1058
    spawn(opts->prefix, link_args, 0);
1059
    strarray_free (link_args);
1060

1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071
    /* set the base address */
    if (opts->image_base)
    {
        const char *prelink = PRELINK;
        if (prelink[0] && strcmp(prelink,"false"))
        {
            strarray *prelink_args = strarray_alloc();
            strarray_add(prelink_args, prelink);
            strarray_add(prelink_args, "--reloc-only");
            strarray_add(prelink_args, opts->image_base);
            strarray_add(prelink_args, strmake("%s.so", output_file));
1072
            spawn(opts->prefix, prelink_args, 1);
1073 1074 1075 1076
            strarray_free(prelink_args);
        }
    }

1077
    /* create the loader script */
1078
    if (generate_app_loader)
1079
        create_file(output_file, 0755, app_loader_template, strmake("%s.so", output_name));
1080 1081 1082
}


1083
static void forward(int argc, char **argv, struct options* opts)
1084
{
1085
    strarray* args = strarray_alloc();
1086 1087
    int j;

1088
    strarray_addall(args, get_translator(opts));
1089 1090

    for( j = 1; j < argc; j++ ) 
1091
	strarray_add(args, argv[j]);
1092

1093
    spawn(opts->prefix, args, 0);
1094
    strarray_free (args);
1095 1096 1097 1098 1099 1100 1101
}

/*
 *      Linker Options
 *          object-file-name  -llibrary -nostartfiles  -nodefaultlibs
 *          -nostdlib -s  -static  -static-libgcc  -shared  -shared-libgcc
 *          -symbolic -Wl,option  -Xlinker option -u symbol
1102
 *	    -framework name
1103 1104 1105 1106 1107
 */
static int is_linker_arg(const char* arg)
{
    static const char* link_switches[] = 
    {
1108
	"-nostartfiles", "-nostdlib", "-s",
1109
	"-static", "-static-libgcc", "-shared", "-shared-libgcc", "-symbolic",
1110
	"-framework", "--coverage", "-fprofile-generate", "-fprofile-use"
1111
    };
1112
    unsigned int j;
1113 1114 1115

    switch (arg[1]) 
    {
1116 1117 1118
	case 'R':
	case 'z':
	case 'l':
1119 1120 1121 1122 1123 1124 1125 1126
	case 'u':
	    return 1;
        case 'W':
            if (strncmp("-Wl,", arg, 4) == 0) return 1;
	    break;
	case 'X':
	    if (strcmp("-Xlinker", arg) == 0) return 1;
	    break;
1127 1128 1129
	case 'a':
	    if (strcmp("-arch", arg) == 0) return 1;
	    break;
1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143
    }

    for (j = 0; j < sizeof(link_switches)/sizeof(link_switches[0]); j++)
	if (strcmp(link_switches[j], arg) == 0) return 1;

    return 0;
}

/*
 *      Target Options
 *          -b machine  -V version
 */
static int is_target_arg(const char* arg)
{
1144
    return arg[1] == 'b' || arg[1] == 'V';
1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158
}


/*
 *      Directory Options
 *          -Bprefix  -Idir  -I-  -Ldir  -specs=file
 */
static int is_directory_arg(const char* arg)
{
    return arg[1] == 'B' || arg[1] == 'L' || arg[1] == 'I' || strncmp("-specs=", arg, 7) == 0;
}

/*
 *      MinGW Options
1159
 *	    -mno-cygwin -mwindows -mconsole -mthreads -municode
1160 1161 1162 1163 1164
 */ 
static int is_mingw_arg(const char* arg)
{
    static const char* mingw_switches[] = 
    {
1165
        "-mno-cygwin", "-mwindows", "-mconsole", "-mthreads", "-municode"
1166
    };
1167
    unsigned int j;
1168 1169 1170 1171 1172 1173

    for (j = 0; j < sizeof(mingw_switches)/sizeof(mingw_switches[0]); j++)
	if (strcmp(mingw_switches[j], arg) == 0) return 1;

    return 0;
}
1174

1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214
static void parse_target_option( struct options *opts, const char *target )
{
    char *p, *platform, *spec = xstrdup( target );
    unsigned int i;

    /* target specification is in the form CPU-MANUFACTURER-OS or CPU-MANUFACTURER-KERNEL-OS */

    /* get the CPU part */

    if (!(p = strchr( spec, '-' ))) error( "Invalid target specification '%s'\n", target );
    *p++ = 0;
    for (i = 0; i < sizeof(cpu_names)/sizeof(cpu_names[0]); i++)
    {
        if (!strcmp( cpu_names[i].name, spec ))
        {
            opts->target_cpu = cpu_names[i].cpu;
            break;
        }
    }
    if (i == sizeof(cpu_names)/sizeof(cpu_names[0]))
        error( "Unrecognized CPU '%s'\n", spec );
    platform = p;
    if ((p = strrchr( p, '-' ))) platform = p + 1;

    /* get the OS part */

    opts->target_platform = PLATFORM_UNSPECIFIED;  /* default value */
    for (i = 0; i < sizeof(platform_names)/sizeof(platform_names[0]); i++)
    {
        if (!strncmp( platform_names[i].name, platform, strlen(platform_names[i].name) ))
        {
            opts->target_platform = platform_names[i].platform;
            break;
        }
    }

    free( spec );
    opts->target = xstrdup( target );
}

1215 1216
int main(int argc, char **argv)
{
1217 1218 1219 1220
    int i, c, next_is_arg = 0, linking = 1;
    int raw_compiler_arg, raw_linker_arg;
    const char* option_arg;
    struct options opts;
1221
    char* lang = 0;
1222
    char* str;
1223

1224
#ifdef SIGHUP
1225
    signal( SIGHUP, exit_on_signal );
1226
#endif
1227 1228
    signal( SIGTERM, exit_on_signal );
    signal( SIGINT, exit_on_signal );
1229
#ifdef HAVE_SIGADDSET
1230 1231 1232 1233
    sigemptyset( &signal_mask );
    sigaddset( &signal_mask, SIGHUP );
    sigaddset( &signal_mask, SIGTERM );
    sigaddset( &signal_mask, SIGINT );
1234
#endif
1235

1236
    /* setup tmp file removal at exit */
1237
    tmp_files = strarray_alloc();
1238 1239
    atexit(clean_temp_files);
    
1240 1241
    /* initialize options */
    memset(&opts, 0, sizeof(opts));
1242 1243
    opts.target_cpu = build_cpu;
    opts.target_platform = build_platform;
1244 1245 1246 1247
    opts.lib_dirs = strarray_alloc();
    opts.files = strarray_alloc();
    opts.linker_args = strarray_alloc();
    opts.compiler_args = strarray_alloc();
1248
    opts.winebuild_args = strarray_alloc();
1249 1250

    /* determine the processor type */
1251 1252
    if (strendswith(argv[0], "winecpp")) opts.processor = proc_cpp;
    else if (strendswith(argv[0], "++")) opts.processor = proc_cxx;
1253
    
1254
    /* parse options */
1255 1256 1257 1258
    for ( i = 1 ; i < argc ; i++ ) 
    {
        if (argv[i][0] == '-')  /* option */
	{
1259
	    /* determine if this switch is followed by a separate argument */
1260
	    next_is_arg = 0;
1261 1262 1263 1264 1265
	    option_arg = 0;
	    switch(argv[i][1])
	    {
		case 'x': case 'o': case 'D': case 'U':
		case 'I': case 'A': case 'l': case 'u':
1266
		case 'b': case 'V': case 'G': case 'L':
1267
		case 'B': case 'R': case 'z':
1268
		    if (argv[i][2]) option_arg = &argv[i][2];
1269 1270 1271 1272 1273 1274 1275 1276
		    else next_is_arg = 1;
		    break;
		case 'i':
		    next_is_arg = 1;
		    break;
		case 'a':
		    if (strcmp("-aux-info", argv[i]) == 0)
			next_is_arg = 1;
1277 1278
		    if (strcmp("-arch", argv[i]) == 0)
			next_is_arg = 1;
1279 1280 1281 1282 1283 1284 1285 1286 1287
		    break;
		case 'X':
		    if (strcmp("-Xlinker", argv[i]) == 0)
			next_is_arg = 1;
		    break;
		case 'M':
		    c = argv[i][2];
		    if (c == 'F' || c == 'T' || c == 'Q')
		    {
1288
			if (argv[i][3]) option_arg = &argv[i][3];
1289 1290 1291
			else next_is_arg = 1;
		    }
		    break;
1292 1293 1294 1295
		case 'f':
		    if (strcmp("-framework", argv[i]) == 0)
			next_is_arg = 1;
		    break;
1296 1297 1298 1299
		case '-':
		    if (strcmp("--param", argv[i]) == 0)
			next_is_arg = 1;
		    break;
1300
	    }
1301 1302 1303 1304 1305
	    if (next_is_arg)
            {
                if (i + 1 >= argc) error("option -%c requires an argument\n", argv[i][1]);
                option_arg = argv[i+1];
            }
1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324

	    /* determine what options go 'as is' to the linker & the compiler */
	    raw_compiler_arg = raw_linker_arg = 0;
	    if (is_linker_arg(argv[i])) 
	    {
		raw_linker_arg = 1;
	    }
	    else 
	    {
		if (is_directory_arg(argv[i]) || is_target_arg(argv[i]))
		    raw_linker_arg = 1;
		raw_compiler_arg = !is_mingw_arg(argv[i]);
	    }

	    /* these things we handle explicitly so we don't pass them 'as is' */
	    if (argv[i][1] == 'l' || argv[i][1] == 'I' || argv[i][1] == 'L')
		raw_linker_arg = 0;
	    if (argv[i][1] == 'c' || argv[i][1] == 'L')
		raw_compiler_arg = 0;
1325
	    if (argv[i][1] == 'o' || argv[i][1] == 'b' || argv[i][1] == 'V')
1326 1327 1328
		raw_compiler_arg = raw_linker_arg = 0;

	    /* do a bit of semantic analysis */
1329 1330
            switch (argv[i][1]) 
	    {
1331 1332
		case 'B':
		    str = strdup(option_arg);
1333
		    if (strendswith(str, "/")) str[strlen(str) - 1] = 0;
1334 1335
		    if (strendswith(str, "/tools/winebuild"))
                    {
1336 1337 1338
                        char *objdir = strdup(str);
                        objdir[strlen(objdir) - sizeof("/tools/winebuild") + 1] = 0;
                        opts.wine_objdir = objdir;
1339 1340 1341 1342 1343
                        /* don't pass it to the compiler, this generates warnings */
                        raw_compiler_arg = raw_linker_arg = 0;
                    }
                    if (!opts.prefix) opts.prefix = strarray_alloc();
                    strarray_add(opts.prefix, str);
1344
		    break;
1345 1346 1347
                case 'b':
                    parse_target_option( &opts, option_arg );
                    break;
1348 1349 1350
                case 'V':
                    opts.version = xstrdup( option_arg );
                    break;
1351
                case 'c':        /* compile or assemble */
1352 1353
		    if (argv[i][2] == 0) opts.compile_only = 1;
		    /* fall through */
1354 1355 1356 1357
                case 'S':        /* generate assembler code */
                case 'E':        /* preprocess only */
                    if (argv[i][2] == 0) linking = 0;
                    break;
1358 1359 1360
		case 'f':
		    if (strcmp("-fno-short-wchar", argv[i]) == 0)
                        opts.noshortwchar = 1;
1361 1362 1363 1364
		    else if (!strcmp("-fasynchronous-unwind-tables", argv[i]))
                        opts.unwind_tables = 1;
		    else if (!strcmp("-fno-asynchronous-unwind-tables", argv[i]))
                        opts.unwind_tables = 0;
1365
		    break;
1366
		case 'l':
1367
		    strarray_add(opts.files, strmake("-l%s", option_arg));
1368 1369 1370 1371
		    break;
		case 'L':
		    strarray_add(opts.lib_dirs, option_arg);
		    break;
1372 1373 1374
                case 'M':        /* map file generation */
                    linking = 0;
                    break;
1375 1376
		case 'm':
		    if (strcmp("-mno-cygwin", argv[i]) == 0)
1377
			opts.use_msvcrt = 1;
1378
		    else if (strcmp("-mwindows", argv[i]) == 0)
1379
			opts.gui_app = 1;
Richard Cohen's avatar
Richard Cohen committed
1380
		    else if (strcmp("-mconsole", argv[i]) == 0)
1381
			opts.gui_app = 0;
1382 1383
		    else if (strcmp("-municode", argv[i]) == 0)
			opts.unicode_app = 1;
1384 1385
		    else if (strcmp("-m16", argv[i]) == 0)
			opts.win16_app = 1;
1386 1387
		    else if (strcmp("-m32", argv[i]) == 0)
                    {
1388 1389
                        if (opts.target_cpu == CPU_x86_64)
                            opts.target_cpu = CPU_x86;
1390
                        opts.force_pointer_size = 4;
1391
			raw_linker_arg = 1;
1392 1393 1394 1395 1396 1397
                    }
		    else if (strcmp("-m64", argv[i]) == 0)
                    {
                        opts.force_pointer_size = 8;
			raw_linker_arg = 1;
                    }
1398 1399
                    else if (strncmp("-mcpu=", argv[i], 6) == 0)
                        strarray_add(opts.winebuild_args, argv[i]);
1400 1401 1402
		    break;
                case 'n':
                    if (strcmp("-nostdinc", argv[i]) == 0)
1403
                        opts.nostdinc = 1;
1404
                    else if (strcmp("-nodefaultlibs", argv[i]) == 0)
1405
                        opts.nodefaultlibs = 1;
1406
                    else if (strcmp("-nostdlib", argv[i]) == 0)
1407
                        opts.nostdlib = 1;
1408 1409
                    else if (strcmp("-nostartfiles", argv[i]) == 0)
                        opts.nostartfiles = 1;
1410
                    break;
1411 1412 1413
		case 'o':
		    opts.output_name = option_arg;
		    break;
1414
                case 's':
1415 1416
                    if (strcmp("-static", argv[i]) == 0) 
			linking = -1;
1417 1418
		    else if(strcmp("-save-temps", argv[i]) == 0)
			keep_generated = 1;
1419 1420 1421 1422 1423
		    else if(strcmp("-shared", argv[i]) == 0)
		    {
			opts.shared = 1;
                        raw_compiler_arg = raw_linker_arg = 0;
		    }
1424 1425 1426 1427 1428 1429 1430 1431 1432
                    else if (strcmp("-s", argv[i]) == 0 && opts.target_platform == PLATFORM_APPLE)
                    {
                        /* On Mac, change -s into -Wl,-x. ld's -s switch
                         * is deprecated, and it doesn't work on Tiger with
                         * MH_BUNDLEs anyway
                         */
                        opts.strip = 1;
                        raw_linker_arg = 0;
                    }
1433
                    break;
1434
                case 'v':
1435
                    if (argv[i][2] == 0) verbose++;
1436
                    break;
1437 1438 1439
                case 'W':
                    if (strncmp("-Wl,", argv[i], 4) == 0)
		    {
1440 1441 1442 1443 1444 1445 1446 1447 1448
                        unsigned int j;
                        strarray* Wl = strarray_fromstring(argv[i] + 4, ",");
                        for (j = 0; j < Wl->size; j++)
                        {
                            if (!strcmp(Wl->base[j], "--image-base") && j < Wl->size - 1)
                            {
                                opts.image_base = strdup( Wl->base[++j] );
                                continue;
                            }
1449 1450 1451 1452 1453
                            if (!strcmp(Wl->base[j], "--section-alignment") && j < Wl->size - 1)
                            {
                                opts.section_align = strdup( Wl->base[++j] );
                                continue;
                            }
1454 1455 1456 1457 1458
                            if (!strcmp(Wl->base[j], "--large-address-aware"))
                            {
                                opts.large_address_aware = 1;
                                continue;
                            }
1459 1460 1461 1462 1463
                            if (!strcmp(Wl->base[j], "-static")) linking = -1;
                            strarray_add(opts.linker_args, strmake("-Wl,%s",Wl->base[j]));
                        }
                        strarray_free(Wl);
                        raw_compiler_arg = raw_linker_arg = 0;
1464
                    }
1465 1466 1467 1468 1469
		    else if (strncmp("-Wb,", argv[i], 4) == 0)
		    {
			strarray* Wb = strarray_fromstring(argv[i] + 4, ",");
			strarray_addall(opts.winebuild_args, Wb);
			strarray_free(Wb);
1470 1471
                        /* don't pass it to the compiler, it generates errors */
                        raw_compiler_arg = raw_linker_arg = 0;
1472
		    }
1473
                    break;
1474 1475 1476
		case 'x':
		    lang = strmake("-x%s", option_arg);
		    strarray_add(opts.files, lang);
Austin English's avatar
Austin English committed
1477
		    /* we'll pass these flags ourselves, explicitly */
1478 1479
                    raw_compiler_arg = raw_linker_arg = 0;
		    break;
1480 1481
                case '-':
                    if (strcmp("-static", argv[i]+1) == 0)
1482
                        linking = -1;
1483 1484 1485 1486 1487 1488
                    else if (!strncmp("--sysroot", argv[i], 9) && opts.wine_objdir)
                    {
                        if (argv[i][9] == '=') opts.wine_objdir = argv[i] + 10;
                        else opts.wine_objdir = argv[++i];
                        raw_compiler_arg = raw_linker_arg = 0;
                    }
1489 1490 1491 1492 1493 1494
                    else if (!strncmp("--lib-suffix", argv[i], 12) && opts.wine_objdir)
                    {
                        if (argv[i][12] == '=') opts.lib_suffix = argv[i] + 13;
                        else opts.lib_suffix = argv[++i];
                        raw_compiler_arg = raw_linker_arg = 0;
                    }
1495 1496
                    break;
            }
1497

1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511
	    /* put the arg into the appropriate bucket */
	    if (raw_linker_arg) 
	    {
		strarray_add(opts.linker_args, argv[i]);
		if (next_is_arg && (i + 1 < argc)) 
		    strarray_add(opts.linker_args, argv[i + 1]);
	    }
	    if (raw_compiler_arg)
	    {
		strarray_add(opts.compiler_args, argv[i]);
		if (next_is_arg && (i + 1 < argc))
		    strarray_add(opts.compiler_args, argv[i + 1]);
	    }

1512 1513 1514
	    /* skip the next token if it's an argument */
	    if (next_is_arg) i++;
        }
1515 1516
	else
	{
1517 1518
	    strarray_add(opts.files, argv[i]);
	} 
1519 1520
    }

1521
    if (opts.processor == proc_cpp) linking = 0;
1522
    if (linking == -1) error("Static linking is not supported\n");
1523

1524 1525
    if (opts.files->size == 0) forward(argc, argv, &opts);
    else if (linking) build(&opts);
1526
    else compile(&opts, lang);
1527

1528
    return 0;
1529
}