alex-ball / beamerswitch

Convenient mode selection in Beamer documents
22 stars 0 forks source link

What is the best way to compile multiple file based on the template? #7

Closed vanabel closed 6 years ago

vanabel commented 6 years ago

This seems kind of off-topic, but I hope you can help me work this out (and may view this as a feature request if you think it is proper).

In case I have to prepare a calculus course, I would like to get beamer and article at the same time for each chapter. So the best way is to write a main file first, and then include each chapter file in the main file. The problem is I can't get them compiled separately when I compile the main file.

For example, the main file given as

\PassOptionsToClass{a4paper,12pt}{article}
\PassOptionsToClass{14pt}{beamer}
\documentclass[alsoarticle]{beamerswitch}
\handoutlayout{nup=3plus,border=1pt}
\articlelayout{maketitle,frametitles=none}
\usepackage[british]{babel}
\mode<article>{
  \usepackage[hmargin=3cm,vmargin=2.5cm]{geometry}
}
\mode<presentation>{
  \usefonttheme{professionalfonts}
}
\mode<handout>{
  \usecolortheme{dove}
}
\usepackage{libertine}

\title{A demonstration of the \textsf{beamerswitch} class}
\author{Alex Ball}
\institute{University of Life}
\date{1 September 2016}
\subject{A LaTeX class}
\keywords{CTAN, literate programming}

\begin{document}
  \include{chapter1}
  \include{chapter2}
\end{document}

with

%chapter1.tex
\subtitle{Chapter 1}
  \begin{frame}
    \maketitle
  \end{frame}

and

%chapter2.tex
\subtitle{Chapter 2}
  \begin{frame}
    \maketitle
  \end{frame}

As you can see, I expect that when I compile main.tex, I will get four separated pdf files: chapter1.pdf, chapter2.pdf and chapter1-article.pdf, chapter2-article.pdf.

I try to search \write18 but I don't know how to make it work. Also, I observed that there is a package named subfiles which almost work as expected, but there are two main problem:

  1. It not work in case I switch the class to beamerswitch;
  2. It needs to compile chapter1.tex and chapter2.tex separately to get chapter1.pdf and chapter2.pdf.

A working MME of subfile is given as following:

\documentclass[a4paper,12pt]{amsart}
\usepackage{subfiles}
\usepackage[british]{babel}
\usepackage[hmargin=3cm,vmargin=2.5cm]{geometry}
\usepackage{libertine}

\title{A demonstration of the \textsf{beamerswitch} class}
\author{Alex Ball}
\date{1 September 2016}

\begin{document}
\subfile{chap1}
\subfile{chap2}
\end{document}

and

%chap1.tex
\documentclass[main.tex]{subfiles}
\begin{document}
  \maketitle
\end{document}
%chap2.tex
\documentclass[main.tex]{subfiles}
\begin{document}
  \maketitle
\end{document}
alex-ball commented 6 years ago

I am not sure that \include does what you think it does.

LaTeX takes a set of inputs and generates a single (main) output file. Packages like beamerswitch cheat by using shell-escape to run LaTeX recursively, so you think you are running it once but are actually (for instance) running it four times to generate four PDFs.

\include and \input behave slightly differently, but in essence what they do is insert the content of the named file into the current one so it is as if you had written them in the main file. (\include does some extra things as well as explained by this answer on TeX.se.) They do not generate additional output PDFs.

The packages subfile and standalone, as you have discovered, allow you some extra flexibility, so you can insert multiple standalone documents into a single 'master' document. The idea is that you either run LaTeX on main.tex to get all the chapters in one main.pdf, or run LaTeX individually on each chapter to get one PDF per chapter. If this is more flexibility than you need, and you only want to get single chapter PDFs, then you need to change tactic.

Instead of trying to include your chapters in your main file, you need to insert a common preamble into each of your chapters.

%preamble.tex
\PassOptionsToClass{a4paper,12pt}{article}
\PassOptionsToClass{14pt}{beamer}
\documentclass[alsoarticle]{beamerswitch}
\handoutlayout{nup=3plus,border=1pt}
\articlelayout{maketitle,frametitles=none}
\usepackage[british]{babel}
\mode<article>{
  \usepackage[hmargin=3cm,vmargin=2.5cm]{geometry}
}
\mode<presentation>{
  \usefonttheme{professionalfonts}
}
\mode<handout>{
  \usecolortheme{dove}
}
\usepackage{libertine}

\title{A demonstration of the \textsf{beamerswitch} class}
\author{Alex Ball}
\institute{University of Life}
\date{1 September 2016}
\subject{A LaTeX class}
\keywords{CTAN, literate programming}
%chapter1.tex
\input{preamble.tex}
\subtitle{Chapter 1}
\begin{document}
\begin{frame}
  \maketitle
