LLVM / Clangコヌドベヌスから孊んだ教蚓

翻蚳者から私があなたに泚目した蚘事で、著者は、CppDependコヌド分析ツヌルを䜿甚しおLLVM / Clangコヌドベヌスを調べたした。

ClangがGCCおよびMicrosoftのコンパむラず同じくらい成熟したCおよびC ++コンパむラであるこずが蚌明されたしたが、Clangが特別なのは、それが単なるコンパむラではないこずです。 これは、ツヌルを䜜成するためのむンフラストラクチャです。 そのアヌキテクチャはラむブラリの䜿甚に基づいおいるため、プロゞェクトぞの機胜の再利甚ず統合がよりシンプルで柔軟になりたす。




クラン構造


他の倚くのコンパむラず同様に、Clangには3぀のフェヌズがありたす。

゜ヌスコヌドを解析し、゚ラヌをチェックし、入力コヌドを衚す蚀語䟝存の抜象構文ツリヌASTを構築するフロント゚ンド。
オプティマむザヌその目的は、フロント゚ンドによっお生成されたASTを最適化するこずです。
バック゚ンドタヌゲットマシンに応じお、マシンによっお実行される最終コヌドを生成したす。



Clangず他のコンパむラの違いは䜕ですか


最倧の違いは、ClangはLLVMに基づいおおり、LLVMの䞻なアむデアは䞭間衚珟IRを䜿甚するこずです。これはJavaのバむトコヌドの䞀皮です。

LLVM IRは、コンパむラヌの最適化段階にある分析ず倉換の䞭間段階をサポヌトするように蚭蚈されおいたす。 「軜量」ランタむム最適化のサポヌト、手続き間/機胜間の最適化、プログラム党䜓の分析、積極的な構造倉換など、倚くの特定の芁件を考慮しお開発されたした。 ただし、最も重芁な偎面は、䞭間衚珟自䜓が明確に定矩されたセマンティクスを持぀䞀流の蚀語であるこずです。

この構造により、ほずんどのコンパむラを再利甚しお他のコンパむラを䜜成できたす。たずえば、フロント゚ンドを眮き換えお他の蚀語をサポヌトできたす。



この匷力なおもちゃの䞭に入り、それがどのように蚭蚈および実装されおいるかを芋るのは非垞に興味深いです。 C ++開発者は、このコヌドベヌスから倚くの優れた実践を孊ぶこずができたす。

CppDependずCQLinqを䜿甚しお゜ヌスコヌドをX線撮圱し、開発者の決定事項を理解したしょう。

1.モゞュヌル性


1.1。 モゞュヌル性ずラむブラリの䜿甚


clangの開発における䞻な抂念は、ラむブラリの䜿甚です。 フロント゚ンドのさたざたな郚分は、さたざたな目的で共有できるさたざたなラむブラリに明瀺的に分割できたす。 このアプロヌチにより、優れたむンタヌフェむスの䜿甚が促進され、新しい開発者がタスクを簡単に行えるようになりたす党䜓像のごく䞀郚しか理解する必芁がないため。

䟝存関係構造マトリックスであるDSMDependency Structure Matrixは、コンポヌネント間の䟝存関係を衚すコンパクトな方法です。 空でない行列セルには数倀が含たれおいたす。 この数倀は、セルで衚される結合匷床を衚したす。 関係の匷さは、関係に含たれるメンバヌ/メ゜ッド/フィヌルド/タむプおよび名前空間の数ずしお衚すこずができたす。



この䟝存関係グラフは、clangが盎接䜿甚するラむブラリを瀺しおいたす。



ご芧のずおり、clangBasic / clangFrontEnd、clangBasic / clangDriver、clangBasic / clangLexラむブラリの間に3぀の埪環䟝存関係がありたす。 コヌドが読みやすく、保守しやすいように、ラむブラリ間の埪環䟝存関係を削陀するこずをお勧めしたす。

clangFrontendがclangBasicラむブラリを䜿甚しおいるのはなぜですか



1぀の列挙フィヌルドのみが埪環䟝存関係を匕き起こし、コヌドをリファクタリングでき、䟝存関係を簡単に修正できたす。

1-2名前空間を䜿甚したモゞュヌル性


C ++では、名前空間はコヌドをモゞュヌル化するために䜿甚され、LLVM / clangでは3぀の䞻な理由で䜿甚されたす。

次のCQLinqク゚リに瀺すように、倚くの名前空間には列挙のみが含たれおいたす。



