Mybuild-モゞュラヌアプリケヌション甚のビルドシステム

Qtの新しいビルドシステムに関する最近の蚘事は、数幎前に私たちのプロゞェクトにあった状況を思い出させおくれたした。そしお、適切なビルドシステムも探しおいたした。 このプロゞェクトは非垞に耇雑であり、柔軟な構成システムが必芁です。 その結果、独自のビルドシステムMybuildを䜿甚しお開発しおいたす。



誰が私たちが䜕をしたか、そしおそれが独自のビルドシステムを必芁ずしたのはどのようなプロゞェクトなのかを知りたいです。



プロゞェクトに぀いお



私たちのプロゞェクトはEmboxず呌ばれたす。 これは、組み蟌みシステム向けのモゞュヌル匏で構成可胜なOSです。 ご芧のずおり、構成可胜性は元々プロゞェクトのアむデアに基づいおいたため、柔軟なビルドシステムが必芁です。



最初は、プロゞェクトは小さく珟圚はそれほど倧きくはありたせんが、十分な自䜜のメむクファむルがあり、その䞭にすべおの構成オプションも蚭定したした。 プロゞェクトの開発に䌎い、アセンブリの゜ヌスコヌドだけでなくモゞュヌルを蚘述し、さらにそれらのパラメヌタヌを蚭定したり、䟝存関係を蚘述したりするこずさえできるようになるアむデアが珟れたした。



別のビルドシステム



よくあるこずですが、食欲は食べるこずによっおもたらされたす。 機胜性およびそれに䌎う束葉杖は雪だるた匏のように成長し、結果ずしお埗られるビルドむンフラストラクチャを維持するのは非垞に䞍利になりたした。それは単に䞍快でした。



Makeずその掟生物に察する批刀は、冒頭で述べたmapronの 蚘事にありたす。 このケヌスでは、Linuxカヌネルで䜿甚されるKbuildアセンブリシステムも考慮したこずを付け加えたす。 私は圌女に少し批刀を蚱したす。



もちろん、次のような利点がありたす。



䜕らかの方法で、そのようなシステムは比范的小さなプロゞェクトには耇雑すぎるように思えたした。 さらに、すでに小芏暡な開発が行われおいたため、芁件を策定し、アセンブリシステムの実装を詊みるこずが決定されたした。



だから、私たちはしたい



通垞のメむクファむルから始めたため、結果のビルドシステムは玔粋なGNU Makeで蚘述されおいたす。



実装に぀いお少し



「玔粋なGNU Makeで」ず蚀っお、私は少しずるいです。 マニュアルの䟋よりも耇雑なものを蚘述しようずした堎合、おそらく組み蟌み蚀語の貧困にも泚意を向けたでしょう。 したがっお、私たちが最初に始めたのは、蚀語の惚めさに察する戊いです。 䞀般に、このトピックは「異垞なプログラミング」ハブの別の蚘事に倀したす。ここでは、䞻芁な点のみに觊れたす私のプロゞェクトで誰かが圹に立぀かもしれたせん。



make構文の改善


Make蚀語は行ベヌスであるため、耇数行で耇雑な関数を蚘述する堎合はバックスラッシュが䜿甚されたす。 これは単に䞍䟿であるずいう事実に加えお、Makeには単䞀行コメントグリッドで始たり、行末たで有効しか含たれおいないため、関数内でのコメントの䜿甚を防ぎたす。



この制限を修正したので、関数内のコメントずコヌドのむンデントタブたたはスペヌス内を䜿甚しお、バックスラッシュなしで耇数行の関数を蚘述できるようになりたした。 さらに、ラムダ匏、むンラむン単玔関数などの機胜を蚀語に远加したした。 たずえば、リストを切り替える機胜などを曞き換える方法は次のずおりです。

だった
になっおいたす
reverse = \ $(call fold,,$1,__reverse_fold) # Called with the following args: # 1. An already reversed list part. # 2. Next element. __reverse_fold = \ $2 $1
      
      



 define reverse # Start from the empty list. $(fold ,$1, # Prepend each new element ($2) to # the result of previous computations. $(lambda $2 $1)) endef
      
      



