make_makefiles 14.9 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
#!/usr/bin/perl -w
#
# Build the auto-generated parts of the Wine makefiles.
#
# Copyright 2006 Alexandre Julliard
#
# 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
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
#

22 23
use strict;

24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
# Dlls and programs that are 16-bit specific
my %modules16 =
(
  "ifsmgr.vxd" => 1,
  "mmdevldr.vxd" => 1,
  "monodebg.vxd" => 1,
  "vdhcp.vxd" => 1,
  "vmm.vxd" => 1,
  "vnbt.vxd" => 1,
  "vnetbios.vxd" => 1,
  "vtdapi.vxd" => 1,
  "vwin32.vxd" => 1,
  "w32skrnl.dll" => 1,
  "winevdm.exe" => 1,
  "wow32.dll" => 1,
);

41 42 43 44 45 46 47
my %exported_wine_headers = (
    "wine/debug.h" => 1,
    "wine/exception.h" => 1,
    "wine/library.h" => 1,
    "wine/unicode.h" => 1,
    "wine/itss.idl" => 1,
    "wine/svcctl.idl" => 1,
48 49
);

50 51 52
my %ignored_source_files = (
    "dlls/wineps.drv/afm2c.c" => 1,
    "dlls/wineps.drv/mkagl.c" => 1,
53
    "include/config.h.in" => 1,
54
    "include/stamp-h.in" => 1,
55
    "programs/winetest/dist.rc" => 1,
56
    "tools/makedep.c" => 1,
57 58
);

59 60 61 62 63 64 65 66 67 68 69 70 71
my @source_vars = (
    "BISON_SRCS",
    "C_SRCS",
    "FONT_SRCS",
    "HEADER_SRCS",
    "IDL_SRCS",
    "IN_SRCS",
    "LEX_SRCS",
    "MANPAGES",
    "MC_SRCS",
    "OBJC_SRCS",
    "PO_SRCS",
    "RC_SRCS",
72
    "SOURCES",
73 74 75 76
    "SVG_SRCS",
    "XTEMPLATE_SRCS"
);

77
my (@makefiles, %makefiles);
78 79 80 81 82 83 84 85

sub dirname($)
{
    my $ret = shift;
    return "" unless $ret =~ /\//;
    $ret =~ s!/[^/]*$!!;
    return $ret;
}
86

87
# update a file if changed
88
sub update_file($$)
89 90
{
    my $file = shift;
91 92 93 94 95 96 97 98
    my $new = shift;

    open FILE, ">$file.new" or die "cannot create $file.new";
    print FILE $new;
    close FILE;
    rename "$file.new", "$file";
    print "$file updated\n";
    if ($file eq "configure.ac")
99
    {
100 101
        system "autoconf";
        print "configure updated\n";
102 103 104 105 106 107 108 109 110
    }
}

# replace some lines in a file between two markers
sub replace_in_file($$$@)
{
    my $file = shift;
    my $start = shift;
    my $end = shift;
111
    my ($old, $new);
112

113 114
    open OLD_FILE, "$file" or die "cannot open $file";
    while (<OLD_FILE>)
115
    {
116 117 118
        $old .= $_;
        last if /$start/;
        $new .= $_;
119 120
    }

121
    $new .= join "", @_;
122

123 124
    my $skip = 1;
    while (<OLD_FILE>)
125
    {
126 127 128
        $old .= $_;
        $new .= $_ unless $skip;
        $skip = 0 if /$end/;
129 130
    }

131 132
    close OLD_FILE;
    update_file($file, $new) if $old ne $new;
133 134
}

