web-dev-qa-db-ja.com

ライブラリを作成するにはどうすればよいですか?

コードをコンパイルするために必要な* .hppファイルと* .cppファイルが10個あるとします。多くの異なるコードに対して同じファイルが必要になることを知っています。これらのファイルで「パッケージ」を作成して、簡単に書くことができますか

#include<mypackage>

の代わりに

#include"file1.hpp"
#include"file2.hpp"
...
#include"file10.hpp"

この「パッケージ」が必要になるたびにメイクファイルを書く必要はありません。

より正確には、Linuxを使用しています。

22
PinkFloyd

CPPソース(HファイルとCPPファイル)のコレクションをまとめて「ライブラリ」にコンパイルし、他のプログラムやライブラリで使用できます。これを行う方法の詳細はプラットフォームおよびツールチェーンに固有であるため、詳細はユーザーにお任せください。ただし、私はあなたが読むことができるいくつかのリンクを提供します:

gnuコンパイラーによる共有および静的ライブラリーの作成[gcc]

チュートリアル:ダイナミックリンクライブラリの作成と使用(C++)

ライブラリは、ソースコードライブラリとバイナリライブラリの2つのタイプに分けることができます。これら2つのタイプのハイブリッドもあります。ライブラリは、ソースライブラリとバイナリライブラリの両方にすることができます。ソースコードライブラリは単純に次のとおりです。単なるソースコードとして配布されるコードのコレクション。通常、ヘッダーファイル。 Boostライブラリのほとんどはこのタイプです。バイナリライブラリは、クライアントプログラムによって実行時ロード可能なパッケージにコンパイルされます。

バイナリライブラリの場合(およびソースライブラリの場合も同様)でも、ヘッダーファイル(または複数のヘッダーファイル)をライブラリのユーザーに提供する必要があります。これは、クライアントプログラムのコンパイラに、ライブラリで検索する関数などを指示します。ライブラリ作成者がよく行うことは、単一のマスターヘッダーファイルが、ライブラリによってエクスポートされるすべての宣言で構成され、クライアントが#includeそのヘッダー。後で、バイナリライブラリの場合、クライアントプログラムはライブラリに「リンク」し、これにより、ヘッダーに記載されているすべての名前が実行可能アドレスに解決されます。

クライアント側のヘッダーファイルを作成するときは、複雑さを念頭に置いてください。クライアントの一部がライブラリの一部のみを使用したい場合が多くあります。ライブラリのすべてを含む1つのマスターヘッダーファイルを作成すると、クライアントのコンパイル時間が不必要に長くなります。

この問題に対処する一般的な方法は、ライブラリの相関部分に個別のヘッダーファイルを提供することです。 Boostのすべてを1つのライブラリと考える場合、Boostはその一例です。 Boostは膨大なライブラリですが、正規表現機能だけが必要な場合は、#includeその機能を取得するための正規表現関連のヘッダー。正規表現だけが必要な場合は、Boostのallを含める必要はありません。

WindowsとLinuxの両方で、バイナリライブラリは、動的と静的の2つのタイプにさらに細分化できます。静的ライブラリの場合、ライブラリのコードは実際にはクライアントプログラムの実行可能ファイルに(より適切な用語がないために)インポートされます。静的ライブラリはユーザーが配布しますが、これはクライアントがコンパイル手順でのみ必要とします。これは、クライアントがプログラムで追加のファイルを配布しなければならないようにしたくない場合に便利です。また、 Dependancy Hell を回避するのにも役立ちます。一方、動的ライブラリは、クライアントプログラムに直接「インポート」されず、実行時にクライアントプログラムによって動的にロードされます。これにより、クライアントプログラムのサイズが削減され、複数のプログラムが同じ動的ライブラリを使用する場合にディスクフットプリントが削減される可能性がありますが、ライブラリバイナリをクライアントプログラムと共に配布およびインストールする必要があります。

40
John Dibling

「file1.hpp」と「file2.hpp」などが密接に関連し、(ほぼ)常に一緒に使用されていると仮定すると、他のコンポーネントのインクルードを含む1つの「mypacakge.h」を作成するのは良い考えです(そうではありません)それ自体がライブラリになります-それはまったく異なるプロセスです)。

