[初級] C++: プログラムのビルド（ライブラリの利用）

C++ のプログラムでライブラリを利用する場合の超基本的なこと
スタティックライブラリ, ダイナミックリンクライブラリ
Visual Studio, VC++, Windows

:::note info
本記事の前提条件は以下の通りです。
* 初心者向け
* とは言っても、何らかのプログラムはそれなりに書けるけど、C とか C++ はちょっと、という人向け
* ざっくり概要しか説明しないので細かいことは気にしないでいただきたい
* Visual Studio 2013 くらい～
* Windowsプログラム (CUI, GUI)
* コードの検証
    * 開発環境: Visual Studio 2022, x64, Release ビルド
    * 実行環境: Windows 10
:::

:::note info
* 本記事は上から順番に読む前提となっている
:::

:::note info
* 「C++」と書いてあるが、本記事の内容としては C でもほぼ同じ
* 「Visual Studio 2013 くらい～」と書いてあるが、本記事の内容だと現在過去未来のどのバージョンでもほぼ同じ
* 「Windowsプログラム (CUI, GUI)」と書いてあるが、本記事の内容だとどの OS でもほぼ同じ。ただし、ダイナミックリンクライブラリ（共有ライブラリ）の作り方、使い方については OS によって違いがあるので注意
* その他、エラーコードなどについても状況によって異なるので注意
* 「...ライブラリ」「...リンクライブラリ」どちらでもよいと思うが、マイクロソフト的には「スタティックライブラリ」「ダイナミックリンクライブラリ」としているようなのでそれに従っている
* DLL を使う場合、（Visual Studio のテンプレートを使ったとしても）実際にはいろいろと処理が必要なのだが、本記事ではそのあたりの詳細には触れないのであしからず
:::

:::note info
前提知識として必要と思われる情報
* [[初級] C++: プログラムのビルド（基本） - 拙著](https://qiita.com/yasu62347/items/1fdc7e71847f7fc6af45)
:::

# そもそもライブラリとは

「図書館」ではさすがにわかりにくいので、「収集コレクション」と考えるのがよいと思う。


コンピュータープログラムにおいては、同じ処理を使いまわすための仕組みということで、単なるコードスニペット群もライブラリと呼べるかと思うが、ここでは、C++ における `*.lib` ファイル、および、`*.dll` を対象とする。

# 静的と動的
ライブラリには、スタティックライブラリ、ダイナミックリックライブラリがある。

以下に、その作り方、使い方を記述し、違いを見てみる。

# ライブラリにしたい処理を作る

例えばここに、共通に利用したい関数 `int add(int a, int b)` があるとする。

```c++ calc.h
int add(int a, int b);
```
```c++ calc.cpp
int add(int a, int b)
{
    return a + b;
}
```

ソースコードを書き、とりあえずコンパイルし、`calc.obj` を作成しておく。

# スタティックライブラリ
## スタティックライブラリを作る

ライブラリアン `lib.exe` でスタティックライブラリを作成する。

`lib.exe calc.obj /out:calc.lib`

:::note info
ライブラリアンは `*.lib` の管理をするツールで、後で別の `*.obj` を追加したりできる。
つまり、`*.lib` は `*.obj` の収集コレクション = ライブラリ、ということである。
:::

## スタティックライブラリを使う
ヘッダファイルをインクルードしてコンパイルする。

```c++ main.cpp
#include <iostream>
#include "calc.h"
int main()
{
    std::cout << add(1, 2) << std::endl;
    return 0;
}
```

`cl.exe main.cpp`

これで `main.obj` が生成される。

リンカに、`main.obj` と、`calc.lib` を渡してリンクする。

`link.exe main.obj calc.lib /out:hogehoge.exe`

:::note info
ライブラリを使わない場合と比べると、リンカに渡すものが `calc.obj` から `calc.lib` になっただけである。
:::

:::note warn
上記ソースコードを実際にリンクする場合には、VCランタイムなどが追加で必要なのであしからず。
:::

## スタティックライブラリを使った場合のポイント

スタティックライブラリを使った場合のポイントとしては、生成された `hogehoge.exe` の中に `add` 関数の本体が埋め込まれている、ということである。

# ダイナミックリンクライブラリ
## ダイナミックリンクライブラリを作る

:::note alert
リンカで `calc.obj` をダイナミックリンクライブラリとしてリンクするのだが、DLL を作成する場合には、どの関数をエクスポートするか、を指定する必要がある。
いくつかの方法があるのだが、それについては本記事では説明しないのであしからず。

参考: [DLL と実行形式のリンク - Microsoft Learn](https://learn.microsoft.com/ja-jp/cpp/build/linking-an-executable-to-a-dll?view=msvc-170)
:::

なんにせよ、`calc.obj` を含んだ　`calc.dll` ができたとする。

## ダイナミックリンクライブラリを使う（Explicit Linking）

ダイナミックリンクライブラリを使う場合には、実行時に DLL から必要な関数を読み込む必要があり、下記のようになる。

```c++ main.cpp
#include <windows.h>
#include <tchar.h>
#include <iostream>
int main()
{
    // DLL をロードする
    HMODULE hLib = LoadLibrary(_T("calc.dll"));
    typedef int (*PFUNC_ADD)(int, int);
    // add 関数のアドレスを取得する
    PFUNC_ADD add = (PFUNC_ADD)GetProcAddress(hLib, "add");

    // 使う
    std::cout << add(1, 2) << std::endl;

    // DLL を解放する
    FreeLibrary(hLib);
    return 0;
}
```

:::note warn
とにかく DLL から関数を読み込む必要がある、ということがわかればよいので、上記コードの詳細は割愛する。
:::

## ダイナミックリンクライブラリを使う（Implicit Linking）

DLL を作成する場合、（設定によるが、通常）リンカはインポートライブラリ `calc.lib` を出力する。
このインポートライブラリには、`add` 関数の実体は含まれておらず、その代わりに `calc.dll` の `add` 関数を「実行時（exe の起動時）にロードする」処理が含まれている。

したがって、ダイナミックリンクライブラリを使う場合でも、ソースコード上はスタティックライブラリを使う時と同じで、まずはヘッダをインクルードしてコンパイルする。

```c++ main.cpp
#include <iostream>
#include "calc.h"
int main()
{
    std::cout << add(1, 2) << std::endl;
    return 0;
}
```

スタティックライブラリを使う場合との違いは、リンカに渡す `calc.lib` がインポートライブラリである、という点のみである。

インポートライブラリをリンクした exe は、起動時に必要な DLL から必要な関数をロードして利用する。

## ダイナミックリンクライブラリを使う場合のポイント

ダイナミックリンクライブラリを使う場合のポイントとしては、生成された `hogehoge.exe` の中には `add` 関数の本体はなく、実行時に見つかった DLL のものを利用する、ということである。