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 |
if ($^O eq 'msys') { |
48 |
$pwdcmd = 'pwd -W'; |
49 |
} |
50 |
else { |
51 |
$pwdcmd = 'pwd'; |
52 |
} |
53 |
|
54 |
# Determine various tree path variables |
55 |
# |
56 |
($topsrcdir, $ptopsrcdir, $depth, @makefiles) = parse_arguments(@ARGV); |
57 |
|
58 |
$object_fullpath = `$pwdcmd`; |
59 |
chdir $depth; |
60 |
$object_root = `$pwdcmd`; |
61 |
chomp $object_fullpath; |
62 |
chomp $object_root; |
63 |
|
64 |
# $source_subdir is the path from the object root to where |
65 |
# 'make-makefile' was called. For example, if make-makefile was |
66 |
# called from "mozilla/gfx/src", then $source_subdir would be |
67 |
# "gfx/src/". |
68 |
$source_subdir = "$object_fullpath/"; |
69 |
my $quoted_object_root = quotemeta($object_root); |
70 |
$source_subdir =~ s|^$quoted_object_root/||; |
71 |
|
72 |
# Prefix makefiles with $source_subdir so that paths |
73 |
# will be relative to the top of the object tree. |
74 |
# |
75 |
for $makefile (@makefiles) { |
76 |
$makefile = "$source_subdir$makefile"; |
77 |
} |
78 |
|
79 |
create_directories(@makefiles); |
80 |
|
81 |
# Find the path to the source directory based on how 'make-makefile' |
82 |
# was invoked. The path is either relative to the object directory |
83 |
# or an absolute path. |
84 |
$given_srcdir = find_srcdir($topsrcdir, $depth); |
85 |
$pgiven_srcdir = find_srcdir($ptopsrcdir, $depth); |
86 |
|
87 |
if ($debug) { |
88 |
warn "object_fullpath = $object_fullpath\n"; |
89 |
warn "object_root = $object_root\n"; |
90 |
warn "source_subdir = $source_subdir\n"; |
91 |
warn "makefiles = @makefiles\n"; |
92 |
warn "given_srcdir = $given_srcdir\n"; |
93 |
} |
94 |
|
95 |
@unhandled = update_makefiles($given_srcdir, $pgiven_srcdir, @makefiles); |
96 |
|
97 |
run_config_status(@unhandled); |
98 |
|
99 |
# end of Main |
100 |
############################################################ |
101 |
|
102 |
sub dirname { |
103 |
return $_[0] =~ /(.*)\/.*/ ? "$1" : '.'; |
104 |
} |
105 |
|
106 |
# find_depth: Pull the value of DEPTH out of a Makefile (or Makefile.in) |
107 |
sub find_depth { |
108 |
my $depth = ''; |
109 |
open(MAKEFILE, "<$_[0]") || die "Unable to open $_[0]: $!\n"; |
110 |
while (<MAKEFILE>) { |
111 |
next unless /^DEPTH\s*=\s*(\..*)/; |
112 |
$depth = $1; |
113 |
last; |
114 |
} |
115 |
close MAKEFILE; |
116 |
return $depth; |
117 |
} |
118 |
|
119 |
sub parse_arguments { |
120 |
my @args = @_; |
121 |
my $depth = ''; |
122 |
my $topsrcdir = ''; |
123 |
my $ptopsrcdir; |
124 |
my @makefiles = (); |
125 |
|
126 |
while (1) { |
127 |
if ($args[0] eq '-d') { |
128 |
$depth = $args[1]; |
129 |
shift @args; |
130 |
shift @args; |
131 |
} elsif ($args[0] eq '-t') { |
132 |
$topsrcdir = $args[1]; |
133 |
shift @args; |
134 |
shift @args; |
135 |
} elsif ($args[0] eq '-p') { |
136 |
$ptopsrcdir = $args[1]; |
137 |
shift @args; |
138 |
shift @args; |
139 |
} else { |
140 |
last; |
141 |
} |
142 |
} |
143 |
|
144 |
if ($topsrcdir eq '') { |
145 |
$topsrcdir = $0; # Figure out topsrcdir based on program name. |
146 |
$topsrcdir =~ s|/?build/autoconf/.*$||; |
147 |
} |
148 |
if ($ptopsrcdir eq '') { |
149 |
$ptopsrcdir = $topsrcdir; |
150 |
} |
151 |
if ($depth eq '') { |
152 |
# Use $(DEPTH) in the Makefile or Makefile.in to determine the depth |
153 |
if (-e "Makefile.in") { |
154 |
$depth = find_depth("Makefile.in"); |
155 |
} elsif (-e "Makefile") { |
156 |
$depth = find_depth("Makefile"); |
157 |
} elsif (-e "../Makefile") { |
158 |
$depth = "../".find_depth("../Makefile"); |
159 |
$depth =~ s/\/\.$//; |
160 |
} else { |
161 |
warn "Unable to determine depth (e.g. ../..) to root of objdir tree.\n"; |
162 |
die "No Makefile(.in) present. Try running with '-d <depth>'\n"; |
163 |
} |
164 |
} |
165 |
|
166 |
# Build the list of makefiles to generate |
167 |
# |
168 |
@makefiles = (); |
169 |
my $makefile; |
170 |
foreach $makefile (@args) { |
171 |
$makefile =~ s/\.in$//; |
172 |
$makefile =~ s/\/$//; |
173 |
$makefile =~ /Makefile$/ or $makefile .= "/Makefile"; |
174 |
push @makefiles, "$makefile"; |
175 |
} |
176 |
@makefiles = "Makefile" unless @args; |
177 |
|
178 |
return ($topsrcdir, $ptopsrcdir, $depth, @makefiles); |
179 |
} |
180 |
|
181 |
|
182 |
# Create all the directories at once. |
183 |
# This can be much faster than calling mkdir() for each one. |
184 |
sub create_directories { |
185 |
my @makefiles = @_; |
186 |
my @dirs = (); |
187 |
my $ac_file; |
188 |
foreach $ac_file (@makefiles) { |
189 |
push @dirs, dirname($ac_file); |
190 |
} |
191 |
# Call mkdir with the directories sorted by subdir count (how many /'s) |
192 |
system "mkdir -p ". join(' ', map("\"$_\"", @dirs)) if @dirs; |
193 |
} |
194 |
|
195 |
# Find the top of the source directory |
196 |
# (Assuming that the executable is in $top_srcdir/build/autoconf) |
197 |
sub find_srcdir { |
198 |
my ($ac_given_srcdir, $depth) = @_; |
199 |
|
200 |
if ($debug) { |
201 |
print "ac_given_srcdir = $ac_given_srcdir\n"; |
202 |
print "depth = $depth\n"; |
203 |
} |
204 |
if ($ac_given_srcdir =~ /^\./ and $depth ne '.') { |
205 |
my $quoted_depth = quotemeta($depth); |
206 |
$ac_given_srcdir =~ s|^$quoted_depth/?||; |
207 |
} |
208 |
if ($debug) { |
209 |
print "ac_given_srcdir = $ac_given_srcdir\n"; |
210 |
} |
211 |
$ac_given_srcdir = '.' if $ac_given_srcdir eq ''; |
212 |
return $ac_given_srcdir; |
213 |
} |
214 |
|
215 |
# Output the makefiles. |
216 |
# |
217 |
sub update_makefiles { |
218 |
my ($ac_given_srcdir, $pac_given_srcdir, @makefiles) = @_; |
219 |
my @unhandled=(); |
220 |
|
221 |
my $ac_file; |
222 |
foreach $ac_file (@makefiles) { |
223 |
my $ac_file_in = "$ac_given_srcdir/${ac_file}.in"; |
224 |
my $ac_dir = dirname($ac_file); |
225 |
my $ac_dots = ''; |
226 |
my $ac_dir_suffix = ''; |
227 |
my $srcdir = '.'; |
228 |
my $top_srcdir = '.'; |
229 |
|
230 |
# Determine $srcdir and $top_srcdir |
231 |
# |
232 |
if ($ac_dir ne '.') { |
233 |
$ac_dir_suffix = "/$ac_dir"; |
234 |
$ac_dir_suffix =~ s%^/\./%/%; |
235 |
$ac_dots = $ac_dir_suffix; |
236 |
# Remove .. components from the provided dir suffix, and |
237 |
# also the forward path components they were reversing. |
238 |
my $backtracks = $ac_dots =~ s%\.\.(/|$)%%g; |
239 |
while ($backtracks--) { |
240 |
$ac_dots =~ s%/[^/]*%%; |
241 |
} |
242 |
$ac_dots =~ s%/[^/]*%../%g; |
243 |
} |
244 |
if ($ac_given_srcdir eq '.') { |
245 |
if ($ac_dots ne '') { |
246 |
$top_srcdir = $ac_dots; |
247 |
$top_srcdir =~ s%/$%%; |
248 |
} |
249 |
} elsif ($pac_given_srcdir =~ m%^/% or $pac_given_srcdir =~ m%^.:/%) { |
250 |
$srcdir = "$pac_given_srcdir$ac_dir_suffix"; |
251 |
$top_srcdir = "$pac_given_srcdir"; |
252 |
} else { |
253 |
if ($debug) { |
254 |
print "ac_dots = $ac_dots\n"; |
255 |
print "ac_dir_suffix = $ac_dir_suffix\n"; |
256 |
} |
257 |
$srcdir = "$ac_dots$ac_given_srcdir$ac_dir_suffix"; |
258 |
$top_srcdir = "$ac_dots$ac_given_srcdir"; |
259 |
} |
260 |
|
261 |
if ($debug) { |
262 |
print "ac_dir = $ac_dir\n"; |
263 |
print "ac_file = $ac_file\n"; |
264 |
print "ac_file_in = $ac_file_in\n"; |
265 |
print "srcdir = $srcdir\n"; |
266 |
print "top_srcdir = $top_srcdir\n"; |
267 |
print "cwd = " . `$pwdcmd` . "\n"; |
268 |
} |
269 |
|
270 |
# Copy the file and make substitutions. |
271 |
# @srcdir@ -> value of $srcdir |
272 |
# @top_srcdir@ -> value of $top_srcdir |
273 |
# |
274 |
if (-e $ac_file) { |
275 |
next if -M _ < -M $ac_file_in; # Next if Makefile is up-to-date. |
276 |
warn "updating $ac_file\n"; |
277 |
} else { |
278 |
warn "creating $ac_file\n"; |
279 |
} |
280 |
|
281 |
open INFILE, "<$ac_file_in" or do { |
282 |
warn "$0: Cannot read $ac_file_in: No such file or directory\n"; |
283 |
next; |
284 |
}; |
285 |
open OUTFILE, ">$ac_file" or do { |
286 |
warn "$0: Unable to create $ac_file\n"; |
287 |
next; |
288 |
}; |
289 |
|
290 |
while (<INFILE>) { |
291 |
#if (/\@[_a-zA-Z]*\@.*\@[_a-zA-Z]*\@/) { |
292 |
# #warn "Two defines on a line:$ac_file:$.:$_"; |
293 |
# push @unhandled, $ac_file; |
294 |
# last; |
295 |
#} |
296 |
|
297 |
s/\@srcdir\@/$srcdir/g; |
298 |
s/\@top_srcdir\@/$top_srcdir/g; |
299 |
|
300 |
if (/\@[_a-zA-Z]*\@/) { |
301 |
#warn "Unknown variable:$ac_file:$.:$_"; |
302 |
push @unhandled, $ac_file; |
303 |
last; |
304 |
} |
305 |
print OUTFILE; |
306 |
} |
307 |
close INFILE; |
308 |
close OUTFILE; |
309 |
} |
310 |
return @unhandled; |
311 |
} |
312 |
|
313 |
sub run_config_status { |
314 |
my @unhandled = @_; |
315 |
|
316 |
# Run config.status with any unhandled files. |
317 |
# |
318 |
if (@unhandled) { |
319 |
$ENV{CONFIG_FILES}= join ' ', @unhandled; |
320 |
system "./config.status"; |
321 |
} |
322 |
} |