翻译: Waf 教程
前言
本人剛剛接觸 Waf ,加之翻譯水平一般,有什么錯誤大家見諒。
精確版本請看 原文地址
Waf 是一份用來幫助編譯軟件工程的軟件。本教程的目標(biāo)是提供如何為一個使用 Waf 的工程設(shè)置腳本的簡要說明。
Waf 腳本與命令
軟件通常有保存在版本管理系統(tǒng)(git, subversion 等等)的 源文件(source files),以及描述如何處理這些文件的 編譯腳本(build scripts) (Makefiles,...)。一些 生成文件(build files) 通常由 源文件(source files) 轉(zhuǎn)換而得,但它們是可選的。在 Waf 中編譯腳本是那些命名為 'wscript' 的文件。
通常,一個工程包含下面若干階段:
- 配置(configure): 配置工程,找到依賴項的位置
- 編譯(build): 將源文件轉(zhuǎn)換為生成文件
- 安裝(install): 安裝生成文件
- 卸載(uninstall): 卸載生成文件
- 打包(dist): 生成源文件的存檔
- 清理(clean): 刪除生成文件
每一階段在 wscript 文件中都是以一個 Python 函數(shù)構(gòu)造的,該函數(shù)使用 waflib.Context.Context 的一個實例作為函數(shù)。
讓我們從在文件夾 /tmp/myproject 下 新建一個 wscript 文件開始:
def configure(conf):print("configure!")
def build(bld):
print("build!")
我們也需要一個 Waf 二進(jìn)制文件,如: http://waf.googlecode.com/files/waf-1.6.1 , 并把該文件拷貝到工程目錄下:
$ cd /tmp/myproject$ wget http://waf.googlecode.com/files/waf-1.6.1
我們只需簡單地將命令作為參數(shù)傳遞給 waf 即可運(yùn)行此工程:
$ ./waf-1.6.1 configure buildconfigure!
build!
目標(biāo)
編譯系統(tǒng)的一個重要組成部分是聲明目標(biāo)的創(chuàng)建過程。這里有一個非常簡單的例子:
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')
調(diào)用 bld(..) 創(chuàng)建了一個 任務(wù)生成器(task generator) ,它用來生成 任務(wù)(tasks) 。 任務(wù)則實際運(yùn)行命令 cp。 命令直到所有腳本都被讀取后才會運(yùn)行,這對計算編譯順序非常重要。
表達(dá)式 ${SRC} 和 ${TGT} 是快捷方式,用來避免文件名重復(fù)。更多的快捷方式可以通過使用 ${} 符合定義,該符號能從 bld.env 屬性讀取對應(yīng)的值。
def build(bld):bld.env.MESSAGE = 'Hello, world!'
bld(rule='echo ${MESSAGE}', always=True)
bld 對象是類 waflib.Build.BuildContext,它的 env 屬性是類 waflib.ConfigSet.ConfigSet 的一個實例。
這些值被保存在此對象中以便于共享/保存/加載。這里是如何在配置和編譯過程中共享數(shù)據(jù)來實現(xiàn)和上個例子同樣的事情:
def configure(cnf):cnf.env.MESSAGE = 'Hello, world!'
def build(bld):
bld(rule='echo ${MESSAGE}', always=True)
腳本與工具
為讓一個腳本使用子目錄下的另一腳本,需要使用方法 waflib.Context.Context.recurse 及包含 wscript 文件夾的相對路徑。例如,調(diào)用 src/wscript 腳本中 build 函數(shù),應(yīng)該這樣寫:、
def build(bld):bld.recurse('src')
Waf 通過特定模塊 Waf tools 提供了對特定語言和編譯器的支持。這些工具與 wscript 文件類似且提供如 configure 或者 build 函數(shù)。這里是一個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')
options 函數(shù)是另一個預(yù)定義的命令,用來設(shè)置命令行選項。它的參數(shù)是 waflib.Options.OptionsContext 的一個實例。 提供了工具 compiler_c用以檢測是否有 C 編譯器存在,并設(shè)置各種參數(shù)如 cnf.env.CFLAGS。
用 bld 聲明的任務(wù)生成器并沒有 規(guī)則(rule) 關(guān)鍵字,而是用一系列 特性(features) 來引用那些調(diào)用適當(dāng)規(guī)則的方法。 在這個例子中,一個規(guī)則被調(diào)用以編譯文件,而另一個用來鏈接目標(biāo)文件到二進(jìn)制文件 app 。 還存在其他一些工具依賴的 特性(features) 如: javac,cs 或者 tex 。
一個同時使用C和C++的工程
下面是一個更復(fù)雜一些工程的腳本
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'])
方法 waflib.Tools.c_config.check 會內(nèi)部執(zhí)行編譯以檢測在操作系統(tǒng)中是否存在 libm 庫。然后它會定義變量如:
- conf.env.LIB_M = ['m']
- conf.env.CFLAGS_M = ['-Wall']
- conf.env.DEFINES_M = ['var=foo']
通過聲明 use=['M', 'mylib'],程序 app 會繼承所有在配置過程中定義的 M 變量。該程序也會使用庫 mylib 并且編譯順序和依賴項都會更改以使 mylib 在 app 之前鏈接。
use 屬性也適用于其他語言如Java(jar 文件之間的依賴)或者C#(程序集之間的依賴)。
工程特定擴(kuò)展
feature 關(guān)鍵字是高層次的對現(xiàn)有 Waf 方法的引用。例如: c feature 會添加方法 waflib.Tools.ccroot.apply_incpaths 以執(zhí)行。要添加一個為所有C目標(biāo)加入任務(wù)生成器路徑到包含路徑的新方法,可以采用如下聲明:
from waflib import Utilsfrom 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 方法被綁定到類 waflib.TaskGen.task_gen ,在這個例子中是對象 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 BuildContextdef 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)。
結(jié)論
教程到此結(jié)束。 更多信息請參考apis,Waf book,examples。
轉(zhuǎn)載于:https://www.cnblogs.com/Lvkun/archive/2012/03/30/trans-waf-tutorial.html
總結(jié)
以上是生活随笔為你收集整理的翻译: Waf 教程的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Silverlight DataGrid
- 下一篇: [已经完美解决]IE下 'docume