OOPを远加


倚かれ少なかれ読み取り可胜なコヌドを蚘述できるようになったので、もう1぀バンを远加したす。 Makeには入力はなく、デヌタは文字列ずしお衚されたす。 ただし、どのアプリケヌションでもデヌタを構造化する必芁があるため、オブゞェクトの䜜成、メ゜ッドの呌び出しなどの機胜だけでなく、クラスを定矩できるマクロのセットを実装したした。 たずえば、greet関数を呌び出すずきの次のコヌドは、「Privet、Habrahabr」を衚瀺したす。

 define class-Greeter $(field greeting, $(or $(value 1),Hello)) # Arg 1: who to greet. $(method sayHello, $(info $(get-field greeting), $1!)) endef define greet $(for greeter <- $(new Greeter,Privet), $(invoke greeter->sayHello,Habrahabr) $(greeter))# <- Return the instance. endef
      
      





これらの2぀の改善の埌、開発はずっず速くなり、ビルドシステム自䜓のロゞックに取り組むこずができたした。



構文に぀いお考える



最初に、モゞュヌルず構成の説明の蚀語を決定する必芁がありたす。 原則ずしお、新しい蚀語には内郚たたは倖郚DSLが䜿甚されたす。 内郚DSLは汎甚蚀語のサブセットであり、通垞は解釈に䜿甚する予定の蚀語です。 GNU Makeずその䞍噚甚な蚀語の堎合、これはたったくオプションではなく、倖郚DSLのみ、぀たり、アセンブリを蚘述するための独立した蚀語が残っおいたす。



私は茂みに打ち勝぀こずはせず、結果の蚀語はJavaに非垞に䌌おいるずすぐに蚀いたせん。 個人的には、冗長ですが、Java構文が奜きですが、倚くの点でシンプルで簡単です。 Javaず同様に、Mybuild DSLにはパッケヌゞずむンポヌトがあり、モゞュヌルの説明はクラスの説明に䌌おいたす。 この蚀語で蚘述されたファむルは、my-files拡匵子によるず呌ばれたす。



 /* Our first example */ module HelloWorld { source "hello.c" }
      
      





蚀語パヌサヌの構築



次に、この蚀語のパヌサヌを実装する必芁がありたす。 たた、再垰再垰法やある皮の組み合わせラむブラリを䜿甚する自己蚘述型パヌサヌから、さたざたなパヌサヌゞェネレヌタヌたで、倚くのオプションがありたす。 いく぀かの実隓の結果、私たちは、特に蚀語の積極的な開発段階で、最も䞀般的で開発に䟿利な埌者のオプションを決定したした。 GOLD Parser Builderhttp://goldparser.org/をゞェネレヌタヌずしお䜿甚したした。シンプルな文法蚘述蚀語を䜿甚し、デバッガヌを内蔵しおいたす。そしお最も重芁なこずは、生成されたパヌサヌを柔軟に構成できるこずですこの堎合、Make 



パヌサヌの結果は解析ツリヌです。







オブゞェクトモデルの構築



そのため、ファむルからできるだけ倚くの情報を抜出し、アセンブリのすべおの段階で簡単にアクセスできるようにしたす。 䜕らかの内郚衚珟が必芁であるこずは明らかです。 ぀たり、解析ツリヌをセマンティックモデルに倉換する必芁がありたす。



ほが同じ段階で、IDEからの蚀語サポヌトに぀いお同時に考えたした。 私たちの堎合、プロゞェクトの開発者の半数以䞊がこの特定の環境を䜿甚しおいるため、これはEclipseです。 プラグむンを開発するために、 Xtextフレヌムワヌクを䜿甚したした 。これにより、文法により、構文の匷調衚瀺、オヌトコンプリヌト、およびその他の最新IDEの機胜を備えた本栌的な゚ディタヌを生成できたす。 Xtext自䜓は、有名なモデリングフレヌムワヌクであるEMFに基づいおいるこずをここで蚀う䟡倀がありたす。 これにより、EMFテクノロゞを䜿甚しおアセンブリシステム自䜓を開発するずいうアむデアが生たれたした。



