TransWikia.com

Getting latexmk to work with both .tex and .Rnw files

TeX - LaTeX Asked on December 17, 2020

System information

  • Mint 19.2
  • latexmk 4.41
  • pdfTeX 3.14159265-2.6-1.40.18 (TeX Live 2017/Debian)

Goal

I am trying to set up my .latexmkrc configuration so it detects whether the file that is passed is an .Rnw file, and if so, knits it before compiling into a .pdf.

Attempt

I found a blog post which suggests the following .latexmkrc file:

@default_files = ("*.Rnw");
$pdf_mode = 1;
$graphicx_opts = "final";
$color_opts = "usenames,dvipsnames";
$pdflatex = '([[ ! "%T" =~ .Rnw$ ]] || Rscript -e "'.
'library(knitr);' .
'opts_knit$set(latex.options.graphicx = "' .
$graphicx_opts .
'", latex.options.color = "' .
$color_opts .
'", concordance = TRUE); ' .
'knit('%B.Rnw');" ' .
') && pdflatex -shell-escape -synctex=1 %O %B ' .
'&& ([[ ! "%T" =~ .Rnw$ ]] || Rscript -e "' .
'library(patchSynctex); ' .
'patchSynctex('%B', verbose = TRUE);")'
;

The only thing I added is the -synctex=1 flag, since I found that otherwise on my system the synctex files would not get produced and the final command with patchSynctex would fail.

Problem 1

It doesn’t seem to work on standard .tex files.
I think this is because there is something in the first part of $pdflatex that is not a correctly checking whether the file is .Rnw or not?

$latexmk plain-example.tex
Latexmk: This is Latexmk, John Collins, 1 January 2015, version: 4.41.
Latexmk: applying rule 'pdflatex'...
Rule 'pdflatex': File changes, etc:
   Non-existent destination files:
      'plain-example.pdf'
------------
Run number 1 of rule 'pdflatex'
------------
------------
Running '([[ ! ""plain-example.tex"" =~ .Rnw$ ]] || Rscript -e "library(knitr);opts_knit$set(latex.options.graphicx = "final", latex.options.color = "usenames,dvipsnames", concordance = TRUE); knit('"plain-example".Rnw');" ) && pdflatex -shell-escape -synctex=1  -recorder  "plain-example" && ([[ ! ""plain-example.tex"" =~ .Rnw$ ]] || Rscript -e "library(patchSynctex); patchSynctex('"plain-example"', verbose = TRUE);")'
------------
sh: 1: [[: not found
Error in file(con, "r") : cannot open the connection
Calls: knit -> readLines -> file
In addition: Warning message:
In file(con, "r") :
  cannot open file 'plain-example.Rnw': No such file or directory
Execution halted
Latexmk: Errors, so I did not complete making targets
Collected error summary (may duplicate other messages):
  pdflatex: (Pdf)LaTeX failed to generate the expected log file 'plain-example.log'
Latexmk: Did not finish processing file 'plain-example.tex':
   (Pdf)LaTeX failed to generate the expected log file 'plain-example.log'
Latexmk: Use the -f option to force complete processing,
 unless error was exceeding maximum runs of latex/pdflatex.

I know very little about shell scripting, so this may be quite obvious.

Problem 2

It seems to work well on simple Rnw files, such as this one, which I pieced together from Overleaf’s explanation:

documentclass{article}
usepackage[utf8]{inputenc}
usepackage[english]{babel}

begin{document}

You can type R commands in your LaTeX{} document and they will be properly run and the output printed in the document.

<<>>=
# Create a sequence of numbers
X = 2:10

# Display basic statistical measures
summary(X)

@

<<summary_plot, fig.height=8>>=
plot(sin, -pi, 2*pi)
@

end{document}

Running latexmk on this file seems to work fine, and in particular, latexmk terminates eventually.

However, in more complicated examples, it seems that latexmk never terminates.
For example, in this blog post there is a fairly complicated file called knitr-example.Rnw, which is linked to here.
If I try to run latexmk knitr-example.Rnw, latexmk never seems to terminate cleanly without hitting the maximum number of runs for pdflatex.

My guess is that maybe this second problem is also due to the first problem?
If the control flow in the shell script isn’t working correctly?


EDIT

Here is a partial workaround, which is not great, but seems ok for my current purposes. The idea is to just have latexmk call another bash script.

I modified the latexmkrc file to look like this:

@default_files = ("*.Rnw", "*.tex");
$pdf_mode = 1;
$graphicx_opts = "final";
$color_opts = "usenames,dvipsnames";
$pdflatex = 'knitr-pdflatex.sh "%T" "%B" "%O"';

Then I wrote a simple bash script called knitr-pdflatex.sh that looks like this:

#!/bin/bash
if [ ${1: -4} == ".Rnw" ]
then
    rcommand="library(knitr);"
    rcommand+="opts_knit$set("
    rcommand+="latex.options.graphicx='final',"
    rcommand+="latex.options.color='usenames,dvipsnames',"
    rcommand+="concordance=TRUE);"
    rcommand+="knit('$1');"
    Rscript --verbose -e $rcommand
fi

pdflatex -shell-escape -synctex=1 $3 $2

if [ ${1: -4} == ".Rnw" ]
then
    rcommand=""library(patchSynctex);"
    rcommand+="patchSynctex('$2',verbose=TRUE);""
    Rscript --verbose -e $rcommand
fi

This "solves" whatever syntax problems were causing 1.

Problem 2 still persisted.
I think that is because if knitr is not caching image files, then they get regenerated on each run of $pdflatex.
latexmk notices that a referenced .pdf file (an image) has changed, then re-runs.
This creates an infinite loop.
My "solution" is again not a solution — I just turned on caching, so that images that are already created do not get re-created.

I would still like to know the right way to solve both problems!

One Answer

The config in Cheng Xu's post works for me. I appended the following code to my .latexmkrc and ran latexmk -pdf -pvc [filename].Rnw, and the pdf successfully compiled:

# only enable when compiling .Rnw or .Rtex file
if(grep(/.(rnw|rtex)$/i, @ARGV)) {
    $latex = 'internal knitrlatex ' . $latex;
    $pdflatex = 'internal knitrlatex ' . $pdflatex;
    my $knitr_compiled = {};
    sub knitrlatex {
        for (@_) {
            next unless -e $_;
            my $input = $_;
            next unless $_ =~ s/.(rnw|rtex)$/.tex/i;
            my $tex = $_;
            my $checksum = (fdb_get($input))[-1];
            if (!$knitr_compiled{$input} || $knitr_compiled{$input} ne $checksum) {
                my $ret = system("Rscript -e "knitr::knit('$input')"");
                if($ret) { return $ret; }
                rdb_ensure_file($rule, $tex);
                $knitr_compiled{$input} = $checksum;
            }
        }
        return system(@_);
    }
    # clean up generated .tex file when running `latexmk -c <root_file>`
    $clean_ext .= ' %R.tex';
}

I'm still trying to understand the code, and am not really sure if this config solves your problem, but hope this could give you some leads. Cheers!

Answered by timokratia on December 17, 2020

Add your own answers!

Ask a Question

Get help from others!

© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP