Merge pull request #4650 from Repiteo/node-explicit-types
[scons.git] / doc / user / add-method.xml
blob001a575004d69d9fd9e2e429f5918588eba8341f
1 <?xml version='1.0'?>
3 <!--
4 SPDX-FileCopyrightText: Copyright The SCons Foundation (https://scons.org)
5 SPDX-License-Identifier: MIT
6 SPDX-FileType: DOCUMENTATION
8 This file is processed by the bin/SConsDoc.py module.
9 -->
11 <!DOCTYPE sconsdoc [
12     <!ENTITY % scons SYSTEM "../scons.mod">
13     %scons;
15     <!ENTITY % builders-mod SYSTEM "../generated/builders.mod">
16     %builders-mod;
17     <!ENTITY % functions-mod SYSTEM "../generated/functions.mod">
18     %functions-mod;
19     <!ENTITY % tools-mod SYSTEM "../generated/tools.mod">
20     %tools-mod;
21     <!ENTITY % variables-mod SYSTEM "../generated/variables.mod">
22     %variables-mod;
26 <chapter id="chap-add-method"
27          xmlns="http://www.scons.org/dbxsd/v1.0"
28          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
29          xsi:schemaLocation="http://www.scons.org/dbxsd/v1.0 http://www.scons.org/dbxsd/v1.0/scons.xsd">
31 <title>Extending &SCons;: Pseudo-Builders and the AddMethod function</title>
33   <para>
35   The &f-link-AddMethod; function is used to add a method
36   to an environment.  It is typically used to add a "pseudo-builder,"
37   a function that looks like a &Builder; but
38   wraps up calls to multiple other &Builders;
39   or otherwise processes its arguments
40   before calling one or more &Builders;.
42   </para>
44   <para>
46   In the following example,
47   we want to install the program into the standard
48   <filename>/usr/bin</filename> directory hierarchy,
49   but also copy it into a local <filename>install/bin</filename>
50   directory from which a package might be built:
52   </para>
54   <scons_example name="addmethod_ex1">
55      <file name="SConstruct" printme="1">
56 def install_in_bin_dirs(env, source):
57     """Install source in both bin directories"""
58     i1 = env.Install("$BIN", source)
59     i2 = env.Install("$LOCALBIN", source)
60     return [i1[0], i2[0]]  # Return a list, like a normal builder
62 env = Environment(BIN='__ROOT__/usr/bin', LOCALBIN='#install/bin')
63 env.AddMethod(install_in_bin_dirs, "InstallInBinDirs")
64 env.InstallInBinDirs(Program('hello.c'))  # installs hello in both bin directories
65      </file>
66      <file name="hello.c">
67 int main() { printf("Hello, world!\n"); }
68      </file>
69   </scons_example>
71   <para>
72   This produces the following:
73   </para>
75   <scons_output example="addmethod_ex1" suffix="1">
76     <scons_output_command>scons -Q /</scons_output_command>
77   </scons_output>
79   <para>
81   A pseudo-builder is useful because it gives you more flexibility
82   parsing arguments than you can get with a standard &Builder;.
83   The next example shows a pseudo-builder with a
84   named argument that modifies the filename, and a separate optional
85   argument for a resource file (rather than having the builder figure it out
86   by file extension).  This example also demonstrates using the global
87   &AddMethod; function to add a method to the global Environment class,
88   so it will be available in all subsequently created environments.
90   </para>
92   <scons_example name="addmethod_ex2">
93      <file name="SConstruct" printme="1">
94 def BuildTestProg(env, testfile, resourcefile="", testdir="tests"):
95     """Build the test program.
97     Prepends "test_" to src and target and puts the target into testdir.
98     If the build is running on Windows, also make use of a resource file,
99     if supplied.
100     """
101     srcfile = f"test_{testfile}.c"
102     target = f"{testdir}/test_{testfile}"
103     if env['PLATFORM'] == 'win32' and resourcefile:
104         resfile = env.RES(resourcefile)
105         p = env.Program(target, [srcfile, resfile])
106     else:
107         p = env.Program(target, srcfile)
108     return p
110 AddMethod(Environment, BuildTestProg)
112 env = Environment()
113 env.BuildTestProg('stuff', resourcefile='res.rc')
114      </file>
115      <file name="test_stuff.c">
116 int main() { printf("Hello, world!\n"); }
117      </file>
118      <file name="res.rc">
119 res.rc
120      </file>
121   </scons_example>
123   <para>
124   This produces the following on Linux:
125   </para>
127   <scons_output example="addmethod_ex2" suffix="1">
128     <scons_output_command>scons -Q</scons_output_command>
129   </scons_output>
131   <para>
132   And the following on Windows:
133   </para>
135   <scons_output example="addmethod_ex2" os="win32" suffix="2">
136     <scons_output_command>scons -Q</scons_output_command>
137   </scons_output>
139   <para>
140   Using &AddMethod; is better than just adding an instance method
141   to a &consenv; because it gets called as a proper method,
142   and because &AddMethod; provides for copying the method
143   to any clones of the &consenv; instance.
144   </para>
146 </chapter>