make_makefiles 14.7 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
my %exported_wine_headers = (
    "wine/debug.h" => 1,
    "wine/exception.h" => 1,
    "wine/library.h" => 1,
    "wine/itss.idl" => 1,
    "wine/svcctl.idl" => 1,
47 48
);

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

58 59 60 61 62 63 64 65 66 67 68 69 70
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",
71
    "SOURCES",
72 73 74 75
    "SVG_SRCS",
    "XTEMPLATE_SRCS"
);

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

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

86
# update a file if changed
87
sub update_file($$)
88 89
{
    my $file = shift;
90 91 92 93 94 95 96 97
    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")
98
    {
99 100
        system "autoconf";
        print "configure updated\n";
101 102 103 104 105 106 107 108 109
    }
}

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

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

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

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

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

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

    open OLD_FILE, "$file.in" or die "cannot open $file.in";
    while (<OLD_FILE>)
    {
147
        $old .= $_;
148
        if (/^\s*($source_vars_regexp)(\s*)=/)
149 150
        {
            # try to preserve formatting
151 152 153 154 155 156 157 158 159 160 161 162 163 164
            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};
            }
165
            my $multiline = /\\$/ || (@values > 1);
166
            my $old_str = $_;
167 168 169 170
            while (/\\$/)
            {
                $_ = <OLD_FILE>;
                last unless $_;
171
                $old .= $_;
172
                $old_str .= $_;
173
            }
174
            my $new_str = "";
175 176 177 178 179
            if (!@values)
            {
                # nothing
            }
            elsif ($multiline)
180
            {
181
                $new_str = "$var = \\\n\t" . join(" \\\n\t", sort @values) . "\n";
182
                $new .= $new_str;
183 184 185
            }
            else
            {
186
                $new_str = "$var$spaces= @values\n";
187
                $new .= $new_str;
188
            }
189
            $replaced{$var} = 1;
190 191
            next;
        }
192
        $new .= $_;
193
    }
194 195
    # if we are using SOURCES, ignore the other variables
    unless ($replaced{"SOURCES"})
196
    {
197 198 199 200 201 202 203 204 205
        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";
        }
206
    }
207
    close OLD_FILE;
208
    update_file("$file.in", $new) if $old ne $new;
209 210
}

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

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

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

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

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

252
    return %make;
253
}
254

255 256 257 258 259 260 261
# 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";
262
    if ($file =~ /\.sfd$/)
263
    {
264
        while (<FILE>)
265
        {
266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287
            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;
            }
288 289 290 291 292 293
        }
    }
    close FILE;
    return %flags;
}

294 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
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;
    }
}

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

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

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

        my $make = $makefiles{"$dir/Makefile"};
343
        my $name = substr( $file, length($dir) + 1 );
344

345
        next if $file =~ /^include\/wine\// && !get_makedep_flags($file) && !$exported_wine_headers{$name};
346

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

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

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

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

420 421
    foreach my $file (sort @_)
    {
422
        next if $file eq "Makefile";
423
        my %make = %{$makefiles{$file}};
424
        (my $dir = $file) =~ s/^(.*)\/Makefile/$1/;
425
        my $args = "";
426
        if (defined($make{"TESTDLL"}))  # test
427
        {
428 429 430 431 432 433 434 435 436 437
            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"};
        }
        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"};
        }
438
        elsif (defined($make{"MODULE"}))  # dll or program
439
        {
440
            (my $name = $file) =~ s/^(dlls|programs)\/(.*)\/Makefile/$2/;
441 442
            my $dllflags = $make{"EXTRADLLFLAGS"} || "";
            if (defined $make{"APPMODE"}) { $dllflags .= " " . $make{"APPMODE"}; }
443
            die "MODULE should not be defined in $file" unless $file =~ /^(dlls|programs)\//;
444
            die "STATICLIB should not be defined in $file" if defined $make{"STATICLIB"};
445 446
            die "Invalid MODULE in $file" if $name =~ /\./ && $make{"MODULE"} ne $name;
            if ($file =~ /^programs\//)
447
            {
448 449
                die "EXTRADLLFLAGS should be defined in $file" unless $dllflags;
                die "EXTRADLLFLAGS should contain -mconsole or -mwindows in $file" unless $dllflags =~ /-m(console|windows)/;
450
                die "Invalid MODULE in $file" unless $name =~ /\./ || $make{"MODULE"} eq "$name.exe";
451 452 453
            }
            else
            {
454
                die "APPMODE should not be defined in $file" if defined $make{"APPMODE"} ;
455
                die "EXTRADLLFLAGS should not contain -mconsole or -mwindows in $file" if $dllflags =~ /-m(console|windows)/;
456
                die "Invalid MODULE in $file" unless $name =~ /\./ || $make{"MODULE"} eq "$name.dll";
457
            }
458
            if (defined $make{"IMPORTLIB"})
459
            {
460 461
                die "IMPORTLIB not allowed in programs\n" if $file =~ /^programs\//;
                die "Invalid IMPORTLIB name in $file" if $make{"IMPORTLIB"} =~ /\./;
462
            }
463
            $args = ",enable_win16" if $make{"MODULE"} =~ /16$/ || $modules16{$make{"MODULE"}};
464
        }
465 466
        elsif ($file =~ /^tools.*\/Makefile$/)
        {
467
            die "APPMODE should not be defined in $file" if defined $make{"APPMODE"};
468
            die "EXTRADLLFLAGS should not be defined in $file" if defined $make{"EXTRADLLFLAGS"};
469
            die "STATICLIB should not be defined in $file" if defined $make{"STATICLIB"};
470
            $args = ",,[test \"x\$enable_tools\" = xno]";
471
        }
472
        push @lines, "WINE_CONFIG_MAKEFILE($dir$args)\n";
473 474
    }

475 476
    # update the source variables in all the makefiles

477
    foreach my $file (sort @_) { replace_makefile_variables( $file ); }
478

479
    push @lines, "dnl End of auto-generated output commands\n";
480
    replace_in_file( "configure.ac", '^WINE_CONFIG_MAKEFILE', '^dnl End of auto-generated output commands\n$', @lines);
481 482
}

483

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

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

491
foreach my $file (sort @makefiles)
492 493 494 495 496
{
    my %make = parse_makefile( $file );
    $makefiles{$file} = \%make;
}

497
assign_sources_to_makefiles( @all_files );
498
update_makefiles( @makefiles );