注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

天道酬勤 玩物丧志

用勇气去改变可以改变的事情,用胸怀去包容无法改变的事情,用智慧去判断两者的区别

 
 
 

日志

 
 

Waf 脚本与命令  

2016-12-22 13:51:29|  分类: RTOS |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

刚刚开始接触RTEMS,记录相关资料信息

http://www.cnblogs.com/Lvkun/archive/2012/03/30/trans-waf-tutorial.html

Waf 是一份用来帮助编译软件工程的软件。本教程的目标是提供如何为一个使用 Waf 的工程设置脚本的简要说明。

Waf 脚本与命令

软件通常有保存在版本管理系统(git, subversion 等等)的 源文件(source files),以及描述如何处理这些文件的 编译脚本(build scripts) (Makefiles,...)。一些 生成文件(build files) 通常由 源文件(source files) 转换而得,但它们是可选的。在 Waf 中编译脚本是那些命名为 'wscript' 的文件。

通常,一个工程包含下面若干阶段:

  • 配置(configure): 配置工程,找到依赖项的位置
  • 编译(build): 将源文件转换为生成文件
  • 安装(install): 安装生成文件
  • 卸载(uninstall): 卸载生成文件
  • 打包(dist): 生成源文件的存档
  • 清理(clean): 删除生成文件

每一阶段在 de>wscriptde> 文件中都是以一个 Python 函数构造的,该函数使用 de>waflib.Context.Contextde> 的一个实例作为函数。

让我们从在文件夹 de>/tmp/myprojectde> 下 新建一个 de>wscriptde> 文件开始:

    def configure(conf):
print("configure!")

def build(bld):
print("build!")

我们也需要一个 Waf 二进制文件,如: http://waf.googlecode.com/files/waf-1.6.1 , 并把该文件拷贝到工程目录下:

    $ cd /tmp/myproject
$ wget http://waf.googlecode.com/files/waf-1.6.1

我们只需简单地将命令作为参数传递给 de>wafde> 即可运行此工程:

    $ ./waf-1.6.1 configure build
configure!
build!

目标

编译系统的一个重要组成部分是声明目标的创建过程。这里有一个非常简单的例子:

    def build(bld):
tg = bld(rule='cp ${SRC} ${TGT}', source='wscript', target='foo.txt')
bld(rule='cp ${SRC} ${TGT}', source='foo.txt', target='bar.txt')

调用 de>bld(..)de> 创建了一个 任务生成器(task generator) ,它用来生成 任务(tasks) 。 任务则实际运行命令 de>cpde>。 命令直到所有脚本都被读取后才会运行,这对计算编译顺序非常重要。

表达式 ${SRC} 和 ${TGT} 是快捷方式,用来避免文件名重复。更多的快捷方式可以通过使用 ${} 符合定义,该符号能从 de>bld.envde> 属性读取对应的值。

    def build(bld):
bld.env.MESSAGE = 'Hello, world!'
bld(rule='echo ${MESSAGE}', always=True)

de>bldde> 对象是类 de>waflib.Build.BuildContextde>,它的 de>envde> 属性是类 de>waflib.ConfigSet.ConfigSetde> 的一个实例。

这些值被保存在此对象中以便于共享/保存/加载。这里是如何在配置和编译过程中共享数据来实现和上个例子同样的事情:

    def configure(cnf):
cnf.env.MESSAGE = 'Hello, world!'

def build(bld):
bld(rule='echo ${MESSAGE}', always=True)

脚本与工具

为让一个脚本使用子目录下的另一脚本,需要使用方法 de>waflib.Context.Context.recursede> 及包含 de>wscriptde> 文件夹的相对路径。例如,调用 de>src/wscriptde> 脚本中 de>buildde>函数,应该这样写:、

    def build(bld):
bld.recurse('src')

Waf 通过特定模块 de>Waf toolsde> 提供了对特定语言和编译器的支持。这些工具与 de>wscriptde> 文件类似且提供如 de>configurede> 或者 de>buildde> 函数。这里是一个C语言的简单工程:

复制代码
    def options(opt):