\end{frame}
\end{document}
%chapter2.tex
\input{preamble.tex}
\subtitle{Chapter 2}
\begin{document}
\begin{frame}
  \maketitle
\end{frame}
\end{document}

Now for the magic. You want to compile all of these in one shot. One of the nice features of latexmk is that if you don't specify a filename it will compile all the .tex files in the current working directory for you. This is slightly more than you want, so you need to create a directory-specific .latexmkrc file to protect the .tex files you don't want to compile directly:

# .latexmkrc
@default_excluded_files = ( 'preamble.tex' );

So to compile all your chapters at once, run the following and go make yourself a hot beverage of your choice while it completes:

latexmk -pdfxe -shell-escape

I hope that helps.

vanabel commented 6 years ago

Thanks for your detailed response. Here is my write18 answer of my original question, which almost output the same results as your posted answer. But fails when I use it with the class beamerswitch:

My main.tex

%main.tex
\documentclass{article}

\gdef\chaplist{sec1,sec2}
\makeatletter
\@for\fname:=\chaplist\do{
  \immediate\write18{%
    pdflatex -jobname="\jobname-\fname"
    \gdef\string\notinmain{1}
    \noexpand\AtBeginDocument{\noexpand\input{\fname}}  
    \string\input\space\jobname%
  }
}
\makeatother
\title{Compile each section based on the master file}
\author{Van Abel}
\date{\today}

\begin{document}
\ifx\notinmain\undefined
  \maketitle
  \tableofcontents
  The value of \texttt{\string\notinmain} in \texttt{\jobname} is: \texttt{\meaning\notinmain}
  \makeatletter
  \@for\fname:=\chaplist\do{
    \include{\fname}
  }
  \makeatother
\fi
\end{document}

and

%sec1.tex
\section{The titile of section 1}
The value of \texttt{\string\notinmain} in \texttt{\jobname} is:\texttt{\meaning\notinmain}
%sec2.tex
\ifdefined\notinmain
  \ifnum\notinmain=1
    \addtocounter{section}{1}
  \fi
\fi
\section{The titile of section 2}
The value of \texttt{\string\notinmain} in \texttt{\jobname} is: \texttt{\meaning\notinmain}

then with a single xelatex --shell-escape main, we will get three files main.pdf, main-sec1.pdf, main-sec2.pdf. Moreover, main.pdf contains all the sections and main-sec1/2 contains only the specified section.

alex-ball commented 6 years ago

What are you trying to achieve here? And is this the best way to go about it?

If you want to have whole_course.pdf, chapter1.pdf, chapter2.pdf in multiple forms, then probably what you want to do is adapt my answer above. Move the maketitle commands to the preamble file:

% preamble.tex
...
\usepackage{etoolbox}
\AfterEndPreamble{
\begin{frame}
  \maketitle
\end{frame}
}
...

...so that you only get the course content in the {document} environment in your chapter files. Your whole course document would then look something like this (the standalone package strips out the preamble in the input files and transforms the inner {document} environment into a simple group):

% whole_course.tex
\input{preamble}
\usepackage{standalone}
\renewcommand{\PassOptionsToClass}[2]{}
\begin{document}

% code for your sectional title slide for chapter 1, then...
\mode<all>{\input{chapter1.tex}}

% code for your sectional title slide for chapter 2, then...
\mode<all>{\input{chapter2.tex}}

\end{document}

Or you could simply concatenate your PDF files with a tool like pdfjam, pdftk or .tex files that use pdfpages (named so they get compiled after your chapters).

But purely as an intellectual exercise, let's have a look at your latest solution. On my system your code fails with the following when initiated from XeLaTeX or PDFLaTeX:

! I can't find file `gdef'.

This is because your backslashes are not properly escaped; you should be using \string\\. Also, recent versions of LuaLaTeX do not support \write18 for running system commands. You should be using the shellesc package instead.

So assuming you fix your code:

\usepackage{shellesc}
\makeatletter
\@for\fname:=\chaplist\do{
  \ShellEscape{%
    pdflatex -jobname="\jobname-\fname"
    \string\\gdef\string\\notinmain{1}
    \string\\AtBeginDocument{\string\\input{\fname}}
    \string\\input{\jobname}%
  }
}
\makeatother

and replace \documentclass{article} with documentclass[article]{beamerswitch} everything works as you intend.

Now, if you then try and use the beamerswitch features you will find yourself running into all sort of complications.

Is it really worth all this hassle when much simpler options are available to you?