makedep.c 117 KB
Newer Older
Alexandre Julliard's avatar
Alexandre Julliard committed
1 2 3
/*
 * Generate include file dependencies
 *
4
 * Copyright 1996, 2013 Alexandre Julliard
5 6 7 8 9 10 11 12 13 14 15 16 17
 *
 * 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
18
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
Alexandre Julliard's avatar
Alexandre Julliard committed
19 20
 */

21
#include "config.h"
22
#define NO_LIBWINE_PORT
23 24
#include "wine/port.h"

25
#include <assert.h>
Alexandre Julliard's avatar
Alexandre Julliard committed
26
#include <ctype.h>
27
#include <errno.h>
Alexandre Julliard's avatar
Alexandre Julliard committed
28 29
#include <stdio.h>
#include <stdlib.h>
30
#include <stdarg.h>
31
#include <signal.h>
Alexandre Julliard's avatar
Alexandre Julliard committed
32
#include <string.h>
33 34 35
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
36
#include "wine/list.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
37

38 39 40 41 42
enum incl_type
{
    INCL_NORMAL,           /* #include "foo.h" */
    INCL_SYSTEM,           /* #include <foo.h> */
    INCL_IMPORT,           /* idl import "foo.idl" */
43
    INCL_IMPORTLIB,        /* idl importlib "foo.tlb" */
44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
    INCL_CPP_QUOTE,        /* idl cpp_quote("#include \"foo.h\"") */
    INCL_CPP_QUOTE_SYSTEM  /* idl cpp_quote("#include <foo.h>") */
};

struct dependency
{
    int                line;          /* source line where this header is included */
    enum incl_type     type;          /* type of include */
    char              *name;          /* header name */
};

struct file
{
    struct list        entry;
    char              *name;          /* full file name relative to cwd */
    void              *args;          /* custom arguments for makefile rule */
    unsigned int       flags;         /* flags (see below) */
    unsigned int       deps_count;    /* files in use */
    unsigned int       deps_size;     /* total allocated size */
    struct dependency *deps;          /* all header dependencies */
};

66
struct incl_file
Alexandre Julliard's avatar
Alexandre Julliard committed
67
{
68
    struct list        entry;
69
    struct file       *file;
Alexandre Julliard's avatar
Alexandre Julliard committed
70 71
    char              *name;
    char              *filename;
72
    char              *sourcename;    /* source file name for generated headers */
73
    struct incl_file  *included_by;   /* file that included this one */
74
    int                included_line; /* line where this file was included */
75
    enum incl_type     type;          /* type of include */
76
    struct incl_file  *owner;
77 78 79
    unsigned int       files_count;   /* files in use */
    unsigned int       files_size;    /* total allocated size */
    struct incl_file **files;
80
};
Alexandre Julliard's avatar
Alexandre Julliard committed
81

82 83
#define FLAG_GENERATED      0x000001  /* generated file */
#define FLAG_INSTALL        0x000002  /* file to install */
84 85 86 87 88 89 90 91 92 93
#define FLAG_IDL_PROXY      0x000100  /* generates a proxy (_p.c) file */
#define FLAG_IDL_CLIENT     0x000200  /* generates a client (_c.c) file */
#define FLAG_IDL_SERVER     0x000400  /* generates a server (_s.c) file */
#define FLAG_IDL_IDENT      0x000800  /* generates an ident (_i.c) file */
#define FLAG_IDL_REGISTER   0x001000  /* generates a registration (_r.res) file */
#define FLAG_IDL_TYPELIB    0x002000  /* generates a typelib (.tlb) file */
#define FLAG_IDL_REGTYPELIB 0x004000  /* generates a registered typelib (_t.res) file */
#define FLAG_IDL_HEADER     0x008000  /* generates a header (.h) file */
#define FLAG_RC_PO          0x010000  /* rc file contains translations */
#define FLAG_C_IMPLIB       0x020000 /* file is part of an import library */
94
#define FLAG_SFD_FONTS      0x040000 /* sfd file generated bitmap fonts */
95 96 97 98 99 100 101

static const struct
{
    unsigned int flag;
    const char *ext;
} idl_outputs[] =
{
102 103 104 105 106 107 108 109
    { FLAG_IDL_TYPELIB,    ".tlb" },
    { FLAG_IDL_REGTYPELIB, "_t.res" },
    { FLAG_IDL_CLIENT,     "_c.c" },
    { FLAG_IDL_IDENT,      "_i.c" },
    { FLAG_IDL_PROXY,      "_p.c" },
    { FLAG_IDL_SERVER,     "_s.c" },
    { FLAG_IDL_REGISTER,   "_r.res" },
    { FLAG_IDL_HEADER,     ".h" }
110 111
};

112 113 114
#define HASH_SIZE 137

static struct list files[HASH_SIZE];
Alexandre Julliard's avatar
Alexandre Julliard committed
115

116 117 118 119 120 121 122
struct strarray
{
    unsigned int count;  /* strings in use */
    unsigned int size;   /* total allocated size */
    const char **str;
};

123 124
static const struct strarray empty_strarray;

125 126
enum install_rules { INSTALL_LIB, INSTALL_DEV, NB_INSTALL_RULES };

127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147
/* variables common to all makefiles */
static struct strarray linguas;
static struct strarray dll_flags;
static struct strarray target_flags;
static struct strarray msvcrt_flags;
static struct strarray extra_cflags;
static struct strarray cpp_flags;
static struct strarray unwind_flags;
static struct strarray libs;
static struct strarray cmdline_vars;
static const char *root_src_dir;
static const char *tools_dir;
static const char *tools_ext;
static const char *exe_ext;
static const char *dll_ext;
static const char *man_ext;
static const char *crosstarget;
static const char *fontforge;
static const char *convert;
static const char *rsvg;
static const char *icotool;
148
static const char *dlltool;
149

150 151 152
struct makefile
{
    struct strarray vars;
153
    struct strarray include_paths;
154
    struct strarray define_args;
155
    struct strarray programs;
156
    struct strarray scripts;
157 158
    struct strarray appmode;
    struct strarray imports;
159
    struct strarray subdirs;
160 161
    struct strarray delayimports;
    struct strarray extradllflags;
162 163
    struct strarray install_lib;
    struct strarray install_dev;
164
    struct list     sources;
165
    struct list     includes;
166 167
    const char     *base_dir;
    const char     *src_dir;
168
    const char     *obj_dir;
169 170 171
    const char     *top_src_dir;
    const char     *top_obj_dir;
    const char     *parent_dir;
172 173
    const char     *module;
    const char     *testdll;
174
    const char     *sharedlib;
175 176
    const char     *staticlib;
    const char     *importlib;
177
    int             use_msvcrt;
178
    int             is_win16;
179
    struct makefile **submakes;
180 181
};

182
static struct makefile *top_makefile;
183

184
static const char *output_makefile_name = "Makefile";
185
static const char *input_file_name;
186 187
static const char *output_file_name;
static const char *temp_file_name;
188
static int relative_dir_mode;
189
static int input_line;
190
static int output_column;
191
static FILE *output_file;
Alexandre Julliard's avatar
Alexandre Julliard committed
192 193

static const char Usage[] =
194
    "Usage: makedep [options] [directories]\n"
Alexandre Julliard's avatar
Alexandre Julliard committed
195
    "Options:\n"
196
    "   -R from to  Compute the relative path between two directories\n"
197
    "   -fxxx       Store output in file 'xxx' (default: Makefile)\n";
Alexandre Julliard's avatar
Alexandre Julliard committed
198 199


200 201 202 203 204 205
#ifndef __GNUC__
#define __attribute__(x)
#endif

static void fatal_error( const char *msg, ... ) __attribute__ ((__format__ (__printf__, 1, 2)));
static void fatal_perror( const char *msg, ... ) __attribute__ ((__format__ (__printf__, 1, 2)));
206
static void output( const char *format, ... ) __attribute__ ((__format__ (__printf__, 1, 2)));
207
static char *strmake( const char* fmt, ... ) __attribute__ ((__format__ (__printf__, 1, 2)));
208

209 210 211 212 213 214 215
/*******************************************************************
 *         fatal_error
 */
static void fatal_error( const char *msg, ... )
{
    va_list valist;
    va_start( valist, msg );
216 217 218 219 220 221 222
    if (input_file_name)
    {
        fprintf( stderr, "%s:", input_file_name );
        if (input_line) fprintf( stderr, "%d:", input_line );
        fprintf( stderr, " error: " );
    }
    else fprintf( stderr, "makedep: error: " );
223 224 225 226 227 228
    vfprintf( stderr, msg, valist );
    va_end( valist );
    exit(1);
}


229 230 231 232 233 234 235 236 237 238 239
/*******************************************************************
 *         fatal_perror
 */
static void fatal_perror( const char *msg, ... )
{
    va_list valist;
    va_start( valist, msg );
    if (input_file_name)
    {
        fprintf( stderr, "%s:", input_file_name );
        if (input_line) fprintf( stderr, "%d:", input_line );
240
        fprintf( stderr, " error: " );
241
    }
242 243
    else fprintf( stderr, "makedep: error: " );
    vfprintf( stderr, msg, valist );
244 245 246 247 248 249
    perror( " " );
    va_end( valist );
    exit(1);
}


250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268
/*******************************************************************
 *         cleanup_files
 */
static void cleanup_files(void)
{
    if (temp_file_name) unlink( temp_file_name );
    if (output_file_name) unlink( output_file_name );
}


/*******************************************************************
 *         exit_on_signal
 */
static void exit_on_signal( int sig )
{
    exit( 1 );  /* this will call the atexit functions */
}


Alexandre Julliard's avatar
Alexandre Julliard committed
269 270 271
/*******************************************************************
 *         xmalloc
 */
272
static void *xmalloc( size_t size )
Alexandre Julliard's avatar
Alexandre Julliard committed
273 274 275
{
    void *res;
    if (!(res = malloc (size ? size : 1)))
276
        fatal_error( "Virtual memory exhausted.\n" );
Alexandre Julliard's avatar
Alexandre Julliard committed
277 278 279 280
    return res;
}


281 282 283
/*******************************************************************
 *         xrealloc
 */
284
static void *xrealloc (void *ptr, size_t size)
285 286 287 288
{
    void *res;
    assert( size );
    if (!(res = realloc( ptr, size )))
289
        fatal_error( "Virtual memory exhausted.\n" );
290 291 292
    return res;
}

Alexandre Julliard's avatar
Alexandre Julliard committed
293 294 295 296 297 298
/*******************************************************************
 *         xstrdup
 */
static char *xstrdup( const char *str )
{
    char *res = strdup( str );
299
    if (!res) fatal_error( "Virtual memory exhausted.\n" );
Alexandre Julliard's avatar
Alexandre Julliard committed
300 301 302 303
    return res;
}


304 305 306
/*******************************************************************
 *         strmake
 */
307
static char *strmake( const char* fmt, ... )
308 309 310 311 312 313 314 315 316 317 318 319 320
{
    int n;
    size_t size = 100;
    va_list ap;

    for (;;)
    {
        char *p = xmalloc (size);
        va_start(ap, fmt);
        n = vsnprintf (p, size, fmt, ap);
        va_end(ap);
        if (n == -1) size *= 2;
        else if ((size_t)n >= size) size = n + 1;
321
        else return xrealloc( p, n + 1 );
322 323 324 325 326
        free(p);
    }
}


327 328 329 330 331
/*******************************************************************
 *         strendswith
 */
static int strendswith( const char* str, const char* end )
{
332 333
    size_t l = strlen( str );
    size_t m = strlen( end );
334 335 336 337

    return l >= m && strcmp(str + l - m, end) == 0;
}

338 339 340 341

/*******************************************************************
 *         output
 */
342
static void output( const char *format, ... )
343 344 345 346 347 348 349 350
{
    int ret;
    va_list valist;

    va_start( valist, format );
    ret = vfprintf( output_file, format, valist );
    va_end( valist );
    if (ret < 0) fatal_perror( "output" );
351 352
    if (format[0] && format[strlen(format) - 1] == '\n') output_column = 0;
    else output_column += ret;
353 354 355
}


356 357 358 359 360 361 362 363 364 365 366 367 368 369 370
/*******************************************************************
 *         strarray_add
 */
static void strarray_add( struct strarray *array, const char *str )
{
    if (array->count == array->size)
    {
	if (array->size) array->size *= 2;
        else array->size = 16;
	array->str = xrealloc( array->str, sizeof(array->str[0]) * array->size );
    }
    array->str[array->count++] = str;
}


371 372 373
/*******************************************************************
 *         strarray_addall
 */
374
static void strarray_addall( struct strarray *array, struct strarray added )
375 376 377
{
    unsigned int i;

378
    for (i = 0; i < added.count; i++) strarray_add( array, added.str[i] );
379 380 381
}


382
/*******************************************************************
383
 *         strarray_exists
384
 */
385
static int strarray_exists( const struct strarray *array, const char *str )
386 387 388
{
    unsigned int i;

389 390 391 392 393 394 395 396 397 398 399
    for (i = 0; i < array->count; i++) if (!strcmp( array->str[i], str )) return 1;
    return 0;
}


/*******************************************************************
 *         strarray_add_uniq
 */
static void strarray_add_uniq( struct strarray *array, const char *str )
{
    if (!strarray_exists( array, str )) strarray_add( array, str );
400 401 402
}


403 404 405 406 407
/*******************************************************************
 *         strarray_get_value
 *
 * Find a value in a name/value pair string array.
 */
408
static const char *strarray_get_value( const struct strarray *array, const char *name )
409 410 411 412
{
    unsigned int i;

    for (i = 0; i < array->count; i += 2)
413
        if (!strcmp( array->str[i], name )) return array->str[i + 1];
414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438
    return NULL;
}


/*******************************************************************
 *         strarray_set_value
 *
 * Define a value in a name/value pair string array.
 */
static void strarray_set_value( struct strarray *array, const char *name, const char *value )
{
    unsigned int i;

    /* redefining a variable replaces the previous value */
    for (i = 0; i < array->count; i += 2)
    {
        if (strcmp( array->str[i], name )) continue;
        array->str[i + 1] = value;
        return;
    }
    strarray_add( array, name );
    strarray_add( array, value );
}


439 440 441
/*******************************************************************
 *         output_filename
 */
442
static void output_filename( const char *name )
443
{
444
    if (output_column + strlen(name) + 1 > 100)
445
    {
446 447
        output( " \\\n" );
        output( "  " );
448
    }
449 450
    else if (output_column) output( " " );
    output( "%s", name );
451 452 453 454 455 456
}


/*******************************************************************
 *         output_filenames
 */
457
static void output_filenames( struct strarray array )
458 459 460
{
    unsigned int i;

461
    for (i = 0; i < array.count; i++) output_filename( array.str[i] );
462 463 464
}


465 466 467 468 469 470 471 472 473 474 475
/*******************************************************************
 *         get_extension
 */
static char *get_extension( char *filename )
{
    char *ext = strrchr( filename, '.' );
    if (ext && strchr( ext, '/' )) ext = NULL;
    return ext;
}


476 477 478
/*******************************************************************
 *         replace_extension
 */
479
static char *replace_extension( const char *name, const char *old_ext, const char *new_ext )
480
{
481
    char *ret;
482 483
    size_t name_len = strlen( name );
    size_t ext_len = strlen( old_ext );
484 485 486 487 488

    if (name_len >= ext_len && !strcmp( name + name_len - ext_len, old_ext )) name_len -= ext_len;
    ret = xmalloc( name_len + strlen( new_ext ) + 1 );
    memcpy( ret, name, name_len );
    strcpy( ret + name_len, new_ext );
489 490 491 492
    return ret;
}


493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511
/*******************************************************************
 *         replace_filename
 */
static char *replace_filename( const char *path, const char *name )
{
    const char *p;
    char *ret;
    size_t len;

    if (!path) return xstrdup( name );
    if (!(p = strrchr( path, '/' ))) return xstrdup( name );
    len = p - path + 1;
    ret = xmalloc( len + strlen( name ) + 1 );
    memcpy( ret, path, len );
    strcpy( ret + len, name );
    return ret;
}


512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527
/*******************************************************************
 *         strarray_replace_extension
 */
static struct strarray strarray_replace_extension( const struct strarray *array,
                                                   const char *old_ext, const char *new_ext )
{
    unsigned int i;
    struct strarray ret;

    ret.count = ret.size = array->count;
    ret.str = xmalloc( sizeof(ret.str[0]) * ret.size );
    for (i = 0; i < array->count; i++) ret.str[i] = replace_extension( array->str[i], old_ext, new_ext );
    return ret;
}


528 529 530
/*******************************************************************
 *         replace_substr
 */
531
static char *replace_substr( const char *str, const char *start, size_t len, const char *replace )
532
{
533
    size_t pos = start - str;
534 535 536 537 538 539 540 541
    char *ret = xmalloc( pos + strlen(replace) + strlen(start + len) + 1 );
    memcpy( ret, str, pos );
    strcpy( ret + pos, replace );
    strcat( ret + pos, start + len );
    return ret;
}


