1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【C++】ヘッダーオンリーライブラリの作成方法と導入方法

Posted at

開発を行っていると、簡便な方法でライブラリを扱えればよいのに…という場面が少なくありません。
ヘッダーオンリーライブラリの仕組みを使用することで簡便にライブラリを作成して扱うことが可能になります。
本記事では配布前提でヘッダーオンリーライブラリの作成方法と使用方法について紹介したいと思います。

前提知識

  • C++の基礎構文を理解している
  • Visual Studio2022からファイルを作成する程度の操作を行える

想定環境

  • Visual Studio2022

ヘッダーオンリーライブラリとは

ヘッダーオンリーライブラリとは、ソースコードをすべてヘッダファイルにまとめて提供したライブラリのことです。
配布時には単一ファイルのみで完結し、導入側もインクルードのみで使用できるため非常に簡便である反面、ライブラリのソースコードが丸見えになったり、ビルド時間が増えるといったデメリットが存在します。
よって、DLL静的リンクライブラリよりも、小規模なツールやユーティリティの実装に向いている配布形式といえます。

項目 ヘッダーオンリー DLL (動的リンクライブラリ) 静的リンクライブラリ
導入方法 #include するだけ DLLファイルを配置し、リンク設定が必要 .lib をリンク設定に追加
配布 ヘッダーファイルのみ DLLファイル+インポートライブラリ .lib ファイル
ビルド時間 長くなりやすい(全ソースに展開) 比較的短い(共有コードはDLL側) 中程度(リンク時に結合)
実行時の依存 なし(ソースに展開済み) DLLが存在しないと実行不可 なし(実行ファイルに埋め込み済み)
更新・差し替え 再コンパイルが必要 DLLを差し替えるだけで更新可能 再リンクが必要
デバッグ ソースが見えるので容易 DLL内部は別途デバッグが必要 ソースがあれば容易
実行ファイルのサイズ 大きい 小さい 大きい

ライブラリ側セットアップ方法

配布を行う際などに使用するプロジェクトのセットアップを行います。
まずは、Visual Studio 2022を開き、新しいプロジェクトの作成をクリックしてください。
スクリーンショット (79).png
ヘッダーオンリーライブラリの場合は.dll.libなどの生成を必要としないため、空のプロジェクトで作成を行います。
空のプロジェクトを選択したら、画面右下の次へをクリックしてください。
スクリーンショット (80).png
プロジェクト名をつけて、右下の作成をクリックします。
ソリューションとプロジェクトを同じディレクトリに配置するの項目は、本記事ではチェックしたままにします。
スクリーンショット (81).png
プロジェクトを作成できたら、ソリューションエクスプローラーGUIにあるすべてのファイルを表示のボタンをクリックしてください。
この操作を行うことで、Visual Studioからフォルダ構成を確認しながらフォルダを作成することが出来ます。
スクリーンショット (83).png
まずは配布するヘッダーファイルを作成します。
新しいフォルダはプロジェクトを右クリックし、追加->新しいフォルダで追加することが出来ます。
スクリーンショット (84).png
本記事では、include->mylib->MyHeaderLib.hppという構成にしました。
includeというフォルダを作成することで、導入側がインクルードを行うべきファイルを迷わなくて良いようになります。
ライブラリ名(本記事ではmylib)のフォルダを用意することで、他ライブラリとのファイル名衝突を事前に避ける意味があります。
スクリーンショット (86).png
次に、サンプルコードを作成します。
導入に直接の関係はありませんが、導入する人のためのガイド的な役割があります。
本記事でのフォルダ構成はexamples->main.cppとしました。
examplesという名前でガイドがここに存在することを示しつつ、main.cppという名前でエントリポイントの位置を示しています。
スクリーンショット (87).png
最後に、main.cppがヘッダーファイルを開けるようにするための設定を行います。
上部GUIからプロジェクト->プロパティをクリックして、プロパティウィンドウを開きます。
スクリーンショット (89).png
プロパティウィンドウの左から構成プロパティ->C/C++->全般を選択し、右の追加のインクルードディレクトリにサンプルコードで使用したいディレクトリ(本記事では$(ProjectDir)include)を追加してOKをクリックします。
スクリーンショット (90).png
プロパティウィンドウの右下の適用ボタンをクリックしてください。
スクリーンショット (91).png
これでセットアップが完了しました。
実際に配布する際にはREADME.mdなど、導入する人への説明書などを配布するのがベストですが、本記事では省略します。

ライブラリ側のコード例

HelloWorldを出力するサンプルコード

