기성 클래스만으로 부족해지면 직접 클래스를 작성할 수 있습니다. 이 페이지는 클래스를 만드는 쪽의 이야기입니다. 먼저 클래스가 보통 받는 표준 옵션(글자 크기, 용지, 단 수 등)을 살펴본 뒤, .cls / .sty 파일의 뼈대, 즉 \ProvidesClass로 자신을 밝히고, \DeclareOption으로 옵션을 선언하고, \ProcessOptions로 실행하고, \LoadClass로 기존 클래스를 기반으로 삼는 흐름을 article을 확장하는 완성 예까지 차례로 구성합니다. 문서 쪽에서 옵션을 사용하는 이야기는 “Document class & preamble”을 참고하세요.
클래스인가, 패키지인가?
무엇을 쓰기 전에 클래스(.cls) 를 만들 것인지 패키지(.sty) 를 만들 것인지 결정합니다. 클래스는 문서 종류 자체를 정의하며 \documentclass로 하나만 불러옵니다. 논문, 책, 슬라이드 같은 전체 뼈대와 기본 체재를 제공하는 것이 클래스입니다. 반면 패키지는 \usepackage로 몇 개든 겹쳐 불러올 수 있고, 문서 종류와 무관한 기능을 더합니다(수학의 amsmath, 그림의 graphicx 등).
공식 clsguide의 표현을 빌리면 판단 기준은 간단합니다. 그 기능이 어떤 문서 클래스에서도 쓸 수 있다면 패키지로 만들고, 그렇지 않다면 클래스로 만든다. 전체 모양을 정의하고 싶으면 클래스, 기능만 더하고 싶으면 패키지라고 기억하면 헷갈리지 않습니다. 작성 방식은 거의 같고, 명령 이름이 Class용과 Package용으로 나뉘어 있을 뿐입니다(\ProvidesClass ↔ \ProvidesPackage, \LoadClass ↔ \RequirePackage, \PassOptionsToClass ↔ \PassOptionsToPackage).
자작 클래스가 받는 표준 옵션
사용자는 표준 클래스에 하듯이 자작 클래스에도 옵션을 넘길 것입니다. 최소한 본문 기준 크기를 고르는 10pt / 11pt / 12pt, 용지의 a4paper / letterpaper, 단 구성의 onecolumn / twocolumn, 면 구성의 oneside / twoside, 그리고 넘친 줄을 검은 표시로 보여 주는 draft(반대는 final) 정도는 갖추고 싶습니다. 이것들을 일일이 직접 구현할 필요는 없습니다. 아래 “기반 클래스에 넘기기”에서 보듯이, article 같은 기반 클래스에 그대로 전달하는 것이 정석입니다.
| 옵션 | 의미 | 기본값 |
|---|---|---|
10pt / 11pt / 12pt | 본문 기준 글자 크기 | 10pt |
a4paper / letterpaper | 용지 크기(b5paper, legalpaper 등도 있음) | letterpaper |
onecolumn / twocolumn | 1단 / 2단 | onecolumn |
oneside / twoside | 단면 / 양면 레이아웃 | oneside(book만 twoside) |
draft / final | 넘친 줄을 검은 표시로 보여 줄지 여부 | final |
문서의 \documentclass[...] 쪽에서 이런 옵션을 지정해 사용하는 구체적인 예와 book 특유의 openright 같은 것은 자매 페이지 “Document class & preamble”에서 다룹니다. 여기서부터는 그 옵션을 받는 쪽의 클래스를 어떻게 쓸 것인가에 집중합니다.
파일 맨 앞에서 자신을 밝히기
클래스 파일(myclass.cls)의 처음 두 줄은 거의 정형화되어 있습니다. 먼저 \NeedsTeXFormat{LaTeX2e} 로 이 파일이 LaTeX2e용임을 선언합니다(더 오래된 포맷에서 읽으려 하면 경고가 납니다). 이어서 \ProvidesClass{myclass}[2026/01/01 v1.0 ...] 로 클래스 이름, 릴리스 날짜, 버전, 설명을 밝힙니다. 대괄호 안은 생략할 수 있지만, 써 두면 사용자가 날짜(YYYY/MM/DD 형식) 를 기준으로 \documentclass{...}[2026/01/01]처럼 최소 버전을 요구할 수 있고 로그에도 기록됩니다.
패키지를 쓴다면 대응 명령은 \ProvidesPackage{mypackage}[2026/01/01 v1.0 ...] 입니다. \NeedsTeXFormat은 둘 다 공통입니다. 또한 \ProvidesClass / \ProvidesPackage의 이름은 실제 파일명과 일치시켜야 하는 것이 철칙입니다. myclass.cls 안에서는 반드시 \ProvidesClass{myclass}라고 씁니다.
\NeedsTeXFormat{LaTeX2e}
\ProvidesClass{myclass}[2026/01/01 v1.0 My example class]옵션 선언하기 — \DeclareOption
클래스가 받을 수 있는 옵션은 \DeclareOption{option}{code} 로 하나씩 선언합니다. 사용자가 그 옵션을 지정하면 뒤에서 설명할 \ProcessOptions 시점에 해당 code 가 실행됩니다. 예를 들어 자체 draft 스위치를 준비해 참거짓 플래그를 세울 수 있습니다.
선언하지 않은 옵션을 받는 곳은 별표 붙은 \DeclareOption*{code}(catch-all)입니다. 그 안에서 \CurrentOption 은 “지금 처리하려는 옵션 이름”으로 펼쳐집니다. 자작 클래스에서 가장 자주 쓰는 것은 알 수 없는 옵션을 기반 클래스에 그대로 전달하는 다음 한 줄입니다. 이 덕분에 10pt나 a4paper 같은 표준 옵션을 직접 선언하지 않아도 사용자가 자연스럽게 넘길 수 있습니다.
% pass anything we do not handle ourselves on to article
\DeclareOption*{\PassOptionsToClass{\CurrentOption}{article}}패키지를 작성할 때는 같은 역할의 \PassOptionsToPackage{\CurrentOption}{base} 를 사용합니다. \ProcessOptions 전에 기본값을 흘려 넣고 싶다면 \ExecuteOptions{a4paper,11pt} 처럼 쓰면 됩니다. 사용자가 아무것도 지정하지 않아도 그 옵션들의 코드가 먼저 실행됩니다.
옵션을 처리한 뒤 기반 클래스에 넘기기
선언만으로는 아무 일도 일어나지 않습니다. \ProcessOptions 를 호출해야 각 옵션의 코드가 실행됩니다. 실무에서는 거의 항상 \ProcessOptions\relax 라고 씁니다. 별표 붙은 \ProcessOptions*라는 다른 형태가 있기 때문에, 끝의 \relax로 “별표 없는 쪽”을 확실히 선택하는 관용구입니다. 별표 없는 \ProcessOptions는 옵션을 선언한 순서로 처리하고, 별표 붙은 형태는 호출자가 지정한 순서로 처리합니다.
레이아웃을 처음부터 짜는 것은 힘들기 때문에, 대부분의 자작 클래스는 기존 클래스를 기반으로 삼습니다. 그 명령이 \LoadClass[options]{article} 이며, article.cls의 명령과 체재를 통째로 읽어 옵니다(대괄호로 twocolumn 같은 옵션을 넘길 수도 있습니다). \LoadClass는 클래스 파일 안에서만 쓸 수 있는 명령입니다. 중요한 것은 순서입니다. 사용자가 \documentclass[...]로 넘긴 옵션이 기반 클래스에 적용되게 하려면 \LoadClass를 옵션 처리(\ProcessOptions) 뒤에 둡니다. 먼저 전달 설정을 하고, \ProcessOptions로 나눈 다음, 그 위에서 기반 클래스를 불러오는 흐름입니다.
기반 클래스에 자신이 받은 것과 같은 옵션을 그대로 넘기고 싶을 뿐이라면 \LoadClassWithOptions{article} 가 편리합니다(클래스의 전역 옵션을 그대로 이어받습니다). 패키지를 작성할 때는 \LoadClass 대신 \RequirePackage(프리앰블의 \usepackage에 해당하는 저자용 명령)를 쓰고, 그대로 모두 넘기려면 \RequirePackageWithOptions 를 씁니다.
\LoadClass 뒤가 드디어 이 클래스다운 부분을 쓰는 곳입니다. \renewcommand로 제목 체재를 바꾸거나, \setlength로 여백을 조정하거나, \newcommand / \newenvironment로 새 명령과 환경을 정의합니다. 필요한 추가 패키지도 여기서부터 \RequirePackage로 불러옵니다.
완성 예: article을 확장하는 최소 클래스
이상 내용을 하나로 모으면 다음과 같은 최소 .cls가 됩니다. article을 기반으로 자체 draft 옵션을 더하고, 알 수 없는 옵션은 article로 전달하며, 마지막에 여백을 정리하고 자체 명령 하나를 정의합니다. 이것을 myclass.cls로 저장하고 문서 쪽에서 \documentclass[11pt,a4paper]{myclass}라고 쓰면 사용할 수 있습니다.
\NeedsTeXFormat{LaTeX2e}
\ProvidesClass{myclass}[2026/01/01 v1.0 My example class]
% --- declare options ---
\newif\ifmy@draft
\DeclareOption{draft}{\my@drafttrue}
% forward everything else to article
\DeclareOption*{\PassOptionsToClass{\CurrentOption}{article}}
% --- execute and load the base class ---
\ExecuteOptions{a4paper} % a default if the user gives none
\ProcessOptions\relax
\LoadClass{article}
% --- this class's own setup ---
\RequirePackage[margin=25mm]{geometry}
\setlength{\parindent}{0pt}
\newcommand{\version}{v1.0}
\ifmy@draft \RequirePackage{draftwatermark}\fi
\endinput끝의 \endinput 은 여기서부터 뒤는 읽지 말라고 LaTeX에 알려 주는 구분자이며, 관례적으로 붙입니다. 패키지를 작성할 때는 앞부분을 \ProvidesPackage로, \LoadClass를 \RequirePackage로 바꾸면 같은 뼈대가 그대로 .sty가 됩니다.
새로운 방식: key-value 옵션(expl3)
여기까지의 \DeclareOption 방식은 지금도 완전히 유효하지만, 주로 “있다/없다” 형태의 스위치 옵션을 중심으로 만들어져 있습니다. name=value 같은 key-value 형식 옵션을 자연스럽게 쓰고 싶은 새 코드에서는 LaTeX 커널이 제공하는 \DeclareKeys 로 key를 선언하고 \ProcessKeyOptions 로 처리하는 방식이 현재 권장됩니다. 이는 expl3(LaTeX3)의 l3keys를 기반으로 한 구조이며, 최근 LaTeX 커널에 표준으로 포함되어 있습니다.
예전에는 같은 일을 l3keys2e 패키지로 했지만, 그 핵심 기능은 이제 커널에 들어갔으므로 새 코드에서는 패키지를 불러오지 않고 \ProcessKeyOptions를 직접 사용할 수 있습니다. 그렇다고 해도 기존 해설과 많은 패키지는 아직 \DeclareOption 방식이 중심이므로, 이 페이지의 뼈대를 이해하는 것은 여전히 중요합니다. key-value 방식으로 나아갈 때는 최신 clsguide(“LaTeX2e for class and package writers”)의 해당 절을 참고하세요.
배포 전 최소 테스트
클래스는 읽히는 순간 문서 전체에 영향을 주므로, 실제 본문을 쓰기 전에 작은 테스트 문서로 동작을 굳힙니다. 먼저 10pt, 11pt, a4paper, draft 같은 표준 옵션이 기반 클래스까지 전달되는지, 그리고 자신의 독자 옵션만 자작 코드에서 처리되는지 확인합니다. 여기서 오류가 난다면 대개 \ProcessOptions / \ProcessKeyOptions의 위치, 알 수 없는 옵션 전달, 또는 \LoadClass의 순서가 원인입니다.
\documentclass[11pt,a4paper,draft]{myclass}
\begin{document}
\section{Smoke test}
本文の基準サイズ、用紙、下書き表示、見出し、余白を確認する。
\end{document}- 로그에 클래스 정보가 나오나요?
\ProvidesClass의 날짜와 버전이.log에 나오는지 확인합니다. 파일명과 클래스명이 다르면 나중에 혼란이 생깁니다. - 표준 옵션을 깨뜨리지 않았나요?
11pt나twocolumn이 무시된다면 알 수 없는 옵션을 기반 클래스로 넘기는 처리를 다시 봅니다. - 문서 매크로가 프리앰블과 본문에서 잘 동작하나요? 실제 사용자가 처음 건드릴 요소이므로 제목, 주석, 그림, 표를 하나씩 두고 컴파일합니다.
\endinput이후는 비활성 상태로 둡니다. 끝에 메모나 샘플을 남겨 두면, 표시가 빠지거나 이동했을 때 예상치 못한 문자열이 읽힐 수 있습니다.
배포 형태까지 생각하기
자작 클래스의 진가는 처음 내 환경에서 동작한 순간이 아니라, 다른 사람이 다른 환경에서 읽는 순간에 검증됩니다. 최소한 .cls, 짧은 샘플 문서, README, 변경 이력을 같은 디렉터리에 두고, 샘플이 그대로 컴파일되는지 확인합니다. README에는 기반 클래스로 전달되는 옵션과 자작 클래스만 받는 옵션을 나누어 적으면, 사용자가 11pt나 a4paper가 어디서 적용되는지 따라가기 쉽습니다. 샘플에는 제목, 목록, 그림/표, 참고문헌을 하나씩 넣어 클래스가 처음 깨뜨리기 쉬운 요소를 함께 확인합니다.
myclass/
myclass.cls
sample.tex
README.md
CHANGELOG.md배포 전 테스트에서는 샘플에 \listfiles를 넣어 로그에 읽힌 파일과 버전이 나오게 합니다. 그러면 사용자가 오래된 myclass.cls를 로컬에 두고 있지 않은지, 필요한 패키지가 예상대로 읽혔는지 확인할 수 있습니다. 클래스는 문서 전체의 기반이므로, 오래 쓰는 문서에서는 본문 매크로를 하나 더 넣는 것보다 읽기 순서, 옵션 처리, 로그 정보를 꼼꼼히 하는 쪽이 더 효과적입니다.