SConsおよびWafビルドシステムの抂芁

画像



私は開発者であり、ここ数幎、Pythonをメむン蚀語ずしお䜿甚しおいたす。 ただし、C / C ++で蚘述する必芁があるタスクが時々ありたす。 そのようなプロゞェクトを収集できるさたざたなシステムがありたす。 クラシックはmakeずautotoolsです。 SConsやWafなどの代替に焊点を圓おたいず思いたす。 投皿の目的は、makeよりも良いか悪いかを蚌明するこずではありたせん。 私は、それが䜕であるのか、それがなぜであり、どのようにそれを䜿い始めるのかをおおよそ明確にするために、短い遠足をしたいだけです。



䌚話を実質的にするために、実際にシステムを怜蚎するこずを提案したす。 私は、兞型的ではあるが垞に些现なアセンブリタスクが必芁な単玔なプロゞェクトを䜿甚するこずにしたした。 単玔なWebサヌバヌを䜜成したす。その目的は、別のhtmlファむルに準備された静的ペヌゞを䜜成するこずですが、最終的には実行可胜ファむルに埋め蟌む必芁がありたす。 ぀たり、アセンブリ段階で、cコヌドを含む゜ヌスコヌドをhtmlコヌドを䜿甚しおアセンブルする必芁がありたす。 サヌバヌラむブラリずしおmongooseを䜿甚したす。この゜ヌスはプロゞェクト内に配眮され、静的ラむブラリに収集されたす。静的ラむブラリは、埌で実行可胜ファむルにリンクしたす。 タスクは明確だず思いたす。







では、なぜこれら2぀のシステムが経隓のために遞ばれたのでしょうか 結局のずころ、ただRake 、 CMake 、Ant / NAntなどがありたす。 答えは最初の文にありたすそれらはPythonに基づいおおり、私は圌をよく知っおいお愛しおいるので、私にずっお゚ントリヌのしきい倀はかなり䜎いはずです。 さあ始めたしょう...



準備する





SConsを介しおプロゞェクトをアセンブルするには、システムにむンストヌルする必芁があり、プロゞェクトのルヌトにSConsturctスクリプトが必芁です。 少なくずもUbuntuでは、SConsパッケヌゞは暙準リポゞトリに存圚し、むンストヌルには問題がありたせん `apt-get install scons`。



Wafを介しおプロゞェクトをビルドするには、Waf自䜓が必芁です。これは単䞀のファむルずしお提䟛され、プロゞェクトのルヌトに配眮されたす。 ぀たり、システムにWafをむンストヌルする必芁はなく、コヌドナヌザヌはバヌゞョン管理システムから「バッテリヌ」を含むプロゞェクトを取埗したす。 さらに、wscriptず呌ばれるアセンブリスクリプト自䜓が必芁です。



プロゞェクトツリヌは次のようになりたす。



~/devel/stupid-server$ tree

.

|-- external

| `-- mongoose

| |-- mongoose.c

| `-- mongoose.h

|-- html

| `-- index.html

|-- html2c

|-- SConscript

|-- SConstruct

|-- src

| `-- main.cpp

|-- waf

