Meson に起因するリンクエラーだけ手動で build.ninja を修正し meta-pkgs/modular-xorg すべて完走するようになった。

まともに自分で X11 入れて動かすの十年ぶりなんだが、ビルド完走おめでとう twm に立ち上がるいつもの xterm 僕にとって新鮮みがないことが成功の証だと思う、ってポエム唱えたくなるくらい代わり映えねえなオイ、いや背景の格子模様が黒一色になってんぞもどして。

せめて xeyes にミャクミャクオプションとかないのか、自分で作るには一発芸過ぎてとうに機を逸してるし関西政界の闇に加担したくないしなによりもう X プログラミングなんて覚えてねえよクソが。

ちなみに GNU Autoconf のままのパッケージは configure が勝手に -std=gnu99 をサポートしてるか確認してくれるんだが、Meson 化されたパッケージはいちいち -std=c99 を指定せんとループ内変数宣言程度でビルドコケるからその度に止まってイライラ MAX であった。 まあ今時 gcc-4.5.3 なんて使ってるのが悪いと言われればそれまでだけども。

そもそも世間逸般は gcc15 が -std=c23 をデフォルトにしやがったせいで阿鼻叫喚みたいなのでまだマシかもしれぬ。 そもそも GNU make とか gdb なんかもまだ K&R スタイルが大量に残ってるからビルド通すだけでもしんどいだろうにようやるわ。

結局リンクエラー出たのは

だけだった、ただ pixman でも発生したことで zlib 固有の問題じゃなくて条件揃っったら発生する事が確認できたので一安心である、今後 Meson 化が進むにつれて壊れるやつ増えると思う(死)。 まぁ GNU ld なんて時代遅れで LLVM lld とか mold 使ってるだろうし誰にも気づかれないままの可能性も高い。

つーか今って Makefile で devel/binutils/buildlink3.mk インクルードしても USE_TOOLS=binutils しても /usr/bin/ld の代わりに /usr/pkg/bin/gld 使うようにならないのな。 昔はできた記憶があるんだが cwrapper 導入したあたりからできなくなったんだろうか。 /usr/bin/ld を /usr/pkg/bin/gld の symlink にしたら問題なくリンクできたじゃねーかクソが。

ということで嫌なら最新の binutils 使えで終わってしまうんだが、やっぱり Meson の –start-group/–end-group を吐く位置が間違ってるとしか思えんし、古い binutils 使う場合には正しい位置で出力してほしいよなって。

まず build.ninja に変換される前の mason.build を眺めた第一印象としては –start-group/–end-group に内包されるべき依存関係は

  • link_whole … 静的リンクライブラリのアーカイブ中のオブジェクトファイルを全てリンクする
  • link_with … 動的リンクライブラリあるいは静的リンクライブラリをリンクする

だけだと思うんだよな、そして link_with では N でいうとこの

  • lib*.a … 静的リンクオブジェクトのアーカイブファイル
  • lib*_pic.a … 位置独立(PIC)オブジェクトのアーカイブファイル
  • lib*_p.a … gperf によるプロファイリングオブジェクトのアーカイブファイル

なんかのアーカイブライブラリだけを指定し、lib*.so といった動的リンクライブラリは

で指定するんもんだよね、まぁ実際 MesaLib の meson.build を読む限りでは使用する側もその認識に沿っているので正しいっぽい。

ところが dependencies も –start-group/–end-group に内包されてしまうので Meson の実装がバグってるという話になるわな。 まぁ古い GNU ld(ld.old?) でないと発覚しないし最新版では許容されてる時点でバグ報告したところで無視される負け戦確定なんだが、古い実装の挙動を許さないでビルドツール名乗るならリンカーも内蔵しとけやという話である。

んじゃあ早速 Meson のコード読んでいくか。

46 GROUP_FLAGS = re.compile(r'''^(?!-Wl,) .*\.so (?:\.[0-9]+)? (?:\.[0-9]+)? (?:\.[0-9]+)?$ |
47                              ^(?:-Wl,)?-l |
48                              \.a$''', re.X)
49 
50 class CLikeCompilerArgs(arglist.CompilerArgs):
...
60     def to_native(self, copy: bool = False) -> T.List[str]:
...
64         # Check if we need to add --start/end-group for circular dependencies
65         # between static libraries, and for recursively searching for symbols
66         # needed by static libraries that are provided by object files or
67         # shared libraries.
68         self.flush_pre_post()
69         if copy:
70             new = self.copy()
71         else:
72             new = self
73         # This covers all ld.bfd, ld.gold, ld.gold, and xild on Linux, which
74         # all act like (or are) gnu ld
75         # TODO: this could probably be added to the DynamicLinker instead
76         if isinstance(self.compiler.linker, (GnuLikeDynamicLinkerMixin, SolarisDynamicLinker, CompCertDynamicLinker)):
77             group_start = -1
78             group_end = -1
79             for i, each in enumerate(new):
80                 if not GROUP_FLAGS.search(each):
81                     continue
82                 group_end = i
83                 if group_start < 0:
84                     # First occurrence of a library
85                     group_start = i
86             # Only add groups if there are multiple libraries.
87             if group_end > group_start >= 0:
88                 # Last occurrence of a library
89                 new.insert(group_end + 1, '-Wl,--end-group')
90                 new.insert(group_start, '-Wl,--start-group')

CLikeCompilerArgs クラスの to_native() メソッドが問題の –start-group/–end-group を生成している部分。

引数リストから 正規表現 GROUP_FLAGS にマッチする引数の先頭と末尾を探し出して –start-group/–end-group を挿入するというやっつけ仕事でもうキレそう。 つまり前述の link_whole/link_with/dependencies がすべて引数リストとして展開されて後の祭りになってから無理矢理ぶっ込んでくるとかさぁ。 しかも正規表現に

^(?!-Wl,) .*\.so (?:\.[0-9]+)? (?:\.[0-9]+)? (?:\.[0-9]+)?$

つまり動的リンクライブラリも含まれてるし何やこれ、コード書いたやつの 頭を開いてちょっと気軽に楽しめ ってか?

うーむ、引数リストになる前段階で link_whole/link_with/dependencies の区別が失われてしまってるので結構修正が必要になりそうね。

数行読んだだけでウンザリしたので続きはまたいずれ、こんな山岡はんの鮎のようなコードよりも binutils ld のコード読んだ方がマシや。