542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587
/*******************************************************************
 *         get_relative_path
 *
 * Determine where the destination path is located relative to the 'from' path.
 */
static char *get_relative_path( const char *from, const char *dest )
{
    const char *start;
    char *ret, *p;
    unsigned int dotdots = 0;

    /* a path of "." is equivalent to an empty path */
    if (!strcmp( from, "." )) from = "";

    for (;;)
    {
        while (*from == '/') from++;
        while (*dest == '/') dest++;
        start = dest;  /* save start of next path element */
        if (!*from) break;

        while (*from && *from != '/' && *from == *dest) { from++; dest++; }
        if ((!*from || *from == '/') && (!*dest || *dest == '/')) continue;

        /* count remaining elements in 'from' */
        do
        {
            dotdots++;
            while (*from && *from != '/') from++;
            while (*from == '/') from++;
        }
        while (*from);
        break;
    }

    if (!start[0] && !dotdots) return NULL;  /* empty path */

    ret = xmalloc( 3 * dotdots + strlen( start ) + 1 );
    for (p = ret; dotdots; dotdots--, p += 3) memcpy( p, "../", 3 );

    if (start[0]) strcpy( p, start );
    else p[-1] = 0;  /* remove trailing slash */
    return ret;
}


588 589 590 591 592
/*******************************************************************
 *         concat_paths
 */
static char *concat_paths( const char *base, const char *path )
{
593
    if (!base || !base[0]) return xstrdup( path && path[0] ? path : "." );
594
    if (!path || !path[0]) return xstrdup( base );
595 596 597 598 599
    if (path[0] == '/') return xstrdup( path );
    return strmake( "%s/%s", base, path );
}


600 601 602
/*******************************************************************
 *         base_dir_path
 */
603
static char *base_dir_path( const struct makefile *make, const char *path )
604
{
605
    return concat_paths( make->base_dir, path );
606 607 608
}


609 610 611
/*******************************************************************
 *         obj_dir_path
 */
612
static char *obj_dir_path( const struct makefile *make, const char *path )
613 614 615 616 617
{
    return concat_paths( make->obj_dir, path );
}


618 619 620
/*******************************************************************
 *         src_dir_path
 */
621
static char *src_dir_path( const struct makefile *make, const char *path )
622
{
623
    if (make->src_dir) return concat_paths( make->src_dir, path );
624
    return obj_dir_path( make, path );
625 626 627 628 629 630
}


/*******************************************************************
 *         top_obj_dir_path
 */
631
static char *top_obj_dir_path( const struct makefile *make, const char *path )
632
{
633
    return concat_paths( make->top_obj_dir, path );
634 635 636 637 638 639
}


/*******************************************************************
 *         top_dir_path
 */
640
static char *top_dir_path( const struct makefile *make, const char *path )
641
{
642
    if (make->top_src_dir) return concat_paths( make->top_src_dir, path );
643
    return top_obj_dir_path( make, path );
644 645 646
}


647 648 649 650 651 652 653 654 655
/*******************************************************************
 *         root_dir_path
 */
static char *root_dir_path( const char *path )
{
    return concat_paths( root_src_dir, path );
}


656 657 658
/*******************************************************************
 *         tools_dir_path
 */
659
static char *tools_dir_path( const struct makefile *make, const char *path )
660
{
661 662
    if (tools_dir) return top_obj_dir_path( make, strmake( "%s/tools/%s", tools_dir, path ));
    return top_obj_dir_path( make, strmake( "tools/%s", path ));
663 664 665
}


666 667 668
/*******************************************************************
 *         tools_path
 */
669
static char *tools_path( const struct makefile *make, const char *name )
670
{
671
    return strmake( "%s/%s%s", tools_dir_path( make, name ), name, tools_ext );
672 673 674
}


675 676 677 678 679 680
/*******************************************************************
 *         get_line
 */
static char *get_line( FILE *file )
{
    static char *buffer;
681
    static size_t size;
682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697

    if (!size)
    {
        size = 1024;
        buffer = xmalloc( size );
    }
    if (!fgets( buffer, size, file )) return NULL;
    input_line++;

    for (;;)
    {
        char *p = buffer + strlen(buffer);
        /* if line is larger than buffer, resize buffer */
        while (p == buffer + size - 1 && p[-1] != '\n')
        {
            buffer = xrealloc( buffer, size * 2 );
698
            if (!fgets( buffer + size - 1, size + 1, file )) break;
699 700 701 702 703 704 705 706 707 708 709
            p = buffer + strlen(buffer);
            size *= 2;
        }
        if (p > buffer && p[-1] == '\n')
        {
            *(--p) = 0;
            if (p > buffer && p[-1] == '\r') *(--p) = 0;
            if (p > buffer && p[-1] == '\\')
            {
                *(--p) = 0;
                /* line ends in backslash, read continuation line */
710
                if (!fgets( p, size - (p - buffer), file )) return buffer;
711 712 713 714 715 716 717 718
                input_line++;
                continue;
            }
        }
        return buffer;
    }
}

719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784

/*******************************************************************
 *         hash_filename
 */
static unsigned int hash_filename( const char *name )
{
    unsigned int ret = 0;
    while (*name) ret = (ret << 7) + (ret << 3) + *name++;
    return ret % HASH_SIZE;
}


/*******************************************************************
 *         add_file
 */
static struct file *add_file( const char *name )
{
    struct file *file = xmalloc( sizeof(*file) );
    memset( file, 0, sizeof(*file) );
    file->name = xstrdup( name );
    list_add_tail( &files[hash_filename( name )], &file->entry );
    return file;
}


/*******************************************************************
 *         add_dependency
 */
static void add_dependency( struct file *file, const char *name, enum incl_type type )
{
    /* enforce some rules for the Wine tree */

    if (!memcmp( name, "../", 3 ))
        fatal_error( "#include directive with relative path not allowed\n" );

    if (!strcmp( name, "config.h" ))
    {
        if (strendswith( file->name, ".h" ))
            fatal_error( "config.h must not be included by a header file\n" );
        if (file->deps_count)
            fatal_error( "config.h must be included before anything else\n" );
    }
    else if (!strcmp( name, "wine/port.h" ))
    {
        if (strendswith( file->name, ".h" ))
            fatal_error( "wine/port.h must not be included by a header file\n" );
        if (!file->deps_count) fatal_error( "config.h must be included before wine/port.h\n" );
        if (file->deps_count > 1)
            fatal_error( "wine/port.h must be included before everything except config.h\n" );
        if (strcmp( file->deps[0].name, "config.h" ))
            fatal_error( "config.h must be included before wine/port.h\n" );
    }

    if (file->deps_count >= file->deps_size)
    {
        file->deps_size *= 2;
        if (file->deps_size < 16) file->deps_size = 16;
        file->deps = xrealloc( file->deps, file->deps_size * sizeof(*file->deps) );
    }
    file->deps[file->deps_count].line = input_line;
    file->deps[file->deps_count].type = type;
    file->deps[file->deps_count].name = xstrdup( name );
    file->deps_count++;
}


785 786 787
/*******************************************************************
 *         find_src_file
 */
788
static struct incl_file *find_src_file( const struct makefile *make, const char *name )
789
{
790
    struct incl_file *file;
791

792
    LIST_FOR_EACH_ENTRY( file, &make->sources, struct incl_file, entry )
793 794 795
        if (!strcmp( name, file->name )) return file;
    return NULL;
}
Alexandre Julliard's avatar
Alexandre Julliard committed
796

797 798 799
/*******************************************************************
 *         find_include_file
 */
800
static struct incl_file *find_include_file( const struct makefile *make, const char *name )
801
{
802
    struct incl_file *file;
803

804
    LIST_FOR_EACH_ENTRY( file, &make->includes, struct incl_file, entry )
805 806 807 808
        if (!strcmp( name, file->name )) return file;
    return NULL;
}

Alexandre Julliard's avatar
Alexandre Julliard committed
809 810 811 812 813
/*******************************************************************
 *         add_include
 *
 * Add an include file if it doesn't already exists.
 */
814
static struct incl_file *add_include( struct makefile *make, struct incl_file *parent,
815
                                      const char *name, int line, enum incl_type type )
Alexandre Julliard's avatar
Alexandre Julliard committed
816
{
817
    struct incl_file *include;
Alexandre Julliard's avatar
Alexandre Julliard committed
818

819 820 821 822 823 824
    if (parent->files_count >= parent->files_size)
    {
        parent->files_size *= 2;
        if (parent->files_size < 16) parent->files_size = 16;
        parent->files = xrealloc( parent->files, parent->files_size * sizeof(*parent->files) );
    }
825

826
    LIST_FOR_EACH_ENTRY( include, &make->includes, struct incl_file, entry )
827 828
        if (!strcmp( name, include->name )) goto found;

829 830
    include = xmalloc( sizeof(*include) );
    memset( include, 0, sizeof(*include) );
831
    include->name = xstrdup(name);
832
    include->included_by = parent;
833
    include->included_line = line;
834
    include->type = type;
835
    list_add_tail( &make->includes, &include->entry );
836
found:
837
    parent->files[parent->files_count++] = include;
838
    return include;
Alexandre Julliard's avatar
Alexandre Julliard committed
839 840 841
}


842 843 844 845 846
/*******************************************************************
 *         add_generated_source
 *
 * Add a generated source file to the list.
 */
847 848
static struct incl_file *add_generated_source( struct makefile *make,
                                               const char *name, const char *filename )
849 850 851
{
    struct incl_file *file;

852
    if ((file = find_src_file( make, name ))) return file;  /* we already have it */
853 854
    file = xmalloc( sizeof(*file) );
    memset( file, 0, sizeof(*file) );
855
    file->file = add_file( name );
856
    file->name = xstrdup( name );
857
    file->filename = obj_dir_path( make, filename ? filename : name );
858
    file->file->flags = FLAG_GENERATED;
859
    list_add_tail( &make->sources, &file->entry );
860 861 862 863
    return file;
}


864 865 866
/*******************************************************************
 *         parse_include_directive
 */
867
static void parse_include_directive( struct file *source, char *str )
868 869 870 871 872 873 874 875 876 877 878
{
    char quote, *include, *p = str;

    while (*p && isspace(*p)) p++;
    if (*p != '\"' && *p != '<' ) return;
    quote = *p++;
    if (quote == '<') quote = '>';
    include = p;
    while (*p && (*p != quote)) p++;
    if (!*p) fatal_error( "malformed include directive '%s'\n", str );
    *p = 0;
879
    add_dependency( source, include, (quote == '>') ? INCL_SYSTEM : INCL_NORMAL );
880 881 882 883 884 885
}


/*******************************************************************
 *         parse_pragma_directive
 */
886
static void parse_pragma_directive( struct file *source, char *str )
887 888 889 890 891 892 893 894 895 896 897 898
{
    char *flag, *p = str;

    if (!isspace( *p )) return;
    while (*p && isspace(*p)) p++;
    p = strtok( p, " \t" );
    if (strcmp( p, "makedep" )) return;

    while ((flag = strtok( NULL, " \t" )))
    {
        if (!strcmp( flag, "depend" ))
        {
899
            while ((p = strtok( NULL, " \t" ))) add_dependency( source, p, INCL_NORMAL );
900 901
            return;
        }
902 903
        else if (!strcmp( flag, "install" )) source->flags |= FLAG_INSTALL;

904 905 906 907 908 909 910 911 912
        if (strendswith( source->name, ".idl" ))
        {
            if (!strcmp( flag, "header" )) source->flags |= FLAG_IDL_HEADER;
            else if (!strcmp( flag, "proxy" )) source->flags |= FLAG_IDL_PROXY;
            else if (!strcmp( flag, "client" )) source->flags |= FLAG_IDL_CLIENT;
            else if (!strcmp( flag, "server" )) source->flags |= FLAG_IDL_SERVER;
            else if (!strcmp( flag, "ident" )) source->flags |= FLAG_IDL_IDENT;
            else if (!strcmp( flag, "typelib" )) source->flags |= FLAG_IDL_TYPELIB;
            else if (!strcmp( flag, "register" )) source->flags |= FLAG_IDL_REGISTER;
913
            else if (!strcmp( flag, "regtypelib" )) source->flags |= FLAG_IDL_REGTYPELIB;
914 915 916 917 918
        }
        else if (strendswith( source->name, ".rc" ))
        {
            if (!strcmp( flag, "po" )) source->flags |= FLAG_RC_PO;
        }
919 920 921 922
        else if (strendswith( source->name, ".sfd" ))
        {
            if (!strcmp( flag, "font" ))
            {
923 924 925 926 927 928 929 930 931
                struct strarray *array = source->args;

                if (!array)
                {
                    source->args = array = xmalloc( sizeof(*array) );
                    *array = empty_strarray;
                    source->flags |= FLAG_SFD_FONTS;
                }
                strarray_add( array, xstrdup( strtok( NULL, "" )));
932 933 934
                return;
            }
        }
935
        else if (!strcmp( flag, "implib" )) source->flags |= FLAG_C_IMPLIB;
936 937 938 939 940 941 942
    }
}


/*******************************************************************
 *         parse_cpp_directive
 */
943
static void parse_cpp_directive( struct file *source, char *str )
944 945 946 947 948 949 950 951 952 953 954 955 956 957
{
    while (*str && isspace(*str)) str++;
    if (*str++ != '#') return;
    while (*str && isspace(*str)) str++;

    if (!strncmp( str, "include", 7 ))
        parse_include_directive( source, str + 7 );
    else if (!strncmp( str, "import", 6 ) && strendswith( source->name, ".m" ))
        parse_include_directive( source, str + 6 );
    else if (!strncmp( str, "pragma", 6 ))
        parse_pragma_directive( source, str + 6 );
}


Alexandre Julliard's avatar
Alexandre Julliard committed
958
/*******************************************************************
959
 *         parse_idl_file
Alexandre Julliard's avatar
Alexandre Julliard committed
960
 */
961
static void parse_idl_file( struct file *source, FILE *file )
Alexandre Julliard's avatar
Alexandre Julliard committed
962
{
963
    char *buffer, *include;
964

965
    input_line = 0;
966

967
    while ((buffer = get_line( file )))
968
    {
969
        char quote;
970 971
        char *p = buffer;
        while (*p && isspace(*p)) p++;
972

973 974 975 976 977 978 979 980 981 982 983 984 985 986 987
        if (!strncmp( p, "importlib", 9 ))
        {
            p += 9;
            while (*p && isspace(*p)) p++;
            if (*p++ != '(') continue;
            while (*p && isspace(*p)) p++;
            if (*p++ != '"') continue;
            include = p;
            while (*p && (*p != '"')) p++;
            if (!*p) fatal_error( "malformed importlib directive\n" );
            *p = 0;
            add_dependency( source, include, INCL_IMPORTLIB );
            continue;
        }

988 989 990 991
        if (!strncmp( p, "import", 6 ))
        {
            p += 6;
            while (*p && isspace(*p)) p++;
992 993 994
            if (*p != '"') continue;
            include = ++p;
            while (*p && (*p != '"')) p++;
995
            if (!*p) fatal_error( "malformed import directive\n" );
996
            *p = 0;
997
            add_dependency( source, include, INCL_IMPORT );
998
            continue;
999
        }
1000

1001 1002
        /* check for #include inside cpp_quote */
        if (!strncmp( p, "cpp_quote", 9 ))
1003
        {
1004 1005 1006 1007 1008
            p += 9;
            while (*p && isspace(*p)) p++;
            if (*p++ != '(') continue;
            while (*p && isspace(*p)) p++;
            if (*p++ != '"') continue;
1009 1010 1011 1012 1013
            if (*p++ != '#') continue;
            while (*p && isspace(*p)) p++;
            if (strncmp( p, "include", 7 )) continue;
            p += 7;
            while (*p && isspace(*p)) p++;
1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026
            if (*p == '\\' && p[1] == '"')
            {
                p += 2;
                quote = '"';
            }
            else
            {
                if (*p++ != '<' ) continue;
                quote = '>';
            }
            include = p;
            while (*p && (*p != quote)) p++;
            if (!*p || (quote == '"' && p[-1] != '\\'))
1027
                fatal_error( "malformed #include directive inside cpp_quote\n" );
1028 1029
            if (quote == '"') p--;  /* remove backslash */
            *p = 0;
1030
            add_dependency( source, include, (quote == '>') ? INCL_CPP_QUOTE_SYSTEM : INCL_CPP_QUOTE );
1031
            continue;
1032 1033
        }

1034
        parse_cpp_directive( source, p );
1035
    }
1036
}
1037

1038 1039 1040
/*******************************************************************
 *         parse_c_file
 */
