diff options
Diffstat (limited to 'support/latexmk/example_rcfiles/precompile-preamble_latexmkrc')
-rw-r--r-- | support/latexmk/example_rcfiles/precompile-preamble_latexmkrc | 234 |
1 files changed, 234 insertions, 0 deletions
diff --git a/support/latexmk/example_rcfiles/precompile-preamble_latexmkrc b/support/latexmk/example_rcfiles/precompile-preamble_latexmkrc new file mode 100644 index 0000000000..843334b05f --- /dev/null +++ b/support/latexmk/example_rcfiles/precompile-preamble_latexmkrc @@ -0,0 +1,234 @@ +print "Latexmk rc file for using precompiled headers.\n", + "John Collins. V. 1.3. 3 Jan 2024.\n"; +# John Collins jcc8 at psu dot edu + +# To implement precompilation of preamble by the package mylatexformat. +# See the documentation for the package mylatexformat for more information. +# Overall strategy: +# 1. At start of each run of *latex rule, copy (relevant part of) preamble +# from the primary .tex file to a file with extension .hdr. +# 2. The base name of the header file has -latex, or -pdflatex, etc +# appended to it. That provides a flag as to which program is to be +# used to make the .fmt file, and what program can use the .fmt file. +# 2. A cus-dep is defined to make a .fmt file from the corresponding .hdr +# file. It uses mylatexformat, and whichever of the -latex, -pdflatex, +# etc strings appears at the end of its base name indicates which +# program to use to create it. (The -ini option is given to the +# program to indicate that a .fmt file is to be made.) +# 4. Compilation of document: use .fmt file if it exists. +# If not, inject a message into the log file, to indicate that the .fmt +# is missing. After the analysis of the results of the compilationi, +# latexmk takes this as an indication that it should try to make the +# .fmt file. +# +# Note that on an initial round of compilation, before the format file has +# been created, latexmk will do one round of compilation without a +# precompiled preamble. After that latexmk creates the format file for the +# precompiled header. Some trickery could be used to get the format file +# to be made first, but since this is a one-time-only issue, it's simpler +# not to do the trickery. +# +# Restriction: Doesn't work with spaces and/or non-ASCII characters in +# name of .tex file. + +# STILL TO DO: +# +# 1. Get full dependency information for the step for making the format. +# Ideally that needs support from latexmk, so as to use its +# already existing tools. (Complication: the usual way in which latexmk +# determines dependencies from a run of a *latex type program assumes +# that a correct run always generates an .aux file. That's not the case +# for "pdflatex -ini" etc. +# I've done a sufficient job, I think, by using the -recorder option, +# analyzing the resulting .fls file and using latexmk's documented +# rdb_set_source subroutine. +# 2. On make of .fmt file, need ideally to use jobname = $root, to avoid +# problems listed in +# https://tex.stackexchange.com/questions/19403/tikzs-externalization-and-mylatex +# Then I would need to do some renaming; perhaps save fls and log files from +# main run, compile the header, rename the fls, log and fmt files from this +# run, and finally, put the original fls and log files in place. +# Better, perhaps: Use subdirectories of auxdir, e.g., named fmt-latex, +# fmt-pdflatex, etc, to contain .fmt file (and .hdr file), along with +# suitable setting of search path (in variable TEXFORMATS). + +# General settings +$out_dir = 'output'; +$aux_dir = 'auxdir'; + +$emulate_aux = 1; # Avoid any problems with TeXLive, which doesn't + # natively support different aux and out directories. +$show_time = 1; # Show diagnostics on timings, so as to make visible + # time savings due to use of preamble. + +# Sub-second sleep time will work in latexmk v. 4.82 upwards. +# That gives excellent responsiveness when preview-continuous mode is used, +# and helps to enhance any significant gain in compilation time from the +# use of a precompiled preamble. +$sleep_time = 0.05; + +$pdf_mode = 1; # Use pdflatex. Note that xelatex and lualatex don't work + # with precompiled preambles. + +# Configuration for precompiled preamble: + +$make_fmt = '%C %O -ini -output-directory=%V -jobname=%B "&%C" mylatexformat.ltx %S'; + +# I only arrange to use latex and pdflatex with precompiled preambles. +# None of lualatex, xelatex, and hilatex can use precompiled headers (from +# tests on 22 Dec 2023). Each had different trouble, and this is a known +# problem. +# But things did work for latex and pdflatex. + +# Therefore only set things up for latex and pdflatex. +foreach my $engine ( 'latex', 'pdflatex' ) { + say "Setting rules for $engine"; + ${$engine} = "internal mylatex %R $engine %O %S"; + push @generated_exts, "%R-$engine.*"; +} + +add_cus_dep( 'hdr', 'fmt', 0, make_fmt_cus_dep ); + +push @generated_exts, '%R-*.hdr', '%R-*.fmt'; + + +#================================================= + +sub make_fmt_cus_dep { + my $path_base = $_[0]; + my ($base, $path) = fileparse($path_base); + my $source = "$path_base.hdr"; + my $dest = "$path_base.fmt"; + my $fls = "$path_base.fls"; + my $engine = 'pdflatex'; + if ( $base =~ /-([^-]+)$/ ) { + $engine = $1; + } + my $cmd = $make_fmt; + $cmd =~ s/%C/$engine/g; + my $options = '-recorder'; + if ($silent) { $options .= ' -interaction=batchmode'; } + my $ret = Run_subst( $cmd, 2, $options, $source, $dest, $base ); + my @source_files = get_fls_inputs( $fls ); + if (@source_files) { rdb_set_source( $rule, @source_files ); } + else { warn "Could not determine source files for '$rule'\n"; } + return $ret; +} + +#================================================= + +sub make_hdrA { + use strict; + my ($source, $dest) = @_; + my $h_in = undef; + my $h_out = undef; + if ( ! open( $h_in, "<", $source ) ) { + print "make_header could not read source file '$source'\n"; + return 1; + } + if (! open( $h_out, ">", $dest ) ) { + print "make_header could not write header file '$dest'\n"; + return 2; + } + while (<$h_in>) { + if ( /^\s*\\begin\s*{document}/ + || /^\s*\\endofdump/ + || /^\s*\\csname\s+endofdump\\endcsname/ + ) + { last; } + print $h_out $_; + } + print $h_out "\\endofdump\n"; + close $h_out; + close $h_in; + return 0; +} + +#================================================= + +sub mylatex { + # Arguments are: + # 1. base name of the fmt file + # 2. the compilation program + # then the arguments to be + use strict; + our ($aux_dir1, $out_dir1, $emulate_aux, $Pbase, $Psource ); + + my ($fmt_base, $engine, @args) = @_; + $fmt_base .= "-$engine"; + my $source = $$Psource; + my $ret = 0; + + my $fmt_file = "$aux_dir1$fmt_base.fmt"; + my $hdr_file = "$aux_dir1$fmt_base.hdr"; + if ( make_hdrA( $source, $hdr_file ) > 0 ) { + die "I'm stopping, since I could not make '$hdr_file' from '$source'.\n"; + } + + # Location of .fls file after running engine, before any fudge to + # emulate aux dir: + my $fls_file = ($emulate_aux ? $aux_dir1 : $out_dir1 ) . "$$Pbase.fls"; + my $log_file = "$aux_dir1$$Pbase.log"; + + if ( -e $fmt_file ) { + @args = ("-fmt=$fmt_base", @args); + } + else { + print "Format file '$fmt_file' does not exist. I'll run without it.\n"; + } + + my @cmd = ($engine, @args); + print "Running '@cmd'\n"; + $ret = system @cmd; + + # Add lines to fls file to add dependency information: + # (a) that a hdr file is generated. + # (b) dependency on fls file. + # Earlier I thought I needed to force a dependence on fls file. + # (22 Dec 2023) I don't remember why, so I'll leave that in. + append( $fls_file, + "INPUT $fls_file\n". + "OUTPUT $hdr_file\n" + ); + + # Ensure latexmk knows that the .fmt file needs to be made if it + # doesn't yet exist: + if ( !-e $fmt_file ) { append( $log_file, "No file $fmt_file.\n" ); } + return $ret; +} + +#================================================= + +sub append { + use strict; + my ($file, $string) = @_; + if ( !-e $file ) { return 1; } + open( my $fh, ">>", $file ) + or die "Cannot append to '$file'\n $_"; + print $fh $string; + close $fh; + return 0; +} + +#================================================= + +sub get_fls_inputs { + my $fls_file = shift; + my %inputs = (); + my $fh = undef; + if ( ! open( $fh, '<', $fls_file ) ) { + warn "Cannot read '$fls_file':\n$!"; + return (); + } + while (my $line = <$fh>) { + if ( $line =~ /^INPUT\s+(.+)\s*$/ ) { + my $file = $1; + $inputs{$file} = 1; + } + } + close $fh; + return keys %inputs; +} + +#================================================= + |