pjs/build/autoconf/make-makefile

479 строки
13 KiB
Perl
Executable File

#!/usr/bin/env perl
# ***** BEGIN LICENSE BLOCK *****
# Version: MPL 1.1/GPL 2.0/LGPL 2.1
#
# The contents of this file are subject to the Mozilla Public License Version
# 1.1 (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
# http://www.mozilla.org/MPL/
#
# Software distributed under the License is distributed on an "AS IS" basis,
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
# for the specific language governing rights and limitations under the
# License.
#
# The Original Code is mozilla.org code.
#
# The Initial Developer of the Original Code is
# Netscape Communications Corporation.
# Portions created by the Initial Developer are Copyright (C) 1999-2011
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Steve Lamm <slamm@netscape.com>
# Joey Armstrong <joey@mozilla.com>
#
# Alternatively, the contents of this file may be used under the terms of
# either of the GNU General Public License Version 2 or later (the "GPL"),
# or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
# in which case the provisions of the GPL or the LGPL are applicable instead
# of those above. If you wish to allow use of your version of this file only
# under the terms of either the GPL or the LGPL, and not to allow others to
# use your version of this file under the terms of the MPL, indicate your
# decision by deleting the provisions above and replace them with the notice
# and other provisions required by the GPL or the LGPL. If you do not delete
# the provisions above, a recipient may use your version of this file under
# the terms of any one of the MPL, the GPL or the LGPL.
#
# ***** END LICENSE BLOCK *****
##----------------------------##
##---] CORE/CPAN INCLUDES [---##
##----------------------------##
use strict;
use warnings;
use Getopt::Long;
use Benchmark;
use Cwd;
use File::Basename;
use File::Copy;
use File::Path qw{mkpath};
##-------------------##
##---] EXPORTS [---##
##-------------------##
our $VERSION = qw(2.0);
##--------------------##
##---] INCLUDES [---##
##--------------------##
##############################################################
# pymake: special case path handling for windows cmd shell.
# if invoked by cmd.exe and msys-perl is in play
# $0 may contain a drive letter
# modules use-or-expect msys/unix paths
# adjust $0 => C:/foo => /c/foo so string tests and
# manipulation can by applied properly.
##############################################################
sub BEGIN
{
if ($^O eq 'msys' && $ENV{PATH} =~ m!\w:/!)
{
$0 =~ s!^(\w):!/$1!;
}
eval 'use FindBin';
die $@ if ($@);
}
use lib $FindBin::Bin;
use makemakefile;
##-------------------##
##---] GLOBALS [---##
##-------------------##
my %argv;
my $t0 = Benchmark->new();
sub END
{
if ($argv{bench})
{
my $t1 = Benchmark->new();
my $delta = timediff($t1, $t0);
print STDERR timestr($delta), "\n";
}
}
##----------------##
##---] MAIN [---##
##----------------##
umask 0;
my $debug = $argv{debug} || 0;
my $pwdcmd = ($^O eq 'msys') ? 'pwd -W' : 'pwd';
# Determine various tree path variables
#
my ($topsrcdir, $ptopsrcdir, $depth, @makefiles) = parse_arguments(@ARGV);
my $object_fullpath = `$pwdcmd`; # Cwd::getcwd()
chdir $depth;
my $object_root = `$pwdcmd`; # Cwd::getcwd()
chomp $object_fullpath;
chomp $object_root;
# $source_subdir is the path from the object root to where
# 'make-makefile' was called. For example, if make-makefile was
# called from "mozilla/gfx/src", then $source_subdir would be
# "gfx/src/".
my $source_subdir = "$object_fullpath/";
my $quoted_object_root = quotemeta($object_root);
$source_subdir =~ s|^$quoted_object_root/||;
# Prefix makefiles with $source_subdir so that paths
# will be relative to the top of the object tree.
#
my $makefile;
for $makefile (@makefiles) { # dead code ?
$makefile = "$source_subdir$makefile";
}
# Find the path to the source directory based on how 'make-makefile'
# was invoked. The path is either relative to the object directory
# or an absolute path.
my $given_srcdir = find_srcdir($topsrcdir, $depth);
my $pgiven_srcdir = find_srcdir($ptopsrcdir, $depth);
if ($debug) {
warn "object_fullpath = $object_fullpath\n";
warn "object_root = $object_root\n";
warn "source_subdir = $source_subdir\n";
warn "makefiles = @makefiles\n";
warn "given_srcdir = $given_srcdir\n";
}
my @errors;
my @unhandled = update_makefiles_legacy($given_srcdir, $pgiven_srcdir, @makefiles);
push(@errors, $@) if ($@);
run_config_status(@unhandled);
push(@errors, $@) if ($@ && $argv{'no-warnings'});
exit scalar(@errors);
# end of Main
############################################################
###########################################################################
# find_depth: Pull the value of DEPTH out of a Makefile (or Makefile.in)
###########################################################################
sub find_depth {
my $depth = '';
open(MAKEFILE, "<$_[0]") || die "Unable to open $_[0]: $!\n";
while (<MAKEFILE>) {
next unless /^DEPTH\s*=\s*(\..*)/;
$depth = $1;
last;
}
close MAKEFILE;
return $depth;
}
###########################################################################
## Intent: Parse command line arguments and assign values
###########################################################################
sub parse_arguments {
my @args = @_;
my @makefiles = ();
my @arglist = qw(badtokens! bench
chdir=s
debug
depth|d=s
enhanced
obj=s top|t=s ptop|p=s
src=s dst=s
);
unless(GetOptions(\%argv, @arglist))
{
my $script = join('/', $FindBin::RealBin, $FindBin::Script);
system("perldoc $script </dev/null");
exit
}
@args = @ARGV;
my $topsrcdir = $argv{top} || '';
if (! $topsrcdir)
{
$topsrcdir = $argv{top} = getTopDir();
}
my $ptopsrcdir ||= $argv{ptop} || $topsrcdir || '';
## Init --no- switch values
foreach my $var (qw(badtokens exclusions warnings))
{
$argv{"no-${var}"} = $argv{$var} || 0;
}
# Propogate parsed arguments for module use [--debug, --verbose]
while (my($k, $v) = each %argv)
{
$main::argv{$k} = $v;
}
if ($argv{chdir})
{
chdir $argv{chdir} || die "chdir $argv{chdir} failed: $!";
}
##############################################################
## Arguments allowing make-makefile to be invoked from $topsrc
##############################################################
if (!$argv{top} || !$argv{obj})
{
}
## Limit access to container makefiles for now
elsif ($argv{enhanced})
{
my @errors;
## iterate over @ARGV to preserve original filename for 'unhandled'
my @files = map{ getRelPath($_) } @ARGV;
my $top = getTopDir();
my $obj = getObjDir();
mkdirr(map{ "$obj/$_" } @files);
push(@errors, $@) if ($@); # legacy behavior: do not exit with status
my $exclude = join('/', $FindBin::RealBin, $FindBin::Script);
$exclude .= '.excl'; # $argv{exclude}
my %exclude = getExclusions($exclude);
my @unhandled;
foreach my $relpath (@files)
{
my $rel = join('/', $relpath, 'Makefile.in');
my $mf = join('/', $top, $rel);
next if ($exclude{$rel});
print STDERR " ** relpath=[$relpath], mf=[$mf]\n" if ($main::argv{debug});
my $rc = updateMakefiles($relpath, {depth=>$depth, obj=>$obj, top=>$top});
if ($@)
{
push(@errors, $@);
}
elsif ($rc eq 'badtokens')
{
push(@unhandled, $mf);
}
}
run_config_status(@unhandled);
push(@errors, $@) if ($@ && $argv{'no-warnings'});
exit scalar(@errors);
}
my $depth = $argv{depth} || '';
if (! $depth)
{
foreach my $fyl (@args)
{
if (my $tmp = find_depth($fyl))
{
$depth = $tmp;
last;
}
}
}
if (! $depth) {
# Use $(DEPTH) in the Makefile or Makefile.in to determine the depth
if (-e "Makefile.in") {
$depth = find_depth("Makefile.in");
} elsif (-e "Makefile") {
$depth = find_depth("Makefile");
} elsif (-e "../Makefile") {
$depth = "../".find_depth("../Makefile");
$depth =~ s/\/\.$//;
} else {
warn "Unable to determine depth (e.g. ../..) to root of objdir tree.\n";
die "No Makefile(.in) present. Try running with '-d <depth>'\n";
}
}
# Build the list of makefiles to generate
#
@makefiles = ();
while (@args)
{
next unless my $makefile = shift @args;
$makefile =~ s/\.in$//;
$makefile =~ s/\/$//;
$makefile =~ /Makefile$/
or $makefile =~ /^\.\//
or $makefile .= "/Makefile";
push @makefiles, "$makefile";
}
@makefiles = "Makefile" unless @makefiles;
return ($topsrcdir, $ptopsrcdir, $depth, @makefiles);
}
# Find the top of the source directory
# (Assuming that the executable is in $top_srcdir/build/autoconf)
sub find_srcdir {
my ($ac_given_srcdir, $depth) = @_;
if ($debug) {
print "ac_given_srcdir = $ac_given_srcdir\n";
print "depth = $depth\n";
}
if ($ac_given_srcdir =~ /^\./ and $depth ne '.') {
my $quoted_depth = quotemeta($depth);
$ac_given_srcdir =~ s|^$quoted_depth/?||;
}
if ($debug) {
print "ac_given_srcdir = $ac_given_srcdir\n";
}
$ac_given_srcdir = '.' if $ac_given_srcdir eq '';
return $ac_given_srcdir;
}
1;
###########################################################################
## perldoc
###########################################################################
__END__
=head1 NAME
make-makefile - Generate a Makefile from a F<Makefile.in> template
=head1 SYNOPSIS
make-makefile [--top t] [--obj o] [--depth d] foo/bar/Makefile.in tans/fans/Makefile foo/bar
=head1 DESCRIPTION
Given options and makefile path arguments determine path to the template
F<Makefile.in> beneath a source directory and path to generated F<Makefile>
beneath $MOZ_OBJDIR. DEPTH from destination directory to the 'root' will
also be determined. F<Makefile.in> will be read in, template strings of the
gorm @token@ will be replaced with derived values and a generated makefile
will be written out as F<Makefile>.
Makefile DEPTH= can be determined in a few different ways:
o The string C<DEPTH=../../..> may be embedded within F<Makefile.in>.
o Search parent directories for F<Makefile.in> and use it to assign the child.
=head2 Option List
=over 4
=item --chdir
Move to this directory before doing anything else
=item -d, --depth
Explicitly specify the relative path from directory containing Makefile.in
to the top sandbox directory. memory/makefile, DEPTH=../.., js/src/config, DEPTH=..
=item --enhanced
Use alternate/simplified path construction when options --top and --obj are
passed. This feature will be used by container makefiles to support makefile
generation while cd'd into the sandbox top directory.
=item -t, --top
Path the root of a development sandbox.
=item --obj
Path to object directory where generated makefile will be written ($MOZ_OBJDIR).
=item --ptop
Print top source dir
=back
=head2 Options List DEBUG
=over 4
=item --bench
Enable script benchmarking, report elapsed runtime.
=item --debug
Enable script debug mode.
=back
=head2 Options List --NO-
=over 4
=item --no-badtokens (wip)
Handle unexpanded @token@ makefile tokens as an error condition.
Do not rely on system(config.status) to externally supply values.
=item --no-excludes
Ignore file entries on the exclusion list, generate everything.
=item --no-warnings
Warnings are handled as an error condition.
=back
=head2 Examples
=over 4
=item * make-makefile -t /mozilla/nightly -d . memory/mozalloc
cd $MOZ_OBJDIR;
--top and --depth are explicitly set for generting memory/mozalloc/Makefile.
=item * make-makefile -t /mozilla/nightly -d ../../../.. html5lib_tree_construction/Makefile
cd $MOZ_OBJDIR/parser/htmlparser/tests/mochitest
--top and --depth are explicitly set for generting a makefile from within
a subdirectory of $MOZ_OBJDIR
=item * make-makefile --top /mozilla/nightly --obj /mozilla/nightly/obj memory/mozalloc
With --top and --obj explicitly set generate $MOZ_OBJDIR/memory/mozalloc/Makefile
while sitting in the sandbox root.
=back
=head2 Work In Progress
=over 4
=item --no-badtokens
Fail on unexpanded @foo@ makefile tokens. Any tokens that can be expanded
directly by make-makefile will avoid config.status shell overhead.
=item Depth from delta(--obj, --top)
If DEPTH= has not been embedded within a makefile the value could
be set directly if --top and --obj are specified and the paths overlap.
=back
=head1 SEE ALSO
L<config/rules.mk>
=cut