msys2でocamlのビルドをしようとしてautotoolsの前に完全敗北した話

# はじめに

WindowsにArch Linuxにも採用されているpacmanを用いてパッケージ管理を行っているmingw環境としてmsys2というのがある。

このパッケージはやはりArch Linuxと同じく`makepkg`でビルドするわけだが、そのためのPKGBUILDなどのファイル群が
https://github.com/msys2/MINGW-packages
で管理されている。

過去の私は何を思ったのかこのなかのocamlのパッケージを更新しようと試みていたようだ。しかし中途半端に終わり投げ出している。

今OCamlは4.10.0がリリースされているらしい。一方で依然としてmsys2のocamlパッケージはメンテ放棄されていて、4.04.0のままで時が止まっている。

しまいにはもうOCaml関係のパッケージ取り除こうぜっていう提案が投げつけられている
https://github.com/msys2/MINGW-packages/issues/6040

なんとかアップデートできないん？

# OCamlのビルド方法

そもそもOCamlをWindows環境でビルドするにはCygwinかCygwin環境のMingw、あるいはmsvcが必要らしい。msys2のことは考えられていない。

OCamlはautotoolsを使ってビルドすることになっている。autotoolsはLinuxで使うぶんには優れたツールだろうが、Windows環境で動かすにはあまりにも辛い。Cygwinとも大きく違うmsys2で動かすには何かしらのパッチを当てなければ動かないことは確実である。

そこで
https://github.com/msys2/MINGW-packages/tree/2cfdf054df2c826d7c61237ee5ac2453b0f3964d/mingw-w64-ocaml
にあるパッチをみつつ、手動でパッチを当てていくことにした。

## `/config/Makefile.mingw32`がないんですが？

環境ごとにMakefileを用意することそのものをやめたらしく、autotoolsを使うように切り替わっている。そのため機械的にパッチを当てることはできず、`configure.ac`の中で該当箇所を探して置き換えていくことになる

## Unicode対応のためにパッチに変更が必要なもの

どうもWindows環境でもUnicodeをまともに扱うために、`wchar_t`系APIを叩いてそれをUTF-8に変換するような扱い方をするようになったらしい。

# パッチを当てたもの

https://bitbucket.org/yumetodo/ocaml-4.10-for-msys2/src/master/

まあとにかくパッチを当ててみた。

# が、だめ

```
$make VERBOSE=1
make coldstart
make[1]: ディレクトリ '/c/Users/yumetodo/Downloads/ocaml-4.10.0.tar/ocaml-4.10.0' に入ります
make -C runtime  all
make[2]: ディレクトリ '/c/Users/yumetodo/Downloads/ocaml-4.10.0.tar/ocaml-4.10.0/runtime' に入ります
echo "-O -mms-bitfields -Wno-unused -Wall -fno-tree-vrp -g -DCAML_NAME_SPACE -DUNICODE -D_UNICODE -DWINDOWS_UNICODE=1 -I"/lib/flexdll""
-O -mms-bitfields -Wno-unused -Wall -fno-tree-vrp -g -DCAML_NAME_SPACE -DUNICODE -D_UNICODE -DWINDOWS_UNICODE=1 -I/lib/flexdll
gcc -c -O -mms-bitfields -Wno-unused -Wall -fno-tree-vrp -g -DCAML_NAME_SPACE -DUNICODE -D_UNICODE -DWINDOWS_UNICODE=1 -I"/lib/flexdll" -o win32_b.o win32.c
win32.c:52:10: fatal error: flexdll.h: No such file or directory
   52 | #include <flexdll.h>
      |          ^~~~~~~~~~~
compilation terminated.
make[2]: *** [Makefile:343: win32_b.o] エラー 1
make[2]: ディレクトリ '/c/Users/yumetodo/Downloads/ocaml-4.10.0.tar/ocaml-4.10.0/runtime' から出ます
make[1]: *** [Makefile:347: coldstart] エラー 2
make[1]: ディレクトリ '/c/Users/yumetodo/Downloads/ocaml-4.10.0.tar/ocaml-4.10.0' から出ます
make: *** [Makefile:476: world.opt] エラー 2
```

