13

私が働いている会社は、Delphiでシステムを開発しています。このシステムには、数十のexeモジュールが含まれており、ソースコードに関しては、それぞれがある程度同一です。悲しいことに、誰もライブラリを使用して共有コードを挿入することを気にしませんでした。つまり、これらすべてのモジュールが共有するコードでバグ修正を行うたびに、プログラマーはそれらすべてを個別に修正する必要があります。いつもとても時間がかかります...

共有コードをライブラリに入れる方法を見つけることにしました。DLLとBPLを検討しました。この場合、BPLはプログラマーにとってはるかに使いやすく、面倒ではないように見えました。特に、コードがソフトウェアでのみ使用され、Delphiでのみ使用されていることがわかりました。

すべてのexeモジュールで共有されているすべてのコードをBPLに入れて、すべてがうまくいくように見えますが、理解できないことがいくつかあり、説明していただければ幸いです。

  1. コードをBPLに分割した後、私が期待したのは、作成したBPLを使用してexeファイルを展開するだけで十分であるということでした。しかし、rtl100.bplとvcl100.bplも必要であることが判明しました。なんでそうなの?exeとBPLのみをデプロイしたい。ボーランドやサードパーティ企業が提供する大量のライブラリをエンドユーザーに提供したくありません:)。以前にコンパイルされていたので、exe内でコンパイルしてほしい。それは可能ですか?

  2. 私がこれまでにしたことは次のとおりです。

    • すべての共有pasユニットをBPLに配置しました。各BPLには同じカテゴリに属する​​ユニットが含まれているため、プログラマーは特定のBPLでどのコードを期待するかが明確になります。
    • 各BPLは、「ランタイムおよびデザインタイム」ライブラリです。
    • 各BPLは「明示的に再構築」されます。後者の2つは、BPLのデフォルトのプロジェクト設定です。
  3. そして、exeプロジェクトに関しては:

    • 以前にBPLに配置したすべてのユニットを削除しました。
    • BDS2006の[ツール]->[パッケージのインストール]メニューからBPLをインストールしました。
    • exeプロジェクトの設定で、[ランタイムパッケージを使用してビルドする]オプションをオンにし、下の編集ボックスにすべてのBPLパッケージを一覧表示しました(そこに表示される他のすべてのパッケージをクリアしたため、パッケージのみ)。

これが私がしたすべてです。exeプロジェクトは正しくコンパイルされますが、すべてのBPLがソースコードファイルと一緒に保存されていても、BPLのソースコードにアクセスできません(exeプロジェクトからそのコードに移動できません)。なんで?それは私には奇妙に思えます。

私はいつも長い説明を書く傾向があります-申し訳ありません:)。よろしくお願いします。私が言及したポイントについて、いくつかの説明が必要です。BPLのみを使用してexeを展開すること、全体として行ったことの正確さ、およびBPLソースコードに移動できないことです。事前にどうもありがとうございました!


議論してくれてありがとう。私が選んだアプローチは良い考えではないと言う人もいました。私たちのソフトウェアは100以上のモジュールで構成されています(それらのほとんどはさまざまなデバイスのドライバーのようなものです)。それらのほとんどは同じコードを共有します-ほとんどの場合クラス。問題は、これらのクラスが常に個別のスタンドアロンpasユニットに配置されるとは限らないことです。つまり、共有コードは、モジュールに固有のコードを含むユニットに入れられることがよくあります。つまり、共有クラスのバグを修正する場合、それが定義されているpasユニットをすべてのソフトウェアモジュールにコピーして再コンパイルするだけでは不十分です。残念ながら、固定されたコードを1つずつコピーして、適切なユニットとクラスに貼り付ける必要があります。これには多くの時間がかかります。これは私が排除したいことであり、正しいアプローチを選択します。助けてください。

BPLを使用することは良い解決策になると思いましたが、一部の人が言及したように、いくつかの欠点があります。最悪の問題は、各EXEに複数のBPLが必要な場合、テクニカルサポート担当者がどのEXEにどのBPLが必要かを把握し、エンドユーザーに適切なファイルを提供する必要があることです。ソフトウェアアップデーターがない限り、これは技術者とエンドユーザーの両方にとって大きなメリットになります。彼らは確かに迷子になって怒ります:-/。

