waf帮助构建及编译系统

本文详细介绍了如何使用WAF框架进行C/C++项目的构建和管理。从下载安装WAF,到项目目录结构、配置环境变量、自定义命令行参数,再到C或C++项目的编译和安装,通过实例演示了WAF的基本用法和高级特性。此外,还讲解了文件节点的概念以及如何处理C/C++项目中的各种目标类型。
摘要由CSDN通过智能技术生成

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项目的目录大致结构如下


   
   
  1. $ tree
  2. |-- src
  3. | `-- wscript
  4. `-- wscript

主目录下有一个主的wscript脚本,要编译的子目录src目录下也有一个wscript脚本(每个wscript是python脚本)。

五、一个简单的例子

主目录的wscript内容:


   
   
  1. #! /usr/bin/env python
  2. # encoding: utf-8
  3. top = '.'
  4. out = 'build'
  5. def configure(ctx):
  6. print( ' -> configureing the project in ' + ctx.path.abspath())
  7. def ping(ctx):
  8. print( '-> ping from ' + ctx.path.abspath())
  9. ctx.recurse( 'src')

说明: 设置top目录为当前路径,输出路径为当前目录的build目录

 src目录下的wscript内容:


   
   
  1. #! /usr/bin/env python
  2. # encoding: utf-8
  3. def ping(ctx):
  4. 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目录会生成一下配置文件


   
   
  1. |-- build
  2. | |-- c4che
  3. | | |-- build.config.py
  4. | | `-- _cache.py
  5. | `-- config.log
  6. |--.lock-wafbuild
  7. |-- src
  8. | `-- wscript
  9. `-- 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命令前添加如:


   
   
  1. #! /usr/bin/env python
  2. # encoding: utf-8
  3. APPNAME = 'waf_learn'
  4. VERSION = '1.0.0'
  5. top = '.'
  6. out = 'build'
  7. def configure(ctx):
  8. print( ' -> configureing the project in ' + ctx.path.abspath())
  9. def ping(ctx):
  10. print( '-> ping from ' + ctx.path.abspath())
  11. ctx.recurse( 'src')

这样生成的压缩包名为:waf_learn-1.0.0.tar.bz2

(4)waf --help


   
   
  1. $ waf --help
  2. waf [command] [options]
  3. Main commands (example: ./waf build -j4)
  4. build : executes the build
  5. clean : cleans the project
  6. configure: configures the project
  7. dist : makes a tarball for redistributing the sources
  8. distcheck: checks if the project compiles (tarball from 'dist')
  9. distclean: removes the build directory
  10. install : installs the targets on the system
  11. list : lists the targets to execute
  12. step : executes tasks in a step-by-step fashion, for debugging
  13. uninstall: removes the targets installed
  14. Options:
  15. --version show program 's version number and exit
  16. -h, --help show this help message and exit
  17. -j JOBS, --jobs=JOBS amount of parallel jobs (2)
  18. -k, --keep keep running happily even if errors are found
  19. -v, --verbose verbosity level -v -vv or -vvv [default: 0]
  20. --zones=ZONES debugging zones (task_gen, deps, tasks, etc)
  21. configure options:
  22. -o OUT, --out=OUT build dir for the project
  23. -t TOP, --top=TOP src dir for the project
  24. --prefix=PREFIX installation prefix [default: '/usr/local/ ']
  25. --download try to download the tools if missing
  26. build and install options:
  27. -p, --progress -p: progress bar; -pp: ide output
  28. --targets=TARGETS task generators, e.g. "target1,target2"
  29. step options:
  30. --files=FILES files to process, by regexp, e.g. "*/main.c,*/test/main.o"
  31. install/uninstall options:
  32. --destdir=DESTDIR installation root [default: ' ']
  33. -f, --force force file installation

(5)自定义命令行参数(定义options函数)


   
   
  1. #! /usr/bin/env python
  2. # encoding: utf-8
  3. APPNAME = 'waf_learn'
  4. VERSION = '1.0.0'
  5. top = '.'
  6. out = 'build'
  7. def options(ctx):
  8. ctx.add_option( '--arg1', action= 'store', default= False, help= 'set argument 1')
  9. ctx.add_option( '--arg2', action= 'store', default= 'false', help= 'set argument 2')
  10. def configure(ctx):
  11. print( ' -> configureing the project in ' + ctx.path.abspath())
  12. print( '-- the value of arg1 is %s' % ctx.options.arg1)
  13. print( '-- the value of arg2 is %s' % ctx.options.arg2)
  14. def ping(ctx):
  15. print( '-> ping from ' + ctx.path.abspath())
  16. 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)

