зеркало из https://github.com/mozilla/gecko-dev.git
479 строки
13 KiB
Perl
Executable File
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
|