かなり大きな(> 300K)、かなり成熟したCコードベースをC++に変換するにはどうすればよいでしょうか。
想定しているCIの種類は、モジュールにほぼ対応するファイルに分割されます(つまり、典型的なOOクラスベースの分解より細かい)、プライベート関数とデータの代わりに内部リンケージを使用し、外部パブリック関数とデータのリンケージ。グローバル変数はモジュール間の通信に広く使用されます。非常に広範な統合テストスイートが利用可能ですが、ユニット(モジュール)レベルのテストはありません。
私は一般的な戦略を念頭に置いています:
明らかに、これはかなりの作業になります。この種の翻訳に関するケーススタディ/戦争の話はありますか?代替戦略?他に役立つアドバイスは?
注1:プログラムはコンパイラーであり、おそらく他の何百万ものプログラムがその動作が変化しないことに依存しているため、大規模な書き換えはほとんどオプションではありません。
注2:ソースはほぼ20年前のものであり、年間30%のコードチャーン(変更された行+追加された行/以前の合計行数)をおそらく持っています。つまり、大幅に維持および拡張されます。したがって、目標の1つは、管理性を向上させることです。
[質問のために、C++への変換は必須であり、Cのままにすることはnotオプションであると想定します。この条件を追加するポイントは、「Cのままにする」の回答を取り除くことです。]
数か月前にほぼ同じことを始めたばかり(10歳の商用プロジェクトで、元々は「C++はスマートstruct
sを使用したC」という哲学で書かれている)の使用をお勧めしますゾウを食べるのに使用するのと同じ戦略:一度に一口ずつ食べる。 :-)
可能な限り、他の部分への影響を最小限に抑えて実行できる段階に分割します。 Federico Ramponi が示唆するように、ファサードシステムを構築することは良いスタートです-すべてがC++ファサードを持ち、それを介して通信している場合は、モジュールの内部を変更できることを確信を持って変更できます。それらの外に影響を与えます。
(以前の小規模なリファクタリングの取り組みにより)部分的なC++インターフェースシステムが既に配置されていたため、このアプローチは私たちのケースでは難しくありませんでした。すべてがC++オブジェクトとして通信するようになると(数週間かかり、完全に別のソースコードブランチで作業し、承認されたとおりにすべての変更をメインブランチに統合しました)、完全にコンパイルできないことはほとんどありませんでした。私たちがその日に出発する前の作業バージョン。
切り替えはまだ完了していません-暫定リリースでは2回一時停止しています(数週間ごとにポイントリリースを目指しています)が、順調に進んでおり、問題について顧客から苦情が寄せられていません。私たちのQA担当者も、私が覚えている問題を1つだけ見つけました。 :-)
何について:
なぜ「C++への変換が必須」なのですか? Cコードをラップして巨大なクラスなどに変換する必要はありません。
あなたのアプリケーションには多くの人々が取り組んでおり、壊されないようにする必要があります。 OOスタイルへの大規模な変換に真剣に取り組んでいる場合、必要なのは、作業を自動化するための大規模な変換ツールです。
基本的な考え方は、データのグループをクラスとして指定し、ツールにコードをリファクタリングしてそのデータをクラスに移動し、そのデータのみの関数をそれらのクラスに移動し、そのデータへのすべてのアクセスをクラスの呼び出しに変更することです。
自動化された事前分析を実行して統計クラスターを形成し、いくつかのアイデアを得ることができますが、グループ化するデータ要素を決定するには、アプリケーションを認識するエンジニアが必要です。
このタスクを実行できるツールは、私たちの DMSソフトウェアリエンジニアリングツールキット です。 DMSには、コードを読み取るための強力なCパーサーがあり、Cのコードをコンパイラの抽象構文ツリーとしてキャプチャします(従来のコンパイラとは異なり)、300K SLOC全体のフロー分析を計算できます。 DMSには、「バック」エンドとして使用できるC++フロントエンドがあります。 C構文をC++構文にマップする変換を記述します。
大規模なアビオニクスシステムでの主要なC++リエンジニアリングタスクは、この種のアクティビティにDMSを使用するのがどのようなものかについていくつかのアイデアを与えます。 www.semdesigns.com/Products/DMS/DMSToolkit.htmlのテクニカルペーパーを参照してください。特に、自動プログラム変換によるC++コンポーネントモデルのリエンジニアリング
このプロセスは、気弱な人のためのものではありません。しかし、大規模なアプリケーションの手動リファクタリングを検討するだれよりも、すでにハードワークを恐れていません。
はい、私はその会社のチーフアーキテクトとして関わっています。
Cインターフェースを介してC++クラスを作成します。 Cコードに触れないことで、混乱の可能性が減り、プロセスが大幅に高速化されます。
C++インターフェースを起動したら、次に、コードをコピーしてクラスに貼り付けるという簡単なタスクです。あなたが述べたように-このステップの間、ユニットテストを行うことが重要です。
GCCは現在、CからC++への移行中です。明らかに、CCCとC++の共通サブセットにすべてを移動することから始めました。彼らがそうしたように、彼らは-Wc++-compat
。それはあなたの旅の最初の部分にあなたを連れて行くはずです。
後者の部分については、実際にすべてをC++コンパイラーでコンパイルしたら、慣用的なC++の対応物があるものを置き換えることに焦点を当てます。たとえば、Cマクロを使用して定義されたリスト、マップ、セット、ビットベクトル、ハッシュテーブルなどを使用している場合、これらをC++に移行することで多くのことを得ることができます。同様にOOを使用すると、C OOイディオム(構造継承など)を既に使用している場合、およびC++を使用するとコードがより明確になり、型チェックが向上するという利点が得られます。
あなたのリストは問題ないようですが、コーディングを行う前に、最初にテストスイートを確認し、それをできるだけ厳しくすることをお勧めします。
おそらく、開始したい方法以外に考慮すべき2つのことは、何をしたいかfocusと、どこにしたいかstopです。
あなたは大きなコードチャーンがあると述べています、これはあなたの努力をfocusするための鍵かもしれません。多くのメンテナンスが必要なコードの部分を選択することをお勧めします。成熟した/安定した部分は明らかに十分に機能しているため、ファサードを備えたいくつかの窓のドレッシングなどを除いて、そのままにしておくことをお勧めします。
どこで停止したいかは、C++に変換したい理由によって異なります。これ自体が目標になることはほとんどありません。サードパーティへの依存が原因である場合は、そのコンポーネントへのインターフェースに集中してください。
私が取り組んでいるソフトウェアは巨大で古いコードベースで、数年前にCからC++に「変換」されました。 GUIがQtに変換されたためだと思います。今でも、ほとんどの場合、クラスを含むCプログラムのように見えます。パブリックデータメンバーによって引き起こされた依存関係を解消し、手続き型のモンスターメソッドを使って巨大なクラスを小さなメソッドやクラスにリファクタリングすることは、実際にはうまくいかなかったと思います。
NB。 「レガシーコードを効果的に使用する」の本をご存知でしょうか。
別の愚かな考えを投げましょう:
あなたのツールはコンパイラーであり、「実際には、タイプマッチングだけでなく、複数のディスパッチでのパターンマッチングの方が優れている」と述べています。
maketea をご覧ください。これは、ASTのパターンマッチング、および抽象文法からのAST定義、ビジター、トランスフォーマーなどを提供します。
これが私がすることです:
小規模または学術的なプロジェクト(たとえば、10,000行未満)の場合は、書き換えがおそらく最良のオプションです。あなたは好きなようにそれを因数分解することができ、それはあまり時間がかかりません。
実際のアプリケーションがある場合は、C++としてコンパイルして(通常は主に関数のプロトタイプなどを修正することを意味します)、リファクタリングとOO wrapping。)に取り組むことをお勧めします。もちろん、私は、コードがOOで構成されている必要があるという哲学に同意しません。C++コードを受け入れられるようにします。ピースごとの変換、リライト、リファクタリングを行います。必要に応じて(機能またはユニットテストを組み込むため)。