六、配置环境变量


   
   
  1. #! /usr/bin/env python
  2. # encoding: utf-8
  3. APPNAME = 'waf_learn'
  4. VERSION = '1.0.0'
  5. top = '.'
  6. out = 'build'
  7. def options(ctx):
  8. # 设置命令行参数,及默认值
  9. ctx.add_option( '--arg1', action= 'store', default= False, help= 'set argument 1')
  10. ctx.add_option( '--arg2', action= 'store', default= 'false', help= 'set argument 2')
  11. def configure(ctx):
  12. print( ' -> configureing the project in ' + ctx.path.abspath())
  13. print( '-- the value of arg1 is %s' % ctx.options.arg1)
  14. print( '-- the value of arg2 is %s' % ctx.options.arg2)
  15. # 将命令行参数赋值给环境变量
  16. ctx.env.ENV_ARG1 = ctx.options.arg1
  17. # 查找应用并赋值给环境变量: 实现 CC=XXX/gcc
  18. ctx.find_program( 'gcc', var= 'CC')
  19. ctx.find_program( 'abc', mandatory= False) #测试不能找到的情况
  20. # 为一个环境变量添加选项列表
  21. ctx.env.CFLAGS = [ '-g'] # 等价于 ctx.env['CFLAGS'] = ['-g']
  22. ctx.env.append_value( 'CFLAGS', [ '-O2', '-Wall'])
  23. ctx.env.append_value( 'CXXFLAGS', [ '-O3', '-g'])
  24. #环境变量的拷贝和保存和读取
  25. env_copy = ctx.env.derive() #浅拷贝
  26. node = ctx.path.make_node( 'save_env.txt') #创建文件节点
  27. env_copy.store(node.abspath()) #将环境变量拷贝到文件
  28. from waflib.ConfigSet import ConfigSet
  29. env2 = ConfigSet()
  30. env2.load(node.abspath()) #加载保存的环境变量
  31. print '------------------------------'
  32. print(node.read()) #打印出来
  33. print '------------------------------'
  34. def build(bld):
  35. print( '++++ build %s' % bld.path.abspath())
  36. print( 'ENV_ARG1 = %s' % bld.env.ENV_ARG1)
  37. print( 'CC = %s' % bld.env.CC)
  38. 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脚本:


   
   
  1. #! /usr/bin/env python
  2. # encoding: utf-8
  3. APPNAME = 'waf_learn'
  4. VERSION = '1.0.0'
  5. top = '.'
  6. out = 'build'
  7. def options(ctx):
  8. # 设置命令行参数,及默认值
  9. ctx.add_option( '--arg1', action= 'store', default= False, help= 'set argument 1')
  10. ctx.add_option( '--arg2', action= 'store', default= 'false', help= 'set argument 2')
  11. def configure(ctx):
  12. print( ' -> configureing the project in ' + ctx.path.abspath())
  13. print( '-- the value of arg1 is %s' % ctx.options.arg1)
  14. print( '-- the value of arg2 is %s' % ctx.options.arg2)
  15. # 将命令行参数赋值给环境变量
  16. ctx.env.ENV_ARG1 = ctx.options.arg1
  17. # 查找应用并赋值给环境变量: 实现 CC=XXX/gcc
  18. ctx.find_program( 'gcc', var= 'CC')
  19. ctx.find_program( 'abc', mandatory= False) #测试不能找到的情况
  20. # 为一个环境变量添加选项列表
  21. ctx.env.CFLAGS = [ '-g'] # 等价于 ctx.env['CFLAGS'] = ['-g']
  22. ctx.env.append_value( 'CFLAGS', [ '-O2', '-Wall'])
  23. ctx.env.append_value( 'CXXFLAGS', [ '-O3', '-g'])
  24. #环境变量的拷贝和保存和读取
  25. env_copy = ctx.env.derive() #浅拷贝
  26. node = ctx.path.make_node( 'save_env.txt') #创建文件节点
  27. env_copy.store(node.abspath()) #将环境变量拷贝到文件
  28. from waflib.ConfigSet import ConfigSet
  29. env2 = ConfigSet()
  30. env2.load(node.abspath()) #加载保存的环境变量
  31. print '------------------------------'
  32. print(node.read()) #打印出来
  33. print '------------------------------'
  34. #定义在编译前执行的函数
  35. def build_before(ctx):
  36. print 'do something before building the project.'
  37. #定义在编译完成后执行的函数
  38. def build_after(ctx):
  39. print 'do something after building the project.'
  40. def build(bld):
  41. print( '++++ build %s' % bld.path.abspath())
  42. print( 'ENV_ARG1 = %s' % bld.env.ENV_ARG1)
  43. print( 'CC = %s' % bld.env.CC)
  44. #动态创建任务: 将save_env.txt拷贝到build目录下另存为env.txt
  45. tg = bld(rule= 'cp ${SRC} ${TGT}', source= 'save_env.txt', target= 'env.txt')
  46. print 'type tg is %s' % type(tg)
  47. print 'post before: tg.tasks list is %s' % tg.tasks
  48. tg.post() #将任务入队
  49. print 'post after: tg.tasks list is %s' % tg.tasks
  50. bld.recurse( 'src')
  51. bld.add_pre_fun(build_before) #添加编译前需要执行的函数
  52. bld.add_post_fun(build_after) #添加编译后需要执行的函数

