1 |
#! /usr/bin/env perl |
2 |
# ***** BEGIN LICENSE BLOCK ***** |
3 |
# Version: MPL 1.1/GPL 2.0/LGPL 2.1 |
4 |
# |
5 |
# The contents of this file are subject to the Mozilla Public License Version |
6 |
# 1.1 (the "License"); you may not use this file except in compliance with |
7 |
# the License. You may obtain a copy of the License at |
8 |
# http://www.mozilla.org/MPL/ |
9 |
# |
10 |
# Software distributed under the License is distributed on an "AS IS" basis, |
11 |
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License |
12 |
# for the specific language governing rights and limitations under the |
13 |
# License. |
14 |
# |
15 |
# The Original Code is mozilla.org code. |
16 |
# |
17 |
# The Initial Developer of the Original Code is |
18 |
# Netscape Communications Corporation. |
19 |
# Portions created by the Initial Developer are Copyright (C) 1999 |
20 |
# the Initial Developer. All Rights Reserved. |
21 |
# |
22 |
# Contributor(s): |
23 |
# |
24 |
# Alternatively, the contents of this file may be used under the terms of |
25 |
# either of the GNU General Public License Version 2 or later (the "GPL"), |
26 |
# or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), |
27 |
# in which case the provisions of the GPL or the LGPL are applicable instead |
28 |
# of those above. If you wish to allow use of your version of this file only |
29 |
# under the terms of either the GPL or the LGPL, and not to allow others to |
30 |
# use your version of this file under the terms of the MPL, indicate your |
31 |
# decision by deleting the provisions above and replace them with the notice |
32 |
# and other provisions required by the GPL or the LGPL. If you do not delete |
33 |
# the provisions above, a recipient may use your version of this file under |
34 |
# the terms of any one of the MPL, the GPL or the LGPL. |
35 |
# |
36 |
# ***** END LICENSE BLOCK ***** |
37 |
|
38 |
# make-makefiles - Quickly create Makefiles for subdirectories. |
39 |
# Also, creates any needed subdirectories. |
40 |
# |
41 |
# usage: make-makefiles [ -t <topsrcdir> -p <print_topsrcdir> -d <depth> ] [ <subdir> | <subdir>/Makefile ] ... |
42 |
|
43 |
# Send comments, improvements, bugs to Steve Lamm (slamm@netscape.com). |
44 |
|
45 |
#$debug = 1; |
46 |
|
47 |
# Determine various tree path variables |
48 |
# |
49 |
($topsrcdir, $ptopsrcdir, $depth, @makefiles) = parse_arguments(@ARGV); |
50 |
|
51 |
$object_fullpath = `pwd`; |
52 |
chdir $depth; |
53 |
$object_root = `pwd`; |
54 |
chomp $object_fullpath; |
55 |
chomp $object_root; |
56 |
|
57 |
# $source_subdir is the path from the object root to where |
58 |
# 'make-makefile' was called. For example, if make-makefile was |
59 |
# called from "mozilla/gfx/src", then $source_subdir would be |
60 |
# "gfx/src/". |
61 |
$source_subdir = "$object_fullpath/"; |
62 |
my $quoted_object_root = quotemeta($object_root); |
63 |
$source_subdir =~ s|^$quoted_object_root/||; |
64 |
|
65 |
# Prefix makefiles with $source_subdir so that paths |
66 |
# will be relative to the top of the object tree. |
67 |
# |
68 |
for $makefile (@makefiles) { |
69 |
$makefile = "$source_subdir$makefile"; |
70 |
} |
71 |
|
72 |
create_directories(@makefiles); |
73 |
|
74 |
# Find the path to the source directory based on how 'make-makefile' |
75 |
# was invoked. The path is either relative to the object directory |
76 |
# or an absolute path. |
77 |
$given_srcdir = find_srcdir($topsrcdir, $depth); |
78 |
$pgiven_srcdir = find_srcdir($ptopsrcdir, $depth); |
79 |
|
80 |
if ($debug) { |
81 |
warn "object_fullpath = $object_fullpath\n"; |
82 |
warn "object_root = $object_root\n"; |
83 |
warn "source_subdir = $source_subdir\n"; |
84 |
warn "makefiles = @makefiles\n"; |
85 |
warn "given_srcdir = $given_srcdir\n"; |
86 |
} |
87 |
|
88 |
@unhandled = update_makefiles($given_srcdir, $pgiven_srcdir, @makefiles); |
89 |
|
90 |
run_config_status(@unhandled); |
91 |
|
92 |
# end of Main |
93 |
############################################################ |
94 |
|
95 |
sub dirname { |
96 |
return $_[0] =~ /(.*)\/.*/ ? "$1" : '.'; |
97 |
} |
98 |
|
99 |
# find_depth: Pull the value of DEPTH out of a Makefile (or Makefile.in) |
100 |
sub find_depth { |
101 |
my $depth = ''; |
102 |
open(MAKEFILE, "<$_[0]") || die "Unable to open $_[0]: $!\n"; |
103 |
while (<MAKEFILE>) { |
104 |
next unless /^DEPTH\s*=\s*(\..*)/; |
105 |
$depth = $1; |
106 |
last; |
107 |
} |
108 |
close MAKEFILE; |
109 |
return $depth; |
110 |
} |
111 |
|
112 |
sub parse_arguments { |
113 |
my @args = @_; |
114 |
my $depth = ''; |
115 |
my $topsrcdir = ''; |
116 |
my $ptopsrcdir; |
117 |
my @makefiles = (); |
118 |
|
119 |
while (1) { |
120 |
if ($args[0] eq '-d') { |
121 |
$depth = $args[1]; |
122 |
shift @args; |
123 |
shift @args; |
124 |
} elsif ($args[0] eq '-t') { |
125 |
$topsrcdir = $args[1]; |
126 |
shift @args; |
127 |
shift @args; |
128 |
} elsif ($args[0] eq '-p') { |
129 |
$ptopsrcdir = $args[1]; |
130 |
shift @args; |
131 |
shift @args; |
132 |
} else { |
133 |
last; |
134 |
} |
135 |
} |
136 |
|
137 |
if ($topsrcdir eq '') { |
138 |
$topsrcdir = $0; # Figure out topsrcdir based on program name. |
139 |
$topsrcdir =~ s|/?build/autoconf/.*$||; |
140 |
} |
141 |
if ($ptopsrcdir eq '') { |
142 |
$ptopsrcdir = $topsrcdir; |
143 |
} |
144 |
if ($depth eq '') { |
145 |
# Use $(DEPTH) in the Makefile or Makefile.in to determine the depth |
146 |
if (-e "Makefile.in") { |
147 |
$depth = find_depth("Makefile.in"); |
148 |
} elsif (-e "Makefile") { |
149 |
$depth = find_depth("Makefile"); |
150 |
} elsif (-e "../Makefile") { |
151 |
$depth = "../".find_depth("../Makefile"); |
152 |
$depth =~ s/\/\.$//; |
153 |
} else { |
154 |
warn "Unable to determine depth (e.g. ../..) to root of objdir tree.\n"; |
155 |
die "No Makefile(.in) present. Try running with '-d <depth>'\n"; |
156 |
} |
157 |
} |
158 |
|
159 |
# Build the list of makefiles to generate |
160 |
# |
161 |
@makefiles = (); |
162 |
my $makefile; |
163 |
foreach $makefile (@args) { |
164 |
$makefile =~ s/\.in$//; |
165 |
$makefile =~ s/\/$//; |
166 |
$makefile =~ /Makefile$/ or $makefile .= "/Makefile"; |
167 |
push @makefiles, "$makefile"; |
168 |
} |
169 |
@makefiles = "Makefile" unless @args; |
170 |
|
171 |
return ($topsrcdir, $ptopsrcdir, $depth, @makefiles); |
172 |
} |
173 |
|
174 |
|
175 |
# Create all the directories at once. |
176 |
# This can be much faster than calling mkdir() for each one. |
177 |
sub create_directories { |
178 |
my @makefiles = @_; |
179 |
my @dirs = (); |
180 |
my $ac_file; |
181 |
foreach $ac_file (@makefiles) { |
182 |
push @dirs, dirname($ac_file); |
183 |
} |
184 |
# Call mkdir with the directories sorted by subdir count (how many /'s) |
185 |
system "mkdir -p ". join(' ', map("\"$_\"", @dirs)) if @dirs; |
186 |
} |
187 |
|
188 |
# Find the top of the source directory |
189 |
# (Assuming that the executable is in $top_srcdir/build/autoconf) |
190 |
sub find_srcdir { |
191 |
my ($ac_given_srcdir, $depth) = @_; |
192 |
|
193 |
if ($debug) { |
194 |
print "ac_given_srcdir = $ac_given_srcdir\n"; |
195 |
print "depth = $depth\n"; |
196 |
} |
197 |
if ($ac_given_srcdir =~ /^\./ and $depth ne '.') { |
198 |
my $quoted_depth = quotemeta($depth); |
199 |
$ac_given_srcdir =~ s|^$quoted_depth/?||; |
200 |
} |
201 |
if ($debug) { |
202 |
print "ac_given_srcdir = $ac_given_srcdir\n"; |
203 |
} |
204 |
$ac_given_srcdir = '.' if $ac_given_srcdir eq ''; |
205 |
return $ac_given_srcdir; |
206 |
} |
207 |
|
208 |
# Output the makefiles. |
209 |
# |
210 |
sub update_makefiles { |
211 |
my ($ac_given_srcdir, $pac_given_srcdir, @makefiles) = @_; |
212 |
my @unhandled=(); |
213 |
|
214 |
my $ac_file; |
215 |
foreach $ac_file (@makefiles) { |
216 |
my $ac_file_in = "$ac_given_srcdir/${ac_file}.in"; |
217 |
my $ac_dir = dirname($ac_file); |
218 |
my $ac_dots = ''; |
219 |
my $ac_dir_suffix = ''; |
220 |
my $srcdir = '.'; |
221 |
my $top_srcdir = '.'; |
222 |
|
223 |
# Determine $srcdir and $top_srcdir |
224 |
# |
225 |
if ($ac_dir ne '.') { |
226 |
$ac_dir_suffix = "/$ac_dir"; |
227 |
$ac_dir_suffix =~ s%^/\./%/%; |
228 |
$ac_dots = $ac_dir_suffix; |
229 |
# Remove .. components from the provided dir suffix, and |
230 |
# also the forward path components they were reversing. |
231 |
my $backtracks = $ac_dots =~ s%\.\.(/|$)%%g; |
232 |
while ($backtracks--) { |
233 |
$ac_dots =~ s%/[^/]*%%; |
234 |
} |
235 |
$ac_dots =~ s%/[^/]*%../%g; |
236 |
} |
237 |
if ($ac_given_srcdir eq '.') { |
238 |
if ($ac_dots ne '') { |
239 |
$top_srcdir = $ac_dots; |
240 |
$top_srcdir =~ s%/$%%; |
241 |
} |
242 |
} elsif ($pac_given_srcdir =~ m%^/% or $pac_given_srcdir =~ m%^.:/%) { |
243 |
$srcdir = "$pac_given_srcdir$ac_dir_suffix"; |
244 |
$top_srcdir = "$pac_given_srcdir"; |
245 |
} else { |
246 |
if ($debug) { |
247 |
print "ac_dots = $ac_dots\n"; |
248 |
print "ac_dir_suffix = $ac_dir_suffix\n"; |
249 |
} |
250 |
$srcdir = "$ac_dots$ac_given_srcdir$ac_dir_suffix"; |
251 |
$top_srcdir = "$ac_dots$ac_given_srcdir"; |
252 |
} |
253 |
|
254 |
if ($debug) { |
255 |
print "ac_dir = $ac_dir\n"; |
256 |
print "ac_file = $ac_file\n"; |
257 |
print "ac_file_in = $ac_file_in\n"; |
258 |
print "srcdir = $srcdir\n"; |
259 |
print "top_srcdir = $top_srcdir\n"; |
260 |
print "cwd = " . `pwd` . "\n"; |
261 |
} |
262 |
|
263 |
# Copy the file and make substitutions. |
264 |
# @srcdir@ -> value of $srcdir |
265 |
# @top_srcdir@ -> value of $top_srcdir |
266 |
# |
267 |
if (-e $ac_file) { |
268 |
next if -M _ < -M $ac_file_in; # Next if Makefile is up-to-date. |
269 |
warn "updating $ac_file\n"; |
270 |
} else { |
271 |
warn "creating $ac_file\n"; |
272 |
} |
273 |
|
274 |
open INFILE, "<$ac_file_in" or do { |
275 |
warn "$0: Cannot read $ac_file_in: No such file or directory\n"; |
276 |
next; |
277 |
}; |
278 |
open OUTFILE, ">$ac_file" or do { |
279 |
warn "$0: Unable to create $ac_file\n"; |
280 |
next; |
281 |
}; |
282 |
|
283 |
while (<INFILE>) { |
284 |
#if (/\@[_a-zA-Z]*\@.*\@[_a-zA-Z]*\@/) { |
285 |
# #warn "Two defines on a line:$ac_file:$.:$_"; |
286 |
# push @unhandled, $ac_file; |
287 |
# last; |
288 |
#} |
289 |
|
290 |
s/\@srcdir\@/$srcdir/g; |
291 |
s/\@top_srcdir\@/$top_srcdir/g; |
292 |
|
293 |
if (/\@[_a-zA-Z]*\@/) { |
294 |
#warn "Unknown variable:$ac_file:$.:$_"; |
295 |
push @unhandled, $ac_file; |
296 |
last; |
297 |
} |
298 |
print OUTFILE; |
299 |
} |
300 |
close INFILE; |
301 |
close OUTFILE; |
302 |
} |
303 |
return @unhandled; |
304 |
} |
305 |
|
306 |
sub run_config_status { |
307 |
my @unhandled = @_; |
308 |
|
309 |
# Run config.status with any unhandled files. |
310 |
# |
311 |
if (@unhandled) { |
312 |
$ENV{CONFIG_FILES}= join ' ', @unhandled; |
313 |
system "./config.status"; |
314 |
} |
315 |
} |