1041
static void parse_c_file( struct file *source, FILE *file )
1042
{
1043
    char *buffer;
Alexandre Julliard's avatar
Alexandre Julliard committed
1044

1045 1046
    input_line = 0;
    while ((buffer = get_line( file )))
Alexandre Julliard's avatar
Alexandre Julliard committed
1047
    {
1048
        parse_cpp_directive( source, buffer );
Alexandre Julliard's avatar
Alexandre Julliard committed
1049
    }
1050 1051 1052
}


1053 1054 1055
/*******************************************************************
 *         parse_rc_file
 */
1056
static void parse_rc_file( struct file *source, FILE *file )
1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085
{
    char *buffer, *include;

    input_line = 0;
    while ((buffer = get_line( file )))
    {
        char quote;
        char *p = buffer;
        while (*p && isspace(*p)) p++;

        if (p[0] == '/' && p[1] == '*')  /* check for magic makedep comment */
        {
            p += 2;
            while (*p && isspace(*p)) p++;
            if (strncmp( p, "@makedep:", 9 )) continue;
            p += 9;
            while (*p && isspace(*p)) p++;
            quote = '"';
            if (*p == quote)
            {
                include = ++p;
                while (*p && *p != quote) p++;
            }
            else
            {
                include = p;
                while (*p && !isspace(*p) && *p != '*') p++;
            }
            if (!*p)
1086
                fatal_error( "malformed makedep comment\n" );
1087
            *p = 0;
1088
            add_dependency( source, include, (quote == '>') ? INCL_SYSTEM : INCL_NORMAL );
1089
            continue;
1090
        }
1091

1092
        parse_cpp_directive( source, buffer );
1093 1094 1095 1096
    }
}


1097
/*******************************************************************
1098
 *         parse_in_file
1099
 */
1100
static void parse_in_file( struct file *source, FILE *file )
1101 1102 1103 1104
{
    char *p, *buffer;

    /* make sure it gets rebuilt when the version changes */
1105
    add_dependency( source, "config.h", INCL_SYSTEM );
1106

1107
    if (!strendswith( source->name, ".man.in" )) return;  /* not a man page */
1108

1109 1110 1111 1112 1113 1114 1115
    input_line = 0;
    while ((buffer = get_line( file )))
    {
        if (strncmp( buffer, ".TH", 3 )) continue;
        if (!(p = strtok( buffer, " \t" ))) continue;  /* .TH */
        if (!(p = strtok( NULL, " \t" ))) continue;  /* program name */
        if (!(p = strtok( NULL, " \t" ))) continue;  /* man section */
1116 1117 1118 1119 1120 1121 1122 1123 1124
        source->args = xstrdup( p );
        return;
    }
}


/*******************************************************************
 *         parse_sfd_file
 */
1125
static void parse_sfd_file( struct file *source, FILE *file )
1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154
{
    char *p, *eol, *buffer;

    input_line = 0;
    while ((buffer = get_line( file )))
    {
        if (strncmp( buffer, "UComments:", 10 )) continue;
        p = buffer + 10;
        while (*p == ' ') p++;
        if (p[0] == '"' && p[1] && buffer[strlen(buffer) - 1] == '"')
        {
            p++;
            buffer[strlen(buffer) - 1] = 0;
        }
        while ((eol = strstr( p, "+AAoA" )))
        {
            *eol = 0;
            while (*p && isspace(*p)) p++;
            if (*p++ == '#')
            {
                while (*p && isspace(*p)) p++;
                if (!strncmp( p, "pragma", 6 )) parse_pragma_directive( source, p + 6 );
            }
            p = eol + 5;
        }
        while (*p && isspace(*p)) p++;
        if (*p++ != '#') return;
        while (*p && isspace(*p)) p++;
        if (!strncmp( p, "pragma", 6 )) parse_pragma_directive( source, p + 6 );
1155 1156 1157 1158 1159
        return;
    }
}


1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179
static const struct
{
    const char *ext;
    void (*parse)( struct file *file, FILE *f );
} parse_functions[] =
{
    { ".c",   parse_c_file },
    { ".h",   parse_c_file },
    { ".inl", parse_c_file },
    { ".l",   parse_c_file },
    { ".m",   parse_c_file },
    { ".rh",  parse_c_file },
    { ".x",   parse_c_file },
    { ".y",   parse_c_file },
    { ".idl", parse_idl_file },
    { ".rc",  parse_rc_file },
    { ".in",  parse_in_file },
    { ".sfd", parse_sfd_file }
};

1180 1181 1182 1183 1184 1185 1186
/*******************************************************************
 *         load_file
 */
static struct file *load_file( const char *name )
{
    struct file *file;
    FILE *f;
1187
    unsigned int i, hash = hash_filename( name );
1188 1189 1190 1191 1192 1193 1194 1195 1196 1197

    LIST_FOR_EACH_ENTRY( file, &files[hash], struct file, entry )
        if (!strcmp( name, file->name )) return file;

    if (!(f = fopen( name, "r" ))) return NULL;

    file = add_file( name );
    input_file_name = file->name;
    input_line = 0;

1198 1199 1200 1201 1202 1203
    for (i = 0; i < sizeof(parse_functions) / sizeof(parse_functions[0]); i++)
    {
        if (!strendswith( name, parse_functions[i].ext )) continue;
        parse_functions[i].parse( file, f );
        break;
    }
1204 1205 1206 1207 1208 1209 1210 1211 1212

    fclose( f );
    input_file_name = NULL;

    return file;
}


/*******************************************************************
1213 1214 1215
 *         open_include_path_file
 *
 * Open a file from a directory on the include path.
1216
 */
1217 1218
static struct file *open_include_path_file( const struct makefile *make, const char *dir,
                                            const char *name, char **filename )
1219
{
1220 1221
    char *src_path = base_dir_path( make, concat_paths( dir, name ));
    struct file *ret = load_file( src_path );
1222

1223
    if (ret) *filename = src_dir_path( make, concat_paths( dir, name ));
1224 1225 1226 1227
    return ret;
}


1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243
/*******************************************************************
 *         open_file_same_dir
 *
 * Open a file in the same directory as the parent.
 */
static struct file *open_file_same_dir( const struct incl_file *parent, const char *name, char **filename )
{
    char *src_path = replace_filename( parent->file->name, name );
    struct file *ret = load_file( src_path );

    if (ret) *filename = replace_filename( parent->filename, name );
    free( src_path );
    return ret;
}


1244 1245 1246 1247 1248
/*******************************************************************
 *         open_local_file
 *
 * Open a file in the source directory of the makefile.
 */
1249
static struct file *open_local_file( const struct makefile *make, const char *path, char **filename )
1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273
{
    char *src_path = root_dir_path( base_dir_path( make, path ));
    struct file *ret = load_file( src_path );

    /* if not found, try parent dir */
    if (!ret && make->parent_dir)
    {
        free( src_path );
        path = strmake( "%s/%s", make->parent_dir, path );
        src_path = root_dir_path( base_dir_path( make, path ));
        ret = load_file( src_path );
    }

    if (ret) *filename = src_dir_path( make, path );
    free( src_path );
    return ret;
}


/*******************************************************************
 *         open_global_file
 *
 * Open a file in the top-level source directory.
 */
1274
static struct file *open_global_file( const struct makefile *make, const char *path, char **filename )
1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289
{
    char *src_path = root_dir_path( path );
    struct file *ret = load_file( src_path );

    if (ret) *filename = top_dir_path( make, path );
    free( src_path );
    return ret;
}


/*******************************************************************
 *         open_global_header
 *
 * Open a file in the global include source directory.
 */
1290
static struct file *open_global_header( const struct makefile *make, const char *path, char **filename )
1291 1292 1293 1294 1295 1296 1297 1298
{
    return open_global_file( make, strmake( "include/%s", path ), filename );
}


/*******************************************************************
 *         open_src_file
 */
1299
static struct file *open_src_file( const struct makefile *make, struct incl_file *pFile )
1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310
{
    struct file *file = open_local_file( make, pFile->name, &pFile->filename );

    if (!file) fatal_perror( "open %s", pFile->name );
    return file;
}


/*******************************************************************
 *         open_include_file
 */
1311
static struct file *open_include_file( const struct makefile *make, struct incl_file *pFile )
1312 1313
{
    struct file *file = NULL;
1314
    char *filename;
1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338
    unsigned int i, len;

    errno = ENOENT;

    /* check for generated bison header */

    if (strendswith( pFile->name, ".tab.h" ) &&
        (file = open_local_file( make, replace_extension( pFile->name, ".tab.h", ".y" ), &filename )))
    {
        pFile->sourcename = filename;
        pFile->filename = obj_dir_path( make, pFile->name );
        return file;
    }

    /* check for corresponding idl file in source dir */

    if (strendswith( pFile->name, ".h" ) &&
        (file = open_local_file( make, replace_extension( pFile->name, ".h", ".idl" ), &filename )))
    {
        pFile->sourcename = filename;
        pFile->filename = obj_dir_path( make, pFile->name );
        return file;
    }

1339 1340 1341 1342 1343 1344 1345 1346 1347 1348
    /* check for corresponding tlb file in source dir */

    if (strendswith( pFile->name, ".tlb" ) &&
        (file = open_local_file( make, replace_extension( pFile->name, ".tlb", ".idl" ), &filename )))
    {
        pFile->sourcename = filename;
        pFile->filename = obj_dir_path( make, pFile->name );
        return file;
    }

1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381
    /* now try in source dir */
    if ((file = open_local_file( make, pFile->name, &pFile->filename ))) return file;

    /* check for corresponding idl file in global includes */

    if (strendswith( pFile->name, ".h" ) &&
        (file = open_global_header( make, replace_extension( pFile->name, ".h", ".idl" ), &filename )))
    {
        pFile->sourcename = filename;
        pFile->filename = top_obj_dir_path( make, strmake( "include/%s", pFile->name ));
        return file;
    }

    /* check for corresponding .in file in global includes (for config.h.in) */

    if (strendswith( pFile->name, ".h" ) &&
        (file = open_global_header( make, replace_extension( pFile->name, ".h", ".h.in" ), &filename )))
    {
        pFile->sourcename = filename;
        pFile->filename = top_obj_dir_path( make, strmake( "include/%s", pFile->name ));
        return file;
    }

    /* check for corresponding .x file in global includes */

    if (strendswith( pFile->name, "tmpl.h" ) &&
        (file = open_global_header( make, replace_extension( pFile->name, ".h", ".x" ), &filename )))
    {
        pFile->sourcename = filename;
        pFile->filename = top_obj_dir_path( make, strmake( "include/%s", pFile->name ));
        return file;
    }

1382 1383 1384 1385 1386 1387 1388 1389 1390 1391
    /* check for corresponding .tlb file in global includes */

    if (strendswith( pFile->name, ".tlb" ) &&
        (file = open_global_header( make, replace_extension( pFile->name, ".tlb", ".idl" ), &filename )))
    {
        pFile->sourcename = filename;
        pFile->filename = top_obj_dir_path( make, strmake( "include/%s", pFile->name ));
        return file;
    }

1392 1393 1394 1395 1396 1397 1398 1399 1400 1401
    /* check in global includes source dir */

    if ((file = open_global_header( make, pFile->name, &pFile->filename ))) return file;

    /* check in global msvcrt includes */
    if (make->use_msvcrt &&
        (file = open_global_header( make, strmake( "msvcrt/%s", pFile->name ), &pFile->filename )))
        return file;

    /* now search in include paths */
1402
    for (i = 0; i < make->include_paths.count; i++)
1403
    {
1404
        const char *dir = make->include_paths.str[i];
1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419
        const char *prefix = make->top_src_dir ? make->top_src_dir : make->top_obj_dir;

        if (prefix)
        {
            len = strlen( prefix );
            if (!strncmp( dir, prefix, len ) && (!dir[len] || dir[len] == '/'))
            {
                while (dir[len] == '/') len++;
                file = open_global_file( make, concat_paths( dir + len, pFile->name ), &pFile->filename );
                if (file) return file;
            }
            if (make->top_src_dir) continue;  /* ignore paths that don't point to the top source dir */
        }
        if (*dir != '/')
        {
1420
            if ((file = open_include_path_file( make, dir, pFile->name, &pFile->filename )))
1421 1422 1423
                return file;
        }
    }
1424
    if (pFile->type == INCL_SYSTEM) return NULL;  /* ignore system files we cannot find */
1425 1426

    /* try in src file directory */
1427
    if ((file = open_file_same_dir( pFile->included_by, pFile->name, &pFile->filename ))) return file;
1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446

    fprintf( stderr, "%s:%d: error: ", pFile->included_by->file->name, pFile->included_line );
    perror( pFile->name );
    pFile = pFile->included_by;
    while (pFile && pFile->included_by)
    {
        const char *parent = pFile->included_by->sourcename;
        if (!parent) parent = pFile->included_by->file->name;
        fprintf( stderr, "%s:%d: note: %s was first included here\n",
                 parent, pFile->included_line, pFile->name );
        pFile = pFile->included_by;
    }
    exit(1);
}


/*******************************************************************
 *         add_all_includes
 */
1447
static void add_all_includes( struct makefile *make, struct incl_file *parent, struct file *file )
1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459
{
    unsigned int i;

    parent->files_count = 0;
    parent->files_size = file->deps_count;
    parent->files = xmalloc( parent->files_size * sizeof(*parent->files) );
    for (i = 0; i < file->deps_count; i++)
    {
        switch (file->deps[i].type)
        {
        case INCL_NORMAL:
        case INCL_IMPORT:
1460 1461 1462 1463
            add_include( make, parent, file->deps[i].name, file->deps[i].line, INCL_NORMAL );
            break;
        case INCL_IMPORTLIB:
            add_include( make, parent, file->deps[i].name, file->deps[i].line, INCL_IMPORTLIB );
1464 1465
            break;
        case INCL_SYSTEM:
1466
            add_include( make, parent, file->deps[i].name, file->deps[i].line, INCL_SYSTEM );
1467 1468 1469 1470 1471 1472 1473 1474 1475
            break;
        case INCL_CPP_QUOTE:
        case INCL_CPP_QUOTE_SYSTEM:
            break;
        }
    }
}


1476 1477 1478
/*******************************************************************
 *         parse_file
 */
1479
static void parse_file( struct makefile *make, struct incl_file *source, int src )
1480
{
1481
    struct file *file = src ? open_src_file( make, source ) : open_include_file( make, source );
1482

1483
    if (!file) return;
1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495

    source->file = file;
    source->files_count = 0;
    source->files_size = file->deps_count;
    source->files = xmalloc( source->files_size * sizeof(*source->files) );

    if (source->sourcename)
    {
        if (strendswith( source->sourcename, ".idl" ))
        {
            unsigned int i;

1496 1497
            if (strendswith( source->name, ".tlb" )) return;  /* typelibs don't include anything */

1498
            /* generated .h file always includes these */
1499 1500
            add_include( make, source, "rpc.h", 0, INCL_NORMAL );
            add_include( make, source, "rpcndr.h", 0, INCL_NORMAL );
1501 1502 1503 1504 1505 1506
            for (i = 0; i < file->deps_count; i++)
            {
                switch (file->deps[i].type)
                {
                case INCL_IMPORT:
                    if (strendswith( file->deps[i].name, ".idl" ))
1507
                        add_include( make, source, replace_extension( file->deps[i].name, ".idl", ".h" ),
1508
                                     file->deps[i].line, INCL_NORMAL );
1509
                    else
1510
                        add_include( make, source, file->deps[i].name, file->deps[i].line, INCL_NORMAL );
1511 1512
                    break;
                case INCL_CPP_QUOTE:
1513
                    add_include( make, source, file->deps[i].name, file->deps[i].line, INCL_NORMAL );
1514 1515
                    break;
                case INCL_CPP_QUOTE_SYSTEM:
1516
                    add_include( make, source, file->deps[i].name, file->deps[i].line, INCL_SYSTEM );
1517 1518 1519
                    break;
                case INCL_NORMAL:
                case INCL_SYSTEM:
1520
                case INCL_IMPORTLIB:
1521 1522 1523 1524 1525 1526 1527 1528 1529
                    break;
                }
            }
            return;
        }
        if (strendswith( source->sourcename, ".y" ))
            return;  /* generated .tab.h doesn't include anything */
    }

1530
    add_all_includes( make, source, file );
Alexandre Julliard's avatar
Alexandre Julliard committed
1531 1532 1533
}


1534 1535 1536 1537 1538
/*******************************************************************
 *         add_src_file
 *
 * Add a source file to the list.
 */
1539
static struct incl_file *add_src_file( struct makefile *make, const char *name )
1540
{
1541
    struct incl_file *file;
1542

1543
    if ((file = find_src_file( make, name ))) return file;  /* we already have it */
1544 1545 1546
    file = xmalloc( sizeof(*file) );
    memset( file, 0, sizeof(*file) );
    file->name = xstrdup(name);
1547
    list_add_tail( &make->sources, &file->entry );
1548
    parse_file( make, file, 1 );
1549
    return file;
1550
}
1551

