! LaTeX Error: Option clash for package inputenc는 보통 “같은 패키지를 서로 다른 옵션으로 두 번 불러왔다”로 설명되지만, 정확한 말은 아닙니다. latex.ltx가 실제로 수행하는 것은 부분집합 검사입니다. 두 번째 \usepackage가 요구한 옵션이 모두 첫 로드의 옵션 안에 들어 있으면 통과하고, 새 이름이 하나라도 나오면 충돌합니다. 그래서 \usepackage[a,b]{X} 뒤의 \usepackage[a]{X}는 무사하고 반대 순서는 실패합니다. 더 성가신 것은 이 검사를 통째로 건너뛰는 패키지가 있다는 점이며, xcolor가 그 대표입니다. 이 페이지는 그 규칙의 정체, \PassOptionsToPackage를 써야 할 정확한 위치, hyperref를 마지막 가까이에 두는 이유, 그리고 TeX Live 2024에서 여전히 정말로 공존하지 못하는 조합을 다룹니다.
충돌을 일으키는 것은 “다른 옵션”이 아니라 “새로운 옵션”입니다
두 번째 \usepackage는 첫 로드에 없던 옵션을 하나라도 요구하는 순간 충돌합니다. 반대로 첫 로드 옵션의 부분집합이라면——순서가 달라도, 개수가 적어도, 아예 없어도——아무 일도 일어나지 않습니다. 이유는 latex.ltx에 있습니다. \@onefilewithoptions@clashchk가 \@if@ptions를 부르고, 그 안의 \@if@pti@ns가 요구된 옵션을 하나씩 꺼내 \in@으로 기록된 목록에서 찾습니다. 하나라도 못 찾으면 두 번째 분기, 즉 \@latex@error{Option clash for …}로 떨어집니다. TeX Live 2024에서 일곱 가지 조합을 실제로 돌린 결과가 아래 표이며, 규칙이 그대로 드러납니다.
| 첫 로드 → 두 번째 로드의 옵션 | 결과(TeX Live 2024 실측) |
|---|---|
[alpha] → [beta] | 충돌. beta는 첫 로드에 없던 새 이름 |
[alpha] → [alpha] | 무사. 같은 옵션을 되풀이하는 것은 아무 일도 일으키지 않음 |
[alpha] → [] | 무사. 공집합은 언제나 부분집합이므로 옵션 없는 재로드는 늘 안전 |
[] → [alpha] | 충돌. 클래스나 다른 패키지가 먼저 불러온 전형적 상황 |
[alpha,beta] → [alpha] | 무사. 더 적게 요구하는 것은 언제나 허용됨 |
[alpha] → [alpha,beta] | 충돌. 더 많이 요구하면 실패. 첫 로드에 모두 적는 것이 정답 |
[beta,alpha] → [alpha,beta] | 무사. 순서는 무관하며 집합으로 비교됨 |
오류 줄 자체는 짧지만, .log에는 그 패키지가 처음 어떤 옵션으로 불려 왔고 지금은 무엇을 요구했는지가 구체적으로 적혀 있습니다. 이 네 줄이 진단의 전부이므로 터미널만 보며 고민하지 말고 로그를 여십시오. 하나 더 알아 두면 좋은 것은 보고되는 행 번호가 어긋난다는 점입니다. \usepackage는 끝에 선택적 날짜 인수를 받을 수 있어서 닫는 중괄호 뒤에 [가 오는지 살펴야 하고, 그 미리 보기가 다음 줄까지 닿습니다. 3행의 \usepackage가 일으킨 충돌이 l.4 \begin{document}로 보고되는 이유가 여기에 있습니다.
% terminal shows only the first line; the rest is in the .log
./oc1.tex:4: LaTeX Error: Option clash for package inputenc.
l.4 \begin
{document}
The package inputenc has already been loaded with options:
[utf8]
There has now been an attempt to load it with options
[latin1]
Adding the global options:
utf8,latin1
to your \documentclass declaration may fix this.xcolor는 왜 충돌하지 않는가: 검사를 우회하는 세 가지 장치
TeX Live 2024에서는 \usepackage[dvipsnames]{xcolor} 다음에 \usepackage[table]{xcolor}라고 써도 오류가 전혀 나지 않습니다. xcolor가 유독 너그러워서가 아니라, 부분집합 검사 자체가 호출되지 않기 때문입니다. 이미 불러온 패키지에 대해 latex.ltx의 \@onefilewithoptions는 먼저 opt@handler@<패키지>.sty라는 매크로가 있는지 봅니다. 없으면 \@onefilewithoptions@clashchk, 곧 앞서 본 부분집합 검사로 가고, 있으면 커널이 통째로 넘겨 그 핸들러가 새로 요구된 옵션을 처리하게 합니다. 그리고 TeX Live 2024의 xcolor.sty는 옵션을 \DeclareKeys로 선언하고 \ProcessKeyOptions로 처리하는 새 방식으로 옮겨 갔으며, 바로 이 \ProcessKeyOptions가 opt@[email protected]를 등록하는 장본인입니다. \show로 들여다보면 내용은 \ProcessKeyOptions [xcolor] 한 줄입니다.
% no error on TeX Live 2024: xcolor uses \DeclareKeys + \ProcessKeyOptions
\usepackage[dvipsnames]{xcolor}
\usepackage[table]{xcolor}
% still an error: inputenc uses the classic \DeclareOption mechanism
\usepackage[utf8]{inputenc}
\usepackage[latin1]{inputenc}
% check for yourself which mechanism a package uses
\makeatletter
\expandafter\show\csname opt@[email protected]\endcsname
% -> \opt@[email protected]=\protected\long macro: ->\ProcessKeyOptions [xcolor].
\makeatother키-값 방식으로 옮겨 가는 것이 가장 예의 바른 우회로지만, 다른 두 가지도 있습니다. fontenc.sty는 자기 파일 끝에서 [email protected]와 [email protected]를 모두 \relax로 되돌립니다. \@ifl@aded가 바로 ver@…를 보고 판정하므로, fontenc는 자신이 불려 왔다는 사실 자체를 지워 다음의 \usepackage[T2A]{fontenc}를 첫 로드로 통과시킵니다. 다른 하나는 caption으로, caption3.sty 안에서 커널의 \@onefilewithoptions를 통째로 갈아 끼웁니다. caption 계열 패키지가 다시 불려 오면 새 옵션을 \captionsetup에 해당하는 처리로 흘려보낸 뒤, 빈 옵션 목록으로 다시 불러옵니다. 그 코드 바로 위의 작성자 주석은 2018년과 2020년 두 차례 LaTeX 팀에 정식 인터페이스를 요청했으나 거절당했다고 적으며, 자신의 이 교체를 “dirty hack”이라 부릅니다. 조용히 충돌하지 않는 패키지 뒤에는 대개 이 셋 중 하나가 있습니다.
| 패키지(새 옵션으로 재로드) | TeX Live 2024에서의 결과와 이유 |
|---|---|
xcolor | 충돌 없음. \DeclareKeys와 \ProcessKeyOptions를 써서 검사를 거치지 않음 |
fontenc | 충돌 없음. 자기 로드 끝에서 [email protected]를 지워 “불러오지 않은” 상태로 되돌림 |
caption | 충돌 없음. caption3.sty가 커널의 \@onefilewithoptions를 교체함 |
inputenc | 충돌함. 여전히 고전적인 \DeclareOption 방식 |
geometry | 충돌함. 설정을 더하려면 다시 부르지 말고 \geometry{…}를 쓸 것 |
hyperref | 충돌함. 설정을 더하려면 다시 부르지 말고 \hypersetup{…}을 쓸 것 |
babel | 충돌함. 언어를 더할 때는 한 번의 \usepackage에 모두 나열할 것 |
amsmath | 충돌함. fleqn이나 leqno 같은 옵션은 관례상 클래스에 주는 편 |
\PassOptionsToPackage를 쓸 자리: 첫 로드보다 앞, 그것뿐입니다
\PassOptionsToPackage{opt}{X}는 X가 처음 불려 오기 전에 놓여야만 의미가 있으며, 확실한 자리는 파일의 첫 줄, \documentclass보다 위입니다. 이 명령이 하는 일은 [email protected]라는 옵션 목록에 opt를 덧붙이는 것뿐입니다. 그런데 이 한 번의 동작이 두 효과를 동시에 냅니다. X가 불려 오는 순간 opt가 전달되고, 뒤에 오는 \usepackage[opt]{X}도 부분집합 검사를 통과합니다. 즉 “옵션을 먹이는 것”과 “충돌을 없애는 것”은 별개의 대처가 아니라 같은 한 줄의 앞뒤입니다. \documentclass보다 앞에 쓸 수 있는 까닭은 \PassOptionsToPackage가 포맷 단계에서 이미 정의돼 있어, \usepackage와 달리 클래스가 읽혔음을 전제하지 않기 때문입니다.
% correct: the very first line, above \documentclass
\PassOptionsToPackage{table}{xcolor}
\documentclass{article}
\usepackage{tikz} % pulls xcolor in -- with table already attached
\usepackage[table]{xcolor} % no clash, and \rowcolor works
% WRONG: after xcolor is already loaded. No error is raised, and the
% option is silently never executed.
\documentclass{article}
\usepackage{tikz}
\PassOptionsToPackage{table}{xcolor}
\usepackage[table]{xcolor}이 명령에는 아주 조용한 실패 방식이 있습니다. X가 이미 불려 온 뒤에 \PassOptionsToPackage를 써도 오류는 전혀 나지 않지만, 옵션은 결코 실행되지 않습니다. 계측용 테스트 패키지로 실측한 결과, 로드 전에 두면 옵션 코드가 실행된 증거가 나오는 반면, 로드 후에 두면 충돌만 사라지고 코드는 실행되지 않은 채였습니다. 오류가 사라졌으니 고쳐졌다고 믿는 것이 이 도구의 가장 위험한 사용법입니다. 오류 본문이 권하는 \documentclass로의 전역 옵션 추가에도 두 번째 함정이 있습니다. 글자 그대로 해서는 듣지 않습니다. \documentclass[beta]{article}을 더해도 \usepackage[alpha]{X}와 \usepackage[beta]{X}를 그대로 두면 충돌이 똑같이 재현됩니다. 두 지역 옵션 목록을 모두 없애고 \documentclass[alpha,beta]{article}에 맨 \usepackage{X} 두 줄로 만들어야 비로소 통과합니다.
불러온 적 없는 패키지를 누가 불렀는지 찾아내기
프리앰블에 \listfiles 한 줄을 넣으면 .log 끝에 실제로 불려 온 파일이 모두 나열되고, “누가 끌어왔는가”는 로그의 괄호 중첩이 답해 줍니다. (로 파일을 열고 )로 닫으므로, xcolor.sty를 여는 (가 pgfcore.sty의 괄호 안쪽에 있다면 끌어온 것은 pgf입니다. 실측하면 맨 article은 3개 파일만 읽지만 tikz 한 줄을 더하면 34개가 되고 그 안에 xcolor가 들어 있습니다. hyperref는 혼자서 30개를 데려옵니다. “xcolor라고 쓴 적도 없는데 Option clash가 난다”의 답은 대개 이 목록 안에 있습니다. 더 세밀히 좇으려면 -recorder를 붙여 .fls에 열린 파일을 전부 기록하면 됩니다.
% the nesting says who pulled xcolor in: pgf did
(.../pgf/basiclayer/pgfcore.sty
(.../pgf/systemlayer/pgfsys.sty
...
)) (.../xcolor/xcolor.sty
...
)
% and with \listfiles, the summary table at the end of the .log
*File List*
article.cls 2023/05/17 v1.4n Standard LaTeX document class
xcolor.sty 2022/06/12 v2.14 LaTeX color extensions (UK)
***********로드 순서: hyperref를 마지막 가까이에 두는 이유와 그 뒤에 오는 것들
hyperref를 마지막 가까이에 두는 이유는 그것이 \ref, \cite, \caption, 목차, 색인 같은 수많은 장치를 덮어쓰기 때문입니다. 덮어쓰기는 최종 정의를 대상으로 이뤄져야 하므로, 뒤에서 누군가 같은 것을 다시 정의하면 hyperref의 손질은 그대로 지워집니다. 다만 규칙은 “마지막”이 아니라 “마지막 가까이”입니다. hyperref가 한 일을 전제로 만들어진 패키지는 당연히 그 뒤에 와야 합니다. 대표적으로 bookmark, cleveref, hypcap, glossaries가 있습니다. 그중 cleveref는 순서 위반을 스스로 감지해 오류를 내므로 틀리면 곧바로 드러납니다. 그 구체적인 순서 요구 사항은 “정의되지 않은 참조” 페이지가 자세히 다룹니다.
한 가지는 분명히 말해 두어야 합니다. “A는 B보다 앞”이라는 식의 전언 상당수는 TeX Live 2024에서 실제로는 아무 일도 일으키지 않습니다. float와 hyperref, geometry와 hyperref, algorithm과 hyperref, bookmark와 hyperref, glossaries와 hyperref를 각각 두 순서로 조합해 보았지만 어느 경우에도 오류도 경고도 나오지 않았습니다. 패키지들이 해마다 호환 코드를 쌓아 온 결과입니다. 따라서 지킬 만한 순서 규칙은 그 패키지 자신의 설명서에 적힌 것들뿐이며, 출처가 분명치 않은 순서 이야기에 맞추어 프리앰블을 재배열하는 것은 대개 시간 낭비입니다. 그래도 hyperref를 끝 가까이 두는 습관은 유지할 만합니다. 그것은 전언이 아니라 덮어쓰기의 성질에서 나오는 합리적 기본값이기 때문입니다.
\usepackage와 \RequirePackage의 차이
프리앰블 안에서 이 둘은 말 그대로 같은 것입니다. latex.ltx는 \documentclass를 처리하는 도중 \let\usepackage\RequirePackage를 실행하므로, 그 뒤로는 완전히 동일한 명령입니다. 차이가 생기는 곳은 \documentclass보다 앞, 그리고 .sty・.cls 파일 안뿐입니다. 그런 자리에서 \usepackage는 ! LaTeX Error: \usepackage before \documentclass.를 내고 멈춥니다. 포맷 단계의 \usepackage는 오직 이 진단을 내기 위해 정의돼 있기 때문입니다. 그래서 패키지나 클래스를 직접 만들 때는 \RequirePackage를 쓰고, \PassOptionsToPackage와 조합하면 \documentclass보다 앞에서 옵션을 끼워 넣을 수 있습니다. 클래스가 자기 옵션을 그대로 하위 패키지에 넘기고 싶을 때를 위해 \RequirePackageWithOptions가 마련돼 있습니다.
% before \documentclass, only \RequirePackage works
\RequirePackage{fix-cm}
\PassOptionsToPackage{table}{xcolor}
\documentclass{article}
% inside your own mystyle.sty, likewise
\ProvidesPackage{mystyle}[2026/01/01 house style]
\RequirePackage{xcolor}
\RequirePackageWithOptions{geometry} % forward this package's own options정말로 공존하지 못하는 조합: TeX Live 2024에서 직접 확인한 것들
옵션 이전의 문제로, 같은 장치를 이중으로 정의하는 바람에 공존하지 못하는 조합이 있습니다. 다만 그 수는 알려진 것보다 적고, 증상도 “불러오는 순간의 오류”라고만은 할 수 없습니다. 대놓고 거부하는 것은 biblatex와 natbib 조합으로, ! Package biblatex Error: Incompatible package 'natbib'.에서 멈춥니다(\citet나 \citep만 필요했다면 \usepackage[natbib=true]{biblatex}로 충분합니다). 성가신 쪽은 조용히 망가지는 경우입니다. subfigure와 subcaption을 함께 불러도 오류가 하나도 나지 않습니다. 문제는 한참 뒤, \begin{subfigure}{0.4\textwidth}라고 쓴 줄에서 ! Missing number, treated as zero.로 드러납니다. subfigure가 정의하는 옛 \subfigure 명령이 \begin{subfigure}를 삼켜 전혀 다르게 해석하기 때문입니다.
| 조합 | TeX Live 2024에서 실제로 일어나는 일 |
|---|---|
biblatex + natbib | 즉시 오류로 정지. \usepackage[natbib=true]{biblatex} 하나로 합칠 것 |
natbib + biblatex | 이 순서에서는 오류가 없고 \citeauthor 등이 재정의된다는 경고만 나옴 |
subfigure + subcaption | 둘 다 아무 말 없이 로드됨. 나중에 \begin{subfigure}가 깨지며 무관해 보이는 오류가 남 |
subfig + subcaption | 둘 다 로드되지만 subcaption이 환경을 정의하지 않아 ! LaTeX Error: Environment subfigure undefined.가 남 |
caption + subfigure | 더 이상 충돌하지 않음. .log에 Package caption Info: subfigure package is loaded.만 남음 |
cleveref + hyperref | cleveref를 먼저 부르면 정지. hyperref와 varioref 뒤에 두어야 함 |
cite + natbib | 오류는 아니지만 natbib이 cite를 함께 쓰지 말라고 경고함. 하나만 남길 것 |
이 표에서 끌어낼 교훈은 “A와 B는 비호환”이라는 전언을 곧이곧대로 믿지 말고, 다섯 줄짜리 문서를 만들어 직접 확인하라는 것입니다. caption과 subfigure의 비호환은 예전에는 실제로 오류였지만 지금은 Info로 강등되었습니다. 반대로 subfigure와 subcaption은 “불러도 오류가 없으니 괜찮다”는 판단이 가장 위험한 예입니다. 증상이 “로드 시점의 오류”에서 “한참 뒤의 무관해 보이는 오류”로 옮겨 갔다는 것이 TeX Live 2024에서 패키지 비호환이 서 있는 자리이며, 그래서 \listfiles를 켜고 .log를 읽는 습관이 값을 합니다.