34

I want to write in the preamble of a LaTeX document code that should be take into account by different compilers when the document is typeset. There are fragments that should be used:

  • only by xelatex
  • only by lualatex
  • only by xelatex or lualatex
  • only by pdflatex

I am using the packages ifxetex and ifluatex that provide the commands \ifxetex and \ifluatex, respectively.

How can I logically combine these commands in a disjunction (or operation)?

The code would be something like:

\ifxetex
  % code used only by xetex
\else
  \ifluatex
    % code used only by luatex
  \fi
\fi

\ifxetex OR \ifluatex     % I do not know how to express this conditional <--------
  % code used by both xetex and luatex
\else
  % code used by other (pdflatex, say)
\fi

Any help?

5 Answers 5

41
\usepackage{ifxetex,ifluatex}
\newif\ifxetexorluatex
\ifxetex
  \xetexorluatextrue
\else
  \ifluatex
    \xetexorluatextrue
  \else
    \xetexorluatexfalse
  \fi
\fi

Now \ifxetexorluatex will do what you want. For instance, for loading fontspec and setting input normalization:

\ifxetexorluatex
   \usepackage{fontspec}
   \setmainfont{TeX Gyre Pagella}
\else
   \usepackage[T1]{fontenc}
   \usepackage{tgpagella}
\fi

\ifxetex
  \XeTeXinputnormalization=1
\fi

A different implementation, just for fun, is

\newif\ifxetexorluatex
\begingroup\catcode94=7 \catcode0=9 % ASCII 94 is ^
\def\empty{}\def\next{^^^^0000}\expandafter\endgroup
\ifx\next\empty\xetexorluatextrue\else\xetexorluatexfalse\fi

It exploits the fact that the XeTeX and LuaTeX engines have the ^^^^ convention for inputting character with their Unicode point. If the engine is Unicode aware, ^^^^0000 counts as a unique token which, by the assignment \catcode0=9 is ignored, so that \next expands to nothing and is equivalent to \empty. In case an 8-bit engine is used, the expansion of \next would contain six tokens (^^^ counts as one, then ^0000) and \ifx will follow the "false" path.

Another way of doing it, without defining an \ifxetexorluatex conditional, is to say

\ifnum 0\ifxetex 1\fi\ifluatex 1\fi>0
   % code for XeTeX or LuaTeX
\else
   % code for pdfLaTeX
\fi

There must be no space between 0 and \ifxetex and between 1 and \fi. This exploits the fact that TeX expands tokens when looking for numbers. So if one of the two inner conditionals is true, the engine will see 01, which is greater than zero. If both are false it will see 0.

So a shorter way to set \ifxetexorluatex can be

\newif\ifxetexorluatex % a new conditional starts as false
\ifnum 0\ifxetex 1\fi\ifluatex 1\fi>0
   \xetexorluatextrue
\fi

A much more general implementation using expl3.

\documentclass{article}

\usepackage{xparse}

\ExplSyntaxOn
\cs_new_eq:NN \pdftexengine \sys_if_engine_pdftex_p:
\cs_new_eq:NN \xetexengine  \sys_if_engine_xetex_p:
\cs_new_eq:NN \luatexengine \sys_if_engine_luatex_p:
\cs_new_eq:NN \ptexengine   \sys_if_engine_ptex_p:
\cs_new_eq:NN \uptexengine  \sys_if_engine_uptex_p:

