색인 및 참고문헌 명령

색인과 참고문헌을 만드는 makeindex, xindy, bibtex, biber는 LaTeX 매크로가 아니라 독립된 프로그램입니다. 그래서 인자를 쓰는 방식도, 종료 코드도, 로그를 두는 자리도 저마다 알아서 정해져 있습니다. 그리고 여기에 CI를 조용히 망가뜨리는 사실이 하나 있습니다. makeindex는 항목을 버려도 종료 코드 0을 돌려주고, bibtex는 “그 문헌을 찾을 수 없다”고 경고해도 0을 돌려줍니다. 실패는 빌드의 성패가 아니라 .ilg.blg에 적힙니다. 이 페이지는 이 넷을 LaTeX 쪽이 아니라 명령 쪽에서 봅니다. 색인 항목을 쓰는 법과 문헌 데이터베이스 설계는 다른 페이지가 맡습니다.

bibtex docmakeindex doc.idx — 확장자를 쓰는 쪽은 어느 쪽인가

여기서는 도출할 것이 없고 그냥 외워야 합니다. 문헌 쪽은 확장자 없이, 색인 쪽은 확장자와 함께. bibtexbiber는 문서의 job name을 받아 스스로 .aux.bcf를 엽니다. 이걸 틀리면 메시지가 뜻밖에 불친절합니다. bibtex doc.texI couldn t open file name doc.tex.aux를 돌려주고 1로 끝나며, biber doc.texERROR - Cannot find 'doc.tex.bcf'!를 돌려줍니다. 둘 다 준 이름 뒤에 확장자를 붙였을 뿐이고, .tex가 잘못이라고는 알려 주지 않습니다. 반면 makeindex, upmendex, texindy는 입력 파일 자체를 받으므로 doc.idx라고 씁니다. 출력 이름을 바꾸려면 -o, 스타일을 지정하려면 -s를 씁니다.

terminal
bibtex   doc          # job name, no extension  -> reads doc.aux, writes doc.bbl
biber    doc          # job name, no extension  -> reads doc.bcf, writes doc.bbl
makeindex doc.idx     # the file itself         -> writes doc.ind and doc.ilg
upmendex -o doc.ind doc.idx
texindy  -C utf8 -L german-din -o doc.ind doc.idx

종료 코드 정리 — CI가 실패를 놓치는 지점

아래 표는 이 기기의 TeX Live 2024에서 실제로 실행해 확인한 값입니다. 읽어 낼 점은 경고와 실패를 가르는 선이 프로그램마다 다르다는 것입니다. bibtex는 “에러 메시지”를 냈을 때만 2를 돌려주고, 인용 키가 .bib에 없는 것만으로는 경고로 처리해 0을 돌려줍니다. makeindex는 입력 파일이 없으면 1을 돌려주지만, 그 안의 항목을 몇 개 버리든 0에 머뭅니다. 즉 latexmk나 CI 작업의 성패만 보고 있으면 색인에서 항목이 사라지고 참고문헌이 빈칸으로 남은 채 초록색 체크가 붙습니다. 색인과 문헌에 관해서는 종료 코드가 아니라 .ilg.blg를 검사하는 것이 옳은 방어입니다.

상황종료 코드와 로그(TeX Live 2024 실측)
makeindex (entries rejected)0. 버린 항목은 .ilg에만 남습니다. -q를 붙이면 화면에서도 사라집니다
makeindex (no input file)1. Input index file nosuch.idx not found.와 한 줄짜리 사용법이 나옵니다
upmendex (no input file)255. Nothing written in output file.1 errors, written in doc.ilg.를 출력합니다
bibtex (warnings only)0. Warning--I didn t find a database entry for "key"는 실패로 치지 않습니다
bibtex (error messages)2. .bib의 구문 오류나 I found no database files일 때
biber경고만이면 0, ERROR -를 내면 2. 집계는 끝에 INFO - WARNINGS: 1 형태로 나옵니다

makeindex.ilg 읽기 — 버려진 항목은 여기에 있습니다

makeindex은 실행할 때마다 .ind(조판될 색인)와 .ilg(작업 기록)를 함께 씁니다. 정상적인 실행은 무미건조합니다. Scanning input file doc.idx....done (6 entries accepted, 0 rejected)., 이어서 Sorting entries....done (19 comparisons)., 그다음 Generating output file doc.ind....done (20 lines written, 0 warnings). 읽을 값어치가 있는 것은 괄호 안 숫자뿐이라고 해도 지나치지 않습니다. 시험 삼아 망가진 .idx를 먹이면 accepted 수가 줄고 이유가 늘어섭니다. !! Input index error (file = bad.idx, line = 4):에 이어 -- Incomplete first argument (premature LFD). 그래도 종료 코드는 0 그대로입니다. accepted 수가 직접 쓴 \index 개수와 맞는지만 확인해도 사고의 대부분은 막을 수 있습니다. 참고로 TeX Live 2024 동봉판은 makeindex 2.17이며, 시작할 때 자신을 (kpathsea + Thai support)라고 밝힙니다.

