PIB - 20201127: Cygwin - g++ で kill() が呼べない

状況

以下のような tweet を見かけた。

多分、 なんだけど、
$ cd /tmp
$ git clone https://github.com/takashi-chikayama/SamurAI-Dig-Here-2020-21
Cloning into 'SamurAI-Dig-Here-2020-21'...
remote: Enumerating objects: 419, done.
remote: Counting objects: 100% (419/419), done.
remote: Compressing objects: 100% (380/380), done.
remote: Total 419 (delta 68), reused 389 (delta 38), pack-reused 0
Receiving objects: 100% (419/419), 11.74 MiB | 1.52 MiB/s, done.
Resolving deltas: 100% (68/68), done.
$ cd SamurAI-Dig-Here-2020-21/
$ git log -1
commit 3825c3dd0e2a31355d0ddafe320a9acf2316ec20 (HEAD -> master, origin/master, origin/HEAD)
Author: Takashi <takashi.cikayama@gmail.com>
Date:   Fri Nov 27 16:16:41 2020 +0900

    Fixed the problem of exportation in dighere.html page
$ make
cd manager; make all
make[1]: ディレクトリ '/tmp/SamurAI-Dig-Here-2020-21/manager' に入ります
c++ -c -g -Wall -std=c++14 main.cc -o main.o
c++ -MM -g -Wall -std=c++14 main.cc > main.d
c++ -c -g -Wall -std=c++14 field.cc -o field.o
c++ -MM -g -Wall -std=c++14 field.cc > field.d
c++ -c -g -Wall -std=c++14 gamelog.cc -o gamelog.o
c++ -MM -g -Wall -std=c++14 gamelog.cc > gamelog.d
c++ -c -g -Wall -std=c++14 playgame.cc -o playgame.o
playgame.cc: 関数 ‘void killPlayerProcess(int)’ 内:
playgame.cc:30:3: エラー: ‘kill’ was not declared in this scope
   30 |   kill(playerIds[p], SIGKILL);
      |   ^~~~
playgame.cc: 関数 ‘std::vector<StepLog> playGame(const Configuration&, char**, char*, int)’ 内:
playgame.cc:136:39: エラー: ‘fdopen’ was not declared in this scope; did you mean ‘fopen’?
  136 |     close(pipeOut[0]); toPlayers[p] = fdopen(pipeOut[1], "w");
      |                                       ^~~~~~
      |                                       fopen
playgame.cc:138:5: エラー: ‘kill’ was not declared in this scope
  138 |     kill(playerIds[p], SIGSTOP);
      |     ^~~~
playgame.cc:181:7: エラー: ‘kill’ was not declared in this scope
  181 |       kill(playerIds[p], SIGCONT);
      |       ^~~~
playgame.cc:194:2: エラー: ‘usleep’ was not declared in this scope; did you mean ‘sleep’?
  194 |  usleep(1000*checkInterval);
      |  ^~~~~~
      |  sleep
make[1]: *** [Makefile:14: playgame.o] エラー 1
make[1]: ディレクトリ '/tmp/SamurAI-Dig-Here-2020-21/manager' から出ます
make: *** [Makefile:2: all] エラー 2
みたいな感じで、スコープ内に kill() の宣言がないぞと言われて腐る。

原因

Cygwin で kill(2) は /usr/include/sys/signal.h の 175-177 行目で以下のように宣言されている。
 175 #if __POSIX_VISIBLE
 176 int kill (pid_t, int);
 177 #endif
