WSL2 で md-to-pdf を使うために四苦八苦した話

2023.06.12

いたくらです。
WSL2 で md-to-pdf を実行できるようになるまでをまとめました。

この記事で得られること

  • WSL2(Linux ディストリビューション:Ubuntu)で md-to-pdf を実行するまでに必要な手順

実行環境

  • エディション:Windows 11 Pro
  • バージョン:22H2
  • OS ビルド:22621.1702

Linux ディストリビューションについては以下コマンドで環境を確認します。

$ cat /etc/lsb-release
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=22.04
DISTRIB_CODENAME=jammy
DISTRIB_DESCRIPTION="Ubuntu 22.04.2 LTS"

0. 大まかな手順

md-to-pdf は npm でインストールするので、前提として node を入れないといけないのですが、
「node を環境に直接ぶち込むのは良くない、Node.js のバージョン管理ツールを入れてやるべし」
とご指導いただき、さらに
「各言語にそれぞれ環境管理(env系)ツールがあるから anyenv でまとめて管理するといい」
とご教示いただいたので、以下の手順で進めます。

  1. anyenv インストール
  2. nodenv インストール
  3. node インストール
  4. md-to-pdf インストール

1. anyenv インストール

こちらを参考に進めました。

anyenv をダウンロード

git clone https://github.com/anyenv/anyenv ~/.anyenv

path を通す

下記のコードを

if [ -e "$HOME/.anyenv" ]
then
    export ANYENV_ROOT="$HOME/.anyenv"
    export PATH="$ANYENV_ROOT/bin:$PATH"
    if command -v anyenv 1>/dev/null 2>&1
    then
        eval "$(anyenv init -)"
    fi
fi

./bashrcに追記・保存しました。

./bashrcに追記した設定を即座に反映させるために以下を実行します。

source ~/.bashrc

プラグインをインストール

nodenv をインストールするために、anyenv-installのプラグインが必要。
自分は/home/ユーザ名/.anyenv/libexec/anyenv-install/にインストールされました。

anyenv install --init

何env がインストールできるんだろう

nodenv 以外何があるんだろうと気になったので以下を実行します。

$ anyenv install --list
  Renv
  crenv
  denv
  erlenv
  exenv
  goenv
  hsenv
  jenv
  jlenv
  kubectlenv
  luaenv
  nodenv
  phpenv
  plenv
  pyenv
  rbenv
  sbtenv
  scalaenv
  swiftenv
  tfenv

めっちゃありました。ちゃんと nodenv もありました。

2. nodenv インストール

nodenv をインストール

以下を実行します。

anyenv install nodenv

インストールが完了すると以下が表示されます。

(省略)
Install nodenv succeeded!
Please reload your profile (exec $SHELL -l) or open a new session.

指示通りプロファイルのリロードを実行します。

exec $SHELL -l

以下を実行し、環境変数が追加されたか確認します。

$ env | grep nodenv
NODENV_ROOT=/home/ユーザ名/.anyenv/envs/nodenv
PATH=/home/ユーザ/.anyenv/envs/nodenv/shims:(以下省略)

ちゃんと追加されてるみたいなので OK です。

3. node インストール

Node.js のバージョン確認

インストール可能なバージョンを確認するために以下を実行します。

$ nodenv install -l

めっっっちゃ種類ある。
何がいいかわからないので以下を参照し、推奨版とされるv18.16.0を導入します。
【参考】ダウンロード | Node.js

node をインストール

以下を実行します。
nodenv globalでコンピュータのデフォルトを指定しました。

$ nodenv install 18.16.0
$ nodenv global 18.16.0

nodenv localを使って、特定ディレクトリ配下のバージョンを指定できるようなので、以下を実行します。

$ cd {開発作業をしているディレクトリ}
$ nodenv local 18.16.0

こんな感じで特定ディレクトリ配下に.node-versionというファイルができます。

念のためバージョンを確認します。

$ node -v
v18.16.0

npm 9.5.1 同梱だったので、そちらもバージョンを確認します。

$ npm -v
9.5.1

4. md-to-pdf インストール

こちらを参照し、以下を実行します。
【参考】simonhaenisch/md-to-pdf: Hackable CLI tool for converting Markdown files to PDF using Node.js and headless Chrome.

$ npm i -g md-to-pdf

実行後、以下が表示されました。

added 230 packages in 44s

15 packages are looking for funding
  run `npm fund` for details