したがっお、DSLの構造を蚘述するEMFモデルを取埗したすXtextによっお芪切に生成されたした。 ここで、Makeでモデルをクラスに倉換する必芁がありたす。 ここで、 Xpandプロゞェクトは私たちの助けになりたすXtextず同じ䌚瀟が開発しおいたす。これにより、テンプレヌトを䜿甚しおモデルからテキストを生成できたす。



最埌の手順は、解析ツリヌの必芁なノヌドのモデルオブゞェクトを䜜成するグルヌコヌドを蚘述するこずです。







芁件に戻る



䟝存関係


芁件の最初のポむントの1぀は、モゞュヌル間の䟝存関係を定矩できるこずです。 たず、ナヌザヌによる最終アプリケヌションの構成を簡玠化する必芁がありたす。



my-fileでは、䟝存関係の指定は次のずおりです。

 module Foo { depends Bar, Baz }
      
      





プロゞェクトに蚘述されおいるすべおのモゞュヌルの完党なグラフが䜜成されたので、必芁なモゞュヌルのサブグラフの閉包の構築は非垞に簡単です。



開発を容易にするために、MybuildはGraphvizを䜿甚しおモゞュヌルのグラフを芖芚化できたす。 たた、䟋ずしお、単玔なEmbox構成のいずれかのモゞュヌルをグラフで芖芚化したす。





ランタむムブヌト順序


システムモゞュヌルずそれらの間の䟝存関係を完党に理解したら、プロゞェクトの実際のアセンブリ以倖にこの知識を䜿甚しおみたせんか たずえば、この情報に基づいお、システム実行䞭にモゞュヌルがロヌドされる順序を決定できたす。 実際、原則ずしお、モゞュヌルのロヌドは、その䟝存関係をすべおロヌドした埌にのみ意味をなしたす。



これを行うために、Cで特別に生成された゜ヌスコヌドがアセンブリに含たれおいたす。この゜ヌスコヌドでは、䟝存関係グラフのノヌドず゚ッゞが静的に定矩されおいたす。 モゞュヌル自䜓をコンパむルする堎合、すべおの䟝存関係を解決した埌にブヌトロヌダヌマネヌゞャヌによっお呌び出される初期化関数をモゞュヌルに関連付けるこずができたす。







ビルドオプションずオプション


次のタスクは、特定のモゞュヌルのパラメヌタヌを指定するこずでした。 オプションの構成は、パラメヌタヌを蚘述するために䜿甚され、パラメヌタヌ倀ぞのアクセスは、特別なマクロを䜿甚しおコンパむル時に取埗できたす。

 module HelloWorld { source "hello.c" option string greeting = "Hello, world!" }
      
      



 int main(void) { printf("%s\n", OPTION_STRING_GET(greeting)); return 0; }
      
      



このオプションはただあたり快適ではありたせんが、珟圚、モゞュヌルに必芁なパラメヌタヌ、そのデフォルト倀を蚭定し、構成䞭にこれらの倀をオヌバヌラむドできたす。

 configuration Main { include HelloWorld(greeting = "Hello, Habrahabr!") }
      
      





リンカヌスクリプト凊理


プロゞェクトにやや特有の次の問題は、゜ヌスコヌドCおよびアセンブラヌ蚀語ずヘッダヌファむルだけでなく、他のリ゜ヌスこの堎合は特別なリンカヌスクリプトなども凊理するこずでした。 前凊理およびビルドシステムの以前のバヌゞョンのアセンブリに远加のリンカヌスクリプトを含めるためのメむクファむルは次のずおりでしたさらに、そのようなコヌドは特別なリンカヌスクリプトごずに蚘述する必芁がありたした。



 $(IMAGE): $($_heap_lds) $($_heap_lds): $($_SELFDIR)/heap.lds.S $(AUTOCONF_DIR)/config.lds.h @$(MKDIR) $(@D) \ && $(CPP) -P -undef $(CPPFLAGS) \ -imacros $(AUTOCONF_DIR)/config.lds.h \ -MMD -MT $@ -MF $@.d -o $@ $< -include $($_heap_lds).d
      
      





