Merge pull request #228 from DOCGroup/jwillemsen-patch-1
[MPC.git] / modules / AutomakeWorkspaceCreator.pm
blobefcd157199d16a184df7313e23daf7a8fff01448
1 package AutomakeWorkspaceCreator;
3 # ************************************************************
4 # Description : A Automake Workspace (Makefile) creator
5 # Author : J.T. Conklin & Steve Huston
6 # Create Date : 5/13/2002
7 # ************************************************************
9 # ************************************************************
10 # Pragmas
11 # ************************************************************
13 use strict;
14 use File::Copy;
16 use AutomakeProjectCreator;
17 use MakePropertyBase;
18 use WorkspaceCreator;
19 use WorkspaceHelper;
21 use vars qw(@ISA);
22 @ISA = qw(MakePropertyBase WorkspaceCreator);
24 # ************************************************************
25 # Data Section
26 # ************************************************************
28 my $acfile = 'configure.ac';
29 my $acmfile = 'configure.ac.Makefiles';
31 # ************************************************************
32 # Subroutine Section
33 # ************************************************************
35 sub compare_output {
36 return 1;
39 ## Can't cache as some intermediate project files are deleted
40 ## and must be regenerated if a project is regenerated.
41 sub default_cacheok {
42 return 0;
45 sub files_are_different {
46 my($self, $old, $new) = @_;
47 my $diff = 1;
48 if (-r $old) {
49 my $lh = new FileHandle();
50 my $rh = new FileHandle();
51 if (open($lh, $old)) {
52 if (open($rh, $new)) {
53 my $done = 0;
54 my $lline;
55 my $rline;
57 $diff = 0;
58 do {
59 $lline = <$lh>;
60 $rline = <$rh>;
61 if (defined $lline) {
62 if (defined $rline) {
63 $lline =~ s/#.*//;
64 $rline =~ s/#.*//;
65 $diff = 1 if ($lline ne $rline);
67 else {
68 $done = 1;
71 else {
72 $diff = 1 if (defined $rline);
73 $done = 1;
75 } while(!$done && !$diff);
76 close($rh);
78 close($lh);
81 return $diff;
85 sub workspace_file_name {
86 return $_[0]->get_modified_workspace_name('Makefile', '.am');
90 sub workspace_per_project {
91 #my $self = shift;
92 return 1;
96 sub pre_workspace {
97 my($self, $fh) = @_;
98 my $crlf = $self->crlf();
100 $self->print_workspace_comment($fh,
101 '## Process this file with automake to create Makefile.in', $crlf,
102 '##', $crlf,
103 '## ', '$', 'Id', '$', $crlf,
104 '##', $crlf,
105 '## This file was generated by MPC. Any changes made directly to', $crlf,
106 '## this file will be lost the next time it is generated.', $crlf,
107 '##', $crlf,
108 '## MPC Command:', $crlf,
109 '## ', $self->create_command_line_string($0, @ARGV), $crlf, $crlf);
113 sub write_comps {
114 my($self, $fh, $creator, $toplevel) = @_;
115 my $projects = $self->get_projects();
116 my @list = $self->sort_dependencies($projects);
117 my $crlf = $self->crlf();
118 my %unique;
119 my @dirs;
120 my @locals;
121 my %proj_dir_seen;
122 my $have_subdirs = 0;
123 my $outdir = $self->get_outdir();
124 my $cond = '--';
126 ## This step writes a configure.ac.Makefiles list into the starting
127 ## directory. The list contains of all the Makefiles generated down
128 ## the tree. configure.ac can include this to get an up-to-date list
129 ## of all the involved Makefiles.
130 my $mfh;
131 my $makefile;
132 if ($toplevel) {
133 my $need_acmfile = 1;
134 if (! -e "$outdir/$acfile") {
135 my $acfh = new FileHandle();
136 if (open($acfh, ">$outdir/$acfile")) {
137 print $acfh "AC_INIT(", $self->get_workspace_name(), ", 1.0)$crlf",
138 "AM_INIT_AUTOMAKE([1.9])$crlf",
139 $crlf,
140 "AC_PROG_CXX$crlf",
141 "AC_PROG_CXXCPP$crlf",
142 "AC_PROG_LIBTOOL$crlf",
143 $crlf;
145 my $fp = $creator->get_feature_parser();
146 my $features = $fp->get_names();
147 my %assoc = %{$self->get_associated_projects()};
148 foreach my $feature (sort @$features) {
149 print $acfh 'AM_CONDITIONAL(BUILD_', uc($feature),
150 ', ', ($fp->get_value($feature) ? 'true' : 'false'),
151 ')', $crlf;
152 delete $assoc{$feature};
154 foreach my $akey (keys %assoc) {
155 print $acfh 'AM_CONDITIONAL(BUILD_', uc($akey), ', true)', $crlf
156 if ($akey ne $cond);
159 print $acfh $crlf,
160 "m4_include([$acmfile])$crlf",
161 $crlf,
162 "AC_OUTPUT$crlf";
163 close($acfh);
166 else {
167 $self->information("$acfile already exists.");
168 $need_acmfile = !$self->edit_config_ac("$outdir/$acfile", \@list);
171 if ($need_acmfile) {
172 unlink("$outdir/$acmfile");
173 $mfh = new FileHandle();
174 open($mfh, ">$outdir/$acmfile");
175 ## The top-level is never listed as a dependency, so it needs to be
176 ## added explicitly.
177 $makefile = $self->mpc_basename($self->get_current_output_name());
178 $makefile =~ s/\.am$//;
179 print $mfh "AC_CONFIG_FILES([ $makefile ])$crlf";
180 $proj_dir_seen{'.'} = 1;
184 ## If we're writing a configure.ac.Makefiles file, every seen project
185 ## goes into it. Since we only write this at the starting directory
186 ## level, it'll include all projects processed at this level and below.
187 foreach my $dep (@list) {
188 if ($mfh) {
189 ## There should be a Makefile at each level, but it's not a project,
190 ## it's a workspace; therefore, it's not in the list of projects.
191 ## Since we're consolidating all the project files into one workspace
192 ## Makefile.am per directory level, be sure to add that Makefile.am
193 ## entry at each level there's a project dependency.
194 my $dep_dir = $self->mpc_dirname($dep);
195 if (!defined $proj_dir_seen{$dep_dir}) {
196 $proj_dir_seen{$dep_dir} = 1;
197 ## If there are directory levels between project-containing
198 ## directories (for example, at this time in
199 ## ACE_wrappers/apps/JAWS/server, there are no projects at the
200 ## apps or apps/JAWS level) we need to insert the Makefile
201 ## entries for the levels without projects. They won't be listed
202 ## in @list but are needed for make to traverse intervening directory
203 ## levels down to where the project(s) to build are.
204 my @dirs = split /\//, $dep_dir;
205 my $inter_dir = "";
206 foreach my $dep (@dirs) {
207 $inter_dir .= $dep;
208 if (!defined $proj_dir_seen{$inter_dir}) {
209 $proj_dir_seen{$inter_dir} = 1;
210 print $mfh "AC_CONFIG_FILES([ $inter_dir/$makefile ])$crlf";
212 $inter_dir .= '/';
214 print $mfh "AC_CONFIG_FILES([ $dep_dir/$makefile ])$crlf";
218 ## Get a unique list of next-level directories for SUBDIRS.
219 ## To make sure we keep the dependencies correct, insert the '.' for
220 ## any local projects in the proper place. Remember if any subdirs
221 ## are seen to know if we need a SUBDIRS entry generated.
222 my $dir = $self->get_first_level_directory($dep);
223 if (!defined $unique{$dir}) {
224 $unique{$dir} = 1;
225 unshift(@dirs, $dir);
227 if ($dir eq '.') {
228 ## At each directory level, each project is written into a separate
229 ## Makefile.<project>.am file. To bring these back into the build
230 ## process, they'll be sucked back into the workspace Makefile.am file.
231 ## Remember which ones to pull in at this level.
232 unshift(@locals, $dep);
234 else {
235 $have_subdirs = 1;
238 close($mfh) if ($mfh);
240 # The Makefile.<project>.am files append values to build target macros
241 # for each program/library to build. When using conditionals, however,
242 # a plain empty assignment is done outside the conditional to be sure
243 # that each append can be done regardless of the condition test. Because
244 # automake fails if the first isn't a plain assignment, we need to resolve
245 # these situations when combining the files. The code below makes sure
246 # that there's always a plain assignment, whether it's one outside a
247 # conditional or the first append is changed to a simple assignment.
249 # We should consider extending this to support all macros that match
250 # automake's uniform naming convention. A true perl wizard probably
251 # would be able to do this in a single line of code.
253 my %seen;
254 my %conditional_targets;
255 my %unconditional_targets;
256 my %first_instance_unconditional;
257 my $installable_headers;
258 my $installable_pkgconfig;
259 my $includedir;
260 my $project_name;
261 my $status = 1;
262 my $errorString;
264 ## To avoid unnecessarily emitting blank assignments, rip through the
265 ## Makefile.<project>.am files and check for conditions.
266 if (@locals) {
267 my $pfh = new FileHandle();
268 foreach my $local (reverse @locals) {
269 if ($local =~ /Makefile\.(.*)\.am/) {
270 $project_name = $1;
272 else {
273 $project_name = 'nobase';
276 if (open($pfh, "$outdir/$local")) {
277 my $in_condition = 0;
278 my $regok = $self->escape_regex_special($project_name);
279 my $inc_pattern = $regok . '_include_HEADERS';
280 my $pkg_pattern = $regok . '_pkginclude_HEADERS';
281 while (<$pfh>) {
282 # Don't look at comments
283 next if (/^#/);
285 $in_condition++ if (/^if\s*/);
286 $in_condition-- if (/^endif\s*/);
288 if ( /(^[a-zA-Z][a-zA-Z0-9_]*_(PROGRAMS|LIBRARIES|LTLIBRARIES|LISP|PYTHON|JAVA|SCRIPTS|DATA|SOURCES|HEADERS|MANS|TEXINFOS|LIBADD|LDADD|DEPENDENCIES))\s*\+=\s*/
289 || /(^CLEANFILES)\s*\+=\s*/
290 || /(^EXTRA_DIST)\s*\+=\s*/
293 if ($in_condition) {
294 $conditional_targets{$1}++;
295 } else {
296 if (! $seen{$1} ) {
297 $first_instance_unconditional{$1} = 1;
299 $unconditional_targets{$1}++;
301 $seen{$1} = 1;
303 $installable_pkgconfig= 1 if (/^pkgconfig_DATA/);
304 $installable_headers = 1
305 if (/^$inc_pattern\s*\+=\s*/ || /^$pkg_pattern\s*\+=\s*/);
307 elsif (/includedir\s*=\s*(.*)/) {
308 $includedir = $1;
312 close($pfh);
313 $in_condition = 0;
315 else {
316 $errorString = "Unable to open $local for reading.";
317 $status = 0;
318 last;
324 # Clear seen hash
326 %seen = ();
328 ## Print out the Makefile.am.
329 my $wsHelper = WorkspaceHelper::get($self);
330 my $convert_header_name;
331 if ($status && ((!defined $includedir && $installable_headers)
332 || $installable_pkgconfig)) {
333 if (!defined $includedir && $installable_headers) {
334 my $incdir = $wsHelper->modify_value('includedir',
335 $self->get_includedir());
336 if ($incdir ne '') {
337 print $fh "includedir = \@includedir\@$incdir$crlf";
338 $convert_header_name = 1;
341 if ($installable_pkgconfig) {
342 print $fh "pkgconfigdir = \@libdir\@/pkgconfig$crlf";
345 print $fh $crlf;
348 if ($status && @locals) {
349 ($status, $errorString) = $wsHelper->write_settings($self, $fh, @locals);
352 ## Create the SUBDIRS setting. If there are associated projects, then
353 ## we will also set up conditionals for it as well.
354 if ($status && $have_subdirs == 1) {
355 my $assoc = $self->get_associated_projects();
356 my @aorder;
357 my %afiles;
358 my $entry = " \\$crlf ";
359 print $fh 'SUBDIRS =';
360 foreach my $dir (reverse @dirs) {
361 my $found;
362 foreach my $akey (keys %$assoc) {
363 if (defined $$assoc{$akey}->{$dir}) {
364 if ($akey eq $cond) {
365 if ($toplevel) {
366 print $fh $entry, '@', $dir, '@';
367 $found = 1;
370 else {
371 push(@aorder, $akey);
372 push(@{$afiles{$akey}}, $dir);
373 $found = 1;
375 last;
377 elsif ($toplevel && defined $$assoc{$akey}->{uc($dir)} &&
378 $akey eq $cond) {
379 print $fh $entry, '@', uc($dir), '@';
380 $found = 1;
381 last;
384 print $fh $entry, $dir if (!$found);
386 print $fh $crlf;
387 my $second = 1;
388 foreach my $aorder (@aorder) {
389 if (defined $afiles{$aorder}) {
390 $second = undef;
391 print $fh $crlf,
392 'if BUILD_', uc($aorder), "\n",
393 'SUBDIRS +=';
394 foreach my $afile (@{$afiles{$aorder}}) {
395 print $fh " $afile";
397 delete $afiles{$aorder};
398 print $fh $crlf, 'endif', $crlf;
401 print $fh $crlf if ($second);
404 ## Now, for each target used in a conditional, emit a blank assignment
405 ## and mark that we've seen that target to avoid changing the += to =
406 ## as the individual files are pulled in.
407 if ($status && %conditional_targets) {
408 my $primary;
409 my $count;
411 while ( ($primary, $count) = each %conditional_targets) {
412 if (! $first_instance_unconditional{$primary}
413 && ($unconditional_targets{$primary} || ($count > 1)))
415 print $fh "$primary =$crlf";
416 $seen{$primary} = 1;
420 print $fh $crlf;
423 ## Take the local Makefile.<project>.am files and insert each one here,
424 ## then delete it.
425 if ($status && @locals) {
426 my $pfh = new FileHandle();
427 my $liblocs = $self->get_lib_locations();
428 my $here = $self->getcwd();
429 my $start = $self->getstartdir();
430 my %explicit;
431 foreach my $local (reverse @locals) {
432 if (open($pfh, "$outdir/$local")) {
433 print $fh "## $local", $crlf;
435 my $look_for_libs = 0;
436 my $prev_line;
437 my $in_explicit;
439 while (<$pfh>) {
440 # Don't emit comments
441 next if (/^#/);
443 # Check for explicit targets
444 if ($in_explicit) {
445 if (/^\t/) {
446 next;
448 else {
449 $in_explicit = undef;
452 elsif ($prev_line !~ /\\$/ && /^([\w\/\.\-\s]+):/) {
453 my $target = $1;
454 $target =~ s/^\s+//;
455 $target =~ s/\s+$//;
456 if (defined $explicit{$target}) {
457 $in_explicit = 1;
458 next;
460 else {
461 $explicit{$target} = 1;
465 if ($convert_header_name) {
466 if ($local =~ /Makefile\.(.*)\.am/) {
467 $project_name = $1;
469 else {
470 $project_name = 'nobase';
472 my $regok = $self->escape_regex_special($project_name);
473 my $inc_pattern = $regok . '_include_HEADERS';
474 my $pkg_pattern = $regok . '_pkginclude_HEADERS';
475 if (/^$inc_pattern\s*\+=\s*/ || /^$pkg_pattern\s*\+=\s*/) {
476 $_ =~ s/^$regok/nobase/;
480 if ( /(^[a-zA-Z][a-zA-Z0-9_]*_(PROGRAMS|LIBRARIES|LTLIBRARIES|LISP|PYTHON|JAVA|SCRIPTS|DATA|SOURCES|HEADERS|MANS|TEXINFOS|LIBADD|LDADD|DEPENDENCIES))\s*\+=\s*/
481 || /(^CLEANFILES)\s*\+=\s*/
482 || /(^EXTRA_DIST)\s*\+=\s*/
484 if (!defined ($seen{$1})) {
485 $seen{$1} = 1;
486 s/\+=/=/;
490 ## This scheme relies on automake.mpd emitting the 'la' libs first.
491 ## Look for all the libXXXX.la, find out where they are located
492 ## relative to the start of the MPC run, and relocate the reference
493 ## to that location under $top_builddir. Unless the referred-to
494 ## library is in the current directory, then leave it undecorated
495 ## so the automake-generated dependency orders the build correctly.
496 if ($look_for_libs) {
497 my @libs = /\s+(lib(\w+).la)/gm;
498 my $libcount = @libs / 2;
499 for(my $i = 0; $i < $libcount; ++$i) {
500 my $libfile = $libs[$i * 2];
501 my $libname = $libs[$i * 2 + 1];
502 my $reldir = $$liblocs{$libname};
504 ## If we could not find a relative directory for this
505 ## library, it may be that it is a decorated library name.
506 ## We will search for an approximate match.
507 if (!defined $reldir) {
508 my $tmpname = $libname;
509 while($tmpname ne '') {
510 $tmpname = substr($tmpname, 0, length($tmpname) - 1);
511 if (defined $$liblocs{$tmpname}) {
512 $reldir = $$liblocs{$tmpname};
513 $self->warning("Relative directory for $libname " .
514 "was approximated with $tmpname.");
515 last;
520 if (defined $reldir) {
521 my $append = ($reldir eq '' ? '' : "/$reldir");
522 if ("$start$append" ne $here) {
523 my $mod = $wsHelper->modify_libpath($_, $reldir, $libfile);
524 if (defined $mod) {
525 $_ = $mod;
527 else {
528 s/$libfile/\$(top_builddir)$append\/$libfile/;
532 else {
533 my $mod = $wsHelper->modify_libpath($_, $reldir, $libfile);
534 if (defined $mod) {
535 $_ = $mod;
537 else {
538 $self->warning("No reldir found for $libname ($libfile).");
542 $look_for_libs = 0 if ($libcount == 0);
544 $look_for_libs = 1 if (/_LDADD = \\$/ || /_LIBADD = \\$/);
546 ## I have introduced a one line delay so that I can simplify
547 ## the automake template. If our current line is empty, then
548 ## we will remove the trailing backslash before printing the
549 ## previous line. Automake is horribly unforgiving so we must
550 ## avoid this situation at all cost.
551 if (defined $prev_line) {
552 $prev_line =~ s/\s*\\$// if ($_ =~ /^\s*$/);
553 print $fh $prev_line;
555 $prev_line = $_;
557 ## The one line delay requires that we print out the previous
558 ## line (if there was one) when we reach the end of the file.
559 if (defined $prev_line) {
560 $prev_line =~ s/\s*\\$//;
561 print $fh $prev_line;
564 close($pfh);
565 unlink("$outdir/$local");
566 print $fh $crlf;
568 else {
569 $errorString = "Unable to open $local for reading.";
570 $status = 0;
571 last;
576 ## If this is the top-level Makefile.am, it needs the directives to pass
577 ## autoconf/automake flags down the tree when running autoconf.
578 ## *** This may be too closely tied to how we have things set up in ACE,
579 ## even though it's recommended practice. ***
580 if ($status && $toplevel) {
581 my $m4inc = '-I m4';
582 print $fh $crlf,
583 'ACLOCAL = @ACLOCAL@', $crlf,
584 'ACLOCAL_AMFLAGS = ',
585 (defined $wsHelper ?
586 $wsHelper->modify_value('amflags', $m4inc) : $m4inc), $crlf,
587 'AUTOMAKE_OPTIONS = foreign', $crlf, $crlf,
588 (defined $wsHelper ?
589 $wsHelper->modify_value('extra', '') : '');
592 ## Finish up with the cleanup specs.
593 if ($status && @locals) {
594 ## There is no reason to emit this if there are no local targets.
595 ## An argument could be made that it shouldn't be emitted in any
596 ## case because it could be handled by CLEANFILES or a verbatim
597 ## clause.
599 print $fh '## Clean up template repositories, etc.', $crlf,
600 'clean-local:', $crlf,
601 "\t-rm -f *~ *.bak *.rpo *.sym lib*.*_pure_* core core.*",
602 $crlf,
603 "\t-rm -f gcctemp.c gcctemp so_locations *.ics", $crlf,
604 "\t-rm -rf cxx_repository ptrepository ti_files", $crlf,
605 "\t-rm -rf templateregistry ir.out", $crlf,
606 "\t-rm -rf ptrepository SunWS_cache Templates.DB", $crlf;
609 return $status, $errorString;
613 sub get_includedir {
614 my $self = shift;
615 my $value = $self->getcwd();
616 my $start = $self->getstartdir();
618 ## Take off the starting directory
619 $value =~ s/\Q$start\E//;
620 return $value;
624 sub edit_config_ac {
625 my($self, $file, $files) = @_;
626 my $fh = new FileHandle();
627 my $status = 0;
629 if (open($fh, $file)) {
630 my $crlf = $self->crlf();
631 my @in;
632 my @lines;
633 my $assoc = $self->get_associated_projects();
634 my $indent = '';
635 my %proj_dir_seen;
636 my $in_config_files = 0;
638 while(<$fh>) {
639 my $line = $_;
640 push(@lines, $line);
642 ## Remove comments and trailing space
643 $line =~ s/\bdnl\s+.*//;
644 $line =~ s/\s+$//;
646 if ($line eq '') {
648 elsif ($line =~ /^\s*if\s+test\s+["]?([^"]+)["]?\s*=\s*\w+;\s*then/) {
649 ## Entering an if test, save the name
650 my $name = $1;
651 $name =~ s/\s+$//;
652 $name =~ s/.*_build_//;
653 push(@in, $name);
655 elsif ($line =~ /^\s*if\s+test\s+-d\s+(.+);\s*then/) {
656 ## Entering an if test -d, save the name
657 my $name = $1;
658 $name =~ s/\s+$//;
659 $name =~ s/\$srcdir\///;
660 push(@in, $name);
662 elsif ($line =~ /^\s*fi$/) {
663 pop(@in);
665 elsif ($line =~ /^(\s*AC_CONFIG_FILES\s*\(\s*\[)/) {
666 ## Entering an AC_CONFIG_FILES section, start ignoring the entries
667 pop(@lines);
668 push(@lines, "$1\n");
669 $indent = ' ';
670 if ($lines[$#lines] =~ /^(\s+)/) {
671 $indent .= $1;
673 $in_config_files = 1;
675 elsif ($in_config_files) {
676 if ($line =~ /(.*)\]\s*\).*/) {
677 ## We've reached the end of the AC_CONFIG_FILES section
678 my $olast = pop(@lines);
679 if ($olast =~ /^[^\s]+(\s*\]\s*\).*)/) {
680 $olast = $1;
682 ## Add in the Makefiles for this configuration
683 if ($#in < 0 && !defined $proj_dir_seen{'.'}) {
684 push(@lines, $indent . 'Makefile' . $crlf);
685 $proj_dir_seen{'.'} = 1;
688 foreach my $dep (@$files) {
689 ## First things first, see if we've already seen this
690 ## project's directory. If we have, then there's nothing
691 ## else we need to do with it.
692 my $dep_dir = $self->mpc_dirname($dep);
693 if (!defined $proj_dir_seen{$dep_dir}) {
694 my $ok = 1;
695 my @dirs = split(/\//, $dep_dir);
696 my $base = $dep;
698 if ($base =~ s/\/.*//) {
699 my $found = 0;
700 foreach my $akey (keys %$assoc) {
701 if (defined $$assoc{$akey}->{$base} ||
702 defined $$assoc{$akey}->{uc($base)}) {
703 if ($#in >= 0) {
704 if (index($base, $in[0]) >= 0) {
705 if ($#in >= 1) {
706 $found = 1;
707 for(my $i = 0; $i <= $#in; $i++) {
708 if (!defined $dirs[$i] ||
709 index($dirs[$i], $in[$i]) < 0) {
710 $found = 0;
711 last;
715 else {
716 ## We need to see into the future here. :-)
717 ## If the second element of @dirs matches an
718 ## association key, we'll guess that there will
719 ## be a "build" section devoted to it.
720 if (!defined $dirs[1] ||
721 !defined $$assoc{$dirs[1]}) {
722 $found = 1;
727 else {
728 $found = 1;
730 last;
733 if ($#in >= 0) {
734 $ok = $found;
736 else {
737 $ok = !$found;
741 if ($ok) {
742 $proj_dir_seen{$dep_dir} = 1;
743 my $inter_dir = '';
744 foreach my $dep (@dirs) {
745 $inter_dir .= $dep;
746 if (!defined $proj_dir_seen{$inter_dir}) {
747 $proj_dir_seen{$inter_dir} = 1;
748 push(@lines, $indent . $inter_dir . "/Makefile$crlf");
750 $inter_dir .= '/';
752 push(@lines, $indent . $dep_dir . "/Makefile$crlf");
756 push(@lines, $olast);
757 $in_config_files = 0;
759 else {
760 ## Ignore the entry
761 pop(@lines);
765 close($fh);
767 ## Make a backup and create the new file
768 my $backup = $file . '.bak';
769 if (copy($file, $backup)) {
770 my @buf = stat($file);
771 if (defined $buf[8] && defined $buf[9]) {
772 utime($buf[8], $buf[9], $backup);
774 if (open($fh, ">$file")) {
775 foreach my $line (@lines) {
776 print $fh $line;
778 close($fh);
779 $status = 1;
782 else {
783 $self->warning("Unable to create backup file: $backup");
786 return $status;