1552

1553 1554 1555
/*******************************************************************
 *         open_input_makefile
 */
1556
static FILE *open_input_makefile( const struct makefile *make )
1557 1558 1559 1560
{
    FILE *ret;

    if (make->base_dir)
1561 1562 1563
        input_file_name = root_dir_path( base_dir_path( make, strmake( "%s.in", output_makefile_name )));
    else
        input_file_name = output_makefile_name;  /* always use output name for main Makefile */
1564 1565

    input_line = 0;
1566
    if (!(ret = fopen( input_file_name, "r" ))) fatal_perror( "open" );
1567 1568 1569 1570
    return ret;
}


1571 1572 1573
/*******************************************************************
 *         get_make_variable
 */
1574
static const char *get_make_variable( const struct makefile *make, const char *name )
1575
{
1576
    const char *ret;
1577

1578
    if ((ret = strarray_get_value( &cmdline_vars, name ))) return ret;
1579
    if ((ret = strarray_get_value( &make->vars, name ))) return ret;
1580
    if (top_makefile && (ret = strarray_get_value( &top_makefile->vars, name ))) return ret;
1581 1582 1583 1584 1585 1586 1587
    return NULL;
}


/*******************************************************************
 *         get_expanded_make_variable
 */
1588
static char *get_expanded_make_variable( const struct makefile *make, const char *name )
1589
{
1590 1591
    const char *var;
    char *p, *end, *expand, *tmp;
1592

1593 1594
    var = get_make_variable( make, name );
    if (!var) return NULL;
1595

1596
    p = expand = xstrdup( var );
1597 1598 1599 1600 1601 1602 1603
    while ((p = strchr( p, '$' )))
    {
        if (p[1] == '(')
        {
            if (!(end = strchr( p + 2, ')' ))) fatal_error( "syntax error in '%s'\n", expand );
            *end++ = 0;
            if (strchr( p + 2, ':' )) fatal_error( "pattern replacement not supported for '%s'\n", p + 2 );
1604
            var = get_make_variable( make, p + 2 );
1605
            tmp = replace_substr( expand, p, end - p, var ? var : "" );
1606 1607 1608 1609
            /* switch to the new string */
            p = tmp + (p - expand);
            free( expand );
            expand = tmp;
1610
        }
1611 1612 1613 1614 1615
        else if (p[1] == '{')  /* don't expand ${} variables */
        {
            if (!(end = strchr( p + 2, '}' ))) fatal_error( "syntax error in '%s'\n", expand );
            p = end + 1;
        }
1616 1617
        else if (p[1] == '$')
        {
1618
            p += 2;
1619 1620 1621
        }
        else fatal_error( "syntax error in '%s'\n", expand );
    }
1622 1623 1624 1625 1626 1627 1628

    /* consider empty variables undefined */
    p = expand;
    while (*p && isspace(*p)) p++;
    if (*p) return expand;
    free( expand );
    return NULL;
1629 1630 1631 1632 1633 1634
}


/*******************************************************************
 *         get_expanded_make_var_array
 */
1635
static struct strarray get_expanded_make_var_array( const struct makefile *make, const char *name )
1636
{
1637
    struct strarray ret = empty_strarray;
1638 1639
    char *value, *token;

1640
    if ((value = get_expanded_make_variable( make, name )))
1641 1642 1643 1644 1645 1646
        for (token = strtok( value, " \t" ); token; token = strtok( NULL, " \t" ))
            strarray_add( &ret, token );
    return ret;
}


1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659
/*******************************************************************
 *         file_local_var
 */
static char *file_local_var( const char *file, const char *name )
{
    char *p, *var;

    var = strmake( "%s_%s", file, name );
    for (p = var; *p; p++) if (!isalnum( *p )) *p = '_';
    return var;
}


1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678
/*******************************************************************
 *         set_make_variable
 */
static int set_make_variable( struct strarray *array, const char *assignment )
{
    char *p, *name;

    p = name = xstrdup( assignment );
    while (isalnum(*p) || *p == '_') p++;
    if (name == p) return 0;  /* not a variable */
    if (isspace(*p))
    {
        *p++ = 0;
        while (isspace(*p)) p++;
    }
    if (*p != '=') return 0;  /* not an assignment */
    *p++ = 0;
    while (isspace(*p)) p++;

1679
    strarray_set_value( array, name, p );
1680 1681 1682 1683
    return 1;
}


1684 1685 1686
/*******************************************************************
 *         parse_makefile
 */
1687
static struct makefile *parse_makefile( const char *path, const char *separator )
1688 1689 1690
{
    char *buffer;
    FILE *file;
1691
    struct makefile *make = xmalloc( sizeof(*make) );
1692

1693 1694 1695 1696 1697 1698 1699 1700
    memset( make, 0, sizeof(*make) );
    if (path)
    {
        make->top_obj_dir = get_relative_path( path, "" );
        make->base_dir = path;
        if (!strcmp( make->base_dir, "." )) make->base_dir = NULL;
    }

1701
    file = open_input_makefile( make );
1702 1703
    while ((buffer = get_line( file )))
    {
1704
        if (separator && !strncmp( buffer, separator, strlen(separator) )) break;
1705 1706 1707
        if (*buffer == '\t') continue;  /* command */
        while (isspace( *buffer )) buffer++;
        if (*buffer == '#') continue;  /* comment */
1708
        set_make_variable( &make->vars, buffer );
1709 1710 1711
    }
    fclose( file );
    input_file_name = NULL;
1712
    return make;
1713 1714 1715
}


1716 1717 1718
/*******************************************************************
 *         add_generated_sources
 */
1719
static void add_generated_sources( struct makefile *make )
1720 1721 1722
{
    struct incl_file *source, *next, *file;

1723
    LIST_FOR_EACH_ENTRY_SAFE( source, next, &make->sources, struct incl_file, entry )
1724
    {
1725
        if (source->file->flags & FLAG_IDL_CLIENT)
1726
        {
1727
            file = add_generated_source( make, replace_extension( source->name, ".idl", "_c.c" ), NULL );
1728
            add_dependency( file->file, replace_extension( source->name, ".idl", ".h" ), INCL_NORMAL );
1729
            add_all_includes( make, file, file->file );
1730
        }
1731
        if (source->file->flags & FLAG_IDL_SERVER)
1732
        {
1733
            file = add_generated_source( make, replace_extension( source->name, ".idl", "_s.c" ), NULL );
1734 1735
            add_dependency( file->file, "wine/exception.h", INCL_NORMAL );
            add_dependency( file->file, replace_extension( source->name, ".idl", ".h" ), INCL_NORMAL );
1736
            add_all_includes( make, file, file->file );
1737
        }
1738
        if (source->file->flags & FLAG_IDL_IDENT)
1739
        {
1740
            file = add_generated_source( make, replace_extension( source->name, ".idl", "_i.c" ), NULL );
1741 1742 1743
            add_dependency( file->file, "rpc.h", INCL_NORMAL );
            add_dependency( file->file, "rpcndr.h", INCL_NORMAL );
            add_dependency( file->file, "guiddef.h", INCL_NORMAL );
1744
            add_all_includes( make, file, file->file );
1745
        }
1746
        if (source->file->flags & FLAG_IDL_PROXY)
1747
        {
1748
            file = add_generated_source( make, "dlldata.o", "dlldata.c" );
1749 1750
            add_dependency( file->file, "objbase.h", INCL_NORMAL );
            add_dependency( file->file, "rpcproxy.h", INCL_NORMAL );
1751
            add_all_includes( make, file, file->file );
1752
            file = add_generated_source( make, replace_extension( source->name, ".idl", "_p.c" ), NULL );
1753 1754 1755 1756
            add_dependency( file->file, "objbase.h", INCL_NORMAL );
            add_dependency( file->file, "rpcproxy.h", INCL_NORMAL );
            add_dependency( file->file, "wine/exception.h", INCL_NORMAL );
            add_dependency( file->file, replace_extension( source->name, ".idl", ".h" ), INCL_NORMAL );
1757
            add_all_includes( make, file, file->file );
1758
        }
1759 1760 1761 1762
        if (source->file->flags & FLAG_IDL_TYPELIB)
        {
            add_generated_source( make, replace_extension( source->name, ".idl", ".tlb" ), NULL );
        }
1763
        if (source->file->flags & FLAG_IDL_REGTYPELIB)
1764
        {
1765
            add_generated_source( make, replace_extension( source->name, ".idl", "_t.res" ), NULL );
1766
        }
1767
        if (source->file->flags & FLAG_IDL_REGISTER)
1768
        {
1769
            add_generated_source( make, replace_extension( source->name, ".idl", "_r.res" ), NULL );
1770
        }
1771 1772 1773 1774
        if (source->file->flags & FLAG_IDL_HEADER)
        {
            add_generated_source( make, replace_extension( source->name, ".idl", ".h" ), NULL );
        }
1775 1776 1777 1778
        if (!source->file->flags && strendswith( source->name, ".idl" ))
        {
            add_generated_source( make, replace_extension( source->name, ".idl", ".h" ), NULL );
        }
1779 1780 1781 1782
        if (strendswith( source->name, ".x" ))
        {
            add_generated_source( make, replace_extension( source->name, ".x", ".h" ), NULL );
        }
1783 1784
        if (strendswith( source->name, ".y" ))
        {
1785
            file = add_generated_source( make, replace_extension( source->name, ".y", ".tab.c" ), NULL );
1786 1787 1788 1789 1790 1791
            /* steal the includes list from the source file */
            file->files_count = source->files_count;
            file->files_size = source->files_size;
            file->files = source->files;
            source->files_count = source->files_size = 0;
            source->files = NULL;
1792 1793 1794
        }
        if (strendswith( source->name, ".l" ))
        {
1795
            file = add_generated_source( make, replace_extension( source->name, ".l", ".yy.c" ), NULL );
1796 1797 1798 1799 1800 1801
            /* steal the includes list from the source file */
            file->files_count = source->files_count;
            file->files_size = source->files_size;
            file->files = source->files;
            source->files_count = source->files_size = 0;
            source->files = NULL;
1802 1803
        }
    }
1804
    if (make->testdll)
1805
    {
1806
        file = add_generated_source( make, "testlist.o", "testlist.c" );
1807
        add_dependency( file->file, "wine/test.h", INCL_NORMAL );
1808
        add_all_includes( make, file, file->file );
1809 1810 1811 1812
    }
}


1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832
/*******************************************************************
 *         create_dir
 */
static void create_dir( const char *dir )
{
    char *p, *path;

    p = path = xstrdup( dir );
    while ((p = strchr( p, '/' )))
    {
        *p = 0;
        if (mkdir( path, 0755 ) == -1 && errno != EEXIST) fatal_perror( "mkdir %s", path );
        *p++ = '/';
        while (*p == '/') p++;
    }
    if (mkdir( path, 0755 ) == -1 && errno != EEXIST) fatal_perror( "mkdir %s", path );
    free( path );
}


1833 1834 1835
/*******************************************************************
 *         output_filenames_obj_dir
 */
1836
static void output_filenames_obj_dir( const struct makefile *make, struct strarray array )
1837 1838 1839
{
    unsigned int i;

1840
    for (i = 0; i < array.count; i++) output_filename( obj_dir_path( make, array.str[i] ));
1841 1842 1843
}


Alexandre Julliard's avatar
Alexandre Julliard committed
1844
/*******************************************************************
1845
 *         get_dependencies
Alexandre Julliard's avatar
Alexandre Julliard committed
1846
 */
1847
static void get_dependencies( struct strarray *deps, struct incl_file *file, struct incl_file *source )
Alexandre Julliard's avatar
Alexandre Julliard committed
1848
{
1849 1850 1851
    unsigned int i;

    if (!file->filename) return;
Alexandre Julliard's avatar
Alexandre Julliard committed
1852

1853 1854 1855 1856 1857 1858 1859 1860 1861 1862
    if (file != source)
    {
        if (file->owner == source) return;  /* already processed */
        if (file->type == INCL_IMPORTLIB &&
            !(source->file->flags & (FLAG_IDL_TYPELIB | FLAG_IDL_REGTYPELIB)))
            return;  /* library is imported only when building a typelib */
        file->owner = source;
        strarray_add( deps, file->filename );
    }
    for (i = 0; i < file->files_count; i++) get_dependencies( deps, file->files[i], source );
Alexandre Julliard's avatar
Alexandre Julliard committed
1863 1864 1865
}


1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887
/*******************************************************************
 *         get_local_dependencies
 *
 * Get the local dependencies of a given target.
 */
static struct strarray get_local_dependencies( const struct makefile *make, const char *name,
                                               struct strarray targets )
{
    unsigned int i;
    struct strarray deps = get_expanded_make_var_array( make, file_local_var( name, "DEPS" ));

    for (i = 0; i < deps.count; i++)
    {
        if (strarray_exists( &targets, deps.str[i] ))
            deps.str[i] = obj_dir_path( make, deps.str[i] );
        else
            deps.str[i] = src_dir_path( make, deps.str[i] );
    }
    return deps;
}


1888 1889 1890
/*******************************************************************
 *         add_install_rule
 */
1891
static void add_install_rule( const struct makefile *make, struct strarray *install_rules,
1892
                              const char *target, const char *file, const char *dest )
1893 1894 1895
{
    if (strarray_exists( &make->install_lib, target ))
    {
1896 1897
        strarray_add( &install_rules[INSTALL_LIB], file );
        strarray_add( &install_rules[INSTALL_LIB], dest );
1898 1899 1900
    }
    else if (strarray_exists( &make->install_dev, target ))
    {
1901 1902
        strarray_add( &install_rules[INSTALL_DEV], file );
        strarray_add( &install_rules[INSTALL_DEV], dest );
1903 1904 1905 1906
    }
}


1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919
/*******************************************************************
 *         get_include_install_path
 *
 * Determine the installation path for a given include file.
 */
static const char *get_include_install_path( const char *name )
{
    if (!strncmp( name, "wine/", 5 )) return name + 5;
    if (!strncmp( name, "msvcrt/", 7 )) return name;
    return strmake( "windows/%s", name );
}


1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955
/*******************************************************************
 *         get_shared_library_name
 *
 * Determine possible names for a shared library with a version number.
 */
static struct strarray get_shared_lib_names( const char *libname )
{
    struct strarray ret = empty_strarray;
    const char *ext, *p;
    char *name, *first, *second;
    size_t len = 0;

    strarray_add( &ret, libname );

    for (p = libname; (p = strchr( p, '.' )); p++)
        if ((len = strspn( p + 1, "0123456789." ))) break;

    if (!len) return ret;
    ext = p + 1 + len;
    if (*ext && ext[-1] == '.') ext--;

    /* keep only the first group of digits */
    name = xstrdup( libname );
    first = name + (p - libname);
    if ((second = strchr( first + 1, '.' )))
    {
        strcpy( second, ext );
        strarray_add( &ret, xstrdup( name ));
    }
    /* now remove all digits */
    strcpy( first, ext );
    strarray_add( &ret, name );
    return ret;
}


1956 1957 1958 1959 1960 1961
/*******************************************************************
 *         output_install_rules
 *
 * Rules are stored as a (file,dest) pair of values.
 * The first char of dest indicates the type of install.
 */
1962 1963
static struct strarray output_install_rules( const struct makefile *make, struct strarray files,
                                             const char *target, struct strarray *phony_targets )
1964 1965 1966
{
    unsigned int i;
    char *install_sh;
1967
    struct strarray uninstall = empty_strarray;
1968 1969
    struct strarray targets = empty_strarray;

1970
    if (!files.count) return uninstall;
1971 1972

    for (i = 0; i < files.count; i += 2)
1973
        if (strchr( "dps", files.str[i + 1][0] ))  /* only for files copied from object dir */
1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007
            strarray_add_uniq( &targets, files.str[i] );

    output( "install %s::", target );
    output_filenames_obj_dir( make, targets );
    output( "\n" );

    install_sh = top_dir_path( make, "tools/install-sh" );
    for (i = 0; i < files.count; i += 2)
    {
        const char *file = files.str[i];
        const char *dest = files.str[i + 1];

        switch (*dest)
        {
        case 'd':  /* data file */
            output( "\t%s -m 644 $(INSTALL_DATA_FLAGS) %s $(DESTDIR)%s\n",
                    install_sh, obj_dir_path( make, file ), dest + 1 );
            break;
        case 'D':  /* data file in source dir */
            output( "\t%s -m 644 $(INSTALL_DATA_FLAGS) %s $(DESTDIR)%s\n",
                    install_sh, src_dir_path( make, file ), dest + 1 );
            break;
        case 'p':  /* program file */
            output( "\tSTRIPPROG=\"$(STRIP)\" %s $(INSTALL_PROGRAM_FLAGS) %s $(DESTDIR)%s\n",
                    install_sh, obj_dir_path( make, file ), dest + 1 );
            break;
        case 's':  /* script */
            output( "\t%s $(INSTALL_SCRIPT_FLAGS) %s $(DESTDIR)%s\n",
                    install_sh, obj_dir_path( make, file ), dest + 1 );
            break;
        case 'S':  /* script in source dir */
            output( "\t%s $(INSTALL_SCRIPT_FLAGS) %s $(DESTDIR)%s\n",
                    install_sh, src_dir_path( make, file ), dest + 1 );
            break;
2008
        case 'y':  /* symlink */
2009
            output( "\trm -f $(DESTDIR)%s && $(LN_S) %s $(DESTDIR)%s\n", dest + 1, file, dest + 1 );
2010
            break;
2011 2012 2013 2014 2015
        default:
            assert(0);
        }
    }

2016 2017
    for (i = 0; i < files.count; i += 2)
        strarray_add( &uninstall, strmake( "$(DESTDIR)%s", files.str[i + 1] + 1 ));
2018

2019 2020 2021
    strarray_add_uniq( phony_targets, "install" );
    strarray_add_uniq( phony_targets, target );
    return uninstall;
2022 2023 2024
}


