#!/usr/bin/env perl # On a UNIX-like system, the above enables latexmk to run independently # of the location of the perl executable. This line relies on the # existence of the program /usr/bin/env # If there is a problem for any reason, you can replace the first line of # this file by: #!/usr/bin/perl -w # with the path of the perl executable adjusted for your system. use warnings; # Delete #??!! when working # See ?? <=============================== ## ?? Issues with clean-up ## List of aux files deleted is those read, not those generated. ## Other files are generated by (pdf)latex; should they be deleted? ## (I have hooks for this). #======================================= #?? Force mode doesn't appear to do force (if error in latex file) #??? Get banner back in. #?? CORRECT DIAGNOSTICS ON CHANGED FILES IF THEY DIDN'T EXIST BEFORE #?? Further corrections to deal with disappeared source files for custom dependencies. # Message repeatedly appears about remake when source file of cusdep doesn't exist. #?? logfile w/o fdb file: don't set changed file, perhaps for generated exts. # Reconsider #?? Do proper run-stuff for bibtex, makeindex, cus-deps. OK I think # Parse and correctly find ist files # ATTEMPT TO ALLOW FILENAMES WITH SPACES: # (as of 1 Apr 2006, and then 14 Sep. 2007) # Problems: # A. Quoting filenames will not always work. # a. Under UNIX, quotes are legal in filenames, so when PERL # directly runs a binary, a quoted filename will be treated as # as a filename containing a quote character. But when it calls # a shell, the quotes are handled by the shell as quotes. # b. Under MSWin32, quotes are illegal filename characters, and tend # to be handled correctly. # c. But under cygwin, results are not so clear (there are many # combinations: native v. cygwin perl, native v cygwin programs # NT v. unix scripts, which shell is called. # B. TeX doesn't always handle filenames with spaces gracefully. # a. UNIX/LINUX: The version on gluon2 Mar 31, 2006 to Sep. 2007) # doesn't handle them at all. (TeX treats space as separator.) # b. At least some later versions actually do (Brad Miller e-mail, # Sep. 2007). # c. fptex [[e-TeXk, Version 3.141592-2.1 (Web2c 7.5.2)] does, on # my MSWin at home. In \input the filename must be in quotes. # d. Bibtex [BibTeX (Web2c 7.5.2) 0.99c on my MSWin system at home, # Sep. 2007] does not allow names of bibfiles to have spaces. # C. =====> Using the shell for command lines is not safe, since special # characters can cause lots of mayhem. # It will therefore be a good idea to sanitize filenames. # # I've sanitized all calls out: # a. system and exec use a single argument, which forces # use of shell, under all circumstances # Thus I can safely use quotes on filenames: They will be handled by # the shell under UNIX, and simply passed on to the program under MSWin32. # b. I reorganized Run, Run_Detached to use single command line # c. All calls to Run and Run_Detached have quoted filenames. # d. So if a space-free filename with wildcards is given on latexmk's # command line, and it globs to space-containing filename(s), that # works (fptex on home computer, native NT tex) # e. ====> But globbing fails: the glob function takes space as filename # separator. ==================== #================= TO DO ================ # # 1. See ?? ESPECIALLY $MSWin_fudge_break # 2. Check fudged conditions in looping and make_files # 3. Should not completely abort after a run that ends in failure from latex # Missing input files (including via custom dependency) should be checked for # a change in status # If sources for missing files from custom dependency # are available, then do a rerun # If sources of any kind become available rerun (esp. for pvc) # rerun # Must parse log_file after unsuccessful run of latex: it may give # information about missing files. # 4. Check file of bug reports and requests # 5. Rationalize bibtex warnings and errors. Two almost identical routines. # Should 1. Use single routine # 2. Convert errors to failure only in calling routine # 3. Save first warning/error. # ?? Use of generated_exts arrays and hashes needs rationalization # To do: # Rationalize again handling of include files. # Now I use kpsewhich to do searches, if file not found # (How do I avoid getting slowed down too much?) # Document the assumptions at each stage of processing algorithm. # Option to restart previewer automatically, if it dies under -pvc # Test for already running previewer gets wrong answer if another # process has the viewed file in its command line $my_name = 'latexmk'; $My_name = 'Latexmk'; $version_num = '4.31'; $version_details = "$My_name, John Collins, 30 March 2012"; use Config; use File::Copy; use File::Basename; use FileHandle; use File::Find; use List::Util qw( max ); use Cwd; # To be able to change cwd use Cwd "chdir"; # Ensure $ENV{PWD} tracks cwd use Digest::MD5; #use strict; # The following variables are assigned once and then used in symbolic # references, so we need to avoid warnings 'name used only once': use vars qw( $dvi_update_command $ps_update_command $pdf_update_command ); # Translation of signal names to numbers and vv: %signo = (); @signame = (); if ( defined $Config{sig_name} ) { $i = 0; foreach $name (split(' ', $Config{sig_name})) { $signo{$name} = $i; $signame[$i] = $name; $i++; } } else { warn "Something wrong with the perl configuration: No signals?\n"; } ## Copyright John Collins 1998-2012 ## (username collins at node phys.psu.edu) ## (and thanks to David Coppit (username david at node coppit.org) ## for suggestions) ## Copyright Evan McLean ## (modifications up to version 2) ## Copyright 1992 by David J. Musliner and The University of Michigan. ## (original version) ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 2 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; if not, write to the Free Software ## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 ## ## ## ## NEW FEATURES, since v. 2.0: ## 1. Correct algorithm for deciding how many times to run latex: ## based on whether source file(s) change between runs ## 2. Continuous preview works, and can be of ps file or dvi file ## 3. pdf creation by pdflatex possible ## 4. Defaults for commands are OS dependent. ## 5. Parsing of log file instead of source file is used to ## obtain dependencies, by default. ## ## Modification log from 9 Dec 2011 onwards in detail ## ## 12 Jan 2012 STILL NEED TO DOCUMENT some items below ## 29, 30 Mar 2012, John Collins Optimize file checking, and # calcs of MD5 ## 24 Jan 2012, John Collins Remove unneeded call to traceback ## 23 Jan 2012, John Collins Remove initial ./ from ./foo entries in .fls file ## 16 Jan 2012, John Collins Make aux and/or out directories if it/they ## don't exist ## 14 Jan 2012, John Collins Correct bug in parse_quotes ## 12 Jan 2012, John Collins $success_cmd, $compiling_cmd, $failure_cmd ## allow actions (e.g., to set window title) ## after successful compilation, before ## compilation, and after failure, in -pvc mode ## Thanks to Aasmud Ervik (12 Jan 2012) ## 2 Jan 2012, John Collins Add MikTeX-specific options to pass-through list ## Remove redundancy of subroutines rdb_ext_cmd and rdb_ext_cmd1 ## In rdb_one_file, give &$file_act null argument list ## 30 Dec 2011 STILL NEED TO DOCUMENT next items ## 30 Dec 2011, John Collins Add nostart to possible keywords in commands ## Insert start before command called from view ## 24 Dec 2011, John Collins Add -xelatex option ## Change OS-X defaults for viewers. ## 21 Dec 2011, John Collins Add options reproducing options of (pdf)latex ## 21 Dec 2011, John Collins Add -latexoption=... option ## 20 Dec 2011, John Collins Command specification string can start ## with "include routine" to invoke a Perl ## subroutine instead of an external cmd. ## 19 Dec 2011, John Collins Recorder option is now on by default. ## 13 Dec 2011, John Collins Add -M -MP and -MF options, like gcc. ## 9 Dec 2011, John Collins Use OS-dependent search path separator when ## when manipulating TEXINPUTS, etc. ## Correct treatment of current directory ## when modifying TEXINPUTS, etc ## ## 1998-2010, John Collins. Many improvements and fixes. ## See CHANGE-log.txt for full list, and CHANGES for summary ## ## Modified by Evan McLean (no longer available for support) ## Original script (RCS version 2.3) called "go" written by David J. Musliner ## ## 2.0 - Final release, no enhancements. LatexMk is no longer supported ## by the author. ## 1.9 - Fixed bug that was introduced in 1.8 with path name fix. ## - Fixed buglet in man page. ## 1.8 - Add not about announcement mailling list above. ## - Added texput.dvi and texput.aux to files deleted with -c and/or ## the -C options. ## - Added landscape mode (-l option and a bunch of RC variables). ## - Added sensing of "\epsfig{file=...}" forms in dependency generation. ## - Fixed path names when specified tex file is not in the current ## directory. ## - Fixed combined use of -pvc and -s options. ## - Fixed a bunch of speling errors in the source. :-) ## - Fixed bugs in xdvi patches in contrib directory. ## 1.7 - Fixed -pvc continuous viewing to reattach to pre-existing ## process correctly. ## - Added $pscmd to allow changing process grepping for different ## systems. ## 1.6 - Fixed buglet in help message ## - Fixed bugs in detection of input and include files. ## 1.5 - Removed test message I accidentally left in version 1.4 ## - Made dvips use -o option instead of stdout redirection as some ## people had problems with dvips not going to stdout by default. ## - Fixed bug in input and include file detection ## - Fixed dependency resolution process so it detects new .toc file ## and makeindex files properly. ## - Added dvi and postscript filtering options -dF and -pF. ## - Added -v version commmand. ## 1.4 - Fixed bug in -pvc option. ## - Made "-F" option include non-existant file in the dependency list. ## (RC variable: $force_include_mode) ## - Added .lot and .lof files to clean up list of extensions. ## - Added file "texput.log" to list of files to clean for -c. ## - LatexMk now handles file names in a similar fashion to latex. ## The ".tex" extension is no longer enforced. ## - Added $texfile_search RC variable to look for default files. ## - Fixed \input and \include so they add ".tex" extension if necessary. ## - Allow intermixing of file names and options. ## - Added "-d" and banner options (-bm, -bs, and -bi). ## (RC variables: $banner, $banner_message, $banner_scale, ## $banner_intensity, $tmpdir) ## - Fixed "-r" option to detect an command line syntax errors better. ## 1.3 - Added "-F" option, patch supplied by Patrick van der Smagt. ## 1.2 - Added "-C" option. ## - Added $clean_ext and $clean_full_ext variables for RC files. ## - Added custom dependency generation capabilities. ## - Added command line and variable to specify custom RC file. ## - Added reading of rc file in current directly. ## 1.1 - Fixed bug where Dependency file generation header is printed ## rependatively. ## - Fixed bug where TEXINPUTS path is searched for file that was ## specified with absolute an pathname. ## 1.0 - Ripped from script by David J. Musliner (RCS version 2.3) called "go" ## - Fixed a couple of file naming bugs ## e.g. when calling latex, left the ".tex" extension off the end ## of the file name which could do some interesting things ## with some file names. ## - Redirected output of dvips. My version of dvips was a filter. ## - Cleaned up the rc file mumbo jumbo and created a dependency file ## instead. Include dependencies are always searched for if a ## dependency file doesn't exist. The -i option regenerates the ## dependency file. ## Getting rid of the rc file stuff also gave the advantage of ## not being restricted to one tex file per directory. ## - Can specify multiple files on the command line or no files ## on the command line. ## - Removed lpr options stuff. I would guess that generally, ## you always use the same options in which case they can ## be set up from an rc file with the $lpr variable. ## - Removed the dviselect stuff. If I ever get time (or money :-) ) ## I might put it back in if I find myself needing it or people ## express interest in it. ## - Made it possible to view dvi or postscript file automatically ## depending on if -ps option selected. ## - Made specification of dvi file viewer seperate for -pv and -pvc ## options. ##----------------------------------------------------------------------- ## Explicit exit codes: ## 10 = bad command line arguments ## 11 = file specified on command line not found ## or other file not found ## 12 = failure in some part of making files ## 13 = error in initialization file ## 20 = probable bug ## or retcode from called program. #Line length in log file that indicates wrapping. # This number EXCLUDES line-end characters, and is one-based # It is the parameter max_print_line in the TeX program. (tex.web) $log_wrap = 79; ######################################################################### ## Default parsing and file-handling settings ## Array of reg-exps for patterns in log-file for file-not-found ## Each item is the string in a regexp, without the enclosing slashes. ## First parenthesized part is the filename. ## Note the need to quote slashes and single right quotes to make them ## appear in the regexp. ## Add items by push, e.g., ## push @file_not_found, '^No data file found `([^\\\']*)\\\''; ## will give match to line starting "No data file found `filename'" @file_not_found = ( '^No file\\s*(.*)\\.$', '^\\! LaTeX Error: File `([^\\\']*)\\\' not found\\.', '.*?:\\d*: LaTeX Error: File `([^\\\']*)\\\' not found\\.', '^LaTeX Warning: File `([^\\\']*)\\\' not found', '^Package .* [fF]ile `([^\\\']*)\\\' not found', 'Error: pdflatex \(file ([^\)]*)\): cannot find image file', ': File (.*) not found:\s*$', ); ## Hash mapping file extension (w/o period, e.g., 'eps') to a single regexp, # whose matching by a line in a file with that extension indicates that the # line is to be ignored in the calculation of the hash number (md5 checksum) # for the file. Typically used for ignoring datestamps in testing whether # a file has changed. # Add items e.g., by # $hash_calc_ignore_pattern{'eps'} = '^%%CreationDate: '; # This makes the hash calculation for an eps file ignore lines starting with # '%%CreationDate: ' # ?? Note that a file will be considered changed if # (a) its size changes # or (b) its hash changes # So it is useful to ignore lines in the hash calculation only if they # are of a fixed size (as with a date/time stamp). %hash_calc_ignore_pattern =(); ######################################################################### ## Default document processing programs, and related settings, ## These are mostly the same on all systems. ## Most of these variables represents the external command needed to ## perform a certain action. Some represent switches. ## Commands to invoke latex, pdflatex $latex = 'latex %O %S'; $pdflatex = 'pdflatex %O %S'; ## Default switches: $latex_default_switches = ''; $pdflatex_default_switches = ''; ## Switch(es) to make them silent: $latex_silent_switch = '-interaction=batchmode'; $pdflatex_silent_switch = '-interaction=batchmode'; # %input_extensions maps primary_rule_name to pointer to hash of file extensions # used for extensionless files specified in the source file by constructs # like \input{file} \includegraphics{file} # Could write #%input_extensions = ( 'latex' => { 'tex' => 1, 'eps' => 1 };, # 'pdflatex' => { 'tex' => 1, 'pdf' => 1, 'jpg' => 1, 'png' => 1 }; ); # Instead we'll exercise the user-friendly access routines: add_input_ext( 'latex', 'tex', 'eps' ); add_input_ext( 'pdflatex', 'tex', 'jpg', 'pdf', 'png' ); #show_input_ext( 'latex' ); show_input_ext( 'pdflatex' ); # Information about options to latex and pdflatex that latexmk will simply # pass through to (pdf)latex # Option without arg. maps to itself. # Option with arg. maps the option part to the full specification # e.g., -kpathsea-debug => -kpathsea-debug=NUMBER %allowed_latex_options = (); %allowed_latex_options_with_arg = (); foreach ( ##### # TeXLive options "-draftmode switch on draft mode (generates no output PDF)", "-enc enable encTeX extensions such as \\mubyte", "-etex enable e-TeX extensions", "-file-line-error enable file:line:error style messages", "-no-file-line-error disable file:line:error style messages", "-fmt=FMTNAME use FMTNAME instead of program name or a %& line", "-halt-on-error stop processing at the first error", "-interaction=STRING set interaction mode (STRING=batchmode/nonstopmode/\n". " scrollmode/errorstopmode)", "-ipc send DVI output to a socket as well as the usual\n". " output file", "-ipc-start as -ipc, and also start the server at the other end", "-kpathsea-debug=NUMBER set path searching debugging flags according to\n". " the bits of NUMBER", "-mktex=FMT enable mktexFMT generation (FMT=tex/tfm/pk)", "-no-mktex=FMT disable mktexFMT generation (FMT=tex/tfm/pk)", "-mltex enable MLTeX extensions such as \charsubdef", "-output-comment=STRING use STRING for DVI file comment instead of date\n". " (no effect for PDF)", "-output-format=FORMAT use FORMAT for job output; FORMAT is `dvi\" or `pdf\"", "-parse-first-line enable parsing of first line of input file", "-no-parse-first-line disable parsing of first line of input file", "-progname=STRING set program (and fmt) name to STRING", "-shell-escape enable \\write18{SHELL COMMAND}", "-no-shell-escape disable \\write18{SHELL COMMAND}", "-shell-restricted enable restricted \\write18", "-src-specials insert source specials into the DVI file", "-src-specials=WHERE insert source specials in certain places of\n". " the DVI file. WHERE is a comma-separated value\n". " list: cr display hbox math par parend vbox", "-synctex=NUMBER generate SyncTeX data for previewers if nonzero", "-translate-file=TCXNAME use the TCX file TCXNAME", "-8bit make all characters printable by default", ##### # MikTeX options not in TeXLive "-alias=app pretend to be app", "-buf-size=n maximum number of characters simultaneously present\n". " in current lines", "-c-style-errors C-style error messages", "-disable-installer disable automatic installation of missing packages", "-disable-pipes disable input (output) from (to) child processes", "-disable-write18 disable the \\write18{command} construct", "-dont-parse-first-line disable checking whether the first line of the main\n". " input file starts with %&", "-enable-enctex enable encTeX extensions such as \\mubyte", "-enable-installer enable automatic installation of missing packages", "-enable-mltex enable MLTeX extensions such as \charsubdef", "-enable-pipes enable input (output) from (to) child processes", "-enable-write18 fully enable the \\write18{command} construct", "-error-line=n set the width of context lines on terminal error\n". " messages", "-extra-mem-bot=n set the extra size (in memory words) for large data\n". " structures", "-extra-mem-top=n set the extra size (in memory words) for chars,\n". " tokens, et al", "-font-max=n set the maximum internal font number", "-font-mem-size=n set the size, in TeX memory words, of the font memory", "-half-error-line=n set the width of first lines of contexts in terminal\n". " error messages", "-hash-extra=n set the extra space for the hash table of control\n". " sequences", "-job-time=file set the time-stamp of all output files equal to\n". " file'stime-stamp", "-main-memory=n change the total size (in memory words) of the main\n". " memory array", "-max-in-open=n set the maximum number of input files and error\n". " insertions that can be going on simultaneously", "-max-print-line=n set the width of longest text lines output", "-max-strings=n set the maximum number of strings", "-nest-size=n set the maximum number of semantic levels\n". " simultaneously active", "-no-c-style-errors standard error messages", "-param-size=n set the the maximum number of simultaneous macro\n". " parameters", "-pool-size=n set the maximum number of characters in strings", "-record-package-usages=file record all package usages and write them into\n". " file", "-restrict-write18 partially enable the \\write18{command} construct", "-save-size=n set the the amount of space for saving values\n". " outside of current group", "-stack-size=n set the maximum number of simultaneous input sources", "-string-vacancies=n set the minimum number of characters that should be\n". " available for the user's control sequences and font\n". " names", "-tcx=name process the TCX table name", "-time-statistics show processing time statistics", "-trace enable trace messages", "-trace=tracestreams enable trace messages. The tracestreams argument is\n". " a comma-separated list of trace stream names", "-trie-size=n set the amount of space for hyphenation patterns", "-undump=name use name as the name of the format to be used,\n". " instead of the name by which the program was\n". " called or a %& line.", ##### # Options passed to (pdf)latex that have special processing by latexmk, # so they are commented out here. #-jobname=STRING set the job name to STRING #-aux-directory=dir Set the directory dir to which auxiliary files are written #-output-directory=DIR use existing DIR as the directory to write files in #-quiet #-recorder enable filename recorder # # Options with different processing by latexmk than (pdf)latex #-help #-version # # Options NOT used by latexmk #-includedirectory=dir prefix dir to the search path #-initialize become the INI variant of the compiler #-ini be pdfinitex, for dumping formats; this is implicitly # true if the program name is `pdfinitex' ) { if ( /^([^\s=]+)=/ ) { $allowed_latex_options_with_arg{$1} = $_; } elsif ( /^([^\s=]+)\s/ ) { $allowed_latex_options{$1} = $_; } else { $allowed_latex_options{$_} = $_; } } # Arrays of options that will be added to latex and pdflatex. # These need to be stored until after the command line parsing is finished, # in case the values of $latex and/or $pdflatex change after an option # is added. @extra_latex_options = (); @extra_pdflatex_options = (); ## Command to invoke biber & bibtex $biber = 'biber %O %B'; $bibtex = 'bibtex %O %B'; # Switch(es) to make biber & bibtex silent: $biber_silent_switch = '--onlylog'; $bibtex_silent_switch = '-terse'; $bibtex_use = 1; # Whether to actually run bibtex to update bbl files # 0: Never run bibtex # 1: Run bibtex only if the bibfiles exists # according to kpsewhich, and the bbl files # appear to be out-of-date # 2: Run bibtex when the bbl files are out-of-date # In any event bibtex is only run if the log file # indicates that the document uses bbl files. ## Command to invoke makeindex $makeindex = 'makeindex %O -o %D %S'; # Switch(es) to make makeinex silent: $makeindex_silent_switch = '-q'; ## Command to convert dvi file to pdf file directly: $dvipdf = 'dvipdf %O %S %D'; ## Command to convert dvi file to ps file: $dvips = 'dvips %O -o %D %S'; ## Command to convert dvi file to ps file in landscape format: $dvips_landscape = 'dvips -tlandscape %O -o %D %S'; # Switch(es) to get dvips to make ps file suitable for conversion to good pdf: # (If this is not used, ps file and hence pdf file contains bitmap fonts # (type 3), which look horrible under acroread. An appropriate switch # ensures type 1 fonts are generated. You can put this switch in the # dvips command if you prefer.) $dvips_pdf_switch = '-P pdf'; # Switch(es) to make dvips silent: $dvips_silent_switch = '-q'; ## Command to convert ps file to pdf file: $ps2pdf = 'ps2pdf %O %S %D'; ## Command to search for tex-related files $kpsewhich = 'kpsewhich %S'; ## Command to run make: $make = 'make'; ##Printing: $print_type = 'ps'; # When printing, print the postscript file. # Possible values: 'dvi', 'ps', 'pdf', 'none' ## Which treatment of default extensions and filenames with ## multiple extensions is used, for given filename on ## tex/latex's command line? See sub find_basename for the ## possibilities. ## Current tex's treat extensions like UNIX teTeX: $extension_treatment = 'unix'; $dvi_update_signal = undef; $ps_update_signal = undef; $pdf_update_signal = undef; $dvi_update_command = undef; $ps_update_command = undef; $pdf_update_command = undef; $new_viewer_always = 0; # If 1, always open a new viewer in pvc mode. # If 0, only open a new viewer if no previous # viewer for the same file is detected. $quote_filenames = 1; # Quote filenames in external commands $del_dir = ''; # Directory into which cleaned up files are to be put. # If $del_dir is '', just delete the files ######################################################################### ################################################################ ## Special variables for system-dependent fudges, etc. $log_file_binary = 0; # Whether to treat log file as binary # Normally not, since the log file SHOULD be pure text. # But Miktex 2.7 sometimes puts binary characters # in it. (Typically in construct \OML ... after # overfull box with mathmode.) # Sometimes there is ctrl/Z, which is not only non-text, # but is end-of-file marker for MS-Win in text mode. $MSWin_fudge_break = 1; # Give special treatment to ctrl/C and ctrl/break # in -pvc mode under MSWin # Under MSWin32 (at least with perl 5.8 and WinXP) # when latexmk is running another program, and the # user gives ctrl/C or ctrl/break, to stop the # daughter program, not only does it reach # the daughter, but also latexmk/perl, so # latexmk is stopped also. In -pvc mode, # this is not normally desired. So when the # $MSWin_fudge_break variable is set, # latexmk arranges to ignore ctrl/C and # ctrl/break during processing of files; # only the daughter programs receive them. # This fudge is not applied in other # situations, since then having latexmk also # stopping because of the ctrl/C or # ctrl/break signal is desirable. # The fudge is not needed under UNIX (at least # with Perl 5.005 on Solaris 8). Only the # daughter programs receive the signal. In # fact the inverse would be useful: In # normal processing, as opposed to -pvc, if # force mode (-f) is set, a ctrl/C is # received by a daughter program does not # also stop latexmk. Under tcsh, we get # back to a command prompt, while latexmk # keeps running in the background! ################################################################ # System-dependent overrides: if ( $^O eq "MSWin32" ) { # Pure MSWindows configuration ## Configuration parameters: ## Use first existing case for $tmpdir: $tmpdir = $ENV{TMPDIR} || $ENV{TEMP} || '.'; $log_file_binary = 1; # Protect against ctrl/Z in log file from # Miktex 2.7. ## List of possibilities for the system-wide initialization file. ## The first one found (if any) is used. @rc_system_files = ( 'C:/latexmk/LatexMk' ); $search_path_separator = ';'; # Separator of elements in search_path # For a pdf-file, "start x.pdf" starts the pdf viewer associated with # pdf files, so no program name is needed: $pdf_previewer = 'start %O %S'; $ps_previewer = 'start %O %S'; $ps_previewer_landscape = $ps_previewer; $dvi_previewer = 'start %O %S'; $dvi_previewer_landscape = "$dvi_previewer"; # Viewer update methods: # 0 => auto update: viewer watches file (e.g., gv) # 1 => manual update: user must do something: e.g., click on window. # (e.g., ghostview, MSWIN previewers, acroread under UNIX) # 2 => send signal. Number of signal in $dvi_update_signal, # $ps_update_signal, $pdf_update_signal # 3 => viewer can't update, because it locks the file and the file # cannot be updated. (acroread under MSWIN) # 4 => run a command to force the update. The commands are # specified by the variables $dvi_update_command, # $ps_update_command, $pdf_update_command $dvi_update_method = 1; $ps_update_method = 1; $pdf_update_method = 3; # acroread locks the pdf file # Use NONE as flag that I am not implementing some commands: $lpr = 'NONE $lpr variable is not configured to allow printing of ps files'; $lpr_dvi = 'NONE $lpr_dvi variable is not configured to allow printing of dvi files'; $lpr_pdf = 'NONE $lpr_pdf variable is not configured to allow printing of pdf files'; # The $pscmd below holds a command to list running processes. It # is used to find the process ID of the viewer looking at the # current output file. The output of the command must include the # process number and the command line of the processes, since the # relevant process is identified by the name of file to be viewed. # Its use is not essential. $pscmd = 'NONE $pscmd variable is not configured to detect running processes'; $pid_position = -1; # offset of PID in output of pscmd. # Negative means I cannot use ps } elsif ( $^O eq "cygwin" ) { # The problem is a mixed MSWin32 and UNIX environment. # Perl decides the OS is cygwin in two situations: # 1. When latexmk is run from a cygwin shell under a cygwin # environment. Perl behaves in a UNIX way. This is OK, since # the user is presumably expecting UNIXy behavior. # 2. When CYGWIN exectuables are in the path, but latexmk is run # from a native NT shell. Presumably the user is expecting NT # behavior. But perl behaves more UNIXy. This causes some # clashes. # The issues to handle are: # 1. Perl sees both MSWin32 and cygwin filenames. This is # normally only an advantage. # 2. Perl uses a UNIX shell in the system command # This is a nasty problem: under native NT, there is a # start command that knows about NT file associations, so that # we can do, e.g., (under native NT) system("start file.pdf"); # But this won't work when perl has decided the OS is cygwin, # even if it is invoked from a native NT command line. An # NT command processor must be used to deal with this. # 3. External executables can be native NT (which only know # NT-style file names) or cygwin executables (which normally # know both cygwin UNIX-style file names and NT file names, # but not always; some do not know about drive names, for # example). # Cygwin executables for tex and latex may only know cygwin # filenames. # 4. The BIBINPUTS environment variables may be # UNIX-style or MSWin-style depending on whether native NT or # cygwin executables are used. They are therefore parsed # differently. Here is the clash: # a. If a user is running under an NT shell, is using a # native NT installation of tex (e.g., fptex or miktex), # but has the cygwin executables in the path, then perl # detects the OS as cygwin, but the user needs NT # behavior from latexmk. # b. If a user is running under an UNIX shell in a cygwin # environment, and is using the cygwin installation of # tex, then perl detects the OS as cygwin, and the user # needs UNIX behavior from latexmk. # Latexmk has no way of detecting the difference. The two # situations may even arise for the same user on the same # computer simply by changing the order of directories in the # path environment variable ## Configuration parameters: We'll assume native NT executables. ## The user should override if they are not. # This may fail: perl converts MSWin temp directory name to cygwin # format. Names containing this string cannot be handled by native # NT executables. $tmpdir = $ENV{TMPDIR} || $ENV{TEMP} || '.'; ## List of possibilities for the system-wide initialization file. ## The first one found (if any) is used. ## We could stay with MSWin files here, since cygwin perl understands them ## @rc_system_files = ( 'C:/latexmk/LatexMk' ); ## But they are deprecated in v. 1.7. So use the UNIX version, prefixed ## with a cygwin equivalent of the MSWin location @rc_system_files = ( '/cygdrive/c/latexmk/LatexMk', '/opt/local/share/latexmk/LatexMk', '/usr/local/share/latexmk/LatexMk', '/usr/local/lib/latexmk/LatexMk' ); $search_path_separator = ';'; # Separator of elements in search_path # This is tricky. The search_path_separator depends on the kind # of executable: native NT v. cygwin. # So the user will have to override this. # We will assume that files can be viewed by native NT programs. # Then we must fix the start command/directive, so that the # NT-native start command of a cmd.exe is used. # For a pdf-file, "start x.pdf" starts the pdf viewer associated with # pdf files, so no program name is needed: $start_NT = "cmd /c start \"\""; $pdf_previewer = "$start_NT %O %S"; $ps_previewer = "$start_NT %O %S"; $ps_previewer_landscape = $ps_previewer; $dvi_previewer = "$start_NT %O %S"; $dvi_previewer_landscape = $dvi_previewer; # Viewer update methods: # 0 => auto update: viewer watches file (e.g., gv) # 1 => manual update: user must do something: e.g., click on window. # (e.g., ghostview, MSWIN previewers, acroread under UNIX) # 2 => send signal. Number of signal in $dvi_update_signal, # $ps_update_signal, $pdf_update_signal # 3 => viewer can't update, because it locks the file and the file # cannot be updated. (acroread under MSWIN) $dvi_update_method = 1; $ps_update_method = 1; $pdf_update_method = 3; # acroread locks the pdf file # Use NONE as flag that I am not implementing some commands: $lpr = 'NONE $lpr variable is not configured to allow printing of ps files'; $lpr_dvi = 'NONE $lpr_dvi variable is not configured to allow printing of dvi files'; $lpr_pdf = 'NONE $lpr_pdf variable is not configured to allow printing of pdf files'; # The $pscmd below holds a command to list running processes. It # is used to find the process ID of the viewer looking at the # current output file. The output of the command must include the # process number and the command line of the processes, since the # relevant process is identified by the name of file to be viewed. # Its use is not essential. # When the OS is detected as cygwin, there are two possibilities: # a. Latexmk was run from an NT prompt, but cygwin is in the # path. Then the cygwin ps command will not see commands # started from latexmk. So we cannot use it. # b. Latexmk was started within a cygwin environment. Then # the ps command works as we need. # Only the user, not latemk knows which, so we default to not # using the ps command. The user can override this in a # configuration file. $pscmd = 'NONE $pscmd variable is not configured to detect running processes'; $pid_position = -1; # offset of PID in output of pscmd. # Negative means I cannot use ps } else { # Assume anything else is UNIX or clone ## Configuration parameters: ## Use first existing case for $tmpdir: $tmpdir = $ENV{TMPDIR} || '/tmp'; ## List of possibilities for the system-wide initialization file. ## The first one found (if any) is used. ## Normally on a UNIX it will be in a subdirectory of /opt/local/share or ## /usr/local/share, depending on the local conventions. ## /usr/local/lib/latexmk/LatexMk is put in the list for ## compatibility with older versions of latexmk. @rc_system_files = ( '/opt/local/share/latexmk/LatexMk', '/usr/local/share/latexmk/LatexMk', '/usr/local/lib/latexmk/LatexMk' ); $search_path_separator = ':'; # Separator of elements in search_path $dvi_update_signal = $signo{USR1} if ( defined $signo{USR1} ); # Suitable for xdvi $ps_update_signal = $signo{HUP} if ( defined $signo{HUP} ); # Suitable for gv $pdf_update_signal = $signo{HUP} if ( defined $signo{HUP} ); # Suitable for gv ## default document processing programs. # Viewer update methods: # 0 => auto update: viewer watches file (e.g., gv) # 1 => manual update: user must do something: e.g., click on window. # (e.g., ghostview, MSWIN previewers, acroread under UNIX) # 2 => send signal. Number of signal in $dvi_update_signal, # $ps_update_signal, $pdf_update_signal # 3 => viewer can't update, because it locks the file and the file # cannot be updated. (acroread under MSWIN) # 4 => Run command to update. Command in $dvi_update_command, # $ps_update_command, $pdf_update_command. $dvi_previewer = 'start xdvi %O %S'; $dvi_previewer_landscape = 'start xdvi -paper usr %O %S'; if ( defined $dvi_update_signal ) { $dvi_update_method = 2; # xdvi responds to signal to update } else { $dvi_update_method = 1; } # if ( defined $ps_update_signal ) { # $ps_update_method = 2; # gv responds to signal to update # $ps_previewer = 'start gv -nowatch'; # $ps_previewer_landscape = 'start gv -swap -nowatch'; # } else { # $ps_update_method = 0; # gv -watch watches the ps file # $ps_previewer = 'start gv -watch'; # $ps_previewer_landscape = 'start gv -swap -watch'; # } # Turn off the fancy options for gv. Regular gv likes -watch etc # GNU gv likes --watch etc. User must configure $ps_update_method = 0; # gv -watch watches the ps file $ps_previewer = 'start gv %O %S'; $ps_previewer_landscape = 'start gv -swap %O %S'; $pdf_previewer = 'start acroread %O %S'; $pdf_update_method = 1; # acroread under unix needs manual update $lpr = 'lpr %O %S'; # Assume lpr command prints postscript files correctly $lpr_dvi = 'NONE $lpr_dvi variable is not configured to allow printing of dvi files'; $lpr_pdf = 'NONE $lpr_pdf variable is not configured to allow printing of pdf files'; # The $pscmd below holds a command to list running processes. It # is used to find the process ID of the viewer looking at the # current output file. The output of the command must include the # process number and the command line of the processes, since the # relevant process is identified by the name of file to be viewed. # Uses: # 1. In preview_continuous mode, to save running a previewer # when one is already running on the relevant file. # 2. With xdvi in preview_continuous mode, xdvi must be # signalled to make it read a new dvi file. # # The following works on Solaris, LINUX, HP-UX, IRIX # Use -f to get full listing, including command line arguments. # Use -u $ENV{CMD} to get all processes started by current user (not just # those associated with current terminal), but none of other users' # processes. $pscmd = "ps -f -u $ENV{USER}"; $pid_position = 1; # offset of PID in output of pscmd; first item is 0. if ( $^O eq "linux" ) { # Ps on Redhat (at least v. 7.2) appears to truncate its output # at 80 cols, so that a long command string is truncated. # Fix this with the --width option. This option works under # other versions of linux even if not necessary (at least # for SUSE 7.2). # However the option is not available under other UNIX-type # systems, e.g., Solaris 8. # But (19 Aug 2010), the truncation doesn't happen on RHEL4 and 5, # unless the output is written to a terminal. So the --width # option is now unnecessary # $pscmd = "ps --width 200 -f -u $ENV{USER}"; } elsif ( $^O eq "darwin" ) { # OS-X on Macintosh # open starts command associated with a file. # For pdf, this is set by default to OS-X's preview, which is suitable. # Manual update is simply by clicking on window etc, which is OK. # For ps, this is set also to preview. This works, but since it # converts the file to pdf and views the pdf file, it doesn't # see updates, and a refresh cannot be done. This is far from # optimal. # For a full installation of MacTeX, which is probably the most common # on OS-X, an association is created between dvi files and TeXShop. # This also converts the file to pdf, so again while it works, it # does not deal with changed dvi files, as far as I can see. $pdf_previewer = 'open %S'; $pdf_update_method = 1; # manual $dvi_previewer = $dvi_previewer_landscape = 'NONE'; $ps_previewer = $ps_previewer_landscape = 'NONE'; # Others $lpr_pdf = 'lpr %O %S'; $pscmd = "ps -ww -u $ENV{USER}"; } } ## default parameters $auto_rc_use = 1; # Whether to read rc files automatically $max_repeat = 5; # Maximum times I repeat latex. Normally # 3 would be sufficient: 1st run generates aux file, # 2nd run picks up aux file, and maybe toc, lof which # contain out-of-date information, e.g., wrong page # references in toc, lof and index, and unresolved # references in the middle of lines. But the # formatting is more-or-less correct. On the 3rd # run, the page refs etc in toc, lof, etc are about # correct, but some slight formatting changes may # occur, which mess up page numbers in the toc and lof, # Hence a 4th run is conceivably necessary. # At least one document class (JHEP.cls) works # in such a way that a 4th run is needed. # We allow an extra run for safety for a # maximum of 5. Needing further runs is # usually an indication of a problem; further # runs may not resolve the problem, and # instead could cause an infinite loop. $clean_ext = ""; # space separated extensions of files that are # to be deleted when doing cleanup, beyond # standard set $clean_full_ext = ""; # space separated extensions of files that are # to be deleted when doing cleanup_full, beyond # standard set and those in $clean_ext @cus_dep_list = (); # Custom dependency list @default_files = ( '*.tex' ); # Array of LaTeX files to process when # no files are specified on the command line. # Wildcards allowed # Best used for project specific files. @default_excluded_files = ( ); # Array of LaTeX files to exclude when using # @default_files, i.e., when no files are specified # on the command line. # Wildcards allowed # Best used for project specific files. $texfile_search = ""; # Specification for extra files to search for # when no files are specified on the command line # and the @default_files variable is empty. # Space separated, and wildcards allowed. # These files are IN ADDITION to *.tex in current # directory. # This variable is obsolete, and only in here for # backward compatibility. $fdb_ext = 'fdb_latexmk'; # Extension for the file for latexmk's # file-database # Make it long to avoid possible collisions. $fdb_ver = 3; # Version number for kind of fdb_file. $jobname = ''; # Jobname: as with current tex, etc indicates # basename of generated files. # Defined so that --jobname=STRING on latexmk's # command line has same effect as with current # tex, etc. (If $jobname is non-empty, then # the --jobname=... option is used on tex.) $out_dir = ''; # Directory for output files. # Cf. --output-directory of current (pdf)latex $aux_dir = ''; # Directory for aux files (log, aux, etc). # Cf. --aux-directory of current (pdf)latex in MiKTeX. ## default flag settings. $recorder = 1; # Whether to use recorder option on latex/pdflatex $silent = 0; # silence latex's messages? $landscape_mode = 0; # default to portrait mode # The following two arrays contain lists of extensions (without # period) for files that are read in during a (pdf)LaTeX run but that # are generated automatically from the previous run, as opposed to # being user generated files (directly or indirectly from a custom # dependency). These files get two kinds of special treatment: # 1. In clean up, where depending on the kind of clean up, some # or all of these generated files are deleted. # (Note that special treatment is given to aux files.) # 2. In analyzing the results of a run of (pdf)LaTeX, to # determine if another run is needed. With an error free run, # a rerun should be provoked by a change in any source file, # whether a user file or a generated file. But with a run # that ends in an error, only a change in a user file during # the run (which might correct the error) should provoke a # rerun, but a change in a generated file should not. # These arrays can be user-configured. @generated_exts = ( 'aux', 'bcf', 'fls', 'idx', 'ind', 'lof', 'lot', 'out', 'toc' ); # N.B. 'out' is generated by hyperref package # Which kinds of file do I have requests to make? # If no requests at all are made, then I will make dvi file # If particular requests are made then other files may also have to be # made. E.g., ps file requires a dvi file $dvi_mode = 0; # No dvi file requested $postscript_mode = 0; # No postscript file requested $pdf_mode = 0; # No pdf file requested to be made by pdflatex # Possible values: # 0 don't create pdf file # 1 to create pdf file by pdflatex # 2 to create pdf file by ps2pdf # 3 to create pdf file by dvipdf $view = 'default'; # Default preview is of highest of dvi, ps, pdf $sleep_time = 2; # time to sleep b/w checks for file changes in -pvc mode $banner = 0; # Non-zero if we have a banner to insert $banner_scale = 220; # Original default scale $banner_intensity = 0.95; # Darkness of the banner message $banner_message = 'DRAFT'; # Original default message $do_cd = 0; # Do not do cd to directory of source file. # Thus behave like latex. $dependents_list = 0; # Whether to display list(s) of dependencies $dependents_phony = 0; # Whether list(s) of dependencies includes phony targets # (as with 'gcc -MP'). $deps_file = '-'; # File for dependency list output. Default stdout. $rules_list = 0; # Whether to display list(s) of dependencies @dir_stack = (); # Stack of pushed directories. $cleanup_mode = 0; # No cleanup of nonessential LaTex-related files. # $cleanup_mode = 0: no cleanup # $cleanup_mode = 1: full cleanup # $cleanup_mode = 2: cleanup except for dvi, # dviF, pdf, ps, & psF $cleanup_fdb = 0; # No removal of file for latexmk's file-database $cleanup_only = 0; # When doing cleanup, do not go-on to making files $cleanup_includes_generated = 0; # Determines whether cleanup deletes files generated by # custom dependencies $cleanup_includes_cusdep_generated = 0; # Determines whether cleanup deletes files generated by # (pdf)latex (found from \openout lines in log file). $diagnostics = 0; $dvi_filter = ''; # DVI filter command $ps_filter = ''; # Postscript filter command $force_mode = 0; # =1 to force processing past errors $go_mode = 0; # =1 to force processing regardless of time-stamps # =2 full clean-up first $preview_mode = 0; $preview_continuous_mode = 0; $printout_mode = 0; # Don't print the file $show_time = 0; @timings = (); $processing_time1 = processing_time(); $use_make_for_missing_files = 0; # Whether to use make to try to make missing files. # Do we make view file in temporary then move to final destination? # (To avoid premature updating by viewer). $always_view_file_via_temporary = 0; # Set to 1 if viewed file is always # made through a temporary. $pvc_view_file_via_temporary = 1; # Set to 1 if only in -pvc mode is viewed # file made through a temporary. # State variables initialized here: $updated = 0; # Flags when something has been remade # Used to allow convenient user message in -pvc mode $waiting = 0; # Flags whether we are in loop waiting for an event # Used to avoid unnecessary repeated o/p in wait loop # Used for some results of parsing log file: $reference_changed = 0; $bad_reference = 0; $bad_citation = 0; # Set search paths for includes. # Set them early so that they can be overridden $BIBINPUTS = $ENV{'BIBINPUTS'}; if (!$BIBINPUTS) { $BIBINPUTS = '.'; } # Convert search paths to arrays: # If any of the paths end in '//' then recursively search the # directory. After these operations, @BIBINPUTS should # have all the directories that need to be searched @BIBINPUTS = find_dirs1( $BIBINPUTS ); ###################################################################### ###################################################################### # # ??? UPDATE THE FOLLOWING!! # # We will need to determine whether source files for runs of various # programs are out of date. In a normal situation, this is done by # asking whether the times of the source files are later than the # destination files. But this won't work for us, since a common # situation is that a file is written on one run of latex, for # example, and read back in on the next run (e.g., an .aux file). # Some situations of this kind are standard in latex generally; others # occur with particular macro packages or with particular # postprocessors. # # The correct criterion for whether a source is out-of-date is # therefore NOT that its modification time is later than the # destination file, but whether the contents of the source file have # changed since the last successful run. This also handles the case # that the user undoes some changes to a source file by replacing the # source file by reverting to an earlier version, which may well have # an older time stamp. Since a direct comparison of old and new files # would involve storage and access of a large number of backup files, # we instead use the md5 signature of the files. (Previous versions # of latexmk used the backup file method, but restricted to the case # of .aux and .idx files, sufficient for most, but not all, # situations.) # # We will have a database of (time, size, md5) for the relevant # files. If the time and size of a file haven't changed, then the file # is assumed not to have changed; this saves us from having to # determine its md5 signature, which would involve reading the whole # file, which is naturally time-consuming, especially if network file # access to a server is needed, and many files are involved, when most # of them don't change. It is of course possible to change a file # without changing its size, but then to adjust its timestamp # to what it was previously; this requires a certain amount of # perversity. We can safely assume that if the user edits a file or # changes its contents, then the file's timestamp changes. The # interesting case is that the timestamp does change, because the file # has actually been written to, but that the contents do not change; # it is for this that we use the md5 signature. However, since # computing the md5 signature involves reading the whole file, which # may be large, we should avoid computing it more than necessary. # # So we get the following structure: # # 1. For each relevant run (latex, pdflatex, each instance of a # custom dependency) we have a database of the state of the # source files that were last used by the run. # 2. On an initial startup, the database for a primary tex file # is read that was created by a previous run of latex or # pdflatex, if this exists. # 3. If the file doesn't exist, then the criterion for # out-of-dateness for an initial run is that it goes by file # timestamps, as in previous versions of latexmk, with due # (dis)regard to those files that are known to be generated by # latex and re-read on the next run. # 4. Immediately before a run, the database is updated to # represent the current conditions of the run's source files. # 5. After the run, it is determined whether any of the source # files have changed. This covers both files written by the # run, which are therefore in a dependency loop, and files that # the user may have updated during the run. (The last often # happens when latex takes a long time, for a big document, # and the user makes edits before latex has finished. This is # particularly prevalent when latexmk is used with # preview-continuous mode.) # 6. In the case of latex or pdflatex, the custom dependencies # must also be checked and redone if out-of-date. # 7. If any source files have changed, the run is redone, # starting at step 1. # 8. There is naturally a limit on the number of reruns, to avoid # infinite loops from bugs and from pathological or unforeseen # conditions. # 9. After the run is done, the run's file database is updated. # (By hypothesis, the sizes and md5s are correct, if the run # is successful.) # 10. To allow reuse of data from previous runs, the file database # is written to a file after every complete set of passes # through latex or pdflatex. (Note that there is separate # information for latex and pdflatex; the necessary # information won't coincide: Out-of-dateness for the files # for each program concerns the properties of the files when # the other program was run, and the set of source files could # be different, e.g., for graphics files.) # # We therefore maintain the following data structures.: # # a. For each run (latex, pdflatex, each custom dependency) a # database is maintained. This is a hash from filenames to a # reference to an array: [time, size, md5]. The semantics of # the database is that it represents the state of the source # files used in the run. During a run it represents the state # immediately before the run; after a run, with all reruns, it # represents the state of the files used, modified by having # the latest timestamps for generated files. # b. There is a global database for all files, which represents # the current state. This saves having to recompute the md5 # signatures of a changed file used in more than one run # (e.g., latex and pdflatex). # c. Each of latex and pdflatex has a list of the relevant custom # dependencies. # # In all the following a fdb-hash is a hash of the form: # filename -> [time, size, md5] # If a file is found to disappear, its entry is removed from the hash. # In returns from fdb access routines, a size entry of -1 indicates a # non-existent file. # List of known rules. Rule types: primary, # external (calls program), internal (calls routine), cusdep. %possible_primaries = ( 'latex' => 'primary', 'pdflatex' => 'primary' ); %primaries = (); # Hash of rules for primary part of make. Keys are # currently 'latex', 'pdflatex' or both. Value is # currently irrelevant. Use hash for ease of lookup # Make remove this later, if use makeB # Hashes, whose keys give names of particular kinds of rule. We use # hashes for ease of lookup. %possible_one_time = ( 'view' => 1, 'print' => 1, 'update_view' => 1, ); %requested_filerules = (); # Hash for rules corresponding to requested files. # The keys are the rulenames and the value is # currently irrelevant. %one_time = (); # Hash for requested one-time-only rules, currently # possible values 'print' and 'view'. %rule_db = (); # Database of all rules: # Hash: rulename -> [array of rule data] # Rule data: # 0: [ cmd_type, ext_cmd, int_cmd, test_kind, # source, dest, base, # out_of_date, out_of_date_user, # time_of_last_run, time_of_last_file_check, # changed # last_result, last_message, # default_extra_generated # ] # where # cmd_type is 'primary', 'external', or 'cusdep' # ext_cmd is string for associated external command # with substitutions (%D for destination, %S # for source, %B for base of current rule, # %R for base of primary tex file, %T for # texfile name, %O for options, # %Y for $aux_dir1, and %Z for $out_dir1 # int_cmd specifies any internal command to be # used to implement the application of the # rule. If this is present, it overrides # the external command, and it is the # responsibility of the perl subroutine # specified in intcmd to execute the # external command if this is appropriate. # This variable intcmd is a reference to an array, # $$intcmd[0] = internal routine # $$intcmd[1...] = its arguments (if any) # test_kind specifies method of determining # whether a file is out-of-date: # 0 for never # 1 for usual: whether there is a source # file change # 2 for dest earlier than source # 3 for method 2 at first run, 1 thereafter # (used when don't have file data from # previous run). # source = name of primary source file, if any # dest = name of primary destination file, # if any # base = base name, if any, of files for # this rule # out_of_date = 1 if it has been detected that # this rule needs to be run # (typically because a source # file has changed). # 0 otherwise # out_of_date_user is like out_of_date, except # that the detection of out-of-dateness # has been made from a change of a # putative user file, i.e., one that is # not a generated file (e.g., aux). This # kind of out-of-dateness should provoke a # rerun whether or not there was an error # during a run of (pdf)LaTeX. Normally, # if there is an error, one should wait # for the user to correct the error. But # it is possible the error condition is # already corrected during the run, e.g., # by the user changing a source file in # response to an error message. # time_of_last_run = time that this rule was # last applied. (In standard units # from perl, to be directly compared # with file modification times.) # time_of_last_file_check = last time that a check # was made for changes in source files. # changed flags whether special changes have been made # that require file-existence status to be ignored # last_result is # -1 if no run has been made, # 0 if the last run was successful # 1 if last run was successful, but # failed to create an output file # 2 if last run failed # 200 if last run gave a warning that is # important enough to be reported with # the error summary. The warning # message is stored in last_message. # last_message is error message for last run # default_extra_generated is a reference to an array # of specifications of extra generated files (beyond # the main dest file. Standard place holders are used. # Example ['%Y%R.log'] for (pdf)latex, and ['%R.blg'] # for bibtex. (There's no need for '%R.aux', here, # since such generated files are detected dynamically.) # 1: {Hash sourcefile -> [source-file data] } # Source-file data array: # 0: time # 1: size # 2: md5 # 3: name of rule to make this file # 4: whether the file is of the kind made by epstopdf.sty # during a primary run. It will have been read during # the run, so that even though the file changes during # a primary run, there is no need to trigger another # run because of this. # Size and md5 correspond to the values at the last run. # But time may be updated to correspond to the time # for the file, if the file is otherwise unchanged. # This saves excessive md5 calculations, which would # otherwise be done everytime the file is checked, # in the following situation: # When the file has been rewritten after a run # has started (commonly aux, bbl files etc), # but the actual file contents haven't # changed. Then because the filetime has # changed, on every file-change check latexmk # would normally redo the md5 calculation to # test for actual changes. Once one such # check is done, and the contents are # unchanged, later checks are superfluous, and # can be avoided by changing the file's time # in the source-file list. # 2: {Hash generated_file -> 1 } # This lists all generated files; the values # are currently unused, only the keys %fdb_current = (); # Fdb-hash for all files used. # User's home directory $HOME = ''; if (exists $ENV{'HOME'} ) { $HOME = $ENV{'HOME'}; } elsif (exists $ENV{'USERPROFILE'} ) { $HOME = $ENV{'USERPROFILE'}; } #================================================== # Options that are to be obeyed before rc files are read: foreach $_ ( @ARGV ) { if (/^-{1,2}norc$/ ) { $auto_rc_use = 0; } } #================================================== ## Read rc files with this subroutine sub read_first_rc_file_in_list { foreach my $rc_file ( @_ ) { #print "===Testing for rc file \"$rc_file\" ...\n"; if ( -e $rc_file ) { #print "===Reading rc file \"$rc_file\" ...\n"; process_rc_file( $rc_file ); return; } } } # Note that each rc file may unset $auto_rc_use to # prevent lower-level rc files from being read. # So test on $auto_rc_use in each case. if ( $auto_rc_use ) { # System rc file: read_first_rc_file_in_list( @rc_system_files ); } if ( $auto_rc_use ) { # User rc file: read_first_rc_file_in_list( "$HOME/.latexmkrc" ); } if ( $auto_rc_use ) { # Rc file in current directory: read_first_rc_file_in_list( "latexmkrc", ".latexmkrc" ); } ## Process command line args. @command_line_file_list = (); $bad_options = 0; while ($_ = $ARGV[0]) { # Make -- and - equivalent at beginning of option, # but save original for possible use in (pdf)latex command line $original = $_; s/^--/-/; shift; if ( /^-aux-directory=(.*)$/ || /^-auxdir=(.*)$/ ) { $aux_dir = $1; } elsif (/^-bibtex$/) { $bibtex_use = 2; } elsif (/^-bibtex-$/) { $bibtex_use = 0; } elsif (/^-nobibtex$/) { $bibtex_use = 0; } elsif (/^-bibtex-cond$/) { $bibtex_use = 1; } elsif (/^-c$/) { $cleanup_mode = 2; $cleanup_fdb = 1; $cleanup_only = 1; } elsif (/^-C$/ || /^-CA$/ ) { $cleanup_mode = 1; $cleanup_fdb = 1; $cleanup_only = 1; } elsif (/^-CF$/) { $cleanup_fdb = 1; } elsif (/^-cd$/) { $do_cd = 1; } elsif (/^-cd-$/) { $do_cd = 0; } elsif (/^-commands$/) { &print_commands; exit; } elsif (/^-d$/) { $banner = 1; } elsif (/^-dependents$/ || /^-deps$/ || /^-M$/ ) { $dependents_list = 1; } elsif (/^-nodependents$/ || /^-dependents-$/ || /^-deps-$/) { $dependents_list = 0; } elsif (/^-deps-out=(.*)$/) { $deps_file = $1; $dependents_list = 1; } elsif (/^-diagnostics/) { $diagnostics = 1; } elsif (/^-dvi$/) { $dvi_mode = 1; } elsif (/^-dvi-$/) { $dvi_mode = 0; } elsif (/^-f$/) { $force_mode = 1; } elsif (/^-f-$/) { $force_mode = 0; } elsif (/^-g$/) { $go_mode = 1; } elsif (/^-g-$/) { $go_mode = 0; } elsif (/^-gg$/) { $go_mode = 2; $cleanup_mode = 1; $cleanup_fdb = 1; $cleanup_only = 0; } elsif ( /^-h$/ || /^-help$/ ) { &print_help; exit;} elsif (/^-jobname=(.*)$/) { $jobname = $1; } elsif (/^-l$/) { $landscape_mode = 1; } elsif (/^-l-$/) { $landscape_mode = 0; } elsif (/^-latex=(.*)$/) { $latex = $1; } elsif (/^-latexoption=(.*)$/) { push @extra_latex_options, $1; push @extra_pdflatex_options, $1; } # See above for -M elsif (/^-MF$/) { if ( $ARGV[0] eq '' ) { &exit_help( "No file name specified after -MF switch"); } $deps_file = $ARGV[0]; shift; } elsif ( /^-MP$/ ) { $dependents_phony = 1; } elsif (/^-new-viewer$/) { $new_viewer_always = 1; } elsif (/^-new-viewer-$/) { $new_viewer_always = 0; } elsif (/^-norc$/ ) { $auto_rc_use = 0; # N.B. This has already been obeyed. } elsif ( /^-output-directory=(.*)$/ ||/^-outdir=(.*)$/ ) { $out_dir = $1; } elsif (/^-p$/) { $printout_mode = 1; $preview_continuous_mode = 0; # to avoid conflicts $preview_mode = 0; } elsif (/^-p-$/) { $printout_mode = 0; } elsif (/^-pdf$/) { $pdf_mode = 1; } elsif (/^-pdf-$/) { $pdf_mode = 0; } elsif (/^-pdfdvi$/){ $pdf_mode = 3; } elsif (/^-pdflatex=(.*)$/) { $pdflatex = $1; } elsif (/^-pdfps$/) { $pdf_mode = 2; } elsif (/^-print=(.*)$/) { $value = $1; if ( $value =~ /^dvi$|^ps$|^pdf$/ ) { $print_type = $value; $printout_mode = 1; } else { &exit_help("$My_name: unknown print type '$value' in option '$_'"); } } elsif (/^-ps$/) { $postscript_mode = 1; } elsif (/^-ps-$/) { $postscript_mode = 0; } elsif (/^-pv$/) { $preview_mode = 1; $preview_continuous_mode = 0; # to avoid conflicts $printout_mode = 0; } elsif (/^-pv-$/) { $preview_mode = 0; } elsif (/^-pvc$/) { $preview_continuous_mode = 1; $force_mode = 0; # So that errors do not cause loops $preview_mode = 0; # to avoid conflicts $printout_mode = 0; } elsif (/^-pvc-$/) { $preview_continuous_mode = 0; } elsif (/^-recorder$/ ){ $recorder = 1; } elsif (/^-recorder-$/ ){ $recorder = 0; } elsif (/^-rules$/ ) { $rules_list = 1; } elsif (/^-norules$/ || /^-rules-$/ ) { $rules_list = 0; } elsif (/^-showextraoptions$/) { print "List of extra latex and pdflatex options recognized by $my_name:\n", "These are passed as is to (pdf)latex. They may not be recognized by\n", "particular versions of (pdf)latex. This list is a combination of those\n", "for TeXLive and MikTeX.\n\n"; foreach $option ( sort( keys %allowed_latex_options, keys %allowed_latex_options_with_arg ) ) { if (exists $allowed_latex_options{$option} ) { print " $allowed_latex_options{$option}\n"; } if (exists $allowed_latex_options_with_arg{$option} ) { print " $allowed_latex_options_with_arg{$option}\n"; } } exit; } elsif (/^-silent$/ || /^-quiet$/ ){ $silent = 1; } elsif (/^-time$/) { $show_time = 1;} elsif (/^-time-$/) { $show_time = 0;} elsif (/^-use-make$/) { $use_make_for_missing_files = 1; } elsif (/^-use-make-$/) { $use_make_for_missing_files = 0; } elsif (/^-v$/ || /^-version$/) { print "\n$version_details. Version $version_num\n"; exit; } elsif (/^-verbose$/) { $silent = 0; } elsif (/^-view=default$/) { $view = "default";} elsif (/^-view=dvi$/) { $view = "dvi";} elsif (/^-view=none$/) { $view = "none";} elsif (/^-view=ps$/) { $view = "ps";} elsif (/^-view=pdf$/) { $view = "pdf"; } elsif (/^-xelatex$/) { $pdflatex = "xelatex %O %S"; $pdf_mode = 1; $dvi_mode = $postscript_mode = 0; } elsif (/^-e$/) { if ( $#ARGV < 0 ) { &exit_help( "No code to execute specified after -e switch"); } execute_code_string( $ARGV[0] ); shift; } elsif (/^-r$/) { if ( $ARGV[0] eq '' ) { &exit_help( "No RC file specified after -r switch"); } if ( -e $ARGV[0] ) { process_rc_file( $ARGV[0] ); } else { die "$My_name: RC file [$ARGV[0]] does not exist\n"; } shift; } elsif (/^-bm$/) { if ( $ARGV[0] eq '' ) { &exit_help( "No message specified after -bm switch"); } $banner = 1; $banner_message = $ARGV[0]; shift; } elsif (/^-bi$/) { if ( $ARGV[0] eq '' ) { &exit_help( "No intensity specified after -bi switch"); } $banner_intensity = $ARGV[0]; shift; } elsif (/^-bs$/) { if ( $ARGV[0] eq '' ) { &exit_help( "No scale specified after -bs switch"); } $banner_scale = $ARGV[0]; shift; } elsif (/^-dF$/) { if ( $ARGV[0] eq '' ) { &exit_help( "No dvi filter specified after -dF switch"); } $dvi_filter = $ARGV[0]; shift; } elsif (/^-pF$/) { if ( $ARGV[0] eq '' ) { &exit_help( "No ps filter specified after -pF switch"); } $ps_filter = $ARGV[0]; shift; } elsif ( ( exists( $allowed_latex_options{$_} ) ) || ( /^(-.+)=/ && exists( $allowed_latex_options_with_arg{$1} ) ) ) { push @extra_latex_options, $original; push @extra_pdflatex_options, $original; } elsif (/^-/) { warn "$My_name: $_ bad option\n"; $bad_options++; } else { push @command_line_file_list, $_ ; } } if ( $bad_options > 0 ) { &exit_help( "Bad options specified" ); } warn "$My_name: This is $version_details, version: $version_num.\n", "**** Report bugs etc to John Collins . ****\n" unless $silent; if ( ($out_dir ne '') && ($aux_dir eq '') ){ $aux_dir = $out_dir; } # Versions terminating in directory/path separator $out_dir1 = $out_dir; $aux_dir1 = $aux_dir; foreach ( $aux_dir1, $out_dir1 ) { if ( ($_ ne '') && ! m([\\/\:]$) ) { $_ .= '/'; } } if ($bibtex_use > 1) { push @generated_exts, 'bbl'; } # For backward compatibility, convert $texfile_search to @default_files # Since $texfile_search is initialized to "", a nonzero value indicates # that an initialization file has set it. if ( $texfile_search ne "" ) { @default_files = split / /, "*.tex $texfile_search"; } #Glob the filenames command line if the script was not invoked under a # UNIX-like environment. # Cases: (1) MS/MSwin native Glob # (OS detected as MSWin32) # (2) MS/MSwin cygwin Glob [because we do not know whether # the cmd interpreter is UNIXy (and does glob) or is # native MS-Win (and does not glob).] # (OS detected as cygwin) # (3) UNIX Don't glob (cmd interpreter does it) # (Currently, I assume this is everything else) if ( ($^O eq "MSWin32") || ($^O eq "cygwin") ) { # Preserve ordering of files @file_list = glob_list1(@command_line_file_list); #print "A1:File list:\n"; #for ($i = 0; $i <= $#file_list; $i++ ) { print "$i: '$file_list[$i]'\n"; } } else { @file_list = @command_line_file_list; } @file_list = uniq1( @file_list ); # Check we haven't selected mutually exclusive modes. # Note that -c overrides all other options, but doesn't cause # an error if they are selected. if (($printout_mode && ( $preview_mode || $preview_continuous_mode )) || ( $preview_mode && $preview_continuous_mode )) { # Each of the options -p, -pv, -pvc turns the other off. # So the only reason to arrive here is an incorrect inititalization # file, or a bug. &exit_help( "Conflicting options (print, preview, preview_continuous) selected"); } if ( @command_line_file_list ) { # At least one file specified on command line (before possible globbing). if ( !@file_list ) { &exit_help( "Wildcards in file names didn't match any files"); } } else { # No files specified on command line, try and find some # Evaluate in order specified. The user may have some special # for wanting processing in a particular order, especially # if there are no wild cards. # Preserve ordering of files my @file_list1 = uniq1( glob_list1(@default_files) ); my @excluded_file_list = uniq1( glob_list1(@default_excluded_files) ); # Make hash of excluded files, for easy checking: my %excl = (); foreach my $file (@excluded_file_list) { $excl{$file} = ''; } foreach my $file (@file_list1) { push( @file_list, $file) unless ( exists $excl{$file} ); } if ( !@file_list ) { &exit_help( "No file name specified, and I couldn't find any"); } } $num_files = $#file_list + 1; $num_specified = $#command_line_file_list + 1; #print "Command line file list:\n"; #for ($i = 0; $i <= $#command_line_file_list; $i++ ) { print "$i: '$command_line_file_list[$i]'\n"; } #print "File list:\n"; #for ($i = 0; $i <= $#file_list; $i++ ) { print "$i: '$file_list[$i]'\n"; } # If selected a preview-continuous mode, make sure exactly one filename was specified if ($preview_continuous_mode && ($num_files != 1) ) { if ($num_specified > 1) { &exit_help( "Need to specify exactly one filename for ". "preview-continuous mode\n". " but $num_specified were specified" ); } elsif ($num_specified == 1) { &exit_help( "Need to specify exactly one filename for ". "preview-continuous mode\n". " but wildcarding produced $num_files files" ); } else { &exit_help( "Need to specify exactly one filename for ". "preview-continuous mode.\n". " Since none were specified on the command line, I looked for \n". " files in '@default_files'.\n". " But I found $num_files files, not 1." ); } } # If selected jobname, can only apply that to one file: if ( ($jobname ne '') && ($num_files > 1) ) { &exit_help( "Need to specify at most one filename if ". "jobname specified, \n". " but $num_files were found (after defaults and wildcarding)." ); } # Normalize the commands, to have place-holders for source, dest etc: &fix_cmds; # Add common options add_option( $latex_default_switches, \$latex ); add_option( $pdflatex_default_switches, \$pdflatex ); foreach (@extra_latex_options) { add_option( $_, \$latex ); } foreach (@extra_pdflatex_options) { add_option( $_, \$pdflatex ); } # If landscape mode, change dvips processor, and the previewers: if ( $landscape_mode ) { $dvips = $dvips_landscape; $dvi_previewer = $dvi_previewer_landscape; $ps_previewer = $ps_previewer_landscape; } if ( $silent ) { add_option( "$latex_silent_switch", \$latex ); add_option( "$pdflatex_silent_switch", \$pdflatex ); add_option( "$biber_silent_switch", \$biber ); add_option( "$bibtex_silent_switch", \$bibtex ); add_option( "$makeindex_silent_switch", \$makeindex ); add_option( "$dvips_silent_switch", \$dvips ); } if ( $recorder ) { add_option( "-recorder", \$latex, \$pdflatex ); } if ( $out_dir ) { add_option( "-output-directory=\"$out_dir\"", \$latex, \$pdflatex ); if ( ! -e $out_dir ) { warn "$My_name: making output directory '$out_dir'\n" if ! $silent; mkdir $out_dir; } elsif ( ! -d $out_dir ) { warn "$My_name: you requested output directory '$out_dir',\n", " but an ordinary file of the same name exists, which will\n", " probably give an error later\n"; } } if ( $aux_dir && ($aux_dir ne $out_dir) ) { # N.B. If $aux_dir and $out_dir are the same, then the -output-directory # option is sufficient, especially because the -aux-directory exists # only in MiKTeX, not in TeXLive. add_option( "-aux-directory=\"$aux_dir\"", \$latex, \$pdflatex ); if ( ! -e $aux_dir ) { warn "$My_name: making auxiliary directory '$aux_dir'\n" if ! $silent; mkdir $aux_dir; } elsif ( ! -d $aux_dir ) { warn "$My_name: you requested aux directory '$aux_dir',\n", " but an ordinary file of the same name exists, which will\n", " probably give an error later\n"; } } if ( $jobname ne '' ) { $jobstring = "--jobname=$jobname"; add_option( "$jobstring", \$latex, \$pdflatex ); } # Which kind of file do we preview? if ( $view eq "default" ) { # If default viewer requested, use "highest" of dvi, ps and pdf # that was requested by user. # No explicit request means view dvi. $view = "dvi"; if ( $postscript_mode ) { $view = "ps"; } if ( $pdf_mode ) { $view = "pdf"; } } # Make sure we make the kind of file we want to view: if ($view eq 'dvi') { $dvi_mode = 1; } if ($view eq 'ps') { $postscript_mode = 1; } if ( ($view eq 'pdf') && ($pdf_mode == 0) ) { $pdf_mode = 1; } # Make sure that we make something if all requests are turned off if ( ! ( $dvi_mode || $pdf_mode || $postscript_mode || $printout_mode) ) { print "No specific requests made, so default to dvi by latex\n"; $dvi_mode = 1; } # Set new-style requested rules: if ( $dvi_mode ) { $requested_filerules{'latex'} = 1; } if ( $pdf_mode == 1 ) { $requested_filerules{'pdflatex'} = 1; } elsif ( $pdf_mode == 2 ) { $requested_filerules{'latex'} = 1; $requested_filerules{'dvips'} = 1; $requested_filerules{'ps2pdf'} = 1; } elsif ( $pdf_mode == 3 ) { $requested_filerules{'latex'} = 1; $requested_filerules{'dvipdf'} = 1; } if ( $postscript_mode ) { $requested_filerules{'latex'} = 1; $requested_filerules{'dvips'} = 1; } if ( $printout_mode ) { $one_time{'print'} = 1; } if ( $preview_continuous_mode || $preview_mode ) { $one_time{'view'} = 1; } if ( length($dvi_filter) != 0 ) { $requested_filerules{'dvi_filter'} = 1; } if ( length($ps_filter) != 0 ) { $requested_filerules{'ps_filter'} = 1; } if ( $banner ) { $requested_filerules{'dvips'} = 1; } if ( $pdf_mode == 2 ) { # We generate pdf from ps. Make sure we have the correct kind of ps. add_option( "$dvips_pdf_switch", \$dvips ); } # Note sleep has granularity of 1 second. # Sleep periods 0 < $sleep_time < 1 give zero delay, # which is probably not what the user intended. # Sleep periods less than zero give infinite delay if ( $sleep_time < 0 ) { warn "$My_name: Correcting negative sleep_time to 1 sec.\n"; $sleep_time = 1; } elsif ( ($sleep_time < 1) && ( $sleep_time != 0 ) ) { warn "$My_name: Correcting nonzero sleep_time of less than 1 sec to 1 sec.\n"; $sleep_time = 1; } elsif ( $sleep_time == 0 ) { warn "$My_name: sleep_time was configured to zero.\n", " Do you really want to do this? It will give 100% CPU usage.\n"; } # Make convenient forms for lookup. # Extensions always have period. # Convert @generated_exts to a hash for ease of look up and deletion # Keep extension without period! %generated_exts_all = (); foreach (@generated_exts ) { $generated_exts_all{$_} = 1; } if ($aux_dir) { # Ensure $aux_dir is in TEXINPUTS search path. # This is used by dvips for files generated by mpost. if ( ! exists $ENV{TEXINPUTS} ) { # Note the trailing ":" which ensures that the last item # in the list of paths is the empty path, which actually # means the default path, i.e., the following means that # the TEXINPUTS search path is $aux_dir and the standard # value. $ENV{TEXINPUTS} = $aux_dir.$search_path_separator; } elsif ( $ENV{TEXINPUTS} !~ /$aux_dir$search_path_separator/ ) { $ENV{TEXINPUTS} = $aux_dir.$search_path_separator.$ENV{TEXINPUTS}; } } $quell_uptodate_msgs = $silent; # Whether to quell informational messages when files are uptodate # Will turn off in -pvc mode $failure_count = 0; @failed_primaries = (); if ($deps_file eq '' ) { # Standardize name used for stdout $deps_file = '-'; } if ( $dependents_list ) { $deps_handle = new FileHandle "> $deps_file"; if (! defined $deps_handle ) { die "Cannot open '$deps_file' for output of dependency information\n"; } } FILE: foreach $filename ( @file_list ) { # Global variables for making of current file: $updated = 0; $failure = 0; # Set nonzero to indicate failure at some point of # a make. Use value as exit code if I exit. $failure_msg = ''; # Indicate reason for failure if ( $do_cd ) { ($filename, $path) = fileparse( $filename ); warn "$My_name: Changing directory to '$path'\n"; pushd( $path ); } else { $path = ''; } ## remove extension from filename if was given. if ( &find_basename($filename, $root_filename, $texfile_name) ) { if ( $force_mode ) { warn "$My_name: Could not find file [$texfile_name]\n"; } else { &ifcd_popd; &exit_msg1( "Could not find file [$texfile_name]", 11); } } if ($jobname ne '' ) { $root_filename = $jobname; } $aux_main = "$aux_dir1$root_filename.aux"; $log_name = "$aux_dir1$root_filename.log"; $fdb_name = "$aux_dir1$root_filename.$fdb_ext"; # Initialize basic dependency information: # For use under error conditions: @default_includes = ($texfile_name, $aux_main); # Initialize file and rule databases. %rule_list = (); &rdb_make_rule_list; &rdb_set_rules(\%rule_list); if ( $cleanup_mode > 0 ) { # ?? MAY NEED TO FIX THE FOLLOWING IF $aux_dir or $out_dir IS SET. my %other_generated = (); my @index_bibtex_generated = (); my @aux_files = (); $have_fdb = 0; if ( -e $fdb_name ) { print "$My_name: Examining fdb file '$fdb_name' for rules ...\n"; $have_fdb = ( 0 == rdb_read( $fdb_name ) ); } if ( $have_fdb ) { rdb_for_all( sub { # Find generated files at rule level my ($base, $path, $ext) = fileparseA( $$Psource ); $base = $path.$base; if ( $rule =~ /^makeindex/ ) { push @index_bibtex_generated, $$Psource, $$Pdest, "$base.ilg"; } elsif ( $rule =~ /^(bibtex|biber)/ ) { push @index_bibtex_generated, $$Pdest, "$base.blg"; push @aux_files, $$Psource; } elsif ( exists $other_generated{$$Psource} ) { $other_generated{$$Pdest}; } }, sub { # Find generated files at source file level if ( $file =~ /\.aux$/ ) { push @aux_files, $file; } } ); } else { # No fdb file, so do inferior job by parse_logB print "$My_name: Examining log file '$log_name' for generated files...\n"; # Variables set by parse_logB. Can I remove them local %generated_log = (); local %dependents = (); # Maps files to status. Not used here. local @bbl_files = (); # Not used here. local %idx_files = (); # Maps idx_file to (ind_file, base). Not used here. local %conversions = (); # (pdf)latex-performed conversions. Not used here. # Maps output file created and read by (pdf)latex # to source file of conversion. local $primary_out = ''; # Actual output file (dvi or pdf). Not used here. &parse_logB; %other_generated = %generated_log; } if ( ($go_mode == 2) && !$silent ) { warn "$My_name: Removing all generated files\n" unless $silent; } if ($bibtex_use < 2) { delete $generated_exts_all{'bbl'}; } # Convert two arrays to hashes: my %index_bibtex_generated = (); my %aux_files = (); foreach (@index_bibtex_generated) { $index_bibtex_generated{$_} = 1 unless ( /\.bbl$/ && ($bibtex_use < 2) ); delete( $other_generated{$_} ); } foreach (@aux_files) { $aux_files{$_} = 1; delete( $other_generated{$_} ); } if ($diagnostics) { show_array( "For deletion:\n" ." Generated (from makeindex and bibtex):", keys %index_bibtex_generated ); show_array( " Aux files:", keys %aux_files ); show_array( "Other generated files:\n" ." (only deleted if \$cleanup_includes_generated is set): ", keys %other_generated ); } &cleanup1( $aux_dir1, $fdb_ext, 'blg', 'ilg', 'log', 'aux.bak', 'idx.bak', split(' ',$clean_ext), keys %generated_exts_all ); unlink_or_move( 'texput.log', "texput.aux", keys %index_bibtex_generated, keys %aux_files ); if ($cleanup_includes_generated) { unlink_or_move( keys %other_generated ); } if ( $cleanup_includes_cusdep_generated) { &cleanup_cusdep_generated; } if ( $cleanup_mode == 1 ) { &cleanup1( $out_dir1, 'dvi', 'dviF', 'ps', 'psF', 'pdf', split(' ', $clean_full_ext) ); } } if ($cleanup_fdb) { unlink_or_move( $fdb_name ); } if ($cleanup_only) { next FILE; } #??? The following are not needed if use makeB. # ?? They may be set too early? # Arrays and hashes for picking out accessible rules. # Distinguish rules for making files and others @accessible_all = sort ( &rdb_accessible( keys %requested_filerules, keys %one_time )); %accessible_filerules = (); foreach (@accessible_all) { unless ( /view/ || /print/ ) { $accessible_filerules{$_} = 1; } } @accessible_filerules = sort keys %accessible_filerules; # show_array ( "=======All rules used", @accessible_all ); # show_array ( "=======Requested file rules", sort keys %requested_filerules ); # show_array ( "=======Rules for files", @accessible_filerules ); if ( $diagnostics ) { print "$My_name: Rules after start up for '$texfile_name'\n"; rdb_show(); } %primaries = (); foreach (@accessible_all) { if ( ($_ eq 'latex') || ($_ eq 'pdflatex') ) { $primaries{$_} = 1; } } $have_fdb = 0; if ( (! -e $fdb_name) && (! -e $aux_main ) ) { # No aux and no fdb file => set up trivial aux file # and corresponding fdb_file. Arrange them to provoke one run # as minimum, but no more if actual aux file is trivial. # (Useful on big files without cross references.) &set_trivial_aux_fdb; } if ( -e $fdb_name ) { $rdb_errors = rdb_read( $fdb_name ); $have_fdb = ($rdb_errors == 0); } if (!$have_fdb) { # We didn't get a valid set of data on files used in # previous run. So use filetime criterion for make # instead of change from previous run, until we have # done our own make. rdb_recurseA( [keys %possible_primaries], sub{ if ( $$Ptest_kind == 1 ) { $$Ptest_kind = 3;} } ); if ( -e $log_name ) { rdb_for_some( [keys %possible_primaries], \&rdb_set_latex_deps ); } } foreach $rule ( rdb_accessible( uniq1( keys %requested_filerules ) ) ){ # For all source files of all accessible rules, # if the file data are not already set (e.g., from fdb_latexmk # file, set them from disk. rdb_one_rule ($rule, undef, sub{ if ( $$Ptime == 0) { &rdb_update1; } } ); } if ($go_mode) { # Force everything to be remade. rdb_recurseA( [keys %requested_filerules], sub{$$Pout_of_date=1;} ); } if ( $diagnostics ) { print "$My_name: Rules after initialization\n"; rdb_show(); } #************************************************************ if ( $preview_continuous_mode ) { &make_preview_continuousB; # Will probably exit by ctrl/C and never arrive here. next FILE; } ## Handling of failures: ## Variable $failure is set to indicate a failure, with information ## put in $failure_msg. ## These variables should be set to 0 and '' at any point at which it ## should be assumed that no failures have occurred. ## When after a routine is called it is found that $failure is set, then ## processing should normally be aborted, e.g., by return. ## Then there is a cascade of returns back to the outermost level whose ## responsibility is to handle the error. ## Exception: An outer level routine may reset $failure and $failure_msg ## after initial processing, when the error condition may get ## ameliorated later. #Initialize failure flags now. $failure = 0; $failure_msg = ''; $failure = rdb_makeB( keys %requested_filerules ); if ($failure > 0) { next FILE; } rdb_for_some( [keys %one_time], \&rdb_run1 ); } # end FILE continue { if ($dependents_list) { deps_list($deps_handle); } if ($rules_list) { rdb_list(); } # Handle any errors $error_message_count = rdb_show_rule_errors(); if ( ($error_message_count == 0) || ($failure > 0) ) { if ( $failure_msg ) { #Remove trailing space $failure_msg =~ s/\s*$//; warn "$My_name: Did not finish processing file:\n $failure_msg\n"; $failure = 1; } } if ( ($failure > 0) || ($error_message_count > 0) ) { $failure_count ++; push @failed_primaries, $filename; } &ifcd_popd; } close($deps_handle) if ( $deps_handle ); if ($show_time) { show_timing();} sub show_timing { my $processing_time = processing_time() - $processing_time1; print @timings, "Accumulated processing time = $processing_time\n"; @timings = (); $processing_time1 = processing_time(); } # If we get here without going through the continue section: if ( $do_cd && ($#dir_stack > -1) ) { # Just in case we did an abnormal exit from the loop warn "$My_name: Potential bug: dir_stack not yet unwound, undoing all directory changes now\n"; &finish_dir_stack; } if ($failure_count > 0) { if ( $#file_list > 0 ) { # Error occured, but multiple files were processed, so # user may not have seen all the error messages warn "\n------------\n"; show_array( "$My_name: Some operations failed, for the following tex file(s)", @failed_primaries); } if ( !$force_mode ) { warn "$My_name: Use the -f option to force complete processing.\n"; } exit 12; } # end MAIN PROGRAM ############################################################# sub fix_cmds { # If commands do not have placeholders for %S etc, put them in foreach ($latex, $pdflatex, $lpr, $lpr_dvi, $lpr_pdf, $pdf_previewer, $ps_previewer, $ps_previewer_landscape, $dvi_previewer, $dvi_previewer_landscape, $kpsewhich ) { # Source only if ( $_ && ! /%/ ) { $_ .= " %O %S"; } } foreach ($pdf_previewer, $ps_previewer, $ps_previewer_landscape, $dvi_previewer, $dvi_previewer_landscape, ) { # Run previewers detached if ( $_ && ! /^(nostart|NONE|internal) / ) { $_ = "start $_"; } } foreach ($biber, $bibtex) { # Base only if ( $_ && ! /%/ ) { $_ .= " %O %B"; } } foreach ($dvipdf, $ps2pdf) { # Source and dest without flag for destination if ( $_ && ! /%/ ) { $_ .= " %O %S %D"; } } foreach ($dvips, $makeindex) { # Source and dest with -o dest before source if ( $_ && ! /%/ ) { $_ .= " %O -o %D %S"; } } foreach ($dvi_filter, $ps_filter) { # Source and dest, but as filters if ( $_ && ! /%/ ) { $_ .= " %O <%S >%D"; } } } #END fix_cmds ############################################################# sub add_option { # Call add_option( $opt, \$cmd ... ) # Add option to one or more commands my $option = shift; while (@_) { if ( ${$_[0]} !~ /%/ ) { &fix_cmds; } ${$_[0]} =~ s/%O/$option %O/; shift; } } #END add_option ############################################################# sub rdb_make_rule_list { # Substitutions: %S = source, %D = dest, %B = this rule's base # %T = texfile, %R = root = base for latex. # %Y for $aux_dir1, %Z for $out_dir1 # Defaults for dvi, ps, and pdf files # Use local, not my, so these variables can be referenced local $dvi_final = "%Z%R.dvi"; local $ps_final = "%Z%R.ps"; local $pdf_final = "%Z%R.pdf"; if ( length($dvi_filter) > 0) { $dvi_final = "%Z%R.dviF"; } if ( length($ps_filter) > 0) { $ps_final = "%Z%R.psF"; } my $print_file = ''; my $print_cmd = ''; if ( $print_type eq 'dvi' ) { $print_file = $dvi_final; $print_cmd = $lpr_dvi; } elsif ( $print_type eq 'pdf' ) { $print_file = $pdf_final; $print_cmd = $lpr_pdf; } elsif ( $print_type eq 'ps' ) { $print_file = $ps_final; $print_cmd = $lpr; } my $view_file = ''; my $viewer = ''; my $viewer_update_method = 0; my $viewer_update_signal = undef; my $viewer_update_command = undef; if ( ($view eq 'dvi') || ($view eq 'pdf') || ($view eq 'ps') ) { $view_file = ${$view.'_final'}; $viewer = ${$view.'_previewer'}; $viewer_update_method = ${$view.'_update_method'}; $viewer_update_signal = ${$view.'_update_signal'}; if (defined ${$view.'_update_command'}) { $viewer_update_command = ${$view.'_update_command'}; } } # Specification of internal command for viewer update: my $PA_update = ['do_update_view', $viewer_update_method, $viewer_update_signal, 0, 1]; # For test_kind: Use file contents for latex and friends, but file time for the others. # This is because, especially for dvi file, the contents of the file may contain # a pointer to a file to be included, not the contents of the file! %rule_list = ( 'latex' => [ 'primary', "$latex", '', "%T", "%Z%B.dvi", "%R", 1, ["%Y%R.log"] ], 'pdflatex' => [ 'primary', "$pdflatex", '', "%T", "%Z%B.pdf", "%R", 1, ["%Y%R.log"] ], 'dvipdf' => [ 'external', "$dvipdf", 'do_viewfile', $dvi_final, "%B.pdf", "%Z%R", 2 ], 'dvips' => [ 'external', "$dvips", 'do_viewfile', $dvi_final, "%B.ps", "%Z%R", 2 ], 'dvifilter'=> [ 'external', $dvi_filter, 'do_viewfile', "%B.dvi", "%B.dviF", "%Z%R", 2 ], 'ps2pdf' => [ 'external', "$ps2pdf", 'do_viewfile', $ps_final, "%B.pdf", "%Z%R", 2 ], 'psfilter' => [ 'external', $ps_filter, 'do_viewfile', "%B.ps", "%B.psF", "%Z%R", 2 ], 'print' => [ 'external', "$print_cmd", 'if_source', $print_file, "", "", 2 ], 'update_view' => [ 'external', $viewer_update_command, $PA_update, $view_file, "", "", 2 ], 'view' => [ 'external', "$viewer", 'if_source', $view_file, "", "", 2 ], ); %source_list = (); foreach my $rule (keys %rule_list) { $source_list{$rule} = []; my $PAsources = $source_list{$rule}; my ( $cmd_type, $cmd, $source, $dest, $root ) = @{$rule_list{$rule}}; if ($source) { push @$PAsources, [ $rule, $source, '' ]; } } # Ensure we only have one way to make pdf file, and that it is appropriate: if ($pdf_mode == 1) { delete $rule_list{'dvipdf'}; delete $rule_list{'ps2pdf'}; } elsif ($pdf_mode == 2) { delete $rule_list{'dvipdf'}; delete $rule_list{'pdflatex'}; } else { delete $rule_list{'pdflatex'}; delete $rule_list{'ps2pdf'}; } } # END rdb_make_rule_list #************************************************************ sub rdb_set_rules { # Call rdb_set_rules( \%rule_list, ...) # Set up rule database from definitions # Map of files to rules that MAKE them: %rule_db = (); foreach my $Prule_list (@_) { foreach my $rule ( keys %$Prule_list) { my ( $cmd_type, $ext_cmd, $int_cmd, $source, $dest, $base, $test_kind, $PA_extra_gen ) = @{$$Prule_list{$rule}}; if ( ! $PA_extra_gen ) { $PA_extra_gen = []; } my $needs_making = 0; # Substitute in the filename variables, since we will use # those for determining filenames. But delay expanding $cmd # until run time, in case of changes. foreach ($base, $source, $dest, @$PA_extra_gen ) { s/%R/$root_filename/; s/%Y/$aux_dir1/; s/%Z/$out_dir1/; } foreach ($source, $dest ) { s/%B/$base/; s/%T/$texfile_name/; } # print "$rule: $cmd_type, EC='$ext_cmd', IC='$int_cmd', $test_kind,\n", # " S='$source', D='$dest', B='$base' $needs_making\n"; rdb_create_rule( $rule, $cmd_type, $ext_cmd, $int_cmd, $test_kind, $source, $dest, $base, $needs_making, undef, undef, 1, $PA_extra_gen ); # !! ?? Last line was # $needs_making, undef, ($test_kind==1) ); } } # End arguments of subroutine &rdb_make_links; } # END rdb_set_rules #************************************************************ sub rdb_make_links { # ?? Problem if there are multiple rules for getting a file. Notably pdf. # Which one to choose? # Create $from_rule if there's a suitable rule. # Map files to rules: local %from_rules = (); rdb_for_all( sub{ if($$Pdest){$from_rules{$$Pdest} = $rule;} } ); #?? foreach (sort keys %from_rules) {print "D='$_' F='$from_rules{$_}\n";} rdb_for_all( 0, sub{ # Set from_rule, but only if it isn't set or is invalid. # Don't forget the biber v. bibtex issue if ( exists $from_rules{$file} && ( (!$$Pfrom_rule) || (! exists $rule_db{$$Pfrom_rule} ) ) ) { $$Pfrom_rule = $from_rules{$file}; } } ); rdb_for_all( 0, sub{ if ( exists $from_rules{$file} ) { $$Pfrom_rule = $from_rules{$file}; } if ( $$Pfrom_rule && (! rdb_rule_exists( $$Pfrom_rule ) ) ) { $$Pfrom_rule = ''; } #?? print "$rule: $file, $$Pfrom_rule\n"; } ); } # END rdb_make_links #************************************************************ sub set_trivial_aux_fdb { # 1. Write aux file EXACTLY as would be written if the tex file # had no cross references, etc. I.e., a minimal .aux file. # 2. Write a corresponding fdb file # 3. Provoke a run of (pdf)latex (actually of all primaries). local *aux_file; open( aux_file, '>', $aux_main ) or die "Cannot write file '$aux_main'\n"; print aux_file "\\relax \n"; close(aux_file); foreach my $rule (keys %primaries ) { rdb_ensure_file( $rule, $texfile_name ); rdb_ensure_file( $rule, $aux_main ); rdb_one_rule( $rule, sub{ $$Pout_of_date = 1; } ); } &rdb_write( $fdb_name ); } #END set_trivial_aux_fdb #************************************************************ #### Particular actions #************************************************************ #************************************************************ sub do_cusdep { # Unconditional application of custom-dependency # except that rule is not applied if the source file source # does not exist, and an error is returned if the dest is not made. # # Assumes rule context for the custom-dependency, and that my first # argument is the name of the subroutine to apply my $func_name = $_[0]; my $return = 0; if ( !-e $$Psource ) { # Source does not exist. Users of this rule will need to turn # it off when custom dependencies are reset if ( !$silent ) { ## ??? Was commented out. 1 Sep. 2008 restored, for cusdep no-file-exists issue warn "$My_name: In trying to apply custom-dependency rule\n", " to make '$$Pdest' from '$$Psource'\n", " the source file has disappeared since the last run\n"; } # Treat as successful } elsif ( !$func_name ) { warn "$My_name: Possible misconfiguration or bug:\n", " In trying to apply custom-dependency rule\n", " to make '$$Pdest' from '$$Psource'\n", " the function name is blank.\n"; } elsif ( ! defined &$func_name ) { warn "$My_name: Misconfiguration or bug,", " in trying to apply custom-dependency rule\n", " to make '$$Pdest' from '$$Psource'\n", " function name '$func_name' does not exists.\n"; } else { my $cusdep_ret = &$func_name( $$Pbase ); if ( defined $cusdep_ret && ($cusdep_ret != 0) ) { $return = $cusdep_ret; if ($return) { warn "Rule '$rule', function '$func_name'\n", " failed with return code = $return\n"; } } elsif ( !-e $$Pdest ) { # Destination non-existent, but routine failed to give an error warn "$My_name: In running custom-dependency rule\n", " to make '$$Pdest' from '$$Psource'\n", " function '$func_name' did not make the destination.\n"; $return = -1; } } return $return; } # END do_cusdep #************************************************************ sub do_viewfile { # Unconditionally make file for viewing, going through temporary file if # Assumes rule context my $return = 0; my ($base, $path, $ext) = fileparseA( $$Pdest ); if ( &view_file_via_temporary ) { if ( $$Pext_cmd =~ /%D/ ) { my $tmpfile = tempfile1( "${root_filename}_tmp", $ext ); warn "$My_name: Making '$$Pdest' via temporary '$tmpfile'...\n"; $return = &Run_subst( undef, undef, undef, undef, $tmpfile ); move( $tmpfile, $$Pdest ); } else { warn "$My_name is configured to make '$$Pdest' via a temporary file\n", " but the command template '$$Pext_cmd' does not have a slot\n", " to set the destination file, so I won't use a temporary file\n"; $return = &Run_subst(); } } else { $return = &Run_subst(); } return $return; } #END do_viewfile #************************************************************ sub do_update_view { # Update viewer # Assumes rule context # Arguments: (method, signal, viewer_process) my $return = 0; # Although the process is passed as an argument, we'll need to update it. # So (FUDGE??) bypass the standard interface for the process. # We might as well do this for all the arguments. my $viewer_update_method = ${$PAint_cmd}[1]; my $viewer_update_signal = ${$PAint_cmd}[2]; my $Pviewer_process = \${$PAint_cmd}[3]; my $Pneed_to_get_viewer_process = \${$PAint_cmd}[4]; if ($viewer_update_method == 2) { if ($$Pneed_to_get_viewer_process) { $$Pviewer_process = &find_process_id( $$Psource ); if ($$Pviewer_process != 0) { $$Pneed_to_get_viewer_process = 0; } } if ($$Pviewer_process == 0) { print "$My_name: need to signal viewer for file '$$Psource', but didn't get \n", " process ID for some reason, e.g., no viewer, bad configuration, bug\n" if $diagnostics ; } elsif ( defined $viewer_update_signal) { print "$My_name: signalling viewer, process ID $$Pviewer_process\n" if $diagnostics ; kill $viewer_update_signal, $$Pviewer_process; } else { warn "$My_name: viewer is supposed to be sent a signal\n", " but no signal is defined. Misconfiguration or bug?\n"; $return = 1; } } elsif ($viewer_update_method == 4) { if (defined $$Pext_cmd) { $return = &Run_subst(); } else { warn "$My_name: viewer is supposed to be updated by running a command,\n", " but no command is defined. Misconfiguration or bug?\n"; } } return $return; } #END do_update_view #************************************************************ sub if_source { # Unconditionally apply rule if source file exists. # Assumes rule context if ( -e $$Psource ) { return &Run_subst(); } else { return -1; } } #END if_source #************************************************************ #### Subroutines #************************************************************ #************************************************************ # Finds the basename of the root file # Arguments: # 1 - Filename to breakdown # 2 - Where to place base file # 3 - Where to place tex file # Returns non-zero if tex file does not exist # # The rules for determining this depend on the implementation of TeX. # The variable $extension_treatment determines which rules are used. sub find_basename #?? Need to use kpsewhich, if possible { local($given_name, $base_name, $ext, $path, $tex_name); $given_name = $_[0]; if ( "$extension_treatment" eq "miktex_old" ) { # Miktex v. 1.20d: # 1. If the filename has an extension, then use it. # 2. Else append ".tex". # 3. The basename is obtained from the filename by # removing the path component, and the extension, if it # exists. If a filename has a multiple extension, then # all parts of the extension are removed. # 4. The names of generated files (log, aux) are obtained by # appending .log, .aux, etc to the basename. Note that # these are all in the CURRENT directory, and the drive/path # part of the originally given filename is ignored. # # Thus when the given filename is "\tmp\a.b.c", the tex # filename is the same, and the basename is "a". ($base_name, $path, $ext) = fileparse( $given_name, '\..*' ); if ( "$ext" eq "") { $tex_name = "$given_name.tex"; } else { $tex_name = $given_name; } $_[1] = $base_name; $_[2] = $tex_name; } elsif ( "$extension_treatment" eq "unix" ) { # unix (at least web2c 7.3.1) => # 1. If filename.tex exists, use it, # 2. else if filename exists, use it. # 3. The base filename is obtained by deleting the path # component and, if an extension exists, the last # component of the extension, even if the extension is # null. (A name ending in "." has a null extension.) # 4. The names of generated files (log, aux) are obtained by # appending .log, .aux, etc to the basename. Note that # these are all in the CURRENT directory, and the drive/path # part of the originally given filename is ignored. # # Thus when the given filename is "/tmp/a.b.c", there are two # cases: # a. /tmp/a.b.c.tex exists. Then this is the tex file, # and the basename is "a.b.c". # b. /tmp/a.b.c.tex does not exist. Then the tex file is # "/tmp/a.b.c", and the basename is "a.b". if ( -e "$given_name.tex" ) { $tex_name = "$given_name.tex"; } else { $tex_name = "$given_name"; } ($base_name, $path, $ext) = fileparse( $tex_name, '\.[^\.]*' ); $_[1] = $base_name; $_[2] = $tex_name; } else { die "$My_name: Incorrect configuration gives \$extension_treatment=", "'$extension_treatment'\n"; } if ($diagnostics) { print "Given='$given_name', tex='$tex_name', base='$base_name'\n"; } return ! -e $tex_name; } #END find_basename #************************************************************ sub make_preview_continuousB { local @changed = (); local @disappeared = (); local @no_dest = (); # Non-existent destination files local @rules_never_run = (); local @rules_to_apply = (); local $failure = 0; local $runs = 0; local %rules_applied = (); local $updated = 0; # What to make? my @targets = keys %requested_filerules; $quell_uptodate_msgs = 1; local $view_file = ''; rdb_one_rule( 'view', sub{ $view_file = $$Psource; } ); if ( ($view eq 'dvi') || ($view eq 'pdf') || ($view eq 'ps') ) { warn "Viewing $view\n"; } elsif ( $view eq 'none' ) { warn "Not using a previewer\n"; $view_file = ''; } else { warn "$My_name: BUG: Invalid preview method '$view'\n"; exit 20; } my $viewer_running = 0; # No viewer known to be running yet # Get information from update_view rule local $viewer_update_method = 0; # Pointers so we can update the following: local $Pviewer_process = undef; local $Pneed_to_get_viewer_process = undef; rdb_one_rule( 'update_view', sub{ $viewer_update_method = $$PAint_cmd[1]; $Pviewer_process = \$$PAint_cmd[3]; $Pneed_to_get_viewer_process = \$$PAint_cmd[4]; } ); # Note that we don't get the previewer process number from the program # that starts it; that might only be a script to get things set up and the # actual previewer could be (and sometimes IS) another process. if ( ($view_file ne '') && (-e $view_file) && !$new_viewer_always ) { # Is a viewer already running? # (We'll save starting up another viewer.) $$Pviewer_process = &find_process_id( $view_file ); if ( $$Pviewer_process ) { warn "$My_name: Previewer is already running\n" if !$silent; $viewer_running = 1; $$Pneed_to_get_viewer_process = 0; } } # Loop forever, rebuilding .dvi and .ps as necessary. # Set $first_time to flag first run (to save unnecessary diagnostics) CHANGE: for (my $first_time = 1; 1; $first_time = 0 ) { my %rules_to_watch = %requested_filerules; $updated = 0; $failure = 0; $failure_msg = ''; if ( $MSWin_fudge_break && ($^O eq "MSWin32") ) { # Fudge under MSWin32 ONLY, to stop perl/latexmk from # catching ctrl/C and ctrl/break, and let it only reach # downstream programs. See comments at first definition of # $MSWin_fudge_break. $SIG{BREAK} = $SIG{INT} = 'IGNORE'; } if ($compiling_cmd) { Run_subst( $compiling_cmd ); } $failure = rdb_makeB( @targets ); ## warn "=========Viewer PID = $$Pviewer_process; updated=$updated\n"; if ( $MSWin_fudge_break && ($^O eq "MSWin32") ) { $SIG{BREAK} = $SIG{INT} = 'DEFAULT'; } # Start viewer if needed. if ( ($failure > 0) && (! $force_mode) ) { # No viewer yet } elsif ( ($view_file ne '') && (-e $view_file) && $updated && $viewer_running ) { # A viewer is running. Explicitly get it to update screen if we have to do it: rdb_one_rule( 'update_view', \&rdb_run1 ); } elsif ( ($view_file ne '') && (-e $view_file) && !$viewer_running ) { # Start the viewer if ( !$silent ) { if ($new_viewer_always) { warn "$My_name: starting previewer for '$view_file'\n", "------------\n"; } else { warn "$My_name: I have not found a previewer that ", "is already running. \n", " So I will start it for '$view_file'\n", "------------\n"; } } local $retcode = 0; rdb_one_rule( 'view', sub { $retcode = &rdb_run1;} ); if ( $retcode != 0 ) { if ($force_mode) { warn "$My_name: I could not run previewer\n"; } else { &exit_msg1( "I could not run previewer", $retcode); } } else { $viewer_running = 1; $$Pneed_to_get_viewer_process = 1; } # end analyze result of trying to run viewer } # end start viewer if ( $failure > 0 ) { if ( !$failure_msg ) { $failure_msg = 'Failure to make the files correctly'; } @pre_primary = (); # Array of rules @post_primary = (); # Array of rules @one_time = (); # Array of rules &rdb_classify_rules( \%possible_primaries, keys %requested_filerules ); # There will be files changed during the run that are irrelevant. # We need to wait for the user to change the files. # So set the GENERATED files from (pdf)latex as up-to-date: rdb_for_some( [keys %current_primaries], \&rdb_update_gen_files ); # And don't watch for changes for post_primary rules (ps and pdf # from dvi, etc haven't been run after an error in (pdf)latex, so # are out-of-date by filetime criterion, but they should not be run # until after another (pdf)latex run: foreach (@post_primary) { delete $rules_to_watch{$_}; } $failure_msg =~ s/\s*$//; #Remove trailing space warn "$My_name: $failure_msg\n", " ==> You will need to change a source file before I do another run <==\n"; if ($failure_cmd) { Run_subst( $failure_cmd ); } } else { if ($success_cmd) { Run_subst( $success_cmd ); } } rdb_show_rule_errors(); if ($show_time && ! $first_time) { show_timing(); } if ( $first_time || $updated || $failure ) { 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 ); if ($have_break) { last WAIT; } if ( rdb_new_changes(keys %rules_to_watch) ) { if (!$silent) { warn "$My_name: Need to remake files.\n"; &rdb_diagnose_changes( ' ' ); } last WAIT; } # Don't count waiting time in processing: $processing_time1 = processing_time(); # Does this do this job???? local $new_files = 0; rdb_for_some( [keys %current_primaries], sub{ $new_files += &rdb_find_new_filesB } ); if ($new_files > 0) { warn "$My_name: New file(s) found.\n"; last WAIT; } if ($have_break) { last WAIT; } } # end WAIT: &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 #************************************************************ sub process_rc_file { # Usage process_rc_file( filename ) # NEW VERSION # Run rc_file whose name is given in first argument # Exit with code 0 on success # Exit with code 1 if file cannot be read or does not exist. # Stop if there is a syntax error or other problem. # PREVIOUSLY: # Exit with code 2 if is a syntax error or other problem. my $rc_file = $_[0]; my $ret_code = 0; warn "$My_name: Executing Perl code in file '$rc_file'...\n" if $diagnostics; # I could use the do command of perl, but the preceeding -r test # to get good diagnostics gets the wrong result under cygwin # (e.g., on /cygdrive/c/latexmk/LatexMk) my $RCH = new FileHandle; if ( !-e $rc_file ) { warn "$My_name: The rc-file '$rc_file' does not exist\n"; return 1; } elsif ( open $RCH, "<$rc_file" ) { { local $/; eval <$RCH>; } close $RCH; } else { warn "$My_name: I cannot read the rc-file '$rc_file'\n"; return 1; } # PREVIOUS VERSION # if ( ! -r $rc_file ) { # warn "$My_name: I cannot read the rc-file '$rc_file'\n", # " or at least that's what Perl (for $^O) reports\n"; # return 1; # } # do( $rc_file ); if ( $@ ) { # Indent each line of possibly multiline message: my $message = prefix( $@, " " ); warn "$My_name: Initialization file '$rc_file' gave an error:\n", "$message\n"; die "$My_name: Stopping because of problem with rc file\n"; # Use the following if want non-fatal error. return 2; } return 0; } #END process_rc_file #************************************************************ sub execute_code_string { # Usage execute_code_string( string_of_code ) # Run the perl code contained in first argument # Halt if there is a syntax error or other problem. # ???Should I leave the exiting to the caller (perhaps as an option)? # But I can always catch it with an eval if necessary. # That confuses ctrl/C and ctrl/break handling. my $code = $_[0]; warn "$My_name: Executing initialization code specified by -e:\n", " '$code'...\n" if $diagnostics; eval $code; # The return value from the eval is not useful, since it is the value of # the last expression evaluated, which could be anything. # The correct test of errors is on the value of $@. if ( $@ ) { # Indent each line of possibly multiline message: my $message = prefix( $@, " " ); die "$My_name: ", "Stopping because executing following code from command line\n", " $code\n", "gave an error:\n", "$message\n"; } } #END execute_code_string #************************************************************ sub cleanup1 { # Usage: cleanup1( directory, exts_without_period, ... ) my $dir = shift; foreach (@_) { (my $name = /%R/ ? $_ : "%R.$_") =~ s/%R/$dir$root_filename/; unlink_or_move("$name"); } } #END cleanup1 #************************************************************ sub cleanup_cusdep_generated { # Remove files generated by custom dependencies rdb_for_all( \&cleanup_one_cusdep_generated ); } #END cleanup_cusdep_generated #************************************************************ sub cleanup_one_cusdep_generated { # Remove destination file generated by one custom dependency # Assume rule context, but not that the rule is a custom dependency. # Only delete destination file if source file exists (so destination # file can be recreated) if ( $$Pcmd_type ne 'cusdep' ) { # NOT cusdep return; } if ( (-e $$Pdest) && (-e $$Psource) ) { unlink_or_move( $$Pdest ); } elsif ( (-e $$Pdest) && (!-e $$Psource) ) { warn "$My_name: For custom dependency '$rule',\n", " I won't delete destination file '$$Pdest'\n", " because the source file '$$Psource' doesn't exist,\n", " so the destination file may not be able to be recreated\n"; } } #END cleanup_one_cusdep_generated #************************************************************ #************************************************************ #************************************************************ # Error handling routines, warning routines, help #************************************************************ sub die_trace { # Call: die_trace( message ); &traceback; # argument(s) passed unchanged die "\n"; } #END die_trace #************************************************************ sub traceback { # Call: &traceback # or traceback( message, ) my $msg = shift; if ($msg) { warn "$msg\n"; } warn "Traceback:\n"; my $i=0; # Start with immediate caller while ( my ($pack, $file, $line, $func) = caller($i++) ) { if ($func eq 'die_trace') { next; } warn " $func called from line $line\n"; } } #END traceback #************************************************************ sub exit_msg1 { # exit_msg1( error_message, retcode [, action]) # 1. display error message # 2. if action set, then restore aux file # 3. exit with retcode warn "\n------------\n"; warn "$My_name: $_[0].\n"; warn "-- Use the -f option to force complete processing.\n"; my $retcode = $_[1]; if ($retcode >= 256) { # Retcode is the kind returned by system from an external command # which is 256 * command's_retcode $retcode /= 256; } exit $retcode; } #END exit_msg1 #************************************************************ sub warn_running { # Message about running program: if ( $silent ) { warn "$My_name: @_\n"; } else { warn "------------\n@_\n------------\n"; } } #END warn_running #************************************************************ sub exit_help # Exit giving diagnostic from arguments and how to get help. { warn "\n$My_name: @_\n", "Use\n", " $my_name -help\nto get usage information\n"; exit 10; } #END exit_help #************************************************************ sub print_help { print "$My_name $version_num: Automatic LaTeX document generation routine\n\n", "Usage: $my_name [latexmk_options] [filename ...]\n\n", " Latexmk_options:\n", " -aux-directory=dir or -auxdir=dir \n", " - set name of directory for auxiliary files (aux, log)\n", " - Currently this only works with MiKTeX\n", " -bibtex - use bibtex when needed (default)\n", " -bibtex- - never use bibtex\n", " -bibtex-cond - use bibtex when needed, but only if the bib files exist\n", " -bm - Print message across the page when converting to postscript\n", " -bi - Set contrast or intensity of banner\n", " -bs - Set scale for banner\n", " -commands - list commands used by $my_name for processing files\n", " -c - clean up (remove) all nonessential files, except\n", " dvi, ps and pdf files.\n", " This and the other clean-ups are instead of a regular make.\n", " -C - clean up (remove) all nonessential files\n", " including aux, dep, dvi, postscript and pdf files\n", " and file of database of file information\n", " -CA - clean up (remove) all nonessential files.\n", " Equivalent to -C option.\n", " -CF - Remove file of database of file information before doing \n", " other actions\n", " -cd - Change to directory of source file when processing it\n", " -cd- - Do NOT change to directory of source file when processing it\n", " -dependents or -deps - Show list of dependent files after processing\n", " -dependents- or -deps- - Do not show list of dependent files\n", " -deps-out=file - Set name of output file for dependency list,\n", " and turn on showing of dependency list\n", " -dF - Filter to apply to dvi file\n", " -dvi - generate dvi\n", " -dvi- - turn off required dvi\n", " -e - Execute specified Perl code (as part of latexmk start-up\n", " code)\n", " -f - force continued processing past errors\n", " -f- - turn off forced continuing processing past errors\n", " -gg - Super go mode: clean out generated files (-CA), and then\n", " process files regardless of file timestamps\n", " -g - process regardless of file timestamps\n", " -g- - Turn off -g\n", " -h - print help\n", " -help - print help\n", " -jobname=STRING - set basename of output file(s) to STRING.\n", " (Like --jobname=STRING on command line for many current\n", " implementations of latex/pdflatex.)\n", " -l - force landscape mode\n", " -l- - turn off -l\n", " -latex= - set program used for latex.\n", " (replace '' by the program name)\n", " -latexoption=