#!/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 # Joey Armstrong # # 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 () { 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 $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 '\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 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 beneath a source directory and path to generated F beneath $MOZ_OBJDIR. DEPTH from destination directory to the 'root' will also be determined. F 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 DEPTH= can be determined in a few different ways: o The string C may be embedded within F. o Search parent directories for F 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 =cut