摘要:以上便是所有的內(nèi)容,可以看到涉及到的文件不算多。用也一樣,一般是再等機(jī)器的轟鳴停止后繼續(xù)工作流。這個(gè)抽象幾乎相互獨(dú)立,個(gè)人認(rèn)為是很好的一個(gè)抽象。從聲明式表達(dá)到生成的這項(xiàng)任務(wù),由完成。
前言
看懂這篇文章需要一點(diǎn)使用waf的經(jīng)驗(yàn),不過(guò)也不費(fèi)事,看看例子也夠了。
構(gòu)建系統(tǒng)簡(jiǎn)談軟件構(gòu)建系統(tǒng)不像是個(gè)很多人在研究的東西,所以在網(wǎng)絡(luò)上很少能找到剖析某個(gè)構(gòu)建系統(tǒng)原理、或者闡述構(gòu)建系統(tǒng)principle的文章??磏s3的過(guò)程中接觸到了waf,發(fā)現(xiàn)其文檔waf book[https://waf.io/book/]很好的闡述了構(gòu)建系統(tǒng)的一些基礎(chǔ)知識(shí),個(gè)人認(rèn)為比cmake的文檔好一些。因?yàn)槠浜诵闹挥惺畮讉€(gè)文件,這個(gè)構(gòu)建系統(tǒng)只需要一個(gè)10k+的waf文件,所以可以放到版本庫(kù)里(像對(duì)python的評(píng)價(jià)一樣,batteries included),唯一要求就是環(huán)境中有python,而這對(duì)一個(gè)開(kāi)發(fā)人員來(lái)說(shuō)顯然不是一件困難的事情。
|-- Build.py |-- ConfigSet.py |-- Configure.py |-- Context.py |-- Errors.py |-- Logs.py |-- Node.py |-- Options.py |-- Runner.py |-- Scripting.py |-- Task.py |-- TaskGen.py |-- Tools [directory] |-- Utils.py |-- ansiterm.py |-- extras |-- fixpy2.py `-- processor.py
以上便是所有waf的內(nèi)容,可以看到涉及到的文件不算多。Tools下包含了很多語(yǔ)言的構(gòu)建工具,比如c/c++/java/qt/ruby/tex等等,如果自己有能力定制,可以只保留自己項(xiàng)目里需要的tool,可以做到更小。(雖然個(gè)人認(rèn)為沒(méi)有必要)
核心抽象如果是寫(xiě)編譯語(yǔ)言的(c/c++/rust/go/fc/d),那么構(gòu)建系統(tǒng)是每天都在用的。在敲擊make
像make clean dist類似,可以在構(gòu)建命令后面自行添加指令,這種capibility由Context提供
構(gòu)建系統(tǒng)最重要的功能就是按需構(gòu)建,要判斷出哪些文件要編譯而哪些是不用的,這用到了TaskGen與Task的抽象
并行構(gòu)建提升速度,由Runner來(lái)提供。
這3個(gè)抽象幾乎相互獨(dú)立,個(gè)人認(rèn)為是很好的一個(gè)抽象。
Context每一個(gè)跟在./waf后面的指令,都對(duì)應(yīng)一個(gè)Context。如果是build/configure/list/step/install/uninstall,waf自行提供了對(duì)應(yīng)的Context的子類用于執(zhí)行這些命令,如果是其他的自定義函數(shù),那么就會(huì)依托于Context本身,可以在自定義函數(shù)里用Context自定義的函數(shù),比如recurse來(lái)遍歷子目錄執(zhí)行子目錄里的同名自定義函數(shù)。
如果項(xiàng)目根目錄下的wscript有do_sth,就可以./waf do_sth
def do_sth(ctx): ctx.load("compiler_cxx") # 加載工具 ctx.recurse(["src","dep"]) # 遍歷子目錄,執(zhí)行子目錄下wscript里的do_sth ctx.exec_command("touch foo.txt") ctx.msg("hello")
這里函數(shù)參數(shù)ctx就是指向了Context的一個(gè)實(shí)例,而do_sth是作為Context上的一個(gè)方法而存在的,可以直觀的理解為,我們?yōu)镃ontext增加了一個(gè)自定義的do_sth方法,所以可以自由調(diào)用Context里本來(lái)提供的方法。
./waf build執(zhí)行時(shí)綁定的Context是BuildConetxt,在Build.py里被定義,在waf build的時(shí)候,執(zhí)行的是wscript里def build(bld)這個(gè)方法。舉一個(gè)例子
def configure(conf): conf.load("compiler_cxx") def build(bld): bld.shlib(source="a.cpp", target="mylib3") bld.program(source="main.cpp", target="app", use="mylib") bld.stlib(target="foo", source="b.cpp") # 直接調(diào)用bld bld(features = "c cprogram glib2", use = "GLIB GIO GOBJECT", source = "main.c org.glib2.test.gresource.xml", target = "gsettings-test")
這里bld指向了BuildContext的一個(gè)實(shí)例,這意味著B(niǎo)uildContext里所有的方法都在這個(gè)函數(shù)里都是可用的,可以通過(guò)bld.xxx來(lái)調(diào)用。
值得注意的是,在Build.py中,可是找不到shlib/probram/stlib這3個(gè)方法的,但是在這里卻調(diào)用成功沒(méi)有報(bào)錯(cuò),這全部依賴于conf.load("compiler_cxx")這一句。執(zhí)行這句話后,就給bld指向的BuildContext實(shí)例綁定了shlib/program/stlib這3個(gè)方法。
那直接調(diào)用bld()呢?這個(gè)就要看Build.py里的BuildContex():__call__方法了。從這里開(kāi)始,就涉及到TaskGen這個(gè)抽象了。
最終需要執(zhí)行的編譯指令、中間代碼生成等,每一條都對(duì)應(yīng)一個(gè)task,我們不可能去一個(gè)一個(gè)的寫(xiě)task,而是希望以一種聲明式的方法表達(dá)想要做的事情,這就是task_gen所完成的任務(wù)。從聲明式表達(dá)到生成task的這項(xiàng)任務(wù),由waf build完成。在執(zhí)行的過(guò)程中,會(huì)對(duì)搜集到的每個(gè)task_gen執(zhí)行一下post(),然后這個(gè)task_gen就生成了自己所有的task。作為一個(gè)靈活的構(gòu)建系統(tǒng),waf提供了很多方法來(lái)讓我們hook到post()的過(guò)程中。對(duì)于每個(gè)task,到底該不該執(zhí)行需不需要執(zhí)行,它自己會(huì)追蹤自己的依賴,職責(zé)分離,我很喜歡這個(gè)設(shè)計(jì)思路。
以前一小節(jié)為例,共在build(bld)里一共進(jìn)行了4次調(diào)用,這意味著生成了4個(gè)task_gen的實(shí)例,在真正執(zhí)行構(gòu)建過(guò)程之前,會(huì)有一個(gè)地方對(duì)這4個(gè)實(shí)例各自調(diào)用一下post(),把所有的task_gen都消滅掉,變成task。至于怎么hook,這是個(gè)比較關(guān)鍵的點(diǎn),如果理解了,就能很好的自定義waf了。
首先看看寫(xiě)好的wscript,它的聲明式體現(xiàn)在什么地方呢?體現(xiàn)在函數(shù)參數(shù)里。得益于python的語(yǔ)言特點(diǎn),可以隨便加參數(shù),然后在函數(shù)實(shí)現(xiàn)里用**kw來(lái)取這些值。這意味著可以隨便加自己想要的key=value進(jìn)去,這些加進(jìn)去的參數(shù)是可以在自定義的hook過(guò)程中取到的,這算是可自定義的一個(gè)基礎(chǔ)。(ruby自定義的能力更強(qiáng),畢竟dsl是其強(qiáng)項(xiàng),但可能限于ruby的流行程度以及發(fā)行版是否默認(rèn)安裝,讓作者最后選擇了python,不過(guò)也已經(jīng)夠用了)
在post()的過(guò)程中,會(huì)從task_gen.meths[]里依次取出方法來(lái)執(zhí)行,hook的方式就是把自定義的方法塞到這個(gè)task_gen.meths[]之中。這只要在自定義的方法上加一個(gè)@TaskGen.taskgen_method的注解就能實(shí)現(xiàn),還是挺簡(jiǎn)潔的吧?聲明式中寫(xiě)的key=val,都能通過(guò)taskgen.key取到,這樣一來(lái),幾乎就獲得了無(wú)限的能力來(lái)自定義構(gòu)建過(guò)程了。
在taskgen.meths[]里有幾項(xiàng)預(yù)定義的方法,waf也提供了指令來(lái)讓我們定制自己方法執(zhí)行的位置??偠灾?,想要什么內(nèi)容,直接在wscript里以key=val的方式指定,然后在自己的方法里用getattr來(lái)取就行了。
這也只是個(gè)支持性框架,具體到某個(gè)語(yǔ)言(c/c++)是怎么做的,到后面再看。
waf自己會(huì)默認(rèn)起和cpu core相同數(shù)量的進(jìn)程來(lái)執(zhí)行構(gòu)建認(rèn)任務(wù),而且構(gòu)建過(guò)程的輸出也很清晰漂亮。waf也提供了lazy的模式,不是一下子把所有的task_gen都轉(zhuǎn)化,所以也是用了一些技巧來(lái)達(dá)成這個(gè)目的。在看waf代碼的過(guò)程中,能看到很多pythonic和近乎炫技的技法,可見(jiàn)作者真是把python語(yǔ)言玩弄于股掌之中。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/45266.html
摘要:在上安裝標(biāo)簽空格分隔監(jiān)控首先說(shuō)一句,在上安裝真的很坑爹。。。或如果上面這個(gè)方法無(wú)法安裝那就用源碼安裝的方法。安裝開(kāi)始好幾次就死在安裝這個(gè)上面,版本的通過(guò)命令安裝的不行,對(duì)應(yīng)版本的包的名字叫做。 在 CentOS 5.8 上安裝 Graphite 標(biāo)簽(空格分隔): 監(jiān)控 monitor CentOS 5.8 Graphite 首先說(shuō)一句,在 CentOS 5.8 上安裝真的很坑爹...
摘要:漢字拼音 Awesome Python A curated list of awesome Python frameworks, libraries and software. Inspired by awesome-php. Awesome Python Environment Management Package Management Package Repositorie...
摘要:如今,多樣化的攻擊手段層出不窮,傳統(tǒng)安全解決方案越來(lái)越難以應(yīng)對(duì)網(wǎng)絡(luò)安全攻擊。自適應(yīng)安全平臺(tái)集成了預(yù)測(cè)預(yù)防檢測(cè)和響應(yīng)的能力,為您提供精準(zhǔn)持續(xù)可視化的安全防護(hù)。 近一年來(lái),Docker 已經(jīng)逐漸成為 container 界的事實(shí)標(biāo)準(zhǔn),成為技術(shù)人員不可或缺的技能之一,就像 Docker 宣稱的那樣,「Build,Ship,and Run Any App,Anywhere」,容器極大簡(jiǎn)化了環(huán)境...
摘要: Caching Libraries for caching data. Beaker - A library for caching and sessions for use with web applications and stand-alone Python scripts and applications. dogpile.cache - dogpile.cache...
閱讀 3500·2019-08-30 15:53
閱讀 3414·2019-08-29 16:54
閱讀 2203·2019-08-29 16:41
閱讀 2412·2019-08-23 16:10
閱讀 3384·2019-08-23 15:04
閱讀 1355·2019-08-23 13:58
閱讀 355·2019-08-23 11:40
閱讀 2459·2019-08-23 10:26