我创建了一个包:一个包含其他文件的公共文件。在公共包文件 ( 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}
不再属于其第一次加载的范围。