From 1253550b4126fb28972becd97fb0296324250c1f Mon Sep 17 00:00:00 2001 From: Karl Berry Date: Thu, 28 May 2009 00:21:43 +0000 Subject: latexmk update (27may09) git-svn-id: svn://tug.org/texlive/trunk@13499 c570f23f-e606-0410-a88d-b1316a301751 --- Master/texmf-dist/scripts/latexmk/latexmk.pl | 321 +++++++++++++++++++++------ 1 file changed, 251 insertions(+), 70 deletions(-) (limited to 'Master/texmf-dist/scripts/latexmk') diff --git a/Master/texmf-dist/scripts/latexmk/latexmk.pl b/Master/texmf-dist/scripts/latexmk/latexmk.pl index 9e7beb249a1..7ae78471e4a 100755 --- a/Master/texmf-dist/scripts/latexmk/latexmk.pl +++ b/Master/texmf-dist/scripts/latexmk/latexmk.pl @@ -140,8 +140,8 @@ use warnings; $my_name = 'latexmk'; $My_name = 'Latexmk'; -$version_num = '4.05'; -$version_details = "$My_name, John Collins, 10 April 2009"; +$version_num = '4.07'; +$version_details = "$My_name, John Collins, 27 May 2009"; use Config; @@ -210,6 +210,25 @@ else { ## ## Modification log for 24 Sep 2008 onwards in detail ## +## 27 May 2009, John Collins V. 4.07 +## 23 May 2009, John Collins Try to work rationally when run of +## (pdf)latex does not produce +## output. +## Diagonostic when latex makes pdf or +## pdflatex makes dvi. +## 28 Apr 2009, John Collins Deal with case that file is written +## during run, but is not in database +## before run. +## 17 Apr 2009, John Collins V. 4.06 +## 14 Apr 2009, John Collins In parse_logB, clean up a bit more +## aggressively non-existent source files +## 11 Apr 2009, John Collins Capture ctrl/C and ctrl/break during wait +## loop in preview_continuous. Then +## control stays within latexmk on break +## from loop. It allows user to do +## postprocessing, like +## "latexmk -pvc file; cleanup;" +## 10 Apr 2009, John Collins Safer use of % in placeholders in commands ## 10 Apr 2009, John Collins V. 4.05 ## 3 Apr 2009, John Collins Change to a nicer #! line ## 26 Mar 2009, John Collins Case independence for one item in @@ -1641,10 +1660,11 @@ foreach $filename ( @file_list ) if ( $cleanup_mode > 0 ) { # Use parse_logB to get names of generated files. # It returns its results in the following variables: - local %dependents = (); # Maps files to status + local %dependents = (); # Maps files to status local @bbl_files = (); - local %idx_files = (); # Maps idx_file to (ind_file, base) - local %generated_log = (); # Lists generated files + local %idx_files = (); # Maps idx_file to (ind_file, base) + local %generated_log = (); # Lists generated files + local $primary_out = ''; # Actual output file (dvi or pdf) print "$My_name: Examining log file for generated files...\n"; &parse_logB; @@ -1791,7 +1811,7 @@ continue { if ( $failure_msg ) { #Remove trailing space $failure_msg =~ s/\s*$//; - warn "$My_name: Did not finish processing file: $failure_msg\n"; + warn "$My_name: Did not finish processing file:\n $failure_msg\n"; $failure = 1; } $failure_count ++; @@ -2392,11 +2412,12 @@ CHANGE: print "\n=== Watching for updated files. Use ctrl/C to stop ...\n"; } $waiting = 1; if ($diagnostics) { warn "WAITING\n"; } + &catch_break; + $have_break = 0; WAIT: while (1) { sleep($sleep_time); - &rdb_clear_change_record; - rdb_recurseA( [@targets], \&rdb_flag_changes_here ); - if ( &rdb_need_run ) { + if ($have_break) { last WAIT; } + if ( rdb_have_changes(@targets) ) { if (!$silent) { warn "$My_name: Need to remake files.\n"; &rdb_diagnose_changes( ' ' ); @@ -2410,8 +2431,14 @@ CHANGE: warn "$My_name: New file(s) found.\n"; last WAIT; } + if ($have_break) { last WAIT; } } # end WAIT: - $waiting = 0; if ($diagnostics) { warn "NOT WAITING\n"; } + &default_break; + if ($have_break) { + print "$My_name: User typed ctrl/C or ctrl/break. I'll stop.\n"; + exit; + } + $waiting = 0; if ($diagnostics) { warn "NOT WAITING\n"; } } #end infinite_loop CHANGE: } #END sub make_preview_continuousB @@ -2772,6 +2799,8 @@ sub parse_logB { # There's no need to do a search. # 4 = definitive, which in this subroutine is only # done for default dependents +# 5 = Had a missing file line. Now the file exists. +# 6 = File was written during run. (Overrides 5) # Treat the following specially, since they have special rules # @bbl_files to list of .bbl files. # %idx_files to map from .idx files to .ind files. @@ -2798,6 +2827,9 @@ sub parse_logB { @bbl_files = (); %idx_files = (); # Maps idx_file to (ind_file, base) %generated_log = (); + # $primary_out is actual output file (dvi or pdf) + # It is initialized before the call to this routine, to ensure + # a sensible default in case of misparsing $reference_changed = 0; $bad_reference = 0; @@ -2875,8 +2907,15 @@ LINE: # Font info line next LINE; } - if ( /^Output written on / ) { - # Latex message + if (/^No pages of output\./) { + $primary_out = ''; + warn "$My_name: Log file says no output from latex\n"; + next LINE; + } + if ( /^Output written on\s+(.*)\s+\(\d+\s+page/ ) { + $primary_out = $1; + warn "$My_name: Log file says output to '$1'\n" + unless $silent; next LINE; } if ( /^Overfull / @@ -2974,11 +3013,6 @@ LINE: if (/^\! LaTeX Error: / ) { next LINE; } - if (/^No pages of output\./) { - warn "$My_name: Log file says no output from latex\n" - unless $silent; - next LINE; - } INCLUDE_CANDIDATE: while ( /\((.*$)/ ) { # Filename found by @@ -3113,7 +3147,15 @@ CANDIDATE: foreach my $candidate (keys %dependents) { my $code = $dependents{$candidate}; if ( -e $candidate ) { - $dependents{$candidate} = 4; + if ( exists $generated_log{$candidate} ){ + $dependents{$candidate} = 6; + } + elsif ($code == 0) { + $dependents{$candidate} = 5; + } + else { + $dependents{$candidate} = 4; + } } elsif ($code == 1) { # Graphics file that is supposed to have been read. @@ -3137,11 +3179,23 @@ CANDIDATE: # which should include pathname if valid input file. # Name does not have pathname-characteristic character (hence # $code==2. - # Candidate file does not exist with given name + # We get here if candidate file does not exist with given name # Almost surely result of a misparsed line in log file. delete $dependents{$candidate}; push @misparse, $candidate; } + elsif ($code == 3) { + # Candidate is from '(...' construct in log file, for input file + # which should include pathname if valid input file. + # Name does have pathname-characteristic character (hence + # $code==3. + # But we get here only if candidate file does not exist with + # given name. + # Almost surely result of a misparsed line in log file. + # But with lower probability than $code == 2 + delete $dependents{$candidate}; + push @misparse, $candidate; + } elsif ($code == 0) { my ($base, $path, $ext) = fileparseA($candidate); $ext =~ s/^\.//; @@ -3171,7 +3225,11 @@ CANDIDATE: "$exist exist, $not_found were not found,\n", " and $missing appear not to exist.\n"; print "Dependents:\n"; - foreach (@dependents) { print " $_\n"; } + foreach (@dependents) { + print " '$_' "; + if ( $dependents{$_} == 6 ) { print " written by (pdf)latex";} + print "\n"; + } if ($not_found > 0) { print "Not found:\n"; foreach (@not_found) { print " $_\n"; } @@ -3190,13 +3248,7 @@ CANDIDATE: print "Apparent input files apparently from misunderstood lines in .log file:\n"; foreach ( @misparse ) { print " $_\n"; } } - print "Log file shows the following generated files: "; - foreach (keys %generated_log) { - print "'$_' "; - } - print "\n"; } - return 1; } #END parse_logB @@ -3667,12 +3719,36 @@ sub rdb_set_from_logB { local @bbl_files = (); local %idx_files = (); # Maps idx_file to (ind_file, base) local %generated_log = (); # Lists generated files found in log file + local $primary_out = $$Pdest; # output file (dvi or pdf) # The following are also returned, but are global, to be used by caller # $reference_changed, $bad_reference $bad_citation &parse_logB; + # Handle result on output file: + # 1. Non-existent output file, which is because of no content. + # This could either be because the source file has genuinely + # no content, or because of a missing input file. Since a + # missing input file might be correctable by a run of some + # other program whose running is provoked AFTER a run of + # (pdf)latex, we'll set a diagnostic and leave it to the + # rdb_makeB to handle after all circular dependencies are + # resolved. + # 2. The output file might be of a different kind than expected + # (i.e., dvi instead of pdf, or vv). This could + # legitimately occur when the source file (or an invoked + # package or class) sets \pdfoutput. + $missing_dvi_pdf = ''; + if ($primary_out eq '') { + warn "$My_name: For rule '$rule', no output was made\n"; + $missing_dvi_pdf = $$Pdest; + } + elsif ($primary_out ne $$Pdest) { + warn "$My_name: ===For rule '$rule', actual output '$primary_out'\n", + " ======appears not to match expected output '$$Pdest'\n"; + } + IDX_FILE: foreach my $idx_file ( keys %idx_files ) { my ($ind_file, $ind_base) = @{$idx_files{$idx_file}}; @@ -3726,7 +3802,25 @@ NEW_SOURCE: foreach my $new_source (keys %dependents) { print " ===Source file for rule '$rule': '$new_source'\n" if ($diagnostics); - rdb_ensure_file( $rule, $new_source ); + if ( ($dependents{$new_source} == 5) + || ($dependents{$new_source} == 6) ) { + # (a) File was detected in "No file..." line in log file. + # Typically file was searched for early in run of + # latex/pdflatex, was not found, and then was written + # later in run. + # or (b) File was written during run. + # In both cases, if file doesn't already exist in database, we + # don't know its previous status. Therefore we tell + # rdb_ensure_file that if it needs to add the file to its + # database, then the previous version of the file should be + # treated as non-existent, to ensure another run is forced. + rdb_ensure_file( $rule, $new_source, undef, 1 ); + } + else { + # But we don't need this precaution for ordinary user files (or + # for files that are generated outside of latex/pdflatex). + rdb_ensure_file( $rule, $new_source ); + } } my @more_sources = &rdb_set_dependentsA( $rule ); @@ -4234,6 +4328,7 @@ sub rdb_makeB { local %pass = (); local $failure = 0; # General accumulated error flag + local $missing_dvi_pdf = ''; # Did primary run fail to make its output file? local $runs = 0; local $too_many_runs = 0; local %rules_applied = (); @@ -4257,7 +4352,6 @@ sub rdb_makeB { print "MakeB: doing pre_primary and primary...\n"; } rdb_for_some( [@pre_primary, $primary], \&rdb_makeB1 ); - if ( ($runs > 0) && ! $too_many_runs ) { $retry_msg = 0; if ( $failure && $newrule_nofile ) { @@ -4277,6 +4371,12 @@ sub rdb_makeB { print "But in fact no new files made\n"; } } + if ( $missing_dvi_pdf ) { + # No output from primary, after completing circular dependence + warn "Failure to make '$missing_dvi_pdf'\n"; + $failure = 1; + last PASS; + } if ($failure && !$force_mode ) { last PASS; } if ($diagnostics) { print "MakeB: doing post_primary...\n"; @@ -4334,15 +4434,46 @@ sub rdb_makeB1 { # up-to-date. if ($diagnostics) { print " MakeB1 $rule\n"; } if ($failure & ! $force_mode) {return;} + if ( ! defined $pass{$rule} ) {$pass{$rule} = 0; } &rdb_clear_change_record; if ( ($$Prun_time == 0) && exists($possible_primaries{$rule}) ) { push @rules_never_run, $rule; $$Pout_of_date = 1; } else { - &rdb_flag_changes_here; + if ( $$Pdest && (! -e $$Pdest) ) { + # With a non-existent desintation, if we haven't made any passes + # through a rule, rerunning the rule is good, because the file + # may fail to exist because of being deleted by the user (for ex.) + # rather than because of a failure on a previous run. + # (We could do better with a flag in fdb file.) + # But after the first pass, the situation is different. + # For a primary rule (pdf)latex, the lack of a destination file + # could result from there being zero content due to a missing + # essential input file. The input file could be generated + # by a program to be run later (e.g., a cusdep or bibtex), + # so we should wait until all passes are completed before + # deciding a non-existent destination file is an error. + # For a custom dependency, the rule may be obsolete, and + # if the source file does not exist also, we should simply + # not run the rule, but not set an error condition. + # Any error will arise at the (pdf)latex level due to a + # missing source file at that level. + if ( ( $$Pcmd_type eq 'cusdep') && $$Psource && (! -e $$Psource) ) { + # No action + } + elsif ( $pass{$rule}==0) { + push @no_dest, $$Pdest; + $$Pout_of_date = 1; + } + if ( $$Pcmd_type eq 'primary' ) { + $missing_dvi_pdf = $$Pdest; + } + } } + &rdb_flag_changes_here; + if (!$$Pout_of_date) { #?? if ( ($$Pcmd_type eq 'primary') && (! $silent) ) { # print "Rule '$rule' up to date\n"; @@ -4352,7 +4483,7 @@ sub rdb_makeB1 { if ($diagnostics) { print " remake\n"; } if (!$silent) { print "$My_name: applying rule '$rule'...\n"; - &rdb_diagnose_changes( "Rule '$rule': "); + &rdb_diagnose_changes( "Rule '$rule': " ); } $rules_applied{$rule} = 1; $runs++; @@ -4387,12 +4518,10 @@ sub rdb_makeB1 { } elsif ( $$Pdest && ( !-e $$Pdest ) && (! $failure) ){ # If there is a destination to make, but for some reason - # it did not get made, then make sure a failure gets reported. - # But if the failure has already been reported, there's no need - # to report here, since that would give a generic error - # message instead of a specific one. - -## ??? 1 Sep. 2008, for cusdep no-file-exists issue + # it did not get made, and no other error was reported, + # then a priori there appears to be an error condition: + # the run failed. But there are two important cases in + # which this is a wrong diagnosis. if ( ( $$Pcmd_type eq 'cusdep') && $$Psource && (! -e $$Psource) ) { # However, if the rule is a custom dependency, this is not by # itself an error, if also the source file does not exist. In @@ -4405,12 +4534,21 @@ sub rdb_makeB1 { # So in this case, do NOT report an error $$Pout_of_date = 0; } + elsif ($$Pcmd_type eq 'primary' ) { + # For a primary rule, i.e., (pdf)latex, not to produce the + # expected output file may not be an error condition. + # Diagnostics were handled in parsing the log file. + # Special action in main loop inrdb_makeB1 + $missing_dvi_pdf = $$Pdest; + } else { $failure = 1; - $failure_msg = "'$rule' did not make '$$Pdest'"; } } - if ($return != 0) {$failure = 1;} + if ($return != 0) { + $failure = 1; + $failure_msg = "Run of rule '$rule' gave a non-zero error code"; + } } #END rdb_makeB1 #************************************************************ @@ -4625,14 +4763,23 @@ sub rdb_ext_cmd1 { #Set character to surround filenames: my $q = $quote_filenames ? '"' : ''; - foreach ($ext_cmd) { - s/%O/$options/g; - s/%R/$q$root_filename$q/g; - s/%B/$q$base$q/g; - s/%T/$q$texfile_name$q/g; - s/%S/$q$source$q/g; - s/%D/$q$dest$q/g; + + %subst = ( + '%O' => $options, + '%R' => $q.$root_filename.$q, + '%B' => $q.$base.$q, + '%T' => $q.$texfile_name.$q, + '%S' => $q.$source.$q, + '%D' => $q.$dest.$q, + '%%' => '%' # To allow literal %B, %R, etc, by %%B. + ); + + my @tokens = split /(%.)/, $ext_cmd; + foreach (@tokens) { + if (exists($subst{$_})) { $_ = $subst{$_}; } } + $ext_cmd = join '', @tokens; + # print "quote is '$q'; ext_cmd = '$ext_cmd'\n"; my ($pid, $return) = &Run_msg($ext_cmd); return $return; @@ -4652,6 +4799,7 @@ sub rdb_primary_run { my $return = 0; my $return_latex = &rdb_run1; + if (-e $$Pdest) { $missing_dvi_pdf = '';} ######### Analyze results of run: if ( ! -e "$root_filename.log" ) { @@ -4680,6 +4828,9 @@ sub rdb_primary_run { my $submake_return = &rdb_submakeB; &rdb_clear_change_record; &rdb_flag_changes_here; + if ($$Pout_of_date && !$silent) { + &rdb_diagnose_changes( "Rule '$rule': " ); + } $updated = 1; # Flag that some dependent file has been remade # Fix the state of the files as of now: this will solve the # problem of latex and pdflatex interfering with each other, @@ -4719,7 +4870,7 @@ sub rdb_clear_change_record { # Initialize diagnostics for reasons for running rule. @changed = (); @disappeared = (); - @no_dest = (); + @no_dest = (); # We are not now using this @rules_never_run = (); @rules_to_apply = (); # This is used in recursive application # of rdb_flag_changes_here, to list @@ -4734,24 +4885,6 @@ sub rdb_flag_changes_here { local $dest_mtime = 0; $dest_mtime = get_mtime($$Pdest) if ($$Pdest); rdb_do_files( \&rdb_file_change1); - if ( $$Pdest && (! -e $$Pdest) ) { -## ??? 1 Sep. 2008, for cusdep no-file-exists issue - if ( ( $$Pcmd_type eq 'cusdep') && $$Psource && (! -e $$Psource) ) { - # However, if the rule is a custom dependency, this is not by - # itself an error, if also the source file does not exist. In - # that case, we may have the situation that (1) the dest file is no - # longer needed by the tex file, and (2) therefore the user - # has deleted the source and dest files. After the next - # latex run and the consequent analysis of the log file, the - # cusdep rule will no longer be needed, and will be removed. - - # So in this case, do NOT report an error - } - else { - $$Pout_of_date = 1; - push @no_dest, $$Pdest; - } - } if ($$Pout_of_date) { push @rules_to_apply, $rule; } @@ -4809,9 +4942,11 @@ sub rdb_file_change1 { #************************************************************ -sub rdb_need_run { +sub rdb_have_changes { + &rdb_clear_change_record; + rdb_recurseA( [@_], \&rdb_flag_changes_here ); return ($#changed >= 0) || ($#no_dest >= 0) || ($#rules_to_apply >= 0); -} #END rdb_need_run +} #END rdb_have_changes #************************************************************ @@ -5183,23 +5318,35 @@ sub rdb_create_rule { #************************************************************ sub rdb_ensure_file { - # rdb_ensure_file( rule, file[, fromrule] ) + # rdb_ensure_file( rule, file[, fromrule[, set_not_exists]] ) # Ensures the source file item exists in the given rule. - # Initialize to current file state if the item is created. # Then if the fromrule is specified, set it for the file item. + # If the item is created, then: + # (a) by default initialize it to current file state. + # (b) but if the fourth argument, set_not_exists, is true, + # initialize the item as if the file does not exist. + # This case is typically used when the log file for a run + # of latex/pdflatex claims that the file was non-existent + # at the beginning of a run. #============ rule and file data set here ====================================== my $rule = shift; - local ( $new_file, $new_from_rule ) = @_; + local ( $new_file, $new_from_rule, $set_not_exists ) = @_; if ( ! rdb_rule_exists( $rule ) ) { die_trace( "$My_name: BUG in rdb_ensure_file: non-existent rule '$rule'" ); } if ( ! defined $new_file ) { die_trace( "$My_name: BUG in rdb_ensure_file: undefined file for '$rule'" ); } + if ( ! defined $set_not_exists ) { $set_not_exists = 0; } rdb_one_rule( $rule, sub{ if (! exists ${$PHsource}{$new_file} ) { - ${$PHsource}{$new_file} = [fdb_get($new_file), '', 0]; + if ( $set_not_exists ) { + ${$PHsource}{$new_file} = [0, -1, 0, '', 0]; + } + else { + ${$PHsource}{$new_file} = [fdb_get($new_file), '', 0]; + } } } ); @@ -6244,3 +6391,37 @@ sub finish_dir_stack { #************************************************************ #************************************************************ +# Break handling routines (for wait-loop in preview continuous) + +sub end_wait { + # Handler for break: Set global variable $have_break to 1. + # Some systems (e.g., MSWin reset) appear to reset the handler. + # So I'll re-enable it + &catch_break; + $have_break = 1; +} + +#======================== + +sub catch_break { +# Capture ctrl/C and ctrl/break. +# $SIG{INT} corresponds to ctrl/C on LINUX/?UNIX and MSWin +# $SIG{BREAK} corresponds to ctrl/break on MSWin, doesn't exist on LINUX + $SIG{INT} = \&end_wait; + if ( exists $SIG{BREAK} ) { + $SIG{BREAK} = \&end_wait; + } +} + +#======================== + +sub default_break { +# Arrange for ctrl/C and ctrl/break to give default behavior + $SIG{INT} = 'DEFAULT'; + if ( exists $SIG{BREAK} ) { + $SIG{BREAK} = 'DEFAULT'; + } +} + +#************************************************************ +#************************************************************ -- cgit v1.2.3