\NewExpandableDocumentCommand{\ifengineTF}{mmm}
 {
  \bool_if:nTF { #1 } { #2 } { #3 }
 }
\ExplSyntaxOff

\begin{document}

\ifengineTF{\pdftexengine}
  {\typeout{pdf}}
  {\typeout{not pdf}}

\ifengineTF{\xetexengine || \luatexengine}
  {\typeout{either xe or lua}}
  {\typeout{neither xe nor lua}}

\ifengineTF{\pdftexengine || \xetexengine || \luatexengine}
 {\typeout{pdf or xe or lua}}
 {\typeout{ptex or uptex}}

\end{document}

Running from the shell the following commands

> pdflatex engines >> engines.out
> xelatex engines >> engines.out
> lualatex engines >> engines.out
> platex engines >> engines.out

results in the following engines.out file (edited to show only the relevant parts)

This is pdfTeX, Version 3.14159265-2.6-1.40.19 (TeX Live 2018) (preloaded format=pdflatex)
 restricted \write18 enabled.
entering extended mode
(./engines.tex
[...]
pdf
neither xe nor lua
pdf or xe or lua
[...]

This is XeTeX, Version 3.14159265-2.6-0.99999 (TeX Live 2018) (preloaded format=xelatex)
 restricted \write18 enabled.
entering extended mode
(./engines.tex
[...]
not pdf
either xe or lua
pdf or xe or lua
[...]

This is LuaTeX, Version 1.07.0 (TeX Live 2018) 
 restricted system commands enabled.
(./engines.tex
[...]
not pdf
either xe or lua
pdf or xe or lua
[...]

This is e-pTeX, Version 3.14159265-p3.8.1-180226-2.6 (utf8.euc) (TeX Live 2018) (preloaded format=platex)
 restricted \write18 enabled.
entering extended mode
(./engines.tex
[...]
not pdf
neither xe nor lua
ptex or uptex
(./engines.aux) )
[...]

A different solution, with perhaps a better syntax, at the expense of expandability (until we will have e-expansion available).

\documentclass{article}

\usepackage{xparse}

\ExplSyntaxOn

\NewDocumentCommand{\ifengineTF}{mmm}
 {
  \bool_if:xTF
   {
    \clist_map_function:nN { #1 } \__egreg_predicate:f \c_true_bool
   }
   { #2 } { #3 }
 }
\cs_generate_variant:Nn \bool_if:nTF { x }

\cs_new:Nn \__egreg_predicate:n
 {
  \use:c { sys_if_engine_#1_p: } ||
 }
\cs_generate_variant:Nn \__egreg_predicate:n { f }
\ExplSyntaxOff

\begin{document}

\ifengineTF{pdftex}
  {\typeout{pdf}}
  {\typeout{not pdf}}

\ifengineTF{xetex,luatex}
  {\typeout{either xe or lua}}
  {\typeout{neither xe nor lua}}

\ifengineTF{pdftex,xetex,luatex}
 {\typeout{pdf or xe or lua}}
 {\typeout{ptex or uptex}}

\end{document}

The output is the same as before.

3
  • Sorry, but \ifxetexorluatex will not distinguish between XeTeX and LuaTeX - which Romildo wants. Mar 10, 2012 at 23:40
  • 7
    @MartinSchröder Of course it won't, how could it? For XeTeX or LuaTeX specific code, \ifxetex and \ifluatex can still be used; where's the problem? Romildo wanted a conditional to distinguish between (XeTeX or LuaTeX) and pdfTeX.
    – egreg
    Mar 10, 2012 at 23:46
  • 3
    A safer version of the catcode trick (only if \scantokens is available) is \begingroup\catcode94=7\catcode0=9\catcode30=12\catcode48=12\everyeof{\noexpand}\expandafter\endgroup\if\scantokens{^^^^0000}??\xetexorluatextrue\else\xetexorluatexfalse\fi. Mar 11, 2012 at 10:49
13

In such situations, the generic \ifboolexpr wrapper provided by the etoolbox package comes in handy:

\usepackage{etoolbox,ifxetex,ifluatex}

\ifboolexpr{bool{xetex} or bool{luatex}}{%
  <true-code>%
}{%
  <false-code>%
}

The bool operator that works with the \ifboolexpr syntax to perform boolean tests operates on all primitive style TeX conditionals. Note that it omits the \if prefix of the original \ifxetex and \ifluatex commands.

9

Sometimes this sort of issue is easier to solve by changing the order of checking things.

\documentclass{article}
\usepackage{ifpdf,ifluatex,ifxetex}
\begin{document}
\ifpdf
      I am in pdf
   \else
       common code for lualatex and xelatex
    \ifluatex  ...    \fi
    \ifxetex   ...    \fi
\fi
\end{document}
5
  • 2
    Won't this approach fail if the tex file happens to be compiled under a TeX format other than pdflatex, xelatex, or lualatex?
    – Mico
    Mar 11, 2012 at 3:14
  • @Mico The OP only wanted to check for this, but in general it wouldn't, provided your code is common to all, otherwise you build more checks \ifvtex etc... Mar 11, 2012 at 3:59
  • 1
    IIRC, \ifpdf checks the output mode not the engine, so it is true for pdftex or luatex in pdf mode and false otherwise. Mar 11, 2012 at 5:26
  • @KhaledHosny The example compiles correctly for the pdfLaTeX, LuaLaTeX and XeLaTeX. It will fail in all other cases due to the documentclass{}. Mar 11, 2012 at 5:40
  • 3
    lualatex '\RequirePackage{ifpdf}\show\ifpdf' produces \ifpdf=\iftrue
    – egreg
    Mar 11, 2012 at 9:26
9

probably I'd advise going with @egreg's answer but an alternative way of combining \if conditionals (which essentially isthe way \ifthenelse \OR works) is shown as follows, using \ifA and \ifB as it works generally not for the engine tests.

\newif\ifA
\newif\ifB

\Atrue\Btrue\typeout{true true}

\if!\ifA!\else\ifB!\else?\fi\fi

\typeout{A or B}

\else

\typeout {neither A nor B}

\fi

\Atrue\Bfalse\typeout{true false}

\if!\ifA!\else\ifB!\else?\fi\fi

\typeout{A or B}

\else

\typeout {neither A nor B}

\fi


\Afalse\Btrue\typeout{false true}

\if!\ifA!\else\ifB!\else?\fi\fi

\typeout{A or B}

\else

\typeout {neither A nor B}

\fi

\Afalse\Bfalse\typeout{false false}

\if!\ifA!\else\ifB!\else?\fi\fi

\typeout{A or B}

\else

\typeout {neither A nor B}

\fi



\stop
2
  • What is the meaning of the characters ! and ? that appear in \if!\ifA!\else\ifB!\else?\fi\fi?
    – Romildo
    Mar 11, 2012 at 11:33
  • any two characters will do so long as they are not the same. If for example ifA is true and ifB is false \ifA!\else\ifB!\else?\fi\fi expands to ! so the outer \if is \if!! which is true. By adjusting which characters are returned you can make other logical connectives such as and or exclusive or Mar 11, 2012 at 11:36
7

For the fun of it, possibly the shortest way:

\documentclass{article}
\usepackage{ifxetex,ifluatex}
\begin{document}

hello

\ifx\ifxetex\ifluatex\else
   xetex or luatex is true
\fi

\end{document}

Indeed, xetex and luatex are mutually exclusive. If the two conditionals coïncide, this must be because both are false. So the opposite is that one of the two is true, which was what was asked for.


As pointed out by egreg in a comment, this construction can not be used as is inside other conditionals (in case it ends up in the skipped branch). This alternative formulation does not have this defect:

\expandafter\ifx\csname ifxetex\expandafter\endcsname \csname ifluatex\endcsname\else 
xetex or luatex is true\fi
7
  • Hehe, I particularly like this one, very clever! (Unless someone comes up with a luaxetex engine, of course...)
    – Daniel
    Oct 22, 2013 at 21:49
  • @Daniel I would be more scared by an egreglisle mix...
    – user4686
    Oct 22, 2013 at 21:51
  • 1
    This is nice, of course, but it can't be used in conditional text, if it belongs to the skipped over branch. Probably it should be used in the preamble to set a new conditional.
    – egreg
    Feb 13, 2014 at 18:42
  • 1
    @egreg \ifx\ifxetex\ifluatex\else xetex or luatex is true \fi\@gobbletwo \fi \fi should do it but this is less simple.
    – user4686
    Feb 14, 2014 at 17:30
  • @egreg or perhaps \expandafter\ifx\csname ifxetex\expandafter\endcsname \csname ifluatex\endcsname\else xetex or luatex is true\fi.
    – user4686
    Feb 14, 2014 at 17:34

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.