また、互換性の問題が発生する可能性があります-1つのBPLが多くのEXEで共有されている場合、1つのBPLの変更は、1つのEXEには有効であり、他のいくつかのEXEには不利になる可能性があります-@WarrenP。

非常に多くのプロジェクトでバグ修正をより迅速に行うには、どうすればよいですか?私は次のアプローチの1つを考えます。もっと良いアイデアがあれば教えてください。

  • 共有コードを個別のスタンドアロンpasユニットに配置します。そのため、そのうちの1つにバグ修正がある場合は、それをすべてのプロジェクトにコピーして(古いファイルを上書きして)、すべてを再コンパイルするだけで十分です。

この解決策は、後から変更されたコードが具体化されている限り、問題ないようです。しかし、一般的な使用機能と手順を備えたpasユニットもあります。これは、多くの場合、変更を取り消すものです。必要に応じて、単一のプロジェクトで新しい機能を追加します。したがって、100個のモジュールの1つに新しい関数を記述し、それを汎用ユニットに配置するとします。1、2か月後、別のモジュールを変更し、2か月前に作成したものと同じ関数が必要だと思います。モジュールを見つけて(それがどれであったかを覚えていないと難しい)、関数をコードにコピーする必要があります。そして明らかに、一般的な使用単位は、各プロジェクトに個別に保存されている限り、モジュールごとに完全に異なります。そして、実行するバグ修正がある場合...全体の話が繰り返されます。

  • すべての共有コードのBPLを作成しますが、EXEをスタンドアロンにするために、それらをEXEにリンクします。

私にとっては今のところ最善の解決策のようですが、いくつかの短所があります。BPLでバグ修正を行う場合、各プログラマーは自分のコンピューターのBPLを更新する必要があります。彼らが忘れたらどうしますか?それでも、それは小さな問題だと思います。変更についてお互いに通知するように注意すれば、すべてがうまくいくはずです。

  • @CodeInChaos:あなたを正しく理解したかどうかはわかりません。プロジェクト間でpasファイルを共有するという意味ですか?どうやってするか?ソースコードはSVNに保存されます。つまり、共有コードを別のフォルダーに保存し、すべてのプロジェクトでそのコードを検索する必要がありますね。そして、SVNからプロジェクトとそれが依存するすべてのフォルダーをダウンロードします...

どうか、私が良い解決策を選ぶのを手伝ってください。ソフトウェア開発への愚かなアプローチのために、バグ修正で必要以上の時間とお金を会社が失うことを望んでいません。

どうもありがとうございます。

4

4 に答える 4

11

この質問には受け入れられた答えがありますが、私はそれを突き刺すつもりです。

タイトルはプロジェクトをbplsに分割する方法を尋ねていますが、本当の質問は「プロジェクト間でコードを共有するための最良の方法は何ですか?」であるように見えます。

これを行うにはいくつかの方法があります。

  • 共有ユニット
  • DLL
  • BPL

どちらの方向に進んでも、プロジェクトを再構築する必要があります。あなたの説明から、各プロジェクトは比較的孤立して開発されているように思えます。コードはコピー/貼り付けを使用して共有されるため、すぐに同期が外れ、多くの重複作業が発生します。それでは、コードを共有するための各手法を調べてみましょう。

共有ユニット


これは最も簡単なアプローチです。共有の場所を作成し、プロジェクト間で再利用するコードをこの場所に配置します。ユニットはプロジェクトに静的にリンクされているため、メインの実行可能ファイルとともに追加の依存関係を展開することを心配する必要はありません。静的にリンクされたユニットは、トラブルシューティングとデバッグがはるかに簡単です。

コンパイラは、共有ユニットを見つけることができる必要があります。コンパイラにどこを見ればよいかを伝える方法は4つあります。

  1. それらをプロジェクトに追加します- SHIFT+ F11-ユニットへの参照をプロジェクトファイル(dpr、dproj)に追加します。ユニットがプロジェクトファイルと同じディレクトリツリーの下にある場合、IDEは通常相対パスを使用します。そうでない場合、絶対パスを使用します。これは、開発者のマシンが同じように構成されていない場合に問題になる可能性があります。
  2. プロジェクトの検索パス- CTRL++ Delphiコンパイラ>検索パス-ディレクトリを追加するSHIFTF11、コンパイラはそこを検索して、プロジェクト内の任意のユニットのuses句に記載されているユニットを検索します。可能であれば、相対パスを使用するのが最善です。環境変数を使用することもできます:$(MyPath)
  3. グローバル検索パス-ツール>オプション>環境オプション>Delphiオプション>ライブラリ-Win32>ライブラリパス-ここにリストされているパスはすべて、マシン上のすべてのプロジェクトで使用できます。これはマシンに依存します
  4. コマンドライン-スクリプトまたはビルド自動化ツールからビルドする場合は、dcc32の-Uスイッチまたはmsbuildの/property:UnitSearchPath=スイッチを使用して検索パスを設定できます。

