0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

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

Last updated at Posted at 2024-11-24

0. はじめに

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

今さら森博嗣「笑わない数学者」のビリヤードの問題を解く(2)~計算機を使う - Qiita

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

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

Windows 用のバイナリはWebP のダウンロードリポジトリからダウンロードできる。この記事を書いている現時点では libwebp-1.4.0-windows-x64.zip が最新版である。残念ながら 64bit 版しか提供されていないので,32bit 版が必要な人は自分でソースコードを入手してビルドする必要がある。

2. ソースコードの入手

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

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

3. Visual Studio のインストール

マイクロソフトの公式サイトより,Visual Studio 2022 Community Edition をインストールする。評判の高い Clang コンパイラも併せてインストールする。なお,Clang は LLVM の公式サイトからダウンロードする手もあるが,Visual Studio との相性を鑑みて Visual Studio Installer からインストールした。

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

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

ショートカット名  ホスト  ターゲット
x64 Native Tools Command Prompt for VS 2022 x64 (64bit)
x64_x86 Cross Tools Command Prompt for VS 2022 x64 (64bit) x86 (32bit)
x86 Native Tools Command Prompt for VS 2022 x86 (32bit)
x86_x64 Cross Tools Command Prompt for VS 2022 x86 (32bit) x64 (64bit)

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

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

オプションの違いをまとめると以下のようになる。※赤字は32bit版のみ有効

表1 コンパイラオプションの違い
項目 変数 Visual C++ Clang
コンパイラ CC cl.exe clang-cl.exe
コンパイラ
オプション
CCFLAGS /GL -flto
ライブラリアン LINKLIB lib.exe llvm-lib.exe
ライブラリアン
オプション
LLFLAGS /LTCG
リンカ LINKEXE link.exe lld-link.exe
リンカ
オプション
LDFLAGS /LTCG /SAFESEH /SAFESEH

メイクファイル共通部

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

Makefile.inc(共通部)はコチラ
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)

メイクファイルの実行

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

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

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

Clang の場合
nmake -f Makefile.clang

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

表2 生成物のフォルダ
コンバイラ ターゲット フォルダ
Visual C++ 32bit output\release-static\x86vc\bin
64bit output\release-static\x64vc\bin
Clang 32bit output\release-static\x86clang\bin
64bit output\release-static\x64clang\bin

バイナリサイズの比較

original とはWebP のダウンロードリポジトリからダウンロードしたものである。

表3 バイナリサイズの比較
コンパイラ 32bit版 64bit版
original なし 742,912 bytes
Visual C++ 609,280 bytes 749,056 bytes
Clang 817,152 bytes 866,816 bytes

バイナリの確認方法

作ったバイナリが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世代のプロセッサで比較することができた。

ちなみに第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. 参考文献

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?