Unused global option with multi-staged options in koma-script

class-optionsdocument-classesdocumentclass-writingkoma-script

We use koma-script for a wide range of different documents, e.g. reports and short legal documents. I would like to make our documents more consistent. My idea was to create a package (myBase.sty) with options, common macros, font configuration, etc. that should be shared across all of our different types of documents. This package should then, in turn, be utilized by other specific document (wrapper) classes.

Specifically, the classes myReport.cls and myLegalDoc.cls should inherit the options defined in myBase.sty.

I created the following MWE to demonstrate the issue I am facing:

\begin{filecontents}{myBase.sty}
\ProvidesPackage{myBase}
\DefineFamily{TEST}
\DefineFamilyMember[]{TEST}

\FamilyBoolKey[]{TEST}{inheritedopt}{TEST@inheritedopt}
\end{filecontents}

\begin{filecontents}{myReport.cls}
\NeedsTeXFormat{LaTeX2e}
\ProvidesClass{myReport}[]

\RequirePackage{scrbase}
\RequirePackage{myBase}

\DefineFamily{TEST}
\DefineFamilyMember{TEST}

\FamilyBoolKey[.myReport.cls]{TEST}{classopt}{TEST@classopt}

% Pass unknown options to the parent class
\DeclareOption*{\PassOptionsToClass{\CurrentOption}{scrreprt}}

% Process options defined in myReport.cls
\FamilyProcessOptions[.myReport.cls]{TEST}\relax

% Process options defined in myBase.sty
\FamilyProcessOptions[]{TEST}\relax

\LoadClass{scrreprt}
\end{filecontents}

\documentclass[%
inheritedopt=true,%
classopt=true%
]{myReport}

\usepackage{etoolbox}

\ifbool{TEST@classopt}{%
    \typeout{classopt=true}
}{
    \typeout{classopt=false}
}

\ifbool{TEST@inheritedopt}{%
    \typeout{inheritedopt=true}
}{
    \typeout{inheritedopt=false}
}

% Leads to:
% LaTeX Warning: Unused global option(s):
%     [classopt].


\begin{document}
This is a test.
\end{document}

The output to \typeout indicates, that the options were correctly processed. However, there is a warning which seems to indicate that classopt was not processed correctly:

$ pdflatex mwe.tex
This is pdfTeX, Version 3.141592653-2.6-1.40.22 (TeX Live 2022/dev/Debian) (preloaded format=pdflatex)
 restricted \write18 enabled.
entering extended mode
(./mwe.tex
LaTeX2e <2021-11-15> patch level 1
L3 programming layer <2022-01-21>

LaTeX Info: Writing file `./myBase.sty'.



LaTeX Info: Writing file `./myReport.cls'.


(./myReport.cls
Document Class: myReport
(/usr/share/texlive/texmf-dist/tex/latex/koma-script/scrbase.sty
(/usr/share/texlive/texmf-dist/tex/latex/koma-script/scrlfile.sty
(/usr/share/texlive/texmf-dist/tex/latex/koma-script/scrlfile-hook.sty
(/usr/share/texlive/texmf-dist/tex/latex/koma-script/scrlogo.sty)))
(/usr/share/texlive/texmf-dist/tex/latex/graphics/keyval.sty)) (./myBase.sty))
(/usr/share/texlive/texmf-dist/tex/latex/koma-script/scrreprt.cls
Document Class: scrreprt 2021/11/13 v3.35 KOMA-Script document class (report)
(/usr/share/texlive/texmf-dist/tex/latex/koma-script/scrkbase.sty)
(/usr/share/texlive/texmf-dist/tex/latex/koma-script/tocbasic.sty)
(/usr/share/texlive/texmf-dist/tex/latex/koma-script/scrsize11pt.clo)
(/usr/share/texlive/texmf-dist/tex/latex/koma-script/typearea.sty))
(/usr/share/texlive/texmf-dist/tex/latex/etoolbox/etoolbox.sty)
classopt=true
inheritedopt=true
(/usr/share/texlive/texmf-dist/tex/latex/l3backend/l3backend-pdftex.def)

LaTeX Warning: Unused global option(s):
    [classopt].

(./mwe.aux) [1{/var/lib/texmf/fonts/map/pdftex/updmap/pdftex.map}] (./mwe.aux)
)</usr/share/texlive/texmf-dist/fonts/type1/public/amsfonts/cm/cmr10.pfb>
Output written on mwe.pdf (1 page, 12551 bytes).
Transcript written on mwe.log.

