1. 程式人生 > >配置docker的pdflatex環境

配置docker的pdflatex環境

# 技術背景 Latex在文件撰寫方面是不可或缺的工具,尤其是在寫文章方面,是必須要用到的文字排版工具。但是latex的環境部署並不是一個特別人性化的操作,尤其是在各種不同的平臺上操作是完全不一樣的,還經常容易報錯。我們可以一個一個的去解決報錯問題,但是這需要耗費極大的精力和時間,所以很多人選擇了直接在[overleaf](https://www.overleaf.com/?nocdn=true)進行latex的創作。但其實overleaf也有它的缺點,比如免費版本的頻寬和速度都比較受限,尤其是在國內的網路,訪問速度可謂是”一絕“。因此這裡我們介紹一個更加人性化的方案,而且對各大平臺的相容性非常都非常好:使用docker來部署latex環境。 # Docker的基本操作 在各大平臺的官方源裡面應該都會有提供docker容器,因此這裡我們也不過多的贅述。作者過去寫過一篇關於[使用docker來部署MindSpore開發環境](https://www.cnblogs.com/dechinphy/p/mindspore.html)的部落格,感興趣的讀者可以當作是拓展文章來閱讀一下。 首先我們在Manjaro Linux平臺上啟動docker(在其他平臺上的操作可能有區別,比如`service start docker`等): ```bash [dechin-root tex]# systemctl start docker ``` 注意上述指令要在root帳號下才能夠啟動,如果要選擇在非root帳號下操作,docker容器是不支援的,但是我們可以選擇singularity這一類似的容器解決方案,相關內容可以參考這篇[部落格](https://www.cnblogs.com/dechinphy/p/singularity-install.html)。啟動服務之後,正常狀態下我們可以看到docker的status是處於active或者running的狀態: ```bash [dechin-root tex]# systemctl status docker ● docker.service - Docker Application Container Engine Loaded: loaded (/usr/lib/systemd/system/docker.service; disabled; vendor preset: disab> Active: active (running) since Sun 2021-03-28 18:50:47 CST; 7s ago TriggeredBy: ● docker.socket Docs: https://docs.docker.com Main PID: 25366 (dockerd) Tasks: 123 (limit: 47875) Memory: 219.1M CGroup: /system.slice/docker.service ├─25366 /usr/bin/dockerd -H fd:// └─25378 containerd --config /var/run/docker/containerd/containerd.toml --log-l> ``` # 拉取容器映象 首先我們可以訪問[dockerhub官網](https://hub.docker.com/)搜尋一下是否存在我們所需要的容器映象,比如我們的搜尋結果如下: ![](https://img2020.cnblogs.com/blog/2277440/202103/2277440-20210328193653610-1751342644.png) 可以看到這裡有很多的選項,一般我們可以直接選擇星星最高的容器映象進行下載使用: ```bash [dechin-root tex]# docker pull fbenz/pdflatex Using default tag: latest latest: Pulling from fbenz/pdflatex f22ccc0b8772: Already exists 3cf8fb62ba5f: Already exists e80c964ece6a: Already exists 9aa2583757a3: Pull complete 2c3d7890d583: Pull complete Digest: sha256:6ecca11b1a203faed5c0a2ace2a13aac100dd19d7a4e0db0474283bcded3c041 Status: Downloaded newer image for fbenz/pdflatex:latest docker.io/fbenz/pdflatex:latest ``` 下載需要一段的時間。下載完成後,可以在本地映象倉庫中找到剛才下載的這個映象檔案: ```bash [dechin-root tex]# docker images REPOSITORY TAG IMAGE ID CREATED SIZE fbenz/pdflatex latest 8e7742722956 3 months ago 24GB ``` 我們可以測試一下這個容器映象中的pdflatex功能是否正常: ```bash [dechin-root tex]# docker run -it fbenz/pdflatex pdflatex --help Usage: pdftex [OPTION]... [TEXNAME[.tex]] [COMMANDS] or: pdftex [OPTION]... \FIRST-LINE or: pdftex [OPTION]... &FMT ARGS Run pdfTeX on TEXNAME, usually creating TEXNAME.pdf. Any remaining COMMANDS are processed as pdfTeX input, after TEXNAME is read. If the first line of TEXNAME is %&FMT, and FMT is an existing .fmt file, use it. Else use `NAME.fmt', where NAME is the program invocation name, most commonly `pdftex'. Alternatively, if the first non-option argument begins with a backslash, interpret all non-option arguments as a line of pdfTeX input. Alternatively, if the first non-option argument begins with a &, the next word is taken as the FMT to read, overriding all else. Any remaining arguments are processed as above. If no arguments or options are specified, prompt for input. -draftmode switch on draft mode (generates no output PDF) -enc enable encTeX extensions such as \mubyte -etex enable e-TeX extensions [-no]-file-line-error disable/enable file:line:error style messages -fmt=FMTNAME use FMTNAME instead of program name or a %& line -halt-on-error stop processing at the first error -ini be pdfinitex, for dumping formats; this is implicitly true if the program name is `pdfinitex' -interaction=STRING set interaction mode (STRING=batchmode/nonstopmode/ scrollmode/errorstopmode) -ipc send DVI output to a socket as well as the usual output file -ipc-start as -ipc, and also start the server at the other end -jobname=STRING set the job name to STRING -kpathsea-debug=NUMBER set path searching debugging flags according to the bits of NUMBER [-no]-mktex=FMT disable/enable mktexFMT generation (FMT=tex/tfm/pk) -mltex enable MLTeX extensions such as \charsubdef -output-comment=STRING use STRING for DVI file comment instead of date (no effect for PDF) -output-directory=DIR use existing DIR as the directory to write files in -output-format=FORMAT use FORMAT for job output; FORMAT is `dvi' or `pdf' [-no]-parse-first-line disable/enable parsing of first line of input file -progname=STRING set program (and fmt) name to STRING -recorder enable filename recorder [-no]-shell-escape disable/enable \write18{SHELL COMMAND} -shell-restricted enable restricted \write18 -src-specials insert source specials into the DVI file -src-specials=WHERE insert source specials in certain places of the DVI file. WHERE is a comma-separated value list: cr display hbox math par parend vbox -synctex=NUMBER generate SyncTeX data for previewers according to bits of NUMBER (`man synctex' for details) -translate-file=TCXNAME use the TCX file TCXNAME -8bit make all characters printable by default -help display this help and exit -version output version information and exit pdfTeX home page:
Email bug reports to [email protected]. ``` 當我們看到`help`指令執行成功時,就表明容器映象可以正常使用。使用容器還有一點需要注意的是,如果我們直接用`docker run -it fbenz/pdflatex`的話,沒有繫結本地的目錄,這樣是無法看到本地所撰寫的tex檔案的。因此我們一般需要在執行的時候加上`-v`的選項來繫結本地的目錄,基本使用方法是:`-v 本地目錄:容器目錄`,注意需要使用絕對路徑,不能使用相對路徑。 # 編譯Tex檔案 在上述章節中完成基於docker的pdflatex環境部署之後,我們可以開始撰寫一些簡單的tex檔案用來測試一下環境。 ## Hello World 首先最簡單的我們測試一個hello world的案例,僅在pdf文件中輸出一個`Hello World!`的字樣,具體tex程式碼如下: ```bash [dechin@dechin-manjaro tex]$ cat hello_world.tex \documentclass{article} \begin{document} Hello world! \end{document} ``` 使用方法也不難,首先我們執行docker容器,注意需要繫結一個本地路徑,然後進入到容器內對應的目錄下: ```bash [dechin-root tex]# docker run -it -v /home/dechin/projects/2021-python/tex/:/home/ fbenz/pdflatex root@d7ed2229a244:/# ll total 72 drwxr-xr-x 1 root root 4096 Mar 28 11:07 ./ drwxr-xr-x 1 root root 4096 Mar 28 11:07 ../ -rwxr-xr-x 1 root root 0 Mar 28 11:07 .dockerenv* drwxr-xr-x 2 root root 4096 Nov 19 13:09 bin/ drwxr-xr-x 2 root root 4096 Apr 24 2018 boot/ drwxr-xr-x 5 root root 360 Mar 28 11:07 dev/ drwxr-xr-x 1 root root 4096 Mar 28 11:07 etc/ drwxr-xr-x 2 1000 1000 4096 Mar 28 04:43 home/ drwxr-xr-x 1 root root 4096 May 23 2017 lib/ drwxr-xr-x 2 root root 4096 Nov 19 13:09 lib64/ drwxr-xr-x 2 root root 4096 Nov 19 13:07 media/ drwxr-xr-x 2 root root 4096 Nov 19 13:07 mnt/ drwxr-xr-x 2 root root 4096 Nov 19 13:07 opt/ dr-xr-xr-x 323 root root 0 Mar 28 11:07 proc/ drwx------ 2 root root 4096 Nov 19 13:09 root/ drwxr-xr-x 1 root root 4096 Nov 25 22:25 run/ drwxr-xr-x 1 root root 4096 Nov 25 22:25 sbin/ drwxr-xr-x 2 root root 4096 Nov 19 13:07 srv/ dr-xr-xr-x 13 root root 0 Mar 28 11:07 sys/ drwxrwxrwt 1 root root 4096 Nov 28 18:34 tmp/ drwxr-xr-x 1 root root 4096 Nov 19 13:07 usr/ drwxr-xr-x 1 root root 4096 Nov 19 13:09 var/ root@d7ed2229a244:/# cd home/ root@d7ed2229a244:/home# ll total 12 drwxr-xr-x 2 1000 1000 4096 Mar 28 04:43 ./ drwxr-xr-x 1 root root 4096 Mar 28 11:07 ../ -rw-r--r-- 1 1000 1000 69 Mar 28 04:43 hello_world.tex ``` 我們看到在容器內的目錄下也能夠看到這個tex檔案,說明路徑的繫結成功的執行了。執行指令很簡單,直接在docker容器內執行`pdflatex your_file.tex`即可: ```bash root@d7ed2229a244:/home# pdflatex hello_world.tex This is pdfTeX, Version 3.14159265-2.6-1.40.18 (TeX Live 2017/Debian) (preloaded format=pdflatex) restricted \write18 enabled. entering extended mode (./hello_world.tex LaTeX2e <2017-04-15> Babel <3.18> and hyphenation patterns for 84 language(s) loaded. (/usr/share/texlive/texmf-dist/tex/latex/base/article.cls Document Class: article 2014/09/29 v1.4h Standard LaTeX document class (/usr/share/texlive/texmf-dist/tex/latex/base/size10.clo)) No file hello_world.aux. [1{/var/lib/texmf/fonts/map/pdftex/updmap/pdftex.map}] (./hello_world.aux) )
Output written on hello_world.pdf (1 page, 11916 bytes). Transcript written on hello_world.log. root@d7ed2229a244:/home# ll total 32 drwxr-xr-x 2 1000 1000 4096 Mar 28 11:08 ./ drwxr-xr-x 1 root root 4096 Mar 28 11:07 ../ -rw-r--r-- 1 root root 8 Mar 28 11:08 hello_world.aux -rw-r--r-- 1 root root 2408 Mar 28 11:08 hello_world.log -rw-r--r-- 1 root root 11916 Mar 28 11:08 hello_world.pdf -rw-r--r-- 1 1000 1000 69 Mar 28 04:43 hello_world.tex root@d7ed2229a244:/home# chmod -R 777 . root@d7ed2229a244:/home# ll total 32 drwxrwxrwx 2 1000 1000 4096 Mar 28 11:08 ./ drwxr-xr-x 1 root root 4096 Mar 28 11:07 ../ -rwxrwxrwx 1 root root 8 Mar 28 11:08 hello_world.aux* -rwxrwxrwx 1 root root 2408 Mar 28 11:08 hello_world.log* -rwxrwxrwx 1 root root 11916 Mar 28 11:08 hello_world.pdf* -rwxrwxrwx 1 1000 1000 69 Mar 28 04:43 hello_world.tex* ``` 執行完成後我們在目錄中看到了幾個新生成的檔案,如果用root改成`777`的許可權,那麼在本地的非root帳號就可以對其進行編輯,否則就只能檢視。我們可以在本地開啟這個pdf檔案看看: ![](https://img2020.cnblogs.com/blog/2277440/202103/2277440-20210328191028182-435916322.png) 可以看到這個pdf檔案生成成功。 ## 測試公式 上面hello world的案例比較簡單,讓我們來測試一下最常用的數學公式是否有問題: ```bash [dechin@dechin-manjaro tex]$ cat equation_test.tex \documentclass{article} \begin{document} Hello world! \begin{equation} e^{iHt}\left|\psi\right>
\end{equation} \end{document} ``` 類似於上一章節的,我們也需要進入到容器的內部執行相關的指令,最後獲得如下所示的一個pdf檔案: ![](https://img2020.cnblogs.com/blog/2277440/202103/2277440-20210328191542588-1269219414.png) 我們可以看到公式顯示也是正常的。 ## 量子線路圖 最後我們測試一個比較難的,在前面寫過一篇關於用ProjectQ生成Latex格式的量子線路圖的[部落格](https://www.cnblogs.com/dechinphy/p/circuit.html),其中生成了如下所示的一個tex檔案: ```bash [dechin@dechin-manjaro quantum-circuit]$ cat circuit.tex \documentclass{standalone} \usepackage[margin=1in]{geometry} \usepackage[hang,small,bf]{caption} \usepackage{tikz} \usepackage{braket} \usetikzlibrary{backgrounds,shadows.blur,fit,decorations.pathreplacing,shapes} \begin{document} \begin{tikzpicture}[scale=0.8, transform shape] \tikzstyle{basicshadow}=[blur shadow={shadow blur steps=8, shadow xshift=0.7pt, shadow yshift=-0.7pt, shadow scale=1.02}]\tikzstyle{basic}=[draw,fill=white,basicshadow] \tikzstyle{operator}=[basic,minimum size=1.5em] \tikzstyle{phase}=[fill=black,shape=circle,minimum size=0.1cm,inner sep=0pt,outer sep=0pt,draw=black] \tikzstyle{none}=[inner sep=0pt,outer sep=-.5pt,minimum height=0.5cm+1pt] \tikzstyle{measure}=[operator,inner sep=0pt,minimum height=0.5cm, minimum width=0.75cm] \tikzstyle{xstyle}=[circle,basic,minimum height=0.35cm,minimum width=0.35cm,inner sep=-1pt,very thin] \tikzset{ shadowed/.style={preaction={transform canvas={shift={(0.5pt,-0.5pt)}}, draw=gray, opacity=0.4}}, } \tikzstyle{swapstyle}=[inner sep=-1pt, outer sep=-1pt, minimum width=0pt] \tikzstyle{edgestyle}=[very thin] \node[none] (line0_gate0) at (0.1,-0) {$\Ket{0}$}; \node[none] (line0_gate1) at (0.5,-0) {}; \node[none,minimum height=0.5cm,outer sep=0] (line0_gate2) at (0.75,-0) {}; \node[none] (line0_gate3) at (1.0,-0) {}; \draw[operator,edgestyle,outer sep=0.5cm] ([yshift=0.25cm]line0_gate1) rectangle ([yshift=-0.25cm]line0_gate3) node[pos=.5] {H}; \draw (line0_gate0) edge[edgestyle] (line0_gate1); \node[none] (line1_gate0) at (0.1,-1) {$\Ket{0}$}; \node[none] (line1_gate1) at (0.5,-1) {}; \node[none,minimum height=0.5cm,outer sep=0] (line1_gate2) at (0.75,-1) {}; \node[none] (line1_gate3) at (1.0,-1) {}; \draw[operator,edgestyle,outer sep=0.5cm] ([yshift=0.25cm]line1_gate1) rectangle ([yshift=-0.25cm]line1_gate3) node[pos=.5] {H}; \draw (line1_gate0) edge[edgestyle] (line1_gate1); \node[none] (line2_gate0) at (0.1,-2) {$\Ket{0}$}; \node[none] (line2_gate1) at (0.5,-2) {}; \node[none,minimum height=0.5cm,outer sep=0] (line2_gate2) at (0.75,-2) {}; \node[none] (line2_gate3) at (1.0,-2) {}; \draw[operator,edgestyle,outer sep=0.5cm] ([yshift=0.25cm]line2_gate1) rectangle ([yshift=-0.25cm]line2_gate3) node[pos=.5] {H}; \draw (line2_gate0) edge[edgestyle] (line2_gate1); \node[xstyle] (line1_gate4) at (1.4000000000000001,-1) {}; \draw[edgestyle] (line1_gate4.north)--(line1_gate4.south); \draw[edgestyle] (line1_gate4.west)--(line1_gate4.east); \node[phase] (line2_gate4) at (1.4000000000000001,-2) {}; \draw (line2_gate4) edge[edgestyle] (line1_gate4); \draw (line1_gate3) edge[edgestyle] (line1_gate4); \draw (line2_gate3) edge[edgestyle] (line2_gate4); \node[xstyle] (line0_gate4) at (1.9500000000000002,-0) {}; \draw[edgestyle] (line0_gate4.north)--(line0_gate4.south); \draw[edgestyle] (line0_gate4.west)--(line0_gate4.east); \node[phase] (line1_gate5) at (1.9500000000000002,-1) {}; \draw (line1_gate5) edge[edgestyle] (line0_gate4); \draw (line0_gate3) edge[edgestyle] (line0_gate4); \draw (line1_gate4) edge[edgestyle] (line1_gate5); \node[measure,edgestyle] (line0_gate5) at (2.6000000000000005,-0) {}; \draw[edgestyle] ([yshift=-0.18cm,xshift=0.07500000000000001cm]line0_gate5.west) to [out=60,in=180] ([yshift=0.035cm]line0_gate5.center) to [out=0, in=120] ([yshift=-0.18cm,xshift=-0.07500000000000001cm]line0_gate5.east); \draw[edgestyle] ([yshift=-0.18cm]line0_gate5.center) to ([yshift=-0.07500000000000001cm,xshift=-0.18cm]line0_gate5.north east); \draw (line0_gate4) edge[edgestyle] (line0_gate5); \node[measure,edgestyle] (line1_gate6) at (2.6000000000000005,-1) {}; \draw[edgestyle] ([yshift=-0.18cm,xshift=0.07500000000000001cm]line1_gate6.west) to [out=60,in=180] ([yshift=0.035cm]line1_gate6.center) to [out=0, in=120] ([yshift=-0.18cm,xshift=-0.07500000000000001cm]line1_gate6.east); \draw[edgestyle] ([yshift=-0.18cm]line1_gate6.center) to ([yshift=-0.07500000000000001cm,xshift=-0.18cm]line1_gate6.north east); \draw (line1_gate5) edge[edgestyle] (line1_gate6); \node[measure,edgestyle] (line2_gate5) at (2.0500000000000003,-2) {}; \draw[edgestyle] ([yshift=-0.18cm,xshift=0.07500000000000001cm]line2_gate5.west) to [out=60,in=180] ([yshift=0.035cm]line2_gate5.center) to [out=0, in=120] ([yshift=-0.18cm,xshift=-0.07500000000000001cm]line2_gate5.east); \draw[edgestyle] ([yshift=-0.18cm]line2_gate5.center) to ([yshift=-0.07500000000000001cm,xshift=-0.18cm]line2_gate5.north east); \draw (line2_gate4) edge[edgestyle] (line2_gate5); \end{tikzpicture} \end{document} ``` 這個檔案不僅結構複雜,對周邊所依賴的tex檔案其實也不少,此前在其他平臺(Win10)測試這個tex檔案的編譯的時候,都需要手動的去下載很多的依賴檔案,然後放到同一個資料夾下才能正常執行和使用。這裡我們直接執行,發現也可以生成這個pdf檔案: ![](https://img2020.cnblogs.com/blog/2277440/202103/2277440-20210328192117516-252688901.png) 說明環境裡面確實已經包含了很多必備的工具,跟overleaf的環境應該是比較類似的,使得我們可以在本地非常人性化的、輕便的可以編譯tex檔案。 # 總結概要 為了在本地構建一個可用性強、易於部署的環境,我們選擇了放棄直接安裝pdflatex的方案,以及線上的overleaf的方案。這些方案各有利弊,但是綜合起來看,對於個人使用的環境而言,還是在本地使用docker映象直接部署一個tex編譯環境是最方便、最人性化的。 # 版權宣告 本文首發連結為:https://www.cnblogs.com/dechinphy/p/pdflatex.html 作者ID:DechinPhy 更多原著文章請參考:https://www.cnblogs.com/dechinphy/ # 參考連結 1. https://www.cnblogs.com/dechinphy/p/circ