2

glossaries supports cross-referenced entries. In particular, if I use one glossary entry in another and only include the second explicitly in my document, glossaries can still figure out that it should include the first entry in the glossary.

However, this requires 2 runs of makeglossaries:

  • compile -> makeglossaries -> compile -> makeglossaries -> compile

or else the first entry will be missing from the list.

So far, this is not especially problematic: just remember to run makeglossaries twice, recompiling in between.

Things get complicated, however, if the first, cross-referenced entry itself cross-references a third entry. Now the third entry should be included, but an additional run of makeglossaries is required. Moreover, should the third entry cross-reference a fourth, yet another run is needed. And so on for any fifth, sixth... entries.

For example:

\begin{filecontents}{mygloss.tex}
\newglossaryentry{animal}{%
    name                        =   animal,
    description     =   {A living organism. Cf.~\gls{plant}}}
\newglossaryentry{apple}{%
    name                        =   apple,
    description     =   {A type of \gls{fruit}}}
\newglossaryentry{fruit}{%
    name                        =   fruit,
    description     =   {A method of seed-dispersal favoured by some \glspl{plant}}}
\newglossaryentry{plant}{%
    name                        =   plant,
    description     =   {A living organism. Cf.~\gls{animal}}}
\end{filecontents}

\documentclass{article}
\usepackage{glossaries}
\makeglossaries
\loadglsentries{mygloss}
\begin{document}
  An \gls{apple} a day keeps the doctor away.
  \printglossaries
\end{document}

Unfortunately, glossaries does not provide any warning when an entry is used by not included in the glossary. It does not tell me, for example, that the reference to fruit is undefined after the first compilation cycle. It just silently includes fruit in the definition of apple without including the definition of fruit in the glossary.

Keeping track of this for complex documents which use complex databases of entries becomes rather problematic.

How can I most easily and reliably determine when an additional compilation cycle is required?

One possibility I'm wondering about is to create a shell script which compares the result of the following commands:

grep glossentry <filename>.glo | wc -l
grep glossentry <filename>.gls | wc -l

and conclude that no further runs are required if, and only if, the results of the two greps are equal.

However, I am not certain if this is generally reliable, especially when multiple .glo and .gls files are involved. Nor am I clear whether there is no more readily-available method for determining that another run is needed.

  • \glsaddallunused is no option? This reduces the number of pdflatex | makeglossaries cycles to 2 runs, in my point of view – user31729 Oct 3 '15 at 14:03
  • @ChristianHupfer No. I don't want to add all entries in the glossaries databases but only those which are actually used somewhere. I'm prepared to deal with the additional runs, although it would be nice if that weren't required, but I lose track of when these are needed and end up not realising I've produced an incomplete glossary. (I've been wondering if Biblatex/Biber might work better but that's another matter and would require a lot of time. And it would probably be impossible to distinguish citations from glossary term....) – cfr Oct 3 '15 at 21:25
2

This is not really an answer, but it does not really belong as part of the question and is rather too long for a comment.

I've written a shell script which attempts to generate a glossary even when there are multiply nested cross-references within the entries. This is highly experimental. It has only been tested on a minimal example. It WILL break. Please leave a comment if you can suggest ways to improve this which do not amount to rewriting the script in another language.

Caveat emptor...

As currently written, the script makes the following assumptions:

  • TeX Live binaries are available in /usr/local/texlive/bin/. This is unlikely to be true on systems other than mine.

  • sed, grep, uniq, sort, wc, printf, echo, getopt, find, xargs etc. are available. Should be true on all reasonably sane Unix-like systems.

  • bash is available as /bin/bash. Should be true on all reasonably sane Unix-like systems.

  • Filenames are sane and do not contain any strange, weird or problematic characters. Should be true on all systems with reasonably sane users.

To use the script, if you really wish to, you need to save it as a file, <super-makeglossaries>, say and then make it executable:

chmod +x super-makeglossaries

Either save the script in ~/bin/ or provide the full path to the script when using it.

The syntax is pretty minimal. There are only 2 options:

  • -h or --help for the minimal help;

  • -o or --options if you want to pass options to pdflatex. Normally, you would wish to quote these.

For example:

super-makeglossaries -o "--synctex=1" <filename>

