SOURCE_DATE_EPOCH

SOURCE_DATE_EPOCH

如果我考虑一个简单的 LaTeX 文档,例如:

\documentclass[11pt]{article}
\begin{document}
Hello, World!
\end{document}

如果我多次排版我每次都会得到不同的校验和

$ pdflatex test
This is pdfTeX, Version 3.1415926-1.40.10 (TeX Live 2009)
 restricted \write18 enabled.
entering extended mode
...
Output written on test.pdf (1 page, 12592 bytes).
Transcript written on test.log.
$ cksum test.pdf
2770399004 12592 test.pdf
$ pdflatex test
This is pdfTeX, Version 3.1415926-1.40.10 (TeX Live 2009)
 restricted \write18 enabled.
entering extended mode
...
Output written on test.pdf (1 page, 12592 bytes).
Transcript written on test.log.
$ cksum test.pdf
1225641903 12592 test.pdf

校验和不同是由于 PDF 文件中三行发生变化:

/CreationDate (D:20101115092454-05'00')
/ModDate (D:20101115092454-05'00')
...
/ID [<E52BBC1CEFDC95455342C233D35D790A> <E52BBC1CEFDC95455342C233D35D790A>] >>

更复杂的 LaTeX 输入也会出现这种情况。有没有办法排版 LaTeX 文件以避免此问题,以便如果排版多次,PDF 文件的校验和保持不变?

答案1

我认为值得在这里重复一下答案。(因为这是来自超级用户,我不应该为此获得任何声誉......所以我将其标记为 CW):

您可以使用 pdftex 的宏来更改 pdf 的信息字典的内容\pdfinfo

\def\fixedpdfdate{D:20100413000000+00’00’}
\pdfinfo{
    /CreationDate (\fixedpdfdate)
    /ModDate (\fixedpdfdate) }

把这个放在文档的开头:字典可能会被分成几块写出来,有一定的风险。

答案2

SOURCE_DATE_EPOCH

总结

创建一个名为 Makefile 的文件并包含这些内容,然后输入make

all: test.pdf
%.pdf: %.tex
	SOURCE_DATE_EPOCH=`(git log -1 --format=%at $< 2>/dev/null; \
	                    date +%s -r $<) | head -1` \
	pdflatex $<

您无需理解这一点即可使用它。


好奇者的解释

虽然接受的答案很好,但还有另一种解决方案,它不需要修改 .tex 文件,可与任何现代 TeX 引擎(pdfTeX、LuaTeX、XeTeX)配合使用,并且可以在 .tex 文件更改时更新。核心思想是设置环境变量SOURCE_DATE_EPOCH,用于的变量可重复的构建

固定日期示例

首先,这里有一个类似于已接受答案的示例,它对特定日期进行硬编码,格式为自时代(啦 date +%s)。

$ export SOURCE_DATE_EPOCH=1694000000
$ pdflatex test.tex && md5sum test.pdf
badef9728436749defaec3982f86e4e0  test.pdf
$ pdflatex test.tex && md5sum test.pdf
badef9728436749defaec3982f86e4e0  test.pdf
$ pdfinfo test.pdf | grep Mod
ModDate:         Wed Sep  6 11:33:20 2023 UTC

这可行,但请继续阅读以找到更好的方法。

使用 latex 文件的修改时间

根据您是否将 latex 文件存储在 git 存储库中,您可以使用以下方法之一来检索修改时间:

  • 使用 gitgit log -1 --format=%at test.tex
  • 没有 gitdate +%s -r test.tex

例如,

SOURCE_DATE_EPOCH=`git log -1 --format=%at test.tex` pdflatex test.tex

综合起来

上述命令可以包装在 shell 脚本中或Makefile。下面是后者的一个例子,它使用 git(如果可用)并回退到文件修改时间戳:

all: test.pdf

# Pattern rule for building a pdf from any latex source file.
# Note: $< represents the .tex filename.
%.pdf: %.tex FORCE
	SOURCE_DATE_EPOCH=`(git log -1 --format=%at $< 2>/dev/null; \
	                    date +%s -r $<) | head -1` \
	pdflatex $<

FORCE:

要使用它,只需键入makecreate test.pdf。或者,由于它使用模式规则,您可以键入make foo.pdf,它会查找名为 foo.tex 的文件。

注意:FORCE目标是可选的。它允许您make根据需要重复运行以重新运行 pdflatex,以进行交叉引用和参考书目。

相关内容