Alexandre Julliard's avatar
Alexandre Julliard committed
2025
/*******************************************************************
2026
 *         output_sources
Alexandre Julliard's avatar
Alexandre Julliard committed
2027
 */
2028
static struct strarray output_sources( const struct makefile *make )
Alexandre Julliard's avatar
Alexandre Julliard committed
2029
{
2030
    struct incl_file *source;
2031
    unsigned int i, j;
2032 2033 2034
    struct strarray object_files = empty_strarray;
    struct strarray crossobj_files = empty_strarray;
    struct strarray res_files = empty_strarray;
2035
    struct strarray clean_files = empty_strarray;
2036
    struct strarray uninstall_files = empty_strarray;
2037
    struct strarray po_files = empty_strarray;
2038
    struct strarray mo_files = empty_strarray;
2039
    struct strarray mc_files = empty_strarray;
2040
    struct strarray ok_files = empty_strarray;
2041
    struct strarray in_files = empty_strarray;
2042
    struct strarray dlldata_files = empty_strarray;
2043
    struct strarray c2man_files = empty_strarray;
2044
    struct strarray implib_objs = empty_strarray;
2045
    struct strarray includes = empty_strarray;
2046
    struct strarray subdirs = empty_strarray;
2047
    struct strarray phony_targets = empty_strarray;
2048
    struct strarray all_targets = empty_strarray;
2049
    struct strarray install_rules[NB_INSTALL_RULES];
2050 2051
    char *ldrpath_local   = get_expanded_make_variable( make, "LDRPATH_LOCAL" );
    char *ldrpath_install = get_expanded_make_variable( make, "LDRPATH_INSTALL" );
2052

2053 2054
    for (i = 0; i < NB_INSTALL_RULES; i++) install_rules[i] = empty_strarray;

2055
    for (i = 0; i < linguas.count; i++)
2056
        strarray_add( &mo_files, strmake( "%s/%s.mo", top_obj_dir_path( make, "po" ), linguas.str[i] ));
2057

2058
    strarray_add( &phony_targets, "all" );
2059
    strarray_add( &includes, strmake( "-I%s", obj_dir_path( make, "" )));
2060
    if (make->src_dir) strarray_add( &includes, strmake( "-I%s", make->src_dir ));
2061
    if (make->parent_dir) strarray_add( &includes, strmake( "-I%s", src_dir_path( make, make->parent_dir )));
2062
    strarray_add( &includes, strmake( "-I%s", top_obj_dir_path( make, "include" )));
2063 2064
    if (make->top_src_dir) strarray_add( &includes, strmake( "-I%s", top_dir_path( make, "include" )));
    if (make->use_msvcrt) strarray_add( &includes, strmake( "-I%s", top_dir_path( make, "include/msvcrt" )));
2065 2066
    for (i = 0; i < make->include_paths.count; i++)
        strarray_add( &includes, strmake( "-I%s", obj_dir_path( make, make->include_paths.str[i] )));
2067

2068
    LIST_FOR_EACH_ENTRY( source, &make->sources, struct incl_file, entry )
Alexandre Julliard's avatar
Alexandre Julliard committed
2069
    {
2070
        struct strarray dependencies = empty_strarray;
2071
        struct strarray extradefs;
2072 2073 2074 2075
        char *obj = xstrdup( source->name );
        char *ext = get_extension( obj );

        if (!ext) fatal_error( "unsupported file type %s\n", source->name );
2076
        *ext++ = 0;
2077

2078
        if (make->src_dir && strchr( obj, '/' ))
2079
        {
2080
            char *subdir = base_dir_path( make, obj );
2081
            *strrchr( subdir, '/' ) = 0;
2082
            strarray_add_uniq( &subdirs, subdir );
2083 2084
        }

2085
        extradefs = get_expanded_make_var_array( make, file_local_var( obj, "EXTRADEFS" ));
2086
        get_dependencies( &dependencies, source, source );
2087

2088
        if (!strcmp( ext, "y" ))  /* yacc file */
Alexandre Julliard's avatar
Alexandre Julliard committed
2089
        {
2090 2091
            /* add source file dependency for parallel makes */
            char *header = strmake( "%s.tab.h", obj );
2092

2093
            if (find_include_file( make, header ))
2094
            {
2095
                output( "%s: %s\n", obj_dir_path( make, header ), source->filename );
2096
                output( "\t$(BISON) -p %s_ -o %s.tab.c -d %s\n",
2097 2098 2099
                        obj, obj_dir_path( make, obj ), source->filename );
                output( "%s.tab.c: %s %s\n", obj_dir_path( make, obj ),
                        source->filename, obj_dir_path( make, header ));
2100
                strarray_add( &clean_files, header );
2101
            }
2102
            else output( "%s.tab.c: %s\n", obj, source->filename );
2103

2104
            output( "\t$(BISON) -p %s_ -o $@ %s\n", obj, source->filename );
Alexandre Julliard's avatar
Alexandre Julliard committed
2105
        }
2106 2107
        else if (!strcmp( ext, "x" ))  /* template file */
        {
2108 2109 2110 2111
            output( "%s.h: %s%s %s\n", obj_dir_path( make, obj ),
                    tools_dir_path( make, "make_xftmpl" ), tools_ext, source->filename );
            output( "\t%s%s -H -o $@ %s\n",
                    tools_dir_path( make, "make_xftmpl" ), tools_ext, source->filename );
2112 2113
            if (source->file->flags & FLAG_INSTALL)
            {
2114 2115
                strarray_add( &install_rules[INSTALL_DEV], source->name );
                strarray_add( &install_rules[INSTALL_DEV],
2116
                              strmake( "D$(includedir)/%s", get_include_install_path( source->name ) ));
2117 2118
                strarray_add( &install_rules[INSTALL_DEV], strmake( "%s.h", obj ));
                strarray_add( &install_rules[INSTALL_DEV],
2119 2120
                              strmake( "d$(includedir)/%s.h", get_include_install_path( obj ) ));
            }
2121
        }
2122
        else if (!strcmp( ext, "l" ))  /* lex file */
Alexandre Julliard's avatar
Alexandre Julliard committed
2123
        {
2124
            output( "%s.yy.c: %s\n", obj_dir_path( make, obj ), source->filename );
2125
            output( "\t$(FLEX) -o$@ %s\n", source->filename );
Alexandre Julliard's avatar
Alexandre Julliard committed
2126
        }
2127
        else if (!strcmp( ext, "rc" ))  /* resource file */
Alexandre Julliard's avatar
Alexandre Julliard committed
2128
        {
2129
            strarray_add( &res_files, strmake( "%s.res", obj ));
2130 2131
            output( "%s.res: %s %s\n", obj_dir_path( make, obj ),
                    tools_path( make, "wrc" ), source->filename );
2132
            output( "\t%s -o $@", tools_path( make, "wrc" ) );
2133
            if (make->is_win16) output_filename( "-m16" );
2134
            else output_filenames( target_flags );
2135 2136
            output_filename( "--nostdinc" );
            output_filenames( includes );
2137
            output_filenames( make->define_args );
2138
            output_filenames( extradefs );
2139
            if (mo_files.count && (source->file->flags & FLAG_RC_PO))
2140
            {
2141
                strarray_add( &po_files, source->filename );
2142
                output_filename( strmake( "--po-dir=%s", top_obj_dir_path( make, "po" )));
2143
                output_filename( source->filename );
2144
                output( "\n" );
2145
                output( "%s.res:", obj_dir_path( make, obj ));
2146 2147
                output_filenames( mo_files );
                output( "\n" );
2148
                output( "%s ", obj_dir_path( make, "rsrc.pot" ));
2149
            }
2150 2151 2152 2153 2154
            else
            {
                output_filename( source->filename );
                output( "\n" );
            }
2155
            output( "%s.res:", obj_dir_path( make, obj ));
2156 2157
            output_filenames( dependencies );
            output( "\n" );
2158
        }
2159
        else if (!strcmp( ext, "mc" ))  /* message file */
2160
        {
2161
            strarray_add( &res_files, strmake( "%s.res", obj ));
2162 2163 2164
            output( "%s.res: %s %s\n", obj_dir_path( make, obj ),
                    tools_path( make, "wmc" ), source->filename );
            output( "\t%s -U -O res -o $@ %s", tools_path( make, "wmc" ), source->filename );
2165 2166 2167
            if (mo_files.count)
            {
                strarray_add( &mc_files, source->filename );
2168
                output_filename( strmake( "--po-dir=%s", top_obj_dir_path( make, "po" )));
2169
                output( "\n" );
2170
                output( "%s.res:", obj_dir_path( make, obj ));
2171 2172
                output_filenames( mo_files );
                output( "\n" );
2173
                output( "%s ", obj_dir_path( make, "msg.pot" ));
2174 2175
            }
            else output( "\n" );
2176
            output( "%s.res:", obj_dir_path( make, obj ));
2177 2178
            output_filenames( dependencies );
            output( "\n" );
Alexandre Julliard's avatar
Alexandre Julliard committed
2179
        }
2180 2181
        else if (!strcmp( ext, "idl" ))  /* IDL file */
        {
2182 2183
            struct strarray targets = empty_strarray;
            char *dest;
2184

2185 2186
            if (!source->file->flags) source->file->flags |= FLAG_IDL_HEADER | FLAG_INSTALL;
            if (find_include_file( make, strmake( "%s.h", obj ))) source->file->flags |= FLAG_IDL_HEADER;
2187

2188
            for (i = 0; i < sizeof(idl_outputs) / sizeof(idl_outputs[0]); i++)
2189
            {
2190
                if (!(source->file->flags & idl_outputs[i].flag)) continue;
2191
                dest = strmake( "%s%s", obj, idl_outputs[i].ext );
2192
                if (!find_src_file( make, dest )) strarray_add( &clean_files, dest );
2193
                strarray_add( &targets, dest );
2194
            }
2195
            if (source->file->flags & FLAG_IDL_PROXY) strarray_add( &dlldata_files, source->name );
2196 2197
            if (source->file->flags & FLAG_INSTALL)
            {
2198 2199
                strarray_add( &install_rules[INSTALL_DEV], xstrdup( source->name ));
                strarray_add( &install_rules[INSTALL_DEV],
2200 2201 2202
                              strmake( "D$(includedir)/%s.idl", get_include_install_path( obj ) ));
                if (source->file->flags & FLAG_IDL_HEADER)
                {
2203 2204
                    strarray_add( &install_rules[INSTALL_DEV], strmake( "%s.h", obj ));
                    strarray_add( &install_rules[INSTALL_DEV],
2205 2206 2207 2208
                                  strmake( "d$(includedir)/%s.h", get_include_install_path( obj ) ));
                }
            }
            if (!targets.count) continue;
2209 2210
            output_filenames_obj_dir( make, targets );
            output( ": %s\n", tools_path( make, "widl" ));
2211
            output( "\t%s -o $@", tools_path( make, "widl" ) );
2212
            output_filenames( target_flags );
2213
            output_filenames( includes );
2214
            output_filenames( make->define_args );
2215
            output_filenames( extradefs );
2216
            output_filenames( get_expanded_make_var_array( make, "EXTRAIDLFLAGS" ));
2217
            output_filename( source->filename );
2218
            output( "\n" );
2219
            output_filenames_obj_dir( make, targets );
2220
            output( ": %s", source->filename );
2221 2222
            output_filenames( dependencies );
            output( "\n" );
2223
        }
2224
        else if (!strcmp( ext, "in" ))  /* .in file or man page */
2225
        {
2226
            if (strendswith( obj, ".man" ) && source->file->args)
2227
            {
2228
                struct strarray symlinks;
2229
                char *dir, *dest = replace_extension( obj, ".man", "" );
2230
                char *lang = strchr( dest, '.' );
2231
                char *section = source->file->args;
2232 2233 2234
                if (lang)
                {
                    *lang++ = 0;
2235
                    dir = strmake( "$(mandir)/%s/man%s", lang, section );
2236
                }
2237
                else dir = strmake( "$(mandir)/man%s", section );
2238 2239
                add_install_rule( make, install_rules, dest, xstrdup(obj),
                                  strmake( "d%s/%s.%s", dir, dest, section ));
2240
                symlinks = get_expanded_make_var_array( make, file_local_var( dest, "SYMLINKS" ));
2241
                for (i = 0; i < symlinks.count; i++)
2242 2243
                    add_install_rule( make, install_rules, symlinks.str[i],
                                      strmake( "%s.%s", dest, section ),
2244
                                      strmake( "y%s/%s.%s", dir, symlinks.str[i], section ));
2245
                free( dest );
2246
                free( dir );
2247
            }
2248
            strarray_add( &in_files, xstrdup(obj) );
2249
            strarray_add( &all_targets, xstrdup(obj) );
2250
            output( "%s: %s\n", obj_dir_path( make, obj ), source->filename );
2251
            output( "\t$(SED_CMD) %s >$@ || (rm -f $@ && false)\n", source->filename );
2252
            output( "%s:", obj_dir_path( make, obj ));
2253 2254
            output_filenames( dependencies );
            output( "\n" );
2255 2256
            add_install_rule( make, install_rules, obj, xstrdup( obj ),
                              strmake( "d$(datadir)/wine/%s", obj ));
2257
        }
2258 2259
        else if (!strcmp( ext, "sfd" ))  /* font file */
        {
2260
            char *ttf_file = src_dir_path( make, strmake( "%s.ttf", obj ));
2261
            if (fontforge && !make->src_dir)
2262
            {
2263
                output( "%s: %s\n", ttf_file, source->filename );
2264
                output( "\t%s -script %s %s $@\n",
2265
                        fontforge, top_dir_path( make, "fonts/genttf.ff" ), source->filename );
2266
                if (!(source->file->flags & FLAG_SFD_FONTS)) output( "all: %s\n", ttf_file );
2267
            }
2268
            if (source->file->flags & FLAG_INSTALL)
2269
            {
2270 2271
                strarray_add( &install_rules[INSTALL_LIB], strmake( "%s.ttf", obj ));
                strarray_add( &install_rules[INSTALL_LIB], strmake( "D$(fontdir)/%s.ttf", obj ));
2272
            }
2273
            if (source->file->flags & FLAG_SFD_FONTS)
2274
            {
2275
                struct strarray *array = source->file->args;
2276 2277 2278 2279 2280 2281

                for (i = 0; i < array->count; i++)
                {
                    char *font = strtok( xstrdup(array->str[i]), " \t" );
                    char *args = strtok( NULL, "" );

2282
                    strarray_add( &all_targets, xstrdup( font ));
2283 2284 2285
                    output( "%s: %s %s\n", obj_dir_path( make, font ),
                            tools_path( make, "sfnt2fon" ), ttf_file );
                    output( "\t%s -o $@ %s %s\n", tools_path( make, "sfnt2fon" ), ttf_file, args );
2286 2287
                    strarray_add( &install_rules[INSTALL_LIB], xstrdup(font) );
                    strarray_add( &install_rules[INSTALL_LIB], strmake( "d$(fontdir)/%s", font ));
2288 2289
                }
            }
2290
        }
2291 2292
        else if (!strcmp( ext, "svg" ))  /* svg file */
        {
2293
            if (convert && rsvg && icotool && !make->src_dir)
2294
            {
2295 2296 2297 2298
                output( "%s.ico %s.bmp: %s\n",
                        src_dir_path( make, obj ), src_dir_path( make, obj ), source->filename );
                output( "\tCONVERT=\"%s\" ICOTOOL=\"%s\" RSVG=\"%s\" %s %s $@\n", convert, icotool, rsvg,
                        top_dir_path( make, "tools/buildimage" ), source->filename );
2299 2300
            }
        }
2301
        else if (!strcmp( ext, "res" ))
2302
        {
2303
            strarray_add( &res_files, source->name );
2304 2305 2306 2307
        }
        else if (!strcmp( ext, "tlb" ))
        {
            strarray_add( &all_targets, source->name );
2308
        }
2309 2310 2311 2312 2313 2314 2315 2316
        else if (!strcmp( ext, "h" ) || !strcmp( ext, "rh" ) || !strcmp( ext, "inl" ))  /* header file */
        {
            if (source->file->flags & FLAG_GENERATED)
            {
                strarray_add( &all_targets, source->name );
            }
            else
            {
2317 2318
                strarray_add( &install_rules[INSTALL_DEV], source->name );
                strarray_add( &install_rules[INSTALL_DEV],
2319 2320 2321
                              strmake( "D$(includedir)/%s", get_include_install_path( source->name ) ));
            }
        }
Alexandre Julliard's avatar
Alexandre Julliard committed
2322 2323
        else
        {
2324
            int need_cross = make->testdll ||
2325
                (source->file->flags & FLAG_C_IMPLIB) ||
2326
                (make->module && make->staticlib);
2327

2328
            if ((source->file->flags & FLAG_GENERATED) &&
2329
                (!make->testdll || !strendswith( source->filename, "testlist.c" )))
2330
                strarray_add( &clean_files, source->filename );
2331
            if (source->file->flags & FLAG_C_IMPLIB) strarray_add( &implib_objs, strmake( "%s.o", obj ));
2332
            strarray_add( &object_files, strmake( "%s.o", obj ));
2333
            output( "%s.o: %s\n", obj_dir_path( make, obj ), source->filename );
2334 2335
            output( "\t$(CC) -c -o $@ %s", source->filename );
            output_filenames( includes );
2336
            output_filenames( make->define_args );
2337
            output_filenames( extradefs );
2338
            if (make->module || make->staticlib || make->testdll)
2339 2340
            {
                output_filenames( dll_flags );
2341
                if (make->use_msvcrt) output_filenames( msvcrt_flags );
2342 2343 2344
            }
            output_filenames( extra_cflags );
            output_filenames( cpp_flags );
2345
            output_filename( "$(CFLAGS)" );
2346 2347
            output( "\n" );
            if (crosstarget && need_cross)
2348
            {
2349
                strarray_add( &crossobj_files, strmake( "%s.cross.o", obj ));
2350
                output( "%s.cross.o: %s\n", obj_dir_path( make, obj ), source->filename );
2351
                output( "\t$(CROSSCC) -c -o $@ %s", source->filename );
2352
                output_filenames( includes );
2353
                output_filenames( make->define_args );
2354
                output_filenames( extradefs );
2355
                output_filename( "-DWINE_CROSSTEST" );
2356
                output_filenames( cpp_flags );
2357
                output_filename( "$(CFLAGS)" );
2358
                output( "\n" );
2359
            }
2360
            if (make->testdll && !strcmp( ext, "c" ) && !(source->file->flags & FLAG_GENERATED))
2361
            {
2362
                strarray_add( &ok_files, strmake( "%s.ok", obj ));
2363
                output( "%s.ok:\n", obj_dir_path( make, obj ));
2364
                output( "\t%s $(RUNTESTFLAGS) -T %s -M %s -p %s%s %s && touch $@\n",
2365
                        top_dir_path( make, "tools/runtest" ), top_obj_dir_path( make, "" ), make->testdll,
2366
                        replace_extension( make->testdll, ".dll", "_test.exe" ), dll_ext, obj );
2367
            }
2368
            if (!strcmp( ext, "c" ) && !(source->file->flags & FLAG_GENERATED))
2369
                strarray_add( &c2man_files, source->filename );
2370 2371
            output( "%s.o", obj_dir_path( make, obj ));
            if (crosstarget && need_cross) output( " %s.cross.o", obj_dir_path( make, obj ));
2372
            output( ":" );
2373 2374
            output_filenames( dependencies );
            output( "\n" );
Alexandre Julliard's avatar
Alexandre Julliard committed
2375
        }
2376
        free( obj );
Alexandre Julliard's avatar
Alexandre Julliard committed
2377
    }
2378 2379 2380

    /* rules for files that depend on multiple sources */

2381
    if (po_files.count)
2382
    {
2383
        output( "%s: %s", obj_dir_path( make, "rsrc.pot" ), tools_path( make, "wrc" ) );
2384
        output_filenames( po_files );
2385
        output( "\n" );
2386
        output( "\t%s -O pot -o $@", tools_path( make, "wrc" ));
2387
        if (make->is_win16) output_filename( "-m16" );
2388
        else output_filenames( target_flags );
2389
        output_filename( "--nostdinc" );
2390
        output_filenames( includes );
2391
        output_filenames( make->define_args );
2392
        output_filenames( po_files );
2393
        output( "\n" );
2394
        strarray_add( &clean_files, "rsrc.pot" );
2395 2396
    }

2397
    if (mc_files.count)
2398
    {
2399
        output( "%s: %s", obj_dir_path( make, "msg.pot" ), tools_path( make, "wmc" ));
2400
        output_filenames( mc_files );
2401
        output( "\n" );
2402
        output( "\t%s -O pot -o $@", tools_path( make, "wmc" ));
2403
        output_filenames( mc_files );
2404
        output( "\n" );
2405
        strarray_add( &clean_files, "msg.pot" );
2406
    }
2407

2408
    if (dlldata_files.count)
2409
    {
2410 2411 2412
        output( "%s: %s %s\n", obj_dir_path( make, "dlldata.c" ),
                tools_path( make, "widl" ), src_dir_path( make, "Makefile.in" ));
        output( "\t%s --dlldata-only -o $@", tools_path( make, "widl" ));
2413
        output_filenames( dlldata_files );
2414 2415
        output( "\n" );
    }
2416

2417
    if (make->module && !make->staticlib)
2418 2419
    {
        struct strarray all_libs = empty_strarray;
2420
        char *module_path = obj_dir_path( make, make->module );
2421
        char *spec_file = NULL;
2422

2423 2424
        if (!make->appmode.count)
            spec_file = src_dir_path( make, replace_extension( make->module, ".dll", ".spec" ));
2425 2426
        for (i = 0; i < make->delayimports.count; i++)
            strarray_add( &all_libs, strmake( "-l%s", make->delayimports.str[i] ));
2427 2428
        for (i = 0; i < make->imports.count; i++)
            strarray_add( &all_libs, strmake( "-l%s", make->imports.str[i] ));
2429 2430
        for (i = 0; i < make->delayimports.count; i++)
            strarray_add( &all_libs, strmake( "-Wb,-d%s", make->delayimports.str[i] ));
2431
        strarray_add( &all_libs, "-lwine" );
2432 2433
        strarray_add( &all_libs, top_obj_dir_path( make, "libs/port/libwine_port.a" ));
        strarray_addall( &all_libs, get_expanded_make_var_array( make, "EXTRALIBS" ));
2434
        strarray_addall( &all_libs, libs );
2435

2436
        if (*dll_ext)
2437
        {
2438 2439
            strarray_add( &all_targets, strmake( "%s%s", make->module, dll_ext ));
            strarray_add( &all_targets, strmake( "%s.fake", make->module ));
2440
            add_install_rule( make, install_rules, make->module, strmake( "%s%s", make->module, dll_ext ),
2441
                              strmake( "p$(dlldir)/%s%s", make->module, dll_ext ));
2442
            add_install_rule( make, install_rules, make->module, strmake( "%s.fake", make->module ),
2443
                              strmake( "d$(fakedlldir)/%s", make->module ));
2444
            output( "%s%s %s.fake:", module_path, dll_ext, module_path );
2445 2446 2447
        }
        else
        {
2448
            strarray_add( &all_targets, make->module );
2449
            add_install_rule( make, install_rules, make->module, make->module,
2450
                              strmake( "p$(%s)/%s", spec_file ? "dlldir" : "bindir", make->module ));
2451
            output( "%s:", module_path );
2452 2453
        }
        if (spec_file) output_filename( spec_file );
2454 2455
        output_filenames_obj_dir( make, object_files );
        output_filenames_obj_dir( make, res_files );
2456
        output( "\n" );
2457 2458 2459
        output( "\t%s -o $@", tools_path( make, "winegcc" ));
        output_filename( strmake( "-B%s", tools_dir_path( make, "winebuild" )));
        if (tools_dir) output_filename( strmake( "--sysroot=%s", top_obj_dir_path( make, "" )));
2460 2461
        output_filenames( target_flags );
        output_filenames( unwind_flags );
2462 2463 2464
        if (spec_file)
        {
            output( " -shared %s", spec_file );
2465
            output_filenames( make->extradllflags );
2466
        }
2467
        else output_filenames( make->appmode );
2468 2469
        output_filenames_obj_dir( make, object_files );
        output_filenames_obj_dir( make, res_files );
2470 2471 2472
        output_filenames( all_libs );
        output_filename( "$(LDFLAGS)" );
        output( "\n" );
2473

2474
        if (spec_file && make->importlib)
2475
        {
2476
            char *importlib_path = obj_dir_path( make, strmake( "lib%s", make->importlib ));
2477
            if (*dll_ext)
2478
            {
2479
                strarray_add( &clean_files, strmake( "lib%s.def", make->importlib ));
2480 2481
                output( "%s.def: %s %s\n", importlib_path, tools_path( make, "winebuild" ), spec_file );
                output( "\t%s -w --def -o $@ --export %s", tools_path( make, "winebuild" ), spec_file );
2482
                output_filenames( target_flags );
2483
                if (make->is_win16) output_filename( "-m16" );
2484
                output( "\n" );
2485 2486
                add_install_rule( make, install_rules, make->importlib,
                                  strmake( "lib%s.def", make->importlib ),
2487
                                  strmake( "d$(dlldir)/lib%s.def", make->importlib ));
2488 2489
                if (implib_objs.count)
                {
2490
                    strarray_add( &clean_files, strmake( "lib%s.def.a", make->importlib ));
2491
                    output( "%s.def.a:", importlib_path );
2492
                    output_filenames_obj_dir( make, implib_objs );
2493
                    output( "\n" );
2494
                    output( "\trm -f $@\n" );
2495
                    output( "\t$(AR) $(ARFLAGS) $@" );
2496
                    output_filenames_obj_dir( make, implib_objs );
2497 2498
                    output( "\n" );
                    output( "\t$(RANLIB) $@\n" );
2499 2500
                    add_install_rule( make, install_rules, make->importlib,
                                      strmake( "lib%s.def.a", make->importlib ),
2501
                                      strmake( "d$(dlldir)/lib%s.def.a", make->importlib ));
2502 2503 2504 2505
                }
            }
            else
            {
2506
                strarray_add( &clean_files, strmake( "lib%s.a", make->importlib ));
2507 2508
                output( "%s.a: %s %s", importlib_path, tools_path( make, "winebuild" ), spec_file );
                output_filenames_obj_dir( make, implib_objs );
2509
                output( "\n" );
2510
                output( "\t%s -w --implib -o $@ --export %s", tools_path( make, "winebuild" ), spec_file );
2511
                output_filenames( target_flags );
2512
                output_filenames_obj_dir( make, implib_objs );
2513
                output( "\n" );
2514 2515
                add_install_rule( make, install_rules, make->importlib,
                                  strmake( "lib%s.a", make->importlib ),
2516
                                  strmake( "d$(dlldir)/lib%s.a", make->importlib ));
2517
            }
2518
            if (crosstarget && !make->is_win16)
2519 2520
            {
                struct strarray cross_files = strarray_replace_extension( &implib_objs, ".o", ".cross.o" );
2521
                strarray_add( &clean_files, strmake( "lib%s.cross.a", make->importlib ));
2522 2523
                output( "%s.cross.a: %s %s", importlib_path, tools_path( make, "winebuild" ), spec_file );
                output_filenames_obj_dir( make, cross_files );
2524
                output( "\n" );
2525
                output( "\t%s -b %s -w --implib -o $@ --export %s",
2526 2527
                        tools_path( make, "winebuild" ), crosstarget, spec_file );
                output_filenames_obj_dir( make, cross_files );
2528 2529 2530
                output( "\n" );
            }
        }
2531 2532 2533

        if (spec_file)
        {
2534
            if (c2man_files.count)
2535 2536
            {
                output( "manpages::\n" );
2537 2538 2539 2540 2541
                output( "\t%s -w %s", top_dir_path( make, "tools/c2man.pl" ), spec_file );
                output_filename( strmake( "-R%s", top_dir_path( make, "" )));
                output_filename( strmake( "-I%s", top_dir_path( make, "include" )));
                output_filename( strmake( "-o %s/man%s",
                                          top_obj_dir_path( make, "documentation" ), man_ext ));
2542 2543 2544
                output_filenames( c2man_files );
                output( "\n" );
                output( "htmlpages::\n" );
2545 2546 2547 2548 2549
                output( "\t%s -Th -w %s", top_dir_path( make, "tools/c2man.pl" ), spec_file );
                output_filename( strmake( "-R%s", top_dir_path( make, "" )));
                output_filename( strmake( "-I%s", top_dir_path( make, "include" )));
                output_filename( strmake( "-o %s",
                                          top_obj_dir_path( make, "documentation/html" )));
2550 2551 2552
                output_filenames( c2man_files );
                output( "\n" );
                output( "sgmlpages::\n" );
2553 2554 2555 2556 2557
                output( "\t%s -Ts -w %s", top_dir_path( make, "tools/c2man.pl" ), spec_file );
                output_filename( strmake( "-R%s", top_dir_path( make, "" )));
                output_filename( strmake( "-I%s", top_dir_path( make, "include" )));
                output_filename( strmake( "-o %s",
                                          top_obj_dir_path( make, "documentation/api-guide" )));
2558 2559 2560
                output_filenames( c2man_files );
                output( "\n" );
                output( "xmlpages::\n" );
2561 2562 2563 2564 2565
                output( "\t%s -Tx -w %s", top_dir_path( make, "tools/c2man.pl" ), spec_file );
                output_filename( strmake( "-R%s", top_dir_path( make, "" )));
                output_filename( strmake( "-I%s", top_dir_path( make, "include" )));
                output_filename( strmake( "-o %s",
                                          top_obj_dir_path( make, "documentation/api-guide-xml" )));
2566 2567 2568 2569 2570 2571 2572 2573 2574
                output_filenames( c2man_files );
                output( "\n" );
                strarray_add( &phony_targets, "manpages" );
                strarray_add( &phony_targets, "htmlpages" );
                strarray_add( &phony_targets, "sgmlpages" );
                strarray_add( &phony_targets, "xmlpages" );
            }
            else output( "manpages htmlpages sgmlpages xmlpages::\n" );
        }
2575 2576 2577
        else if (*dll_ext)
        {
            char *binary = replace_extension( make->module, ".exe", "" );
2578
            add_install_rule( make, install_rules, binary, tools_dir_path( make, "wineapploader" ),
2579 2580
                              strmake( "s$(bindir)/%s", binary ));
        }
2581 2582
    }

2583
    if (make->staticlib)
2584
    {
2585
        strarray_add( &all_targets, make->staticlib );
2586 2587
        output( "%s:", obj_dir_path( make, make->staticlib ));
        output_filenames_obj_dir( make, object_files );
2588
        output( "\n\trm -f $@\n" );
2589
        output( "\t$(AR) $(ARFLAGS) $@" );
2590
        output_filenames_obj_dir( make, object_files );
2591
        output( "\n\t$(RANLIB) $@\n" );
2592
        if (crosstarget && make->module)
2593
        {
2594
            char *name = replace_extension( make->staticlib, ".a", ".cross.a" );
2595 2596

            strarray_add( &all_targets, name );
2597 2598
            output( "%s:", obj_dir_path( make, name ));
            output_filenames_obj_dir( make, crossobj_files );
2599
            output( "\n\trm -f $@\n" );
2600
            output( "\t%s-ar $(ARFLAGS) $@", crosstarget );
2601
            output_filenames_obj_dir( make, crossobj_files );
2602 2603 2604 2605
            output( "\n\t%s-ranlib $@\n", crosstarget );
        }
    }

2606 2607 2608 2609 2610 2611 2612 2613 2614 2615 2616 2617 2618 2619 2620 2621
    if (make->sharedlib)
    {
        char *basename, *p;
        struct strarray names = get_shared_lib_names( make->sharedlib );
        struct strarray all_libs = empty_strarray;

        basename = xstrdup( make->sharedlib );
        if ((p = strchr( basename, '.' ))) *p = 0;

        strarray_addall( &all_libs, get_expanded_make_var_array( make,
                                                                 file_local_var( basename, "LDFLAGS" )));
        strarray_addall( &all_libs, get_expanded_make_var_array( make, "EXTRALIBS" ));
        strarray_addall( &all_libs, libs );

        output( "%s:", obj_dir_path( make, make->sharedlib ));
        output_filenames_obj_dir( make, object_files );
2622
        output_filenames( get_local_dependencies( make, basename, in_files ));
2623 2624 2625 2626 2627 2628
        output( "\n" );
        output( "\t$(CC) -o $@" );
        output_filenames_obj_dir( make, object_files );
        output_filenames( all_libs );
        output_filename( "$(LDFLAGS)" );
        output( "\n" );
2629 2630
        add_install_rule( make, install_rules, make->sharedlib, make->sharedlib,
                          strmake( "p$(libdir)/%s", make->sharedlib ));
2631 2632 2633 2634
        for (i = 1; i < names.count; i++)
        {
            output( "%s: %s\n", obj_dir_path( make, names.str[i] ), obj_dir_path( make, names.str[i-1] ));
            output( "\trm -f $@ && $(LN_S) %s $@\n", names.str[i-1] );
2635 2636
            add_install_rule( make, install_rules, names.str[i], names.str[i-1],
                              strmake( "y$(libdir)/%s", names.str[i] ));
2637 2638 2639 2640
        }
        strarray_addall( &all_targets, names );
    }

2641 2642 2643 2644 2645 2646 2647 2648 2649 2650 2651 2652
    if (make->importlib && !make->module)  /* stand-alone import lib (for libwine) */
    {
        char *def_file = replace_extension( make->importlib, ".a", ".def" );

        if (!strncmp( def_file, "lib", 3 )) def_file += 3;
        output( "%s: %s\n", obj_dir_path( make, make->importlib ), src_dir_path( make, def_file ));
        output( "\t%s -l $@ -d %s\n", dlltool, src_dir_path( make, def_file ));
        add_install_rule( make, install_rules, make->importlib, make->importlib,
                          strmake( "d$(libdir)/%s", make->importlib ));
        strarray_add( &all_targets, make->importlib );
    }

2653
    if (make->testdll)
2654
    {
2655 2656
        char *testmodule = replace_extension( make->testdll, ".dll", "_test.exe" );
        char *stripped = replace_extension( make->testdll, ".dll", "_test-stripped.exe" );
2657
        char *testres = replace_extension( make->testdll, ".dll", "_test.res" );
2658 2659
        struct strarray all_libs = empty_strarray;

2660 2661
        for (i = 0; i < make->imports.count; i++)
            strarray_add( &all_libs, strmake( "-l%s", make->imports.str[i] ));
2662
        strarray_addall( &all_libs, libs );
2663

2664 2665
        strarray_add( &all_targets, strmake( "%s%s", testmodule, dll_ext ));
        strarray_add( &clean_files, strmake( "%s%s", stripped, dll_ext ));
2666 2667 2668 2669
        output( "%s%s:\n", obj_dir_path( make, testmodule ), dll_ext );
        output( "\t%s -o $@", tools_path( make, "winegcc" ));
        output_filename( strmake( "-B%s", tools_dir_path( make, "winebuild" )));
        if (tools_dir) output_filename( strmake( "--sysroot=%s", top_obj_dir_path( make, "" )));
2670 2671
        output_filenames( target_flags );
        output_filenames( unwind_flags );
2672
        output_filenames( make->appmode );
2673 2674
        output_filenames_obj_dir( make, object_files );
        output_filenames_obj_dir( make, res_files );
2675 2676 2677
        output_filenames( all_libs );
        output_filename( "$(LDFLAGS)" );
        output( "\n" );
2678 2679 2680 2681
        output( "%s%s:\n", obj_dir_path( make, stripped ), dll_ext );
        output( "\t%s -o $@", tools_path( make, "winegcc" ));
        output_filename( strmake( "-B%s", tools_dir_path( make, "winebuild" )));
        if (tools_dir) output_filename( strmake( "--sysroot=%s", top_obj_dir_path( make, "" )));
2682 2683
        output_filenames( target_flags );
        output_filenames( unwind_flags );
2684
        output_filename( strmake( "-Wb,-F,%s", testmodule ));
2685
        output_filenames( make->appmode );
2686 2687
        output_filenames_obj_dir( make, object_files );
        output_filenames_obj_dir( make, res_files );
2688 2689 2690
        output_filenames( all_libs );
        output_filename( "$(LDFLAGS)" );
        output( "\n" );
2691 2692 2693 2694
        output( "%s%s %s%s:", obj_dir_path( make, testmodule ), dll_ext,
                obj_dir_path( make, stripped ), dll_ext );
        output_filenames_obj_dir( make, object_files );
        output_filenames_obj_dir( make, res_files );
2695 2696
        output( "\n" );

2697 2698 2699
        output( "all: %s/%s\n", top_obj_dir_path( make, "programs/winetest" ), testres );
        output( "%s/%s: %s%s\n", top_obj_dir_path( make, "programs/winetest" ), testres,
                obj_dir_path( make, stripped ), dll_ext );
2700
        output( "\techo \"%s TESTRES \\\"%s%s\\\"\" | %s -o $@\n",
2701
                testmodule, obj_dir_path( make, stripped ), dll_ext, tools_path( make, "wrc" ));
2702 2703 2704

        if (crosstarget)
        {
2705
            char *crosstest = replace_extension( make->testdll, ".dll", "_crosstest.exe" );
2706 2707

            strarray_add( &clean_files, crosstest );
2708 2709 2710 2711
            output( "%s: %s\n", obj_dir_path( make, "crosstest" ), obj_dir_path( make, crosstest ));
            output( "%s:", obj_dir_path( make, crosstest ));
            output_filenames_obj_dir( make, crossobj_files );
            output_filenames_obj_dir( make, res_files );
2712
            output( "\n" );
2713 2714 2715
            output( "\t%s -o $@ -b %s", tools_path( make, "winegcc" ), crosstarget );
            output_filename( strmake( "-B%s", tools_dir_path( make, "winebuild" )));
            if (tools_dir) output_filename( strmake( "--sysroot=%s", top_obj_dir_path( make, "" )));
2716
            output_filename( "--lib-suffix=.cross.a" );
2717 2718
            output_filenames_obj_dir( make, crossobj_files );
            output_filenames_obj_dir( make, res_files );
2719 2720 2721
            output_filenames( all_libs );
            output_filename( "$(LDFLAGS)" );
            output( "\n" );
2722 2723
            strarray_add( &phony_targets, obj_dir_path( make, "crosstest" ));
            if (make->obj_dir) output( "crosstest: %s\n", obj_dir_path( make, "crosstest" ));
2724 2725
        }

2726
        output_filenames_obj_dir( make, ok_files );
2727
        output( ": %s%s ../%s%s\n", testmodule, dll_ext, make->testdll, dll_ext );
2728
        output( "check test:" );
2729
        output_filenames_obj_dir( make, ok_files );
2730
        output( "\n" );
2731
        output( "testclean::\n" );
2732
        output( "\trm -f" );
2733
        output_filenames_obj_dir( make, ok_files );
2734
        output( "\n" );
2735
        strarray_addall( &clean_files, ok_files );
2736 2737 2738
        strarray_add( &phony_targets, "check" );
        strarray_add( &phony_targets, "test" );
        strarray_add( &phony_targets, "testclean" );
2739 2740
    }

2741 2742
    for (i = 0; i < make->programs.count; i++)
    {
2743
        char *program_installed = NULL;
2744 2745
        char *program = strmake( "%s%s", make->programs.str[i], exe_ext );
        struct strarray all_libs = empty_strarray;
2746
        struct strarray deps = get_local_dependencies( make, make->programs.str[i], in_files );
2747 2748
        struct strarray objs = get_expanded_make_var_array( make,
                                                 file_local_var( make->programs.str[i], "OBJS" ));
2749 2750
        struct strarray symlinks = get_expanded_make_var_array( make,
                                                 file_local_var( make->programs.str[i], "SYMLINKS" ));
2751 2752 2753 2754

        if (!objs.count) objs = object_files;
        output( "%s:", obj_dir_path( make, program ) );
        output_filenames_obj_dir( make, objs );
2755
        output_filenames( deps );
2756 2757 2758 2759 2760 2761 2762 2763
        output( "\n" );
        output( "\t$(CC) -o $@" );
        output_filenames_obj_dir( make, objs );
        strarray_add( &all_libs, top_obj_dir_path( make, "libs/port/libwine_port.a" ));
        strarray_addall( &all_libs, get_expanded_make_var_array( make, "EXTRALIBS" ));
        strarray_addall( &all_libs, libs );
        strarray_addall( &all_libs, get_expanded_make_var_array( make,
                                                      file_local_var( make->programs.str[i], "LDFLAGS" )));
2764 2765 2766 2767 2768 2769

        if (strarray_exists( &all_libs, "-lwine" ))
        {
            strarray_add( &all_libs, strmake( "-L%s", top_obj_dir_path( make, "libs/wine" )));
            if (ldrpath_local && ldrpath_install)
            {
2770
                program_installed = strmake( "%s-installed%s", make->programs.str[i], exe_ext );
2771 2772 2773 2774 2775 2776
                output_filename( ldrpath_local );
                output_filenames( all_libs );
                output_filename( "$(LDFLAGS)" );
                output( "\n" );
                output( "%s:", obj_dir_path( make, program_installed ) );
                output_filenames_obj_dir( make, objs );
2777
                output_filenames( deps );
2778 2779 2780 2781 2782 2783 2784 2785
                output( "\n" );
                output( "\t$(CC) -o $@" );
                output_filenames_obj_dir( make, objs );
                output_filename( ldrpath_install );
                strarray_add( &all_targets, program_installed );
            }
        }

2786 2787 2788 2789
        output_filenames( all_libs );
        output_filename( "$(LDFLAGS)" );
        output( "\n" );
        strarray_add( &all_targets, program );
2790

2791 2792 2793 2794
        if (symlinks.count)
        {
            output_filenames_obj_dir( make, symlinks );
            output( ": %s\n", obj_dir_path( make, program ));
2795
            output( "\trm -f $@ && $(LN_S) %s $@\n", obj_dir_path( make, program ));
2796 2797 2798
            strarray_addall( &all_targets, symlinks );
        }

2799
        add_install_rule( make, install_rules, program, program_installed ? program_installed : program,
2800
                          strmake( "p$(bindir)/%s", program ));
2801
        for (j = 0; j < symlinks.count; j++)
2802
            add_install_rule( make, install_rules, symlinks.str[j], program,
2803
                              strmake( "y$(bindir)/%s%s", symlinks.str[j], exe_ext ));
2804 2805
    }

2806
    for (i = 0; i < make->scripts.count; i++)
2807
        add_install_rule( make, install_rules, make->scripts.str[i], make->scripts.str[i],
2808 2809
                          strmake( "S$(bindir)/%s", make->scripts.str[i] ));

2810 2811 2812
    if (all_targets.count)
    {
        output( "all:" );
2813
        output_filenames_obj_dir( make, all_targets );
2814 2815 2816
        output( "\n" );
    }

2817 2818 2819 2820 2821 2822 2823 2824 2825 2826 2827 2828
    strarray_addall( &uninstall_files, output_install_rules( make, install_rules[INSTALL_LIB],
                                                             "install-lib", &phony_targets ));
    strarray_addall( &uninstall_files, output_install_rules( make, install_rules[INSTALL_DEV],
                                                             "install-dev", &phony_targets ));
    if (uninstall_files.count)
    {
        output( "uninstall::\n" );
        output( "\trm -f" );
        output_filenames( uninstall_files );
        output( "\n" );
        strarray_add_uniq( &phony_targets, "uninstall" );
    }
2829

2830 2831 2832
    strarray_addall( &clean_files, object_files );
    strarray_addall( &clean_files, crossobj_files );
    strarray_addall( &clean_files, res_files );
2833
    strarray_addall( &clean_files, all_targets );
2834
    strarray_addall( &clean_files, get_expanded_make_var_array( make, "EXTRA_TARGETS" ));
2835

2836 2837
    if (clean_files.count)
    {
2838
        output( "%s::\n", obj_dir_path( make, "clean" ));
2839
        output( "\trm -f" );
2840
        output_filenames_obj_dir( make, clean_files );
2841
        output( "\n" );
2842 2843
        if (make->obj_dir) output( "__clean__: %s\n", obj_dir_path( make, "clean" ));
        strarray_add( &phony_targets, obj_dir_path( make, "clean" ));
2844
    }
2845

2846 2847
    if (make->subdirs.count)
    {
2848
        struct strarray makefile_deps = empty_strarray;
2849
        struct strarray distclean_files = empty_strarray;
2850

2851 2852
        for (i = 0; i < make->subdirs.count; i++)
        {
2853 2854
            strarray_add( &makefile_deps, top_dir_path( make, base_dir_path( make->submakes[i],
                                                         strmake ( "%s.in", output_makefile_name ))));
2855 2856 2857 2858 2859 2860
            strarray_add( &distclean_files, base_dir_path( make->submakes[i], output_makefile_name ));
            if (!make->src_dir)
                strarray_add( &distclean_files, base_dir_path( make->submakes[i], ".gitignore" ));
            if (make->submakes[i]->testdll)
                strarray_add( &distclean_files, base_dir_path( make->submakes[i], "testlist.c" ));
        }
2861 2862 2863
        output( "Makefile:" );
        output_filenames( makefile_deps );
        output( "\n" );
2864 2865 2866 2867 2868 2869 2870
        output( "distclean::\n");
        output( "\trm -f" );
        output_filenames( distclean_files );
        output( "\n" );
        strarray_add( &phony_targets, "distclean" );
    }

2871 2872
    if (phony_targets.count)
    {
2873
        output( ".PHONY:" );
2874
        output_filenames( phony_targets );
2875 2876 2877
        output( "\n" );
    }

2878 2879
    for (i = 0; i < subdirs.count; i++) create_dir( subdirs.str[i] );

2880
    return clean_files;
Alexandre Julliard's avatar
Alexandre Julliard committed
2881 2882 2883
}