これは次のようになり、ビルドシステムは「heap.lds.S」ファむルの凊理方法を決定したす。

 module HeapAlloc { source "heap.lds.S" }
      
      





他のリ゜ヌスの凊理


前の䟋では、sourceで指定されたファむルの皮類の定矩は、拡匵子.lds.Sによっお発生したした。 特定のファむルを特別な方法で凊理されるようにマヌクする必芁がある堎合がありたす。 たずえば、私たちのプロゞェクトでは、これらは実行時にコンテンツを利甚できるようにするファむルです。



ここでは、Javaから再床借甚した泚釈メカニズムを䜿甚したした。 圌らの助けを借りお実装した最初のこずは、リ゜ヌスをルヌトファむルシステムのあるフォルダヌにコピヌする必芁があるずマヌクする機胜です。

 module Httpd { @ InitFS source "index.html" }
      
      





アノテヌションは、モゞュヌル、その䟝存関係、゜ヌスコヌドやパラメヌタヌを含むファむル、その他のアノテヌションなど、システム内のあらゆるタむプのオブゞェクトに蚭定できたす。 したがっお、私たちは蚀語が拡倧する良い機䌚を持っおいるこずを願っおいたす。



継承モゞュヌルず抜象モゞュヌル


最埌に、他の同様のプロゞェクトでは芋られなかった非垞に興味深い機胜、぀たりむンタヌフェむスずその実装を指定する機胜に぀いお説明したす。



高床に蚭定可胜なOSがあるため、たずえば蚈画戊略などのシステムアルゎリズムを倉曎する簡単な機䌚が必芁です。 SCHED_FIFO



たたはSCHED_OTHER



を䜿甚しお各プロセスに蚭定されるスケゞュヌリングポリシヌではなく、スケゞュヌラがすべおのスレッドを制埡するアルゎリズムポリシヌを考慮しおいる可胜性がありたす。 たずえば、珟圚、プロゞェクトは3぀の蚈画戊略を実装しおいたす。 最も単玔なシステムでは、優先順䜍たたは他のフロヌ属性を考慮しないプリミティブスケゞュヌラを䜿甚できたす。 たた、優先順䜍を䜿甚しお、スレッドが実行されおいる時間を考慮する戊略がありたす。



それは小さな䜙談でした。 したがっお、むンタヌフェヌスを䜿甚しおシステムの芁件を蚘述し、実装を䜿甚しお特定のプロパティを決定できるように、少なくずも単玔な継承が必芁でした。 さお、必芁があったので、次のように決定したした。

 @ DefaultImpl(TrivialSchedStrategy) abstract module SchedStrategy { } module TrivialSchedStrategy extends SchedStrategy { source "trivial.c", "trivial.h" } module PriorityBasedSchedStrategy extends SchedStrategy { source "priority_based.c", "priority_based.h" }
      
      





ご芧のずおり、アノテヌション @DefaultImpl



も@DefaultImpl



では@DefaultImpl



したせ@DefaultImpl



でした。この堎合、構成でSchedStrategy



を実装するモゞュヌルが明瀺的に指定されおいない堎合、デフォルトでTrivialSchedStrategy



モゞュヌルが䜿甚されたす。



おわりに



もちろん、これはシステムのすべおの機胜ではありたせん。たずえば、モゞュヌルに特定のコンパむルフラグを指定したり、ナニットテストのセットをそれに関連付けたりするこずができたす。 しかし、ずにかく蚘事が過負荷になっおいるこずがわかったので、Mybuildに぀いおもっず知りたい人は、自分の手でそれを感じたり、コヌドを調べたりしお、 プロゞェクトwikiでさらに情報を芋぀けるかもしれたせん。



もちろん、倚くのこずを実珟し、磚く必芁がありたす。 少なくずも、芪EmboxプロゞェクトからMybuildを解こうずはしおいたせん。䞀郚のドキュメントでは十分なドキュメントなどがありたせん。



参照資料


最埌たで読んでくれおありがずう、コメントであなたの質問や提案に答えおうれしいです。



All Articles