オプション1と2が最も便利です。

SVNリポジトリに関する限り、プロジェクトと共有ユニットを整理するためのいくつかのオプションがあります。最も簡単なのは、すべてのプロジェクトを共有ユニットとともに単一のトランクの下に配置することです。

Projects
    trunk
        ProjectA
        ProjectB
        ProjectC
        Library (shared units)

何らかの理由で上記の構造が不可能な場合は、次の方法を試すことができます。

ProjectA
    trunk
        Library (branch of main library)
ProjectB
    trunk
        Library (branch of main library)
ProjectC
    trunk
        Library (branch of main library)
Library
    trunk (main library)

この構成では、各プロジェクトのライブラリフォルダーに加えられた変更は、他のプロジェクトですぐには利用できません。各プロジェクトは、定期的にメインのライブラリプロジェクトと変更を同期する必要があります。これの副作用は、他のプロジェクトを壊す変更が他のプロジェクトが同期されるまで遅れることです。これを良いことと悪いことのどちらと見なすかは異なります。一方では、バグに関連するコードが開発者の心の中でまだ新鮮である場合、バグを修正するのは簡単で安価です。一方、単体テストを練習していない場合(これを行うことを強くお勧めします)、コードが非常に壊れやすい場合、または開発者が無謀な変更を行う傾向がある場合は、それらの変更が他のプロジェクトにプッシュされる頻度を制御する必要があります。

DLL


DLLを使用すると、実行時にコードにリンクしてコードを共有できます。これらは、メインの実行可能ファイルまたは別のdllから呼び出すことができる関数を公開します。

dllは実行時に常にリンクされますが、アプリケーションの起動時にロードするか、必要な場合にのみロードするかを決定します。起動時のロードは静的ロードと呼ばれ、Delphiではexternalディレクティブを使用して実行されます。システムAPI呼び出しをラップするrtl/vclクラスの大部分は、静的ロードを使用します。動的ロードでは、必要になるまでdllのロードを遅らせることができます。これは、WinAPI関数LoadLibraryおよびGetProcAddressを使用します。FreeLibraryへの対応する呼び出しは、dllをアンロードします。

残念ながら、標準のdllは、渡すことができるデータ型の種類を制限します。Delphi以外のプロジェクトからdllにアクセスする必要がある場合は、cスタイルのデータ型の使用に制限する必要があります。Delphiプロジェクトでdllのみを使用する場合は、dllでSharedMemユニットとそれを使用するプロジェクトを使用すれば、Delphi文字列と動的配列も安全に使用できます。

dll内のオブジェクトを問題なく安全に使用できますが、dllとアプリケーションの間でオブジェクトを渡したい場合は、オブジェクトのデータを抽出してプリミティブ型として渡し、もう一方の端でオブジェクトに再アセンブルする必要があります。これは(逆)シリアル化またはマーシャリングと呼ばれ、独自にローリングするよりもはるかに簡単な方法があります。

COM(コンポーネントオブジェクトモデル)はDelphiで十分にサポートされていますが、少し学習曲線があります。COMオブジェクトの使用は非常に簡単ですが、COMに慣れていない場合は、オブジェクトの設計に時間がかかります。COMには、言語に依存せず、Windowsプラットフォームを対象とするほとんどの言語(.NET Frameworkを対象とする言語を含む)でサポートされているという利点があります。

Bpls