2884 2885 2886
/*******************************************************************
 *         create_temp_file
 */
2887
static FILE *create_temp_file( const char *orig )
2888
{
2889
    char *name = xmalloc( strlen(orig) + 13 );
2890 2891 2892 2893 2894 2895
    unsigned int i, id = getpid();
    int fd;
    FILE *ret = NULL;

    for (i = 0; i < 100; i++)
    {
2896
        sprintf( name, "%s.tmp%08x", orig, id );
2897
        if ((fd = open( name, O_RDWR | O_CREAT | O_EXCL, 0666 )) != -1)
2898 2899 2900 2901 2902 2903 2904
        {
            ret = fdopen( fd, "w" );
            break;
        }
        if (errno != EEXIST) break;
        id += 7777;
    }
2905
    if (!ret) fatal_error( "failed to create output file for '%s'\n", orig );
2906
    temp_file_name = name;
2907 2908 2909 2910
    return ret;
}


2911 2912 2913
/*******************************************************************
 *         rename_temp_file
 */
2914
static void rename_temp_file( const char *dest )
2915
{
2916
    int ret = rename( temp_file_name, dest );
2917 2918 2919 2920
    if (ret == -1 && errno == EEXIST)
    {
        /* rename doesn't overwrite on windows */
        unlink( dest );
2921
        ret = rename( temp_file_name, dest );
2922
    }
2923 2924
    if (ret == -1) fatal_error( "failed to rename output file to '%s'\n", dest );
    temp_file_name = NULL;
2925 2926 2927
}


