自炊の画像形式をPNGからWebPに移行する３～WebPユーティリティを最強Intel C++コンパイラでビルドする

# 0. はじめに

かつて業界最強とも呼ばれた Intel C++ コンパイラがいつの間にか無償で提供されるようになっていた。正しくは Intel oneAPI と呼ばれる CPU や GPU，そして FPGA までを対象に含めた統合開発環境が無償で提供されるようになったというのだ。ただしサポートは有償である。

[前回の記事](https://qiita.com/TETSURO1999/items/239a359f337b2211ac04)では，WebP ユーティリティを評判の高い Clang を用いてビルドしてみたが，今回は業界最強と呼ばれる Intel C++ コンパイラを試してみたい。

# 1. Intel oneAPI ツールキットの入手

Intel 公式のページ [Free Intel® Software Development Tools](https://www.intel.com/content/www/us/en/developer/articles/news/free-intel-software-developer-tools.html) からダウンロードできる。このうち Intel C++ コンパイラのみを使用するのであれば Intel® oneAPI Base Toolkit のみをダウンロードすればよい。ちなみに Visual Studio 2022（もしくは 2019）を事前にインストールしておいたほうが良いだろう。

なお，この記事を書いているときのバージョンは <b>oneAPI 2024.2, Compiler Release 2024.2.1</b> である。

# 2. コマンドライン開発環境の設定

Intel oneAPI をインストールすると，スタートメニューに

- Intel oneAPI command prompt for IA32 for Visual Studio 2022
- Intel oneAPI command prompt for Intel 64 for Visual Studio 2022

というショートカットが作られるので，ターゲットに応じて選択する。

# 3. コンパイラオプション

オプションの違いをまとめると以下のようになる。※<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>
    <th style="text-align:center">Intel C++</th></tr>
</thead>
<tbody>
<tr><td>コンパイラ</td>
    <td>CC</td>
    <td>cl.exe</td>
    <td>clang-cl.exe</td>
    <td>icx-cl.exe</td></tr>
<tr><td>コンパイラ<br>オプション</td>
    <td>CCFLAGS</td>
    <td>/O2 /GL</td>
    <td>/O2 -flto</td>
    <td>/O3 -flto</td></tr>
<tr><td>ライブラリアン</td>
    <td>LINKLIB</td>
    <td>lib.exe</td>
    <td>llvm-lib.exe</td>
    <td>llvm-lib.exe</td></tr>
<tr><td>ライブラリアン<br>オプション</td>
    <td>LLFLAGS</td>
    <td>/LTCG</td>
    <td></td>
    <td></td></tr>
<tr><td>リンカ</td>
    <td>LINKEXE</td>
    <td>link.exe</td>
    <td>lld-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>
    <td><font color=red><b>/SAFESEH</b></font></td></tr>
</tbody>
</table>

ちなみにリンク時最適化オプション `-flto` を用いなければ Visual C++ の `lib.exe` および `link.exe` を使用できる。しかし，オプション `-flto` を用いると専用の `llvm-lib.exe` および `lld-link.exe` を使用する必要がある。Intel onAPI ツールキットに含まれる `xilib.exe` や `xilink.exe` でもダメなのは，それらが単に内部で `lib.exe` や `link.exe` を呼び出しているに過ぎないからだ。

`llvm-lib.exe` および `lld-link.exe` は Clang ツールのものではなく，Intel oneAPI ツールキット専用のものを使う必要があるが，名前が衝突してしまうので Intel oneAPI ツールキット専用のほうにはパスが通っていない。このため絶対パス指定で呼び出す必要がある。ちなみに `llvm.exe` と `lld-link.exe` が置かれているフォルダ(*)にある `README.txt` には下記のコメントがある。

(*) デフォルトは `C:\Program Files (x86)\Intel\oneAPI\compiler\latest\bin\compiler\`

> These binaries are not placed in PATH during environment setup in order to reduce collisions with other toolchains.
>
> This is a departure from OneAPI Compiler Releases before 2022.0 (December 2021), where these tools were in PATH. There may be cases where the tools which are no longer in PATH were being invoked directly in some application Makefile (or CMake configuration) and ...

Intel oneAPI の昔のリリースではパスの中に入っていたが，他のツールチェーン（おそらく Clang のこと）との衝突を防ぐためにパスから外したとのこと。しかし，必要であれば直接呼び出しても良いようだ。

# 4. メイクファイル

Intel C++ コンパイラ固有部を以下に示す。最適化オプションは `/O3` とした。前項で述べたようにライブラリアンとリンカは絶対パス指定で呼び出す。

```:Makefile.intel
#-------------------------------------------------------------------------------
# Makefile for Intel C++, release build, static link
#-------------------------------------------------------------------------------
CC      = icx-cl.exe
LINKLIB = "C:\Program Files (x86)\Intel\oneAPI\compiler\latest\bin\compiler\llvm-lib.exe"
LINKEXE = "C:\Program Files (x86)\Intel\oneAPI\compiler\latest\bin\compiler\lld-link.exe"
CCFLAGS = /nologo /c /O3 /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) /GS- /arch:AVX2 -flto
LLFLAGS = /nologo
LDFLAGS = /nologo /LARGEADDRESSAWARE /MANIFEST:EMBED /NXCOMPAT /DYNAMICBASE
!IF "$(VS_TARGET_ARCH)" == "x86"
LDFLAGS = $(LDFLAGS) /SAFESEH
!ENDIF
WINLIBS = ole32.lib windowscodecs.lib shlwapi.lib
!IFDEF VS_TARGET_ARCH
OUT_DIR = output\release-static\$(VS_TARGET_ARCH)intel
!ELSE
!ERROR 環境変数 VS_TARGET_ARCH が未定義です。
!ENDIF
#-------------------------------------------------------------------------------
!INCLUDE Makefile.inc
```

共通部は長いので以下参照されたい。

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

```:Makefile.inc
#-------------------------------------------------------------------------------
# このファイルは下記のメイクファイルでインクルードして使用します。
# Makefile.vc2   ... x86/x64, cl.exe
# Makefile.clang ... x86/x64, clang-cl.exe
# Makefile.intel ... x86/x64, icx-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>

メイクファイルの実行は 32bit or 64bit いずれかの開発環境で下記のコマンドを実行するだけだ。

```:ビルド手順
nmake -f Makefile.intel
```

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

<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>
<tr></tr>
<tr><th rowspan=3>Intel C++</th>
    <th style="text-align:center">32bit</th>
    <td><code>output\release-static\x86intel\bin</code></td></tr>
<tr></tr>
<tr><th style="text-align:center">64bit</th>
    <td><code>output\release-static\x64intel\bin</code></td></tr>
</tbody>
</table>

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

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>
<tr></tr>
<tr><th>Intel C++</th>
    <td style="text-align:right">814,592 bytes</td>
    <td style="text-align:right">866,816 bytes</td>
</tbody>
</table>

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

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

なお，今回もインテル第8，11，13世代のプロセッサで比較した。

```plantuml
@startuml
<style>
root {
  padding 0
  margin 0
}
title {
  fontSize 17
  fontColor black
}
</style>
title
<img:https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3490655/27deba78-5310-ce7e-0ef9-a4ad91986890.png>

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

```plantuml
@startuml
<style>
root {
  padding 0
  margin 0
}
title {
  fontSize 17
  fontColor black
}
</style>
title
<img:https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3490655/8160064e-c062-a6f6-9e19-91d6fad06229.png>

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

```plantuml
@startuml
<style>
root {
  padding 0
  margin 0
}
title {
  fontSize 17
  fontColor black
}
</style>
title
<img:https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3490655/f5e95dc4-321f-33fd-73ea-7760aadc23c3.png>

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

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

# 7. まとめ

- やはり Intel C++ コンパイラは最強である。
 
- ただし，プロセッサの世代が新しくなるにつれて Intel C++ コンパイラの優位性が徐々に小さくなっていくのが悲しいところである。

- 最大の課題は Intel C++ コンパイラは機能・オプションが多過ぎて＊正直＊使いこなすのが難しいことだろうか。

# 8. 参考文献

- [intel oneAPI Base Toolkit + HPC Toolkit (Intel Fortran)のインストール（Windows版）- Qiita](https://qiita.com/implicit_none/items/620b440ba6d6167a1b73)

- [intel_software:oneapi:インストール [雑多な記録] - 京都大学](https://www2.yukawa.kyoto-u.ac.jp/~koudai.sugimoto/dokuwiki/doku.php?id=intel_software:oneapi:インストール)

- [Intel one API (icx/icpx) 時代の makefile - Zenn](https://zenn.dev/satoeu/articles/ddc67cc9fbd6fe)

- [Intel コンパイラ 利用の手引き - 東京工業大学](https://www.t4.gsic.titech.ac.jp/docs/intel_compiler/usage/)

- [インテル® oneAPI プログラミング・ガイド - intel <img width=16 src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3490655/66e66c9d-a6f3-f215-951a-9d79cc94a9d6.png">](https://hpc-event.jp/hpsc2023/doc/oneapi/programming-guide.pdf)
- [インテル oneAPI ポーティング・ガイド DPCPP または ICX へ移行する ICC ユーザー向け - iSUS <img width=16 src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3490655/66e66c9d-a6f3-f215-951a-9d79cc94a9d6.png">](https://www.isus.jp/wp-content/uploads/pdf/oneapi-porting-guide_JA.pdf)
- [Intel oneAPIを入れるとClangが死ぬかもしれない - Zenn](https://zenn.dev/hishinuma_t/articles/intel-oneapi_clang)

- [エクセルソフト株式会社「インテルコンパイラー概要」- 理化学研究所 <img width=16 src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3490655/66e66c9d-a6f3-f215-951a-9d79cc94a9d6.png">](https://i.riken.jp/download/IntelCompiler2020.pdf)