npm notice 
npm notice New minor version of npm available! 9.5.1 -> 9.7.1
npm notice Changelog: https://github.com/npm/cli/releases/tag/v9.7.1
npm notice Run npm install -g npm@9.7.1 to update!
npm notice

とりあえず言われた通りバージョンアップします。

$ npm install -g npm@9.7.1

実行後、以下が表示されました。

removed 3 packages, and changed 64 packages in 3s

27 packages are looking for funding
  run `npm fund` for details

特に問題なさそうなので、再度インストールを実行します。

$ npm i -g md-to-pdf

changed 230 packages in 7s

15 packages are looking for funding
  run `npm fund` for details

成功したっぽいです。
npm でパッケージをインストールしたらrehash コマンドを実行して、nodenv に認識されているすべての Node.js の実行可能ファイルをインストールする必要があるらしいです。
【参考】【解決方法】nodenvで入れたnpmのグローバルインストールでパスが通らない場合の対処について | とあるクリエイターのエンジニアブログ
ということで、以下を実行します。

$ nodenv rehash

パスが通っていることを確認しつつ、バージョンを確認します。

$ md-to-pdf -v
5.2.4

インストールは完了、後は .md ファイルが PDF に変換できることを確認するだけ、
のはずでした。。。

5. md-to-pdf で PDF 変換できない(;;)

md-to-pdf を使って PDF 変換できるか確認しようと(実際は違うけど)こんな感じのコマンドを実行します。

$ md-to-pdf test.md > test.pdf

そしたら以下が返ってきました。

  Puppeteer old Headless deprecation warning:
    In the near feature `headless: true` will default to the new Headless mode
    for Chrome instead of the old Headless implementation. For more
    information, please see https://developer.chrome.com/articles/new-headless/.
    Consider opting in early by passing `headless: "new"` to `puppeteer.launch()`
    If you encounter any bugs, please report them to https://github.com/puppeteer/puppeteer/issues/new/choose.

Error: Failed to launch the browser process!
/home/ユーザ名/.cache/puppeteer/chrome/linux-113.0.5672.63/chrome-linux64/chrome: error while loading shared libraries: libnss3.so: cannot open shared object file: No such file or directory


TROUBLESHOOTING: https://pptr.dev/troubleshooting

    at Interface.onClose (/home/ユーザ名/.anyenv/envs/nodenv/versions/18.16.0/lib/node_modules/md-to-pdf/node_modules/@puppeteer/browsers/lib/cjs/launch.js:259:24)
    at Interface.emit (node:events:525:35)
    at Interface.close (node:internal/readline/interface:533:10)
    at Socket.onend (node:internal/readline/interface:259:10)
    at Socket.emit (node:events:525:35)
    at endReadableNT (node:internal/streams/readable:1359:12)
    at process.processTicksAndRejections (node:internal/process/task_queues:82:21)

わぁ・・・^ω^

調査:1~6 行目の文章

こちらは一旦放置して大丈夫そうなので Warning だけど無視することにします。
理由はこちらの記事を参照ください。

調査:8~9 行目の文章

エラーメッセージで調査すると、下記の記事と状況が似ていました。

どうやら依存関係にあるライブラリが見つからないというエラーみたいです。
記事にあるldd コマンドを使用して、以下を実行します。

$ ldd /home/ユーザ名/.cache/puppeteer/chrome/linux-113.0.5672.63/chrome-linux64/chrome | grep "not found"

ldd コマンドの詳細はこちらを参照ください。
【参考】Linuxコマンド【 ldd 】共有ライブラリへの依存関係を表示 - Linux入門 - Webkaru
返ってきた結果がこちら。

$ ldd /home/ユーザ名/.cache/puppeteer/chrome/linux-113.0.5672.63/chrome-linux64/chrome | grep "not found"
        libnss3.so => not found
        libnssutil3.so => not found
        libsmime3.so => not found
        libnspr4.so => not found
        libatk-1.0.so.0 => not found
        libatk-bridge-2.0.so.0 => not found
        libcups.so.2 => not found
        libxkbcommon.so.0 => not found
        libatspi.so.0 => not found
        libXcomposite.so.1 => not found
        libXdamage.so.1 => not found
        libXfixes.so.3 => not found
        libXrandr.so.2 => not found
        libgbm.so.1 => not found
        libpango-1.0.so.0 => not found
        libcairo.so.2 => not found
        libasound.so.2 => not found

全然足りないじゃん!!!!

足りないパッケージ集めの旅