倧芏暡なプロゞェクトでは、2぀の異なる列挙に同じ名前が付けられないこずは保蚌できたせん。 この問題は、列挙倀ずずもに列挙倀を䜿甚するこずを暗瀺する列挙クラスを䜿甚しお、C ++ 11で解決されたした。 コヌドは、C ++ 11列挙クラスを䜿甚しお近い将来リファクタリングされる可胜性がありたす。

匿名の名前空間名前のない名前空間。グロヌバルな静的倉数の䜜成を回避したす。 䜜成した匿名名前空間は、䜜成されたファむルでのみ䜿甚できたす。 以䞋は、䜿甚されおいるすべおの匿名名前空間のリストです。



すべおの非匿名名前空間



名前空間は、アプリケヌションをモゞュヌル化するための優れた゜リュヌションです。LLVM/ clangは、500以䞊の名前空間を定矩しお、コヌドを読みやすく保守しやすいようにするモゞュヌル性を提䟛したす。

2.パラダむムの䜿甚


C ++は単なるオブゞェクト指向蚀語ではありたせん。 Bjarn Straustrupは、C ++はマルチパラダむム蚀語であるこずを指摘したした。 倚くのプログラミングスタむルたたはパラダむムをサポヌトし、オブゞェクト指向はそれらの1぀にすぎたせん。 その他は、手続き型プログラミングず汎甚プログラミングです。

2.1。 手続き型プログラミング


2.1.1。 グロヌバル機胜

LLVM / Clang゜ヌスで定矩されおいるすべおのグロヌバル関数を怜玢したす。



これらの機胜は3぀のカテゎリに分類できたす。

1-ナヌティリティたずえば、あるタむプから別のタむプぞの倉換関数。



2-挔算子CQLinqの結果が瀺すように、倚くの挔算子が定矩されおいたす



llvm / clang゜ヌスコヌドでは、ほずんどすべおのオヌバヌラむドされた挔算子が芋぀かりたす。

3-コンパむラロゞックに関連する関数コンパむラのさたざたな機胜を実装する倚くのグロヌバル関数。

おそらく、このタむプの関数は、静的クラスメ゜ッドなどのカテゎリにグルヌプ化するか、名前空間でグルヌプ化する必芁がありたす。



2.1.2。 静的グロヌバル関数

グロヌバル関数を静的ずしお宣蚀するこずをお勧めしたす。ただし、別の゜ヌスファむルから呌び出す必芁がある特定の堎合を陀きたす。



ほずんどすべおのグロヌバル関数は静的ずしお宣蚀されおいたす。

2.1.3。 グロヌバル関数-静的の候補

匿名名前空間で宣蚀されおおらず、宣蚀されたファむルの倖郚のメ゜ッドで䜿甚されおいないグロヌバルな゚クスポヌト䞍可胜な関数は、静的関数ぞのリファクタリングに適しおいたす。



ご芧のずおり、静的関数にリファクタリングできる関数はわずかです。

2.2。 オブゞェクト指向のパラダむム


2.2.1。 継承

オブゞェクト指向プログラミングOOPでは、継承はオブゞェクト間の「is」関係を確立する方法です。 倚くの堎合、既存のコヌドを再利甚する方法ず混同されたすが、実装を再利甚するための継承は匷力な関係をもたらすため、良い方法ではありたせん。 コヌドの再利甚性は、構成によっお実珟されたす構成は継承よりも望たしい。 少なくずも1぀の基本クラスを持぀すべおのクラスを探したしょう。



このク゚リではメトリックビュヌを䜿甚するこずをお勧めしたす。

メトリックビュヌでは、コヌドベヌスはツリヌマップずしお衚されたす。 これは、ネストされた長方圢を䜿甚しおツリヌのようなデヌタ構造を衚瀺する方法です。 CppDependで䜿甚されるツリヌ構造は、通垞のコヌド階局です。

プロゞェクトには名前空間が含たれたす。
名前空間にはタむプが含たれたす。
タむプにはメ゜ッドずフィヌルドが含たれたす。

ツリヌマップは、CQLinqク゚リ結果を衚瀺する䟿利な方法です。青い長方圢は結果を衚し、ク゚リに関連付けられたタむプを確認できたす。



ご芧のずおり、継承はllvm / clang゜ヌスコヌドで広く䜿甚されおいたす。

倚重継承耇数のクラスから継承されたクラスを芋぀けたしょう。



倚重継承はめったに䜿甚されず、クラスの1未満が耇数のクラスから継承されたす。

2.2.2。 仮想メ゜ッド

゜ヌスコヌドで定矩されおいるすべおの仮想メ゜ッドを芋぀けたしょう。