135 136
# replace all source variables in a makefile
sub replace_makefile_variables($)
137
{
138
    my $file = shift;
139
    my $make = $makefiles{$file};
140 141
    my $source_vars_regexp = join "|", @source_vars;
    my %replaced;
142 143
    my $old;
    my $new;
144 145 146 147

    open OLD_FILE, "$file.in" or die "cannot open $file.in";
    while (<OLD_FILE>)
    {
148
        $old .= $_;
149
        if (/^\s*($source_vars_regexp)(\s*)=/)
150 151
        {
            # try to preserve formatting
152 153 154 155 156 157 158 159 160 161 162 163 164 165
            my $var = $1;
            my $spaces = $2;
            my $replaced = 0;
            my @values;

            if (defined ${$make}{"=$var"})
            {
                @values = @{${$make}{"=$var"}};
                ${$make}{$var} = \@values;
            }
            else
            {
                undef ${$make}{$var};
            }
166
            my $multiline = /\\$/ || (@values > 1);
167
            my $old_str = $_;
168 169 170 171
            while (/\\$/)
            {
                $_ = <OLD_FILE>;
                last unless $_;
172
                $old .= $_;
173
                $old_str .= $_;
174
            }
175
            my $new_str = "";
176 177 178 179 180
            if (!@values)
            {
                # nothing
            }
            elsif ($multiline)
181
            {
182
                $new_str = "$var = \\\n\t" . join(" \\\n\t", sort @values) . "\n";
183
                $new .= $new_str;
184 185 186
            }
            else
            {
187
                $new_str = "$var$spaces= @values\n";
188
                $new .= $new_str;
189
            }
190
            $replaced{$var} = 1;
191 192
            next;
        }
193
        $new .= $_;
194
    }
195 196
    # if we are using SOURCES, ignore the other variables
    unless ($replaced{"SOURCES"})
197
    {
198 199 200 201 202 203 204 205 206
        foreach my $var (@source_vars)
        {
            next if defined $replaced{$var};
            next if $var eq "SOURCES";
            next unless defined ${$make}{"=$var"};
            my @values = @{${$make}{"=$var"}};
            next unless @values;
            $new .= "\n$var = \\\n\t" . join(" \\\n\t", sort @values) . "\n";
        }
207
    }
208
    close OLD_FILE;
209
    update_file("$file.in", $new) if $old ne $new;
210 211
}

