MSYS2 にある複数環境、C++ アプリ開発

## MSYS2 の構成が大きく変更

最近（最近でもないか・・）、[MSYS2](https://www.msys2.org/) の構成が大きく変更になり、昔の環境と大きく様変わりしています。

自分は、主に MSYS2 の下で clang や gcc コンパイラを使って、OpenGL、GLFW、などを利用したアプリを実装していました。

最近、RXマイコン関係の作業を継続して行っていて PC 環境用アプリを触らない状況が長く続いていました。

そんな折 PC 環境用アプリを作ろうと思い、そーいえば、MSYS2 のアップデートをしてないなぁーと思い、MSYS2 の環境整備から始めました。

ところが、MSYS2 のアップデートが上手く出来ないのです・・・

どうやら、システムが大きく変更になり、昔の環境は廃止になったようで、コンフリクトを起こしているようです。

そこで、MSYS2 の古い環境を一応保持して、新規に MSYS2 をインストールして、最初から環境を作り直す事にしました。

**MSYS2 の本体は、C:/msys64 なので、それを単純に、リネームして残してあります。**

---

## 新しい MSYS2 には、複数のショートカットが増えている。 

![msys2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58667/f7b63a08-9dd2-76dd-1135-d509f116e1dc.png)

新規に、「MSYS2 CLANG64」、「MSYS2 UCRT64」が増えています。
※ショートカットには無いですが、実際には「CLANG32」もあります。

今まで、「clang」は、「MINGW64」と同居していましたが、分離したようです。
「UCRT64」は何でしょうか？

ここで、MSYS2 の解説を観に行きました。

### Overview
|Name|Prefix|Toolchain|Architecture|C Library|C++ Library|
|---|---|---|:-:|---|---|
|MSYS|/usr|gcc|x86_64|cygwin|libstdc++|
|UCRT64|/ucrt64|gcc|x86_64|ucrt|libstdc++|
|CLANG64|/clang64|llvm|x86_64|ucrt|libc++|
|CLANGARM64|/clangarm64|llvm|aarch64|ucrt|libc++|
|CLANG32|/clang32|llvm|i686|ucrt|libc++|
|MINGW64|/mingw64|gcc|x86_64|msvcrt|libstdc++|
|MINGW32|/mingw32|gcc|i686|msvcrt|libstdc++|

どうやら上記のような違いがあるようです。

MSYS2 のパッケージは一般的な Linux ディストリビューションのパッケージのように動作します。
それに加えて、Windows 依存のツールキットライブラリで API を叩く事が出来るので、プログラミングの幅が広がります。

自分は、この環境が非常に心地よく、色々な事をやるのに便利なので長らく使い続けています。
良く、C++ なら VisualStudio を使えば良いのにと言われる事がありますが、オープンソースのコードをコンパイルして組み込むのに適しているし。
Linux や Mac 環境にも親和性が高いので、当分この環境を離れられません。

---

## CLANG64 環境に色々パッケージをインストール

MSYS2 のパッケージマネージャーは、「Arch Linux」で知られる「pacman」が使われています。
最近の実装では、マルチスレッドで複数パッケージをインストールするなど、かなり便利に使えるようになっています。

### キーワードでパッケージを探す：
```bash
% pacman -Ss xxxxx
```

### パッケージのインストール：
```bash
% pacman -S xxxxx
```

---

CLANG64 環境のパッケージをインストール：
pacman は、どの環境で動かしても、良く、各環境毎にプレフィックスを追加するだけです。

たとえば、libpng は、環境毎に以下のような名称になっています。
```bash
 % pacman -Ss libpng
clangarm64/mingw-w64-clang-aarch64-libpng 1.6.39-1
    A collection of routines used to create PNG format graphics (mingw-w64)
mingw32/mingw-w64-i686-libpng 1.6.39-1
    A collection of routines used to create PNG format graphics (mingw-w64)
mingw64/mingw-w64-x86_64-libpng 1.6.39-1 [インストール済み: 1.6.38-1]
    A collection of routines used to create PNG format graphics (mingw-w64)
ucrt64/mingw-w64-ucrt-x86_64-libpng 1.6.39-1 [インストール済み: 1.6.38-1]
    A collection of routines used to create PNG format graphics (mingw-w64)
clang32/mingw-w64-clang-i686-libpng 1.6.39-1
    A collection of routines used to create PNG format graphics (mingw-w64)
clang64/mingw-w64-clang-x86_64-libpng 1.6.39-1 [インストール済み: 1.6.38-1]
    A collection of routines used to create PNG format graphics (mingw-w64)
```

CLANG64 用パッケージは「mingw-w64-clang-x86_64-libpng」となります。

---

## 俺俺アプリケーションのビルド

自分のアプリケーションビルドに必要な各種パッケージをインストールします。

```bash
   pacman -S mingw-w64-clang-x86_64-clang
   pacman -S mingw-w64-clang-x86_64-boost
   pacman -S mingw-w64-clang-x86_64-glfw
   pacman -S mingw-w64-clang-x86_64-freetype
   pacman -S mingw-w64-clang-x86_64-glew
   pacman -S mingw-w64-clang-x86_64-libjpeg-turbo
   pacman -S mingw-w64-clang-x86_64-openjpeg2
   pacman -S mingw-w64-clang-x86_64-libpng
   pacman -S mingw-w64-clang-x86_64-faad2
   pacman -S mingw-w64-clang-x86_64-libmad
   pacman -S mingw-w64-clang-x86_64-ffmpeg
```

次に、自分のアプリをビルドしようとしますが、意味不明のエラーで先に進みません・・・

```bash
In file included from C:/msys64/clang64/include/c++/v1/__type_traits/apply_cv.h:16:
In file included from C:/msys64/clang64/include/c++/v1/__type_traits/remove_reference.h:13:
C:/msys64/clang64/include/c++/v1/cstddef:50:9: error: no member named 'nullptr_t' in the global namespace
using ::nullptr_t;
      ~~^
In file included from main.cpp:7:
```

これは、単に、Makefile で与えているインクルードパスが余計な為でした・・・

```bash
clang++ -c -O2 -std=c++17 -DWIN32 -DBOOST_USE_WINDOWS_H -DHAVE_STDINT_H -DNDEBUG -isystem /clang64/include -isystem /clang64/include/freetype2 -isystem /clang64/include/openjpeg-2.5 -isystem /clang64/include/openjpeg-1.5  -I. -I../common -Wall -Werror -Wno-unused-private-field -Wno-unused-variable -Wno-unused-function -Wno-unused-but-set-variable -o release/main.o main.cpp
```

※「-isystem /clang64/include」が不必要
clang コンパイラは、起動すると、自身の環境に適した順序で、標準的なインクルードパスを内部で設定します。
この仕組みは結構複雑で、このような指定は、それを阻害するようです。
取り除いたら、素直にコンパイル出来ました。
以前の、mingw64 の時は、この指定が無いと、逆に正しくコンパイル出来なかった覚えがあります。

「freetype」や「openjpeg」では、ルートのディレクトリーを追加で指定する必要があるので、以下のように「Makefile」に記述しています。

```Makefile
LOCAL_INC_PATH := /clang64/include

INC_SYS		=	$(LOCAL_INC_PATH)/freetype2 $(OPENJPEG_PATH) \
				$(INC_USR)
```

openjpeg はバージョンがあるので、簡易的に、バージョン番号を取り込むようにしています。
```Makefile
OPENJPEG_PATH := $(shell ls -r -d $(LOCAL_INC_PATH)/openjpeg*)
```

これらは CMake などを使うと、もっとスマートに出来るものと思いますが、自分のアプリ環境はそこまで複雑では無いので、Makefileだけで何とかしています。

この Makefile には、従属規則の生成も自動化してあります。
※タイムスタンプを評価してコンパイルを自動化する。

ちなみに、Makefile には、マルチプラットホーム環境に対応したスクリプトを入れてあります。
```Makefile
# platform switcher (Windows, Linux, OS-X)
ifeq ($(OS),Windows_NT)
    FEXT	= .exe
    SYSTEM := WIN
	CPP_VER := -std=c++17
    LOCAL_INC_PATH := /clang64/include
    LOCAL_LIB_PATH :=
	OPTLIBS = opengl32 glu32 glew32 openal glfw3 \
			  comdlg32 hid setupapi ksguid
	CPMM	=	g++
	CCMM	=	gcc
	CFLAGS  += -DWIN32
	PFLAGS  += -DWIN32 -DBOOST_USE_WINDOWS_H
	LFLAGS	+=
else
  FEXT	=
  UNAME := $(shell uname -s)
  ifeq ($(UNAME),Linux)
    SYSTEM := LINUX
	CPP_VER := -std=c++17
	CFLAGS +=
	PFLAGS +=
	LFLAGS +=
  endif
  ifeq ($(UNAME),Darwin)
    SYSTEM := OSX
	OSX_VER := $(shell sw_vers -productVersion | sed 's/^\([0-9]*.[0-9]*\).[0-9]*/\1/')
	CPP_VER := -std=c++17
	CFLAGS +=
	PFLAGS +=
	LFLAGS += -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk \
		-Wl,-search_paths_first -Wl,-headerpad_max_install_names \
		-framework AGL -framework Cocoa -framework OpenGL -framework IOKit \
		-framework CoreFoundation -framework CoreVideo -framework OpenAL
    LOCAL_INC_PATH := /opt/local/include
    LOCAL_LIB_PATH := /opt/local/lib
    OPTLIBS = glfw GLEW
  else
    LOCAL_INC_PATH := /usr/local/include
    LOCAL_LIB_PATH := /usr/local/lib
  endif
  CPMM	=	clang++
  CCMM	=	clang
endif
```

---

## mintty の設定

最近の MSYS2 コンソールは、mintty が標準になっています。

ただ、何もしないと、多少見ずらいので、自分は以下の設定を、ホームディレクトリ以下に「.minttyrc」でセーブしてあります。

```
# mintty Settings
BoldAsFont=no
FontHeight=11

Columns=110
Rows=40
Locale=ja_JP
Charset=UTF-8
Term=xterm-256color

CopyOnSelect=yes
BackspaceSendsBS=yes

IMECursorColour=255,0,0
```

---

## VSCode を使う

テキストエディタは、emacs を昔から使ってきました。
今でも使いますが、最近では、VSCode を使っています。
※emacsのキーバインドがあるのが大きいです。

MSYS2 環境で clang を使う場合、「c_cpp_properties.json」に設定を追加します。
※ネットで拾った記述に自分用の物を追加しています。
インテリセンスを正しく動作させるには、パスが重要なのですが、良く判っていません・・
```
{
    "configurations": [
        {
            "name": "Win32",
            "includePath": [
                "${workspaceRoot}",
                "C:/msys64/clang64/include",
                "C:/msys64/clang64/include/**",
                "C:/msys64/clang64",
                "C:/msys64/clang64/include/c++/v1",
                "C:/msys64/clang64/lib/clang/15.0.4/include",
                "C:/msys64/clang64/lib/clang/15.0.4/include/**",
                "${workspaceFolder}/**",
                "C:/msys64/clang64/bin",
                "C:/msys64",
                "D:/Git/glfw_app/glfw_app/common"
            ],
            "defines": [
                "_DEBUG",
                "UNICODE",
                "_UNICODE"
            ],
            "windowsSdkVersion": "10.0.19041.0",
            "compilerPath": "C:/msys64/clang64/bin/clang++.exe",
            "cStandard": "c17",
            "cppStandard": "c++17",
            "intelliSenseMode": "clang-x64",
            "browse": {
                "path": [
                    "C:/msys64/clang64/include",
                    "C:/msys64/clang64/include/**",
                    "C:/msys64/clang64/include/c++/v1",
                    "C:/msys64/clang64/lib/clang/15.0.4/include",
                    "C:/msys64/clang64/lib/clang/15.0.4/include/**",
                    "${workspaceRoot}",
                    "C:/msys64/clang64/bin",
                    "C:/msys64",
                    "D:/Git/glfw_app/glfw_app/common"
                ],"limitSymbolsToIncludedHeaders": true,
                "databaseFilename": ""
            }
        }
    ],
    "version": 4
}
```

---

## GLFW OpenAL などを使ったアプリ開発

GLFW、OpenAL などを使う事で、マルチプラットホームで、2D/3Dグラフィックス、オーディオを使ったアプリを開発出来ます。
まぁ、そのようなフレームワークは、沢山ありますが、自分は、初期の頃から、自分用フレームワークを構築していて、小回りが利き自分には使いやすいです。

全ソースコードは [github](https://github.com/hirakuni45/glfw3_app) に上げてあり、MIT ライセンスで公開してあります。

元々、GLFW が出る以前に OpenGL,OpenAL のみを使って実装していたので、「gl_fw」と言うネーミングになっています。（現在は、glfw3_app）

中途な物や、実験的な物など色々ありますが、参考として、MMD のファイルをプレビューする為に作った物のスクリーンショットを載せておきます。
※MMDのファイルを読んで、レンダリングするだけの物で、アニメーションとかは実装中です・・・

![pmdv.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58667/9764b28f-25bd-8d51-185e-12b2dabd99e3.png)

機能的に、イマイチな部分もありますが、GUI など、何かアプリを作る場合に必要な機能は、大体あります。

このフレームワークの特殊性として、描画は全て OpenGL によって行っており、リアルタイムで表示しています。
最近のマシンは、描画性能が極めて高いので、リッチな物でもビクともしません。
漢字や日本語も、freetype でビットマップを生成して、それをテクスチャに登録して管理しています。
このような特異な手法は、ゲームのような場面に向いていて、ダブルバッファで描画するので応答が良く、リアルタイムに何か操作するような用途に向いていると思います。