それらが密接に関連および/または一緒に使用されていない場合、必要のないものの束をドラッグするだけなので、このような「メガインクルード」はありません。

ライブラリを作成するには、コードを1回ビルドし、.libファイルまたは共有ライブラリ(.dllまたは.soファイル)を生成する必要があります。これを行う正確な手順は、使用しているシステムによって異なります。ここで説明するには少し複雑すぎます。

編集:さらに説明するには:すべてのC++ライブラリは、実際には1つのライブラリファイルまたは共有ライブラリファイルです(いくつかのコードと、ライブラリ内のコードを使用するために必要な宣言を含む多数のヘッダーファイル)。ただし、<iostream><vector>を別々にインクルードします。入力がずっと少なくても、1つの<allcpplibrary>にすべての異なるC++ライブラリヘッダーのすべてをインクルードすると、かなりひどくなります。ヘッダーファイルごとに1つのことを行うセクションに分割されます。したがって、1つのヘッダーファイルから「完全な」セットを取得しますが、実際に必要のない他のことはあまりありません。

2
Mats Petersson

Linuxの場合:

g ++フラグ-shared -Wl、-soname、libLIBNAME.so.1 -o libLIBNAME.VERSION OBJECT_FILES

どこ

フラグ:典型的なフラグ(例:-g、-Wall、-Wextraなど)

LIBNAME:ライブラリの名前

OBJECT_FILES:cppファイルのコンパイルから生じるオブジェクトファイル

バージョン:ライブラリのバージョン

1
Claudio

クライアントが実際に「パッケージ」(ライブラリ)を使用するために10個のヘッダーすべてを必要とする場合、それはかなり悪いインターフェース設計です。

クライアントがsomeヘッダーのみを必要とする場合、ライブラリのどの部分が使用されているかに応じて、クライアントに適切なヘッダーを含めて、識別子の最小限のセットのみが導入されるようにします。これは、スコープ、モジュール化、およびコンパイル時間に役立ちます。

他のすべてが失敗した場合、外部で使用するための「インターフェースヘッダー」を作成できます。これは、実際にライブラリをコンパイルするために内部で使用するものとは異なります。これがインストールされ、他のヘッダーの必要なコンテンツで構成されます。 (私はまだあなたのライブラリにeverything from every headerが必要だとは思わない。)

サルガーのソリューションを思いとどまらせるでしょう。 either個々のヘッダーを持っている、orモノリシックなヘッダーを持っている。個々のヘッダーを提供するplus他のヘッダーのみを含む中心的なヘッダーは、かなり貧弱なレイアウトだと思います。

私がすることnot理解することは、Makefileがこれにどの程度関与するかです。ヘッダーの依存関係は、Makefile /ビルドシステムによって自動的に解決される必要があります。つまり、ここでヘッダーファイルがどのようにレイアウトされるかは重要ではありません。

1
DevSolar

はいといいえ。

Include_allヘッダーを記述して、#include "myLib.h"で十分なようにできます。これは、これらのヘッダーをすべて単一のヘッダーに含めるためです。ただし、10個の「.cpp」ファイルのコンテンツをプロジェクトに自動的にリンクするには、1つのインクルードだけで十分というわけではありません。それらをライブラリにコンパイルし、そのすべてのオブジェクトファイルではなく、その単一のライブラリを「myLib.h」を使用するプロジェクトにリンクする必要があります。ライブラリバイナリは静的および動的ライブラリとして提供され、ファイルは通常、静的ライブラリおよび動的ライブラリの場合、それぞれ.libおよび.dll(windows)および.aおよび.so(linux)という名前になります。 。

そのようなライブラリをビルドおよびリンクする方法は、ビルドシステムによって異なります。ネット上でこれらの用語を無視することをお勧めします。

1つの代替方法は、ヘッダー内のすべての関数を定義することにより、.cppファイルを削除することです。この方法では、追加のライブラリをリンクする必要はありませんが、ヘッダーを翻訳ユニットの1つに直接または間接的にインクルードするたびにコンパイラがこれらのすべての関数を処理する必要があるため、ビルド時間が長くなります。

1
Arne Mertz