D言語からC言語のライブラリ、オブジェクトファイルを利用することは簡単

# はじめに

**D言語**では、[ABI(Application Binary Interface)](https://dlang.org/spec/abi.html)がサポートされています。
つまり、D言語からC言語で作成したライブラリ、オブジェクトファイルをそのまま利用することができます。その実例を示したいと思います。

# 環境

* Windows 10
* [Visual C++ ビルドツール 2019](https://visualstudio.microsoft.com/ja/downloads/)　→　[インストール手順](https://www.kkaneko.jp/tools/win/buildtool.html)
* [dmd](https://dlang.org/download.html)

※ Cコンパイラとして[clang](https://releases.llvm.org/download.html) 、Dコンパイラとして[ldc](https://github.com/ldc-developers/ldc/releases)を使っても同じ結果となります。

# ソースコード

想定として、もともと C言語で作成した関数`func`があり、それを D言語にわざわざ作りかえることなく、そのまま利用したいケースだと考えてください。

```c:abi_c.c
#include <math.h>

typedef struct {
	long   p;
	double x;
	double y;
} S;

void func(S *s)
{
	s->x = log(s->p);
	s->y = exp(s->p);
}
```

```d:abi1_d.d
struct S {
	long   p;
	double x;
	double y;
}

extern (C) void func(S *s);
extern (C) int _cprintf(scope const char* format, ...); 
extern (C) int _getch();
import core.stdc.ctype : tolower;

void main()
{
	S s = S(2);
	int c;
	do {
		func(&s);
		_cprintf("log(%d) = %f,exp(%d) = %f\n",s.p,s.x,s.p,s.y);
		_cprintf("select [n]ext / [s]top\n");
		do {
			c = tolower(_getch());
		} while ( c != 'n' && c != 's' );
		if ( c == 'n' ){
			s.p++;
		}
	} while ( c != 's' );
}
```

C言語側関数の引数に**構造体**が含まれていたり、**可変長引数**であったとしても、D言語から全く問題なく呼び出しできることが、わかる実装例にしました。

# コンパイル手順

**64ビット**版のexeファイルを作成します。
先にC言語で作成したソースをコンパイルするために、「VS2019用 x64 Native Tools コマンドプロンプト」を[起動します](https://docs.microsoft.com/ja-jp/cpp/build/building-on-the-command-line?view=vs-2019)。
引き続き、生成されたCのオブジェクトファイルをD言語ソースとあわせて、コンパイルを行います。

```text:コマンド実行例
D:\Dev> cl -c abi_c.c
Microsoft(R) C/C++ Optimizing Compiler Version 19.24.28314 for x64
Copyright (C) Microsoft Corporation.  All rights reserved.

abi_c.c

D:\Dev> dmd -m64 abi1_d.d abi_c.obj

D:\Dev> dir /B
abi1_d.d
abi1_d.exe
abi1_d.obj
abi_c.c
abi_c.obj
```

# exeファイル実行例

exeファイル実行後、`n`を押すと続きが表示され、`s`を押すと処理が終了します。

```text:exeの実行例
D:\Dev> abi1_d.exe
log(2) = 0.693147,exp(2) = 7.389056
select [n]ext / [s]top
log(3) = 1.098612,exp(3) = 20.085537
select [n]ext / [s]top
log(4) = 1.386294,exp(4) = 54.598150
select [n]ext / [s]top
```

# 補足説明

**D言語**がABIをサポートするために、Dコンパイラが以下の仕組みを実装していることがわかります。

* プログラマがC言語で作成した関数を D言語から利用可能。
（Dコンパイラ（リンカー）がオブジェクトファイルを利用可能）

* `int`や`double`といった基本データ型の他に、`struct`にも対応。
他にも、C言語の様々なタイプに対応。[データタイプ互換表](https://dlang.org/spec/interfaceToC.html#data_type_compat)

* C言語ソースの中で、Cの標準ライブラリを使っている。(`log`や`exp`関数)
それらのライブラリファイルも、あわせてリンク可能。

* D言語ソースの中で、Cのライブラリを直接呼び出して使っている。(`_cprintf`や`_getch`関数)
それらのライブラリファイルも、あわせてリンク可能。
 + Cの標準ライブラリは、D言語で`import`して利用可能です。[tolowerの場合](https://dlang.org/phobos/core_stdc_ctype.html#.tolower)
 + `_cprintf`や`_getch`関数は、`<conio.h>`に含まれる[Windows固有のライブラリ](https://docs.microsoft.com/ja-jp/cpp/c-runtime-library/console-and-port-i-o?view=vs-2019)であり、`core.stdc`に定義がありません。この場合、`extern (C)`で定義することで利用可能となります。

今回は Cライブラリの使いたい関数が２つなので、`extern (C)`を直接記述しました。
もっと多くの関数を扱いたい場合には、ヘッダーファイルからD言語ソースを生成するツールを使う手があります。[こちら](https://qiita.com/lempiji/items/122c49a6c67a5b6d37a0)で詳しく紹介されています。

# 参考情報

[ABI(Application Binary Interface)](https://dlang.org/spec/abi.html) *英語*
[Interfacing to C](https://dlang.org/spec/interfaceToC.html) *英語*

[Visual C++ ビルドツール 2019のインストール方法](https://www.kkaneko.jp/tools/win/buildtool.html)
[コマンド ラインから Microsoft C++ ツールセットを使用する](https://docs.microsoft.com/ja-jp/cpp/build/building-on-the-command-line?view=vs-2019)

[Cランタイムライブラリ/コンソール入出力とポート入出力](https://docs.microsoft.com/ja-jp/cpp/c-runtime-library/console-and-port-i-o?view=vs-2019)
[D言語でのCランタイム定義(tolowerの場合)](https://dlang.org/phobos/core_stdc_ctype.html#.tolower)

[C言語のヘッダーファイルをD言語用に変換する dstep の使い方](https://qiita.com/lempiji/items/122c49a6c67a5b6d37a0)