3

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!

  • For the first problem change @default_files = ("*.Rnw"); to @default_files = ("*.Rnw", "*.tex"); so that files with extension .Rnw or .tex get parsed. I don't have Rscript on my machine so can not debug the other problem. – Andrew Swann Dec 20 '19 at 20:21
  • That didn't solve the first problem. I think the issue is this line, which still appears even after changing @default_files: sh: 1: [[: not found. Something about latexmk is using sh where [[ is only understood in bash? I do not know enough about shell scripting, perl, or latexmk to see it myself! – evencoil Dec 21 '19 at 1:09
0

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!

| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.