[Tex/LaTex] Compile to PDF file with different name than the source

macrospdf

I have a latex document containing some problems and their solutions. I also have a macro \excludecomment{sol} which if uncommented, excludes the solution environments. (Similar command is there for prob environment.)

The general question is whether I can include a command in these macros or otherwise so that depending on whether the macro is active or not is reflected in the filename of the PDF file (e.g., by adding a _sol to the filename when the solutions are present.)

Best Answer

You can't change the name of the output files/the name of the .pdf file during the TeX run/LaTeX run.

The reason is:

The output files are created anew and opened for writing right at the beginning of the TeX run/LaTeX run.
(E.g., the .log file is created anew and opened for writing right after starting the tex-executable or latex-executable. E.g., the .pdf file is created anew and opened for writing when shipping out the very first page of the document. )
The output files (and thus also the .pdf file) are left open for writing until the end of the TeX run/LaTeX run.
With most computer platforms you can't change the name of a file while that file is open for writing.

But with most TeX-platforms you can run tex-binaries/executables with command line options.

One of these options is the option -jobname.

If you have the main .tex-file foo.tex and compile it by running latex from the command line as

pdflatex --jobname=bar foo.tex

, you won't get the output files foo.aux, foo.log and foo.pdf, etc, but you will get output files bar.aux, bar.log and bar.pdf, etc.

Also the primitive \jobname won't deliver the phrase foo in this case but will deliver the phrase bar.

You can't use a macro for changing the names of output files during the LaTeX run but you can go the other direction:

Create a macro which examines whether the expansion of \jobname contains some specific phrase and forks accordingly. Be aware that \jobname spits out explicit space tokens of category code 10(space) and explicit character tokens of category code 12(other).


Example:

Save the following example as test.tex :

\documentclass{article}
\usepackage{comment}