ここで、__POSIX_VISIBLE は /usr/include/sys/signal.h にて、幾つかのマクロの設定状況を反映して、マクロ定義されてる。
ところが、どうもこれを設定する際に参照しているマクロが -std=standard の設定で変化するらしく、-std=c++14 だと __POSIX_VISIBLE = 0 となってしまうため kill() の宣言をしてくれない。
これは、以下のようにすることで確認できる。
$ echo "#include <signal.h>" >killcheck.cc
$ g++ -fdump-tree-all -E killcheck.cc | grep kill
# 1 "killcheck.cc"
# 1 "killcheck.cc"
int kill (pid_t, int);
int killpg (pid_t, int);
int pthread_kill (pthread_t, int);
# 2 "killcheck.cc" 2
$ g++ -std=c++14 -fdump-tree-all -E killcheck.cc | grep kill
# 1 "killcheck.cc"
# 1 "killcheck.cc"
# 2 "killcheck.cc" 2
$ g++ -dM -E killcheck.cc | grep -E "VISIBLE|SOURCE"
#define _ATFILE_SOURCE 1
#define _POSIX_SOURCE 1
#define _DEFAULT_SOURCE 1
#define __LARGEFILE_VISIBLE 0
#define __ISO_C_VISIBLE 2011
#define __RCSID_SOURCE(s) struct __hack
#define __XSI_VISIBLE 0
#define __GNU_VISIBLE 0
#define __BSD_VISIBLE 1
#define __POSIX_VISIBLE 200809
#define __SVID_VISIBLE 1
#define _POSIX_C_SOURCE 200809L
#define __ATFILE_VISIBLE 1
#define __MISC_VISIBLE 1
$ g++ -std=c++14 -dM -E killcheck.cc | grep -E "VISIBLE|SOURCE"
#define __LARGEFILE_VISIBLE 0
#define __ISO_C_VISIBLE 2011
#define __RCSID_SOURCE(s) struct __hack
#define __XSI_VISIBLE 0
#define __GNU_VISIBLE 0
#define __BSD_VISIBLE 0
#define __POSIX_VISIBLE 0
#define __SVID_VISIBLE 0
#define __ATFILE_VISIBLE 0
#define __MISC_VISIBLE 0

解決方法

g++ posix_visible std c++11」でググって、以下のページを見つけた。
− stackoverflow / 2018-09-04: Compiling with -std=c++11 on Cygwin hides available system calls
曰く、最近の g++ は標準で C++14 準拠なので -std=c++14 は不要との事。古い g++ 対策でもし付ける場合 -std=gnu++14 とかしとけと。

ということで、g++ でシステムコールを使う場合、-std=c++11 とか -std=c++14 とかは使っちゃ駄目ってことらしい。

SamurAI-Dig-Here-2020-21 に限って言えば g++ の場合
make CXXFLAGS='-g -Wall'
または
make CXXFLAGS='-g -Wall -std=gnu++14'
とすれば OK

また clang++ は -std=c++14 付けても影響ないらしく
make CXX=clang++
としても大丈夫だった。

Pull Request 投げてみた。

追記: 2020-11-29

Pull Request に返信付いて、こちらにもコメントを頂いたのだが、
コンパイルは出来たけど実行時にエラーになって、対処が難しそうとの事。
試しに
manager/manager -S samples/sample.dighere players/{random,random}Player >result.dighere
みたいにしてみると動くんだけど、
Cygwin だと一見きちんと動いているように見えて、何度か繰り返し実行してみると確かに何かおかしい。
調子が良いときは何事もなく動いているようなのだが、
調子が悪いと
Step: 1
Golds known: 6@(6,6)
Agent 0 timed out
となって止まったり、
Agent 2 error in flushing pipe
となって、それ以降 Agent 2 が
Agent 2@(4,1) stay (4,1)  0 msec left
みたいににゲーム進行から脱落したりと挙動が安定しない。
agent が simple や digger だと不安定さが高い気もしたのが、何度かやってみると、発生頻度もかなりばらついているようで、どうも種類自体はあまり関係なさそうな雰囲気。
apt-cyg の裏で散々 pipe や fork は使われてるはずなのだが、こんな変な挙動は出会ったこと無いので、pipe や fork 自体が問題ってわけでもないと思うのだが、
なんだ、これ?

Ruby で OLE が安定しない件と関係あったりするんだろうか?