Bpl(単に「パッケージ」とも呼ばれます)は、オブジェクトの操作を非常に簡単にする特別にフォーマットされたdllです。標準のdllと同様に、実行時にリンクされ、静的または動的にロードできます。これらはCOMdllよりも習得と使用が簡単で、COMよりもプロジェクトへのシームレスな統合を提供します。パッケージは、bplとdcpの2つの部分で構成されています。dcpは、通常のユニットファイルをコンパイルするときに生成されるdcuファイルに似ていますが、ユニットが多数含まれている点が異なります。bplでコンパイルされたクラスの使用は、プロジェクトのパッケージリストにdcpを追加してから、プロジェクトのユニットの1つのuses句にユニットを追加するのと同じくらい簡単です。

アプリをデプロイするときは、bplもインストールする必要があります。他の人が指摘しているように、少なくともrtlパッケージを含める必要があり、フォームを使用する場合はvclパッケージを含める必要があります。Borlandが提供するbplsをプロジェクトにデプロイする方法があります。プロジェクトに必要なユニットのみを含む「ミニ」rtlパッケージを作成できます。含めるユニットを決定するのは困難です。

概要


あなたが与えた説明から、静的にリンクする共有ユニットファイルのライブラリを作成することが最も便利なルートかもしれません。また、 Simianというプログラムを試してみることをお勧めします。共有ライブラリに含めるために、コードベース内の重複コードを追跡するのに役立ちます。これはpascalを直接サポートしていませんが、構成を少し調整するだけでプレーンテキストパーサーを使用して十分に適切な仕事をします。

また、単体テストの価値を十分に強調することはできません。特に共有ライブラリに移行する場合。頻繁に実行される一連の適切に記述された単体テストは、開発者がクラスを変更し、無関係のプロジェクトを中断したときに即座にフィードバックを提供します。

于 2011-09-08T17:24:29.420 に答える
8

EXEと2つの異なるBPLモジュールを含むプロジェクトがあり、そのコードベースのどこかに、という行があるとしますif MyObject is TStringList then DoSomething;。オペレーターはis、VMTに格納されているオブジェクトのクラスメタデータを調べ、ポインターを介してVMTのチェーンをたどりClassParent、それらのいずれかがのクラス参照(VMTポインターでもある)と一致するかどうかを確認しますTStringList。これが正しく機能することを確認するには、分割されたBPLの数に関係なく、プログラム全体で同じTStringList用の単一のVMTが必要です。つまり、独自のパッケージに含まれている必要があります。そのため、rtl*.bplやvcl*.bplなどのシステムランタイムが必要であり、それについてできることはあまりありません。これは、BPLを使用する場合の価格の一部です。

デバッグできない場合は、BPLがデバッグ情報を有効にしてビルドされていること、およびデバッガーがDCP(BPLのデバッグ情報を含むファイル)が配置されているフォルダーを見つける方法を認識していることを確認する必要があります。また、デバッグ対応のDCPがご使用のバージョンに付属していないため、システムBPLをトレースすることはできません。それらはかなり最近追加されました、私はXEで思うが、それはD2010にあったかもしれません。

于 2011-08-12T16:53:24.123 に答える
2

ソースコードを閲覧できないのはなぜですか?これを修正する方法はありますか?

パッケージに含まれているユニットのソースコードは、プロジェクト、ライブラリ、または検索パスのいずれにも含まれていないため、参照できません。

検索パスの構成

これを解決する方法は、プロジェクトの検索パスにディレクトリを追加することです。このように、コンパイラはそれらのファイルを認識しません(そしてそれらを再コンパイルしようとはしません)が、IDEはそれらのコンテンツを参照してデバッグすることができます。

于 2011-08-12T17:29:31.417 に答える
1

「exeプロジェクトの設定で、「ランタイムパッケージでビルドする」オプションをチェックしました

そのため、BPLなどなしではデプロイできません。このオプションは多くの開発者にとって混乱を招きます。「ランタイムパッケージを使用してビルドする」とは、実行時にbplが存在する必要があることを意味します。このオプションのチェックを外すと、パッケージはcompileTimeでexeにリンクされます。(exeのサイズは大きくなります。)「ランタイムパッケージを使用してビルド」の背後にある考え方は、exeのサイズを小さくし、複数のアプリがexe @ compileTimeにリンクされていないため、共通のbplを共有できるようにすることです。これは利点です。あなたが今経験している欠点-あなたはあなたのexeファイルであなたのbplを配布しなければなりません。

于 2011-08-13T04:02:40.253 に答える