ひとまず不足しているファイルは判明しました。
でもどのパッケージをインストールすればいいんでしょう。
同じ疑問を持った方がいらっしゃいました。

こちらを参考に、まずは一番上にあるlibnss3.soを検索します。

検索結果が表示され、必要なパッケージ名が判明しました!

検索結果を見ると CPU のアーキテクチャごとにパッケージ名が異なるようだったので、
amd64 だろうと思いつつ念のため以下を実行して確認します。

$ lscpu
Architecture:            x86_64
  CPU op-mode(s):        32-bit, 64-bit
(省略)
Vendor ID:               AuthenticAMD
  Model name:            AMD Ryzen 5 Microsoft Surface (R) Edition

AMD の x86_64 ということが確認できたので、libnss3をインストールします。

$ sudo apt install libnss3

パッケージによって途中で Yes/No があったり無かったりでしたが、とりあえず全部 Yes で進めます。
インストール完了後、不足パッケージが減っているか確認します。

$ ldd /home/ユーザ名/.cache/puppeteer/chrome/linux-113.0.5672.63/chrome-linux64/chrome | grep "not found"
        libatk-1.0.so.0 => not found
        libatk-bridge-2.0.so.0 => not found
        libcups.so.2 => not found
        libxkbcommon.so.0 => not found
        libatspi.so.0 => not found
        libXcomposite.so.1 => not found
        libXdamage.so.1 => not found
        libXfixes.so.3 => not found
        libXrandr.so.2 => not found
        libgbm.so.1 => not found
        libpango-1.0.so.0 => not found
        libcairo.so.2 => not found
        libasound.so.2 => not found

ちゃんと減っています!
ということで、残りもひたすらファイルを検索、パッケージ特定・インストールを繰り返します。
最後のパッケージをインストール後、再度 .md ファイルが PDF に変換できることを確認します。

$ md-to-pdf test.md > test.pdf

  Puppeteer old Headless deprecation warning:
    In the near feature `headless: true` will default to the new Headless mode
    for Chrome instead of the old Headless implementation. For more
    information, please see https://developer.chrome.com/articles/new-headless/.
    Consider opting in early by passing `headless: "new"` to `puppeteer.launch()`
    If you encounter any bugs, please report them to https://github.com/puppeteer/puppeteer/issues/new/choose.

$

(Warning は無視するとして)エラーが消えたし、PDF ファイルもできました!

るんるんで PDF ファイルを開いたら、日本語が全部お豆腐(□)になっていました・・・

6. 日本語フォントを入れましょう

日本語フォントがないんだからそりゃお豆腐になりますね。
こちらを参考にさっさとインストールします。
【参考】日本語フォント IPAフォントのインストール - Ubuntuサーバー構築入門 - Ubuntuサーバーでゼロから環境構築

$ sudo apt install -y fonts-ipafont
$ fc-cache -fv
$ fc-list | grep -i ipa
/usr/share/fonts/opentype/ipafont-mincho/ipam.ttf: IPAMincho,IPA明朝:style=Regular
/usr/share/fonts/opentype/ipafont-gothic/ipagp.ttf: IPAPGothic,IPA Pゴシック:style=Regular
/usr/share/fonts/opentype/ipafont-mincho/ipamp.ttf: IPAPMincho,IPA P明朝:style=Regular
/usr/share/fonts/opentype/ipafont-gothic/ipag.ttf: IPAGothic,IPAゴシック:style=Regular
/usr/share/fonts/truetype/fonts-japanese-mincho.ttf: IPAMincho,IPA明朝:style=Regular
/usr/share/fonts/truetype/fonts-japanese-gothic.ttf: IPAGothic,IPAゴシック:style=Regular

ちゃんとインストールされました。
再度、.md ファイル ⇒ PDF 変換を実施して、PDF ファイルを確認します。

できました~!!

あとがき

開発環境の構築は奥が深い。 WSL2 と仲良くなれるように頑張らないとなぁと思いました。

アノテーション株式会社について

アノテーション株式会社は、クラスメソッド社のグループ企業として「オペレーション・エクセレンス」を担える企業を目指してチャレンジを続けています。
「らしく働く、らしく生きる」のスローガンを掲げ、様々な背景をもつ多様なメンバーが自由度の高い働き方を通してお客様へサービスを提供し続けてきました。
現在当社では一緒に会社を盛り上げていただけるメンバーを募集中です。少しでもご興味あれば、アノテーション株式会社WEBサイトをご覧ください。