どういうわけか`-I"/lib/flexdll"`になってしまうがために、flexdllを見つけられない。

これには心当たりがある。実は次のようなパッチを当てている。

```patch:configure.ac
diff --git a/configure.ac b/configure.ac
index e3e28fb..9c6f51d 100644
--- a/configure.ac
+++ b/configure.ac
@@ -627,7 +627,7 @@ AS_CASE([$CC,$host],
     common_cppflags="$common_cppflags -U_WIN32"
     AS_IF([$with_sharedlibs],
       [flexlink="flexlink -chain $flavor -merge-manifest -stack 16777216"
-      flexdir=`$flexlink -where | tr -d '\015'`
+      flexdir="$(prefix)/lib/flexdll"
       AS_IF([test -z "$flexdir"],
         [AC_MSG_WARN(
           [flexlink not found: native shared libraries won't be available.]
@@ -639,7 +639,7 @@ AS_CASE([$CC,$host],
       )]
     )
     AS_IF([! $with_sharedlibs],
-      [mkexe="$mkexe -Wl,--stack,16777216"
+      [mkexe="$mkexe -L$(shell cygpath -m /mingw32/i686-w64-mingw32/lib) -Wl,--stack,16777216"
       oc_ldflags="-Wl,--stack,16777216"]
     )
     ostype="Cygwin"],
@@ -649,7 +649,6 @@ AS_CASE([$CC,$host],
         [i686-*-*], [flexdll_chain="mingw"],
         [x86_64-*-*], [flexdll_chain="mingw64"])
       flexlink="flexlink -chain $flexdll_chain -merge-manifest -stack 16777216"
-      flexdir=`$flexlink -where | tr -d '\015'`
       AS_IF([test -z "$flexdir"], [flexdir='$(ROOTDIR)/flexdll'])
       iflexdir="-I\"$flexdir\""
       mkexedebugflag="-link -g"])
```

つまり何らかの理由で`prefix`という変数が展開されていないのではないか、そう考えた。

## Debug printを仕込めない・・・だと!?

こうなると誰でも思いつくのがとりあえずprintfデバッグしよう、ということだ。怪しそうなところに片っ端から

```
AC_MSG_NOTICE(["line: 652, prefix=$(prefix)"])
```

のようなものを仕込んでいった。しかし結果はいかのような散々なものだった。

```
︙
./configure: line 12566: prefix: command not found
./configure: line 12567: prefix: command not found
configure: "line: 652, prefix="
︙
./configure: line 16762: prefix: command not found
./configure: line 16764: prefix: command not found
configure: "line: 1763; then :
  prefix="
./configure: line 16832: prefix: command not found
./configure: line 16833: prefix: command not found
configure: "line: 1806, prefix="
︙
```

`; then :`ってどっから来たし。`command not found`ってどういうこと？

まあまて、落ち着くんだ。そもそもこれは`./configure`を吐き出しているんだからそっちを直接書き換えて・・・

```diff
diff --git a/configure b/configure
index 28ac47d..4f8603f 100644
--- a/configure
+++ b/configure
@@ -16758,13 +16758,10 @@ if test x"$libdir" = x'${exec_prefix}/lib'; then :
 fi

 if test x"$mandir" = x'${datarootdir}/man'; then :
-  { $as_echo "$as_me:${as_lineno-$LINENO}: \"line: 1763
-elif prefix=$(prefix)\"" >&5
-$as_echo "$as_me: \"line: 1763; then :
-  prefix=$(prefix)\"" >&6;}
 else
   mandir='${prefix}/man'
 fi
+echo 'line: 1763 prefix=$(prefix)'

 case $host in #(
   *-*-mingw32|*-pc-windows) :
```

結果は

```
line: 1763 prefix=$(prefix)
```

あっ

> https://mastodon.cardina1.red/@lo48576/104116608117787838
>
> @yumetodo そういえば configure (という名のシェルスクリプト) が吐く Makefile 内で効果を発揮すべき変数であれば、 configure 内ではエスケープされた状態になってたりするわけですね……つらそう

もうautotoolsなんか投げ捨ててCMake書いたほうが速いまであるきがしてきたけど、どう考えてもそんなモチベはないので、この記事を書いて終わることにします。