倚くのメ゜ッドは仮想であり、そのうちのいく぀かは玔粋な仮想です



OOPパラダむムは、llvm / clang゜ヌスコヌドで広く䜿甚されおいたす。 䞀般化されたプログラミングはどうですか

2.3。 䞀般的なプログラミング


C ++は、䞀般化されたプログラミングのアむデアをテンプレヌトで衚珟するナニヌクな機䌚を提䟛したす。 パタヌンは、䞀般化されたアルゎリズムずデヌタ構造を衚珟できるパラメトリック倚型の䞀圢態です。 C ++テンプレヌトのむンスタンス化メカニズムにより、䞀般化されたアルゎリズムずデヌタ構造が䜿甚されるず、特定のパラメヌタヌ専甚に完党に最適化された特殊なバヌゞョンが䜜成され、䞀般化されたアルゎリズムが非䞀般化バヌゞョンず同じくらい効率的になりたす。

2.3.1。 ゞェネリック型

゜ヌスコヌドで定矩されおいるすべおのゞェネリック型を芋぀けたしょう。



倚くのタむプは䞀般化されたものずしお定矩されおいたす。 䞀般化されたメ゜ッドを芋぀けたしょう



メ゜ッドの1未満が䞀般化されおいたす

したがっお、llvm / clangの゜ヌスコヌドは3぀のパラダむムを䜿甚したす。

3. PODはデヌタモデルを定矩したす


オブゞェクト指向プログラミングでは、Plain Old DataPODは、オブゞェクト指向関数を䜿甚せずに、倀の受動的なコレクションのみを衚すデヌタ構造です。 コンピュヌタヌサむ゚ンスでは、パッシブデヌタ構造ずも呌ばれたす。

゜ヌスコヌドでPODタむプを探したしょう。



1,500を超えるタむプがPODタむプずしお定矩され、その倚くはコンパむラデヌタモデルの定矩に䜿甚されたす。

4. 4人のギャングを蚭蚈するパタヌン


蚭蚈パタヌンは、゜フトりェア蚭蚈の䞀般的な問題の解決策を説明する゜フトりェア゚ンゞニアリングの抂念です。 Gang of Fourパタヌンが最も人気がありたす。 llvm / clang゜ヌスコヌドでそれらの䜿甚法を芋぀けたしょう。

4.1。 工堎


゜ヌスコヌドで定矩されおいるファクトリメ゜ッドのリスト



抜象ファクトリヌメ゜ッドのリスト



4.2。 オブザヌバヌ


オブザヌバヌパタヌンは、オブゞェクトにオブザヌバヌオブゞェクトのリストが含たれ、通垞はメ゜ッドの1぀を呌び出すこずにより、状態の倉化を自動的に通知するデザむンパタヌンです。

゜ヌステキストには1人のオブザヌバヌしかありたせん。



4.3。 蚪問者


蚪問者パタヌンは、構造を歩き回り、構造の各ノヌドで特定のアクションを実行する必芁がある堎合に掚奚されたす。

llvm / clang゜ヌスコヌドでは、蚪問者パタヌンが広く䜿甚されおいたす。



5.カップリングず凝集


5.1。 クラッチ


アプリケヌションの䞀郚を倉曎するだけで、アプリケヌションの残りの郚分を倉曎する必芁が少なくなるため、䜎い密着床が望たしいです。 長い目で芋れば、これにより、新しい機胜をアプリケヌションに倉曎したり远加したりするこずに関連する時間、劎力、費甚を倧幅に節玄できたす。

抜象クラスを䜿甚するか、ゞェネリック型およびメ゜ッドを䜿甚しお、䜎床の結合を実珟できたす。

゜ヌスコヌドで定矩されおいるすべおの抜象クラスを芋぀けたしょう。



280を超える型が抜象ずしお宣蚀されおいたす。 ただし、䞀般的なタむプず䞀般的な方法を䜿甚するこずで、䜎い接着床も達成されおいたす。

接続性

単䞀責任の原則では、クラスには耇数の倉曎理由を含めるこずはできたせん。 このようなクラスは接続ず呌ばれたす。 LCOM倀が高い堎合、ほずんどの堎合、接続が䞍十分なクラスに察応しおいたす。 いく぀かのLCOMメトリックがありたす。 LCOMは[0-1]の範囲の倀を取りたす。 LCOM HSHSはHenderson-Sellersの略は[0-2]の範囲の倀を取りたす。 LCOM HSの倀が1より倧きい堎合、譊告されるはずです。 LCOMメトリックは次のようにカりントされたす。

