共有ライブラリと単一の実行可能ファイルの使用
-
07-07-2019 - |
質問
同僚は、C ++アプリケーション(C ++、Linux)を共有ライブラリに分解して、コードのモジュール性、テスト容易性、および再利用を改善する必要があると主張しています。
私の観点からすると、同じマシン上のアプリケーション間で動的にロードまたはアンロードするためにコードを共有する必要がなく、モノリシックな実行可能アプリケーションを単純にリンクできるため、負担になります。
さらに、C関数インターフェイスでC ++クラスをラップすると、IMHOは見苦しくなります。
また、単一ファイルのアプリケーションは、顧客のサイトでリモートで簡単にアップグレードできると思います。
アプリケーション間でバイナリコードを共有する必要がなく、ダイナミックコードをロードしない場合、ダイナミックライブラリを使用すべきですか?
解決
コードを共有ライブラリに分割して、目先の目標を念頭に置かずに改善すると言うのは、流行語がin延する開発環境の兆候です。ある時点で簡単に分割できるコードを書くことをお勧めします。
しかし、C ++クラスをC関数インターフェイスにラップする必要があるのは、オブジェクトの作成を除いて、おそらく
また、ここで共有ライブラリに分割することは、インタプリタ言語の考え方のように聞こえます。コンパイルされた言語では、コンパイル時にできることを実行時まで延期しないようにします。不要な動的リンクがまさにそのケースです。
他のヒント
共有ライブラリを強制すると、ライブラリに循環依存関係がなくなります。共有ライブラリを使用すると、多くの場合、より高速なリンケージが発生し、最終アプリケーションがリンクされる前にリンクが存在しない場合よりも早い段階でリンクエラーが検出されます。複数のファイルを顧客に出荷しないようにするには、開発環境でアプリケーションを動的にリンクし、リリースビルドを作成するときに静的にリンクすることを検討できます。
編集:Cインターフェイスを使用してC ++クラスをラップする必要がある理由は実際にはわかりません-これは舞台裏で行われます。 Linuxでは、特別な処理をせずに共有ライブラリを使用できます。ただし、Windowsでは、___ declspec(export)および___ declspec(import)が必要です。
ない場合でも再利用を改善しますか?強い議論のように聞こえません。
コードのモジュール性とテスト容易性は、最終的な展開の単位に依存する必要はありません。リンクは遅い決定になると思います。
本当に1つの成果物があり、それに対する変更をまったく予想しない場合、分割して提供するのはやり過ぎであり、不必要な複雑さのように聞こえます。
簡単な答え:いいえ。
より長い答え:動的ライブラリは、モノリシックアプリでは簡単に実行できないテスト、モジュール性、または再利用に追加するものを何も追加しません。私が考えることができる唯一の利点については、自分でそれを行うための規律を持っていないチームでAPIの作成を強制することができるということです。
ライブラリには魔法のようなものはありません(動的またはその他)。さまざまなライブラリを含むアプリケーションをビルドするためのすべてのコードがある場合、単一の実行可能ファイルですべてを一緒にコンパイルすることができます。
一般的に、動的ライブラリを処理するコストは、切迫したニーズがない限り価値がありません(複数のアプリケーションのライブラリ、再コンパイルせずに多数のアプリケーションを更新する必要があり、ユーザーがアプリケーションに機能を追加します)。
同僚の議論の分析
コードを共有ライブラリに分割すると、コードのモジュール性、テスト容易性、再利用性が向上すると彼が信じている場合、これは、あなたがあなたのコードに問題があると考えていること、そして「共有ライブラリ」を強制していることを意味していると思いますアーキテクチャが修正します。
モジュール性
コードには、「ライブラリコード」と「ライブラリコード」を明確に分離することで発生しない望ましくない相互依存関係が必要です。および「ライブラリコードを使用したコード」。
現在、これは静的ライブラリでも実現できます。
テスト?
コードをよりよくテストできます。おそらく、コンパイルごとに自動化された個別の共有ライブラリごとに単体テストを作成します。
現在、これは静的ライブラリでも実現できます。
コードの再利用?
同僚は、モノリシックアプリケーションのソースに隠されているために公開されていないコードを再利用したいと考えています。
結論
静的ライブラリを使用しても、ポイント1と2は引き続き実現できます。 3は共有ライブラリを必須にします。
今、ライブラリのリンクの深さが複数ある場合(すでにコンパイルされた2つの静的ライブラリを他のライブラリにリンクすることを考えています)、これは複雑になる可能性があります。 Windowsでは、一部の関数(通常、静的にリンクされている場合はC / C ++ランタイム関数)が複数回参照され、コンパイラーが呼び出す関数を選択できないため、リンクエラーが発生します。 Linuxでこれがどのように機能するかはわかりませんが、これも起こり得ると思います。
独自の引数の分析
あなた自身の引数はいくらか偏っています:
共有ライブラリのコンパイル/リンクの負担?
静的ライブラリのコンパイルおよびリンクと比較して、共有ライブラリのコンパイルおよびリンクの負担は存在しません。したがって、この引数には値がありません。
動的なロード/アンロード?
共有ライブラリの動的なロード/アンロードは、非常に限られたユースケースで問題になる可能性があります。通常、OSはユーザーの介入なしに必要に応じてライブラリをロード/アンロードします。とにかく、パフォーマンスの問題は他の場所にあります。
Cインターフェースを使用したC ++コードの公開?
C ++コードでC関数インターフェイスを使用する場合、理解できません。静的ライブラリを既にC ++インターフェイスにリンクしています。共有ライブラリのリンクも同様です。
アプリケーションの各ライブラリを生成するコンパイラが異なる場合は問題が発生しますが、すでにライブラリを静的にリンクしているため、そうではありません。
単一のファイルバイナリの方が簡単ですか?
そのとおりです。
Windowsの場合、違いはごくわずかですが、それでも DLLヘル。ライブラリ名にバージョンを追加するか、Windows  XPで作業すると消えます。
Linuxでは、上記のWindowsの問題に加えて、共有ライブラリはデフォルトで使用できるようにいくつかのシステムデフォルトディレクトリにある必要があるため、インストール時にそれらをコピーする必要があります(これは面倒なことがあります...)またはデフォルトの環境設定を変更します(面倒なこともあります...)
結論:誰が正しいのですか?
今、あなたの問題は「私の同僚は正しいですか?」ではありません。彼は。あなたもそうです。
あなたの問題は:
- 本当に達成したいことは何ですか?
- このタスクに必要な作業は価値がありますか?
最初の質問は非常に重要です。あなたの議論と同僚の議論は、あなたにとってより自然な結論に導くように偏っているように思えます。
別の言葉遣いでそれを入れてください:あなたはそれぞれ理想的な解決法がどうあるべきかを知っています(それぞれの観点から)そしてあなたはそれぞれrへの引数を積み上げます
単純なコスト/利益分析を行う-モジュール性、テスト容易性、再利用が本当に必要ですか?これらの機能を取得するためにコードをリファクタリングする時間はありますか?最も重要なことは、リファクタリングを行う場合、得られる利点はリファクタリングの実行にかかった時間を正当化するでしょうか?
テストに問題がある場合を除き、アプリを現状のままにしておくことをお勧めします。モジュール化は素晴らしいですが、Linuxには独自のバージョンの「DLL地獄」があります。 ( ldconfig
を参照)、再利用は必要ないことを既に示しました。
質問をしていて、答えが明らかでない場合は、今いる場所にとどまります。モノリシックアプリケーションの構築に時間がかかりすぎたり、グループが一緒に作業するのが非常に面倒な場合は、ライブラリに移行する説得力のある理由はありません。必要に応じてアプリケーションのファイルで動作するテストフレームワークを構築するか、同じファイルを使用する別のプロジェクトを作成するだけで、テストAPIをアタッチし、それを使用してライブラリを構築できます。
出荷の目的で、ライブラリを構築して1つの大きな実行可能ファイルを出荷する場合は、いつでも静的にリンクできます。
モジュール性が開発に役立つ場合、つまり、ファイルの変更について他の開発者と常に頭を突き合わせている場合、ライブラリは役立つ可能性があります が、それも保証ではありません。優れたオブジェクト指向コード設計を使用すると、関係なく役立ちます。
さらに、Cから呼び出し可能にしたい場合を除き、ライブラリを作成するために必要なC呼び出し可能インターフェイスで関数をラップする理由はありません。
共有ライブラリには頭痛の種がありますが、共有ライブラリはここに行く正しい方法だと思います。ほとんどの場合、アプリケーションの一部をモジュール化し、ビジネスの他の場所で再利用できるようにする必要があります。また、このモノリシック実行可能ファイルのサイズによっては、1つの大きなファイルではなく、更新されたライブラリのセットをアップロードする方が簡単な場合があります。
IMO、ライブラリは一般的に、より良いコード、よりテスト可能なコードにつながり、車輪を再発明しないので、将来のプロジェクトをより効率的な方法で作成することができます。
要するに、私はあなたの同僚に同意します。
Linux(およびWindows)では、C ++を使用して共有ライブラリを作成でき、C関数のエクスポートを使用してロードする必要はありません。
つまり、classA.cppをclassA.soにビルドし、classB.cppをclassA.soにリンクするclassB(.exe)にビルドします。実際にやっているのは、アプリケーションを複数のバイナリファイルに分割することだけです。これには、コンパイルが速く、管理が簡単で、テスト用にそのライブラリコードだけを読み込むアプリケーションを作成できるという利点があります。
すべてはまだC ++で、すべてがリンクしていますが、.soは静的にリンクされたアプリケーションとは別のものです。
今、実行時に別のオブジェクトをロードする場合(つまり、実行時までロードするオブジェクトがわからない場合)、c-exportsで共有オブジェクトを作成する必要がありますが、これらの関数を手動でロードします。リンカーを使用してこれを行うことはできません。