should, theoretically run pdflatex --synctex=1 and makeglossaries on <filename> or <filename>.tex as necessary until all glossary entries are stabilised. 'Theoretically' means 'according to my current hope' and not 'according to this theory I have worked out'.

Don't use the version I posted earlier. It didn't work even for me. It stands an icicle in the Sahara's chance of working for anybody else. Here's the current code which may, possibly, work for me, at least:

#!/bin/bash -
#set -x
PATH=/usr/local/texlive/bin:/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin
export PATH

allan=0
options=""
pdflatex=/usr/local/texlive/bin/pdflatex
makeglossaries=/usr/local/texlive/bin/makeglossaries

usage="Usage: $0 [OPTION] FILE
makeglossaries wrapper which will run pdflatex and makeglossaries until cross-referenced entries are stable.
Options:
        -h --help       print this message and exit
        -o --options    options to be passed to pdflatex
FILE should be a TeX file, specified with or without the .tex extension." 
error () {
        echo "$@" 1>&2
        ((allan++))
        usage_and_exit $allan
}
usage () {
        printf %b "$usage\n"
}
usage_and_exit () {
        usage
        exit $1
}
tex_error () {
        echo "$@" 1>&2
        ((allan++))
        exit $allan
}
find_gen () {
        find  $(dirname "$1") -maxdepth 1 -type f -readable -name "$(basename $1).*.$2"
        find  $(dirname "$1") -maxdepth 1 -type f -readable -name "$(basename $1).$2"
}
gen_exists () {
        n=1
        k=$(find_gen "$1" "$2" | wc -l)
        [[ $k -ne 0 ]] && n=0
        return $n
}

[[ -x $pdflatex ]] || error Ni allaf ffeindio "$pdflatex".
[[ -x $makeglossaries ]] || error Ni allaf ffeindio "$makeglossaries".


tempargs=$(getopt -o ho: --long help,options: -- "$@")
if [ $? != 0 ];
then
        usage_and_exit
fi
eval set -- "$tempargs"

while true
do
        case "$1"
        in
                -h | --help)
                        usage;
                        exit $allan;;
                -o | --opt | --opti | --optn | --option | --options)
                        options="$2"
                        shift;
                        shift;;
                --)
                        shift;
                        break;;
                *)
                        error Unrecognised option "$1".
        esac
done

args="$@"

[[ "$#" != 1 ]] && error Mae angen o leiaf un enw ffeil ac nid mwy nag un! 
enw=${1%.tex}
gen_exists "$enw" glo
if [ $? != 0 ]
then
        printf %b "Running pdfLaTeX, $makeglossaries and pdfLaTeX to create glossary.\n"
        $pdflatex $options $enw || tex_error pdfLaTeX exited with errors.
        $makeglossaries $enw || tex_error $makeglossaries exited with errors.
        $pdflatex $options $enw || tex_error pdfLaTeX exited with errors.
else
        gen_exists "$enw" gls
        if [ $? != 0 ]
        then
                printf %b "Running $makeglossaries and pdfLaTeX to create glossary.\n"
                $makeglossaries $enw || tex_error $makeglossaries exited with errors.
                $pdflatex $options $enw || tex_error pdfLaTeX exited with errors.
        fi
fi
$(gen_exists "$enw" glo) || error Ni allaf ffeindio .glo!
$(gen_exists "$enw" gls) || error Ni allaf ffeindio .gls!
gloentries=$(find_gen "$enw" glo | xargs grep glossentry | sed 's/|setentrycounter.*$//' | sort | uniq | wc -l)
glsentries=$(find_gen "$enw" gls | xargs grep glossentry | wc -l)
while [ ! "$gloentries" == "$glsentries" ]
do
        printf %b "Rerunning $makeglossaries and pdfLaTeX to resolve cross-references.\n"
        $makeglossaries $enw || tex_error $makeglossaries exited with errors.
        $pdflatex $options $enw || tex_error pdfLaTeX exited with errors.
        gloentries=$(find_gen "$enw" glo | xargs grep glossentry | sed 's/|setentrycounter.*$//' | sort | uniq | wc -l)
        glsentries=$(find_gen "$enw" gls | xargs grep glossentry | wc -l)
done

exit $allan
# vim: set nospell: 
1

It's not really possible for glossaries to provide a warning for all those nested levels of dependency, but adding hyperref does give a warning if an entry has been used but doesn't appear in the glossary.

Example:

\documentclass{article}

\usepackage[hidelinks]{hyperref}
\usepackage{glossaries}

\makeglossaries

\newglossaryentry{animal}{%
    name                        =   animal,
    description     =   {A living organism. Cf.~\gls{plant}}}
\newglossaryentry{apple}{%
    name                        =   apple,
    description     =   {A type of \gls{fruit}}}
\newglossaryentry{fruit}{%
    name                        =   fruit,
    description     =   {A method of seed-dispersal favoured by some
\glspl{plant}}}
\newglossaryentry{plant}{%
    name                        =   plant,
    description     =   {A living organism. Cf.~\gls{animal}}}

\begin{document}
  An \gls{apple} a day keeps the doctor away.
  \printglossaries
\end{document}

With the first pdflatex run, pdfTeX produces the following warning:

pdfTeX warning (dest): name{glo:apple} has been referenced but does not exist,
replaced by a fixed one

This is because hyperref has inserted an internal hyperlink but the target doesn't exist. At this point, only apple has been used. The other entries, including fruit, haven't been used. The fruit entry doesn't get used until the glossary has been created. Then pdfTeX warns

pdfTeX warning (dest): name{glo:fruit} has been referenced but does 
not exist, replaced by a fixed one

This doesn't help with the nested dependencies. The problem here is that glossaries doesn't know that the apple entry requires the fruit entry until it processes the apple entry description, which it doesn't do until the apple entry is in the glossary.

The glossaries-extra package, which extends the glossaries package, provides a solution to this type of problem, but only when the dependency is indicated by the see key. For example:

% arara: pdflatex
% arara: makeglossaries
% arara: pdflatex
\documentclass{article}

\usepackage{glossaries-extra}

\makeglossaries

\newglossaryentry{animal}{%
    name                        =   animal,
    description     =   {A living organism},
    see=[cf.]{plant}}
\newglossaryentry{apple}{%
    name                        =   apple,
    description     =   {A type of \gls{fruit}},
    see={fruit}}
\newglossaryentry{fruit}{%
    name                        =   fruit,
    description     =   {A method of seed-dispersal favoured by some
\glspl{plant}},
    see={plant}}
\newglossaryentry{plant}{%
    name                        =   plant,
    description     =   {A living organism},
    see=[cf.]{animal}}

\begin{document}
  An \gls{apple} a day keeps the doctor away.
  \printglossaries
\end{document}

This just requires pdflatex, makeglossaries and pdflatex to produce:

image of document

This puts the cross-reference in the location list, which may not be what you want, but it does make the .gls file easier to post-process with a script if required. The .gls file for this example contains:

\glossarysection[\glossarytoctitle]{\glossarytitle}\glossarypreamble
\begin{theglossary}\glossaryheader
\glsgroupheading{A}\relax \glsresetentrylist %
\glossentry{animal}{\glossaryentrynumbers{\relax 
        \setentrycounter[]{page}\glsxtrunusedformat{1}\delimN 
        \glsseeformat[cf.]{plant}{Z}}}%
\glossentry{apple}{\glossaryentrynumbers{\relax 
        \setentrycounter[]{page}\glsnumberformat{1}\delimN 
        \glsseeformat[\seename ]{fruit}{Z}}}\glsgroupskip
\glsgroupheading{F}\relax \glsresetentrylist %
\glossentry{fruit}{\glossaryentrynumbers{\relax 
        \setentrycounter[]{page}\glsxtrunusedformat{1}\delimN 
        \glsseeformat[\seename ]{plant}{Z}}}\glsgroupskip
\glsgroupheading{P}\relax \glsresetentrylist %
\glossentry{plant}{\glossaryentrynumbers{\relax 
        \setentrycounter[]{page}\glsxtrunusedformat{1}\delimN 
        \glsseeformat[cf.]{animal}{Z}}}%
\end{theglossary}\glossarypostamble

So each cross-reference in the location list is in the form \\delimN\\s*\\n\\s+\\glsseeformat\[.+?\]\{.+?\}{Z}

  • Thanks. This doesn't really help me, but I appreciate the ideas and I'm sure it will help somebody else. I've been starting to think that maybe glossaries isn't the right package for my purposes as it seems designed for a very different kind of project, but perhaps that is just my lack of eptitude. – cfr Jan 26 '16 at 18:55

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.