2928 2929 2930 2931 2932 2933 2934 2935 2936 2937 2938 2939 2940 2941 2942 2943 2944 2945 2946 2947 2948 2949 2950 2951 2952 2953 2954 2955 2956 2957 2958 2959 2960 2961 2962 2963 2964 2965 2966 2967 2968 2969 2970 2971 2972 2973
/*******************************************************************
 *         are_files_identical
 */
static int are_files_identical( FILE *file1, FILE *file2 )
{
    for (;;)
    {
        char buffer1[8192], buffer2[8192];
        int size1 = fread( buffer1, 1, sizeof(buffer1), file1 );
        int size2 = fread( buffer2, 1, sizeof(buffer2), file2 );
        if (size1 != size2) return 0;
        if (!size1) return feof( file1 ) && feof( file2 );
        if (memcmp( buffer1, buffer2, size1 )) return 0;
    }
}


/*******************************************************************
 *         rename_temp_file_if_changed
 */
static void rename_temp_file_if_changed( const char *dest )
{
    FILE *file1, *file2;
    int do_rename = 1;

    if ((file1 = fopen( dest, "r" )))
    {
        if ((file2 = fopen( temp_file_name, "r" )))
        {
            do_rename = !are_files_identical( file1, file2 );
            fclose( file2 );
        }
        fclose( file1 );
    }
    if (!do_rename)
    {
        unlink( temp_file_name );
        temp_file_name = NULL;
    }
    else rename_temp_file( dest );
}


/*******************************************************************
 *         output_testlist
 */
