LoginSignup
8
1

More than 3 years have passed since last update.

dub v1.23.0のx86_omfについて

Last updated at Posted at 2020-09-26

こんにちは。
ついに2.094.0がリリースされましたね! なんかアナウンスないけど…されました!!

さて、このリリースには私の携わったdubの改良があります。それがx86_omfというアーキテクチャ指定
この記事ではどうやって使うのかというところから、なぜそれが必要になったか、という点について触れたいと思います。

x86_omfとは何ぞや

D言語のWindowsのdmdコンパイラでは、32bitと64bitのバイナリをコンパイルすることができますが、その中でも32bitには、MSVC(Microsoft Visual Studio)のランタイムを使うものと、DegitalMars謹製のランタイムを使うものが2種類あります。
まあ、性能面で言えばMSVCのランタイム一択なのですが、DigitalMars製のランタイムがデフォルトなのです。ちなみに64bitは選択の余地なくMSVCのランタイムを使用します。

以下にWindowsでmain.dから各種バイナリを得る方法を記載します

32bit-DigitalMarsランタイム
dmd main.d
32bit-MSVCランタイム
dmd -m32mscoff main.d
64bit-MSVCランタイム
dmd -m64 main.d

ビルド中、MSVCのランタイムを使用する場合は、内部のフォーマットとしてCOFF形式のライブラリとリンクします。※正確にはCOFF形式のオブジェクトを集めた静的リンクライブラリ
ではDigitalMarsのものはというと、OMF形式のライブラリとリンクします。
ここまで説明するとお分かりいただけると思いますが、x86_omfというのは、dubでビルドする際にx86(32bit)のOMF形式のライブラリとリンクしてビルドするよ、というアーキテクチャ指定なのです。

ビット数 ランタイム オブジェクト形式 使用するリンカ コンパイル指定 アーキテクチャ
32bit DigitalMars OMF optlink.exe -m32 または無指定 x86_omf
32bit MSVC COFF (MSの)link.exe -m32mscoff x86_mscoff
64bit MSVC COFF (MSの)link.exe -m64 x86_64

x86_omfの使い方

x86_omfの使い方はx86_mscoffと同じです。(x86_mscoffは従来からあった)

dubビルド時にコマンドライン引数で指定する

今回追加された仕様
dub build -a=x86_omf

または

従来からある仕様
dub build -a=x86

上記のようにすることで、明示的にDigitalMarsの(OMF形式の)ランタイムを使用するように指定できます。
ちなみに、dubのデフォルト(無指定)では、ビルド環境のビット数のMSVCランタイムが使用されるようになっています。(64bit Windowsを使ってビルドすればx86_64、32bit Windowsを使ってビルドすればx86_mscoffが選択される)

この使い方は従来とほとんど変わらないので割愛します。

dubのプロジェクト設定ファイル(dub.json/dub.sdl)に記載する

問題はこちらです。JSON形式で設定ファイルを記載した場合で説明します。

今回のアーキテクチャ指定は主にlibssourceFilesでライブラリとのリンク指定を行う際に効果を発揮します。
先述の通り、リンクすべきライブラリの種類は3種類あるので、3種類それぞれをアーキテクチャに応じて分けて指定する必要があります。その例が以下。

dub.json
{
  "sourceFiles-windows-x86_omf-dmd":    ["libs/windows-x86_omf/test.lib"],
  "sourceFiles-windows-x86_mscoff-dmd": ["libs/windows-x86_mscoff/test.lib"],
  "sourceFiles-windows-x86_64-dmd":     ["libs/windows-x86_64/test.lib"]
}

上記のようにすることで、それぞれ別のディレクトリに格納した3種類のライブラリをアーキテクチャ別に指定することができます。

また、先述の表にある通り、ライブラリの種類が異なれば、使用するリンカも異なります。OMFはDigitalMars製のリンカを、MSCOFFはMSVCのリンカを使用する必要があります。リンカが異なれば、リンカに指定するオプションも異なります。そう、lflagsなんかにも役立つのです。以下の指定はGUIアプリケーションをビルドする際にコンソール画面がでなくなるようにする設定です。

dub.json
{
  "lflags-windows-x86_omf-dmd":    ["/exet:nt/su:windows:6.0"],
  "lflags-windows-x86_mscoff-dmd": ["/SUBSYSTEM:WINDOWS", "/ENTRY:mainCRTStartup"],
  "lflags-windows-x86_64-dmd":     ["/SUBSYSTEM:WINDOWS", "/ENTRY:mainCRTStartup"]
}

x86_omfはなぜ必要なのか?