212
# parse the specified makefile and load the variables
213 214 215
sub parse_makefile($)
{
    my $file = shift;
216
    my %make;
217

218 219
    ($make{"=dir"} = $file) =~ s/[^\/]+$//;

220 221 222 223 224
    open MAKE, "$file.in" or die "cannot open $file.in\n";

    while (<MAKE>)
    {
        chomp;
225
        next if (/^\s*#/);
226
        while (/\\$/) { chop; $_ .= <MAKE>; chomp; }  # merge continued lines
227
        next if (/^\s*$/);
228

229 230
        if (/\@[A-Z_]+\@/)  # config.status substitution variable
        {
231
            die "Configure substitution is not allowed in $file" unless $file eq "Makefile";
232
        }
233
        if (/^\s*(MODULE|IMPORTLIB|TESTDLL|PARENTSRC|APPMODE)\s*=\s*(.*)/)
234
        {
235 236
            my $var = $1;
            $make{$var} = $2;
237 238
            next;
        }
239 240
        my $source_vars_regexp = join "|", @source_vars;
        if (/^\s*($source_vars_regexp|PROGRAMS|EXTRA_TARGETS|EXTRA_OBJS|INSTALL_LIB|INSTALL_DEV)\s*=\s*(.*)/)
241
        {
242
            my $var = $1;
243
            my @list = split(/\s+/, $2);
244
            $make{$var} = \@list;
245 246
            next;
        }
247 248 249 250
        if (/^\s*(TOPSRCDIR|TOPOBJDIR|SRCDIR|VPATH)\s*=\s*(.*)/)
        {
            die "Variable $1 in $file.in is obsolete";
        }
251
    }
252

253
    return %make;
254
}
255

256 257 258 259 260 261 262
# read pragma makedep flags from a source file
sub get_makedep_flags($)
{
    my $file = shift;
    my %flags;

    open FILE, $file or die "cannot open $file";
263
    if ($file =~ /\.sfd$/)
264
    {
265
        while (<FILE>)
266
        {
267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288
            next unless /^UComments:\s*\"(.*)\"$/;
            foreach my $pragma (split /\+AAoA/, $1)
            {
                next unless $pragma =~ /^#\s*pragma\s+makedep\s+(.*)/;
                foreach my $flag (split /\s+/, $1)
                {
                    $flags{$flag} = 1;
                    last if $flag eq "font";
                }
            }
        }
    }
    else
    {
        while (<FILE>)
        {
            next unless /^#\s*pragma\s+makedep\s+(.*)/;
            foreach my $flag (split /\s+/, $1)
            {
                last if $flag eq "depend";
                $flags{$flag} = 1;
            }
289 290 291 292 293 294
        }
    }
    close FILE;
    return %flags;
}

295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326
sub get_parent_makefile($)
{
    my $file = shift;
    my %make = %{$makefiles{$file}};
    my $reldir = $make{"PARENTSRC"} || "";
    return "" unless $reldir;
    (my $path = $file) =~ s/\/Makefile$/\//;
    while ($reldir =~ /^\.\.\//)
    {
        $reldir =~ s/^\.\.\///;
        $path =~ s/[^\/]+\/$//;
    }
    return "$path$reldir/Makefile";
}

# preserve shared source files that are listed in the existing makefile
sub preserve_shared_source_files($$$)
{
    my ($make, $parent, $var) = @_;
    my %srcs;

    return unless defined ${$parent}{"=$var"};
    foreach my $file (@{${$parent}{"=$var"}}) { $srcs{$file} = 1; }
    foreach my $file (@{${$make}{"=$var"}}) { $srcs{$file} = 0; }

    foreach my $file (@{${$make}{$var}})
    {
        next unless defined $srcs{$file} && $srcs{$file} == 1;
        push @{${$make}{"=$var"}}, $file;
    }
}

327
# assign source files to their respective makefile
328
sub assign_sources_to_makefiles(@)
329
{
330
    foreach my $file (@_)
331 332
    {
        next if defined $ignored_source_files{$file};
333
        next if $file =~ /Makefile\.in$/;
334
        my $dir = dirname( $file );
335
        my $subdir = $dir;
336 337

        while ($dir && !defined $makefiles{"$dir/Makefile"}) { $dir = dirname( $dir ); }
338
        $subdir =~ s/^$dir\/?//;
339 340 341 342 343
        next unless $dir;

        die "no makefile found for $file\n" unless defined $makefiles{"$dir/Makefile"};

        my $make = $makefiles{"$dir/Makefile"};
344
        my $name = substr( $file, length($dir) + 1 );
345 346 347
        my %flags = get_makedep_flags( $file );

        next if $file =~ /^include\/wine\// && !%flags && !$exported_wine_headers{$name};
348

349 350 351 352
        if ($name =~ /\.m$/) { push @{${$make}{"=OBJC_SRCS"}}, $name; }
        elsif ($name =~ /\.l$/) { push @{${$make}{"=LEX_SRCS"}}, $name; }
        elsif ($name =~ /\.y$/) { push @{${$make}{"=BISON_SRCS"}}, $name; }
        elsif ($name =~ /\.svg$/) { push @{${$make}{"=SVG_SRCS"}}, $name; }
353 354 355 356
        elsif ($name =~ /\.sfd$/)
        {
            push @{${$make}{"=FONT_SRCS"}}, $name;
        }
357
        elsif ($name =~ /\.c$/)
358
        {
359
            push @{${$make}{"=C_SRCS"}}, $name;
360
        }
361
        elsif ($name =~ /\.h$/ || $name =~ /\.rh$/ || $name =~ /\.inl$/ || $name =~ /\.x$/)
362
        {
363 364 365 366 367 368 369 370 371 372
            next if $dir ne "include";
        }
        elsif ($name =~ /\.rc$/)
        {
            push @{${$make}{"=RC_SRCS"}}, $name;
        }
        elsif ($name =~ /\.mc$/)
        {
            push @{${$make}{"=MC_SRCS"}}, $name;
        }
373 374 375 376
        elsif ($name =~ /\.po$/)
        {
            push @{${$make}{"=PO_SRCS"}}, $name;
        }
377 378 379 380 381 382 383 384 385 386 387 388
        elsif ($name =~ /\.idl$/)
        {
            die "no makedep flags specified in $file" unless %flags || $dir eq "include";
            push @{${$make}{"=IDL_SRCS"}}, $name;
        }
        elsif ($name =~ /\.man\.in$/)
        {
            push @{${$make}{"=MANPAGES"}}, $name;
        }
        elsif ($name =~ /\.in$/)
        {
            push @{${$make}{"=IN_SRCS"}}, $name;
389
        }
390 391 392 393
        elsif ($name =~ /\.spec$/)
        {
            next unless defined ${$make}{"TESTDLL"};
        }
394
        elsif ($dir ne "loader")  # loader dir contains misc files
395 396 397 398
        {
            next;
        }
        push @{${$make}{"=SOURCES"}}, $name;
399 400
    }

401 402 403
    # preserve shared source files from the parent makefile
    foreach my $file (@makefiles)
    {
404
        my $make = $makefiles{$file};
405 406 407
        my $parent = get_parent_makefile( $file );
        next unless $parent;
        preserve_shared_source_files( $makefiles{$file}, $makefiles{$parent}, "C_SRCS" );
408
        preserve_shared_source_files( $makefiles{$file}, $makefiles{$parent}, "IDL_SRCS" );
409 410 411
        preserve_shared_source_files( $makefiles{$file}, $makefiles{$parent}, "LEX_SRCS" );
        preserve_shared_source_files( $makefiles{$file}, $makefiles{$parent}, "BISON_SRCS" );
    }
412
}
413

414
################################################################
415
# update the makefile list in configure.ac
416

417
sub update_makefiles(@)
418
{
419
    my (@lines);
420

421 422
    foreach my $file (sort @_)
    {
423
        my %make = %{$makefiles{$file}};
424
        my $args = "";
425
        my $is_win16 = $make{"MODULE"} && ($make{"MODULE"} =~ /16$/ || $modules16{$make{"MODULE"}});
426
        if (defined($make{"TESTDLL"}))  # test
427
        {
428 429 430 431
            die "TESTDLL should not be defined in $file" unless $file =~ /\/tests\/Makefile$/;
            die "MODULE should not be defined in $file" if defined $make{"MODULE"};
            die "STATICLIB should not be defined in $file" if defined $make{"STATICLIB"};
            (my $dir = $file) =~ s/^(.*)\/Makefile/$1/;
432
            push @lines, "WINE_CONFIG_TEST($dir)\n";
433 434 435 436 437 438
        }
        elsif (defined($make{"MODULE"}) && $make{"MODULE"} =~ /\.a$/)  # import lib
        {
            die "MODULE should not be defined as static lib in $file" unless $file =~ /^dlls\//;
            die "APPMODE should not be defined in $file" if defined $make{"APPMODE"};
            die "STATICLIB should not be defined in $file" if defined $make{"STATICLIB"};
439
            (my $name = $file) =~ s/^dlls\/(.*)\/Makefile/$1/;
440
            push @lines, "WINE_CONFIG_LIB($name)\n";
441 442 443 444 445 446
        }
        elsif (defined($make{"MODULE"}) && defined($make{"APPMODE"}))  # program
        {
            die "APPMODE should not be defined in $file" unless $file =~ /^programs\//;
            die "STATICLIB should not be defined in $file" if defined $make{"STATICLIB"};
            (my $name = $file) =~ s/^programs\/(.*)\/Makefile/$1/;
447 448 449 450 451 452
            if ($name =~ /\./)
            {
                die "Invalid MODULE in $file" unless $make{"MODULE"} eq $name;
            }
            else
            {
453
                die "Invalid MODULE in $file" unless $make{"MODULE"} eq "$name.exe";
454
            }
455 456
            $args .= ",enable_win16" if $is_win16;
            push @lines, "WINE_CONFIG_PROGRAM($name$args)\n";
457
        }
458
        elsif (defined($make{"MODULE"}))  # dll
459
        {
460 461 462 463
            die "APPMODE should be defined in $file" if $file =~ /^programs\//;
            die "MODULE should not be defined in $file" unless $file =~ /^dlls\//;
            die "STATICLIB should not be defined in $file" if defined $make{"STATICLIB"};
            (my $name = $file) =~ s/^dlls\/(.*)\/Makefile/$1/;
464 465 466 467 468 469
            if ($name =~ /\./)
            {
                die "Invalid MODULE in $file" unless $make{"MODULE"} eq $name;
            }
            else
            {
470
                die "Invalid MODULE in $file" unless $make{"MODULE"} eq "$name.dll";
471
            }
472
            my $implib = $make{"IMPORTLIB"} || "";
473
            die "Invalid IMPORTLIB name in $file" if $implib =~ /\./;
474
            $args .= ",enable_win16" if $is_win16;
475
            push @lines, "WINE_CONFIG_DLL($name$args)\n";
476
        }
477 478
        elsif ($file =~ /^tools.*\/Makefile$/)
        {
479 480
            die "APPMODE should not be defined in $file" if defined $make{"APPMODE"};
            die "STATICLIB should not be defined in $file" if defined $make{"STATICLIB"};
481
            (my $name = $file) =~ s/^(.*)\/Makefile/$1/;
482
            push @lines, "WINE_CONFIG_TOOL($name)\n";
483
        }
484
        elsif ($file =~ /\/Makefile$/)
485
        {
486
            (my $name = $file) =~ s/^(.*)\/Makefile/$1/;
487
            push @lines, "WINE_CONFIG_MAKEFILE($name)\n";
488
        }
489 490
    }

491 492
    # update the source variables in all the makefiles

493
    foreach my $file (sort @_) { replace_makefile_variables( $file ); }
494

495
    push @lines, "dnl End of auto-generated output commands\n";
496
    replace_in_file( "configure.ac", '^WINE_CONFIG_DLL', '^dnl End of auto-generated output commands\n$', @lines);
497 498
}

499

500 501
my $git_dir = $ENV{GIT_DIR} || ".git";
die "needs to be run from a git checkout" unless -d $git_dir;
502

503
my @all_files = split /\0/, `git ls-files -c -z`;
504
map { $ignored_source_files{$_} = 1; } split /\0/, `git ls-files -d -z`;
505
@makefiles = map { (my $ret = $_) =~ s/\.in$//; $ret; } grep /Makefile.in$/, @all_files;
506

507
foreach my $file (sort @makefiles)
508 509 510 511 512
{
    my %make = parse_makefile( $file );
    $makefiles{$file} = \%make;
}

513
assign_sources_to_makefiles( @all_files );
514
update_makefiles( @makefiles );