src目录下的wscript脚本:


   
   
  1. #! /usr/bin/env python
  2. # encoding: utf-8
  3. def configure(ctx):
  4. pass
  5. def build(bld):
  6. print( '++++ build %s' % bld.path.abspath())
  7. bld(rule= 'touch ${TGT}', target= 'test.o')
  8. print( 'ENV_PREFIX = %s' % bld.env[ 'PREFIX'])
  9. #只有执行waf install或uninstall 才执行
  10. #将build的文件安装到某路径下
  11. bld.install_files( '/tmp/', 'test.o')
  12. bld.install_as( '/tmp/abc.o', 'test.o')
  13. bld(rule= 'touch ${TGT}', target= 'test.so.1')
  14. #创建一个符号链接
  15. 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 查看生成的目标列表。

八、文件节点的概念

一个文件或目录称为一个节点


   
   
  1. def build(bld):
  2. #bld.path是当前wscript的路径
  3. print( '++++ build %s' % bld.path.abspath())
  4. #打印当前目录下的内容
  5. print 'bld.path contents: %r' % bld.path.children
  6. #打印当前目录的父目录路径
  7. print 'bld.path parent: %s' % bld.path.parent.abspath()
  8. #在系统中搜索节点
  9. print bld.path.find_node( 'wscript')
  10. #在系统中搜索节点,如果没有则创建
  11. print bld.path.make_node( 'test.o')
  12. #在系统中搜索节点,找不到也不去创建
  13. print bld.path.search_node( 'test.oo')
  14. print 'ant_glob Test...'
  15. # ant_glob 用于递归列出文件和目录
  16. print bld.path.ant_glob( '*.c') + bld.path.ant_glob( '*.h') #打印当前目录下所有的.c和.h文件
  17. print bld.path.ant_glob([ 'test*', 'wscri*'])
  18. print bld.path.ant_glob([ 'test*', 'wscri*'], excl = [ '*.bak']) #排除结尾是bak的文件
  19. print bld.path.parent.ant_glob( 'wscri*') #列出当前节点的父目录下的文件 这样写无效: bld.path.ant_glob('../wscri*')
  20. node = bld.path.find_node( 'wscript')
  21. print node.get_src() #打印wscript所在源文件目录
  22. print node.get_bld() #打印wscript所在目录的build目录
  23. nd = bld.path.make_node( 'test.txt')
  24. nd.write( 'hello world!') #往文件节点写数据
  25. print nd.read() #从文件节点读取数据
  26. print bld.path.listdir() #打印当前目录下的内容
  27. bld(rule= 'touch ${TGT}', target= 'test.o')
  28. print( 'ENV_PREFIX = %s' % bld.env[ 'PREFIX'])
  29. #只有执行waf install或uninstall 才执行
  30. #将build的文件安装到某路径下
  31. bld.install_files( '/tmp/', 'test.o')
  32. bld.install_as( '/tmp/abc.o', 'test.o')
  33. bld(rule= 'touch ${TGT}', target= 'test.so.1')
  34. #创建一个符号链接
  35. bld.symlink_as( '/tmp/test.so', 'test.so.1')

九、C或C++项目


   
   
  1. def options(opt):
  2. opt.load( 'compiler_c')
  3. def configure(conf):
  4. conf.load( 'compiler_c')
  5. def build(bld):
  6. #program: 目标是生成应用程序 app
  7. bld.program(source= 'main.c', target= 'app', use= 'myshlib mystlib')
  8. #stlib: 目标是生成静态库 mystlib.a
  9. bld.stlib(source= 'a.c', target= 'mystlib', use= 'myobjects')
  10. #shlib: 目标是生成动态库 myshlib.so
  11. bld.shlib(source= 'b.c', target= 'myshlib')
  12. #objects:目标是生成c.o
  13. bld.objects(source= 'c.c', target= 'myobjects')
Uselib variableAttributeUsage

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.csdn.net/download/u010312436/10615769

 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值