2974
static void output_testlist( const struct makefile *make )
2975
{
2976 2977 2978 2979 2980 2981 2982 2983 2984 2985 2986
    const char *dest = base_dir_path( make, "testlist.c" );
    struct strarray files = empty_strarray;
    struct incl_file *source;
    unsigned int i;

    LIST_FOR_EACH_ENTRY( source, &make->sources, struct incl_file, entry )
    {
        if (source->file->flags & FLAG_GENERATED) continue;
        if (!strendswith( source->name, ".c" )) continue;
        strarray_add( &files, replace_extension( source->name, ".c", "" ));
    }
2987 2988 2989 2990 2991 2992 2993 2994 2995 2996 2997 2998 2999 3000 3001 3002 3003 3004 3005 3006 3007 3008 3009

    output_file = create_temp_file( dest );

    output( "/* Automatically generated by make depend; DO NOT EDIT!! */\n\n" );
    output( "#define WIN32_LEAN_AND_MEAN\n" );
    output( "#include <windows.h>\n\n" );
    output( "#define STANDALONE\n" );
    output( "#include \"wine/test.h\"\n\n" );

    for (i = 0; i < files.count; i++) output( "extern void func_%s(void);\n", files.str[i] );
    output( "\n" );
    output( "const struct test winetest_testlist[] =\n" );
    output( "{\n" );
    for (i = 0; i < files.count; i++) output( "    { \"%s\", func_%s },\n", files.str[i], files.str[i] );
    output( "    { 0, 0 }\n" );
    output( "};\n" );

    if (fclose( output_file )) fatal_perror( "write" );
    output_file = NULL;
    rename_temp_file_if_changed( dest );
}


3010 3011 3012
/*******************************************************************
 *         output_gitignore
 */
3013
static void output_gitignore( const char *dest, struct strarray files )
3014 3015 3016
{
    int i;

3017
    output_file = create_temp_file( dest );
3018 3019

    output( "# Automatically generated by make depend; DO NOT EDIT!!\n" );
3020
    for (i = 0; i < files.count; i++)
3021
    {
3022 3023
        if (!strchr( files.str[i], '/' )) output( "/" );
        output( "%s\n", files.str[i] );
3024 3025
    }

3026
    if (fclose( output_file )) fatal_perror( "write" );
3027
    output_file = NULL;
3028
    rename_temp_file( dest );
3029 3030 3031
}


3032 3033 3034
/*******************************************************************
 *         output_top_variables
 */
3035
static void output_top_variables( const struct makefile *make )
3036 3037 3038 3039 3040 3041 3042 3043 3044
{
    unsigned int i;
    struct strarray *vars = &top_makefile->vars;

    if (!make->base_dir) return;  /* don't output variables in the top makefile */

    output( "# Automatically generated by make depend; DO NOT EDIT!!\n\n" );
    output( "all:\n\n" );
    for (i = 0; i < vars->count; i += 2)
3045 3046
    {
        if (!strcmp( vars->str[i], "SUBDIRS" )) continue;  /* not inherited */
3047
        output( "%s = %s\n", vars->str[i], get_make_variable( make, vars->str[i] ));
3048
    }
3049 3050 3051 3052
    output( "\n" );
}


Alexandre Julliard's avatar
Alexandre Julliard committed
3053 3054 3055
/*******************************************************************
 *         output_dependencies
 */
3056
static void output_dependencies( const struct makefile *make )
Alexandre Julliard's avatar
Alexandre Julliard committed
3057
{
3058
    static const char separator[] = "### Dependencies";
3059
    struct strarray targets, ignore_files = empty_strarray;
3060
    char buffer[1024];
3061
    FILE *src_file;
3062
    int found = 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
3063

3064
    output_file_name = base_dir_path( make, output_makefile_name );
3065 3066
    output_file = create_temp_file( output_file_name );
    output_top_variables( make );
3067

3068
    /* copy the contents of the source makefile */
3069
    src_file = open_input_makefile( make );
3070 3071
    while (fgets( buffer, sizeof(buffer), src_file ) && !found)
    {
3072
        if (fwrite( buffer, 1, strlen(buffer), output_file ) != strlen(buffer)) fatal_perror( "write" );
3073 3074
        found = !strncmp( buffer, separator, strlen(separator) );
    }
3075
    if (fclose( src_file )) fatal_perror( "close" );
3076
    input_file_name = NULL;
3077

3078
    if (!found) output( "\n%s (everything below this line is auto-generated; DO NOT EDIT!!)\n", separator );
3079
    targets = output_sources( make );
3080 3081 3082

    fclose( output_file );
    output_file = NULL;
3083
    rename_temp_file( output_file_name );
3084

3085 3086
    strarray_add( &ignore_files, ".gitignore" );
    strarray_add( &ignore_files, "Makefile" );
3087 3088 3089 3090 3091
    if (make->testdll)
    {
        output_testlist( make );
        strarray_add( &ignore_files, "testlist.c" );
    }
3092
    strarray_addall( &ignore_files, targets );
3093 3094
    if (!make->src_dir && make->base_dir)
        output_gitignore( base_dir_path( make, ".gitignore" ), ignore_files );
3095 3096

    output_file_name = NULL;
3097 3098 3099 3100
}


/*******************************************************************
3101
 *         load_sources
3102
 */
3103
static void load_sources( struct makefile *make )
3104 3105 3106 3107 3108 3109 3110
{
    static const char *source_vars[] =
    {
        "C_SRCS",
        "OBJC_SRCS",
        "RC_SRCS",
        "MC_SRCS",
3111
        "IDL_SRCS",
3112 3113
        "BISON_SRCS",
        "LEX_SRCS",
3114
        "HEADER_SRCS",
3115
        "XTEMPLATE_SRCS",
3116
        "SVG_SRCS",
3117
        "FONT_SRCS",
3118 3119 3120 3121 3122 3123 3124 3125 3126
        "IN_SRCS",
        "MANPAGES",
        NULL
    };
    const char **var;
    unsigned int i;
    struct strarray value;
    struct incl_file *file;

3127 3128 3129 3130 3131
    if (root_src_dir)
    {
        make->top_src_dir = concat_paths( make->top_obj_dir, root_src_dir );
        make->src_dir = concat_paths( make->top_src_dir, make->base_dir );
    }
3132 3133 3134
    strarray_set_value( &make->vars, "top_builddir", top_obj_dir_path( make, "" ));
    strarray_set_value( &make->vars, "top_srcdir", top_dir_path( make, "" ));
    strarray_set_value( &make->vars, "srcdir", src_dir_path( make, "" ));
3135

3136 3137 3138
    make->parent_dir    = get_expanded_make_variable( make, "PARENTSRC" );
    make->module        = get_expanded_make_variable( make, "MODULE" );
    make->testdll       = get_expanded_make_variable( make, "TESTDLL" );
3139
    make->sharedlib     = get_expanded_make_variable( make, "SHAREDLIB" );
3140 3141
    make->staticlib     = get_expanded_make_variable( make, "STATICLIB" );
    make->importlib     = get_expanded_make_variable( make, "IMPORTLIB" );
3142

3143
    make->programs      = get_expanded_make_var_array( make, "PROGRAMS" );
3144
    make->scripts       = get_expanded_make_var_array( make, "SCRIPTS" );
3145 3146 3147 3148
    make->appmode       = get_expanded_make_var_array( make, "APPMODE" );
    make->imports       = get_expanded_make_var_array( make, "IMPORTS" );
    make->delayimports  = get_expanded_make_var_array( make, "DELAYIMPORTS" );
    make->extradllflags = get_expanded_make_var_array( make, "EXTRADLLFLAGS" );
3149 3150
    make->install_lib   = get_expanded_make_var_array( make, "INSTALL_LIB" );
    make->install_dev   = get_expanded_make_var_array( make, "INSTALL_DEV" );
3151 3152

    if (make->module && strendswith( make->module, ".a" )) make->staticlib = make->module;
3153

3154 3155 3156
    make->is_win16   = strarray_exists( &make->extradllflags, "-m16" );
    make->use_msvcrt = strarray_exists( &make->appmode, "-mno-cygwin" );

3157
    for (i = 0; i < make->imports.count && !make->use_msvcrt; i++)
3158 3159
        make->use_msvcrt = !strncmp( make->imports.str[i], "msvcr", 5 ) ||
                           !strcmp( make->imports.str[i], "ucrtbase" );
3160

3161
    if (make->module && !make->install_lib.count) strarray_add( &make->install_lib, make->module );
3162

3163
    make->include_paths = empty_strarray;
3164 3165
    make->define_args = empty_strarray;
    strarray_add( &make->define_args, "-D__WINESRC__" );
3166

3167
    value = get_expanded_make_var_array( make, "EXTRAINCL" );
3168 3169
    for (i = 0; i < value.count; i++)
        if (!strncmp( value.str[i], "-I", 2 ))
3170
            strarray_add_uniq( &make->include_paths, value.str[i] + 2 );
3171
        else
3172
            strarray_add_uniq( &make->define_args, value.str[i] );
3173
    strarray_addall( &make->define_args, get_expanded_make_var_array( make, "EXTRADEFS" ));
3174

3175
    list_init( &make->sources );
3176
    list_init( &make->includes );
3177

3178 3179 3180
    /* FIXME: target dir has to exist to allow locating srcdir-relative include files */
    if (make->base_dir) create_dir( make->base_dir );

3181 3182
    for (var = source_vars; *var; var++)
    {
3183 3184
        value = get_expanded_make_var_array( make, *var );
        for (i = 0; i < value.count; i++) add_src_file( make, value.str[i] );
3185 3186
    }

3187
    add_generated_sources( make );
3188

3189
    value = get_expanded_make_var_array( make, "EXTRA_OBJS" );
3190 3191 3192 3193
    for (i = 0; i < value.count; i++)
    {
        /* default to .c for unknown extra object files */
        if (strendswith( value.str[i], ".o" ))
3194
            add_generated_source( make, value.str[i], replace_extension( value.str[i], ".o", ".c" ) );
3195
        else
3196
            add_generated_source( make, value.str[i], NULL );
3197 3198
    }

3199
    LIST_FOR_EACH_ENTRY( file, &make->includes, struct incl_file, entry ) parse_file( make, file, 0 );
Alexandre Julliard's avatar
Alexandre Julliard committed
3200 3201 3202
}


3203 3204 3205 3206 3207 3208 3209 3210 3211 3212 3213 3214 3215 3216 3217 3218 3219 3220 3221 3222 3223 3224 3225
/*******************************************************************
 *         parse_makeflags
 */
static void parse_makeflags( const char *flags )
{
    const char *p = flags;
    char *var, *buffer = xmalloc( strlen(flags) + 1 );

    while (*p)
    {
        while (isspace(*p)) p++;
        var = buffer;
        while (*p && !isspace(*p))
        {
            if (*p == '\\' && p[1]) p++;
            *var++ = *p++;
        }
        *var = 0;
        if (var > buffer) set_make_variable( &cmdline_vars, buffer );
    }
}


Alexandre Julliard's avatar
Alexandre Julliard committed
3226 3227 3228
/*******************************************************************
 *         parse_option
 */
3229
static int parse_option( const char *opt )
Alexandre Julliard's avatar
Alexandre Julliard committed
3230
{
3231 3232 3233 3234 3235
    if (opt[0] != '-')
    {
        if (strchr( opt, '=' )) return set_make_variable( &cmdline_vars, opt );
        return 0;
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
3236 3237 3238
    switch(opt[1])
    {
    case 'f':
3239 3240
        if (opt[2]) output_makefile_name = opt + 2;
        break;
3241 3242 3243
    case 'R':
        relative_dir_mode = 1;
        break;
Alexandre Julliard's avatar
Alexandre Julliard committed
3244
    default:
3245
        fprintf( stderr, "Unknown option '%s'\n%s", opt, Usage );
Alexandre Julliard's avatar
Alexandre Julliard committed
3246 3247
        exit(1);
    }
3248
    return 1;
Alexandre Julliard's avatar
Alexandre Julliard committed
3249 3250 3251 3252 3253 3254 3255 3256
}


/*******************************************************************
 *         main
 */
int main( int argc, char *argv[] )
{
3257
    const char *makeflags = getenv( "MAKEFLAGS" );
3258
    int i, j;
Alexandre Julliard's avatar
Alexandre Julliard committed
3259

3260 3261
    if (makeflags) parse_makeflags( makeflags );

3262 3263
    i = 1;
    while (i < argc)
Alexandre Julliard's avatar
Alexandre Julliard committed
3264
    {
3265
        if (parse_option( argv[i] ))
3266 3267 3268 3269 3270 3271 3272
        {
            for (j = i; j < argc; j++) argv[j] = argv[j+1];
            argc--;
        }
        else i++;
    }

3273 3274 3275 3276 3277 3278
    if (relative_dir_mode)
    {
        char *relpath;

        if (argc != 3)
        {
3279
            fprintf( stderr, "Option -R needs two directories\n%s", Usage );
3280 3281 3282 3283 3284 3285 3286
            exit( 1 );
        }
        relpath = get_relative_path( argv[1], argv[2] );
        printf( "%s\n", relpath ? relpath : "." );
        exit( 0 );
    }

3287 3288 3289 3290 3291 3292 3293
    atexit( cleanup_files );
    signal( SIGTERM, exit_on_signal );
    signal( SIGINT, exit_on_signal );
#ifdef SIGHUP
    signal( SIGHUP, exit_on_signal );
#endif

3294 3295
    for (i = 0; i < HASH_SIZE; i++) list_init( &files[i] );

3296 3297 3298 3299 3300 3301 3302 3303 3304 3305 3306 3307 3308 3309 3310 3311
    top_makefile = parse_makefile( NULL, "# End of common header" );

    linguas      = get_expanded_make_var_array( top_makefile, "LINGUAS" );
    target_flags = get_expanded_make_var_array( top_makefile, "TARGETFLAGS" );
    msvcrt_flags = get_expanded_make_var_array( top_makefile, "MSVCRTFLAGS" );
    dll_flags    = get_expanded_make_var_array( top_makefile, "DLLFLAGS" );
    extra_cflags = get_expanded_make_var_array( top_makefile, "EXTRACFLAGS" );
    cpp_flags    = get_expanded_make_var_array( top_makefile, "CPPFLAGS" );
    unwind_flags = get_expanded_make_var_array( top_makefile, "UNWINDFLAGS" );
    libs         = get_expanded_make_var_array( top_makefile, "LIBS" );

    root_src_dir = get_expanded_make_variable( top_makefile, "srcdir" );
    tools_dir    = get_expanded_make_variable( top_makefile, "TOOLSDIR" );
    tools_ext    = get_expanded_make_variable( top_makefile, "TOOLSEXT" );
    exe_ext      = get_expanded_make_variable( top_makefile, "EXEEXT" );
    man_ext      = get_expanded_make_variable( top_makefile, "api_manext" );
3312
    dll_ext      = (exe_ext && !strcmp( exe_ext, ".exe" )) ? "" : ".so";
3313 3314 3315 3316 3317
    crosstarget  = get_expanded_make_variable( top_makefile, "CROSSTARGET" );
    fontforge    = get_expanded_make_variable( top_makefile, "FONTFORGE" );
    convert      = get_expanded_make_variable( top_makefile, "CONVERT" );
    rsvg         = get_expanded_make_variable( top_makefile, "RSVG" );
    icotool      = get_expanded_make_variable( top_makefile, "ICOTOOL" );
3318
    dlltool      = get_expanded_make_variable( top_makefile, "DLLTOOL" );
3319

3320
    if (root_src_dir && !strcmp( root_src_dir, "." )) root_src_dir = NULL;
3321
    if (tools_dir && !strcmp( tools_dir, "." )) tools_dir = NULL;
3322
    if (!exe_ext) exe_ext = "";
3323 3324 3325
    if (!tools_ext) tools_ext = "";
    if (!man_ext) man_ext = "3w";

3326 3327 3328 3329 3330 3331 3332 3333 3334 3335 3336 3337 3338 3339 3340 3341 3342 3343 3344 3345 3346 3347 3348 3349 3350
    if (argc == 1)
    {
        top_makefile->subdirs = get_expanded_make_var_array( top_makefile, "SUBDIRS" );
        top_makefile->submakes = xmalloc( top_makefile->subdirs.count * sizeof(*top_makefile->submakes) );

        for (i = 0; i < top_makefile->subdirs.count; i++)
            top_makefile->submakes[i] = parse_makefile( top_makefile->subdirs.str[i], NULL );

        load_sources( top_makefile );
        for (i = 0; i < top_makefile->subdirs.count; i++)
            load_sources( top_makefile->submakes[i] );

        for (i = 0; i < top_makefile->subdirs.count; i++)
            output_dependencies( top_makefile->submakes[i] );

        output_dependencies( top_makefile );
        return 0;
    }

    for (i = 1; i < argc; i++)
    {
        struct makefile *make = parse_makefile( argv[i], NULL );
        load_sources( make );
        output_dependencies( make );
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
3351 3352
    return 0;
}