opt.load('compiler_c')
def configure(cnf):
cnf.load('compiler_c')
def build(bld):
bld(features='c cprogram', source='main.c', target='app')
复制代码

de>optionsde> 函数是另一个预定义的命令,用来设置命令行选项。它的参数是 de>waflib.Options.OptionsContextde> 的一个实例。 提供了工具 de>compiler_cde>用以检测是否有 C 编译器存在,并设置各种参数如 de>cnf.env.CFLAGSde>。

用 de>bldde> 声明的任务生成器并没有 规则(rule) 关键字,而是用一系列 特性(features) 来引用那些调用适当规则的方法。 在这个例子中,一个规则被调用以编译文件,而另一个用来链接目标文件到二进制文件 de>appde> 。 还存在其他一些工具依赖的 特性(features) 如: de>javacde>,de>csde> 或者 de>texde> 。

一个同时使用C和C++的工程

下面是一个更复杂一些工程的脚本

复制代码
    def options(opt):
opt.load('compiler_c compiler_cxx')
def configure(cnf):
cnf.load('compiler_c compiler_cxx')
configure.check(features='cxx cxxprogram', lib=['m'], cflags=['-Wall'], defines=['var=foo'], uselib_store='M')
def build(bld):
bld(features='c cshlib', source='b.c', target='mylib')
bld(features='c cxx cxxprogram', source='a.c main.cpp', target='app', use=['M','mylib'], lib=['dl'])
复制代码

方法 de>waflib.Tools.c_config.checkde> 会内部执行编译以检测在操作系统中是否存在 de>libmde> 库。然后它会定义变量如:

  • de>conf.env.LIB_M = ['m']de>
  • de>conf.env.CFLAGS_M = ['-Wall']de>
  • de>conf.env.DEFINES_M = ['var=foo']de>

通过声明 de>use=['M', 'mylib']de>,程序 app 会继承所有在配置过程中定义的 M 变量。该程序也会使用库 mylib 并且编译顺序和依赖项都会更改以使 mylib 在 app 之前链接。

de>usede> 属性也适用于其他语言如Java(jar 文件之间的依赖)或者C#(程序集之间的依赖)。

工程特定扩展

feature 关键字是高层次的对现有 Waf 方法的引用。例如: c feature 会添加方法 de>waflib.Tools.ccroot.apply_incpathsde> 以执行。要添加一个为所有C目标加入任务生成器路径到包含路径的新方法,可以采用如下声明:

复制代码
    from waflib import Utils
from waflib.TaskGen import feature, before_method
@feature('c')
@before_method('apply_incpaths')
def add_current_dir_to_includes(self):
self.includes = Utils.to_list(self.includes)
self.includes.append(self.path)

def build(bld):
tg = bld(features='c', source='main.c', target='app')
复制代码

这些 feature 方法被绑定到类 de>waflib.TaskGen.task_gende> ,在这个例子中是对象 tg 的类。新的 feature 可以以相同的方式声明:

复制代码
    from waflib.TaskGen import feature, after_method
@feature('debug_tasks')
@after_method('apply_link')
def print_debug(self):
print('tasks created %r' % self.tasks)

def build(bld):
tg = bld(features='c cprogram debug_tasks', source='main.c', target='app')
复制代码

通过绑定新方法到 context 类, 声明可以变得更加用户友好。

复制代码
    from waflib.Build import BuildContext
def enterprise_program(self, *k, **kw):
kw['features'] = 'c cprogram debug_tasks'
return self(*k, **kw)
BuildContext.enterprise_program = enterprise_program

def build(bld):
# no feature line
bld.enterprise_program(source='main.c', target='app')
复制代码

这些辅助代码放到单独文件中即可以成为一个 Waf 工具。为了便于部署,新的 Waf 工具甚至可以被添加到 Waf 文件中(参见 http://code.google.com/p/waf/source/browse/trunk/README)。

结论

教程到此结束。 更多信息请参考apisWaf bookexamples

  评论这张
 
阅读(156)| 评论(0)
推荐 转载

历史上的今天

在LOFTER的更多文章

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2018