terminal
makeindex doc.idx
# This is makeindex, version 2.17 [TeX Live 2024] (kpathsea + Thai support).
# Scanning input file doc.idx....done (6 entries accepted, 0 rejected).
# Sorting entries....done (19 comparisons).
# Generating output file doc.ind....done (20 lines written, 0 warnings).

grep -c "^\\\\indexentry" doc.idx   # compare this with "entries accepted"
grep "rejected"          doc.ilg   # the number CI should be watching

이 수수한 프로그램에는 뜻밖의 내력이 있습니다. 작성자는 Pehong Chen이지만, man 페이지의 감사말에는 “Leslie Lamport contributed significantly to the design of MakeIndex.” 라고 적혀 있습니다. LaTeX을 쓴 당사자가 색인 프로그램 설계에 깊이 관여했다는 뜻입니다. \index의 서식이 LaTeX의 다른 명령과 이어져 있는 것처럼 느껴지는 것은 우연이 아닙니다. \index{key@printed}에서 @를 쓰는 법이나 악센트가 붙은 낱말에 정렬 키를 주는 이야기는 색인 자체를 다루는 페이지에 자세히 있습니다.

어떤 색인 프로그램을 고를까 — 같은 네 낱말을 셋에게 정렬시켜 본다

선택 기준은 하나, 다루는 언어에 정렬 규칙(collation)이 필요한가입니다. Zeta, Ähre, Apfel, Öl 네 낱말을 그대로 .idx에 넣어 세 프로그램에 건네면 차이가 한눈에 드러납니다. makeindex은 Apfel, Zeta, Ähre, Öl 순으로 놓았습니다. Ä와 Ö는 UTF-8 바이트 값이 Z보다 크므로 알파벳 끝 뒤로 밀려납니다. texindy -C utf8 -L german-dinupmendex은 둘 다 Ähre, Apfel, Öl, Zeta로 놓았습니다. 독일어 DIN 규칙대로 Ä를 A로, Ö를 O로 다룬 결과입니다. xindy(Joachim Schrod 제작, release 2.5.1)는 언어 모듈로, upmendex(version 1.08)은 ICU 74.2의 정렬 알고리즘으로 같은 답에 이릅니다.