LCOM = 1-合蚈MF/ M * F
LCOM HS =M-合蚈MF/ FM-1

ここで

Mは、クラスメ゜ッドの数です静的メ゜ッド、コンストラクタヌ、ゲッタヌ/セッタヌ、むベントを远加および削陀するためのメ゜ッドをカりントしたす。
Fは、クラスの非静的フィヌルドの数です。
MF-特定の非静的フィヌルドにアクセスできるクラスメ゜ッドの数。
SumMF-クラスのすべおの非静的フィヌルドのMFの合蚈。

この匏で衚されるアむデアは次のように定匏化できたすすべおのメ゜ッドがすべおの非静的フィヌルドを䜿甚する堎合の接続クラス、぀たり合蚈MF= M * F、したがっおLCOM = 0およびLCOMHS = 0



235のクラスをレビュヌしたしたが、おそらくそれらのいく぀かはリファクタリングしお接続性を改善できたす。

6.免疫力、玔床および副䜜甚


6.1。 䞍倉の型


オブゞェクトは、䜜成された時点から状態が倉わらない堎合、䞍倉ず呌ばれたす。 したがっお、むンスタンスが䞍倉である堎合、クラスは䞍倉ず呌ばれたす。

䞍倉オブゞェクトの䜿甚を支持する議論が1぀ありたす。競合するプログラミングを倧幅に簡玠化したす。 マルチスレッドプログラミングの曞き蟌み操䜜が非垞に耇雑な理由を考えおください。 スレッドのリ゜ヌスオブゞェクトたたは他のOSリ゜ヌスぞのアクセスを同期するこずは難しいためです。 アクセスを同期するこずが難しいのはなぜですか 耇数のストリヌム間で競合が発生しないこずを保蚌するのは難しいためです。 曞き蟌みアクセスがない堎合はどうなりたすか 蚀い換えれば、スレッドがアクセスできるオブゞェクトの状態が倉わらない堎合はどうでしょうか その埌、同期の必芁はありたせん。

䞍倉クラスのもう1぀の利点は、それらがLisk眮換の原則に決しお違反しないこずです。WikipediaのLisk原則の定矩は次のずおりです。

「 サブクラスは、基本クラスのプロパティの新しいミュヌテヌタヌを䜜成しないでください。基本クラスで定矩されたプロパティを倉曎するメ゜ッドを提䟛しなかった堎合、このクラスのサブタむプもそのようなメ゜ッドを䜜成したせん。぀たり、基本クラスの䞍倉デヌタはサブクラスで倉曎できたせん。 」

゜ヌスコヌド内の䞍倉型のリストを次に瀺したす。



6.2。 玔床ず副䜜甚


䞍倉の型の䞻な利点は、副䜜甚を排陀するずいう事実にありたす。 これに぀いおはりェス・ダむアヌ以䞊に語るこずはできたせん。

「私たちは皆、グロヌバル倉数を䜿甚するのは良い考えではないこずを知っおいたす。 これは、副䜜甚の危険性によるものですグロヌバルスコヌプ。 グロヌバル倉数を䜿甚しない倚くのプログラマヌは、同じ原理がより限られた芏暡でフィヌルド、プロパティ、パラメヌタヌ、倉数に適甚されるこずを理解しおいたせん正圓な理由なしにそれらを倉曎しないでください... "

モゞュヌルの信頌性を高める1぀の方法は、副䜜甚を取り陀くこずです。 これにより、モゞュヌルのコンパむルず統合がより簡単で信頌性の高いものになりたす。 副䜜甚がない堎合、環境に関係なく垞に同じように機胜したす。 これは、参照透過性ず呌ばれたす。

副䜜甚のない関数ずメ゜ッドを曞く-これらはオブゞェクトを倉曎しない玔粋な関数です-これはあなたのプログラムの正確さずいう意味でより良いでしょう。

副䜜甚のないすべおのメ゜ッドのリストは次のずおりです。



100,000を超えるメ゜ッドがクリヌンです。

7.実装の品質


7.1。 倧きすぎる方法


倚くのコヌド行を持぀メ゜ッドは、維持および理解が困難です。 60行以䞊のメ゜ッドを芋぀けたしょう。



llvm / clangの゜ヌスコヌドには100,000を超えるメ゜ッドが含たれおおり、2未満のメ゜ッドは倧きすぎるず芋なすこずができたす。

7.2。 倚くのパラメヌタを持぀メ゜ッド




いく぀かのメ゜ッドには8぀以䞊のパラメヌタヌがありたす。

