自炊の画像形式をPNGからWebPに移行する２～WebPユーティリティを評判のClangでビルドする

# 0. はじめに

[前回の記事](https://qiita.com/TETSURO1999/items/7a4f3d8b2c57d44a4ddf)で WebP ユーティリティの cwebp.exe を試行したが，公式サイトで提供されているバイナリは 64bit 版のみであり，32bit 版はない。32bit 版が必要であれば自分でソースコードを入手してビルドする必要があるのだ。なぜ 32bit 版に拘るかというと筆者の経験では 32bit 版のほうが速い場合もあるからだ。ちなみに下記の記事は 32bit 版のほうが速いという稀有なケースであった。

[今さら森博嗣「笑わない数学者」のビリヤードの問題を解く(2)～計算機を使う - Qiita](https://qiita.com/TETSURO1999/items/be4a8b460a690a48236b)

ということでソースコードを入手して自分で 32bit 版をビルドすることにする。ついでに近年評判の高い Clang でもビルドを試みることにした。

# 1. WebPユーティリティのダウンロード

Windows 用のバイナリは[WebP のダウンロードリポジトリ](https://storage.googleapis.com/downloads.webmproject.org/releases/webp/index.html)からダウンロードできる。この記事を書いている現時点では libwebp-1.4.0-windows-x64.zip が最新版である。残念ながら 64bit 版しか提供されていないので，32bit 版が必要な人は自分でソースコードを入手してビルドする必要がある。

# 2. ソースコードの入手

まずソースコードをダウンロードする。

```:ソースコードのダウンロード
git clone https://chromium.googlesource.com/webm/libwebp
```

# 3. Visual Studio のインストール

[マイクロソフトの公式サイト](https://visualstudio.microsoft.com/ja/vs/community/)より，Visual Studio 2022 Community Edition をインストールする。評判の高い Clang コンパイラも併せてインストールする。なお，Clang は [LLVM の公式サイト](https://llvm.org/)からダウンロードする手もあるが，Visual Studio との相性を鑑みて Visual Studio Installer からインストールした。

```plantuml
@startuml
<style>
root {
  margin 0
  padding 0
}
title {
  fontStyle normal
  fontSize 16
  fontColor black
}
</style>
title
<img:https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3490655/4acf3ad6-229b-2bbf-5900-5a5705397c6c.png>

図１　Visual Studio Installer の変更画面
end title
@enduml
```

# 4. コマンドラインビルド

Visual Studio をインストールしていればスタートメニューに下記のショートカットが作られているので，用途に応じて選択する。ホスト環境とターゲット環境を混同し易いので，特に必要でない限りは Cross Tools ではなく Native Tools を使ったほうが良いだろう。

<table>
<caption</caption>
<thead>
<tr><th>ショートカット名</th><th>　ホスト　</th><th>ターゲット</th></tr>
</thead>
<tbody>
<tr><td>x64 Native Tools Command Prompt for VS 2022</td>
    <td colspan=2 style="text-align:center">x64 (64bit)</td></tr>
<tr><td>x64_x86 Cross Tools Command Prompt for VS 2022</td>
    <td style="text-align:center">x64 (64bit)</td>
    <td style="text-align:center">x86 (32bit)</td></tr>
<tr><td>x86 Native Tools Command Prompt for VS 2022</td>
    <td colspan=2 style="text-align:center">x86 (32bit)</td></tr>
<tr><td>x86_x64 Cross Tools Command Prompt for VS 2022</td>
    <td style="text-align:center">x86 (32bit)</td>
    <td style="text-align:center">x64 (64bit)</td></tr>
</tbody>
</table>

Visual C++ 用のメイクファイルが提供されているのでコマンドプロンプトから `nmake.exe` を用いてビルドする。google 謹製のツールの良いところはビルドが簡単かつスムーズに通ることである。ターゲット（32bit/64bit）によらず，全く同じようにビルドできるのが凄いところだ。

```:ビルド手順
cd libwebp
nmake /f Makefile.vc CFG=release-static RTLIBCFG=static OBJDIR=output
```

# 5. メイクファイルを改造する。

この後いろいろカスタマイズすることを考えてメイクファイルを改造する。

google 謹製のメイクファイルは大仰で内容を把握するのが大変である。このためスタティックリンクかつリリースビルド専用として作り直すことにした。目的はメイクファイルの見通しを良くすることによって，さらなる最適化の余地を図ること，そして評判の高い Clang コンパイラの適用である。なお，デフォルトでは Clang には対応していない様子。CMake を使えば良いのかもしれないが。

コンパイラのオプションが多少異なるだけで大半が共通のため，共通部分を抜き出して別ファイル `Makefile.inc` とした。

### Visual C++ 用メイクファイル

google 謹製のメイクファイルに対してバッファーのセキュリティチェックの省略オプション `/GS-` およびプログラム全体の最適化オプション `/GL` を追加した。併せてリンカオプションにも `/LTCG` を追加した。また，対応プロセッサがインテル第4世代プロセッサ haswell 以降に限られてしまうが，オプション `/arch:AVX2` を追加した。

```:Makefile.vc2
#-------------------------------------------------------------------------------
# Makefile for Microsoft Visual C++, release build, static link
#-------------------------------------------------------------------------------
CC      = cl.exe
LINKLIB = lib.exe
LINKEXE = link.exe
CCFLAGS = /nologo /c /O2 /DNDEBUG /MT /I. /Isrc /W3 /EHsc
CCFLAGS = $(CCFLAGS) /DWIN32 /D_CRT_SECURE_NO_WARNINGS /DWIN32_LEAN_AND_MEAN
CCFLAGS = $(CCFLAGS) /DHAVE_WINCODEC_H /DWEBP_USE_THREAD
CCFLAGS = $(CCFLAGS) /arch:AVX2 /GS- /GL
LLFLAGS = /nologo /LTCG
LDFLAGS = /nologo /LARGEADDRESSAWARE /MANIFEST:EMBED /NXCOMPAT /DYNAMICBASE
LDFLAGS = $(LDFLAGS) /LTCG
!IF "$(VSCMD_ARG_TGT_ARCH)" == "x86"
LDFLAGS = $(LDFLAGS) /SAFESEH
!ENDIF
WINLIBS = ole32.lib windowscodecs.lib shlwapi.lib
!IFDEF VSCMD_ARG_TGT_ARCH
OUT_DIR = output\release-static\$(VSCMD_ARG_TGT_ARCH)vc
!ELSE
!ERROR 環境変数 VSCMD_ARG_TGT_ARCH が未定義です。
!ENDIF
#-------------------------------------------------------------------------------
!INCLUDE Makefile.inc
```

### Clang 用メイクファイル

プログラム全体の最適化オプション `/GL` を外して，代わりにリンク時最適化オプション `-flto` を付けた。同様にリンカオプションの `/LTCG` も外した。ちなみに Clang の場合，リンク時最適化オプション `-flto` を用いなければ Visual C++ の `lib.exe` および `link.exe` を使用できる。しかし，オプション `-flto` を用いると専用の `llvm-lib.exe` および `lld-link.exe` を使用する必要がある。

```:Makefile.clang
#-------------------------------------------------------------------------------
# Makefile for LLVM Clang, release build, static link
#-------------------------------------------------------------------------------
CC      = clang-cl.exe
LINKLIB = llvm-lib.exe
LINKEXE = lld-link.exe
CCFLAGS = /nologo /c /O2 /DNDEBUG /MT /I. /Isrc /W3
CCFLAGS = $(CCFLAGS) /DWIN32 /D_CRT_SECURE_NO_WARNINGS /DWIN32_LEAN_AND_MEAN
CCFLAGS = $(CCFLAGS) /DHAVE_WINCODEC_H /DWEBP_USE_THREAD
CCFLAGS = $(CCFLAGS) /GS- /arch:AVX2 -flto
LLFLAGS = /nologo
LDFLAGS = /nologo /LARGEADDRESSAWARE /MANIFEST:EMBED /NXCOMPAT /DYNAMICBASE
!IF "$(VSCMD_ARG_TGT_ARCH)" == "x86"
LDFLAGS = $(LDFLAGS) /SAFESEH
!ENDIF
WINLIBS = ole32.lib windowscodecs.lib shlwapi.lib
!IFDEF VSCMD_ARG_TGT_ARCH
OUT_DIR = output\release-static\$(VSCMD_ARG_TGT_ARCH)clang
!ELSE
!ERROR 環境変数 VSCMD_ARG_TGT_ARCH が未定義です。
!ENDIF
#-------------------------------------------------------------------------------
!INCLUDE Makefile.inc
```

### コンパイラオプションの違い

オプションの違いをまとめると以下のようになる。※<font color=red><b>赤字</b></font>は32bit版のみ有効

<table>
<caption>表１　コンパイラオプションの違い</caption>
<thead>
<tr><th style="text-align:center">項目</th>
    <th style="text-align:center">変数</th>
    <th style="text-align:center">Visual C++</th>
    <th style="text-align:center">Clang</th></tr>
</thead>
<tbody>
<tr><td>コンパイラ</td>
    <td>CC</td>
    <td>cl.exe</td>
    <td>clang-cl.exe</td></tr>
<tr><td>コンパイラ<br>オプション</td>
    <td>CCFLAGS</td>
    <td>/GL</td>
    <td>-flto</td></tr>
<tr><td>ライブラリアン</td>
    <td>LINKLIB</td>
    <td>lib.exe</td>
    <td>llvm-lib.exe</td></tr>
<tr><td>ライブラリアン<br>オプション</td>
    <td>LLFLAGS</td>
    <td>/LTCG</td>
    <td></td></tr>
<tr><td>リンカ</td>
    <td>LINKEXE</td>
    <td>link.exe</td>
    <td>lld-link.exe</td></tr>
<tr><td>リンカ<br>オプション</td>
    <td>LDFLAGS</td>
    <td>/LTCG <font color=red><b>/SAFESEH</b></font></td>
    <td><font color=red><b>/SAFESEH</b></font></td></tr>
</tbody>
</table>

### メイクファイル共通部

長いので興味のある方は以下参照されたい。

<details><summary><b>Makefile.inc（共通部）はコチラ</b></summary>

```:Makefile.inc
#-------------------------------------------------------------------------------
# このファイルは下記のメイクファイルでインクルードして使用します。
# Makefile.vc2   ... x86/x64, cl.exe
# Makefile.clang ... x86/x64, clang-cl.exe
#-------------------------------------------------------------------------------
# 出力ディレクトリ
#-------------------------------------------------------------------------------
OUTPUT_DIRS = \
	$(OUT_DIR)\lib \
	$(OUT_DIR)\bin \
	$(OUT_DIR)\obj\dec \
	$(OUT_DIR)\obj\demux \
	$(OUT_DIR)\obj\dsp \
	$(OUT_DIR)\obj\enc \
	$(OUT_DIR)\obj\examples \
	$(OUT_DIR)\obj\extras \
	$(OUT_DIR)\obj\imageio \
	$(OUT_DIR)\obj\mux \
	$(OUT_DIR)\obj\sharpyuv \
	$(OUT_DIR)\obj\utils
#-------------------------------------------------------------------------------
# ターゲットの定義
#-------------------------------------------------------------------------------
all: \
	$(OUTPUT_DIRS) \
	$(OUT_DIR)\lib\libwebpdecoder.lib \
	$(OUT_DIR)\lib\libsharpyuv.lib \
	$(OUT_DIR)\lib\libwebp.lib \
	$(OUT_DIR)\lib\libwebpdemux.lib \
	$(OUT_DIR)\lib\libwebpmux.lib \
	$(OUT_DIR)\bin\cwebp.exe \
	$(OUT_DIR)\bin\dwebp.exe \
	$(OUT_DIR)\bin\vwebp.exe \
	$(OUT_DIR)\bin\webpmux.exe \
	$(OUT_DIR)\bin\img2webp.exe \
	$(OUT_DIR)\bin\get_disto.exe \
	$(OUT_DIR)\bin\webp_quality.exe \
	$(OUT_DIR)\bin\vwebp_sdl.exe \
	$(OUT_DIR)\bin\webpinfo.exe \
	$(OUT_DIR)\bin\gif2webp.exe \
	$(OUT_DIR)\bin\anim_diff.exe \
	$(OUT_DIR)\bin\anim_dump.exe
#-------------------------------------------------------------------------------
# オブジェクトの定義
#-------------------------------------------------------------------------------
SHARPYUV_OBJS = \
	$(OUT_DIR)\obj\sharpyuv\sharpyuv.obj \
	$(OUT_DIR)\obj\sharpyuv\sharpyuv_cpu.obj \
	$(OUT_DIR)\obj\sharpyuv\sharpyuv_csp.obj \
	$(OUT_DIR)\obj\sharpyuv\sharpyuv_dsp.obj \
	$(OUT_DIR)\obj\sharpyuv\sharpyuv_gamma.obj \
	$(OUT_DIR)\obj\sharpyuv\sharpyuv_neon.obj \
	$(OUT_DIR)\obj\sharpyuv\sharpyuv_sse2.obj
DEC_OBJS = \
	$(OUT_DIR)\obj\dec\alpha_dec.obj \
	$(OUT_DIR)\obj\dec\buffer_dec.obj \
	$(OUT_DIR)\obj\dec\frame_dec.obj \
	$(OUT_DIR)\obj\dec\idec_dec.obj \
	$(OUT_DIR)\obj\dec\io_dec.obj \
	$(OUT_DIR)\obj\dec\quant_dec.obj \
	$(OUT_DIR)\obj\dec\tree_dec.obj \
	$(OUT_DIR)\obj\dec\vp8_dec.obj \
	$(OUT_DIR)\obj\dec\vp8l_dec.obj \
	$(OUT_DIR)\obj\dec\webp_dec.obj
ENC_OBJS = \
	$(OUT_DIR)\obj\enc\alpha_enc.obj \
	$(OUT_DIR)\obj\enc\analysis_enc.obj \
	$(OUT_DIR)\obj\enc\backward_references_cost_enc.obj \
	$(OUT_DIR)\obj\enc\backward_references_enc.obj \
	$(OUT_DIR)\obj\enc\config_enc.obj \
	$(OUT_DIR)\obj\enc\cost_enc.obj \
	$(OUT_DIR)\obj\enc\filter_enc.obj \
	$(OUT_DIR)\obj\enc\frame_enc.obj \
	$(OUT_DIR)\obj\enc\histogram_enc.obj \
	$(OUT_DIR)\obj\enc\iterator_enc.obj \
	$(OUT_DIR)\obj\enc\near_lossless_enc.obj \
	$(OUT_DIR)\obj\enc\picture_enc.obj \
	$(OUT_DIR)\obj\enc\picture_csp_enc.obj \
	$(OUT_DIR)\obj\enc\picture_psnr_enc.obj \
	$(OUT_DIR)\obj\enc\picture_rescale_enc.obj \
	$(OUT_DIR)\obj\enc\picture_tools_enc.obj \
	$(OUT_DIR)\obj\enc\predictor_enc.obj \
	$(OUT_DIR)\obj\enc\quant_enc.obj \
	$(OUT_DIR)\obj\enc\syntax_enc.obj \
	$(OUT_DIR)\obj\enc\token_enc.obj \
	$(OUT_DIR)\obj\enc\tree_enc.obj \
	$(OUT_DIR)\obj\enc\vp8l_enc.obj \
	$(OUT_DIR)\obj\enc\webp_enc.obj
DSP_DEC_OBJS = \
	$(OUT_DIR)\obj\dsp\alpha_processing.obj \
	$(OUT_DIR)\obj\dsp\alpha_processing_mips_dsp_r2.obj \
	$(OUT_DIR)\obj\dsp\alpha_processing_neon.obj \
	$(OUT_DIR)\obj\dsp\alpha_processing_sse2.obj \
	$(OUT_DIR)\obj\dsp\alpha_processing_sse41.obj \
	$(OUT_DIR)\obj\dsp\cpu.obj $(OUT_DIR)\obj\dsp\dec.obj \
	$(OUT_DIR)\obj\dsp\dec_clip_tables.obj \
	$(OUT_DIR)\obj\dsp\dec_mips32.obj \
	$(OUT_DIR)\obj\dsp\dec_mips_dsp_r2.obj \
	$(OUT_DIR)\obj\dsp\dec_msa.obj \
	$(OUT_DIR)\obj\dsp\dec_neon.obj \
	$(OUT_DIR)\obj\dsp\dec_sse2.obj \
	$(OUT_DIR)\obj\dsp\dec_sse41.obj \
	$(OUT_DIR)\obj\dsp\filters.obj \
	$(OUT_DIR)\obj\dsp\filters_mips_dsp_r2.obj \
	$(OUT_DIR)\obj\dsp\filters_msa.obj \
	$(OUT_DIR)\obj\dsp\filters_neon.obj \
	$(OUT_DIR)\obj\dsp\filters_sse2.obj \
	$(OUT_DIR)\obj\dsp\lossless.obj \
	$(OUT_DIR)\obj\dsp\lossless_mips_dsp_r2.obj \
	$(OUT_DIR)\obj\dsp\lossless_msa.obj \
	$(OUT_DIR)\obj\dsp\lossless_neon.obj \
	$(OUT_DIR)\obj\dsp\lossless_sse2.obj \
	$(OUT_DIR)\obj\dsp\lossless_sse41.obj \
	$(OUT_DIR)\obj\dsp\rescaler.obj \
	$(OUT_DIR)\obj\dsp\rescaler_mips32.obj \
	$(OUT_DIR)\obj\dsp\rescaler_mips_dsp_r2.obj \
	$(OUT_DIR)\obj\dsp\rescaler_msa.obj \
	$(OUT_DIR)\obj\dsp\rescaler_neon.obj \
	$(OUT_DIR)\obj\dsp\rescaler_sse2.obj \
	$(OUT_DIR)\obj\dsp\upsampling.obj \
	$(OUT_DIR)\obj\dsp\upsampling_mips_dsp_r2.obj \
	$(OUT_DIR)\obj\dsp\upsampling_msa.obj \
	$(OUT_DIR)\obj\dsp\upsampling_neon.obj \
	$(OUT_DIR)\obj\dsp\upsampling_sse2.obj \
	$(OUT_DIR)\obj\dsp\upsampling_sse41.obj \
	$(OUT_DIR)\obj\dsp\yuv.obj \
	$(OUT_DIR)\obj\dsp\yuv_mips32.obj \
	$(OUT_DIR)\obj\dsp\yuv_mips_dsp_r2.obj \
	$(OUT_DIR)\obj\dsp\yuv_neon.obj \
	$(OUT_DIR)\obj\dsp\yuv_sse2.obj \
	$(OUT_DIR)\obj\dsp\yuv_sse41.obj
DSP_ENC_OBJS = \
	$(OUT_DIR)\obj\dsp\cost.obj \
	$(OUT_DIR)\obj\dsp\cost_mips32.obj \
	$(OUT_DIR)\obj\dsp\cost_mips_dsp_r2.obj \
	$(OUT_DIR)\obj\dsp\cost_neon.obj \
	$(OUT_DIR)\obj\dsp\cost_sse2.obj \
	$(OUT_DIR)\obj\dsp\enc.obj \
	$(OUT_DIR)\obj\dsp\enc_mips32.obj \
	$(OUT_DIR)\obj\dsp\enc_mips_dsp_r2.obj \
	$(OUT_DIR)\obj\dsp\enc_msa.obj \
	$(OUT_DIR)\obj\dsp\enc_neon.obj \
	$(OUT_DIR)\obj\dsp\enc_sse2.obj \
	$(OUT_DIR)\obj\dsp\enc_sse41.obj \
	$(OUT_DIR)\obj\dsp\lossless_enc.obj \
	$(OUT_DIR)\obj\dsp\lossless_enc_mips32.obj \
	$(OUT_DIR)\obj\dsp\lossless_enc_mips_dsp_r2.obj \
	$(OUT_DIR)\obj\dsp\lossless_enc_msa.obj \
	$(OUT_DIR)\obj\dsp\lossless_enc_neon.obj \
	$(OUT_DIR)\obj\dsp\lossless_enc_sse2.obj \
	$(OUT_DIR)\obj\dsp\lossless_enc_sse41.obj \
	$(OUT_DIR)\obj\dsp\ssim.obj \
	$(OUT_DIR)\obj\dsp\ssim_sse2.obj
UTILS_DEC_OBJS = \
	$(OUT_DIR)\obj\utils\bit_reader_utils.obj \
	$(OUT_DIR)\obj\utils\color_cache_utils.obj \
	$(OUT_DIR)\obj\utils\filters_utils.obj \
	$(OUT_DIR)\obj\utils\huffman_utils.obj \
	$(OUT_DIR)\obj\utils\palette.obj \
	$(OUT_DIR)\obj\utils\quant_levels_dec_utils.obj \
	$(OUT_DIR)\obj\utils\rescaler_utils.obj \
	$(OUT_DIR)\obj\utils\random_utils.obj \
	$(OUT_DIR)\obj\utils\thread_utils.obj \
	$(OUT_DIR)\obj\utils\utils.obj
UTILS_ENC_OBJS = \
	$(OUT_DIR)\obj\utils\bit_writer_utils.obj \
	$(OUT_DIR)\obj\utils\huffman_encode_utils.obj \
	$(OUT_DIR)\obj\utils\quant_levels_utils.obj
IMAGEIO_DEC_OBJS = \
	$(OUT_DIR)\obj\imageio\image_dec.obj \
	$(OUT_DIR)\obj\imageio\jpegdec.obj \
	$(OUT_DIR)\obj\imageio\metadata.obj \
	$(OUT_DIR)\obj\imageio\pngdec.obj \
	$(OUT_DIR)\obj\imageio\pnmdec.obj \
	$(OUT_DIR)\obj\imageio\tiffdec.obj \
	$(OUT_DIR)\obj\imageio\webpdec.obj \
	$(OUT_DIR)\obj\imageio\wicdec.obj
IMAGEIO_ENC_OBJS = \
	$(OUT_DIR)\obj\imageio\image_enc.obj
IMAGEIO_UTIL_OBJS = \
	$(OUT_DIR)\obj\imageio\imageio_util.obj
MUX_OBJS = \
	$(OUT_DIR)\obj\mux\anim_encode.obj \
	$(OUT_DIR)\obj\mux\muxedit.obj \
	$(OUT_DIR)\obj\mux\muxinternal.obj \
	$(OUT_DIR)\obj\mux\muxread.obj
DEMUX_OBJS = \
	$(OUT_DIR)\obj\demux\anim_decode.obj \
	$(OUT_DIR)\obj\demux\demux.obj
EXTRAS_OBJS = \
	$(OUT_DIR)\obj\extras\extras.obj \
	$(OUT_DIR)\obj\extras\quality_estimate.obj \
	$(OUT_DIR)\obj\extras\sharpyuv_risk_table.obj
EX_UTIL_OBJS = \
	$(OUT_DIR)\obj\examples\example_util.obj
EX_GIF_DEC_OBJS = \
	$(OUT_DIR)\obj\examples\gifdec.obj
EX_ANIM_UTIL_OBJS = \
	$(OUT_DIR)\obj\examples\anim_util.obj
#-------------------------------------------------------------------------------
# スタティックリンクライブラリ *.LIB の依存関係の定義
#-------------------------------------------------------------------------------
$(OUT_DIR)\lib\libsharpyuv.lib: $(SHARPYUV_OBJS)
$(OUT_DIR)\lib\libwebpmux.lib: $(MUX_OBJS)
$(OUT_DIR)\lib\libwebpdemux.lib: $(DEMUX_OBJS)
$(OUT_DIR)\lib\libwebpdecoder.lib: \
	$(DEC_OBJS) $(DSP_DEC_OBJS) $(UTILS_DEC_OBJS)
$(OUT_DIR)\lib\libwebp.lib: \
	$(DEC_OBJS) $(DSP_DEC_OBJS) $(UTILS_ENC_OBJS) \
	$(ENC_OBJS) $(DSP_ENC_OBJS) $(UTILS_DEC_OBJS) \
	$(OUT_DIR)\lib\libsharpyuv.lib
#-------------------------------------------------------------------------------
# 実行ファイル *.EXE の依存関係の定義
#-------------------------------------------------------------------------------
$(OUT_DIR)\bin\cwebp.exe: $(OUT_DIR)\obj\examples\cwebp.obj \
	$(EX_UTIL_OBJS) \
	$(IMAGEIO_DEC_OBJS) $(IMAGEIO_UTIL_OBJS) \
	$(OUT_DIR)\lib\libwebpdemux.lib \
	$(OUT_DIR)\lib\libsharpyuv.lib \
	$(OUT_DIR)\lib\libwebp.lib
$(OUT_DIR)\bin\dwebp.exe: $(OUT_DIR)\obj\examples\dwebp.obj \
	$(EX_UTIL_OBJS) \
	$(IMAGEIO_DEC_OBJS) $(IMAGEIO_ENC_OBJS) $(IMAGEIO_UTIL_OBJS) \
	$(OUT_DIR)\lib\libwebpdemux.lib \
	$(OUT_DIR)\lib\libwebp.lib
$(OUT_DIR)\bin\vwebp.exe: $(OUT_DIR)\obj\examples\vwebp.obj \
	$(EX_UTIL_OBJS) \
	$(IMAGEIO_UTIL_OBJS) \
	$(OUT_DIR)\lib\libwebpdemux.lib \
	$(OUT_DIR)\lib\libwebp.lib
$(OUT_DIR)\bin\webpmux.exe: $(OUT_DIR)\obj\examples\webpmux.obj \
	$(EX_UTIL_OBJS) \
	$(IMAGEIO_UTIL_OBJS) \
	$(OUT_DIR)\lib\libwebpmux.lib \
	$(OUT_DIR)\lib\libwebp.lib
$(OUT_DIR)\bin\img2webp.exe: $(OUT_DIR)\obj\examples\img2webp.obj \
	$(EX_UTIL_OBJS) \
	$(IMAGEIO_DEC_OBJS) $(IMAGEIO_UTIL_OBJS) \
	$(OUT_DIR)\lib\libsharpyuv.lib \
	$(OUT_DIR)\lib\libwebp.lib \
	$(OUT_DIR)\lib\libwebpdemux.lib \
	$(OUT_DIR)\lib\libwebpmux.lib
$(OUT_DIR)\bin\get_disto.exe: $(OUT_DIR)\obj\extras\get_disto.obj \
	$(IMAGEIO_DEC_OBJS) $(IMAGEIO_UTIL_OBJS) \
	$(OUT_DIR)\lib\libwebpdemux.lib \
	$(OUT_DIR)\lib\libwebp.lib
$(OUT_DIR)\bin\webp_quality.exe: $(OUT_DIR)\obj\extras\webp_quality.obj \
	$(EXTRAS_OBJS) \
	$(IMAGEIO_UTIL_OBJS) \
	$(OUT_DIR)\lib\libwebp.lib
$(OUT_DIR)\bin\vwebp_sdl.exe: $(OUT_DIR)\obj\extras\vwebp_sdl.obj \
	$(OUT_DIR)\obj\extras\webp_to_sdl.obj \
	$(IMAGEIO_UTIL_OBJS) \
	$(OUT_DIR)\lib\libwebp.lib
$(OUT_DIR)\bin\webpinfo.exe: $(OUT_DIR)\obj\examples\webpinfo.obj \
	$(EX_UTIL_OBJS) \
	$(IMAGEIO_DEC_OBJS) $(IMAGEIO_UTIL_OBJS) \
	$(OUT_DIR)\lib\libwebpdemux.lib \
	$(OUT_DIR)\lib\libwebp.lib
$(OUT_DIR)\bin\gif2webp.exe: $(OUT_DIR)\obj\examples\gif2webp.obj \
	$(EX_UTIL_OBJS) $(EX_GIF_DEC_OBJS) \
	$(IMAGEIO_UTIL_OBJS) \
	$(OUT_DIR)\lib\libwebpmux.lib \
	$(OUT_DIR)\lib\libwebp.lib
$(OUT_DIR)\bin\anim_diff.exe: $(OUT_DIR)\obj\examples\anim_diff.obj \
	$(EX_UTIL_OBJS) $(EX_GIF_DEC_OBJS) $(EX_ANIM_UTIL_OBJS) \
	$(IMAGEIO_UTIL_OBJS) \
	$(OUT_DIR)\lib\libwebpdemux.lib \
	$(OUT_DIR)\lib\libwebp.lib
$(OUT_DIR)\bin\anim_dump.exe: $(OUT_DIR)\obj\examples\anim_dump.obj \
	$(EX_UTIL_OBJS) $(EX_GIF_DEC_OBJS) $(EX_ANIM_UTIL_OBJS) \
	$(IMAGEIO_ENC_OBJS) $(IMAGEIO_UTIL_OBJS) \
	$(OUT_DIR)\lib\libwebpdemux.lib \
	$(OUT_DIR)\lib\libwebp.lib
#-------------------------------------------------------------------------------
# 出力ディレクトリの生成
#-------------------------------------------------------------------------------
$(OUTPUT_DIRS):
	@if not exist $@ mkdir $@
#-------------------------------------------------------------------------------
# ライブラリ *.LIB の生成コマンド
#-------------------------------------------------------------------------------
$(OUT_DIR)\lib\libwebpdecoder.lib \
$(OUT_DIR)\lib\libsharpyuv.lib \
$(OUT_DIR)\lib\libwebp.lib \
$(OUT_DIR)\lib\libwebpdemux.lib \
$(OUT_DIR)\lib\libwebpmux.lib:
	$(LINKLIB) $(LLFLAGS) /out:$@ $**
#-------------------------------------------------------------------------------
# 実行ファイル *.EXE の生成コマンド
#-------------------------------------------------------------------------------
$(OUT_DIR)\bin\cwebp.exe \
$(OUT_DIR)\bin\dwebp.exe \
$(OUT_DIR)\bin\vwebp.exe \
$(OUT_DIR)\bin\webpmux.exe \
$(OUT_DIR)\bin\img2webp.exe \
$(OUT_DIR)\bin\get_disto.exe \
$(OUT_DIR)\bin\webp_quality.exe \
$(OUT_DIR)\bin\vwebp_sdl.exe \
$(OUT_DIR)\bin\webpinfo.exe \
$(OUT_DIR)\bin\gif2webp.exe \
$(OUT_DIR)\bin\anim_diff.exe \
$(OUT_DIR)\bin\anim_dump.exe:
	$(LINKEXE) $(LDFLAGS) /out:$@ $** $(WINLIBS)
#-------------------------------------------------------------------------------
# オブジェクト *.OBJ の生成コマンド
#-------------------------------------------------------------------------------
{examples}.c{$(OUT_DIR)\obj\examples}.obj::
	$(CC) $(CCFLAGS) /Fo$(OUT_DIR)\obj\examples\ $<
{extras}.c{$(OUT_DIR)\obj\extras}.obj::
	$(CC) $(CCFLAGS) /Fo$(OUT_DIR)\obj\extras\ $<
{imageio}.c{$(OUT_DIR)\obj\imageio}.obj::
	$(CC) $(CCFLAGS) /Fo$(OUT_DIR)\obj\imageio\ $<
{sharpyuv}.c{$(OUT_DIR)\obj\sharpyuv}.obj::
	$(CC) $(CCFLAGS) /Fo$(OUT_DIR)\obj\sharpyuv\ $<
{src\dec}.c{$(OUT_DIR)\obj\dec}.obj::
	$(CC) $(CCFLAGS) /Fo$(OUT_DIR)\obj\dec\ $<
{src\dsp}.c{$(OUT_DIR)\obj\dsp}.obj::
	$(CC) $(CCFLAGS) /Fo$(OUT_DIR)\obj\dsp\ $<
{src\enc}.c{$(OUT_DIR)\obj\enc}.obj::
	$(CC) $(CCFLAGS) /Fo$(OUT_DIR)\obj\enc\ $<
{src\mux}.c{$(OUT_DIR)\obj\mux}.obj::
	$(CC) $(CCFLAGS) /Fo$(OUT_DIR)\obj\mux\ $<
{src\demux}.c{$(OUT_DIR)\obj\demux}.obj::
	$(CC) $(CCFLAGS) /Fo$(OUT_DIR)\obj\demux\ $<
{src\utils}.c{$(OUT_DIR)\obj\utils}.obj::
	$(CC) $(CCFLAGS) /Fo$(OUT_DIR)\obj\utils\ $<
#-------------------------------------------------------------------------------
# 生成物のクリーンナップ
#-------------------------------------------------------------------------------
clean:
	@if exist $(OUT_DIR) rd /s /q $(OUT_DIR)
```

</details>

### メイクファイルの実行

Visual C++ の場合，下記のコマンドを実行する。`Makefile.vc2` はオリジナルの `Makefile.vc` と同じフォルダにあるものとする。

```:Visual C++ の場合
nmake -f Makefile.vc2
```

Clang の場合，下記のコマンドを実行する。`Makefile.clang` はオリジナルの `Makefile.vc` と同じフォルダにあるものとする。

```:Clang の場合
nmake -f Makefile.clang
```

こうして生成物は下記のフォルダに作られる。

<table>
<caption>表２　生成物のフォルダ</caption>
<thead>
<tr><th style="text-align:center">コンバイラ</th>
     <th style="text-align:center">ターゲット</th>
    <th style="text-align:center">フォルダ</th></tr>
</thead>
<tbody>
<tr></tr>
<tr><th rowspan=3>Visual C++</th>
    <th style="text-align:center">32bit</th>
    <td><code>output\release-static\x86vc\bin</code></td></tr>
<tr></tr>
<tr><th style="text-align:center">64bit</th>
    <td><code>output\release-static\x64vc\bin</code></td></tr>
<tr></tr>
<tr><th rowspan=3>Clang</th>
    <th style="text-align:center">32bit</th>
    <td><code>output\release-static\x86clang\bin</code></td></tr>
<tr></tr>
<tr><th style="text-align:center">64bit</th>
    <td><code>output\release-static\x64clang\bin</code></td></tr>
</tbody>
</table>

### バイナリサイズの比較

original とは[WebP のダウンロードリポジトリ](https://storage.googleapis.com/downloads.webmproject.org/releases/webp/index.html)からダウンロードしたものである。

<table>
<caption>表３　バイナリサイズの比較</caption>
<thead>
<tr><th style="text-align:center">コンパイラ</th>
    <th style="text-align:center">32bit版</th>
    <th style="text-align:center">64bit版</th></tr>
</thead>
<tbody>
<tr></tr>
<tr><th>original</th>
    <td style="text-align:center">なし</td>
    <td style="text-align:right">742,912 bytes</td></tr>
<tr></tr>
<tr><th>Visual C++</th>
    <td style="text-align:right">609,280 bytes</td>
    <td style="text-align:right">749,056 bytes</td>
<tr></tr>
<tr><th>Clang</th>
    <td style="text-align:right">817,152 bytes</td>
    <td style="text-align:right">866,816 bytes</td>
</tbody>
</table>

### バイナリの確認方法

作ったバイナリが32bit版 or 64bit版のいずれか確認する方法を示す。

```
c:\libwebp>dumpbin /headers output\release-static\x86vc\bin\cwebp.exe | findstr machine
             14C machine (x86)
                   32 bit word machine

c:\libwebp>dumpbin /headers output\release-static\x64vc\bin\cwebp.exe | findstr machine
            8664 machine (x64)

c:\libwebp>dumpbin /headers output\release-static\x86clang\bin\cwebp.exe | findstr machine
             14C machine (x86)
                   32 bit word machine

c:\libwebp>dumpbin /headers output\release-static\x64clang\bin\cwebp.exe | findstr machine
            8664 machine (x64)
```

# 6. パフォーマンス比較

題材は[前回の記事]()で用いたサンプル画像である。300dpiでスキャンしたカラー画像4枚，白黒画像36枚のビットマップファイル *.BMP を `cwebp.exe` を用いて可逆圧縮（lossless）モードかつ最高品質 `z=9` にて圧縮した際に要した計算時間の平均値を示す。original を基準100とした相対値で示す。

なお，今回はインテル第8，11，13世代のプロセッサで比較することができた。

```plantuml
@startuml
<style>
root {
  margin 0
  padding 0
}
title {
  fontStyle normal
  fontSize 16
  fontColor black
}
</style>
title
<img:https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3490655/ea860f60-c4f2-ac49-1e02-bc5117ce7b40.png>

図２　インテル第8世代プロセッサの場合
end title
@enduml
```

```plantuml
@startuml
<style>
root {
  margin 0
  padding 0
}
title {
  fontStyle normal
  fontSize 16
  fontColor black
}
</style>
title
<img:https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3490655/52725c5e-4d35-269d-54cc-ba8cb118d5b3.png>

図３　インテル第11世代プロセッサの場合
end title
@enduml
```

```plantuml
@startuml
<style>
root {
  margin 0
  padding 0
}
title {
  fontStyle normal
  fontSize 16
  fontColor black
}
</style>
title
<img:https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3490655/2fb70b9c-f319-11d3-8a99-aeb4b7318fec.png>

図４　インテル第13世代プロセッサの場合
end title
@enduml
```

ちなみに第8世代を 100 とすると，第11世代は 70～75，第13世代は 50～55 となる。

# 7. 結論

- コンパイラの 32bit版 or 64bit 版問題については明確な結論が出た。コンパイラを問わず，プロセッサの世代を問わず 64bit版のほうが明らかに高速である。google の公式サイトで64bit版しか提供しないのも当たり前であろう。

- コンパイルオプションの工夫により，同じ Visual C++ でも第8世代プロセッサでは original に対して 5% 程度の改善を得ることができたが，プロセッサの世代が新しくなるにつれて優位性が無くなり，第13世代では逆効果になってしまったのは悲しい。

- Clang は凄い。プロセッサの世代を問わず，最強である。ただし，プロセッサの世代が新しくなるにつれ，Clang の優位性が少しずつ薄れていくのは不思議である。Clang のバイナリサイズは増えていることから，Clang ではループアンローリングや関数のインライン展開などの最適化を積極的に行っていたと考えられるが，新世代のプロセッサではこれらのテクニックの効果が薄れているのだろう。

なお，オリジナルのメイクファイルだと `gif2webp.exe`, `anim_diff.exe`, `anim_dump.exe` のビルドに失敗してしまうので，この機にビルドできるよう修正した。ただし動作未検証である。

# 8. 参考文献

- [nmake リファレンス - Qiita](https://qiita.com/hana_moto/items/30ed1cf4340d416d9003)

- [Visual Studioでも最新のClangが使いたい！ - Qiita](https://qiita.com/kazatsuyu/items/b85e97e38a25bc302054)

- [Visual Studio C++ Build Tools + clang-cl + CMake + Ninja で C++ バッチビルドや VSCode 連携環境を整える - Qiita](https://qiita.com/syoyo/items/bd4f81e7803afb5a3d19)

- [msvc(cl.exe)と clang-cl の違いのメモ - Qiita](https://qiita.com/syoyo/items/140b6ba487b700b553cd)

- [(2019年版)コマンドラインからclを使ってコンパイルできるようにしたので共有する - Qiita](https://qiita.com/asana_yui/items/d545b5eccd994c0cdaab)

- [Clang with Microsoft CodeGenがでたので試す - Qiita](
https://qiita.com/yumetodo/items/bd41f31f39dd590e8c80)

- [Visual Studio 2019 上の clang-cl と ARM64 - Qiita](https://qiita.com/umezawatakeshi/items/f543ab51dfe484a9d037)

- [Windowsのclangで2通りのHello, World! - Qiita](https://qiita.com/HaruoWakakusa/items/6508f1c8c3c87c40ef62)