ここまでの説明でお分かりいただけると思いますが、3種類のアーキテクチャ(ビット数×オブジェクト形式)に対しては、3種類のアーキテクチャ指定ができるのが自然です。が、従来はx86_omfがありませんでした。従来はどのようにして上記問題を解決していたのでしょうか?答えはconfigurationsです。

dub.json
{
  "configurations": [
    {
      "name": "application",
      "lflags-windows-x86-dmd":    ["/exet:nt/su:windows:6.0"],
      "lflags-windows-x86_64-dmd": ["/SUBSYSTEM:WINDOWS", "/ENTRY:mainCRTStartup"]
    },
    {
      "name": "application_mscoff",
      "lflags-windows-x86-dmd":    ["/SUBSYSTEM:WINDOWS", "/ENTRY:mainCRTStartup"]
    }
  ]
}

上記のようにmscoff用に"configurations"で分けて、

dub build -a=x86 -c=application
dub build -a=x86_mscoff -c=application_mscoff
dub build -a=x86_64 -c=application

のようにして3種類のアーキテクチャに対応していたのです。

できるなら必要ないじゃないか?いいえ、問題はこれにとどまりません。
依存関係がある場合はもっと複雑になります。というか、依存先がこのことを知っててconfigurationsを分けてくれているかどうかはライブラリの作者依存ですし、プロジェクト固有にあるconfigurationsの設定を調べるのは大変でした。

dub.json
{
  "dependencies": {
    "vibe-d": "~>0.8.0"
  }
  "configurations": [
    {
      "name": "application",
      "lflags-windows-x86-dmd":    ["/exet:nt/su:windows:6.0"],
      "lflags-windows-x86_64-dmd": ["/SUBSYSTEM:WINDOWS", "/ENTRY:mainCRTStartup"],
    },
    {
      "name": "application_mscoff",
      "lflags-windows-x86-dmd":    ["/SUBSYSTEM:WINDOWS", "/ENTRY:mainCRTStartup"]
      "subConfigurations": {
        "vibe-d": "win32_mscoff"
      }
    }
  ]
}

というか、まじめに対応しようとすると普通にconfigurationsが2倍必要で面倒くさいことこの上ない。

dub.json
{
  "dependencies": {
    "vibe-d": "~>0.8.0"
  }
  "configurations": [
    {
      "name": "application",
      "lflags-windows-x86-dmd":    ["/exet:nt/su:windows:6.0"],
      "lflags-windows-x86_64-dmd": ["/SUBSYSTEM:WINDOWS", "/ENTRY:mainCRTStartup"],
    },
    {
      "name": "application_mscoff",
      "lflags-windows-x86-dmd":    ["/SUBSYSTEM:WINDOWS", "/ENTRY:mainCRTStartup"]
      "subConfigurations": {
        "vibe-d": "win32_mscoff"
      }
    },
    {
      "name": "library",
      "targetType": "library"
    },
    {
      "name": "library_mscoff",
      "targetType": "library",
      "subConfigurations": {
        "vibe-d": "win32_mscoff"
      }
    },
    {
      "name": "unittest",
      "dependencies": { "silly": "~>1.0.2" }
    },
    {
      "name": "unittest_mscoff",
      "dependencies": { "silly": "~>1.0.2" },
      "subConfigurations": {
        "vibe-d": "win32_mscoff"
      }
    }
  ]
}

x86_omfがあれば以下のようにすっきりします。依存先のconfigurationsの指定も必要ありません。

dub.json
{
  "dependencies": {
    "vibe-d": "~>0.X.0"
  }
  "configurations": [
    {
      "name": "application",
      "lflags-windows-x86_omf-dmd":    ["/exet:nt/su:windows:6.0"],
      "lflags-windows-x86_mscoff-dmd": ["/SUBSYSTEM:WINDOWS", "/ENTRY:mainCRTStartup"]
      "lflags-windows-x86_64-dmd":     ["/SUBSYSTEM:WINDOWS", "/ENTRY:mainCRTStartup"],
    },
    {
      "name": "library",
      "targetType": "library"
    },
    {
      "name": "unittest",
      "dependencies": { "silly": "~>1.0.2" }
    }
  ]
}

※現時点では引き合いに出したvibe.dがx86_omfに対応した書き方をしていないので無理だが、いずれ上記のようになる(ことが期待できる)

最後に

今回私は上記のような複雑な設定に嫌気がさし、プルリクエストを出したところ、議論もなくすぐにマージされたのでした。(あとでChagneLog必要じゃない?という話が出たくらい)
ものは言ってみるものだなぁ。
今回の変更によって、全部のコンパイラ・アーキテクチャに対応させるのもそれほど難しくなくなったので、ぜひ活用してみてくださいね。

8
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
1