waf 是一个帮助构建和编译系统的框架。
一、下载waf安装包
下载安装包: https://waf.io/
或者: $ curl -o waf-2.0.9.tar.bz2 https://waf.io/waf-2.0.9.tar.bz2
二、解压及安装
$ tar xjvf waf-2.0.9.tar.bz2
$ cd waf-2.0.9
$ ./waf-light
三、为了方便使用,将waf添加到PATH路径
$ cd waf-2.0.9
$ PATH=$PATH:$PWD
四、waf项目的目录大致结构如下
$ tree |-- src | `-- wscript `-- wscript
主目录下有一个主的wscript脚本,要编译的子目录src目录下也有一个wscript脚本(每个wscript是python脚本)。
五、一个简单的例子
主目录的wscript内容:
-
#! /usr/bin/env python
-
# encoding: utf-8
-
-
top =
'.'
-
out =
'build'
-
-
def configure(ctx):
-
print(
' -> configureing the project in ' + ctx.path.abspath())
-
-
def ping(ctx):
-
print(
'-> ping from ' + ctx.path.abspath())
-
ctx.recurse(
'src')
说明: 设置top目录为当前路径,输出路径为当前目录的build目录
src目录下的wscript内容:
-
#! /usr/bin/env python
-
# encoding: utf-8
-
-
def ping(ctx):
-
print(
'-> ping from ' + ctx.path.abspath())
(1) 首先执行
$ waf configure
Setting top to : /home/fcx/share/test/waf_learn/simple_test
Setting out to : /home/fcx/share/test/waf_learn/simple_test/build
-> configureing the project in /home/fcx/share/test/waf_learn/simple_test
'configure' finished successfully (0.036s)
于是在新建的build目录会生成一下配置文件
|-- build | |-- c4che | | |-- build.config.py | | `-- _cache.py | `-- config.log |--.lock-wafbuild |-- src | `-- wscript `-- wscript
其中配置数据存储在build/c4che/目录下,命令行选项和环境变量存储在build.config.py中。用户的配置设置存储在_cache.py中。
(2)然后执行:
$ waf ping
-> ping from /home/fcx/share/test/waf_learn/simple_test
-> ping from /home/fcx/share/test/waf_learn/simple_test/src
'ping' finished successfully (0.002s)
如果执行 waf distclean 将会删除build的目录。distclean函数不需要在主wscript脚本中定义,如果你自己定义了该函数,则默认的distclean函数调用将会被你定义的函数覆盖。
(3)waf dist命令
默认执行该命令将会把项目代码打包为一个名为noname-1.0.tar.bz2的压缩包,如果要自己命名,则在主wscript脚本的top命令前添加如:
-
#! /usr/bin/env python
-
# encoding: utf-8
-
-
APPNAME =
'waf_learn'
-
VERSION =
'1.0.0'
-
-
top =
'.'
-
out =
'build'
-
-
def configure(ctx):
-
print(
' -> configureing the project in ' + ctx.path.abspath())
-
-
def ping(ctx):
-
print(
'-> ping from ' + ctx.path.abspath())
-
ctx.recurse(
'src')
这样生成的压缩包名为:waf_learn-1.0.0.tar.bz2
(4)waf --help
-
$ waf --help
-
waf [command] [options]
-
-
Main commands (example: ./waf build -j4)
-
build : executes the build
-
clean : cleans the project
-
configure: configures the project
-
dist : makes a tarball
for redistributing the sources
-
distcheck: checks
if the project compiles (tarball
from
'dist')
-
distclean: removes the build directory
-
install : installs the targets on the system
-
list : lists the targets to execute
-
step : executes tasks
in a step-by-step fashion,
for debugging
-
uninstall: removes the targets installed
-
-
Options:
-
--version show program
's version number and exit
-
-h, --help show this help message and exit
-
-j JOBS, --jobs=JOBS amount of parallel jobs (2)
-
-k, --keep keep running happily even if errors are found
-
-v, --verbose verbosity level -v -vv or -vvv [default: 0]
-
--zones=ZONES debugging zones (task_gen, deps, tasks, etc)
-
-
configure options:
-
-o OUT, --out=OUT build dir for the project
-
-t TOP, --top=TOP src dir for the project
-
--prefix=PREFIX installation prefix [default: '/usr/local/
']
-
--download try to download the tools if missing
-
-
build and install options:
-
-p, --progress -p: progress bar; -pp: ide output
-
--targets=TARGETS task generators, e.g. "target1,target2"
-
-
step options:
-
--files=FILES files to process, by regexp, e.g. "*/main.c,*/test/main.o"
-
-
install/uninstall options:
-
--destdir=DESTDIR installation root [default: '
']
-
-f, --force force file installation
(5)自定义命令行参数(定义options函数)
-
#! /usr/bin/env python
-
# encoding: utf-8
-
-
APPNAME =
'waf_learn'
-
VERSION =
'1.0.0'
-
-
top =
'.'
-
out =
'build'
-
-
def options(ctx):
-
ctx.add_option(
'--arg1', action=
'store', default=
False, help=
'set argument 1')
-
ctx.add_option(
'--arg2', action=
'store', default=
'false', help=
'set argument 2')
-
-
def configure(ctx):
-
print(
' -> configureing the project in ' + ctx.path.abspath())
-
print(
'-- the value of arg1 is %s' % ctx.options.arg1)
-
print(
'-- the value of arg2 is %s' % ctx.options.arg2)
-
-
def ping(ctx):
-
print(
'-> ping from ' + ctx.path.abspath())
-
ctx.recurse(
'src')
然后执行 : waf configure --arg1=true --arg2='false'
有如下输出:
Setting top to : /home/fcx/share/test/waf_learn/simple_test
Setting out to : /home/fcx/share/test/waf_learn/simple_test/build
-> configureing the project in /home/fcx/share/test/waf_learn/simple_test
-- the value of arg1 is true
-- the value of arg2 is false
'configure' finished successfully (0.012s)
六、配置环境变量
-
#! /usr/bin/env python
-
# encoding: utf-8
-
-
APPNAME =
'waf_learn'
-
VERSION =
'1.0.0'
-
-
top =
'.'
-
out =
'build'
-
-
def options(ctx):
-
# 设置命令行参数,及默认值
-
ctx.add_option(
'--arg1', action=
'store', default=
False, help=
'set argument 1')
-
ctx.add_option(
'--arg2', action=
'store', default=
'false', help=
'set argument 2')
-
-
def configure(ctx):
-
print(
' -> configureing the project in ' + ctx.path.abspath())
-
print(
'-- the value of arg1 is %s' % ctx.options.arg1)
-
print(
'-- the value of arg2 is %s' % ctx.options.arg2)
-
# 将命令行参数赋值给环境变量
-
ctx.env.ENV_ARG1 = ctx.options.arg1
-
# 查找应用并赋值给环境变量: 实现 CC=XXX/gcc
-
ctx.find_program(
'gcc', var=
'CC')
-
ctx.find_program(
'abc', mandatory=
False)
#测试不能找到的情况
-
-
# 为一个环境变量添加选项列表
-
ctx.env.CFLAGS = [
'-g']
# 等价于 ctx.env['CFLAGS'] = ['-g']
-
ctx.env.append_value(
'CFLAGS', [
'-O2',
'-Wall'])
-
-
ctx.env.append_value(
'CXXFLAGS', [
'-O3',
'-g'])
-
-
#环境变量的拷贝和保存和读取
-
env_copy = ctx.env.derive()
#浅拷贝
-
node = ctx.path.make_node(
'save_env.txt')
#创建文件节点
-
env_copy.store(node.abspath())
#将环境变量拷贝到文件
-
-
from waflib.ConfigSet
import ConfigSet
-
env2 = ConfigSet()
-
env2.load(node.abspath())
#加载保存的环境变量
-
print
'------------------------------'
-
print(node.read())
#打印出来
-
print
'------------------------------'
-
-
-
def build(bld):
-
print(
'++++ build %s' % bld.path.abspath())
-
print(
'ENV_ARG1 = %s' % bld.env.ENV_ARG1)
-
print(
'CC = %s' % bld.env.CC)
-
bld.recurse(
'src')
执行:
$ waf configure build
Setting top to : /home/fcx/share/test/waf_learn/simple_test
Setting out to : /home/fcx/share/test/waf_learn/simple_test/build
-> configureing the project in /home/fcx/share/test/waf_learn/simple_test
-- the value of arg1 is False
-- the value of arg2 is false
Checking for program 'gcc' : /usr/bin/gcc
Checking for program 'abc' : not found
------------------------------
BINDIR = '/usr/local/bin'
CC = ['/usr/bin/gcc']
CFLAGS = ['-g', '-O2', '-Wall']
CXXFLAGS = ['-O3', '-g']
ENV_ARG1 = False
LIBDIR = '/usr/local/lib'
PREFIX = '/usr/local'
------------------------------
'configure' finished successfully (0.014s)
Waf: Entering directory `/home/fcx/share/test/waf_learn/simple_test/build'
++++ build /home/fcx/share/test/waf_learn/simple_test
ENV_ARG1 = False
CC = ['/usr/bin/gcc']
++++ build /home/fcx/share/test/waf_learn/simple_test/src
Waf: Leaving directory `/home/fcx/share/test/waf_learn/simple_test/build'
'build' finished successfully (0.018s)
七、BUILD 例子
主目录下的wscript脚本:
-
#! /usr/bin/env python
-
# encoding: utf-8
-
-
APPNAME =
'waf_learn'
-
VERSION =
'1.0.0'
-
-
top =
'.'
-
out =
'build'
-
-
def options(ctx):
-
# 设置命令行参数,及默认值
-
ctx.add_option(
'--arg1', action=
'store', default=
False, help=
'set argument 1')
-
ctx.add_option(
'--arg2', action=
'store', default=
'false', help=
'set argument 2')
-
-
def configure(ctx):
-
print(
' -> configureing the project in ' + ctx.path.abspath())
-
print(
'-- the value of arg1 is %s' % ctx.options.arg1)
-
print(
'-- the value of arg2 is %s' % ctx.options.arg2)
-
# 将命令行参数赋值给环境变量
-
ctx.env.ENV_ARG1 = ctx.options.arg1
-
# 查找应用并赋值给环境变量: 实现 CC=XXX/gcc
-
ctx.find_program(
'gcc', var=
'CC')
-
ctx.find_program(
'abc', mandatory=
False)
#测试不能找到的情况
-
-
# 为一个环境变量添加选项列表
-
ctx.env.CFLAGS = [
'-g']
# 等价于 ctx.env['CFLAGS'] = ['-g']
-
ctx.env.append_value(
'CFLAGS', [
'-O2',
'-Wall'])
-
-
ctx.env.append_value(
'CXXFLAGS', [
'-O3',
'-g'])
-
-
#环境变量的拷贝和保存和读取
-
env_copy = ctx.env.derive()
#浅拷贝
-
node = ctx.path.make_node(
'save_env.txt')
#创建文件节点
-
env_copy.store(node.abspath())
#将环境变量拷贝到文件
-
-
from waflib.ConfigSet
import ConfigSet
-
env2 = ConfigSet()
-
env2.load(node.abspath())
#加载保存的环境变量
-
print
'------------------------------'
-
print(node.read())
#打印出来
-
print
'------------------------------'
-
-
#定义在编译前执行的函数
-
def build_before(ctx):
-
print
'do something before building the project.'
-
-
#定义在编译完成后执行的函数
-
def build_after(ctx):
-
print
'do something after building the project.'
-
-
-
def build(bld):
-
print(
'++++ build %s' % bld.path.abspath())
-
print(
'ENV_ARG1 = %s' % bld.env.ENV_ARG1)
-
print(
'CC = %s' % bld.env.CC)
-
-
#动态创建任务: 将save_env.txt拷贝到build目录下另存为env.txt
-
tg = bld(rule=
'cp ${SRC} ${TGT}', source=
'save_env.txt', target=
'env.txt')
-
print
'type tg is %s' % type(tg)
-
print
'post before: tg.tasks list is %s' % tg.tasks
-
tg.post()
#将任务入队
-
print
'post after: tg.tasks list is %s' % tg.tasks
-
-
bld.recurse(
'src')
-
-
bld.add_pre_fun(build_before)
#添加编译前需要执行的函数
-
bld.add_post_fun(build_after)
#添加编译后需要执行的函数
src目录下的wscript脚本:
-
#! /usr/bin/env python
-
# encoding: utf-8
-
-
def configure(ctx):
-
pass
-
-
def build(bld):
-
print(
'++++ build %s' % bld.path.abspath())
-
bld(rule=
'touch ${TGT}', target=
'test.o')
-
print(
'ENV_PREFIX = %s' % bld.env[
'PREFIX'])
-
-
#只有执行waf install或uninstall 才执行
-
#将build的文件安装到某路径下
-
bld.install_files(
'/tmp/',
'test.o')
-
bld.install_as(
'/tmp/abc.o',
'test.o')
-
-
bld(rule=
'touch ${TGT}', target=
'test.so.1')
-
#创建一个符号链接
-
bld.symlink_as(
'/tmp/test.so',
'test.so.1')
执行: waf configure build install
Setting top to : /home/fcx/share/test/waf_learn/simple_test
Setting out to : /home/fcx/share/test/waf_learn/simple_test/build
-> configureing the project in /home/fcx/share/test/waf_learn/simple_test
-- the value of arg1 is False
-- the value of arg2 is false
Checking for program 'gcc' : /usr/bin/gcc
Checking for program 'abc' : not found
------------------------------
BINDIR = '/usr/local/bin'
CC = ['/usr/bin/gcc']
CFLAGS = ['-g', '-O2', '-Wall']
CXXFLAGS = ['-O3', '-g']
ENV_ARG1 = False
LIBDIR = '/usr/local/lib'
PREFIX = '/usr/local'
------------------------------
'configure' finished successfully (0.025s)
Waf: Entering directory `/home/fcx/share/test/waf_learn/simple_test/build'
++++ build /home/fcx/share/test/waf_learn/simple_test
ENV_ARG1 = False
CC = ['/usr/bin/gcc']
type tg is <class 'waflib.TaskGen.task_gen'>
post before: tg.tasks list is []
post after: tg.tasks list is [
{task 139906055718384: env.txt save_env.txt -> env.txt}]
++++ build /home/fcx/share/test/waf_learn/simple_test/src
ENV_PREFIX = /usr/local
do something before building the project.
Waf: Leaving directory `/home/fcx/share/test/waf_learn/simple_test/build'
do something after building the project.
'build' finished successfully (0.104s)
Waf: Entering directory `/home/fcx/share/test/waf_learn/simple_test/build'
++++ build /home/fcx/share/test/waf_learn/simple_test
ENV_ARG1 = False
CC = ['/usr/bin/gcc']
type tg is <class 'waflib.TaskGen.task_gen'>
post before: tg.tasks list is []
post after: tg.tasks list is [
{task 139906017850024: env.txt save_env.txt -> env.txt}]
++++ build /home/fcx/share/test/waf_learn/simple_test/src
ENV_PREFIX = /usr/local
do something before building the project.
+ install /tmp/test.o (from build/src/test.o)
+ install /tmp/abc.o (from build/src/test.o)
+ symlink /tmp/test.so (to test.so.1)
Waf: Leaving directory `/home/fcx/share/test/waf_learn/simple_test/build'
do something after building the project.
'install' finished successfully (0.016s)
在/tmp/目录下也会生成 test.o abc.o test.so文件。可以通过执行命令: waf list 查看生成的目标列表。
八、文件节点的概念
一个文件或目录称为一个节点
-
def build(bld):
-
#bld.path是当前wscript的路径
-
print(
'++++ build %s' % bld.path.abspath())
-
#打印当前目录下的内容
-
print
'bld.path contents: %r' % bld.path.children
-
#打印当前目录的父目录路径
-
print
'bld.path parent: %s' % bld.path.parent.abspath()
-
#在系统中搜索节点
-
print bld.path.find_node(
'wscript')
-
#在系统中搜索节点,如果没有则创建
-
print bld.path.make_node(
'test.o')
-
#在系统中搜索节点,找不到也不去创建
-
print bld.path.search_node(
'test.oo')
-
-
print
'ant_glob Test...'
-
# ant_glob 用于递归列出文件和目录
-
print bld.path.ant_glob(
'*.c') + bld.path.ant_glob(
'*.h')
#打印当前目录下所有的.c和.h文件
-
print bld.path.ant_glob([
'test*',
'wscri*'])
-
print bld.path.ant_glob([
'test*',
'wscri*'], excl = [
'*.bak'])
#排除结尾是bak的文件
-
print bld.path.parent.ant_glob(
'wscri*')
#列出当前节点的父目录下的文件 这样写无效: bld.path.ant_glob('../wscri*')
-
-
node = bld.path.find_node(
'wscript')
-
print node.get_src()
#打印wscript所在源文件目录
-
print node.get_bld()
#打印wscript所在目录的build目录
-
-
nd = bld.path.make_node(
'test.txt')
-
nd.write(
'hello world!')
#往文件节点写数据
-
print nd.read()
#从文件节点读取数据
-
-
print bld.path.listdir()
#打印当前目录下的内容
-
-
bld(rule=
'touch ${TGT}', target=
'test.o')
-
print(
'ENV_PREFIX = %s' % bld.env[
'PREFIX'])
-
-
#只有执行waf install或uninstall 才执行
-
#将build的文件安装到某路径下
-
bld.install_files(
'/tmp/',
'test.o')
-
bld.install_as(
'/tmp/abc.o',
'test.o')
-
-
bld(rule=
'touch ${TGT}', target=
'test.so.1')
-
#创建一个符号链接
-
bld.symlink_as(
'/tmp/test.so',
'test.so.1')
九、C或C++项目
-
def options(opt):
-
opt.load(
'compiler_c')
-
-
def configure(conf):
-
conf.load(
'compiler_c')
-
-
def build(bld):
-
#program: 目标是生成应用程序 app
-
bld.program(source=
'main.c', target=
'app', use=
'myshlib mystlib')
-
#stlib: 目标是生成静态库 mystlib.a
-
bld.stlib(source=
'a.c', target=
'mystlib', use=
'myobjects')
-
#shlib: 目标是生成动态库 myshlib.so
-
bld.shlib(source=
'b.c', target=
'myshlib')
-
#objects:目标是生成c.o
-
bld.objects(source=
'c.c', target=
'myobjects')
Uselib variable | Attribute | Usage |
---|---|---|
LIB | lib | 使用的共享库名 |
LIBPATH | libpath | 使用的共享库路径 |
STLIB | stlib | 使用的静态库名 |
STLIBPATH | stlibpath | 使用的静态库路径 |
LINKFLAGS | linkflags | 放在链接命令前面的链接参数 |
LDFLAGS | ldflags | 放在链接命令末尾的链接参数 |
RPATH | rpath | 在链接时硬编码为二进制文件的路径 |
CFLAGS | cflags | c文件的编译选项 |
CXXFLAGS | cxxflags | c++文件的编译选项 |
CPPFLAGS | cppflags | c++文件的编译选项放在编译命令的末尾 |
FCFLAGS | fcflags | list of Fortran compilation flags |
DFLAGS | dflags | list of compilation flags for d files |
INCLUDES | includes | 头文件路径 |
CXXDEPS |
| 当发生变更时需要重新编译的依赖文件 |
CCDEPS |
| 同上for C |
LINKDEPS |
| 链接依赖 |
DEFINES | defines | list of defines in the form [‘key=value’, …] |
FRAMEWORK | framework | list of frameworks to use |
FRAMEWORKPATH | frameworkpath | list of framework paths to use |
ARCH | arch | list of architectures in the form [ppc, x86]
|
十、例子总结
用waf编译了一个小工程:sendMessage, 代码请参考:
https://download.youkuaiyun.com/download/u010312436/10615769