diff --git a/v2/doc/src/extending.xml b/v2/doc/src/extending.xml index a1c98c3c4..6cdb1fc55 100644 --- a/v2/doc/src/extending.xml +++ b/v2/doc/src/extending.xml @@ -2,7 +2,7 @@ - + Extender Manual
@@ -265,8 +265,127 @@ generators.register-composing mex.mex : CPP LIB : MEX ; (Need a note about UNIX) Custom generator classes + + The standard generators allows you to specify source and target + types, action, and a set of flags. If you need anything more complex, + you need to create a new generator class with your own logic. Then, + you have to create an instance of that class and register it. Here's + an example how you can create your own generator class: + +class custom-generator : generator +{ + rule __init__ ( * : * ) + { + generator.__init__ $(1) : $(2) : $(3) : $(4) : $(5) : $(6) : $(7) : $(8) : $(9) ; + } +} + +generators.register + [ new custom-generator verbatim.inline-file : VERBATIM : CPP ] ; + + This generator will work exactly like the + verbatim.inline-file generator we've defined above, but + it's possible to customize the behaviour by overriding methods of the + generator class. + + + There are two methods of interest. The run methods is + responsible for overall process - it takes a number of source targets, + converts them the the right types, and creates the result. The + generated-targets method is called when all sources are + converted to the right types to actually create the result. + + + The generated-target method can be overrided when you + want to add additional properties to the generated targets or use + additional sources. For example (which is real), you have a tool for + analysing programs, which should be given a name of executable and the + list of all sources. Naturally, you don't want to list all source + files manually. Here's how the generated-target method + can find the list of sources automatically: + +class itrace-generator : generator { +.... + rule generated-targets ( sources + : property-set : project name ? ) + { + local leafs ; + local temp = [ virtual-target.traverse $(sources[1]) : : include-sources ] ; + for local t in $(temp) + { + if ! [ $(t).action ] + { + leafs += $(t) ; + } + } + return [ generator.generated-targets $(sources) $(leafs) + : $(property-set) : $(project) $(name) ] ; + } +} +generators.register [ new itrace-generator nm.itrace : EXE : ITRACE ] ; + + The generated-targets rule will be called with a single + source target of type EXE. The call to the + virtual-target.traverse will return all targets the + executable depends on, and we further find files which are not + produced from anything. The found targets are added to the sources. + - + The run method can be overriden to completely + customize the way generator works. In particular, the conversion of + sources to the desired types can be completely customized. Here's + another real example. Tests for the Boost Python library usually + consist of two parts: a Python program and a C++ file. The C++ file is + compiled to Python extension which is loaded by the Python + program. But in the likely case that both files have the same name, + the created Python extension must be renamed. Otherwise, Python + program will import itself, not the extension. Here's how it can be + done: + +rule run ( project name ? : property-set : sources * : multiple ? ) +{ + local python ; + for local s in $(sources) + { + if [ $(s).type ] = PY + { + python = $(s) ; + } + } + + local libs ; + for local s in $(sources) + { + if [ type.is-derived [ $(s).type ] LIB ] + { + libs += $(s) ; + } + } + + local new-sources ; + for local s in $(sources) + { + if [ type.is-derived [ $(s).type ] CPP ] + { + local name = [ $(s).name ] ; + if $(name) = [ $(python).name ] + { + name = $(name)_ext ; + } + new-sources += [ generators.construct $(project) $(name) : + PYTHON_EXTENSION : $(property-set) : $(s) $(libs) ] ; + } + } + + result = [ construct-result $(python) $(new-sources) : $(project) $(name) + : $(property-set) ] ; +} + + First, we separate all source into python files, libraries and C++ + sources. For each C++ source we create a separate Python extension by + calling generators.construct and passing the C++ source + and the libraries. At this point, we also change the extension's name, + if necessary. +
@@ -280,10 +399,13 @@ generators.register-composing mex.mex : CPP LIB : MEX ; # Declare a new feature import feature : feature ; feature verbatim-options : : free ; + # Cause the value of the 'verbatim-options' feature to be # available as 'OPTIONS' variable inside verbatim.inline-file import toolset : flags ; flags verbatim.inline-file OPTIONS <verbatim-options> ; + +# Use the "OPTIONS" variable actions inline-file { "./inline-file.py" $(OPTIONS) $(<) $(>) @@ -325,7 +447,8 @@ actions inline-file - + + Steps for adding a feauture Adding a feature requires three steps: @@ -364,6 +487,8 @@ actions inline-file + Another example + Here's an another example. Let's see how we can make a feature which refers to a target. For example, when linking dynamic libraries on windows, one sometimes needs to specific @@ -428,9 +553,8 @@ rule link Sometimes you want to create a shorcut for some set of features. For example, release is a value of the - variant and is a shortcut for - a set of features. - . + variant and is a shortcut for a set of features. + . It is possible to define your build variants. For example: @@ -518,7 +642,87 @@ generators.register-standard obfuscate.file : CPP : OBFUSCATED_CPP ; -
+
+ + Toolset modules + + If your extensions will be used only on one project, they can be + placed in a separate .jam file which will be + imported by your project-root.jam. If the + extensions will be used on many projects, the users will thank you for + a finishing touch. + + + The standard way to use a tool in Boost.Build is the + using rule. To make it work, you module should provide an + init rule. The rule will be called with the same parameters + which were passed to the using rule. The set of allowed + parameters is determined by you. For example, you can allow the user to + specify paths, tool version, or tool options. + + + Here are some guidelines which help to make Boost.Build more + consistent: + + The init rule should never fail. Even if + user provided a wrong path, you should emit a warning and go + on. Configuration may be shared between different machines, and + wrong values on one machine can be OK on another. + + + Prefer specifying command to be executed to specifying + path. First of all, this gives more control: it's possible to + specify + +/usr/bin/g++-snapshot +time g++ + + as the command. Second, while some tools have a logical + "installation root", it better if user don't have to remember if + a specific tool requires a full command or a path. + + + Check for multiple initialization. A user can try to + initialize the module several times. You need to check for this + and decide what to do. Typically, unless you support several + versions of a tool, duplicate initialization is a user error. If + tool version can be specified during initialization, make sure the + version is either always specified, or never specified (in which + case the tool is initialied only once). For example, if you allow: + +using yfc ; +using yfc : 3.3 ; +using yfc : 3.4 ; + + Then it's not clear if the first initialization corresponds to + version 3.3 of the tool, version 3.4 of the tool, or some other + version. This can lead to building twice with the same version. + + + If possible, the init must be callable + with no parameters. In which case, it should try to autodetect all + the necessary information, for example, by looking for a tool in + PATH or in common installation locations. Often this + is possible and allows the user to simply write: + +using yfc ; + + + + Consider using facilities in the + tools/common module. You can take a look at how + tools/gcc.jam uses that module in the init rule. + + + + + + + + +
+ + + Boost Build System V2 recipes -
- Targets in site-config.jam - - It is desirable to declare standard libraries available on a - given system. Putting target declaration in Jamfile is not really - good, since locations of the libraries can vary. The solution is - to put the following to site-config.jam. - - -import project ; -project.initialize $(__name__) ; -project site-config ; -lib zlib : : <name>z ; - - - The second line allows this module to act as project. The - third line gives id to this project — it really has no location - and cannot be used otherwise. The fourth line just declares a - target. Now, one can write - - -exe hello : hello.cpp /site-config//zlib ; - - - in any Jamfile. - -
diff --git a/v2/doc/src/userman.xml b/v2/doc/src/userman.xml index 9d69bcff6..f4a9202f1 100644 --- a/v2/doc/src/userman.xml +++ b/v2/doc/src/userman.xml @@ -12,12 +12,11 @@ + - -