9

In C, I can write #pragma once as a preprocessor directive at the top of a header file, which tells any compiler that supports it to include the file a maximum of one time per compilation cycle, regardless of how many times I #include that header file in the other source files. It is a common alternative to #ifndef/#define/#endif include guards, despite not being an officially documented/supported part of the standard.

La(TeX) has several facilities for so-called "include guards", many of which are outlined in the answers to Conditional typesetting / build.

My question is: Does there exist (or is there a possibility of) a construct in (La)TeX analogous to #pragma once in the C language; that is, a directive set on one line of a file which causes that file to be input only one time during the compilation?

MWE for Testing:

\documentclass{article}
\usepackage{filecontents}

\begin{filecontents*}{mydefs.tex}
%<-- insert magic *#pragma once*-like line here to prevent errors
\newcommand{\foo}{foo}
\newcommand{\baz}{baz}
\end{filecontents*}

\begin{document}
\input{mydefs}
\input{mydefs}
\foo\ \baz\ test.
\end{document}

Note:

You might say to just use \providecommand and be done with it, which is a valid answer. But I would like to know if what I've proposed is possible with (La)TeX, for science!

  • You could use a flag, and wrap the \input command to test first. – Ethan Bolker Aug 6 '14 at 16:15
  • 3
    You know that's what \usepackage does, I suppose? If you want to do things 'by hand' it's normal to do \csname myresevedname\endcsname\let\myreservedname\endinput (if it's not been defined, the \csname construct will do nothing important, and on a second pass it will be set up equal to \endinput). – Joseph Wright Aug 6 '14 at 16:23
  • 2
    Well, you can use gpp on LaTeX files. – Raphael Aug 6 '14 at 20:58
8

May be you needn't to deal with the name of the file or with another special identifier at the start ot such file. If I understand your question, you need only simply type \pragmaonce at the start of the file. I've looked to the LaTeX internals and I've found that: if the \input is followed by {, i. e. \input{filename}, then the \@iinput{filename} macro is processed. Thus I redefined this macro:

\documentclass{article}
\usepackage{filecontents}

\makeatletter
\let\pragma@iinput=\@iinput
\def\@iinput#1{\xdef\@pragmafile{#1}\pragma@iinput{#1}}
\def\@pragmafile{default}
\def\pragmaonce{%
   \csname pragma@\@pragmafile\endcsname
   \global\expandafter\let \csname pragma@\@pragmafile\endcsname = \endinput
}
\makeatother

\begin{filecontents*}{mydefs.tex}
\pragmaonce %<-- insert magic *#pragma once*-like line here to prevent errors
\newcommand{\foo}{foo}
\newcommand{\baz}{baz}
\end{filecontents*}

\begin{document}
\input{mydefs}
\input{mydefs}
\foo\ \baz\ test.
\end{document}

Of course, you have to respect the discipline and to type the \input only with braces around filename.

  • Very nice! This is basically what I was looking for. – Paul Gessler Aug 7 '14 at 14:19
5

If you load mydefs with \usepackage, giving it the .sty extension, LaTeX will load it only once. But it will not be available after \begin{document}.

The analog of #pragma once could be

\ifcsname mydefs.tex\endcsname
  \expandafter\endinput
\fi
\expandafter\gdef\csname mydefs.tex\endcsname{loaded}

<code in mydefs.tex>
  • shouldn't it be \gdef instead of \global\let? – clemens Aug 6 '14 at 17:08
  • @cgnieder Yes, wrong code. Fixed – egreg Aug 6 '14 at 17:10

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.