Perhaps the option is passed to koma-script's scrreprt class for further processing? I suspect that this is somehow related to \FamilyKeyState but I'm not sure how to further debug this. Thanks in advance!


Update (2022-05-20):
Unfortunately I forgot to mention that I would like to have the option to process the options defined in myBase.sty in myBase.sty. Example code:

\begin{filecontents}{myBase.sty}
\ProvidesPackage{myBase}
\RequirePackage{scrbase}% <- added
\DefineFamily{TEST}
\DefineFamilyMember{TEST}% <- define family member .myBase.sty
\FamilyBoolKey{TEST}{inheritedopt}{TEST@inheritedopt}% inheriteopt is key of family member .myBase.sty
\FamilyProcessOptions{TEST}\relax% process (family options and) options of family member .myBase.cls

\ifbool{TEST@inheritedopt}{%
    % Do something ...
}{}
\end{filecontents}

\begin{filecontents}{myReport.cls}
\NeedsTeXFormat{LaTeX2e}
\ProvidesClass{myReport}

\RequirePackage{scrbase}

\DefineFamily{TEST}
\DefineFamilyMember{TEST}% <- define family member .myReport.cls
\FamilyBoolKey{TEST}{classopt}{TEST@classopt}% classopt is key of family member .myReport.cls

\DeclareOption*{\PassOptionsToClass{\CurrentOption}{scrreprt}}% pass unknown options to the parent class

\FamilyProcessOptions{TEST}\relax% process (family options and) options of family member .myReport.cls

\LoadClass{scrreprt}
\RequirePackage{myBase}% <- moved
\end{filecontents}

\documentclass[
inheritedopt=true,
classopt=true
]{myReport}

\begin{document}
\makeatletter
\ifTEST@classopt
  classopt=true
\else
  classopt=false
\fi
\quad
\ifTEST@inheritedopt
  inheriteopt=true
\else
  inheriteopt=false
\fi
\makeatother
\end{document}

Best Answer

Remove \FamilyProcessOptions[]{TEST}\relax from your code. These keys of the family (keys with empty family memember) are set by \FamilyProcessOptions[.myReport.cls]{TEST}\relax before the keys of the family member .myReport.cls.

You could use \FamilyProcessOptions{TEST}\relax. Then the keys of the family are set, followed by the keys of the family member .\@currname.\@currext. While myReport.cls is loaded, .\@currname.\@currext represents .myReport.cls.

Here are two suggestions depending on what you want to do:

\begin{filecontents}{myBase.sty}
\ProvidesPackage{myBase}
\RequirePackage{scrbase}% <- added
\DefineFamily{TEST}
%\DefineFamilyMember[]{TEST}% family itself -> can be removed
\FamilyBoolKey[]{TEST}{inheritedopt}{TEST@inheritedopt}% inheriteopt is key of family TEST
\end{filecontents}

\begin{filecontents}{myReport.cls}
\NeedsTeXFormat{LaTeX2e}
\ProvidesClass{myReport}

\RequirePackage{scrbase}
\RequirePackage{myBase}

\DefineFamily{TEST}
\DefineFamilyMember{TEST}% <- define family member .myReport.cls
\FamilyBoolKey{TEST}{classopt}{TEST@classopt}% classopt is key of family member .myReport.cls