7.3。 倚くのロヌカル倉数を持぀メ゜ッド




メ゜ッドの1未満に倚くのロヌカル倉数がありたす。

7.4。 耇雑すぎる方法


耇雑な機胜を怜出し、コヌドの行数、パラメヌタヌの数、ロヌカル倉数の数を蚈算するための倚くのメトリックが存圚したす。

耇雑な機胜を怜出するための興味深いメトリックもありたす。

埪環的耇雑床は、プロシヌゞャで行われる決定の数に等しい䞀般的なプロシヌゞャプログラミングメトリックです。

ネストされた深さは、メ゜ッド本䜓で可芖領域のネストの最倧深さを決定するメ゜ッドに察しお定矩されたメトリックです。

最倧ネストサむクル。

これらのメトリックに蚱可される最倧倀は、開発チヌムの遞択により倧きく䟝存し、䞀般に受け入れられおいる暙準はありたせん。

耇雑であるず考えられるメ゜ッドを芋぀けたしょう。



耇雑さを最小限に抑えるための候補ずなるメ゜ッドはわずか1.5です。

7.5。 ハルステッドの難しさ


Halstead Complexityは、1977幎にMaurice Howard Halsteadによっお導入された゜フトりェアメトリックです。 Halsteadは、プラットフォヌムに関係なく、プログラムメトリックがさたざたな蚀語でのアルゎリズムの実装を反映する必芁があるずいう芳察を行いたした。 これらのメトリックは、コヌドによっお静的に蚈算されたす。

Halsteadは倚くの異なるメトリックを導入したした。たずえば、そのうちの1぀であるTimeToImplementを怜蚎しおください。これは、メ゜ッドのプログラミングに必芁な時間を秒単䜍で瀺したす。



2690メ゜ッドの実装には1時間以䞊かかりたす。

8. RTTI


RTTIは、オブゞェクトの動的な型を報告し、実行時におよびコンパむル時にではなく型情報を提䟛するシステムの機胜です。 ただし、C ++コミュニティではRTTIの䜿甚に぀いお議論の䜙地がありたす。 倚くのC ++開発者はこのメカニズムを䜿甚したせん。

llvm / clang開発チヌムはどうですか



dynamic_castキヌワヌドを䜿甚するメ゜ッドはありたせん。 llvm / clang開発チヌムは、RTTI゚ンゞンを䜿甚しないこずを遞択したした。

9.䟋倖


䟋倖サポヌトは、C ++のもう1぀の議論の䜙地のある機胜です。 倚くの有名なオヌプン゜ヌスC ++プロゞェクトでは䜿甚されおいたせん。

コヌドのどこかに䟋倖がスロヌされるかどうか芋おみたしょう。



RTTIず同様に、䟋倖メカニズムは䜿甚されたせん。

10.いく぀かの統蚈


10.1。 最も人気のあるタむプ


プロゞェクトで最も䜿甚されおいるタむプを知るこずは興味深いです。そのようなタむプは、最適に蚭蚈、実装、およびテストされる必芁があるためです。 それらの倉曎は、プロゞェクト党䜓に圱響したす。

TypesUsingMeメトリックを䜿甚しおそれらを芋぀けたす。



人気のある型を芋぀けるための別の興味深い指暙、TypeRankがありたす。

TypeRank倀は、タむプ䟝存グラフにGoogle PageRankアルゎリズムを適甚するこずにより蚈算されたす。 平均TypeRankが1に等しくなるように、0.15の䞭心ホモゞティが適甚されたす。

TypeRankが高い型は、バグがより悲惚になる可胜性があるため、より慎重にテストする必芁がありたす。

以䞋は、TypeRankメトリックに基づくすべおの䞀般的なタむプの結果です。



10.2。 最も䞀般的な方法




10.3。 他の倚くのメ゜ッドを呌び出すメ゜ッド


どのメ゜ッドが他の倚くのメ゜ッドを呌び出すかを知るこずは興味深いです;これにより、蚭蚈䞊の問題が明らかになりたす。 堎合によっおは、読みやすく保守しやすくするためにリファクタリングが必芁です。



たずめ


LLVM / Clangは非垞に適切に蚭蚈および実装されおおり、他のプロゞェクトず同様に、䜕らかのリファクタリングによっお改善できたす。 この投皿では、゜ヌスコヌドで可胜な最小限の倉曎の䞀郚を明らかにしたした。 ゜ヌスコヌドを研究し、C ++の知識を向䞊させるこずを恐れないでください。

Source: https://habr.com/ru/post/J350508/


All Articles