summaryrefslogtreecommitdiffabout
authorSergey Poznyakoff <gray@gnu.org>2016-07-30 07:14:19 (GMT)
committer Sergey Poznyakoff <gray@gnu.org>2016-07-30 07:19:04 (GMT)
commit71e51308e7fe0136b76799f5e6dbbec94e279f46 (patch) (unidiff)
tree820ee704751fd7a498464ecfb5c42ea6da530ead
parentbde49d719c1894d0e502a73d42ab546d905492f2 (diff)
downloaddico-71e51308e7fe0136b76799f5e6dbbec94e279f46.tar.gz
dico-71e51308e7fe0136b76799f5e6dbbec94e279f46.tar.bz2
Rename modinc to bootstrap.modinc
* modinc: Rename to bootstrap. * bootstrap: Add generic bootstrapping code. * stub.ac: Rename to configure.boot. * Makefile.am: Fix EXTRA_DIST * README-hacking: Document bootstrap.
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--Makefile.am4
-rw-r--r--README-hacking36
-rwxr-xr-xbootstrap807
-rw-r--r--configure.boot (renamed from stub.ac)10
-rwxr-xr-xmodinc641
5 files changed, 813 insertions, 685 deletions
diff --git a/Makefile.am b/Makefile.am
index a157141..fa15921 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1,5 +1,5 @@
1# This file is part of GNU Dico 1# This file is part of GNU Dico
2# Copyright (C) 1998-2000, 2008-2010, 2012 Sergey Poznyakoff 2# Copyright (C) 1998-2000, 2008-2010, 2012, 2016 Sergey Poznyakoff
3# 3#
4# GNU Dico is free software; you can redistribute it and/or modify 4# GNU Dico is free software; you can redistribute it and/or modify
5# it under the terms of the GNU General Public License as published by 5# it under the terms of the GNU General Public License as published by
@@ -34,7 +34,7 @@ SUBDIRS=\
34 po 34 po
35#FIXME: add these when ready: makedict client fonts 35#FIXME: add these when ready: makedict client fonts
36 36
37EXTRA_DIST = ChangeLog.2008 stub.ac modinc 37EXTRA_DIST = ChangeLog.2008 configure.boot bootstrap
38 38
39dist-hook: 39dist-hook:
40 tar -C $(srcdir) -c -f - --exclude-vcs app dicoweb | \ 40 tar -C $(srcdir) -c -f - --exclude-vcs app dicoweb | \
diff --git a/README-hacking b/README-hacking
index 74cb866..7037357 100644
--- a/README-hacking
+++ b/README-hacking
@@ -42,39 +42,43 @@ which are extracted from other source packages:
42 42
43 ./bootstrap 43 ./bootstrap
44 44
45Use one or more --verbose options to see details about its progress.
46
45Once done, proceed as described in the file README (section 47Once done, proceed as described in the file README (section
46INSTALLATION). 48INSTALLATION).
47 49
48Normally you will have to run bootstrap only once. However, if you
49intend to hack on Dico, you might need to run it again later. In
50this case, you will probably want to save some time and bandwidth by
51avoiding downloading the same files again. If so, create in the project's
52root directory a file named `.bootstrap' with the following
53contents:
54
55 --gnulib-srcdir=$HOME/gnulib
56
57Replace `$HOME/gnulib' with the actual directory where the Gnulib
58sources reside.
59
60For more information about `bootstrap', run `bootstrap --help'. 50For more information about `bootstrap', run `bootstrap --help'.
61 51
62* Debugging 52* Debugging
63 53
64To debug dictd, use the following command: 54To debug dicod, use the following command:
65 55
66 libtool --mode execute gdb dictd 56 libtool --mode execute gdb dicod
67 57
68For debugging from Emacs run: 58For debugging from Emacs run:
69 59
70 M-x gdb RET gud-wrapper dictd RET 60 M-x gdb RET gud-wrapper dicod RET
71 61
72(the script gud-wrapper is located in the ./utils subdirectory) 62(the script gud-wrapper is located in the ./utils subdirectory)
73 63
64* Adding new modules
65
66If you want to add a new module to Dico (e.g. named `foo'), run the
67following command from the Dico source tree topmost directory:
68
69 ./bootstrap --add foo
70
71This will create the directory modules/foo, populate it with the
72necessary files, and add the appropriate statements to configure.ac
73and modules/Makefile.am files.
74
75After running this command, change to the modules/foo directory and
76start hacking on your new module.
77
74 78
75* Copyright information 79* Copyright information
76 80
77Copyright (C) 2008, 2010, 2012 Sergey Poznyakoff 81Copyright (C) 2008, 2010, 2012, 2016 Sergey Poznyakoff
78 82
79 Permission is granted to anyone to make or distribute verbatim copies 83 Permission is granted to anyone to make or distribute verbatim copies
80 of this document as received, in any medium, provided that the 84 of this document as received, in any medium, provided that the
diff --git a/bootstrap b/bootstrap
index 7589553..5a3ce01 100755
--- a/bootstrap
+++ b/bootstrap
@@ -1,23 +1,784 @@
1#! /bin/sh 1#! /usr/bin/perl
2 2# This file is part of GNU Dico
3chksrc() { 3# Copyright (C) 2014, 2016 Sergey Poznyakoff
4 test -f modinc || return 1 4#
5 test -f stub.ac || return 1 5# GNU Dico is free software; you can redistribute it and/or modify
6 src=`sed -n 's/AC_CONFIG_SRCDIR(\[\(.*\)\]).*/\1/p' stub.ac` 6# it under the terms of the GNU General Public License as published by
7 test -n "$src" || return 1 7# the Free Software Foundation; either version 3, or (at your option)
8 test -f $src 8# any later version.
9} 9#
10 10# GNU Dico is distributed in the hope that it will be useful,
11if ! chksrc; then 11# but WITHOUT ANY WARRANTY; without even the implied warranty of
12 echo "$0: must be run from the Dico source tree root directory" 12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 exit 1 13# GNU General Public License for more details.
14fi 14#
15 15# You should have received a copy of the GNU General Public License
16set -e 16# along with GNU Dico. If not, see <http://www.gnu.org/licenses/>.
17git submodule init 17
18git submodule update 18=head1 NAME
19./modinc 19
20set +e 20bootstrap - Bootstrap the Dico project
21gnulib=gnulibinit 21
22test -L $gnulib || ln -sf ./gnulib/build-aux/bootstrap $gnulib 22=head1 SYNOPSIS
23./$gnulib 23
24B<bootstrap>
25[B<-ahmnv>]
26[B<--add>]
27[B<--help>]
28[B<--new>]
29[B<--modules>]
30[B<--dry-run>]
31[B<--verbose>]
32[I<NAME>...]
33
34=head1 DESCRIPTION
35
36Bootstrap the Dico project. This is the first command that should be run
37after cloning the project from the repository in order to be able to built
38it.
39
40When run without arguments performs the following actions:
41
42=over 4
43
44=item 1. Pulls in git submodules.
45
46=item 2. Creates autoconf/automake sources for building Dico modules.
47
48Recreates F<configure.ac> and F<modules/Makefile.am> from stub files
49F<configure.boot> and F<modules/stub.am>. The list of modules is obtained
50from the contents of the F<modules> directory -- each subdirectory
51is supposed to contain one module.
52
53Additional F<configure.ac> code for each module is obtained from
54file F<module.ac> in each module directory. See the description of
55this file in section B<FILES>.
56
57=item 3. Bootstraps the B<gnulib> submodule.
58
59=back
60
61The program must be run from the Dico source tree topmost directory.
62
63When given the B<-m> (B<--modules>) option, only the second step is
64performed.
65
66When run with B<-a> (B<--add>, B<--new>) option, the program creates
67basic infrastructure for modules named in the command line. For each
68I<NAME> it creates directory F<modules/I<NAME>>. Withih that directory,
69it creates two files: F<Makefile.am> from F<modules/template.am>, and
70F<I<NAME>.c>, which contains a stub code for the module. The new module
71is then integrated into F<configure.ac> and F<modules/Makefile.am> files.
72
73By default, the program prints only error diagnostics. That means that
74upon success, it will terminate quietly, without producing a single line
75on output. This can be changed using the B<-v> (or B<--verbose>) option.
76When the option is given once, the program prints general description before
77running each of the three steps described above. Two B<-v> options instruct
78it to also print whatever output that was generated when running auxiliary
79commands. Finally, three B<-v>'s produce additional debugging information.
80
81The B<-n> (B<--dry-run>) option instructs the tool to print what would have
82been done without actually doing it.
83
84=head1 OPTIONS
85
86=over 4
87
88=item B<-a>, B<--add>, B<--new>
89
90Create basic infrastructure for modules named in the command line and
91add them to F<configure.ac> and F<modules/Makefile.am>
92
93=item B<-n>, B<--dry-run>
94
95Don't do anything, just print what would have been done.
96
97=item B<-m>, B<--modules>
98
99Run only the second step: creation of autoconf/automake sources for
100Dico modules.
101
102=item B<-v>, B<--verbose>
103
104Increase output verbosity. Multiple options accumulate.
105
106=back
107
108The following options are passed to the B<gnulib> bootstrap script
109verbatim:
110
111=over 4
112
113=item B<--gnulib-srcdir=>I<DIRNAME>
114
115Specifies the local directory where B<gnulib> sources reside. Use this if
116you already have gnulib sources on your machine, and do not want to waste
117your bandwidth downloading them again.
118
119=item B<--no-git>
120
121Do not use git to update B<gnulib>. Requires that B<--gnulib-srcdir> point
122to a correct gnulib snapshot.
123
124=item B<--skip-po>
125
126Do not download po files.
127
128=back
129
130The following options cause the program to display informative text and
131exit:
132
133=over 4
134
135=item B<-h>
136
137Show a short usage summary.
138
139=item B<--help>
140
141Show man page.
142
143=item B<--usage>
144
145Show a concise command line syntax reminder.
146
147=back
148
149=head1 FILES
150
151The following files are used as templates to create output files. When
152creating output file, each line from the corresponding template is read,
153I<macro expansion> is performed, and the resulting string is written to the
154output file.
155
156During macro expansion, each occurrence of B<< <I<NAME>> >> is replaced with
157the contents of the macro variable I<NAME>, if it is defined. Expansion
158of undefined variables leaves the text as is.
159
160The construct B<< <I<NAME>#I<TEXT>> >> is expanded if it appears on a line
161alone, possibly preceded by any string of characters. It works similarly
162to B<< <I<NAME>> >>, except that if I<NAME> expands to multiple lines, the
163second and subsequent lines of expansion are prefixed with I<TEXT> on output.
164If I<TEXT> is empty, the content of the source line immediately preceding the
165construct is used instead. This makes it possible to use expansions after a
166comment character. E.g. if the variable B<HEADING> contains:
167
168 This file is generated automatically.
169 Please, do not edit.
170 See the docs for more info.
171
172and the input file contains:
173
174 dnl <HEADING#>
175
176Then, the resulting expansion will be:
177
178 dnl This file is generated automatically.
179 dnl Please, do not edit.
180 dnl See the docs for more info.
181
182The macro variables are specific for each file, and are described below.
183
184For each file, a special comment sequence is defined. Lines beginning
185with that sequence are omitted from the output.
186
187=over 4
188
189=item F<configure.boot>
190
191Produces the F<configure.ac> file. Comment marker is B<##>.
192The following variables are defined:
193
194=over 8
195
196=item B<MODULES>
197
198B<Autoconf> code for each module, obtained from the F<module.ac>
199files.
200
201=item B<HEADING>
202
203Generates an initial header text, warning the reader that the file is
204generated automatically and informing him about the ways to recreate
205that file.
206
207=item B<STATUS_OUTPUT>
208
209A list of printable description for modules that can be disabled. Each
210module is represented with a line
211
212 MODNAME ................ STATUS
213
214where MODNAME is the module name and STATUS is the module status variable
215(which produces B<yes> or B<no> at configure time, depending on whether
216the module is enabled or not).
217
218This is intended for use in B<AC_CONFIG_COMMANDS>.
219
220=item B<STATUS_DEFN>
221
222A list of assignments for module status variables, intended
223for use in B<AC_CONFIG_COMMANDS>.
224
225=back
226
227The following code illustrates the use of the latter two variables:
228
229 AC_CONFIG_COMMANDS([status],[
230echo<STATUS_OUTPUT>
231],
232 [<STATUS_DEFN>])
233
234=item F<modules/*/module.ac>
235
236This file is optional. If present, it contains the B<autoconf> code for
237that module, which is appended to the contents of the B<MODULES> variable
238used for creating F<configure.ac>.
239
240No macro substitutions are performed for that file.
241
242Comment marker is B<##>.
243
244The following comments starting with B<## module> are I<pragmatic> ones,
245and are treated specially:
246
247=over 8
248
249=item B<## module name: I<NAME>>
250
251Use I<NAME> as module name when creating variable names for that module. This
252is useful when the module name contains symbols that cannot be used in variable
253names (as in, e.g. B<dict.org>).
254
255=item B<## module description: I<TEXT>>
256
257Use I<TEXT> as module description in B<STATUS_OUTPUT> (see F<configure.boot>).
258
259=item B<## module category:>
260
261Reserved for future use.
262
263=back
264
265As well as other B<##> comments, these comments do not appear in the output.
266
267=item F<modules/stub.am>
268
269Produces the file F<modules/Makefile.am>. Comment marker is B<##>.
270
271Macro variables:
272
273=over 8
274
275=item B<HEADING>
276
277Same as in F<configure.boot>.
278
279=item B<MODULES>
280
281Produces B<Makefille.am> code for the B<SUBDIRS> variable.
282
283=back
284
285=item F<modules/template.c>
286
287This template is used when B<-a> (B<--add>, B<--new>) option is given.
288It produces the file F<modules/I<NAME>/I<NAME>.c>. Comment marker is B<//>.
289
290Macro variables:
291
292=over 8
293
294=item B<MODNAME>
295
296Expands to the name of the module.
297
298=back
299
300=item F<modules/template.am>
301
302This template is used when B<-a> (B<--add>, B<--new>) option is given.
303It produces the file F<modules/I<NAME>/Makefile.am>.
304
305Macro variables:
306
307=over 8
308
309=item B<MODNAME>
310
311Expands to the name of the module.
312
313=back
314
315=back
316
317=head1 EXIT CODES
318
319=over 4
320
321=item B<0>
322
323Successful termination.
324
325=item B<64>
326
327Command line usage error.
328
329=item B<66>
330
331Can't open input file.
332
333=item B<73>
334
335Can't create output file.
336
337=back
338
339=head1 BUGS
340
341Error handling can be made better.
342
343=cut
344
345use strict;
346use Getopt::Long qw(:config gnu_getopt no_ignore_case);
347use Pod::Usage;
348use Pod::Man;
349use File::Temp qw(tempfile);
350use File::Basename;
351use Data::Dumper;
352use IPC::Open3;
353use Symbol 'gensym';
354
355use constant EX_OK => 0;
356use constant EX_USAGE => 64; # command line usage error
357use constant EX_DATAERR => 65; # data format error
358use constant EX_NOINPUT => 66; # cannot open input file
359use constant EX_SOFTWARE => 70; # internal software error (not used yet)
360use constant EX_CANTCREAT => 73; # can't create (user) output file
361
362my $progname = basename($0);
363my $progdescr = "Recreate Dico module autoconf structure";
364my $addmod;
365my $dry_run;
366my $verbose;
367my $modules;
368my @gnulib_options;
369my $autoconf = "module.ac";
370my $config_stub = "configure.boot";
371my $makefile_stub = "modules/stub.am";
372my $makefile = "modules/Makefile.am";
373my %outfile;
374
375my %categories; # not used now
376
377sub error {
378 my $msg = shift;
379 local %_ = @_;
380 my $fd = defined($_{fd}) ? $_{fd} : \*STDERR;
381 print $fd "$progname: " if defined($progname);
382 print $fd "$_{prefix}: " if defined($_{prefix});
383 print $fd "$msg\n"
384}
385
386sub abend {
387 my $code = shift;
388 print STDERR "$progname: " if defined($progname);
389 print STDERR "@_\n";
390 exit $code;
391}
392
393my $status = 0;
394
395sub rewrite_configure_ac {
396 my $ref = shift;
397
398 my %vartab = (
399 'overwrite' => 1,
400 'tempfile' => 1,
401 'ignorecomm' => '##',
402 'HEADING' => "Do not edit. -*- mode: autoconf; buffer-read-only: t; -*- vi: set ro:\
403This file is created automatically from $config_stub.\
404To recreate, run $progname from the top of Dico source tree.
405",
406 'MODULES' => sub {
407 my $s;
408
409 foreach my $name (sort keys %{$ref}) {
410 my $h = $ref->{$name};
411 $s .= "# Module $name\n";
412 if (defined($h->{autoconf})) {
413 open(my $afd, "<", $h->{autoconf})
414 or abend(EX_NOINPUT,
415 "can't open $h->{autoconf} for reading: $!");
416 while (<$afd>) {
417 next if /^##/;
418 $s .= $_;
419 }
420 close $afd;
421 }
422 $s .= "\n";
423 $s .= "DICO_TESTS($h->{dir})\n" if ($h->{tests});
424 $s .= "AC_CONFIG_FILES([$h->{dir}/Makefile])\n";
425 $s .= "\n# End of module $name\n\n";
426 }
427 return $s;
428 },
429 'STATUS_OUTPUT' => sub {
430 return join "\n",
431 map {
432 my $n;
433 if (defined($ref->{$_}{descr})) {
434 $n = $ref->{$_}{descr};
435 } else {
436 $n = $_;
437 $n =~ s/\b(\w)/\U$1/g;
438 }
439
440 my $l = 34 - length($n) - 2;
441
442 "$n " .
443 (($l > 0) ? '.' x $l : '') .
444 " \$status_$ref->{$_}{modname}";
445 }
446 grep { $ref->{$_}{status} }
447 sort keys %{$ref};
448 },
449 'STATUS_DEFN' => sub {
450 return join "\n",
451 map { "status_$ref->{$_}{modname}=\$status_$ref->{$_}{modname}" }
452 grep { defined($ref->{$_}{status}) }
453 sort keys %{$ref};
454 }
455 );
456 make_file($config_stub, "configure.ac", \%vartab);
457}
458
459sub rewrite_makefile {
460 my $ref = shift;
461
462 my %vartab = (
463 'overwrite' => 1,
464 'tempfile' => 1,
465 'ignorecomm' => '##',
466 'HEADING' => "Do not edit. -*- buffer-read-only: t; -*- vi: set ro:\
467This file is created automatically from $makefile_stub.\
468To recreate, run $progname from the top of Dico source tree.
469",
470 'MODULES' => sub {
471 my $s;
472 foreach my $am (map { $ref->{$_}{am} }
473 grep { defined($ref->{$_}{am}) }
474 sort keys %{$ref}) {
475 $s .= "$am\n";
476 }
477 $s .= "SUBDIRS=";
478 foreach my $dir (map { $ref->{$_}{SUBDIRS} } sort keys %{$ref}) {
479 $s .= "\\\n $dir";
480 }
481 $s .= "\n";
482 return $s;
483 }
484 );
485 make_file($makefile_stub, $makefile, \%vartab);
486}
487
488sub add_module {
489 my ($name,$ref) = @_;
490 my $dir = "modules/$name";
491
492 error("adding module $name", prefix=>'DEBUG') if ($verbose>1);
493 my $acname = uc($name);
494 $ref->{$name}{dir} = $dir;
495 $ref->{$name}{SUBDIRS} = $name;
496 $ref->{$name}{modname} = $name;
497 if (-r "$dir/$autoconf") {
498 $ref->{$name}{autoconf} = "$dir/$autoconf";
499 open(my $fd, "<", "$dir/$autoconf")
500 or abend(EX_NOINPUT,
501 "can't open $dir/$autoconf for reading: $!");
502 while (<$fd>) {
503 chomp;
504 s/\s+$//;
505 if (/^##\s*module\s+name\s*:\s*([^\s]+).*$/) {
506 $ref->{$name}{modname} = $1;
507 } elsif (/^##\s*module\s+description\s*:\s*(.+).*$/) {
508 $ref->{$name}{descr} = $1;
509 } elsif (/^##\s*module\s+category\s*:\s*(.+).*$/) {
510 $ref->{$name}{category} = $1;
511 $categories{$1}++;
512 }
513 s/#.*//;
514 next if ($_ eq "");
515 if (/AM_CONDITIONAL\s*\(\s*\[${acname}_COND\]/) {
516 $ref->{$name}{am} = <<EOT;
517if ${acname}_COND
518 ${acname}_DIR=$name
519endif
520EOT
521 ;
522 $ref->{$name}{SUBDIRS} = "\$(${acname}_DIR)";
523 }
524 $ref->{$name}{status} = 1
525 if (!$ref->{$name}{status} and /status_$ref->{$name}{modname}=/);
526 }
527 close $fd;
528 }
529 $ref->{$name}{tests} = (-d "$dir/tests"
530 and -f "$dir/tests/Makefile.am"
531 and -f "$dir/tests/testsuite.at");
532
533 if (-f "$dir/Makefile.am") {
534 open(my $fd, "<", "$dir/Makefile.am")
535 or abend(EX_NOINPUT,
536 "can't open $dir/$autoconf for reading: $!");
537 my %checks = ('mod' => "mod_LTLIBRARIES does not contain $ref->{$name}{modname}.la",
538 'SOURCES' => "$ref->{$name}{modname}_la_SOURCES not defined");
539 while (<$fd>) {
540 chomp;
541 s/\s+$//;
542 s/#.*//;
543 next if ($_ eq "");
544 if (/mod_LTLIBRARIES\s*=\s*$ref->{$name}{modname}.la/) {
545 delete $checks{mod};
546 } elsif (/$ref->{$name}{modname}_la_SOURCES\s*=/) {
547 delete $checks{SOURCES};
548 }
549 }
550 close $fd;
551 if (keys(%checks)) {
552 while (my ($k,$v) = each %checks) {
553 error("$dir/Makefile.am: $v");
554 }
555 $status = EX_DATAERR;
556 return;
557 }
558 }
559
560 if ($verbose>2) {
561 print STDERR "module $name:\n";
562 print STDERR Dumper($ref->{$name});
563 }
564}
565
566sub replace_macro {
567 my $name = shift;
568 my $ref = shift;
569
570 my $s;
571
572 if (defined($ref->{$name})) {
573 if (ref($ref->{$name}) eq 'CODE') {
574 $s = &{$ref->{$name}};
575 } else {
576 $s = $ref->{$name};
577 }
578 } else {
579 $s = "<$name>";
580 }
581
582 return $s;
583}
584
585sub make_file {
586 my $infile = shift;
587 my $ofile = shift;
588 my $ref = shift;
589
590 error("creating $ofile from $infile", prefix => 'DEBUG') if ($verbose>1);
591 return if $dry_run;
592 if (!$ref->{overwrite} and -e $ofile) {
593 error("$ofile already exists", prefix => 'warning');
594 } else {
595 open(my $ifd, "<", $infile)
596 or abend(EX_DATAERR, "can't open $infile for reading: $!");
597
598 my $ofd;
599 if (defined($ref->{tempfile})) {
600 my $tempname;
601 ($ofd, $tempname) = tempfile(DIR => dirname($infile))
602 or abend(EX_CANTCREAT,
603 "can't open temporary file for creating $ofile: $!");
604 $outfile{$tempname} = $ofile;
605 } else {
606 open($ofd, ">", $ofile)
607 or abend(EX_CANTCREAT, "can't open $ofile for writing: $!");
608 }
609 while (<$ifd>) {
610 next if (defined($ref->{ignorecomm}) and /^$ref->{ignorecomm}/);
611 if (/^(.*)<([A-Z][A-Z0-9_]+)#([^>]*)>\s*$/) {
612 my $pfx = $3 || $1;
613 $_ = $1 . replace_macro($2, $ref);
614 chomp;
615 s/\n/\n$pfx/g;
616 $_ .= "\n";
617 } else {
618 s/<([A-Z][A-Z0-9_]+)>/replace_macro($1, $ref)/gex;
619 }
620 print $ofd $_;
621 }
622 close($ifd);
623 close($ofd);
624 }
625}
626
627sub create_module {
628 my $name = shift;
629 my $dir = "modules/$name";
630
631 if (-d $dir) {
632 error("$dir already exists", prefix => 'warning');
633 } else {
634 error("creating $dir", prefix => 'DEBUG') if ($verbose>1);
635 mkdir($dir) unless $dry_run;
636 }
637 make_file("modules/template.am", "$dir/Makefile.am",
638 { ignorecomm => '##',
639 MODNAME => $name });
640 make_file("modules/template.c", "$dir/${name}.c",
641 { ignorecomm => '//',
642 MODNAME => $name });
643}
644
645sub cleanup {
646 foreach my $f (keys %outfile) {
647 unlink $f if (-e $f);
648 }
649}
650
651sub checksrc {
652 return 0 unless -e $config_stub;
653 open(my $fd, '<', $config_stub)
654 or abend(EX_NOINPUT, "can't open $config_stub: $!");
655 my $anchor;
656 while (<$fd>) {
657 chomp;
658 s/^\s+//;
659 if (/^AC_CONFIG_SRCDIR\(\[(.*)\]\)/) {
660 $anchor = $1;
661 last;
662 }
663 }
664 close $fd;
665 abend(EX_DATAERR, "AC_CONFIG_SRCDIR not found in $config_stub")
666 unless defined $anchor;
667 return -e $anchor;
668}
669
670sub modproc {
671 my %modtab;
672 my @modnames = map { s#modules/##; $_; } grep { -d $_; } glob "modules/*";
673
674 error("Bootstrapping dico modules", fd => \*STDOUT) if $verbose;
675
676 foreach my $m (@modnames) {
677 add_module($m, \%modtab);
678 }
679
680 rewrite_configure_ac(\%modtab);
681 rewrite_makefile(\%modtab);
682
683 if ($status == 0 and !$dry_run) {
684 while (my ($from, $to) = each %outfile) {
685 rename $from, $to
686 or abend(EX_CANTCREAT, "can't rename $from to $to: $!");
687 }
688 }
689}
690
691sub run {
692 error("running @_", prefix=>'DEBUG') if ($verbose>2);
693 return if $dry_run;
694 my $out = gensym;
695 open(my $err, ">&", \*STDERR) or die "can't dup STDERR: $!";
696 open(my $in, "<&", \*STDIN) or die "can't dup STDIN: $!";
697 my $pid = open3($in, $out, $err, @_);
698 my $logpid;
699 if ($verbose > 1) {
700 $logpid = fork();
701 if ($logpid == 0) {
702 while (<$out>) {
703 chomp;
704 error($_, fd => \*STDOUT, prefix => "[$_[0]]");
705 }
706 exit;
707 }
708 }
709 waitpid($pid, 0);
710 my $ret = 0;
711 if ($? == -1) {
712 abend(EX_CANTCREAT, "failed to run @_");
713 } elsif ($? & 127) {
714 abend(EX_CANTCREAT, "$@ exited on signal " . ($? & 127));
715 } elsif (my $e = ($? >> 8)) {
716 abend(EX_CANTCREAT, "$@ exited with status $e");
717 }
718 waitpid($logpid, 0) if defined $logpid;
719}
720
721sub gnulib_init {
722 my $gnulib = 'gnulibinit';
723 unless (-l $gnulib) {
724 symlink('gnulib/build-aux/bootstrap', $gnulib)
725 or abend(EX_CANTCREAT, "can't symlink gnulib/build-aux/bootstrap: $!");
726 }
727 error("Bootstrapping gnulib", fd => \*STDOUT) if $verbose;
728 run('sh', $gnulib, @gnulib_options);
729}
730
731END {
732 cleanup;
733}
734
735$SIG{HUP} = $SIG{INT} = $SIG{QUIT} = $SIG{TERM} = \&cleanup;
736
737#
738GetOptions("h" => sub {
739 pod2usage(-message => "$progname: $progdescr",
740 -exitstatus => 0);
741 },
742 "help" => sub {
743 pod2usage(-exitstatus => EX_OK, -verbose => 2);
744 },
745 "usage" => sub {
746 pod2usage(-exitstatus => EX_OK, -verbose => 0);
747 },
748 "add|new|a" => \$addmod,
749 "dry-run|n" => \$dry_run,
750 "verbose|v+" => \$verbose,
751 "modules|m" => \$modules,
752 "gnulib-srcdir=s" => sub { push @gnulib_options, "--$_[0]=$_[1]" },
753 "skip-po|no-git" => sub { push @gnulib_options, "--$_[0]" }
754) or exit(EX_USAGE);
755
756abend(EX_USAGE, "must run from the Dico source tree topmost directory")
757 unless checksrc();
758
759++$verbose if $dry_run;
760
761if ($addmod) {
762 abend(EX_USAGE, "not enough arguments") unless @ARGV;
763 foreach my $mod (@ARGV) {
764 create_module($mod);
765 }
766 modproc();
767} elsif ($modules) {
768 abend(EX_USAGE, "too many arguments") if @ARGV;
769 modproc();
770} elsif ($#ARGV >= 0) {
771 abend(EX_USAGE, "too many arguments; did you mean --new?");
772} else {
773 abend(EX_USAGE, "this does not look like a clone of the Dico repository; try $progname --help for more info")
774 unless -d '.git';
775
776 error("Initializing submodules", fd => \*STDOUT) if $verbose;
777 run('git submodule init');
778 run('git submodule update');
779 modproc();
780 gnulib_init();
781}
782
783exit($status);
784
diff --git a/stub.ac b/configure.boot
index 7e9b812..e518ece 100644
--- a/stub.ac
+++ b/configure.boot
@@ -1,10 +1,14 @@
1## This file is a source for configure.ac. -*- autoconf -*- 1## This file is a source for configure.ac. -*- autoconf -*-
2## Run ./modinc to create it. 2## Run ./bootstrap to create it.
3## Run ./modinc --help for a detailed description. 3## Run ./bootstrap --help for a detailed description.
4## A short reminder: 4## A short reminder:
5## 1. Comments starting with ## are removed from the output. 5## 1. Comments starting with ## are removed from the output.
6## 2. A construct <NAME> is replaced with the value of the variable NAME. 6## 2. A construct <NAME> is replaced with the value of the variable NAME.
7## 3. Everything else is reproduced verbatim. 7## 3. <NAME#TEXT> on a line alone (arbitrary leading characters allowed)
8## is replaced with (multiline) expansion of NAME. The second and
9## subsequent lines are prefixed with TEXT (or leading characters, if
10## TEXT is empty).
11## 4. Everything else is reproduced verbatim.
8dnl <HEADING#> 12dnl <HEADING#>
9dnl Process this file with -*- autoconf -*- to produce a configure script. 13dnl Process this file with -*- autoconf -*- to produce a configure script.
10# This file is part of GNU Dico 14# This file is part of GNU Dico
diff --git a/modinc b/modinc
deleted file mode 100755
index 5b88051..0000000
--- a/modinc
+++ b/dev/null
@@ -1,641 +0,0 @@
1#! /usr/bin/perl
2# This file is part of GNU Dico
3# Copyright (C) 2014, 2016 Sergey Poznyakoff
4#
5# GNU Dico is free software; you can redistribute it and/or modify
6# it under the terms of the GNU General Public License as published by
7# the Free Software Foundation; either version 3, or (at your option)
8# any later version.
9#
10# GNU Dico is distributed in the hope that it will be useful,
11# but WITHOUT ANY WARRANTY; without even the implied warranty of
12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13# GNU General Public License for more details.
14#
15# You should have received a copy of the GNU General Public License
16# along with GNU Dico. If not, see <http://www.gnu.org/licenses/>.
17
18=head1 NAME
19
20modinc - Recreate Dico module autoconf structure
21
22=head1 SYNOPSIS
23
24B<modinc>
25[B<-ahnv>]
26[B<--add>]
27[B<--help>]
28[B<--new>]
29[B<--dry-run>]
30[B<--verbose>]
31[I<NAME>...]
32
33=head1 DESCRIPTION
34
35Recreates F<configure.ac> and F<modules/Makefile.am> from stub files
36F<stub.ac> and F<modules/stub.am>. The list of modules is obtained
37from the contents of the F<modules> directory -- each subdirectory
38is supposed to contain one module.
39
40Additional F<configure.ac> code for each module is obtained from
41file F<module.ac> in each module directory. See the description of
42this file in section B<FILES>.
43
44When run with B<-a> (B<--add>, B<--new>) option, the program creates
45basic infrastructure for modules named in the command line. For each
46I<NAME> it creates directory F<modules/I<NAME>>. Withih that directory,
47it creates two files: F<Makefile.am> from F<modules/template.am>, and
48F<I<NAME>.c>, which contains a stub code for the module.
49
50The program must be run from the Dico source tree topmost directory.
51
52=head1 OPTIONS
53
54=over 4
55
56=item B<-a>, B<--add>, B<--new>
57
58Create basic infrastructure for modules named in the command line and
59add them to F<configure.ac> and F<modules/Makefile.am>
60
61=item B<-n>, B<--dry-run>
62
63Don't do anything, just print what would have been done.
64
65=item B<-v>, B<--verbose>
66
67Increase output verbosity. Multiple options accumulate.
68
69=back
70
71The following options cause the program to display informative text and
72exit:
73
74=over 4
75
76=item B<-h>
77
78Show a short usage summary.
79
80=item B<--help>
81
82Show man page.
83
84=item B<--usage>
85
86Show a concise command line syntax reminder.
87
88=back
89
90=head1 FILES
91
92The following files are used as templates to create output files. When
93creating output file, each line from the corresponding template is read,
94I<macro expansion> is performed, and the resulting string is written to the
95output file.
96
97During macro expansion, each occurrence of B<< <I<NAME>> >> is replaced with
98the contents of the macro variable I<NAME>, if it is defined. Expansion
99of undefined variables leaves the text as is.
100
101The construct B<< <I<NAME>#I<TEXT>> >> is expanded if it appears on a line
102alone, possibly preceded by any string of characters. It works similarly
103to B<< <I<NAME>> >>, except that if I<NAME> expands to multiple lines, the
104second and subsequent lines of expansion are prefixed with I<TEXT> on output.
105If I<TEXT> is empty, the content of the source line immediately preceding the
106construct is used instead. This makes it possible to use expansions after a
107comment character. E.g. if the variable B<HEADING> contains:
108
109 This file is generated automatically.
110 Please, do not edit.
111 See the docs for more info.
112
113and the input file contains:
114
115 dnl <HEADING#>
116
117Then, the resulting expansion will be:
118
119 dnl This file is generated automatically.
120 dnl Please, do not edit.
121 dnl See the docs for more info.
122
123The macro variables are specific for each file, and are described below.
124
125For each file, a special comment sequence is defined. Lines beginning
126with that sequence are omitted from the output.
127
128=over 4
129
130=item F<stub.ac>
131
132Produces the F<configure.ac> file. Comment marker is B<##>.
133The following variables are defined:
134
135=over 8
136
137=item B<MODULES>
138
139B<Autoconf> code for each module, obtained from the F<module.ac>
140files.
141
142=item B<HEADING>
143
144Generates an initial header text, warning the reader that the file is
145generated automatically and informing him about the ways to recreate
146that file.
147
148=item B<STATUS_OUTPUT>
149
150A list of printable description for modules that can be disabled. Each
151module is represented with a line
152
153 MODNAME ................ STATUS
154
155where MODNAME is the module name and STATUS is the module status variable
156(which produces B<yes> or B<no> at configure time, depending on whether
157the module is enabled or not).
158
159This is intended for use in B<AC_CONFIG_COMMANDS>.
160
161=item B<STATUS_DEFN>
162
163A list of assignments for module status variables, intended
164for use in B<AC_CONFIG_COMMANDS>.
165
166=back
167
168The following code illustrates the use of the latter two variables:
169
170 AC_CONFIG_COMMANDS([status],[
171echo<STATUS_OUTPUT>
172],
173 [<STATUS_DEFN>])
174
175=item F<modules/*/module.ac>
176
177This file is optional. If present, it contains the B<autoconf> code for
178that module, which is appended to the contents of the B<MODULES> variable
179used for creating F<configure.ac>.
180
181No macro substitutions are performed for that file.
182
183Comment marker is B<##>.
184
185The following comments starting with B<## module> are I<pragmatic> ones,
186and are treated specially:
187
188=over 8
189
190=item B<## module name: I<NAME>>
191
192Use I<NAME> as module name when creating variable names for that module. This
193is useful when the module name contains symbols that cannot be used in variable
194names (as in, e.g. B<dict.org>).
195
196=item B<## module description: I<TEXT>>
197
198Use I<TEXT> as module description in B<STATUS_OUTPUT> (see F<stub.ac>).
199
200=item B<## module category:>
201
202Reserved for future use.
203
204=back
205
206As well as other B<##> comments, these comments do not appear in the output.
207
208=item F<modules/stub.am>
209
210Produces the file F<modules/Makefile.am>. Comment marker is B<##>.
211
212Macro variables:
213
214=over 8
215
216=item B<HEADING>
217
218Same as in F<stub.ac>.
219
220=item B<MODULES>
221
222Produces B<Makefille.am> code for the B<SUBDIRS> variable.
223
224=back
225
226=item F<modules/template.c>
227
228This template is used when B<-a> (B<--add>, B<--new>) option is given.
229It produces the file F<modules/I<NAME>/I<NAME>.c>. Comment marker is B<//>.
230
231Macro variables:
232
233=over 8
234
235=item B<MODNAME>
236
237Expands to the name of the module.
238
239=back
240
241=item F<modules/template.am>
242
243This template is used when B<-a> (B<--add>, B<--new>) option is given.
244It produces the file F<modules/I<NAME>/Makefile.am>.
245
246Macro variables:
247
248=over 8
249
250=item B<MODNAME>
251
252Expands to the name of the module.
253
254=back
255
256=back
257
258=head1 EXIT CODES
259
260=over 4
261
262=item B<0>
263
264Successful termination.
265
266=item B<64>
267
268Command line usage error.
269
270=item B<66>
271
272Can't open input file.
273
274=item B<73>
275
276Can't create output file.
277
278=back
279
280=head1 BUGS
281
282Error handling can be made better.
283
284=cut
285
286use strict;
287use Getopt::Long qw(:config gnu_getopt no_ignore_case);
288use Pod::Usage;
289use Pod::Man;
290use File::Temp qw(tempfile);
291use File::Basename;
292use Data::Dumper;
293
294use constant EX_OK => 0;
295use constant EX_USAGE => 64; # command line usage error
296use constant EX_DATAERR => 65; # data format error
297use constant EX_NOINPUT => 66; # cannot open input file
298use constant EX_SOFTWARE => 70; # internal software error (not used yet)
299use constant EX_CANTCREAT => 73; # can't create (user) output file
300
301my $progname = basename($0);
302my $progdescr = "Recreate Dico module autoconf structure";
303my $addmod;
304my $dry_run;
305my $verbose;
306my $autoconf = "module.ac";
307my $config_stub = "stub.ac";
308my $makefile_stub = "modules/stub.am";
309my $makefile = "modules/Makefile.am";
310my %outfile;
311
312my %categories; # not used now
313
314sub error {
315 my $msg = shift;
316 local %_ = @_;
317 print STDERR "$progname: " if defined($progname);
318 print STDERR "$_{prefix}: " if defined($_{prefix});
319 print STDERR "$msg\n"
320}
321
322sub abend {
323 my $code = shift;
324 print STDERR "$progname: " if defined($progname);
325 print STDERR "@_\n";
326 exit $code;
327}
328
329my $status = 0;
330
331sub rewrite_configure_ac {
332 my $ref = shift;
333
334 my %vartab = (
335 'overwrite' => 1,
336 'tempfile' => 1,
337 'ignorecomm' => '##',
338 'HEADING' => "Do not edit. -*- mode: autoconf; buffer-read-only: t; -*- vi: set ro:\
339This file is created automatically from $config_stub.\
340To recreate, run $progname from the top of Dico source tree.
341",
342 'MODULES' => sub {
343 my $s;
344
345 foreach my $name (sort keys %{$ref}) {
346 my $h = $ref->{$name};
347 $s .= "# Module $name\n";
348 if (defined($h->{autoconf})) {
349 open(my $afd, "<", $h->{autoconf})
350 or abend(EX_NOINPUT,
351 "can't open $h->{autoconf} for reading: $!");
352 while (<$afd>) {
353 next if /^##/;
354 $s .= $_;
355 }
356 close $afd;
357 }
358 $s .= "\n";
359 $s .= "DICO_TESTS($h->{dir})\n" if ($h->{tests});
360 $s .= "AC_CONFIG_FILES([$h->{dir}/Makefile])\n";
361 $s .= "\n# End of module $name\n\n";
362 }
363 return $s;
364 },
365 'STATUS_OUTPUT' => sub {
366 return join "\n",
367 map {
368 my $n;
369 if (defined($ref->{$_}{descr})) {
370 $n = $ref->{$_}{descr};
371 } else {
372 $n = $_;
373 $n =~ s/\b(\w)/\U$1/g;
374 }
375
376 my $l = 34 - length($n) - 2;
377
378 "$n " .
379 (($l > 0) ? '.' x $l : '') .
380 " \$status_$ref->{$_}{modname}";
381 }
382 grep { $ref->{$_}{status} }
383 sort keys %{$ref};
384 },
385 'STATUS_DEFN' => sub {
386 return join "\n",
387 map { "status_$ref->{$_}{modname}=\$status_$ref->{$_}{modname}" }
388 grep { defined($ref->{$_}{status}) }
389 sort keys %{$ref};
390 }
391 );
392 make_file($config_stub, "configure.ac", \%vartab);
393}
394
395sub rewrite_makefile {
396 my $ref = shift;
397
398 my %vartab = (
399 'overwrite' => 1,
400 'tempfile' => 1,
401 'ignorecomm' => '##',
402 'HEADING' => "Do not edit. -*- buffer-read-only: t; -*- vi: set ro:\
403This file is created automatically from $makefile_stub.\
404To recreate, run $progname from the top of Dico source tree.
405",
406 'MODULES' => sub {
407 my $s;
408 foreach my $am (map { $ref->{$_}{am} }
409 grep { defined($ref->{$_}{am}) }
410 sort keys %{$ref}) {
411 $s .= "$am\n";
412 }
413 $s .= "SUBDIRS=";
414 foreach my $dir (map { $ref->{$_}{SUBDIRS} } sort keys %{$ref}) {
415 $s .= "\\\n $dir";
416 }
417 $s .= "\n";
418 return $s;
419 }
420 );
421 make_file($makefile_stub, $makefile, \%vartab);
422}
423
424sub add_module {
425 my ($name,$ref) = @_;
426 my $dir = "modules/$name";
427
428 error("adding module $name", prefix=>'DEBUG') if ($verbose);
429 my $acname = uc($name);
430 $ref->{$name}{dir} = $dir;
431 $ref->{$name}{SUBDIRS} = $name;
432 $ref->{$name}{modname} = $name;
433 if (-r "$dir/$autoconf") {
434 $ref->{$name}{autoconf} = "$dir/$autoconf";
435 open(my $fd, "<", "$dir/$autoconf")
436 or abend(EX_NOINPUT,
437 "can't open $dir/$autoconf for reading: $!");
438 while (<$fd>) {
439 chomp;
440 s/\s+$//;
441 if (/^##\s*module\s+name\s*:\s*([^\s]+).*$/) {
442 $ref->{$name}{modname} = $1;
443 } elsif (/^##\s*module\s+description\s*:\s*(.+).*$/) {
444 $ref->{$name}{descr} = $1;
445 } elsif (/^##\s*module\s+category\s*:\s*(.+).*$/) {
446 $ref->{$name}{category} = $1;
447 $categories{$1}++;
448 }
449 s/#.*//;
450 next if ($_ eq "");
451 if (/AM_CONDITIONAL\s*\(\s*\[${acname}_COND\]/) {
452 $ref->{$name}{am} = <<EOT;
453if ${acname}_COND
454 ${acname}_DIR=$name
455endif
456EOT
457 ;
458 $ref->{$name}{SUBDIRS} = "\$(${acname}_DIR)";
459 }
460 $ref->{$name}{status} = 1
461 if (!$ref->{$name}{status} and /status_$ref->{$name}{modname}=/);
462 }
463 close $fd;
464 }
465 $ref->{$name}{tests} = (-d "$dir/tests"
466 and -f "$dir/tests/Makefile.am"
467 and -f "$dir/tests/testsuite.at");
468
469 if (-f "$dir/Makefile.am") {
470 open(my $fd, "<", "$dir/Makefile.am")
471 or abend(EX_NOINPUT,
472 "can't open $dir/$autoconf for reading: $!");
473 my %checks = ('mod' => "mod_LTLIBRARIES does not contain $ref->{$name}{modname}.la",
474 'SOURCES' => "$ref->{$name}{modname}_la_SOURCES not defined");
475 while (<$fd>) {
476 chomp;
477 s/\s+$//;
478 s/#.*//;
479 next if ($_ eq "");
480 if (/mod_LTLIBRARIES\s*=\s*$ref->{$name}{modname}.la/) {
481 delete $checks{mod};
482 } elsif (/$ref->{$name}{modname}_la_SOURCES\s*=/) {
483 delete $checks{SOURCES};
484 }
485 }
486 close $fd;
487 if (keys(%checks)) {
488 while (my ($k,$v) = each %checks) {
489 error("$dir/Makefile.am: $v");
490 }
491 $status = EX_DATAERR;
492 return;
493 }
494 }
495
496 if ($verbose>1) {
497 print STDERR "module $name:\n";
498 print STDERR Dumper($ref->{$name});
499 }
500}
501
502sub replace_macro {
503 my $name = shift;
504 my $ref = shift;
505
506 my $s;
507
508 if (defined($ref->{$name})) {
509 if (ref($ref->{$name}) eq 'CODE') {
510 $s = &{$ref->{$name}};
511 } else {
512 $s = $ref->{$name};
513 }
514 } else {
515 $s = "<$name>";
516 }
517
518 return $s;
519}
520
521sub make_file {
522 my $infile = shift;
523 my $ofile = shift;
524 my $ref = shift;
525
526 error("creating $ofile from $infile", prefix => 'DEBUG') if ($verbose);
527 return if $dry_run;
528 if (!$ref->{overwrite} and -e $ofile) {
529 error("$ofile already exists", prefix => 'warning');
530 } else {
531 open(my $ifd, "<", $infile)
532 or abend(EX_DATAERR, "can't open $infile for reading: $!");
533
534 my $ofd;
535 if (defined($ref->{tempfile})) {
536 my $tempname;
537 ($ofd, $tempname) = tempfile(DIR => dirname($infile))
538 or abend(EX_CANTCREAT,
539 "can't open temporary file for creating $ofile: $!");
540 $outfile{$tempname} = $ofile;
541 } else {
542 open($ofd, ">", $ofile)
543 or abend(EX_CANTCREAT, "can't open $ofile for writing: $!");
544 }
545 while (<$ifd>) {
546 next if (defined($ref->{ignorecomm}) and /^$ref->{ignorecomm}/);
547 if (/^(.*)<([A-Z][A-Z0-9_]+)#([^>]*)>\s*$/) {
548 my $pfx = $3 || $1;
549 $_ = $1 . replace_macro($2, $ref);
550 chomp;
551 s/\n/\n$pfx/g;
552 $_ .= "\n";
553 } else {
554 s/<([A-Z][A-Z0-9_]+)>/replace_macro($1, $ref)/gex;
555 }
556 print $ofd $_;
557 }
558 close($ifd);
559 close($ofd);
560 }
561}
562
563sub create_module {
564 my $name = shift;
565 my $dir = "modules/$name";
566
567 if (-d $dir) {
568 error("$dir already exists", prefix => 'warning');
569 } else {
570 error("creating $dir", prefix => 'DEBUG') if ($verbose);
571 mkdir($dir) unless $dry_run;
572 }
573 make_file("modules/template.am", "$dir/Makefile.am",
574 { ignorecomm => '##',
575 MODNAME => $name });
576 make_file("modules/template.c", "$dir/${name}.c",
577 { ignorecomm => '//',
578 MODNAME => $name });
579}
580
581sub cleanup {
582 foreach my $f (keys %outfile) {
583 unlink $f if (-e $f);
584 }
585}
586
587END {
588 cleanup;
589}
590
591$SIG{HUP} = $SIG{INT} = $SIG{QUIT} = $SIG{TERM} = \&cleanup;
592
593#
594GetOptions("h" => sub {
595 pod2usage(-message => "$progname: $progdescr",
596 -exitstatus => 0);
597 },
598 "help" => sub {
599 pod2usage(-exitstatus => EX_OK, -verbose => 2);
600 },
601 "usage" => sub {
602 pod2usage(-exitstatus => EX_OK, -verbose => 0);
603 },
604 "add|new|a" => \$addmod,
605 "dry-run|n" => \$dry_run,
606 "verbose|v+" => \$verbose,
607) or exit(EX_USAGE);
608
609abend(EX_USAGE, "must run from the Dico source tree topmost directory")
610 unless (-d "modules");
611
612++$verbose if $dry_run;
613
614if ($addmod) {
615 abend(EX_USAGE, "not enough arguments") unless ($#ARGV >= 0);
616 foreach my $mod (@ARGV) {
617 create_module($mod);
618 }
619} elsif ($#ARGV >= 0) {
620 abend(EX_USAGE, "too many arguments; did you mean --new?");
621}
622
623my %modtab;
624my @modnames = map { s#modules/##; $_; } grep { -d $_; } glob "modules/*";
625
626foreach my $m (@modnames) {
627 add_module($m, \%modtab);
628}
629
630rewrite_configure_ac(\%modtab);
631rewrite_makefile(\%modtab);
632
633if ($status == 0 and !$dry_run) {
634 while (my ($from, $to) = each %outfile) {
635 rename $from, $to
636 or abend(EX_CANTCREAT, "can't rename $from to $to: $!");
637 }
638}
639
640exit($status);
641

Return to:

Send suggestions and report system problems to the System administrator.