CentOS7 に Emacs 26.3 をインストールして ShellCheck を Emacs 内でオンザフライ実行する

CentOS7 で利用可能な emacs パッケージは標準 RPM では 24.3.任意のバージョンをインストールしたいので,ここでは 26.3 をソースからビルドする(emacs で flycheck パッケージを使用するが,flycheck 自体は 24.3 以降で利用はできる).

開発ツールのインストール

$ sudo yum -y groupinstall "Development Tools"
$ sudo yum -y install gnutls-devel ncurses-devel

ソースの入手

$ curl -LO https://ftpmirror.gnu.org/emacs/emacs-26.3.tar.gz

ソースの展開

$ zcat emacs-26.3.tar.gz | tar xf -

make/make install

ここでは Emacs はターミナル内でのみ使用することにし,X-Window 上の GUI は使用しないことにするので --with-x=no を指定する.

$ cd emacs-26.3
$ configure --with-x=no --without-pop
$ make
$ sudo make install

インストール完了

$ which emacs
/usr/local/bin/emacs
$ emacs --version
GNU Emacs 26.3
Copyright (C) 2019 Free Software Foundation, Inc.
GNU Emacs comes with ABSOLUTELY NO WARRANTY.
You may redistribute copies of GNU Emacs
under the terms of the GNU General Public License.
For more information about these matters, see the file named COPYING.

ShellCheck をインストール

$ sudo yum -y install ShellCheck-0.8.0-1.x86_64.rpm

Emacs の設定

emacs 初回起動時にホームディレクトリに .emacs.d が作成される.init.el は手動作成する.