프로그램같은 네 낱말을 어떻게 정렬했는가고를 상황
makeindexApfel, Zeta, Ähre, Öl — 비 ASCII는 Z 뒤로영어만 다루거나, 정렬 키를 손으로 줄 각오가 있을 때
texindyÄhre, Apfel, Öl, Zeta — -L german-din 지정유럽 언어. -L에 언어 이름을 넘기기만 하면 됩니다
upmendexÄhre, Apfel, Öl, Zeta — ICU로 정렬일본어와 다국어 혼재. makeindex 스타일을 그대로 읽습니다
mendex입력 문자 인코딩을 추측해 (guessed encoding #4: UTF-8 = utf8)를 표시오래된 pLaTeX 자산을 다룰 때. 새로 시작한다면 upmendex

실무상 주의 두 가지. 첫째, texindy가 써 내는 .indmakeindex의 것과 구조가 다릅니다. 머리글자별 소제목을 붙이려고 \lettergroup을 쓰고, 그 정의도 \providecommand로 스스로 써 넣습니다. 문서 쪽에서 이를 재정의하고 있으면 충돌하므로, 갈아탈 때는 출력을 한 번 확인하십시오. 둘째, xindy는 커먼 리스프(이 판에서는 CLISP 2.49.93) 위에서 돌기 때문에 기동이 무겁고, 거대한 색인에서는 체감할 만큼 느립니다. 일본어가 섞인다면 upmendex이 빠르고 무던합니다.

bibtex.blg 끝에 있는 기묘한 목록

bibtex doc를 실행한 뒤 doc.blg를 열면, 경고 다음으로 낯선 표가 이어집니다. if$ -- 47, while$ -- 2, swap$ -- 1, substring$ -- 6…… 이것은 BibTeX 내부 스택 머신의 명령이 각각 몇 번 실행되었는지의 집계입니다. 이번 실행에서는 모두 237회였습니다. 이런 것이 있는 이유는 .bst 스타일 파일이 설정 파일이 아니라 그 가상 기계를 위한 프로그램이기 때문입니다. 같은 .blg의 앞쪽에는 Capacity: max_strings=200000, hash_size=200000, hash_prime=170003이라는 줄도 있습니다. 1980년대의 메모리 사정이 그대로 남은 숫자이며, 거대한 문헌 목록에서 Sorry---you ve exceeded BibTeX s로 시작하는 비명이 터지는 것도 이 상한 때문입니다. 작성자는 스탠퍼드의 Oren Patashnik이고, TeX Live 2024에 들어 있는 것은 BibTeX 0.99d입니다.

BibTeX에는 8비트와 유니코드에 대응하는 파생판이 있고, TeX Live 2024에는 모두 들어 있습니다. bibtex8은 “8-bit Big BibTeX version 0.99d-x4.02”라 자칭하고, bibtexu는 “UTF-8 Big BibTeX”로 ICU 74.2를 품고 있습니다. 일본어에는 pbibtex(pTeX 계열)와 upbibtex(upTeX 계열, upBibTeX 0.99d-j0.36-u1.30 (utf8.uptex)이라고 밝힙니다)를 씁니다. 모두 밑바탕은 같은 0.99d 계통이고, 다른 것은 문자 처리와 정렬 규칙뿐입니다. 실무에서 흔한 오류는 두 가지입니다. .bib의 서식이 망가지면 Illegal end of database file---line 14 of file broken.bibI m skipping whatever remains of this entry가 나오고 종료 코드는 2이며, \bibliography가 가리키는 파일이 없으면 I found no database files---while reading file doc.aux가 나옵니다.

biber — 줄마다 INFO / WARN / ERROR를 밝히는 로그

biber는 Perl로 쓰인 새로운 설계라 로그의 생김새부터 완전히 다릅니다. INFO - This is Biber 2.19로 시작해, 읽어 들인 .bcf, 찾아낸 인용 키의 수, 적용한 로케일, 써 낸 .bbl까지 한 줄씩 INFO - 딱지를 붙여 보고합니다. 문제가 있으면 딱지가 바뀌어 WARN - I didn t find a database entry for 'missingkey' (section 0) 같은 줄이 나오고, 끝에 INFO - WARNINGS: 1이라는 집계가 붙습니다. 이 기계 가독성이 bibtex과의 가장 큰 실무적 차이입니다. CI에서는 grep으로 WARN -ERROR -를 세기만 해도 검사를 만들 수 있습니다. 흔한 사고는 입력 이름 오타로, biber doc.texERROR - Cannot find 'doc.tex.bcf'!를 내고 2로 끝납니다. 또한 biberbibtex는 둘 다 .blg 확장자를 쓰므로, 양쪽을 다 시도했다면 첫 줄을 보고 혼동을 막으십시오.

terminal
biber doc
# INFO - This is Biber 2.19
# INFO - Found 2 citekeys in bib section 0
# INFO - Output to doc.bbl
# WARN - I didn t find a database entry for 'missingkey' (section 0)
# INFO - WARNINGS: 1

# a CI check that the exit code will not give you
grep -c "^WARN -\|^ERROR -" doc.blg
grep "rejected" doc.ilg

실행 순서, 그리고 횟수를 세어 주는 상대

순서는 “조판 → 색인과 문헌 → 조판 → 조판”입니다. 첫 회에 LaTeX이 .idx.aux(biblatex라면 .bcf)를 쓰고, 거기에 이 프로그램들을 돌려 .ind.bbl을 만들고, 다시 조판해 가져오고, 번호가 어긋났으면 한 번 더 — 이런 절차입니다. 횟수가 고정되어 있지 않다는 점이 까다롭고, 바로 그래서 latexmk 같은 빌드 도구가 존재합니다. 손으로 치는 것은 어느 단계에서 멈췄는지 가려낼 때만으로 충분한데, 그 가려내기에도 정해진 순서가 있습니다. 먼저 .idx.bcf가 생성되었는지 봅니다(없으면 LaTeX 쪽 문제). 다음으로 .ilg.blg를 읽습니다(있으면 프로그램 쪽 문제). 마지막으로 한 번 더 조판해 .ind.bbl이 본문에 들어갔는지 봅니다. 이 세 단계면 원인은 거의 한 점으로 좁혀집니다.

terminal
# the classic Japanese sequence, written out
uplatex   paper          # writes paper.aux and paper.idx
upbibtex  paper          # reads paper.aux -> paper.bbl
upmendex  paper.idx      # reads paper.idx -> paper.ind
uplatex   paper          # pulls both in
uplatex   paper          # settles the numbering

# and the same thing delegated
latexmk paper.tex