\makeatletter 和 \makeatother
如果你做了一些 LaTeX 编程,可能遇到过这两个命令:\makeatletter\makeatother

在 TeX 中,@ 字符默认属于 catcode 11 类别。这意味着你可以将它用作宏名称。LaTeX 利用这个 catcode 规则来规定:所有不希望用户访问的内部宏,其名称中至少包含一个 @ 字符。在文档中,LaTeX 会将 @ 的 catcode 改为 12。

因此,当你需要访问 LaTeX 内部宏时,必须将所有访问私有函数的命令放在 \makeatletter\makeatother 之间。它们仅在常规文档中有意义,在包或类文件中不需要。

\documentclass{...}
% ...

\begin{document}

\makeatletter
\@author
\makeatother

\end{document}

创建你自己的包
你的包可以像其他任何包一样在文档中使用,方法是使用 \usepackage 命令。编写包基本上是将文档前言中的内容复制到一个以 .sty 结尾的独立文件中。

下面是一个简单的 custom.sty 文件,作为示例包:

\NeedsTeXFormat{LaTeX2e}[1994/06/01]
\ProvidesPackage{custom}[2013/01/13 Custom Package]

\RequirePackage{lmodern}

%% 'sans serif' 选项
\DeclareOption{sans}{
  \renewcommand{\familydefault}{\sfdefault}
}

%% 'roman' 选项
\DeclareOption{roman}{
  \renewcommand{\familydefault}{\rmdefault}
}

%% 全局缩进选项
\newif\if@neverindent\@neverindentfalse
\DeclareOption{neverindent}{
  \@neverindenttrue
}

\ExecuteOptions{roman}

\ProcessOptions\relax

%% LaTeX 或 TeX 之后的代码
% ...

\newlength{\pardefault}
\setlength{\pardefault}{\parindent}
\newcommand{\neverindent}{ \setlength{\parindent}{0pt} }
\newcommand{\autoindent}{ \setlength{\parindent}{\pardefault} }

\if@neverindent
\neverindent
\fi

% ...

\endinput

解释:

  • \NeedsTeXFormat{...} 指定至少需要的 TeX 或 LaTeX 版本来运行此包。可选的日期用于更精确地指定版本。

  • \ProvidesPackage{<name>}[<version>] 通过该命令包声明自己,<name> 应与文件本身的基名一致,<version> 应使用 YYYY/MM/DD 格式的日期。

  • \RequirePackage 等同于 \usepackage

  • \DeclareOption 是定义的用户参数。

  • \ExecuteOptions{...} 设定默认选项。

  • \ProcessOptions\relax 结束选项处理。

一旦包准备好,我们可以在任何文档中使用它。只需通过 \usepackage{mypack} 导入新包。确保 custom.sty 文件与正在编译的 LaTeX 源文件在同一目录。

\documentclass{...}
\usepackage[neverindent,sans]{custom}
% ...

\begin{document}

Blah...

\end{document}

对于更方便的使用,可以将包放置在 $TEXMFHOME(默认是 ~/texmf)目录下,符合 TeX 目录结构(TDS)。文件路径为:

$TEXMFHOME/tex/latex/custom/custom.sty

在 Windows 上,~ 通常是 C:\Users\username

你可能需要运行 texhash(或等效命令)以使 TeX 分发版索引新文件,从而使其在任何文档中可用。这使得你可以像上面那样使用包,而不必将包放在文档的同一目录中。

创建你自己的类文件
你也可以创建自己的类文件。这个过程与创建包类似,你可以通过在文档前言中调用自定义类文件:

\documentclass{myclass}

类文件的名称将是 myclass.cls。我们来写一个简单的例子,使用之前定义的 custom.sty

\NeedsTeXFormat{LaTeX2e}
\ProvidesClass{myclass}[2011/12/23 My Class]

%% 文章选项
\DeclareOption{10pt}{
  \PassOptionsToClass{\CurrentOption}{article}
}

%% 自定义包选项
\DeclareOption{sans}{
  \PassOptionsToPackage{\CurrentOption}{custom}
}
\DeclareOption{neverindent}{
  \PassOptionsToPackage{\CurrentOption}{custom}
}

%% 回退
\DeclareOption*{
  \ClassWarning{myclass}{Unknown option '\CurrentOption'}
}

%% 执行默认选项
\ExecuteOptions{10pt}

%% 处理给定选项
\ProcessOptions\relax

%% 加载基础类
\LoadClass[a4paper]{article}

%% 加载其他包和命令
\RequirePackage{custom}

%% 额外的 TeX/LaTeX 代码...

\endinput

解释:

  • \ProvidesClass\ProvidesPackage 的对应命令。

  • \PassOptionsToClass\PassOptionsToPackage 用于在加载类或包时自动传递相应的选项。

  • \DeclareOption* 允许处理未实现的选项。

  • \ClassWarning 会在 TeX 编译器输出中显示相应的消息。

  • \LoadClass 指定唯一的父类(如果有)。

钩子
类和包也有钩子:

\AtEndOfPackage
\AtEndOfClass

它们与文档钩子类似。详细息请参见 LaTeX Hooks


Last modified: Wednesday, 23 April 2025, 11:53 AM