我自己的包裹的“未知选项”

我自己的包裹的“未知选项”

我创建了一个包:一个包含其他文件的公共文件。在公共包文件 ( russian_post.sty) 中,我定义了选项:

\DeclareOption{times}{\@seriffalse}
\DeclareOption{landscape}{\@lscapetrue}
\DeclareOption{portrait}{\@lscapefalse}
\DeclareOption{smalltab}{\PassOptionsToPackage{smalltab}{form_110}}
\DeclareOption{tinytab}{\PassOptionsToPackage{tinytab}{form_110}}
\DeclareOption*{\PackageWarning{russian_post}{Unknown option `\CurrentOption'}}
\ProcessOptions\relax

之后我添加了包,有趣的是

\RequirePackage{form_110}

在文件中form_110.sty我再次定义它们:

\DeclareOption{smalltab}{\@smallt@btrue}
\DeclareOption{tinytab}{\@tinyt@btrue}
\ProcessOptions\relax

file.tex尝试使用带有以下选项的包:

\usepackage[times,tinytab]{russian_post}

这会导致乳胶错误:

! LaTeX Error: Unknown option `times' for package `russian_post'.
! LaTeX Error: Unknown option `tinytab' for package `russian_post'.

尽管如此,我已经为未知选项定义了默认操作(仅显示警告)。

奇怪的事情随后出现了:忽略这些错误后,我得到了正确的 pdf 文件。

如果我移动所有\RequirePackage 选项声明块,latex 工作正常,没有错误,但选项没有传递给包。我知道,我可以使用russian_post.sty其他包中的全局变量,但如果我想单独使用该包怎么办?

怎么会这样?我怎样才能避免这样的错误?

更新:*

感谢@Werner。我添加了最小示例:

\documentclass{article}
\usepackage{filecontents}
\begin{filecontents*}{russian_post.sty}
\DeclareOption{smalltab}{\PassOptionsToPackage{smalltab}{form_110}}
\DeclareOption{tinytab}{\PassOptionsToPackage{tinytab}{form_110}}
\DeclareOption*{\PackageWarning{russian_post}{Unknown option `\CurrentOption'}}
\ProcessOptions\relax

\RequirePackage{form_110}
\end{filecontents*}

\begin{filecontents*}{form_110.sty}
\newif\if@smallt@b\newif\if@tinyt@b
\@smallt@bfalse\@tinyt@bfalse
\DeclareOption{smalltab}{\@smallt@btrue}
\DeclareOption{tinytab}{\@tinyt@btrue}
\ProcessOptions\relax

\RequirePackage{russian_post}

\def\testsmall{\if@smallt@b TRUE\else FALSE\fi}
\def\testtiny{\if@tinyt@b TRUE\else FALSE\fi}
\end{filecontents*}

\usepackage[smalltab]{russian_post}

\begin{document}
small: \testsmall

tiny: \testtiny
\end{document}

问题似乎出在 的多次包含上russian_post.sty。但是当您使用\RequirePackage或 时,LaTeX 应该可以防止此类情况发生\usepackage。我什么都不明白!!!

更新2:越来越奇怪了!

如果我把此选项移到\documentclass,一切就都正常了!这是什么?

答案1

通用部分

评论这表明更通用的答案可能会有用。

如果 LaTeX 加载包foo,则它会定义宏(包含版本日期和信息)。在下一次加载请求(,)时,它会看到\[email protected]\RequirePackage{foo}\usepackage{foo}\[email protected]定义,并执行不是再次加载包。如果包使用了\newcommand(好的包应该这样做...),那将是相当致命的。

但是它会检查选项。LaTeX 对选项的理解是,选项会添加/启用附加功能。因此,如果同一包的后续\RequirePackage\usepackage调用不包含新选项,则 LaTeX 会很高兴并继续。否则,如果 LaTeX 看到新选项,它就无法再次加载包以启用新选项。并且 LaTeX 会抱怨。示例:

\usepackage[ngerman]{babel}
\usepackage[english]{babel}

LaTeX 因错误而停止:

! LaTeX Error: Option clash for package babel.

按下h提示符将显示:

The package babel has already been loaded with options:
  [ngerman]
There has now been an attempt to load it with options
  [english]
Adding the global options:
  ngerman,english
to your \documentclass declaration may fix this.

或者不使用全局选项:

\usepackage[ngerman,english]{babel}

或者如果第一个包加载隐藏在类或包中:

\PassOptionsToPackage{ngerman,english}{babel}
\documentclass{...}

现在,我们到达了\PassOptionsToPackage。这很有用包第一次加载时,否则 LaTeX 选项代码看不到后续的选项添加。需要注意的是:

  • \PassOptionsToPackage不是检查该包是否会被加载。
  • 也确实如此不是检查软件包是否已加载。(在这种情况下,也许可以给出警告。软件包稍后可以检查新选项,但\@ifpackagewith仅限于前言。)

具体问题

您有以下包加载顺序:

* \usepackage[smalltab]{russian_post}
  * \RequirePackage{form_110}
    * \RequirePackage{russian_post}

问题是russian_post再次请求加载第一次加载完成。包文件尚未加载,但 LaTeX 仍需处理选项。

form_110解决方法:使用延迟包的加载\AtEndOfPackage,然后 的嵌套加载russain_post足够晚,以完成第一次加载的 LaTeX 选项内容:

包装russian_post内含有:

\AtEndOfPackage{RequirePackage{form_110}}

测试文件的加载顺序/嵌套如下:

* \usepackage[smalltab]{russian_post}
* \RequirePackage{form_110}
   * \usepackage{russian_post}

因此第二次\usepackage{russian_post}不再属于其第一次加载的范围。

相关内容