What you forgot is that a custom dependency is intended to have input and output files that differ only in their extensions, e.g., to convert foo.ltx
to foo.fmt
. But they don't work to convert, for example, fmt/preamble.tex
to main.fmt
. A second, but less severe, problem is that when pdfLaTeX doesn't find the .fmt
file, it dies with an error message to the screen, but it doesn't put the error message in the log file (so that latexmk
doesn't detect that there is a missing file).
If you rename your preamble file to main.ltx
(not in a subdirectory), then the following initialization code should work:
$recorder = 1;
$pdflatex = 'pdflatex -fmt main %O %S';
add_input_ext('pdflatex','fmt');
add_cus_dep('ltx', 'fmt', 1, 'compilepreamble');
sub compilepreamble {
print "Preamble compiling for '$_[0]'...\n";
my $fls_file = "$_[0].fls";
my $source = "$_[0].ltx";
my $fmt_file = "$_[0].fmt";
my $return = system( "pdflatex", "-interaction=batchmode",
"-ini", "-recorder", "-jobname=$_[0]",
"&pdflatex $source \\dump" );
if ($return) {
warn "Error in making format file '$fmt_file'\n";
return $return;
}
my %input_files = ();
my %output_files = ();
$return = parse_fls( $fls_file, \%input_files, \%output_files );
if ($return) {
warn "No fls file '$fls_file' made; I cannot get dependency data\n";
return 0;
}
# Use latexmk's internal variables and subroutines for setting the
# dependency information.
# Note that when this subroutine is called to implement a custom
# dependency, the following variables are set:
# $rule contains the name of the current rule (as in the
# fdb_latexmk file)
# $PHsource is a pointer to a hash of source file
# information for the rule. The keys of the hash are
# the names of the source files of the rule.
foreach my $file (keys %input_files) {
rdb_ensure_file( $rule, $file );
}
foreach my $file (keys %$PHsource) {
if ( ! exists $input_files{$file} ) {
print " Source file of previous run '$file' ",
"IS NO LONGER IN USE\n";
rdb_remove_files( $rule, $file );
}
}
return 0;
};
I've used an extension .ltx
rather than .tex
so that you can have a preamble file with the same basename as the main file.
You'll need to run the pdflatex -ini ...
manually the first time, to create the .fmt
file. After that latexmk
should handle things automatically.
Edit (2 April 2012): I improved the code so that it detects dependencies on files used by pdflatex -ini
. This uses some of the internal variables and subroutines of latexmk
.
If you look carefully at the output from the run, you'll see that on the first run, pdflatex
detects a first missing file. Since nonstopmode is being used, that causes a fatal error, and pdflatex
goes no further. Then latexmk
sees a message about a single missing file, makes it, and repeats the run. Then an error comes up about the second missing file, etc, with the annoying phenomenon you observed. The situation is different when \include
is used instead of \input
. This macro behaves differently: the missing file is no longer a fatal error; instead there are messages in the log file for all the missing files, all on the first run.
There are two solutions. One is to run pdflatex
in its normal mode, where it will stop and ask you to correct the filename. Just hitting the enter key will cause pdflatex
to continue, ignoring the missing file. To automate this, change the second line of your Makefile
to
latexmk -pdf -pdflatex="cat responses | pdflatex -interaction=nonstopmode" -use-make test.tex
where responses
is a file containing many blank lines.
A more systematic solution is to replace \input
by a macro which gives a warning instead of a fatal error when a file is missing:
\documentclass{article}
\newcommand\inputA[1]{%
\InputIfFileExists{#1}{}{\typeout{No file #1.}}%
}
\begin{document}
\inputA{foo1}
\inputA{foo2}
\inputA{foo3}
\inputA{foo4}
\inputA{foo5}
\inputA{foo6}
\end{document}
I've used this trick quite a few times.
Best Answer
@tohecz: You are correct.
The problem is that the dependencies depend in a complicated way on the detailed contents of the TeX file (and all the files it calls in, including the class file and the style files). The only easy way to determine the dependencies is to run
pdflatex
(orlatex
as appropriate), and then analyze the resulting files (the relevant ones are the.fls
,.log
and.aux
files). If the.tex
file changes, then both the.pdf
and the dependency information are simultaneously out of date.Therefore, if you want to run
pdflatex
to determine the dependencies, you get a new.pdf
file as a side effect. So there's no point to trying to update the dependency information without updating the.pdf
file.