tutorial.rst 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  1. Waf tutorial
  2. ============
  3. Waf is a piece of software used to help building software projects.
  4. The goal of this tutorial is to provide a quick overview of how to set up
  5. the scripts for a project using Waf.
  6. Waf scripts and commands
  7. ------------------------
  8. A software typically has *source files* which are kept in a version control system (git, subversion, etc),
  9. and *build scripts* (Makefiles, ..) which describe what to do with those files. A few *build files* are usually
  10. obtained after transforming the *source files*, but they are optional. The build scripts in Waf are files named 'wscript'.
  11. In general, a project will consist of several phases:
  12. * configure: configure the project, find the location of the prerequisites
  13. * build: transform the source files into build files
  14. * install: install the build files
  15. * uninstall: uninstall the build files
  16. * dist: create an archive of the source files
  17. * clean: remove the build files
  18. Each phase is modelled in the wscript file as a python function which takes as argument an instance of :py:class:`waflib.Context.Context`.
  19. Let's start with a new wscript file in the directory '/tmp/myproject'::
  20. def configure(conf):
  21. print("configure!")
  22. def build(bld):
  23. print("build!")
  24. We will also use a Waf binary file, for example waf-2.0.0, which we will copy in the project directory::
  25. $ cd /tmp/myproject
  26. $ wget https://waf.io/waf-2.0.0
  27. To execute the project, we will simply call the command as an argument to ``waf``::
  28. $ python ./waf-2.0.0 configure build
  29. configure!
  30. build!
  31. Targets
  32. -------
  33. An important part of the build system is to declare the creation of targets. Here is a very simple example::
  34. def build(bld):
  35. tg = bld(rule='cp ${SRC} ${TGT}', source='wscript', target='foo.txt')
  36. bld(rule='cp ${SRC} ${TGT}', source='foo.txt', target='bar.txt')
  37. The call ``bld(..)`` creates an object called *task generator*, which is used to create *tasks* which will actually
  38. call the command ``cp``. The commands are not executed unless all the scripts have been read, which is important
  39. for computing the build order.
  40. The expressions *${SRC}* and *${TGT}* are shortcuts to avoid repeating the file names. More shortcuts can be defined
  41. by using the *${}* symbol, which reads the values from the attribute bld.env::
  42. def build(bld):
  43. bld.env.MESSAGE = 'Hello, world!'
  44. bld(rule='echo ${MESSAGE}', always=True)
  45. The bld object is an instance of :py:class:`waflib.Build.BuildContext`, its *env* attribute is an instance :py:class:`waflib.ConfigSet.ConfigSet`.
  46. The values are set in this object to be shared/stored/loaded easily. Here is how to do the same thing by sharing data between the configuration and build::
  47. def configure(cnf):
  48. cnf.env.MESSAGE = 'Hello, world!'
  49. def build(bld):
  50. bld(rule='echo ${MESSAGE}', always=True)
  51. Scripts and Tools
  52. -----------------
  53. To let a script use a script from a subdirectory, the method :py:meth:`waflib.Context.Context.recurse` has to be used with
  54. the relative path to the folder containing the wscript file. For example, to call the function *build* in the script ``src/wscript``,
  55. one should write::
  56. def build(bld):
  57. bld.recurse('src')
  58. The support for specific languages and compilers is provided through specific modules called *Waf tools*. The tools are
  59. similar to wscript files and provide functions such as *configure* or *build*. Here is a simple project for the C programming language::
  60. def options(opt):
  61. opt.load('compiler_c')
  62. def configure(cnf):
  63. cnf.load('compiler_c')
  64. def build(bld):
  65. bld(features='c cprogram', source='main.c', target='app')
  66. The function *options* is another predefined command used for setting command-line options. Its argument is an instance of :py:meth:`waflib.Options.OptionsContext`. The tool *compiler_c* is provided for detecting if a C compiler is present and to set various variables such as ``cnf.env.CFLAGS``.
  67. The task generator declared in *bld* does not have a *rule* keyword, but a list of *features* which is used to reference methods that will call the appropriate rules. In this case, a rule is called for compiling the file, and another is used for linking the object files into the binary *app*. Other tool-dependent features exist such as *javac*, *cs*, or *tex*.
  68. A C and C++ project
  69. -------------------
  70. Here is a script for a more complicated project::
  71. def options(opt):
  72. opt.load('compiler_c compiler_cxx')
  73. def configure(cnf):
  74. cnf.load('compiler_c compiler_cxx')
  75. cnf.check(features='cxx cxxprogram', lib=['m'], cflags=['-Wall'], defines=['var=foo'], uselib_store='M')
  76. def build(bld):
  77. bld(features='c cshlib', source='b.c', target='mylib')
  78. bld(features='c cxx cxxprogram', source='a.c main.cpp', target='app', use=['M','mylib'], lib=['dl'])
  79. The method :py:func:`waflib.Tools.c_config.check` executes a build internally to check if the library ``libm`` is present on the operating system.
  80. It will then define variables such as:
  81. * ``conf.env.LIB_M = ['m']``
  82. * ``conf.env.CFLAGS_M = ['-Wall']``
  83. * ``conf.env.DEFINES_M = ['var=foo']``
  84. By stating ``use=['M', 'mylib']``, the program *app* is going to inherit all the *M* variables defined
  85. during the configuration. The program will also use the library *mylib* and both the build order and the dependencies
  86. will be modified so that *mylib* is linked before *app*.
  87. The ``use`` attribute is also working for other languages such as Java (dependencies between jar files) or C# (dependencies between assemblies).
  88. Project-specific extensions
  89. ---------------------------
  90. The *feature* keyword is a high-level reference to existing Waf methods.
  91. For example, the **c** feature will add the method :py:func:`waflib.Tools.ccroot.apply_incpaths` for execution.
  92. To add a new method that will add the task generator path to the include path for all C targets,
  93. one may use such a declaration::
  94. from waflib import Utils
  95. from waflib.TaskGen import feature, before_method
  96. @feature('c')
  97. @before_method('apply_incpaths')
  98. def add_current_dir_to_includes(self):
  99. self.includes = Utils.to_list(self.includes)
  100. self.includes.append(self.path)
  101. def build(bld):
  102. tg = bld(features='c', source='main.c', target='app')
  103. The *feature* methods are bound to the :py:class:`waflib.TaskGen.task_gen` class, which is the class of the
  104. object *tg* in the example. New features can be declared in the same manner::
  105. from waflib.TaskGen import feature, after_method
  106. @feature('debug_tasks')
  107. @after_method('apply_link')
  108. def print_debug(self):
  109. print('tasks created %r' % self.tasks)
  110. def build(bld):
  111. tg = bld(features='c cprogram debug_tasks', source='main.c', target='app')
  112. The declaration can be made more user-friendly by binding new methods to the context classes::
  113. from waflib.Build import BuildContext
  114. def enterprise_program(self, *k, **kw):
  115. kw['features'] = 'c cprogram debug_tasks'
  116. return self(*k, **kw)
  117. BuildContext.enterprise_program = enterprise_program
  118. def build(bld):
  119. # no feature line
  120. bld.enterprise_program(source='main.c', target='app')
  121. The support code may be turned into a Waf tool by moving it to a separate file.
  122. To ease the deployment, the new Waf tool can even be added to the waf file (see https://gitlab.com/ita1024/waf/blob/master/README.md#L20).
  123. Conclusion
  124. ----------
  125. This concludes the tutorial. For more information consult the apis, the Waf book and the examples.