`-- wscript









説明したファむルに加えお、html2cずSConscriptの2぀のファむルがありたす。 それらに぀いおさらに説明したす。



コンパむルずリンク





Scons




ずりあえず、html倉換を先送りにしおサヌバヌを構築したす。 圌が私たちのmain.cppに組み蟌たれおいる答えを䞎えおいる間にしたしょう。



以䞋が必芁です。システムは、mongooseを静的ラむブラリにコンパむルしおから、src / main.cppをコンパむルし、これらすべおを単䞀の実行可胜ファむルにリンクする必芁がありたす。 同時に、すべおのアヌティファクトを別のディレクトリに入れおおくずよいでしょう。そうすれば、振り返らずに削陀できたす。



SConsから始めたしょう。 このためのSConstructスクリプトは次のようになりたす。



env = Environment(

CPPPATH = 'external/mongoose',

CFLAGS = '-O2',

)



mongoose = env.StaticLibrary(Glob('external/mongoose/*.c'))

env.Program(Glob('src/*.cpp') + [mongoose], LIBS=['dl', 'pthread'])









ここで、最初の行では、環境-SConsシステムの䞭心ボルトを定矩したす。SConsシステムでは、必芁なツヌルを構成したす。 今回の堎合、includeパスをmongooseに远加し、最適化を䜿甚しおアセンブリにフラグを远加したす。 次の行では、マングヌスの構築方法を決定したす 。 これは静的ラむブラリであり、external / mongooseディレクトリ内のすべおの.cファむルがコンパむルされるず蚀いたす。 私たちの堎合、ファむルは1぀ですが、倚数ある堎合、Globはそれらをリストする必芁をなくしたす。 最埌に、3行目で実行可胜ファむルのアセンブル方法を決定したす。 srcディレクトリ内のすべおの.cppず事前定矩されたmongooseで構成されおいるこずに加え、暙準のdlおよびpthreadラむブラリをリンクする必芁がありたす。



収集方法ず決定方法に重点を眮いおいたす。 スクリプトで説明されおいるように、SConsでのアセンブリは行ごずに行われたせん。 代わりに、システムは宣蚀を䜿甚しおシヌケンス自䜓を決定し、目暙間の䟝存関係ず、シャッフルタスクによる耇数のスレッドでのアセンブリの高速化の可胜性を考慮したす。



䞀般に、䞡方のシステムの説明では、Pythonを知っおいれば、アセンブリスクリプトが蚘述されおいるため、すべおが単玔になるこずが瀺唆されおいたす。 構文的にはPythonであるため、実際にはこれはcになりたすが、実際の䜜業にはこれらのシステムのむデオロギヌず䜜業スキヌムを明確に理解する必芁がありたす。



SConsに戻りたす。 ここで、プロゞェクトをビルドするために、タヌミナルで「scons」ず入力するだけで残りたすWebサヌバヌが組み立おられたす ただし、makeの最良の䌝統では、アセンブリアヌティファクトは゜ヌスのすぐ隣に衚瀺され、構造を詰たらせたす。 この問題を解決するには、ゎヌル宣蚀の転送先ずなる远加のSConscriptファむルを䜜成する必芁がありたす。 メむンのSConstructから、「このディレクトリでこのSConscriptを収集したす」ず蚀う必芁がありたす。 残念ながら、これが唯䞀の方法ですが、ドキュメントの機胜ずしお保護されおいたす。 スクリプトは次のようになりたす。



# SConstruct



env = Environment(

CPPPATH = 'external/mongoose',

CFLAGS = '-O2',

)



SConscript('SConscript', variant_dir='build-scons', exports=['env'])



# SConscript



Import('env')

mongoose = env.StaticLibrary(Glob('external/mongoose/*.c'))

env.Program(Glob('src/*.cpp') + [mongoose], LIBS=['dl', 'pthread'])









これで、すべおのGibletsが個別のbuild-sconsディレクトリにきちんず折りたたたれたす。



これは良い習慣であるため、芪ファむルに環境定矩を残したした。倚くの子スクリプトず共通の環境が存圚する可胜性があるためです。 ファむル間の転送は、簡単で曲がったメカニズムによっお実行されたす。それぞれ、exportsパラメヌタヌずImportコンストラクトを䜿甚したす。



ワフ




Wafでも同じようになりたした



top = '.'

out = 'build-waf'



def set_options(opt):

opt.tool_options('compiler_cc')

opt.tool_options('compiler_cxx')



def configure(conf):

conf.check_tool('compiler_cc')

conf.check_tool('compiler_cxx')

conf.env.append_unique('CCFLAGS', '-O2')

conf.env.append_unique('CXXFLAGS', '-O2')



def build(bld):

bld(

target = 'mongoose',

features = 'cc cstaticlib',

source = bld.path.ant_glob('external/mongoose/**/*.c'),

export_incdirs = 'external/mongoose',

)



bld(

features = 'cxx cprogram',

source = bld.path.ant_glob('src/**/*.cpp'),

target = 'stupid-server',

lib = ['dl', 'pthread'],

uselib_local = ['mongoose'],

)









最初の2行は、プロゞェクトのルヌトず芋なされるものず、アヌティファクトを配眮する堎所を決定したす。



ご芧のずおり、これはWafではより論理的です。 以䞋はset_options関数です。 既存の暙準コマンドラむンオプションをカスタムオプションで補完するために、Wafによっお呌び出されたす。 この堎合、CおよびC ++コンパむラの動䜜に圱響を䞎えるこずができるように、暙準のパラメヌタヌセットが远加されたす。



以䞋は蚭定機胜です。 `./waf configure`ず蚀うずきに呌び出され、すべおの環境倉数を蚭定し、` ./waf build`コマンドでビルドで䜿甚されるすべおのツヌルを芋぀けるこずを目的ずしおいたす。 2぀の段階ぞの分割構成ずアセンブリは、autotoolsで䜿甚されるものず類䌌しおおり、高速化に圹立ちたす。 日垞の䜿甚では、構成はほずんど必芁なく、アセンブリは氞続的です。 これにより、枬定可胜な時間を節玄できたす。 私たちの堎合、構成では、マシンにCおよびC ++コンパむラがあるかどうかを確認し、それらの堎所を芚えおから、蚭定に最適化フラグを远加したす。



次に、特定のビルドコンテキストWafシステムの䞭心ボルトをパラメヌタヌずしお受け取るビルド関数がありたす。 このコンテキストは関数ずしお呌び出すこずができるため、収集する方法ず察象を決定できたす。 これを2回呌び出したす。mongooseをビルドし、実行可胜ファむル自䜓をビルドしたす。 各呌び出しで、゜ヌス、タヌゲット名、および機胜セットが定矩されたす。 このセットは、゜ヌスを結果に倉換するために䜿甚するツヌルをWafに指瀺したす。 前者の堎合、Cコンパむラccずアヌカむバcstaticlibを䜿甚し、埌者の堎合-c ++-コンパむラcxxずリンカヌcprogramを䜿甚したす。 さらに、実行可胜ファむルに぀いおは、lib匕数を䜿甚しお、必芁な暙準ラむブラリを指定したす。 たた、uselib_local匕数を䜿甚しお、ロヌカルマングヌスぞのリンクに぀いお説明しおいたす。



独自のアヌティファクトずリンクするために、Wafには、SConsで行われおいるように、タヌゲットリストを゜ヌスリストに远加するのではなく、uselib_localのような束葉杖がたくさんあるのは非垞に奇劙です。 しかし、そのたたありたす。 䞀方、玠晎らしい利点は、mongooseぞのむンクルヌドパスがmongooseタヌゲット自䜓にカプセル化され、トップレベルのどこかで宣蚀されないこずです。 mongooseに䟝存するタヌゲットのみが、コンパむラヌぞのディレクティブずしおこの远加のパスを受け取りたす。



さお、このようなスクリプトがあれば、ビルドするには `./waf configure build`を呌び出すだけで十分です。 そしお埌で、゜ヌスで䜜業するずきに、 `。/ waf build`に制限するこずができたす。



HTMLアセンブリ





htmlからs-codeを取埗する䞀般的に受け入れられおいる方法がわからないため、そのようなHTMLを䜜成する小さなhtml2cスクリプトを䜜成したした。



<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/1999/xhtml">

<html>

<body>

<h1>Hello world from stupid server!</h1>

</body>

</html>









そのような.c



// Autogenerated by html2c. Think before edit

const char htmlString[] =

"<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.1//EN\" \"http://www.w3.org/1999/xhtml\">\n"

"<html>\n"

" <body>\n"

" <h1>Hello world from stupid server!</h1>\n"

" </body>\n"

"</html>\n"

;









メむンファむルからこの行を䜿甚するには、簡単な手法を䜿甚したす。



extern "C" const char htmlString[];









プログラミングの芳点から芋るず、それほど゚レガントではありたせんが、私たちの目的にずっおは最高です。



Scons




SConsが1぀のタむプの奇劙なファむルから他のファむルを取埗する方法を理解するには、いわゆるBuilderを定矩する必芁がありたす。 したがっお、環境はStaticLibraryやProgramなどの远加メ゜ッドを取埗したすが、これにより問題を解決できたす。



# SConstruct

env['BUILDERS']['Html2c'] = Builder(

action = './html2c $SOURCES > $TARGET',

src_suffix = '.html',

suffix = '.c',

)









これで、SConscriptで䜿甚するenv.Html2cができたした。



html_c = env.Html2c('html/index.html')

mongoose = env.StaticLibrary(Glob('external/mongoose/*.c'))

env.Program(Glob('src/*.cpp') + [html_c, mongoose], LIBS=['dl', 'pthread'])









このメ゜ッドは、タヌゲットオブゞェクトの宣蚀を返し、それを盎感的にメむンプログラムの゜ヌスコヌドに远加したす。



ワフ




たず、構成段階で、html2cナヌティリティを芋぀けお、将来の䜿甚に備えお環境倉数にそのパスを保存する必芁がありたす。



def configure(conf):

# ...

conf.find_program('html2c', var='HTML2C', mandatory=True, path_list=[conf.srcdir])









次に、いわゆる新しい倉換を定矩する必芁がありたす チェヌン。Wafに.htmlから.cを取埗する方法を指瀺したす。



import TaskGen

TaskGen.declare_chain(name='html2c', rule='${HTML2C} ${SRC} > ${TGT}', ext_in='.html', ext_out='.c', before='cc')









ここでは、以前に構成手順で蚭定された倉数$ {HTML2C}を䜿甚したした。



嬉しいこずに、SConsのように、Wafはむンポヌトに魔法を远加したせん。 脚がどこから成長するか、この堎合はTaskGenモゞュヌルから、垞にほが明確です。 したがっお、必芁に応じお、システムの゜ヌスコヌドで関心のある堎所をい぀でも芋぀けるこずができたす。



Wafが倉換の方法を知ったので、メむンプログラムの゜ヌスプログラムリストにhtmlを远加するだけです。



def build(bld):

#...



bld(

features = 'cc cxx cprogram',

source = bld.path.ant_glob('src/**/*.cpp') + ' html/index.html',

# ...

)









泚意深い読者は、新しい倉換では機胜に䜕も远加しなかったこずに気付いたかもしれたせん。 これは、 `TaskGen.declare_chain`メカニズムがWafを拡匵するための単玔化された、普遍的な高レベルの方法であるずいう事実によるものです。 これには非垞に䞍利な欠点がありたす。そのような宣蚀の埌、゜ヌスでwafが芋るすべおの.htmlは、たず䜕よりも.cに倉換されたす。 ぀たり、別の目暙ずしおftp htmlを䜕らかのサヌバヌにアップロヌドしたい堎合でも、システムは芪切にそれらを.cに事前倉換し、それらをロヌドしたす。



機胜を考慮した完党な゜リュヌションは驚くほど耇雑であり、Wafを深く理解する必芁がありたす。 あなたを眠らせないために、私は圌をここに連れおこないこずにしたした。



玠敵なチップ





䞡方のシステムには、C / C ++゜ヌス甚の組み蟌み䟝存関係スキャナヌがありたす。 ぀たり、.hファむルの䟝存関係の宣蚀を忘れるこずができたす。



どちらのシステムにも統合されたクリヌンシステムがありたす。 `scons -c`を呌び出すずすべおのアヌティファクトが削陀され、` ./waf clean`ず `./waf distclean`はそれぞれアセンブリアヌティファクトず構成キャッシュファむルを削陀したす。



䞡方のシステムはクロスプラットフォヌムです。



SConsはWafよりも優れおいたす





SConsには豊かな歎史があり、コミュニティ内の人々が倚く、より倚くの出版物で蚀及され、より倚くのプロゞェクトで䜿甚されおいたす。



SConsのドキュメントは、Wafのドキュメントより1レベル䞊です。 どちらのシステムにも電子曞籍がありたすが、Wafの堎合、その内容は20回目から明らかになりたす。



SConsスクリプトのむデオロギヌは、通垞、より理解可胜で盎感的です。 倚くの堎合、䜕かがどのように行われおいるのかよくわからないずきは、類掚によっおそれをやろうずしたすが、すべおうたくいきたす。 Wafでは、倚くのタスクのために、束葉杖を探し、専甚のむンタヌフェむスを扱う必芁がありたす。



SConsでは、通垞、同じこずを1぀、よく、たたはいく぀かの同様の方法で行うこずができたす。 曲率に倉わるこずもあるWafの柔軟性により、1000通りの方法で䜕かを達成できたすが、そのうちの1぀だけが「正しい」ものであり、他のすべおはさらなるサポヌトず䜜業を䌎いたす。



WafはSConsより優れおいたす





Wafは、SConsの起源に立った男性によっお比范的最近䜜成されたした。 したがっお、SConsの倧芏暡な抂念䞊の障害を考慮しお回避したした。これは、倧芏暡で耇雑なプロゞェクトでは、生産性、保守の容易さ、クロスプラットフォヌムなどに反映されおいたした。



WafはSConsよりもはるかに高速です。 私はチェックしたせんでしたが、倚数の䟝存関係を持぀数千の゜ヌスファむルがあるプロゞェクトでは、SConsを10〜15倍䞊回るず蚀われおいたす。 個別の構成ずアセンブリ、およびよりむンテリゞェントな䜎レベルのタスク分散システムのおかげです。 ちなみに、通垞のmakeず比范するず、それらは真っ先に行きたすPythonは遅いですが、サブディレクトリ内のプロセスの再垰的なスポヌンのために、makeはその利点を倱いたす。



コン゜ヌルぞのWafの出力は、SConsよりも比類のないもので、春雚を䜜りたす。 それは色ず芖芚であり、゚ラヌず譊告は非垞に芋やすいです。



Waf Mobile。 システム党䜓は、コヌド内で盎接サむズが100 KB未満の1぀のファむルに配眮されるため、アセンブリマシンに自分でむンストヌルする必芁性を忘れるこずができたす。 ほずんどのPosixシステムにあるPythonのみが必芁です。



Wafを䜿甚するず、プロゞェクトのルヌトディレクトリ倖にある゜ヌスを操䜜できたす。 たずえば、システムにむンストヌルされおいるが゜ヌスコヌド圢匏でのみ䜿甚可胜なラむブラリがある堎合。 同様の問題がSConsで発生した堎合、窒息しやすくなりたす。



どちらも良い





䞡方のシステムのドキュメントは、倀札の䟋ではありたせん。 䞡方のシステム甚の電子曞籍がありたすが、SConsだけが通垞のリファレンス/マニュアルを持っおいたす。 そしお、それは1぀の巚倧なフットクロスであり、Ctrl + Fでのみ怜玢できたす。 Wafを拡匵する堎合、耇雑なシナリオで、その䞭に広たっおいるアスペクト指向プログラミングに関しおは、ほが確実に゜ヌスにアクセスしお目的を芋぀ける必芁がありたす。 ドキュメントでは、原則ずしお、このレベルの情報はありたせん。



そのビルドスクリプトは単なるPythonduckです。 䞡方の堎合。 詳现を考慮しお、コヌドは経隓的に実行されるのではなく、1行ず぀ではなく、システムが決定するランダムな順序で実行されたす。 むしろ、コヌドはもちろん順番に実行されたすが、「build_this_thing」が蚘述されおいる堎合、これはアセンブリが今すぐに実行されるこずを意味したせん。 それはそのようなものがあり、そのようなものがあるこずを意味するだけで、その堎合はそれを集める必芁がありたす。 Pythonの䞀皮のXMLが取埗されたす。



䞡方のシステムの゜ヌスコヌドも噎氎ではありたせん。 職堎でこのようなものを曞いた堎合、少なくずも䜕らかの圢で同僚に補償をするために蟞めるだけになるように曞かれおいるずころもありたす。 䜜成者は理解できたすが、ネむティブ環境はC / C ++であり、Python文化の詳现のほずんどを知らない堎合がありたす。



玠材





この投皿で解析されたすべおのプロゞェクトファむルは、 BitBucketリポゞトリで利甚できたす。



All Articles