摘要:以上便是所有的内容,可以看到涉及到的文件不算多。用也一样,一般是再等机器的轰鸣停止后继续工作流。这个抽象几乎相互独立,个人认为是很好的一个抽象。从声明式表达到生成的这项任务,由完成。
前言
看懂这篇文章需要一点使用waf的经验,不过也不费事,看看例子也够了。
构建系统简谈软件构建系统不像是个很多人在研究的东西,所以在网络上很少能找到剖析某个构建系统原理、或者阐述构建系统principle的文章。看ns3的过程中接触到了waf,发现其文档waf book[https://waf.io/book/]很好的阐述了构建系统的一些基础知识,个人认为比cmake的文档好一些。因为其核心只有十几个文件,这个构建系统只需要一个10k+的waf文件,所以可以放到版本库里(像对python的评价一样,batteries included),唯一要求就是环境中有python,而这对一个开发人员来说显然不是一件困难的事情。
|-- 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的内容,可以看到涉及到的文件不算多。Tools下包含了很多语言的构建工具,比如c/c++/java/qt/ruby/tex等等,如果自己有能力定制,可以只保留自己项目里需要的tool,可以做到更小。(虽然个人认为没有必要)
核心抽象如果是写编译语言的(c/c++/rust/go/fc/d),那么构建系统是每天都在用的。在敲击make
像make clean dist类似,可以在构建命令后面自行添加指令,这种capibility由Context提供
构建系统最重要的功能就是按需构建,要判断出哪些文件要编译而哪些是不用的,这用到了TaskGen与Task的抽象
并行构建提升速度,由Runner来提供。
这3个抽象几乎相互独立,个人认为是很好的一个抽象。
Context每一个跟在./waf后面的指令,都对应一个Context。如果是build/configure/list/step/install/uninstall,waf自行提供了对应的Context的子类用于执行这些命令,如果是其他的自定义函数,那么就会依托于Context本身,可以在自定义函数里用Context自定义的函数,比如recurse来遍历子目录执行子目录里的同名自定义函数。
如果项目根目录下的wscript有do_sth,就可以./waf do_sth
def do_sth(ctx): ctx.load("compiler_cxx") # 加载工具 ctx.recurse(["src","dep"]) # 遍历子目录,执行子目录下wscript里的do_sth ctx.exec_command("touch foo.txt") ctx.msg("hello")
这里函数参数ctx就是指向了Context的一个实例,而do_sth是作为Context上的一个方法而存在的,可以直观的理解为,我们为Context增加了一个自定义的do_sth方法,所以可以自由调用Context里本来提供的方法。
./waf build执行时绑定的Context是BuildConetxt,在Build.py里被定义,在waf build的时候,执行的是wscript里def build(bld)这个方法。举一个例子
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") # 直接调用bld bld(features = "c cprogram glib2", use = "GLIB GIO GOBJECT", source = "main.c org.glib2.test.gresource.xml", target = "gsettings-test")
这里bld指向了BuildContext的一个实例,这意味着BuildContext里所有的方法都在这个函数里都是可用的,可以通过bld.xxx来调用。
值得注意的是,在Build.py中,可是找不到shlib/probram/stlib这3个方法的,但是在这里却调用成功没有报错,这全部依赖于conf.load("compiler_cxx")这一句。执行这句话后,就给bld指向的BuildContext实例绑定了shlib/program/stlib这3个方法。
那直接调用bld()呢?这个就要看Build.py里的BuildContex():__call__方法了。从这里开始,就涉及到TaskGen这个抽象了。
最终需要执行的编译指令、中间代码生成等,每一条都对应一个task,我们不可能去一个一个的写task,而是希望以一种声明式的方法表达想要做的事情,这就是task_gen所完成的任务。从声明式表达到生成task的这项任务,由waf build完成。在执行的过程中,会对搜集到的每个task_gen执行一下post(),然后这个task_gen就生成了自己所有的task。作为一个灵活的构建系统,waf提供了很多方法来让我们hook到post()的过程中。对于每个task,到底该不该执行需不需要执行,它自己会追踪自己的依赖,职责分离,我很喜欢这个设计思路。
以前一小节为例,共在build(bld)里一共进行了4次调用,这意味着生成了4个task_gen的实例,在真正执行构建过程之前,会有一个地方对这4个实例各自调用一下post(),把所有的task_gen都消灭掉,变成task。至于怎么hook,这是个比较关键的点,如果理解了,就能很好的自定义waf了。
首先看看写好的wscript,它的声明式体现在什么地方呢?体现在函数参数里。得益于python的语言特点,可以随便加参数,然后在函数实现里用**kw来取这些值。这意味着可以随便加自己想要的key=value进去,这些加进去的参数是可以在自定义的hook过程中取到的,这算是可自定义的一个基础。(ruby自定义的能力更强,毕竟dsl是其强项,但可能限于ruby的流行程度以及发行版是否默认安装,让作者最后选择了python,不过也已经够用了)
在post()的过程中,会从task_gen.meths[]里依次取出方法来执行,hook的方式就是把自定义的方法塞到这个task_gen.meths[]之中。这只要在自定义的方法上加一个@TaskGen.taskgen_method的注解就能实现,还是挺简洁的吧?声明式中写的key=val,都能通过taskgen.key取到,这样一来,几乎就获得了无限的能力来自定义构建过程了。
在taskgen.meths[]里有几项预定义的方法,waf也提供了指令来让我们定制自己方法执行的位置。总而言之,想要什么内容,直接在wscript里以key=val的方式指定,然后在自己的方法里用getattr来取就行了。
这也只是个支持性框架,具体到某个语言(c/c++)是怎么做的,到后面再看。
waf自己会默认起和cpu core相同数量的进程来执行构建认任务,而且构建过程的输出也很清晰漂亮。waf也提供了lazy的模式,不是一下子把所有的task_gen都转化,所以也是用了一些技巧来达成这个目的。在看waf代码的过程中,能看到很多pythonic和近乎炫技的技法,可见作者真是把python语言玩弄于股掌之中。
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/45266.html
摘要:在上安装标签空格分隔监控首先说一句,在上安装真的很坑爹。。。或如果上面这个方法无法安装那就用源码安装的方法。安装开始好几次就死在安装这个上面,版本的通过命令安装的不行,对应版本的包的名字叫做。 在 CentOS 5.8 上安装 Graphite 标签(空格分隔): 监控 monitor CentOS 5.8 Graphite 首先说一句,在 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...
摘要:如今,多样化的攻击手段层出不穷,传统安全解决方案越来越难以应对网络安全攻击。自适应安全平台集成了预测预防检测和响应的能力,为您提供精准持续可视化的安全防护。 近一年来,Docker 已经逐渐成为 container 界的事实标准,成为技术人员不可或缺的技能之一,就像 Docker 宣称的那样,「Build,Ship,and Run Any App,Anywhere」,容器极大简化了环境...
摘要: 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...
阅读 3492·2019-08-30 15:53
阅读 3407·2019-08-29 16:54
阅读 2192·2019-08-29 16:41
阅读 2400·2019-08-23 16:10
阅读 3379·2019-08-23 15:04
阅读 1344·2019-08-23 13:58
阅读 348·2019-08-23 11:40
阅读 2454·2019-08-23 10:26