\DeclareOption*{\PassOptionsToClass{\CurrentOption}{scrreprt}}% pass unknown options to the parent class

\FamilyProcessOptions{TEST}\relax% process family options and options of family member .myReport.cls

\LoadClass{scrreprt}
\end{filecontents}

\documentclass[
inheritedopt=true,
classopt=true
]{myReport}

\begin{document}
\makeatletter
\ifTEST@classopt
  classopt=true
\else
  classopt=false
\fi
\quad
\ifTEST@inheritedopt
  inheriteopt=true
\else
  inheriteopt=false
\fi
\makeatother
\end{document}

or

\begin{filecontents}{myBase.sty}
\ProvidesPackage{myBase}
\RequirePackage{scrbase}% <- added
\DefineFamily{TEST}
\DefineFamilyMember{TEST}% <- define family member .myBase.sty
\FamilyBoolKey{TEST}{inheritedopt}{TEST@inheritedopt}% inheriteopt is key of family member .myBase.sty
\FamilyProcessOptions{TEST}\relax% process (family options and) options of family member .myBase.cls
\end{filecontents}

\begin{filecontents}{myReport.cls}
\NeedsTeXFormat{LaTeX2e}
\ProvidesClass{myReport}

\RequirePackage{scrbase}

\DefineFamily{TEST}
\DefineFamilyMember{TEST}% <- define family member .myReport.cls
\FamilyBoolKey{TEST}{classopt}{TEST@classopt}% classopt is key of family member .myReport.cls

\DeclareOption*{\PassOptionsToClass{\CurrentOption}{scrreprt}}% pass unknown options to the parent class

\FamilyProcessOptions{TEST}\relax% process (family options and) options of family member .myReport.cls

\LoadClass{scrreprt}
\RequirePackage{myBase}% <- moved
\end{filecontents}

\documentclass[
inheritedopt=true,
classopt=true
]{myReport}

\begin{document}
\makeatletter
\ifTEST@classopt
  classopt=true
\else
  classopt=false
\fi
\quad
\ifTEST@inheritedopt
  inheriteopt=true
\else
  inheriteopt=false
\fi
\makeatother
\end{document}

Other example (regarding the update in the question):

\begin{filecontents}{myBase.sty}
\ProvidesPackage{myBase}
\RequirePackage{scrbase}% <- added
\DefineFamily{TEST}
\DefineFamilyMember{TEST}% <- define family member .myBase.sty
\FamilyBoolKey{TEST}{inheritedopt}{TEST@inheritedopt}% inheriteopt is key of family member .myBase.sty
\FamilyProcessOptions{TEST}\relax% process (family options and) options of family member .myBase.cls
\ifTEST@inheritedopt
    \RequirePackage{showframe}
  \else
    \Ifundefinedorrelax{KOMAoptions}{}{\KOMAoptions{paper=landscape}}
  \fi 
\end{filecontents}

\begin{filecontents}{myReport.cls}
\NeedsTeXFormat{LaTeX2e}
\ProvidesClass{myReport}

\RequirePackage{scrbase}

\DefineFamily{TEST}
\DefineFamilyMember{TEST}% <- define family member .myReport.cls
\FamilyBoolKey{TEST}{classopt}{TEST@classopt}% classopt is key of family member .myReport.cls

\DeclareOption*{\PassOptionsToClass{\CurrentOption}{scrreprt}}% pass unknown options to the parent class

\FamilyProcessOptions{TEST}\relax% process (family options and) options of family member .myReport.cls

\LoadClass{scrreprt}
\RequirePackage{myBase}% <- moved
\end{filecontents}

\documentclass[
inheritedopt=true,
classopt=true
]{myReport}

\begin{document}
\makeatletter
\ifTEST@classopt
  classopt=true
\else
  classopt=false
\fi
\quad
\ifTEST@inheritedopt
  inheriteopt=true
\else
  inheriteopt=false
\fi
\makeatother
\end{document}