MyHeaderLib.hpp
//-------------------------------------------------------------
//! @file MyHeaderLib.hpp
//! @brief "Hello, World!"を出力する関数のみが入ったヘッダーオンリーのライブラリ
//! @author つきの
//-------------------------------------------------------------
#pragma once
#include <iostream>
//-------------------------------------------------------------
//! @namespace mylib
//! @brief ヘッダーオンリーライブラリの名前空間
//! @details "Hello, World!"を出力する関数のみを提供したライブラリ
//-------------------------------------------------------------
namespace mylib {
	//-------------------------------------------------------------
	//! @brief "Hello, World!"を出力するだけの関数
	//-------------------------------------------------------------
    inline void PrintHelloWorld() {
        std::cout << "Hello, World!" << std::endl;
    }

} // namespace mylib
main.cpp
//-------------------------------------------------------------
//! @file main.cpp
//! @brief MyHeaderLib.hppを使用するサンプルコード
//! @author つきの
//-------------------------------------------------------------
#include <mylib/MyHeaderLib.hpp>
//エントリポイント
int main() {
    // ライブラリの関数を呼び出す
    mylib::PrintHelloWorld();
    return 0;
}
result
Hello, World!

サンプルコードが正常に動きました。
ヘッダーオンリーライブラリでは、その性質上ヘッダーファイルに定義を書かざるを得ません。
そのため、複数の.cppから呼ばれた際の多重定義エラー対策として、関数の頭にinlineとつけ、インライン関数にします。
また、実際の開発では名前の衝突が考えられます。
名前空間にライブラリの名前を使用しておくことで、他ライブラリなどとの衝突を防いでおくことを私は推奨します。

MyHeaderLib.hpp
//-------------------------------------------------------------
//! @namespace mylib
//! @brief ヘッダーオンリーライブラリの名前空間
//! @details "Hello, World!"を出力する関数のみを提供したライブラリ
//-------------------------------------------------------------
namespace mylib {
	//-------------------------------------------------------------
	//! @brief "Hello, World!"を出力するだけ関数
	//-------------------------------------------------------------
    inline void PrintHelloWorld() {
        std::cout << "Hello, World!" << std::endl;
    }

} // namespace mylib

導入側のセットアップ

ライブラリが作成できたので、導入側プロジェクトのセットアップを行います。
プロジェクトの作成は先ほど紹介したので省略します。
同じように空のプロジェクトを作成してください。
本記事ではソリューションとプロジェクトは同じディレクトリに配置し、プロジェクト名はHeaderLibTestとしました。
スクリーンショット (94).png

エクスプローラーでソリューションディレクトリを開き、externalという名前のディレクトリを作成します。
externalは外部から取り込んだファイルであることを明示する名前です。
スクリーンショット (95).png
externalに、追加するライブラリ名(本記事ではMyHeaderLib)のディレクトリを作成します。
スクリーンショット (96).png
追加するライブラリ名のディレクトリに、追加したいヘッダーオンリーライブラリincludeディレクトリをコピーしてください。
これでライブラリをソリューションに配置できました。
スクリーンショット (97).png
Visual Studio2022に戻り、あらかじめエントリポイントとなるファイルを作成しておきます。
ファイルが存在しないとインクルードディレクトリを追加することが出来ません。
スクリーンショット (98).png
右上のGUIからプロジェクト->プロパティをクリックしてプロパティウィンドウを表示し、プロパティウィンドウ左から構成プロパティ->C/C++->全般を選択し、右側の追加のインクルードディレクトリから、使用したいライブラリのパス(本記事では$(SolutionDir)external\MyHeaderLib\include)を追加します。
OKをクリックし、プロパティウィンドウ適用をクリックしてください。
スクリーンショット (99).png
これでヘッダーオンリーライブラリの導入が完了しました。
コードでは#includeを行うだけで使用ができます。

導入側のコード例

main.cpp
//---------------------------------------------------------
//! @file  main.cpp
//! @brief 外部ライブラリの導入サンプル
//! @author つきの
//---------------------------------------------------------
#include <mylib/MyHeaderLib.hpp>  // 外部ライブラリのヘッダーをインクルード
//エントリポイント
int main() {
    // ライブラリの関数を呼び出す
    mylib::PrintHelloWorld();
    return 0;
}
result
Hello, World!

特に追加で説明することもないかと思います。
#includeを行うだけで、非常に簡便にライブラリを使用することが可能です。
追加のインクルードディレクトリでは$(SolutionDir)external\MyHeaderLib\includeと追加したので、includeディレクトリ配下のmylibからを#includeで指定してください。

main.cpp
#include <mylib/MyHeaderLib.hpp>  // 外部ライブラリのヘッダーをインクルード

総括

  • ヘッダーオンリーライブラリとはソースコードをすべてヘッダーファイルにまとめて提供する形式のこと。
  • 配布や導入が非常に簡便
  • ビルド時間が長くなるデメリットがあるため、小規模なライブラリに向いている。
  • ヘッダーファイル内の定義はインラインにすることで多重定義エラーを回避することが必須となる。
1
0
3

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
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?