\begingroup    
\makeatletter
%%----------------------------------------------------------------------
%% Check whether argument is empty:
%%......................................................................
%% \UD@CheckWhetherNull{<Argument which is to be checked>}%
%%                     {<Tokens to be delivered in case that argument
%%                       which is to be checked is empty>}%
%%                     {<Tokens to be delivered in case that argument
%%                       which is to be checked is not empty>}%
%% The gist of this macro comes from Robert R. Schneck's \ifempty-macro:
%% <https://groups.google.com/forum/#!original/comp.text.tex/kuOEIQIrElc/lUg37FmhA74J>
\long\def\UD@CheckWhetherNull#1{%
  \romannumeral0\expandafter\@secondoftwo\string{\expandafter
  \@secondoftwo\expandafter{\expandafter{\string#1}\expandafter
  \@secondoftwo\string}\expandafter\@firstoftwo\expandafter{\expandafter
  \@secondoftwo\string}\expandafter\expandafter\@firstoftwo{ }{}%
  \@secondoftwo}{\expandafter\expandafter\@firstoftwo{ }{}\@firstoftwo}%
}%
%%----------------------------------------------------------------------
%% Check whether expansion of \jobname contains no phase "_sol"
%%......................................................................
%% \UD@CheckWhetherNoSolInJobname{<Tokens to be delivered in case that
%%                                 \jobname contains no phrase "_sol">}%
%%                               {<Tokens to be delivered in case that
%%                                 \jobname contains the phrsae "_sol">}%
\def\UD@GobbleToSol{_sol}%
\@onelevel@sanitize\UD@GobbleToSol
\edef\CheckWhetherNoSolInJobname{%
  \noexpand\expandafter\noexpand\UD@CheckWhetherNull
  \noexpand\expandafter{\noexpand\UD@GobbleToSol\jobname\UD@GobbleToSol}%
}%
\expandafter\long\expandafter\def
\expandafter\UD@GobbleToSol\expandafter#\expandafter1\UD@GobbleToSol{}%
\CheckWhetherNoSolInJobname{%
  \endgroup
  \newcommand\CheckWhetherNoSolInJobname[2]{#1}%
}{%
  \endgroup
  \newcommand\CheckWhetherNoSolInJobname[2]{#2}%
}%
%% \makeatother not needed. Instead the group is closed.
%%----------------------------------------------------------------------

\CheckWhetherNoSolInJobname{%
  \excludecomment{sol}%
}{%
  \includecomment{sol}%
}%

\begin{document}

Expansion of \verb|\jobname| is: \texttt{\jobname}

\texttt{\string\jobname} does
\CheckWhetherNoSolInJobname{%
  not%
}{%
  indeed%
}
contain the phrase \verb|_sol|.

Thus solutions
\CheckWhetherNoSolInJobname{%
  are not included%
}{%
  get included also%
}.

\bigskip

This is the question.
\begin{sol}

This is the answer.
\end{sol}

\end{document}

Compiling from the command line via pdflatex test.tex yields test.pdf which looks like this:

enter image description here

Compiling from the command line via pdflatex --jobname=test_sol test.tex yields test_sol.pdf which looks like this:

enter image description here



Another approach could be:

File test_sol.tex:

\newcommand\solutioninorexclude{%
  \includecomment{sol}%
}%
\input test.tex

File test.tex:

\documentclass{article}
\usepackage{comment}
\providecommand\solutioninorexclude{%
  \excludecomment{sol}%
}%
\solutioninorexclude    

\begin{document}

This is the question.
\begin{sol}

This is the answer.
\end{sol}

\end{document}

Compiling test_sol.tex yields test_sol.pdf:

enter image description here

Compiling test.tex yields test.pdf:

enter image description here

A variation on this approach can be having test.tex create the file test_sol.tex for you automatically in case it does not exist:

When you save the example below as test.tex and compile it, you will get a file test.pdf which contains the text without solutions. You also get a file test_sol.tex. If you compile that, it will—via \input—import test.tex in a way where sol-environments are included. Thus you get a file test_sol.pdf which does also contain solutions:

\documentclass{article}
\usepackage{comment}
\providecommand\solutioninorexclude{%
  \excludecomment{sol}%
  \includecomment{solinputfile}%
}%
\solutioninorexclude    

\begin{solinputfile}
\begingroup
\makeatletter
\IfFileExists{\jobname\string_sol.tex}{%
  \@latex@warning@no@line{File \jobname\string_sol.tex already exists. Not generating it}%
}{%
  \@latex@warning@no@line{Generating file \jobname\string_sol.tex}%
  \newwrite\solinputfile
  \immediate\openout\solinputfile\jobname\string_sol.tex\relax
  \immediate\write\solinputfile{%
    \string\newcommand\string\solutioninorexclude{\@percentchar^^J%
    \space\space\string\includecomment{sol}\@percentchar^^J%
    \space\space\string\excludecomment{solinputfile}\@percentchar^^J%
    }\@percentchar^^J%
    \string\input\space\jobname.tex%
  }%
  \immediate\closeout\solinputfile
}%
\endgroup
\end{solinputfile}

\begin{document}

This is the question.
\begin{sol}

This is the answer.
\end{sol}

\end{document}


Yet another approach could be using something like the docstrip package. The purpose of the docstrip package is copying files of tex-source-code with having comments removed. It provides means for conditional inclusion of code into the copies.

E.g. if you save the following example as test.tex and compile it, you don't get a .pdf file but you get two new text files.

%<*ignore>
\input docstrip
\nopreamble
\nopostamble
\askforoverwritetrue
\generate{\file{\jobname\string_sol.tex}{\from{\jobname.tex}{sol}}}
\generate{\file{\jobname\string_nosol.tex}{\from{\jobname.tex}{}}}
% Here you can do some \immediate\write18-calls for calling LaTeX or
% TeXify or latexmk for compiling \jobname_sol.tex and
%\jobname_nosol.tex.
% You need to have the \write18-feature enabled for this.
% Some people take enabling \write18 for a security issue.
\csname stop\endcsname
\bye
%</ignore>
\documentclass{article}
% This comment won't occur in the generated files.
% This comment won't occur in the generated files.
\begin{document}
This is the question.
%<*sol>
    
This is the answer.
%</sol>
\end{document}

One of these text files is named test_nosol.tex and its content is:

\documentclass{article}
\begin{document}
This is the question.
\end{document}

The other of these text files is named test_sol.tex and its content is:

\documentclass{article}
\begin{document}
This is the question.

This is the answer.
\end{document}
Related Question