$ emacs # 起動して何もせず終了する
$ cat <<EOF > ~/.emacs.d/init.el
(require 'package)

(add-to-list 'package-archives
             '("MELPA Stable" . "https://stable.melpa.org/packages/") t)
(package-initialize)
EOF

このあと emacs をまた起動し,M-x package-install[RET] し,Install package:flycheck[RET] を入力する.これで flycheck が ~/.emacs.d/ にダウンロードされ,init.el に必要な設定が追記される.

最後に emacs をまた終了し,以下のように sh-mode で flycheck が自動起動するよう設定を .emacs.d/init.el に追記する.

echo "(add-hook 'sh-mode-hook 'flycheck-mode)" >> ~/.emacs.d/init.el

これで次回 emacs を起動してシェルスクリプトを作成または編集するときには,バッファ内コンテンツに対して ShellCheck が稼働して,引っかかった部分を太字や下線でハイライトして見せてくれるようになる.(https://www.flycheck.org/en/latest/languages.html にある通り,デフォルトで sh-shellcheck が入っているので,flycheck に ShellCheck 用の設定を追加で施す必要はない)

CentOS7 での ShellCheck ビルドメモ

CentOS7 の場合 EPEL に ShellCheck は存在するけれども,バージョンが 0.3.8 と古い(※ pkgs.org によれば,RHEL9 ならば最新の 0.8.0 の RPM が EPEL にあるようだ)ので,ソースからビルドする.

ShellCheck のソースは, https://github.com/koalaman/shellcheck から入手できる.ShellCheck のコンパイルには Haskell/Cabal も必要なので,まずそれをインストールする.なお,README.md によると 2GB RAM でコンパイルできるとあるが,6GB ないと成功しなかった(swap 容量の設定は変えず,単純に VM の RAM 容量を増やして解決した).

Cabal のインストール

$ sudo yum -y install gcc gmp gmp-devel make ncurses xz perl zlib-devel
$ curl --proto '=https' --tlsv1.2 -sSf https://get-ghcup.haskell.org | sh
$ cabal install --constraint="lukko -ofd-locking" cabal-install

ShellCheck のソース入手+コンパイル

$ sudo yum -y install git
$ git clone https://github.com/koalaman/shellcheck.git
$ cd shellcheck/
$ cabal install

以上で ShellCheck がコンパイルされて,~/.cabal/bin/shellcheck にインストールされる.--version オプションをつけて実行するとこんな具合だ.

$ shellcheck --version
ShellCheck - shell script analysis tool
version: 0.8.0
license: GNU General Public License, version 3
website: https://www.shellcheck.net
[snakai@task2140 shellcheck]$ shellcheck --help
Usage: shellcheck [OPTIONS...] FILES...
  -a                  --check-sourced            Include warnings from sourced files
  -C[WHEN]            --color[=WHEN]             Use color (auto, always, never)
  -i CODE1,CODE2..    --include=CODE1,CODE2..    Consider only given types of warnings
  -e CODE1,CODE2..    --exclude=CODE1,CODE2..    Exclude types of warnings
  -f FORMAT           --format=FORMAT            Output format (checkstyle, diff, gcc, json, json1, quiet, tty)
                      --list-optional            List checks disabled by default
                      --norc                     Don't look for .shellcheckrc files
  -o check1,check2..  --enable=check1,check2..   List of optional checks to enable (or 'all')
  -P SOURCEPATHS      --source-path=SOURCEPATHS  Specify path when looking for sourced files ("SCRIPTDIR" for script's dir)
  -s SHELLNAME        --shell=SHELLNAME          Specify dialect (sh, bash, dash, ksh)
  -S SEVERITY         --severity=SEVERITY        Minimum severity of errors to consider (error, warning, info, style)
  -V                  --version                  Print version information
  -W NUM              --wiki-link-count=NUM      The number of wiki links to show, when applicable
  -x                  --external-sources         Allow 'source' outside of FILES
                      --help                     Show this usage summary and exit

man の生成

man ページを pandoc で作成することができる.pandoc は以下で導入可能.

$ curl -LO https://github.com/jgm/pandoc/releases/download/2.19.2/pandoc-2.19.2-linux-amd64.tar.gz
$ zcat pandoc-2.19.2-linux-amd64.tar.gz | tar xvf -
$ sudo cp pandoc-2.19.2/bin/* /usr/local/bin
$ sudo cp pandoc-2.19.2/share/man/man1/pandoc* /usr/local/share/man/man1
$ which pandoc
/usr/local/bin/pandoc

pandoc が使えるようになったら,以下で ShellCheck の man ページが生成される.(/usr/local/share/man/man1 へのインストールも行っている)

$ cd shellcheck/
$ pandoc -s -f markdown-smart -t man shellcheck.1.md -o shellcheck.1
$ sudo cp shellcheck.1 /usr/local/share/man/man1
$ man shellcheck

rpm 作成

rpm 作成用パッケージを導入する.

$ yum -y install rpmdevtools
$ rpmdev-setuptree

SPEC ファイルを作成する.

$ cat <<EOF > ~/rpmbuild/SPECS/ShellCheck.spec
Name: ShellCheck
Version: 0.8.0
Release: 1
Summary: ShellCheck - A shell script static analysis tool

License: GPLv3+
URL: https://www.shellcheck.net/
Source0: %{name}-%{version}.tar.gz

%description
ShellCheck is a GPLv3 tool that gives warnings and suggestions for bash/sh shell scripts.
The goals of ShellCheck are

* To point out and clarify typical beginner's syntax issues that cause a shell to give cryptic error messages.

* To point out and clarify typical intermediate level semantic problems that cause a shell to behave strangely and counter-intuitively.

* To point out subtle caveats, corner cases and pitfalls that may cause an advanced user's otherwise working script to fail under future circumstances.

%prep

%setup

%build

%define  debug_package %{nil}

%install
mkdir -p $RPM_BUILD_ROOT/usr/local/bin
mkdir -p $RPM_BUILD_ROOT/usr/local/man/man1
install -m 755 shellcheck $RPM_BUILD_ROOT/usr/local/bin
install -m 644 shellcheck.1 $RPM_BUILD_ROOT/usr/local/man/man1

%files
/usr/local/bin/shellcheck
/usr/local/man/man1/shellcheck.1

%changelog
* <DOW> <Mon> <Day> <Year> <Packager Name> <<Packager Email>>
- Initial release
EOF

バイナリ tar.gz の準備と rpmbuild 実行.

$ mkdir ShellCheck-0.8.0
$ cp ~/.cabal/bin/shellcheck/shellcheck ShellCheck-0.8.0/
$ cp shellcheck/shellcheck.1 ShellCheck-0.8.0/
$ tar czf ShellCheck-0.8.0.tar.gz ShellCheck-0.8.0
$ cp ShellCheck-0.8.0.tar.gz ~/rpmbuild/SOURCES/
$ cd ~
$ rpmbuild -bb ~/rpmbuild/SPECS/ShellCheck.spec

以上で,未署名 RPM ~/rpmbuild/RPMS/x86_64/ShellCheck-0.8.0-1.x86_64.rpm が作成される.必要に応じて GPG 署名する.